内核协议栈数据包转发完全解析
- 格式:doc
- 大小:752.00 KB
- 文档页数:22
内核协议栈数据包转发
目录
1 NAPI流程与非NAPI
1.1NAPI驱动流程
1.2非NAPI流程
1.3NAPI和非NAPI的区别
2内核接受数据
2.1数据接收过程
2.2 采取DMA技术实现
3 e100采用NAPI接收数据过程
3.1 e100_open 启动e100网卡
3.2 e100_rx_alloc_list 建立环形缓冲区
3.3 e100_rx_alloc_skb 分配skb缓存
3.4 e100_poll 轮询函数
3.5 e100_rx_clean 数据包的接收和传输
3.6 e100_rx_indicate
4 队列层
4.1、软中断与下半部
4.2、队列层
5采用非NAPI接收数据过程
5.1netif_rx
5.2轮询与中断调用netif_rx_schedule不同点
5.3 netif_rx_schedule
5.4 net_rx_action
5.5 process_backlog
6数据包进入网络层
6.1 netif_receive_skb():
6.2 ip_rcv():
6.3 ip_rcv_finish():
6.4 dst_input():
6.5本地流程ip_local_deliver:
6.6转发流程ip_forward():
1 NAPI流程与非NAPI
1.1NAPI驱动流程:
中断发生
-->确定中断原因是数据接收完毕(中断原因也可能是发送完毕,DMA完毕,甚至是中断通道上的其他设备中断)
-->通过netif_rx_schedule将驱动自己的napi结构加入softnet_data的poll_list 链表,禁用网卡中断,并发出软中断NET_RX_SOFTIRQ
-->中断返回时触发软中断调用相应的函数net_rx_action,从softnet_data的
poll_list上取下刚挂入的napi结构,并且调用其 poll函数,这个poll函数也是驱动自己提供的,比如e100网卡驱动中的e100_poll等。
-->在poll函数中进行轮询,直到接受完所有的数据或者预算(budget)耗尽。每接收一个报文要分配skb,用eth_type_trans处理并交给netif_receive_skb。
-->如果数据全部接收完(预算没有用完),则重新使能中断并将napi从链表中取下。如果数据没接收完,则什么也不作,等待下一次poll函数被调度。
1.2非NAPI流程:
中断发生
-->确定中断发生的原因是接收完毕。分配skb,读入数据,用eth_type_trans处理并且将skb交给netif_rx
-->在netif_rx中,将packet加入到softnet_data的input_pkt_queue末尾(NAPI 驱动不使用这个 input_pkt_queue),再通过napi_schedule将softnet_data中的backlog(这也是个napi结构)加入 softnet_data的poll_list,最后发出软中断 -->软中断net_rx_action从poll_list上取下softnet_data的backlog,调用其poll 函数,这个poll函数是内核提供的process_backlog
-->函数process_backlog从softnet_data的input_pkt_queue末尾取下skb,并且直接交给netif_receive_skb处理。
-->如果input_pkt_queue中所有skb都处理完则将backlog从队列中除去(注意input_pkt_queue中可能有多个网卡加入的报文,因为它是每cpu公用的)并退出循环;如果预算用完后也跳出循环。最后返回接受到的包数
1.3 NAPI和非NAPI的区别
NAPI和非NAPI的区别
1.NAPI使用中断+轮询的方式,中断产生之后暂时关闭中断然后轮询接收完所有的数据包,接着再开中断。而非NAPI采用纯粹中断的方式,一个中断接收一个数据包
2.NAPI都有自己的struct napi结构,非NAPI没有
3.NAPI有自己的poll函数,而且接收数据都是在软中断调用poll函数时做的,而非NAPI使用公共的process_backlog函数作为其poll函数,接收数据是在硬件中断中做的
4.NAPI在poll函数中接收完数据之后直接把skb发给netif_receive_skb,而非NAPI 在硬件中断中接收了数据通过 netif_rx把skb挂到公共的input_pkt_queue上,最后由软中断调用的process_backlog函数来将其发送给 netif_receive_skb
驱动以及软中断这块对skb仅仅做了以下简单处理:
1.调用skb_reserve预留出2个字节的空间,这是为了让ip首部对齐,因为以太网首部是14字节
2.调用skb_put将tail指向数据末尾
3.调用eth_type_trans进行如下处理:
(1)将skb->dev指向接收设备
(2)将skb->mac_header指向data(此时data就是指向mac起始地址)
(3)调用skb_pull(skb, ETH_HLEN)将skb->data后移14字节指向ip首部
(4)通过比较目的mac地址判断包的类型,并将skb->pkt_type赋值PACKET_BROADCAST或PACKET_MULTICAST或者PACKET_OTHERHOST,因为PACKET_HOST为0,所以是默认值
(5)最后判断协议类型,并返回(大部分情况下直接返回eth首部的protocol 字段的值),这个返回值被存在skb->protocol字段中
总结,结束后,skb->data指向ip首部,skb->mac_header指向 mac首部,skb->protocol 储存L3的协议代码,skb->pkt_type已被设置,skb->len等于接收到的报文长度减去eth 首部长度,也就是整个ip报文的总长。其余字段基本上还是默认值。