summaryrefslogtreecommitdiffstats
path: root/net/batman-adv/routing.c
diff options
context:
space:
mode:
authorAntonio Quartulli <ordex@autistici.org>2011-04-27 14:27:57 +0200
committerSven Eckelmann <sven@narfation.org>2011-06-20 11:37:27 +0200
commitcc47f66e6b9ec7e7d465f74739a6fc9844593894 (patch)
tree8fbda7f59267bca45f9e887d09ba1de2f3c62f8d /net/batman-adv/routing.c
parentbatman-adv: improved client announcement mechanism (diff)
downloadlinux-cc47f66e6b9ec7e7d465f74739a6fc9844593894.tar.xz
linux-cc47f66e6b9ec7e7d465f74739a6fc9844593894.zip
batman-adv: improved roaming mechanism
With the current client announcement implementation, in case of roaming, an update is triggered on the new AP serving the client. At that point the new information is spread around by means of the OGM broadcasting mechanism. Until this operations is not executed, no node is able to correctly route traffic towards the client. This obviously causes packet drops and introduces a delay in the time needed by the client to recover its connections. A new packet type called ROAMING_ADVERTISEMENT is added to account this issue. This message is sent in case of roaming from the new AP serving the client to the old one and will contain the client MAC address. In this way an out-of-OGM update is immediately committed, so that the old node can update its global translation table. Traffic reaching this node will then be redirected to the correct destination utilising the fresher information. Thus reducing the packet drops and the connection recovery delay. Signed-off-by: Antonio Quartulli <ordex@autistici.org> Signed-off-by: Sven Eckelmann <sven@narfation.org>
Diffstat (limited to 'net/batman-adv/routing.c')
-rw-r--r--net/batman-adv/routing.c61
1 files changed, 57 insertions, 4 deletions
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index 8b0f8330b06d..05d50ca3c4db 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -93,6 +93,9 @@ static void update_transtable(struct bat_priv *bat_priv,
spin_lock_bh(&bat_priv->tt_ghash_lock);
orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
spin_unlock_bh(&bat_priv->tt_ghash_lock);
+ /* Roaming phase is over: tables are in sync again. I can
+ * unset the flag */
+ orig_node->tt_poss_change = false;
} else {
/* if we missed more than one change or our tables are not
* in sync anymore -> request fresh tt data */
@@ -1252,6 +1255,54 @@ out:
return NET_RX_DROP;
}
+int recv_roam_adv(struct sk_buff *skb, struct hard_iface *recv_if)
+{
+ struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
+ struct roam_adv_packet *roam_adv_packet;
+ struct orig_node *orig_node;
+ struct ethhdr *ethhdr;
+
+ /* drop packet if it has not necessary minimum size */
+ if (unlikely(!pskb_may_pull(skb, sizeof(struct roam_adv_packet))))
+ goto out;
+
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
+
+ /* packet with unicast indication but broadcast recipient */
+ if (is_broadcast_ether_addr(ethhdr->h_dest))
+ goto out;
+
+ /* packet with broadcast sender address */
+ if (is_broadcast_ether_addr(ethhdr->h_source))
+ goto out;
+
+ roam_adv_packet = (struct roam_adv_packet *)skb->data;
+
+ if (!is_my_mac(roam_adv_packet->dst))
+ return route_unicast_packet(skb, recv_if);
+
+ orig_node = orig_hash_find(bat_priv, roam_adv_packet->src);
+ if (!orig_node)
+ goto out;
+
+ bat_dbg(DBG_TT, bat_priv, "Received ROAMING_ADV from %pM "
+ "(client %pM)\n", roam_adv_packet->src,
+ roam_adv_packet->client);
+
+ tt_global_add(bat_priv, orig_node, roam_adv_packet->client,
+ atomic_read(&orig_node->last_ttvn) + 1, true);
+
+ /* Roaming phase starts: I have new information but the ttvn has not
+ * been incremented yet. This flag will make me check all the incoming
+ * packets for the correct destination. */
+ bat_priv->tt_poss_change = true;
+
+ orig_node_free_ref(orig_node);
+out:
+ /* returning NET_RX_DROP will make the caller function kfree the skb */
+ return NET_RX_DROP;
+}
+
/* find a suitable router for this originator, and use
* bonding if possible. increases the found neighbors
* refcount.*/
@@ -1445,6 +1496,7 @@ static int check_unicast_ttvn(struct bat_priv *bat_priv,
struct ethhdr *ethhdr;
struct hard_iface *primary_if;
struct unicast_packet *unicast_packet;
+ bool tt_poss_change;
/* I could need to modify it */
if (skb_cow(skb, sizeof(struct unicast_packet)) < 0)
@@ -1452,27 +1504,28 @@ static int check_unicast_ttvn(struct bat_priv *bat_priv,
unicast_packet = (struct unicast_packet *)skb->data;
- if (is_my_mac(unicast_packet->dest))
+ if (is_my_mac(unicast_packet->dest)) {
+ tt_poss_change = bat_priv->tt_poss_change;
curr_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
- else {
+ } else {
orig_node = orig_hash_find(bat_priv, unicast_packet->dest);
if (!orig_node)
return 0;
curr_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
+ tt_poss_change = orig_node->tt_poss_change;
orig_node_free_ref(orig_node);
}
/* Check whether I have to reroute the packet */
- if (seq_before(unicast_packet->ttvn, curr_ttvn)) {
+ if (seq_before(unicast_packet->ttvn, curr_ttvn) || tt_poss_change) {
/* Linearize the skb before accessing it */
if (skb_linearize(skb) < 0)
return 0;
ethhdr = (struct ethhdr *)(skb->data +
sizeof(struct unicast_packet));
-
orig_node = transtable_search(bat_priv, ethhdr->h_dest);
if (!orig_node) {