[百度分享]Bonding 模块代码及主要工作模式分析(3)

baiduforum 2010-05-20 10:09:59
* bond_release

原型

static int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)

该函数在试图解除一个物理网卡的绑定状态时被调用,其中bond_dev表示虚拟的网卡,slave_dev表示真实的物理网卡。该函数主要做如下操作:

1. 取出bond_dev的私有数据,用bond指向它(struct bonding *)。
2. 寻找对应的slave结构。
3. 一系列的合法性检查,包括:

1. slave_dev->flags是否设置了IFF_SLAVE。
2. slave结构是否存在。
3. slave_dev原来的MAC地址是否和bond_dev相同,如果相同给出警告(防止MAC冲突)

4. 如果虚拟网卡工作在BOND_MODE_8023AD模式,调用bond_3ad_unbind_slave

5. 调用bond_detach_slave把slave从bond的链表中摘除(通过维护bond-> first_slave和slave结构的next,prev指针)。
6. 如果slave_dev是虚拟网卡以前的主物理网卡,则设置bond->primary_slave为NULL。
7. 如果slave_dev是虚拟网卡以前的活动网卡,则设置bond->active_slave为NULL(通过调用bond_change_active_slave函数)。
8. 如果虚拟网卡工作在模式BOND_MODE_TLB或者BOND_MODE_ALB则调用bond_alb_deinit_slave。
9. 如果slave_dev是虚拟网卡以前的活动网卡,则调用bond_select_active_slave寻找一个新的活动网卡。
10. 如果虚拟网卡再也没有管辖的物理网卡,清除虚拟网卡的MAC地址(如果新调用ifenslave绑定物理网卡,则重新设置这个MAC地址)。
11. 维护VLAN和Multicast相关的数据结构。
12. 调用netdev_set_master解除master和slave的绑定关系并且调用dev_close关闭slave_dev。
13. 恢复slave_dev的MAC地址(根据slave->perm_hwaddr)和flags(根据slave->original_flags)。
14. 调用kfree释放slave结构。

3. 网卡驱动通用接口(interface service routines)

既然bonding模块本质上是一个虚拟网卡的驱动模块,所以必须提供一组所有网卡驱动模块都遵守的通用接口函数。

1. open/close

* bond_open(net_device->open接口)

原型:

static int bond_open(struct net_device *bond_dev)

该函数在对应的虚拟网卡被打开时调用(即使用ifup/ifconfig工具启动网卡的时候),主要做如下操作(只分析三种主要模式):

1. 设置bond->kill_timers为0。
2. 如果使用MII链路状态监控:

1. 初始化mii_timer。
2. 设置超时时间mii_timer->expires为当前jiffies+1(立即调用bond_mii_monitor函数)
3. 设置bond_mii_monitor为定时器的超时处理函数。

3. 如果使用ARP链路状态监控:

1. 初始化arp_timer。
2. 设置超时时间arp_timer->expires为当前jiffies+1(立即调用定时器的超时处理函数)
3. 如果工作在BOND_MODE_ACTIVEBACKUP,设置bond_activebackup_arp_mon为超时处理函数。
4. 如果工作在其他模式,设置bond_loadbalance_arp_mon为超时处理函数。



* bond_close(net_device->stop接口)

原型:

static int bond_close(struct net_device *bond_dev)

该函数在对应的虚拟网卡被关闭时调用(即使用ifdown/ifconfig工具关闭网卡的时候),主要做如下操作(只分析三种主要模式):

1. 调用bond_mc_list_destroy维护Multicast相关数据结构。
2. 设置bond->kill_timers为1,所有的计时器超时后就不再重新设置,从而可以被安全删除。
3. 删除所有的定时器,包括mii_timer和arp_timer。
4. 调用bond_release_all释放所有被绑定的物理网卡,本质上该函数只是遍历slave链表并且对每一个元素调用bond_release。
5. 如果虚拟网卡工作在BOND_MODE_TLB或者BOND_MODE_ALB模式下,调用bond_alb_deinitialize。

2. ioctl接口

* bond_do_ioctl(net_device->do_ioctl 接口)

原型:

static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd)

该函数是虚拟网卡的IOCTRL接口,仅仅根据不同的IOCTRL命令调用其他函数执行相应的功能,所以不再列出操作流程而仅仅列举出这些被调用的函数和相应的功能:

* 链路状态设置和查询(bond_ethtool_ioctl或者if_mii)
* Bonding模块状态查询(bond_info_query)
* 被绑定的物理网卡状态查询(bond_slave_info_query)
* 物理网卡的绑定和解除绑定(bond_enslave/bond_release)
* 虚拟网卡的MAC地址设置(bond_sethwaddr)
* 切换当前活动的物理网卡(bond_ioctl_change_active)

3. 统计值查询

* bond_get_stats(net_device-> get_stats 接口)

原型:

static struct net_device_stats *bond_get_stats(struct net_device *bond_dev)

该函数枚举所有被管辖的物理网卡,并且对每一个物理网卡调用get_stats接口,然后把对应的统计值加起来并作为最终的返回值,这些统计值包括。
名称 含义
rx_packets 接收包总数
rx_bytes 接收字节总数
rx_errors 接收过程中错误数据包数
rx_dropped 接受过程中丢弃包数
tx_packets 发送包总数
tx_bytes 发送字节总数
tx_errors 发送过程中错误数据包数
tx_dropped 发送过程中丢弃包数
multicast Multicast数据包总数
collisions MAC地址冲突次数
rx_length_errors 接收数据包长度错误总数
rx_over_errors ring buff溢出次数
rx_crc_errors 接收数据包CRC校验错误总数
rx_frame_errors 接收数据包frame对齐错误总数
rx_fifo_errors 接收队列溢出次数
rx_missed_errors 接收时丢失的包数(仅仅对某些媒体有效)
tx_aborted_errors 发送取消次数(例如发送超时)
tx_carrier_errors 链路错误总数
tx_fifo_errors 发送队列溢出次数
tx_heartbeat_errors 心跳信号丢失(仅仅对某些媒体有效)
tx_window_errors 接收窗口错误(不明,需要进一步确认)


* bond_set_multicast_list(net_device-> set_multicast_list 接口)

原型:

static void bond_set_multicast_list(struct net_device *bond_dev)

该函数设置和Multicast和混杂模式相关的一组数据结构,由于三种主要工作模式并不过多地涉及这个函数,所以本文档不给出详细的说明。

* bond_change_mtu(net_device-> change_mtu 接口)

原型:

static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)

该函数把被虚拟网卡的MTU和被它管辖的所有物理网卡的MTU设置为同一值,主要做如下操作:

1. 枚举所有被管辖的物理网卡,对每一个物理网卡调用change_mtu设置新的MTU值,如果物理网卡没有change_mtu接口函数,则直接设置slave->dev->mtu等于new_mtu。
2. 设置bond_dev->mtu的值等于new_mtu。



* bond_set_mac_address(net_device-> set_mac_address 接口)

原型:

static int bond_set_mac_address(struct net_device *bond_dev, void *addr)

该函数设置虚拟网卡的MAC地址和被管辖的物理网卡的MAC地址为同一值,主要做如下操作:

1. 枚举所有被管辖的物理网卡,对每一个物理网卡调用set_mac_address设置新的MAC地址,如果物理网卡没有set_mac_address函数,则错误返回。
2. 设置bond_dev->dev_addr的值等于新的MAC地址。

4. 数据包传输(接收/发送)

Bonding模块仅仅负责把发送数据包按照特定的工作模式转给被管辖的物理网卡发送,而每一个物理网卡负责自己的数据包接收,即虚拟网卡不管理各个物理网卡的数据接收过程,它能做的仅仅是设置它们的IFF_NOARP标志,使某一个物理网卡对ARP请求不做出回应。

在模块初始化时, bond_init函数根据工作模式把net_device-> hard_start_xmit接口设置为不同的函数,对于 BOND_MODE_ROUNDROBIN、BOND_MODE_ACTIVEBACKUP和BOND_MODE_BROADCAST 模式,该接口分别被设置为下列三个函数之一

* bond_xmit_roundrobin(net_device-> hard_start_xmit 接口)

原型:

static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev)

该函数用来在BOND_MODE_ROUNDROBIN模式中发送数据包,主要做如下操作:

1. 合法性检查,包括:

1. 检查bond_dev ->flags中IFF_UP标志是否设置
2. netif_running(bond_dev)是否返回非0值
3. 对应的虚拟网卡是否至少有一个管辖的物理网卡

2. 从bond->curr_active_slave开始遍历slave链表,找到第一个链路状态为BOND_LINK_UP,活动状态为BOND_STATE_ACTIVE的物理网卡并且调用bond_dev_queue_xmit向这个物理网卡发送数据,然后设置bond->curr_active_slave为slave链表中的下一个物理网卡。

3. 如果没有找到这样的网卡或者bond_dev_queue_xmit返回非0值,则调用dev_kfree_skb丢弃数据包。



* bond_xmit_activebackup(net_device-> hard_start_xmit 接口)

原型:

static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_dev)

该函数用来在BOND_MODE_ACTIVEBACKUP模式中发送数据包,主要做如下操作:

1. 如果是试图发送ARP请求,则把全局变量my_ip设置为ARP请求中的发送方IP地址(skb->data+以太网头长度+ARP头长度+6),这个全局变量在ARP链路状态监控中被使用。
2. 合法性检查,包括:

1. 检查bond_dev ->flags中IFF_UP标志是否设置
2. netif_running(bond_dev)是否返回非0值
3. 对应的虚拟网卡是否至少有一个管辖的物理网卡

3. 如果bond->curr_active_slave不为空,则调用bond_dev_queue_xmit向这个物理网卡发送数据。

4. 否则,调用dev_kfree_skb丢弃数据包。



* bond_xmit_broadcast(net_device-> hard_start_xmit接口)

原型:

static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev)

该函数用来在BOND_MODE_BROADCAST模式中发送数据包,主要做如下操作:

1. 合法性检查,包括:

1. 检查bond_dev ->flags中IFF_UP标志是否设置
2. netif_running(bond_dev)是否返回非0值
3. 对应的虚拟网卡是否至少有一个管辖的物理网卡

2. 从bond->curr_active_slave开始遍历slave链表,找到所有状态为BOND_LINK_UP,活动状态为BOND_STATE_ACTIVE的物理网卡,包括bond->curr_active_slave,调用bond_dev_queue_xmit向这些物理网卡发送数据(其中需要通过skb_clone复制skb结构)。

3. 如果发送失败,调用dev_kfree_skb丢弃数据包



* bond_dev_queue_xmit

原型:

int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev)

该函数被bond_xmit_roundrobin,bond_xmit_activebackup 和bond_xmit_broadcast 调用,向实际的物理网卡发送数据包,主要做如下操作:

1. 设置skb->dev为slave_dev(在此之前skb->dev指向虚拟网卡,现在指向真实的物理网卡)
2. 维护和VLAN相关的数据结构。
3. 调用dev_queue_xmit发送数据包。



* dev_queue_xmit

原型:

该函数不是bonding模块的一部分而是内核的一个标准接口,为了清楚起见也把它列出来,请参考net/core/dev.c文件。

int dev_queue_xmit(struct sk_buff *skb)

1. 如果底层的物理网卡不支持Scatter/Gather IO,而skb包含了分片(注意不是IP分片,而是和DMA相关的一个概念,见skbbuff.h),则调用__skb_linearize合并分片。
2. 如果底层的设备不支持计算校验和,则计算一系列校验和。
3. 如果底层的设备有发送队列(qdisc),则把数据包放入发送队列中,退出。
4. 如果底层的设备没有发送队列(例如loopback或者其他没有真实物理网卡对应的设备,bonding模块自然也算一个),则直接调用底层设备的hard_start_xmit发送数据包。
5. 如果发送失败,调用dev_kfree_skb丢弃数据包

4. 链路状态监控

1. MII链路状态监控

* bond_mii_monitor

原型:

static void bond_mii_monitor(struct net_device *bond_dev)

如果使用MII链路状态监控,则该函数被周期调用以检测每一个被绑定物理网卡的链路状态, 主要做如下操作:

1. 计算局部变量delta_in_ticks = (bond->params.miimon * HZ) / 1000,即miimon参数的jiffies表示。
2. 如果kill_timers被设置,直接退出。
3. 如果没有任何物理网卡被绑定,重新设置定时器,退出。
4. 根据bond_check_dev_link的结果,按照第5节描述的MII链路状态监控模型设置网卡的链路状态。
5. 如果原来物理网卡的链路状态为BOND_LINK_FAIL,而 bond_check_dev_link返回非BMSR_LSTATUS值,则除了把链路状态设置为BOND_LINK_DOWN之外,还做如下操作:

1. 如果虚拟网卡工作在模式BOND_MODE_8023AD,调用bond_3ad_handle_link_change
2. 如果虚拟网卡工作在模式BOND_MODE_TLB或者BOND_MODE_ALB模式下,调用bond_alb_handle_link_change。
3. 如果当前被检查的slave不是curr_active_slave,设置标志do_failover表明可能会发生slave切换。

6. 如果原来物理网卡的链路状态为BOND_LINK_BACK而bond_check_dev_link 返回BMSR_LSTATUS,则除了把链路状态设置为BOND_LINK_UP之外,还做如下操作:

1. 如果虚拟网卡工作在模式BOND_MODE_8023AD或者被监测网卡不是primary_slave,则设置物理网卡的活动状态为BOND_STATE_BACKUP
2. 如果虚拟网卡*不是*工作在模式BOND_MODE_ACTIVEBACKUP,则设置物理网卡的活动状态为BOND_STATE_ACTIVE
3. 如果虚拟网卡工作在模式BOND_MODE_8023AD,调用bond_3ad_handle_link_change
4. 如果虚拟网卡工作在模式BOND_MODE_TLB或者BOND_MODE_ALB模式下,调用bond_alb_handle_link_change。
5. 如果当前被检查的slave不是curr_active_slave,设置标志do_failover表明可能会发生slave切换。

7. 调用bond_update_speed_duplex更新物理网卡的速率。

8. 如果do_failover被设置,调用bond_select_active_slave。
9. 设置定时器的超时值为jiffies+delta_in_ticks。
...全文
599 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
steptodream 2010-05-24
  • 打赏
  • 举报
回复
好帖就顶。百度名人!
2010-05-24
  • 打赏
  • 举报
回复
kwest 2010-05-21
  • 打赏
  • 举报
回复
好帖就顶。
  • 打赏
  • 举报
回复
很好,继续收藏。
steptodream 2010-05-20
  • 打赏
  • 举报
回复

百度名人勋章是什么 楼主先讲讲 我就看你发的内容 嘿嘿

3,286

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 实用资料发布区
社区管理员
  • 实用资料发布区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧