Skip to contentSkip to conversation

batman adv unicast fragmentation (version 4)

B.A.T.M.A.N. In review Andreas Langer 5 participants 11 messages Jul 6, 2010 – Jul 7, 2010

lore
Share & tools
lore
#0 lore raw

Hi,
i changed the packet type to the old order and add fragmented at the end. So that other programs not need to be adjusted.

regards,
andreas

#1 lore raw

PATCH 1/2 batctl: layer2 unicast packet fragmentation

This patch add options to enable/disable fragmentation

Signed-off-by Andreas Langer <an.langer at gmx.de>
---
 batctl/main.c |   41 +++++++++++++++++++++++------------------
 batctl/sys.c  |    7 +++++++
 batctl/sys.h  |    2 ++
 3 files changed, 32 insertions(+), 18 deletions(-)
batctl/main.c +23 -18
index 0506dce..1ee4279 100644
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
  *
- * Andreas Langer <[email protected]>, Marek Lindner <[email protected]>
+ * Andreas Langer <[email protected]>, Marek Lindner <[email protected]>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of version 2 of the GNU General Public
@@ -41,24 +41,25 @@
 void print_usage(void) {
 	printf("Usage: batctl [options] commands \n");
 	printf("commands:\n");
-	printf(" \tinterface|if   [add|del iface(s)]\tdisplay or modify the interface settings\n");
-	printf(" \toriginators|o                    \tdisplay the originator table\n");
-	printf(" \tinterval|it    [orig_interval]   \tdisplay or modify the originator interval (in ms)\n");
-	printf(" \tloglevel|ll    [level]           \tdisplay or modify the log level\n");
-	printf(" \tlog|l                            \tread the log produced by the kernel module\n");
-	printf(" \tgw_mode|gw     [mode]            \tdisplay or modify the gateway mode\n");
-	printf(" \tgateways|gwl                     \tdisplay the gateway server list\n");
-	printf(" \ttranslocal|tl                    \tdisplay the local translation table\n");
-	printf(" \ttransglobal|tg                   \tdisplay the global translation table\n");
-	printf(" \tvis_mode|vm    [mode]            \tdisplay or modify the status of the VIS server\n");
-	printf(" \tvis_data|vd    [dot|JSON]        \tdisplay the VIS data in dot or JSON format\n");
-	printf(" \taggregation|ag [0|1]             \tdisplay or modify the packet aggregation setting\n");
-	printf(" \tbonding|b      [0|1]             \tdisplay or modify the bonding mode setting\n");
+	printf(" \tinterface|if    [add|del iface(s)]\tdisplay or modify the interface settings\n");
+	printf(" \toriginators|o                     \tdisplay the originator table\n");
+	printf(" \tinterval|it     [orig_interval]   \tdisplay or modify the originator interval (in ms)\n");
+	printf(" \tloglevel|ll     [level]           \tdisplay or modify the log level\n");
+	printf(" \tlog|l                             \tread the log produced by the kernel module\n");
+	printf(" \tgw_mode|gw      [mode]            \tdisplay or modify the gateway mode\n");
+	printf(" \tgateways|gwl                      \tdisplay the gateway server list\n");
+	printf(" \ttranslocal|tl                     \tdisplay the local translation table\n");
+	printf(" \ttransglobal|tg                    \tdisplay the global translation table\n");
+	printf(" \tvis_mode|vm     [mode]            \tdisplay or modify the status of the VIS server\n");
+	printf(" \tvis_data|vd     [dot|JSON]        \tdisplay the VIS data in dot or JSON format\n");
+	printf(" \taggregation|ag  [0|1]             \tdisplay or modify the packet aggregation setting\n");
+	printf(" \tbonding|b       [0|1]             \tdisplay or modify the bonding mode setting\n");
+	printf(" \tfragmentation|f [0|1]             \tdisplay or modify the fragmentation mode setting\n");
 	printf("\n");
-	printf(" \tping|p         <destination>     \tping another batman adv host via layer 2\n");
-	printf(" \ttraceroute|tr  <destination>     \ttraceroute another batman adv host via layer 2\n");
-	printf(" \ttcpdump|td     <interface>       \ttcpdump layer 2 traffic on the given interface\n");
-	printf(" \tbisect         <file1> .. <fileN>\tanalyze given log files for routing stability\n");
+	printf(" \tping|p          <destination>     \tping another batman adv host via layer 2\n");
+	printf(" \ttraceroute|tr   <destination>     \ttraceroute another batman adv host via layer 2\n");
+	printf(" \ttcpdump|td      <interface>       \ttcpdump layer 2 traffic on the given interface\n");
+	printf(" \tbisect          <file1> .. <fileN>\tanalyze given log files for routing stability\n");
 	printf("options:\n");
 	printf(" \t-h print this help (or 'batctl <command> -h' for the command specific help)\n");
 	printf(" \t-v print version\n");
@@ -149,6 +150,10 @@ int main(int argc, char **argv)
 
 		ret = handle_sys_setting(argc - 1, argv + 1, SYS_BONDING, bonding_usage, sysfs_param_enable);
 
+	} else if ((strcmp(argv[1], "fragmentation") == 0) || (strcmp(argv[1], "f") == 0)) {
+
+		ret = handle_sys_setting(argc - 1, argv + 1, SYS_FRAG, fragmentation_usage, sysfs_param_enable);
+
 	} else if ((strcmp(argv[1], "bisect") == 0)) {
 
 		ret = bisect(argc - 1, argv + 1);
batctl/sys.c +7 -0
index 321dfc9..1fa59d8 100644
@@ -252,6 +252,13 @@ void orig_interval_usage(void)
 	printf(" \t -h print this help\n");
 }
 
+void fragmentation_usage(void)
+{
+	printf("Usage: batctl [options] fragmentation [0|1]\n");
+	printf("options:\n");
+	printf(" \t -h print this help\n");
+}
+
 int handle_sys_setting(int argc, char **argv,
 		       char *file_path, void setting_usage(void),
 		       const char *sysfs_param[])
batctl/sys.h +2 -0
index 7a1db03..7e0d52e 100644
@@ -31,12 +31,14 @@
 #define SYS_IFACE_PATH "/sys/class/net"
 #define SYS_MESH_IFACE_FMT SYS_IFACE_PATH"/%s/batman_adv/mesh_iface"
 #define SYS_IFACE_STATUS_FMT SYS_IFACE_PATH"/%s/batman_adv/iface_status"
+#define SYS_FRAG "fragmentation"
 
 extern const char *sysfs_param_enable[];
 extern const char *sysfs_param_server[];
 
 void aggregation_usage(void);
 void bonding_usage(void);
+void fragmentation_usage(void);
 void gw_mode_usage(void);
 void vis_mode_usage(void);
 void orig_interval_usage(void);
Signature · 1 line
1.7.0.4
#2 lore raw

PATCH 2/2 batman-adv: layer2 unicast packet fragmentation

In reply to Andreas Langer

This patch implements a simple layer2 fragmentation to allow traffic exchange over network interfaces with a MTU smaller than 1500 bytes. The fragmentation splits the big packets into two parts and marks the frames accordingly. The receiving end buffers the packets to reassemble the orignal packet before passing it to the higher layers. This feature makes it necessary to modify the batman-adv encapsulation for unicast packets by adding a sequence number, flags and the originator address. This modifcation is part of a seperate packet type for fragemented packets to keep the original overhead as low as possible. This patch enables the feature by default to ensure the data traffic can travel through the network. But it also prints a warning to notify the user about the performance implications.

Note: Fragmentation should be avoided at all costs since it has a dramatic impact on the performance, especially when it comes wifi networks. Instead of a single packet, 2 packets have to be sent! Not only valuable airtime is wasted but also packetloss decreases the throughput. A link with 50% packetloss and fragmentation enabled is pretty much unusable.

Signed-off-by Andreas Langer <an.langer at gmx.de>
---
 batman-adv/Makefile.kbuild  |    2 +-
 batman-adv/bat_sysfs.c      |   55 ++++++++++++++++
 batman-adv/fragmentation.c  |  152 +++++++++++++++++++++++++++++++++++++++++++
 batman-adv/fragmentation.h  |   34 ++++++++++
 batman-adv/hard-interface.c |   34 +++++++++-
 batman-adv/originator.c     |   10 +++
 batman-adv/packet.h         |   26 ++++++--
 batman-adv/routing.c        |  144 ++++++++++++++++++++++++++++++++---------
 batman-adv/routing.h        |    1 +
 batman-adv/soft-interface.c |   76 ++++++++++++++++++----
 batman-adv/types.h          |   10 +++
 11 files changed, 493 insertions(+), 51 deletions(-)
 create mode 100644 batman-adv/fragmentation.c
 create mode 100644 batman-adv/fragmentation.h
batman-adv/Makefile.kbuild +1 -1
index 762ee4e..3e99ba5 100644
@@ -32,4 +32,4 @@ EXTRA_CFLAGS += -DREVISION_VERSION=\"$(REVISION)\"
 endif
 
 obj-m += batman-adv.o
-batman-adv-objs := main.o bat_debugfs.o bat_sysfs.o send.o routing.o soft-interface.o icmp_socket.o translation-table.o bitarray.o hash.o ring_buffer.o vis.o hard-interface.o aggregation.o originator.o gateway_common.o gateway_client.o $(shell [ "2" -eq "$(VERSION)" ] 2>&- && [ "6" -eq "$(PATCHLEVEL)" ] 2>&- && [ "$(SUBLEVEL)" -le "28" ] 2>&- && echo bat_printk.o)
+batman-adv-objs := main.o bat_debugfs.o bat_sysfs.o send.o routing.o soft-interface.o icmp_socket.o translation-table.o bitarray.o hash.o ring_buffer.o vis.o hard-interface.o aggregation.o originator.o gateway_common.o gateway_client.o fragmentation.o $(shell [ "2" -eq "$(VERSION)" ] 2>&- && [ "6" -eq "$(PATCHLEVEL)" ] 2>&- && [ "$(SUBLEVEL)" -le "28" ] 2>&- && echo bat_printk.o)
batman-adv/bat_sysfs.c +55 -0

79 lines not on this page · raw message

batman-adv/fragmentation.c new file +152 -0

152 lines not on this page · raw message

batman-adv/fragmentation.h new file +34 -0
new file mode 100644
index 0000000..09011b3
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2010 B.A.T.M.A.N. contributors:
+ *
+ * Andreas Langer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ */
+
+#define FRAG_TIMEOUT 60000	/* purge frag list entrys after time in ms */
+#define FRAG_BUFFER_SIZE 6	/* number of list elements in buffer */
+#define FRAG_MAX_SEQ 65535
+
+struct sk_buff *merge_frag_packet(struct list_head *head,
+	struct frag_packet_list_entry *tfp,
+	struct sk_buff *skb);
+
+void create_frag_entry(struct list_head *head, struct sk_buff *skb);
+void create_frag_buffer(struct list_head *head);
+struct frag_packet_list_entry *search_frag_packet(struct list_head *head,
+	struct unicast_frag_packet *up);
+void frag_list_free(struct list_head *head);
batman-adv/hard-interface.c +33 -1
index 5ff9dcb..87c84c1 100644
@@ -166,6 +166,11 @@ int hardif_min_mtu(void)
 	/* allow big frames if all devices are capable to do so
 	 * (have MTU > 1500 + BAT_HEADER_LEN) */
 	int min_mtu = ETH_DATA_LEN;
+	/* FIXME: each batman_if will be attached to a softif */
+	struct bat_priv *bat_priv = netdev_priv(soft_device);
+
+	if (atomic_read(&bat_priv->frag_enabled))
+		goto out;
 
 	rcu_read_lock();
 	list_for_each_entry_rcu(batman_if, &if_list, list) {
@@ -175,7 +180,7 @@ int hardif_min_mtu(void)
 				      min_mtu);
 	}
 	rcu_read_unlock();
-
+out:
 	return min_mtu;
 }
 
@@ -265,8 +270,30 @@ int hardif_enable_interface(struct batman_if *batman_if)
 	orig_hash_add_if(batman_if, bat_priv->num_ifaces);
 
 	atomic_set(&batman_if->seqno, 1);
+	atomic_set(&batman_if->frag_seqno, 1);
 	bat_info(soft_device, "Adding interface: %s\n", batman_if->dev);
 
+	if (atomic_read(&bat_priv->frag_enabled) && batman_if->net_dev->mtu <
+		ETH_DATA_LEN + BAT_HEADER_LEN)
+		bat_info(soft_device,
+			"The MTU of interface %s is too small (%zi) to handle "
+			"the transport of batman-adv packets. Packets going "
+			"over this interface will be fragmented on layer2 "
+			"which could impact the performance. Setting the MTU "
+			"to %zi would solve the problem.\n",
+			batman_if->dev, ETH_DATA_LEN + BAT_HEADER_LEN,
+			ETH_DATA_LEN + BAT_HEADER_LEN);
+
+	if (!atomic_read(&bat_priv->frag_enabled) && batman_if->net_dev->mtu <
+		ETH_DATA_LEN + BAT_HEADER_LEN)
+		bat_info(soft_device,
+			"The MTU of interface %s is too small (%zi) to handle "
+			"the transport of batman-adv packets. If you experience"
+			" problems getting traffic through try increasing the "
+			"MTU to %zi.\n",
+			batman_if->dev, ETH_DATA_LEN + BAT_HEADER_LEN,
+			ETH_DATA_LEN + BAT_HEADER_LEN);
+
 	if (hardif_is_iface_up(batman_if))
 		hardif_activate_interface(soft_device, bat_priv, batman_if);
 	else
@@ -514,6 +541,11 @@ int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
 		ret = recv_unicast_packet(skb, batman_if);
 		break;
 
+		/* fragmented unicast packet */
+	case BAT_UNICAST_FRAG:
+		ret = recv_ucast_frag_packet(skb, batman_if);
+		break;
+
 		/* broadcast packet */
 	case BAT_BCAST:
 		ret = recv_bcast_packet(skb);
batman-adv/originator.c +10 -0
index 5343ab2..66852ea 100644
@@ -29,6 +29,7 @@
 #include "compat.h"
 #include "gateway_client.h"
 #include "hard-interface.h"
+#include "fragmentation.h"
 
 static DECLARE_DELAYED_WORK(purge_orig_wq, purge_orig);
 
@@ -97,6 +98,7 @@ static void free_orig_node(void *data)
 		kfree(neigh_node);
 	}
 
+	frag_list_free(&orig_node->frag_list);
 	hna_global_del_orig(orig_node, "originator timed out");
 
 	kfree(orig_node->bcast_own);
@@ -159,6 +161,10 @@ struct orig_node *get_orig_node(uint8_t *addr)
 
 	size = bat_priv->num_ifaces * sizeof(uint8_t);
 	orig_node->bcast_own_sum = kzalloc(size, GFP_ATOMIC);
+
+	INIT_LIST_HEAD(&orig_node->frag_list);
+	orig_node->last_frag_packet = 0;
+
 	if (!orig_node->bcast_own_sum)
 		goto free_bcast_own;
 
@@ -275,6 +281,10 @@ void purge_orig(struct work_struct *work)
 			hash_remove_bucket(orig_hash, &hashit);
 			free_orig_node(orig_node);
 		}
+
+		if (time_after(jiffies, (orig_node->last_frag_packet +
+			msecs_to_jiffies(FRAG_TIMEOUT))))
+			frag_list_free(&orig_node->frag_list);
 	}
 
 	spin_unlock_irqrestore(&orig_hash_lock, flags);
batman-adv/packet.h +20 -6
index e94960d..87e652e 100644
@@ -24,14 +24,15 @@
 
 #define ETH_P_BATMAN  0x4305	/* unofficial/not registered Ethertype */
 
-#define BAT_PACKET    0x01
-#define BAT_ICMP      0x02
-#define BAT_UNICAST   0x03
-#define BAT_BCAST     0x04
-#define BAT_VIS       0x05
+#define BAT_PACKET       0x01
+#define BAT_ICMP         0x02
+#define BAT_UNICAST      0x03
+#define BAT_BCAST        0x04
+#define BAT_VIS          0x05
+#define BAT_UNICAST_FRAG 0x06
 
 /* this file is included by batctl which needs these defines */
-#define COMPAT_VERSION 10
+#define COMPAT_VERSION 12
 #define DIRECTLINK 0x40
 #define VIS_SERVER 0x20
 #define PRIMARIES_FIRST_HOP 0x10
@@ -47,6 +48,9 @@
 #define VIS_TYPE_SERVER_SYNC		0
 #define VIS_TYPE_CLIENT_UPDATE		1
 
+/* fragmentation defines */
+#define UNI_FRAG_HEAD 0x01
+
 struct batman_packet {
 	uint8_t  packet_type;
 	uint8_t  version;  /* batman version field */
@@ -98,6 +102,16 @@ struct unicast_packet {
 	uint8_t  ttl;
 } __attribute__((packed));
 
+struct unicast_frag_packet {
+	uint8_t  packet_type;
+	uint8_t  version;  /* batman version field */
+	uint8_t  dest[6];
+	uint8_t  ttl;
+	uint8_t  flags;
+	uint8_t  orig[6];
+	uint16_t seqno;
+} __attribute__((packed));
+
 struct bcast_packet {
 	uint8_t  packet_type;
 	uint8_t  version;  /* batman version field */
batman-adv/routing.c +113 -31

175 lines not on this page · raw message

batman-adv/routing.h +1 -0
index 3eac64e..81c684f 100644
@@ -34,6 +34,7 @@ void update_routes(struct orig_node *orig_node,
 				unsigned char *hna_buff, int hna_buff_len);
 int recv_icmp_packet(struct sk_buff *skb);
 int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if);
+int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if);
 int recv_bcast_packet(struct sk_buff *skb);
 int recv_vis_packet(struct sk_buff *skb);
 int recv_bat_packet(struct sk_buff *skb,
batman-adv/soft-interface.c +64 -12

112 lines not on this page · raw message

batman-adv/types.h +10 -0
index 9cd19b7..e3c4d2d 100644
@@ -41,6 +41,7 @@ struct batman_if {
 	char addr_str[ETH_STR_LEN];
 	struct net_device *net_dev;
 	atomic_t seqno;
+	atomic_t frag_seqno;
 	unsigned char *packet_buff;
 	int packet_len;
 	struct kobject *hardif_obj;
@@ -82,6 +83,8 @@ struct orig_node {
 	TYPE_OF_WORD bcast_bits[NUM_WORDS];
 	uint32_t last_bcast_seqno;
 	struct list_head neigh_list;
+	struct list_head frag_list;
+	unsigned long last_frag_packet;
 	struct {
 		uint8_t candidates;
 		struct neigh_node *selected;
@@ -118,6 +121,7 @@ struct bat_priv {
 	struct net_device_stats stats;
 	atomic_t aggregation_enabled;
 	atomic_t bonding_enabled;
+	atomic_t frag_enabled;
 	atomic_t vis_mode;
 	atomic_t gw_mode;
 	atomic_t gw_class;
@@ -192,4 +196,10 @@ struct debug_log {
 	wait_queue_head_t queue_wait;
 };
 
+struct frag_packet_list_entry {
+	struct list_head list;
+	uint16_t seqno;
+	struct sk_buff *skb;
+};
+
 #endif /* _NET_BATMAN_ADV_TYPES_H_ */
Signature · 1 line
1.7.0.4
#3 lore raw

Re: [B.A.T.M.A.N.] [PATCH 2/2] batman-adv: layer2 unicast packet fragmentation

batman-adv/fragmentation.c line 105

Quoted 13 lines
batman-adv/fragmentation.c new file +13 -0
+struct frag_packet_list_entry *search_frag_packet(struct list_head *head,
+	struct unicast_frag_packet *up) {
+
+	struct frag_packet_list_entry *tfp;
+	struct unicast_frag_packet *tmp_up = NULL;
+
+	list_for_each_entry(tfp, head, list) {
+
+		if (!tfp->skb)
+			continue;
+
+		if (tfp->seqno == ntohs(up->seqno))
+			goto mov_tail;

Please could you explain this last bit? If we have received a retransmit we move it to the tail of the list?

Quoted 10 lines
batman-adv/fragmentation.c new file +10 -0
+
+		tmp_up = (struct unicast_frag_packet *) tfp->skb->data;
+
+		if (up->flags & UNI_FRAG_HEAD) {
+
+			if (tfp->seqno == ntohs(up->seqno)+1) {
+				if (tmp_up->flags & UNI_FRAG_HEAD)
+					goto mov_tail;
+				else
+					goto ret_tfp;

batman-adv/fragmentation.c line 125

Quoted 10 lines
batman-adv/fragmentation.c new file +10 -0
+			}
+		} else {
+
+			if (tfp->seqno == ntohs(up->seqno)-1) {
+				if (tmp_up->flags & UNI_FRAG_HEAD)
+					goto ret_tfp;
+				else
+					goto mov_tail;
+			}
+		}

How about simplifying this loop a little. Not tested, probably broken, but i hope expresses the idea:

	if (up->flags & UNI_FRAG_HEAD) {
	      search_seqno = ntohs(up->seqno)+1
	} else {
	      search_seqno = ntohs(up->seqno)-1
	}
    
	list_for_each_entry(tfp, head, list) {
		if (!tfp->skb)
			continue;
		
		/* Found the other fragment? */
		if (tfp->seqno == search_seqno)
		    /* Head and a tail? */
		    if ((tmp_up->flags & UNI_FRAG_HEAD) != 
 		        (tfp->flags & UNI_FRAG_HEAD)
		       return tfp;
		    } else {
		      /* Two heads or tails. Move to tail of list so it will 
		         get recycled */
		      list_move_tail(&tfp->list, head);
		      return NULL;
                    }
        }
	return NULL;

Moving the ntohs() out of the loop should save a few cycles and it is hopefully a little bit more readable.

batman-adv/fragmentation.c line 134

Quoted 9 lines
batman-adv/fragmentation.c new file +9 -0
+	}
+	goto ret_null;
+
+ret_tfp:
+	return tfp;
+mov_tail:
+	list_move_tail(&tfp->list, head);
+ret_null:
+	return NULL;

Assuming you don't like my re-write, could we remove ret_tfp and ret_null. I don't think they aid the understandability of the code. They are just return statements.

batman-adv/fragmentation.c line 146

Quoted 12 lines
batman-adv/fragmentation.c new file +12 -0
+}
+
+void frag_list_free(struct list_head *head)
+{
+
+	struct frag_packet_list_entry *pf, *tmp_pf;
+
+	if (!list_empty(head)) {
+
+		list_for_each_entry_safe(pf, tmp_pf, head, list) {
+			if (pf->skb)
+				kfree_skb(pf->skb);

kfree_skb() is happy to take a NULL pointer. So there is no need to do the comparison here. It will get repeated inside kfree_skb(). This happens in a few places.

Quoted 59 lines
batman-adv/routing.c +57 -0
+			list_del(&pf->list);
+			kfree(pf);
+		}
+	}
+	return;
 
 
+int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if)
+{
+	struct unicast_packet *unicast_packet;
+	struct ethhdr *ethhdr;
+	int hdr_size = sizeof(struct unicast_packet);
+
+	/* drop packet if it has not necessary minimum size */
+	if (skb_headlen(skb) < hdr_size)
+		return NET_RX_DROP;
+
+	ethhdr = (struct ethhdr *) skb_mac_header(skb);
+
+	/* packet with unicast indication but broadcast recipient */
+	if (is_bcast(ethhdr->h_dest))
+		return NET_RX_DROP;
+
+	/* packet with broadcast sender address */
+	if (is_bcast(ethhdr->h_source))
+		return NET_RX_DROP;
+
+	/* not for me */
+	if (!is_my_mac(ethhdr->h_dest))
+		return NET_RX_DROP;
+
+	unicast_packet = (struct unicast_packet *) skb->data;
+
+	/* packet for me */
+	if (is_my_mac(unicast_packet->dest)) {
+		interface_rx(skb, hdr_size);
+		return NET_RX_SUCCESS;
+	}
+
+	return route_unicast_packet(skb, recv_if, hdr_size);
+}
+
+int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if)
+{
+	struct unicast_frag_packet *unicast_packet;
+	struct orig_node *orig_node;
+	struct ethhdr *ethhdr;
+	struct frag_packet_list_entry *tmp_frag_entry;
+	int hdr_size = sizeof(struct unicast_frag_packet);
+	unsigned long flags;
+
+	/* drop packet if it has not necessary minimum size */
+	if (skb_headlen(skb) < hdr_size)
+		return NET_RX_DROP;
+
+	ethhdr = (struct ethhdr *) skb_mac_header(skb);
+
+	/* packet with unicast indication but broadcast recipient */
+	if (is_bcast(ethhdr->h_dest))

batman-adv/routing.c int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) · line 1231

Quoted 10 lines
batman-adv/routing.c +10 -0
+		return NET_RX_DROP;
+
+	/* packet with broadcast sender address */
+	if (is_bcast(ethhdr->h_source))
+		return NET_RX_DROP;
+
+	/* not for me */
+	if (!is_my_mac(ethhdr->h_dest))
+		return NET_RX_DROP;
+

There is some code here which is identical to recv_unicast_packet(). Could it be refactored into a helper function?

Andrew

#4 lore raw

Re: [B.A.T.M.A.N.] [PATCH 2/2] batman-adv: layer2 unicast packet fragmentation

Hi Andrew, answers see below

Quoted 8 lines
Quoted 8 lines
batman-adv/fragmentation.c new file +8 -0
+struct frag_packet_list_entry *search_frag_packet(struct list_head *head,
+	struct unicast_frag_packet *up) {
+
+	struct frag_packet_list_entry *tfp;
+	struct unicast_frag_packet *tmp_up = NULL;
+
+	list_for_each_entry(tfp, head, list) {
+
Quoted 8 lines

batman-adv/fragmentation.c line 105

Quoted 5 lines
batman-adv/fragmentation.c new file +5 -0
+		if (!tfp->skb)
+			continue;
+
+		if (tfp->seqno == ntohs(up->seqno))
+			goto mov_tail;

Please could you explain this last bit? If we have received a retransmit we move it to the tail of the list?

If we receive a packet with the same seqno we move the list entry to the tail then return null.

	tmp_frag_entry =
			search_frag_packet(&orig_node->frag_list,
			unicast_packet);

	if (!tmp_frag_entry) {
		create_frag_entry(&orig_node->frag_list, skb);

In routing.c it creates now a new entry, create_frag_entry takes the last list entry. So the old packet with the same seqno will be now overwritten. I hope it is clear, do you see any problems with this ?

Quoted 49 lines
Quoted 10 lines
batman-adv/fragmentation.c new file +10 -0
+
+		tmp_up = (struct unicast_frag_packet *) tfp->skb->data;
+
+		if (up->flags & UNI_FRAG_HEAD) {
+
+			if (tfp->seqno == ntohs(up->seqno)+1) {
+				if (tmp_up->flags & UNI_FRAG_HEAD)
+					goto mov_tail;
+				else
+					goto ret_tfp;

batman-adv/fragmentation.c line 125

Quoted 10 lines
batman-adv/fragmentation.c new file +10 -0
+			}
+		} else {
+
+			if (tfp->seqno == ntohs(up->seqno)-1) {
+				if (tmp_up->flags & UNI_FRAG_HEAD)
+					goto ret_tfp;
+				else
+					goto mov_tail;
+			}
+		}

How about simplifying this loop a little. Not tested, probably broken, but i hope expresses the idea:

	if (up->flags & UNI_FRAG_HEAD) {
	      search_seqno = ntohs(up->seqno)+1
	} else {
	      search_seqno = ntohs(up->seqno)-1
	}
    
	list_for_each_entry(tfp, head, list) {
		if (!tfp->skb)
			continue;
		
		/* Found the other fragment? */
		if (tfp->seqno == search_seqno)
		    /* Head and a tail? */
		    if ((tmp_up->flags & UNI_FRAG_HEAD) != 
 		        (tfp->flags & UNI_FRAG_HEAD)
		       return tfp;
		    } else {
		      /* Two heads or tails. Move to tail of list so it will 
		         get recycled */
		      list_move_tail(&tfp->list, head);
		      return NULL;
                    }
        }
	return NULL;
Quoted 2 lines

Moving the ntohs() out of the loop should save a few cycles and it is hopefully a little bit more readable.

Thanks for the hint, it is more comprehensible.

Quoted 14 lines

batman-adv/fragmentation.c line 134

Quoted 10 lines
batman-adv/fragmentation.c new file +9 -0
+	}
+	goto ret_null;
+
+ret_tfp:
+	return tfp;
+mov_tail:
+	list_move_tail(&tfp->list, head);
+ret_null:
+	return NULL;

Assuming you don't like my re-write, could we remove ret_tfp and ret_null. I don't think they aid the understandability of the code. They are just return statements.

I like your re-write.

Quoted 8 lines
Quoted 8 lines
batman-adv/fragmentation.c new file +8 -0
+}
+
+void frag_list_free(struct list_head *head)
+{
+
+	struct frag_packet_list_entry *pf, *tmp_pf;
+
+	if (!list_empty(head)) {
Quoted 8 lines

batman-adv/fragmentation.c line 146

Quoted 4 lines
batman-adv/fragmentation.c new file +4 -0
+
+		list_for_each_entry_safe(pf, tmp_pf, head, list) {
+			if (pf->skb)
+				kfree_skb(pf->skb);

kfree_skb() is happy to take a NULL pointer. So there is no need to do the comparison here. It will get repeated inside kfree_skb(). This happens in a few places.

Thanks for the hint.

Quoted 64 lines
Quoted 64 lines
batman-adv/routing.c +62 -0
+			list_del(&pf->list);
+			kfree(pf);
+		}
+	}
+	return;
 
 
+int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if)
+{
+	struct unicast_packet *unicast_packet;
+	struct ethhdr *ethhdr;
+	int hdr_size = sizeof(struct unicast_packet);
+
+	/* drop packet if it has not necessary minimum size */
+	if (skb_headlen(skb) < hdr_size)
+		return NET_RX_DROP;
+
+	ethhdr = (struct ethhdr *) skb_mac_header(skb);
+
+	/* packet with unicast indication but broadcast recipient */
+	if (is_bcast(ethhdr->h_dest))
+		return NET_RX_DROP;
+
+	/* packet with broadcast sender address */
+	if (is_bcast(ethhdr->h_source))
+		return NET_RX_DROP;
+
+	/* not for me */
+	if (!is_my_mac(ethhdr->h_dest))
+		return NET_RX_DROP;
+
+	unicast_packet = (struct unicast_packet *) skb->data;
+
+	/* packet for me */
+	if (is_my_mac(unicast_packet->dest)) {
+		interface_rx(skb, hdr_size);
+		return NET_RX_SUCCESS;
+	}
+
+	return route_unicast_packet(skb, recv_if, hdr_size);
+}
+
+int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if)
+{
+	struct unicast_frag_packet *unicast_packet;
+	struct orig_node *orig_node;
+	struct ethhdr *ethhdr;
+	struct frag_packet_list_entry *tmp_frag_entry;
+	int hdr_size = sizeof(struct unicast_frag_packet);
+	unsigned long flags;
+
+	/* drop packet if it has not necessary minimum size */
+	if (skb_headlen(skb) < hdr_size)
+		return NET_RX_DROP;
+
+	ethhdr = (struct ethhdr *) skb_mac_header(skb);
+
+	/* packet with unicast indication but broadcast recipient */
+	if (is_bcast(ethhdr->h_dest))
+		return NET_RX_DROP;
+
+	/* packet with broadcast sender address */
+	if (is_bcast(ethhdr->h_source))
+		return NET_RX_DROP;
Quoted 8 lines

batman-adv/routing.c int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) · line 1193

Quoted 5 lines
batman-adv/routing.c +5 -0
+
+	/* not for me */
+	if (!is_my_mac(ethhdr->h_dest))
+		return NET_RX_DROP;
+

There is some code here which is identical to recv_unicast_packet(). Could it be refactored into a helper function?

Yes it could, i already thought about it.

Quoted 2 lines

Andrew

Thanks again, i will send a new patch.

regards,
Andreas

#5 lore raw

Re: [B.A.T.M.A.N.] [PATCH 2/2] batman-adv: layer2 unicast packet fragmentation

In reply to Andreas Langer

Hi all, Hi Andreas,

Quoted 2 lines

+#define FRAG_TIMEOUT 60000 /* purge frag list entrys after time in
ms */

Why did you choose a so large timeout? Is there a particular reason for that?

I think that in 60 seconds an host could receive a very large amount of "orphan" packets in case of a bad link causing memory problems.

Could 5000/10000 be a better value?

Regards,

Signature · 4 lines
Antonio Quartulli

..each of us alone is worth nothing..
Ernesto "Che" Guevara
#6 lore raw

Re: [B.A.T.M.A.N.] [PATCH 2/2] batman-adv: layer2 unicast packet fragmentation

Hi Antonio,
thanks for the question. The timeout came up to my mind just in that moment. I don't know if 5000/10000 be a better value, has somebody else an opinion regarding that matter ?

regards,
Andreas

Quoted 16 lines

Hi all, Hi Andreas,

Quoted 2 lines

+#define FRAG_TIMEOUT 60000 /* purge frag list entrys after time in
ms */

Why did you choose a so large timeout? Is there a particular reason for that?

I think that in 60 seconds an host could receive a very large amount of "orphan" packets in case of a bad link causing memory problems.

Could 5000/10000 be a better value?

Regards,

#7 lore raw

Re: [B.A.T.M.A.N.] [PATCH 2/2] batman-adv: layer2 unicast packet fragmentation

In reply to Antonio Quartulli
Quoted 10 lines · Antonio Quartulli

Hi all, Hi Andreas,

Quoted 2 lines

+#define FRAG_TIMEOUT 60000 /* purge frag list entrys after time in
ms */

Why did you choose a so large timeout? Is there a particular reason for that?

I think that in 60 seconds an host could receive a very large amount of "orphan" packets in case of a bad link causing memory problems.

It will not cause memory problems. The linked list is limited to FRAG_BUFFER_SIZE (6) segments.

Andrew

#8 lore raw

Re: [B.A.T.M.A.N.] [PATCH 2/2] batman-adv: layer2 unicast packet fragmentation

Quoted 6 lines · Andrew Lunn
Quoted 5 lines · Antonio Quartulli

Hi all, Hi Andreas,

Quoted 2 lines

+#define FRAG_TIMEOUT 60000 /* purge frag list entrys after time in
ms */

Quoted 8 lines
Quoted 5 lines

Why did you choose a so large timeout? Is there a particular reason for that?

I think that in 60 seconds an host could receive a very large amount of "orphan" packets in case of a bad link causing memory problems.

It will not cause memory problems. The linked list is limited to FRAG_BUFFER_SIZE (6) segments.

He didn't say that it will take all available system memory. There is still the problem that the 6 slots per originator (so the memory per originator) could be full when we have a bad link and a too big waiting time for missing fragments.

Best regards,
Sven

#9 lore raw

Re: [B.A.T.M.A.N.] [PATCH 2/2] batman-adv: layer2 unicast packet fragmentation

Quoted 4 lines · On Tuesday, July 06, 2010 21:13:11 Sven Eckelmann wrote:

He didn't say that it will take all available system memory. There is still the problem that the 6 slots per originator (so the memory per originator) could be full when we have a bad link and a too big waiting time for missing fragments.

I also think the timeout could be a bit smaller but just to make sure we all agree on one thing: The fragmentation should never be used over lossy links.

Imagine we have a link with 50% packet loss and fragmentation enabled which makes out of every packet 2 packets. Now, we have a pretty high probability that one of these 2 packets gets lost during transit. Therefore batman-adv can not reassemble the packet on the other side which will lead to a retransmission that has the same chance of success as the previous packet ...

Regards,
Marek

#10 lore raw

Re: [B.A.T.M.A.N.] [PATCH 2/2] batman-adv: layer2 unicast packet fragmentation

In reply to Andreas Langer

batman-adv/hard-interface.c int hardif_enable_interface(struct batman_if *batman_if) · line 285

Quoted 10 lines · On Tuesday, July 06, 2010 17:59:20 Andreas Langer wrote:

+ if (atomic_read(&bat_priv->frag_enabled) && batman_if->net_dev->mtu
< + ETH_DATA_LEN + BAT_HEADER_LEN)

batman-adv/hard-interface.c +8 -0
+               bat_info(soft_device,
+               "The MTU of interface %s is too small (%zi) to handle "
+               "the transport of batman-adv packets. Packets going "
+               "over this interface will be fragmented on layer2 "
+               "which could impact the performance. Setting the MTU "
+               "to %zi would solve the problem.\n",
+                batman_if->dev, ETH_DATA_LEN + BAT_HEADER_LEN,
+                ETH_DATA_LEN + BAT_HEADER_LEN);

The required MTU gets printed twice here. I guess you wanted to print this:
batman_if->dev, batman_if->net_dev->mtu,
ETH_DATA_LEN + BAT_HEADER_LEN

batman-adv/hard-interface.c int hardif_enable_interface(struct batman_if *batman_if) · line 295

Quoted 9 lines

+ if (!atomic_read(&bat_priv->frag_enabled) &&
batman_if->net_dev->mtu < + ETH_DATA_LEN + BAT_HEADER_LEN)

batman-adv/hard-interface.c +7 -0
+               bat_info(soft_device,
+               "The MTU of interface %s is too small (%zi) to handle "
+               "the transport of batman-adv packets. If you experience"
+               " problems getting traffic through try increasing the "
+                "MTU to %zi.\n",
+                batman_if->dev, ETH_DATA_LEN + BAT_HEADER_LEN,
+                ETH_DATA_LEN + BAT_HEADER_LEN);

Here we have the same issue.

Regards,
Marek