X-Git-Url: https://git.karo-electronics.de/?a=blobdiff_plain;f=drivers%2Fnet%2Fbonding%2Fbond_main.c;h=db82876ceb286198e9d8e94390af6a9233ba6dd0;hb=0519d83d83ed485b5a1f9222ff69d7d6c9bb8a01;hp=69c5b15e22daca1239e5d10bc6f00b767ae3ce4c;hpb=fe61c99a1227aeb5a4324e39cecf465a4b2052d3;p=mv-sheeva.git diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 69c5b15e22d..db82876ceb2 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -94,6 +94,7 @@ static int downdelay; static int use_carrier = 1; static char *mode; static char *primary; +static char *primary_reselect; static char *lacp_rate; static char *ad_select; static char *xmit_hash_policy; @@ -126,6 +127,14 @@ MODULE_PARM_DESC(mode, "Mode of operation : 0 for balance-rr, " "6 for balance-alb"); module_param(primary, charp, 0); MODULE_PARM_DESC(primary, "Primary network device to use"); +module_param(primary_reselect, charp, 0); +MODULE_PARM_DESC(primary_reselect, "Reselect primary slave " + "once it comes up; " + "0 for always (default), " + "1 for only if speed of primary is " + "better, " + "2 for only on active slave " + "failure"); module_param(lacp_rate, charp, 0); MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner " "(slow/fast)"); @@ -200,6 +209,13 @@ const struct bond_parm_tbl fail_over_mac_tbl[] = { { NULL, -1}, }; +const struct bond_parm_tbl pri_reselect_tbl[] = { +{ "always", BOND_PRI_RESELECT_ALWAYS}, +{ "better", BOND_PRI_RESELECT_BETTER}, +{ "failure", BOND_PRI_RESELECT_FAILURE}, +{ NULL, -1}, +}; + struct bond_parm_tbl ad_select_tbl[] = { { "stable", BOND_AD_STABLE}, { "bandwidth", BOND_AD_BANDWIDTH}, @@ -691,7 +707,7 @@ static int bond_check_dev_link(struct bonding *bond, struct net_device *slave_dev, int reporting) { const struct net_device_ops *slave_ops = slave_dev->netdev_ops; - static int (*ioctl)(struct net_device *, struct ifreq *, int); + int (*ioctl)(struct net_device *, struct ifreq *, int); struct ifreq ifr; struct mii_ioctl_data *mii; @@ -1070,6 +1086,25 @@ out: } +static bool bond_should_change_active(struct bonding *bond) +{ + struct slave *prim = bond->primary_slave; + struct slave *curr = bond->curr_active_slave; + + if (!prim || !curr || curr->link != BOND_LINK_UP) + return true; + if (bond->force_primary) { + bond->force_primary = false; + return true; + } + if (bond->params.primary_reselect == BOND_PRI_RESELECT_BETTER && + (prim->speed < curr->speed || + (prim->speed == curr->speed && prim->duplex <= curr->duplex))) + return false; + if (bond->params.primary_reselect == BOND_PRI_RESELECT_FAILURE) + return false; + return true; +} /** * find_best_interface - select the best available slave to be the active one @@ -1084,7 +1119,7 @@ static struct slave *bond_find_best_slave(struct bonding *bond) int mintime = bond->params.updelay; int i; - new_active = old_active = bond->curr_active_slave; + new_active = bond->curr_active_slave; if (!new_active) { /* there were no active slaves left */ if (bond->slave_cnt > 0) /* found one slave */ @@ -1094,7 +1129,8 @@ static struct slave *bond_find_best_slave(struct bonding *bond) } if ((bond->primary_slave) && - bond->primary_slave->link == BOND_LINK_UP) { + bond->primary_slave->link == BOND_LINK_UP && + bond_should_change_active(bond)) { new_active = bond->primary_slave; } @@ -1678,8 +1714,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (USES_PRIMARY(bond->params.mode) && bond->params.primary[0]) { /* if there is a primary slave, remember it */ - if (strcmp(bond->params.primary, new_slave->dev->name) == 0) + if (strcmp(bond->params.primary, new_slave->dev->name) == 0) { bond->primary_slave = new_slave; + bond->force_primary = true; + } } write_lock_bh(&bond->curr_slave_lock); @@ -3201,11 +3239,14 @@ static void bond_info_show_master(struct seq_file *seq) } if (USES_PRIMARY(bond->params.mode)) { - seq_printf(seq, "Primary Slave: %s\n", + seq_printf(seq, "Primary Slave: %s", (bond->primary_slave) ? bond->primary_slave->dev->name : "None"); + if (bond->primary_slave) + seq_printf(seq, " (primary_reselect %s)", + pri_reselect_tbl[bond->params.primary_reselect].modename); - seq_printf(seq, "Currently Active Slave: %s\n", + seq_printf(seq, "\nCurrently Active Slave: %s\n", (curr) ? curr->dev->name : "None"); } @@ -3334,7 +3375,7 @@ static const struct file_operations bond_info_fops = { .release = seq_release, }; -static int bond_create_proc_entry(struct bonding *bond) +static void bond_create_proc_entry(struct bonding *bond) { struct net_device *bond_dev = bond->dev; @@ -3349,8 +3390,6 @@ static int bond_create_proc_entry(struct bonding *bond) else memcpy(bond->proc_file_name, bond_dev->name, IFNAMSIZ); } - - return 0; } static void bond_remove_proc_entry(struct bonding *bond) @@ -3389,7 +3428,7 @@ static void bond_destroy_proc_dir(void) #else /* !CONFIG_PROC_FS */ -static int bond_create_proc_entry(struct bonding *bond) +static void bond_create_proc_entry(struct bonding *bond) { } @@ -3657,18 +3696,17 @@ void bond_unregister_arp(struct bonding *bond) * Hash for the output device based upon layer 2 and layer 3 data. If * the packet is not IP mimic bond_xmit_hash_policy_l2() */ -static int bond_xmit_hash_policy_l23(struct sk_buff *skb, - struct net_device *bond_dev, int count) +static int bond_xmit_hash_policy_l23(struct sk_buff *skb, int count) { struct ethhdr *data = (struct ethhdr *)skb->data; struct iphdr *iph = ip_hdr(skb); if (skb->protocol == htons(ETH_P_IP)) { return ((ntohl(iph->saddr ^ iph->daddr) & 0xffff) ^ - (data->h_dest[5] ^ bond_dev->dev_addr[5])) % count; + (data->h_dest[5] ^ data->h_source[5])) % count; } - return (data->h_dest[5] ^ bond_dev->dev_addr[5]) % count; + return (data->h_dest[5] ^ data->h_source[5]) % count; } /* @@ -3676,8 +3714,7 @@ static int bond_xmit_hash_policy_l23(struct sk_buff *skb, * the packet is a frag or not TCP or UDP, just use layer 3 data. If it is * altogether not IP, mimic bond_xmit_hash_policy_l2() */ -static int bond_xmit_hash_policy_l34(struct sk_buff *skb, - struct net_device *bond_dev, int count) +static int bond_xmit_hash_policy_l34(struct sk_buff *skb, int count) { struct ethhdr *data = (struct ethhdr *)skb->data; struct iphdr *iph = ip_hdr(skb); @@ -3695,18 +3732,17 @@ static int bond_xmit_hash_policy_l34(struct sk_buff *skb, } - return (data->h_dest[5] ^ bond_dev->dev_addr[5]) % count; + return (data->h_dest[5] ^ data->h_source[5]) % count; } /* * Hash for the output device based upon layer 2 data */ -static int bond_xmit_hash_policy_l2(struct sk_buff *skb, - struct net_device *bond_dev, int count) +static int bond_xmit_hash_policy_l2(struct sk_buff *skb, int count) { struct ethhdr *data = (struct ethhdr *)skb->data; - return (data->h_dest[5] ^ bond_dev->dev_addr[5]) % count; + return (data->h_dest[5] ^ data->h_source[5]) % count; } /*-------------------------- Device entry points ----------------------------*/ @@ -4295,7 +4331,7 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev) if (!BOND_IS_OK(bond)) goto out; - slave_no = bond->xmit_hash_policy(skb, bond_dev, bond->slave_cnt); + slave_no = bond->xmit_hash_policy(skb, bond->slave_cnt); bond_for_each_slave(bond, slave, i) { slave_no--; @@ -4646,7 +4682,7 @@ int bond_parse_parm(const char *buf, const struct bond_parm_tbl *tbl) static int bond_check_params(struct bond_params *params) { - int arp_validate_value, fail_over_mac_value; + int arp_validate_value, fail_over_mac_value, primary_reselect_value; /* * Convert string parameters. @@ -4665,7 +4701,8 @@ static int bond_check_params(struct bond_params *params) if ((bond_mode != BOND_MODE_XOR) && (bond_mode != BOND_MODE_8023AD)) { pr_info(DRV_NAME - ": xor_mode param is irrelevant in mode %s\n", + ": xmit_hash_policy param is irrelevant in" + " mode %s\n", bond_mode_name(bond_mode)); } else { xmit_hashtype = bond_parse_parm(xmit_hash_policy, @@ -4945,6 +4982,20 @@ static int bond_check_params(struct bond_params *params) primary = NULL; } + if (primary && primary_reselect) { + primary_reselect_value = bond_parse_parm(primary_reselect, + pri_reselect_tbl); + if (primary_reselect_value == -1) { + pr_err(DRV_NAME + ": Error: Invalid primary_reselect \"%s\"\n", + primary_reselect == + NULL ? "NULL" : primary_reselect); + return -EINVAL; + } + } else { + primary_reselect_value = BOND_PRI_RESELECT_ALWAYS; + } + if (fail_over_mac) { fail_over_mac_value = bond_parse_parm(fail_over_mac, fail_over_mac_tbl); @@ -4976,6 +5027,7 @@ static int bond_check_params(struct bond_params *params) params->use_carrier = use_carrier; params->lacp_fast = lacp_fast; params->primary[0] = 0; + params->primary_reselect = primary_reselect_value; params->fail_over_mac = fail_over_mac_value; if (primary) {