在上一篇文章中,知道了为什么要有用户态协议栈,它具备什么功能。
今天来讲述,如何实现一个用户态协议栈。
它的原理就是, 将TCP/UDP到达网卡经解析后的数据,存储起来, 然后存储的位置通过映射的方法,直接到达应用程序处理。
网络协议栈
请问,网卡是属于哪一层协议栈?
先解释一下,
物理层 传输的是 物理信号, 即 光电信号。
数据链路层 , 对应的是 数字信号。
而从物理层的 光电信号 转化为 数据链路层的 数字信号, 靠的是 网卡。
网卡, 也可将 数字信号转为 光电信号。
所以,网卡并不属于网络协议栈里的任何一层。
UDP数据包的结构图
它是一层一层的,往外包的。
以太网协议
mac地址是以太网产物
mac地址有什么用?
mac地址,在局域网内有用。出了局域网之后,mac的地址就无效了。
//定义一个以太网的协议头
struct ethhdr {
unsigned char h_dest[ETH_ALEN]; // mac 目的地址,固定6个字节
unsigned char h_source[ETH_ALEN]; // 源地址, 固定6个字节
unsigned short h_proto; // 类型
};
这个以太网协议头这个结构体,大小为14字节。
IP协议
IP地址是网络层产物
// IP协议头
struct iphdr {
unsigned char version; // 版本号 ipv4 /ipv6
unsigned char tos; // 8bit 的 服务类型
unsigned short tot_len;
unsigned short id; // 标识, 每个包都有自己的id,identidy
unsigned short flag_off; // 3bit的标志, 13bit的偏移量
unsigned char ttl; // 生命周期
unsigned char protocol; // 协议
unsigned short check; // 校验和
unsigned int saddr; // 源ip地址
unsigned int daddr; // 目的地址
};
什么时候选择有符号的char,啥时候选择无符号char.
如果有用来计算的话,就选择有符号的char型。
如果没有,只是单纯的表示值。那么就选择无符号的char。
ARP协议
// 28字节的 ARP请求/应答 ARP协议头
struct arphdr {
unsigned short h_type; // 硬件类型
unsigned short h_proto; // 协议类型
unsigned char h_addrlen; // 硬件地址长度
unsigned char protolen; // 协议地址长度
unsigned short oper; // op 操作
unsigned char smac[ETH_ALEN]; // 发送端以太网地址
unsigned int sip; // 发送端IP地址
unsigned char dmac[ETH_ALEN]; // 目的以太网地址
unsigned int dip; // 目的IP地址
};
// 一个ARP的数据包
struct arppkt {
struct ethhdr eh; // 以太网头
struct arphdr arp; // ARP请求/应答 ARP协议头
};
ICMP协议
// ICMP协议头
struct icmphdr {
unsigned char type;
unsigned char code;
unsigned short check;
unsigned short identifier;
unsigned short seq;
unsigned char data[32];
};
//一个ICMP的数据包
struct icmppkt {
struct ethhdr eh; // 以太网
struct iphdr ip; // IP头
struct icmphdr icmp; // ICMP协议头
};
用户态协议栈的实现
以下是使用了netmap 框架来实现的一个,用户态协议栈
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/poll.h>
#include <arpa/inet.h>
#define NETMAP_WITH_LIBS
#include <net/netmap_user.h>
#pragma pack(1)
#define ETH_ALEN 6
#define PROTO_IP 0x0800
#define PROTO_ARP 0x0806
#define PROTO_UDP 17
#define PROTO_ICMP 1