bond_main.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 2,408 行 · 第 1/5 页
C
2,408 行
slave_dev->vlan_rx_kill_vid(slave_dev, vid); bond->vlgrp->vlan_devices[vid] = vlan_dev; } } res = bond_del_vlan(bond, vid); if (res) { printk(KERN_ERR DRV_NAME ": %s: Error: Failed to remove vlan id %d\n", bond_dev->name, vid); }}static void bond_add_vlans_on_slave(struct bonding *bond, struct net_device *slave_dev){ struct vlan_entry *vlan; write_lock_bh(&bond->lock); if (list_empty(&bond->vlan_list)) { goto out; } if ((slave_dev->features & NETIF_F_HW_VLAN_RX) && slave_dev->vlan_rx_register) { slave_dev->vlan_rx_register(slave_dev, bond->vlgrp); } if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) || !(slave_dev->vlan_rx_add_vid)) { goto out; } list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { slave_dev->vlan_rx_add_vid(slave_dev, vlan->vlan_id); }out: write_unlock_bh(&bond->lock);}static void bond_del_vlans_from_slave(struct bonding *bond, struct net_device *slave_dev){ struct vlan_entry *vlan; struct net_device *vlan_dev; write_lock_bh(&bond->lock); if (list_empty(&bond->vlan_list)) { goto out; } if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) || !(slave_dev->vlan_rx_kill_vid)) { goto unreg; } list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { /* Save and then restore vlan_dev in the grp array, * since the slave's driver might clear it. */ vlan_dev = bond->vlgrp->vlan_devices[vlan->vlan_id]; slave_dev->vlan_rx_kill_vid(slave_dev, vlan->vlan_id); bond->vlgrp->vlan_devices[vlan->vlan_id] = vlan_dev; }unreg: if ((slave_dev->features & NETIF_F_HW_VLAN_RX) && slave_dev->vlan_rx_register) { slave_dev->vlan_rx_register(slave_dev, NULL); }out: write_unlock_bh(&bond->lock);}/*------------------------------- Link status -------------------------------*//* * Set the carrier state for the master according to the state of its * slaves. If any slaves are up, the master is up. In 802.3ad mode, * do special 802.3ad magic. * * Returns zero if carrier state does not change, nonzero if it does. */static int bond_set_carrier(struct bonding *bond){ struct slave *slave; int i; if (bond->slave_cnt == 0) goto down; if (bond->params.mode == BOND_MODE_8023AD) return bond_3ad_set_carrier(bond); bond_for_each_slave(bond, slave, i) { if (slave->link == BOND_LINK_UP) { if (!netif_carrier_ok(bond->dev)) { netif_carrier_on(bond->dev); return 1; } return 0; } }down: if (netif_carrier_ok(bond->dev)) { netif_carrier_off(bond->dev); return 1; } return 0;}/* * Get link speed and duplex from the slave's base driver * using ethtool. If for some reason the call fails or the * values are invalid, fake speed and duplex to 100/Full * and return error. */static int bond_update_speed_duplex(struct slave *slave){ struct net_device *slave_dev = slave->dev; static int (* ioctl)(struct net_device *, struct ifreq *, int); struct ifreq ifr; struct ethtool_cmd etool; /* Fake speed and duplex */ slave->speed = SPEED_100; slave->duplex = DUPLEX_FULL; if (slave_dev->ethtool_ops) { int res; if (!slave_dev->ethtool_ops->get_settings) { return -1; } res = slave_dev->ethtool_ops->get_settings(slave_dev, &etool); if (res < 0) { return -1; } goto verify; } ioctl = slave_dev->do_ioctl; strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ); etool.cmd = ETHTOOL_GSET; ifr.ifr_data = (char*)&etool; if (!ioctl || (IOCTL(slave_dev, &ifr, SIOCETHTOOL) < 0)) { return -1; }verify: switch (etool.speed) { case SPEED_10: case SPEED_100: case SPEED_1000: break; default: return -1; } switch (etool.duplex) { case DUPLEX_FULL: case DUPLEX_HALF: break; default: return -1; } slave->speed = etool.speed; slave->duplex = etool.duplex; return 0;}/* * if <dev> supports MII link status reporting, check its link status. * * We either do MII/ETHTOOL ioctls, or check netif_carrier_ok(), * depening upon the setting of the use_carrier parameter. * * Return either BMSR_LSTATUS, meaning that the link is up (or we * can't tell and just pretend it is), or 0, meaning that the link is * down. * * If reporting is non-zero, instead of faking link up, return -1 if * both ETHTOOL and MII ioctls fail (meaning the device does not * support them). If use_carrier is set, return whatever it says. * It'd be nice if there was a good way to tell if a driver supports * netif_carrier, but there really isn't. */static int bond_check_dev_link(struct bonding *bond, struct net_device *slave_dev, int reporting){ static int (* ioctl)(struct net_device *, struct ifreq *, int); struct ifreq ifr; struct mii_ioctl_data *mii; struct ethtool_value etool; if (bond->params.use_carrier) { return netif_carrier_ok(slave_dev) ? BMSR_LSTATUS : 0; } ioctl = slave_dev->do_ioctl; if (ioctl) { /* TODO: set pointer to correct ioctl on a per team member */ /* bases to make this more efficient. that is, once */ /* we determine the correct ioctl, we will always */ /* call it and not the others for that team */ /* member. */ /* * We cannot assume that SIOCGMIIPHY will also read a * register; not all network drivers (e.g., e100) * support that. */ /* Yes, the mii is overlaid on the ifreq.ifr_ifru */ strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ); mii = if_mii(&ifr); if (IOCTL(slave_dev, &ifr, SIOCGMIIPHY) == 0) { mii->reg_num = MII_BMSR; if (IOCTL(slave_dev, &ifr, SIOCGMIIREG) == 0) { return (mii->val_out & BMSR_LSTATUS); } } } /* try SIOCETHTOOL ioctl, some drivers cache ETHTOOL_GLINK */ /* for a period of time so we attempt to get link status */ /* from it last if the above MII ioctls fail... */ if (slave_dev->ethtool_ops) { if (slave_dev->ethtool_ops->get_link) { u32 link; link = slave_dev->ethtool_ops->get_link(slave_dev); return link ? BMSR_LSTATUS : 0; } } if (ioctl) { strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ); etool.cmd = ETHTOOL_GLINK; ifr.ifr_data = (char*)&etool; if (IOCTL(slave_dev, &ifr, SIOCETHTOOL) == 0) { if (etool.data == 1) { return BMSR_LSTATUS; } else { dprintk("SIOCETHTOOL shows link down\n"); return 0; } } } /* * If reporting, report that either there's no dev->do_ioctl, * or both SIOCGMIIREG and SIOCETHTOOL failed (meaning that we * cannot report link status). If not reporting, pretend * we're ok. */ return (reporting ? -1 : BMSR_LSTATUS);}/*----------------------------- Multicast list ------------------------------*//* * Returns 0 if dmi1 and dmi2 are the same, non-0 otherwise */static inline int bond_is_dmi_same(struct dev_mc_list *dmi1, struct dev_mc_list *dmi2){ return memcmp(dmi1->dmi_addr, dmi2->dmi_addr, dmi1->dmi_addrlen) == 0 && dmi1->dmi_addrlen == dmi2->dmi_addrlen;}/* * returns dmi entry if found, NULL otherwise */static struct dev_mc_list *bond_mc_list_find_dmi(struct dev_mc_list *dmi, struct dev_mc_list *mc_list){ struct dev_mc_list *idmi; for (idmi = mc_list; idmi; idmi = idmi->next) { if (bond_is_dmi_same(dmi, idmi)) { return idmi; } } return NULL;}/* * Push the promiscuity flag down to appropriate slaves */static void bond_set_promiscuity(struct bonding *bond, int inc){ if (USES_PRIMARY(bond->params.mode)) { /* write lock already acquired */ if (bond->curr_active_slave) { dev_set_promiscuity(bond->curr_active_slave->dev, inc); } } else { struct slave *slave; int i; bond_for_each_slave(bond, slave, i) { dev_set_promiscuity(slave->dev, inc); } }}/* * Push the allmulti flag down to all slaves */static void bond_set_allmulti(struct bonding *bond, int inc){ if (USES_PRIMARY(bond->params.mode)) { /* write lock already acquired */ if (bond->curr_active_slave) { dev_set_allmulti(bond->curr_active_slave->dev, inc); } } else { struct slave *slave; int i; bond_for_each_slave(bond, slave, i) { dev_set_allmulti(slave->dev, inc); } }}/* * Add a Multicast address to slaves * according to mode */static void bond_mc_add(struct bonding *bond, void *addr, int alen){ if (USES_PRIMARY(bond->params.mode)) { /* write lock already acquired */ if (bond->curr_active_slave) { dev_mc_add(bond->curr_active_slave->dev, addr, alen, 0); } } else { struct slave *slave; int i; bond_for_each_slave(bond, slave, i) { dev_mc_add(slave->dev, addr, alen, 0); } }}/* * Remove a multicast address from slave * according to mode */static void bond_mc_delete(struct bonding *bond, void *addr, int alen){ if (USES_PRIMARY(bond->params.mode)) { /* write lock already acquired */ if (bond->curr_active_slave) { dev_mc_delete(bond->curr_active_slave->dev, addr, alen, 0); } } else { struct slave *slave; int i; bond_for_each_slave(bond, slave, i) { dev_mc_delete(slave->dev, addr, alen, 0); } }}/* * Totally destroys the mc_list in bond */static void bond_mc_list_destroy(struct bonding *bond){ struct dev_mc_list *dmi; dmi = bond->mc_list; while (dmi) { bond->mc_list = dmi->next; kfree(dmi); dmi = bond->mc_list; }}/* * Copy all the Multicast addresses from src to the bonding device dst */static int bond_mc_list_copy(struct dev_mc_list *mc_list, struct bonding *bond, gfp_t gfp_flag){ struct dev_mc_list *dmi, *new_dmi; for (dmi = mc_list; dmi; dmi = dmi->next) { new_dmi = kmalloc(sizeof(struct dev_mc_list), gfp_flag); if (!new_dmi) { /* FIXME: Potential memory leak !!! */ return -ENOMEM; } new_dmi->next = bond->mc_list; bond->mc_list = new_dmi; new_dmi->dmi_addrlen = dmi->dmi_addrlen; memcpy(new_dmi->dmi_addr, dmi->dmi_addr, dmi->dmi_addrlen); new_dmi->dmi_users = dmi->dmi_users; new_dmi->dmi_gusers = dmi->dmi_gusers; } return 0;}/* * flush all members of flush->mc_list from device dev->mc_list */static void bond_mc_list_flush(struct net_device *bond_dev, struct net_device *slave_dev){ struct bonding *bond = bond_dev->priv; struct dev_mc_list *dmi; for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) { dev_mc_delete(slave_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); } if (bond->params.mode == BOND_MODE_8023AD) { /* del lacpdu mc addr from mc list */ u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR; dev_mc_delete(slave_dev, lacpdu_multicast, ETH_ALEN, 0); }}/*--------------------------- Active slave change ---------------------------*//* * Update the mc list and multicast-related flags for the new and * old active slaves (if any) according to the multicast mode, and * promiscuous flags unconditionally. */static void bond_mc_swap(struct bonding *bond, struct slave *new_active, struct slave *old_active){ struct dev_mc_list *dmi; if (!USES_PRIMARY(bond->params.mode)) { /* nothing to do - mc list is already up-to-date on * all slaves */ return; } if (old_active) { if (bond->dev->flags & IFF_PROMISC) { dev_set_promiscuity(old_active->dev, -1); } if (bond->dev->flags & IFF_ALLMULTI) { dev_set_allmulti(old_active->dev, -1); } for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next) { dev_mc_delete(old_active->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); } } if (new_active) { if (bond->dev->flags & IFF_PROMISC) { dev_set_promiscuity(new_active->dev, 1); } if (bond->dev->flags & IFF_ALLMULTI) { dev_set_allmulti(new_active->dev, 1); } for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next) { dev_mc_add(new_active->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); } }}/** * find_best_interface - select the best available slave to be the active one
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?