diff options
-rw-r--r-- | net/batman-adv/fragmentation.c | 121 | ||||
-rw-r--r-- | net/batman-adv/fragmentation.h | 3 | ||||
-rw-r--r-- | net/batman-adv/send.c | 21 | ||||
-rw-r--r-- | net/batman-adv/soft-interface.c | 7 | ||||
-rw-r--r-- | net/batman-adv/types.h | 6 |
5 files changed, 154 insertions, 4 deletions
diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c index c829d3cee89c..271d321b3a04 100644 --- a/net/batman-adv/fragmentation.c +++ b/net/batman-adv/fragmentation.c | |||
@@ -368,3 +368,124 @@ out: | |||
368 | batadv_neigh_node_free_ref(neigh_node); | 368 | batadv_neigh_node_free_ref(neigh_node); |
369 | return ret; | 369 | return ret; |
370 | } | 370 | } |
371 | |||
372 | /** | ||
373 | * batadv_frag_create - create a fragment from skb | ||
374 | * @skb: skb to create fragment from | ||
375 | * @frag_head: header to use in new fragment | ||
376 | * @mtu: size of new fragment | ||
377 | * | ||
378 | * Split the passed skb into two fragments: A new one with size matching the | ||
379 | * passed mtu and the old one with the rest. The new skb contains data from the | ||
380 | * tail of the old skb. | ||
381 | * | ||
382 | * Returns the new fragment, NULL on error. | ||
383 | */ | ||
384 | static struct sk_buff *batadv_frag_create(struct sk_buff *skb, | ||
385 | struct batadv_frag_packet *frag_head, | ||
386 | unsigned int mtu) | ||
387 | { | ||
388 | struct sk_buff *skb_fragment; | ||
389 | unsigned header_size = sizeof(*frag_head); | ||
390 | unsigned fragment_size = mtu - header_size; | ||
391 | |||
392 | skb_fragment = netdev_alloc_skb(NULL, mtu + ETH_HLEN); | ||
393 | if (!skb_fragment) | ||
394 | goto err; | ||
395 | |||
396 | skb->priority = TC_PRIO_CONTROL; | ||
397 | |||
398 | /* Eat the last mtu-bytes of the skb */ | ||
399 | skb_reserve(skb_fragment, header_size + ETH_HLEN); | ||
400 | skb_split(skb, skb_fragment, skb->len - fragment_size); | ||
401 | |||
402 | /* Add the header */ | ||
403 | skb_push(skb_fragment, header_size); | ||
404 | memcpy(skb_fragment->data, frag_head, header_size); | ||
405 | |||
406 | err: | ||
407 | return skb_fragment; | ||
408 | } | ||
409 | |||
410 | /** | ||
411 | * batadv_frag_send_packet - create up to 16 fragments from the passed skb | ||
412 | * @skb: skb to create fragments from | ||
413 | * @orig_node: final destination of the created fragments | ||
414 | * @neigh_node: next-hop of the created fragments | ||
415 | * | ||
416 | * Returns true on success, false otherwise. | ||
417 | */ | ||
418 | bool batadv_frag_send_packet(struct sk_buff *skb, | ||
419 | struct batadv_orig_node *orig_node, | ||
420 | struct batadv_neigh_node *neigh_node) | ||
421 | { | ||
422 | struct batadv_priv *bat_priv; | ||
423 | struct batadv_hard_iface *primary_if; | ||
424 | struct batadv_frag_packet frag_header; | ||
425 | struct sk_buff *skb_fragment; | ||
426 | unsigned mtu = neigh_node->if_incoming->net_dev->mtu; | ||
427 | unsigned header_size = sizeof(frag_header); | ||
428 | unsigned max_fragment_size, max_packet_size; | ||
429 | |||
430 | /* To avoid merge and refragmentation at next-hops we never send | ||
431 | * fragments larger than BATADV_FRAG_MAX_FRAG_SIZE | ||
432 | */ | ||
433 | mtu = min_t(unsigned, mtu, BATADV_FRAG_MAX_FRAG_SIZE); | ||
434 | max_fragment_size = (mtu - header_size - ETH_HLEN); | ||
435 | max_packet_size = max_fragment_size * BATADV_FRAG_MAX_FRAGMENTS; | ||
436 | |||
437 | /* Don't even try to fragment, if we need more than 16 fragments */ | ||
438 | if (skb->len > max_packet_size) | ||
439 | goto out_err; | ||
440 | |||
441 | bat_priv = orig_node->bat_priv; | ||
442 | primary_if = batadv_primary_if_get_selected(bat_priv); | ||
443 | if (!primary_if) | ||
444 | goto out_err; | ||
445 | |||
446 | /* Create one header to be copied to all fragments */ | ||
447 | frag_header.header.packet_type = BATADV_UNICAST_FRAG; | ||
448 | frag_header.header.version = BATADV_COMPAT_VERSION; | ||
449 | frag_header.header.ttl = BATADV_TTL; | ||
450 | frag_header.seqno = htons(atomic_inc_return(&bat_priv->frag_seqno)); | ||
451 | frag_header.reserved = 0; | ||
452 | frag_header.no = 0; | ||
453 | frag_header.total_size = htons(skb->len); | ||
454 | memcpy(frag_header.orig, primary_if->net_dev->dev_addr, ETH_ALEN); | ||
455 | memcpy(frag_header.dest, orig_node->orig, ETH_ALEN); | ||
456 | |||
457 | /* Eat and send fragments from the tail of skb */ | ||
458 | while (skb->len > max_fragment_size) { | ||
459 | skb_fragment = batadv_frag_create(skb, &frag_header, mtu); | ||
460 | if (!skb_fragment) | ||
461 | goto out_err; | ||
462 | |||
463 | batadv_inc_counter(bat_priv, BATADV_CNT_FRAG_TX); | ||
464 | batadv_add_counter(bat_priv, BATADV_CNT_FRAG_TX_BYTES, | ||
465 | skb_fragment->len + ETH_HLEN); | ||
466 | batadv_send_skb_packet(skb_fragment, neigh_node->if_incoming, | ||
467 | neigh_node->addr); | ||
468 | frag_header.no++; | ||
469 | |||
470 | /* The initial check in this function should cover this case */ | ||
471 | if (frag_header.no == BATADV_FRAG_MAX_FRAGMENTS - 1) | ||
472 | goto out_err; | ||
473 | } | ||
474 | |||
475 | /* Make room for the fragment header. */ | ||
476 | if (batadv_skb_head_push(skb, header_size) < 0 || | ||
477 | pskb_expand_head(skb, header_size + ETH_HLEN, 0, GFP_ATOMIC) < 0) | ||
478 | goto out_err; | ||
479 | |||
480 | memcpy(skb->data, &frag_header, header_size); | ||
481 | |||
482 | /* Send the last fragment */ | ||
483 | batadv_inc_counter(bat_priv, BATADV_CNT_FRAG_TX); | ||
484 | batadv_add_counter(bat_priv, BATADV_CNT_FRAG_TX_BYTES, | ||
485 | skb->len + ETH_HLEN); | ||
486 | batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); | ||
487 | |||
488 | return true; | ||
489 | out_err: | ||
490 | return false; | ||
491 | } | ||
diff --git a/net/batman-adv/fragmentation.h b/net/batman-adv/fragmentation.h index 883a6f46005e..ca029e2676e7 100644 --- a/net/batman-adv/fragmentation.h +++ b/net/batman-adv/fragmentation.h | |||
@@ -27,6 +27,9 @@ bool batadv_frag_skb_fwd(struct sk_buff *skb, | |||
27 | struct batadv_orig_node *orig_node_src); | 27 | struct batadv_orig_node *orig_node_src); |
28 | bool batadv_frag_skb_buffer(struct sk_buff **skb, | 28 | bool batadv_frag_skb_buffer(struct sk_buff **skb, |
29 | struct batadv_orig_node *orig_node); | 29 | struct batadv_orig_node *orig_node); |
30 | bool batadv_frag_send_packet(struct sk_buff *skb, | ||
31 | struct batadv_orig_node *orig_node, | ||
32 | struct batadv_neigh_node *neigh_node); | ||
30 | 33 | ||
31 | /** | 34 | /** |
32 | * batadv_frag_check_entry - check if a list of fragments has timed out | 35 | * batadv_frag_check_entry - check if a list of fragments has timed out |
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index b8356ec067bf..1a1aa59d78ee 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c | |||
@@ -28,8 +28,7 @@ | |||
28 | #include "gateway_client.h" | 28 | #include "gateway_client.h" |
29 | #include "originator.h" | 29 | #include "originator.h" |
30 | #include "network-coding.h" | 30 | #include "network-coding.h" |
31 | 31 | #include "fragmentation.h" | |
32 | #include <linux/if_ether.h> | ||
33 | 32 | ||
34 | static void batadv_send_outstanding_bcast_packet(struct work_struct *work); | 33 | static void batadv_send_outstanding_bcast_packet(struct work_struct *work); |
35 | 34 | ||
@@ -109,7 +108,19 @@ int batadv_send_skb_to_orig(struct sk_buff *skb, | |||
109 | /* batadv_find_router() increases neigh_nodes refcount if found. */ | 108 | /* batadv_find_router() increases neigh_nodes refcount if found. */ |
110 | neigh_node = batadv_find_router(bat_priv, orig_node, recv_if); | 109 | neigh_node = batadv_find_router(bat_priv, orig_node, recv_if); |
111 | if (!neigh_node) | 110 | if (!neigh_node) |
112 | return ret; | 111 | goto out; |
112 | |||
113 | /* Check if the skb is too large to send in one piece and fragment | ||
114 | * it if needed. | ||
115 | */ | ||
116 | if (atomic_read(&bat_priv->fragmentation) && | ||
117 | skb->len > neigh_node->if_incoming->net_dev->mtu) { | ||
118 | /* Fragment and send packet. */ | ||
119 | if (batadv_frag_send_packet(skb, orig_node, neigh_node)) | ||
120 | ret = NET_XMIT_SUCCESS; | ||
121 | |||
122 | goto out; | ||
123 | } | ||
113 | 124 | ||
114 | /* try to network code the packet, if it is received on an interface | 125 | /* try to network code the packet, if it is received on an interface |
115 | * (i.e. being forwarded). If the packet originates from this node or if | 126 | * (i.e. being forwarded). If the packet originates from this node or if |
@@ -123,7 +134,9 @@ int batadv_send_skb_to_orig(struct sk_buff *skb, | |||
123 | ret = NET_XMIT_SUCCESS; | 134 | ret = NET_XMIT_SUCCESS; |
124 | } | 135 | } |
125 | 136 | ||
126 | batadv_neigh_node_free_ref(neigh_node); | 137 | out: |
138 | if (neigh_node) | ||
139 | batadv_neigh_node_free_ref(neigh_node); | ||
127 | 140 | ||
128 | return ret; | 141 | return ret; |
129 | } | 142 | } |
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index dd189e6bf05a..18b1fd915d1f 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c | |||
@@ -442,6 +442,7 @@ static void batadv_softif_destroy_finish(struct work_struct *work) | |||
442 | static int batadv_softif_init_late(struct net_device *dev) | 442 | static int batadv_softif_init_late(struct net_device *dev) |
443 | { | 443 | { |
444 | struct batadv_priv *bat_priv; | 444 | struct batadv_priv *bat_priv; |
445 | uint32_t random_seqno; | ||
445 | int ret; | 446 | int ret; |
446 | size_t cnt_len = sizeof(uint64_t) * BATADV_CNT_NUM; | 447 | size_t cnt_len = sizeof(uint64_t) * BATADV_CNT_NUM; |
447 | 448 | ||
@@ -491,6 +492,10 @@ static int batadv_softif_init_late(struct net_device *dev) | |||
491 | bat_priv->tt.last_changeset = NULL; | 492 | bat_priv->tt.last_changeset = NULL; |
492 | bat_priv->tt.last_changeset_len = 0; | 493 | bat_priv->tt.last_changeset_len = 0; |
493 | 494 | ||
495 | /* randomize initial seqno to avoid collision */ | ||
496 | get_random_bytes(&random_seqno, sizeof(random_seqno)); | ||
497 | atomic_set(&bat_priv->frag_seqno, random_seqno); | ||
498 | |||
494 | bat_priv->primary_if = NULL; | 499 | bat_priv->primary_if = NULL; |
495 | bat_priv->num_ifaces = 0; | 500 | bat_priv->num_ifaces = 0; |
496 | 501 | ||
@@ -758,6 +763,8 @@ static const struct { | |||
758 | { "mgmt_tx_bytes" }, | 763 | { "mgmt_tx_bytes" }, |
759 | { "mgmt_rx" }, | 764 | { "mgmt_rx" }, |
760 | { "mgmt_rx_bytes" }, | 765 | { "mgmt_rx_bytes" }, |
766 | { "frag_tx" }, | ||
767 | { "frag_tx_bytes" }, | ||
761 | { "frag_rx" }, | 768 | { "frag_rx" }, |
762 | { "frag_rx_bytes" }, | 769 | { "frag_rx_bytes" }, |
763 | { "frag_fwd" }, | 770 | { "frag_fwd" }, |
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 5a2cc7a9a620..d517d5dde6ad 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h | |||
@@ -300,6 +300,8 @@ struct batadv_bcast_duplist_entry { | |||
300 | * @BATADV_CNT_MGMT_TX_BYTES: transmitted routing protocol traffic bytes counter | 300 | * @BATADV_CNT_MGMT_TX_BYTES: transmitted routing protocol traffic bytes counter |
301 | * @BATADV_CNT_MGMT_RX: received routing protocol traffic packet counter | 301 | * @BATADV_CNT_MGMT_RX: received routing protocol traffic packet counter |
302 | * @BATADV_CNT_MGMT_RX_BYTES: received routing protocol traffic bytes counter | 302 | * @BATADV_CNT_MGMT_RX_BYTES: received routing protocol traffic bytes counter |
303 | * @BATADV_CNT_FRAG_TX: transmitted fragment traffic packet counter | ||
304 | * @BATADV_CNT_FRAG_TX_BYTES: transmitted fragment traffic bytes counter | ||
303 | * @BATADV_CNT_FRAG_RX: received fragment traffic packet counter | 305 | * @BATADV_CNT_FRAG_RX: received fragment traffic packet counter |
304 | * @BATADV_CNT_FRAG_RX_BYTES: received fragment traffic bytes counter | 306 | * @BATADV_CNT_FRAG_RX_BYTES: received fragment traffic bytes counter |
305 | * @BATADV_CNT_FRAG_FWD: forwarded fragment traffic packet counter | 307 | * @BATADV_CNT_FRAG_FWD: forwarded fragment traffic packet counter |
@@ -341,6 +343,8 @@ enum batadv_counters { | |||
341 | BATADV_CNT_MGMT_TX_BYTES, | 343 | BATADV_CNT_MGMT_TX_BYTES, |
342 | BATADV_CNT_MGMT_RX, | 344 | BATADV_CNT_MGMT_RX, |
343 | BATADV_CNT_MGMT_RX_BYTES, | 345 | BATADV_CNT_MGMT_RX_BYTES, |
346 | BATADV_CNT_FRAG_TX, | ||
347 | BATADV_CNT_FRAG_TX_BYTES, | ||
344 | BATADV_CNT_FRAG_RX, | 348 | BATADV_CNT_FRAG_RX, |
345 | BATADV_CNT_FRAG_RX_BYTES, | 349 | BATADV_CNT_FRAG_RX_BYTES, |
346 | BATADV_CNT_FRAG_FWD, | 350 | BATADV_CNT_FRAG_FWD, |
@@ -542,6 +546,7 @@ struct batadv_priv_nc { | |||
542 | * @aggregated_ogms: bool indicating whether OGM aggregation is enabled | 546 | * @aggregated_ogms: bool indicating whether OGM aggregation is enabled |
543 | * @bonding: bool indicating whether traffic bonding is enabled | 547 | * @bonding: bool indicating whether traffic bonding is enabled |
544 | * @fragmentation: bool indicating whether traffic fragmentation is enabled | 548 | * @fragmentation: bool indicating whether traffic fragmentation is enabled |
549 | * @frag_seqno: incremental counter to identify chains of egress fragments | ||
545 | * @ap_isolation: bool indicating whether ap isolation is enabled | 550 | * @ap_isolation: bool indicating whether ap isolation is enabled |
546 | * @bridge_loop_avoidance: bool indicating whether bridge loop avoidance is | 551 | * @bridge_loop_avoidance: bool indicating whether bridge loop avoidance is |
547 | * enabled | 552 | * enabled |
@@ -585,6 +590,7 @@ struct batadv_priv { | |||
585 | atomic_t aggregated_ogms; | 590 | atomic_t aggregated_ogms; |
586 | atomic_t bonding; | 591 | atomic_t bonding; |
587 | atomic_t fragmentation; | 592 | atomic_t fragmentation; |
593 | atomic_t frag_seqno; | ||
588 | atomic_t ap_isolation; | 594 | atomic_t ap_isolation; |
589 | #ifdef CONFIG_BATMAN_ADV_BLA | 595 | #ifdef CONFIG_BATMAN_ADV_BLA |
590 | atomic_t bridge_loop_avoidance; | 596 | atomic_t bridge_loop_avoidance; |