This patch adds interface alternating to the new bonding feature.
Instead of only sending in a round robin fashion on the usable interfaces, we can also attempt to use a different interface for sending than for receiving (interface alternating). This should reduce problems of the half-duplex nature of WiFi Hardware and thus increase performance. The bonding modes are now enhanced from two modes (disabled/enabled) to the following 4 modes:
* 0 - bonding off * 1 - round robin (as before) * 2 - interface alternating * 3 - smart bonding (round robin + interface alternating)
This is an experimental patch and targeted for upcoming experiments at Wireless Battle Mesh v3 in Bracciano/Italy.
Feedback, comments and reviews appreciated!
Signed-off-by: Simon Wunderlich siwu@hrz.tu-chemnitz.de --- Index: a/batman-adv-kernelland/types.h =================================================================== --- a/batman-adv-kernelland/types.h (revision 1679) +++ a/batman-adv-kernelland/types.h (working copy) @@ -119,7 +119,7 @@ struct bat_priv { struct net_device_stats stats; atomic_t aggregation_enabled; - atomic_t bonding_enabled; + atomic_t bonding_mode; atomic_t vis_mode; atomic_t gw_mode; atomic_t gw_class; Index: a/batman-adv-kernelland/soft-interface.c =================================================================== --- a/batman-adv-kernelland/soft-interface.c (revision 1679) +++ a/batman-adv-kernelland/soft-interface.c (working copy) @@ -250,7 +250,7 @@ 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; Index: a/batman-adv-kernelland/hard-interface.c =================================================================== --- a/batman-adv-kernelland/hard-interface.c (revision 1679) +++ a/batman-adv-kernelland/hard-interface.c (working copy) @@ -514,7 +514,7 @@
/* unicast packet */ case BAT_UNICAST: - ret = recv_unicast_packet(skb); + ret = recv_unicast_packet(skb, batman_if); break;
/* broadcast packet */ Index: a/batman-adv-kernelland/routing.c =================================================================== --- a/batman-adv-kernelland/routing.c (revision 1679) +++ a/batman-adv-kernelland/routing.c (working copy) @@ -417,7 +417,7 @@
{ /* don't care if bonding is not enabled */ - if (!atomic_read(&bat_priv->bonding_enabled)) { + if (!atomic_read(&bat_priv->bonding_mode)) { orig_node->bond.candidates = 0; return; } @@ -429,7 +429,7 @@ return; }
-/* mark possible bonding candidates in the neighbor list */ +/* mark possible bond.candidates in the neighbor list */ void update_bonding_candidates(struct bat_priv *bat_priv, struct orig_node *orig_node) { @@ -440,7 +440,7 @@ struct neigh_node *first_candidate, *last_candidate;
/* don't care if bonding is not enabled */ - if (!atomic_read(&bat_priv->bonding_enabled)) { + if (!atomic_read(&bat_priv->bonding_mode)) { orig_node->bond.candidates = 0; return; } @@ -453,7 +453,7 @@
best_tq = orig_node->router->tq_avg;
- /* update bonding candidates */ + /* update bond.candidates */
candidates = 0;
@@ -1007,14 +1007,16 @@
/* 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; static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; + int bonding_mode;
if (!orig_node) return NULL; @@ -1022,8 +1024,9 @@ if (!orig_node->router) return NULL;
- /* don't care if bonding is not enabled */ - if (!atomic_read(&bat_priv->bonding_enabled)) + /* just return default router if bonding is not enabled */ + bonding_mode = atomic_read(&bat_priv->bonding_mode); + if (!bonding_mode) return orig_node->router;
router_orig = orig_node->router->orig_node; @@ -1052,19 +1055,50 @@ if (primary_orig_node->bond.candidates < 2) return orig_node->router;
- router = primary_orig_node->bond.selected; + switch (bonding_mode) { + case BONDING_ROUNDROBIN: + router = primary_orig_node->bond.selected;
- /* sanity check - this should never happen. */ - if (!router) - return orig_node->router; + /* sanity check - this should never happen. */ + if (!router) + return orig_node->router;
- /* select the next bonding partner ... */ - primary_orig_node->bond.selected = router->next_bond_candidate; + /* select the next bonding partner ... */ + primary_orig_node->bond.selected = router->next_bond_candidate; + break; + case BONDING_ALTERNATE: + /* in alternate mode, the first node should + * always choose the default router. */ + if (recv_if == NULL) + return orig_node->router;
+ /* all nodes between should choose a candidate which + * is is not on the interface where the packet came + * in. There might be more than one alternative + * interface, and we send the packet in a round robin + * fashion on these interfaces in this case. */ + case BONDING_SMART: + first_candidate = primary_orig_node->bond.selected; + router = first_candidate; + + do { + /* recv_if == NULL on the first node. */ + if (router->if_incoming != recv_if) + break; + router = router->next_bond_candidate; + } while (router != first_candidate); + + /* select the next to have some diversity here. */ + primary_orig_node->bond.selected = router->next_bond_candidate; + break; + default: + router = orig_node->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; @@ -1116,7 +1150,7 @@ 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: a/batman-adv-kernelland/main.h =================================================================== --- a/batman-adv-kernelland/main.h (revision 1679) +++ a/batman-adv-kernelland/main.h (working copy) @@ -63,6 +63,10 @@ * to be considered as bonding candidates */
#define BONDING_TQ_THRESHOLD 50 +#define BONDING_NONE 0 +#define BONDING_ROUNDROBIN 1 +#define BONDING_ALTERNATE 2 +#define BONDING_SMART 3
#define MAX_AGGREGATION_BYTES 512 /* should not be bigger than 512 bytes or * change the size of Index: a/batman-adv-kernelland/routing.h =================================================================== --- a/batman-adv-kernelland/routing.h (revision 1679) +++ a/batman-adv-kernelland/routing.h (working copy) @@ -32,11 +32,12 @@ 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: a/batman-adv-kernelland/bat_sysfs.c =================================================================== --- a/batman-adv-kernelland/bat_sysfs.c (revision 1679) +++ a/batman-adv-kernelland/bat_sysfs.c (working copy) @@ -92,10 +92,9 @@ { struct device *dev = to_dev(kobj->parent); struct bat_priv *bat_priv = netdev_priv(to_net_dev(dev)); - int bond_status = atomic_read(&bat_priv->bonding_enabled); + int bonding_mode = atomic_read(&bat_priv->bonding_mode);
- return sprintf(buff, "%s\n", - bond_status == 0 ? "disabled" : "enabled"); + return sprintf(buff, "%d\n", bonding_mode); }
static ssize_t store_bond(struct kobject *kobj, struct attribute *attr, @@ -104,17 +103,25 @@ struct device *dev = to_dev(kobj->parent); struct net_device *net_dev = to_net_dev(dev); struct bat_priv *bat_priv = netdev_priv(net_dev); - int bonding_enabled_tmp = -1; + int bonding_mode_tmp = -1;
- if (((count == 2) && (buff[0] == '1')) || - (strncmp(buff, "enable", 6) == 0)) - bonding_enabled_tmp = 1; + if (count == 2) + switch (buff[0]) { + case '0': + bonding_mode_tmp = 0; + break; + case '1': + bonding_mode_tmp = BONDING_ROUNDROBIN; + break; + case '2': + bonding_mode_tmp = BONDING_ALTERNATE; + break; + case '3': + bonding_mode_tmp = BONDING_SMART; + break; + }
- if (((count == 2) && (buff[0] == '0')) || - (strncmp(buff, "disable", 7) == 0)) - bonding_enabled_tmp = 0; - - if (bonding_enabled_tmp < 0) { + if (bonding_mode_tmp < 0) { if (buff[count - 1] == '\n') buff[count - 1] = '\0';
@@ -123,16 +130,14 @@ return -EINVAL; }
- if (atomic_read(&bat_priv->bonding_enabled) == bonding_enabled_tmp) + if (atomic_read(&bat_priv->bonding_mode) == bonding_mode_tmp) return count;
- printk(KERN_INFO "batman-adv:Changing bonding from: %s to: %s on mesh: %s\n", - atomic_read(&bat_priv->bonding_enabled) == 1 ? - "enabled" : "disabled", - bonding_enabled_tmp == 1 ? "enabled" : "disabled", + printk(KERN_INFO "batman-adv:Changing bonding from: %d to: %d on mesh: %s\n", + atomic_read(&bat_priv->bonding_mode), bonding_mode_tmp, net_dev->name);
- atomic_set(&bat_priv->bonding_enabled, (unsigned)bonding_enabled_tmp); + atomic_set(&bat_priv->bonding_mode, (unsigned)bonding_mode_tmp); return count; }
@@ -303,7 +308,7 @@ /* FIXME: should be done in the general mesh setup routine as soon as we have it */ atomic_set(&bat_priv->aggregation_enabled, 1); - atomic_set(&bat_priv->bonding_enabled, 0); + atomic_set(&bat_priv->bonding_mode, 0); atomic_set(&bat_priv->vis_mode, VIS_TYPE_CLIENT_UPDATE); atomic_set(&bat_priv->gw_mode, GW_MODE_OFF); atomic_set(&bat_priv->gw_class, 0);