From 551586292b39da6e4fbfbb5b96b57b68decfdab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20L=C3=BCssing?= Date: Mon, 14 Mar 2011 22:43:27 +0000 Subject: batman-adv: Move bonding / iface alternating router search to own functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This decreases the size of find_router() by outsourcing the router search for the bonding and interface alternating modes to their own sub functions. This shall make it easier to keep track of the correct refcounting later. Signed-off-by: Linus Lüssing Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann --- net/batman-adv/routing.c | 180 +++++++++++++++++++++++++++-------------------- 1 file changed, 105 insertions(+), 75 deletions(-) (limited to 'net/batman-adv') diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index c172f5d0e05a..f212abe745bc 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -1092,6 +1092,106 @@ out: return ret; } +/* In the bonding case, send the packets in a round + * robin fashion over the remaining interfaces. + * + * This method rotates the bonding list and increases the + * returned router's refcount. */ +static struct neigh_node *find_bond_router(struct orig_node *primary_orig, + struct hard_iface *recv_if) +{ + struct neigh_node *tmp_neigh_node; + struct neigh_node *router = NULL, *first_candidate = NULL; + + rcu_read_lock(); + list_for_each_entry_rcu(tmp_neigh_node, &primary_orig->bond_list, + bonding_list) { + if (!first_candidate) + first_candidate = tmp_neigh_node; + + /* recv_if == NULL on the first node. */ + if (tmp_neigh_node->if_incoming == recv_if) + continue; + + if (!atomic_inc_not_zero(&tmp_neigh_node->refcount)) + continue; + + router = tmp_neigh_node; + break; + } + + /* use the first candidate if nothing was found. */ + if (!router && first_candidate && + atomic_inc_not_zero(&first_candidate->refcount)) + router = first_candidate; + + if (!router) + goto out; + + /* selected should point to the next element + * after the current router */ + spin_lock_bh(&primary_orig->neigh_list_lock); + /* this is a list_move(), which unfortunately + * does not exist as rcu version */ + list_del_rcu(&primary_orig->bond_list); + list_add_rcu(&primary_orig->bond_list, + &router->bonding_list); + spin_unlock_bh(&primary_orig->neigh_list_lock); + +out: + rcu_read_unlock(); + return router; +} + +/* Interface Alternating: Use the best of the + * remaining candidates which are not using + * this interface. + * + * Increases the returned router's refcount */ +static struct neigh_node *find_ifalter_router(struct orig_node *primary_orig, + struct hard_iface *recv_if) +{ + struct neigh_node *tmp_neigh_node; + struct neigh_node *router = NULL, *first_candidate = NULL; + + rcu_read_lock(); + list_for_each_entry_rcu(tmp_neigh_node, &primary_orig->bond_list, + bonding_list) { + if (!first_candidate) + first_candidate = tmp_neigh_node; + + /* recv_if == NULL on the first node. */ + if (tmp_neigh_node->if_incoming == recv_if) + continue; + + if (!atomic_inc_not_zero(&tmp_neigh_node->refcount)) + continue; + + /* if we don't have a router yet + * or this one is better, choose it. */ + if ((!router) || + (tmp_neigh_node->tq_avg > router->tq_avg)) { + /* decrement refcount of + * previously selected router */ + if (router) + neigh_node_free_ref(router); + + router = tmp_neigh_node; + atomic_inc_not_zero(&router->refcount); + } + + neigh_node_free_ref(tmp_neigh_node); + } + + /* use the first candidate if nothing was found. */ + if (!router && first_candidate && + atomic_inc_not_zero(&first_candidate->refcount)) + router = first_candidate; + + rcu_read_unlock(); + return router; +} + /* find a suitable router for this originator, and use * bonding if possible. increases the found neighbors * refcount.*/ @@ -1101,7 +1201,7 @@ struct neigh_node *find_router(struct bat_priv *bat_priv, { struct orig_node *primary_orig_node; struct orig_node *router_orig; - struct neigh_node *router, *first_candidate, *tmp_neigh_node; + struct neigh_node *router; static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; int bonding_enabled; @@ -1157,82 +1257,12 @@ struct neigh_node *find_router(struct bat_priv *bat_priv, * in. */ neigh_node_free_ref(router); - first_candidate = NULL; - router = NULL; - - if (bonding_enabled) { - /* in the bonding case, send the packets in a round - * robin fashion over the remaining interfaces. */ - - list_for_each_entry_rcu(tmp_neigh_node, - &primary_orig_node->bond_list, bonding_list) { - if (!first_candidate) - first_candidate = tmp_neigh_node; - /* recv_if == NULL on the first node. */ - if (tmp_neigh_node->if_incoming != recv_if && - atomic_inc_not_zero(&tmp_neigh_node->refcount)) { - router = tmp_neigh_node; - break; - } - } - - /* use the first candidate if nothing was found. */ - if (!router && first_candidate && - atomic_inc_not_zero(&first_candidate->refcount)) - router = first_candidate; - if (!router) { - rcu_read_unlock(); - return NULL; - } - - /* selected should point to the next element - * after the current router */ - spin_lock_bh(&primary_orig_node->neigh_list_lock); - /* this is a list_move(), which unfortunately - * does not exist as rcu version */ - list_del_rcu(&primary_orig_node->bond_list); - list_add_rcu(&primary_orig_node->bond_list, - &router->bonding_list); - spin_unlock_bh(&primary_orig_node->neigh_list_lock); - - } else { - /* if bonding is disabled, use the best of the - * remaining candidates which are not using - * this interface. */ - list_for_each_entry_rcu(tmp_neigh_node, - &primary_orig_node->bond_list, bonding_list) { - if (!first_candidate) - first_candidate = tmp_neigh_node; - - /* recv_if == NULL on the first node. */ - if (tmp_neigh_node->if_incoming == recv_if) - continue; - - if (!atomic_inc_not_zero(&tmp_neigh_node->refcount)) - continue; - - /* if we don't have a router yet - * or this one is better, choose it. */ - if ((!router) || - (tmp_neigh_node->tq_avg > router->tq_avg)) { - /* decrement refcount of - * previously selected router */ - if (router) - neigh_node_free_ref(router); - - router = tmp_neigh_node; - atomic_inc_not_zero(&router->refcount); - } - - neigh_node_free_ref(tmp_neigh_node); - } + if (bonding_enabled) + router = find_bond_router(primary_orig_node, recv_if); + else + router = find_ifalter_router(primary_orig_node, recv_if); - /* use the first candidate if nothing was found. */ - if (!router && first_candidate && - atomic_inc_not_zero(&first_candidate->refcount)) - router = first_candidate; - } return_router: rcu_read_unlock(); return router; -- cgit v1.2.3 From 4c804850572f70a2350e4d1e79d6659392b07733 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20L=C3=BCssing?= Date: Mon, 14 Mar 2011 22:43:30 +0000 Subject: batman-adv: Make gateway_get_selected type safe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the return value explicit instead of (void *). Signed-off-by: Linus Lüssing Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann --- net/batman-adv/gateway_client.c | 2 +- net/batman-adv/gateway_client.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'net/batman-adv') diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 3cc43558cf9c..27b87add044b 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -42,7 +42,7 @@ static void gw_node_free_ref(struct gw_node *gw_node) call_rcu(&gw_node->rcu, gw_node_free_rcu); } -void *gw_get_selected(struct bat_priv *bat_priv) +struct orig_node *gw_get_selected(struct bat_priv *bat_priv) { struct gw_node *curr_gateway_tmp; struct orig_node *orig_node = NULL; diff --git a/net/batman-adv/gateway_client.h b/net/batman-adv/gateway_client.h index 2aa439124ee3..97c31d178163 100644 --- a/net/batman-adv/gateway_client.h +++ b/net/batman-adv/gateway_client.h @@ -24,7 +24,7 @@ void gw_deselect(struct bat_priv *bat_priv); void gw_election(struct bat_priv *bat_priv); -void *gw_get_selected(struct bat_priv *bat_priv); +struct orig_node *gw_get_selected(struct bat_priv *bat_priv); void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node); void gw_node_update(struct bat_priv *bat_priv, struct orig_node *orig_node, uint8_t new_gwflags); -- cgit v1.2.3 From 57f0c07c4d0da8bcc23e21c330fe9c7c5cf776b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20L=C3=BCssing?= Date: Mon, 14 Mar 2011 22:43:33 +0000 Subject: batman-adv: Simplify gw_check_election(), use gw_get_selected() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gw_get_selected() can get us the desired orig_node directly, therefore reusing that function in gw_check_election(). Signed-off-by: Linus Lüssing Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann --- net/batman-adv/gateway_client.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'net/batman-adv') diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 27b87add044b..879ac1594869 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -23,6 +23,7 @@ #include "gateway_client.h" #include "gateway_common.h" #include "hard-interface.h" +#include "originator.h" #include #include #include @@ -203,28 +204,25 @@ void gw_election(struct bat_priv *bat_priv) void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node) { - struct gw_node *curr_gateway_tmp; + struct orig_node *curr_gw_orig; uint8_t gw_tq_avg, orig_tq_avg; - rcu_read_lock(); - curr_gateway_tmp = rcu_dereference(bat_priv->curr_gw); - if (!curr_gateway_tmp) - goto out_rcu; + curr_gw_orig = gw_get_selected(bat_priv); + if (!curr_gw_orig) + goto deselect; - if (!curr_gateway_tmp->orig_node) - goto deselect_rcu; - - if (!curr_gateway_tmp->orig_node->router) + rcu_read_lock(); + if (!curr_gw_orig->router) goto deselect_rcu; /* this node already is the gateway */ - if (curr_gateway_tmp->orig_node == orig_node) + if (curr_gw_orig == orig_node) goto out_rcu; if (!orig_node->router) goto out_rcu; - gw_tq_avg = curr_gateway_tmp->orig_node->router->tq_avg; + gw_tq_avg = curr_gw_orig->router->tq_avg; rcu_read_unlock(); orig_tq_avg = orig_node->router->tq_avg; @@ -255,6 +253,9 @@ deselect_rcu: deselect: gw_deselect(bat_priv); out: + if (curr_gw_orig) + orig_node_free_ref(curr_gw_orig); + return; } -- cgit v1.2.3 From e1a5382f978b67b5cc36eec65e6046730ce07714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20L=C3=BCssing?= Date: Mon, 14 Mar 2011 22:43:37 +0000 Subject: batman-adv: Make orig_node->router an rcu protected pointer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rcu protected macros rcu_dereference() and rcu_assign_pointer() for the orig_node->router need to be used, as well as spin/rcu locking. Otherwise we might end up using a router pointer pointing to already freed memory. Therefore this commit introduces the safe getter method orig_node_get_router(). Signed-off-by: Linus Lüssing Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann --- net/batman-adv/gateway_client.c | 80 ++++++++++------- net/batman-adv/icmp_socket.c | 18 +--- net/batman-adv/originator.c | 37 ++++++-- net/batman-adv/originator.h | 1 + net/batman-adv/routing.c | 194 +++++++++++++++++++--------------------- net/batman-adv/send.c | 19 ++-- net/batman-adv/types.h | 4 +- net/batman-adv/vis.c | 91 ++++++++++--------- 8 files changed, 232 insertions(+), 212 deletions(-) (limited to 'net/batman-adv') diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 879ac1594869..42a8a7ba06e6 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -98,6 +98,7 @@ void gw_election(struct bat_priv *bat_priv) { struct hlist_node *node; struct gw_node *gw_node, *curr_gw, *curr_gw_tmp = NULL; + struct neigh_node *router; uint8_t max_tq = 0; uint32_t max_gw_factor = 0, tmp_gw_factor = 0; int down, up; @@ -133,10 +134,11 @@ void gw_election(struct bat_priv *bat_priv) } hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { - if (!gw_node->orig_node->router) + if (gw_node->deleted) continue; - if (gw_node->deleted) + router = orig_node_get_router(gw_node->orig_node); + if (!router) continue; switch (atomic_read(&bat_priv->gw_sel_class)) { @@ -144,15 +146,14 @@ void gw_election(struct bat_priv *bat_priv) gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up); - tmp_gw_factor = (gw_node->orig_node->router->tq_avg * - gw_node->orig_node->router->tq_avg * + tmp_gw_factor = (router->tq_avg * router->tq_avg * down * 100 * 100) / (TQ_LOCAL_WINDOW_SIZE * TQ_LOCAL_WINDOW_SIZE * 64); if ((tmp_gw_factor > max_gw_factor) || ((tmp_gw_factor == max_gw_factor) && - (gw_node->orig_node->router->tq_avg > max_tq))) + (router->tq_avg > max_tq))) curr_gw_tmp = gw_node; break; @@ -164,19 +165,25 @@ void gw_election(struct bat_priv *bat_priv) * soon as a better gateway appears which has * $routing_class more tq points) **/ - if (gw_node->orig_node->router->tq_avg > max_tq) + if (router->tq_avg > max_tq) curr_gw_tmp = gw_node; break; } - if (gw_node->orig_node->router->tq_avg > max_tq) - max_tq = gw_node->orig_node->router->tq_avg; + if (router->tq_avg > max_tq) + max_tq = router->tq_avg; if (tmp_gw_factor > max_gw_factor) max_gw_factor = tmp_gw_factor; + + neigh_node_free_ref(router); } if (curr_gw != curr_gw_tmp) { + router = orig_node_get_router(curr_gw_tmp->orig_node); + if (!router) + goto out; + if ((curr_gw) && (!curr_gw_tmp)) bat_dbg(DBG_BATMAN, bat_priv, "Removing selected gateway - " @@ -187,45 +194,47 @@ void gw_election(struct bat_priv *bat_priv) "(gw_flags: %i, tq: %i)\n", curr_gw_tmp->orig_node->orig, curr_gw_tmp->orig_node->gw_flags, - curr_gw_tmp->orig_node->router->tq_avg); + router->tq_avg); else bat_dbg(DBG_BATMAN, bat_priv, "Changing route to gateway %pM " "(gw_flags: %i, tq: %i)\n", curr_gw_tmp->orig_node->orig, curr_gw_tmp->orig_node->gw_flags, - curr_gw_tmp->orig_node->router->tq_avg); + router->tq_avg); + neigh_node_free_ref(router); gw_select(bat_priv, curr_gw_tmp); } +out: rcu_read_unlock(); } void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node) { struct orig_node *curr_gw_orig; + struct neigh_node *router_gw = NULL, *router_orig = NULL; uint8_t gw_tq_avg, orig_tq_avg; curr_gw_orig = gw_get_selected(bat_priv); if (!curr_gw_orig) goto deselect; - rcu_read_lock(); - if (!curr_gw_orig->router) - goto deselect_rcu; + router_gw = orig_node_get_router(curr_gw_orig); + if (!router_gw) + goto deselect; /* this node already is the gateway */ if (curr_gw_orig == orig_node) - goto out_rcu; - - if (!orig_node->router) - goto out_rcu; + goto out; - gw_tq_avg = curr_gw_orig->router->tq_avg; - rcu_read_unlock(); + router_orig = orig_node_get_router(orig_node); + if (!router_orig) + goto out; - orig_tq_avg = orig_node->router->tq_avg; + gw_tq_avg = router_gw->tq_avg; + orig_tq_avg = router_orig->tq_avg; /* the TQ value has to be better */ if (orig_tq_avg < gw_tq_avg) @@ -243,18 +252,16 @@ void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node) "Restarting gateway selection: better gateway found (tq curr: " "%i, tq new: %i)\n", gw_tq_avg, orig_tq_avg); - goto deselect; -out_rcu: - rcu_read_unlock(); - goto out; -deselect_rcu: - rcu_read_unlock(); deselect: gw_deselect(bat_priv); out: if (curr_gw_orig) orig_node_free_ref(curr_gw_orig); + if (router_gw) + neigh_node_free_ref(router_gw); + if (router_orig) + neigh_node_free_ref(router_orig); return; } @@ -362,23 +369,30 @@ void gw_node_purge(struct bat_priv *bat_priv) spin_unlock_bh(&bat_priv->gw_list_lock); } +/** + * fails if orig_node has no router + */ static int _write_buffer_text(struct bat_priv *bat_priv, struct seq_file *seq, struct gw_node *gw_node) { struct gw_node *curr_gw; - int down, up, ret; + struct neigh_node *router; + int down, up, ret = -1; gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up); + router = orig_node_get_router(gw_node->orig_node); + if (!router) + goto out; + rcu_read_lock(); curr_gw = rcu_dereference(bat_priv->curr_gw); ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n", (curr_gw == gw_node ? "=>" : " "), gw_node->orig_node->orig, - gw_node->orig_node->router->tq_avg, - gw_node->orig_node->router->addr, - gw_node->orig_node->router->if_incoming->net_dev->name, + router->tq_avg, router->addr, + router->if_incoming->net_dev->name, gw_node->orig_node->gw_flags, (down > 2048 ? down / 1024 : down), (down > 2048 ? "MBit" : "KBit"), @@ -386,6 +400,8 @@ static int _write_buffer_text(struct bat_priv *bat_priv, (up > 2048 ? "MBit" : "KBit")); rcu_read_unlock(); + neigh_node_free_ref(router); +out: return ret; } @@ -423,10 +439,10 @@ int gw_client_seq_print_text(struct seq_file *seq, void *offset) if (gw_node->deleted) continue; - if (!gw_node->orig_node->router) + /* fails if orig_node has no router */ + if (_write_buffer_text(bat_priv, seq, gw_node) < 0) continue; - _write_buffer_text(bat_priv, seq, gw_node); gw_count++; } rcu_read_unlock(); diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c index 34ce56c358e5..49079c254476 100644 --- a/net/batman-adv/icmp_socket.c +++ b/net/batman-adv/icmp_socket.c @@ -218,23 +218,13 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE) goto dst_unreach; - rcu_read_lock(); orig_node = orig_hash_find(bat_priv, icmp_packet->dst); - if (!orig_node) - goto unlock; - - neigh_node = orig_node->router; + goto dst_unreach; + neigh_node = orig_node_get_router(orig_node); if (!neigh_node) - goto unlock; - - if (!atomic_inc_not_zero(&neigh_node->refcount)) { - neigh_node = NULL; - goto unlock; - } - - rcu_read_unlock(); + goto dst_unreach; if (!neigh_node->if_incoming) goto dst_unreach; @@ -252,8 +242,6 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); goto out; -unlock: - rcu_read_unlock(); dst_unreach: icmp_packet->msg_type = DESTINATION_UNREACHABLE; bat_socket_add_packet(socket_client, icmp_packet, packet_len); diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 0b9133022d2d..b4cfe3686155 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -70,6 +70,21 @@ void neigh_node_free_ref(struct neigh_node *neigh_node) call_rcu(&neigh_node->rcu, neigh_node_free_rcu); } +/* increases the refcounter of a found router */ +struct neigh_node *orig_node_get_router(struct orig_node *orig_node) +{ + struct neigh_node *router; + + rcu_read_lock(); + router = rcu_dereference(orig_node->router); + + if (router && !atomic_inc_not_zero(&router->refcount)) + router = NULL; + + rcu_read_unlock(); + return router; +} + struct neigh_node *create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node, uint8_t *neigh, @@ -390,7 +405,7 @@ int orig_seq_print_text(struct seq_file *seq, void *offset) struct hlist_node *node, *node_tmp; struct hlist_head *head; struct orig_node *orig_node; - struct neigh_node *neigh_node; + struct neigh_node *neigh_node, *neigh_node_tmp; int batman_count = 0; int last_seen_secs; int last_seen_msecs; @@ -421,37 +436,41 @@ int orig_seq_print_text(struct seq_file *seq, void *offset) rcu_read_lock(); hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { - if (!orig_node->router) + neigh_node = orig_node_get_router(orig_node); + if (!neigh_node) continue; - if (orig_node->router->tq_avg == 0) - continue; + if (neigh_node->tq_avg == 0) + goto next; last_seen_secs = jiffies_to_msecs(jiffies - orig_node->last_valid) / 1000; last_seen_msecs = jiffies_to_msecs(jiffies - orig_node->last_valid) % 1000; - neigh_node = orig_node->router; seq_printf(seq, "%pM %4i.%03is (%3i) %pM [%10s]:", orig_node->orig, last_seen_secs, last_seen_msecs, neigh_node->tq_avg, neigh_node->addr, neigh_node->if_incoming->net_dev->name); - hlist_for_each_entry_rcu(neigh_node, node_tmp, + hlist_for_each_entry_rcu(neigh_node_tmp, node_tmp, &orig_node->neigh_list, list) { - seq_printf(seq, " %pM (%3i)", neigh_node->addr, - neigh_node->tq_avg); + seq_printf(seq, " %pM (%3i)", + neigh_node_tmp->addr, + neigh_node_tmp->tq_avg); } seq_printf(seq, "\n"); batman_count++; + +next: + neigh_node_free_ref(neigh_node); } rcu_read_unlock(); } - if ((batman_count == 0)) + if (batman_count == 0) seq_printf(seq, "No batman nodes in range ...\n"); return 0; diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h index 5cc011057da1..e1d641f27aa9 100644 --- a/net/batman-adv/originator.h +++ b/net/batman-adv/originator.h @@ -34,6 +34,7 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node, uint8_t *neigh, struct hard_iface *if_incoming); void neigh_node_free_ref(struct neigh_node *neigh_node); +struct neigh_node *orig_node_get_router(struct orig_node *orig_node); int orig_seq_print_text(struct seq_file *seq, void *offset); int orig_hash_add_if(struct hard_iface *hard_iface, int max_if_num); int orig_hash_del_if(struct hard_iface *hard_iface, int max_if_num); diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index f212abe745bc..b7d43caaa9c8 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -87,18 +87,20 @@ static void update_route(struct bat_priv *bat_priv, struct neigh_node *neigh_node, unsigned char *hna_buff, int hna_buff_len) { - struct neigh_node *neigh_node_tmp; + struct neigh_node *curr_router; + + curr_router = orig_node_get_router(orig_node); /* route deleted */ - if ((orig_node->router) && (!neigh_node)) { + if ((curr_router) && (!neigh_node)) { bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n", orig_node->orig); hna_global_del_orig(bat_priv, orig_node, "originator timed out"); - /* route added */ - } else if ((!orig_node->router) && (neigh_node)) { + /* route added */ + } else if ((!curr_router) && (neigh_node)) { bat_dbg(DBG_ROUTES, bat_priv, "Adding route towards: %pM (via %pM)\n", @@ -106,21 +108,29 @@ static void update_route(struct bat_priv *bat_priv, hna_global_add_orig(bat_priv, orig_node, hna_buff, hna_buff_len); - /* route changed */ + /* route changed */ } else { bat_dbg(DBG_ROUTES, bat_priv, "Changing route towards: %pM " "(now via %pM - was via %pM)\n", orig_node->orig, neigh_node->addr, - orig_node->router->addr); + curr_router->addr); } + if (curr_router) + neigh_node_free_ref(curr_router); + + /* increase refcount of new best neighbor */ if (neigh_node && !atomic_inc_not_zero(&neigh_node->refcount)) neigh_node = NULL; - neigh_node_tmp = orig_node->router; - orig_node->router = neigh_node; - if (neigh_node_tmp) - neigh_node_free_ref(neigh_node_tmp); + + spin_lock_bh(&orig_node->neigh_list_lock); + rcu_assign_pointer(orig_node->router, neigh_node); + spin_unlock_bh(&orig_node->neigh_list_lock); + + /* decrease refcount of previous best neighbor */ + if (curr_router) + neigh_node_free_ref(curr_router); } @@ -128,16 +138,23 @@ void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node, struct neigh_node *neigh_node, unsigned char *hna_buff, int hna_buff_len) { + struct neigh_node *router = NULL; if (!orig_node) - return; + goto out; + + router = orig_node_get_router(orig_node); - if (orig_node->router != neigh_node) + if (router != neigh_node) update_route(bat_priv, orig_node, neigh_node, hna_buff, hna_buff_len); /* may be just HNA changed */ else update_HNA(bat_priv, orig_node, hna_buff, hna_buff_len); + +out: + if (router) + neigh_node_free_ref(router); } static int is_bidirectional_neigh(struct orig_node *orig_node, @@ -288,8 +305,8 @@ static void bonding_candidate_add(struct orig_node *orig_node, struct neigh_node *neigh_node) { struct hlist_node *node; - struct neigh_node *tmp_neigh_node; - uint8_t best_tq, interference_candidate = 0; + struct neigh_node *tmp_neigh_node, *router = NULL; + uint8_t interference_candidate = 0; spin_lock_bh(&orig_node->neigh_list_lock); @@ -298,13 +315,12 @@ static void bonding_candidate_add(struct orig_node *orig_node, neigh_node->orig_node->primary_addr)) goto candidate_del; - if (!orig_node->router) + router = orig_node_get_router(orig_node); + if (!router) goto candidate_del; - best_tq = orig_node->router->tq_avg; - /* ... and is good enough to be considered */ - if (neigh_node->tq_avg < best_tq - BONDING_TQ_THRESHOLD) + if (neigh_node->tq_avg < router->tq_avg - BONDING_TQ_THRESHOLD) goto candidate_del; /** @@ -350,7 +366,9 @@ candidate_del: out: spin_unlock_bh(&orig_node->neigh_list_lock); - return; + + if (router) + neigh_node_free_ref(router); } /* copy primary address for bonding */ @@ -373,6 +391,7 @@ static void update_orig(struct bat_priv *bat_priv, char is_duplicate) { struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; + struct neigh_node *router = NULL; struct orig_node *orig_node_tmp; struct hlist_node *node; int tmp_hna_buff_len; @@ -441,19 +460,18 @@ static void update_orig(struct bat_priv *bat_priv, /* if this neighbor already is our next hop there is nothing * to change */ - if (orig_node->router == neigh_node) + router = orig_node_get_router(orig_node); + if (router == neigh_node) goto update_hna; /* if this neighbor does not offer a better TQ we won't consider it */ - if ((orig_node->router) && - (orig_node->router->tq_avg > neigh_node->tq_avg)) + if (router && (router->tq_avg > neigh_node->tq_avg)) goto update_hna; /* if the TQ is the same and the link not more symetric we * won't consider it either */ - if ((orig_node->router) && - (neigh_node->tq_avg == orig_node->router->tq_avg)) { - orig_node_tmp = orig_node->router->orig_node; + if (router && (neigh_node->tq_avg == router->tq_avg)) { + orig_node_tmp = router->orig_node; spin_lock_bh(&orig_node_tmp->ogm_cnt_lock); bcast_own_sum_orig = orig_node_tmp->bcast_own_sum[if_incoming->if_num]; @@ -474,7 +492,7 @@ static void update_orig(struct bat_priv *bat_priv, goto update_gw; update_hna: - update_routes(bat_priv, orig_node, orig_node->router, + update_routes(bat_priv, orig_node, router, hna_buff, tmp_hna_buff_len); update_gw: @@ -496,6 +514,8 @@ unlock: out: if (neigh_node) neigh_node_free_ref(neigh_node); + if (router) + neigh_node_free_ref(router); } /* checks whether the host restarted and is in the protection time. @@ -603,6 +623,8 @@ void receive_bat_packet(struct ethhdr *ethhdr, struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); struct hard_iface *hard_iface; struct orig_node *orig_neigh_node, *orig_node; + struct neigh_node *router = NULL, *router_router = NULL; + struct neigh_node *orig_neigh_router = NULL; char has_directlink_flag; char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0; char is_broadcast = 0, is_bidirectional, is_single_hop_neigh; @@ -747,14 +769,15 @@ void receive_bat_packet(struct ethhdr *ethhdr, goto out; } + router = orig_node_get_router(orig_node); + if (router) + router_router = orig_node_get_router(router->orig_node); + /* avoid temporary routing loops */ - if ((orig_node->router) && - (orig_node->router->orig_node->router) && - (compare_eth(orig_node->router->addr, - batman_packet->prev_sender)) && + if (router && router_router && + (compare_eth(router->addr, batman_packet->prev_sender)) && !(compare_eth(batman_packet->orig, batman_packet->prev_sender)) && - (compare_eth(orig_node->router->addr, - orig_node->router->orig_node->router->addr))) { + (compare_eth(router->addr, router_router->addr))) { bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: ignoring all rebroadcast packets that " "may make me loop (sender: %pM)\n", ethhdr->h_source); @@ -769,9 +792,11 @@ void receive_bat_packet(struct ethhdr *ethhdr, if (!orig_neigh_node) goto out; + orig_neigh_router = orig_node_get_router(orig_neigh_node); + /* drop packet if sender is not a direct neighbor and if we * don't route towards it */ - if (!is_single_hop_neigh && (!orig_neigh_node->router)) { + if (!is_single_hop_neigh && (!orig_neigh_router)) { bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: OGM via unknown neighbor!\n"); goto out_neigh; @@ -825,6 +850,13 @@ out_neigh: if ((orig_neigh_node) && (!is_single_hop_neigh)) orig_node_free_ref(orig_neigh_node); out: + if (router) + neigh_node_free_ref(router); + if (router_router) + neigh_node_free_ref(router_router); + if (orig_neigh_router) + neigh_node_free_ref(orig_neigh_router); + orig_node_free_ref(orig_node); } @@ -869,7 +901,7 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, struct sk_buff *skb, size_t icmp_len) { struct orig_node *orig_node = NULL; - struct neigh_node *neigh_node = NULL; + struct neigh_node *router = NULL; struct icmp_packet_rr *icmp_packet; int ret = NET_RX_DROP; @@ -886,23 +918,13 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, /* answer echo request (ping) */ /* get routing information */ - rcu_read_lock(); orig_node = orig_hash_find(bat_priv, icmp_packet->orig); - if (!orig_node) - goto unlock; - - neigh_node = orig_node->router; - - if (!neigh_node) - goto unlock; - - if (!atomic_inc_not_zero(&neigh_node->refcount)) { - neigh_node = NULL; - goto unlock; - } + goto out; - rcu_read_unlock(); + router = orig_node_get_router(orig_node); + if (!router) + goto out; /* create a copy of the skb, if needed, to modify it. */ if (skb_cow(skb, sizeof(struct ethhdr)) < 0) @@ -916,15 +938,12 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, icmp_packet->msg_type = ECHO_REPLY; icmp_packet->ttl = TTL; - send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); + send_skb_packet(skb, router->if_incoming, router->addr); ret = NET_RX_SUCCESS; - goto out; -unlock: - rcu_read_unlock(); out: - if (neigh_node) - neigh_node_free_ref(neigh_node); + if (router) + neigh_node_free_ref(router); if (orig_node) orig_node_free_ref(orig_node); return ret; @@ -934,7 +953,7 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, struct sk_buff *skb) { struct orig_node *orig_node = NULL; - struct neigh_node *neigh_node = NULL; + struct neigh_node *router = NULL; struct icmp_packet *icmp_packet; int ret = NET_RX_DROP; @@ -952,23 +971,13 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, goto out; /* get routing information */ - rcu_read_lock(); orig_node = orig_hash_find(bat_priv, icmp_packet->orig); - if (!orig_node) - goto unlock; - - neigh_node = orig_node->router; - - if (!neigh_node) - goto unlock; - - if (!atomic_inc_not_zero(&neigh_node->refcount)) { - neigh_node = NULL; - goto unlock; - } + goto out; - rcu_read_unlock(); + router = orig_node_get_router(orig_node); + if (!router) + goto out; /* create a copy of the skb, if needed, to modify it. */ if (skb_cow(skb, sizeof(struct ethhdr)) < 0) @@ -982,15 +991,12 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, icmp_packet->msg_type = TTL_EXCEEDED; icmp_packet->ttl = TTL; - send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); + send_skb_packet(skb, router->if_incoming, router->addr); ret = NET_RX_SUCCESS; - goto out; -unlock: - rcu_read_unlock(); out: - if (neigh_node) - neigh_node_free_ref(neigh_node); + if (router) + neigh_node_free_ref(router); if (orig_node) orig_node_free_ref(orig_node); return ret; @@ -1003,7 +1009,7 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if) struct icmp_packet_rr *icmp_packet; struct ethhdr *ethhdr; struct orig_node *orig_node = NULL; - struct neigh_node *neigh_node = NULL; + struct neigh_node *router = NULL; int hdr_size = sizeof(struct icmp_packet); int ret = NET_RX_DROP; @@ -1050,23 +1056,13 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if) return recv_icmp_ttl_exceeded(bat_priv, skb); /* get routing information */ - rcu_read_lock(); orig_node = orig_hash_find(bat_priv, icmp_packet->dst); - if (!orig_node) - goto unlock; - - neigh_node = orig_node->router; - - if (!neigh_node) - goto unlock; - - if (!atomic_inc_not_zero(&neigh_node->refcount)) { - neigh_node = NULL; - goto unlock; - } + goto out; - rcu_read_unlock(); + router = orig_node_get_router(orig_node); + if (!router) + goto out; /* create a copy of the skb, if needed, to modify it. */ if (skb_cow(skb, sizeof(struct ethhdr)) < 0) @@ -1078,15 +1074,12 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if) icmp_packet->ttl--; /* route it */ - send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); + send_skb_packet(skb, router->if_incoming, router->addr); ret = NET_RX_SUCCESS; - goto out; -unlock: - rcu_read_unlock(); out: - if (neigh_node) - neigh_node_free_ref(neigh_node); + if (router) + neigh_node_free_ref(router); if (orig_node) orig_node_free_ref(orig_node); return ret; @@ -1208,7 +1201,8 @@ struct neigh_node *find_router(struct bat_priv *bat_priv, if (!orig_node) return NULL; - if (!orig_node->router) + router = orig_node_get_router(orig_node); + if (!router) return NULL; /* without bonding, the first node should @@ -1217,9 +1211,8 @@ struct neigh_node *find_router(struct bat_priv *bat_priv, rcu_read_lock(); /* select default router to output */ - router = orig_node->router; - router_orig = orig_node->router->orig_node; - if (!router_orig || !atomic_inc_not_zero(&router->refcount)) { + router_orig = router->orig_node; + if (!router_orig) { rcu_read_unlock(); return NULL; } @@ -1251,7 +1244,6 @@ struct neigh_node *find_router(struct bat_priv *bat_priv, if (atomic_read(&primary_orig_node->bond_candidates) < 2) goto return_router; - /* all nodes between should choose a candidate which * is is not on the interface where the packet came * in. */ diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index d49e54d932af..e78670c3c4b7 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -308,6 +308,7 @@ void schedule_forward_packet(struct orig_node *orig_node, struct hard_iface *if_incoming) { struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); + struct neigh_node *router; unsigned char in_tq, in_ttl, tq_avg = 0; unsigned long send_time; @@ -316,6 +317,8 @@ void schedule_forward_packet(struct orig_node *orig_node, return; } + router = orig_node_get_router(orig_node); + in_tq = batman_packet->tq; in_ttl = batman_packet->ttl; @@ -324,20 +327,22 @@ void schedule_forward_packet(struct orig_node *orig_node, /* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast * of our best tq value */ - if ((orig_node->router) && (orig_node->router->tq_avg != 0)) { + if (router && router->tq_avg != 0) { /* rebroadcast ogm of best ranking neighbor as is */ - if (!compare_eth(orig_node->router->addr, ethhdr->h_source)) { - batman_packet->tq = orig_node->router->tq_avg; + if (!compare_eth(router->addr, ethhdr->h_source)) { + batman_packet->tq = router->tq_avg; - if (orig_node->router->last_ttl) - batman_packet->ttl = orig_node->router->last_ttl - - 1; + if (router->last_ttl) + batman_packet->ttl = router->last_ttl - 1; } - tq_avg = orig_node->router->tq_avg; + tq_avg = router->tq_avg; } + if (router) + neigh_node_free_ref(router); + /* apply hop penalty */ batman_packet->tq = hop_penalty(batman_packet->tq, bat_priv); diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 83445cf0cc9f..1854cbb4c1b6 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -67,7 +67,7 @@ struct hard_iface { struct orig_node { uint8_t orig[ETH_ALEN]; uint8_t primary_addr[ETH_ALEN]; - struct neigh_node *router; + struct neigh_node __rcu *router; /* rcu protected pointer */ unsigned long *bcast_own; uint8_t *bcast_own_sum; unsigned long last_valid; @@ -83,7 +83,7 @@ struct orig_node { uint32_t last_bcast_seqno; struct hlist_head neigh_list; struct list_head frag_list; - spinlock_t neigh_list_lock; /* protects neighbor list */ + spinlock_t neigh_list_lock; /* protects neigh_list and router */ atomic_t refcount; struct rcu_head rcu; struct hlist_node hash_entry; diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c index f90212f42082..d4cc4f5399f4 100644 --- a/net/batman-adv/vis.c +++ b/net/batman-adv/vis.c @@ -558,6 +558,7 @@ static int find_best_vis_server(struct bat_priv *bat_priv, struct vis_info *info) { struct hashtable_t *hash = bat_priv->orig_hash; + struct neigh_node *router; struct hlist_node *node; struct hlist_head *head; struct orig_node *orig_node; @@ -571,13 +572,17 @@ static int find_best_vis_server(struct bat_priv *bat_priv, rcu_read_lock(); hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { - if ((orig_node) && (orig_node->router) && - (orig_node->flags & VIS_SERVER) && - (orig_node->router->tq_avg > best_tq)) { - best_tq = orig_node->router->tq_avg; + router = orig_node_get_router(orig_node); + if (!router) + continue; + + if ((orig_node->flags & VIS_SERVER) && + (router->tq_avg > best_tq)) { + best_tq = router->tq_avg; memcpy(packet->target_orig, orig_node->orig, ETH_ALEN); } + neigh_node_free_ref(router); } rcu_read_unlock(); } @@ -605,7 +610,7 @@ static int generate_vis_packet(struct bat_priv *bat_priv) struct hlist_node *node; struct hlist_head *head; struct orig_node *orig_node; - struct neigh_node *neigh_node; + struct neigh_node *router; struct vis_info *info = (struct vis_info *)bat_priv->my_vis_info; struct vis_packet *packet = (struct vis_packet *)info->skb_packet->data; struct vis_info_entry *entry; @@ -633,30 +638,32 @@ static int generate_vis_packet(struct bat_priv *bat_priv) rcu_read_lock(); hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { - neigh_node = orig_node->router; - - if (!neigh_node) + router = orig_node_get_router(orig_node); + if (!router) continue; - if (!compare_eth(neigh_node->addr, orig_node->orig)) - continue; + if (!compare_eth(router->addr, orig_node->orig)) + goto next; - if (neigh_node->if_incoming->if_status != IF_ACTIVE) - continue; + if (router->if_incoming->if_status != IF_ACTIVE) + goto next; - if (neigh_node->tq_avg < 1) - continue; + if (router->tq_avg < 1) + goto next; /* fill one entry into buffer. */ entry = (struct vis_info_entry *) skb_put(info->skb_packet, sizeof(*entry)); memcpy(entry->src, - neigh_node->if_incoming->net_dev->dev_addr, + router->if_incoming->net_dev->dev_addr, ETH_ALEN); memcpy(entry->dest, orig_node->orig, ETH_ALEN); - entry->quality = neigh_node->tq_avg; + entry->quality = router->tq_avg; packet->entries++; +next: + neigh_node_free_ref(router); + if (vis_packet_full(info)) goto unlock; } @@ -725,6 +732,7 @@ static void purge_vis_packets(struct bat_priv *bat_priv) static void broadcast_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) { + struct neigh_node *router; struct hashtable_t *hash = bat_priv->orig_hash; struct hlist_node *node; struct hlist_head *head; @@ -745,19 +753,26 @@ static void broadcast_vis_packet(struct bat_priv *bat_priv, rcu_read_lock(); hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { /* if it's a vis server and reachable, send it. */ - if ((!orig_node) || (!orig_node->router)) - continue; if (!(orig_node->flags & VIS_SERVER)) continue; + + router = orig_node_get_router(orig_node); + if (!router) + continue; + /* don't send it if we already received the packet from - * this node. */ + * this node. */ if (recv_list_is_in(bat_priv, &info->recv_list, - orig_node->orig)) + orig_node->orig)) { + neigh_node_free_ref(router); continue; + } memcpy(packet->target_orig, orig_node->orig, ETH_ALEN); - hard_iface = orig_node->router->if_incoming; - memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); + hard_iface = router->if_incoming; + memcpy(dstaddr, router->addr, ETH_ALEN); + + neigh_node_free_ref(router); skb = skb_clone(info->skb_packet, GFP_ATOMIC); if (skb) @@ -772,45 +787,29 @@ static void unicast_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) { struct orig_node *orig_node; - struct neigh_node *neigh_node = NULL; + struct neigh_node *router = NULL; struct sk_buff *skb; struct vis_packet *packet; packet = (struct vis_packet *)info->skb_packet->data; - rcu_read_lock(); orig_node = orig_hash_find(bat_priv, packet->target_orig); - if (!orig_node) - goto unlock; + goto out; - neigh_node = orig_node->router; - - if (!neigh_node) - goto unlock; - - if (!atomic_inc_not_zero(&neigh_node->refcount)) { - neigh_node = NULL; - goto unlock; - } - - rcu_read_unlock(); + router = orig_node_get_router(orig_node); + if (!router) + goto out; skb = skb_clone(info->skb_packet, GFP_ATOMIC); if (skb) - send_skb_packet(skb, neigh_node->if_incoming, - neigh_node->addr); - - goto out; + send_skb_packet(skb, router->if_incoming, router->addr); -unlock: - rcu_read_unlock(); out: - if (neigh_node) - neigh_node_free_ref(neigh_node); + if (router) + neigh_node_free_ref(router); if (orig_node) orig_node_free_ref(orig_node); - return; } /* only send one vis packet. called from send_vis_packets() */ -- cgit v1.2.3 From 68003903e4eeec5288f074ff0751a381750ceb34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20L=C3=BCssing?= Date: Mon, 14 Mar 2011 22:43:40 +0000 Subject: batman-adv: Protect global TQ window with a spinlock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Linus Lüssing Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann --- net/batman-adv/originator.c | 1 + net/batman-adv/routing.c | 4 ++++ net/batman-adv/types.h | 1 + 3 files changed, 6 insertions(+) (limited to 'net/batman-adv') diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index b4cfe3686155..5b8fe32043da 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -102,6 +102,7 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node, INIT_HLIST_NODE(&neigh_node->list); INIT_LIST_HEAD(&neigh_node->bonding_list); + spin_lock_init(&neigh_node->tq_lock); memcpy(neigh_node->addr, neigh, ETH_ALEN); neigh_node->orig_node = orig_neigh_node; diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index b7d43caaa9c8..f6c642246972 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -415,10 +415,12 @@ static void update_orig(struct bat_priv *bat_priv, if (is_duplicate) continue; + spin_lock_bh(&tmp_neigh_node->tq_lock); ring_buffer_set(tmp_neigh_node->tq_recv, &tmp_neigh_node->tq_index, 0); tmp_neigh_node->tq_avg = ring_buffer_avg(tmp_neigh_node->tq_recv); + spin_unlock_bh(&tmp_neigh_node->tq_lock); } if (!neigh_node) { @@ -443,10 +445,12 @@ static void update_orig(struct bat_priv *bat_priv, orig_node->flags = batman_packet->flags; neigh_node->last_valid = jiffies; + spin_lock_bh(&neigh_node->tq_lock); ring_buffer_set(neigh_node->tq_recv, &neigh_node->tq_index, batman_packet->tq); neigh_node->tq_avg = ring_buffer_avg(neigh_node->tq_recv); + spin_unlock_bh(&neigh_node->tq_lock); if (!is_duplicate) { orig_node->last_ttl = batman_packet->ttl; diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 1854cbb4c1b6..091476df4f0e 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -125,6 +125,7 @@ struct neigh_node { struct rcu_head rcu; struct orig_node *orig_node; struct hard_iface *if_incoming; + spinlock_t tq_lock; /* protects: tq_recv, tq_index */ }; -- cgit v1.2.3 From c4aac1ab9b973798163b34939b522f01e4d28ac9 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Wed, 23 Mar 2011 11:24:34 +0100 Subject: batman-adv: concentrate all curr_gw related rcu operations in select/deselect functions Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann --- net/batman-adv/gateway_client.c | 170 +++++++++++++++++++++++----------------- net/batman-adv/gateway_client.h | 2 +- net/batman-adv/unicast.c | 2 +- 3 files changed, 100 insertions(+), 74 deletions(-) (limited to 'net/batman-adv') diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 42a8a7ba06e6..2acd7a666bda 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -43,61 +43,75 @@ static void gw_node_free_ref(struct gw_node *gw_node) call_rcu(&gw_node->rcu, gw_node_free_rcu); } -struct orig_node *gw_get_selected(struct bat_priv *bat_priv) +static struct gw_node *gw_get_selected_gw_node(struct bat_priv *bat_priv) { - struct gw_node *curr_gateway_tmp; - struct orig_node *orig_node = NULL; + struct gw_node *gw_node; rcu_read_lock(); - curr_gateway_tmp = rcu_dereference(bat_priv->curr_gw); - if (!curr_gateway_tmp) - goto out; - - orig_node = curr_gateway_tmp->orig_node; - if (!orig_node) + gw_node = rcu_dereference(bat_priv->curr_gw); + if (!gw_node) goto out; - if (!atomic_inc_not_zero(&orig_node->refcount)) - orig_node = NULL; + if (!atomic_inc_not_zero(&gw_node->refcount)) + gw_node = NULL; out: rcu_read_unlock(); - return orig_node; + return gw_node; } -void gw_deselect(struct bat_priv *bat_priv) +struct orig_node *gw_get_selected_orig(struct bat_priv *bat_priv) { struct gw_node *gw_node; + struct orig_node *orig_node = NULL; - spin_lock_bh(&bat_priv->gw_list_lock); - gw_node = rcu_dereference(bat_priv->curr_gw); - rcu_assign_pointer(bat_priv->curr_gw, NULL); - spin_unlock_bh(&bat_priv->gw_list_lock); + gw_node = gw_get_selected_gw_node(bat_priv); + if (!gw_node) + goto out; + + rcu_read_lock(); + orig_node = gw_node->orig_node; + if (!orig_node) + goto unlock; + + if (!atomic_inc_not_zero(&orig_node->refcount)) + orig_node = NULL; +unlock: + rcu_read_unlock(); +out: if (gw_node) gw_node_free_ref(gw_node); + return orig_node; } static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node) { struct gw_node *curr_gw_node; + spin_lock_bh(&bat_priv->gw_list_lock); + if (new_gw_node && !atomic_inc_not_zero(&new_gw_node->refcount)) new_gw_node = NULL; - spin_lock_bh(&bat_priv->gw_list_lock); - curr_gw_node = rcu_dereference(bat_priv->curr_gw); + curr_gw_node = bat_priv->curr_gw; rcu_assign_pointer(bat_priv->curr_gw, new_gw_node); - spin_unlock_bh(&bat_priv->gw_list_lock); if (curr_gw_node) gw_node_free_ref(curr_gw_node); + + spin_unlock_bh(&bat_priv->gw_list_lock); +} + +void gw_deselect(struct bat_priv *bat_priv) +{ + gw_select(bat_priv, NULL); } void gw_election(struct bat_priv *bat_priv) { struct hlist_node *node; - struct gw_node *gw_node, *curr_gw, *curr_gw_tmp = NULL; + struct gw_node *gw_node, *curr_gw = NULL, *curr_gw_tmp = NULL; struct neigh_node *router; uint8_t max_tq = 0; uint32_t max_gw_factor = 0, tmp_gw_factor = 0; @@ -112,25 +126,17 @@ void gw_election(struct bat_priv *bat_priv) if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT) return; - rcu_read_lock(); - curr_gw = rcu_dereference(bat_priv->curr_gw); - if (curr_gw) { - rcu_read_unlock(); - return; - } + curr_gw = gw_get_selected_gw_node(bat_priv); + if (!curr_gw) + goto out; + rcu_read_lock(); if (hlist_empty(&bat_priv->gw_list)) { - - if (curr_gw) { - rcu_read_unlock(); - bat_dbg(DBG_BATMAN, bat_priv, - "Removing selected gateway - " - "no gateway in range\n"); - gw_deselect(bat_priv); - } else - rcu_read_unlock(); - - return; + bat_dbg(DBG_BATMAN, bat_priv, + "Removing selected gateway - " + "no gateway in range\n"); + gw_deselect(bat_priv); + goto unlock; } hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { @@ -182,7 +188,7 @@ void gw_election(struct bat_priv *bat_priv) if (curr_gw != curr_gw_tmp) { router = orig_node_get_router(curr_gw_tmp->orig_node); if (!router) - goto out; + goto unlock; if ((curr_gw) && (!curr_gw_tmp)) bat_dbg(DBG_BATMAN, bat_priv, @@ -207,8 +213,11 @@ void gw_election(struct bat_priv *bat_priv) gw_select(bat_priv, curr_gw_tmp); } -out: +unlock: rcu_read_unlock(); +out: + if (curr_gw) + gw_node_free_ref(curr_gw); } void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node) @@ -217,7 +226,7 @@ void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node) struct neigh_node *router_gw = NULL, *router_orig = NULL; uint8_t gw_tq_avg, orig_tq_avg; - curr_gw_orig = gw_get_selected(bat_priv); + curr_gw_orig = gw_get_selected_orig(bat_priv); if (!curr_gw_orig) goto deselect; @@ -299,7 +308,11 @@ void gw_node_update(struct bat_priv *bat_priv, struct orig_node *orig_node, uint8_t new_gwflags) { struct hlist_node *node; - struct gw_node *gw_node; + struct gw_node *gw_node, *curr_gw; + + curr_gw = gw_get_selected_gw_node(bat_priv); + if (!curr_gw) + goto out; rcu_read_lock(); hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { @@ -320,22 +333,26 @@ void gw_node_update(struct bat_priv *bat_priv, "Gateway %pM removed from gateway list\n", orig_node->orig); - if (gw_node == rcu_dereference(bat_priv->curr_gw)) { - rcu_read_unlock(); - gw_deselect(bat_priv); - return; - } + if (gw_node == curr_gw) + goto deselect; } - rcu_read_unlock(); - return; + goto unlock; } - rcu_read_unlock(); if (new_gwflags == 0) - return; + goto unlock; gw_node_add(bat_priv, orig_node, new_gwflags); + goto unlock; + +deselect: + gw_deselect(bat_priv); +unlock: + rcu_read_unlock(); +out: + if (curr_gw) + gw_node_free_ref(curr_gw); } void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node) @@ -345,9 +362,12 @@ void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node) void gw_node_purge(struct bat_priv *bat_priv) { - struct gw_node *gw_node; + struct gw_node *gw_node, *curr_gw; struct hlist_node *node, *node_tmp; unsigned long timeout = 2 * PURGE_TIMEOUT * HZ; + char do_deselect = 0; + + curr_gw = gw_get_selected_gw_node(bat_priv); spin_lock_bh(&bat_priv->gw_list_lock); @@ -358,15 +378,21 @@ void gw_node_purge(struct bat_priv *bat_priv) atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) continue; - if (rcu_dereference(bat_priv->curr_gw) == gw_node) - gw_deselect(bat_priv); + if (curr_gw == gw_node) + do_deselect = 1; hlist_del_rcu(&gw_node->list); gw_node_free_ref(gw_node); } - spin_unlock_bh(&bat_priv->gw_list_lock); + + /* gw_deselect() needs to acquire the gw_list_lock */ + if (do_deselect) + gw_deselect(bat_priv); + + if (curr_gw) + gw_node_free_ref(curr_gw); } /** @@ -385,22 +411,22 @@ static int _write_buffer_text(struct bat_priv *bat_priv, if (!router) goto out; - rcu_read_lock(); - curr_gw = rcu_dereference(bat_priv->curr_gw); + curr_gw = gw_get_selected_gw_node(bat_priv); ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n", - (curr_gw == gw_node ? "=>" : " "), - gw_node->orig_node->orig, - router->tq_avg, router->addr, - router->if_incoming->net_dev->name, - gw_node->orig_node->gw_flags, - (down > 2048 ? down / 1024 : down), - (down > 2048 ? "MBit" : "KBit"), - (up > 2048 ? up / 1024 : up), - (up > 2048 ? "MBit" : "KBit")); + (curr_gw == gw_node ? "=>" : " "), + gw_node->orig_node->orig, + router->tq_avg, router->addr, + router->if_incoming->net_dev->name, + gw_node->orig_node->gw_flags, + (down > 2048 ? down / 1024 : down), + (down > 2048 ? "MBit" : "KBit"), + (up > 2048 ? up / 1024 : up), + (up > 2048 ? "MBit" : "KBit")); - rcu_read_unlock(); neigh_node_free_ref(router); + if (curr_gw) + gw_node_free_ref(curr_gw); out: return ret; } @@ -459,6 +485,7 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) struct iphdr *iphdr; struct ipv6hdr *ipv6hdr; struct udphdr *udphdr; + struct gw_node *curr_gw; unsigned int header_len = 0; if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF) @@ -523,12 +550,11 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) if (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER) return -1; - rcu_read_lock(); - if (!rcu_dereference(bat_priv->curr_gw)) { - rcu_read_unlock(); + curr_gw = gw_get_selected_gw_node(bat_priv); + if (!curr_gw) return 0; - } - rcu_read_unlock(); + if (curr_gw) + gw_node_free_ref(curr_gw); return 1; } diff --git a/net/batman-adv/gateway_client.h b/net/batman-adv/gateway_client.h index 97c31d178163..1ce8c6066da1 100644 --- a/net/batman-adv/gateway_client.h +++ b/net/batman-adv/gateway_client.h @@ -24,7 +24,7 @@ void gw_deselect(struct bat_priv *bat_priv); void gw_election(struct bat_priv *bat_priv); -struct orig_node *gw_get_selected(struct bat_priv *bat_priv); +struct orig_node *gw_get_selected_orig(struct bat_priv *bat_priv); void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node); void gw_node_update(struct bat_priv *bat_priv, struct orig_node *orig_node, uint8_t new_gwflags); diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c index 19f84bd443af..d46acc815138 100644 --- a/net/batman-adv/unicast.c +++ b/net/batman-adv/unicast.c @@ -289,7 +289,7 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) /* get routing information */ if (is_multicast_ether_addr(ethhdr->h_dest)) { - orig_node = (struct orig_node *)gw_get_selected(bat_priv); + orig_node = (struct orig_node *)gw_get_selected_orig(bat_priv); if (orig_node) goto find_router; } -- cgit v1.2.3 From ba85fac28005a59e6e03fdb13918fc6f6e69a3ca Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Sun, 17 Apr 2011 20:34:27 +0200 Subject: batman-adv: protect softif_neigh by rcu Add get/set wrapper functions for softif_neigh and use rcu functions to manipulate the pointers. Signed-off-by: Simon Wunderlich Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann --- net/batman-adv/soft-interface.c | 114 ++++++++++++++++++++++++++++++---------- net/batman-adv/types.h | 2 +- 2 files changed, 88 insertions(+), 28 deletions(-) (limited to 'net/batman-adv') diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 9ed26140a269..ad6da4c7ddb5 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -90,10 +90,51 @@ static void softif_neigh_free_ref(struct softif_neigh *softif_neigh) call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu); } +static struct softif_neigh *softif_neigh_get_selected(struct bat_priv *bat_priv) +{ + struct softif_neigh *neigh; + + rcu_read_lock(); + neigh = rcu_dereference(bat_priv->softif_neigh); + + if (neigh && !atomic_inc_not_zero(&neigh->refcount)) + neigh = NULL; + + rcu_read_unlock(); + return neigh; +} + +static void softif_neigh_select(struct bat_priv *bat_priv, + struct softif_neigh *new_neigh) +{ + struct softif_neigh *curr_neigh; + + spin_lock_bh(&bat_priv->softif_neigh_lock); + + if (new_neigh && !atomic_inc_not_zero(&new_neigh->refcount)) + new_neigh = NULL; + + curr_neigh = bat_priv->softif_neigh; + rcu_assign_pointer(bat_priv->softif_neigh, new_neigh); + + if (curr_neigh) + softif_neigh_free_ref(curr_neigh); + + spin_unlock_bh(&bat_priv->softif_neigh_lock); +} + +static void softif_neigh_deselect(struct bat_priv *bat_priv) +{ + softif_neigh_select(bat_priv, NULL); +} + void softif_neigh_purge(struct bat_priv *bat_priv) { - struct softif_neigh *softif_neigh, *softif_neigh_tmp; + struct softif_neigh *softif_neigh, *curr_softif_neigh; struct hlist_node *node, *node_tmp; + char do_deselect = 0; + + curr_softif_neigh = softif_neigh_get_selected(bat_priv); spin_lock_bh(&bat_priv->softif_neigh_lock); @@ -105,22 +146,26 @@ void softif_neigh_purge(struct bat_priv *bat_priv) (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)) continue; - hlist_del_rcu(&softif_neigh->list); - - if (bat_priv->softif_neigh == softif_neigh) { + if (curr_softif_neigh == softif_neigh) { bat_dbg(DBG_ROUTES, bat_priv, "Current mesh exit point '%pM' vanished " "(vid: %d).\n", softif_neigh->addr, softif_neigh->vid); - softif_neigh_tmp = bat_priv->softif_neigh; - bat_priv->softif_neigh = NULL; - softif_neigh_free_ref(softif_neigh_tmp); + do_deselect = 1; } + hlist_del_rcu(&softif_neigh->list); softif_neigh_free_ref(softif_neigh); } spin_unlock_bh(&bat_priv->softif_neigh_lock); + + /* soft_neigh_deselect() needs to acquire the softif_neigh_lock */ + if (do_deselect) + softif_neigh_deselect(bat_priv); + + if (curr_softif_neigh) + softif_neigh_free_ref(curr_softif_neigh); } static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv, @@ -171,6 +216,7 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) struct bat_priv *bat_priv = netdev_priv(net_dev); struct softif_neigh *softif_neigh; struct hlist_node *node; + struct softif_neigh *curr_softif_neigh; if (!bat_priv->primary_if) { return seq_printf(seq, "BATMAN mesh %s disabled - " @@ -180,14 +226,17 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name); + curr_softif_neigh = softif_neigh_get_selected(bat_priv); rcu_read_lock(); hlist_for_each_entry_rcu(softif_neigh, node, &bat_priv->softif_neigh_list, list) seq_printf(seq, "%s %pM (vid: %d)\n", - bat_priv->softif_neigh == softif_neigh + curr_softif_neigh == softif_neigh ? "=>" : " ", softif_neigh->addr, softif_neigh->vid); rcu_read_unlock(); + if (curr_softif_neigh) + softif_neigh_free_ref(curr_softif_neigh); return 0; } @@ -198,7 +247,8 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, struct bat_priv *bat_priv = netdev_priv(dev); struct ethhdr *ethhdr = (struct ethhdr *)skb->data; struct batman_packet *batman_packet; - struct softif_neigh *softif_neigh, *softif_neigh_tmp; + struct softif_neigh *softif_neigh; + struct softif_neigh *curr_softif_neigh = NULL; if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) batman_packet = (struct batman_packet *) @@ -223,7 +273,8 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, if (!softif_neigh) goto err; - if (bat_priv->softif_neigh == softif_neigh) + curr_softif_neigh = softif_neigh_get_selected(bat_priv); + if (curr_softif_neigh == softif_neigh) goto out; /* we got a neighbor but its mac is 'bigger' than ours */ @@ -232,38 +283,39 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, goto out; /* switch to new 'smallest neighbor' */ - if ((bat_priv->softif_neigh) && - (memcmp(softif_neigh->addr, bat_priv->softif_neigh->addr, + if ((curr_softif_neigh) && + (memcmp(softif_neigh->addr, curr_softif_neigh->addr, ETH_ALEN) < 0)) { bat_dbg(DBG_ROUTES, bat_priv, "Changing mesh exit point from %pM (vid: %d) " "to %pM (vid: %d).\n", - bat_priv->softif_neigh->addr, - bat_priv->softif_neigh->vid, + curr_softif_neigh->addr, + curr_softif_neigh->vid, softif_neigh->addr, softif_neigh->vid); - softif_neigh_tmp = bat_priv->softif_neigh; - bat_priv->softif_neigh = softif_neigh; - softif_neigh_free_ref(softif_neigh_tmp); - /* we need to hold the additional reference */ - goto err; + + softif_neigh_select(bat_priv, softif_neigh); + goto out; } /* close own batX device and use softif_neigh as exit node */ - if ((!bat_priv->softif_neigh) && + if ((!curr_softif_neigh) && (memcmp(softif_neigh->addr, bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) { bat_dbg(DBG_ROUTES, bat_priv, "Setting mesh exit point to %pM (vid: %d).\n", softif_neigh->addr, softif_neigh->vid); - bat_priv->softif_neigh = softif_neigh; - /* we need to hold the additional reference */ - goto err; + + softif_neigh_select(bat_priv, softif_neigh); + goto out; } out: softif_neigh_free_ref(softif_neigh); err: kfree_skb(skb); + if (curr_softif_neigh) + softif_neigh_free_ref(curr_softif_neigh); + return; } @@ -321,6 +373,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) struct bat_priv *bat_priv = netdev_priv(soft_iface); struct bcast_packet *bcast_packet; struct vlan_ethhdr *vhdr; + struct softif_neigh *curr_softif_neigh = NULL; int data_len = skb->len, ret; short vid = -1; bool do_bcast = false; @@ -348,7 +401,8 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) * if we have a another chosen mesh exit node in range * it will transport the packets to the mesh */ - if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) + curr_softif_neigh = softif_neigh_get_selected(bat_priv); + if ((curr_softif_neigh) && (curr_softif_neigh->vid == vid)) goto dropped; /* TODO: check this for locks */ @@ -410,6 +464,8 @@ dropped: dropped_freed: bat_priv->stats.tx_dropped++; end: + if (curr_softif_neigh) + softif_neigh_free_ref(curr_softif_neigh); return NETDEV_TX_OK; } @@ -421,6 +477,7 @@ void interface_rx(struct net_device *soft_iface, struct unicast_packet *unicast_packet; struct ethhdr *ethhdr; struct vlan_ethhdr *vhdr; + struct softif_neigh *curr_softif_neigh = NULL; short vid = -1; int ret; @@ -450,7 +507,8 @@ void interface_rx(struct net_device *soft_iface, * if we have a another chosen mesh exit node in range * it will transport the packets to the non-mesh network */ - if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) { + curr_softif_neigh = softif_neigh_get_selected(bat_priv); + if (curr_softif_neigh && (curr_softif_neigh->vid == vid)) { skb_push(skb, hdr_size); unicast_packet = (struct unicast_packet *)skb->data; @@ -461,7 +519,7 @@ void interface_rx(struct net_device *soft_iface, skb_reset_mac_header(skb); memcpy(unicast_packet->dest, - bat_priv->softif_neigh->addr, ETH_ALEN); + curr_softif_neigh->addr, ETH_ALEN); ret = route_unicast_packet(skb, recv_if); if (ret == NET_RX_DROP) goto dropped; @@ -486,11 +544,13 @@ void interface_rx(struct net_device *soft_iface, soft_iface->last_rx = jiffies; netif_rx(skb); - return; + goto out; dropped: kfree_skb(skb); out: + if (curr_softif_neigh) + softif_neigh_free_ref(curr_softif_neigh); return; } diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 091476df4f0e..75123b1ae0de 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -147,7 +147,7 @@ struct bat_priv { atomic_t batman_queue_left; char num_ifaces; struct hlist_head softif_neigh_list; - struct softif_neigh *softif_neigh; + struct softif_neigh __rcu *softif_neigh; struct debug_log *debug_log; struct hard_iface *primary_if; struct kobject *mesh_obj; -- cgit v1.2.3 From af20b710479ae662829cf739b521390daa7fcbcb Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sun, 17 Apr 2011 20:39:07 +0200 Subject: batman-adv: Set the txqueuelen to zero when creating soft interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Like other virtual interfaces, e.g. br0, we don't need a transmit queue. Packets should only be queued on real interfaces which are underneath. In practice this patch makes little difference since the virtual interfaces can accept packets as fast as they come, but the patch will avoid bufferbloat questions to the mailling lists in the future. Signed-off-by: Andrew Lunn Tested-by: Linus Lüssing Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann --- net/batman-adv/soft-interface.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net/batman-adv') diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index ad6da4c7ddb5..58ce4400d581 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -584,6 +584,7 @@ static void interface_setup(struct net_device *dev) dev->hard_start_xmit = interface_tx; #endif dev->destructor = free_netdev; + dev->tx_queue_len = 0; /** * can't call min_mtu, because the needed variables -- cgit v1.2.3