用户态协议栈:
把协议栈当应用来写
网络协议的解析,放到应用层
本来协议栈是在系统层,用户态是调用到应用层来写的。
系统调用
listen
accept
为什么会有用户态协议栈
1、减少CPU上下切换
网卡作用:光电信号(模拟信号)转换为数字信号,AD转换,在物理层和数据链路层之前
内核态协议栈处理:
网卡把数据放到sk_buff,
协议栈对网卡数据进行解析,放到recvbuff中
两次拷贝:网卡copy到协议栈 协议栈copy到应用程序
将网卡内存映射到内存中间,dma方式,内存直接通道,减少网卡到协议栈拷贝,减少一次拷贝
dma没有拷贝,dma方式,cpu不需要干预,网卡数据直接到内存,零拷贝,即cpu没有干预
mmap原理:
磁盘中间的文件进行映射,蓝牙、U盘、网卡,都可以进行dma方式,把存储映射到内存中间
mmap前提:有dma总线,即支持dma方式
dma方式:数据映射完,会给cpu发送触发中断。
网卡驱动运行在哪里:运行在内核中,nic子系统,使网卡正常工作的
从网卡中取到一帧完整的数据:
实现一个协议栈:
1、netmap 开源
以太网协议头:
#define ETH_ALEN 6
struct ethhdr {
unsigned char h_dest[ETH_ALEN];
unsigned char h_source[ETH_ALEN];
unsigned short h_proto;
};
ip头:
struct iphdr {
unsigned char version;
unsigned char tos;//实时流数据,流媒体数据方法,不一样的
unsigned short tot_len;//ip包总长度,65535byte=64k
unsigned short id;//每个ip包都有id,
unsigned short flag_off;
unsigned char ttl;//8位生存时间,每经过一个网关减一,0时网关就丢弃,返回目的不可到达。
unsigned char protocol;
unsigned short check;
unsigned int saddr;
unsigned int daddr;
};
MTU是网卡的限制,超过1500byte,ip就会进行分包。
UDP头:
struct udphdr {
unsigned short source;
unsigned short dest;
unsigned short len;
unsigned short check;
};
UDP没有数据包的概念
MAC地址是以太网产物,
IP地址是网络层产物
端口号是传输层产物
路由器工作在网络层的
二层交换机在局域网内,在链路层,只对mac地址进行交换
在网络层,则需要路由器,或者是三层交换机
nat 需要对传输层协议进行,
负载均衡LB:
nginx 工作在应用层
haproxy tcp端口代理处理,传输层
lvs 网络层
f5 数据联络层
UDP packet:
struct udppkt {
struct ethhdr eh;
struct iphdr ip;
struct udphdr udp;
unsigned char body[0];//柔性数组,数组首地址
};
sizeof(udppkt)= 44;
柔性数组使用条件:
1、内存已分配好
2、柔性数组的长度可以计算出来
netmap 依赖库,翻墙,url以浏览器方式下载
virtio,uio
将网卡映射到内存中间,应用程序之间在网卡中取数据
虚拟机中将改为ens33->etho
#include <sys/poll.h>
#include <arpa/inet.h>
#define NETMAP_WITH_LIBS
#include <net/netmap_user.h>
#pragma pack(1) //以一个字节对齐,sizeof(udppkt)= 42,这时就不是上面的44字节了
#define PROTO_IP 0x0800
#define PROTO_ARP 0x0806
#define PROTO_UDP 17
#define PROTO_ICMP 1
#define PROTO_IGMP 2
struct udppkt {
struct ethhdr eh;
struct iphdr ip;
struct udphdr udp;
unsigned char body[0];//柔性数组,数组首地址
};
int main() {
struct ethhdr *eh;
struct pollfd pfd = {0};
struct nm_pkthdr h;
unsigned char *stream = NULL;
struct nm_desc *nmr = nm_open("netmap:eth0", NULL, 0, NULL);//将网卡的数据映射到内存中,不会再走内核协议栈,etch0被netmap接管
if (nmr == NULL) {
return -1;
}
pfd.fd = nmr->fd;
pfd.events = POLLIN;
while (1) {
int ret = poll(&pfd, 1, -1);//dma方式数据映射完,会给cpu发送触发中断。知道网卡来数据了,netmap封装的数据
if (ret < 0) continue;
if (pfd.revents & POLLIN) {
stream = nm_nextpkt(nmr, &h);//操作内存,循环队列,读出下一个包,netmap封装,纯内存操作,没有所谓的阻塞和非阻塞概念
eh = (struct ethhdr*)stream;
if (ntohs(eh->h_proto) == PROTO_IP) {
struct udppkt *udp = (struct udppkt*)stream;
if (udp->ip.protocol == PROTO_UDP) {//ntohs()??
struct in_addr addr;
addr.s_addr = udp->ip.saddr;
int udp_length = ntohs(udp->udp.len);
printf("%s:%d:length:%d, ip_len:%d --> ", inet_ntoa(addr), udp->udp.source,
udp_length, ntohs(udp->ip.tot_len));
udp->body[udp_length-8] = '\0';
printf("udp --> %s\n", udp->body);
#if 1
struct udppkt udp_rt;
echo_udp_pkt(udp, &udp_rt);
nm_inject(nmr, &udp_rt, sizeof(struct udppkt));
#endif
#if 0
} else if (udp->ip.protocol == PROTO_ICMP) {//ntohs()??
struct icmppkt *icmp = (struct icmppkt*)stream;
printf("icmp ---------- --> %d, %x\n", icmp->icmp.type, icmp->icmp.check);
if (icmp->icmp.type == 0x08) {
struct icmppkt icmp_rt = {0};
echo_icmp_pkt(icmp, &icmp_rt);
//printf("icmp check %x\n", icmp_rt.icmp.check);
nm_inject(nmr, &icmp_rt, sizeof(struct icmppkt));
}
#endif
} else if (udp->ip.protocol == PROTO_IGMP) {//ntohs()??
} else {
printf("other ip packet");
}
#if 0
} else if (ntohs(eh->h_proto) == PROTO_ARP) {
struct arppkt *arp = (struct arppkt *)stream;
struct arppkt arp_rt;
if (arp->arp.dip == inet_addr("192.168.2.217")) {
echo_arp_pkt(arp, &arp_rt, "00:50:56:33:1c:ca");
nm_inject(nmr, &arp_rt, sizeof(struct arppkt));
}
#endif
}
}
}
}
libpcap 原生socket
netmap 对socket进行了优化
read :从外存读到内存
write:
外界向网卡发送数据时,网卡将数据映射到内存中,内存中用循环队列存储,只要记得队列都在哪,
0拷贝运用场景
日志操作 fwrite,write
mmap,open文件映射到内存,日志 落盘到内存,由netmap操作内存写到文件中
效率:mmap效率比之间操作文件要快。
缺点:可能会丢数据,进程断电时,会丢几帧数据。不能保证数据完全存入到文件
ntohs 网络字节 操作2字节以上的 必须做网络字节序转换 网络字节转本地
arp,linux用netmap接管的网卡,代码中没有实现arp协议,windows arp缓存表超时删除了接管网卡的mac地址,没有学到mac地址,所以ping不通,
同时接管的网卡也没有实现icmp协议
arp:局域网内,广播,我是192.168.0.1 你的mac地址是多少,本地建立arp表,ip地址是多少,mac地址是多少
windows下 查看arp表:
arp -a
UDP优点
1、实时性强,游戏
2、不带拥塞控制,传输速度比tcp快
用户态协议栈使用场景:网关,负载均衡,网络防火墙,性能,