91 lines
3.5 KiB
Diff
91 lines
3.5 KiB
Diff
From: Sven Eckelmann <sven@narfation.org>
|
|
Date: Wed, 22 Feb 2017 17:25:42 +0100
|
|
Subject: [PATCH] batman-adv: Keep fragments equally sized
|
|
|
|
The batman-adv fragmentation packets have the design problem that they
|
|
cannot be refragmented. This often leads to problems when networks are
|
|
incorrectly configured and don't use a common MTU.
|
|
|
|
The sender could for example fragment a 1500 byte packet to fit in a 1280
|
|
bytes large MTU. This would create a 1280 large packet and a 284 bytes
|
|
large packet. But the next hop is then not able to transport 1280 bytes to
|
|
its next hop. The 1280 byte large packet will be dropped but the 284 bytes
|
|
large packet will still be forwarded to its destination.
|
|
|
|
This can partly being avoided by splitting packets more equally. In this
|
|
example, the two 782 bytes large packets could both potentially reach its
|
|
destination.
|
|
|
|
Signed-off-by: Sven Eckelmann <sven@narfation.org>
|
|
Acked-by: Linus Lüssing <linus.luessing@c0d3.blue>
|
|
|
|
Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/3caa5d14206ce8d4bd48bc931f213dec47ea1566
|
|
---
|
|
net/batman-adv/fragmentation.c | 20 +++++++++++++-------
|
|
1 file changed, 13 insertions(+), 7 deletions(-)
|
|
|
|
diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c
|
|
index d33f16b9b8ac13ba630bf9ac8c5f4f0ca79fc878..70e512111528b0345889cea4ffd0ad5d984a4e6a 100644
|
|
--- a/net/batman-adv/fragmentation.c
|
|
+++ b/net/batman-adv/fragmentation.c
|
|
@@ -404,7 +404,7 @@ out:
|
|
* batadv_frag_create - create a fragment from skb
|
|
* @skb: skb to create fragment from
|
|
* @frag_head: header to use in new fragment
|
|
- * @mtu: size of new fragment
|
|
+ * @fragment_size: size of new fragment
|
|
*
|
|
* Split the passed skb into two fragments: A new one with size matching the
|
|
* passed mtu and the old one with the rest. The new skb contains data from the
|
|
@@ -414,11 +414,11 @@ out:
|
|
*/
|
|
static struct sk_buff *batadv_frag_create(struct sk_buff *skb,
|
|
struct batadv_frag_packet *frag_head,
|
|
- unsigned int mtu)
|
|
+ unsigned int fragment_size)
|
|
{
|
|
struct sk_buff *skb_fragment;
|
|
unsigned int header_size = sizeof(*frag_head);
|
|
- unsigned int fragment_size = mtu - header_size;
|
|
+ unsigned int mtu = fragment_size + header_size;
|
|
|
|
skb_fragment = netdev_alloc_skb(NULL, mtu + ETH_HLEN);
|
|
if (!skb_fragment)
|
|
@@ -456,7 +456,7 @@ int batadv_frag_send_packet(struct sk_buff *skb,
|
|
struct sk_buff *skb_fragment;
|
|
unsigned int mtu = neigh_node->if_incoming->net_dev->mtu;
|
|
unsigned int header_size = sizeof(frag_header);
|
|
- unsigned int max_fragment_size, max_packet_size;
|
|
+ unsigned int max_fragment_size, num_fragments;
|
|
int ret;
|
|
|
|
/* To avoid merge and refragmentation at next-hops we never send
|
|
@@ -464,10 +464,15 @@ int batadv_frag_send_packet(struct sk_buff *skb,
|
|
*/
|
|
mtu = min_t(unsigned int, mtu, BATADV_FRAG_MAX_FRAG_SIZE);
|
|
max_fragment_size = mtu - header_size;
|
|
- max_packet_size = max_fragment_size * BATADV_FRAG_MAX_FRAGMENTS;
|
|
+
|
|
+ if (skb->len == 0 || max_fragment_size == 0)
|
|
+ return -EINVAL;
|
|
+
|
|
+ num_fragments = (skb->len - 1) / max_fragment_size + 1;
|
|
+ max_fragment_size = (skb->len - 1) / num_fragments + 1;
|
|
|
|
/* Don't even try to fragment, if we need more than 16 fragments */
|
|
- if (skb->len > max_packet_size) {
|
|
+ if (num_fragments > BATADV_FRAG_MAX_FRAGMENTS) {
|
|
ret = -EAGAIN;
|
|
goto free_skb;
|
|
}
|
|
@@ -507,7 +512,8 @@ int batadv_frag_send_packet(struct sk_buff *skb,
|
|
goto put_primary_if;
|
|
}
|
|
|
|
- skb_fragment = batadv_frag_create(skb, &frag_header, mtu);
|
|
+ skb_fragment = batadv_frag_create(skb, &frag_header,
|
|
+ max_fragment_size);
|
|
if (!skb_fragment) {
|
|
ret = -ENOMEM;
|
|
goto put_primary_if;
|