diff options
Diffstat (limited to 'drivers/net/bonding')
-rw-r--r-- | drivers/net/bonding/bond_alb.c | 41 | ||||
-rw-r--r-- | drivers/net/bonding/bond_main.c | 80 | ||||
-rw-r--r-- | drivers/net/bonding/bonding.h | 10 |
3 files changed, 97 insertions, 34 deletions
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index b211486a0ca..87437c78847 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -38,6 +38,7 @@ #include <linux/in.h> #include <net/ipx.h> #include <net/arp.h> +#include <net/ipv6.h> #include <asm/byteorder.h> #include "bonding.h" #include "bond_alb.h" @@ -81,6 +82,7 @@ #define RLB_PROMISC_TIMEOUT 10*ALB_TIMER_TICKS_PER_SEC static const u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; +static const u8 mac_v6_allmcast[ETH_ALEN] = {0x33,0x33,0x00,0x00,0x00,0x01}; static const int alb_delta_in_ticks = HZ / ALB_TIMER_TICKS_PER_SEC; #pragma pack(1) @@ -167,11 +169,14 @@ static void tlb_clear_slave(struct bonding *bond, struct slave *slave, int save_ /* clear slave from tx_hashtbl */ tx_hash_table = BOND_ALB_INFO(bond).tx_hashtbl; - index = SLAVE_TLB_INFO(slave).head; - while (index != TLB_NULL_INDEX) { - u32 next_index = tx_hash_table[index].next; - tlb_init_table_entry(&tx_hash_table[index], save_load); - index = next_index; + /* skip this if we've already freed the tx hash table */ + if (tx_hash_table) { + index = SLAVE_TLB_INFO(slave).head; + while (index != TLB_NULL_INDEX) { + u32 next_index = tx_hash_table[index].next; + tlb_init_table_entry(&tx_hash_table[index], save_load); + index = next_index; + } } tlb_init_slave(slave); @@ -710,7 +715,7 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) struct arp_pkt *arp = arp_pkt(skb); struct slave *tx_slave = NULL; - if (arp->op_code == __constant_htons(ARPOP_REPLY)) { + if (arp->op_code == htons(ARPOP_REPLY)) { /* the arp must be sent on the selected * rx channel */ @@ -719,7 +724,7 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) memcpy(arp->mac_src,tx_slave->dev->dev_addr, ETH_ALEN); } dprintk("Server sent ARP Reply packet\n"); - } else if (arp->op_code == __constant_htons(ARPOP_REQUEST)) { + } else if (arp->op_code == htons(ARPOP_REQUEST)) { /* Create an entry in the rx_hashtbl for this client as a * place holder. * When the arp reply is received the entry will be updated @@ -1290,6 +1295,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) u32 hash_index = 0; const u8 *hash_start = NULL; int res = 1; + struct ipv6hdr *ip6hdr; skb_reset_mac_header(skb); eth_data = eth_hdr(skb); @@ -1319,11 +1325,32 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) } break; case ETH_P_IPV6: + /* IPv6 doesn't really use broadcast mac address, but leave + * that here just in case. + */ if (memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) { do_tx_balance = 0; break; } + /* IPv6 uses all-nodes multicast as an equivalent to + * broadcasts in IPv4. + */ + if (memcmp(eth_data->h_dest, mac_v6_allmcast, ETH_ALEN) == 0) { + do_tx_balance = 0; + break; + } + + /* Additianally, DAD probes should not be tx-balanced as that + * will lead to false positives for duplicate addresses and + * prevent address configuration from working. + */ + ip6hdr = ipv6_hdr(skb); + if (ipv6_addr_any(&ip6hdr->saddr)) { + do_tx_balance = 0; + break; + } + hash_start = (char *)&(ipv6_hdr(skb)->daddr); hash_size = sizeof(ipv6_hdr(skb)->daddr); break; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index c792138511e..a3efba59eee 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1341,18 +1341,24 @@ static int bond_compute_features(struct bonding *bond) int i; features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES); - features |= NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | - NETIF_F_GSO_MASK | NETIF_F_NO_CSUM; + features |= NETIF_F_GSO_MASK | NETIF_F_NO_CSUM; + + if (!bond->first_slave) + goto done; + + features &= ~NETIF_F_ONE_FOR_ALL; bond_for_each_slave(bond, slave, i) { - features = netdev_compute_features(features, - slave->dev->features); + features = netdev_increment_features(features, + slave->dev->features, + NETIF_F_ONE_FOR_ALL); if (slave->dev->hard_header_len > max_hard_header_len) max_hard_header_len = slave->dev->hard_header_len; } +done: features |= (bond_dev->features & BOND_VLAN_FEATURES); - bond_dev->features = features; + bond_dev->features = netdev_fix_features(features, NULL); bond_dev->hard_header_len = max_hard_header_len; return 0; @@ -1973,6 +1979,20 @@ void bond_destroy(struct bonding *bond) unregister_netdevice(bond->dev); } +static void bond_destructor(struct net_device *bond_dev) +{ + struct bonding *bond = bond_dev->priv; + + if (bond->wq) + destroy_workqueue(bond->wq); + + netif_addr_lock_bh(bond_dev); + bond_mc_list_destroy(bond); + netif_addr_unlock_bh(bond_dev); + + free_netdev(bond_dev); +} + /* * First release a slave and than destroy the bond if no more slaves iare left. * Must be under rtnl_lock when this function is called. @@ -2370,6 +2390,9 @@ static void bond_miimon_commit(struct bonding *bond) continue; case BOND_LINK_DOWN: + if (slave->link_failure_count < UINT_MAX) + slave->link_failure_count++; + slave->link = BOND_LINK_DOWN; if (bond->params.mode == BOND_MODE_ACTIVEBACKUP || @@ -3702,7 +3725,7 @@ static int bond_xmit_hash_policy_l23(struct sk_buff *skb, struct ethhdr *data = (struct ethhdr *)skb->data; struct iphdr *iph = ip_hdr(skb); - if (skb->protocol == __constant_htons(ETH_P_IP)) { + if (skb->protocol == htons(ETH_P_IP)) { return ((ntohl(iph->saddr ^ iph->daddr) & 0xffff) ^ (data->h_dest[5] ^ bond_dev->dev_addr[5])) % count; } @@ -3723,8 +3746,8 @@ static int bond_xmit_hash_policy_l34(struct sk_buff *skb, __be16 *layer4hdr = (__be16 *)((u32 *)iph + iph->ihl); int layer4_xor = 0; - if (skb->protocol == __constant_htons(ETH_P_IP)) { - if (!(iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) && + if (skb->protocol == htons(ETH_P_IP)) { + if (!(iph->frag_off & htons(IP_MF|IP_OFFSET)) && (iph->protocol == IPPROTO_TCP || iph->protocol == IPPROTO_UDP)) { layer4_xor = ntohs((*layer4hdr ^ *(layer4hdr + 1))); @@ -4493,6 +4516,12 @@ static void bond_ethtool_get_drvinfo(struct net_device *bond_dev, static const struct ethtool_ops bond_ethtool_ops = { .get_drvinfo = bond_ethtool_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_tx_csum = ethtool_op_get_tx_csum, + .get_sg = ethtool_op_get_sg, + .get_tso = ethtool_op_get_tso, + .get_ufo = ethtool_op_get_ufo, + .get_flags = ethtool_op_get_flags, }; /* @@ -4538,7 +4567,7 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params) bond_set_mode_ops(bond, bond->params.mode); - bond_dev->destructor = free_netdev; + bond_dev->destructor = bond_destructor; /* Initialize the device options */ bond_dev->tx_queue_len = 0; @@ -4577,20 +4606,6 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params) return 0; } -/* De-initialize device specific data. - * Caller must hold rtnl_lock. - */ -static void bond_deinit(struct net_device *bond_dev) -{ - struct bonding *bond = bond_dev->priv; - - list_del(&bond->bond_list); - -#ifdef CONFIG_PROC_FS - bond_remove_proc_entry(bond); -#endif -} - static void bond_work_cancel_all(struct bonding *bond) { write_lock_bh(&bond->lock); @@ -4612,6 +4627,22 @@ static void bond_work_cancel_all(struct bonding *bond) cancel_delayed_work(&bond->ad_work); } +/* De-initialize device specific data. + * Caller must hold rtnl_lock. + */ +static void bond_deinit(struct net_device *bond_dev) +{ + struct bonding *bond = bond_dev->priv; + + list_del(&bond->bond_list); + + bond_work_cancel_all(bond); + +#ifdef CONFIG_PROC_FS + bond_remove_proc_entry(bond); +#endif +} + /* Unregister and free all bond devices. * Caller must hold rtnl_lock. */ @@ -4623,9 +4654,6 @@ static void bond_free_all(void) struct net_device *bond_dev = bond->dev; bond_work_cancel_all(bond); - netif_addr_lock_bh(bond_dev); - bond_mc_list_destroy(bond); - netif_addr_unlock_bh(bond_dev); /* Release the bonded slaves */ bond_release_all(bond_dev); bond_destroy(bond); diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index fb730ec0396..ffb668dd6d3 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -32,7 +32,7 @@ #ifdef BONDING_DEBUG #define dprintk(fmt, args...) \ printk(KERN_DEBUG \ - DRV_NAME ": %s() %d: " fmt, __FUNCTION__, __LINE__ , ## args ) + DRV_NAME ": %s() %d: " fmt, __func__, __LINE__ , ## args ) #else #define dprintk(fmt, args...) #endif /* BONDING_DEBUG */ @@ -333,5 +333,13 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active); void bond_register_arp(struct bonding *); void bond_unregister_arp(struct bonding *); +/* exported from bond_main.c */ +extern struct list_head bond_dev_list; +extern struct bond_parm_tbl bond_lacp_tbl[]; +extern struct bond_parm_tbl bond_mode_tbl[]; +extern struct bond_parm_tbl xmit_hashtype_tbl[]; +extern struct bond_parm_tbl arp_validate_tbl[]; +extern struct bond_parm_tbl fail_over_mac_tbl[]; + #endif /* _LINUX_BONDING_H */ |