aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv/network-coding.c
diff options
context:
space:
mode:
authorMartin Hundebøll <martin@hundeboll.net>2013-01-25 05:12:42 -0500
committerAntonio Quartulli <ordex@autistici.org>2013-03-13 17:53:50 -0400
commit612d2b4fe0a1ff2f8389462a6f8be34e54124c05 (patch)
tree033dc44cbb8a68965e2eb0b7e5039a46ed845a52 /net/batman-adv/network-coding.c
parent3c12de9a5c756b23fe7c9ab332474ece1568914c (diff)
batman-adv: network coding - save overheard and tx packets for decoding
To be able to decode a network coded packet, a node must already know one of the two coded packets. This is done by buffering skbs before transmission and buffering packets sniffed with promiscuous mode from other hosts. Packets are kept in a buffer similar to the one with forward-skbs: A hash table, where each entry, which corresponds to a src-dst pair, has a linked list packets. Signed-off-by: Martin Hundebøll <martin@hundeboll.net> Signed-off-by: Marek Lindner <lindner_marek@yahoo.de> Signed-off-by: Antonio Quartulli <ordex@autistici.org>
Diffstat (limited to 'net/batman-adv/network-coding.c')
-rw-r--r--net/batman-adv/network-coding.c208
1 files changed, 207 insertions, 1 deletions
diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c
index fce2846e9656..3d2ed2fe5421 100644
--- a/net/batman-adv/network-coding.c
+++ b/net/batman-adv/network-coding.c
@@ -27,6 +27,7 @@
27#include "hard-interface.h" 27#include "hard-interface.h"
28 28
29static struct lock_class_key batadv_nc_coding_hash_lock_class_key; 29static struct lock_class_key batadv_nc_coding_hash_lock_class_key;
30static struct lock_class_key batadv_nc_decoding_hash_lock_class_key;
30 31
31static void batadv_nc_worker(struct work_struct *work); 32static void batadv_nc_worker(struct work_struct *work);
32 33
@@ -47,8 +48,9 @@ static void batadv_nc_start_timer(struct batadv_priv *bat_priv)
47int batadv_nc_init(struct batadv_priv *bat_priv) 48int batadv_nc_init(struct batadv_priv *bat_priv)
48{ 49{
49 bat_priv->nc.timestamp_fwd_flush = jiffies; 50 bat_priv->nc.timestamp_fwd_flush = jiffies;
51 bat_priv->nc.timestamp_sniffed_purge = jiffies;
50 52
51 if (bat_priv->nc.coding_hash) 53 if (bat_priv->nc.coding_hash || bat_priv->nc.decoding_hash)
52 return 0; 54 return 0;
53 55
54 bat_priv->nc.coding_hash = batadv_hash_new(128); 56 bat_priv->nc.coding_hash = batadv_hash_new(128);
@@ -58,6 +60,13 @@ int batadv_nc_init(struct batadv_priv *bat_priv)
58 batadv_hash_set_lock_class(bat_priv->nc.coding_hash, 60 batadv_hash_set_lock_class(bat_priv->nc.coding_hash,
59 &batadv_nc_coding_hash_lock_class_key); 61 &batadv_nc_coding_hash_lock_class_key);
60 62
63 bat_priv->nc.decoding_hash = batadv_hash_new(128);
64 if (!bat_priv->nc.decoding_hash)
65 goto err;
66
67 batadv_hash_set_lock_class(bat_priv->nc.coding_hash,
68 &batadv_nc_decoding_hash_lock_class_key);
69
61 INIT_DELAYED_WORK(&bat_priv->nc.work, batadv_nc_worker); 70 INIT_DELAYED_WORK(&bat_priv->nc.work, batadv_nc_worker);
62 batadv_nc_start_timer(bat_priv); 71 batadv_nc_start_timer(bat_priv);
63 72
@@ -76,6 +85,7 @@ void batadv_nc_init_bat_priv(struct batadv_priv *bat_priv)
76 atomic_set(&bat_priv->network_coding, 1); 85 atomic_set(&bat_priv->network_coding, 1);
77 bat_priv->nc.min_tq = 200; 86 bat_priv->nc.min_tq = 200;
78 bat_priv->nc.max_fwd_delay = 10; 87 bat_priv->nc.max_fwd_delay = 10;
88 bat_priv->nc.max_buffer_time = 200;
79} 89}
80 90
81/** 91/**
@@ -176,6 +186,26 @@ static bool batadv_nc_to_purge_nc_path_coding(struct batadv_priv *bat_priv,
176} 186}
177 187
178/** 188/**
189 * batadv_nc_to_purge_nc_path_decoding - checks whether an nc path has timed out
190 * @bat_priv: the bat priv with all the soft interface information
191 * @nc_path: the nc path to check
192 *
193 * Returns true if the entry has to be purged now, false otherwise
194 */
195static bool batadv_nc_to_purge_nc_path_decoding(struct batadv_priv *bat_priv,
196 struct batadv_nc_path *nc_path)
197{
198 if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
199 return true;
200
201 /* purge the path when no packets has been added for 10 times the
202 * max_buffer time
203 */
204 return batadv_has_timed_out(nc_path->last_valid,
205 bat_priv->nc.max_buffer_time*10);
206}
207
208/**
179 * batadv_nc_purge_orig_nc_nodes - go through list of nc nodes and purge stale 209 * batadv_nc_purge_orig_nc_nodes - go through list of nc nodes and purge stale
180 * entries 210 * entries
181 * @bat_priv: the bat priv with all the soft interface information 211 * @bat_priv: the bat priv with all the soft interface information
@@ -441,6 +471,43 @@ static void batadv_nc_send_packet(struct batadv_nc_packet *nc_packet)
441} 471}
442 472
443/** 473/**
474 * batadv_nc_sniffed_purge - Checks timestamp of given sniffed nc_packet.
475 * @bat_priv: the bat priv with all the soft interface information
476 * @nc_path: the nc path the packet belongs to
477 * @nc_packet: the nc packet to be checked
478 *
479 * Checks whether the given sniffed (overheard) nc_packet has hit its buffering
480 * timeout. If so, the packet is no longer kept and the entry deleted from the
481 * queue. Has to be called with the appropriate locks.
482 *
483 * Returns false as soon as the entry in the fifo queue has not been timed out
484 * yet and true otherwise.
485 */
486static bool batadv_nc_sniffed_purge(struct batadv_priv *bat_priv,
487 struct batadv_nc_path *nc_path,
488 struct batadv_nc_packet *nc_packet)
489{
490 unsigned long timeout = bat_priv->nc.max_buffer_time;
491 bool res = false;
492
493 /* Packets are added to tail, so the remaining packets did not time
494 * out and we can stop processing the current queue
495 */
496 if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_ACTIVE &&
497 !batadv_has_timed_out(nc_packet->timestamp, timeout))
498 goto out;
499
500 /* purge nc packet */
501 list_del(&nc_packet->list);
502 batadv_nc_packet_free(nc_packet);
503
504 res = true;
505
506out:
507 return res;
508}
509
510/**
444 * batadv_nc_fwd_flush - Checks the timestamp of the given nc packet. 511 * batadv_nc_fwd_flush - Checks the timestamp of the given nc packet.
445 * @bat_priv: the bat priv with all the soft interface information 512 * @bat_priv: the bat priv with all the soft interface information
446 * @nc_path: the nc path the packet belongs to 513 * @nc_path: the nc path the packet belongs to
@@ -540,6 +607,8 @@ static void batadv_nc_worker(struct work_struct *work)
540 batadv_nc_purge_orig_hash(bat_priv); 607 batadv_nc_purge_orig_hash(bat_priv);
541 batadv_nc_purge_paths(bat_priv, bat_priv->nc.coding_hash, 608 batadv_nc_purge_paths(bat_priv, bat_priv->nc.coding_hash,
542 batadv_nc_to_purge_nc_path_coding); 609 batadv_nc_to_purge_nc_path_coding);
610 batadv_nc_purge_paths(bat_priv, bat_priv->nc.decoding_hash,
611 batadv_nc_to_purge_nc_path_decoding);
543 612
544 timeout = bat_priv->nc.max_fwd_delay; 613 timeout = bat_priv->nc.max_fwd_delay;
545 614
@@ -549,6 +618,13 @@ static void batadv_nc_worker(struct work_struct *work)
549 bat_priv->nc.timestamp_fwd_flush = jiffies; 618 bat_priv->nc.timestamp_fwd_flush = jiffies;
550 } 619 }
551 620
621 if (batadv_has_timed_out(bat_priv->nc.timestamp_sniffed_purge,
622 bat_priv->nc.max_buffer_time)) {
623 batadv_nc_process_nc_paths(bat_priv, bat_priv->nc.decoding_hash,
624 batadv_nc_sniffed_purge);
625 bat_priv->nc.timestamp_sniffed_purge = jiffies;
626 }
627
552 /* Schedule a new check */ 628 /* Schedule a new check */
553 batadv_nc_start_timer(bat_priv); 629 batadv_nc_start_timer(bat_priv);
554} 630}
@@ -1143,6 +1219,41 @@ batadv_nc_skb_src_search(struct batadv_priv *bat_priv,
1143} 1219}
1144 1220
1145/** 1221/**
1222 * batadv_nc_skb_store_before_coding - set the ethernet src and dst of the
1223 * unicast skb before it is stored for use in later decoding
1224 * @bat_priv: the bat priv with all the soft interface information
1225 * @skb: data skb to store
1226 * @eth_dst_new: new destination mac address of skb
1227 */
1228static void batadv_nc_skb_store_before_coding(struct batadv_priv *bat_priv,
1229 struct sk_buff *skb,
1230 uint8_t *eth_dst_new)
1231{
1232 struct ethhdr *ethhdr;
1233
1234 /* Copy skb header to change the mac header */
1235 skb = pskb_copy(skb, GFP_ATOMIC);
1236 if (!skb)
1237 return;
1238
1239 /* Set the mac header as if we actually sent the packet uncoded */
1240 ethhdr = (struct ethhdr *)skb_mac_header(skb);
1241 memcpy(ethhdr->h_source, ethhdr->h_dest, ETH_ALEN);
1242 memcpy(ethhdr->h_dest, eth_dst_new, ETH_ALEN);
1243
1244 /* Set data pointer to MAC header to mimic packets from our tx path */
1245 skb_push(skb, ETH_HLEN);
1246
1247 /* Add the packet to the decoding packet pool */
1248 batadv_nc_skb_store_for_decoding(bat_priv, skb);
1249
1250 /* batadv_nc_skb_store_for_decoding() clones the skb, so we must free
1251 * our ref
1252 */
1253 kfree_skb(skb);
1254}
1255
1256/**
1146 * batadv_nc_skb_dst_search - Loops through list of neighboring nodes to dst. 1257 * batadv_nc_skb_dst_search - Loops through list of neighboring nodes to dst.
1147 * @skb: data skb to forward 1258 * @skb: data skb to forward
1148 * @neigh_node: next hop to forward packet to 1259 * @neigh_node: next hop to forward packet to
@@ -1181,6 +1292,12 @@ static bool batadv_nc_skb_dst_search(struct sk_buff *skb,
1181 if (!nc_packet) 1292 if (!nc_packet)
1182 return false; 1293 return false;
1183 1294
1295 /* Save packets for later decoding */
1296 batadv_nc_skb_store_before_coding(bat_priv, skb,
1297 neigh_node->addr);
1298 batadv_nc_skb_store_before_coding(bat_priv, nc_packet->skb,
1299 nc_packet->neigh_node->addr);
1300
1184 /* Code and send packets */ 1301 /* Code and send packets */
1185 if (batadv_nc_code_packets(bat_priv, skb, ethhdr, nc_packet, 1302 if (batadv_nc_code_packets(bat_priv, skb, ethhdr, nc_packet,
1186 neigh_node)) 1303 neigh_node))
@@ -1288,14 +1405,98 @@ out:
1288} 1405}
1289 1406
1290/** 1407/**
1408 * batadv_nc_skb_store_for_decoding - save a clone of the skb which can be used
1409 * when decoding coded packets
1410 * @bat_priv: the bat priv with all the soft interface information
1411 * @skb: data skb to store
1412 */
1413void batadv_nc_skb_store_for_decoding(struct batadv_priv *bat_priv,
1414 struct sk_buff *skb)
1415{
1416 struct batadv_unicast_packet *packet;
1417 struct batadv_nc_path *nc_path;
1418 struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb);
1419 __be32 packet_id;
1420 u8 *payload;
1421
1422 /* Check if network coding is enabled */
1423 if (!atomic_read(&bat_priv->network_coding))
1424 goto out;
1425
1426 /* Check for supported packet type */
1427 payload = skb_network_header(skb);
1428 packet = (struct batadv_unicast_packet *)payload;
1429 if (packet->header.packet_type != BATADV_UNICAST)
1430 goto out;
1431
1432 /* Find existing nc_path or create a new */
1433 nc_path = batadv_nc_get_path(bat_priv,
1434 bat_priv->nc.decoding_hash,
1435 ethhdr->h_source,
1436 ethhdr->h_dest);
1437
1438 if (!nc_path)
1439 goto out;
1440
1441 /* Clone skb and adjust skb->data to point at batman header */
1442 skb = skb_clone(skb, GFP_ATOMIC);
1443 if (unlikely(!skb))
1444 goto free_nc_path;
1445
1446 if (unlikely(!pskb_may_pull(skb, ETH_HLEN)))
1447 goto free_skb;
1448
1449 if (unlikely(!skb_pull_rcsum(skb, ETH_HLEN)))
1450 goto free_skb;
1451
1452 /* Add skb to nc_path */
1453 packet_id = batadv_skb_crc32(skb, payload + sizeof(*packet));
1454 if (!batadv_nc_skb_add_to_path(skb, nc_path, NULL, packet_id))
1455 goto free_skb;
1456
1457 batadv_inc_counter(bat_priv, BATADV_CNT_NC_BUFFER);
1458 return;
1459
1460free_skb:
1461 kfree_skb(skb);
1462free_nc_path:
1463 batadv_nc_path_free_ref(nc_path);
1464out:
1465 return;
1466}
1467
1468/**
1469 * batadv_nc_skb_store_sniffed_unicast - check if a received unicast packet
1470 * should be saved in the decoding buffer and, if so, store it there
1471 * @bat_priv: the bat priv with all the soft interface information
1472 * @skb: unicast skb to store
1473 */
1474void batadv_nc_skb_store_sniffed_unicast(struct batadv_priv *bat_priv,
1475 struct sk_buff *skb)
1476{
1477 struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb);
1478
1479 if (batadv_is_my_mac(ethhdr->h_dest))
1480 return;
1481
1482 /* Set data pointer to MAC header to mimic packets from our tx path */
1483 skb_push(skb, ETH_HLEN);
1484
1485 batadv_nc_skb_store_for_decoding(bat_priv, skb);
1486}
1487
1488/**
1291 * batadv_nc_free - clean up network coding memory 1489 * batadv_nc_free - clean up network coding memory
1292 * @bat_priv: the bat priv with all the soft interface information 1490 * @bat_priv: the bat priv with all the soft interface information
1293 */ 1491 */
1294void batadv_nc_free(struct batadv_priv *bat_priv) 1492void batadv_nc_free(struct batadv_priv *bat_priv)
1295{ 1493{
1296 cancel_delayed_work_sync(&bat_priv->nc.work); 1494 cancel_delayed_work_sync(&bat_priv->nc.work);
1495
1297 batadv_nc_purge_paths(bat_priv, bat_priv->nc.coding_hash, NULL); 1496 batadv_nc_purge_paths(bat_priv, bat_priv->nc.coding_hash, NULL);
1298 batadv_hash_destroy(bat_priv->nc.coding_hash); 1497 batadv_hash_destroy(bat_priv->nc.coding_hash);
1498 batadv_nc_purge_paths(bat_priv, bat_priv->nc.decoding_hash, NULL);
1499 batadv_hash_destroy(bat_priv->nc.decoding_hash);
1299} 1500}
1300 1501
1301/** 1502/**
@@ -1376,6 +1577,11 @@ int batadv_nc_init_debugfs(struct batadv_priv *bat_priv)
1376 if (!file) 1577 if (!file)
1377 goto out; 1578 goto out;
1378 1579
1580 file = debugfs_create_u32("max_buffer_time", S_IRUGO | S_IWUSR, nc_dir,
1581 &bat_priv->nc.max_buffer_time);
1582 if (!file)
1583 goto out;
1584
1379 return 0; 1585 return 0;
1380 1586
1381out: 1587out: