Commit aae8c287 authored by David S. Miller's avatar David S. Miller

Merge branch 'bonding_neighbours'

bonding: use neighbours instead of own lists

Veaceslav Falico says:

====================
This patchset introduces all the needed infrastructure, on top of current
adjacent lists, to be able to remove bond's slave_list/slave->list. The
overhead in memory/CPU is minimal, and after the patchset bonding can rely
on its slave-related functions, given the proper locking. I've done some
netperf benchmarks on a vm, and the delta was about 0.1gbps for 35gbps as a
whole, so no speed fluctuations.

It also automatically creates lower/upper and master symlinks in dev's
sysfs directory.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 4ed377e3 5831d66e
...@@ -2117,7 +2117,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work) ...@@ -2117,7 +2117,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
read_lock(&bond->lock); read_lock(&bond->lock);
//check if there are any slaves //check if there are any slaves
if (list_empty(&bond->slave_list)) if (!bond_has_slaves(bond))
goto re_arm; goto re_arm;
// check if agg_select_timer timer after initialize is timed out // check if agg_select_timer timer after initialize is timed out
...@@ -2417,14 +2417,15 @@ int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info) ...@@ -2417,14 +2417,15 @@ int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info)
int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
{ {
struct slave *slave, *start_at;
struct bonding *bond = netdev_priv(dev); struct bonding *bond = netdev_priv(dev);
int slave_agg_no; struct slave *slave, *first_ok_slave;
int slaves_in_agg; struct aggregator *agg;
int agg_id;
int i;
struct ad_info ad_info; struct ad_info ad_info;
struct list_head *iter;
int slaves_in_agg;
int slave_agg_no;
int res = 1; int res = 1;
int agg_id;
read_lock(&bond->lock); read_lock(&bond->lock);
if (__bond_3ad_get_active_agg_info(bond, &ad_info)) { if (__bond_3ad_get_active_agg_info(bond, &ad_info)) {
...@@ -2437,20 +2438,28 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) ...@@ -2437,20 +2438,28 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
agg_id = ad_info.aggregator_id; agg_id = ad_info.aggregator_id;
if (slaves_in_agg == 0) { if (slaves_in_agg == 0) {
/*the aggregator is empty*/
pr_debug("%s: Error: active aggregator is empty\n", dev->name); pr_debug("%s: Error: active aggregator is empty\n", dev->name);
goto out; goto out;
} }
slave_agg_no = bond->xmit_hash_policy(skb, slaves_in_agg); slave_agg_no = bond->xmit_hash_policy(skb, slaves_in_agg);
first_ok_slave = NULL;
bond_for_each_slave(bond, slave) { bond_for_each_slave(bond, slave, iter) {
struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator; agg = SLAVE_AD_INFO(slave).port.aggregator;
if (!agg || agg->aggregator_identifier != agg_id)
continue;
if (agg && (agg->aggregator_identifier == agg_id)) { if (slave_agg_no >= 0) {
if (!first_ok_slave && SLAVE_IS_OK(slave))
first_ok_slave = slave;
slave_agg_no--; slave_agg_no--;
if (slave_agg_no < 0) continue;
break; }
if (SLAVE_IS_OK(slave)) {
res = bond_dev_queue_xmit(bond, skb, slave->dev);
goto out;
} }
} }
...@@ -2460,20 +2469,10 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) ...@@ -2460,20 +2469,10 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
goto out; goto out;
} }
start_at = slave; /* we couldn't find any suitable slave after the agg_no, so use the
* first suitable found, if found. */
bond_for_each_slave_from(bond, slave, i, start_at) { if (first_ok_slave)
int slave_agg_id = 0; res = bond_dev_queue_xmit(bond, skb, first_ok_slave->dev);
struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator;
if (agg)
slave_agg_id = agg->aggregator_identifier;
if (SLAVE_IS_OK(slave) && agg && (slave_agg_id == agg_id)) {
res = bond_dev_queue_xmit(bond, skb, slave->dev);
break;
}
}
out: out:
read_unlock(&bond->lock); read_unlock(&bond->lock);
...@@ -2515,11 +2514,12 @@ int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond, ...@@ -2515,11 +2514,12 @@ int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
void bond_3ad_update_lacp_rate(struct bonding *bond) void bond_3ad_update_lacp_rate(struct bonding *bond)
{ {
struct port *port = NULL; struct port *port = NULL;
struct list_head *iter;
struct slave *slave; struct slave *slave;
int lacp_fast; int lacp_fast;
lacp_fast = bond->params.lacp_fast; lacp_fast = bond->params.lacp_fast;
bond_for_each_slave(bond, slave) { bond_for_each_slave(bond, slave, iter) {
port = &(SLAVE_AD_INFO(slave).port); port = &(SLAVE_AD_INFO(slave).port);
__get_state_machine_lock(port); __get_state_machine_lock(port);
if (lacp_fast) if (lacp_fast)
......
...@@ -223,13 +223,14 @@ static long long compute_gap(struct slave *slave) ...@@ -223,13 +223,14 @@ static long long compute_gap(struct slave *slave)
static struct slave *tlb_get_least_loaded_slave(struct bonding *bond) static struct slave *tlb_get_least_loaded_slave(struct bonding *bond)
{ {
struct slave *slave, *least_loaded; struct slave *slave, *least_loaded;
struct list_head *iter;
long long max_gap; long long max_gap;
least_loaded = NULL; least_loaded = NULL;
max_gap = LLONG_MIN; max_gap = LLONG_MIN;
/* Find the slave with the largest gap */ /* Find the slave with the largest gap */
bond_for_each_slave(bond, slave) { bond_for_each_slave(bond, slave, iter) {
if (SLAVE_IS_OK(slave)) { if (SLAVE_IS_OK(slave)) {
long long gap = compute_gap(slave); long long gap = compute_gap(slave);
...@@ -382,30 +383,31 @@ static int rlb_arp_recv(const struct sk_buff *skb, struct bonding *bond, ...@@ -382,30 +383,31 @@ static int rlb_arp_recv(const struct sk_buff *skb, struct bonding *bond,
static struct slave *rlb_next_rx_slave(struct bonding *bond) static struct slave *rlb_next_rx_slave(struct bonding *bond)
{ {
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
struct slave *rx_slave, *slave, *start_at; struct slave *before = NULL, *rx_slave = NULL, *slave;
int i = 0; struct list_head *iter;
bool found = false;
if (bond_info->next_rx_slave)
start_at = bond_info->next_rx_slave;
else
start_at = bond_first_slave(bond);
rx_slave = NULL;
bond_for_each_slave_from(bond, slave, i, start_at) { bond_for_each_slave(bond, slave, iter) {
if (SLAVE_IS_OK(slave)) { if (!SLAVE_IS_OK(slave))
if (!rx_slave) { continue;
rx_slave = slave; if (!found) {
} else if (slave->speed > rx_slave->speed) { if (!before || before->speed < slave->speed)
before = slave;
} else {
if (!rx_slave || rx_slave->speed < slave->speed)
rx_slave = slave; rx_slave = slave;
}
} }
if (slave == bond_info->rx_slave)
found = true;
} }
/* we didn't find anything after the current or we have something
* better before and up to the current slave
*/
if (!rx_slave || (before && rx_slave->speed < before->speed))
rx_slave = before;
if (rx_slave) { if (rx_slave)
slave = bond_next_slave(bond, rx_slave); bond_info->rx_slave = rx_slave;
bond_info->next_rx_slave = slave;
}
return rx_slave; return rx_slave;
} }
...@@ -1019,7 +1021,7 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]) ...@@ -1019,7 +1021,7 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[])
/* loop through vlans and send one packet for each */ /* loop through vlans and send one packet for each */
rcu_read_lock(); rcu_read_lock();
netdev_for_each_upper_dev_rcu(bond->dev, upper, iter) { netdev_for_each_all_upper_dev_rcu(bond->dev, upper, iter) {
if (upper->priv_flags & IFF_802_1Q_VLAN) if (upper->priv_flags & IFF_802_1Q_VLAN)
alb_send_lp_vid(slave, mac_addr, alb_send_lp_vid(slave, mac_addr,
vlan_dev_vlan_id(upper)); vlan_dev_vlan_id(upper));
...@@ -1172,10 +1174,11 @@ static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *sla ...@@ -1172,10 +1174,11 @@ static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *sla
*/ */
static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave) static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave)
{ {
struct slave *tmp_slave1, *free_mac_slave = NULL;
struct slave *has_bond_addr = bond->curr_active_slave; struct slave *has_bond_addr = bond->curr_active_slave;
struct slave *tmp_slave1, *free_mac_slave = NULL;
struct list_head *iter;
if (list_empty(&bond->slave_list)) { if (!bond_has_slaves(bond)) {
/* this is the first slave */ /* this is the first slave */
return 0; return 0;
} }
...@@ -1196,7 +1199,7 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav ...@@ -1196,7 +1199,7 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
/* The slave's address is equal to the address of the bond. /* The slave's address is equal to the address of the bond.
* Search for a spare address in the bond for this slave. * Search for a spare address in the bond for this slave.
*/ */
bond_for_each_slave(bond, tmp_slave1) { bond_for_each_slave(bond, tmp_slave1, iter) {
if (!bond_slave_has_mac(bond, tmp_slave1->perm_hwaddr)) { if (!bond_slave_has_mac(bond, tmp_slave1->perm_hwaddr)) {
/* no slave has tmp_slave1's perm addr /* no slave has tmp_slave1's perm addr
* as its curr addr * as its curr addr
...@@ -1246,15 +1249,16 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav ...@@ -1246,15 +1249,16 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
*/ */
static int alb_set_mac_address(struct bonding *bond, void *addr) static int alb_set_mac_address(struct bonding *bond, void *addr)
{ {
char tmp_addr[ETH_ALEN]; struct slave *slave, *rollback_slave;
struct slave *slave; struct list_head *iter;
struct sockaddr sa; struct sockaddr sa;
char tmp_addr[ETH_ALEN];
int res; int res;
if (bond->alb_info.rlb_enabled) if (bond->alb_info.rlb_enabled)
return 0; return 0;
bond_for_each_slave(bond, slave) { bond_for_each_slave(bond, slave, iter) {
/* save net_device's current hw address */ /* save net_device's current hw address */
memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN); memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN);
...@@ -1274,10 +1278,12 @@ static int alb_set_mac_address(struct bonding *bond, void *addr) ...@@ -1274,10 +1278,12 @@ static int alb_set_mac_address(struct bonding *bond, void *addr)
sa.sa_family = bond->dev->type; sa.sa_family = bond->dev->type;
/* unwind from head to the slave that failed */ /* unwind from head to the slave that failed */
bond_for_each_slave_continue_reverse(bond, slave) { bond_for_each_slave(bond, rollback_slave, iter) {
memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN); if (rollback_slave == slave)
dev_set_mac_address(slave->dev, &sa); break;
memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN); memcpy(tmp_addr, rollback_slave->dev->dev_addr, ETH_ALEN);
dev_set_mac_address(rollback_slave->dev, &sa);
memcpy(rollback_slave->dev->dev_addr, tmp_addr, ETH_ALEN);
} }
return res; return res;
...@@ -1458,11 +1464,12 @@ void bond_alb_monitor(struct work_struct *work) ...@@ -1458,11 +1464,12 @@ void bond_alb_monitor(struct work_struct *work)
struct bonding *bond = container_of(work, struct bonding, struct bonding *bond = container_of(work, struct bonding,
alb_work.work); alb_work.work);
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
struct list_head *iter;
struct slave *slave; struct slave *slave;
read_lock(&bond->lock); read_lock(&bond->lock);
if (list_empty(&bond->slave_list)) { if (!bond_has_slaves(bond)) {
bond_info->tx_rebalance_counter = 0; bond_info->tx_rebalance_counter = 0;
bond_info->lp_counter = 0; bond_info->lp_counter = 0;
goto re_arm; goto re_arm;
...@@ -1480,7 +1487,7 @@ void bond_alb_monitor(struct work_struct *work) ...@@ -1480,7 +1487,7 @@ void bond_alb_monitor(struct work_struct *work)
*/ */
read_lock(&bond->curr_slave_lock); read_lock(&bond->curr_slave_lock);
bond_for_each_slave(bond, slave) bond_for_each_slave(bond, slave, iter)
alb_send_learning_packets(slave, slave->dev->dev_addr); alb_send_learning_packets(slave, slave->dev->dev_addr);
read_unlock(&bond->curr_slave_lock); read_unlock(&bond->curr_slave_lock);
...@@ -1493,7 +1500,7 @@ void bond_alb_monitor(struct work_struct *work) ...@@ -1493,7 +1500,7 @@ void bond_alb_monitor(struct work_struct *work)
read_lock(&bond->curr_slave_lock); read_lock(&bond->curr_slave_lock);
bond_for_each_slave(bond, slave) { bond_for_each_slave(bond, slave, iter) {
tlb_clear_slave(bond, slave, 1); tlb_clear_slave(bond, slave, 1);
if (slave == bond->curr_active_slave) { if (slave == bond->curr_active_slave) {
SLAVE_TLB_INFO(slave).load = SLAVE_TLB_INFO(slave).load =
...@@ -1599,13 +1606,13 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave) ...@@ -1599,13 +1606,13 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave)
*/ */
void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave) void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave)
{ {
if (!list_empty(&bond->slave_list)) if (bond_has_slaves(bond))
alb_change_hw_addr_on_detach(bond, slave); alb_change_hw_addr_on_detach(bond, slave);
tlb_clear_slave(bond, slave, 0); tlb_clear_slave(bond, slave, 0);
if (bond->alb_info.rlb_enabled) { if (bond->alb_info.rlb_enabled) {
bond->alb_info.next_rx_slave = NULL; bond->alb_info.rx_slave = NULL;
rlb_clear_slave(bond, slave); rlb_clear_slave(bond, slave);
} }
} }
...@@ -1669,7 +1676,7 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave ...@@ -1669,7 +1676,7 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
swap_slave = bond->curr_active_slave; swap_slave = bond->curr_active_slave;
rcu_assign_pointer(bond->curr_active_slave, new_slave); rcu_assign_pointer(bond->curr_active_slave, new_slave);
if (!new_slave || list_empty(&bond->slave_list)) if (!new_slave || !bond_has_slaves(bond))
return; return;
/* set the new curr_active_slave to the bonds mac address /* set the new curr_active_slave to the bonds mac address
......
...@@ -154,9 +154,7 @@ struct alb_bond_info { ...@@ -154,9 +154,7 @@ struct alb_bond_info {
u8 rx_ntt; /* flag - need to transmit u8 rx_ntt; /* flag - need to transmit
* to all rx clients * to all rx clients
*/ */
struct slave *next_rx_slave;/* next slave to be assigned struct slave *rx_slave;/* last slave to xmit from */
* to a new rx client for
*/
u8 primary_is_promisc; /* boolean */ u8 primary_is_promisc; /* boolean */
u32 rlb_promisc_timeout_counter;/* counts primary u32 rlb_promisc_timeout_counter;/* counts primary
* promiscuity time * promiscuity time
......
This diff is collapsed.
...@@ -10,8 +10,9 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos) ...@@ -10,8 +10,9 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos)
__acquires(&bond->lock) __acquires(&bond->lock)
{ {
struct bonding *bond = seq->private; struct bonding *bond = seq->private;
loff_t off = 0; struct list_head *iter;
struct slave *slave; struct slave *slave;
loff_t off = 0;
/* make sure the bond won't be taken away */ /* make sure the bond won't be taken away */
rcu_read_lock(); rcu_read_lock();
...@@ -20,7 +21,7 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos) ...@@ -20,7 +21,7 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos)
if (*pos == 0) if (*pos == 0)
return SEQ_START_TOKEN; return SEQ_START_TOKEN;
bond_for_each_slave(bond, slave) bond_for_each_slave(bond, slave, iter)
if (++off == *pos) if (++off == *pos)
return slave; return slave;
......
...@@ -168,41 +168,6 @@ static const struct class_attribute class_attr_bonding_masters = { ...@@ -168,41 +168,6 @@ static const struct class_attribute class_attr_bonding_masters = {
.namespace = bonding_namespace, .namespace = bonding_namespace,
}; };
int bond_create_slave_symlinks(struct net_device *master,
struct net_device *slave)
{
char linkname[IFNAMSIZ+7];
int ret = 0;
/* first, create a link from the slave back to the master */
ret = sysfs_create_link(&(slave->dev.kobj), &(master->dev.kobj),
"master");
if (ret)
return ret;
/* next, create a link from the master to the slave */
sprintf(linkname, "slave_%s", slave->name);
ret = sysfs_create_link(&(master->dev.kobj), &(slave->dev.kobj),
linkname);
/* free the master link created earlier in case of error */
if (ret)
sysfs_remove_link(&(slave->dev.kobj), "master");
return ret;
}
void bond_destroy_slave_symlinks(struct net_device *master,
struct net_device *slave)
{
char linkname[IFNAMSIZ+7];
sysfs_remove_link(&(slave->dev.kobj), "master");
sprintf(linkname, "slave_%s", slave->name);
sysfs_remove_link(&(master->dev.kobj), linkname);
}
/* /*
* Show the slaves in the current bond. * Show the slaves in the current bond.
*/ */
...@@ -210,11 +175,12 @@ static ssize_t bonding_show_slaves(struct device *d, ...@@ -210,11 +175,12 @@ static ssize_t bonding_show_slaves(struct device *d,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
struct list_head *iter;
struct slave *slave; struct slave *slave;
int res = 0; int res = 0;
read_lock(&bond->lock); read_lock(&bond->lock);
bond_for_each_slave(bond, slave) { bond_for_each_slave(bond, slave, iter) {
if (res > (PAGE_SIZE - IFNAMSIZ)) { if (res > (PAGE_SIZE - IFNAMSIZ)) {
/* not enough space for another interface name */ /* not enough space for another interface name */
if ((PAGE_SIZE - res) > 10) if ((PAGE_SIZE - res) > 10)
...@@ -326,7 +292,7 @@ static ssize_t bonding_store_mode(struct device *d, ...@@ -326,7 +292,7 @@ static ssize_t bonding_store_mode(struct device *d,
goto out; goto out;
} }
if (!list_empty(&bond->slave_list)) { if (bond_has_slaves(bond)) {
pr_err("unable to update mode of %s because it has slaves.\n", pr_err("unable to update mode of %s because it has slaves.\n",
bond->dev->name); bond->dev->name);
ret = -EPERM; ret = -EPERM;
...@@ -522,7 +488,7 @@ static ssize_t bonding_store_fail_over_mac(struct device *d, ...@@ -522,7 +488,7 @@ static ssize_t bonding_store_fail_over_mac(struct device *d,
if (!rtnl_trylock()) if (!rtnl_trylock())
return restart_syscall(); return restart_syscall();
if (!list_empty(&bond->slave_list)) { if (bond_has_slaves(bond)) {
pr_err("%s: Can't alter fail_over_mac with slaves in bond.\n", pr_err("%s: Can't alter fail_over_mac with slaves in bond.\n",
bond->dev->name); bond->dev->name);
ret = -EPERM; ret = -EPERM;
...@@ -656,6 +622,7 @@ static ssize_t bonding_store_arp_targets(struct device *d, ...@@ -656,6 +622,7 @@ static ssize_t bonding_store_arp_targets(struct device *d,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
struct list_head *iter;
struct slave *slave; struct slave *slave;
__be32 newtarget, *targets; __be32 newtarget, *targets;
unsigned long *targets_rx; unsigned long *targets_rx;
...@@ -688,7 +655,7 @@ static ssize_t bonding_store_arp_targets(struct device *d, ...@@ -688,7 +655,7 @@ static ssize_t bonding_store_arp_targets(struct device *d,
&newtarget); &newtarget);
/* not to race with bond_arp_rcv */ /* not to race with bond_arp_rcv */
write_lock_bh(&bond->lock); write_lock_bh(&bond->lock);
bond_for_each_slave(bond, slave) bond_for_each_slave(bond, slave, iter)
slave->target_last_arp_rx[ind] = jiffies; slave->target_last_arp_rx[ind] = jiffies;
targets[ind] = newtarget; targets[ind] = newtarget;
write_unlock_bh(&bond->lock); write_unlock_bh(&bond->lock);
...@@ -714,7 +681,7 @@ static ssize_t bonding_store_arp_targets(struct device *d, ...@@ -714,7 +681,7 @@ static ssize_t bonding_store_arp_targets(struct device *d,
&newtarget); &newtarget);
write_lock_bh(&bond->lock); write_lock_bh(&bond->lock);
bond_for_each_slave(bond, slave) { bond_for_each_slave(bond, slave, iter) {
targets_rx = slave->target_last_arp_rx; targets_rx = slave->target_last_arp_rx;
j = ind; j = ind;
for (; (j < BOND_MAX_ARP_TARGETS-1) && targets[j+1]; j++) for (; (j < BOND_MAX_ARP_TARGETS-1) && targets[j+1]; j++)
...@@ -1111,6 +1078,7 @@ static ssize_t bonding_store_primary(struct device *d, ...@@ -1111,6 +1078,7 @@ static ssize_t bonding_store_primary(struct device *d,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
struct list_head *iter;
char ifname[IFNAMSIZ]; char ifname[IFNAMSIZ];
struct slave *slave; struct slave *slave;
...@@ -1138,7 +1106,7 @@ static ssize_t bonding_store_primary(struct device *d, ...@@ -1138,7 +1106,7 @@ static ssize_t bonding_store_primary(struct device *d,
goto out; goto out;
} }
bond_for_each_slave(bond, slave) { bond_for_each_slave(bond, slave, iter) {
if (strncmp(slave->dev->name, ifname, IFNAMSIZ) == 0) { if (strncmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {
pr_info("%s: Setting %s as primary slave.\n", pr_info("%s: Setting %s as primary slave.\n",
bond->dev->name, slave->dev->name); bond->dev->name, slave->dev->name);
...@@ -1286,6 +1254,7 @@ static ssize_t bonding_store_active_slave(struct device *d, ...@@ -1286,6 +1254,7 @@ static ssize_t bonding_store_active_slave(struct device *d,
{ {
struct slave *slave, *old_active, *new_active; struct slave *slave, *old_active, *new_active;
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
struct list_head *iter;
char ifname[IFNAMSIZ]; char ifname[IFNAMSIZ];
if (!rtnl_trylock()) if (!rtnl_trylock())
...@@ -1313,7 +1282,7 @@ static ssize_t bonding_store_active_slave(struct device *d, ...@@ -1313,7 +1282,7 @@ static ssize_t bonding_store_active_slave(struct device *d,
goto out; goto out;
} }
bond_for_each_slave(bond, slave) { bond_for_each_slave(bond, slave, iter) {
if (strncmp(slave->dev->name, ifname, IFNAMSIZ) == 0) { if (strncmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {
old_active = bond->curr_active_slave; old_active = bond->curr_active_slave;
new_active = slave; new_active = slave;
...@@ -1493,6 +1462,7 @@ static ssize_t bonding_show_queue_id(struct device *d, ...@@ -1493,6 +1462,7 @@ static ssize_t bonding_show_queue_id(struct device *d,
char *buf) char *buf)
{ {
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
struct list_head *iter;
struct slave *slave; struct slave *slave;
int res = 0; int res = 0;
...@@ -1500,7 +1470,7 @@ static ssize_t bonding_show_queue_id(struct device *d, ...@@ -1500,7 +1470,7 @@ static ssize_t bonding_show_queue_id(struct device *d,
return restart_syscall(); return restart_syscall();
read_lock(&bond->lock); read_lock(&bond->lock);
bond_for_each_slave(bond, slave) { bond_for_each_slave(bond, slave, iter) {
if (res > (PAGE_SIZE - IFNAMSIZ - 6)) { if (res > (PAGE_SIZE - IFNAMSIZ - 6)) {
/* not enough space for another interface_name:queue_id pair */ /* not enough space for another interface_name:queue_id pair */
if ((PAGE_SIZE - res) > 10) if ((PAGE_SIZE - res) > 10)
...@@ -1529,6 +1499,7 @@ static ssize_t bonding_store_queue_id(struct device *d, ...@@ -1529,6 +1499,7 @@ static ssize_t bonding_store_queue_id(struct device *d,
{ {
struct slave *slave, *update_slave; struct slave *slave, *update_slave;
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
struct list_head *iter;
u16 qid; u16 qid;
int ret = count; int ret = count;
char *delim; char *delim;
...@@ -1565,7 +1536,7 @@ static ssize_t bonding_store_queue_id(struct device *d, ...@@ -1565,7 +1536,7 @@ static ssize_t bonding_store_queue_id(struct device *d,
/* Search for thes slave and check for duplicate qids */ /* Search for thes slave and check for duplicate qids */
update_slave = NULL; update_slave = NULL;
bond_for_each_slave(bond, slave) { bond_for_each_slave(bond, slave, iter) {
if (sdev == slave->dev) if (sdev == slave->dev)
/* /*
* We don't need to check the matching * We don't need to check the matching
...@@ -1619,6 +1590,7 @@ static ssize_t bonding_store_slaves_active(struct device *d, ...@@ -1619,6 +1590,7 @@ static ssize_t bonding_store_slaves_active(struct device *d,
{ {
struct bonding *bond = to_bond(d); struct bonding *bond = to_bond(d);
int new_value, ret = count; int new_value, ret = count;
struct list_head *iter;
struct slave *slave; struct slave *slave;
if (sscanf(buf, "%d", &new_value) != 1) { if (sscanf(buf, "%d", &new_value) != 1) {
...@@ -1641,7 +1613,7 @@ static ssize_t bonding_store_slaves_active(struct device *d, ...@@ -1641,7 +1613,7 @@ static ssize_t bonding_store_slaves_active(struct device *d,
} }
read_lock(&bond->lock); read_lock(&bond->lock);
bond_for_each_slave(bond, slave) { bond_for_each_slave(bond, slave, iter) {
if (!bond_is_active_slave(slave)) { if (!bond_is_active_slave(slave)) {
if (new_value) if (new_value)
slave->inactive = 0; slave->inactive = 0;
......
...@@ -72,63 +72,40 @@ ...@@ -72,63 +72,40 @@
res; }) res; })
/* slave list primitives */ /* slave list primitives */
#define bond_to_slave(ptr) list_entry(ptr, struct slave, list) #define bond_slave_list(bond) (&(bond)->dev->adj_list.lower)
#define bond_has_slaves(bond) !list_empty(bond_slave_list(bond))
/* IMPORTANT: bond_first/last_slave can return NULL in case of an empty list */ /* IMPORTANT: bond_first/last_slave can return NULL in case of an empty list */
#define bond_first_slave(bond) \ #define bond_first_slave(bond) \
list_first_entry_or_null(&(bond)->slave_list, struct slave, list) (bond_has_slaves(bond) ? \
netdev_adjacent_get_private(bond_slave_list(bond)->next) : \
NULL)
#define bond_last_slave(bond) \ #define bond_last_slave(bond) \
(list_empty(&(bond)->slave_list) ? NULL : \ (bond_has_slaves(bond) ? \
bond_to_slave((bond)->slave_list.prev)) netdev_adjacent_get_private(bond_slave_list(bond)->prev) : \
NULL)
#define bond_is_first_slave(bond, pos) ((pos)->list.prev == &(bond)->slave_list) #define bond_is_first_slave(bond, pos) (pos == bond_first_slave(bond))
#define bond_is_last_slave(bond, pos) ((pos)->list.next == &(bond)->slave_list) #define bond_is_last_slave(bond, pos) (pos == bond_last_slave(bond))
/* Since bond_first/last_slave can return NULL, these can return NULL too */ /* Since bond_first/last_slave can return NULL, these can return NULL too */
#define bond_next_slave(bond, pos) \ #define bond_next_slave(bond, pos) __bond_next_slave(bond, pos)
(bond_is_last_slave(bond, pos) ? bond_first_slave(bond) : \
bond_to_slave((pos)->list.next))
#define bond_prev_slave(bond, pos) \
(bond_is_first_slave(bond, pos) ? bond_last_slave(bond) : \
bond_to_slave((pos)->list.prev))
/**
* bond_for_each_slave_from - iterate the slaves list from a starting point
* @bond: the bond holding this list.
* @pos: current slave.
* @cnt: counter for max number of moves
* @start: starting point.
*
* Caller must hold bond->lock
*/
#define bond_for_each_slave_from(bond, pos, cnt, start) \
for (cnt = 0, pos = start; pos && cnt < (bond)->slave_cnt; \
cnt++, pos = bond_next_slave(bond, pos))
/** /**
* bond_for_each_slave - iterate over all slaves * bond_for_each_slave - iterate over all slaves
* @bond: the bond holding this list * @bond: the bond holding this list
* @pos: current slave * @pos: current slave
* @iter: list_head * iterator
* *
* Caller must hold bond->lock * Caller must hold bond->lock
*/ */
#define bond_for_each_slave(bond, pos) \ #define bond_for_each_slave(bond, pos, iter) \
list_for_each_entry(pos, &(bond)->slave_list, list) netdev_for_each_lower_private((bond)->dev, pos, iter)
/* Caller must have rcu_read_lock */ /* Caller must have rcu_read_lock */
#define bond_for_each_slave_rcu(bond, pos) \ #define bond_for_each_slave_rcu(bond, pos, iter) \
list_for_each_entry_rcu(pos, &(bond)->slave_list, list) netdev_for_each_lower_private_rcu((bond)->dev, pos, iter)
/**
* bond_for_each_slave_reverse - iterate in reverse from a given position
* @bond: the bond holding this list
* @pos: slave to continue from
*
* Caller must hold bond->lock
*/
#define bond_for_each_slave_continue_reverse(bond, pos) \
list_for_each_entry_continue_reverse(pos, &(bond)->slave_list, list)
#ifdef CONFIG_NET_POLL_CONTROLLER #ifdef CONFIG_NET_POLL_CONTROLLER
extern atomic_t netpoll_block_tx; extern atomic_t netpoll_block_tx;
...@@ -188,7 +165,6 @@ struct bond_parm_tbl { ...@@ -188,7 +165,6 @@ struct bond_parm_tbl {
struct slave { struct slave {
struct net_device *dev; /* first - useful for panic debug */ struct net_device *dev; /* first - useful for panic debug */
struct list_head list;
struct bonding *bond; /* our master */ struct bonding *bond; /* our master */
int delay; int delay;
unsigned long jiffies; unsigned long jiffies;
...@@ -228,7 +204,6 @@ struct slave { ...@@ -228,7 +204,6 @@ struct slave {
*/ */
struct bonding { struct bonding {
struct net_device *dev; /* first - useful for panic debug */ struct net_device *dev; /* first - useful for panic debug */
struct list_head slave_list;
struct slave *curr_active_slave; struct slave *curr_active_slave;
struct slave *current_arp_slave; struct slave *current_arp_slave;
struct slave *primary_slave; struct slave *primary_slave;
...@@ -268,6 +243,34 @@ struct bonding { ...@@ -268,6 +243,34 @@ struct bonding {
#define bond_slave_get_rtnl(dev) \ #define bond_slave_get_rtnl(dev) \
((struct slave *) rtnl_dereference(dev->rx_handler_data)) ((struct slave *) rtnl_dereference(dev->rx_handler_data))
/**
* __bond_next_slave - get the next slave after the one provided
* @bond - bonding struct
* @slave - the slave provided
*
* Returns the next slave after the slave provided, first slave if the
* slave provided is the last slave and NULL if slave is not found
*/
static inline struct slave *__bond_next_slave(struct bonding *bond,
struct slave *slave)
{
struct slave *slave_iter;
struct list_head *iter;
bool found = false;
netdev_for_each_lower_private(bond->dev, slave_iter, iter) {
if (found)
return slave_iter;
if (slave_iter == slave)
found = true;
}
if (found)
return bond_first_slave(bond);
return NULL;
}
/** /**
* Returns NULL if the net_device does not belong to any of the bond's slaves * Returns NULL if the net_device does not belong to any of the bond's slaves
* *
...@@ -276,13 +279,7 @@ struct bonding { ...@@ -276,13 +279,7 @@ struct bonding {
static inline struct slave *bond_get_slave_by_dev(struct bonding *bond, static inline struct slave *bond_get_slave_by_dev(struct bonding *bond,
struct net_device *slave_dev) struct net_device *slave_dev)
{ {
struct slave *slave = NULL; return netdev_lower_dev_get_private(bond->dev, slave_dev);
bond_for_each_slave(bond, slave)
if (slave->dev == slave_dev)
return slave;
return NULL;
} }
static inline struct bonding *bond_get_bond_by_slave(struct slave *slave) static inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
...@@ -439,8 +436,6 @@ int bond_create(struct net *net, const char *name); ...@@ -439,8 +436,6 @@ int bond_create(struct net *net, const char *name);
int bond_create_sysfs(struct bond_net *net); int bond_create_sysfs(struct bond_net *net);
void bond_destroy_sysfs(struct bond_net *net); void bond_destroy_sysfs(struct bond_net *net);
void bond_prepare_sysfs_group(struct bonding *bond); void bond_prepare_sysfs_group(struct bonding *bond);
int bond_create_slave_symlinks(struct net_device *master, struct net_device *slave);
void bond_destroy_slave_symlinks(struct net_device *master, struct net_device *slave);
int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev); int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev);
int bond_release(struct net_device *bond_dev, struct net_device *slave_dev); int bond_release(struct net_device *bond_dev, struct net_device *slave_dev);
void bond_mii_monitor(struct work_struct *); void bond_mii_monitor(struct work_struct *);
...@@ -492,9 +487,10 @@ static inline void bond_destroy_proc_dir(struct bond_net *bn) ...@@ -492,9 +487,10 @@ static inline void bond_destroy_proc_dir(struct bond_net *bn)
static inline struct slave *bond_slave_has_mac(struct bonding *bond, static inline struct slave *bond_slave_has_mac(struct bonding *bond,
const u8 *mac) const u8 *mac)
{ {
struct list_head *iter;
struct slave *tmp; struct slave *tmp;
bond_for_each_slave(bond, tmp) bond_for_each_slave(bond, tmp, iter)
if (ether_addr_equal_64bits(mac, tmp->dev->dev_addr)) if (ether_addr_equal_64bits(mac, tmp->dev->dev_addr))
return tmp; return tmp;
......
...@@ -3983,6 +3983,7 @@ static int cxgb4_inet6addr_handler(struct notifier_block *this, ...@@ -3983,6 +3983,7 @@ static int cxgb4_inet6addr_handler(struct notifier_block *this,
struct net_device *event_dev; struct net_device *event_dev;
int ret = NOTIFY_DONE; int ret = NOTIFY_DONE;
struct bonding *bond = netdev_priv(ifa->idev->dev); struct bonding *bond = netdev_priv(ifa->idev->dev);
struct list_head *iter;
struct slave *slave; struct slave *slave;
struct pci_dev *first_pdev = NULL; struct pci_dev *first_pdev = NULL;
...@@ -3995,7 +3996,7 @@ static int cxgb4_inet6addr_handler(struct notifier_block *this, ...@@ -3995,7 +3996,7 @@ static int cxgb4_inet6addr_handler(struct notifier_block *this,
* in all of them only once. * in all of them only once.
*/ */
read_lock(&bond->lock); read_lock(&bond->lock);
bond_for_each_slave(bond, slave) { bond_for_each_slave(bond, slave, iter) {
if (!first_pdev) { if (!first_pdev) {
ret = clip_add(slave->dev, ifa, event); ret = clip_add(slave->dev, ifa, event);
/* If clip_add is success then only initialize /* If clip_add is success then only initialize
......
...@@ -1143,8 +1143,18 @@ struct net_device { ...@@ -1143,8 +1143,18 @@ struct net_device {
struct list_head dev_list; struct list_head dev_list;
struct list_head napi_list; struct list_head napi_list;
struct list_head unreg_list; struct list_head unreg_list;
struct list_head upper_dev_list; /* List of upper devices */
struct list_head lower_dev_list; /* directly linked devices, like slaves for bonding */
struct {
struct list_head upper;
struct list_head lower;
} adj_list;
/* all linked devices, *including* neighbours */
struct {
struct list_head upper;
struct list_head lower;
} all_adj_list;
/* currently active device features */ /* currently active device features */
...@@ -2813,24 +2823,49 @@ extern int bpf_jit_enable; ...@@ -2813,24 +2823,49 @@ extern int bpf_jit_enable;
extern bool netdev_has_upper_dev(struct net_device *dev, extern bool netdev_has_upper_dev(struct net_device *dev,
struct net_device *upper_dev); struct net_device *upper_dev);
extern bool netdev_has_any_upper_dev(struct net_device *dev); extern bool netdev_has_any_upper_dev(struct net_device *dev);
extern struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev, extern struct net_device *netdev_all_upper_get_next_dev_rcu(struct net_device *dev,
struct list_head **iter); struct list_head **iter);
/* iterate through upper list, must be called under RCU read lock */ /* iterate through upper list, must be called under RCU read lock */
#define netdev_for_each_upper_dev_rcu(dev, upper, iter) \ #define netdev_for_each_all_upper_dev_rcu(dev, updev, iter) \
for (iter = &(dev)->upper_dev_list, \ for (iter = &(dev)->all_adj_list.upper, \
upper = netdev_upper_get_next_dev_rcu(dev, &(iter)); \ updev = netdev_all_upper_get_next_dev_rcu(dev, &(iter)); \
upper; \ updev; \
upper = netdev_upper_get_next_dev_rcu(dev, &(iter))) updev = netdev_all_upper_get_next_dev_rcu(dev, &(iter)))
extern void *netdev_lower_get_next_private(struct net_device *dev,
struct list_head **iter);
extern void *netdev_lower_get_next_private_rcu(struct net_device *dev,
struct list_head **iter);
#define netdev_for_each_lower_private(dev, priv, iter) \
for (iter = (dev)->adj_list.lower.next, \
priv = netdev_lower_get_next_private(dev, &(iter)); \
priv; \
priv = netdev_lower_get_next_private(dev, &(iter)))
#define netdev_for_each_lower_private_rcu(dev, priv, iter) \
for (iter = &(dev)->adj_list.lower, \
priv = netdev_lower_get_next_private_rcu(dev, &(iter)); \
priv; \
priv = netdev_lower_get_next_private_rcu(dev, &(iter)))
extern void *netdev_adjacent_get_private(struct list_head *adj_list);
extern struct net_device *netdev_master_upper_dev_get(struct net_device *dev); extern struct net_device *netdev_master_upper_dev_get(struct net_device *dev);
extern struct net_device *netdev_master_upper_dev_get_rcu(struct net_device *dev); extern struct net_device *netdev_master_upper_dev_get_rcu(struct net_device *dev);
extern int netdev_upper_dev_link(struct net_device *dev, extern int netdev_upper_dev_link(struct net_device *dev,
struct net_device *upper_dev); struct net_device *upper_dev);
extern int netdev_master_upper_dev_link(struct net_device *dev, extern int netdev_master_upper_dev_link(struct net_device *dev,
struct net_device *upper_dev); struct net_device *upper_dev);
extern int netdev_master_upper_dev_link_private(struct net_device *dev,
struct net_device *upper_dev,
void *private);
extern void netdev_upper_dev_unlink(struct net_device *dev, extern void netdev_upper_dev_unlink(struct net_device *dev,
struct net_device *upper_dev); struct net_device *upper_dev);
extern void *netdev_lower_dev_get_private_rcu(struct net_device *dev,
struct net_device *lower_dev);
extern void *netdev_lower_dev_get_private(struct net_device *dev,
struct net_device *lower_dev);
extern int skb_checksum_help(struct sk_buff *skb); extern int skb_checksum_help(struct sk_buff *skb);
extern struct sk_buff *__skb_gso_segment(struct sk_buff *skb, extern struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
netdev_features_t features, bool tx_path); netdev_features_t features, bool tx_path);
......
...@@ -98,14 +98,14 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) ...@@ -98,14 +98,14 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
vlan_gvrp_request_leave(dev); vlan_gvrp_request_leave(dev);
vlan_group_set_device(grp, vlan->vlan_proto, vlan_id, NULL); vlan_group_set_device(grp, vlan->vlan_proto, vlan_id, NULL);
netdev_upper_dev_unlink(real_dev, dev);
/* Because unregister_netdevice_queue() makes sure at least one rcu /* Because unregister_netdevice_queue() makes sure at least one rcu
* grace period is respected before device freeing, * grace period is respected before device freeing,
* we dont need to call synchronize_net() here. * we dont need to call synchronize_net() here.
*/ */
unregister_netdevice_queue(dev, head); unregister_netdevice_queue(dev, head);
netdev_upper_dev_unlink(real_dev, dev);
if (grp->nr_vlan_devs == 0) { if (grp->nr_vlan_devs == 0) {
vlan_mvrp_uninit_applicant(real_dev); vlan_mvrp_uninit_applicant(real_dev);
vlan_gvrp_uninit_applicant(real_dev); vlan_gvrp_uninit_applicant(real_dev);
...@@ -169,13 +169,13 @@ int register_vlan_dev(struct net_device *dev) ...@@ -169,13 +169,13 @@ int register_vlan_dev(struct net_device *dev)
if (err < 0) if (err < 0)
goto out_uninit_mvrp; goto out_uninit_mvrp;
err = netdev_upper_dev_link(real_dev, dev);
if (err)
goto out_uninit_mvrp;
err = register_netdevice(dev); err = register_netdevice(dev);
if (err < 0) if (err < 0)
goto out_upper_dev_unlink; goto out_uninit_mvrp;
err = netdev_upper_dev_link(real_dev, dev);
if (err)
goto out_unregister_netdev;
/* Account for reference in struct vlan_dev_priv */ /* Account for reference in struct vlan_dev_priv */
dev_hold(real_dev); dev_hold(real_dev);
...@@ -191,8 +191,8 @@ int register_vlan_dev(struct net_device *dev) ...@@ -191,8 +191,8 @@ int register_vlan_dev(struct net_device *dev)
return 0; return 0;
out_upper_dev_unlink: out_unregister_netdev:
netdev_upper_dev_unlink(real_dev, dev); unregister_netdevice(dev);
out_uninit_mvrp: out_uninit_mvrp:
if (grp->nr_vlan_devs == 0) if (grp->nr_vlan_devs == 0)
vlan_mvrp_uninit_applicant(real_dev); vlan_mvrp_uninit_applicant(real_dev);
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment