diff options
-rw-r--r-- | net/batman-adv/network-coding.c | 487 | ||||
-rw-r--r-- | net/batman-adv/network-coding.h | 10 | ||||
-rw-r--r-- | net/batman-adv/routing.c | 18 | ||||
-rw-r--r-- | net/batman-adv/types.h | 49 |
4 files changed, 557 insertions, 7 deletions
diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c index ff4985d84726..2c38c540c6db 100644 --- a/net/batman-adv/network-coding.c +++ b/net/batman-adv/network-coding.c | |||
@@ -20,10 +20,14 @@ | |||
20 | #include <linux/debugfs.h> | 20 | #include <linux/debugfs.h> |
21 | 21 | ||
22 | #include "main.h" | 22 | #include "main.h" |
23 | #include "hash.h" | ||
23 | #include "network-coding.h" | 24 | #include "network-coding.h" |
25 | #include "send.h" | ||
24 | #include "originator.h" | 26 | #include "originator.h" |
25 | #include "hard-interface.h" | 27 | #include "hard-interface.h" |
26 | 28 | ||
29 | static struct lock_class_key batadv_nc_coding_hash_lock_class_key; | ||
30 | |||
27 | static void batadv_nc_worker(struct work_struct *work); | 31 | static void batadv_nc_worker(struct work_struct *work); |
28 | 32 | ||
29 | /** | 33 | /** |
@@ -42,10 +46,25 @@ static void batadv_nc_start_timer(struct batadv_priv *bat_priv) | |||
42 | */ | 46 | */ |
43 | int batadv_nc_init(struct batadv_priv *bat_priv) | 47 | int batadv_nc_init(struct batadv_priv *bat_priv) |
44 | { | 48 | { |
49 | bat_priv->nc.timestamp_fwd_flush = jiffies; | ||
50 | |||
51 | if (bat_priv->nc.coding_hash) | ||
52 | return 0; | ||
53 | |||
54 | bat_priv->nc.coding_hash = batadv_hash_new(128); | ||
55 | if (!bat_priv->nc.coding_hash) | ||
56 | goto err; | ||
57 | |||
58 | batadv_hash_set_lock_class(bat_priv->nc.coding_hash, | ||
59 | &batadv_nc_coding_hash_lock_class_key); | ||
60 | |||
45 | INIT_DELAYED_WORK(&bat_priv->nc.work, batadv_nc_worker); | 61 | INIT_DELAYED_WORK(&bat_priv->nc.work, batadv_nc_worker); |
46 | batadv_nc_start_timer(bat_priv); | 62 | batadv_nc_start_timer(bat_priv); |
47 | 63 | ||
48 | return 0; | 64 | return 0; |
65 | |||
66 | err: | ||
67 | return -ENOMEM; | ||
49 | } | 68 | } |
50 | 69 | ||
51 | /** | 70 | /** |
@@ -56,6 +75,7 @@ void batadv_nc_init_bat_priv(struct batadv_priv *bat_priv) | |||
56 | { | 75 | { |
57 | atomic_set(&bat_priv->network_coding, 1); | 76 | atomic_set(&bat_priv->network_coding, 1); |
58 | bat_priv->nc.min_tq = 200; | 77 | bat_priv->nc.min_tq = 200; |
78 | bat_priv->nc.max_fwd_delay = 10; | ||
59 | } | 79 | } |
60 | 80 | ||
61 | /** | 81 | /** |
@@ -96,6 +116,30 @@ static void batadv_nc_node_free_ref(struct batadv_nc_node *nc_node) | |||
96 | } | 116 | } |
97 | 117 | ||
98 | /** | 118 | /** |
119 | * batadv_nc_path_free_ref - decrements the nc path refcounter and possibly | ||
120 | * frees it | ||
121 | * @nc_path: the nc node to free | ||
122 | */ | ||
123 | static void batadv_nc_path_free_ref(struct batadv_nc_path *nc_path) | ||
124 | { | ||
125 | if (atomic_dec_and_test(&nc_path->refcount)) | ||
126 | kfree_rcu(nc_path, rcu); | ||
127 | } | ||
128 | |||
129 | /** | ||
130 | * batadv_nc_packet_free - frees nc packet | ||
131 | * @nc_packet: the nc packet to free | ||
132 | */ | ||
133 | static void batadv_nc_packet_free(struct batadv_nc_packet *nc_packet) | ||
134 | { | ||
135 | if (nc_packet->skb) | ||
136 | kfree_skb(nc_packet->skb); | ||
137 | |||
138 | batadv_nc_path_free_ref(nc_packet->nc_path); | ||
139 | kfree(nc_packet); | ||
140 | } | ||
141 | |||
142 | /** | ||
99 | * batadv_nc_to_purge_nc_node - checks whether an nc node has to be purged | 143 | * batadv_nc_to_purge_nc_node - checks whether an nc node has to be purged |
100 | * @bat_priv: the bat priv with all the soft interface information | 144 | * @bat_priv: the bat priv with all the soft interface information |
101 | * @nc_node: the nc node to check | 145 | * @nc_node: the nc node to check |
@@ -112,6 +156,26 @@ static bool batadv_nc_to_purge_nc_node(struct batadv_priv *bat_priv, | |||
112 | } | 156 | } |
113 | 157 | ||
114 | /** | 158 | /** |
159 | * batadv_nc_to_purge_nc_path_coding - checks whether an nc path has timed out | ||
160 | * @bat_priv: the bat priv with all the soft interface information | ||
161 | * @nc_path: the nc path to check | ||
162 | * | ||
163 | * Returns true if the entry has to be purged now, false otherwise | ||
164 | */ | ||
165 | static bool batadv_nc_to_purge_nc_path_coding(struct batadv_priv *bat_priv, | ||
166 | struct batadv_nc_path *nc_path) | ||
167 | { | ||
168 | if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) | ||
169 | return true; | ||
170 | |||
171 | /* purge the path when no packets has been added for 10 times the | ||
172 | * max_fwd_delay time | ||
173 | */ | ||
174 | return batadv_has_timed_out(nc_path->last_valid, | ||
175 | bat_priv->nc.max_fwd_delay * 10); | ||
176 | } | ||
177 | |||
178 | /** | ||
115 | * batadv_nc_purge_orig_nc_nodes - go through list of nc nodes and purge stale | 179 | * batadv_nc_purge_orig_nc_nodes - go through list of nc nodes and purge stale |
116 | * entries | 180 | * entries |
117 | * @bat_priv: the bat priv with all the soft interface information | 181 | * @bat_priv: the bat priv with all the soft interface information |
@@ -203,6 +267,262 @@ static void batadv_nc_purge_orig_hash(struct batadv_priv *bat_priv) | |||
203 | } | 267 | } |
204 | 268 | ||
205 | /** | 269 | /** |
270 | * batadv_nc_purge_paths - traverse all nc paths part of the hash and remove | ||
271 | * unused ones | ||
272 | * @bat_priv: the bat priv with all the soft interface information | ||
273 | * @hash: hash table containing the nc paths to check | ||
274 | * @to_purge: function in charge to decide whether an entry has to be purged or | ||
275 | * not. This function takes the nc node as argument and has to return | ||
276 | * a boolean value: true is the entry has to be deleted, false | ||
277 | * otherwise | ||
278 | */ | ||
279 | static void batadv_nc_purge_paths(struct batadv_priv *bat_priv, | ||
280 | struct batadv_hashtable *hash, | ||
281 | bool (*to_purge)(struct batadv_priv *, | ||
282 | struct batadv_nc_path *)) | ||
283 | { | ||
284 | struct hlist_head *head; | ||
285 | struct hlist_node *node_tmp; | ||
286 | struct batadv_nc_path *nc_path; | ||
287 | spinlock_t *lock; /* Protects lists in hash */ | ||
288 | uint32_t i; | ||
289 | |||
290 | for (i = 0; i < hash->size; i++) { | ||
291 | head = &hash->table[i]; | ||
292 | lock = &hash->list_locks[i]; | ||
293 | |||
294 | /* For each nc_path in this bin */ | ||
295 | spin_lock_bh(lock); | ||
296 | hlist_for_each_entry_safe(nc_path, node_tmp, head, hash_entry) { | ||
297 | /* if an helper function has been passed as parameter, | ||
298 | * ask it if the entry has to be purged or not | ||
299 | */ | ||
300 | if (to_purge && !to_purge(bat_priv, nc_path)) | ||
301 | continue; | ||
302 | |||
303 | /* purging an non-empty nc_path should never happen, but | ||
304 | * is observed under high CPU load. Delay the purging | ||
305 | * until next iteration to allow the packet_list to be | ||
306 | * emptied first. | ||
307 | */ | ||
308 | if (!unlikely(list_empty(&nc_path->packet_list))) { | ||
309 | net_ratelimited_function(printk, | ||
310 | KERN_WARNING | ||
311 | "Skipping free of non-empty nc_path (%pM -> %pM)!\n", | ||
312 | nc_path->prev_hop, | ||
313 | nc_path->next_hop); | ||
314 | continue; | ||
315 | } | ||
316 | |||
317 | /* nc_path is unused, so remove it */ | ||
318 | batadv_dbg(BATADV_DBG_NC, bat_priv, | ||
319 | "Remove nc_path %pM -> %pM\n", | ||
320 | nc_path->prev_hop, nc_path->next_hop); | ||
321 | hlist_del_rcu(&nc_path->hash_entry); | ||
322 | batadv_nc_path_free_ref(nc_path); | ||
323 | } | ||
324 | spin_unlock_bh(lock); | ||
325 | } | ||
326 | } | ||
327 | |||
328 | /** | ||
329 | * batadv_nc_hash_key_gen - computes the nc_path hash key | ||
330 | * @key: buffer to hold the final hash key | ||
331 | * @src: source ethernet mac address going into the hash key | ||
332 | * @dst: destination ethernet mac address going into the hash key | ||
333 | */ | ||
334 | static void batadv_nc_hash_key_gen(struct batadv_nc_path *key, const char *src, | ||
335 | const char *dst) | ||
336 | { | ||
337 | memcpy(key->prev_hop, src, sizeof(key->prev_hop)); | ||
338 | memcpy(key->next_hop, dst, sizeof(key->next_hop)); | ||
339 | } | ||
340 | |||
341 | /** | ||
342 | * batadv_nc_hash_choose - compute the hash value for an nc path | ||
343 | * @data: data to hash | ||
344 | * @size: size of the hash table | ||
345 | * | ||
346 | * Returns the selected index in the hash table for the given data. | ||
347 | */ | ||
348 | static uint32_t batadv_nc_hash_choose(const void *data, uint32_t size) | ||
349 | { | ||
350 | const struct batadv_nc_path *nc_path = data; | ||
351 | uint32_t hash = 0; | ||
352 | |||
353 | hash = batadv_hash_bytes(hash, &nc_path->prev_hop, | ||
354 | sizeof(nc_path->prev_hop)); | ||
355 | hash = batadv_hash_bytes(hash, &nc_path->next_hop, | ||
356 | sizeof(nc_path->next_hop)); | ||
357 | |||
358 | hash += (hash << 3); | ||
359 | hash ^= (hash >> 11); | ||
360 | hash += (hash << 15); | ||
361 | |||
362 | return hash % size; | ||
363 | } | ||
364 | |||
365 | /** | ||
366 | * batadv_nc_hash_compare - comparing function used in the network coding hash | ||
367 | * tables | ||
368 | * @node: node in the local table | ||
369 | * @data2: second object to compare the node to | ||
370 | * | ||
371 | * Returns 1 if the two entry are the same, 0 otherwise | ||
372 | */ | ||
373 | static int batadv_nc_hash_compare(const struct hlist_node *node, | ||
374 | const void *data2) | ||
375 | { | ||
376 | const struct batadv_nc_path *nc_path1, *nc_path2; | ||
377 | |||
378 | nc_path1 = container_of(node, struct batadv_nc_path, hash_entry); | ||
379 | nc_path2 = data2; | ||
380 | |||
381 | /* Return 1 if the two keys are identical */ | ||
382 | if (memcmp(nc_path1->prev_hop, nc_path2->prev_hop, | ||
383 | sizeof(nc_path1->prev_hop)) != 0) | ||
384 | return 0; | ||
385 | |||
386 | if (memcmp(nc_path1->next_hop, nc_path2->next_hop, | ||
387 | sizeof(nc_path1->next_hop)) != 0) | ||
388 | return 0; | ||
389 | |||
390 | return 1; | ||
391 | } | ||
392 | |||
393 | /** | ||
394 | * batadv_nc_hash_find - search for an existing nc path and return it | ||
395 | * @hash: hash table containing the nc path | ||
396 | * @data: search key | ||
397 | * | ||
398 | * Returns the nc_path if found, NULL otherwise. | ||
399 | */ | ||
400 | static struct batadv_nc_path * | ||
401 | batadv_nc_hash_find(struct batadv_hashtable *hash, | ||
402 | void *data) | ||
403 | { | ||
404 | struct hlist_head *head; | ||
405 | struct batadv_nc_path *nc_path, *nc_path_tmp = NULL; | ||
406 | int index; | ||
407 | |||
408 | if (!hash) | ||
409 | return NULL; | ||
410 | |||
411 | index = batadv_nc_hash_choose(data, hash->size); | ||
412 | head = &hash->table[index]; | ||
413 | |||
414 | rcu_read_lock(); | ||
415 | hlist_for_each_entry_rcu(nc_path, head, hash_entry) { | ||
416 | if (!batadv_nc_hash_compare(&nc_path->hash_entry, data)) | ||
417 | continue; | ||
418 | |||
419 | if (!atomic_inc_not_zero(&nc_path->refcount)) | ||
420 | continue; | ||
421 | |||
422 | nc_path_tmp = nc_path; | ||
423 | break; | ||
424 | } | ||
425 | rcu_read_unlock(); | ||
426 | |||
427 | return nc_path_tmp; | ||
428 | } | ||
429 | |||
430 | /** | ||
431 | * batadv_nc_send_packet - send non-coded packet and free nc_packet struct | ||
432 | * @nc_packet: the nc packet to send | ||
433 | */ | ||
434 | static void batadv_nc_send_packet(struct batadv_nc_packet *nc_packet) | ||
435 | { | ||
436 | batadv_send_skb_packet(nc_packet->skb, | ||
437 | nc_packet->neigh_node->if_incoming, | ||
438 | nc_packet->nc_path->next_hop); | ||
439 | nc_packet->skb = NULL; | ||
440 | batadv_nc_packet_free(nc_packet); | ||
441 | } | ||
442 | |||
443 | /** | ||
444 | * batadv_nc_fwd_flush - Checks the timestamp of the given nc packet. | ||
445 | * @bat_priv: the bat priv with all the soft interface information | ||
446 | * @nc_path: the nc path the packet belongs to | ||
447 | * @nc_packet: the nc packet to be checked | ||
448 | * | ||
449 | * Checks whether the given nc packet has hit its forward timeout. If so, the | ||
450 | * packet is no longer delayed, immediately sent and the entry deleted from the | ||
451 | * queue. Has to be called with the appropriate locks. | ||
452 | * | ||
453 | * Returns false as soon as the entry in the fifo queue has not been timed out | ||
454 | * yet and true otherwise. | ||
455 | */ | ||
456 | static bool batadv_nc_fwd_flush(struct batadv_priv *bat_priv, | ||
457 | struct batadv_nc_path *nc_path, | ||
458 | struct batadv_nc_packet *nc_packet) | ||
459 | { | ||
460 | unsigned long timeout = bat_priv->nc.max_fwd_delay; | ||
461 | |||
462 | /* Packets are added to tail, so the remaining packets did not time | ||
463 | * out and we can stop processing the current queue | ||
464 | */ | ||
465 | if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_ACTIVE && | ||
466 | !batadv_has_timed_out(nc_packet->timestamp, timeout)) | ||
467 | return false; | ||
468 | |||
469 | /* Send packet */ | ||
470 | batadv_inc_counter(bat_priv, BATADV_CNT_FORWARD); | ||
471 | batadv_add_counter(bat_priv, BATADV_CNT_FORWARD_BYTES, | ||
472 | nc_packet->skb->len + ETH_HLEN); | ||
473 | list_del(&nc_packet->list); | ||
474 | batadv_nc_send_packet(nc_packet); | ||
475 | |||
476 | return true; | ||
477 | } | ||
478 | |||
479 | /** | ||
480 | * batadv_nc_process_nc_paths - traverse given nc packet pool and free timed out | ||
481 | * nc packets | ||
482 | * @bat_priv: the bat priv with all the soft interface information | ||
483 | * @hash: to be processed hash table | ||
484 | * @process_fn: Function called to process given nc packet. Should return true | ||
485 | * to encourage this function to proceed with the next packet. | ||
486 | * Otherwise the rest of the current queue is skipped. | ||
487 | */ | ||
488 | static void | ||
489 | batadv_nc_process_nc_paths(struct batadv_priv *bat_priv, | ||
490 | struct batadv_hashtable *hash, | ||
491 | bool (*process_fn)(struct batadv_priv *, | ||
492 | struct batadv_nc_path *, | ||
493 | struct batadv_nc_packet *)) | ||
494 | { | ||
495 | struct hlist_head *head; | ||
496 | struct batadv_nc_packet *nc_packet, *nc_packet_tmp; | ||
497 | struct batadv_nc_path *nc_path; | ||
498 | bool ret; | ||
499 | int i; | ||
500 | |||
501 | if (!hash) | ||
502 | return; | ||
503 | |||
504 | /* Loop hash table bins */ | ||
505 | for (i = 0; i < hash->size; i++) { | ||
506 | head = &hash->table[i]; | ||
507 | |||
508 | /* Loop coding paths */ | ||
509 | rcu_read_lock(); | ||
510 | hlist_for_each_entry_rcu(nc_path, head, hash_entry) { | ||
511 | /* Loop packets */ | ||
512 | spin_lock_bh(&nc_path->packet_list_lock); | ||
513 | list_for_each_entry_safe(nc_packet, nc_packet_tmp, | ||
514 | &nc_path->packet_list, list) { | ||
515 | ret = process_fn(bat_priv, nc_path, nc_packet); | ||
516 | if (!ret) | ||
517 | break; | ||
518 | } | ||
519 | spin_unlock_bh(&nc_path->packet_list_lock); | ||
520 | } | ||
521 | rcu_read_unlock(); | ||
522 | } | ||
523 | } | ||
524 | |||
525 | /** | ||
206 | * batadv_nc_worker - periodic task for house keeping related to network coding | 526 | * batadv_nc_worker - periodic task for house keeping related to network coding |
207 | * @work: kernel work struct | 527 | * @work: kernel work struct |
208 | */ | 528 | */ |
@@ -211,12 +531,23 @@ static void batadv_nc_worker(struct work_struct *work) | |||
211 | struct delayed_work *delayed_work; | 531 | struct delayed_work *delayed_work; |
212 | struct batadv_priv_nc *priv_nc; | 532 | struct batadv_priv_nc *priv_nc; |
213 | struct batadv_priv *bat_priv; | 533 | struct batadv_priv *bat_priv; |
534 | unsigned long timeout; | ||
214 | 535 | ||
215 | delayed_work = container_of(work, struct delayed_work, work); | 536 | delayed_work = container_of(work, struct delayed_work, work); |
216 | priv_nc = container_of(delayed_work, struct batadv_priv_nc, work); | 537 | priv_nc = container_of(delayed_work, struct batadv_priv_nc, work); |
217 | bat_priv = container_of(priv_nc, struct batadv_priv, nc); | 538 | bat_priv = container_of(priv_nc, struct batadv_priv, nc); |
218 | 539 | ||
219 | batadv_nc_purge_orig_hash(bat_priv); | 540 | batadv_nc_purge_orig_hash(bat_priv); |
541 | batadv_nc_purge_paths(bat_priv, bat_priv->nc.coding_hash, | ||
542 | batadv_nc_to_purge_nc_path_coding); | ||
543 | |||
544 | timeout = bat_priv->nc.max_fwd_delay; | ||
545 | |||
546 | if (batadv_has_timed_out(bat_priv->nc.timestamp_fwd_flush, timeout)) { | ||
547 | batadv_nc_process_nc_paths(bat_priv, bat_priv->nc.coding_hash, | ||
548 | batadv_nc_fwd_flush); | ||
549 | bat_priv->nc.timestamp_fwd_flush = jiffies; | ||
550 | } | ||
220 | 551 | ||
221 | /* Schedule a new check */ | 552 | /* Schedule a new check */ |
222 | batadv_nc_start_timer(bat_priv); | 553 | batadv_nc_start_timer(bat_priv); |
@@ -407,12 +738,163 @@ out: | |||
407 | } | 738 | } |
408 | 739 | ||
409 | /** | 740 | /** |
741 | * batadv_nc_get_path - get existing nc_path or allocate a new one | ||
742 | * @bat_priv: the bat priv with all the soft interface information | ||
743 | * @hash: hash table containing the nc path | ||
744 | * @src: ethernet source address - first half of the nc path search key | ||
745 | * @dst: ethernet destination address - second half of the nc path search key | ||
746 | * | ||
747 | * Returns pointer to nc_path if the path was found or created, returns NULL | ||
748 | * on error. | ||
749 | */ | ||
750 | static struct batadv_nc_path *batadv_nc_get_path(struct batadv_priv *bat_priv, | ||
751 | struct batadv_hashtable *hash, | ||
752 | uint8_t *src, | ||
753 | uint8_t *dst) | ||
754 | { | ||
755 | int hash_added; | ||
756 | struct batadv_nc_path *nc_path, nc_path_key; | ||
757 | |||
758 | batadv_nc_hash_key_gen(&nc_path_key, src, dst); | ||
759 | |||
760 | /* Search for existing nc_path */ | ||
761 | nc_path = batadv_nc_hash_find(hash, (void *)&nc_path_key); | ||
762 | |||
763 | if (nc_path) { | ||
764 | /* Set timestamp to delay removal of nc_path */ | ||
765 | nc_path->last_valid = jiffies; | ||
766 | return nc_path; | ||
767 | } | ||
768 | |||
769 | /* No existing nc_path was found; create a new */ | ||
770 | nc_path = kzalloc(sizeof(*nc_path), GFP_ATOMIC); | ||
771 | |||
772 | if (!nc_path) | ||
773 | return NULL; | ||
774 | |||
775 | /* Initialize nc_path */ | ||
776 | INIT_LIST_HEAD(&nc_path->packet_list); | ||
777 | spin_lock_init(&nc_path->packet_list_lock); | ||
778 | atomic_set(&nc_path->refcount, 2); | ||
779 | nc_path->last_valid = jiffies; | ||
780 | memcpy(nc_path->next_hop, dst, ETH_ALEN); | ||
781 | memcpy(nc_path->prev_hop, src, ETH_ALEN); | ||
782 | |||
783 | batadv_dbg(BATADV_DBG_NC, bat_priv, "Adding nc_path %pM -> %pM\n", | ||
784 | nc_path->prev_hop, | ||
785 | nc_path->next_hop); | ||
786 | |||
787 | /* Add nc_path to hash table */ | ||
788 | hash_added = batadv_hash_add(hash, batadv_nc_hash_compare, | ||
789 | batadv_nc_hash_choose, &nc_path_key, | ||
790 | &nc_path->hash_entry); | ||
791 | |||
792 | if (hash_added < 0) { | ||
793 | kfree(nc_path); | ||
794 | return NULL; | ||
795 | } | ||
796 | |||
797 | return nc_path; | ||
798 | } | ||
799 | |||
800 | /** | ||
801 | * batadv_nc_skb_add_to_path - buffer skb for later encoding / decoding | ||
802 | * @skb: skb to add to path | ||
803 | * @nc_path: path to add skb to | ||
804 | * @neigh_node: next hop to forward packet to | ||
805 | * @packet_id: checksum to identify packet | ||
806 | * | ||
807 | * Returns true if the packet was buffered or false in case of an error. | ||
808 | */ | ||
809 | static bool batadv_nc_skb_add_to_path(struct sk_buff *skb, | ||
810 | struct batadv_nc_path *nc_path, | ||
811 | struct batadv_neigh_node *neigh_node, | ||
812 | __be32 packet_id) | ||
813 | { | ||
814 | struct batadv_nc_packet *nc_packet; | ||
815 | |||
816 | nc_packet = kzalloc(sizeof(*nc_packet), GFP_ATOMIC); | ||
817 | if (!nc_packet) | ||
818 | return false; | ||
819 | |||
820 | /* Initialize nc_packet */ | ||
821 | nc_packet->timestamp = jiffies; | ||
822 | nc_packet->packet_id = packet_id; | ||
823 | nc_packet->skb = skb; | ||
824 | nc_packet->neigh_node = neigh_node; | ||
825 | nc_packet->nc_path = nc_path; | ||
826 | |||
827 | /* Add coding packet to list */ | ||
828 | spin_lock_bh(&nc_path->packet_list_lock); | ||
829 | list_add_tail(&nc_packet->list, &nc_path->packet_list); | ||
830 | spin_unlock_bh(&nc_path->packet_list_lock); | ||
831 | |||
832 | return true; | ||
833 | } | ||
834 | |||
835 | /** | ||
836 | * batadv_nc_skb_forward - try to code a packet or add it to the coding packet | ||
837 | * buffer | ||
838 | * @skb: data skb to forward | ||
839 | * @neigh_node: next hop to forward packet to | ||
840 | * @ethhdr: pointer to the ethernet header inside the skb | ||
841 | * | ||
842 | * Returns true if the skb was consumed (encoded packet sent) or false otherwise | ||
843 | */ | ||
844 | bool batadv_nc_skb_forward(struct sk_buff *skb, | ||
845 | struct batadv_neigh_node *neigh_node, | ||
846 | struct ethhdr *ethhdr) | ||
847 | { | ||
848 | const struct net_device *netdev = neigh_node->if_incoming->soft_iface; | ||
849 | struct batadv_priv *bat_priv = netdev_priv(netdev); | ||
850 | struct batadv_unicast_packet *packet; | ||
851 | struct batadv_nc_path *nc_path; | ||
852 | __be32 packet_id; | ||
853 | u8 *payload; | ||
854 | |||
855 | /* Check if network coding is enabled */ | ||
856 | if (!atomic_read(&bat_priv->network_coding)) | ||
857 | goto out; | ||
858 | |||
859 | /* We only handle unicast packets */ | ||
860 | payload = skb_network_header(skb); | ||
861 | packet = (struct batadv_unicast_packet *)payload; | ||
862 | if (packet->header.packet_type != BATADV_UNICAST) | ||
863 | goto out; | ||
864 | |||
865 | /* Find or create a nc_path for this src-dst pair */ | ||
866 | nc_path = batadv_nc_get_path(bat_priv, | ||
867 | bat_priv->nc.coding_hash, | ||
868 | ethhdr->h_source, | ||
869 | neigh_node->addr); | ||
870 | |||
871 | if (!nc_path) | ||
872 | goto out; | ||
873 | |||
874 | /* Add skb to nc_path */ | ||
875 | packet_id = batadv_skb_crc32(skb, payload + sizeof(*packet)); | ||
876 | if (!batadv_nc_skb_add_to_path(skb, nc_path, neigh_node, packet_id)) | ||
877 | goto free_nc_path; | ||
878 | |||
879 | /* Packet is consumed */ | ||
880 | return true; | ||
881 | |||
882 | free_nc_path: | ||
883 | batadv_nc_path_free_ref(nc_path); | ||
884 | out: | ||
885 | /* Packet is not consumed */ | ||
886 | return false; | ||
887 | } | ||
888 | |||
889 | /** | ||
410 | * batadv_nc_free - clean up network coding memory | 890 | * batadv_nc_free - clean up network coding memory |
411 | * @bat_priv: the bat priv with all the soft interface information | 891 | * @bat_priv: the bat priv with all the soft interface information |
412 | */ | 892 | */ |
413 | void batadv_nc_free(struct batadv_priv *bat_priv) | 893 | void batadv_nc_free(struct batadv_priv *bat_priv) |
414 | { | 894 | { |
415 | cancel_delayed_work_sync(&bat_priv->nc.work); | 895 | cancel_delayed_work_sync(&bat_priv->nc.work); |
896 | batadv_nc_purge_paths(bat_priv, bat_priv->nc.coding_hash, NULL); | ||
897 | batadv_hash_destroy(bat_priv->nc.coding_hash); | ||
416 | } | 898 | } |
417 | 899 | ||
418 | /** | 900 | /** |
@@ -488,6 +970,11 @@ int batadv_nc_init_debugfs(struct batadv_priv *bat_priv) | |||
488 | if (!file) | 970 | if (!file) |
489 | goto out; | 971 | goto out; |
490 | 972 | ||
973 | file = debugfs_create_u32("max_fwd_delay", S_IRUGO | S_IWUSR, nc_dir, | ||
974 | &bat_priv->nc.max_fwd_delay); | ||
975 | if (!file) | ||
976 | goto out; | ||
977 | |||
491 | return 0; | 978 | return 0; |
492 | 979 | ||
493 | out: | 980 | out: |
diff --git a/net/batman-adv/network-coding.h b/net/batman-adv/network-coding.h index 4c56cd98d9de..c32602a3939a 100644 --- a/net/batman-adv/network-coding.h +++ b/net/batman-adv/network-coding.h | |||
@@ -35,6 +35,9 @@ void batadv_nc_purge_orig(struct batadv_priv *bat_priv, | |||
35 | struct batadv_nc_node *)); | 35 | struct batadv_nc_node *)); |
36 | void batadv_nc_init_bat_priv(struct batadv_priv *bat_priv); | 36 | void batadv_nc_init_bat_priv(struct batadv_priv *bat_priv); |
37 | void batadv_nc_init_orig(struct batadv_orig_node *orig_node); | 37 | void batadv_nc_init_orig(struct batadv_orig_node *orig_node); |
38 | bool batadv_nc_skb_forward(struct sk_buff *skb, | ||
39 | struct batadv_neigh_node *neigh_node, | ||
40 | struct ethhdr *ethhdr); | ||
38 | int batadv_nc_nodes_seq_print_text(struct seq_file *seq, void *offset); | 41 | int batadv_nc_nodes_seq_print_text(struct seq_file *seq, void *offset); |
39 | int batadv_nc_init_debugfs(struct batadv_priv *bat_priv); | 42 | int batadv_nc_init_debugfs(struct batadv_priv *bat_priv); |
40 | 43 | ||
@@ -79,6 +82,13 @@ static inline void batadv_nc_init_orig(struct batadv_orig_node *orig_node) | |||
79 | return; | 82 | return; |
80 | } | 83 | } |
81 | 84 | ||
85 | static inline bool batadv_nc_skb_forward(struct sk_buff *skb, | ||
86 | struct batadv_neigh_node *neigh_node, | ||
87 | struct ethhdr *ethhdr) | ||
88 | { | ||
89 | return false; | ||
90 | } | ||
91 | |||
82 | static inline int batadv_nc_nodes_seq_print_text(struct seq_file *seq, | 92 | static inline int batadv_nc_nodes_seq_print_text(struct seq_file *seq, |
83 | void *offset) | 93 | void *offset) |
84 | { | 94 | { |
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 322c97ac10c7..44fda7c6171e 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include "unicast.h" | 29 | #include "unicast.h" |
30 | #include "bridge_loop_avoidance.h" | 30 | #include "bridge_loop_avoidance.h" |
31 | #include "distributed-arp-table.h" | 31 | #include "distributed-arp-table.h" |
32 | #include "network-coding.h" | ||
32 | 33 | ||
33 | static int batadv_route_unicast_packet(struct sk_buff *skb, | 34 | static int batadv_route_unicast_packet(struct sk_buff *skb, |
34 | struct batadv_hard_iface *recv_if); | 35 | struct batadv_hard_iface *recv_if); |
@@ -860,14 +861,17 @@ static int batadv_route_unicast_packet(struct sk_buff *skb, | |||
860 | /* decrement ttl */ | 861 | /* decrement ttl */ |
861 | unicast_packet->header.ttl--; | 862 | unicast_packet->header.ttl--; |
862 | 863 | ||
863 | /* Update stats counter */ | 864 | /* network code packet if possible */ |
864 | batadv_inc_counter(bat_priv, BATADV_CNT_FORWARD); | 865 | if (batadv_nc_skb_forward(skb, neigh_node, ethhdr)) { |
865 | batadv_add_counter(bat_priv, BATADV_CNT_FORWARD_BYTES, | ||
866 | skb->len + ETH_HLEN); | ||
867 | |||
868 | /* route it */ | ||
869 | if (batadv_send_skb_to_orig(skb, orig_node, recv_if)) | ||
870 | ret = NET_RX_SUCCESS; | 866 | ret = NET_RX_SUCCESS; |
867 | } else if (batadv_send_skb_to_orig(skb, orig_node, recv_if)) { | ||
868 | ret = NET_RX_SUCCESS; | ||
869 | |||
870 | /* Update stats counter */ | ||
871 | batadv_inc_counter(bat_priv, BATADV_CNT_FORWARD); | ||
872 | batadv_add_counter(bat_priv, BATADV_CNT_FORWARD_BYTES, | ||
873 | skb->len + ETH_HLEN); | ||
874 | } | ||
871 | 875 | ||
872 | out: | 876 | out: |
873 | if (neigh_node) | 877 | if (neigh_node) |
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 1544ab40bedd..43caf7f493c1 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h | |||
@@ -442,11 +442,19 @@ struct batadv_priv_dat { | |||
442 | * @work: work queue callback item for cleanup | 442 | * @work: work queue callback item for cleanup |
443 | * @debug_dir: dentry for nc subdir in batman-adv directory in debugfs | 443 | * @debug_dir: dentry for nc subdir in batman-adv directory in debugfs |
444 | * @min_tq: only consider neighbors for encoding if neigh_tq > min_tq | 444 | * @min_tq: only consider neighbors for encoding if neigh_tq > min_tq |
445 | * @max_fwd_delay: maximum packet forward delay to allow coding of packets | ||
446 | * @timestamp_fwd_flush: timestamp of last forward packet queue flush | ||
447 | * @coding_hash: Hash table used to buffer skbs while waiting for another | ||
448 | * incoming skb to code it with. Skbs are added to the buffer just before being | ||
449 | * forwarded in routing.c | ||
445 | */ | 450 | */ |
446 | struct batadv_priv_nc { | 451 | struct batadv_priv_nc { |
447 | struct delayed_work work; | 452 | struct delayed_work work; |
448 | struct dentry *debug_dir; | 453 | struct dentry *debug_dir; |
449 | u8 min_tq; | 454 | u8 min_tq; |
455 | u32 max_fwd_delay; | ||
456 | unsigned long timestamp_fwd_flush; | ||
457 | struct batadv_hashtable *coding_hash; | ||
450 | }; | 458 | }; |
451 | 459 | ||
452 | /** | 460 | /** |
@@ -748,6 +756,47 @@ struct batadv_nc_node { | |||
748 | }; | 756 | }; |
749 | 757 | ||
750 | /** | 758 | /** |
759 | * struct batadv_nc_path - network coding path | ||
760 | * @hash_entry: next and prev pointer for the list handling | ||
761 | * @rcu: struct used for freeing in an RCU-safe manner | ||
762 | * @refcount: number of contexts the object is used by | ||
763 | * @packet_list: list of buffered packets for this path | ||
764 | * @packet_list_lock: access lock for packet list | ||
765 | * @next_hop: next hop (destination) of path | ||
766 | * @prev_hop: previous hop (source) of path | ||
767 | * @last_valid: timestamp for last validation of path | ||
768 | */ | ||
769 | struct batadv_nc_path { | ||
770 | struct hlist_node hash_entry; | ||
771 | struct rcu_head rcu; | ||
772 | atomic_t refcount; | ||
773 | struct list_head packet_list; | ||
774 | spinlock_t packet_list_lock; /* Protects packet_list */ | ||
775 | uint8_t next_hop[ETH_ALEN]; | ||
776 | uint8_t prev_hop[ETH_ALEN]; | ||
777 | unsigned long last_valid; | ||
778 | }; | ||
779 | |||
780 | /** | ||
781 | * struct batadv_nc_packet - network coding packet used when coding and | ||
782 | * decoding packets | ||
783 | * @list: next and prev pointer for the list handling | ||
784 | * @packet_id: crc32 checksum of skb data | ||
785 | * @timestamp: field containing the info when the packet was added to path | ||
786 | * @neigh_node: pointer to original next hop neighbor of skb | ||
787 | * @skb: skb which can be encoded or used for decoding | ||
788 | * @nc_path: pointer to path this nc packet is attached to | ||
789 | */ | ||
790 | struct batadv_nc_packet { | ||
791 | struct list_head list; | ||
792 | __be32 packet_id; | ||
793 | unsigned long timestamp; | ||
794 | struct batadv_neigh_node *neigh_node; | ||
795 | struct sk_buff *skb; | ||
796 | struct batadv_nc_path *nc_path; | ||
797 | }; | ||
798 | |||
799 | /** | ||
751 | * struct batadv_forw_packet - structure for bcast packets to be sent/forwarded | 800 | * struct batadv_forw_packet - structure for bcast packets to be sent/forwarded |
752 | * @list: list node for batadv_socket_client::queue_list | 801 | * @list: list node for batadv_socket_client::queue_list |
753 | * @send_time: execution time for delayed_work (packet sending) | 802 | * @send_time: execution time for delayed_work (packet sending) |