This patchset adds the network wide multi interface optimization as proposed in our wiki [1] for BATMAN IV. The main purpose is to do interface alternating and bonding by considering multi interface capabilities globally and not just for the (next) link, otherwise non-optimal links may be chosen.
This patchset needs to change a lot of core data structures and routing, please review it carefully. A local development branch exists on the public git repo [2].
Changes from PATCH series earlier this month (thanks Marek and Antonio for suggestions) are: * change locking from implicit rcu locking to refcount based locking * add debugfs folder for hardif (new patch 7) and use separate tables per interface * split *ifinfo_get() functions into ifinfo_new() and ifinfo_get() * simplify function names and change to new naming scheme * review bonding locking * various kerneldoc/style/comment improvements * rebase on latest master * ... and some more in the changelog of the individual patches
I've tested the patchset in my VMs to confirm that bonding and alternating works as expected. Patches should be checkpatch and sparse clean.
As always, any comments are appreciated!
Thanks, Simon
[1] http://www.open-mesh.org/projects/batman-adv/wiki/network-wide-multi-link-op... [2] http://git.open-mesh.org/batman-adv.git/shortlog/refs/heads/simon/network-wi...
Simon Wunderlich (8): batman-adv: remove bonding and interface alternating batman-adv: split tq information in neigh_node struct batman-adv: split out router from orig_node batman-adv: add WiFi penalty batman-adv: consider outgoing interface in OGM sending batman-adv: add bonding again batman-adv: add debugfs structure for information per interface batman-adv: add debugfs support to view multiif tables
bat_iv_ogm.c | 855 +++++++++++++++++++++++++++++++---------------- debugfs.c | 83 +++++ debugfs.h | 3 + distributed-arp-table.c | 3 +- gateway_client.c | 83 ++++- hard-interface.c | 9 + hard-interface.h | 18 + icmp_socket.c | 3 +- main.h | 5 + network-coding.c | 9 +- originator.c | 501 ++++++++++++++++++++++++--- originator.h | 20 +- routing.c | 426 ++++++++--------------- routing.h | 12 +- send.c | 19 +- soft-interface.c | 2 +- translation-table.c | 6 +- types.h | 129 ++++--- 18 files changed, 1498 insertions(+), 688 deletions(-)
From: Simon Wunderlich simon@open-mesh.com
Remove bonding and interface alternating code - it will be replaced by a new, network-wide multi interface optimization which enables both bonding and interface alternating in a better way.
Keep the sysfs and find router function though, this will be needed later.
Signed-off-by: Simon Wunderlich simon@open-mesh.com --- bat_iv_ogm.c | 5 - originator.c | 15 +-- routing.c | 300 ++-------------------------------------------------------- routing.h | 9 -- types.h | 10 +- 5 files changed, 12 insertions(+), 327 deletions(-)
diff --git a/bat_iv_ogm.c b/bat_iv_ogm.c index a2b480a..6cd9a0f 100644 --- a/bat_iv_ogm.c +++ b/bat_iv_ogm.c @@ -976,8 +976,6 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, neigh_node->last_ttl = batadv_ogm_packet->header.ttl; }
- batadv_bonding_candidate_add(bat_priv, orig_node, neigh_node); - /* if this neighbor already is our next hop there is nothing * to change */ @@ -1426,9 +1424,6 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, is_bidirect = batadv_iv_ogm_calc_tq(orig_node, orig_neigh_node, batadv_ogm_packet, if_incoming);
- batadv_bonding_save_primary(orig_node, orig_neigh_node, - batadv_ogm_packet); - /* update ranking if it is not a duplicate or has the same * seqno and similar ttl as the non-duplicate */ diff --git a/originator.c b/originator.c index 8ab1434..919fdc0 100644 --- a/originator.c +++ b/originator.c @@ -198,8 +198,6 @@ batadv_neigh_node_new(struct batadv_hard_iface *hard_iface, neigh_node->if_incoming = hard_iface; neigh_node->orig_node = orig_node;
- INIT_LIST_HEAD(&neigh_node->bonding_list); - /* extra reference for return */ atomic_set(&neigh_node->refcount, 2);
@@ -210,20 +208,13 @@ out: static void batadv_orig_node_free_rcu(struct rcu_head *rcu) { struct hlist_node *node_tmp; - struct batadv_neigh_node *neigh_node, *tmp_neigh_node; + struct batadv_neigh_node *neigh_node; struct batadv_orig_node *orig_node;
orig_node = container_of(rcu, struct batadv_orig_node, rcu);
spin_lock_bh(&orig_node->neigh_list_lock);
- /* for all bonding members ... */ - list_for_each_entry_safe(neigh_node, tmp_neigh_node, - &orig_node->bond_list, bonding_list) { - list_del_rcu(&neigh_node->bonding_list); - batadv_neigh_node_free_ref(neigh_node); - } - /* for all neighbors towards this originator ... */ hlist_for_each_entry_safe(neigh_node, node_tmp, &orig_node->neigh_list, list) { @@ -327,7 +318,6 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, return NULL;
INIT_HLIST_HEAD(&orig_node->neigh_list); - INIT_LIST_HEAD(&orig_node->bond_list); INIT_LIST_HEAD(&orig_node->vlan_list); spin_lock_init(&orig_node->bcast_seqno_lock); spin_lock_init(&orig_node->neigh_list_lock); @@ -352,8 +342,6 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, orig_node->bcast_seqno_reset = reset_time; orig_node->batman_seqno_reset = reset_time;
- atomic_set(&orig_node->bond_candidates, 0); - /* create a vlan object for the "untagged" LAN */ vlan = batadv_orig_node_vlan_new(orig_node, BATADV_NO_FLAGS); if (!vlan) @@ -418,7 +406,6 @@ batadv_purge_orig_neighbors(struct batadv_priv *bat_priv, neigh_purged = true;
hlist_del_rcu(&neigh_node->list); - batadv_bonding_candidate_del(orig_node, neigh_node); batadv_neigh_node_free_ref(neigh_node); } else { /* store the best_neighbour if this is the first diff --git a/routing.c b/routing.c index 59fff2e..360a5b9 100644 --- a/routing.c +++ b/routing.c @@ -98,115 +98,6 @@ out: batadv_neigh_node_free_ref(router); }
-/* caller must hold the neigh_list_lock */ -void batadv_bonding_candidate_del(struct batadv_orig_node *orig_node, - struct batadv_neigh_node *neigh_node) -{ - /* this neighbor is not part of our candidate list */ - if (list_empty(&neigh_node->bonding_list)) - goto out; - - list_del_rcu(&neigh_node->bonding_list); - INIT_LIST_HEAD(&neigh_node->bonding_list); - batadv_neigh_node_free_ref(neigh_node); - atomic_dec(&orig_node->bond_candidates); - -out: - return; -} - -/** - * batadv_bonding_candidate_add - consider a new link for bonding mode towards - * the given originator - * @bat_priv: the bat priv with all the soft interface information - * @orig_node: the target node - * @neigh_node: the neighbor representing the new link to consider for bonding - * mode - */ -void batadv_bonding_candidate_add(struct batadv_priv *bat_priv, - struct batadv_orig_node *orig_node, - struct batadv_neigh_node *neigh_node) -{ - struct batadv_algo_ops *bao = bat_priv->bat_algo_ops; - struct batadv_neigh_node *tmp_neigh_node, *router = NULL; - uint8_t interference_candidate = 0; - - spin_lock_bh(&orig_node->neigh_list_lock); - - /* only consider if it has the same primary address ... */ - if (!batadv_compare_eth(orig_node->orig, - neigh_node->orig_node->primary_addr)) - goto candidate_del; - - router = batadv_orig_node_get_router(orig_node); - if (!router) - goto candidate_del; - - - /* ... and is good enough to be considered */ - if (bao->bat_neigh_is_equiv_or_better(neigh_node, router)) - goto candidate_del; - - /* check if we have another candidate with the same mac address or - * interface. If we do, we won't select this candidate because of - * possible interference. - */ - hlist_for_each_entry_rcu(tmp_neigh_node, - &orig_node->neigh_list, list) { - if (tmp_neigh_node == neigh_node) - continue; - - /* we only care if the other candidate is even - * considered as candidate. - */ - if (list_empty(&tmp_neigh_node->bonding_list)) - continue; - - if ((neigh_node->if_incoming == tmp_neigh_node->if_incoming) || - (batadv_compare_eth(neigh_node->addr, - tmp_neigh_node->addr))) { - interference_candidate = 1; - break; - } - } - - /* don't care further if it is an interference candidate */ - if (interference_candidate) - goto candidate_del; - - /* this neighbor already is part of our candidate list */ - if (!list_empty(&neigh_node->bonding_list)) - goto out; - - if (!atomic_inc_not_zero(&neigh_node->refcount)) - goto out; - - list_add_rcu(&neigh_node->bonding_list, &orig_node->bond_list); - atomic_inc(&orig_node->bond_candidates); - goto out; - -candidate_del: - batadv_bonding_candidate_del(orig_node, neigh_node); - -out: - spin_unlock_bh(&orig_node->neigh_list_lock); - - if (router) - batadv_neigh_node_free_ref(router); -} - -/* copy primary address for bonding */ -void -batadv_bonding_save_primary(const struct batadv_orig_node *orig_node, - struct batadv_orig_node *orig_neigh_node, - const struct batadv_ogm_packet *batman_ogm_packet) -{ - if (!(batman_ogm_packet->flags & BATADV_PRIMARIES_FIRST_HOP)) - return; - - memcpy(orig_neigh_node->primary_addr, orig_node->orig, ETH_ALEN); -} - /* checks whether the host restarted and is in the protection time. * returns: * 0 if the packet is to be accepted @@ -461,114 +352,6 @@ 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 batadv_neigh_node * -batadv_find_bond_router(struct batadv_orig_node *primary_orig, - const struct batadv_hard_iface *recv_if) -{ - struct batadv_neigh_node *tmp_neigh_node; - struct batadv_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; -} - -/** - * batadv_find_ifalter_router - find the best of the remaining candidates which - * are not using this interface - * @bat_priv: the bat priv with all the soft interface information - * @primary_orig: the destination - * @recv_if: the interface that the router returned by this function has to not - * use - * - * Returns the best candidate towards primary_orig that is not using recv_if. - * Increases the returned neighbor's refcount - */ -static struct batadv_neigh_node * -batadv_find_ifalter_router(struct batadv_priv *bat_priv, - struct batadv_orig_node *primary_orig, - const struct batadv_hard_iface *recv_if) -{ - struct batadv_neigh_node *router = NULL, *first_candidate = NULL; - struct batadv_algo_ops *bao = bat_priv->bat_algo_ops; - struct batadv_neigh_node *tmp_neigh_node; - - 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 (router && bao->bat_neigh_cmp(tmp_neigh_node, router)) - continue; - - if (!atomic_inc_not_zero(&tmp_neigh_node->refcount)) - continue; - - /* decrement refcount of previously selected router */ - if (router) - batadv_neigh_node_free_ref(router); - - /* we found a better router (or at least one valid router) */ - router = 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; -} - /** * batadv_check_unicast_packet - Check for malformed unicast packets * @bat_priv: the bat priv with all the soft interface information @@ -606,95 +389,30 @@ static int batadv_check_unicast_packet(struct batadv_priv *bat_priv, return 0; }
-/* find a suitable router for this originator, and use - * bonding if possible. increases the found neighbors - * refcount. +/** + * batadv_find_router - find a suitable router for this originator + * @bat_priv: the bat priv with all the soft interface information + * @orig_node: the destination node + * @recv_if: pointer to interface this packet was received on + * + * Returns the router which should be used for this orig_node on + * this interface, or NULL if not available. */ struct batadv_neigh_node * batadv_find_router(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, const struct batadv_hard_iface *recv_if) { - struct batadv_orig_node *primary_orig_node; - struct batadv_orig_node *router_orig; struct batadv_neigh_node *router; - static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; - int bonding_enabled; - uint8_t *primary_addr;
if (!orig_node) return NULL;
router = batadv_orig_node_get_router(orig_node); - if (!router) - goto err;
- /* without bonding, the first node should - * always choose the default router. - */ - bonding_enabled = atomic_read(&bat_priv->bonding); + /* TODO: fill this later with new bonding mechanism */
- rcu_read_lock(); - /* select default router to output */ - router_orig = router->orig_node; - if (!router_orig) - goto err_unlock; - - if ((!recv_if) && (!bonding_enabled)) - goto return_router; - - primary_addr = router_orig->primary_addr; - - /* if we have something in the primary_addr, we can search - * for a potential bonding candidate. - */ - if (batadv_compare_eth(primary_addr, zero_mac)) - goto return_router; - - /* find the orig_node which has the primary interface. might - * even be the same as our router_orig in many cases - */ - if (batadv_compare_eth(primary_addr, router_orig->orig)) { - primary_orig_node = router_orig; - } else { - primary_orig_node = batadv_orig_hash_find(bat_priv, - primary_addr); - if (!primary_orig_node) - goto return_router; - - batadv_orig_node_free_ref(primary_orig_node); - } - - /* with less than 2 candidates, we can't do any - * bonding and prefer the original router. - */ - 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. - */ - batadv_neigh_node_free_ref(router); - - if (bonding_enabled) - router = batadv_find_bond_router(primary_orig_node, recv_if); - else - router = batadv_find_ifalter_router(bat_priv, primary_orig_node, - recv_if); - -return_router: - if (router && router->if_incoming->if_status != BATADV_IF_ACTIVE) - goto err_unlock; - - rcu_read_unlock(); return router; -err_unlock: - rcu_read_unlock(); -err: - if (router) - batadv_neigh_node_free_ref(router); - return NULL; }
static int batadv_route_unicast_packet(struct sk_buff *skb, diff --git a/routing.h b/routing.h index 19544dd..b8fed80 100644 --- a/routing.h +++ b/routing.h @@ -46,15 +46,6 @@ struct batadv_neigh_node * batadv_find_router(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, const struct batadv_hard_iface *recv_if); -void batadv_bonding_candidate_del(struct batadv_orig_node *orig_node, - struct batadv_neigh_node *neigh_node); -void batadv_bonding_candidate_add(struct batadv_priv *bat_priv, - struct batadv_orig_node *orig_node, - struct batadv_neigh_node *neigh_node); -void batadv_bonding_save_primary(const struct batadv_orig_node *orig_node, - struct batadv_orig_node *orig_neigh_node, - const struct batadv_ogm_packet - *batman_ogm_packet); int batadv_window_protected(struct batadv_priv *bat_priv, int32_t seq_num_diff, unsigned long *last_reset);
diff --git a/types.h b/types.h index 91dd369..63ddff5 100644 --- a/types.h +++ b/types.h @@ -189,12 +189,10 @@ struct batadv_orig_bat_iv { * last_bcast_seqno) * @last_bcast_seqno: last broadcast sequence number received by this host * @neigh_list: list of potential next hop neighbor towards this orig node - * @neigh_list_lock: lock protecting neigh_list, router and bonding_list + * @neigh_list_lock: lock protecting neigh_list and router * @hash_entry: hlist node for batadv_priv::orig_hash * @bat_priv: pointer to soft_iface this orig node belongs to * @bcast_seqno_lock: lock protecting bcast_bits & last_bcast_seqno - * @bond_candidates: how many candidates are available - * @bond_list: list of bonding candidates * @refcount: number of contexts the object is used * @rcu: struct used for freeing in an RCU-safe manner * @in_coding_list: list of nodes this orig can hear @@ -230,14 +228,12 @@ struct batadv_orig_node { DECLARE_BITMAP(bcast_bits, BATADV_TQ_LOCAL_WINDOW_SIZE); uint32_t last_bcast_seqno; struct hlist_head neigh_list; - /* neigh_list_lock protects: neigh_list, router & bonding_list */ + /* neigh_list_lock protects: neigh_list and router */ spinlock_t neigh_list_lock; struct hlist_node hash_entry; struct batadv_priv *bat_priv; /* bcast_seqno_lock protects: bcast_bits & last_bcast_seqno */ spinlock_t bcast_seqno_lock; - atomic_t bond_candidates; - struct list_head bond_list; atomic_t refcount; struct rcu_head rcu; #ifdef CONFIG_BATMAN_ADV_NC @@ -310,7 +306,6 @@ struct batadv_neigh_bat_iv { * @if_incoming: pointer to incoming hard interface * @last_seen: when last packet via this neighbor was received * @last_ttl: last received ttl from this neigh node - * @bonding_list: list node for batadv_orig_node::bond_list * @refcount: number of contexts the object is used * @rcu: struct used for freeing in an RCU-safe manner * @bat_iv: B.A.T.M.A.N. IV private structure @@ -322,7 +317,6 @@ struct batadv_neigh_node { struct batadv_hard_iface *if_incoming; unsigned long last_seen; uint8_t last_ttl; - struct list_head bonding_list; atomic_t refcount; struct rcu_head rcu; struct batadv_neigh_bat_iv bat_iv;
From: Simon Wunderlich simon@open-mesh.com
For the network wide multi interface optimization it is required to save metrics per outgoing interface in one neighbor. Therefore a new type is introduced to keep interface-specific information. This also requires some changes in access and list management.
The compare and equiv_or_better API calls are changed to take the outgoing interface into consideration.
Signed-off-by: Simon Wunderlich simon@open-mesh.com --- Changes to PATCH: * change neigh_ifinfo locking from implicit rcu style to refcount locking * rename batadv_neigh_node_get_ifinfo to batadv_neigh_ifinfo_get to comply to new naming scheme * split into batadv_neigh_ifinfo_new() and batadv_neigh_ifinfo_get() functions * rename batadv_neigh_node_ifinfo* to batadv_neigh_ifinfo* - name is still long enough * added BATADV_IF_DEFAULT to ease review * fix batadv_gw_check_election goto bug
Changes to RFCv2: * change bat_neigh_cmp and equiv_or_better to use two neighbor and if_outgoing as parameter * keep bat_neigh_is_equiv_or_better name (no _ifinfo_) * various style and documentation fixes
Changes to RFC: * rebase on latest master * change compare API to consider outgoing interface * change EOB API to use ifinfo - this will be required to compare routers for different ougoing interfaces in the bonding patch * fix missing spin_unlock_bh --- bat_iv_ogm.c | 255 ++++++++++++++++++++++++++++++++++++++++----------- gateway_client.c | 72 +++++++++++++-- hard-interface.h | 17 ++++ main.h | 5 + originator.c | 213 ++++++++++++++++++++++++++++++++++++++---- originator.h | 7 ++ translation-table.c | 3 +- types.h | 74 +++++++++------ 8 files changed, 539 insertions(+), 107 deletions(-)
diff --git a/bat_iv_ogm.c b/bat_iv_ogm.c index 6cd9a0f..66ce1a7 100644 --- a/bat_iv_ogm.c +++ b/bat_iv_ogm.c @@ -274,7 +274,13 @@ batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface, if (!neigh_node) goto out;
- spin_lock_init(&neigh_node->bat_iv.lq_update_lock); + if (!atomic_inc_not_zero(&hard_iface->refcount)) { + kfree(neigh_node); + goto out; + } + + neigh_node->orig_node = orig_neigh; + neigh_node->if_incoming = hard_iface;
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Creating new neighbor %pM for orig_node %pM on interface %s\n", @@ -897,15 +903,30 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface) batadv_hardif_free_ref(primary_if); }
+/** + * batadv_iv_ogm_orig_update - use OGM to update corresponding data in an + * originator + * @bat_priv: the bat priv with all the soft interface information + * @orig_node: the orig node who originally emitted the ogm packet + * @ethhdr: Ethernet header of the OGM + * @batadv_ogm_packet: the ogm packet + * @if_incoming: interface where the packet was received + * @if_outgoing: interface for which the retransmission should be considered + * @tt_buff: pointer to the tt buffer + * @dup_status: the duplicate status of this ogm packet. + */ static void batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, const struct ethhdr *ethhdr, const struct batadv_ogm_packet *batadv_ogm_packet, struct batadv_hard_iface *if_incoming, + struct batadv_hard_iface *if_outgoing, const unsigned char *tt_buff, enum batadv_dup_status dup_status) { + struct batadv_neigh_ifinfo *neigh_ifinfo = NULL; + struct batadv_neigh_ifinfo *router_ifinfo = NULL; struct batadv_neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; struct batadv_neigh_node *router = NULL; struct batadv_orig_node *orig_node_tmp; @@ -933,12 +954,20 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, if (dup_status != BATADV_NO_DUP) continue;
- spin_lock_bh(&tmp_neigh_node->bat_iv.lq_update_lock); - batadv_ring_buffer_set(tmp_neigh_node->bat_iv.tq_recv, - &tmp_neigh_node->bat_iv.tq_index, 0); - tq_avg = batadv_ring_buffer_avg(tmp_neigh_node->bat_iv.tq_recv); - tmp_neigh_node->bat_iv.tq_avg = tq_avg; - spin_unlock_bh(&tmp_neigh_node->bat_iv.lq_update_lock); + /* only update the entry for this outgoing interface */ + neigh_ifinfo = batadv_neigh_ifinfo_get(tmp_neigh_node, + if_outgoing); + if (!neigh_ifinfo) + continue; + + spin_lock_bh(&tmp_neigh_node->ifinfo_lock); + batadv_ring_buffer_set(neigh_ifinfo->bat_iv.tq_recv, + &neigh_ifinfo->bat_iv.tq_index, 0); + tq_avg = batadv_ring_buffer_avg(neigh_ifinfo->bat_iv.tq_recv); + neigh_ifinfo->bat_iv.tq_avg = tq_avg; + spin_unlock_bh(&tmp_neigh_node->ifinfo_lock); + + batadv_neigh_ifinfo_free_ref(neigh_ifinfo); }
if (!neigh_node) { @@ -960,20 +989,23 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, "Updating existing last-hop neighbor of originator\n");
rcu_read_unlock(); + neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing); + if (!neigh_ifinfo) + goto out;
neigh_node->last_seen = jiffies;
- spin_lock_bh(&neigh_node->bat_iv.lq_update_lock); - batadv_ring_buffer_set(neigh_node->bat_iv.tq_recv, - &neigh_node->bat_iv.tq_index, + spin_lock_bh(&neigh_node->ifinfo_lock); + batadv_ring_buffer_set(neigh_ifinfo->bat_iv.tq_recv, + &neigh_ifinfo->bat_iv.tq_index, batadv_ogm_packet->tq); - tq_avg = batadv_ring_buffer_avg(neigh_node->bat_iv.tq_recv); - neigh_node->bat_iv.tq_avg = tq_avg; - spin_unlock_bh(&neigh_node->bat_iv.lq_update_lock); + tq_avg = batadv_ring_buffer_avg(neigh_ifinfo->bat_iv.tq_recv); + neigh_ifinfo->bat_iv.tq_avg = tq_avg; + spin_unlock_bh(&neigh_node->ifinfo_lock);
if (dup_status == BATADV_NO_DUP) { orig_node->last_ttl = batadv_ogm_packet->header.ttl; - neigh_node->last_ttl = batadv_ogm_packet->header.ttl; + neigh_ifinfo->last_ttl = batadv_ogm_packet->header.ttl; }
/* if this neighbor already is our next hop there is nothing @@ -983,14 +1015,17 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, if (router == neigh_node) goto out;
+ router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing); /* if this neighbor does not offer a better TQ we won't consider it */ - if (router && (router->bat_iv.tq_avg > neigh_node->bat_iv.tq_avg)) + if (router_ifinfo && + (router_ifinfo->bat_iv.tq_avg > neigh_ifinfo->bat_iv.tq_avg)) goto out;
/* if the TQ is the same and the link not more symmetric we * won't consider it either */ - if (router && (neigh_node->bat_iv.tq_avg == router->bat_iv.tq_avg)) { + if (router_ifinfo && + (neigh_ifinfo->bat_iv.tq_avg == router_ifinfo->bat_iv.tq_avg)) { orig_node_tmp = router->orig_node; spin_lock_bh(&orig_node_tmp->bat_iv.ogm_cnt_lock); if_num = router->if_incoming->if_num; @@ -1007,6 +1042,7 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, goto out; }
+ /* TODO: pass if_outgoing later */ batadv_update_route(bat_priv, orig_node, neigh_node); goto out;
@@ -1017,15 +1053,31 @@ out: batadv_neigh_node_free_ref(neigh_node); if (router) batadv_neigh_node_free_ref(router); + if (neigh_ifinfo) + batadv_neigh_ifinfo_free_ref(neigh_ifinfo); + if (router_ifinfo) + batadv_neigh_ifinfo_free_ref(router_ifinfo); }
+/** + * batadv_iv_ogm_calc_tq - calculate tq for current received ogm packet + * @orig_node: the orig node who originally emitted the ogm packet + * @orig_neigh_node: the orig node struct of the neighbor who sent the packet + * @batadv_ogm_packet: the ogm packet + * @if_incoming: interface where the packet was received + * @if_outgoing: interface for which the retransmission should be considered + * + * Returns 1 if the link can be considered bidirectional, 0 otherwise + */ static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, struct batadv_orig_node *orig_neigh_node, struct batadv_ogm_packet *batadv_ogm_packet, - struct batadv_hard_iface *if_incoming) + struct batadv_hard_iface *if_incoming, + struct batadv_hard_iface *if_outgoing) { struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); struct batadv_neigh_node *neigh_node = NULL, *tmp_neigh_node; + struct batadv_neigh_ifinfo *neigh_ifinfo; uint8_t total_count; uint8_t orig_eq_count, neigh_rq_count, neigh_rq_inv, tq_own; unsigned int neigh_rq_inv_cube, neigh_rq_max_cube; @@ -1070,7 +1122,13 @@ static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); if_num = if_incoming->if_num; orig_eq_count = orig_neigh_node->bat_iv.bcast_own_sum[if_num]; - neigh_rq_count = neigh_node->bat_iv.real_packet_count; + neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing); + if (neigh_ifinfo) { + neigh_rq_count = neigh_ifinfo->bat_iv.real_packet_count; + batadv_neigh_ifinfo_free_ref(neigh_ifinfo); + } else { + neigh_rq_count = 0; + } spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock);
/* pay attention to not get a value bigger than 100 % */ @@ -1134,17 +1192,20 @@ out: * @ethhdr: ethernet header of the packet * @batadv_ogm_packet: OGM packet to be considered * @if_incoming: interface on which the OGM packet was received + * @if_outgoing: interface for which the retransmission should be considered * * Returns duplicate status as enum batadv_dup_status */ static enum batadv_dup_status batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, const struct batadv_ogm_packet *batadv_ogm_packet, - const struct batadv_hard_iface *if_incoming) + const struct batadv_hard_iface *if_incoming, + struct batadv_hard_iface *if_outgoing) { struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); struct batadv_orig_node *orig_node; - struct batadv_neigh_node *tmp_neigh_node; + struct batadv_neigh_node *neigh_node; + struct batadv_neigh_ifinfo *neigh_ifinfo; int is_dup; int32_t seq_diff; int need_update = 0; @@ -1171,15 +1232,19 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, }
rcu_read_lock(); - hlist_for_each_entry_rcu(tmp_neigh_node, - &orig_node->neigh_list, list) { - neigh_addr = tmp_neigh_node->addr; - is_dup = batadv_test_bit(tmp_neigh_node->bat_iv.real_bits, + hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) { + neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, + if_outgoing); + if (!neigh_ifinfo) + continue; + + neigh_addr = neigh_node->addr; + is_dup = batadv_test_bit(neigh_ifinfo->bat_iv.real_bits, orig_node->last_real_seqno, seqno);
if (batadv_compare_eth(neigh_addr, ethhdr->h_source) && - tmp_neigh_node->if_incoming == if_incoming) { + neigh_node->if_incoming == if_incoming) { set_mark = 1; if (is_dup) ret = BATADV_NEIGH_DUP; @@ -1190,13 +1255,14 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, }
/* if the window moved, set the update flag. */ - bitmap = tmp_neigh_node->bat_iv.real_bits; + bitmap = neigh_ifinfo->bat_iv.real_bits; need_update |= batadv_bit_get_packet(bat_priv, bitmap, seq_diff, set_mark);
- packet_count = bitmap_weight(tmp_neigh_node->bat_iv.real_bits, + packet_count = bitmap_weight(bitmap, BATADV_TQ_LOCAL_WINDOW_SIZE); - tmp_neigh_node->bat_iv.real_packet_count = packet_count; + neigh_ifinfo->bat_iv.real_packet_count = packet_count; + batadv_neigh_ifinfo_free_ref(neigh_ifinfo); } rcu_read_unlock();
@@ -1223,6 +1289,7 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, struct batadv_orig_node *orig_neigh_node, *orig_node, *orig_node_tmp; struct batadv_neigh_node *router = NULL, *router_router = NULL; struct batadv_neigh_node *orig_neigh_router = NULL; + struct batadv_neigh_ifinfo *router_ifinfo = NULL; int has_directlink_flag; int is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0; int is_bidirect; @@ -1355,7 +1422,8 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, return;
dup_status = batadv_iv_ogm_update_seqnos(ethhdr, batadv_ogm_packet, - if_incoming); + if_incoming, + BATADV_IF_DEFAULT);
if (dup_status == BATADV_PROTECTED) { batadv_dbg(BATADV_DBG_BATMAN, bat_priv, @@ -1374,9 +1442,11 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, if (router) { orig_node_tmp = router->orig_node; router_router = batadv_orig_node_get_router(orig_node_tmp); + router_ifinfo = batadv_neigh_ifinfo_get(router, + BATADV_IF_DEFAULT); }
- if ((router && router->bat_iv.tq_avg != 0) && + if ((router && router_ifinfo->bat_iv.tq_avg != 0) && (batadv_compare_eth(router->addr, ethhdr->h_source))) is_from_best_next_hop = true;
@@ -1422,7 +1492,8 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, }
is_bidirect = batadv_iv_ogm_calc_tq(orig_node, orig_neigh_node, - batadv_ogm_packet, if_incoming); + batadv_ogm_packet, if_incoming, + BATADV_IF_DEFAULT);
/* update ranking if it is not a duplicate or has the same * seqno and similar ttl as the non-duplicate @@ -1433,7 +1504,8 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, (sameseq && similar_ttl))) batadv_iv_ogm_orig_update(bat_priv, orig_node, ethhdr, batadv_ogm_packet, if_incoming, - tt_buff, dup_status); + BATADV_IF_DEFAULT, tt_buff, + dup_status);
/* is single hop (direct) neighbor */ if (is_single_hop_neigh) { @@ -1529,6 +1601,35 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb, return NET_RX_SUCCESS; }
+/* batadv_iv_ogm_orig_print_neigh - print neighbors for the originator table + * @orig_node: the orig_node for which the neighbors are printed + * @if_outgoing: outgoing interface for these entries + * @seq: debugfs table seq_file struct + * + * Must be called while holding a rcu lock. + */ + +static void +batadv_iv_ogm_orig_print_neigh(struct batadv_orig_node *orig_node, + struct batadv_hard_iface *if_outgoing, + struct seq_file *seq) +{ + struct batadv_neigh_node *neigh_node; + struct batadv_neigh_ifinfo *n_ifinfo; + + hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) { + n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing); + if (!n_ifinfo) + continue; + + seq_printf(seq, " %pM (%3i)", + neigh_node->addr, + n_ifinfo->bat_iv.tq_avg); + + batadv_neigh_ifinfo_free_ref(n_ifinfo); + } +} + /** * batadv_iv_ogm_orig_print - print the originator table * @bat_priv: the bat priv with all the soft interface information @@ -1537,10 +1638,11 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb, static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv, struct seq_file *seq) { - struct batadv_neigh_node *neigh_node, *neigh_node_tmp; + struct batadv_neigh_node *neigh_node; struct batadv_hashtable *hash = bat_priv->orig_hash; int last_seen_msecs, last_seen_secs; struct batadv_orig_node *orig_node; + struct batadv_neigh_ifinfo *n_ifinfo; unsigned long last_seen_jiffies; struct hlist_head *head; int batman_count = 0; @@ -1559,7 +1661,12 @@ static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv, if (!neigh_node) continue;
- if (neigh_node->bat_iv.tq_avg == 0) + n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, + BATADV_IF_DEFAULT); + if (!n_ifinfo) + goto next; + + if (n_ifinfo->bat_iv.tq_avg == 0) goto next;
last_seen_jiffies = jiffies - orig_node->last_seen; @@ -1569,17 +1676,12 @@ static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv,
seq_printf(seq, "%pM %4i.%03is (%3i) %pM [%10s]:", orig_node->orig, last_seen_secs, - last_seen_msecs, neigh_node->bat_iv.tq_avg, + last_seen_msecs, n_ifinfo->bat_iv.tq_avg, neigh_node->addr, neigh_node->if_incoming->net_dev->name);
- hlist_for_each_entry_rcu(neigh_node_tmp, - &orig_node->neigh_list, list) { - seq_printf(seq, " %pM (%3i)", - neigh_node_tmp->addr, - neigh_node_tmp->bat_iv.tq_avg); - } - + batadv_iv_ogm_orig_print_neigh(orig_node, + BATADV_IF_DEFAULT, seq); seq_puts(seq, "\n"); batman_count++;
@@ -1596,37 +1698,84 @@ next: /** * batadv_iv_ogm_neigh_cmp - compare the metrics of two neighbors * @neigh1: the first neighbor object of the comparison + * @if_outgoing1: outgoing interface for the first neighbor * @neigh2: the second neighbor object of the comparison + * @if_outgoing2: outgoing interface for the second neighbor * * Returns a value less, equal to or greater than 0 if the metric via neigh1 is * lower, the same as or higher than the metric via neigh2 */ static int batadv_iv_ogm_neigh_cmp(struct batadv_neigh_node *neigh1, - struct batadv_neigh_node *neigh2) + struct batadv_hard_iface *if_outgoing1, + struct batadv_neigh_node *neigh2, + struct batadv_hard_iface *if_outgoing2) { + struct batadv_neigh_ifinfo *neigh1_ifinfo, *neigh2_ifinfo; uint8_t tq1, tq2; + int diff;
- tq1 = neigh1->bat_iv.tq_avg; - tq2 = neigh2->bat_iv.tq_avg; + neigh1_ifinfo = batadv_neigh_ifinfo_get(neigh1, if_outgoing1); + neigh2_ifinfo = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
- return tq1 - tq2; + if (!neigh1_ifinfo || !neigh2_ifinfo) { + diff = 0; + goto out; + } + + tq1 = neigh1_ifinfo->bat_iv.tq_avg; + tq2 = neigh2_ifinfo->bat_iv.tq_avg; + diff = tq1 - tq2; + +out: + if (neigh1_ifinfo) + batadv_neigh_ifinfo_free_ref(neigh1_ifinfo); + if (neigh2_ifinfo) + batadv_neigh_ifinfo_free_ref(neigh2_ifinfo); + + return diff; }
/** * batadv_iv_ogm_neigh_is_eob - check if neigh1 is equally good or better than * neigh2 from the metric prospective * @neigh1: the first neighbor object of the comparison + * @if_outgoing: outgoing interface for the first neighbor * @neigh2: the second neighbor object of the comparison - * - * Returns true if the metric via neigh1 is equally good or better than the - * metric via neigh2, false otherwise. + * @if_outgoing2: outgoing interface for the second neighbor + + * Returns true if the metric via neigh1 is equally good or better than + * the metric via neigh2, false otherwise. */ -static bool batadv_iv_ogm_neigh_is_eob(struct batadv_neigh_node *neigh1, - struct batadv_neigh_node *neigh2) +static bool +batadv_iv_ogm_neigh_is_eob(struct batadv_neigh_node *neigh1, + struct batadv_hard_iface *if_outgoing1, + struct batadv_neigh_node *neigh2, + struct batadv_hard_iface *if_outgoing2) { - int diff = batadv_iv_ogm_neigh_cmp(neigh1, neigh2); + struct batadv_neigh_ifinfo *neigh1_ifinfo, *neigh2_ifinfo; + uint8_t tq1, tq2; + bool ret;
- return diff > -BATADV_TQ_SIMILARITY_THRESHOLD; + neigh1_ifinfo = batadv_neigh_ifinfo_get(neigh1, if_outgoing1); + neigh2_ifinfo = batadv_neigh_ifinfo_get(neigh2, if_outgoing2); + + /* we can't say that the metric is better */ + if (!neigh1_ifinfo || !neigh2_ifinfo) { + ret = false; + goto out; + } + + tq1 = neigh1_ifinfo->bat_iv.tq_avg; + tq2 = neigh2_ifinfo->bat_iv.tq_avg; + ret = (tq1 - tq2) > -BATADV_TQ_SIMILARITY_THRESHOLD; + +out: + if (neigh1_ifinfo) + batadv_neigh_ifinfo_free_ref(neigh1_ifinfo); + if (neigh2_ifinfo) + batadv_neigh_ifinfo_free_ref(neigh2_ifinfo); + + return ret; }
static struct batadv_algo_ops batadv_batman_iv __read_mostly = { diff --git a/gateway_client.c b/gateway_client.c index 2449afa..71759d0 100644 --- a/gateway_client.c +++ b/gateway_client.c @@ -114,6 +114,7 @@ static struct batadv_gw_node * batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) { struct batadv_neigh_node *router; + struct batadv_neigh_ifinfo *router_ifinfo; struct batadv_gw_node *gw_node, *curr_gw = NULL; uint32_t max_gw_factor = 0, tmp_gw_factor = 0; uint32_t gw_divisor; @@ -134,10 +135,15 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) if (!router) continue;
+ router_ifinfo = batadv_neigh_ifinfo_get(router, + BATADV_IF_DEFAULT); + if (!router_ifinfo) + goto next; + if (!atomic_inc_not_zero(&gw_node->refcount)) goto next;
- tq_avg = router->bat_iv.tq_avg; + tq_avg = router_ifinfo->bat_iv.tq_avg;
switch (atomic_read(&bat_priv->gw_sel_class)) { case 1: /* fast connection */ @@ -182,6 +188,8 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv)
next: batadv_neigh_node_free_ref(router); + if (router_ifinfo) + batadv_neigh_ifinfo_free_ref(router_ifinfo); } rcu_read_unlock();
@@ -219,6 +227,7 @@ void batadv_gw_election(struct batadv_priv *bat_priv) { struct batadv_gw_node *curr_gw = NULL, *next_gw = NULL; struct batadv_neigh_node *router = NULL; + struct batadv_neigh_ifinfo *router_ifinfo = NULL; char gw_addr[18] = { '\0' };
if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_CLIENT) @@ -242,6 +251,13 @@ void batadv_gw_election(struct batadv_priv *bat_priv) batadv_gw_deselect(bat_priv); goto out; } + + router_ifinfo = batadv_neigh_ifinfo_get(router, + BATADV_IF_DEFAULT); + if (!router_ifinfo) { + batadv_gw_deselect(bat_priv); + goto out; + } }
if ((curr_gw) && (!next_gw)) { @@ -256,7 +272,8 @@ void batadv_gw_election(struct batadv_priv *bat_priv) next_gw->bandwidth_down / 10, next_gw->bandwidth_down % 10, next_gw->bandwidth_up / 10, - next_gw->bandwidth_up % 10, router->bat_iv.tq_avg); + next_gw->bandwidth_up % 10, + router_ifinfo->bat_iv.tq_avg); batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_ADD, gw_addr); } else { @@ -266,7 +283,8 @@ void batadv_gw_election(struct batadv_priv *bat_priv) next_gw->bandwidth_down / 10, next_gw->bandwidth_down % 10, next_gw->bandwidth_up / 10, - next_gw->bandwidth_up % 10, router->bat_iv.tq_avg); + next_gw->bandwidth_up % 10, + router_ifinfo->bat_iv.tq_avg); batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_CHANGE, gw_addr); } @@ -280,11 +298,15 @@ out: batadv_gw_node_free_ref(next_gw); if (router) batadv_neigh_node_free_ref(router); + if (router_ifinfo) + batadv_neigh_ifinfo_free_ref(router_ifinfo); }
void batadv_gw_check_election(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node) { + struct batadv_neigh_ifinfo *router_orig_tq = NULL; + struct batadv_neigh_ifinfo *router_gw_tq = NULL; struct batadv_orig_node *curr_gw_orig; struct batadv_neigh_node *router_gw = NULL, *router_orig = NULL; uint8_t gw_tq_avg, orig_tq_avg; @@ -297,6 +319,11 @@ void batadv_gw_check_election(struct batadv_priv *bat_priv, if (!router_gw) goto deselect;
+ router_gw_tq = batadv_neigh_ifinfo_get(router_gw, + BATADV_IF_DEFAULT); + if (!router_gw_tq) + goto deselect; + /* this node already is the gateway */ if (curr_gw_orig == orig_node) goto out; @@ -305,8 +332,13 @@ void batadv_gw_check_election(struct batadv_priv *bat_priv, if (!router_orig) goto out;
- gw_tq_avg = router_gw->bat_iv.tq_avg; - orig_tq_avg = router_orig->bat_iv.tq_avg; + router_orig_tq = batadv_neigh_ifinfo_get(router_orig, + BATADV_IF_DEFAULT); + if (!router_orig_tq) + goto out; + + gw_tq_avg = router_gw_tq->bat_iv.tq_avg; + orig_tq_avg = router_orig_tq->bat_iv.tq_avg;
/* the TQ value has to be better */ if (orig_tq_avg < gw_tq_avg) @@ -332,6 +364,10 @@ out: batadv_neigh_node_free_ref(router_gw); if (router_orig) batadv_neigh_node_free_ref(router_orig); + if (router_gw_tq) + batadv_neigh_ifinfo_free_ref(router_gw_tq); + if (router_orig_tq) + batadv_neigh_ifinfo_free_ref(router_orig_tq);
return; } @@ -517,18 +553,23 @@ static int batadv_write_buffer_text(struct batadv_priv *bat_priv, { struct batadv_gw_node *curr_gw; struct batadv_neigh_node *router; + struct batadv_neigh_ifinfo *router_ifinfo; int ret = -1;
router = batadv_orig_node_get_router(gw_node->orig_node); if (!router) goto out;
+ router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT); + if (!router_ifinfo) + goto out; + curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %u.%u/%u.%u MBit\n", (curr_gw == gw_node ? "=>" : " "), gw_node->orig_node->orig, - router->bat_iv.tq_avg, router->addr, + router_ifinfo->bat_iv.tq_avg, router->addr, router->if_incoming->net_dev->name, gw_node->bandwidth_down / 10, gw_node->bandwidth_down % 10, @@ -538,6 +579,8 @@ static int batadv_write_buffer_text(struct batadv_priv *bat_priv, batadv_neigh_node_free_ref(router); if (curr_gw) batadv_gw_node_free_ref(curr_gw); + if (router_ifinfo) + batadv_neigh_ifinfo_free_ref(router_ifinfo); out: return ret; } @@ -741,6 +784,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, struct batadv_neigh_node *neigh_curr = NULL, *neigh_old = NULL; struct batadv_orig_node *orig_dst_node = NULL; struct batadv_gw_node *gw_node = NULL, *curr_gw = NULL; + struct batadv_neigh_ifinfo *curr_ifinfo, *old_ifinfo; struct ethhdr *ethhdr; bool ret, out_of_range = false; unsigned int header_len = 0; @@ -792,7 +836,14 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, if (!neigh_curr) goto out;
- curr_tq_avg = neigh_curr->bat_iv.tq_avg; + curr_ifinfo = batadv_neigh_ifinfo_get(neigh_curr, + BATADV_IF_DEFAULT); + if (!curr_ifinfo) + goto out; + + curr_tq_avg = curr_ifinfo->bat_iv.tq_avg; + batadv_neigh_ifinfo_free_ref(curr_ifinfo); + break; case BATADV_GW_MODE_OFF: default: @@ -803,8 +854,13 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, if (!neigh_old) goto out;
- if (curr_tq_avg - neigh_old->bat_iv.tq_avg > BATADV_GW_THRESHOLD) + old_ifinfo = batadv_neigh_ifinfo_get(neigh_old, BATADV_IF_DEFAULT); + if (!old_ifinfo) + goto out; + + if ((curr_tq_avg - old_ifinfo->bat_iv.tq_avg) > BATADV_GW_THRESHOLD) out_of_range = true; + batadv_neigh_ifinfo_free_ref(old_ifinfo);
out: if (orig_dst_node) diff --git a/hard-interface.h b/hard-interface.h index df4c8bd..6b609b0 100644 --- a/hard-interface.h +++ b/hard-interface.h @@ -53,6 +53,11 @@ int batadv_hardif_min_mtu(struct net_device *soft_iface); void batadv_update_min_mtu(struct net_device *soft_iface); void batadv_hardif_free_rcu(struct rcu_head *rcu);
+/** + * batadv_hardif_free_ref - decrement the hard interface refcounter and + * possibly free it + * @hard_iface: the hard interface to free + */ static inline void batadv_hardif_free_ref(struct batadv_hard_iface *hard_iface) { @@ -60,6 +65,18 @@ batadv_hardif_free_ref(struct batadv_hard_iface *hard_iface) call_rcu(&hard_iface->rcu, batadv_hardif_free_rcu); }
+/** + * batadv_hardif_free_ref_now - decrement the hard interface refcounter and + * possibly free it (without rcu callback) + * @hard_iface: the hard interface to free + */ +static inline void +batadv_hardif_free_ref_now(struct batadv_hard_iface *hard_iface) +{ + if (atomic_dec_and_test(&hard_iface->refcount)) + batadv_hardif_free_rcu(&hard_iface->rcu); +} + static inline struct batadv_hard_iface * batadv_primary_if_get_selected(struct batadv_priv *bat_priv) { diff --git a/main.h b/main.h index c5d6eb2..e6c4c1c 100644 --- a/main.h +++ b/main.h @@ -72,6 +72,11 @@
#define BATADV_NULL_IFINDEX 0 /* dummy ifindex used to avoid iface checks */
+/* default interface for multi interface operation. The default interface is + * used for communication which originated locally (i.e. is not forwarded) + * or where special forwarding is not desired/necessary. */ +#define BATADV_IF_DEFAULT ((struct batadv_hard_iface *)NULL) + #define BATADV_NUM_WORDS BITS_TO_LONGS(BATADV_TQ_LOCAL_WINDOW_SIZE)
#define BATADV_LOG_BUF_LEN 8192 /* has to be a power of 2 */ diff --git a/originator.c b/originator.c index 919fdc0..acbd254 100644 --- a/originator.c +++ b/originator.c @@ -150,10 +150,81 @@ err: return -ENOMEM; }
+/* batadv_neigh_ifinfo_free_rcu - free the neigh_ifinfo object + * @rcu: rcu pointer of the neigh_ifinfo object + */ +static void batadv_neigh_ifinfo_free_rcu(struct rcu_head *rcu) +{ + struct batadv_neigh_ifinfo *neigh_ifinfo; + + neigh_ifinfo = container_of(rcu, struct batadv_neigh_ifinfo, rcu); + + if (neigh_ifinfo->if_outgoing != BATADV_IF_DEFAULT) + batadv_hardif_free_ref_now(neigh_ifinfo->if_outgoing); + + kfree(neigh_ifinfo); +} + +/** + * batadv_neigh_ifinfo_free_ref - decrement the refcounter and possibly free + * the neigh_ifinfo (without rcu callback) + * @neigh_ifinfo: the neigh_ifinfo object to release + */ +static void +batadv_neigh_ifinfo_free_ref_now(struct batadv_neigh_ifinfo *neigh_ifinfo) +{ + if (atomic_dec_and_test(&neigh_ifinfo->refcount)) + batadv_neigh_ifinfo_free_rcu(&neigh_ifinfo->rcu); +} + +/** + * batadv_neigh_ifinfo_free_ref - decrement the refcounter and possibly free + * the neigh_ifinfo + * @neigh_ifinfo: the neigh_ifinfo object to release + */ +void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo) +{ + if (atomic_dec_and_test(&neigh_ifinfo->refcount)) + call_rcu(&neigh_ifinfo->rcu, batadv_neigh_ifinfo_free_rcu); +} + +static void batadv_neigh_node_free_rcu(struct rcu_head *rcu) +{ + struct hlist_node *node_tmp; + struct batadv_neigh_node *neigh_node; + struct batadv_neigh_ifinfo *neigh_ifinfo; + + neigh_node = container_of(rcu, struct batadv_neigh_node, rcu); + + hlist_for_each_entry_safe(neigh_ifinfo, node_tmp, + &neigh_node->ifinfo_list, list) { + batadv_neigh_ifinfo_free_ref_now(neigh_ifinfo); + } + + kfree(neigh_node); +} + +/** + * batadv_neigh_node_free_ref_now - decrement the neighbors refcounter + * and possibly free it (without rcu callback) + * neigh_node: neigh neighbor to free + */ +static void +batadv_neigh_node_free_ref_now(struct batadv_neigh_node *neigh_node) +{ + if (atomic_dec_and_test(&neigh_node->refcount)) + batadv_neigh_node_free_rcu(&neigh_node->rcu); +} + +/** + * batadv_neigh_node_free_ref - decrement the neighbors refcounter + * and possibly free it + * neigh_node: neigh neighbor to free + */ void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node) { if (atomic_dec_and_test(&neigh_node->refcount)) - kfree_rcu(neigh_node, rcu); + call_rcu(&neigh_node->rcu, batadv_neigh_node_free_rcu); }
/* increases the refcounter of a found router */ @@ -173,6 +244,84 @@ batadv_orig_node_get_router(struct batadv_orig_node *orig_node) }
/** + * batadv_neigh_ifinfo_get - find the ifinfo from an neigh_node + * @neigh_node: the neigh node to be queried + * @if_outgoing: the interface for which the ifinfo should be acquired + * + * The object is returned with refcounter increased by 1. + * + * Returns the requested neigh_ifinfo or NULL if not found + */ +struct batadv_neigh_ifinfo * +batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh, + struct batadv_hard_iface *if_outgoing) +{ + struct batadv_neigh_ifinfo *neigh_ifinfo = NULL, + *tmp_neigh_ifinfo; + + rcu_read_lock(); + hlist_for_each_entry_rcu(tmp_neigh_ifinfo, &neigh->ifinfo_list, + list) { + if (tmp_neigh_ifinfo->if_outgoing != if_outgoing) + continue; + + if (!atomic_inc_not_zero(&tmp_neigh_ifinfo->refcount)) + continue; + + neigh_ifinfo = tmp_neigh_ifinfo; + break; + } + rcu_read_unlock(); + + return neigh_ifinfo; +} + +/** + * batadv_neigh_ifinfo_new - search and possibly create an neigh_ifinfo object + * @neigh_node: the neigh node to be queried + * @if_outgoing: the interface for which the ifinfo should be acquired + * + * Returns NULL in case of failure or the neigh_ifinfo object for the + * if_outgoing interface otherwise. The object is created and added to the list + * if it does not exist. + * + * The object is returned with refcounter increased by 1. + */ +struct batadv_neigh_ifinfo * +batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh, + struct batadv_hard_iface *if_outgoing) +{ + struct batadv_neigh_ifinfo *neigh_ifinfo; + + spin_lock_bh(&neigh->ifinfo_lock); + + neigh_ifinfo = batadv_neigh_ifinfo_get(neigh, if_outgoing); + if (neigh_ifinfo) + goto out; + + neigh_ifinfo = kzalloc(sizeof(*neigh_ifinfo), GFP_ATOMIC); + if (!neigh_ifinfo) + goto out; + + if (if_outgoing && !atomic_inc_not_zero(&if_outgoing->refcount)) { + kfree(neigh_ifinfo); + neigh_ifinfo = NULL; + goto out; + } + + INIT_HLIST_NODE(&neigh_ifinfo->list); + atomic_set(&neigh_ifinfo->refcount, 2); + neigh_ifinfo->if_outgoing = if_outgoing; + + hlist_add_head_rcu(&neigh_ifinfo->list, &neigh->ifinfo_list); + +out: + spin_unlock_bh(&neigh->ifinfo_lock); + + return neigh_ifinfo; +} + +/** * batadv_neigh_node_new - create and init a new neigh_node object * @hard_iface: the interface where the neighbour is connected to * @neigh_addr: the mac address of the neighbour interface @@ -193,6 +342,8 @@ batadv_neigh_node_new(struct batadv_hard_iface *hard_iface, goto out;
INIT_HLIST_NODE(&neigh_node->list); + INIT_HLIST_HEAD(&neigh_node->ifinfo_list); + spin_lock_init(&neigh_node->ifinfo_lock);
memcpy(neigh_node->addr, neigh_addr, ETH_ALEN); neigh_node->if_incoming = hard_iface; @@ -219,7 +370,7 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu) hlist_for_each_entry_safe(neigh_node, node_tmp, &orig_node->neigh_list, list) { hlist_del_rcu(&neigh_node->list); - batadv_neigh_node_free_ref(neigh_node); + batadv_neigh_node_free_ref_now(neigh_node); }
spin_unlock_bh(&orig_node->neigh_list_lock); @@ -364,20 +515,23 @@ free_orig_node: return NULL; }
+/** + * batadv_purge_orig_neighbors - purges neighbors from originator + * @bat_priv: the bat priv with all the soft interface information + * @orig_node: orig node which is to be checked + * + * Returns true if any neighbor was purged, false otherwise + */ static bool batadv_purge_orig_neighbors(struct batadv_priv *bat_priv, - struct batadv_orig_node *orig_node, - struct batadv_neigh_node **best_neigh) + struct batadv_orig_node *orig_node) { - struct batadv_algo_ops *bao = bat_priv->bat_algo_ops; struct hlist_node *node_tmp; struct batadv_neigh_node *neigh_node; bool neigh_purged = false; unsigned long last_seen; struct batadv_hard_iface *if_incoming;
- *best_neigh = NULL; - spin_lock_bh(&orig_node->neigh_list_lock);
/* for all neighbors towards this originator ... */ @@ -407,13 +561,6 @@ batadv_purge_orig_neighbors(struct batadv_priv *bat_priv,
hlist_del_rcu(&neigh_node->list); batadv_neigh_node_free_ref(neigh_node); - } else { - /* store the best_neighbour if this is the first - * iteration or if a better neighbor has been found - */ - if (!*best_neigh || - bao->bat_neigh_cmp(neigh_node, *best_neigh) > 0) - *best_neigh = neigh_node; } }
@@ -421,6 +568,33 @@ batadv_purge_orig_neighbors(struct batadv_priv *bat_priv, return neigh_purged; }
+/** + * batadv_find_best_neighbor - finds the best neighbor after purging + * @bat_priv: the bat priv with all the soft interface information + * @orig_node: orig node which is to be checked + * @if_outgoing: the interface for which the metric should be compared + * + * Returns the current best neighbor + */ +static struct batadv_neigh_node * +batadv_find_best_neighbor(struct batadv_priv *bat_priv, + struct batadv_orig_node *orig_node, + struct batadv_hard_iface *if_outgoing) +{ + struct batadv_neigh_node *best = NULL, *neigh; + struct batadv_algo_ops *bao = bat_priv->bat_algo_ops; + + rcu_read_lock(); + hlist_for_each_entry_rcu(neigh, &orig_node->neigh_list, list) + if (!best || + (bao->bat_neigh_cmp(neigh, if_outgoing, + best, if_outgoing) <= 0)) + best = neigh; + rcu_read_unlock(); + + return best; +} + static bool batadv_purge_orig_node(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node) { @@ -433,12 +607,13 @@ static bool batadv_purge_orig_node(struct batadv_priv *bat_priv, orig_node->orig, jiffies_to_msecs(orig_node->last_seen)); return true; - } else { - if (batadv_purge_orig_neighbors(bat_priv, orig_node, - &best_neigh_node)) - batadv_update_route(bat_priv, orig_node, - best_neigh_node); } + if (!batadv_purge_orig_neighbors(bat_priv, orig_node)) + return false; + + best_neigh_node = batadv_find_best_neighbor(bat_priv, orig_node, + BATADV_IF_DEFAULT); + batadv_update_route(bat_priv, orig_node, best_neigh_node);
return false; } diff --git a/originator.h b/originator.h index 6f77d80..76a8de6 100644 --- a/originator.h +++ b/originator.h @@ -37,6 +37,13 @@ batadv_neigh_node_new(struct batadv_hard_iface *hard_iface, void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node); struct batadv_neigh_node * batadv_orig_node_get_router(struct batadv_orig_node *orig_node); +struct batadv_neigh_ifinfo * +batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh, + struct batadv_hard_iface *if_outgoing); +struct batadv_neigh_ifinfo * +batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh, + struct batadv_hard_iface *if_outgoing); +void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo); int batadv_orig_seq_print_text(struct seq_file *seq, void *offset); int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, int max_if_num); diff --git a/translation-table.c b/translation-table.c index 4add57d..135c165 100644 --- a/translation-table.c +++ b/translation-table.c @@ -1390,7 +1390,8 @@ batadv_transtable_best_orig(struct batadv_priv *bat_priv, continue;
if (best_router && - bao->bat_neigh_cmp(router, best_router) <= 0) { + bao->bat_neigh_cmp(router, BATADV_IF_DEFAULT, + best_router, BATADV_IF_DEFAULT) <= 0) { batadv_neigh_node_free_ref(router); continue; } diff --git a/types.h b/types.h index 63ddff5..11d448f 100644 --- a/types.h +++ b/types.h @@ -279,47 +279,62 @@ struct batadv_gw_node { };
/** - * struct batadv_neigh_bat_iv - B.A.T.M.A.N. IV specific structure for single - * hop neighbors + * struct batadv_neigh_node - structure for single hops neighbors + * @list: list node for batadv_orig_node::neigh_list + * @orig_node: pointer to corresponding orig_node + * @addr: the MAC address of the neighboring interface + * @ifinfo_list: list for routing metrics per outgoing interface + * @ifinfo_lock: lock protecting private ifinfo members and list + * @if_incoming: pointer to incoming hard interface + * @last_seen: when last packet via this neighbor was received + * @last_ttl: last received ttl from this neigh node + * @rcu: struct used for freeing in an RCU-safe manner + * @bat_iv: B.A.T.M.A.N. IV private structure + */ +struct batadv_neigh_node { + struct hlist_node list; + struct batadv_orig_node *orig_node; + uint8_t addr[ETH_ALEN]; + struct hlist_head ifinfo_list; + spinlock_t ifinfo_lock; /* protects ifinfo_list and its members */ + struct batadv_hard_iface *if_incoming; + unsigned long last_seen; + atomic_t refcount; + struct rcu_head rcu; +}; + +/* struct batadv_neigh_node_bat_iv - neighbor information per outgoing + * interface for BATMAN IV * @tq_recv: ring buffer of received TQ values from this neigh node * @tq_index: ring buffer index * @tq_avg: averaged tq of all tq values in the ring buffer (tq_recv) * @real_bits: bitfield containing the number of OGMs received from this neigh * node (relative to orig_node->last_real_seqno) * @real_packet_count: counted result of real_bits - * @lq_update_lock: lock protecting tq_recv & tq_index */ -struct batadv_neigh_bat_iv { +struct batadv_neigh_ifinfo_bat_iv { uint8_t tq_recv[BATADV_TQ_GLOBAL_WINDOW_SIZE]; uint8_t tq_index; uint8_t tq_avg; DECLARE_BITMAP(real_bits, BATADV_TQ_LOCAL_WINDOW_SIZE); uint8_t real_packet_count; - spinlock_t lq_update_lock; /* protects tq_recv & tq_index */ };
-/** - * struct batadv_neigh_node - structure for single hops neighbors - * @list: list node for batadv_orig_node::neigh_list - * @orig_node: pointer to corresponding orig_node - * @addr: the MAC address of the neighboring interface - * @if_incoming: pointer to incoming hard interface - * @last_seen: when last packet via this neighbor was received +/* struct batadv_neigh_ifinfo - neighbor information per outgoing interface + * @list: list node for batadv_neigh_node::ifinfo_list + * @if_outgoing: pointer to outgoing hard interface + * @bat_iv: B.A.T.M.A.N. IV private structure * @last_ttl: last received ttl from this neigh node * @refcount: number of contexts the object is used - * @rcu: struct used for freeing in an RCU-safe manner - * @bat_iv: B.A.T.M.A.N. IV private structure + * @rcu: struct used for freeing in a RCU-safe manner */ -struct batadv_neigh_node { +struct batadv_neigh_ifinfo { struct hlist_node list; - struct batadv_orig_node *orig_node; - uint8_t addr[ETH_ALEN]; - struct batadv_hard_iface *if_incoming; - unsigned long last_seen; + struct batadv_hard_iface *if_outgoing; + struct batadv_neigh_ifinfo_bat_iv bat_iv; uint8_t last_ttl; atomic_t refcount; struct rcu_head rcu; - struct batadv_neigh_bat_iv bat_iv; };
/** @@ -1001,9 +1016,11 @@ struct batadv_forw_packet { * @bat_primary_iface_set: called when primary interface is selected / changed * @bat_ogm_schedule: prepare a new outgoing OGM for the send queue * @bat_ogm_emit: send scheduled OGM - * @bat_neigh_cmp: compare the metrics of two neighbors - * @bat_neigh_is_equiv_or_better: check if neigh1 is equally good or - * better than neigh2 from the metric prospective + * @bat_neigh_cmp: compare the metrics of two neighbors for their respective + * outgoing interfaces + * @bat_neigh_is_equiv_or_better: check if neigh1 is equally good or better + * than neigh2 for their respective outgoing interface from the metric + * prospective * @bat_orig_print: print the originator table (optional) * @bat_orig_free: free the resources allocated by the routing algorithm for an * orig_node object @@ -1022,9 +1039,14 @@ struct batadv_algo_ops { void (*bat_ogm_schedule)(struct batadv_hard_iface *hard_iface); void (*bat_ogm_emit)(struct batadv_forw_packet *forw_packet); int (*bat_neigh_cmp)(struct batadv_neigh_node *neigh1, - struct batadv_neigh_node *neigh2); - bool (*bat_neigh_is_equiv_or_better)(struct batadv_neigh_node *neigh1, - struct batadv_neigh_node *neigh2); + struct batadv_hard_iface *if_outgoing1, + struct batadv_neigh_node *neigh2, + struct batadv_hard_iface *if_outgoing2); + bool (*bat_neigh_is_equiv_or_better) + (struct batadv_neigh_node *neigh1, + struct batadv_hard_iface *if_outgoing1, + struct batadv_neigh_node *neigh2, + struct batadv_hard_iface *if_outgoing2); /* orig_node handling API */ void (*bat_orig_print)(struct batadv_priv *priv, struct seq_file *seq); void (*bat_orig_free)(struct batadv_orig_node *orig_node);
On Wednesday 30 October 2013 15:01:47 Simon Wunderlich wrote:
@@ -1559,7 +1661,12 @@ static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv, if (!neigh_node) continue;
if (neigh_node->bat_iv.tq_avg == 0)
n_ifinfo = batadv_neigh_ifinfo_get(neigh_node,
BATADV_IF_DEFAULT);
if (!n_ifinfo)
goto next;
if (n_ifinfo->bat_iv.tq_avg == 0) goto next; last_seen_jiffies = jiffies - orig_node->last_seen;
@@ -1569,17 +1676,12 @@ static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv,
seq_printf(seq, "%pM %4i.%03is (%3i) %pM [%10s]:", orig_node->orig, last_seen_secs,
last_seen_msecs, neigh_node->bat_iv.tq_avg,
last_seen_msecs, n_ifinfo->bat_iv.tq_avg, neigh_node->addr, neigh_node->if_incoming->net_dev->name);
hlist_for_each_entry_rcu(neigh_node_tmp,
&orig_node->neigh_list, list) {
seq_printf(seq, " %pM (%3i)",
neigh_node_tmp->addr,
neigh_node_tmp->bat_iv.tq_avg);
}
batadv_iv_ogm_orig_print_neigh(orig_node,
BATADV_IF_DEFAULT, seq); seq_puts(seq, "\n"); batman_count++;
Aren't we missing a free_ref(n_ifinfo) here ?
+/**
- batadv_neigh_node_free_ref - decrement the neighbors refcounter
- and possibly free it
- neigh_node: neigh neighbor to free
- */
void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node) { if (atomic_dec_and_test(&neigh_node->refcount))
kfree_rcu(neigh_node, rcu);
call_rcu(&neigh_node->rcu, batadv_neigh_node_free_rcu);
}
Isn't there some compat code you can remove as well ?
Cheers, Marek
On Wed, Oct 30, 2013 at 03:01:47PM +0100, Simon Wunderlich wrote:
From: Simon Wunderlich simon@open-mesh.com diff --git a/bat_iv_ogm.c b/bat_iv_ogm.c index 6cd9a0f..66ce1a7 100644 --- a/bat_iv_ogm.c +++ b/bat_iv_ogm.c @@ -274,7 +274,13 @@ batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface, if (!neigh_node) goto out;
- spin_lock_init(&neigh_node->bat_iv.lq_update_lock);
- if (!atomic_inc_not_zero(&hard_iface->refcount)) {
kfree(neigh_node);
here seems to be a "neigh_node = NULL" missing
goto out;
}
neigh_node->orig_node = orig_neigh;
neigh_node->if_incoming = hard_iface;
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Creating new neighbor %pM for orig_node %pM on interface %s\n",
@@ -897,15 +903,30 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface) batadv_hardif_free_ref(primary_if); }
+/**
- batadv_iv_ogm_orig_update - use OGM to update corresponding data in an
- originator
- @bat_priv: the bat priv with all the soft interface information
- @orig_node: the orig node who originally emitted the ogm packet
- @ethhdr: Ethernet header of the OGM
- @batadv_ogm_packet: the ogm packet
- @if_incoming: interface where the packet was received
- @if_outgoing: interface for which the retransmission should be considered
- @tt_buff: pointer to the tt buffer
- @dup_status: the duplicate status of this ogm packet.
- */
static void batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, const struct ethhdr *ethhdr, const struct batadv_ogm_packet *batadv_ogm_packet, struct batadv_hard_iface *if_incoming,
struct batadv_hard_iface *if_outgoing, const unsigned char *tt_buff, enum batadv_dup_status dup_status)
{
- struct batadv_neigh_ifinfo *neigh_ifinfo = NULL;
- struct batadv_neigh_ifinfo *router_ifinfo = NULL; struct batadv_neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; struct batadv_neigh_node *router = NULL; struct batadv_orig_node *orig_node_tmp;
@@ -933,12 +954,20 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, if (dup_status != BATADV_NO_DUP) continue;
spin_lock_bh(&tmp_neigh_node->bat_iv.lq_update_lock);
batadv_ring_buffer_set(tmp_neigh_node->bat_iv.tq_recv,
&tmp_neigh_node->bat_iv.tq_index, 0);
tq_avg = batadv_ring_buffer_avg(tmp_neigh_node->bat_iv.tq_recv);
tmp_neigh_node->bat_iv.tq_avg = tq_avg;
spin_unlock_bh(&tmp_neigh_node->bat_iv.lq_update_lock);
/* only update the entry for this outgoing interface */
neigh_ifinfo = batadv_neigh_ifinfo_get(tmp_neigh_node,
if_outgoing);
if (!neigh_ifinfo)
continue;
spin_lock_bh(&tmp_neigh_node->ifinfo_lock);
batadv_ring_buffer_set(neigh_ifinfo->bat_iv.tq_recv,
&neigh_ifinfo->bat_iv.tq_index, 0);
tq_avg = batadv_ring_buffer_avg(neigh_ifinfo->bat_iv.tq_recv);
neigh_ifinfo->bat_iv.tq_avg = tq_avg;
spin_unlock_bh(&tmp_neigh_node->ifinfo_lock);
batadv_neigh_ifinfo_free_ref(neigh_ifinfo);
if we free the neigh_ifinfo here...
}
if (!neigh_node) { @@ -960,20 +989,23 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, "Updating existing last-hop neighbor of originator\n");
rcu_read_unlock();
... and fail somewhere up to here (so if we take one of the two "goto unlocks" above) ...
neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing);
if (!neigh_ifinfo)
goto out;
neigh_node->last_seen = jiffies;
- spin_lock_bh(&neigh_node->bat_iv.lq_update_lock);
- batadv_ring_buffer_set(neigh_node->bat_iv.tq_recv,
&neigh_node->bat_iv.tq_index,
- spin_lock_bh(&neigh_node->ifinfo_lock);
- batadv_ring_buffer_set(neigh_ifinfo->bat_iv.tq_recv,
&neigh_ifinfo->bat_iv.tq_index, batadv_ogm_packet->tq);
- tq_avg = batadv_ring_buffer_avg(neigh_node->bat_iv.tq_recv);
- neigh_node->bat_iv.tq_avg = tq_avg;
- spin_unlock_bh(&neigh_node->bat_iv.lq_update_lock);
tq_avg = batadv_ring_buffer_avg(neigh_ifinfo->bat_iv.tq_recv);
neigh_ifinfo->bat_iv.tq_avg = tq_avg;
spin_unlock_bh(&neigh_node->ifinfo_lock);
if (dup_status == BATADV_NO_DUP) { orig_node->last_ttl = batadv_ogm_packet->header.ttl;
neigh_node->last_ttl = batadv_ogm_packet->header.ttl;
neigh_ifinfo->last_ttl = batadv_ogm_packet->header.ttl;
}
/* if this neighbor already is our next hop there is nothing
@@ -983,14 +1015,17 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, if (router == neigh_node) goto out;
- router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing); /* if this neighbor does not offer a better TQ we won't consider it */
- if (router && (router->bat_iv.tq_avg > neigh_node->bat_iv.tq_avg))
if (router_ifinfo &&
(router_ifinfo->bat_iv.tq_avg > neigh_ifinfo->bat_iv.tq_avg))
goto out;
/* if the TQ is the same and the link not more symmetric we
- won't consider it either
*/
- if (router && (neigh_node->bat_iv.tq_avg == router->bat_iv.tq_avg)) {
- if (router_ifinfo &&
orig_node_tmp = router->orig_node; spin_lock_bh(&orig_node_tmp->bat_iv.ogm_cnt_lock); if_num = router->if_incoming->if_num;(neigh_ifinfo->bat_iv.tq_avg == router_ifinfo->bat_iv.tq_avg)) {
@@ -1007,6 +1042,7 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, goto out; }
- /* TODO: pass if_outgoing later */ batadv_update_route(bat_priv, orig_node, neigh_node); goto out;
@@ -1017,15 +1053,31 @@ out: batadv_neigh_node_free_ref(neigh_node); if (router) batadv_neigh_node_free_ref(router);
- if (neigh_ifinfo)
... then we are going to call this once too often on the same neigh_ifinfo
batadv_neigh_ifinfo_free_ref(neigh_ifinfo);
- if (router_ifinfo)
batadv_neigh_ifinfo_free_ref(router_ifinfo);
}
+/**
- batadv_iv_ogm_calc_tq - calculate tq for current received ogm packet
- @orig_node: the orig node who originally emitted the ogm packet
- @orig_neigh_node: the orig node struct of the neighbor who sent the packet
- @batadv_ogm_packet: the ogm packet
- @if_incoming: interface where the packet was received
- @if_outgoing: interface for which the retransmission should be considered
- Returns 1 if the link can be considered bidirectional, 0 otherwise
- */
static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, struct batadv_orig_node *orig_neigh_node, struct batadv_ogm_packet *batadv_ogm_packet,
struct batadv_hard_iface *if_incoming)
struct batadv_hard_iface *if_incoming,
struct batadv_hard_iface *if_outgoing)
{ struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); struct batadv_neigh_node *neigh_node = NULL, *tmp_neigh_node;
- struct batadv_neigh_ifinfo *neigh_ifinfo; uint8_t total_count; uint8_t orig_eq_count, neigh_rq_count, neigh_rq_inv, tq_own; unsigned int neigh_rq_inv_cube, neigh_rq_max_cube;
@@ -1070,7 +1122,13 @@ static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); if_num = if_incoming->if_num; orig_eq_count = orig_neigh_node->bat_iv.bcast_own_sum[if_num];
- neigh_rq_count = neigh_node->bat_iv.real_packet_count;
neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing);
if (neigh_ifinfo) {
neigh_rq_count = neigh_ifinfo->bat_iv.real_packet_count;
batadv_neigh_ifinfo_free_ref(neigh_ifinfo);
} else {
neigh_rq_count = 0;
} spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock);
/* pay attention to not get a value bigger than 100 % */
@@ -1134,17 +1192,20 @@ out:
- @ethhdr: ethernet header of the packet
- @batadv_ogm_packet: OGM packet to be considered
- @if_incoming: interface on which the OGM packet was received
*/
- @if_outgoing: interface for which the retransmission should be considered
- Returns duplicate status as enum batadv_dup_status
static enum batadv_dup_status batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, const struct batadv_ogm_packet *batadv_ogm_packet,
const struct batadv_hard_iface *if_incoming)
const struct batadv_hard_iface *if_incoming,
struct batadv_hard_iface *if_outgoing)
{ struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); struct batadv_orig_node *orig_node;
- struct batadv_neigh_node *tmp_neigh_node;
- struct batadv_neigh_node *neigh_node;
- struct batadv_neigh_ifinfo *neigh_ifinfo; int is_dup; int32_t seq_diff; int need_update = 0;
@@ -1171,15 +1232,19 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, }
rcu_read_lock();
- hlist_for_each_entry_rcu(tmp_neigh_node,
&orig_node->neigh_list, list) {
neigh_addr = tmp_neigh_node->addr;
is_dup = batadv_test_bit(tmp_neigh_node->bat_iv.real_bits,
- hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) {
neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node,
if_outgoing);
hm, not quite sure, but would a batadv_neigh_ifinfo_get() be sufficient here?
if (!neigh_ifinfo)
continue;
neigh_addr = neigh_node->addr;
is_dup = batadv_test_bit(neigh_ifinfo->bat_iv.real_bits, orig_node->last_real_seqno, seqno);
if (batadv_compare_eth(neigh_addr, ethhdr->h_source) &&
tmp_neigh_node->if_incoming == if_incoming) {
neigh_node->if_incoming == if_incoming) { set_mark = 1; if (is_dup) ret = BATADV_NEIGH_DUP;
@@ -1190,13 +1255,14 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, }
/* if the window moved, set the update flag. */
bitmap = tmp_neigh_node->bat_iv.real_bits;
need_update |= batadv_bit_get_packet(bat_priv, bitmap, seq_diff, set_mark);bitmap = neigh_ifinfo->bat_iv.real_bits;
packet_count = bitmap_weight(tmp_neigh_node->bat_iv.real_bits,
packet_count = bitmap_weight(bitmap, BATADV_TQ_LOCAL_WINDOW_SIZE);
tmp_neigh_node->bat_iv.real_packet_count = packet_count;
neigh_ifinfo->bat_iv.real_packet_count = packet_count;
} rcu_read_unlock();batadv_neigh_ifinfo_free_ref(neigh_ifinfo);
@@ -1223,6 +1289,7 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, struct batadv_orig_node *orig_neigh_node, *orig_node, *orig_node_tmp; struct batadv_neigh_node *router = NULL, *router_router = NULL; struct batadv_neigh_node *orig_neigh_router = NULL;
- struct batadv_neigh_ifinfo *router_ifinfo = NULL; int has_directlink_flag; int is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0; int is_bidirect;
@@ -1355,7 +1422,8 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, return;
dup_status = batadv_iv_ogm_update_seqnos(ethhdr, batadv_ogm_packet,
if_incoming);
if_incoming,
BATADV_IF_DEFAULT);
if (dup_status == BATADV_PROTECTED) { batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
@@ -1374,9 +1442,11 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, if (router) { orig_node_tmp = router->orig_node; router_router = batadv_orig_node_get_router(orig_node_tmp);
router_ifinfo = batadv_neigh_ifinfo_get(router,
}BATADV_IF_DEFAULT);
- if ((router && router->bat_iv.tq_avg != 0) &&
- if ((router && router_ifinfo->bat_iv.tq_avg != 0) && (batadv_compare_eth(router->addr, ethhdr->h_source))) is_from_best_next_hop = true;
@@ -1422,7 +1492,8 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, }
is_bidirect = batadv_iv_ogm_calc_tq(orig_node, orig_neigh_node,
batadv_ogm_packet, if_incoming);
batadv_ogm_packet, if_incoming,
BATADV_IF_DEFAULT);
/* update ranking if it is not a duplicate or has the same
- seqno and similar ttl as the non-duplicate
@@ -1433,7 +1504,8 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, (sameseq && similar_ttl))) batadv_iv_ogm_orig_update(bat_priv, orig_node, ethhdr, batadv_ogm_packet, if_incoming,
tt_buff, dup_status);
BATADV_IF_DEFAULT, tt_buff,
dup_status);
/* is single hop (direct) neighbor */ if (is_single_hop_neigh) {
@@ -1529,6 +1601,35 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb, return NET_RX_SUCCESS; }
+/* batadv_iv_ogm_orig_print_neigh - print neighbors for the originator table
- @orig_node: the orig_node for which the neighbors are printed
- @if_outgoing: outgoing interface for these entries
- @seq: debugfs table seq_file struct
- Must be called while holding a rcu lock.
- */
+static void +batadv_iv_ogm_orig_print_neigh(struct batadv_orig_node *orig_node,
struct batadv_hard_iface *if_outgoing,
struct seq_file *seq)
+{
- struct batadv_neigh_node *neigh_node;
- struct batadv_neigh_ifinfo *n_ifinfo;
- hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) {
n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
if (!n_ifinfo)
continue;
seq_printf(seq, " %pM (%3i)",
neigh_node->addr,
n_ifinfo->bat_iv.tq_avg);
batadv_neigh_ifinfo_free_ref(n_ifinfo);
- }
+}
/**
- batadv_iv_ogm_orig_print - print the originator table
- @bat_priv: the bat priv with all the soft interface information
@@ -1537,10 +1638,11 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb, static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv, struct seq_file *seq) {
- struct batadv_neigh_node *neigh_node, *neigh_node_tmp;
- struct batadv_neigh_node *neigh_node; struct batadv_hashtable *hash = bat_priv->orig_hash; int last_seen_msecs, last_seen_secs; struct batadv_orig_node *orig_node;
- struct batadv_neigh_ifinfo *n_ifinfo; unsigned long last_seen_jiffies; struct hlist_head *head; int batman_count = 0;
@@ -1559,7 +1661,12 @@ static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv, if (!neigh_node) continue;
if (neigh_node->bat_iv.tq_avg == 0)
n_ifinfo = batadv_neigh_ifinfo_get(neigh_node,
BATADV_IF_DEFAULT);
if (!n_ifinfo)
goto next;
if (n_ifinfo->bat_iv.tq_avg == 0) goto next; last_seen_jiffies = jiffies - orig_node->last_seen;
@@ -1569,17 +1676,12 @@ static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv,
seq_printf(seq, "%pM %4i.%03is (%3i) %pM [%10s]:", orig_node->orig, last_seen_secs,
last_seen_msecs, neigh_node->bat_iv.tq_avg,
last_seen_msecs, n_ifinfo->bat_iv.tq_avg, neigh_node->addr, neigh_node->if_incoming->net_dev->name);
hlist_for_each_entry_rcu(neigh_node_tmp,
&orig_node->neigh_list, list) {
seq_printf(seq, " %pM (%3i)",
neigh_node_tmp->addr,
neigh_node_tmp->bat_iv.tq_avg);
}
batadv_iv_ogm_orig_print_neigh(orig_node,
BATADV_IF_DEFAULT, seq); seq_puts(seq, "\n"); batman_count++;
@@ -1596,37 +1698,84 @@ next: /**
- batadv_iv_ogm_neigh_cmp - compare the metrics of two neighbors
- @neigh1: the first neighbor object of the comparison
- @if_outgoing1: outgoing interface for the first neighbor
- @neigh2: the second neighbor object of the comparison
*/
- @if_outgoing2: outgoing interface for the second neighbor
- Returns a value less, equal to or greater than 0 if the metric via neigh1 is
- lower, the same as or higher than the metric via neigh2
static int batadv_iv_ogm_neigh_cmp(struct batadv_neigh_node *neigh1,
struct batadv_neigh_node *neigh2)
struct batadv_hard_iface *if_outgoing1,
struct batadv_neigh_node *neigh2,
struct batadv_hard_iface *if_outgoing2)
{
- struct batadv_neigh_ifinfo *neigh1_ifinfo, *neigh2_ifinfo; uint8_t tq1, tq2;
- int diff;
- tq1 = neigh1->bat_iv.tq_avg;
- tq2 = neigh2->bat_iv.tq_avg;
- neigh1_ifinfo = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
- neigh2_ifinfo = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
- return tq1 - tq2;
- if (!neigh1_ifinfo || !neigh2_ifinfo) {
diff = 0;
goto out;
- }
- tq1 = neigh1_ifinfo->bat_iv.tq_avg;
- tq2 = neigh2_ifinfo->bat_iv.tq_avg;
- diff = tq1 - tq2;
+out:
- if (neigh1_ifinfo)
batadv_neigh_ifinfo_free_ref(neigh1_ifinfo);
- if (neigh2_ifinfo)
batadv_neigh_ifinfo_free_ref(neigh2_ifinfo);
- return diff;
}
/**
- batadv_iv_ogm_neigh_is_eob - check if neigh1 is equally good or better than
- neigh2 from the metric prospective
- @neigh1: the first neighbor object of the comparison
- @if_outgoing: outgoing interface for the first neighbor
- @neigh2: the second neighbor object of the comparison
- Returns true if the metric via neigh1 is equally good or better than the
- metric via neigh2, false otherwise.
- @if_outgoing2: outgoing interface for the second neighbor
- Returns true if the metric via neigh1 is equally good or better than
*/
- the metric via neigh2, false otherwise.
-static bool batadv_iv_ogm_neigh_is_eob(struct batadv_neigh_node *neigh1,
struct batadv_neigh_node *neigh2)
+static bool +batadv_iv_ogm_neigh_is_eob(struct batadv_neigh_node *neigh1,
struct batadv_hard_iface *if_outgoing1,
struct batadv_neigh_node *neigh2,
struct batadv_hard_iface *if_outgoing2)
{
- int diff = batadv_iv_ogm_neigh_cmp(neigh1, neigh2);
- struct batadv_neigh_ifinfo *neigh1_ifinfo, *neigh2_ifinfo;
- uint8_t tq1, tq2;
- bool ret;
- return diff > -BATADV_TQ_SIMILARITY_THRESHOLD;
- neigh1_ifinfo = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
- neigh2_ifinfo = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
- /* we can't say that the metric is better */
- if (!neigh1_ifinfo || !neigh2_ifinfo) {
ret = false;
goto out;
- }
- tq1 = neigh1_ifinfo->bat_iv.tq_avg;
- tq2 = neigh2_ifinfo->bat_iv.tq_avg;
- ret = (tq1 - tq2) > -BATADV_TQ_SIMILARITY_THRESHOLD;
+out:
- if (neigh1_ifinfo)
batadv_neigh_ifinfo_free_ref(neigh1_ifinfo);
- if (neigh2_ifinfo)
batadv_neigh_ifinfo_free_ref(neigh2_ifinfo);
- return ret;
}
static struct batadv_algo_ops batadv_batman_iv __read_mostly = { diff --git a/gateway_client.c b/gateway_client.c index 2449afa..71759d0 100644 --- a/gateway_client.c +++ b/gateway_client.c @@ -114,6 +114,7 @@ static struct batadv_gw_node * batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) { struct batadv_neigh_node *router;
- struct batadv_neigh_ifinfo *router_ifinfo; struct batadv_gw_node *gw_node, *curr_gw = NULL; uint32_t max_gw_factor = 0, tmp_gw_factor = 0; uint32_t gw_divisor;
@@ -134,10 +135,15 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) if (!router) continue;
router_ifinfo = batadv_neigh_ifinfo_get(router,
BATADV_IF_DEFAULT);
if (!router_ifinfo)
goto next;
- if (!atomic_inc_not_zero(&gw_node->refcount)) goto next;
tq_avg = router->bat_iv.tq_avg;
tq_avg = router_ifinfo->bat_iv.tq_avg;
switch (atomic_read(&bat_priv->gw_sel_class)) { case 1: /* fast connection */
@@ -182,6 +188,8 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv)
next: batadv_neigh_node_free_ref(router);
if (router_ifinfo)
} rcu_read_unlock();batadv_neigh_ifinfo_free_ref(router_ifinfo);
@@ -219,6 +227,7 @@ void batadv_gw_election(struct batadv_priv *bat_priv) { struct batadv_gw_node *curr_gw = NULL, *next_gw = NULL; struct batadv_neigh_node *router = NULL;
struct batadv_neigh_ifinfo *router_ifinfo = NULL; char gw_addr[18] = { '\0' };
if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_CLIENT)
@@ -242,6 +251,13 @@ void batadv_gw_election(struct batadv_priv *bat_priv) batadv_gw_deselect(bat_priv); goto out; }
router_ifinfo = batadv_neigh_ifinfo_get(router,
BATADV_IF_DEFAULT);
if (!router_ifinfo) {
batadv_gw_deselect(bat_priv);
goto out;
}
}
if ((curr_gw) && (!next_gw)) {
@@ -256,7 +272,8 @@ void batadv_gw_election(struct batadv_priv *bat_priv) next_gw->bandwidth_down / 10, next_gw->bandwidth_down % 10, next_gw->bandwidth_up / 10,
next_gw->bandwidth_up % 10, router->bat_iv.tq_avg);
next_gw->bandwidth_up % 10,
batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_ADD, gw_addr); } else {router_ifinfo->bat_iv.tq_avg);
@@ -266,7 +283,8 @@ void batadv_gw_election(struct batadv_priv *bat_priv) next_gw->bandwidth_down / 10, next_gw->bandwidth_down % 10, next_gw->bandwidth_up / 10,
next_gw->bandwidth_up % 10, router->bat_iv.tq_avg);
next_gw->bandwidth_up % 10,
batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_CHANGE, gw_addr); }router_ifinfo->bat_iv.tq_avg);
@@ -280,11 +298,15 @@ out: batadv_gw_node_free_ref(next_gw); if (router) batadv_neigh_node_free_ref(router);
- if (router_ifinfo)
batadv_neigh_ifinfo_free_ref(router_ifinfo);
}
void batadv_gw_check_election(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node) {
- struct batadv_neigh_ifinfo *router_orig_tq = NULL;
- struct batadv_neigh_ifinfo *router_gw_tq = NULL; struct batadv_orig_node *curr_gw_orig; struct batadv_neigh_node *router_gw = NULL, *router_orig = NULL; uint8_t gw_tq_avg, orig_tq_avg;
@@ -297,6 +319,11 @@ void batadv_gw_check_election(struct batadv_priv *bat_priv, if (!router_gw) goto deselect;
- router_gw_tq = batadv_neigh_ifinfo_get(router_gw,
BATADV_IF_DEFAULT);
- if (!router_gw_tq)
goto deselect;
- /* this node already is the gateway */ if (curr_gw_orig == orig_node) goto out;
@@ -305,8 +332,13 @@ void batadv_gw_check_election(struct batadv_priv *bat_priv, if (!router_orig) goto out;
- gw_tq_avg = router_gw->bat_iv.tq_avg;
- orig_tq_avg = router_orig->bat_iv.tq_avg;
router_orig_tq = batadv_neigh_ifinfo_get(router_orig,
BATADV_IF_DEFAULT);
if (!router_orig_tq)
goto out;
gw_tq_avg = router_gw_tq->bat_iv.tq_avg;
orig_tq_avg = router_orig_tq->bat_iv.tq_avg;
/* the TQ value has to be better */ if (orig_tq_avg < gw_tq_avg)
@@ -332,6 +364,10 @@ out: batadv_neigh_node_free_ref(router_gw); if (router_orig) batadv_neigh_node_free_ref(router_orig);
if (router_gw_tq)
batadv_neigh_ifinfo_free_ref(router_gw_tq);
if (router_orig_tq)
batadv_neigh_ifinfo_free_ref(router_orig_tq);
return;
} @@ -517,18 +553,23 @@ static int batadv_write_buffer_text(struct batadv_priv *bat_priv, { struct batadv_gw_node *curr_gw; struct batadv_neigh_node *router;
struct batadv_neigh_ifinfo *router_ifinfo; int ret = -1;
router = batadv_orig_node_get_router(gw_node->orig_node); if (!router) goto out;
router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT);
if (!router_ifinfo)
we are missing to call _free_ref() for *router in this case:
goto out;
curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %u.%u/%u.%u MBit\n", (curr_gw == gw_node ? "=>" : " "), gw_node->orig_node->orig,
router->bat_iv.tq_avg, router->addr,
router_ifinfo->bat_iv.tq_avg, router->addr, router->if_incoming->net_dev->name, gw_node->bandwidth_down / 10, gw_node->bandwidth_down % 10,
@@ -538,6 +579,8 @@ static int batadv_write_buffer_text(struct batadv_priv *bat_priv, batadv_neigh_node_free_ref(router); if (curr_gw) batadv_gw_node_free_ref(curr_gw);
- if (router_ifinfo)
batadv_neigh_ifinfo_free_ref(router_ifinfo);
out: return ret; } @@ -741,6 +784,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, struct batadv_neigh_node *neigh_curr = NULL, *neigh_old = NULL; struct batadv_orig_node *orig_dst_node = NULL; struct batadv_gw_node *gw_node = NULL, *curr_gw = NULL;
- struct batadv_neigh_ifinfo *curr_ifinfo, *old_ifinfo; struct ethhdr *ethhdr; bool ret, out_of_range = false; unsigned int header_len = 0;
@@ -792,7 +836,14 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, if (!neigh_curr) goto out;
curr_tq_avg = neigh_curr->bat_iv.tq_avg;
curr_ifinfo = batadv_neigh_ifinfo_get(neigh_curr,
BATADV_IF_DEFAULT);
if (!curr_ifinfo)
goto out;
curr_tq_avg = curr_ifinfo->bat_iv.tq_avg;
batadv_neigh_ifinfo_free_ref(curr_ifinfo);
- break; case BATADV_GW_MODE_OFF: default:
@@ -803,8 +854,13 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, if (!neigh_old) goto out;
- if (curr_tq_avg - neigh_old->bat_iv.tq_avg > BATADV_GW_THRESHOLD)
- old_ifinfo = batadv_neigh_ifinfo_get(neigh_old, BATADV_IF_DEFAULT);
- if (!old_ifinfo)
goto out;
- if ((curr_tq_avg - old_ifinfo->bat_iv.tq_avg) > BATADV_GW_THRESHOLD) out_of_range = true;
- batadv_neigh_ifinfo_free_ref(old_ifinfo);
out: if (orig_dst_node) diff --git a/hard-interface.h b/hard-interface.h index df4c8bd..6b609b0 100644 --- a/hard-interface.h +++ b/hard-interface.h @@ -53,6 +53,11 @@ int batadv_hardif_min_mtu(struct net_device *soft_iface); void batadv_update_min_mtu(struct net_device *soft_iface); void batadv_hardif_free_rcu(struct rcu_head *rcu);
+/**
- batadv_hardif_free_ref - decrement the hard interface refcounter and
- possibly free it
- @hard_iface: the hard interface to free
- */
static inline void batadv_hardif_free_ref(struct batadv_hard_iface *hard_iface) { @@ -60,6 +65,18 @@ batadv_hardif_free_ref(struct batadv_hard_iface *hard_iface) call_rcu(&hard_iface->rcu, batadv_hardif_free_rcu); }
+/**
- batadv_hardif_free_ref_now - decrement the hard interface refcounter and
- possibly free it (without rcu callback)
- @hard_iface: the hard interface to free
- */
+static inline void +batadv_hardif_free_ref_now(struct batadv_hard_iface *hard_iface) +{
- if (atomic_dec_and_test(&hard_iface->refcount))
batadv_hardif_free_rcu(&hard_iface->rcu);
+}
static inline struct batadv_hard_iface * batadv_primary_if_get_selected(struct batadv_priv *bat_priv) { diff --git a/main.h b/main.h index c5d6eb2..e6c4c1c 100644 --- a/main.h +++ b/main.h @@ -72,6 +72,11 @@
#define BATADV_NULL_IFINDEX 0 /* dummy ifindex used to avoid iface checks */
+/* default interface for multi interface operation. The default interface is
- used for communication which originated locally (i.e. is not forwarded)
- or where special forwarding is not desired/necessary. */
+#define BATADV_IF_DEFAULT ((struct batadv_hard_iface *)NULL)
#define BATADV_NUM_WORDS BITS_TO_LONGS(BATADV_TQ_LOCAL_WINDOW_SIZE)
#define BATADV_LOG_BUF_LEN 8192 /* has to be a power of 2 */ diff --git a/originator.c b/originator.c index 919fdc0..acbd254 100644 --- a/originator.c +++ b/originator.c @@ -150,10 +150,81 @@ err: return -ENOMEM; }
+/* batadv_neigh_ifinfo_free_rcu - free the neigh_ifinfo object
- @rcu: rcu pointer of the neigh_ifinfo object
- */
+static void batadv_neigh_ifinfo_free_rcu(struct rcu_head *rcu) +{
- struct batadv_neigh_ifinfo *neigh_ifinfo;
- neigh_ifinfo = container_of(rcu, struct batadv_neigh_ifinfo, rcu);
- if (neigh_ifinfo->if_outgoing != BATADV_IF_DEFAULT)
batadv_hardif_free_ref_now(neigh_ifinfo->if_outgoing);
- kfree(neigh_ifinfo);
+}
+/**
- batadv_neigh_ifinfo_free_ref - decrement the refcounter and possibly free
- the neigh_ifinfo (without rcu callback)
- @neigh_ifinfo: the neigh_ifinfo object to release
- */
+static void +batadv_neigh_ifinfo_free_ref_now(struct batadv_neigh_ifinfo *neigh_ifinfo) +{
- if (atomic_dec_and_test(&neigh_ifinfo->refcount))
batadv_neigh_ifinfo_free_rcu(&neigh_ifinfo->rcu);
+}
+/**
- batadv_neigh_ifinfo_free_ref - decrement the refcounter and possibly free
- the neigh_ifinfo
- @neigh_ifinfo: the neigh_ifinfo object to release
- */
+void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo) +{
- if (atomic_dec_and_test(&neigh_ifinfo->refcount))
call_rcu(&neigh_ifinfo->rcu, batadv_neigh_ifinfo_free_rcu);
+}
+static void batadv_neigh_node_free_rcu(struct rcu_head *rcu) +{
- struct hlist_node *node_tmp;
- struct batadv_neigh_node *neigh_node;
- struct batadv_neigh_ifinfo *neigh_ifinfo;
- neigh_node = container_of(rcu, struct batadv_neigh_node, rcu);
- hlist_for_each_entry_safe(neigh_ifinfo, node_tmp,
&neigh_node->ifinfo_list, list) {
batadv_neigh_ifinfo_free_ref_now(neigh_ifinfo);
- }
two things are missing here: orig_node and if_incoming refcounters need to be decreased
- kfree(neigh_node);
+}
+/**
- batadv_neigh_node_free_ref_now - decrement the neighbors refcounter
- and possibly free it (without rcu callback)
- neigh_node: neigh neighbor to free
- */
+static void +batadv_neigh_node_free_ref_now(struct batadv_neigh_node *neigh_node) +{
- if (atomic_dec_and_test(&neigh_node->refcount))
batadv_neigh_node_free_rcu(&neigh_node->rcu);
+}
+/**
- batadv_neigh_node_free_ref - decrement the neighbors refcounter
- and possibly free it
- neigh_node: neigh neighbor to free
- */
void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node) { if (atomic_dec_and_test(&neigh_node->refcount))
kfree_rcu(neigh_node, rcu);
call_rcu(&neigh_node->rcu, batadv_neigh_node_free_rcu);
}
/* increases the refcounter of a found router */ @@ -173,6 +244,84 @@ batadv_orig_node_get_router(struct batadv_orig_node *orig_node) }
/**
- batadv_neigh_ifinfo_get - find the ifinfo from an neigh_node
- @neigh_node: the neigh node to be queried
- @if_outgoing: the interface for which the ifinfo should be acquired
- The object is returned with refcounter increased by 1.
- Returns the requested neigh_ifinfo or NULL if not found
- */
+struct batadv_neigh_ifinfo * +batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh,
struct batadv_hard_iface *if_outgoing)
+{
- struct batadv_neigh_ifinfo *neigh_ifinfo = NULL,
*tmp_neigh_ifinfo;
- rcu_read_lock();
- hlist_for_each_entry_rcu(tmp_neigh_ifinfo, &neigh->ifinfo_list,
list) {
if (tmp_neigh_ifinfo->if_outgoing != if_outgoing)
continue;
if (!atomic_inc_not_zero(&tmp_neigh_ifinfo->refcount))
continue;
neigh_ifinfo = tmp_neigh_ifinfo;
break;
- }
- rcu_read_unlock();
- return neigh_ifinfo;
+}
+/**
- batadv_neigh_ifinfo_new - search and possibly create an neigh_ifinfo object
- @neigh_node: the neigh node to be queried
- @if_outgoing: the interface for which the ifinfo should be acquired
- Returns NULL in case of failure or the neigh_ifinfo object for the
- if_outgoing interface otherwise. The object is created and added to the list
- if it does not exist.
- The object is returned with refcounter increased by 1.
- */
+struct batadv_neigh_ifinfo * +batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh,
struct batadv_hard_iface *if_outgoing)
+{
- struct batadv_neigh_ifinfo *neigh_ifinfo;
- spin_lock_bh(&neigh->ifinfo_lock);
- neigh_ifinfo = batadv_neigh_ifinfo_get(neigh, if_outgoing);
- if (neigh_ifinfo)
goto out;
- neigh_ifinfo = kzalloc(sizeof(*neigh_ifinfo), GFP_ATOMIC);
- if (!neigh_ifinfo)
goto out;
- if (if_outgoing && !atomic_inc_not_zero(&if_outgoing->refcount)) {
kfree(neigh_ifinfo);
neigh_ifinfo = NULL;
goto out;
- }
- INIT_HLIST_NODE(&neigh_ifinfo->list);
- atomic_set(&neigh_ifinfo->refcount, 2);
- neigh_ifinfo->if_outgoing = if_outgoing;
- hlist_add_head_rcu(&neigh_ifinfo->list, &neigh->ifinfo_list);
+out:
- spin_unlock_bh(&neigh->ifinfo_lock);
- return neigh_ifinfo;
+}
+/**
- batadv_neigh_node_new - create and init a new neigh_node object
- @hard_iface: the interface where the neighbour is connected to
- @neigh_addr: the mac address of the neighbour interface
@@ -193,6 +342,8 @@ batadv_neigh_node_new(struct batadv_hard_iface *hard_iface, goto out;
INIT_HLIST_NODE(&neigh_node->list);
INIT_HLIST_HEAD(&neigh_node->ifinfo_list);
spin_lock_init(&neigh_node->ifinfo_lock);
memcpy(neigh_node->addr, neigh_addr, ETH_ALEN); neigh_node->if_incoming = hard_iface;
@@ -219,7 +370,7 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu) hlist_for_each_entry_safe(neigh_node, node_tmp, &orig_node->neigh_list, list) { hlist_del_rcu(&neigh_node->list);
batadv_neigh_node_free_ref(neigh_node);
batadv_neigh_node_free_ref_now(neigh_node);
}
spin_unlock_bh(&orig_node->neigh_list_lock);
@@ -364,20 +515,23 @@ free_orig_node: return NULL; }
+/**
- batadv_purge_orig_neighbors - purges neighbors from originator
- @bat_priv: the bat priv with all the soft interface information
- @orig_node: orig node which is to be checked
- Returns true if any neighbor was purged, false otherwise
- */
static bool batadv_purge_orig_neighbors(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
struct batadv_neigh_node **best_neigh)
struct batadv_orig_node *orig_node)
{
struct batadv_algo_ops *bao = bat_priv->bat_algo_ops; struct hlist_node *node_tmp; struct batadv_neigh_node *neigh_node; bool neigh_purged = false; unsigned long last_seen; struct batadv_hard_iface *if_incoming;
*best_neigh = NULL;
spin_lock_bh(&orig_node->neigh_list_lock);
/* for all neighbors towards this originator ... */
@@ -407,13 +561,6 @@ batadv_purge_orig_neighbors(struct batadv_priv *bat_priv,
hlist_del_rcu(&neigh_node->list); batadv_neigh_node_free_ref(neigh_node);
} else {
/* store the best_neighbour if this is the first
* iteration or if a better neighbor has been found
*/
if (!*best_neigh ||
bao->bat_neigh_cmp(neigh_node, *best_neigh) > 0)
} }*best_neigh = neigh_node;
@@ -421,6 +568,33 @@ batadv_purge_orig_neighbors(struct batadv_priv *bat_priv, return neigh_purged; }
+/**
- batadv_find_best_neighbor - finds the best neighbor after purging
- @bat_priv: the bat priv with all the soft interface information
- @orig_node: orig node which is to be checked
- @if_outgoing: the interface for which the metric should be compared
- Returns the current best neighbor
- */
+static struct batadv_neigh_node * +batadv_find_best_neighbor(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
struct batadv_hard_iface *if_outgoing)
+{
- struct batadv_neigh_node *best = NULL, *neigh;
- struct batadv_algo_ops *bao = bat_priv->bat_algo_ops;
- rcu_read_lock();
- hlist_for_each_entry_rcu(neigh, &orig_node->neigh_list, list)
if (!best ||
(bao->bat_neigh_cmp(neigh, if_outgoing,
best, if_outgoing) <= 0))
best = neigh;
why not simply using a "break" within the if-case here instead of the "!best" check and continuing to iterate over the list?
- rcu_read_unlock();
- return best;
+}
Cheers, Linus
Hey Linus,
Thanks for the comments! I applied your proposed changes/fixes and will include them in the next patchset, a few comments below:
@@ -1171,15 +1232,19 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
}
rcu_read_lock();
- hlist_for_each_entry_rcu(tmp_neigh_node,
&orig_node->neigh_list, list) {
neigh_addr = tmp_neigh_node->addr;
is_dup = batadv_test_bit(tmp_neigh_node->bat_iv.real_bits,
- hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) {
neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node,
if_outgoing);
hm, not quite sure, but would a batadv_neigh_ifinfo_get() be sufficient here?
I don't think so. batadv_iv_ogm_update_seqnos() is called before batadv_iv_ogm_orig_update() which is the other function to call _new(). We need batadv_iv_ogm_update_seqnos() to call _new to create the ifinfo and put the first mark in the bitfield.
+static void batadv_neigh_node_free_rcu(struct rcu_head *rcu) +{
- struct hlist_node *node_tmp;
- struct batadv_neigh_node *neigh_node;
- struct batadv_neigh_ifinfo *neigh_ifinfo;
- neigh_node = container_of(rcu, struct batadv_neigh_node, rcu);
- hlist_for_each_entry_safe(neigh_ifinfo, node_tmp,
&neigh_node->ifinfo_list, list) {
batadv_neigh_ifinfo_free_ref_now(neigh_ifinfo);
- }
two things are missing here: orig_node and if_incoming refcounters need to be decreased
This appears to be broken in the current code already: * batadv_iv_ogm_neigh_new() calls batadv_neigh_node_new() and increases the if_incoming refcount (shouldn't be that in batadv_neigh_node_new() instead?) * orig_node does not get its refcounter increased in both functions * both functions set hard_iface and orig_node within the neigh_node struct (that seems to be redundant) * the current code does not free_ref neigh->if_incoming
As we have a cyclic dependency here (neigh_node -> orig_node and vice versa), I'm not sure if we add more problems by adding refcounting to the orig_node here (when cleaning up, that is).
I'll therefore add the free_ref for if_incoming and keep the orig_node refcounting as it is.
why not simply using a "break" within the if-case here instead of the "!best" check and continuing to iterate over the list?
because we could have found a better neighbor then the previous "best", but not yet the "best" of the whole list. We need to check the whole list to find the best.
Thanks, Simon
Various places with broken kenel doc and one more bug, I think.
Cheers, Linus
On Wed, Oct 30, 2013 at 03:01:47PM +0100, Simon Wunderlich wrote:
From: Simon Wunderlich simon@open-mesh.com
For the network wide multi interface optimization it is required to save metrics per outgoing interface in one neighbor. Therefore a new type is introduced to keep interface-specific information. This also requires some changes in access and list management.
The compare and equiv_or_better API calls are changed to take the outgoing interface into consideration.
Signed-off-by: Simon Wunderlich simon@open-mesh.com
Changes to PATCH:
- change neigh_ifinfo locking from implicit rcu style to refcount locking
- rename batadv_neigh_node_get_ifinfo to batadv_neigh_ifinfo_get to comply to new naming scheme
- split into batadv_neigh_ifinfo_new() and batadv_neigh_ifinfo_get() functions
- rename batadv_neigh_node_ifinfo* to batadv_neigh_ifinfo* - name is still long enough
- added BATADV_IF_DEFAULT to ease review
- fix batadv_gw_check_election goto bug
Changes to RFCv2:
- change bat_neigh_cmp and equiv_or_better to use two neighbor and if_outgoing as parameter
- keep bat_neigh_is_equiv_or_better name (no _ifinfo_)
- various style and documentation fixes
Changes to RFC:
- rebase on latest master
- change compare API to consider outgoing interface
- change EOB API to use ifinfo - this will be required to compare routers for different ougoing interfaces in the bonding patch
- fix missing spin_unlock_bh
bat_iv_ogm.c | 255 ++++++++++++++++++++++++++++++++++++++++----------- gateway_client.c | 72 +++++++++++++-- hard-interface.h | 17 ++++ main.h | 5 + originator.c | 213 ++++++++++++++++++++++++++++++++++++++---- originator.h | 7 ++ translation-table.c | 3 +- types.h | 74 +++++++++------ 8 files changed, 539 insertions(+), 107 deletions(-)
diff --git a/bat_iv_ogm.c b/bat_iv_ogm.c index 6cd9a0f..66ce1a7 100644 --- a/bat_iv_ogm.c +++ b/bat_iv_ogm.c @@ -274,7 +274,13 @@ batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface, if (!neigh_node) goto out;
- spin_lock_init(&neigh_node->bat_iv.lq_update_lock);
if (!atomic_inc_not_zero(&hard_iface->refcount)) {
kfree(neigh_node);
goto out;
}
neigh_node->orig_node = orig_neigh;
neigh_node->if_incoming = hard_iface;
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Creating new neighbor %pM for orig_node %pM on interface %s\n",
@@ -897,15 +903,30 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface) batadv_hardif_free_ref(primary_if); }
+/**
- batadv_iv_ogm_orig_update - use OGM to update corresponding data in an
- originator
- @bat_priv: the bat priv with all the soft interface information
- @orig_node: the orig node who originally emitted the ogm packet
- @ethhdr: Ethernet header of the OGM
- @batadv_ogm_packet: the ogm packet
- @if_incoming: interface where the packet was received
- @if_outgoing: interface for which the retransmission should be considered
- @tt_buff: pointer to the tt buffer
- @dup_status: the duplicate status of this ogm packet.
- */
static void batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, const struct ethhdr *ethhdr, const struct batadv_ogm_packet *batadv_ogm_packet, struct batadv_hard_iface *if_incoming,
struct batadv_hard_iface *if_outgoing, const unsigned char *tt_buff, enum batadv_dup_status dup_status)
{
- struct batadv_neigh_ifinfo *neigh_ifinfo = NULL;
- struct batadv_neigh_ifinfo *router_ifinfo = NULL; struct batadv_neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; struct batadv_neigh_node *router = NULL; struct batadv_orig_node *orig_node_tmp;
@@ -933,12 +954,20 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, if (dup_status != BATADV_NO_DUP) continue;
spin_lock_bh(&tmp_neigh_node->bat_iv.lq_update_lock);
batadv_ring_buffer_set(tmp_neigh_node->bat_iv.tq_recv,
&tmp_neigh_node->bat_iv.tq_index, 0);
tq_avg = batadv_ring_buffer_avg(tmp_neigh_node->bat_iv.tq_recv);
tmp_neigh_node->bat_iv.tq_avg = tq_avg;
spin_unlock_bh(&tmp_neigh_node->bat_iv.lq_update_lock);
/* only update the entry for this outgoing interface */
neigh_ifinfo = batadv_neigh_ifinfo_get(tmp_neigh_node,
if_outgoing);
if (!neigh_ifinfo)
continue;
spin_lock_bh(&tmp_neigh_node->ifinfo_lock);
batadv_ring_buffer_set(neigh_ifinfo->bat_iv.tq_recv,
&neigh_ifinfo->bat_iv.tq_index, 0);
tq_avg = batadv_ring_buffer_avg(neigh_ifinfo->bat_iv.tq_recv);
neigh_ifinfo->bat_iv.tq_avg = tq_avg;
spin_unlock_bh(&tmp_neigh_node->ifinfo_lock);
batadv_neigh_ifinfo_free_ref(neigh_ifinfo);
}
if (!neigh_node) {
@@ -960,20 +989,23 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, "Updating existing last-hop neighbor of originator\n");
rcu_read_unlock();
neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing);
if (!neigh_ifinfo)
goto out;
neigh_node->last_seen = jiffies;
- spin_lock_bh(&neigh_node->bat_iv.lq_update_lock);
- batadv_ring_buffer_set(neigh_node->bat_iv.tq_recv,
&neigh_node->bat_iv.tq_index,
- spin_lock_bh(&neigh_node->ifinfo_lock);
- batadv_ring_buffer_set(neigh_ifinfo->bat_iv.tq_recv,
&neigh_ifinfo->bat_iv.tq_index, batadv_ogm_packet->tq);
- tq_avg = batadv_ring_buffer_avg(neigh_node->bat_iv.tq_recv);
- neigh_node->bat_iv.tq_avg = tq_avg;
- spin_unlock_bh(&neigh_node->bat_iv.lq_update_lock);
tq_avg = batadv_ring_buffer_avg(neigh_ifinfo->bat_iv.tq_recv);
neigh_ifinfo->bat_iv.tq_avg = tq_avg;
spin_unlock_bh(&neigh_node->ifinfo_lock);
if (dup_status == BATADV_NO_DUP) { orig_node->last_ttl = batadv_ogm_packet->header.ttl;
neigh_node->last_ttl = batadv_ogm_packet->header.ttl;
neigh_ifinfo->last_ttl = batadv_ogm_packet->header.ttl;
}
/* if this neighbor already is our next hop there is nothing
@@ -983,14 +1015,17 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, if (router == neigh_node) goto out;
- router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing); /* if this neighbor does not offer a better TQ we won't consider it */
- if (router && (router->bat_iv.tq_avg > neigh_node->bat_iv.tq_avg))
if (router_ifinfo &&
(router_ifinfo->bat_iv.tq_avg > neigh_ifinfo->bat_iv.tq_avg))
goto out;
/* if the TQ is the same and the link not more symmetric we
- won't consider it either
*/
- if (router && (neigh_node->bat_iv.tq_avg == router->bat_iv.tq_avg)) {
- if (router_ifinfo &&
orig_node_tmp = router->orig_node; spin_lock_bh(&orig_node_tmp->bat_iv.ogm_cnt_lock); if_num = router->if_incoming->if_num;(neigh_ifinfo->bat_iv.tq_avg == router_ifinfo->bat_iv.tq_avg)) {
@@ -1007,6 +1042,7 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, goto out; }
- /* TODO: pass if_outgoing later */ batadv_update_route(bat_priv, orig_node, neigh_node); goto out;
@@ -1017,15 +1053,31 @@ out: batadv_neigh_node_free_ref(neigh_node); if (router) batadv_neigh_node_free_ref(router);
- if (neigh_ifinfo)
batadv_neigh_ifinfo_free_ref(neigh_ifinfo);
- if (router_ifinfo)
batadv_neigh_ifinfo_free_ref(router_ifinfo);
}
+/**
- batadv_iv_ogm_calc_tq - calculate tq for current received ogm packet
- @orig_node: the orig node who originally emitted the ogm packet
- @orig_neigh_node: the orig node struct of the neighbor who sent the packet
- @batadv_ogm_packet: the ogm packet
- @if_incoming: interface where the packet was received
- @if_outgoing: interface for which the retransmission should be considered
- Returns 1 if the link can be considered bidirectional, 0 otherwise
- */
static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, struct batadv_orig_node *orig_neigh_node, struct batadv_ogm_packet *batadv_ogm_packet,
struct batadv_hard_iface *if_incoming)
struct batadv_hard_iface *if_incoming,
struct batadv_hard_iface *if_outgoing)
{ struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); struct batadv_neigh_node *neigh_node = NULL, *tmp_neigh_node;
- struct batadv_neigh_ifinfo *neigh_ifinfo; uint8_t total_count; uint8_t orig_eq_count, neigh_rq_count, neigh_rq_inv, tq_own; unsigned int neigh_rq_inv_cube, neigh_rq_max_cube;
@@ -1070,7 +1122,13 @@ static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); if_num = if_incoming->if_num; orig_eq_count = orig_neigh_node->bat_iv.bcast_own_sum[if_num];
- neigh_rq_count = neigh_node->bat_iv.real_packet_count;
neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing);
if (neigh_ifinfo) {
neigh_rq_count = neigh_ifinfo->bat_iv.real_packet_count;
batadv_neigh_ifinfo_free_ref(neigh_ifinfo);
} else {
neigh_rq_count = 0;
} spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock);
/* pay attention to not get a value bigger than 100 % */
@@ -1134,17 +1192,20 @@ out:
- @ethhdr: ethernet header of the packet
- @batadv_ogm_packet: OGM packet to be considered
- @if_incoming: interface on which the OGM packet was received
*/
- @if_outgoing: interface for which the retransmission should be considered
- Returns duplicate status as enum batadv_dup_status
static enum batadv_dup_status batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, const struct batadv_ogm_packet *batadv_ogm_packet,
const struct batadv_hard_iface *if_incoming)
const struct batadv_hard_iface *if_incoming,
struct batadv_hard_iface *if_outgoing)
{ struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); struct batadv_orig_node *orig_node;
- struct batadv_neigh_node *tmp_neigh_node;
- struct batadv_neigh_node *neigh_node;
- struct batadv_neigh_ifinfo *neigh_ifinfo; int is_dup; int32_t seq_diff; int need_update = 0;
@@ -1171,15 +1232,19 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, }
rcu_read_lock();
- hlist_for_each_entry_rcu(tmp_neigh_node,
&orig_node->neigh_list, list) {
neigh_addr = tmp_neigh_node->addr;
is_dup = batadv_test_bit(tmp_neigh_node->bat_iv.real_bits,
hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) {
neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node,
if_outgoing);
if (!neigh_ifinfo)
continue;
neigh_addr = neigh_node->addr;
is_dup = batadv_test_bit(neigh_ifinfo->bat_iv.real_bits, orig_node->last_real_seqno, seqno);
if (batadv_compare_eth(neigh_addr, ethhdr->h_source) &&
tmp_neigh_node->if_incoming == if_incoming) {
neigh_node->if_incoming == if_incoming) { set_mark = 1; if (is_dup) ret = BATADV_NEIGH_DUP;
@@ -1190,13 +1255,14 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, }
/* if the window moved, set the update flag. */
bitmap = tmp_neigh_node->bat_iv.real_bits;
need_update |= batadv_bit_get_packet(bat_priv, bitmap, seq_diff, set_mark);bitmap = neigh_ifinfo->bat_iv.real_bits;
packet_count = bitmap_weight(tmp_neigh_node->bat_iv.real_bits,
packet_count = bitmap_weight(bitmap, BATADV_TQ_LOCAL_WINDOW_SIZE);
tmp_neigh_node->bat_iv.real_packet_count = packet_count;
neigh_ifinfo->bat_iv.real_packet_count = packet_count;
} rcu_read_unlock();batadv_neigh_ifinfo_free_ref(neigh_ifinfo);
@@ -1223,6 +1289,7 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, struct batadv_orig_node *orig_neigh_node, *orig_node, *orig_node_tmp; struct batadv_neigh_node *router = NULL, *router_router = NULL; struct batadv_neigh_node *orig_neigh_router = NULL;
- struct batadv_neigh_ifinfo *router_ifinfo = NULL; int has_directlink_flag; int is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0; int is_bidirect;
@@ -1355,7 +1422,8 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, return;
dup_status = batadv_iv_ogm_update_seqnos(ethhdr, batadv_ogm_packet,
if_incoming);
if_incoming,
BATADV_IF_DEFAULT);
if (dup_status == BATADV_PROTECTED) { batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
@@ -1374,9 +1442,11 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, if (router) { orig_node_tmp = router->orig_node; router_router = batadv_orig_node_get_router(orig_node_tmp);
router_ifinfo = batadv_neigh_ifinfo_get(router,
}BATADV_IF_DEFAULT);
- if ((router && router->bat_iv.tq_avg != 0) &&
- if ((router && router_ifinfo->bat_iv.tq_avg != 0) && (batadv_compare_eth(router->addr, ethhdr->h_source))) is_from_best_next_hop = true;
@@ -1422,7 +1492,8 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, }
is_bidirect = batadv_iv_ogm_calc_tq(orig_node, orig_neigh_node,
batadv_ogm_packet, if_incoming);
batadv_ogm_packet, if_incoming,
BATADV_IF_DEFAULT);
/* update ranking if it is not a duplicate or has the same
- seqno and similar ttl as the non-duplicate
@@ -1433,7 +1504,8 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, (sameseq && similar_ttl))) batadv_iv_ogm_orig_update(bat_priv, orig_node, ethhdr, batadv_ogm_packet, if_incoming,
tt_buff, dup_status);
BATADV_IF_DEFAULT, tt_buff,
dup_status);
/* is single hop (direct) neighbor */ if (is_single_hop_neigh) {
@@ -1529,6 +1601,35 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb, return NET_RX_SUCCESS; }
+/* batadv_iv_ogm_orig_print_neigh - print neighbors for the originator table
- @orig_node: the orig_node for which the neighbors are printed
- @if_outgoing: outgoing interface for these entries
- @seq: debugfs table seq_file struct
- Must be called while holding a rcu lock.
- */
Broken kernel doc
+static void +batadv_iv_ogm_orig_print_neigh(struct batadv_orig_node *orig_node,
struct batadv_hard_iface *if_outgoing,
struct seq_file *seq)
+{
- struct batadv_neigh_node *neigh_node;
- struct batadv_neigh_ifinfo *n_ifinfo;
- hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) {
n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
if (!n_ifinfo)
continue;
seq_printf(seq, " %pM (%3i)",
neigh_node->addr,
n_ifinfo->bat_iv.tq_avg);
batadv_neigh_ifinfo_free_ref(n_ifinfo);
- }
+}
/**
- batadv_iv_ogm_orig_print - print the originator table
- @bat_priv: the bat priv with all the soft interface information
@@ -1537,10 +1638,11 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb, static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv, struct seq_file *seq) {
- struct batadv_neigh_node *neigh_node, *neigh_node_tmp;
- struct batadv_neigh_node *neigh_node; struct batadv_hashtable *hash = bat_priv->orig_hash; int last_seen_msecs, last_seen_secs; struct batadv_orig_node *orig_node;
- struct batadv_neigh_ifinfo *n_ifinfo; unsigned long last_seen_jiffies; struct hlist_head *head; int batman_count = 0;
@@ -1559,7 +1661,12 @@ static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv, if (!neigh_node) continue;
if (neigh_node->bat_iv.tq_avg == 0)
n_ifinfo = batadv_neigh_ifinfo_get(neigh_node,
BATADV_IF_DEFAULT);
if (!n_ifinfo)
goto next;
if (n_ifinfo->bat_iv.tq_avg == 0) goto next; last_seen_jiffies = jiffies - orig_node->last_seen;
@@ -1569,17 +1676,12 @@ static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv,
seq_printf(seq, "%pM %4i.%03is (%3i) %pM [%10s]:", orig_node->orig, last_seen_secs,
last_seen_msecs, neigh_node->bat_iv.tq_avg,
last_seen_msecs, n_ifinfo->bat_iv.tq_avg, neigh_node->addr, neigh_node->if_incoming->net_dev->name);
hlist_for_each_entry_rcu(neigh_node_tmp,
&orig_node->neigh_list, list) {
seq_printf(seq, " %pM (%3i)",
neigh_node_tmp->addr,
neigh_node_tmp->bat_iv.tq_avg);
}
batadv_iv_ogm_orig_print_neigh(orig_node,
BATADV_IF_DEFAULT, seq); seq_puts(seq, "\n"); batman_count++;
@@ -1596,37 +1698,84 @@ next: /**
- batadv_iv_ogm_neigh_cmp - compare the metrics of two neighbors
- @neigh1: the first neighbor object of the comparison
- @if_outgoing1: outgoing interface for the first neighbor
- @neigh2: the second neighbor object of the comparison
*/
- @if_outgoing2: outgoing interface for the second neighbor
- Returns a value less, equal to or greater than 0 if the metric via neigh1 is
- lower, the same as or higher than the metric via neigh2
static int batadv_iv_ogm_neigh_cmp(struct batadv_neigh_node *neigh1,
struct batadv_neigh_node *neigh2)
struct batadv_hard_iface *if_outgoing1,
struct batadv_neigh_node *neigh2,
struct batadv_hard_iface *if_outgoing2)
{
- struct batadv_neigh_ifinfo *neigh1_ifinfo, *neigh2_ifinfo; uint8_t tq1, tq2;
- int diff;
- tq1 = neigh1->bat_iv.tq_avg;
- tq2 = neigh2->bat_iv.tq_avg;
- neigh1_ifinfo = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
- neigh2_ifinfo = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
- return tq1 - tq2;
- if (!neigh1_ifinfo || !neigh2_ifinfo) {
diff = 0;
goto out;
- }
- tq1 = neigh1_ifinfo->bat_iv.tq_avg;
- tq2 = neigh2_ifinfo->bat_iv.tq_avg;
- diff = tq1 - tq2;
+out:
- if (neigh1_ifinfo)
batadv_neigh_ifinfo_free_ref(neigh1_ifinfo);
- if (neigh2_ifinfo)
batadv_neigh_ifinfo_free_ref(neigh2_ifinfo);
- return diff;
}
/**
- batadv_iv_ogm_neigh_is_eob - check if neigh1 is equally good or better than
- neigh2 from the metric prospective
- @neigh1: the first neighbor object of the comparison
- @if_outgoing: outgoing interface for the first neighbor
- @neigh2: the second neighbor object of the comparison
- Returns true if the metric via neigh1 is equally good or better than the
- metric via neigh2, false otherwise.
- @if_outgoing2: outgoing interface for the second neighbor
- Returns true if the metric via neigh1 is equally good or better than
*/
- the metric via neigh2, false otherwise.
-static bool batadv_iv_ogm_neigh_is_eob(struct batadv_neigh_node *neigh1,
struct batadv_neigh_node *neigh2)
+static bool +batadv_iv_ogm_neigh_is_eob(struct batadv_neigh_node *neigh1,
struct batadv_hard_iface *if_outgoing1,
struct batadv_neigh_node *neigh2,
struct batadv_hard_iface *if_outgoing2)
{
- int diff = batadv_iv_ogm_neigh_cmp(neigh1, neigh2);
- struct batadv_neigh_ifinfo *neigh1_ifinfo, *neigh2_ifinfo;
- uint8_t tq1, tq2;
- bool ret;
- return diff > -BATADV_TQ_SIMILARITY_THRESHOLD;
- neigh1_ifinfo = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
- neigh2_ifinfo = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
- /* we can't say that the metric is better */
- if (!neigh1_ifinfo || !neigh2_ifinfo) {
ret = false;
goto out;
- }
- tq1 = neigh1_ifinfo->bat_iv.tq_avg;
- tq2 = neigh2_ifinfo->bat_iv.tq_avg;
- ret = (tq1 - tq2) > -BATADV_TQ_SIMILARITY_THRESHOLD;
+out:
- if (neigh1_ifinfo)
batadv_neigh_ifinfo_free_ref(neigh1_ifinfo);
- if (neigh2_ifinfo)
batadv_neigh_ifinfo_free_ref(neigh2_ifinfo);
- return ret;
}
static struct batadv_algo_ops batadv_batman_iv __read_mostly = { diff --git a/gateway_client.c b/gateway_client.c index 2449afa..71759d0 100644 --- a/gateway_client.c +++ b/gateway_client.c @@ -114,6 +114,7 @@ static struct batadv_gw_node * batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) { struct batadv_neigh_node *router;
- struct batadv_neigh_ifinfo *router_ifinfo; struct batadv_gw_node *gw_node, *curr_gw = NULL; uint32_t max_gw_factor = 0, tmp_gw_factor = 0; uint32_t gw_divisor;
@@ -134,10 +135,15 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) if (!router) continue;
router_ifinfo = batadv_neigh_ifinfo_get(router,
BATADV_IF_DEFAULT);
if (!router_ifinfo)
goto next;
- if (!atomic_inc_not_zero(&gw_node->refcount)) goto next;
tq_avg = router->bat_iv.tq_avg;
tq_avg = router_ifinfo->bat_iv.tq_avg;
switch (atomic_read(&bat_priv->gw_sel_class)) { case 1: /* fast connection */
@@ -182,6 +188,8 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv)
next: batadv_neigh_node_free_ref(router);
if (router_ifinfo)
} rcu_read_unlock();batadv_neigh_ifinfo_free_ref(router_ifinfo);
@@ -219,6 +227,7 @@ void batadv_gw_election(struct batadv_priv *bat_priv) { struct batadv_gw_node *curr_gw = NULL, *next_gw = NULL; struct batadv_neigh_node *router = NULL;
struct batadv_neigh_ifinfo *router_ifinfo = NULL; char gw_addr[18] = { '\0' };
if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_CLIENT)
@@ -242,6 +251,13 @@ void batadv_gw_election(struct batadv_priv *bat_priv) batadv_gw_deselect(bat_priv); goto out; }
router_ifinfo = batadv_neigh_ifinfo_get(router,
BATADV_IF_DEFAULT);
if (!router_ifinfo) {
batadv_gw_deselect(bat_priv);
goto out;
}
}
if ((curr_gw) && (!next_gw)) {
@@ -256,7 +272,8 @@ void batadv_gw_election(struct batadv_priv *bat_priv) next_gw->bandwidth_down / 10, next_gw->bandwidth_down % 10, next_gw->bandwidth_up / 10,
next_gw->bandwidth_up % 10, router->bat_iv.tq_avg);
next_gw->bandwidth_up % 10,
batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_ADD, gw_addr); } else {router_ifinfo->bat_iv.tq_avg);
@@ -266,7 +283,8 @@ void batadv_gw_election(struct batadv_priv *bat_priv) next_gw->bandwidth_down / 10, next_gw->bandwidth_down % 10, next_gw->bandwidth_up / 10,
next_gw->bandwidth_up % 10, router->bat_iv.tq_avg);
next_gw->bandwidth_up % 10,
batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_CHANGE, gw_addr); }router_ifinfo->bat_iv.tq_avg);
@@ -280,11 +298,15 @@ out: batadv_gw_node_free_ref(next_gw); if (router) batadv_neigh_node_free_ref(router);
- if (router_ifinfo)
batadv_neigh_ifinfo_free_ref(router_ifinfo);
}
void batadv_gw_check_election(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node) {
- struct batadv_neigh_ifinfo *router_orig_tq = NULL;
- struct batadv_neigh_ifinfo *router_gw_tq = NULL; struct batadv_orig_node *curr_gw_orig; struct batadv_neigh_node *router_gw = NULL, *router_orig = NULL; uint8_t gw_tq_avg, orig_tq_avg;
@@ -297,6 +319,11 @@ void batadv_gw_check_election(struct batadv_priv *bat_priv, if (!router_gw) goto deselect;
- router_gw_tq = batadv_neigh_ifinfo_get(router_gw,
BATADV_IF_DEFAULT);
- if (!router_gw_tq)
goto deselect;
- /* this node already is the gateway */ if (curr_gw_orig == orig_node) goto out;
@@ -305,8 +332,13 @@ void batadv_gw_check_election(struct batadv_priv *bat_priv, if (!router_orig) goto out;
- gw_tq_avg = router_gw->bat_iv.tq_avg;
- orig_tq_avg = router_orig->bat_iv.tq_avg;
router_orig_tq = batadv_neigh_ifinfo_get(router_orig,
BATADV_IF_DEFAULT);
if (!router_orig_tq)
goto out;
gw_tq_avg = router_gw_tq->bat_iv.tq_avg;
orig_tq_avg = router_orig_tq->bat_iv.tq_avg;
/* the TQ value has to be better */ if (orig_tq_avg < gw_tq_avg)
@@ -332,6 +364,10 @@ out: batadv_neigh_node_free_ref(router_gw); if (router_orig) batadv_neigh_node_free_ref(router_orig);
if (router_gw_tq)
batadv_neigh_ifinfo_free_ref(router_gw_tq);
if (router_orig_tq)
batadv_neigh_ifinfo_free_ref(router_orig_tq);
return;
} @@ -517,18 +553,23 @@ static int batadv_write_buffer_text(struct batadv_priv *bat_priv, { struct batadv_gw_node *curr_gw; struct batadv_neigh_node *router;
struct batadv_neigh_ifinfo *router_ifinfo; int ret = -1;
router = batadv_orig_node_get_router(gw_node->orig_node); if (!router) goto out;
router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT);
if (!router_ifinfo)
goto out;
curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %u.%u/%u.%u MBit\n", (curr_gw == gw_node ? "=>" : " "), gw_node->orig_node->orig,
router->bat_iv.tq_avg, router->addr,
router_ifinfo->bat_iv.tq_avg, router->addr, router->if_incoming->net_dev->name, gw_node->bandwidth_down / 10, gw_node->bandwidth_down % 10,
@@ -538,6 +579,8 @@ static int batadv_write_buffer_text(struct batadv_priv *bat_priv, batadv_neigh_node_free_ref(router); if (curr_gw) batadv_gw_node_free_ref(curr_gw);
- if (router_ifinfo)
batadv_neigh_ifinfo_free_ref(router_ifinfo);
out: return ret; } @@ -741,6 +784,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, struct batadv_neigh_node *neigh_curr = NULL, *neigh_old = NULL; struct batadv_orig_node *orig_dst_node = NULL; struct batadv_gw_node *gw_node = NULL, *curr_gw = NULL;
- struct batadv_neigh_ifinfo *curr_ifinfo, *old_ifinfo; struct ethhdr *ethhdr; bool ret, out_of_range = false; unsigned int header_len = 0;
@@ -792,7 +836,14 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, if (!neigh_curr) goto out;
curr_tq_avg = neigh_curr->bat_iv.tq_avg;
curr_ifinfo = batadv_neigh_ifinfo_get(neigh_curr,
BATADV_IF_DEFAULT);
if (!curr_ifinfo)
goto out;
curr_tq_avg = curr_ifinfo->bat_iv.tq_avg;
batadv_neigh_ifinfo_free_ref(curr_ifinfo);
- break; case BATADV_GW_MODE_OFF: default:
@@ -803,8 +854,13 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, if (!neigh_old) goto out;
- if (curr_tq_avg - neigh_old->bat_iv.tq_avg > BATADV_GW_THRESHOLD)
- old_ifinfo = batadv_neigh_ifinfo_get(neigh_old, BATADV_IF_DEFAULT);
- if (!old_ifinfo)
goto out;
- if ((curr_tq_avg - old_ifinfo->bat_iv.tq_avg) > BATADV_GW_THRESHOLD) out_of_range = true;
- batadv_neigh_ifinfo_free_ref(old_ifinfo);
out: if (orig_dst_node) diff --git a/hard-interface.h b/hard-interface.h index df4c8bd..6b609b0 100644 --- a/hard-interface.h +++ b/hard-interface.h @@ -53,6 +53,11 @@ int batadv_hardif_min_mtu(struct net_device *soft_iface); void batadv_update_min_mtu(struct net_device *soft_iface); void batadv_hardif_free_rcu(struct rcu_head *rcu);
+/**
- batadv_hardif_free_ref - decrement the hard interface refcounter and
- possibly free it
- @hard_iface: the hard interface to free
- */
static inline void batadv_hardif_free_ref(struct batadv_hard_iface *hard_iface) { @@ -60,6 +65,18 @@ batadv_hardif_free_ref(struct batadv_hard_iface *hard_iface) call_rcu(&hard_iface->rcu, batadv_hardif_free_rcu); }
+/**
- batadv_hardif_free_ref_now - decrement the hard interface refcounter and
- possibly free it (without rcu callback)
- @hard_iface: the hard interface to free
- */
+static inline void +batadv_hardif_free_ref_now(struct batadv_hard_iface *hard_iface) +{
- if (atomic_dec_and_test(&hard_iface->refcount))
batadv_hardif_free_rcu(&hard_iface->rcu);
+}
static inline struct batadv_hard_iface * batadv_primary_if_get_selected(struct batadv_priv *bat_priv) { diff --git a/main.h b/main.h index c5d6eb2..e6c4c1c 100644 --- a/main.h +++ b/main.h @@ -72,6 +72,11 @@
#define BATADV_NULL_IFINDEX 0 /* dummy ifindex used to avoid iface checks */
+/* default interface for multi interface operation. The default interface is
- used for communication which originated locally (i.e. is not forwarded)
- or where special forwarding is not desired/necessary. */
+#define BATADV_IF_DEFAULT ((struct batadv_hard_iface *)NULL)
#define BATADV_NUM_WORDS BITS_TO_LONGS(BATADV_TQ_LOCAL_WINDOW_SIZE)
#define BATADV_LOG_BUF_LEN 8192 /* has to be a power of 2 */ diff --git a/originator.c b/originator.c index 919fdc0..acbd254 100644 --- a/originator.c +++ b/originator.c @@ -150,10 +150,81 @@ err: return -ENOMEM; }
+/* batadv_neigh_ifinfo_free_rcu - free the neigh_ifinfo object
- @rcu: rcu pointer of the neigh_ifinfo object
- */
Broken kernel doc
+static void batadv_neigh_ifinfo_free_rcu(struct rcu_head *rcu) +{
- struct batadv_neigh_ifinfo *neigh_ifinfo;
- neigh_ifinfo = container_of(rcu, struct batadv_neigh_ifinfo, rcu);
- if (neigh_ifinfo->if_outgoing != BATADV_IF_DEFAULT)
batadv_hardif_free_ref_now(neigh_ifinfo->if_outgoing);
- kfree(neigh_ifinfo);
+}
+/**
- batadv_neigh_ifinfo_free_ref - decrement the refcounter and possibly free
- the neigh_ifinfo (without rcu callback)
- @neigh_ifinfo: the neigh_ifinfo object to release
- */
+static void +batadv_neigh_ifinfo_free_ref_now(struct batadv_neigh_ifinfo *neigh_ifinfo) +{
- if (atomic_dec_and_test(&neigh_ifinfo->refcount))
batadv_neigh_ifinfo_free_rcu(&neigh_ifinfo->rcu);
+}
+/**
- batadv_neigh_ifinfo_free_ref - decrement the refcounter and possibly free
- the neigh_ifinfo
- @neigh_ifinfo: the neigh_ifinfo object to release
- */
+void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo) +{
- if (atomic_dec_and_test(&neigh_ifinfo->refcount))
call_rcu(&neigh_ifinfo->rcu, batadv_neigh_ifinfo_free_rcu);
+}
Missing kernel doc
+static void batadv_neigh_node_free_rcu(struct rcu_head *rcu) +{
- struct hlist_node *node_tmp;
- struct batadv_neigh_node *neigh_node;
- struct batadv_neigh_ifinfo *neigh_ifinfo;
- neigh_node = container_of(rcu, struct batadv_neigh_node, rcu);
- hlist_for_each_entry_safe(neigh_ifinfo, node_tmp,
&neigh_node->ifinfo_list, list) {
batadv_neigh_ifinfo_free_ref_now(neigh_ifinfo);
- }
- kfree(neigh_node);
+}
+/**
- batadv_neigh_node_free_ref_now - decrement the neighbors refcounter
- and possibly free it (without rcu callback)
- neigh_node: neigh neighbor to free
- */
Broken kernel doc
+static void +batadv_neigh_node_free_ref_now(struct batadv_neigh_node *neigh_node) +{
- if (atomic_dec_and_test(&neigh_node->refcount))
batadv_neigh_node_free_rcu(&neigh_node->rcu);
+}
+/**
- batadv_neigh_node_free_ref - decrement the neighbors refcounter
- and possibly free it
- neigh_node: neigh neighbor to free
- */
Broken kernel doc
void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node) { if (atomic_dec_and_test(&neigh_node->refcount))
kfree_rcu(neigh_node, rcu);
call_rcu(&neigh_node->rcu, batadv_neigh_node_free_rcu);
}
/* increases the refcounter of a found router */ @@ -173,6 +244,84 @@ batadv_orig_node_get_router(struct batadv_orig_node *orig_node) }
/**
- batadv_neigh_ifinfo_get - find the ifinfo from an neigh_node
- @neigh_node: the neigh node to be queried
- @if_outgoing: the interface for which the ifinfo should be acquired
- The object is returned with refcounter increased by 1.
- Returns the requested neigh_ifinfo or NULL if not found
- */
+struct batadv_neigh_ifinfo * +batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh,
struct batadv_hard_iface *if_outgoing)
+{
- struct batadv_neigh_ifinfo *neigh_ifinfo = NULL,
*tmp_neigh_ifinfo;
- rcu_read_lock();
- hlist_for_each_entry_rcu(tmp_neigh_ifinfo, &neigh->ifinfo_list,
list) {
if (tmp_neigh_ifinfo->if_outgoing != if_outgoing)
continue;
if (!atomic_inc_not_zero(&tmp_neigh_ifinfo->refcount))
continue;
neigh_ifinfo = tmp_neigh_ifinfo;
break;
- }
- rcu_read_unlock();
- return neigh_ifinfo;
+}
+/**
- batadv_neigh_ifinfo_new - search and possibly create an neigh_ifinfo object
- @neigh_node: the neigh node to be queried
- @if_outgoing: the interface for which the ifinfo should be acquired
- Returns NULL in case of failure or the neigh_ifinfo object for the
- if_outgoing interface otherwise. The object is created and added to the list
- if it does not exist.
- The object is returned with refcounter increased by 1.
- */
+struct batadv_neigh_ifinfo * +batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh,
struct batadv_hard_iface *if_outgoing)
+{
- struct batadv_neigh_ifinfo *neigh_ifinfo;
- spin_lock_bh(&neigh->ifinfo_lock);
- neigh_ifinfo = batadv_neigh_ifinfo_get(neigh, if_outgoing);
- if (neigh_ifinfo)
goto out;
- neigh_ifinfo = kzalloc(sizeof(*neigh_ifinfo), GFP_ATOMIC);
- if (!neigh_ifinfo)
goto out;
- if (if_outgoing && !atomic_inc_not_zero(&if_outgoing->refcount)) {
kfree(neigh_ifinfo);
neigh_ifinfo = NULL;
goto out;
- }
- INIT_HLIST_NODE(&neigh_ifinfo->list);
- atomic_set(&neigh_ifinfo->refcount, 2);
- neigh_ifinfo->if_outgoing = if_outgoing;
- hlist_add_head_rcu(&neigh_ifinfo->list, &neigh->ifinfo_list);
+out:
- spin_unlock_bh(&neigh->ifinfo_lock);
- return neigh_ifinfo;
+}
+/**
- batadv_neigh_node_new - create and init a new neigh_node object
- @hard_iface: the interface where the neighbour is connected to
- @neigh_addr: the mac address of the neighbour interface
@@ -193,6 +342,8 @@ batadv_neigh_node_new(struct batadv_hard_iface *hard_iface, goto out;
INIT_HLIST_NODE(&neigh_node->list);
INIT_HLIST_HEAD(&neigh_node->ifinfo_list);
spin_lock_init(&neigh_node->ifinfo_lock);
memcpy(neigh_node->addr, neigh_addr, ETH_ALEN); neigh_node->if_incoming = hard_iface;
@@ -219,7 +370,7 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu) hlist_for_each_entry_safe(neigh_node, node_tmp, &orig_node->neigh_list, list) { hlist_del_rcu(&neigh_node->list);
batadv_neigh_node_free_ref(neigh_node);
batadv_neigh_node_free_ref_now(neigh_node);
}
spin_unlock_bh(&orig_node->neigh_list_lock);
@@ -364,20 +515,23 @@ free_orig_node: return NULL; }
+/**
- batadv_purge_orig_neighbors - purges neighbors from originator
- @bat_priv: the bat priv with all the soft interface information
- @orig_node: orig node which is to be checked
- Returns true if any neighbor was purged, false otherwise
- */
static bool batadv_purge_orig_neighbors(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
struct batadv_neigh_node **best_neigh)
struct batadv_orig_node *orig_node)
{
struct batadv_algo_ops *bao = bat_priv->bat_algo_ops; struct hlist_node *node_tmp; struct batadv_neigh_node *neigh_node; bool neigh_purged = false; unsigned long last_seen; struct batadv_hard_iface *if_incoming;
*best_neigh = NULL;
spin_lock_bh(&orig_node->neigh_list_lock);
/* for all neighbors towards this originator ... */
@@ -407,13 +561,6 @@ batadv_purge_orig_neighbors(struct batadv_priv *bat_priv,
hlist_del_rcu(&neigh_node->list); batadv_neigh_node_free_ref(neigh_node);
} else {
/* store the best_neighbour if this is the first
* iteration or if a better neighbor has been found
*/
if (!*best_neigh ||
bao->bat_neigh_cmp(neigh_node, *best_neigh) > 0)
} }*best_neigh = neigh_node;
@@ -421,6 +568,33 @@ batadv_purge_orig_neighbors(struct batadv_priv *bat_priv, return neigh_purged; }
+/**
- batadv_find_best_neighbor - finds the best neighbor after purging
- @bat_priv: the bat priv with all the soft interface information
- @orig_node: orig node which is to be checked
- @if_outgoing: the interface for which the metric should be compared
- Returns the current best neighbor
- */
+static struct batadv_neigh_node * +batadv_find_best_neighbor(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node,
struct batadv_hard_iface *if_outgoing)
+{
- struct batadv_neigh_node *best = NULL, *neigh;
- struct batadv_algo_ops *bao = bat_priv->bat_algo_ops;
- rcu_read_lock();
- hlist_for_each_entry_rcu(neigh, &orig_node->neigh_list, list)
if (!best ||
(bao->bat_neigh_cmp(neigh, if_outgoing,
best, if_outgoing) <= 0))
best = neigh;
There seems to be some refcounting missing? Or the caller would need to hold rcu_read_lock()s appropriately (which it does not seem to be).
- rcu_read_unlock();
- return best;
+}
static bool batadv_purge_orig_node(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node) { @@ -433,12 +607,13 @@ static bool batadv_purge_orig_node(struct batadv_priv *bat_priv, orig_node->orig, jiffies_to_msecs(orig_node->last_seen)); return true;
- } else {
if (batadv_purge_orig_neighbors(bat_priv, orig_node,
&best_neigh_node))
batadv_update_route(bat_priv, orig_node,
}best_neigh_node);
if (!batadv_purge_orig_neighbors(bat_priv, orig_node))
return false;
best_neigh_node = batadv_find_best_neighbor(bat_priv, orig_node,
BATADV_IF_DEFAULT);
batadv_update_route(bat_priv, orig_node, best_neigh_node);
return false;
} diff --git a/originator.h b/originator.h index 6f77d80..76a8de6 100644 --- a/originator.h +++ b/originator.h @@ -37,6 +37,13 @@ batadv_neigh_node_new(struct batadv_hard_iface *hard_iface, void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node); struct batadv_neigh_node * batadv_orig_node_get_router(struct batadv_orig_node *orig_node); +struct batadv_neigh_ifinfo * +batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh,
struct batadv_hard_iface *if_outgoing);
+struct batadv_neigh_ifinfo * +batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh,
struct batadv_hard_iface *if_outgoing);
+void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo); int batadv_orig_seq_print_text(struct seq_file *seq, void *offset); int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, int max_if_num); diff --git a/translation-table.c b/translation-table.c index 4add57d..135c165 100644 --- a/translation-table.c +++ b/translation-table.c @@ -1390,7 +1390,8 @@ batadv_transtable_best_orig(struct batadv_priv *bat_priv, continue;
if (best_router &&
bao->bat_neigh_cmp(router, best_router) <= 0) {
bao->bat_neigh_cmp(router, BATADV_IF_DEFAULT,
}best_router, BATADV_IF_DEFAULT) <= 0) { batadv_neigh_node_free_ref(router); continue;
diff --git a/types.h b/types.h index 63ddff5..11d448f 100644 --- a/types.h +++ b/types.h @@ -279,47 +279,62 @@ struct batadv_gw_node { };
/**
- struct batadv_neigh_bat_iv - B.A.T.M.A.N. IV specific structure for single
- hop neighbors
- struct batadv_neigh_node - structure for single hops neighbors
- @list: list node for batadv_orig_node::neigh_list
- @orig_node: pointer to corresponding orig_node
- @addr: the MAC address of the neighboring interface
- @ifinfo_list: list for routing metrics per outgoing interface
- @ifinfo_lock: lock protecting private ifinfo members and list
- @if_incoming: pointer to incoming hard interface
- @last_seen: when last packet via this neighbor was received
- @last_ttl: last received ttl from this neigh node
- @rcu: struct used for freeing in an RCU-safe manner
- @bat_iv: B.A.T.M.A.N. IV private structure
- */
+struct batadv_neigh_node {
- struct hlist_node list;
- struct batadv_orig_node *orig_node;
- uint8_t addr[ETH_ALEN];
- struct hlist_head ifinfo_list;
- spinlock_t ifinfo_lock; /* protects ifinfo_list and its members */
- struct batadv_hard_iface *if_incoming;
- unsigned long last_seen;
- atomic_t refcount;
- struct rcu_head rcu;
+};
+/* struct batadv_neigh_node_bat_iv - neighbor information per outgoing
- interface for BATMAN IV
- @tq_recv: ring buffer of received TQ values from this neigh node
- @tq_index: ring buffer index
- @tq_avg: averaged tq of all tq values in the ring buffer (tq_recv)
- @real_bits: bitfield containing the number of OGMs received from this neigh
- node (relative to orig_node->last_real_seqno)
- @real_packet_count: counted result of real_bits
*/
- @lq_update_lock: lock protecting tq_recv & tq_index
-struct batadv_neigh_bat_iv { +struct batadv_neigh_ifinfo_bat_iv { uint8_t tq_recv[BATADV_TQ_GLOBAL_WINDOW_SIZE]; uint8_t tq_index; uint8_t tq_avg; DECLARE_BITMAP(real_bits, BATADV_TQ_LOCAL_WINDOW_SIZE); uint8_t real_packet_count;
- spinlock_t lq_update_lock; /* protects tq_recv & tq_index */
};
-/**
- struct batadv_neigh_node - structure for single hops neighbors
- @list: list node for batadv_orig_node::neigh_list
- @orig_node: pointer to corresponding orig_node
- @addr: the MAC address of the neighboring interface
- @if_incoming: pointer to incoming hard interface
- @last_seen: when last packet via this neighbor was received
+/* struct batadv_neigh_ifinfo - neighbor information per outgoing interface
- @list: list node for batadv_neigh_node::ifinfo_list
- @if_outgoing: pointer to outgoing hard interface
- @bat_iv: B.A.T.M.A.N. IV private structure
- @last_ttl: last received ttl from this neigh node
- @refcount: number of contexts the object is used
- @rcu: struct used for freeing in an RCU-safe manner
- @bat_iv: B.A.T.M.A.N. IV private structure
*/
- @rcu: struct used for freeing in a RCU-safe manner
-struct batadv_neigh_node { +struct batadv_neigh_ifinfo { struct hlist_node list;
- struct batadv_orig_node *orig_node;
- uint8_t addr[ETH_ALEN];
- struct batadv_hard_iface *if_incoming;
- unsigned long last_seen;
- struct batadv_hard_iface *if_outgoing;
- struct batadv_neigh_ifinfo_bat_iv bat_iv; uint8_t last_ttl; atomic_t refcount; struct rcu_head rcu;
- struct batadv_neigh_bat_iv bat_iv;
};
/** @@ -1001,9 +1016,11 @@ struct batadv_forw_packet {
- @bat_primary_iface_set: called when primary interface is selected / changed
- @bat_ogm_schedule: prepare a new outgoing OGM for the send queue
- @bat_ogm_emit: send scheduled OGM
- @bat_neigh_cmp: compare the metrics of two neighbors
- @bat_neigh_is_equiv_or_better: check if neigh1 is equally good or
- better than neigh2 from the metric prospective
- @bat_neigh_cmp: compare the metrics of two neighbors for their respective
- outgoing interfaces
- @bat_neigh_is_equiv_or_better: check if neigh1 is equally good or better
- than neigh2 for their respective outgoing interface from the metric
- prospective
- @bat_orig_print: print the originator table (optional)
- @bat_orig_free: free the resources allocated by the routing algorithm for an
- orig_node object
@@ -1022,9 +1039,14 @@ struct batadv_algo_ops { void (*bat_ogm_schedule)(struct batadv_hard_iface *hard_iface); void (*bat_ogm_emit)(struct batadv_forw_packet *forw_packet); int (*bat_neigh_cmp)(struct batadv_neigh_node *neigh1,
struct batadv_neigh_node *neigh2);
- bool (*bat_neigh_is_equiv_or_better)(struct batadv_neigh_node *neigh1,
struct batadv_neigh_node *neigh2);
struct batadv_hard_iface *if_outgoing1,
struct batadv_neigh_node *neigh2,
struct batadv_hard_iface *if_outgoing2);
- bool (*bat_neigh_is_equiv_or_better)
(struct batadv_neigh_node *neigh1,
struct batadv_hard_iface *if_outgoing1,
struct batadv_neigh_node *neigh2,
/* orig_node handling API */ void (*bat_orig_print)(struct batadv_priv *priv, struct seq_file *seq); void (*bat_orig_free)(struct batadv_orig_node *orig_node);struct batadv_hard_iface *if_outgoing2);
-- 1.7.10.4
From: Simon Wunderlich simon@open-mesh.com
For the network wide multi interface optimization there are different routers for each outgoing interface (outgoing from the OGM perspective, incoming for payload traffic). To reflect this, change the router and associated data to a list of routers.
While at it, rename batadv_orig_node_get_router() to batadv_orig_router_get() to follow the new naming scheme.
Signed-off-by: Simon Wunderlich simon@open-mesh.com --- Changes to PATCH: * change orig_ifinfo locking from implicit rcu style to refcount locking * pass skb instead of buffers to the OGM processing functions * remove unused tt_buff pointer from some bat_iv functions * rename batadv_orig_node_ifinfo* to batadv_orig_ifinfo* - name is still long enough * rename batadv_orig_node_get_router to batadv_orig_router_get * rename batadv_orig_node_get_ifinfo to batadv_orig_ifinfo_get
Changes to RFCv2: * various style changes * remove unneccesary batadv_orig_node_set_router prototype
Changes to RFC: * rebase on current master * remove useless goto * split out batman_seqno_reset as well to avoid false seqno window protections --- bat_iv_ogm.c | 456 ++++++++++++++++++++++++++++------------------- distributed-arp-table.c | 3 +- gateway_client.c | 11 +- icmp_socket.c | 3 +- network-coding.c | 9 +- originator.c | 225 ++++++++++++++++++++++- originator.h | 12 +- routing.c | 35 +++- routing.h | 1 + translation-table.c | 3 +- types.h | 31 +++- 11 files changed, 570 insertions(+), 219 deletions(-)
diff --git a/bat_iv_ogm.c b/bat_iv_ogm.c index 66ce1a7..3ba2402 100644 --- a/bat_iv_ogm.c +++ b/bat_iv_ogm.c @@ -908,21 +908,21 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface) * originator * @bat_priv: the bat priv with all the soft interface information * @orig_node: the orig node who originally emitted the ogm packet + * @orig_ifinfo: ifinfo for the outgoing interface of the orig_node * @ethhdr: Ethernet header of the OGM * @batadv_ogm_packet: the ogm packet * @if_incoming: interface where the packet was received * @if_outgoing: interface for which the retransmission should be considered - * @tt_buff: pointer to the tt buffer * @dup_status: the duplicate status of this ogm packet. */ static void batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, + struct batadv_orig_ifinfo *orig_ifinfo, const struct ethhdr *ethhdr, const struct batadv_ogm_packet *batadv_ogm_packet, struct batadv_hard_iface *if_incoming, struct batadv_hard_iface *if_outgoing, - const unsigned char *tt_buff, enum batadv_dup_status dup_status) { struct batadv_neigh_ifinfo *neigh_ifinfo = NULL; @@ -1004,22 +1004,30 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, spin_unlock_bh(&neigh_node->ifinfo_lock);
if (dup_status == BATADV_NO_DUP) { - orig_node->last_ttl = batadv_ogm_packet->header.ttl; + orig_ifinfo->last_ttl = batadv_ogm_packet->header.ttl; neigh_ifinfo->last_ttl = batadv_ogm_packet->header.ttl; }
/* if this neighbor already is our next hop there is nothing * to change */ - router = batadv_orig_node_get_router(orig_node); + router = batadv_orig_router_get(orig_node, if_outgoing); if (router == neigh_node) goto out;
- router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing); - /* if this neighbor does not offer a better TQ we won't consider it */ - if (router_ifinfo && - (router_ifinfo->bat_iv.tq_avg > neigh_ifinfo->bat_iv.tq_avg)) - goto out; + if (router) { + router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing); + /* if this neighbor does not offer a better TQ we won't + * consider it + */ + if (!router_ifinfo) + goto out; + + if (router_ifinfo->bat_iv.tq_avg > neigh_ifinfo->bat_iv.tq_avg) + goto out; + } else { + router_ifinfo = NULL; + }
/* if the TQ is the same and the link not more symmetric we * won't consider it either @@ -1042,8 +1050,7 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, goto out; }
- /* TODO: pass if_outgoing later */ - batadv_update_route(bat_priv, orig_node, neigh_node); + batadv_update_route(bat_priv, orig_node, if_outgoing, neigh_node); goto out;
unlock: @@ -1204,6 +1211,7 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, { struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); struct batadv_orig_node *orig_node; + struct batadv_orig_ifinfo *orig_ifinfo = NULL; struct batadv_neigh_node *neigh_node; struct batadv_neigh_ifinfo *neigh_ifinfo; int is_dup; @@ -1220,13 +1228,19 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, if (!orig_node) return BATADV_NO_DUP;
+ orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing); + if (WARN_ON(!orig_ifinfo)) { + batadv_orig_node_free_ref(orig_node); + return 0; + } + spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); - seq_diff = seqno - orig_node->last_real_seqno; + seq_diff = seqno - orig_ifinfo->last_real_seqno;
/* signalize caller that the packet is to be dropped. */ if (!hlist_empty(&orig_node->neigh_list) && batadv_window_protected(bat_priv, seq_diff, - &orig_node->batman_seqno_reset)) { + &orig_ifinfo->batman_seqno_reset)) { ret = BATADV_PROTECTED; goto out; } @@ -1240,7 +1254,7 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
neigh_addr = neigh_node->addr; is_dup = batadv_test_bit(neigh_ifinfo->bat_iv.real_bits, - orig_node->last_real_seqno, + orig_ifinfo->last_real_seqno, seqno);
if (batadv_compare_eth(neigh_addr, ethhdr->h_source) && @@ -1268,37 +1282,225 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
if (need_update) { batadv_dbg(BATADV_DBG_BATMAN, bat_priv, - "updating last_seqno: old %u, new %u\n", - orig_node->last_real_seqno, seqno); - orig_node->last_real_seqno = seqno; + "%s updating last_seqno: old %u, new %u\n", + if_outgoing ? if_outgoing->net_dev->name : "DEFAULT", + orig_ifinfo->last_real_seqno, seqno); + orig_ifinfo->last_real_seqno = seqno; }
out: spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock); batadv_orig_node_free_ref(orig_node); + if (orig_ifinfo) + batadv_orig_ifinfo_free_ref(orig_ifinfo); return ret; }
-static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, - struct batadv_ogm_packet *batadv_ogm_packet, - const unsigned char *tt_buff, - struct batadv_hard_iface *if_incoming) + +/** + * batadv_iv_ogm_process_per_outif - process a batman iv OGM for an outgoing if + * @skb: the skb containing the OGM + * @orig_node: the (cached) orig node for the originator of this OGM + * @if_incoming: the interface where this packet was receved + * @if_outgoing: the interface for which the packet should be considered + */ +static void +batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset, + struct batadv_orig_node *orig_node, + struct batadv_hard_iface *if_incoming, + struct batadv_hard_iface *if_outgoing) { struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); - struct batadv_hard_iface *hard_iface; - struct batadv_orig_node *orig_neigh_node, *orig_node, *orig_node_tmp; struct batadv_neigh_node *router = NULL, *router_router = NULL; + struct batadv_orig_node *orig_neigh_node, *orig_node_tmp; + struct batadv_orig_ifinfo *orig_ifinfo; struct batadv_neigh_node *orig_neigh_router = NULL; struct batadv_neigh_ifinfo *router_ifinfo = NULL; - int has_directlink_flag; - int is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0; - int is_bidirect; - bool is_single_hop_neigh = false; - bool is_from_best_next_hop = false; - int sameseq, similar_ttl; + struct batadv_ogm_packet *ogm_packet; enum batadv_dup_status dup_status; - uint32_t if_incoming_seqno; + bool is_from_best_next_hop = false; + bool is_single_hop_neigh = false; + bool sameseq, similar_ttl; + struct sk_buff *skb_priv; + struct ethhdr *ethhdr; uint8_t *prev_sender; + int is_bidirect; + + /* create a private copy of the skb, as some functions change tq value + * and/or flags. + */ + skb_priv = skb_copy(skb, GFP_ATOMIC); + if (!skb_priv) + return; + + ethhdr = eth_hdr(skb_priv); + ogm_packet = (struct batadv_ogm_packet *)(skb_priv->data + ogm_offset); + + dup_status = batadv_iv_ogm_update_seqnos(ethhdr, ogm_packet, + if_incoming, if_outgoing); + if (batadv_compare_eth(ethhdr->h_source, ogm_packet->orig)) + is_single_hop_neigh = true; + + if (dup_status == BATADV_PROTECTED) { + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Drop packet: packet within seqno protection time (sender: %pM)\n", + ethhdr->h_source); + goto out; + } + + if (ogm_packet->tq == 0) { + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Drop packet: originator packet with tq equal 0\n"); + goto out; + } + + router = batadv_orig_router_get(orig_node, if_outgoing); + if (router) { + orig_node_tmp = router->orig_node; + router_router = batadv_orig_router_get(router->orig_node, + if_outgoing); + router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing); + } + + if ((router_ifinfo && router_ifinfo->bat_iv.tq_avg != 0) && + (batadv_compare_eth(router->addr, ethhdr->h_source))) + is_from_best_next_hop = true; + + prev_sender = ogm_packet->prev_sender; + /* avoid temporary routing loops */ + if (router && router_router && + (batadv_compare_eth(router->addr, prev_sender)) && + !(batadv_compare_eth(ogm_packet->orig, prev_sender)) && + (batadv_compare_eth(router->addr, router_router->addr))) { + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Drop packet: ignoring all rebroadcast packets that may make me loop (sender: %pM)\n", + ethhdr->h_source); + goto out; + } + + /* if sender is a direct neighbor the sender mac equals + * originator mac + */ + if (is_single_hop_neigh) + orig_neigh_node = orig_node; + else + orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv, + ethhdr->h_source); + + if (!orig_neigh_node) + goto out; + + /* Update nc_nodes of the originator */ + batadv_nc_update_nc_node(bat_priv, orig_node, orig_neigh_node, + ogm_packet, is_single_hop_neigh); + + orig_neigh_router = batadv_orig_router_get(orig_neigh_node, + if_outgoing); + + /* drop packet if sender is not a direct neighbor and if we + * don't route towards it + */ + if (!is_single_hop_neigh && (!orig_neigh_router)) { + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Drop packet: OGM via unknown neighbor!\n"); + goto out_neigh; + } + + is_bidirect = batadv_iv_ogm_calc_tq(orig_node, orig_neigh_node, + ogm_packet, if_incoming, + if_outgoing); + + /* update ranking if it is not a duplicate or has the same + * seqno and similar ttl as the non-duplicate + */ + orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing); + if (!orig_ifinfo) + goto out_neigh; + + sameseq = orig_ifinfo->last_real_seqno == ntohl(ogm_packet->seqno); + similar_ttl = (orig_ifinfo->last_ttl - 3) <= ogm_packet->header.ttl; + if (is_bidirect && ((dup_status == BATADV_NO_DUP) || + (sameseq && similar_ttl))) { + batadv_iv_ogm_orig_update(bat_priv, orig_node, + orig_ifinfo, ethhdr, + ogm_packet, if_incoming, + if_outgoing, dup_status); + } + batadv_orig_ifinfo_free_ref(orig_ifinfo); + + /* is single hop (direct) neighbor */ + if (is_single_hop_neigh) { + if ((ogm_packet->header.ttl <= 2) && + (if_incoming != if_outgoing)) { + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Drop packet: OGM from secondary interface and wrong outgoing interface\n"); + goto out_neigh; + } + /* mark direct link on incoming interface */ + batadv_iv_ogm_forward(orig_node, ethhdr, ogm_packet, + is_single_hop_neigh, + is_from_best_next_hop, if_incoming); + + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Forwarding packet: rebroadcast neighbor packet with direct link flag\n"); + goto out_neigh; + } + + /* multihop originator */ + if (!is_bidirect) { + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Drop packet: not received via bidirectional link\n"); + goto out_neigh; + } + + if (dup_status == BATADV_NEIGH_DUP) { + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Drop packet: duplicate packet received\n"); + goto out_neigh; + } + + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Forwarding packet: rebroadcast originator packet\n"); + batadv_iv_ogm_forward(orig_node, ethhdr, ogm_packet, + is_single_hop_neigh, is_from_best_next_hop, + if_incoming); + +out_neigh: + if ((orig_neigh_node) && (!is_single_hop_neigh)) + batadv_orig_node_free_ref(orig_neigh_node); +out: + if (router) + batadv_neigh_node_free_ref(router); + if (router_router) + batadv_neigh_node_free_ref(router_router); + if (orig_neigh_router) + batadv_neigh_node_free_ref(orig_neigh_router); + + kfree_skb(skb_priv); +} + +/** + * batadv_iv_ogm_process - process an incoming batman iv OGM + * @skb: the skb containing the OGM + * @ogm_offset: offset to the OGM which should be processed (for aggregates) + * @if_incoming: the interface where this packet was receved + */ +static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset, + struct batadv_hard_iface *if_incoming) +{ + struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); + struct batadv_orig_node *orig_neigh_node, *orig_node; + struct batadv_hard_iface *hard_iface; + struct batadv_ogm_packet *ogm_packet; + uint32_t if_incoming_seqno; + int has_directlink_flag; + struct ethhdr *ethhdr; + int is_my_oldorig = 0; + int is_my_addr = 0; + int is_my_orig = 0; + + ogm_packet = (struct batadv_ogm_packet *)(skb->data + ogm_offset); + ethhdr = eth_hdr(skb);
/* Silently drop when the batman packet is actually not a * correct packet. @@ -1312,28 +1514,24 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, * packet in an aggregation. Here we expect that the padding * is always zero (or not 0x01) */ - if (batadv_ogm_packet->header.packet_type != BATADV_IV_OGM) + if (ogm_packet->header.packet_type != BATADV_IV_OGM) return;
/* could be changed by schedule_own_packet() */ if_incoming_seqno = atomic_read(&if_incoming->bat_iv.ogm_seqno);
- if (batadv_ogm_packet->flags & BATADV_DIRECTLINK) + if (ogm_packet->flags & BATADV_DIRECTLINK) has_directlink_flag = 1; else has_directlink_flag = 0;
- if (batadv_compare_eth(ethhdr->h_source, batadv_ogm_packet->orig)) - is_single_hop_neigh = true; - batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Received BATMAN packet via NB: %pM, IF: %s [%pM] (from OG: %pM, via prev OG: %pM, seqno %u, tq %d, TTL %d, V %d, IDF %d)\n", ethhdr->h_source, if_incoming->net_dev->name, - if_incoming->net_dev->dev_addr, batadv_ogm_packet->orig, - batadv_ogm_packet->prev_sender, - ntohl(batadv_ogm_packet->seqno), batadv_ogm_packet->tq, - batadv_ogm_packet->header.ttl, - batadv_ogm_packet->header.version, has_directlink_flag); + if_incoming->net_dev->dev_addr, ogm_packet->orig, + ogm_packet->prev_sender, ntohl(ogm_packet->seqno), + ogm_packet->tq, ogm_packet->header.ttl, + ogm_packet->header.version, has_directlink_flag);
rcu_read_lock(); list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { @@ -1347,11 +1545,11 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, hard_iface->net_dev->dev_addr)) is_my_addr = 1;
- if (batadv_compare_eth(batadv_ogm_packet->orig, + if (batadv_compare_eth(ogm_packet->orig, hard_iface->net_dev->dev_addr)) is_my_orig = 1;
- if (batadv_compare_eth(batadv_ogm_packet->prev_sender, + if (batadv_compare_eth(ogm_packet->prev_sender, hard_iface->net_dev->dev_addr)) is_my_oldorig = 1; } @@ -1382,14 +1580,14 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, */ if (has_directlink_flag && batadv_compare_eth(if_incoming->net_dev->dev_addr, - batadv_ogm_packet->orig)) { + ogm_packet->orig)) { if_num = if_incoming->if_num; offset = if_num * BATADV_NUM_WORDS;
spin_lock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock); word = &(orig_neigh_node->bat_iv.bcast_own[offset]); bit_pos = if_incoming_seqno - 2; - bit_pos -= ntohl(batadv_ogm_packet->seqno); + bit_pos -= ntohl(ogm_packet->seqno); batadv_set_bit(word, bit_pos); weight = &orig_neigh_node->bat_iv.bcast_own_sum[if_num]; *weight = bitmap_weight(word, @@ -1410,144 +1608,34 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, return; }
- if (batadv_ogm_packet->flags & BATADV_NOT_BEST_NEXT_HOP) { + if (ogm_packet->flags & BATADV_NOT_BEST_NEXT_HOP) { batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Drop packet: ignoring all packets not forwarded from the best next hop (sender: %pM)\n", ethhdr->h_source); return; }
- orig_node = batadv_iv_ogm_orig_get(bat_priv, batadv_ogm_packet->orig); + orig_node = batadv_iv_ogm_orig_get(bat_priv, ogm_packet->orig); if (!orig_node) return;
- dup_status = batadv_iv_ogm_update_seqnos(ethhdr, batadv_ogm_packet, - if_incoming, - BATADV_IF_DEFAULT); + batadv_tvlv_ogm_receive(bat_priv, ogm_packet, orig_node);
- if (dup_status == BATADV_PROTECTED) { - batadv_dbg(BATADV_DBG_BATMAN, bat_priv, - "Drop packet: packet within seqno protection time (sender: %pM)\n", - ethhdr->h_source); - goto out; - } - - if (batadv_ogm_packet->tq == 0) { - batadv_dbg(BATADV_DBG_BATMAN, bat_priv, - "Drop packet: originator packet with tq equal 0\n"); - goto out; - } - - router = batadv_orig_node_get_router(orig_node); - if (router) { - orig_node_tmp = router->orig_node; - router_router = batadv_orig_node_get_router(orig_node_tmp); - router_ifinfo = batadv_neigh_ifinfo_get(router, - BATADV_IF_DEFAULT); - } - - if ((router && router_ifinfo->bat_iv.tq_avg != 0) && - (batadv_compare_eth(router->addr, ethhdr->h_source))) - is_from_best_next_hop = true; - - prev_sender = batadv_ogm_packet->prev_sender; - /* avoid temporary routing loops */ - if (router && router_router && - (batadv_compare_eth(router->addr, prev_sender)) && - !(batadv_compare_eth(batadv_ogm_packet->orig, prev_sender)) && - (batadv_compare_eth(router->addr, router_router->addr))) { - batadv_dbg(BATADV_DBG_BATMAN, bat_priv, - "Drop packet: ignoring all rebroadcast packets that may make me loop (sender: %pM)\n", - ethhdr->h_source); - goto out; - } - - batadv_tvlv_ogm_receive(bat_priv, batadv_ogm_packet, orig_node); - - /* if sender is a direct neighbor the sender mac equals - * originator mac - */ - if (is_single_hop_neigh) - orig_neigh_node = orig_node; - else - orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv, - ethhdr->h_source); - - if (!orig_neigh_node) - goto out; + batadv_iv_ogm_process_per_outif(skb, ogm_offset, orig_node, + if_incoming, BATADV_IF_DEFAULT);
- /* Update nc_nodes of the originator */ - batadv_nc_update_nc_node(bat_priv, orig_node, orig_neigh_node, - batadv_ogm_packet, is_single_hop_neigh); + rcu_read_lock(); + list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { + if (hard_iface->if_status != BATADV_IF_ACTIVE) + continue;
- orig_neigh_router = batadv_orig_node_get_router(orig_neigh_node); + if (hard_iface->soft_iface != bat_priv->soft_iface) + continue;
- /* drop packet if sender is not a direct neighbor and if we - * don't route towards it - */ - if (!is_single_hop_neigh && (!orig_neigh_router)) { - batadv_dbg(BATADV_DBG_BATMAN, bat_priv, - "Drop packet: OGM via unknown neighbor!\n"); - goto out_neigh; + batadv_iv_ogm_process_per_outif(skb, ogm_offset, orig_node, + if_incoming, hard_iface); } - - is_bidirect = batadv_iv_ogm_calc_tq(orig_node, orig_neigh_node, - batadv_ogm_packet, if_incoming, - BATADV_IF_DEFAULT); - - /* update ranking if it is not a duplicate or has the same - * seqno and similar ttl as the non-duplicate - */ - sameseq = orig_node->last_real_seqno == ntohl(batadv_ogm_packet->seqno); - similar_ttl = orig_node->last_ttl - 3 <= batadv_ogm_packet->header.ttl; - if (is_bidirect && ((dup_status == BATADV_NO_DUP) || - (sameseq && similar_ttl))) - batadv_iv_ogm_orig_update(bat_priv, orig_node, ethhdr, - batadv_ogm_packet, if_incoming, - BATADV_IF_DEFAULT, tt_buff, - dup_status); - - /* is single hop (direct) neighbor */ - if (is_single_hop_neigh) { - /* mark direct link on incoming interface */ - batadv_iv_ogm_forward(orig_node, ethhdr, batadv_ogm_packet, - is_single_hop_neigh, - is_from_best_next_hop, if_incoming); - - batadv_dbg(BATADV_DBG_BATMAN, bat_priv, - "Forwarding packet: rebroadcast neighbor packet with direct link flag\n"); - goto out_neigh; - } - - /* multihop originator */ - if (!is_bidirect) { - batadv_dbg(BATADV_DBG_BATMAN, bat_priv, - "Drop packet: not received via bidirectional link\n"); - goto out_neigh; - } - - if (dup_status == BATADV_NEIGH_DUP) { - batadv_dbg(BATADV_DBG_BATMAN, bat_priv, - "Drop packet: duplicate packet received\n"); - goto out_neigh; - } - - batadv_dbg(BATADV_DBG_BATMAN, bat_priv, - "Forwarding packet: rebroadcast originator packet\n"); - batadv_iv_ogm_forward(orig_node, ethhdr, batadv_ogm_packet, - is_single_hop_neigh, is_from_best_next_hop, - if_incoming); - -out_neigh: - if ((orig_neigh_node) && (!is_single_hop_neigh)) - batadv_orig_node_free_ref(orig_neigh_node); -out: - if (router) - batadv_neigh_node_free_ref(router); - if (router_router) - batadv_neigh_node_free_ref(router_router); - if (orig_neigh_router) - batadv_neigh_node_free_ref(orig_neigh_router); + rcu_read_unlock();
batadv_orig_node_free_ref(orig_node); } @@ -1556,11 +1644,9 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb, struct batadv_hard_iface *if_incoming) { struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); - struct batadv_ogm_packet *batadv_ogm_packet; - struct ethhdr *ethhdr; - int buff_pos = 0, packet_len; - unsigned char *tvlv_buff, *packet_buff; + struct batadv_ogm_packet *ogm_packet; uint8_t *packet_pos; + int ogm_offset; bool ret;
ret = batadv_check_management_packet(skb, if_incoming, BATADV_OGM_HLEN); @@ -1577,24 +1663,19 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb, batadv_add_counter(bat_priv, BATADV_CNT_MGMT_RX_BYTES, skb->len + ETH_HLEN);
- packet_len = skb_headlen(skb); - ethhdr = eth_hdr(skb); - packet_buff = skb->data; - batadv_ogm_packet = (struct batadv_ogm_packet *)packet_buff; + ogm_offset = 0; + ogm_packet = (struct batadv_ogm_packet *)skb->data;
/* unpack the aggregated packets and process them one by one */ - while (batadv_iv_ogm_aggr_packet(buff_pos, packet_len, - batadv_ogm_packet->tvlv_len)) { - tvlv_buff = packet_buff + buff_pos + BATADV_OGM_HLEN; + while (batadv_iv_ogm_aggr_packet(ogm_offset, skb_headlen(skb), + ogm_packet->tvlv_len)) { + batadv_iv_ogm_process(skb, ogm_offset, if_incoming);
- batadv_iv_ogm_process(ethhdr, batadv_ogm_packet, - tvlv_buff, if_incoming); + ogm_offset += BATADV_OGM_HLEN; + ogm_offset += ntohs(ogm_packet->tvlv_len);
- buff_pos += BATADV_OGM_HLEN; - buff_pos += ntohs(batadv_ogm_packet->tvlv_len); - - packet_pos = packet_buff + buff_pos; - batadv_ogm_packet = (struct batadv_ogm_packet *)packet_pos; + packet_pos = skb->data + ogm_offset; + ogm_packet = (struct batadv_ogm_packet *)packet_pos; }
kfree_skb(skb); @@ -1657,7 +1738,8 @@ static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv,
rcu_read_lock(); hlist_for_each_entry_rcu(orig_node, head, hash_entry) { - neigh_node = batadv_orig_node_get_router(orig_node); + neigh_node = batadv_orig_router_get(orig_node, + BATADV_IF_DEFAULT); if (!neigh_node) continue;
diff --git a/distributed-arp-table.c b/distributed-arp-table.c index 6c8c393..ae0404e 100644 --- a/distributed-arp-table.c +++ b/distributed-arp-table.c @@ -591,7 +591,8 @@ static bool batadv_dat_send_data(struct batadv_priv *bat_priv, if (cand[i].type == BATADV_DAT_CANDIDATE_NOT_FOUND) continue;
- neigh_node = batadv_orig_node_get_router(cand[i].orig_node); + neigh_node = batadv_orig_router_get(cand[i].orig_node, + BATADV_IF_DEFAULT); if (!neigh_node) goto free_orig;
diff --git a/gateway_client.c b/gateway_client.c index 71759d0..722a051 100644 --- a/gateway_client.c +++ b/gateway_client.c @@ -131,7 +131,7 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) continue;
orig_node = gw_node->orig_node; - router = batadv_orig_node_get_router(orig_node); + router = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT); if (!router) continue;
@@ -246,7 +246,8 @@ void batadv_gw_election(struct batadv_priv *bat_priv) if (next_gw) { sprintf(gw_addr, "%pM", next_gw->orig_node->orig);
- router = batadv_orig_node_get_router(next_gw->orig_node); + router = batadv_orig_router_get(next_gw->orig_node, + BATADV_IF_DEFAULT); if (!router) { batadv_gw_deselect(bat_priv); goto out; @@ -315,7 +316,7 @@ void batadv_gw_check_election(struct batadv_priv *bat_priv, if (!curr_gw_orig) goto deselect;
- router_gw = batadv_orig_node_get_router(curr_gw_orig); + router_gw = batadv_orig_router_get(curr_gw_orig, BATADV_IF_DEFAULT); if (!router_gw) goto deselect;
@@ -328,7 +329,7 @@ void batadv_gw_check_election(struct batadv_priv *bat_priv, if (curr_gw_orig == orig_node) goto out;
- router_orig = batadv_orig_node_get_router(orig_node); + router_orig = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT); if (!router_orig) goto out;
@@ -556,7 +557,7 @@ static int batadv_write_buffer_text(struct batadv_priv *bat_priv, struct batadv_neigh_ifinfo *router_ifinfo; int ret = -1;
- router = batadv_orig_node_get_router(gw_node->orig_node); + router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT); if (!router) goto out;
diff --git a/icmp_socket.c b/icmp_socket.c index 29ae4ef..6b15efc 100644 --- a/icmp_socket.c +++ b/icmp_socket.c @@ -217,7 +217,8 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff, if (!orig_node) goto dst_unreach;
- neigh_node = batadv_orig_node_get_router(orig_node); + neigh_node = batadv_orig_router_get(orig_node, + BATADV_IF_DEFAULT); if (!neigh_node) goto dst_unreach;
diff --git a/network-coding.c b/network-coding.c index 351e199..792a072 100644 --- a/network-coding.c +++ b/network-coding.c @@ -1019,12 +1019,17 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv, int coded_size = sizeof(*coded_packet); int header_add = coded_size - unicast_size;
- router_neigh = batadv_orig_node_get_router(neigh_node->orig_node); + /* TODO: do we need to consider the outgoing interface for + * coded packets? + */ + router_neigh = batadv_orig_router_get(neigh_node->orig_node, + BATADV_IF_DEFAULT); if (!router_neigh) goto out;
neigh_tmp = nc_packet->neigh_node; - router_coding = batadv_orig_node_get_router(neigh_tmp->orig_node); + router_coding = batadv_orig_router_get(neigh_tmp->orig_node, + BATADV_IF_DEFAULT); if (!router_coding) goto out;
diff --git a/originator.c b/originator.c index acbd254..62691d0 100644 --- a/originator.c +++ b/originator.c @@ -227,14 +227,30 @@ void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node) call_rcu(&neigh_node->rcu, batadv_neigh_node_free_rcu); }
-/* increases the refcounter of a found router */ +/** + * batadv_orig_node_get_router - router to the originator depending on iface + * @orig_node: the orig node for the router + * @if_received: the interface where the packet to be transmitted was received + * + * Returns the neighbor which should be router for this orig_node/iface. + * + * The object is returned with refcounter increased by 1. + */ struct batadv_neigh_node * -batadv_orig_node_get_router(struct batadv_orig_node *orig_node) +batadv_orig_router_get(struct batadv_orig_node *orig_node, + const struct batadv_hard_iface *if_received) { - struct batadv_neigh_node *router; + struct batadv_orig_ifinfo *orig_ifinfo; + struct batadv_neigh_node *router = NULL;
rcu_read_lock(); - router = rcu_dereference(orig_node->router); + hlist_for_each_entry_rcu(orig_ifinfo, &orig_node->ifinfo_list, list) { + if (orig_ifinfo->if_outgoing != if_received) + continue; + + router = rcu_dereference(orig_ifinfo->router); + break; + }
if (router && !atomic_inc_not_zero(&router->refcount)) router = NULL; @@ -244,6 +260,86 @@ batadv_orig_node_get_router(struct batadv_orig_node *orig_node) }
/** + * batadv_orig_ifinfo_get - find the ifinfo from an orig_node + * @orig_node: the orig node to be queried + * @if_received: the interface for which the ifinfo should be acquired + * + * Returns the requested orig_ifinfo or NULL if not found. + * + * The object is returned with refcounter increased by 1. + */ +struct batadv_orig_ifinfo * +batadv_orig_ifinfo_get(struct batadv_orig_node *orig_node, + struct batadv_hard_iface *if_received) +{ + struct batadv_orig_ifinfo *tmp, *orig_ifinfo = NULL; + + rcu_read_lock(); + hlist_for_each_entry_rcu(tmp, &orig_node->ifinfo_list, + list) { + if (tmp->if_outgoing != if_received) + continue; + + if (!atomic_inc_not_zero(&tmp->refcount)) + continue; + + orig_ifinfo = tmp; + break; + } + rcu_read_unlock(); + + return orig_ifinfo; +} + +/** + * batadv_orig_ifinfo_new - search and possibly create an orig_ifinfo object + * @orig_node: the orig node to be queried + * @if_received: the interface for which the ifinfo should be acquired + * + * Returns NULL in case of failure or the orig_ifinfo object for the if_outgoing + * interface otherwise. The object is created and added to the list + * if it does not exist. + * + * The object is returned with refcounter increased by 1. + */ +struct batadv_orig_ifinfo * +batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node, + struct batadv_hard_iface *if_received) +{ + struct batadv_orig_ifinfo *orig_ifinfo = NULL; + unsigned long reset_time; + + spin_lock_bh(&orig_node->neigh_list_lock); + + orig_ifinfo = batadv_orig_ifinfo_get(orig_node, if_received); + if (orig_ifinfo) + goto out; + + orig_ifinfo = kzalloc(sizeof(*orig_ifinfo), GFP_ATOMIC); + if (!orig_ifinfo) + goto out; + + if (if_received != BATADV_IF_DEFAULT && + !atomic_inc_not_zero(&if_received->refcount)) { + kfree(orig_ifinfo); + orig_ifinfo = NULL; + goto out; + } + + reset_time = jiffies - 1; + reset_time -= msecs_to_jiffies(BATADV_RESET_PROTECTION_MS); + orig_ifinfo->batman_seqno_reset = reset_time; + orig_ifinfo->if_outgoing = if_received; + INIT_HLIST_NODE(&orig_ifinfo->list); + atomic_set(&orig_ifinfo->refcount, 2); + hlist_add_head_rcu(&orig_ifinfo->list, + &orig_node->ifinfo_list); +out: + spin_unlock_bh(&orig_node->neigh_list_lock); + return orig_ifinfo; +} + +/** * batadv_neigh_ifinfo_get - find the ifinfo from an neigh_node * @neigh_node: the neigh node to be queried * @if_outgoing: the interface for which the ifinfo should be acquired @@ -356,11 +452,50 @@ out: return neigh_node; }
+/* batadv_orig_ifinfo_free_rcu - free the orig_ifinfo object + * @rcu: rcu pointer of the orig_ifinfo object + */ +static void batadv_orig_ifinfo_free_rcu(struct rcu_head *rcu) +{ + struct batadv_orig_ifinfo *orig_ifinfo; + + orig_ifinfo = container_of(rcu, struct batadv_orig_ifinfo, rcu); + + if (orig_ifinfo->if_outgoing != BATADV_IF_DEFAULT) + batadv_hardif_free_ref_now(orig_ifinfo->if_outgoing); + + kfree(orig_ifinfo); +} + +/** + * batadv_orig_ifinfo_free_ref - decrement the refcounter and possibly free + * the orig_ifinfo (without rcu callback) + * @orig_ifinfo: the orig_ifinfo object to release + */ +static void +batadv_orig_ifinfo_free_ref_now(struct batadv_orig_ifinfo *orig_ifinfo) +{ + if (atomic_dec_and_test(&orig_ifinfo->refcount)) + batadv_orig_ifinfo_free_rcu(&orig_ifinfo->rcu); +} + +/** + * batadv_orig_ifinfo_free_ref - decrement the refcounter and possibly free + * the orig_ifinfo + * @orig_ifinfo: the orig_ifinfo object to release + */ +void batadv_orig_ifinfo_free_ref(struct batadv_orig_ifinfo *orig_ifinfo) +{ + if (atomic_dec_and_test(&orig_ifinfo->refcount)) + call_rcu(&orig_ifinfo->rcu, batadv_orig_ifinfo_free_rcu); +} + static void batadv_orig_node_free_rcu(struct rcu_head *rcu) { struct hlist_node *node_tmp; struct batadv_neigh_node *neigh_node; struct batadv_orig_node *orig_node; + struct batadv_orig_ifinfo *orig_ifinfo;
orig_node = container_of(rcu, struct batadv_orig_node, rcu);
@@ -373,6 +508,11 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu) batadv_neigh_node_free_ref_now(neigh_node); }
+ hlist_for_each_entry_safe(orig_ifinfo, node_tmp, + &orig_node->ifinfo_list, list) { + hlist_del_rcu(&orig_ifinfo->list); + batadv_orig_ifinfo_free_ref_now(orig_ifinfo); + } spin_unlock_bh(&orig_node->neigh_list_lock);
/* Free nc_nodes */ @@ -470,6 +610,7 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv,
INIT_HLIST_HEAD(&orig_node->neigh_list); INIT_LIST_HEAD(&orig_node->vlan_list); + INIT_HLIST_HEAD(&orig_node->ifinfo_list); spin_lock_init(&orig_node->bcast_seqno_lock); spin_lock_init(&orig_node->neigh_list_lock); spin_lock_init(&orig_node->tt_buff_lock); @@ -485,13 +626,11 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, orig_node->bat_priv = bat_priv; memcpy(orig_node->orig, addr, ETH_ALEN); batadv_dat_init_orig_node_addr(orig_node); - orig_node->router = NULL; atomic_set(&orig_node->last_ttvn, 0); orig_node->tt_buff = NULL; orig_node->tt_buff_len = 0; reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS); orig_node->bcast_seqno_reset = reset_time; - orig_node->batman_seqno_reset = reset_time;
/* create a vlan object for the "untagged" LAN */ vlan = batadv_orig_node_vlan_new(orig_node, BATADV_NO_FLAGS); @@ -516,6 +655,52 @@ free_orig_node: }
/** + * batadv_purge_orig_ifinfo - purge ifinfo entries from originator + * @bat_priv: the bat priv with all the soft interface information + * @orig_node: orig node which is to be checked + * + * Returns true if any ifinfo entry was purged, false otherwise. + */ +static bool +batadv_purge_orig_ifinfo(struct batadv_priv *bat_priv, + struct batadv_orig_node *orig_node) +{ + struct batadv_orig_ifinfo *orig_ifinfo; + struct batadv_hard_iface *if_outgoing; + struct hlist_node *node_tmp; + bool ifinfo_purged = false; + + spin_lock_bh(&orig_node->neigh_list_lock); + + /* for all neighbors towards this originator ... */ + hlist_for_each_entry_safe(orig_ifinfo, node_tmp, + &orig_node->ifinfo_list, list) { + if_outgoing = orig_ifinfo->if_outgoing; + if (!if_outgoing) + continue; + + if ((if_outgoing->if_status != BATADV_IF_INACTIVE) && + (if_outgoing->if_status != BATADV_IF_NOT_IN_USE) && + (if_outgoing->if_status != BATADV_IF_TO_BE_REMOVED)) + continue; + + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "router/ifinfo purge: originator %pM, iface: %s\n", + orig_node->orig, if_outgoing->net_dev->name); + + ifinfo_purged = true; + + hlist_del_rcu(&orig_ifinfo->list); + batadv_orig_ifinfo_free_ref(orig_ifinfo); + } + + spin_unlock_bh(&orig_node->neigh_list_lock); + + return ifinfo_purged; +} + + +/** * batadv_purge_orig_neighbors - purges neighbors from originator * @bat_priv: the bat priv with all the soft interface information * @orig_node: orig node which is to be checked @@ -599,6 +784,8 @@ static bool batadv_purge_orig_node(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node) { struct batadv_neigh_node *best_neigh_node; + struct batadv_hard_iface *hard_iface; + bool changed;
if (batadv_has_timed_out(orig_node->last_seen, 2 * BATADV_PURGE_TIMEOUT)) { @@ -608,12 +795,34 @@ static bool batadv_purge_orig_node(struct batadv_priv *bat_priv, jiffies_to_msecs(orig_node->last_seen)); return true; } - if (!batadv_purge_orig_neighbors(bat_priv, orig_node)) + changed = batadv_purge_orig_ifinfo(bat_priv, orig_node); + changed = changed || batadv_purge_orig_neighbors(bat_priv, orig_node); + + if (!changed) return false;
+ /* first for NULL ... */ best_neigh_node = batadv_find_best_neighbor(bat_priv, orig_node, BATADV_IF_DEFAULT); - batadv_update_route(bat_priv, orig_node, best_neigh_node); + batadv_update_route(bat_priv, orig_node, BATADV_IF_DEFAULT, + best_neigh_node); + + /* ... then for all other interfaces. */ + rcu_read_lock(); + list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { + if (hard_iface->if_status != BATADV_IF_ACTIVE) + continue; + + if (hard_iface->soft_iface != bat_priv->soft_iface) + continue; + + best_neigh_node = batadv_find_best_neighbor(bat_priv, + orig_node, + hard_iface); + batadv_update_route(bat_priv, orig_node, hard_iface, + best_neigh_node); + } + rcu_read_unlock();
return false; } diff --git a/originator.h b/originator.h index 76a8de6..404f7cb 100644 --- a/originator.h +++ b/originator.h @@ -36,7 +36,8 @@ batadv_neigh_node_new(struct batadv_hard_iface *hard_iface, struct batadv_orig_node *orig_node); void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node); struct batadv_neigh_node * -batadv_orig_node_get_router(struct batadv_orig_node *orig_node); +batadv_orig_router_get(struct batadv_orig_node *orig_node, + const struct batadv_hard_iface *if_received); struct batadv_neigh_ifinfo * batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh, struct batadv_hard_iface *if_outgoing); @@ -44,6 +45,15 @@ struct batadv_neigh_ifinfo * batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh, struct batadv_hard_iface *if_outgoing); void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo); + +struct batadv_orig_ifinfo * +batadv_orig_ifinfo_get(struct batadv_orig_node *orig_node, + struct batadv_hard_iface *if_received); +struct batadv_orig_ifinfo * +batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node, + struct batadv_hard_iface *if_received); +void batadv_orig_ifinfo_free_ref(struct batadv_orig_ifinfo *orig_ifinfo); + int batadv_orig_seq_print_text(struct seq_file *seq, void *offset); int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, int max_if_num); diff --git a/routing.c b/routing.c index 360a5b9..da6741a 100644 --- a/routing.c +++ b/routing.c @@ -35,13 +35,29 @@ static int batadv_route_unicast_packet(struct sk_buff *skb, struct batadv_hard_iface *recv_if);
+/* _batadv_update_route - set the router for this originator + * @bat_priv: the bat priv with all the soft interface information + * @orig_node: orig node which is to be configured + * @recv_if: the receive interface for which this route is set + * @neigh_node: neighbor which should be the next router + * + * This function does not perform any error checks + */ static void _batadv_update_route(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, + struct batadv_hard_iface *recv_if, struct batadv_neigh_node *neigh_node) { + struct batadv_orig_ifinfo *orig_ifinfo; struct batadv_neigh_node *curr_router;
- curr_router = batadv_orig_node_get_router(orig_node); + orig_ifinfo = batadv_orig_ifinfo_get(orig_node, recv_if); + if (!orig_ifinfo) + return; + + curr_router = rcu_dereference(orig_ifinfo->router); + if (curr_router && !atomic_inc_not_zero(&curr_router->refcount)) + curr_router = NULL;
/* route deleted */ if ((curr_router) && (!neigh_node)) { @@ -71,16 +87,25 @@ static void _batadv_update_route(struct batadv_priv *bat_priv, neigh_node = NULL;
spin_lock_bh(&orig_node->neigh_list_lock); - rcu_assign_pointer(orig_node->router, neigh_node); + rcu_assign_pointer(orig_ifinfo->router, neigh_node); spin_unlock_bh(&orig_node->neigh_list_lock); + batadv_orig_ifinfo_free_ref(orig_ifinfo);
/* decrease refcount of previous best neighbor */ if (curr_router) batadv_neigh_node_free_ref(curr_router); }
+/** + * batadv_update_route - set the router for this originator + * @bat_priv: the bat priv with all the soft interface information + * @orig_node: orig node which is to be configured + * @recv_if: the receive interface for which this route is set + * @neigh_node: neighbor which should be the next router + */ void batadv_update_route(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, + struct batadv_hard_iface *recv_if, struct batadv_neigh_node *neigh_node) { struct batadv_neigh_node *router = NULL; @@ -88,10 +113,10 @@ void batadv_update_route(struct batadv_priv *bat_priv, if (!orig_node) goto out;
- router = batadv_orig_node_get_router(orig_node); + router = batadv_orig_router_get(orig_node, recv_if);
if (router != neigh_node) - _batadv_update_route(bat_priv, orig_node, neigh_node); + _batadv_update_route(bat_priv, orig_node, recv_if, neigh_node);
out: if (router) @@ -408,7 +433,7 @@ batadv_find_router(struct batadv_priv *bat_priv, if (!orig_node) return NULL;
- router = batadv_orig_node_get_router(orig_node); + router = batadv_orig_router_get(orig_node, recv_if);
/* TODO: fill this later with new bonding mechanism */
diff --git a/routing.h b/routing.h index b8fed80..7a7c6e9 100644 --- a/routing.h +++ b/routing.h @@ -25,6 +25,7 @@ bool batadv_check_management_packet(struct sk_buff *skb, int header_len); void batadv_update_route(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, + struct batadv_hard_iface *recv_if, struct batadv_neigh_node *neigh_node); int batadv_recv_icmp_packet(struct sk_buff *skb, struct batadv_hard_iface *recv_if); diff --git a/translation-table.c b/translation-table.c index 135c165..1b2a615 100644 --- a/translation-table.c +++ b/translation-table.c @@ -1385,7 +1385,8 @@ batadv_transtable_best_orig(struct batadv_priv *bat_priv,
head = &tt_global_entry->orig_list; hlist_for_each_entry_rcu(orig_entry, head, list) { - router = batadv_orig_node_get_router(orig_entry->orig_node); + router = batadv_orig_router_get(orig_entry->orig_node, + BATADV_IF_DEFAULT); if (!router) continue;
diff --git a/types.h b/types.h index 11d448f..167c3a5 100644 --- a/types.h +++ b/types.h @@ -90,6 +90,27 @@ struct batadv_hard_iface { struct work_struct cleanup_work; };
+/* struct batadv_orig_ifinfo - originator info per outgoing interface + * @list: list node for orig_node::ifinfo_list + * @if_outgoing: pointer to outgoing hard interface + * @router: router that should be used to reach this originator + * @last_real_seqno: last and best known sequence number + * @last_ttl: ttl of last received packet + * @batman_seqno_reset: time when the batman seqno window was reset + * @refcount: number of contexts the object is used + * @rcu: struct used for freeing in an RCU-safe manner + */ +struct batadv_orig_ifinfo { + struct hlist_node list; + struct batadv_hard_iface *if_outgoing; + struct batadv_neigh_node __rcu *router; /* rcu protected pointer */ + uint32_t last_real_seqno; + uint8_t last_ttl; + unsigned long batman_seqno_reset; + atomic_t refcount; + struct rcu_head rcu; +}; + /** * struct batadv_frag_table_entry - head in the fragment buffer table * @head: head of list with fragments @@ -165,11 +186,10 @@ struct batadv_orig_bat_iv { * struct batadv_orig_node - structure for orig_list maintaining nodes of mesh * @orig: originator ethernet address * @primary_addr: hosts primary interface address - * @router: router that should be used to reach this originator + * @ifinfo_list: list for routers per outgoing interface * @batadv_dat_addr_t: address of the orig node in the distributed hash * @last_seen: time when last packet from this node was received * @bcast_seqno_reset: time when the broadcast seqno window was reset - * @batman_seqno_reset: time when the batman seqno window was reset * @capabilities: announced capabilities of this originator * @last_ttvn: last seen translation table version number * @tt_buff: last tt changeset this node received from the orig node @@ -182,8 +202,6 @@ struct batadv_orig_bat_iv { * made up by two operations (data structure update and metdata -CRC/TTVN- * recalculation) and they have to be executed atomically in order to avoid * another thread to read the table/metadata between those. - * @last_real_seqno: last and best known sequence number - * @last_ttl: ttl of last received packet * @bcast_bits: bitfield containing the info which payload broadcast originated * from this orig node this host already has seen (relative to * last_bcast_seqno) @@ -208,13 +226,12 @@ struct batadv_orig_bat_iv { struct batadv_orig_node { uint8_t orig[ETH_ALEN]; uint8_t primary_addr[ETH_ALEN]; - struct batadv_neigh_node __rcu *router; /* rcu protected pointer */ + struct hlist_head ifinfo_list; #ifdef CONFIG_BATMAN_ADV_DAT batadv_dat_addr_t dat_addr; #endif unsigned long last_seen; unsigned long bcast_seqno_reset; - unsigned long batman_seqno_reset; uint8_t capabilities; atomic_t last_ttvn; unsigned char *tt_buff; @@ -223,8 +240,6 @@ struct batadv_orig_node { bool tt_initialised; /* prevents from changing the table while reading it */ spinlock_t tt_lock; - uint32_t last_real_seqno; - uint8_t last_ttl; DECLARE_BITMAP(bcast_bits, BATADV_TQ_LOCAL_WINDOW_SIZE); uint32_t last_bcast_seqno; struct hlist_head neigh_list;
Hi Simon,
I could only find one or two potential bugs, so I had to come up with a few, additional style suggestions ;).
On Wed, Oct 30, 2013 at 03:01:48PM +0100, Simon Wunderlich wrote:
From: Simon Wunderlich simon@open-mesh.com
For the network wide multi interface optimization there are different routers for each outgoing interface (outgoing from the OGM perspective, incoming for payload traffic). To reflect this, change the router and associated data to a list of routers.
While at it, rename batadv_orig_node_get_router() to batadv_orig_router_get() to follow the new naming scheme.
Signed-off-by: Simon Wunderlich simon@open-mesh.com
Changes to PATCH:
- change orig_ifinfo locking from implicit rcu style to refcount locking
- pass skb instead of buffers to the OGM processing functions
- remove unused tt_buff pointer from some bat_iv functions
- rename batadv_orig_node_ifinfo* to batadv_orig_ifinfo* - name is still long enough
- rename batadv_orig_node_get_router to batadv_orig_router_get
- rename batadv_orig_node_get_ifinfo to batadv_orig_ifinfo_get
Changes to RFCv2:
- various style changes
- remove unneccesary batadv_orig_node_set_router prototype
Changes to RFC:
- rebase on current master
- remove useless goto
- split out batman_seqno_reset as well to avoid false seqno window protections
bat_iv_ogm.c | 456 ++++++++++++++++++++++++++++------------------- distributed-arp-table.c | 3 +- gateway_client.c | 11 +- icmp_socket.c | 3 +- network-coding.c | 9 +- originator.c | 225 ++++++++++++++++++++++- originator.h | 12 +- routing.c | 35 +++- routing.h | 1 + translation-table.c | 3 +- types.h | 31 +++- 11 files changed, 570 insertions(+), 219 deletions(-)
diff --git a/bat_iv_ogm.c b/bat_iv_ogm.c index 66ce1a7..3ba2402 100644 --- a/bat_iv_ogm.c +++ b/bat_iv_ogm.c @@ -908,21 +908,21 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
- originator
- @bat_priv: the bat priv with all the soft interface information
- @orig_node: the orig node who originally emitted the ogm packet
- @orig_ifinfo: ifinfo for the outgoing interface of the orig_node
- @ethhdr: Ethernet header of the OGM
- @batadv_ogm_packet: the ogm packet
- @if_incoming: interface where the packet was received
- @if_outgoing: interface for which the retransmission should be considered
*/
- @tt_buff: pointer to the tt buffer
- @dup_status: the duplicate status of this ogm packet.
static void batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node,
struct batadv_orig_ifinfo *orig_ifinfo, const struct ethhdr *ethhdr, const struct batadv_ogm_packet *batadv_ogm_packet, struct batadv_hard_iface *if_incoming, struct batadv_hard_iface *if_outgoing,
const unsigned char *tt_buff, enum batadv_dup_status dup_status)
{ struct batadv_neigh_ifinfo *neigh_ifinfo = NULL; @@ -1004,22 +1004,30 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, spin_unlock_bh(&neigh_node->ifinfo_lock);
if (dup_status == BATADV_NO_DUP) {
orig_node->last_ttl = batadv_ogm_packet->header.ttl;
orig_ifinfo->last_ttl = batadv_ogm_packet->header.ttl;
neigh_ifinfo->last_ttl = batadv_ogm_packet->header.ttl; }
/* if this neighbor already is our next hop there is nothing
- to change
*/
- router = batadv_orig_node_get_router(orig_node);
- router = batadv_orig_router_get(orig_node, if_outgoing); if (router == neigh_node) goto out;
- router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing);
- /* if this neighbor does not offer a better TQ we won't consider it */
- if (router_ifinfo &&
(router_ifinfo->bat_iv.tq_avg > neigh_ifinfo->bat_iv.tq_avg))
goto out;
Ok, if *router can actually be NULL, then the following "if (router)" check, the diff block to follow, should probably have been introduced in the previous patch already?
- if (router) {
router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing);
This comment might be better suited three lines later?
/* if this neighbor does not offer a better TQ we won't
* consider it
*/
if (!router_ifinfo)
goto out;
if (router_ifinfo->bat_iv.tq_avg > neigh_ifinfo->bat_iv.tq_avg)
goto out;
This else-clause seems redundant:
} else {
router_ifinfo = NULL;
}
/* if the TQ is the same and the link not more symmetric we
- won't consider it either
@@ -1042,8 +1050,7 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, goto out; }
Hm, if the TODO is solved within the same patchset, then maybe it's not necessary to add the comment in the first place, in the previous patch?
- /* TODO: pass if_outgoing later */
- batadv_update_route(bat_priv, orig_node, neigh_node);
- batadv_update_route(bat_priv, orig_node, if_outgoing, neigh_node); goto out;
unlock: @@ -1204,6 +1211,7 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, { struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); struct batadv_orig_node *orig_node;
- struct batadv_orig_ifinfo *orig_ifinfo = NULL; struct batadv_neigh_node *neigh_node; struct batadv_neigh_ifinfo *neigh_ifinfo; int is_dup;
@@ -1220,13 +1228,19 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, if (!orig_node) return BATADV_NO_DUP;
- orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing);
- if (WARN_ON(!orig_ifinfo)) {
batadv_orig_node_free_ref(orig_node);
return 0;
- }
- spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock);
- seq_diff = seqno - orig_node->last_real_seqno;
seq_diff = seqno - orig_ifinfo->last_real_seqno;
/* signalize caller that the packet is to be dropped. */ if (!hlist_empty(&orig_node->neigh_list) && batadv_window_protected(bat_priv, seq_diff,
&orig_node->batman_seqno_reset)) {
ret = BATADV_PROTECTED; goto out; }&orig_ifinfo->batman_seqno_reset)) {
@@ -1240,7 +1254,7 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
neigh_addr = neigh_node->addr; is_dup = batadv_test_bit(neigh_ifinfo->bat_iv.real_bits,
orig_node->last_real_seqno,
orig_ifinfo->last_real_seqno, seqno);
if (batadv_compare_eth(neigh_addr, ethhdr->h_source) &&
@@ -1268,37 +1282,225 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
if (need_update) { batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"updating last_seqno: old %u, new %u\n",
orig_node->last_real_seqno, seqno);
orig_node->last_real_seqno = seqno;
"%s updating last_seqno: old %u, new %u\n",
if_outgoing ? if_outgoing->net_dev->name : "DEFAULT",
orig_ifinfo->last_real_seqno, seqno);
}orig_ifinfo->last_real_seqno = seqno;
out: spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock); batadv_orig_node_free_ref(orig_node);
- if (orig_ifinfo)
return ret;batadv_orig_ifinfo_free_ref(orig_ifinfo);
}
-static void batadv_iv_ogm_process(const struct ethhdr *ethhdr,
struct batadv_ogm_packet *batadv_ogm_packet,
const unsigned char *tt_buff,
struct batadv_hard_iface *if_incoming)
+/**
- batadv_iv_ogm_process_per_outif - process a batman iv OGM for an outgoing if
- @skb: the skb containing the OGM
- @orig_node: the (cached) orig node for the originator of this OGM
typo (receved vs. received):
- @if_incoming: the interface where this packet was receved
- @if_outgoing: the interface for which the packet should be considered
- */
+static void +batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset,
struct batadv_orig_node *orig_node,
struct batadv_hard_iface *if_incoming,
struct batadv_hard_iface *if_outgoing)
{ struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
- struct batadv_hard_iface *hard_iface;
- struct batadv_orig_node *orig_neigh_node, *orig_node, *orig_node_tmp; struct batadv_neigh_node *router = NULL, *router_router = NULL;
- struct batadv_orig_node *orig_neigh_node, *orig_node_tmp;
- struct batadv_orig_ifinfo *orig_ifinfo; struct batadv_neigh_node *orig_neigh_router = NULL; struct batadv_neigh_ifinfo *router_ifinfo = NULL;
- int has_directlink_flag;
- int is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;
- int is_bidirect;
- bool is_single_hop_neigh = false;
- bool is_from_best_next_hop = false;
- int sameseq, similar_ttl;
- struct batadv_ogm_packet *ogm_packet; enum batadv_dup_status dup_status;
- uint32_t if_incoming_seqno;
- bool is_from_best_next_hop = false;
- bool is_single_hop_neigh = false;
- bool sameseq, similar_ttl;
- struct sk_buff *skb_priv;
- struct ethhdr *ethhdr; uint8_t *prev_sender;
- int is_bidirect;
- /* create a private copy of the skb, as some functions change tq value
* and/or flags.
*/
- skb_priv = skb_copy(skb, GFP_ATOMIC);
- if (!skb_priv)
return;
- ethhdr = eth_hdr(skb_priv);
- ogm_packet = (struct batadv_ogm_packet *)(skb_priv->data + ogm_offset);
- dup_status = batadv_iv_ogm_update_seqnos(ethhdr, ogm_packet,
if_incoming, if_outgoing);
To avoid redundant code execution, move this if statement to the calling function maybe?
- if (batadv_compare_eth(ethhdr->h_source, ogm_packet->orig))
is_single_hop_neigh = true;
- if (dup_status == BATADV_PROTECTED) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: packet within seqno protection time (sender: %pM)\n",
ethhdr->h_source);
goto out;
- }
Move this if statement to the calling function maybe?
- if (ogm_packet->tq == 0) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: originator packet with tq equal 0\n");
goto out;
- }
- router = batadv_orig_router_get(orig_node, if_outgoing);
- if (router) {
orig_node_tmp = router->orig_node;
router_router = batadv_orig_router_get(router->orig_node,
if_outgoing);
router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing);
- }
- if ((router_ifinfo && router_ifinfo->bat_iv.tq_avg != 0) &&
(batadv_compare_eth(router->addr, ethhdr->h_source)))
is_from_best_next_hop = true;
- prev_sender = ogm_packet->prev_sender;
- /* avoid temporary routing loops */
- if (router && router_router &&
(batadv_compare_eth(router->addr, prev_sender)) &&
!(batadv_compare_eth(ogm_packet->orig, prev_sender)) &&
(batadv_compare_eth(router->addr, router_router->addr))) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: ignoring all rebroadcast packets that may make me loop (sender: %pM)\n",
ethhdr->h_source);
goto out;
- }
Move this to ...
- /* if sender is a direct neighbor the sender mac equals
* originator mac
*/
- if (is_single_hop_neigh)
orig_neigh_node = orig_node;
- else
orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv,
ethhdr->h_source);
- if (!orig_neigh_node)
goto out;
- /* Update nc_nodes of the originator */
- batadv_nc_update_nc_node(bat_priv, orig_node, orig_neigh_node,
ogm_packet, is_single_hop_neigh);
... this to the calling function, maybe?
- orig_neigh_router = batadv_orig_router_get(orig_neigh_node,
if_outgoing);
- /* drop packet if sender is not a direct neighbor and if we
* don't route towards it
*/
- if (!is_single_hop_neigh && (!orig_neigh_router)) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: OGM via unknown neighbor!\n");
goto out_neigh;
- }
- is_bidirect = batadv_iv_ogm_calc_tq(orig_node, orig_neigh_node,
ogm_packet, if_incoming,
if_outgoing);
- /* update ranking if it is not a duplicate or has the same
* seqno and similar ttl as the non-duplicate
*/
- orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing);
- if (!orig_ifinfo)
goto out_neigh;
- sameseq = orig_ifinfo->last_real_seqno == ntohl(ogm_packet->seqno);
- similar_ttl = (orig_ifinfo->last_ttl - 3) <= ogm_packet->header.ttl;
- if (is_bidirect && ((dup_status == BATADV_NO_DUP) ||
(sameseq && similar_ttl))) {
batadv_iv_ogm_orig_update(bat_priv, orig_node,
orig_ifinfo, ethhdr,
ogm_packet, if_incoming,
if_outgoing, dup_status);
- }
- batadv_orig_ifinfo_free_ref(orig_ifinfo);
- /* is single hop (direct) neighbor */
- if (is_single_hop_neigh) {
if ((ogm_packet->header.ttl <= 2) &&
(if_incoming != if_outgoing)) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: OGM from secondary interface and wrong outgoing interface\n");
goto out_neigh;
}
The check above, is this just an optimization independant of this patchset or is it somehow needed for the multi interface patchset? Maybe a comment could be added?
/* mark direct link on incoming interface */
batadv_iv_ogm_forward(orig_node, ethhdr, ogm_packet,
is_single_hop_neigh,
is_from_best_next_hop, if_incoming);
Hmm, okay, now we are forwarding OGMs on an interface multiple times. Though you are fixing this in "batman-adv: consider outgoing interface in OGM sending" I guess, this is still a regression here, isn't it?
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Forwarding packet: rebroadcast neighbor packet with direct link flag\n");
goto out_neigh;
- }
- /* multihop originator */
- if (!is_bidirect) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: not received via bidirectional link\n");
goto out_neigh;
- }
- if (dup_status == BATADV_NEIGH_DUP) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: duplicate packet received\n");
goto out_neigh;
- }
- batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Forwarding packet: rebroadcast originator packet\n");
- batadv_iv_ogm_forward(orig_node, ethhdr, ogm_packet,
is_single_hop_neigh, is_from_best_next_hop,
if_incoming);
+out_neigh:
- if ((orig_neigh_node) && (!is_single_hop_neigh))
batadv_orig_node_free_ref(orig_neigh_node);
+out:
- if (router)
batadv_neigh_node_free_ref(router);
- if (router_router)
batadv_neigh_node_free_ref(router_router);
- if (orig_neigh_router)
batadv_neigh_node_free_ref(orig_neigh_router);
- kfree_skb(skb_priv);
+}
Although this is mostly just code moved around, maybe it would be a good idea to split it into several functions now? Would make it easier to debug and find potential regressions introduced by this patch later, wouldn't it?
Maybe batadv_iv_ogm_process() would benefit from some more splits, too?
+/**
- batadv_iv_ogm_process - process an incoming batman iv OGM
- @skb: the skb containing the OGM
- @ogm_offset: offset to the OGM which should be processed (for aggregates)
- @if_incoming: the interface where this packet was receved
- */
+static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset,
struct batadv_hard_iface *if_incoming)
+{
- struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
- struct batadv_orig_node *orig_neigh_node, *orig_node;
- struct batadv_hard_iface *hard_iface;
- struct batadv_ogm_packet *ogm_packet;
- uint32_t if_incoming_seqno;
- int has_directlink_flag;
- struct ethhdr *ethhdr;
maybe change these three to bool while we are at it? and has_directlink_flag, too?
int is_my_oldorig = 0;
int is_my_addr = 0;
int is_my_orig = 0;
ogm_packet = (struct batadv_ogm_packet *)(skb->data + ogm_offset);
ethhdr = eth_hdr(skb);
/* Silently drop when the batman packet is actually not a
- correct packet.
@@ -1312,28 +1514,24 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, * packet in an aggregation. Here we expect that the padding * is always zero (or not 0x01) */
- if (batadv_ogm_packet->header.packet_type != BATADV_IV_OGM)
if (ogm_packet->header.packet_type != BATADV_IV_OGM) return;
/* could be changed by schedule_own_packet() */ if_incoming_seqno = atomic_read(&if_incoming->bat_iv.ogm_seqno);
- if (batadv_ogm_packet->flags & BATADV_DIRECTLINK)
- if (ogm_packet->flags & BATADV_DIRECTLINK) has_directlink_flag = 1; else has_directlink_flag = 0;
- if (batadv_compare_eth(ethhdr->h_source, batadv_ogm_packet->orig))
is_single_hop_neigh = true;
- batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Received BATMAN packet via NB: %pM, IF: %s [%pM] (from OG: %pM, via prev OG: %pM, seqno %u, tq %d, TTL %d, V %d, IDF %d)\n", ethhdr->h_source, if_incoming->net_dev->name,
if_incoming->net_dev->dev_addr, batadv_ogm_packet->orig,
batadv_ogm_packet->prev_sender,
ntohl(batadv_ogm_packet->seqno), batadv_ogm_packet->tq,
batadv_ogm_packet->header.ttl,
batadv_ogm_packet->header.version, has_directlink_flag);
if_incoming->net_dev->dev_addr, ogm_packet->orig,
ogm_packet->prev_sender, ntohl(ogm_packet->seqno),
ogm_packet->tq, ogm_packet->header.ttl,
ogm_packet->header.version, has_directlink_flag);
rcu_read_lock(); list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
@@ -1347,11 +1545,11 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, hard_iface->net_dev->dev_addr)) is_my_addr = 1;
if (batadv_compare_eth(batadv_ogm_packet->orig,
if (batadv_compare_eth(ogm_packet->orig, hard_iface->net_dev->dev_addr)) is_my_orig = 1;
if (batadv_compare_eth(batadv_ogm_packet->prev_sender,
}if (batadv_compare_eth(ogm_packet->prev_sender, hard_iface->net_dev->dev_addr)) is_my_oldorig = 1;
@@ -1382,14 +1580,14 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, */ if (has_directlink_flag && batadv_compare_eth(if_incoming->net_dev->dev_addr,
batadv_ogm_packet->orig)) {
ogm_packet->orig)) { if_num = if_incoming->if_num; offset = if_num * BATADV_NUM_WORDS; spin_lock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock); word = &(orig_neigh_node->bat_iv.bcast_own[offset]); bit_pos = if_incoming_seqno - 2;
bit_pos -= ntohl(batadv_ogm_packet->seqno);
bit_pos -= ntohl(ogm_packet->seqno); batadv_set_bit(word, bit_pos); weight = &orig_neigh_node->bat_iv.bcast_own_sum[if_num]; *weight = bitmap_weight(word,
@@ -1410,144 +1608,34 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, return; }
- if (batadv_ogm_packet->flags & BATADV_NOT_BEST_NEXT_HOP) {
- if (ogm_packet->flags & BATADV_NOT_BEST_NEXT_HOP) { batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Drop packet: ignoring all packets not forwarded from the best next hop (sender: %pM)\n", ethhdr->h_source); return; }
- orig_node = batadv_iv_ogm_orig_get(bat_priv, batadv_ogm_packet->orig);
- orig_node = batadv_iv_ogm_orig_get(bat_priv, ogm_packet->orig); if (!orig_node) return;
- dup_status = batadv_iv_ogm_update_seqnos(ethhdr, batadv_ogm_packet,
if_incoming,
BATADV_IF_DEFAULT);
- batadv_tvlv_ogm_receive(bat_priv, ogm_packet, orig_node);
Hmm, moving the tvlv_ogm processing upwards, in front of all the duplicate/protected/etc. checks seems like a notable, functional change. Though there don't seem to be any problems with the OGM TVLVs we are currently having as far as I can tell, maybe this change could be mentioned in the commit message though?
- if (dup_status == BATADV_PROTECTED) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: packet within seqno protection time (sender: %pM)\n",
ethhdr->h_source);
goto out;
- }
- if (batadv_ogm_packet->tq == 0) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: originator packet with tq equal 0\n");
goto out;
- }
- router = batadv_orig_node_get_router(orig_node);
- if (router) {
orig_node_tmp = router->orig_node;
router_router = batadv_orig_node_get_router(orig_node_tmp);
router_ifinfo = batadv_neigh_ifinfo_get(router,
BATADV_IF_DEFAULT);
- }
- if ((router && router_ifinfo->bat_iv.tq_avg != 0) &&
(batadv_compare_eth(router->addr, ethhdr->h_source)))
is_from_best_next_hop = true;
- prev_sender = batadv_ogm_packet->prev_sender;
- /* avoid temporary routing loops */
- if (router && router_router &&
(batadv_compare_eth(router->addr, prev_sender)) &&
!(batadv_compare_eth(batadv_ogm_packet->orig, prev_sender)) &&
(batadv_compare_eth(router->addr, router_router->addr))) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: ignoring all rebroadcast packets that may make me loop (sender: %pM)\n",
ethhdr->h_source);
goto out;
- }
- batadv_tvlv_ogm_receive(bat_priv, batadv_ogm_packet, orig_node);
- /* if sender is a direct neighbor the sender mac equals
* originator mac
*/
- if (is_single_hop_neigh)
orig_neigh_node = orig_node;
- else
orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv,
ethhdr->h_source);
- if (!orig_neigh_node)
goto out;
- batadv_iv_ogm_process_per_outif(skb, ogm_offset, orig_node,
if_incoming, BATADV_IF_DEFAULT);
- /* Update nc_nodes of the originator */
- batadv_nc_update_nc_node(bat_priv, orig_node, orig_neigh_node,
batadv_ogm_packet, is_single_hop_neigh);
- rcu_read_lock();
- list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
if (hard_iface->if_status != BATADV_IF_ACTIVE)
continue;
- orig_neigh_router = batadv_orig_node_get_router(orig_neigh_node);
if (hard_iface->soft_iface != bat_priv->soft_iface)
continue;
- /* drop packet if sender is not a direct neighbor and if we
* don't route towards it
*/
- if (!is_single_hop_neigh && (!orig_neigh_router)) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: OGM via unknown neighbor!\n");
goto out_neigh;
batadv_iv_ogm_process_per_outif(skb, ogm_offset, orig_node,
}if_incoming, hard_iface);
- is_bidirect = batadv_iv_ogm_calc_tq(orig_node, orig_neigh_node,
batadv_ogm_packet, if_incoming,
BATADV_IF_DEFAULT);
- /* update ranking if it is not a duplicate or has the same
* seqno and similar ttl as the non-duplicate
*/
- sameseq = orig_node->last_real_seqno == ntohl(batadv_ogm_packet->seqno);
- similar_ttl = orig_node->last_ttl - 3 <= batadv_ogm_packet->header.ttl;
- if (is_bidirect && ((dup_status == BATADV_NO_DUP) ||
(sameseq && similar_ttl)))
batadv_iv_ogm_orig_update(bat_priv, orig_node, ethhdr,
batadv_ogm_packet, if_incoming,
BATADV_IF_DEFAULT, tt_buff,
dup_status);
- /* is single hop (direct) neighbor */
- if (is_single_hop_neigh) {
/* mark direct link on incoming interface */
batadv_iv_ogm_forward(orig_node, ethhdr, batadv_ogm_packet,
is_single_hop_neigh,
is_from_best_next_hop, if_incoming);
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Forwarding packet: rebroadcast neighbor packet with direct link flag\n");
goto out_neigh;
- }
- /* multihop originator */
- if (!is_bidirect) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: not received via bidirectional link\n");
goto out_neigh;
- }
- if (dup_status == BATADV_NEIGH_DUP) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: duplicate packet received\n");
goto out_neigh;
- }
- batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Forwarding packet: rebroadcast originator packet\n");
- batadv_iv_ogm_forward(orig_node, ethhdr, batadv_ogm_packet,
is_single_hop_neigh, is_from_best_next_hop,
if_incoming);
-out_neigh:
- if ((orig_neigh_node) && (!is_single_hop_neigh))
batadv_orig_node_free_ref(orig_neigh_node);
-out:
- if (router)
batadv_neigh_node_free_ref(router);
- if (router_router)
batadv_neigh_node_free_ref(router_router);
- if (orig_neigh_router)
batadv_neigh_node_free_ref(orig_neigh_router);
rcu_read_unlock();
batadv_orig_node_free_ref(orig_node);
} @@ -1556,11 +1644,9 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb, struct batadv_hard_iface *if_incoming) { struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
- struct batadv_ogm_packet *batadv_ogm_packet;
- struct ethhdr *ethhdr;
- int buff_pos = 0, packet_len;
- unsigned char *tvlv_buff, *packet_buff;
struct batadv_ogm_packet *ogm_packet; uint8_t *packet_pos;
int ogm_offset; bool ret;
ret = batadv_check_management_packet(skb, if_incoming, BATADV_OGM_HLEN);
@@ -1577,24 +1663,19 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb, batadv_add_counter(bat_priv, BATADV_CNT_MGMT_RX_BYTES, skb->len + ETH_HLEN);
- packet_len = skb_headlen(skb);
- ethhdr = eth_hdr(skb);
- packet_buff = skb->data;
- batadv_ogm_packet = (struct batadv_ogm_packet *)packet_buff;
ogm_offset = 0;
ogm_packet = (struct batadv_ogm_packet *)skb->data;
/* unpack the aggregated packets and process them one by one */
- while (batadv_iv_ogm_aggr_packet(buff_pos, packet_len,
batadv_ogm_packet->tvlv_len)) {
tvlv_buff = packet_buff + buff_pos + BATADV_OGM_HLEN;
- while (batadv_iv_ogm_aggr_packet(ogm_offset, skb_headlen(skb),
ogm_packet->tvlv_len)) {
batadv_iv_ogm_process(skb, ogm_offset, if_incoming);
batadv_iv_ogm_process(ethhdr, batadv_ogm_packet,
tvlv_buff, if_incoming);
ogm_offset += BATADV_OGM_HLEN;
ogm_offset += ntohs(ogm_packet->tvlv_len);
buff_pos += BATADV_OGM_HLEN;
buff_pos += ntohs(batadv_ogm_packet->tvlv_len);
packet_pos = packet_buff + buff_pos;
batadv_ogm_packet = (struct batadv_ogm_packet *)packet_pos;
packet_pos = skb->data + ogm_offset;
ogm_packet = (struct batadv_ogm_packet *)packet_pos;
}
kfree_skb(skb);
@@ -1657,7 +1738,8 @@ static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv,
rcu_read_lock(); hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
neigh_node = batadv_orig_node_get_router(orig_node);
neigh_node = batadv_orig_router_get(orig_node,
BATADV_IF_DEFAULT); if (!neigh_node) continue;
diff --git a/distributed-arp-table.c b/distributed-arp-table.c index 6c8c393..ae0404e 100644 --- a/distributed-arp-table.c +++ b/distributed-arp-table.c @@ -591,7 +591,8 @@ static bool batadv_dat_send_data(struct batadv_priv *bat_priv, if (cand[i].type == BATADV_DAT_CANDIDATE_NOT_FOUND) continue;
neigh_node = batadv_orig_node_get_router(cand[i].orig_node);
neigh_node = batadv_orig_router_get(cand[i].orig_node,
if (!neigh_node) goto free_orig;BATADV_IF_DEFAULT);
diff --git a/gateway_client.c b/gateway_client.c index 71759d0..722a051 100644 --- a/gateway_client.c +++ b/gateway_client.c @@ -131,7 +131,7 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) continue;
orig_node = gw_node->orig_node;
router = batadv_orig_node_get_router(orig_node);
if (!router) continue;router = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT);
@@ -246,7 +246,8 @@ void batadv_gw_election(struct batadv_priv *bat_priv) if (next_gw) { sprintf(gw_addr, "%pM", next_gw->orig_node->orig);
router = batadv_orig_node_get_router(next_gw->orig_node);
router = batadv_orig_router_get(next_gw->orig_node,
if (!router) { batadv_gw_deselect(bat_priv); goto out;BATADV_IF_DEFAULT);
@@ -315,7 +316,7 @@ void batadv_gw_check_election(struct batadv_priv *bat_priv, if (!curr_gw_orig) goto deselect;
- router_gw = batadv_orig_node_get_router(curr_gw_orig);
- router_gw = batadv_orig_router_get(curr_gw_orig, BATADV_IF_DEFAULT); if (!router_gw) goto deselect;
@@ -328,7 +329,7 @@ void batadv_gw_check_election(struct batadv_priv *bat_priv, if (curr_gw_orig == orig_node) goto out;
- router_orig = batadv_orig_node_get_router(orig_node);
- router_orig = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT); if (!router_orig) goto out;
@@ -556,7 +557,7 @@ static int batadv_write_buffer_text(struct batadv_priv *bat_priv, struct batadv_neigh_ifinfo *router_ifinfo; int ret = -1;
- router = batadv_orig_node_get_router(gw_node->orig_node);
- router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT); if (!router) goto out;
diff --git a/icmp_socket.c b/icmp_socket.c index 29ae4ef..6b15efc 100644 --- a/icmp_socket.c +++ b/icmp_socket.c @@ -217,7 +217,8 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff, if (!orig_node) goto dst_unreach;
neigh_node = batadv_orig_node_get_router(orig_node);
neigh_node = batadv_orig_router_get(orig_node,
if (!neigh_node) goto dst_unreach;BATADV_IF_DEFAULT);
diff --git a/network-coding.c b/network-coding.c index 351e199..792a072 100644 --- a/network-coding.c +++ b/network-coding.c @@ -1019,12 +1019,17 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv, int coded_size = sizeof(*coded_packet); int header_add = coded_size - unicast_size;
- router_neigh = batadv_orig_node_get_router(neigh_node->orig_node);
/* TODO: do we need to consider the outgoing interface for
* coded packets?
*/
router_neigh = batadv_orig_router_get(neigh_node->orig_node,
BATADV_IF_DEFAULT);
if (!router_neigh) goto out;
neigh_tmp = nc_packet->neigh_node;
- router_coding = batadv_orig_node_get_router(neigh_tmp->orig_node);
- router_coding = batadv_orig_router_get(neigh_tmp->orig_node,
if (!router_coding) goto out;BATADV_IF_DEFAULT);
diff --git a/originator.c b/originator.c index acbd254..62691d0 100644 --- a/originator.c +++ b/originator.c @@ -227,14 +227,30 @@ void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node) call_rcu(&neigh_node->rcu, batadv_neigh_node_free_rcu); }
-/* increases the refcounter of a found router */ +/**
- batadv_orig_node_get_router - router to the originator depending on iface
- @orig_node: the orig node for the router
- @if_received: the interface where the packet to be transmitted was received
Yet another naming for "if_incoming"? (there are few more occurences of "if_received" introduced in this patch)
- Returns the neighbor which should be router for this orig_node/iface.
- The object is returned with refcounter increased by 1.
- */
struct batadv_neigh_node * -batadv_orig_node_get_router(struct batadv_orig_node *orig_node) +batadv_orig_router_get(struct batadv_orig_node *orig_node,
const struct batadv_hard_iface *if_received)
{
- struct batadv_neigh_node *router;
struct batadv_orig_ifinfo *orig_ifinfo;
struct batadv_neigh_node *router = NULL;
rcu_read_lock();
- router = rcu_dereference(orig_node->router);
hlist_for_each_entry_rcu(orig_ifinfo, &orig_node->ifinfo_list, list) {
if (orig_ifinfo->if_outgoing != if_received)
continue;
router = rcu_dereference(orig_ifinfo->router);
break;
}
if (router && !atomic_inc_not_zero(&router->refcount)) router = NULL;
@@ -244,6 +260,86 @@ batadv_orig_node_get_router(struct batadv_orig_node *orig_node) }
/**
- batadv_orig_ifinfo_get - find the ifinfo from an orig_node
- @orig_node: the orig node to be queried
- @if_received: the interface for which the ifinfo should be acquired
- Returns the requested orig_ifinfo or NULL if not found.
- The object is returned with refcounter increased by 1.
- */
+struct batadv_orig_ifinfo * +batadv_orig_ifinfo_get(struct batadv_orig_node *orig_node,
struct batadv_hard_iface *if_received)
+{
- struct batadv_orig_ifinfo *tmp, *orig_ifinfo = NULL;
- rcu_read_lock();
- hlist_for_each_entry_rcu(tmp, &orig_node->ifinfo_list,
list) {
if (tmp->if_outgoing != if_received)
continue;
if (!atomic_inc_not_zero(&tmp->refcount))
continue;
orig_ifinfo = tmp;
break;
- }
- rcu_read_unlock();
- return orig_ifinfo;
+}
+/**
- batadv_orig_ifinfo_new - search and possibly create an orig_ifinfo object
- @orig_node: the orig node to be queried
- @if_received: the interface for which the ifinfo should be acquired
- Returns NULL in case of failure or the orig_ifinfo object for the if_outgoing
- interface otherwise. The object is created and added to the list
- if it does not exist.
- The object is returned with refcounter increased by 1.
- */
+struct batadv_orig_ifinfo * +batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node,
struct batadv_hard_iface *if_received)
+{
- struct batadv_orig_ifinfo *orig_ifinfo = NULL;
- unsigned long reset_time;
- spin_lock_bh(&orig_node->neigh_list_lock);
- orig_ifinfo = batadv_orig_ifinfo_get(orig_node, if_received);
- if (orig_ifinfo)
goto out;
- orig_ifinfo = kzalloc(sizeof(*orig_ifinfo), GFP_ATOMIC);
- if (!orig_ifinfo)
goto out;
- if (if_received != BATADV_IF_DEFAULT &&
!atomic_inc_not_zero(&if_received->refcount)) {
kfree(orig_ifinfo);
orig_ifinfo = NULL;
goto out;
- }
- reset_time = jiffies - 1;
- reset_time -= msecs_to_jiffies(BATADV_RESET_PROTECTION_MS);
- orig_ifinfo->batman_seqno_reset = reset_time;
- orig_ifinfo->if_outgoing = if_received;
- INIT_HLIST_NODE(&orig_ifinfo->list);
- atomic_set(&orig_ifinfo->refcount, 2);
- hlist_add_head_rcu(&orig_ifinfo->list,
&orig_node->ifinfo_list);
+out:
- spin_unlock_bh(&orig_node->neigh_list_lock);
- return orig_ifinfo;
+}
+/**
- batadv_neigh_ifinfo_get - find the ifinfo from an neigh_node
- @neigh_node: the neigh node to be queried
- @if_outgoing: the interface for which the ifinfo should be acquired
@@ -356,11 +452,50 @@ out: return neigh_node; }
+/* batadv_orig_ifinfo_free_rcu - free the orig_ifinfo object
- @rcu: rcu pointer of the orig_ifinfo object
- */
+static void batadv_orig_ifinfo_free_rcu(struct rcu_head *rcu) +{
- struct batadv_orig_ifinfo *orig_ifinfo;
- orig_ifinfo = container_of(rcu, struct batadv_orig_ifinfo, rcu);
- if (orig_ifinfo->if_outgoing != BATADV_IF_DEFAULT)
batadv_hardif_free_ref_now(orig_ifinfo->if_outgoing);
- kfree(orig_ifinfo);
+}
+/**
- batadv_orig_ifinfo_free_ref - decrement the refcounter and possibly free
- the orig_ifinfo (without rcu callback)
- @orig_ifinfo: the orig_ifinfo object to release
- */
+static void +batadv_orig_ifinfo_free_ref_now(struct batadv_orig_ifinfo *orig_ifinfo) +{
- if (atomic_dec_and_test(&orig_ifinfo->refcount))
batadv_orig_ifinfo_free_rcu(&orig_ifinfo->rcu);
+}
+/**
- batadv_orig_ifinfo_free_ref - decrement the refcounter and possibly free
- the orig_ifinfo
- @orig_ifinfo: the orig_ifinfo object to release
- */
+void batadv_orig_ifinfo_free_ref(struct batadv_orig_ifinfo *orig_ifinfo) +{
- if (atomic_dec_and_test(&orig_ifinfo->refcount))
call_rcu(&orig_ifinfo->rcu, batadv_orig_ifinfo_free_rcu);
+}
static void batadv_orig_node_free_rcu(struct rcu_head *rcu) { struct hlist_node *node_tmp; struct batadv_neigh_node *neigh_node; struct batadv_orig_node *orig_node;
struct batadv_orig_ifinfo *orig_ifinfo;
orig_node = container_of(rcu, struct batadv_orig_node, rcu);
@@ -373,6 +508,11 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu) batadv_neigh_node_free_ref_now(neigh_node); }
hlist_for_each_entry_safe(orig_ifinfo, node_tmp,
&orig_node->ifinfo_list, list) {
hlist_del_rcu(&orig_ifinfo->list);
batadv_orig_ifinfo_free_ref_now(orig_ifinfo);
} spin_unlock_bh(&orig_node->neigh_list_lock);
/* Free nc_nodes */
@@ -470,6 +610,7 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv,
INIT_HLIST_HEAD(&orig_node->neigh_list); INIT_LIST_HEAD(&orig_node->vlan_list);
- INIT_HLIST_HEAD(&orig_node->ifinfo_list); spin_lock_init(&orig_node->bcast_seqno_lock); spin_lock_init(&orig_node->neigh_list_lock); spin_lock_init(&orig_node->tt_buff_lock);
@@ -485,13 +626,11 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, orig_node->bat_priv = bat_priv; memcpy(orig_node->orig, addr, ETH_ALEN); batadv_dat_init_orig_node_addr(orig_node);
orig_node->router = NULL; atomic_set(&orig_node->last_ttvn, 0); orig_node->tt_buff = NULL; orig_node->tt_buff_len = 0; reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS); orig_node->bcast_seqno_reset = reset_time;
orig_node->batman_seqno_reset = reset_time;
/* create a vlan object for the "untagged" LAN */ vlan = batadv_orig_node_vlan_new(orig_node, BATADV_NO_FLAGS);
@@ -516,6 +655,52 @@ free_orig_node: }
/**
- batadv_purge_orig_ifinfo - purge ifinfo entries from originator
- @bat_priv: the bat priv with all the soft interface information
- @orig_node: orig node which is to be checked
- Returns true if any ifinfo entry was purged, false otherwise.
- */
+static bool +batadv_purge_orig_ifinfo(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node)
+{
- struct batadv_orig_ifinfo *orig_ifinfo;
- struct batadv_hard_iface *if_outgoing;
- struct hlist_node *node_tmp;
- bool ifinfo_purged = false;
- spin_lock_bh(&orig_node->neigh_list_lock);
- /* for all neighbors towards this originator ... */
- hlist_for_each_entry_safe(orig_ifinfo, node_tmp,
&orig_node->ifinfo_list, list) {
if_outgoing = orig_ifinfo->if_outgoing;
if (!if_outgoing)
continue;
if ((if_outgoing->if_status != BATADV_IF_INACTIVE) &&
(if_outgoing->if_status != BATADV_IF_NOT_IN_USE) &&
(if_outgoing->if_status != BATADV_IF_TO_BE_REMOVED))
continue;
Hm, if we aren't purging them now, when are we going to do that instead? Later we can't because the orig_node and its ifinfo list is gone, can we?
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"router/ifinfo purge: originator %pM, iface: %s\n",
orig_node->orig, if_outgoing->net_dev->name);
ifinfo_purged = true;
hlist_del_rcu(&orig_ifinfo->list);
batadv_orig_ifinfo_free_ref(orig_ifinfo);
- }
- spin_unlock_bh(&orig_node->neigh_list_lock);
- return ifinfo_purged;
+}
+/**
- batadv_purge_orig_neighbors - purges neighbors from originator
- @bat_priv: the bat priv with all the soft interface information
- @orig_node: orig node which is to be checked
@@ -599,6 +784,8 @@ static bool batadv_purge_orig_node(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node) { struct batadv_neigh_node *best_neigh_node;
struct batadv_hard_iface *hard_iface;
bool changed;
if (batadv_has_timed_out(orig_node->last_seen, 2 * BATADV_PURGE_TIMEOUT)) {
@@ -608,12 +795,34 @@ static bool batadv_purge_orig_node(struct batadv_priv *bat_priv, jiffies_to_msecs(orig_node->last_seen)); return true; }
- if (!batadv_purge_orig_neighbors(bat_priv, orig_node))
changed = batadv_purge_orig_ifinfo(bat_priv, orig_node);
changed = changed || batadv_purge_orig_neighbors(bat_priv, orig_node);
if (!changed) return false;
/* first for NULL ... */ best_neigh_node = batadv_find_best_neighbor(bat_priv, orig_node, BATADV_IF_DEFAULT);
- batadv_update_route(bat_priv, orig_node, best_neigh_node);
batadv_update_route(bat_priv, orig_node, BATADV_IF_DEFAULT,
best_neigh_node);
/* ... then for all other interfaces. */
rcu_read_lock();
list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
if (hard_iface->if_status != BATADV_IF_ACTIVE)
continue;
if (hard_iface->soft_iface != bat_priv->soft_iface)
continue;
best_neigh_node = batadv_find_best_neighbor(bat_priv,
orig_node,
hard_iface);
batadv_update_route(bat_priv, orig_node, hard_iface,
best_neigh_node);
}
rcu_read_unlock();
return false;
} diff --git a/originator.h b/originator.h index 76a8de6..404f7cb 100644 --- a/originator.h +++ b/originator.h @@ -36,7 +36,8 @@ batadv_neigh_node_new(struct batadv_hard_iface *hard_iface, struct batadv_orig_node *orig_node); void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node); struct batadv_neigh_node * -batadv_orig_node_get_router(struct batadv_orig_node *orig_node); +batadv_orig_router_get(struct batadv_orig_node *orig_node,
const struct batadv_hard_iface *if_received);
struct batadv_neigh_ifinfo * batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh, struct batadv_hard_iface *if_outgoing); @@ -44,6 +45,15 @@ struct batadv_neigh_ifinfo * batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh, struct batadv_hard_iface *if_outgoing); void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo);
+struct batadv_orig_ifinfo * +batadv_orig_ifinfo_get(struct batadv_orig_node *orig_node,
struct batadv_hard_iface *if_received);
+struct batadv_orig_ifinfo * +batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node,
struct batadv_hard_iface *if_received);
+void batadv_orig_ifinfo_free_ref(struct batadv_orig_ifinfo *orig_ifinfo);
int batadv_orig_seq_print_text(struct seq_file *seq, void *offset); int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, int max_if_num); diff --git a/routing.c b/routing.c index 360a5b9..da6741a 100644 --- a/routing.c +++ b/routing.c @@ -35,13 +35,29 @@ static int batadv_route_unicast_packet(struct sk_buff *skb, struct batadv_hard_iface *recv_if);
+/* _batadv_update_route - set the router for this originator
- @bat_priv: the bat priv with all the soft interface information
- @orig_node: orig node which is to be configured
- @recv_if: the receive interface for which this route is set
- @neigh_node: neighbor which should be the next router
- This function does not perform any error checks
- */
static void _batadv_update_route(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node,
struct batadv_hard_iface *recv_if, struct batadv_neigh_node *neigh_node)
{
- struct batadv_orig_ifinfo *orig_ifinfo; struct batadv_neigh_node *curr_router;
- curr_router = batadv_orig_node_get_router(orig_node);
- orig_ifinfo = batadv_orig_ifinfo_get(orig_node, recv_if);
- if (!orig_ifinfo)
return;
Looks like there is an rcu_read_lock() missing for the following three lines:
curr_router = rcu_dereference(orig_ifinfo->router);
if (curr_router && !atomic_inc_not_zero(&curr_router->refcount))
curr_router = NULL;
/* route deleted */ if ((curr_router) && (!neigh_node)) {
@@ -71,16 +87,25 @@ static void _batadv_update_route(struct batadv_priv *bat_priv, neigh_node = NULL;
spin_lock_bh(&orig_node->neigh_list_lock);
- rcu_assign_pointer(orig_node->router, neigh_node);
rcu_assign_pointer(orig_ifinfo->router, neigh_node); spin_unlock_bh(&orig_node->neigh_list_lock);
batadv_orig_ifinfo_free_ref(orig_ifinfo);
/* decrease refcount of previous best neighbor */ if (curr_router) batadv_neigh_node_free_ref(curr_router);
}
+/**
- batadv_update_route - set the router for this originator
- @bat_priv: the bat priv with all the soft interface information
- @orig_node: orig node which is to be configured
- @recv_if: the receive interface for which this route is set
- @neigh_node: neighbor which should be the next router
- */
void batadv_update_route(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node,
struct batadv_hard_iface *recv_if, struct batadv_neigh_node *neigh_node)
{ struct batadv_neigh_node *router = NULL; @@ -88,10 +113,10 @@ void batadv_update_route(struct batadv_priv *bat_priv, if (!orig_node) goto out;
- router = batadv_orig_node_get_router(orig_node);
router = batadv_orig_router_get(orig_node, recv_if);
if (router != neigh_node)
_batadv_update_route(bat_priv, orig_node, neigh_node);
_batadv_update_route(bat_priv, orig_node, recv_if, neigh_node);
out: if (router) @@ -408,7 +433,7 @@ batadv_find_router(struct batadv_priv *bat_priv, if (!orig_node) return NULL;
- router = batadv_orig_node_get_router(orig_node);
router = batadv_orig_router_get(orig_node, recv_if);
/* TODO: fill this later with new bonding mechanism */
diff --git a/routing.h b/routing.h index b8fed80..7a7c6e9 100644 --- a/routing.h +++ b/routing.h @@ -25,6 +25,7 @@ bool batadv_check_management_packet(struct sk_buff *skb, int header_len); void batadv_update_route(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node,
struct batadv_hard_iface *recv_if, struct batadv_neigh_node *neigh_node);
int batadv_recv_icmp_packet(struct sk_buff *skb, struct batadv_hard_iface *recv_if); diff --git a/translation-table.c b/translation-table.c index 135c165..1b2a615 100644 --- a/translation-table.c +++ b/translation-table.c @@ -1385,7 +1385,8 @@ batadv_transtable_best_orig(struct batadv_priv *bat_priv,
head = &tt_global_entry->orig_list; hlist_for_each_entry_rcu(orig_entry, head, list) {
router = batadv_orig_node_get_router(orig_entry->orig_node);
router = batadv_orig_router_get(orig_entry->orig_node,
if (!router) continue;BATADV_IF_DEFAULT);
diff --git a/types.h b/types.h index 11d448f..167c3a5 100644 --- a/types.h +++ b/types.h @@ -90,6 +90,27 @@ struct batadv_hard_iface { struct work_struct cleanup_work; };
+/* struct batadv_orig_ifinfo - originator info per outgoing interface
- @list: list node for orig_node::ifinfo_list
- @if_outgoing: pointer to outgoing hard interface
- @router: router that should be used to reach this originator
- @last_real_seqno: last and best known sequence number
- @last_ttl: ttl of last received packet
- @batman_seqno_reset: time when the batman seqno window was reset
- @refcount: number of contexts the object is used
- @rcu: struct used for freeing in an RCU-safe manner
- */
+struct batadv_orig_ifinfo {
- struct hlist_node list;
- struct batadv_hard_iface *if_outgoing;
- struct batadv_neigh_node __rcu *router; /* rcu protected pointer */
- uint32_t last_real_seqno;
- uint8_t last_ttl;
- unsigned long batman_seqno_reset;
- atomic_t refcount;
- struct rcu_head rcu;
+};
/**
- struct batadv_frag_table_entry - head in the fragment buffer table
- @head: head of list with fragments
@@ -165,11 +186,10 @@ struct batadv_orig_bat_iv {
- struct batadv_orig_node - structure for orig_list maintaining nodes of mesh
- @orig: originator ethernet address
- @primary_addr: hosts primary interface address
- @router: router that should be used to reach this originator
- @ifinfo_list: list for routers per outgoing interface
- @batadv_dat_addr_t: address of the orig node in the distributed hash
- @last_seen: time when last packet from this node was received
- @bcast_seqno_reset: time when the broadcast seqno window was reset
- @batman_seqno_reset: time when the batman seqno window was reset
- @capabilities: announced capabilities of this originator
- @last_ttvn: last seen translation table version number
- @tt_buff: last tt changeset this node received from the orig node
@@ -182,8 +202,6 @@ struct batadv_orig_bat_iv {
- made up by two operations (data structure update and metdata -CRC/TTVN-
- recalculation) and they have to be executed atomically in order to avoid
- another thread to read the table/metadata between those.
- @last_real_seqno: last and best known sequence number
- @last_ttl: ttl of last received packet
- @bcast_bits: bitfield containing the info which payload broadcast originated
- from this orig node this host already has seen (relative to
- last_bcast_seqno)
@@ -208,13 +226,12 @@ struct batadv_orig_bat_iv { struct batadv_orig_node { uint8_t orig[ETH_ALEN]; uint8_t primary_addr[ETH_ALEN];
- struct batadv_neigh_node __rcu *router; /* rcu protected pointer */
- struct hlist_head ifinfo_list;
#ifdef CONFIG_BATMAN_ADV_DAT batadv_dat_addr_t dat_addr; #endif unsigned long last_seen; unsigned long bcast_seqno_reset;
- unsigned long batman_seqno_reset; uint8_t capabilities; atomic_t last_ttvn; unsigned char *tt_buff;
@@ -223,8 +240,6 @@ struct batadv_orig_node { bool tt_initialised; /* prevents from changing the table while reading it */ spinlock_t tt_lock;
- uint32_t last_real_seqno;
- uint8_t last_ttl; DECLARE_BITMAP(bcast_bits, BATADV_TQ_LOCAL_WINDOW_SIZE); uint32_t last_bcast_seqno; struct hlist_head neigh_list;
-- 1.7.10.4
Cheers, Linus
Hey Linus,
again, all suggestions not commented are approved. Some comments inline (BTW, it would be enough if you just keep the hunk you comment and don't keep the whole patchset in the reply).
- @if_incoming: the interface where this packet was receved
- @if_outgoing: the interface for which the packet should be considered
- */
+static void +batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset, + struct batadv_orig_node *orig_node,
struct batadv_hard_iface *if_incoming,
struct batadv_hard_iface *if_outgoing)
{
struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
struct batadv_hard_iface *hard_iface;
struct batadv_orig_node *orig_neigh_node, *orig_node, *orig_node_tmp;
struct batadv_neigh_node *router = NULL, *router_router = NULL;
struct batadv_orig_node *orig_neigh_node, *orig_node_tmp;
struct batadv_orig_ifinfo *orig_ifinfo;
struct batadv_neigh_node *orig_neigh_router = NULL; struct batadv_neigh_ifinfo *router_ifinfo = NULL;
- int has_directlink_flag;
- int is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;
- int is_bidirect;
- bool is_single_hop_neigh = false;
- bool is_from_best_next_hop = false;
- int sameseq, similar_ttl;
struct batadv_ogm_packet *ogm_packet;
enum batadv_dup_status dup_status;
- uint32_t if_incoming_seqno;
bool is_from_best_next_hop = false;
bool is_single_hop_neigh = false;
bool sameseq, similar_ttl;
struct sk_buff *skb_priv;
struct ethhdr *ethhdr;
uint8_t *prev_sender;
int is_bidirect;
/* create a private copy of the skb, as some functions change tq
value
* and/or flags.
*/
- skb_priv = skb_copy(skb, GFP_ATOMIC);
- if (!skb_priv)
return;
- ethhdr = eth_hdr(skb_priv);
- ogm_packet = (struct batadv_ogm_packet *)(skb_priv->data +
ogm_offset);
- dup_status = batadv_iv_ogm_update_seqnos(ethhdr, ogm_packet,
if_incoming, if_outgoing);
To avoid redundant code execution, move this if statement to the calling function maybe?
No, this has to be called per outgoing interface.
- if (batadv_compare_eth(ethhdr->h_source, ogm_packet->orig))
is_single_hop_neigh = true;
- if (dup_status == BATADV_PROTECTED) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: packet within seqno protection time
(sender:
%pM)\n", + ethhdr->h_source);
goto out;
- }
Move this if statement to the calling function maybe?
... depends on dup_status.
- if (ogm_packet->tq == 0) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: originator packet with tq equal 0\n");
goto out;
- }
- router = batadv_orig_router_get(orig_node, if_outgoing);
- if (router) {
orig_node_tmp = router->orig_node;
router_router = batadv_orig_router_get(router->orig_node,
if_outgoing);
router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing);
- }
- if ((router_ifinfo && router_ifinfo->bat_iv.tq_avg != 0) &&
(batadv_compare_eth(router->addr, ethhdr->h_source)))
is_from_best_next_hop = true;
- prev_sender = ogm_packet->prev_sender;
- /* avoid temporary routing loops */
- if (router && router_router &&
(batadv_compare_eth(router->addr, prev_sender)) &&
!(batadv_compare_eth(ogm_packet->orig, prev_sender)) &&
(batadv_compare_eth(router->addr, router_router->addr))) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: ignoring all rebroadcast packets that
may make me
loop (sender: %pM)\n", + ethhdr->h_source);
goto out;
- }
Move this to ...
Nope, this comes after the duplicate check/filling of the respective bitfields. As we can't move the dupstatus changing the order is not a good idea imho.
- /* if sender is a direct neighbor the sender mac equals
* originator mac
*/
- if (is_single_hop_neigh)
orig_neigh_node = orig_node;
- else
orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv,
ethhdr->h_source);
- if (!orig_neigh_node)
goto out;
- /* Update nc_nodes of the originator */
- batadv_nc_update_nc_node(bat_priv, orig_node, orig_neigh_node,
ogm_packet, is_single_hop_neigh);
... this to the calling function, maybe?
Not sure here, but I'd rather not fiddle with network coding here.
To summarise here: I wanted to split the ogm_process function between the outif-independent part and the outif-dependent part while keeping the order of the processing as it was before - to not introduce new bugs here. Therefore I prefer to keep the order, even if some checks are done twice after the bitfield setting.
- orig_neigh_router = batadv_orig_router_get(orig_neigh_node,
if_outgoing);
- /* drop packet if sender is not a direct neighbor and if we
* don't route towards it
*/
- if (!is_single_hop_neigh && (!orig_neigh_router)) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: OGM via unknown neighbor!\n");
goto out_neigh;
- }
- is_bidirect = batadv_iv_ogm_calc_tq(orig_node, orig_neigh_node,
ogm_packet, if_incoming,
if_outgoing);
- /* update ranking if it is not a duplicate or has the same
* seqno and similar ttl as the non-duplicate
*/
- orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing);
- if (!orig_ifinfo)
goto out_neigh;
- sameseq = orig_ifinfo->last_real_seqno == ntohl(ogm_packet->seqno);
- similar_ttl = (orig_ifinfo->last_ttl - 3) <= ogm_packet->header.ttl;
- if (is_bidirect && ((dup_status == BATADV_NO_DUP) ||
(sameseq && similar_ttl))) {
batadv_iv_ogm_orig_update(bat_priv, orig_node,
orig_ifinfo, ethhdr,
ogm_packet, if_incoming,
if_outgoing, dup_status);
- }
- batadv_orig_ifinfo_free_ref(orig_ifinfo);
- /* is single hop (direct) neighbor */
- if (is_single_hop_neigh) {
if ((ogm_packet->header.ttl <= 2) &&
(if_incoming != if_outgoing)) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: OGM from secondary interface and
wrong outgoing
interface\n"); + goto out_neigh;
}
The check above, is this just an optimization independant of this patchset or is it somehow needed for the multi interface patchset? Maybe a comment could be added?
Yeah this is required now as the function is called multiple times, I'll add a comment.
/* mark direct link on incoming interface */
batadv_iv_ogm_forward(orig_node, ethhdr, ogm_packet,
is_single_hop_neigh,
is_from_best_next_hop, if_incoming);
Hmm, okay, now we are forwarding OGMs on an interface multiple times. Though you are fixing this in "batman-adv: consider outgoing interface in OGM sending" I guess, this is still a regression here, isn't it?
Well, yes, you are probably right. I'll add a check here to only schedule for the default interface and will remove in the next one again. The "consider outgoing interface" patch is not trivial so I wanted to keep it seperate.
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Forwarding packet: rebroadcast neighbor packet with
direct link
flag\n"); + goto out_neigh;
- }
- /* multihop originator */
- if (!is_bidirect) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: not received via bidirectional
link\n");
goto out_neigh;
- }
- if (dup_status == BATADV_NEIGH_DUP) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: duplicate packet received\n");
goto out_neigh;
- }
- batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Forwarding packet: rebroadcast originator packet\n");
- batadv_iv_ogm_forward(orig_node, ethhdr, ogm_packet,
is_single_hop_neigh, is_from_best_next_hop,
if_incoming);
+out_neigh:
- if ((orig_neigh_node) && (!is_single_hop_neigh))
batadv_orig_node_free_ref(orig_neigh_node);
+out:
- if (router)
batadv_neigh_node_free_ref(router);
- if (router_router)
batadv_neigh_node_free_ref(router_router);
- if (orig_neigh_router)
batadv_neigh_node_free_ref(orig_neigh_router);
- kfree_skb(skb_priv);
+}
Although this is mostly just code moved around, maybe it would be a good idea to split it into several functions now? Would make it easier to debug and find potential regressions introduced by this patch later, wouldn't it?
Maybe batadv_iv_ogm_process() would benefit from some more splits, too?
Apart from my personal laziness, the idea was to actually keep the code as much as it was as possible to make it easier to compare to the previous one. I think doing refactoring now would even complicate the review later.
@@ -1382,14 +1580,14 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr,
*/
if (has_directlink_flag && batadv_compare_eth(if_incoming->net_dev->dev_addr,
batadv_ogm_packet->orig)) {
ogm_packet->orig)) { if_num = if_incoming->if_num; offset = if_num * BATADV_NUM_WORDS;
spin_lock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock); word = &(orig_neigh_node->bat_iv.bcast_own[offset]); bit_pos = if_incoming_seqno - 2;
bit_pos -= ntohl(batadv_ogm_packet->seqno);
bit_pos -= ntohl(ogm_packet->seqno); batadv_set_bit(word, bit_pos); weight = &orig_neigh_node->bat_iv.bcast_own_sum[if_num]; *weight = bitmap_weight(word,
@@ -1410,144 +1608,34 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr,
return;
}
- if (batadv_ogm_packet->flags & BATADV_NOT_BEST_NEXT_HOP) {
if (ogm_packet->flags & BATADV_NOT_BEST_NEXT_HOP) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: ignoring all packets not forwarded from the
best
next hop (sender: %pM)\n", ethhdr->h_source);
return;
}
- orig_node = batadv_iv_ogm_orig_get(bat_priv, batadv_ogm_packet->orig);
orig_node = batadv_iv_ogm_orig_get(bat_priv, ogm_packet->orig);
if (!orig_node)
return;
- dup_status = batadv_iv_ogm_update_seqnos(ethhdr, batadv_ogm_packet,
if_incoming,
BATADV_IF_DEFAULT);
- batadv_tvlv_ogm_receive(bat_priv, ogm_packet, orig_node);
Hmm, moving the tvlv_ogm processing upwards, in front of all the duplicate/protected/etc. checks seems like a notable, functional change. Though there don't seem to be any problems with the OGM TVLVs we are currently having as far as I can tell, maybe this change could be mentioned in the commit message though?
You are right ... I'll better keep it at the original place and just perform that for the default outgoing interface.
- batadv_purge_orig_ifinfo - purge ifinfo entries from originator
- @bat_priv: the bat priv with all the soft interface information
- @orig_node: orig node which is to be checked
- Returns true if any ifinfo entry was purged, false otherwise.
- */
+static bool +batadv_purge_orig_ifinfo(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node)
+{
- struct batadv_orig_ifinfo *orig_ifinfo;
- struct batadv_hard_iface *if_outgoing;
- struct hlist_node *node_tmp;
- bool ifinfo_purged = false;
- spin_lock_bh(&orig_node->neigh_list_lock);
- /* for all neighbors towards this originator ... */
- hlist_for_each_entry_safe(orig_ifinfo, node_tmp,
&orig_node->ifinfo_list, list) {
if_outgoing = orig_ifinfo->if_outgoing;
if (!if_outgoing)
continue;
if ((if_outgoing->if_status != BATADV_IF_INACTIVE) &&
(if_outgoing->if_status != BATADV_IF_NOT_IN_USE) &&
(if_outgoing->if_status != BATADV_IF_TO_BE_REMOVED))
continue;
Hm, if we aren't purging them now, when are we going to do that instead? Later we can't because the orig_node and its ifinfo list is gone, can we?
The purge function is there to remove obsolete ifinfos of the orig node, just as purge_orig_node checks and removes obsolete neighbors and other parts (or the whole orig node if it timed out).
I'll update the kerneldoc and will also add kerneldoc to batadv_purge_orig_node, this is not very clear.
Thanks, Simon
Broken kernel doc continued :).
On Wed, Oct 30, 2013 at 03:01:48PM +0100, Simon Wunderlich wrote:
From: Simon Wunderlich simon@open-mesh.com
For the network wide multi interface optimization there are different routers for each outgoing interface (outgoing from the OGM perspective, incoming for payload traffic). To reflect this, change the router and associated data to a list of routers.
While at it, rename batadv_orig_node_get_router() to batadv_orig_router_get() to follow the new naming scheme.
Signed-off-by: Simon Wunderlich simon@open-mesh.com
Changes to PATCH:
- change orig_ifinfo locking from implicit rcu style to refcount locking
- pass skb instead of buffers to the OGM processing functions
- remove unused tt_buff pointer from some bat_iv functions
- rename batadv_orig_node_ifinfo* to batadv_orig_ifinfo* - name is still long enough
- rename batadv_orig_node_get_router to batadv_orig_router_get
- rename batadv_orig_node_get_ifinfo to batadv_orig_ifinfo_get
Changes to RFCv2:
- various style changes
- remove unneccesary batadv_orig_node_set_router prototype
Changes to RFC:
- rebase on current master
- remove useless goto
- split out batman_seqno_reset as well to avoid false seqno window protections
bat_iv_ogm.c | 456 ++++++++++++++++++++++++++++------------------- distributed-arp-table.c | 3 +- gateway_client.c | 11 +- icmp_socket.c | 3 +- network-coding.c | 9 +- originator.c | 225 ++++++++++++++++++++++- originator.h | 12 +- routing.c | 35 +++- routing.h | 1 + translation-table.c | 3 +- types.h | 31 +++- 11 files changed, 570 insertions(+), 219 deletions(-)
diff --git a/bat_iv_ogm.c b/bat_iv_ogm.c index 66ce1a7..3ba2402 100644 --- a/bat_iv_ogm.c +++ b/bat_iv_ogm.c @@ -908,21 +908,21 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
- originator
- @bat_priv: the bat priv with all the soft interface information
- @orig_node: the orig node who originally emitted the ogm packet
- @orig_ifinfo: ifinfo for the outgoing interface of the orig_node
- @ethhdr: Ethernet header of the OGM
- @batadv_ogm_packet: the ogm packet
- @if_incoming: interface where the packet was received
- @if_outgoing: interface for which the retransmission should be considered
*/
- @tt_buff: pointer to the tt buffer
- @dup_status: the duplicate status of this ogm packet.
static void batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node,
struct batadv_orig_ifinfo *orig_ifinfo, const struct ethhdr *ethhdr, const struct batadv_ogm_packet *batadv_ogm_packet, struct batadv_hard_iface *if_incoming, struct batadv_hard_iface *if_outgoing,
const unsigned char *tt_buff, enum batadv_dup_status dup_status)
{ struct batadv_neigh_ifinfo *neigh_ifinfo = NULL; @@ -1004,22 +1004,30 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, spin_unlock_bh(&neigh_node->ifinfo_lock);
if (dup_status == BATADV_NO_DUP) {
orig_node->last_ttl = batadv_ogm_packet->header.ttl;
orig_ifinfo->last_ttl = batadv_ogm_packet->header.ttl;
neigh_ifinfo->last_ttl = batadv_ogm_packet->header.ttl; }
/* if this neighbor already is our next hop there is nothing
- to change
*/
- router = batadv_orig_node_get_router(orig_node);
- router = batadv_orig_router_get(orig_node, if_outgoing); if (router == neigh_node) goto out;
- router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing);
- /* if this neighbor does not offer a better TQ we won't consider it */
- if (router_ifinfo &&
(router_ifinfo->bat_iv.tq_avg > neigh_ifinfo->bat_iv.tq_avg))
goto out;
if (router) {
router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing);
/* if this neighbor does not offer a better TQ we won't
* consider it
*/
if (!router_ifinfo)
goto out;
if (router_ifinfo->bat_iv.tq_avg > neigh_ifinfo->bat_iv.tq_avg)
goto out;
} else {
router_ifinfo = NULL;
}
/* if the TQ is the same and the link not more symmetric we
- won't consider it either
@@ -1042,8 +1050,7 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, goto out; }
- /* TODO: pass if_outgoing later */
- batadv_update_route(bat_priv, orig_node, neigh_node);
- batadv_update_route(bat_priv, orig_node, if_outgoing, neigh_node); goto out;
unlock: @@ -1204,6 +1211,7 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, { struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); struct batadv_orig_node *orig_node;
- struct batadv_orig_ifinfo *orig_ifinfo = NULL; struct batadv_neigh_node *neigh_node; struct batadv_neigh_ifinfo *neigh_ifinfo; int is_dup;
@@ -1220,13 +1228,19 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, if (!orig_node) return BATADV_NO_DUP;
- orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing);
- if (WARN_ON(!orig_ifinfo)) {
batadv_orig_node_free_ref(orig_node);
return 0;
- }
- spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock);
- seq_diff = seqno - orig_node->last_real_seqno;
seq_diff = seqno - orig_ifinfo->last_real_seqno;
/* signalize caller that the packet is to be dropped. */ if (!hlist_empty(&orig_node->neigh_list) && batadv_window_protected(bat_priv, seq_diff,
&orig_node->batman_seqno_reset)) {
ret = BATADV_PROTECTED; goto out; }&orig_ifinfo->batman_seqno_reset)) {
@@ -1240,7 +1254,7 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
neigh_addr = neigh_node->addr; is_dup = batadv_test_bit(neigh_ifinfo->bat_iv.real_bits,
orig_node->last_real_seqno,
orig_ifinfo->last_real_seqno, seqno);
if (batadv_compare_eth(neigh_addr, ethhdr->h_source) &&
@@ -1268,37 +1282,225 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
if (need_update) { batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"updating last_seqno: old %u, new %u\n",
orig_node->last_real_seqno, seqno);
orig_node->last_real_seqno = seqno;
"%s updating last_seqno: old %u, new %u\n",
if_outgoing ? if_outgoing->net_dev->name : "DEFAULT",
orig_ifinfo->last_real_seqno, seqno);
}orig_ifinfo->last_real_seqno = seqno;
out: spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock); batadv_orig_node_free_ref(orig_node);
- if (orig_ifinfo)
return ret;batadv_orig_ifinfo_free_ref(orig_ifinfo);
}
-static void batadv_iv_ogm_process(const struct ethhdr *ethhdr,
struct batadv_ogm_packet *batadv_ogm_packet,
const unsigned char *tt_buff,
struct batadv_hard_iface *if_incoming)
+/**
- batadv_iv_ogm_process_per_outif - process a batman iv OGM for an outgoing if
- @skb: the skb containing the OGM
- @orig_node: the (cached) orig node for the originator of this OGM
- @if_incoming: the interface where this packet was receved
- @if_outgoing: the interface for which the packet should be considered
- */
+static void +batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset,
struct batadv_orig_node *orig_node,
struct batadv_hard_iface *if_incoming,
struct batadv_hard_iface *if_outgoing)
{ struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
- struct batadv_hard_iface *hard_iface;
- struct batadv_orig_node *orig_neigh_node, *orig_node, *orig_node_tmp; struct batadv_neigh_node *router = NULL, *router_router = NULL;
- struct batadv_orig_node *orig_neigh_node, *orig_node_tmp;
- struct batadv_orig_ifinfo *orig_ifinfo; struct batadv_neigh_node *orig_neigh_router = NULL; struct batadv_neigh_ifinfo *router_ifinfo = NULL;
- int has_directlink_flag;
- int is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;
- int is_bidirect;
- bool is_single_hop_neigh = false;
- bool is_from_best_next_hop = false;
- int sameseq, similar_ttl;
- struct batadv_ogm_packet *ogm_packet; enum batadv_dup_status dup_status;
- uint32_t if_incoming_seqno;
- bool is_from_best_next_hop = false;
- bool is_single_hop_neigh = false;
- bool sameseq, similar_ttl;
- struct sk_buff *skb_priv;
- struct ethhdr *ethhdr; uint8_t *prev_sender;
- int is_bidirect;
- /* create a private copy of the skb, as some functions change tq value
* and/or flags.
*/
- skb_priv = skb_copy(skb, GFP_ATOMIC);
- if (!skb_priv)
return;
- ethhdr = eth_hdr(skb_priv);
- ogm_packet = (struct batadv_ogm_packet *)(skb_priv->data + ogm_offset);
- dup_status = batadv_iv_ogm_update_seqnos(ethhdr, ogm_packet,
if_incoming, if_outgoing);
- if (batadv_compare_eth(ethhdr->h_source, ogm_packet->orig))
is_single_hop_neigh = true;
- if (dup_status == BATADV_PROTECTED) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: packet within seqno protection time (sender: %pM)\n",
ethhdr->h_source);
goto out;
- }
- if (ogm_packet->tq == 0) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: originator packet with tq equal 0\n");
goto out;
- }
- router = batadv_orig_router_get(orig_node, if_outgoing);
- if (router) {
orig_node_tmp = router->orig_node;
router_router = batadv_orig_router_get(router->orig_node,
if_outgoing);
router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing);
- }
- if ((router_ifinfo && router_ifinfo->bat_iv.tq_avg != 0) &&
(batadv_compare_eth(router->addr, ethhdr->h_source)))
is_from_best_next_hop = true;
- prev_sender = ogm_packet->prev_sender;
- /* avoid temporary routing loops */
- if (router && router_router &&
(batadv_compare_eth(router->addr, prev_sender)) &&
!(batadv_compare_eth(ogm_packet->orig, prev_sender)) &&
(batadv_compare_eth(router->addr, router_router->addr))) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: ignoring all rebroadcast packets that may make me loop (sender: %pM)\n",
ethhdr->h_source);
goto out;
- }
- /* if sender is a direct neighbor the sender mac equals
* originator mac
*/
- if (is_single_hop_neigh)
orig_neigh_node = orig_node;
- else
orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv,
ethhdr->h_source);
- if (!orig_neigh_node)
goto out;
- /* Update nc_nodes of the originator */
- batadv_nc_update_nc_node(bat_priv, orig_node, orig_neigh_node,
ogm_packet, is_single_hop_neigh);
- orig_neigh_router = batadv_orig_router_get(orig_neigh_node,
if_outgoing);
- /* drop packet if sender is not a direct neighbor and if we
* don't route towards it
*/
- if (!is_single_hop_neigh && (!orig_neigh_router)) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: OGM via unknown neighbor!\n");
goto out_neigh;
- }
- is_bidirect = batadv_iv_ogm_calc_tq(orig_node, orig_neigh_node,
ogm_packet, if_incoming,
if_outgoing);
- /* update ranking if it is not a duplicate or has the same
* seqno and similar ttl as the non-duplicate
*/
- orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing);
- if (!orig_ifinfo)
goto out_neigh;
- sameseq = orig_ifinfo->last_real_seqno == ntohl(ogm_packet->seqno);
- similar_ttl = (orig_ifinfo->last_ttl - 3) <= ogm_packet->header.ttl;
- if (is_bidirect && ((dup_status == BATADV_NO_DUP) ||
(sameseq && similar_ttl))) {
batadv_iv_ogm_orig_update(bat_priv, orig_node,
orig_ifinfo, ethhdr,
ogm_packet, if_incoming,
if_outgoing, dup_status);
- }
- batadv_orig_ifinfo_free_ref(orig_ifinfo);
- /* is single hop (direct) neighbor */
- if (is_single_hop_neigh) {
if ((ogm_packet->header.ttl <= 2) &&
(if_incoming != if_outgoing)) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: OGM from secondary interface and wrong outgoing interface\n");
goto out_neigh;
}
/* mark direct link on incoming interface */
batadv_iv_ogm_forward(orig_node, ethhdr, ogm_packet,
is_single_hop_neigh,
is_from_best_next_hop, if_incoming);
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Forwarding packet: rebroadcast neighbor packet with direct link flag\n");
goto out_neigh;
- }
- /* multihop originator */
- if (!is_bidirect) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: not received via bidirectional link\n");
goto out_neigh;
- }
- if (dup_status == BATADV_NEIGH_DUP) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: duplicate packet received\n");
goto out_neigh;
- }
- batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Forwarding packet: rebroadcast originator packet\n");
- batadv_iv_ogm_forward(orig_node, ethhdr, ogm_packet,
is_single_hop_neigh, is_from_best_next_hop,
if_incoming);
+out_neigh:
- if ((orig_neigh_node) && (!is_single_hop_neigh))
batadv_orig_node_free_ref(orig_neigh_node);
+out:
- if (router)
batadv_neigh_node_free_ref(router);
- if (router_router)
batadv_neigh_node_free_ref(router_router);
- if (orig_neigh_router)
batadv_neigh_node_free_ref(orig_neigh_router);
- kfree_skb(skb_priv);
+}
+/**
- batadv_iv_ogm_process - process an incoming batman iv OGM
- @skb: the skb containing the OGM
- @ogm_offset: offset to the OGM which should be processed (for aggregates)
- @if_incoming: the interface where this packet was receved
- */
+static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset,
struct batadv_hard_iface *if_incoming)
+{
struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
struct batadv_orig_node *orig_neigh_node, *orig_node;
struct batadv_hard_iface *hard_iface;
struct batadv_ogm_packet *ogm_packet;
uint32_t if_incoming_seqno;
int has_directlink_flag;
struct ethhdr *ethhdr;
int is_my_oldorig = 0;
int is_my_addr = 0;
int is_my_orig = 0;
ogm_packet = (struct batadv_ogm_packet *)(skb->data + ogm_offset);
ethhdr = eth_hdr(skb);
/* Silently drop when the batman packet is actually not a
- correct packet.
@@ -1312,28 +1514,24 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, * packet in an aggregation. Here we expect that the padding * is always zero (or not 0x01) */
- if (batadv_ogm_packet->header.packet_type != BATADV_IV_OGM)
if (ogm_packet->header.packet_type != BATADV_IV_OGM) return;
/* could be changed by schedule_own_packet() */ if_incoming_seqno = atomic_read(&if_incoming->bat_iv.ogm_seqno);
- if (batadv_ogm_packet->flags & BATADV_DIRECTLINK)
- if (ogm_packet->flags & BATADV_DIRECTLINK) has_directlink_flag = 1; else has_directlink_flag = 0;
- if (batadv_compare_eth(ethhdr->h_source, batadv_ogm_packet->orig))
is_single_hop_neigh = true;
- batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Received BATMAN packet via NB: %pM, IF: %s [%pM] (from OG: %pM, via prev OG: %pM, seqno %u, tq %d, TTL %d, V %d, IDF %d)\n", ethhdr->h_source, if_incoming->net_dev->name,
if_incoming->net_dev->dev_addr, batadv_ogm_packet->orig,
batadv_ogm_packet->prev_sender,
ntohl(batadv_ogm_packet->seqno), batadv_ogm_packet->tq,
batadv_ogm_packet->header.ttl,
batadv_ogm_packet->header.version, has_directlink_flag);
if_incoming->net_dev->dev_addr, ogm_packet->orig,
ogm_packet->prev_sender, ntohl(ogm_packet->seqno),
ogm_packet->tq, ogm_packet->header.ttl,
ogm_packet->header.version, has_directlink_flag);
rcu_read_lock(); list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
@@ -1347,11 +1545,11 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, hard_iface->net_dev->dev_addr)) is_my_addr = 1;
if (batadv_compare_eth(batadv_ogm_packet->orig,
if (batadv_compare_eth(ogm_packet->orig, hard_iface->net_dev->dev_addr)) is_my_orig = 1;
if (batadv_compare_eth(batadv_ogm_packet->prev_sender,
}if (batadv_compare_eth(ogm_packet->prev_sender, hard_iface->net_dev->dev_addr)) is_my_oldorig = 1;
@@ -1382,14 +1580,14 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, */ if (has_directlink_flag && batadv_compare_eth(if_incoming->net_dev->dev_addr,
batadv_ogm_packet->orig)) {
ogm_packet->orig)) { if_num = if_incoming->if_num; offset = if_num * BATADV_NUM_WORDS; spin_lock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock); word = &(orig_neigh_node->bat_iv.bcast_own[offset]); bit_pos = if_incoming_seqno - 2;
bit_pos -= ntohl(batadv_ogm_packet->seqno);
bit_pos -= ntohl(ogm_packet->seqno); batadv_set_bit(word, bit_pos); weight = &orig_neigh_node->bat_iv.bcast_own_sum[if_num]; *weight = bitmap_weight(word,
@@ -1410,144 +1608,34 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, return; }
- if (batadv_ogm_packet->flags & BATADV_NOT_BEST_NEXT_HOP) {
- if (ogm_packet->flags & BATADV_NOT_BEST_NEXT_HOP) { batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Drop packet: ignoring all packets not forwarded from the best next hop (sender: %pM)\n", ethhdr->h_source); return; }
- orig_node = batadv_iv_ogm_orig_get(bat_priv, batadv_ogm_packet->orig);
- orig_node = batadv_iv_ogm_orig_get(bat_priv, ogm_packet->orig); if (!orig_node) return;
- dup_status = batadv_iv_ogm_update_seqnos(ethhdr, batadv_ogm_packet,
if_incoming,
BATADV_IF_DEFAULT);
- batadv_tvlv_ogm_receive(bat_priv, ogm_packet, orig_node);
- if (dup_status == BATADV_PROTECTED) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: packet within seqno protection time (sender: %pM)\n",
ethhdr->h_source);
goto out;
- }
- if (batadv_ogm_packet->tq == 0) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: originator packet with tq equal 0\n");
goto out;
- }
- router = batadv_orig_node_get_router(orig_node);
- if (router) {
orig_node_tmp = router->orig_node;
router_router = batadv_orig_node_get_router(orig_node_tmp);
router_ifinfo = batadv_neigh_ifinfo_get(router,
BATADV_IF_DEFAULT);
- }
- if ((router && router_ifinfo->bat_iv.tq_avg != 0) &&
(batadv_compare_eth(router->addr, ethhdr->h_source)))
is_from_best_next_hop = true;
- prev_sender = batadv_ogm_packet->prev_sender;
- /* avoid temporary routing loops */
- if (router && router_router &&
(batadv_compare_eth(router->addr, prev_sender)) &&
!(batadv_compare_eth(batadv_ogm_packet->orig, prev_sender)) &&
(batadv_compare_eth(router->addr, router_router->addr))) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: ignoring all rebroadcast packets that may make me loop (sender: %pM)\n",
ethhdr->h_source);
goto out;
- }
- batadv_tvlv_ogm_receive(bat_priv, batadv_ogm_packet, orig_node);
- /* if sender is a direct neighbor the sender mac equals
* originator mac
*/
- if (is_single_hop_neigh)
orig_neigh_node = orig_node;
- else
orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv,
ethhdr->h_source);
- if (!orig_neigh_node)
goto out;
- batadv_iv_ogm_process_per_outif(skb, ogm_offset, orig_node,
if_incoming, BATADV_IF_DEFAULT);
- /* Update nc_nodes of the originator */
- batadv_nc_update_nc_node(bat_priv, orig_node, orig_neigh_node,
batadv_ogm_packet, is_single_hop_neigh);
- rcu_read_lock();
- list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
if (hard_iface->if_status != BATADV_IF_ACTIVE)
continue;
- orig_neigh_router = batadv_orig_node_get_router(orig_neigh_node);
if (hard_iface->soft_iface != bat_priv->soft_iface)
continue;
- /* drop packet if sender is not a direct neighbor and if we
* don't route towards it
*/
- if (!is_single_hop_neigh && (!orig_neigh_router)) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: OGM via unknown neighbor!\n");
goto out_neigh;
batadv_iv_ogm_process_per_outif(skb, ogm_offset, orig_node,
}if_incoming, hard_iface);
- is_bidirect = batadv_iv_ogm_calc_tq(orig_node, orig_neigh_node,
batadv_ogm_packet, if_incoming,
BATADV_IF_DEFAULT);
- /* update ranking if it is not a duplicate or has the same
* seqno and similar ttl as the non-duplicate
*/
- sameseq = orig_node->last_real_seqno == ntohl(batadv_ogm_packet->seqno);
- similar_ttl = orig_node->last_ttl - 3 <= batadv_ogm_packet->header.ttl;
- if (is_bidirect && ((dup_status == BATADV_NO_DUP) ||
(sameseq && similar_ttl)))
batadv_iv_ogm_orig_update(bat_priv, orig_node, ethhdr,
batadv_ogm_packet, if_incoming,
BATADV_IF_DEFAULT, tt_buff,
dup_status);
- /* is single hop (direct) neighbor */
- if (is_single_hop_neigh) {
/* mark direct link on incoming interface */
batadv_iv_ogm_forward(orig_node, ethhdr, batadv_ogm_packet,
is_single_hop_neigh,
is_from_best_next_hop, if_incoming);
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Forwarding packet: rebroadcast neighbor packet with direct link flag\n");
goto out_neigh;
- }
- /* multihop originator */
- if (!is_bidirect) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: not received via bidirectional link\n");
goto out_neigh;
- }
- if (dup_status == BATADV_NEIGH_DUP) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: duplicate packet received\n");
goto out_neigh;
- }
- batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Forwarding packet: rebroadcast originator packet\n");
- batadv_iv_ogm_forward(orig_node, ethhdr, batadv_ogm_packet,
is_single_hop_neigh, is_from_best_next_hop,
if_incoming);
-out_neigh:
- if ((orig_neigh_node) && (!is_single_hop_neigh))
batadv_orig_node_free_ref(orig_neigh_node);
-out:
- if (router)
batadv_neigh_node_free_ref(router);
- if (router_router)
batadv_neigh_node_free_ref(router_router);
- if (orig_neigh_router)
batadv_neigh_node_free_ref(orig_neigh_router);
rcu_read_unlock();
batadv_orig_node_free_ref(orig_node);
} @@ -1556,11 +1644,9 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb, struct batadv_hard_iface *if_incoming) { struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
- struct batadv_ogm_packet *batadv_ogm_packet;
- struct ethhdr *ethhdr;
- int buff_pos = 0, packet_len;
- unsigned char *tvlv_buff, *packet_buff;
struct batadv_ogm_packet *ogm_packet; uint8_t *packet_pos;
int ogm_offset; bool ret;
ret = batadv_check_management_packet(skb, if_incoming, BATADV_OGM_HLEN);
@@ -1577,24 +1663,19 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb, batadv_add_counter(bat_priv, BATADV_CNT_MGMT_RX_BYTES, skb->len + ETH_HLEN);
- packet_len = skb_headlen(skb);
- ethhdr = eth_hdr(skb);
- packet_buff = skb->data;
- batadv_ogm_packet = (struct batadv_ogm_packet *)packet_buff;
ogm_offset = 0;
ogm_packet = (struct batadv_ogm_packet *)skb->data;
/* unpack the aggregated packets and process them one by one */
- while (batadv_iv_ogm_aggr_packet(buff_pos, packet_len,
batadv_ogm_packet->tvlv_len)) {
tvlv_buff = packet_buff + buff_pos + BATADV_OGM_HLEN;
- while (batadv_iv_ogm_aggr_packet(ogm_offset, skb_headlen(skb),
ogm_packet->tvlv_len)) {
batadv_iv_ogm_process(skb, ogm_offset, if_incoming);
batadv_iv_ogm_process(ethhdr, batadv_ogm_packet,
tvlv_buff, if_incoming);
ogm_offset += BATADV_OGM_HLEN;
ogm_offset += ntohs(ogm_packet->tvlv_len);
buff_pos += BATADV_OGM_HLEN;
buff_pos += ntohs(batadv_ogm_packet->tvlv_len);
packet_pos = packet_buff + buff_pos;
batadv_ogm_packet = (struct batadv_ogm_packet *)packet_pos;
packet_pos = skb->data + ogm_offset;
ogm_packet = (struct batadv_ogm_packet *)packet_pos;
}
kfree_skb(skb);
@@ -1657,7 +1738,8 @@ static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv,
rcu_read_lock(); hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
neigh_node = batadv_orig_node_get_router(orig_node);
neigh_node = batadv_orig_router_get(orig_node,
BATADV_IF_DEFAULT); if (!neigh_node) continue;
diff --git a/distributed-arp-table.c b/distributed-arp-table.c index 6c8c393..ae0404e 100644 --- a/distributed-arp-table.c +++ b/distributed-arp-table.c @@ -591,7 +591,8 @@ static bool batadv_dat_send_data(struct batadv_priv *bat_priv, if (cand[i].type == BATADV_DAT_CANDIDATE_NOT_FOUND) continue;
neigh_node = batadv_orig_node_get_router(cand[i].orig_node);
neigh_node = batadv_orig_router_get(cand[i].orig_node,
if (!neigh_node) goto free_orig;BATADV_IF_DEFAULT);
diff --git a/gateway_client.c b/gateway_client.c index 71759d0..722a051 100644 --- a/gateway_client.c +++ b/gateway_client.c @@ -131,7 +131,7 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) continue;
orig_node = gw_node->orig_node;
router = batadv_orig_node_get_router(orig_node);
if (!router) continue;router = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT);
@@ -246,7 +246,8 @@ void batadv_gw_election(struct batadv_priv *bat_priv) if (next_gw) { sprintf(gw_addr, "%pM", next_gw->orig_node->orig);
router = batadv_orig_node_get_router(next_gw->orig_node);
router = batadv_orig_router_get(next_gw->orig_node,
if (!router) { batadv_gw_deselect(bat_priv); goto out;BATADV_IF_DEFAULT);
@@ -315,7 +316,7 @@ void batadv_gw_check_election(struct batadv_priv *bat_priv, if (!curr_gw_orig) goto deselect;
- router_gw = batadv_orig_node_get_router(curr_gw_orig);
- router_gw = batadv_orig_router_get(curr_gw_orig, BATADV_IF_DEFAULT); if (!router_gw) goto deselect;
@@ -328,7 +329,7 @@ void batadv_gw_check_election(struct batadv_priv *bat_priv, if (curr_gw_orig == orig_node) goto out;
- router_orig = batadv_orig_node_get_router(orig_node);
- router_orig = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT); if (!router_orig) goto out;
@@ -556,7 +557,7 @@ static int batadv_write_buffer_text(struct batadv_priv *bat_priv, struct batadv_neigh_ifinfo *router_ifinfo; int ret = -1;
- router = batadv_orig_node_get_router(gw_node->orig_node);
- router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT); if (!router) goto out;
diff --git a/icmp_socket.c b/icmp_socket.c index 29ae4ef..6b15efc 100644 --- a/icmp_socket.c +++ b/icmp_socket.c @@ -217,7 +217,8 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff, if (!orig_node) goto dst_unreach;
neigh_node = batadv_orig_node_get_router(orig_node);
neigh_node = batadv_orig_router_get(orig_node,
if (!neigh_node) goto dst_unreach;BATADV_IF_DEFAULT);
diff --git a/network-coding.c b/network-coding.c index 351e199..792a072 100644 --- a/network-coding.c +++ b/network-coding.c @@ -1019,12 +1019,17 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv, int coded_size = sizeof(*coded_packet); int header_add = coded_size - unicast_size;
- router_neigh = batadv_orig_node_get_router(neigh_node->orig_node);
/* TODO: do we need to consider the outgoing interface for
* coded packets?
*/
router_neigh = batadv_orig_router_get(neigh_node->orig_node,
BATADV_IF_DEFAULT);
if (!router_neigh) goto out;
neigh_tmp = nc_packet->neigh_node;
- router_coding = batadv_orig_node_get_router(neigh_tmp->orig_node);
- router_coding = batadv_orig_router_get(neigh_tmp->orig_node,
if (!router_coding) goto out;BATADV_IF_DEFAULT);
diff --git a/originator.c b/originator.c index acbd254..62691d0 100644 --- a/originator.c +++ b/originator.c @@ -227,14 +227,30 @@ void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node) call_rcu(&neigh_node->rcu, batadv_neigh_node_free_rcu); }
-/* increases the refcounter of a found router */ +/**
- batadv_orig_node_get_router - router to the originator depending on iface
- @orig_node: the orig node for the router
- @if_received: the interface where the packet to be transmitted was received
- Returns the neighbor which should be router for this orig_node/iface.
- The object is returned with refcounter increased by 1.
- */
struct batadv_neigh_node * -batadv_orig_node_get_router(struct batadv_orig_node *orig_node) +batadv_orig_router_get(struct batadv_orig_node *orig_node,
const struct batadv_hard_iface *if_received)
{
- struct batadv_neigh_node *router;
struct batadv_orig_ifinfo *orig_ifinfo;
struct batadv_neigh_node *router = NULL;
rcu_read_lock();
- router = rcu_dereference(orig_node->router);
hlist_for_each_entry_rcu(orig_ifinfo, &orig_node->ifinfo_list, list) {
if (orig_ifinfo->if_outgoing != if_received)
continue;
router = rcu_dereference(orig_ifinfo->router);
break;
}
if (router && !atomic_inc_not_zero(&router->refcount)) router = NULL;
@@ -244,6 +260,86 @@ batadv_orig_node_get_router(struct batadv_orig_node *orig_node) }
/**
- batadv_orig_ifinfo_get - find the ifinfo from an orig_node
- @orig_node: the orig node to be queried
- @if_received: the interface for which the ifinfo should be acquired
- Returns the requested orig_ifinfo or NULL if not found.
- The object is returned with refcounter increased by 1.
- */
+struct batadv_orig_ifinfo * +batadv_orig_ifinfo_get(struct batadv_orig_node *orig_node,
struct batadv_hard_iface *if_received)
+{
- struct batadv_orig_ifinfo *tmp, *orig_ifinfo = NULL;
- rcu_read_lock();
- hlist_for_each_entry_rcu(tmp, &orig_node->ifinfo_list,
list) {
if (tmp->if_outgoing != if_received)
continue;
if (!atomic_inc_not_zero(&tmp->refcount))
continue;
orig_ifinfo = tmp;
break;
- }
- rcu_read_unlock();
- return orig_ifinfo;
+}
+/**
- batadv_orig_ifinfo_new - search and possibly create an orig_ifinfo object
- @orig_node: the orig node to be queried
- @if_received: the interface for which the ifinfo should be acquired
- Returns NULL in case of failure or the orig_ifinfo object for the if_outgoing
- interface otherwise. The object is created and added to the list
- if it does not exist.
- The object is returned with refcounter increased by 1.
- */
+struct batadv_orig_ifinfo * +batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node,
struct batadv_hard_iface *if_received)
+{
- struct batadv_orig_ifinfo *orig_ifinfo = NULL;
- unsigned long reset_time;
- spin_lock_bh(&orig_node->neigh_list_lock);
- orig_ifinfo = batadv_orig_ifinfo_get(orig_node, if_received);
- if (orig_ifinfo)
goto out;
- orig_ifinfo = kzalloc(sizeof(*orig_ifinfo), GFP_ATOMIC);
- if (!orig_ifinfo)
goto out;
- if (if_received != BATADV_IF_DEFAULT &&
!atomic_inc_not_zero(&if_received->refcount)) {
kfree(orig_ifinfo);
orig_ifinfo = NULL;
goto out;
- }
- reset_time = jiffies - 1;
- reset_time -= msecs_to_jiffies(BATADV_RESET_PROTECTION_MS);
- orig_ifinfo->batman_seqno_reset = reset_time;
- orig_ifinfo->if_outgoing = if_received;
- INIT_HLIST_NODE(&orig_ifinfo->list);
- atomic_set(&orig_ifinfo->refcount, 2);
- hlist_add_head_rcu(&orig_ifinfo->list,
&orig_node->ifinfo_list);
+out:
- spin_unlock_bh(&orig_node->neigh_list_lock);
- return orig_ifinfo;
+}
+/**
- batadv_neigh_ifinfo_get - find the ifinfo from an neigh_node
- @neigh_node: the neigh node to be queried
- @if_outgoing: the interface for which the ifinfo should be acquired
@@ -356,11 +452,50 @@ out: return neigh_node; }
Broken kernel doc
+/* batadv_orig_ifinfo_free_rcu - free the orig_ifinfo object
- @rcu: rcu pointer of the orig_ifinfo object
- */
+static void batadv_orig_ifinfo_free_rcu(struct rcu_head *rcu) +{
- struct batadv_orig_ifinfo *orig_ifinfo;
- orig_ifinfo = container_of(rcu, struct batadv_orig_ifinfo, rcu);
- if (orig_ifinfo->if_outgoing != BATADV_IF_DEFAULT)
batadv_hardif_free_ref_now(orig_ifinfo->if_outgoing);
- kfree(orig_ifinfo);
+}
+/**
- batadv_orig_ifinfo_free_ref - decrement the refcounter and possibly free
- the orig_ifinfo (without rcu callback)
- @orig_ifinfo: the orig_ifinfo object to release
- */
+static void +batadv_orig_ifinfo_free_ref_now(struct batadv_orig_ifinfo *orig_ifinfo) +{
- if (atomic_dec_and_test(&orig_ifinfo->refcount))
batadv_orig_ifinfo_free_rcu(&orig_ifinfo->rcu);
+}
+/**
- batadv_orig_ifinfo_free_ref - decrement the refcounter and possibly free
- the orig_ifinfo
- @orig_ifinfo: the orig_ifinfo object to release
- */
+void batadv_orig_ifinfo_free_ref(struct batadv_orig_ifinfo *orig_ifinfo) +{
- if (atomic_dec_and_test(&orig_ifinfo->refcount))
call_rcu(&orig_ifinfo->rcu, batadv_orig_ifinfo_free_rcu);
+}
static void batadv_orig_node_free_rcu(struct rcu_head *rcu) { struct hlist_node *node_tmp; struct batadv_neigh_node *neigh_node; struct batadv_orig_node *orig_node;
struct batadv_orig_ifinfo *orig_ifinfo;
orig_node = container_of(rcu, struct batadv_orig_node, rcu);
@@ -373,6 +508,11 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu) batadv_neigh_node_free_ref_now(neigh_node); }
hlist_for_each_entry_safe(orig_ifinfo, node_tmp,
&orig_node->ifinfo_list, list) {
hlist_del_rcu(&orig_ifinfo->list);
batadv_orig_ifinfo_free_ref_now(orig_ifinfo);
} spin_unlock_bh(&orig_node->neigh_list_lock);
/* Free nc_nodes */
@@ -470,6 +610,7 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv,
INIT_HLIST_HEAD(&orig_node->neigh_list); INIT_LIST_HEAD(&orig_node->vlan_list);
- INIT_HLIST_HEAD(&orig_node->ifinfo_list); spin_lock_init(&orig_node->bcast_seqno_lock); spin_lock_init(&orig_node->neigh_list_lock); spin_lock_init(&orig_node->tt_buff_lock);
@@ -485,13 +626,11 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, orig_node->bat_priv = bat_priv; memcpy(orig_node->orig, addr, ETH_ALEN); batadv_dat_init_orig_node_addr(orig_node);
orig_node->router = NULL; atomic_set(&orig_node->last_ttvn, 0); orig_node->tt_buff = NULL; orig_node->tt_buff_len = 0; reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS); orig_node->bcast_seqno_reset = reset_time;
orig_node->batman_seqno_reset = reset_time;
/* create a vlan object for the "untagged" LAN */ vlan = batadv_orig_node_vlan_new(orig_node, BATADV_NO_FLAGS);
@@ -516,6 +655,52 @@ free_orig_node: }
/**
- batadv_purge_orig_ifinfo - purge ifinfo entries from originator
- @bat_priv: the bat priv with all the soft interface information
- @orig_node: orig node which is to be checked
- Returns true if any ifinfo entry was purged, false otherwise.
- */
+static bool +batadv_purge_orig_ifinfo(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node)
+{
- struct batadv_orig_ifinfo *orig_ifinfo;
- struct batadv_hard_iface *if_outgoing;
- struct hlist_node *node_tmp;
- bool ifinfo_purged = false;
- spin_lock_bh(&orig_node->neigh_list_lock);
- /* for all neighbors towards this originator ... */
- hlist_for_each_entry_safe(orig_ifinfo, node_tmp,
&orig_node->ifinfo_list, list) {
if_outgoing = orig_ifinfo->if_outgoing;
if (!if_outgoing)
continue;
if ((if_outgoing->if_status != BATADV_IF_INACTIVE) &&
(if_outgoing->if_status != BATADV_IF_NOT_IN_USE) &&
(if_outgoing->if_status != BATADV_IF_TO_BE_REMOVED))
continue;
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"router/ifinfo purge: originator %pM, iface: %s\n",
orig_node->orig, if_outgoing->net_dev->name);
ifinfo_purged = true;
hlist_del_rcu(&orig_ifinfo->list);
batadv_orig_ifinfo_free_ref(orig_ifinfo);
- }
- spin_unlock_bh(&orig_node->neigh_list_lock);
- return ifinfo_purged;
+}
+/**
- batadv_purge_orig_neighbors - purges neighbors from originator
- @bat_priv: the bat priv with all the soft interface information
- @orig_node: orig node which is to be checked
@@ -599,6 +784,8 @@ static bool batadv_purge_orig_node(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node) { struct batadv_neigh_node *best_neigh_node;
struct batadv_hard_iface *hard_iface;
bool changed;
if (batadv_has_timed_out(orig_node->last_seen, 2 * BATADV_PURGE_TIMEOUT)) {
@@ -608,12 +795,34 @@ static bool batadv_purge_orig_node(struct batadv_priv *bat_priv, jiffies_to_msecs(orig_node->last_seen)); return true; }
- if (!batadv_purge_orig_neighbors(bat_priv, orig_node))
changed = batadv_purge_orig_ifinfo(bat_priv, orig_node);
changed = changed || batadv_purge_orig_neighbors(bat_priv, orig_node);
if (!changed) return false;
/* first for NULL ... */ best_neigh_node = batadv_find_best_neighbor(bat_priv, orig_node, BATADV_IF_DEFAULT);
- batadv_update_route(bat_priv, orig_node, best_neigh_node);
batadv_update_route(bat_priv, orig_node, BATADV_IF_DEFAULT,
best_neigh_node);
/* ... then for all other interfaces. */
rcu_read_lock();
list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
if (hard_iface->if_status != BATADV_IF_ACTIVE)
continue;
if (hard_iface->soft_iface != bat_priv->soft_iface)
continue;
best_neigh_node = batadv_find_best_neighbor(bat_priv,
orig_node,
hard_iface);
batadv_update_route(bat_priv, orig_node, hard_iface,
best_neigh_node);
}
rcu_read_unlock();
return false;
} diff --git a/originator.h b/originator.h index 76a8de6..404f7cb 100644 --- a/originator.h +++ b/originator.h @@ -36,7 +36,8 @@ batadv_neigh_node_new(struct batadv_hard_iface *hard_iface, struct batadv_orig_node *orig_node); void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node); struct batadv_neigh_node * -batadv_orig_node_get_router(struct batadv_orig_node *orig_node); +batadv_orig_router_get(struct batadv_orig_node *orig_node,
const struct batadv_hard_iface *if_received);
struct batadv_neigh_ifinfo * batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh, struct batadv_hard_iface *if_outgoing); @@ -44,6 +45,15 @@ struct batadv_neigh_ifinfo * batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh, struct batadv_hard_iface *if_outgoing); void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo);
+struct batadv_orig_ifinfo * +batadv_orig_ifinfo_get(struct batadv_orig_node *orig_node,
struct batadv_hard_iface *if_received);
+struct batadv_orig_ifinfo * +batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node,
struct batadv_hard_iface *if_received);
+void batadv_orig_ifinfo_free_ref(struct batadv_orig_ifinfo *orig_ifinfo);
int batadv_orig_seq_print_text(struct seq_file *seq, void *offset); int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, int max_if_num); diff --git a/routing.c b/routing.c index 360a5b9..da6741a 100644 --- a/routing.c +++ b/routing.c @@ -35,13 +35,29 @@ static int batadv_route_unicast_packet(struct sk_buff *skb, struct batadv_hard_iface *recv_if);
+/* _batadv_update_route - set the router for this originator
- @bat_priv: the bat priv with all the soft interface information
- @orig_node: orig node which is to be configured
- @recv_if: the receive interface for which this route is set
- @neigh_node: neighbor which should be the next router
- This function does not perform any error checks
- */
Broken kernel doc
static void _batadv_update_route(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node,
struct batadv_hard_iface *recv_if, struct batadv_neigh_node *neigh_node)
{
- struct batadv_orig_ifinfo *orig_ifinfo; struct batadv_neigh_node *curr_router;
- curr_router = batadv_orig_node_get_router(orig_node);
orig_ifinfo = batadv_orig_ifinfo_get(orig_node, recv_if);
if (!orig_ifinfo)
return;
curr_router = rcu_dereference(orig_ifinfo->router);
if (curr_router && !atomic_inc_not_zero(&curr_router->refcount))
curr_router = NULL;
/* route deleted */ if ((curr_router) && (!neigh_node)) {
@@ -71,16 +87,25 @@ static void _batadv_update_route(struct batadv_priv *bat_priv, neigh_node = NULL;
spin_lock_bh(&orig_node->neigh_list_lock);
- rcu_assign_pointer(orig_node->router, neigh_node);
rcu_assign_pointer(orig_ifinfo->router, neigh_node); spin_unlock_bh(&orig_node->neigh_list_lock);
batadv_orig_ifinfo_free_ref(orig_ifinfo);
/* decrease refcount of previous best neighbor */ if (curr_router) batadv_neigh_node_free_ref(curr_router);
}
+/**
- batadv_update_route - set the router for this originator
- @bat_priv: the bat priv with all the soft interface information
- @orig_node: orig node which is to be configured
- @recv_if: the receive interface for which this route is set
- @neigh_node: neighbor which should be the next router
- */
void batadv_update_route(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node,
struct batadv_hard_iface *recv_if, struct batadv_neigh_node *neigh_node)
{ struct batadv_neigh_node *router = NULL; @@ -88,10 +113,10 @@ void batadv_update_route(struct batadv_priv *bat_priv, if (!orig_node) goto out;
- router = batadv_orig_node_get_router(orig_node);
router = batadv_orig_router_get(orig_node, recv_if);
if (router != neigh_node)
_batadv_update_route(bat_priv, orig_node, neigh_node);
_batadv_update_route(bat_priv, orig_node, recv_if, neigh_node);
out: if (router) @@ -408,7 +433,7 @@ batadv_find_router(struct batadv_priv *bat_priv, if (!orig_node) return NULL;
- router = batadv_orig_node_get_router(orig_node);
router = batadv_orig_router_get(orig_node, recv_if);
/* TODO: fill this later with new bonding mechanism */
diff --git a/routing.h b/routing.h index b8fed80..7a7c6e9 100644 --- a/routing.h +++ b/routing.h @@ -25,6 +25,7 @@ bool batadv_check_management_packet(struct sk_buff *skb, int header_len); void batadv_update_route(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node,
struct batadv_hard_iface *recv_if, struct batadv_neigh_node *neigh_node);
int batadv_recv_icmp_packet(struct sk_buff *skb, struct batadv_hard_iface *recv_if); diff --git a/translation-table.c b/translation-table.c index 135c165..1b2a615 100644 --- a/translation-table.c +++ b/translation-table.c @@ -1385,7 +1385,8 @@ batadv_transtable_best_orig(struct batadv_priv *bat_priv,
head = &tt_global_entry->orig_list; hlist_for_each_entry_rcu(orig_entry, head, list) {
router = batadv_orig_node_get_router(orig_entry->orig_node);
router = batadv_orig_router_get(orig_entry->orig_node,
if (!router) continue;BATADV_IF_DEFAULT);
diff --git a/types.h b/types.h index 11d448f..167c3a5 100644 --- a/types.h +++ b/types.h @@ -90,6 +90,27 @@ struct batadv_hard_iface { struct work_struct cleanup_work; };
+/* struct batadv_orig_ifinfo - originator info per outgoing interface
- @list: list node for orig_node::ifinfo_list
- @if_outgoing: pointer to outgoing hard interface
- @router: router that should be used to reach this originator
- @last_real_seqno: last and best known sequence number
- @last_ttl: ttl of last received packet
- @batman_seqno_reset: time when the batman seqno window was reset
- @refcount: number of contexts the object is used
- @rcu: struct used for freeing in an RCU-safe manner
- */
Broken kernel doc
+struct batadv_orig_ifinfo {
- struct hlist_node list;
- struct batadv_hard_iface *if_outgoing;
- struct batadv_neigh_node __rcu *router; /* rcu protected pointer */
- uint32_t last_real_seqno;
- uint8_t last_ttl;
- unsigned long batman_seqno_reset;
- atomic_t refcount;
- struct rcu_head rcu;
+};
/**
- struct batadv_frag_table_entry - head in the fragment buffer table
- @head: head of list with fragments
@@ -165,11 +186,10 @@ struct batadv_orig_bat_iv {
- struct batadv_orig_node - structure for orig_list maintaining nodes of mesh
- @orig: originator ethernet address
- @primary_addr: hosts primary interface address
- @router: router that should be used to reach this originator
- @ifinfo_list: list for routers per outgoing interface
- @batadv_dat_addr_t: address of the orig node in the distributed hash
- @last_seen: time when last packet from this node was received
- @bcast_seqno_reset: time when the broadcast seqno window was reset
- @batman_seqno_reset: time when the batman seqno window was reset
- @capabilities: announced capabilities of this originator
- @last_ttvn: last seen translation table version number
- @tt_buff: last tt changeset this node received from the orig node
@@ -182,8 +202,6 @@ struct batadv_orig_bat_iv {
- made up by two operations (data structure update and metdata -CRC/TTVN-
- recalculation) and they have to be executed atomically in order to avoid
- another thread to read the table/metadata between those.
- @last_real_seqno: last and best known sequence number
- @last_ttl: ttl of last received packet
- @bcast_bits: bitfield containing the info which payload broadcast originated
- from this orig node this host already has seen (relative to
- last_bcast_seqno)
@@ -208,13 +226,12 @@ struct batadv_orig_bat_iv { struct batadv_orig_node { uint8_t orig[ETH_ALEN]; uint8_t primary_addr[ETH_ALEN];
- struct batadv_neigh_node __rcu *router; /* rcu protected pointer */
- struct hlist_head ifinfo_list;
#ifdef CONFIG_BATMAN_ADV_DAT batadv_dat_addr_t dat_addr; #endif unsigned long last_seen; unsigned long bcast_seqno_reset;
- unsigned long batman_seqno_reset; uint8_t capabilities; atomic_t last_ttvn; unsigned char *tt_buff;
@@ -223,8 +240,6 @@ struct batadv_orig_node { bool tt_initialised; /* prevents from changing the table while reading it */ spinlock_t tt_lock;
- uint32_t last_real_seqno;
- uint8_t last_ttl; DECLARE_BITMAP(bcast_bits, BATADV_TQ_LOCAL_WINDOW_SIZE); uint32_t last_bcast_seqno; struct hlist_head neigh_list;
-- 1.7.10.4
From: Simon Wunderlich simon@open-mesh.com
If the same interface is used for sending and receiving, there might be throughput degradation on half-duplex interfaces such as WiFi. Add a penalty if the same interface is used to reflect this problem in the metric. At the same time, change the hop penalty from 30 to 15 so there will be no change for single wifi mesh network. the effective hop penalty will stay at 30 due to the new wifi penalty for these networks.
Signed-off-by: Simon Wunderlich simon@open-mesh.com --- Changes to RFCv2: * various style changes
Changes to RFCv1: * use hop penalty for wifi penalty, and use half of the original hop penalty. --- bat_iv_ogm.c | 26 ++++++++++++++++++++++---- hard-interface.h | 1 + soft-interface.c | 2 +- 3 files changed, 24 insertions(+), 5 deletions(-)
diff --git a/bat_iv_ogm.c b/bat_iv_ogm.c index 3ba2402..a7e9cac 100644 --- a/bat_iv_ogm.c +++ b/bat_iv_ogm.c @@ -1090,6 +1090,7 @@ static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, unsigned int neigh_rq_inv_cube, neigh_rq_max_cube; int tq_asym_penalty, inv_asym_penalty, if_num, ret = 0; unsigned int combined_tq; + int tq_iface_penalty;
/* find corresponding one hop neighbor */ rcu_read_lock(); @@ -1171,15 +1172,32 @@ static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, inv_asym_penalty /= neigh_rq_max_cube; tq_asym_penalty = BATADV_TQ_MAX_VALUE - inv_asym_penalty;
- combined_tq = batadv_ogm_packet->tq * tq_own * tq_asym_penalty; - combined_tq /= BATADV_TQ_MAX_VALUE * BATADV_TQ_MAX_VALUE; + /* penalize if the OGM is forwarded on the same interface. WiFi + * interfaces and other half duplex devices suffer from throughput + * drops as they can't send and receive at the same time. + */ + tq_iface_penalty = BATADV_TQ_MAX_VALUE; + if (if_outgoing && (if_incoming == if_outgoing) && + batadv_is_wifi_netdev(if_outgoing->net_dev)) + tq_iface_penalty = batadv_hop_penalty(BATADV_TQ_MAX_VALUE, + bat_priv); + + combined_tq = batadv_ogm_packet->tq * + tq_own * + tq_asym_penalty * + tq_iface_penalty; + combined_tq /= BATADV_TQ_MAX_VALUE * + BATADV_TQ_MAX_VALUE * + BATADV_TQ_MAX_VALUE; batadv_ogm_packet->tq = combined_tq;
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, - "bidirectional: orig = %-15pM neigh = %-15pM => own_bcast = %2i, real recv = %2i, local tq: %3i, asym_penalty: %3i, total tq: %3i\n", + "bidirectional: orig = %-15pM neigh = %-15pM => own_bcast = %2i, real recv = %2i, local tq: %3i, asym_penalty: %3i, iface_penalty: %3i, total tq: %3i, if_incoming = %s, if_outgoing = %s\n", orig_node->orig, orig_neigh_node->orig, total_count, neigh_rq_count, tq_own, - tq_asym_penalty, batadv_ogm_packet->tq); + tq_asym_penalty, tq_iface_penalty, batadv_ogm_packet->tq, + if_incoming ? if_incoming->net_dev->name : "NULL", + if_outgoing ? if_outgoing->net_dev->name : "DEFAULT");
/* if link has the minimum required transmission quality * consider it bidirectional diff --git a/hard-interface.h b/hard-interface.h index 6b609b0..82b7127 100644 --- a/hard-interface.h +++ b/hard-interface.h @@ -42,6 +42,7 @@ enum batadv_hard_if_cleanup { extern struct notifier_block batadv_hard_if_notifier;
bool batadv_is_wifi_netdev(struct net_device *net_device); +bool batadv_is_wifi_iface(int ifindex); struct batadv_hard_iface* batadv_hardif_get_by_netdev(const struct net_device *net_dev); int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, diff --git a/soft-interface.c b/soft-interface.c index 36f0508..33a2df6 100644 --- a/soft-interface.c +++ b/soft-interface.c @@ -672,7 +672,7 @@ static int batadv_softif_init_late(struct net_device *dev) atomic_set(&bat_priv->gw.bandwidth_down, 100); atomic_set(&bat_priv->gw.bandwidth_up, 20); atomic_set(&bat_priv->orig_interval, 1000); - atomic_set(&bat_priv->hop_penalty, 30); + atomic_set(&bat_priv->hop_penalty, 15); #ifdef CONFIG_BATMAN_ADV_DEBUG atomic_set(&bat_priv->log_level, 0); #endif
From: Simon Wunderlich simon@open-mesh.com
The current OGM sending an aggregation functionality decides on which interfaces a packet should be sent when it parses the forward packet struct. However, with the network wide multi interface optimization the outgoing interface is decided by the OGM processing function.
This is reflected by moving the decision in the OGM processing function and add the outgoing interface in the forwarding packet struct. This practically implies that an OGM may be added multiple times (once per outgoing interface), and this also affects aggregation which needs to consider the outgoing interface as well.
Signed-off-by: Simon Wunderlich simon@open-mesh.com --- Changes to PATCH: * beautify big if/else block in batadv_iv_ogm_schedule() and comments * remove TODO (obviously everyone is confused by that anyway. If someone wants to optimize the aggregation later, I'm sure he/she can do that without having my TODO in the code. :] )
Changes to RFCv2: * rework kerneldoc and comments --- bat_iv_ogm.c | 141 +++++++++++++++++++++++++++++++++++++++------------------- send.c | 19 +++++--- types.h | 7 ++- 3 files changed, 115 insertions(+), 52 deletions(-)
diff --git a/bat_iv_ogm.c b/bat_iv_ogm.c index a7e9cac..c44bca6 100644 --- a/bat_iv_ogm.c +++ b/bat_iv_ogm.c @@ -467,7 +467,6 @@ static void batadv_iv_ogm_send_to_if(struct batadv_forw_packet *forw_packet, /* send a batman ogm packet */ static void batadv_iv_ogm_emit(struct batadv_forw_packet *forw_packet) { - struct batadv_hard_iface *hard_iface; struct net_device *soft_iface; struct batadv_priv *bat_priv; struct batadv_hard_iface *primary_if = NULL; @@ -487,6 +486,12 @@ static void batadv_iv_ogm_emit(struct batadv_forw_packet *forw_packet) soft_iface = forw_packet->if_incoming->soft_iface; bat_priv = netdev_priv(soft_iface);
+ if (WARN_ON(!forw_packet->if_outgoing)) + goto out; + + if (WARN_ON(forw_packet->if_outgoing->soft_iface != soft_iface)) + goto out; + if (forw_packet->if_incoming->if_status != BATADV_IF_ACTIVE) goto out;
@@ -494,52 +499,35 @@ static void batadv_iv_ogm_emit(struct batadv_forw_packet *forw_packet) if (!primary_if) goto out;
- /* multihomed peer assumed - * non-primary OGMs are only broadcasted on their interface - */ - if ((directlink && (batadv_ogm_packet->header.ttl == 1)) || - (forw_packet->own && (forw_packet->if_incoming != primary_if))) { - /* FIXME: what about aggregated packets ? */ - batadv_dbg(BATADV_DBG_BATMAN, bat_priv, - "%s packet (originator %pM, seqno %u, TTL %d) on interface %s [%pM]\n", - (forw_packet->own ? "Sending own" : "Forwarding"), - batadv_ogm_packet->orig, - ntohl(batadv_ogm_packet->seqno), - batadv_ogm_packet->header.ttl, - forw_packet->if_incoming->net_dev->name, - forw_packet->if_incoming->net_dev->dev_addr); - - /* skb is only used once and than forw_packet is free'd */ - batadv_send_skb_packet(forw_packet->skb, - forw_packet->if_incoming, - batadv_broadcast_addr); - forw_packet->skb = NULL; - - goto out; - } - - /* broadcast on every interface */ - rcu_read_lock(); - list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { - if (hard_iface->soft_iface != soft_iface) - continue; - - batadv_iv_ogm_send_to_if(forw_packet, hard_iface); - } - rcu_read_unlock(); + /* only for one specific outgoing interface */ + batadv_iv_ogm_send_to_if(forw_packet, forw_packet->if_outgoing);
out: if (primary_if) batadv_hardif_free_ref(primary_if); }
-/* return true if new_packet can be aggregated with forw_packet */ +/** + * batadv_iv_ogm_can_aggregate - find out if an OGM can be aggregated on an + * existing forward packet + * @new_bat_ogm_packet: OGM packet to be aggregated + * @bat_priv: the bat priv with all the soft interface information + * @packet_len: (total) length of the OGM + * @send_time: timestamp (jiffies) when the packet is to be sent + * @direktlink: true if this is a direct link packet + * @if_incoming: interface where the packet was received + * @if_outgoing: interface for which the retransmission should be considered + * @forw_packet: the forwarded packet which should be checked + * + * Returns true if new_packet can be aggregated with forw_packet + */ static bool batadv_iv_ogm_can_aggregate(const struct batadv_ogm_packet *new_bat_ogm_packet, struct batadv_priv *bat_priv, int packet_len, unsigned long send_time, bool directlink, const struct batadv_hard_iface *if_incoming, + const struct batadv_hard_iface *if_outgoing, const struct batadv_forw_packet *forw_packet) { struct batadv_ogm_packet *batadv_ogm_packet; @@ -573,6 +561,10 @@ batadv_iv_ogm_can_aggregate(const struct batadv_ogm_packet *new_bat_ogm_packet, if (!primary_if) goto out;
+ /* packet is not leaving on the same interface. */ + if (forw_packet->if_outgoing != if_outgoing) + goto out; + /* packets without direct link flag and high TTL * are flooded through the net */ @@ -614,11 +606,21 @@ out: return res; }
-/* create a new aggregated packet and add this packet to it */ +/* batadv_iv_ogm_aggregate_new - create a new aggregated packet and add this + * packet to it. + * @packet_buff: pointer to the OGM + * @packet_len: (total) length of the OGM + * @send_time: timestamp (jiffies) when the packet is to be sent + * @direct_link: whether this OGM has direct link status + * @if_incoming: interface where the packet was received + * @if_outgoing: interface for which the retransmission should be considered + * @own_packet: true if it is a self-generated ogm + */ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff, int packet_len, unsigned long send_time, bool direct_link, struct batadv_hard_iface *if_incoming, + struct batadv_hard_iface *if_outgoing, int own_packet) { struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); @@ -629,6 +631,9 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff, if (!atomic_inc_not_zero(&if_incoming->refcount)) return;
+ if (!atomic_inc_not_zero(&if_outgoing->refcount)) + goto out_free_incoming; + /* own packet should always be scheduled */ if (!own_packet) { if (!batadv_atomic_dec_not_zero(&bat_priv->batman_queue_left)) { @@ -669,6 +674,7 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
forw_packet_aggr->own = own_packet; forw_packet_aggr->if_incoming = if_incoming; + forw_packet_aggr->if_outgoing = if_outgoing; forw_packet_aggr->num_packets = 0; forw_packet_aggr->direct_link_flags = BATADV_NO_FLAGS; forw_packet_aggr->send_time = send_time; @@ -691,6 +697,8 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
return; out: + batadv_hardif_free_ref(if_outgoing); +out_free_incoming: batadv_hardif_free_ref(if_incoming); }
@@ -714,10 +722,21 @@ static void batadv_iv_ogm_aggregate(struct batadv_forw_packet *forw_packet_aggr, } }
+/** + * batadv_iv_ogm_queue_add - queue up an OGM for transmission + * @bat_priv: the bat priv with all the soft interface information + * @packet_buff: pointer to the OGM + * @packet_len: (total) length of the OGM + * @if_incoming: interface where the packet was received + * @if_outgoing: interface for which the retransmission should be considered + * @own_packet: true if it is a self-generated ogm + * @send_time: timestamp (jiffies) when the packet is to be sent + */ static void batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv, unsigned char *packet_buff, int packet_len, struct batadv_hard_iface *if_incoming, + struct batadv_hard_iface *if_outgoing, int own_packet, unsigned long send_time) { /* _aggr -> pointer to the packet we want to aggregate with @@ -743,6 +762,7 @@ static void batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv, bat_priv, packet_len, send_time, direct_link, if_incoming, + if_outgoing, forw_packet_pos)) { forw_packet_aggr = forw_packet_pos; break; @@ -766,7 +786,8 @@ static void batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv,
batadv_iv_ogm_aggregate_new(packet_buff, packet_len, send_time, direct_link, - if_incoming, own_packet); + if_incoming, if_outgoing, + own_packet); } else { batadv_iv_ogm_aggregate(forw_packet_aggr, packet_buff, packet_len, direct_link); @@ -779,7 +800,8 @@ static void batadv_iv_ogm_forward(struct batadv_orig_node *orig_node, struct batadv_ogm_packet *batadv_ogm_packet, bool is_single_hop_neigh, bool is_from_best_next_hop, - struct batadv_hard_iface *if_incoming) + struct batadv_hard_iface *if_incoming, + struct batadv_hard_iface *if_outgoing) { struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); uint16_t tvlv_len; @@ -824,7 +846,8 @@ static void batadv_iv_ogm_forward(struct batadv_orig_node *orig_node,
batadv_iv_ogm_queue_add(bat_priv, (unsigned char *)batadv_ogm_packet, BATADV_OGM_HLEN + tvlv_len, - if_incoming, 0, batadv_iv_ogm_fwd_send_time()); + if_incoming, if_outgoing, 0, + batadv_iv_ogm_fwd_send_time()); }
/** @@ -869,10 +892,11 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface) struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); unsigned char **ogm_buff = &hard_iface->bat_iv.ogm_buff; struct batadv_ogm_packet *batadv_ogm_packet; - struct batadv_hard_iface *primary_if; + struct batadv_hard_iface *primary_if, *tmp_hard_iface; int *ogm_buff_len = &hard_iface->bat_iv.ogm_buff_len; uint32_t seqno; uint16_t tvlv_len = 0; + unsigned long send_time;
primary_if = batadv_primary_if_get_selected(bat_priv);
@@ -895,10 +919,32 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface) atomic_inc(&hard_iface->bat_iv.ogm_seqno);
batadv_iv_ogm_slide_own_bcast_window(hard_iface); - batadv_iv_ogm_queue_add(bat_priv, hard_iface->bat_iv.ogm_buff, - hard_iface->bat_iv.ogm_buff_len, hard_iface, 1, - batadv_iv_ogm_emit_send_time(bat_priv));
+ send_time = batadv_iv_ogm_emit_send_time(bat_priv); + + if (hard_iface != primary_if) { + /* OGMs from secondary interfaces are only scheduled on their + * respective interfaces. + */ + batadv_iv_ogm_queue_add(bat_priv, *ogm_buff, *ogm_buff_len, + hard_iface, hard_iface, 1, send_time); + goto out; + } + + /* OGMs from primary interfaces are scheduled on all + * interfaces. + */ + rcu_read_lock(); + list_for_each_entry_rcu(tmp_hard_iface, &batadv_hardif_list, list) { + if (tmp_hard_iface->soft_iface != hard_iface->soft_iface) + continue; + batadv_iv_ogm_queue_add(bat_priv, *ogm_buff, + *ogm_buff_len, hard_iface, + tmp_hard_iface, 1, send_time); + } + rcu_read_unlock(); + +out: if (primary_if) batadv_hardif_free_ref(primary_if); } @@ -1446,6 +1492,10 @@ batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset, } batadv_orig_ifinfo_free_ref(orig_ifinfo);
+ /* only forward for specific interface, not for the default one. */ + if (if_outgoing == BATADV_IF_DEFAULT) + goto out_neigh; + /* is single hop (direct) neighbor */ if (is_single_hop_neigh) { if ((ogm_packet->header.ttl <= 2) && @@ -1457,7 +1507,8 @@ batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset, /* mark direct link on incoming interface */ batadv_iv_ogm_forward(orig_node, ethhdr, ogm_packet, is_single_hop_neigh, - is_from_best_next_hop, if_incoming); + is_from_best_next_hop, if_incoming, + if_outgoing);
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Forwarding packet: rebroadcast neighbor packet with direct link flag\n"); @@ -1481,7 +1532,7 @@ batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset, "Forwarding packet: rebroadcast originator packet\n"); batadv_iv_ogm_forward(orig_node, ethhdr, ogm_packet, is_single_hop_neigh, is_from_best_next_hop, - if_incoming); + if_incoming, if_outgoing);
out_neigh: if ((orig_neigh_node) && (!is_single_hop_neigh)) diff --git a/send.c b/send.c index c83be5e..a0dbeef 100644 --- a/send.c +++ b/send.c @@ -379,6 +379,8 @@ static void batadv_forw_packet_free(struct batadv_forw_packet *forw_packet) kfree_skb(forw_packet->skb); if (forw_packet->if_incoming) batadv_hardif_free_ref(forw_packet->if_incoming); + if (forw_packet->if_outgoing) + batadv_hardif_free_ref(forw_packet->if_outgoing); kfree(forw_packet); }
@@ -442,6 +444,7 @@ int batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv,
forw_packet->skb = newskb; forw_packet->if_incoming = primary_if; + forw_packet->if_outgoing = NULL;
/* how often did we send the bcast packet ? */ forw_packet->num_packets = 0; @@ -537,11 +540,16 @@ void batadv_send_outstanding_bat_ogm_packet(struct work_struct *work)
bat_priv->bat_algo_ops->bat_ogm_emit(forw_packet);
- /* we have to have at least one packet in the queue - * to determine the queues wake up time unless we are - * shutting down + /* we have to have at least one packet in the queue to determine the + * queues wake up time unless we are shutting down. + * + * only re-schedule if this is the "original" copy, e.g. the OGM of the + * primary interface should only be rescheduled once per period, but + * this function will be called for the forw_packet instances of the + * other secondary interfaces as well. */ - if (forw_packet->own) + if (forw_packet->own && + forw_packet->if_incoming == forw_packet->if_outgoing) batadv_schedule_bat_ogm(forw_packet->if_incoming);
out: @@ -602,7 +610,8 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv, * we delete only packets belonging to the given interface */ if ((hard_iface) && - (forw_packet->if_incoming != hard_iface)) + (forw_packet->if_incoming != hard_iface) && + (forw_packet->if_outgoing != hard_iface)) continue;
spin_unlock_bh(&bat_priv->forw_bat_list_lock); diff --git a/types.h b/types.h index 167c3a5..be3a4fd 100644 --- a/types.h +++ b/types.h @@ -1005,8 +1005,10 @@ struct batadv_skb_cb { * @direct_link_flags: direct link flags for aggregated OGM packets * @num_packets: counter for bcast packet retransmission * @delayed_work: work queue callback item for packet sending - * @if_incoming: pointer incoming hard-iface or primary iface if locally - * generated packet + * @if_incoming: pointer to incoming hard-iface or primary iface if + * locally generated packet + * @if_outgoing: packet where the packet should be sent to, or NULL if + * unspecified */ struct batadv_forw_packet { struct hlist_node list; @@ -1018,6 +1020,7 @@ struct batadv_forw_packet { uint8_t num_packets; struct delayed_work delayed_work; struct batadv_hard_iface *if_incoming; + struct batadv_hard_iface *if_outgoing; };
/**
From: Simon Wunderlich simon@open-mesh.com
With the new interface alternating, the first hop may send packets in a round robin fashion to it's neighbors because it has multiple valid routes built by the multi interface optimization. This patch enables the feature if bonding is selected. Note that unlike the bonding implemented before, this version is much simpler and may even enable multi path routing to a certain degree.
Signed-off-by: Simon Wunderlich simon@open-mesh.com --- Changes to PATCH: * use new references for orig_ifinfo in the bonding code * fix/beautify comments
Changes to RFCv2: * style changes (allo variables on one line * use new bat_neigh_is_equiv_or_better parameters * simplify last candidate lookup (Antonios suggestion) * remove last_bonding_candidate pointer when purging --- originator.c | 4 +++ routing.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- routing.h | 2 +- types.h | 2 ++ 4 files changed, 117 insertions(+), 4 deletions(-)
diff --git a/originator.c b/originator.c index 62691d0..589bfed 100644 --- a/originator.c +++ b/originator.c @@ -692,6 +692,10 @@ batadv_purge_orig_ifinfo(struct batadv_priv *bat_priv,
hlist_del_rcu(&orig_ifinfo->list); batadv_orig_ifinfo_free_ref(orig_ifinfo); + if (orig_node->last_bonding_candidate == orig_ifinfo) { + orig_node->last_bonding_candidate = NULL; + batadv_orig_ifinfo_free_ref(orig_ifinfo); + } }
spin_unlock_bh(&orig_node->neigh_list_lock); diff --git a/routing.c b/routing.c index da6741a..c221e8c 100644 --- a/routing.c +++ b/routing.c @@ -426,16 +426,123 @@ static int batadv_check_unicast_packet(struct batadv_priv *bat_priv, struct batadv_neigh_node * batadv_find_router(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, - const struct batadv_hard_iface *recv_if) + struct batadv_hard_iface *recv_if) { - struct batadv_neigh_node *router; + struct batadv_algo_ops *bao = bat_priv->bat_algo_ops; + struct batadv_neigh_node *first_candidate_router = NULL; + struct batadv_neigh_node *next_candidate_router; + struct batadv_neigh_node *router, *cand_router = NULL; + struct batadv_orig_ifinfo *cand, *first_candidate = NULL; + struct batadv_orig_ifinfo *next_candidate = NULL; + bool last_candidate_found = false;
if (!orig_node) return NULL;
router = batadv_orig_router_get(orig_node, recv_if);
- /* TODO: fill this later with new bonding mechanism */ + /* only consider bonding for recv_if == BATADV_IF_DEFAULT (first hop) + * and if activated. + */ + if (recv_if == BATADV_IF_DEFAULT || !atomic_read(&bat_priv->bonding) || + !router) + return router; + + /* bonding: loop through the list of possible routers found + * for the various outgoing interfaces and find a candidate after + * the last chosen bonding candidate (next_candidate). If no such + * router is found, use the first candidate found (the previously + * chosen bonding candidate might have been the last one in the list). + * If this can't be found either, return the previously choosen + * router - obviously there are no other candidates. + */ + rcu_read_lock(); + hlist_for_each_entry_rcu(cand, &orig_node->ifinfo_list, list) { + /* acquire some structures and references ... */ + if (!atomic_inc_not_zero(&cand->refcount)) + continue; + + cand_router = rcu_dereference(cand->router); + if (!cand_router) + goto next; + + if (!atomic_inc_not_zero(&cand_router->refcount)) { + cand_router = NULL; + goto next; + } + + /* alternative candidate should be good enough to be + * considered + */ + if (!bao->bat_neigh_is_equiv_or_better(cand_router, + cand->if_outgoing, + router, recv_if)) + goto next; + + /* don't use the same router twice */ + if (orig_node->last_bonding_candidate && + (orig_node->last_bonding_candidate->router == cand_router)) + goto next; + + /* mark the first possible candidate */ + if (!first_candidate) { + atomic_inc(&cand_router->refcount); + atomic_inc(&cand->refcount); + first_candidate = cand; + first_candidate_router = cand_router; + } + + /* check if the loop has already passed the previously selected + * candidate ... this function should select the next candidate + * AFTER the previously used bonding candidate. + */ + if (!orig_node->last_bonding_candidate || + last_candidate_found) { + next_candidate = cand; + next_candidate_router = cand_router; + break; + } + + if (orig_node->last_bonding_candidate == cand) + last_candidate_found = true; +next: + /* free references */ + if (cand_router) { + batadv_neigh_node_free_ref(cand_router); + cand_router = NULL; + } + batadv_orig_ifinfo_free_ref(cand); + } + rcu_read_unlock(); + + /* last_bonding_candidate is reset below, remove the old reference. */ + if (orig_node->last_bonding_candidate) + batadv_orig_ifinfo_free_ref(orig_node->last_bonding_candidate); + + /* After finding candidates, handle the three cases: + * 1) there is a next candidate, use that + * 2) there is no next candidate, use the first of the list + * 3) there is no candidate at all, return the default router + */ + if (next_candidate) { + batadv_neigh_node_free_ref(router); + + /* remove references to first candidate, we don't need it. */ + if (first_candidate) { + batadv_neigh_node_free_ref(first_candidate_router); + batadv_orig_ifinfo_free_ref(first_candidate); + } + router = next_candidate_router; + orig_node->last_bonding_candidate = next_candidate; + } else if (first_candidate) { + batadv_neigh_node_free_ref(router); + + /* refcounting has already been done in the loop above. */ + router = first_candidate_router; + orig_node->last_bonding_candidate = first_candidate; + } else { + orig_node->last_bonding_candidate = NULL; + }
return router; } diff --git a/routing.h b/routing.h index 7a7c6e9..2c80b6a 100644 --- a/routing.h +++ b/routing.h @@ -46,7 +46,7 @@ int batadv_recv_unhandled_unicast_packet(struct sk_buff *skb, struct batadv_neigh_node * batadv_find_router(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, - const struct batadv_hard_iface *recv_if); + struct batadv_hard_iface *recv_if); int batadv_window_protected(struct batadv_priv *bat_priv, int32_t seq_num_diff, unsigned long *last_reset);
diff --git a/types.h b/types.h index be3a4fd..2793b64 100644 --- a/types.h +++ b/types.h @@ -187,6 +187,7 @@ struct batadv_orig_bat_iv { * @orig: originator ethernet address * @primary_addr: hosts primary interface address * @ifinfo_list: list for routers per outgoing interface + * @last_bonding_candidate: pointer to last ifinfo of last used router * @batadv_dat_addr_t: address of the orig node in the distributed hash * @last_seen: time when last packet from this node was received * @bcast_seqno_reset: time when the broadcast seqno window was reset @@ -227,6 +228,7 @@ struct batadv_orig_node { uint8_t orig[ETH_ALEN]; uint8_t primary_addr[ETH_ALEN]; struct hlist_head ifinfo_list; + struct batadv_orig_ifinfo *last_bonding_candidate; #ifdef CONFIG_BATMAN_ADV_DAT batadv_dat_addr_t dat_addr; #endif
From: Simon Wunderlich simon@open-mesh.com
To show information per interface, add a debugfs hardif structure similar to the system in sysfs. A folder "$debugfs/batman_adv/hardif" will be created and will contain all hard interfaces. Files are not yet added.
Signed-off-by: Simon Wunderlich simon@open-mesh.com --- debugfs.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ debugfs.h | 3 +++ hard-interface.c | 9 ++++++++ types.h | 2 ++ 4 files changed, 80 insertions(+)
diff --git a/debugfs.c b/debugfs.c index 049a7a2..53e13a3 100644 --- a/debugfs.c +++ b/debugfs.c @@ -34,6 +34,7 @@ #include "network-coding.h"
static struct dentry *batadv_debugfs; +static struct dentry *batadv_hardif_debugfs;
#ifdef CONFIG_BATMAN_ADV_DEBUG #define BATADV_LOG_BUFF_MASK (batadv_log_buff_len - 1) @@ -371,6 +372,10 @@ static struct batadv_debuginfo *batadv_mesh_debuginfos[] = { NULL, };
+static struct batadv_debuginfo *batadv_hardif_debuginfos[] = { + NULL, +}; + void batadv_debugfs_init(void) { struct batadv_debuginfo **bat_debug; @@ -383,6 +388,11 @@ void batadv_debugfs_init(void) if (!batadv_debugfs) goto err;
+ batadv_hardif_debugfs = debugfs_create_dir(BATADV_DEBUGFS_HARDIF_SUBDIR, + batadv_debugfs); + if (batadv_hardif_debugfs == ERR_PTR(-ENODEV)) + goto err; + for (bat_debug = batadv_general_debuginfos; *bat_debug; ++bat_debug) { file = debugfs_create_file(((*bat_debug)->attr).name, S_IFREG | ((*bat_debug)->attr).mode, @@ -398,12 +408,68 @@ void batadv_debugfs_init(void) return; err: debugfs_remove_recursive(batadv_debugfs); + batadv_debugfs = NULL; + batadv_hardif_debugfs = NULL; }
void batadv_debugfs_destroy(void) { debugfs_remove_recursive(batadv_debugfs); batadv_debugfs = NULL; + batadv_hardif_debugfs = NULL; +} + +/** + * batadv_debugfs_add_hardif - creates the base directory for a hard interface + * in debugfs. + * @hard_iface: hard interface which should be added. + */ +int batadv_debugfs_add_hardif(struct batadv_hard_iface *hard_iface) +{ + struct batadv_debuginfo **bat_debug; + struct dentry *file; + + if (!batadv_debugfs) + goto out; + + hard_iface->debug_dir = debugfs_create_dir(hard_iface->net_dev->name, + batadv_hardif_debugfs); + if (!hard_iface->debug_dir) + goto out; + + for (bat_debug = batadv_hardif_debuginfos; *bat_debug; ++bat_debug) { + file = debugfs_create_file(((*bat_debug)->attr).name, + S_IFREG | ((*bat_debug)->attr).mode, + hard_iface->debug_dir, + hard_iface->net_dev, + &(*bat_debug)->fops); + if (!file) + goto rem_attr; + } + + return 0; +rem_attr: + debugfs_remove_recursive(hard_iface->debug_dir); + hard_iface->debug_dir = NULL; +out: +#ifdef CONFIG_DEBUG_FS + return -ENOMEM; +#else + return 0; +#endif /* CONFIG_DEBUG_FS */ +} + +/** + * batadv_debugfs_del_hardif - delete the base directory for a hard interface + * in debugfs. + * @hard_iface: hard interface which is deleted. + */ +void batadv_debugfs_del_hardif(struct batadv_hard_iface *hard_iface) +{ + if (batadv_hardif_debugfs) { + debugfs_remove_recursive(hard_iface->debug_dir); + hard_iface->debug_dir = NULL; + } }
int batadv_debugfs_add_meshif(struct net_device *dev) diff --git a/debugfs.h b/debugfs.h index f8c3849..5228d63 100644 --- a/debugfs.h +++ b/debugfs.h @@ -21,10 +21,13 @@ #define _NET_BATMAN_ADV_DEBUGFS_H_
#define BATADV_DEBUGFS_SUBDIR "batman_adv" +#define BATADV_DEBUGFS_HARDIF_SUBDIR "hardif"
void batadv_debugfs_init(void); void batadv_debugfs_destroy(void); int batadv_debugfs_add_meshif(struct net_device *dev); void batadv_debugfs_del_meshif(struct net_device *dev); +int batadv_debugfs_add_hardif(struct batadv_hard_iface *hard_iface); +void batadv_debugfs_del_hardif(struct batadv_hard_iface *hard_iface);
#endif /* _NET_BATMAN_ADV_DEBUGFS_H_ */ diff --git a/hard-interface.c b/hard-interface.c index 57c2a19..ded7043 100644 --- a/hard-interface.c +++ b/hard-interface.c @@ -25,6 +25,7 @@ #include "translation-table.h" #include "routing.h" #include "sysfs.h" +#include "debugfs.h" #include "originator.h" #include "hash.h" #include "bridge_loop_avoidance.h" @@ -541,6 +542,7 @@ static void batadv_hardif_remove_interface_finish(struct work_struct *work) hard_iface = container_of(work, struct batadv_hard_iface, cleanup_work);
+ batadv_debugfs_del_hardif(hard_iface); batadv_sysfs_del_hardif(&hard_iface->hardif_obj); batadv_hardif_free_ref(hard_iface); } @@ -571,6 +573,11 @@ batadv_hardif_add_interface(struct net_device *net_dev) hard_iface->net_dev = net_dev; hard_iface->soft_iface = NULL; hard_iface->if_status = BATADV_IF_NOT_IN_USE; + + ret = batadv_debugfs_add_hardif(hard_iface); + if (ret) + goto free_sysfs; + INIT_LIST_HEAD(&hard_iface->list); INIT_WORK(&hard_iface->cleanup_work, batadv_hardif_remove_interface_finish); @@ -587,6 +594,8 @@ batadv_hardif_add_interface(struct net_device *net_dev)
return hard_iface;
+free_sysfs: + batadv_sysfs_del_hardif(&hard_iface->hardif_obj); free_if: kfree(hard_iface); release_dev: diff --git a/types.h b/types.h index 2793b64..25a9815 100644 --- a/types.h +++ b/types.h @@ -74,6 +74,7 @@ struct batadv_hard_iface_bat_iv { * @rcu: struct used for freeing in an RCU-safe manner * @bat_iv: BATMAN IV specific per hard interface data * @cleanup_work: work queue callback item for hard interface deinit + * @debug_dir: dentry for nc subdir in batman-adv directory in debugfs */ struct batadv_hard_iface { struct list_head list; @@ -88,6 +89,7 @@ struct batadv_hard_iface { struct rcu_head rcu; struct batadv_hard_iface_bat_iv bat_iv; struct work_struct cleanup_work; + struct dentry *debug_dir; };
/* struct batadv_orig_ifinfo - originator info per outgoing interface
From: Simon Wunderlich simon@open-mesh.com
Show tables for the multi interface operation. Originator tables are added per hard interface.
This patch also changes the API by adding the interface to the bat_orig_print() parameters.
Signed-off-by: Simon Wunderlich simon@open-mesh.com --- Changes to PATCH: * use one file per interface instead of all tables in one file * kernel doc and commit message improvement --- bat_iv_ogm.c | 12 +++++++----- debugfs.c | 17 +++++++++++++++++ originator.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++- originator.h | 1 + types.h | 3 ++- 5 files changed, 74 insertions(+), 7 deletions(-)
diff --git a/bat_iv_ogm.c b/bat_iv_ogm.c index c44bca6..c7e5eb7 100644 --- a/bat_iv_ogm.c +++ b/bat_iv_ogm.c @@ -1784,9 +1784,11 @@ batadv_iv_ogm_orig_print_neigh(struct batadv_orig_node *orig_node, * batadv_iv_ogm_orig_print - print the originator table * @bat_priv: the bat priv with all the soft interface information * @seq: debugfs table seq_file struct + * @if_outgoing: the outgoing interface for which this should be printed */ static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv, - struct seq_file *seq) + struct seq_file *seq, + struct batadv_hard_iface *if_outgoing) { struct batadv_neigh_node *neigh_node; struct batadv_hashtable *hash = bat_priv->orig_hash; @@ -1808,12 +1810,12 @@ static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv, rcu_read_lock(); hlist_for_each_entry_rcu(orig_node, head, hash_entry) { neigh_node = batadv_orig_router_get(orig_node, - BATADV_IF_DEFAULT); + if_outgoing); if (!neigh_node) continue;
n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, - BATADV_IF_DEFAULT); + if_outgoing); if (!n_ifinfo) goto next;
@@ -1831,8 +1833,8 @@ static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv, neigh_node->addr, neigh_node->if_incoming->net_dev->name);
- batadv_iv_ogm_orig_print_neigh(orig_node, - BATADV_IF_DEFAULT, seq); + batadv_iv_ogm_orig_print_neigh(orig_node, if_outgoing, + seq); seq_puts(seq, "\n"); batman_count++;
diff --git a/debugfs.c b/debugfs.c index 53e13a3..2aac76a 100644 --- a/debugfs.c +++ b/debugfs.c @@ -251,6 +251,19 @@ static int batadv_originators_open(struct inode *inode, struct file *file) return single_open(file, batadv_orig_seq_print_text, net_dev); }
+/** + * batadv_originators_open_multiif - handles debugfs output for the + * originators_multiif table + * @inode: inode pointer to debugfs file + * @file: pointer to the seq_file + */ +static int batadv_originators_open_multiif(struct inode *inode, + struct file *file) +{ + struct net_device *net_dev = (struct net_device *)inode->i_private; + return single_open(file, batadv_orig_multiif_seq_print_text, net_dev); +} + static int batadv_gateways_open(struct inode *inode, struct file *file) { struct net_device *net_dev = (struct net_device *)inode->i_private; @@ -372,7 +385,11 @@ static struct batadv_debuginfo *batadv_mesh_debuginfos[] = { NULL, };
+static BATADV_DEBUGINFO(originators_multiif, S_IRUGO, + batadv_originators_open_multiif); + static struct batadv_debuginfo *batadv_hardif_debuginfos[] = { + &batadv_debuginfo_originators_multiif, NULL, };
diff --git a/originator.c b/originator.c index 589bfed..e67749a 100644 --- a/originator.c +++ b/originator.c @@ -909,11 +909,57 @@ int batadv_orig_seq_print_text(struct seq_file *seq, void *offset) return 0; }
- bat_priv->bat_algo_ops->bat_orig_print(bat_priv, seq); + bat_priv->bat_algo_ops->bat_orig_print(bat_priv, seq, + BATADV_IF_DEFAULT);
return 0; }
+/** + * batadv_orig_multiif_seq_print_text - writes originator infos for all + * outgoing interfaces + * @seq: debugfs table seq_file struct + * @offset: not used + * + * Returns 0 + */ +int batadv_orig_multiif_seq_print_text(struct seq_file *seq, void *offset) +{ + struct net_device *net_dev = (struct net_device *)seq->private; + struct batadv_hard_iface *hard_iface; + struct batadv_priv *bat_priv; + + hard_iface = batadv_hardif_get_by_netdev(net_dev); + + if (!hard_iface || !hard_iface->soft_iface) { + seq_puts(seq, "Interface not known to to B.A.T.M.A.N.\n"); + goto out; + } + + bat_priv = netdev_priv(hard_iface->soft_iface); + if (!bat_priv->bat_algo_ops->bat_orig_print) { + seq_puts(seq, + "No printing function for this routing protocol\n"); + goto out; + } + + if (hard_iface->if_status != BATADV_IF_ACTIVE) { + seq_puts(seq, "Interface not active\n"); + goto out; + } + + seq_printf(seq, "[B.A.T.M.A.N. adv %s, IF/MAC: %s/%pM (%s %s)]\n", + BATADV_SOURCE_VERSION, hard_iface->net_dev->name, + hard_iface->net_dev->dev_addr, + hard_iface->soft_iface->name, bat_priv->bat_algo_ops->name); + + bat_priv->bat_algo_ops->bat_orig_print(bat_priv, seq, hard_iface); + +out: + batadv_hardif_free_ref(hard_iface); + return 0; +} + int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, int max_if_num) { diff --git a/originator.h b/originator.h index 404f7cb..28e8487 100644 --- a/originator.h +++ b/originator.h @@ -55,6 +55,7 @@ batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node, void batadv_orig_ifinfo_free_ref(struct batadv_orig_ifinfo *orig_ifinfo);
int batadv_orig_seq_print_text(struct seq_file *seq, void *offset); +int batadv_orig_multiif_seq_print_text(struct seq_file *seq, void *offset); int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, int max_if_num); int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface, diff --git a/types.h b/types.h index 25a9815..65b76fa 100644 --- a/types.h +++ b/types.h @@ -1070,7 +1070,8 @@ struct batadv_algo_ops { struct batadv_neigh_node *neigh2, struct batadv_hard_iface *if_outgoing2); /* orig_node handling API */ - void (*bat_orig_print)(struct batadv_priv *priv, struct seq_file *seq); + void (*bat_orig_print)(struct batadv_priv *priv, struct seq_file *seq, + struct batadv_hard_iface *hard_iface); void (*bat_orig_free)(struct batadv_orig_node *orig_node); int (*bat_orig_add_if)(struct batadv_orig_node *orig_node, int max_if_num);
b.a.t.m.a.n@lists.open-mesh.org