📄 bond_main.c
字号:
!(slave_dev->features & NETIF_F_HW_VLAN_TX)) { res = vlan_get_tag(skb, &vlan_id); if (res) { return -EINVAL; } 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: 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, * since the slave's driver might clear it. */ vlan_dev = bond->vlgrp->vlan_devices[vid]; 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: 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 -------------------------------*//* * 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) { u32 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -