From: Simon Wunderlich Date: Mon, 21 Jun 2010 23:25:53 +0000 (+0200) Subject: Staging: batman-adv: bonding and interface alternating X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=11f79decfd4e33e29694075a859f529e6d4321ad;p=linux-beck.git Staging: batman-adv: bonding and interface alternating This patch adds interface alternating to the new bonding feature. By default, we now try to avoid forwarding packets on the receiving interface, instead choosing alternative interfaces. This feature works only on nodes which have multiple interfaces connected to the mesh. This approach should reduce problems of the half-duplex nature of WiFi Hardware and thus increase performance. Signed-off-by: Simon Wunderlich Acked-by: Marek Lindner [sven.eckelmann@gmx.de: Rework on top of current version] Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c index f393cc0d744e..5f8213786eaf 100644 --- a/drivers/staging/batman-adv/hard-interface.c +++ b/drivers/staging/batman-adv/hard-interface.c @@ -512,7 +512,7 @@ int batman_skb_recv(struct sk_buff *skb, struct net_device *dev, /* unicast packet */ case BAT_UNICAST: - ret = recv_unicast_packet(skb); + ret = recv_unicast_packet(skb, batman_if); break; /* broadcast packet */ diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c index 6a2c2d18d3f5..048795e319a8 100644 --- a/drivers/staging/batman-adv/routing.c +++ b/drivers/staging/batman-adv/routing.c @@ -402,12 +402,6 @@ static void mark_bonding_address(struct bat_priv *bat_priv, struct batman_packet *batman_packet) { - /* don't care if bonding is not enabled */ - if (!atomic_read(&bat_priv->bonding_enabled)) { - orig_node->bond.candidates = 0; - return; - } - if (batman_packet->flags & PRIMARIES_FIRST_HOP) memcpy(orig_neigh_node->primary_addr, orig_node->orig, ETH_ALEN); @@ -425,12 +419,6 @@ void update_bonding_candidates(struct bat_priv *bat_priv, struct neigh_node *tmp_neigh_node, *tmp_neigh_node2; struct neigh_node *first_candidate, *last_candidate; - /* don't care if bonding is not enabled */ - if (!atomic_read(&bat_priv->bonding_enabled)) { - orig_node->bond.candidates = 0; - return; - } - /* update the candidates for this originator */ if (!orig_node->router) { orig_node->bond.candidates = 0; @@ -986,14 +974,16 @@ int recv_icmp_packet(struct sk_buff *skb) /* find a suitable router for this originator, and use * bonding if possible. */ -struct neigh_node *find_router(struct orig_node *orig_node) +struct neigh_node *find_router(struct orig_node *orig_node, + struct batman_if *recv_if) { /* FIXME: each orig_node->batman_if will be attached to a softif */ struct bat_priv *bat_priv = netdev_priv(soft_device); struct orig_node *primary_orig_node; struct orig_node *router_orig; - struct neigh_node *router; + struct neigh_node *router, *first_candidate, *best_router; static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; + int bonding_enabled; if (!orig_node) return NULL; @@ -1001,9 +991,12 @@ struct neigh_node *find_router(struct orig_node *orig_node) if (!orig_node->router) return NULL; - /* don't care if bonding is not enabled */ - if (!atomic_read(&bat_priv->bonding_enabled)) - return orig_node->router; + /* without bonding, the first node should + * always choose the default router. */ + + bonding_enabled = atomic_read(&bat_priv->bonding_enabled); + if (!bonding_enabled && (recv_if == NULL)) + return orig_node->router; router_orig = orig_node->router->orig_node; @@ -1031,19 +1024,48 @@ struct neigh_node *find_router(struct orig_node *orig_node) if (primary_orig_node->bond.candidates < 2) return orig_node->router; - router = primary_orig_node->bond.selected; - /* sanity check - this should never happen. */ - if (!router) - return orig_node->router; + /* all nodes between should choose a candidate which + * is is not on the interface where the packet came + * in. */ + first_candidate = primary_orig_node->bond.selected; + router = first_candidate; + + if (bonding_enabled) { + /* in the bonding case, send the packets in a round + * robin fashion over the remaining interfaces. */ + do { + /* recv_if == NULL on the first node. */ + if (router->if_incoming != recv_if) + break; + + router = router->next_bond_candidate; + } while (router != first_candidate); + + primary_orig_node->bond.selected = router->next_bond_candidate; - /* select the next bonding partner ... */ - primary_orig_node->bond.selected = router->next_bond_candidate; + } else { + /* if bonding is disabled, use the best of the + * remaining candidates which are not using + * this interface. */ + best_router = first_candidate; + + do { + /* recv_if == NULL on the first node. */ + if ((router->if_incoming != recv_if) && + (router->tq_avg > best_router->tq_avg)) + best_router = router; + + router = router->next_bond_candidate; + } while (router != first_candidate); + + router = best_router; + } return router; } -int recv_unicast_packet(struct sk_buff *skb) +int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) { struct unicast_packet *unicast_packet; struct orig_node *orig_node; @@ -1095,7 +1117,7 @@ int recv_unicast_packet(struct sk_buff *skb) orig_node = ((struct orig_node *) hash_find(orig_hash, unicast_packet->dest)); - router = find_router(orig_node); + router = find_router(orig_node, recv_if); if (!router) { spin_unlock_irqrestore(&orig_hash_lock, flags); diff --git a/drivers/staging/batman-adv/routing.h b/drivers/staging/batman-adv/routing.h index 0e33d227cf19..43387a2a3324 100644 --- a/drivers/staging/batman-adv/routing.h +++ b/drivers/staging/batman-adv/routing.h @@ -30,11 +30,12 @@ void update_routes(struct orig_node *orig_node, struct neigh_node *neigh_node, unsigned char *hna_buff, int hna_buff_len); int recv_icmp_packet(struct sk_buff *skb); -int recv_unicast_packet(struct sk_buff *skb); +int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if); int recv_bcast_packet(struct sk_buff *skb); int recv_vis_packet(struct sk_buff *skb); int recv_bat_packet(struct sk_buff *skb, struct batman_if *batman_if); -struct neigh_node *find_router(struct orig_node *orig_node); +struct neigh_node *find_router(struct orig_node *orig_node, + struct batman_if *recv_if); void update_bonding_candidates(struct bat_priv *bat_priv, struct orig_node *orig_node); diff --git a/drivers/staging/batman-adv/soft-interface.c b/drivers/staging/batman-adv/soft-interface.c index 37fd56565ca5..ef7860d53a5c 100644 --- a/drivers/staging/batman-adv/soft-interface.c +++ b/drivers/staging/batman-adv/soft-interface.c @@ -188,7 +188,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *dev) if (!orig_node) orig_node = transtable_search(ethhdr->h_dest); - router = find_router(orig_node); + router = find_router(orig_node, NULL); if (!router) goto unlock;