aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv/routing.c
diff options
context:
space:
mode:
authorAntonio Quartulli <ordex@autistici.org>2011-04-27 08:27:44 -0400
committerSven Eckelmann <sven@narfation.org>2011-06-20 05:37:24 -0400
commita73105b8d4c765d9ebfb664d0a66802127d8e4c7 (patch)
treeb4b11a4050109d8f042c7ac87a5a6d6d91b5d1d2 /net/batman-adv/routing.c
parent3b27ffb00fbe9d9189715ea13ce8712e2f0cb0c5 (diff)
batman-adv: improved client announcement mechanism
The client announcement mechanism informs every mesh node in the network of any connected non-mesh client, in order to find the path towards that client from any given point in the mesh. The old implementation was based on the simple idea of appending a data buffer to each OGM containing all the client MAC addresses the node is serving. All other nodes can populate their global translation tables (table which links client MAC addresses to node addresses) using this MAC address buffer and linking it to the node's address contained in the OGM. A node that wants to contact a client has to lookup the node the client is connected to and its address in the global translation table. It is easy to understand that this implementation suffers from several issues: - big overhead (each and every OGM contains the entire list of connected clients) - high latencies for client route updates due to long OGM trip time and OGM losses The new implementation addresses these issues by appending client changes (new client joined or a client left) to the OGM instead of filling it with all the client addresses each time. In this way nodes can modify their global tables by means of "updates", thus reducing the overhead within the OGMs. To keep the entire network in sync each node maintains a translation table version number (ttvn) and a translation table checksum. These values are spread with the OGM to allow all the network participants to determine whether or not they need to update their translation table information. When a translation table lookup is performed in order to send a packet to a client attached to another node, the destination's ttvn is added to the payload packet. Forwarding nodes can compare the packet's ttvn with their destination's ttvn (this node could have a fresher information than the source) and re-route the packet if necessary. This greatly reduces the packet loss of clients roaming from one AP to the next. Signed-off-by: Antonio Quartulli <ordex@autistici.org> Signed-off-by: Marek Lindner <lindner_marek@yahoo.de> Signed-off-by: Sven Eckelmann <sven@narfation.org>
Diffstat (limited to 'net/batman-adv/routing.c')
-rw-r--r--net/batman-adv/routing.c252
1 files changed, 204 insertions, 48 deletions
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index eb6fb7d2d368..8b0f8330b06d 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -64,27 +64,56 @@ void slide_own_bcast_window(struct hard_iface *hard_iface)
64 } 64 }
65} 65}
66 66
67static void update_TT(struct bat_priv *bat_priv, struct orig_node *orig_node, 67static void update_transtable(struct bat_priv *bat_priv,
68 const unsigned char *tt_buff, int tt_buff_len) 68 struct orig_node *orig_node,
69 const unsigned char *tt_buff,
70 uint8_t tt_num_changes, uint8_t ttvn,
71 uint16_t tt_crc)
69{ 72{
70 if ((tt_buff_len != orig_node->tt_buff_len) || 73 uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
71 ((tt_buff_len > 0) && 74 bool full_table = true;
72 (orig_node->tt_buff_len > 0) && 75
73 (memcmp(orig_node->tt_buff, tt_buff, tt_buff_len) != 0))) { 76 /* the ttvn increased by one -> we can apply the attached changes */
74 77 if (ttvn - orig_ttvn == 1) {
75 if (orig_node->tt_buff_len > 0) 78 /* the OGM could not contain the changes because they were too
76 tt_global_del_orig(bat_priv, orig_node, 79 * many to fit in one frame or because they have already been
77 "originator changed tt"); 80 * sent TT_OGM_APPEND_MAX times. In this case send a tt
78 81 * request */
79 if ((tt_buff_len > 0) && (tt_buff)) 82 if (!tt_num_changes) {
80 tt_global_add_orig(bat_priv, orig_node, 83 full_table = false;
81 tt_buff, tt_buff_len); 84 goto request_table;
85 }
86
87 tt_update_changes(bat_priv, orig_node, tt_num_changes, ttvn,
88 (struct tt_change *)tt_buff);
89
90 /* Even if we received the crc into the OGM, we prefer
91 * to recompute it to spot any possible inconsistency
92 * in the global table */
93 spin_lock_bh(&bat_priv->tt_ghash_lock);
94 orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
95 spin_unlock_bh(&bat_priv->tt_ghash_lock);
96 } else {
97 /* if we missed more than one change or our tables are not
98 * in sync anymore -> request fresh tt data */
99 if (ttvn != orig_ttvn || orig_node->tt_crc != tt_crc) {
100request_table:
101 bat_dbg(DBG_TT, bat_priv, "TT inconsistency for %pM. "
102 "Need to retrieve the correct information "
103 "(ttvn: %u last_ttvn: %u crc: %u last_crc: "
104 "%u num_changes: %u)\n", orig_node->orig, ttvn,
105 orig_ttvn, tt_crc, orig_node->tt_crc,
106 tt_num_changes);
107 send_tt_request(bat_priv, orig_node, ttvn, tt_crc,
108 full_table);
109 return;
110 }
82 } 111 }
83} 112}
84 113
85static void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node, 114static void update_route(struct bat_priv *bat_priv,
86 struct neigh_node *neigh_node, 115 struct orig_node *orig_node,
87 const unsigned char *tt_buff, int tt_buff_len) 116 struct neigh_node *neigh_node)
88{ 117{
89 struct neigh_node *curr_router; 118 struct neigh_node *curr_router;
90 119
@@ -92,11 +121,10 @@ static void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node,
92 121
93 /* route deleted */ 122 /* route deleted */
94 if ((curr_router) && (!neigh_node)) { 123 if ((curr_router) && (!neigh_node)) {
95
96 bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n", 124 bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n",
97 orig_node->orig); 125 orig_node->orig);
98 tt_global_del_orig(bat_priv, orig_node, 126 tt_global_del_orig(bat_priv, orig_node,
99 "originator timed out"); 127 "Deleted route towards originator");
100 128
101 /* route added */ 129 /* route added */
102 } else if ((!curr_router) && (neigh_node)) { 130 } else if ((!curr_router) && (neigh_node)) {
@@ -104,9 +132,6 @@ static void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node,
104 bat_dbg(DBG_ROUTES, bat_priv, 132 bat_dbg(DBG_ROUTES, bat_priv,
105 "Adding route towards: %pM (via %pM)\n", 133 "Adding route towards: %pM (via %pM)\n",
106 orig_node->orig, neigh_node->addr); 134 orig_node->orig, neigh_node->addr);
107 tt_global_add_orig(bat_priv, orig_node,
108 tt_buff, tt_buff_len);
109
110 /* route changed */ 135 /* route changed */
111 } else if (neigh_node && curr_router) { 136 } else if (neigh_node && curr_router) {
112 bat_dbg(DBG_ROUTES, bat_priv, 137 bat_dbg(DBG_ROUTES, bat_priv,
@@ -133,8 +158,7 @@ static void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node,
133} 158}
134 159
135void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node, 160void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
136 struct neigh_node *neigh_node, const unsigned char *tt_buff, 161 struct neigh_node *neigh_node)
137 int tt_buff_len)
138{ 162{
139 struct neigh_node *router = NULL; 163 struct neigh_node *router = NULL;
140 164
@@ -144,11 +168,7 @@ void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
144 router = orig_node_get_router(orig_node); 168 router = orig_node_get_router(orig_node);
145 169
146 if (router != neigh_node) 170 if (router != neigh_node)
147 update_route(bat_priv, orig_node, neigh_node, 171 update_route(bat_priv, orig_node, neigh_node);
148 tt_buff, tt_buff_len);
149 /* may be just TT changed */
150 else
151 update_TT(bat_priv, orig_node, tt_buff, tt_buff_len);
152 172
153out: 173out:
154 if (router) 174 if (router)
@@ -360,14 +380,12 @@ static void update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
360 const struct ethhdr *ethhdr, 380 const struct ethhdr *ethhdr,
361 const struct batman_packet *batman_packet, 381 const struct batman_packet *batman_packet,
362 struct hard_iface *if_incoming, 382 struct hard_iface *if_incoming,
363 const unsigned char *tt_buff, int tt_buff_len, 383 const unsigned char *tt_buff, int is_duplicate)
364 int is_duplicate)
365{ 384{
366 struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; 385 struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
367 struct neigh_node *router = NULL; 386 struct neigh_node *router = NULL;
368 struct orig_node *orig_node_tmp; 387 struct orig_node *orig_node_tmp;
369 struct hlist_node *node; 388 struct hlist_node *node;
370 int tmp_tt_buff_len;
371 uint8_t bcast_own_sum_orig, bcast_own_sum_neigh; 389 uint8_t bcast_own_sum_orig, bcast_own_sum_neigh;
372 390
373 bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): " 391 bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): "
@@ -432,9 +450,6 @@ static void update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
432 450
433 bonding_candidate_add(orig_node, neigh_node); 451 bonding_candidate_add(orig_node, neigh_node);
434 452
435 tmp_tt_buff_len = (tt_buff_len > batman_packet->num_tt * ETH_ALEN ?
436 batman_packet->num_tt * ETH_ALEN : tt_buff_len);
437
438 /* if this neighbor already is our next hop there is nothing 453 /* if this neighbor already is our next hop there is nothing
439 * to change */ 454 * to change */
440 router = orig_node_get_router(orig_node); 455 router = orig_node_get_router(orig_node);
@@ -464,15 +479,19 @@ static void update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
464 goto update_tt; 479 goto update_tt;
465 } 480 }
466 481
467 update_routes(bat_priv, orig_node, neigh_node, 482 update_routes(bat_priv, orig_node, neigh_node);
468 tt_buff, tmp_tt_buff_len);
469 goto update_gw;
470 483
471update_tt: 484update_tt:
472 update_routes(bat_priv, orig_node, router, 485 /* I have to check for transtable changes only if the OGM has been
473 tt_buff, tmp_tt_buff_len); 486 * sent through a primary interface */
487 if (((batman_packet->orig != ethhdr->h_source) &&
488 (batman_packet->ttl > 2)) ||
489 (batman_packet->flags & PRIMARIES_FIRST_HOP))
490 update_transtable(bat_priv, orig_node, tt_buff,
491 batman_packet->tt_num_changes,
492 batman_packet->ttvn,
493 batman_packet->tt_crc);
474 494
475update_gw:
476 if (orig_node->gw_flags != batman_packet->gw_flags) 495 if (orig_node->gw_flags != batman_packet->gw_flags)
477 gw_node_update(bat_priv, orig_node, batman_packet->gw_flags); 496 gw_node_update(bat_priv, orig_node, batman_packet->gw_flags);
478 497
@@ -594,7 +613,7 @@ out:
594 613
595void receive_bat_packet(const struct ethhdr *ethhdr, 614void receive_bat_packet(const struct ethhdr *ethhdr,
596 struct batman_packet *batman_packet, 615 struct batman_packet *batman_packet,
597 const unsigned char *tt_buff, int tt_buff_len, 616 const unsigned char *tt_buff,
598 struct hard_iface *if_incoming) 617 struct hard_iface *if_incoming)
599{ 618{
600 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); 619 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
@@ -633,12 +652,14 @@ void receive_bat_packet(const struct ethhdr *ethhdr,
633 652
634 bat_dbg(DBG_BATMAN, bat_priv, 653 bat_dbg(DBG_BATMAN, bat_priv,
635 "Received BATMAN packet via NB: %pM, IF: %s [%pM] " 654 "Received BATMAN packet via NB: %pM, IF: %s [%pM] "
636 "(from OG: %pM, via prev OG: %pM, seqno %d, tq %d, " 655 "(from OG: %pM, via prev OG: %pM, seqno %d, ttvn %u, "
637 "TTL %d, V %d, IDF %d)\n", 656 "crc %u, changes %u, td %d, TTL %d, V %d, IDF %d)\n",
638 ethhdr->h_source, if_incoming->net_dev->name, 657 ethhdr->h_source, if_incoming->net_dev->name,
639 if_incoming->net_dev->dev_addr, batman_packet->orig, 658 if_incoming->net_dev->dev_addr, batman_packet->orig,
640 batman_packet->prev_sender, batman_packet->seqno, 659 batman_packet->prev_sender, batman_packet->seqno,
641 batman_packet->tq, batman_packet->ttl, batman_packet->version, 660 batman_packet->ttvn, batman_packet->tt_crc,
661 batman_packet->tt_num_changes, batman_packet->tq,
662 batman_packet->ttl, batman_packet->version,
642 has_directlink_flag); 663 has_directlink_flag);
643 664
644 rcu_read_lock(); 665 rcu_read_lock();
@@ -790,14 +811,14 @@ void receive_bat_packet(const struct ethhdr *ethhdr,
790 ((orig_node->last_real_seqno == batman_packet->seqno) && 811 ((orig_node->last_real_seqno == batman_packet->seqno) &&
791 (orig_node->last_ttl - 3 <= batman_packet->ttl)))) 812 (orig_node->last_ttl - 3 <= batman_packet->ttl))))
792 update_orig(bat_priv, orig_node, ethhdr, batman_packet, 813 update_orig(bat_priv, orig_node, ethhdr, batman_packet,
793 if_incoming, tt_buff, tt_buff_len, is_duplicate); 814 if_incoming, tt_buff, is_duplicate);
794 815
795 /* is single hop (direct) neighbor */ 816 /* is single hop (direct) neighbor */
796 if (is_single_hop_neigh) { 817 if (is_single_hop_neigh) {
797 818
798 /* mark direct link on incoming interface */ 819 /* mark direct link on incoming interface */
799 schedule_forward_packet(orig_node, ethhdr, batman_packet, 820 schedule_forward_packet(orig_node, ethhdr, batman_packet,
800 1, tt_buff_len, if_incoming); 821 1, if_incoming);
801 822
802 bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: " 823 bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: "
803 "rebroadcast neighbor packet with direct link flag\n"); 824 "rebroadcast neighbor packet with direct link flag\n");
@@ -820,7 +841,7 @@ void receive_bat_packet(const struct ethhdr *ethhdr,
820 bat_dbg(DBG_BATMAN, bat_priv, 841 bat_dbg(DBG_BATMAN, bat_priv,
821 "Forwarding packet: rebroadcast originator packet\n"); 842 "Forwarding packet: rebroadcast originator packet\n");
822 schedule_forward_packet(orig_node, ethhdr, batman_packet, 843 schedule_forward_packet(orig_node, ethhdr, batman_packet,
823 0, tt_buff_len, if_incoming); 844 0, if_incoming);
824 845
825out_neigh: 846out_neigh:
826 if ((orig_neigh_node) && (!is_single_hop_neigh)) 847 if ((orig_neigh_node) && (!is_single_hop_neigh))
@@ -1167,6 +1188,70 @@ static struct neigh_node *find_ifalter_router(struct orig_node *primary_orig,
1167 return router; 1188 return router;
1168} 1189}
1169 1190
1191int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if)
1192{
1193 struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
1194 struct tt_query_packet *tt_query;
1195 struct ethhdr *ethhdr;
1196
1197 /* drop packet if it has not necessary minimum size */
1198 if (unlikely(!pskb_may_pull(skb, sizeof(struct tt_query_packet))))
1199 goto out;
1200
1201 /* I could need to modify it */
1202 if (skb_cow(skb, sizeof(struct tt_query_packet)) < 0)
1203 goto out;
1204
1205 ethhdr = (struct ethhdr *)skb_mac_header(skb);
1206
1207 /* packet with unicast indication but broadcast recipient */
1208 if (is_broadcast_ether_addr(ethhdr->h_dest))
1209 goto out;
1210
1211 /* packet with broadcast sender address */
1212 if (is_broadcast_ether_addr(ethhdr->h_source))
1213 goto out;
1214
1215 tt_query = (struct tt_query_packet *)skb->data;
1216
1217 tt_query->tt_data = ntohs(tt_query->tt_data);
1218
1219 switch (tt_query->flags & TT_QUERY_TYPE_MASK) {
1220 case TT_REQUEST:
1221 /* If we cannot provide an answer the tt_request is
1222 * forwarded */
1223 if (!send_tt_response(bat_priv, tt_query)) {
1224 bat_dbg(DBG_TT, bat_priv,
1225 "Routing TT_REQUEST to %pM [%c]\n",
1226 tt_query->dst,
1227 (tt_query->flags & TT_FULL_TABLE ? 'F' : '.'));
1228 tt_query->tt_data = htons(tt_query->tt_data);
1229 return route_unicast_packet(skb, recv_if);
1230 }
1231 break;
1232 case TT_RESPONSE:
1233 /* packet needs to be linearised to access the TT changes */
1234 if (skb_linearize(skb) < 0)
1235 goto out;
1236
1237 if (is_my_mac(tt_query->dst))
1238 handle_tt_response(bat_priv, tt_query);
1239 else {
1240 bat_dbg(DBG_TT, bat_priv,
1241 "Routing TT_RESPONSE to %pM [%c]\n",
1242 tt_query->dst,
1243 (tt_query->flags & TT_FULL_TABLE ? 'F' : '.'));
1244 tt_query->tt_data = htons(tt_query->tt_data);
1245 return route_unicast_packet(skb, recv_if);
1246 }
1247 break;
1248 }
1249
1250out:
1251 /* returning NET_RX_DROP will make the caller function kfree the skb */
1252 return NET_RX_DROP;
1253}
1254
1170/* find a suitable router for this originator, and use 1255/* find a suitable router for this originator, and use
1171 * bonding if possible. increases the found neighbors 1256 * bonding if possible. increases the found neighbors
1172 * refcount.*/ 1257 * refcount.*/
@@ -1353,14 +1438,82 @@ out:
1353 return ret; 1438 return ret;
1354} 1439}
1355 1440
1441static int check_unicast_ttvn(struct bat_priv *bat_priv,
1442 struct sk_buff *skb) {
1443 uint8_t curr_ttvn;
1444 struct orig_node *orig_node;
1445 struct ethhdr *ethhdr;
1446 struct hard_iface *primary_if;
1447 struct unicast_packet *unicast_packet;
1448
1449 /* I could need to modify it */
1450 if (skb_cow(skb, sizeof(struct unicast_packet)) < 0)
1451 return 0;
1452
1453 unicast_packet = (struct unicast_packet *)skb->data;
1454
1455 if (is_my_mac(unicast_packet->dest))
1456 curr_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
1457 else {
1458 orig_node = orig_hash_find(bat_priv, unicast_packet->dest);
1459
1460 if (!orig_node)
1461 return 0;
1462
1463 curr_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
1464 orig_node_free_ref(orig_node);
1465 }
1466
1467 /* Check whether I have to reroute the packet */
1468 if (seq_before(unicast_packet->ttvn, curr_ttvn)) {
1469 /* Linearize the skb before accessing it */
1470 if (skb_linearize(skb) < 0)
1471 return 0;
1472
1473 ethhdr = (struct ethhdr *)(skb->data +
1474 sizeof(struct unicast_packet));
1475
1476 orig_node = transtable_search(bat_priv, ethhdr->h_dest);
1477
1478 if (!orig_node) {
1479 if (!is_my_client(bat_priv, ethhdr->h_dest))
1480 return 0;
1481 primary_if = primary_if_get_selected(bat_priv);
1482 if (!primary_if)
1483 return 0;
1484 memcpy(unicast_packet->dest,
1485 primary_if->net_dev->dev_addr, ETH_ALEN);
1486 hardif_free_ref(primary_if);
1487 } else {
1488 memcpy(unicast_packet->dest, orig_node->orig,
1489 ETH_ALEN);
1490 curr_ttvn = (uint8_t)
1491 atomic_read(&orig_node->last_ttvn);
1492 orig_node_free_ref(orig_node);
1493 }
1494
1495 bat_dbg(DBG_ROUTES, bat_priv, "TTVN mismatch (old_ttvn %u "
1496 "new_ttvn %u)! Rerouting unicast packet (for %pM) to "
1497 "%pM\n", unicast_packet->ttvn, curr_ttvn,
1498 ethhdr->h_dest, unicast_packet->dest);
1499
1500 unicast_packet->ttvn = curr_ttvn;
1501 }
1502 return 1;
1503}
1504
1356int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if) 1505int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
1357{ 1506{
1507 struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
1358 struct unicast_packet *unicast_packet; 1508 struct unicast_packet *unicast_packet;
1359 int hdr_size = sizeof(*unicast_packet); 1509 int hdr_size = sizeof(*unicast_packet);
1360 1510
1361 if (check_unicast_packet(skb, hdr_size) < 0) 1511 if (check_unicast_packet(skb, hdr_size) < 0)
1362 return NET_RX_DROP; 1512 return NET_RX_DROP;
1363 1513
1514 if (!check_unicast_ttvn(bat_priv, skb))
1515 return NET_RX_DROP;
1516
1364 unicast_packet = (struct unicast_packet *)skb->data; 1517 unicast_packet = (struct unicast_packet *)skb->data;
1365 1518
1366 /* packet for me */ 1519 /* packet for me */
@@ -1383,6 +1536,9 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if)
1383 if (check_unicast_packet(skb, hdr_size) < 0) 1536 if (check_unicast_packet(skb, hdr_size) < 0)
1384 return NET_RX_DROP; 1537 return NET_RX_DROP;
1385 1538
1539 if (!check_unicast_ttvn(bat_priv, skb))
1540 return NET_RX_DROP;
1541
1386 unicast_packet = (struct unicast_frag_packet *)skb->data; 1542 unicast_packet = (struct unicast_frag_packet *)skb->data;
1387 1543
1388 /* packet for me */ 1544 /* packet for me */