Staging: batman-adv: bonding and interface alternating
authorSimon Wunderlich <siwu@hrz.tu-chemnitz.de>
Mon, 21 Jun 2010 23:25:53 +0000 (01:25 +0200)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 22 Jun 2010 21:05:06 +0000 (14:05 -0700)
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 <siwu@hrz.tu-chemnitz.de>
Acked-by: Marek Lindner <lindner_marek@yahoo.de>
[sven.eckelmann@gmx.de: Rework on top of current version]
Signed-off-by: Sven Eckelmann <sven.eckelmann@gmx.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/staging/batman-adv/hard-interface.c
drivers/staging/batman-adv/routing.c
drivers/staging/batman-adv/routing.h
drivers/staging/batman-adv/soft-interface.c

index f393cc0d744e81904e0f03d87b02f549cec3e752..5f8213786eaf91f7f2ff163ce88f84a6aabd907c 100644 (file)
@@ -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 */
index 6a2c2d18d3f5aa225b9c40ece3bce0d8c5d6e3b8..048795e319a80b83e73b3f06df234ae86d933d71 100644 (file)
@@ -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);
index 0e33d227cf199b4ef27c1c13a2f881ec263556f0..43387a2a33241c81a7ae16d5e0155ff675cf213c 100644 (file)
@@ -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);
index 37fd56565ca5a804ff54ef42874f7a5c0a7bde88..ef7860d53a5c332a0dff55fa9130dff8c32c3d44 100644 (file)
@@ -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;