Chinaunix首页 | 论坛 | 博客
  • 博客访问: 522815
  • 博文数量: 122
  • 博客积分: 2024
  • 博客等级: 上尉
  • 技术积分: 1484
  • 用 户 组: 普通用户
  • 注册时间: 2010-01-08 21:17
文章分类

全部博文(122)

文章存档

2012年(2)

2011年(25)

2010年(95)

分类: LINUX

2010-03-17 09:49:10

网卡驱动把数据从设备拷贝到内存后会通过 netif_rx 把数据提交给上层,而上层通过 dev_queue_xmit 发送数
据,如果符合条件,调用驱动的 hard_start_xmit 把数据发送出去。本文
主要描述这两个流程的细节,其中流量控制,虚拟设备的绑定,网桥都在这一层有所涉及,但不予讨论,并且
基本不涉及 NAPI。
1,核心数据结构
struct softnet_data
{
    int             throttle;
    int             cng_level;
    int             avg_blog;
    struct sk_buff_head     input_pkt_queue;
    struct list_head        poll_list;
    struct net_device       *output_queue;
    struct sk_buff          *completion_queue;
    struct net_device       backlog_dev;
}
前三个用于流量控制,
input_pkt_queue,接受的 skb 队列
poll_list,如果设备上有要接收的数据,就把设备添加到 poll_list 中,并把 skb 挂在 input_pkt_queue 上,
由 net_rx_action 处理
output_queue,如果设备上有发送的数据,就把设备添加到这个队列
completion_queue,数据如果成功发送(通过中断指示),就把 skb 挂在这个队列上,net_tx_action 会释放掉
skb 占用的内存
backlog_dev,处理接收数据的时候,提供通用的设备轮询方法,backlog_process
每个 cpu 都有一个这样的数据结构
2,数据的接收
netdevice->state 中的_ _LINK_STATE_START flag 字段用于表示网卡是否开启,数据接收的时候也用于
检查这个字段。
netif_rx:
作用:把数据挂在 input_pkt_queue 上
如果 input_pkt_queue 上没有数据,就调用 netif_rx_schedule(&queue->backlog_dev),把这个 backlog 设备
添加到 poll_list 的链表中,对非 NAPI 驱动来说,这个设备就是链表上的唯一设备.如果队列上有数据就把数
据挂在 input_pkt_queue 上。等待软中断处理函数 net_rx_action 对队列上的数据进行处理。而对于 NAPI 驱
动,每个设备都有私有的 input_pkt_queue,驱动把 dev 添加到 poll_list 链表中(dev 是 realdev,而不是 back
log dev),把 skb 挂在私有队列上。
net_rx_action
作用:负责把 input_pkt_queue 上的数据提交给上层
The job of net_rx_action is pretty simple: to browse the poll_list list of devices that hav
e something in their ingress queue and invoke for each one the associated poll virtual function
对于非 NAPI 驱动来说,就是调用 backlog_dev 的 poll 方法 process_backlog。而对于 NAPI 驱动,则调用驱动
定义的 poll 方法。也就是说,process_backlog 处理共有的 input_pkt_queue,NAPI 驱动利用 poll 处理私有的
input_pkt_queue
2,数据的发送
__link_state_xoff 字段用于指示设备是否可以发送。netif_start_queue 和 netif_stop_queue 用于开启传输
和关闭传输。这是由驱动做的事。
与 netif_rx 对应的函数是 dev_queue_xmit,数据的发送有两个路径,1,将 skb 放到设备的发送队列,通过 qd
isc_run 发送,2,而没有流量控制的直接调用 hard_start_xmit 将数据发送出去(一些虚拟设备)。
qdisc_run,调用 qdisc_restart,经过一些复杂的队列控制,将数据通过 hard_start_xmit 发送出去。
net_tx_action,主要做两件事
1,轮询 output_queue 的 net 设备,调用 qdisc_run 将设备发送队列上的数据发送出去
2,释放 complete 队列上的 skb 内存
可见数据的接受有公共队列,而发送都是私有队列,当数据从上层传下来时就已经指定要通过哪个设备发送 s
kb->dev。
3,数据接受和发送是对称的两个过程,实质上就是对输入队列和输出队列的操作。
    • poll_list is the list of devices that are polled because they have a non
       empty receive queue. output_queue is the list of devices that have some
       thing to transmit.
    • Only open devices (ones with the _ _LINK_STATE_START flag set) can be
       scheduled for reception. Only devices with transmission enabled (ones with
       the _ _LINK_STATE_XOFF flag cleared) can be scheduled for transmission.
    • When a device is scheduled for reception, its _ _LINK_STATE_RX_SCHED
       flag is set. When a device is scheduled for transmission, its _ _LINK_ST
       ATE_SCHED flag is set.

阅读(2897) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~