bond_main.c
来自「linux2.6.16版本」· C语言 代码 · 共 2,394 行 · 第 1/5 页
C
2,394 行
/* * originally based on the dummy device. * * Copyright 1999, Thomas Davis, tadavis@lbl.gov. * Licensed under the GPL. Based on dummy.c, and eql.c devices. * * bonding.c: an Ethernet Bonding driver * * This is useful to talk to a Cisco EtherChannel compatible equipment: * Cisco 5500 * Sun Trunking (Solaris) * Alteon AceDirector Trunks * Linux Bonding * and probably many L2 switches ... * * How it works: * ifconfig bond0 ipaddress netmask up * will setup a network device, with an ip address. No mac address * will be assigned at this time. The hw mac address will come from * the first slave bonded to the channel. All slaves will then use * this hw mac address. * * ifconfig bond0 down * will release all slaves, marking them as down. * * ifenslave bond0 eth0 * will attach eth0 to bond0 as a slave. eth0 hw mac address will either * a: be used as initial mac address * b: if a hw mac address already is there, eth0's hw mac address * will then be set from bond0. * *///#define BONDING_DEBUG 1#include <linux/config.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/interrupt.h>#include <linux/ptrace.h>#include <linux/ioport.h>#include <linux/in.h>#include <net/ip.h>#include <linux/ip.h>#include <linux/tcp.h>#include <linux/udp.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/init.h>#include <linux/timer.h>#include <linux/socket.h>#include <linux/ctype.h>#include <linux/inet.h>#include <linux/bitops.h>#include <asm/system.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/uaccess.h>#include <linux/errno.h>#include <linux/netdevice.h>#include <linux/inetdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <net/sock.h>#include <linux/rtnetlink.h>#include <linux/proc_fs.h>#include <linux/seq_file.h>#include <linux/smp.h>#include <linux/if_ether.h>#include <net/arp.h>#include <linux/mii.h>#include <linux/ethtool.h>#include <linux/if_vlan.h>#include <linux/if_bonding.h>#include <net/route.h>#include "bonding.h"#include "bond_3ad.h"#include "bond_alb.h"/*---------------------------- Module parameters ----------------------------*//* monitor all links that often (in milliseconds). <=0 disables monitoring */#define BOND_LINK_MON_INTERV 0#define BOND_LINK_ARP_INTERV 0static int max_bonds = BOND_DEFAULT_MAX_BONDS;static int miimon = BOND_LINK_MON_INTERV;static int updelay = 0;static int downdelay = 0;static int use_carrier = 1;static char *mode = NULL;static char *primary = NULL;static char *lacp_rate = NULL;static char *xmit_hash_policy = NULL;static int arp_interval = BOND_LINK_ARP_INTERV;static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, };struct bond_params bonding_defaults;module_param(max_bonds, int, 0);MODULE_PARM_DESC(max_bonds, "Max number of bonded devices");module_param(miimon, int, 0);MODULE_PARM_DESC(miimon, "Link check interval in milliseconds");module_param(updelay, int, 0);MODULE_PARM_DESC(updelay, "Delay before considering link up, in milliseconds");module_param(downdelay, int, 0);MODULE_PARM_DESC(downdelay, "Delay before considering link down, " "in milliseconds");module_param(use_carrier, int, 0);MODULE_PARM_DESC(use_carrier, "Use netif_carrier_ok (vs MII ioctls) in miimon; " "0 for off, 1 for on (default)");module_param(mode, charp, 0);MODULE_PARM_DESC(mode, "Mode of operation : 0 for balance-rr, " "1 for active-backup, 2 for balance-xor, " "3 for broadcast, 4 for 802.3ad, 5 for balance-tlb, " "6 for balance-alb");module_param(primary, charp, 0);MODULE_PARM_DESC(primary, "Primary network device to use");module_param(lacp_rate, charp, 0);MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner " "(slow/fast)");module_param(xmit_hash_policy, charp, 0);MODULE_PARM_DESC(xmit_hash_policy, "XOR hashing method: 0 for layer 2 (default)" ", 1 for layer 3+4");module_param(arp_interval, int, 0);MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds");module_param_array(arp_ip_target, charp, NULL, 0);MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form");/*----------------------------- Global variables ----------------------------*/static const char *version = DRV_DESCRIPTION ": v" DRV_VERSION " (" DRV_RELDATE ")\n";LIST_HEAD(bond_dev_list);#ifdef CONFIG_PROC_FSstatic struct proc_dir_entry *bond_proc_dir = NULL;#endifextern struct rw_semaphore bonding_rwsem;static u32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ;static int arp_ip_count = 0;static int bond_mode = BOND_MODE_ROUNDROBIN;static int xmit_hashtype= BOND_XMIT_POLICY_LAYER2;static int lacp_fast = 0;struct bond_parm_tbl bond_lacp_tbl[] = {{ "slow", AD_LACP_SLOW},{ "fast", AD_LACP_FAST},{ NULL, -1},};struct bond_parm_tbl bond_mode_tbl[] = {{ "balance-rr", BOND_MODE_ROUNDROBIN},{ "active-backup", BOND_MODE_ACTIVEBACKUP},{ "balance-xor", BOND_MODE_XOR},{ "broadcast", BOND_MODE_BROADCAST},{ "802.3ad", BOND_MODE_8023AD},{ "balance-tlb", BOND_MODE_TLB},{ "balance-alb", BOND_MODE_ALB},{ NULL, -1},};struct bond_parm_tbl xmit_hashtype_tbl[] = {{ "layer2", BOND_XMIT_POLICY_LAYER2},{ "layer3+4", BOND_XMIT_POLICY_LAYER34},{ NULL, -1},};/*-------------------------- Forward declarations ---------------------------*/static void bond_send_gratuitous_arp(struct bonding *bond);/*---------------------------- General routines -----------------------------*/const char *bond_mode_name(int mode){ switch (mode) { case BOND_MODE_ROUNDROBIN : return "load balancing (round-robin)"; case BOND_MODE_ACTIVEBACKUP : return "fault-tolerance (active-backup)"; case BOND_MODE_XOR : return "load balancing (xor)"; case BOND_MODE_BROADCAST : return "fault-tolerance (broadcast)"; case BOND_MODE_8023AD: return "IEEE 802.3ad Dynamic link aggregation"; case BOND_MODE_TLB: return "transmit load balancing"; case BOND_MODE_ALB: return "adaptive load balancing"; default: return "unknown"; }}/*---------------------------------- VLAN -----------------------------------*//** * bond_add_vlan - add a new vlan id on bond * @bond: bond that got the notification * @vlan_id: the vlan id to add * * Returns -ENOMEM if allocation failed. */static int bond_add_vlan(struct bonding *bond, unsigned short vlan_id){ struct vlan_entry *vlan; dprintk("bond: %s, vlan id %d\n", (bond ? bond->dev->name: "None"), vlan_id); vlan = kmalloc(sizeof(struct vlan_entry), GFP_KERNEL); if (!vlan) { return -ENOMEM; } INIT_LIST_HEAD(&vlan->vlan_list); vlan->vlan_id = vlan_id; vlan->vlan_ip = 0; write_lock_bh(&bond->lock); list_add_tail(&vlan->vlan_list, &bond->vlan_list); write_unlock_bh(&bond->lock); dprintk("added VLAN ID %d on bond %s\n", vlan_id, bond->dev->name); return 0;}/** * bond_del_vlan - delete a vlan id from bond * @bond: bond that got the notification * @vlan_id: the vlan id to delete * * returns -ENODEV if @vlan_id was not found in @bond. */static int bond_del_vlan(struct bonding *bond, unsigned short vlan_id){ struct vlan_entry *vlan, *next; int res = -ENODEV; dprintk("bond: %s, vlan id %d\n", bond->dev->name, vlan_id); write_lock_bh(&bond->lock); list_for_each_entry_safe(vlan, next, &bond->vlan_list, vlan_list) { if (vlan->vlan_id == vlan_id) { list_del(&vlan->vlan_list); if ((bond->params.mode == BOND_MODE_TLB) || (bond->params.mode == BOND_MODE_ALB)) { bond_alb_clear_vlan(bond, vlan_id); } dprintk("removed VLAN ID %d from bond %s\n", vlan_id, bond->dev->name); kfree(vlan); if (list_empty(&bond->vlan_list) && (bond->slave_cnt == 0)) { /* Last VLAN removed and no slaves, so * restore block on adding VLANs. This will * be removed once new slaves that are not * VLAN challenged will be added. */ bond->dev->features |= NETIF_F_VLAN_CHALLENGED; } res = 0; goto out; } } dprintk("couldn't find VLAN ID %d in bond %s\n", vlan_id, bond->dev->name);out: write_unlock_bh(&bond->lock); return res;}/** * bond_has_challenged_slaves * @bond: the bond we're working on * * Searches the slave list. Returns 1 if a vlan challenged slave * was found, 0 otherwise. * * Assumes bond->lock is held. */static int bond_has_challenged_slaves(struct bonding *bond){ struct slave *slave; int i; bond_for_each_slave(bond, slave, i) { if (slave->dev->features & NETIF_F_VLAN_CHALLENGED) { dprintk("found VLAN challenged slave - %s\n", slave->dev->name); return 1; } } dprintk("no VLAN challenged slaves found\n"); return 0;}/** * bond_next_vlan - safely skip to the next item in the vlans list. * @bond: the bond we're working on * @curr: item we're advancing from * * Returns %NULL if list is empty, bond->next_vlan if @curr is %NULL, * or @curr->next otherwise (even if it is @curr itself again). * * Caller must hold bond->lock */struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr){ struct vlan_entry *next, *last; if (list_empty(&bond->vlan_list)) { return NULL; } if (!curr) { next = list_entry(bond->vlan_list.next, struct vlan_entry, vlan_list); } else { last = list_entry(bond->vlan_list.prev, struct vlan_entry, vlan_list); if (last == curr) { next = list_entry(bond->vlan_list.next, struct vlan_entry, vlan_list); } else { next = list_entry(curr->vlan_list.next, struct vlan_entry, vlan_list); } } return next;}/** * bond_dev_queue_xmit - Prepare skb for xmit. * * @bond: bond device that got this skb for tx. * @skb: hw accel VLAN tagged skb to transmit * @slave_dev: slave that is supposed to xmit this skbuff * * When the bond gets an skb to transmit that is * already hardware accelerated VLAN tagged, and it * needs to relay this skb to a slave that is not * hw accel capable, the skb needs to be "unaccelerated", * i.e. strip the hwaccel tag and re-insert it as part * of the payload. */int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev){ unsigned short vlan_id; if (!list_empty(&bond->vlan_list) && !(slave_dev->features & NETIF_F_HW_VLAN_TX) && vlan_get_tag(skb, &vlan_id) == 0) { skb->dev = slave_dev; skb = vlan_put_tag(skb, vlan_id); if (!skb) { /* vlan_put_tag() frees the skb in case of error, * so return success here so the calling functions * won't attempt to free is again. */ return 0; } } else { skb->dev = slave_dev; } skb->priority = 1; dev_queue_xmit(skb); return 0;}/* * In the following 3 functions, bond_vlan_rx_register(), bond_vlan_rx_add_vid * and bond_vlan_rx_kill_vid, We don't protect the slave list iteration with a * lock because: * a. This operation is performed in IOCTL context, * b. The operation is protected by the RTNL semaphore in the 8021q code, * c. Holding a lock with BH disabled while directly calling a base driver * entry point is generally a BAD idea. * * The design of synchronization/protection for this operation in the 8021q * module is good for one or more VLAN devices over a single physical device * and cannot be extended for a teaming solution like bonding, so there is a * potential race condition here where a net device from the vlan group might * be referenced (either by a base driver or the 8021q code) while it is being * removed from the system. However, it turns out we're not making matters * worse, and if it works for regular VLAN usage it will work here too.*//** * bond_vlan_rx_register - Propagates registration to slaves * @bond_dev: bonding net device that got called * @grp: vlan group being registered */static void bond_vlan_rx_register(struct net_device *bond_dev, struct vlan_group *grp){ struct bonding *bond = bond_dev->priv; struct slave *slave; int i; bond->vlgrp = grp; bond_for_each_slave(bond, slave, i) { struct net_device *slave_dev = slave->dev; if ((slave_dev->features & NETIF_F_HW_VLAN_RX) && slave_dev->vlan_rx_register) { slave_dev->vlan_rx_register(slave_dev, grp); } }}/** * bond_vlan_rx_add_vid - Propagates adding an id to slaves * @bond_dev: bonding net device that got called * @vid: vlan id being added */static void bond_vlan_rx_add_vid(struct net_device *bond_dev, uint16_t vid){ struct bonding *bond = bond_dev->priv; struct slave *slave; int i, res; bond_for_each_slave(bond, slave, i) { struct net_device *slave_dev = slave->dev; if ((slave_dev->features & NETIF_F_HW_VLAN_FILTER) && slave_dev->vlan_rx_add_vid) { slave_dev->vlan_rx_add_vid(slave_dev, vid); } } res = bond_add_vlan(bond, vid); if (res) { printk(KERN_ERR DRV_NAME ": %s: Error: Failed to add vlan id %d\n", bond_dev->name, vid); }}/** * bond_vlan_rx_kill_vid - Propagates deleting an id to slaves * @bond_dev: bonding net device that got called * @vid: vlan id being removed */static void bond_vlan_rx_kill_vid(struct net_device *bond_dev, uint16_t vid){ struct bonding *bond = bond_dev->priv; struct slave *slave; struct net_device *vlan_dev; int i, res; bond_for_each_slave(bond, slave, i) { struct net_device *slave_dev = slave->dev; if ((slave_dev->features & NETIF_F_HW_VLAN_FILTER) && slave_dev->vlan_rx_kill_vid) { /* Save and then restore vlan_dev in the grp array,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?