b.a.t.m.a.n.lists.open-mesh.org archive mirror
 help / color / mirror / Atom feed
* [B.A.T.M.A.N.] [RFC PATCH 0/6] batman-adv: broadcast packet aggregation
@ 2016-12-19 11:25 Linus Lüssing
  2016-12-19 11:25 ` [B.A.T.M.A.N.] [RFC PATCH 1/6] batman-adv: Allow TVLVs greater than 128 bytes Linus Lüssing
                   ` (6 more replies)
  0 siblings, 7 replies; 10+ messages in thread
From: Linus Lüssing @ 2016-12-19 11:25 UTC (permalink / raw)
  To: b.a.t.m.a.n

Hi,

Here is a first patchset to reintroduce aggregation support for BATMAN V, too.
And while at it, for BATMAN VI, VII... etc, as well - in fact, it allows
aggregating any batman packet with a broadcast destination ;).

I am sending it as an RFC for now as compat code is still missing. And although
it was tested in VMs, I still need to do some stress testing on some
embedded routers.

Regards, Linus

PS: Requires: "batman-adv: Introduce packet type independent TVLV handler API"
(1ddd189528fc, available on patchwork or linus/aggregation branch)


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [B.A.T.M.A.N.] [RFC PATCH 1/6] batman-adv: Allow TVLVs greater than 128 bytes
  2016-12-19 11:25 [B.A.T.M.A.N.] [RFC PATCH 0/6] batman-adv: broadcast packet aggregation Linus Lüssing
@ 2016-12-19 11:25 ` Linus Lüssing
  2016-12-19 11:25 ` [B.A.T.M.A.N.] [RFC PATCH 2/6] batman-adv: aggregation packet reception Linus Lüssing
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Linus Lüssing @ 2016-12-19 11:25 UTC (permalink / raw)
  To: b.a.t.m.a.n

The upcoming aggregation TVLVs will need to be able to hold larger
broadcast packets too.

For one thing this patch increases the according stack buffer to
256 bytes to be able to handle the most common broadcast packet cases
quickly.

For larger TVLVs, this patch will try to linearize skb data up to
and including the TVLV within the received packet.

Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
---
 net/batman-adv/bat_iv_ogm.c |  4 ++--
 net/batman-adv/bat_v_ogm.c  |  4 ++--
 net/batman-adv/tvlv.c       | 20 +++++++++++---------
 net/batman-adv/tvlv.h       |  4 ++--
 4 files changed, 17 insertions(+), 15 deletions(-)

diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
index 07bf38e..a1472ab 100644
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -1409,7 +1409,7 @@ out:
  * @if_outgoing: the interface for which the packet should be considered
  */
 static void
-batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset,
+batadv_iv_ogm_process_per_outif(struct sk_buff *skb, int ogm_offset,
 				struct batadv_orig_node *orig_node,
 				struct batadv_hard_iface *if_incoming,
 				struct batadv_hard_iface *if_outgoing)
@@ -1613,7 +1613,7 @@ out:
  * @ogm_offset: offset to the OGM which should be processed (for aggregates)
  * @if_incoming: the interface where this packet was receved
  */
-static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset,
+static void batadv_iv_ogm_process(struct sk_buff *skb, int ogm_offset,
 				  struct batadv_hard_iface *if_incoming)
 {
 	struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
diff --git a/net/batman-adv/bat_v_ogm.c b/net/batman-adv/bat_v_ogm.c
index 002f52a..b6a275d 100644
--- a/net/batman-adv/bat_v_ogm.c
+++ b/net/batman-adv/bat_v_ogm.c
@@ -606,7 +606,7 @@ out:
  */
 static void
 batadv_v_ogm_process_per_outif(struct batadv_priv *bat_priv,
-			       const struct sk_buff *skb,
+			       struct sk_buff *skb,
 			       const struct batadv_ogm2_packet *ogm2,
 			       struct batadv_orig_node *orig_node,
 			       struct batadv_neigh_node *neigh_node,
@@ -676,7 +676,7 @@ static bool batadv_v_ogm_aggr_packet(int buff_pos, int packet_len,
  * @ogm_offset: offset to the OGM which should be processed (for aggregates)
  * @if_incoming: the interface where this packet was receved
  */
-static void batadv_v_ogm_process(const struct sk_buff *skb, int ogm_offset,
+static void batadv_v_ogm_process(struct sk_buff *skb, int ogm_offset,
 				 struct batadv_hard_iface *if_incoming)
 {
 	struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
diff --git a/net/batman-adv/tvlv.c b/net/batman-adv/tvlv.c
index d432e16..c824d74 100644
--- a/net/batman-adv/tvlv.c
+++ b/net/batman-adv/tvlv.c
@@ -498,12 +498,12 @@ static void batadv_tvlv_call_unfound_handlers(struct batadv_priv *bat_priv,
  * any TVLV handler called successfully. Returns NET_RX_DROP otherwise.
  */
 int batadv_tvlv_containers_process2(struct batadv_priv *bat_priv,
-				    const struct sk_buff *skb, u8 packet_type,
+				    struct sk_buff *skb, u8 packet_type,
 				    unsigned int tvlv_offset,
 				    u16 tvlv_value_len, void *ctx)
 {
 	struct batadv_tvlv_hdr *tvlv_hdr, tvlv_hdr_buff;
-	u8 *tvlv_value, tvlv_value_buff[128];
+	u8 *tvlv_value, tvlv_value_buff[256];
 	u16 tvlv_value_cont_len;
 	int ret = NET_RX_SUCCESS;
 
@@ -518,14 +518,16 @@ int batadv_tvlv_containers_process2(struct batadv_priv *bat_priv,
 		tvlv_offset += sizeof(*tvlv_hdr);
 		tvlv_value_len -= sizeof(*tvlv_hdr);
 
-		if (tvlv_value_cont_len > sizeof(tvlv_value_buff)) {
-			pr_warn_once("batman-adv: TVLVs greater than 128 bytes unsupported for now, ignoring\n");
-			goto skip_handler_call;
-		}
-
 		if (tvlv_value_cont_len > tvlv_value_len)
 			return NET_RX_DROP;
 
+		/* check for sufficient space either in stack buffer or
+		 * in skb's linear data buffer
+		 */
+		if (tvlv_value_cont_len > sizeof(tvlv_value_buff) &&
+		    !pskb_may_pull(skb, tvlv_offset + tvlv_value_cont_len))
+			return NET_RX_DROP;
+
 		tvlv_value = skb_header_pointer(skb, tvlv_offset,
 						tvlv_value_cont_len,
 						tvlv_value_buff);
@@ -536,7 +538,7 @@ int batadv_tvlv_containers_process2(struct batadv_priv *bat_priv,
 						 tvlv_hdr->type,
 						 tvlv_hdr->version, tvlv_value,
 						 tvlv_value_cont_len, ctx);
-skip_handler_call:
+
 		tvlv_offset += tvlv_value_cont_len;
 		tvlv_value_len -= tvlv_value_cont_len;
 	}
@@ -656,7 +658,7 @@ struct batadv_orig_node *batadv_tvlv_ogm_unpack_ctx(void *ctx)
  * OGM header.
  */
 void batadv_tvlv_ogm_receive(struct batadv_priv *bat_priv,
-			     const struct sk_buff *skb,
+			     struct sk_buff *skb,
 			     struct batadv_orig_node *orig_node)
 {
 	void *ctx = batadv_tvlv_ogm_pack_ctx(orig_node);
diff --git a/net/batman-adv/tvlv.h b/net/batman-adv/tvlv.h
index 0d2d586..d8cdf6b 100644
--- a/net/batman-adv/tvlv.h
+++ b/net/batman-adv/tvlv.h
@@ -33,7 +33,7 @@ u16 batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv,
 void *batadv_tvlv_ogm_pack_ctx(struct batadv_orig_node *orig_node);
 struct batadv_orig_node *batadv_tvlv_ogm_unpack_ctx(void *ctx);
 void batadv_tvlv_ogm_receive(struct batadv_priv *bat_priv,
-			     const struct sk_buff *skb,
+			     struct sk_buff *skb,
 			     struct batadv_orig_node *orig_node);
 void batadv_tvlv_container_unregister(struct batadv_priv *bat_priv,
 				      u8 type, u8 version);
@@ -67,7 +67,7 @@ int batadv_tvlv_containers_process(struct batadv_priv *bat_priv,
 				   u8 *src, u8 *dst,
 				   void *tvlv_buff, u16 tvlv_buff_len);
 int batadv_tvlv_containers_process2(struct batadv_priv *bat_priv,
-				    const struct sk_buff *skb, u8 packet_type,
+				    struct sk_buff *skb, u8 packet_type,
 				    unsigned int tvlv_offset,
 				    u16 tvlv_value_len, void *ctx);
 void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, u8 *src,
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [B.A.T.M.A.N.] [RFC PATCH 2/6] batman-adv: aggregation packet reception
  2016-12-19 11:25 [B.A.T.M.A.N.] [RFC PATCH 0/6] batman-adv: broadcast packet aggregation Linus Lüssing
  2016-12-19 11:25 ` [B.A.T.M.A.N.] [RFC PATCH 1/6] batman-adv: Allow TVLVs greater than 128 bytes Linus Lüssing
@ 2016-12-19 11:25 ` Linus Lüssing
  2016-12-19 11:25 ` [B.A.T.M.A.N.] [RFC PATCH 3/6] batman-adv: aggregation packet queueing and transmission Linus Lüssing
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Linus Lüssing @ 2016-12-19 11:25 UTC (permalink / raw)
  To: b.a.t.m.a.n

This patch implements the de-aggregation and reception of
broadcast aggregation packets, which areintroduced through
the new BATADV_BCAST_AGGR packet type.

It enables us to receive aggregation packets consisting of any
batman packet type with a broadcast ethernet destination.

Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
---
 Makefile                        |   3 +
 gen-compat-autoconf.sh          |   1 +
 net/batman-adv/Makefile         |   1 +
 net/batman-adv/aggregation.c    | 194 ++++++++++++++++++++++++++++++++++++++++
 net/batman-adv/aggregation.h    |  66 ++++++++++++++
 net/batman-adv/main.c           |   9 ++
 net/batman-adv/packet.h         |  18 ++++
 net/batman-adv/routing.c        |  63 +++++++++++++
 net/batman-adv/routing.h        |   2 +
 net/batman-adv/soft-interface.c |   6 ++
 net/batman-adv/tvlv.c           |  13 ++-
 net/batman-adv/types.h          |  38 ++++++++
 12 files changed, 412 insertions(+), 2 deletions(-)
 create mode 100644 net/batman-adv/aggregation.c
 create mode 100644 net/batman-adv/aggregation.h

diff --git a/Makefile b/Makefile
index b852a17..5a34086 100644
--- a/Makefile
+++ b/Makefile
@@ -29,6 +29,8 @@ export CONFIG_BATMAN_ADV_DAT=y
 export CONFIG_BATMAN_ADV_NC=n
 # B.A.T.M.A.N. multicast optimizations:
 export CONFIG_BATMAN_ADV_MCAST=y
+# B.A.T.M.A.N. generic broadcast aggregation:
+export CONFIG_BATMAN_ADV_AGGR=y
 # B.A.T.M.A.N. V routing algorithm (experimental):
 export CONFIG_BATMAN_ADV_BATMAN_V=n
 
@@ -83,6 +85,7 @@ BUILD_FLAGS := \
 	CONFIG_BATMAN_ADV_DAT=$(CONFIG_BATMAN_ADV_DAT) \
 	CONFIG_BATMAN_ADV_NC=$(CONFIG_BATMAN_ADV_NC) \
 	CONFIG_BATMAN_ADV_MCAST=$(CONFIG_BATMAN_ADV_MCAST) \
+	CONFIG_BATMAN_ADV_AGGR=$(CONFIG_BATMAN_ADV_AGGR) \
 	CONFIG_BATMAN_ADV_BATMAN_V=$(CONFIG_BATMAN_ADV_BATMAN_V) \
 	INSTALL_MOD_DIR=updates/
 
diff --git a/gen-compat-autoconf.sh b/gen-compat-autoconf.sh
index cf36e55..c835a6d 100755
--- a/gen-compat-autoconf.sh
+++ b/gen-compat-autoconf.sh
@@ -41,6 +41,7 @@ gen_config 'CONFIG_BATMAN_ADV_DEBUG' ${CONFIG_BATMAN_ADV_DEBUG:="n"} >> "${TMP}"
 gen_config 'CONFIG_BATMAN_ADV_BLA' ${CONFIG_BATMAN_ADV_BLA:="y"} >> "${TMP}"
 gen_config 'CONFIG_BATMAN_ADV_DAT' ${CONFIG_BATMAN_ADV_DAT:="y"} >> "${TMP}"
 gen_config 'CONFIG_BATMAN_ADV_MCAST' ${CONFIG_BATMAN_ADV_MCAST:="y"} >> "${TMP}"
+gen_config 'CONFIG_BATMAN_ADV_AGGR' ${CONFIG_BATMAN_ADV_AGGR:="y"} >> "${TMP}"
 gen_config 'CONFIG_BATMAN_ADV_NC' ${CONFIG_BATMAN_ADV_NC:="n"} >> "${TMP}"
 gen_config 'CONFIG_BATMAN_ADV_BATMAN_V' ${CONFIG_BATMAN_ADV_BATMAN_V:="n"} >> "${TMP}"
 
diff --git a/net/batman-adv/Makefile b/net/batman-adv/Makefile
index f724d3c..78ddf57 100644
--- a/net/batman-adv/Makefile
+++ b/net/batman-adv/Makefile
@@ -17,6 +17,7 @@
 #
 
 obj-$(CONFIG_BATMAN_ADV) += batman-adv.o
+batman-adv-$(CONFIG_BATMAN_ADV_AGGR) += aggregation.o
 batman-adv-y += bat_algo.o
 batman-adv-y += bat_iv_ogm.o
 batman-adv-$(CONFIG_BATMAN_ADV_BATMAN_V) += bat_v.o
diff --git a/net/batman-adv/aggregation.c b/net/batman-adv/aggregation.c
new file mode 100644
index 0000000..2ee4dae
--- /dev/null
+++ b/net/batman-adv/aggregation.c
@@ -0,0 +1,194 @@
+/* Copyright (C) 2016  B.A.T.M.A.N. contributors:
+ *
+ * Linus Lüssing
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "aggregation.h"
+#include "main.h"
+
+#include <linux/etherdevice.h>
+#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include "tvlv.h"
+
+/**
+ * batadv_aggr_unpack_ctx - unpack context received with a TVLV handler call
+ * @ctx: handler specific context information
+ *  (here: recv_if, h_source and packet type of aggregate)
+ *
+ * This unpacks the context received within an aggregation TVLV handler, here
+ * the interface and source address of the neighbor this packet came from,
+ * as well as the packet type of the according aggregate.
+ *
+ * Return: An aggregation context regarding where the packet came from.
+ */
+static inline struct batadv_aggr_ctx *batadv_aggr_unpack_ctx(void *ctx)
+{
+	return (struct batadv_aggr_ctx *)ctx;
+}
+
+/**
+ * batadv_aggr_add_counter_rx - update aggregation rx statistics
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: the skb to count
+ *
+ * Updates statistics for received aggregation packets with the given skb.
+ */
+void batadv_aggr_add_counter_rx(struct batadv_priv *bat_priv,
+				struct sk_buff *skb)
+{
+	batadv_inc_counter(bat_priv, BATADV_CNT_AGGR_RX);
+	batadv_add_counter(bat_priv, BATADV_CNT_AGGR_RX_BYTES,
+			   skb->len + ETH_HLEN);
+}
+
+/**
+ * batadv_aggr_put_ethhdr - append a mac header to skb
+ * @skb: the packet to append to
+ * @h_source: the ethernet source address to set
+ *
+ * Appends a mac header to the given skb with the ethernet source address
+ * set to the provided h_source and the ethernet destination address to
+ * a broadcast one. Furthermore, sets the ethernet type to ETH_P_BATMAN.
+ *
+ * Also sets the skb mac header pointer to the beginning of the appended mac
+ * header.
+ */
+static void batadv_aggr_put_ethhdr(struct sk_buff *skb, unsigned char *h_source)
+{
+	struct ethhdr *ethhdr;
+
+	skb_reset_mac_header(skb);
+
+	ethhdr = (struct ethhdr *)skb_put(skb, ETH_HLEN);
+	ethhdr->h_proto = htons(ETH_P_BATMAN);
+	ether_addr_copy(ethhdr->h_source, h_source);
+	ether_addr_copy(ethhdr->h_dest, batadv_broadcast_addr);
+}
+
+/**
+ * batadv_aggr_put_batadv - append batman header and data to skb
+ * @skb: the packet to append to
+ * @data: the data to append after the batman header
+ * @data_len: the length of the data to append
+ * @packet_type: the packet type to set in the batman header
+ *
+ * First appends a batman header consisting of the given packet type and the
+ * compatibility version to the given skb. Then copies the given data behind
+ * this minimal batman header in the skb.
+ *
+ * Also sets the skb network header pointer to the beginning of the batman
+ * header.
+ */
+static void batadv_aggr_put_batadv(struct sk_buff *skb, void *data,
+				   u16 data_len, u8 packet_type)
+{
+	u8 version = BATADV_COMPAT_VERSION;
+	u8 *pos;
+
+	skb_reset_network_header(skb);
+	skb_reset_mac_len(skb);
+
+	pos = (u8 *)skb_put(skb, sizeof(packet_type));
+	*pos = packet_type;
+	pos = (u8 *)skb_put(skb, sizeof(version));
+	*pos = version;
+
+	pos = (u8 *)skb_put(skb, data_len);
+	memcpy(pos, data, data_len);
+}
+
+/**
+ * batadv_aggr_tvlv_handler - process incoming aggregation tvlv container
+ * @bat_priv: the bat priv with all the soft interface information
+ * @tvlv_value: tvlv buffer containing an aggregated packet
+ * @tvlv_value_len: length of the aggregated packet
+ * @ctx: handler specific context information
+ *  (here: recv_if, h_source and packet type of aggregated packet)
+ *
+ * De-aggregates the given, specific broadcast packet and transparently
+ * forwards it for broadcast packet reception.
+ *
+ * Return: NET_RX_SUCCESS on success, NET_RX_DROP otherwise.
+ */
+static int batadv_aggr_tvlv_handler(struct batadv_priv *bat_priv,
+				    void *tvlv_value, u16 tvlv_value_len,
+				    void *ctx)
+{
+	struct batadv_aggr_ctx *aggr_ctx;
+	struct batadv_hard_iface *recv_if;
+	struct sk_buff *skb;
+	unsigned int size;
+	u8 version = BATADV_COMPAT_VERSION;
+	u8 packet_type;
+
+	aggr_ctx = batadv_aggr_unpack_ctx(ctx);
+	recv_if = aggr_ctx->recv_if;
+	packet_type = aggr_ctx->handler.tvlv_type;
+
+	/* disallow aggr-in-aggr-in-... to avoid stack overflows */
+	if (packet_type == BATADV_BCAST_AGGR)
+		return NET_RX_DROP;
+
+	size = NET_IP_ALIGN + ETH_HLEN;
+	size += sizeof(packet_type) + sizeof(version);
+	size += tvlv_value_len;
+
+	skb = dev_alloc_skb(size);
+	if (!skb)
+		return NET_RX_DROP;
+
+	skb_reserve(skb, NET_IP_ALIGN);
+	batadv_aggr_put_ethhdr(skb, aggr_ctx->h_source);
+	skb_pull(skb, ETH_HLEN);
+	batadv_aggr_put_batadv(skb, tvlv_value, tvlv_value_len, packet_type);
+
+	batadv_inc_counter(bat_priv, BATADV_CNT_AGGR_PARTS_RX);
+	batadv_add_counter(bat_priv, BATADV_CNT_AGGR_PARTS_RX_BYTES,
+			   skb->len + ETH_HLEN);
+
+	return batadv_batman_skb_recv(skb, recv_if->net_dev,
+				      &recv_if->batman_adv_ptype, NULL);
+}
+
+/**
+ * batadv_aggr_mesh_init - initialise the generic aggregation engine
+ * @bat_priv: the bat priv with all the soft interface information
+ *
+ * Return: 0 on success or a negative error code in case of failure
+ */
+int batadv_aggr_mesh_init(struct batadv_priv *bat_priv)
+{
+	batadv_tvlv_handler_register2(bat_priv, batadv_aggr_tvlv_handler,
+				      BATADV_BCAST_AGGR, BATADV_TVLV_ANY, 1,
+				      BATADV_TVLV_HANDLER_MORECTX);
+	batadv_tvlv_container_register(bat_priv, BATADV_TVLV_AGGR, 1, NULL, 0);
+
+	return 0;
+}
+
+/**
+ * batadv_mcast_free - shutdown the generic aggregation engine
+ * @bat_priv: the bat priv with all the soft interface information
+ */
+void batadv_aggr_mesh_free(struct batadv_priv *bat_priv)
+{
+	batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_AGGR, 1);
+	batadv_tvlv_handler_unregister2(bat_priv, BATADV_BCAST_AGGR,
+					BATADV_TVLV_ANY, 1);
+}
diff --git a/net/batman-adv/aggregation.h b/net/batman-adv/aggregation.h
new file mode 100644
index 0000000..db3b06b
--- /dev/null
+++ b/net/batman-adv/aggregation.h
@@ -0,0 +1,66 @@
+/* Copyright (C) 2016  B.A.T.M.A.N. contributors:
+ *
+ * Linus Lüssing
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _NET_BATMAN_ADV_AGGREGATION_H_
+#define _NET_BATMAN_ADV_AGGREGATION_H_
+
+#include "main.h"
+
+struct sk_buff;
+
+/**
+ * batadv_aggr_pack_ctx - pack context to be passed to aggregation TVLV handler
+ * @aggr_ctx: the data to pack (mandatory, may *not* be NULL!)
+ *
+ * This packs the context, here the interface and source address the packet came
+ * from, as well as the packet type of the according aggregate, so that it is
+ * later available to the to be called aggregation TVLV handler.
+ *
+ * Return: The wrapped context.
+ */
+static inline void *batadv_aggr_pack_ctx(struct batadv_aggr_ctx *aggr_ctx)
+{
+	return (void *)aggr_ctx;
+}
+
+#ifdef CONFIG_BATMAN_ADV_AGGR
+
+void batadv_aggr_add_counter_rx(struct batadv_priv *bat_priv,
+				struct sk_buff *skb);
+
+int batadv_aggr_mesh_init(struct batadv_priv *bat_priv);
+void batadv_aggr_mesh_free(struct batadv_priv *bat_priv);
+
+#else
+
+static inline void batadv_aggr_add_counter_rx(struct batadv_priv *bat_priv,
+					      struct sk_buff *skb)
+{
+}
+
+static inline int batadv_aggr_mesh_init(struct batadv_priv *bat_priv)
+{
+	return 0;
+}
+
+static inline void batadv_aggr_mesh_free(struct batadv_priv *bat_priv)
+{
+}
+
+#endif /* CONFIG_BATMAN_ADV_AGGR */
+
+#endif /* _NET_BATMAN_ADV_AGGREGATION_H_ */
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index 7aa384a..fe6b904 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -47,6 +47,7 @@
 #include <net/rtnetlink.h>
 #include <uapi/linux/batman_adv.h>
 
+#include "aggregation.h"
 #include "bat_algo.h"
 #include "bat_iv_ogm.h"
 #include "bat_v.h"
@@ -180,6 +181,10 @@ int batadv_mesh_init(struct net_device *soft_iface)
 	INIT_HLIST_HEAD(&bat_priv->softif_vlan_list);
 	INIT_HLIST_HEAD(&bat_priv->tp_list);
 
+	ret = batadv_aggr_mesh_init(bat_priv);
+	if (ret < 0)
+		goto err;
+
 	ret = batadv_v_mesh_init(bat_priv);
 	if (ret < 0)
 		goto err;
@@ -227,6 +232,7 @@ void batadv_mesh_free(struct net_device *soft_iface)
 
 	batadv_gw_node_free(bat_priv);
 
+	batadv_aggr_mesh_free(bat_priv);
 	batadv_v_mesh_free(bat_priv);
 	batadv_nc_mesh_free(bat_priv);
 	batadv_dat_free(bat_priv);
@@ -508,6 +514,7 @@ static void batadv_recv_handler_init(void)
 	BUILD_BUG_ON(sizeof(struct batadv_unicast_packet) != 10);
 	BUILD_BUG_ON(sizeof(struct batadv_unicast_4addr_packet) != 18);
 	BUILD_BUG_ON(sizeof(struct batadv_frag_packet) != 20);
+	BUILD_BUG_ON(sizeof(struct batadv_aggr_packet) != 4);
 	BUILD_BUG_ON(sizeof(struct batadv_bcast_packet) != 14);
 	BUILD_BUG_ON(sizeof(struct batadv_coded_packet) != 46);
 	BUILD_BUG_ON(sizeof(struct batadv_unicast_tvlv_packet) != 20);
@@ -531,6 +538,8 @@ static void batadv_recv_handler_init(void)
 	batadv_rx_handler[BATADV_ICMP] = batadv_recv_icmp_packet;
 	/* Fragmented packets */
 	batadv_rx_handler[BATADV_UNICAST_FRAG] = batadv_recv_frag_packet;
+	/* Aggregation packets */
+	batadv_rx_handler[BATADV_BCAST_AGGR] = batadv_recv_aggr_packet;
 }
 
 int
diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h
index a14547c..3492332 100644
--- a/net/batman-adv/packet.h
+++ b/net/batman-adv/packet.h
@@ -31,6 +31,7 @@
  * @BATADV_CODED: network coded packets
  * @BATADV_ELP: echo location packets for B.A.T.M.A.N. V
  * @BATADV_OGM2: originator messages for B.A.T.M.A.N. V
+ * @BATADV_AGGR: broadcast aggregation packets
  *
  * @BATADV_UNICAST: unicast packets carrying unicast payload traffic
  * @BATADV_UNICAST_FRAG: unicast packets carrying a fragment of the original
@@ -47,6 +48,7 @@ enum batadv_packettype {
 	BATADV_CODED            = 0x02,
 	BATADV_ELP		= 0x03,
 	BATADV_OGM2		= 0x04,
+	BATADV_BCAST_AGGR	= 0x05,
 	/* 0x40 - 0x7f: unicast */
 #define BATADV_UNICAST_MIN     0x40
 	BATADV_UNICAST          = 0x40,
@@ -154,6 +156,8 @@ enum batadv_bla_claimframe {
  * @BATADV_TVLV_TT: translation table tvlv
  * @BATADV_TVLV_ROAM: roaming advertisement tvlv
  * @BATADV_TVLV_MCAST: multicast capability tvlv
+ * @BATADV_TVLV_AGGR: generic broadcast aggregation capability tvlv
+ * @BATADV_ANYTYPE: internal place holder for TVLV handlers, not for the "wire"
  */
 enum batadv_tvlv_type {
 	BATADV_TVLV_GW		= 0x01,
@@ -162,6 +166,8 @@ enum batadv_tvlv_type {
 	BATADV_TVLV_TT		= 0x04,
 	BATADV_TVLV_ROAM	= 0x05,
 	BATADV_TVLV_MCAST	= 0x06,
+	BATADV_TVLV_AGGR	= 0x07,
+	BATADV_TVLV_ANY		= 0xff,
 };
 
 /**
@@ -468,6 +474,18 @@ struct batadv_frag_packet {
 };
 
 /**
+ * struct batadv_aggr_packet - aggregation packet for broadcast packets
+ * @packet_type: batman-adv packet type, part of the general header
+ * @version: batman-adv protocol version, part of the genereal header
+ * @tvlv_len: length of tvlv data following the aggregation header
+ */
+struct batadv_aggr_packet {
+	u8     packet_type;
+	u8     version;  /* batman version field */
+	__be16 tvlv_len;
+};
+
+/**
  * struct batadv_bcast_packet - broadcast packet for network payload
  * @packet_type: batman-adv packet type, part of the general header
  * @version: batman-adv protocol version, part of the genereal header
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index 6713bdf..ee5f3d0 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -34,6 +34,7 @@
 #include <linux/spinlock.h>
 #include <linux/stddef.h>
 
+#include "aggregation.h"
 #include "bitarray.h"
 #include "bridge_loop_avoidance.h"
 #include "distributed-arp-table.h"
@@ -1137,6 +1138,68 @@ free_skb:
 	return ret;
 }
 
+/**
+ * batadv_recv_aggr_get_tvlv_len - get tvlv_len of an aggregation packet
+ * @skb: the aggregation packet to parse
+ *
+ * Return: Length of the tvlv data of the given skb on success,
+ * -EINVAL otherwise (i.e. packet is too short).
+ */
+static int batadv_recv_aggr_get_tvlv_len(struct sk_buff *skb)
+{
+	unsigned int tvlv_len_offset;
+	__be16 *tvlv_len, tvlv_len_buff;
+
+	tvlv_len_offset = offsetof(struct batadv_aggr_packet, tvlv_len);
+	tvlv_len = skb_header_pointer(skb, tvlv_len_offset,
+				      sizeof(tvlv_len_buff), &tvlv_len_buff);
+
+	if (!tvlv_len)
+		return -EINVAL;
+
+	return ntohs(*tvlv_len);
+}
+
+/**
+ * batadv_recv_aggr_packet - process received aggregation packet
+ * @skb: the aggregation packet to process
+ * @recv_if: interface that the skb is received on
+ *
+ * This function de-aggregates broadcast packets from the given
+ * aggregation packet.
+ *
+ * Frees/consumes the provided skb.
+ *
+ * Return: NET_RX_SUCCESS on success, NET_RX_DROP otherwise.
+ */
+int batadv_recv_aggr_packet(struct sk_buff *skb,
+			    struct batadv_hard_iface *recv_if)
+{
+	struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface);
+	struct batadv_aggr_ctx aggr_ctx;
+	unsigned int tvlv_offset = sizeof(struct batadv_aggr_packet);
+	int tvlv_len, ret;
+	void *ctx;
+
+	aggr_ctx.recv_if = recv_if;
+	aggr_ctx.h_source = eth_hdr(skb)->h_source;
+	ctx = batadv_aggr_pack_ctx(&aggr_ctx);
+	tvlv_len = batadv_recv_aggr_get_tvlv_len(skb);
+
+	if (tvlv_len < 0) {
+		kfree_skb(skb);
+		return NET_RX_DROP;
+	}
+
+	batadv_aggr_add_counter_rx(bat_priv, skb);
+
+	ret = batadv_tvlv_containers_process2(bat_priv, skb, BATADV_BCAST_AGGR,
+					      tvlv_offset, tvlv_len, ctx);
+
+	consume_skb(skb);
+	return ret;
+}
+
 int batadv_recv_bcast_packet(struct sk_buff *skb,
 			     struct batadv_hard_iface *recv_if)
 {
diff --git a/net/batman-adv/routing.h b/net/batman-adv/routing.h
index 05c3ff4..fcf3967 100644
--- a/net/batman-adv/routing.h
+++ b/net/batman-adv/routing.h
@@ -37,6 +37,8 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
 			       struct batadv_hard_iface *recv_if);
 int batadv_recv_frag_packet(struct sk_buff *skb,
 			    struct batadv_hard_iface *iface);
+int batadv_recv_aggr_packet(struct sk_buff *skb,
+			    struct batadv_hard_iface *recv_if);
 int batadv_recv_bcast_packet(struct sk_buff *skb,
 			     struct batadv_hard_iface *recv_if);
 int batadv_recv_tt_query(struct sk_buff *skb,
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index 7b3494a..fce69b7 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -1150,6 +1150,12 @@ static const struct {
 	{ "frag_rx_bytes" },
 	{ "frag_fwd" },
 	{ "frag_fwd_bytes" },
+#ifdef CONFIG_BATMAN_ADV_AGGR
+	{ "aggr_rx" },
+	{ "aggr_rx_bytes" },
+	{ "aggr_parts_rx" },
+	{ "aggr_parts_rx_bytes" },
+#endif
 	{ "tt_request_tx" },
 	{ "tt_request_rx" },
 	{ "tt_response_tx" },
diff --git a/net/batman-adv/tvlv.c b/net/batman-adv/tvlv.c
index c824d74..0d5be4b 100644
--- a/net/batman-adv/tvlv.c
+++ b/net/batman-adv/tvlv.c
@@ -88,10 +88,12 @@ batadv_tvlv_handler_get(struct batadv_priv *bat_priv, int packet_type,
 		if (tvlv_handler_tmp->packet_type != packet_type)
 			continue;
 
-		if (tvlv_handler_tmp->tvlv_type != tvlv_type)
+		if (tvlv_handler_tmp->tvlv_type != BATADV_TVLV_ANY &&
+		    tvlv_handler_tmp->tvlv_type != tvlv_type)
 			continue;
 
-		if (tvlv_handler_tmp->tvlv_version != tvlv_version)
+		if (tvlv_handler_tmp->tvlv_type != BATADV_TVLV_ANY &&
+		    tvlv_handler_tmp->tvlv_version != tvlv_version)
 			continue;
 
 		if (!kref_get_unless_zero(&tvlv_handler_tmp->refcount))
@@ -431,6 +433,7 @@ static int batadv_tvlv_call_handler2(struct batadv_priv *bat_priv,
 				     u8 tvlv_version, void *tvlv_value,
 				     u16 tvlv_value_len, void *ctx)
 {
+	struct batadv_tvlv_handler_ctx *handler_ctx;
 	struct batadv_tvlv_handler *tvlv_handler;
 	int ret;
 
@@ -439,6 +442,12 @@ static int batadv_tvlv_call_handler2(struct batadv_priv *bat_priv,
 	if (!tvlv_handler)
 		return NET_RX_DROP;
 
+	if (tvlv_handler->flags & BATADV_TVLV_HANDLER_MORECTX) {
+		handler_ctx = (struct batadv_tvlv_handler_ctx *)ctx;
+		handler_ctx->tvlv_type = tvlv_type;
+		handler_ctx->tvlv_version = tvlv_version;
+	}
+
 	ret = tvlv_handler->handler(bat_priv, tvlv_value, tvlv_value_len, ctx);
 	tvlv_handler->flags |= BATADV_TVLV_HANDLER_CALLED;
 
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index fc552a9..e2dbb5a 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -575,6 +575,10 @@ struct batadv_bcast_duplist_entry {
  * @BATADV_CNT_FRAG_RX_BYTES: received fragment traffic bytes counter
  * @BATADV_CNT_FRAG_FWD: forwarded fragment traffic packet counter
  * @BATADV_CNT_FRAG_FWD_BYTES: forwarded fragment traffic bytes counter
+ * @BATADV_CNT_AGGR_RX: received aggregation traffic packet count
+ * @BATADV_CNT_AGGR_RX_BYTES: received aggregation traffic bytes counter
+ * @BATADV_CNT_AGGR_PARTS_RX: received aggregated traffic packet counter
+ * @BATADV_CNT_AGGR_PARTS_RX_BYTES: received aggregated bytes counter
  * @BATADV_CNT_TT_REQUEST_TX: transmitted tt req traffic packet counter
  * @BATADV_CNT_TT_REQUEST_RX: received tt req traffic packet counter
  * @BATADV_CNT_TT_RESPONSE_TX: transmitted tt resp traffic packet counter
@@ -618,6 +622,12 @@ enum batadv_counters {
 	BATADV_CNT_FRAG_RX_BYTES,
 	BATADV_CNT_FRAG_FWD,
 	BATADV_CNT_FRAG_FWD_BYTES,
+#ifdef CONFIG_BATMAN_ADV_AGGR
+	BATADV_CNT_AGGR_RX,
+	BATADV_CNT_AGGR_RX_BYTES,
+	BATADV_CNT_AGGR_PARTS_RX,
+	BATADV_CNT_AGGR_PARTS_RX_BYTES,
+#endif
 	BATADV_CNT_TT_REQUEST_TX,
 	BATADV_CNT_TT_REQUEST_RX,
 	BATADV_CNT_TT_RESPONSE_TX,
@@ -1648,16 +1658,44 @@ struct batadv_tvlv_handler {
 };
 
 /**
+ * struct batadv_tvlv_handler_ctx - handler meta information
+ * @tvlv_type: type of the processed tvlv
+ * @tvlv_version: version of the processed tvlv
+ *
+ * This structure is provided to a tvlv handler if the
+ * BATADV_TVLV_HANDLER_MORECTX flag was set during registration.
+ */
+struct batadv_tvlv_handler_ctx {
+	u8 tvlv_type;
+	u8 tvlv_version;
+};
+
+/**
+ * struct batadv_aggr_ctx - aggregation tvlv context
+ * @handler: information regarding the tvlv handler itself
+ * @recv_if: interface the packet was received from
+ * @h_source: ethernet address of the neighbor the packet was received from
+ */
+struct batadv_aggr_ctx {
+	struct batadv_tvlv_handler_ctx handler;
+	struct batadv_hard_iface *recv_if;
+	unsigned char *h_source;
+};
+
+/**
  * enum batadv_tvlv_handler_flags - tvlv handler flags definitions
  * @BATADV_TVLV_HANDLER_CIFNOTFND: tvlv processing function will call
  *  this handler even if its type was not found (with no data)
  * @BATADV_TVLV_HANDLER_CALLED: internal tvlv handling flag - the API marks
  *  a handler as being called, so it won't be called if the
  *  BATADV_TVLV_HANDLER_CIFNOTFND flag was set
+ * @BATADV_TVLV_HANDLER_MORECTX: tvlv processing function will be provided with
+ *  handler specific context (e.g. tvlv type and version)
  */
 enum batadv_tvlv_handler_flags {
 	BATADV_TVLV_HANDLER_CIFNOTFND = BIT(1),
 	BATADV_TVLV_HANDLER_CALLED = BIT(2),
+	BATADV_TVLV_HANDLER_MORECTX = BIT(3),
 };
 
 /**
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [B.A.T.M.A.N.] [RFC PATCH 3/6] batman-adv: aggregation packet queueing and transmission
  2016-12-19 11:25 [B.A.T.M.A.N.] [RFC PATCH 0/6] batman-adv: broadcast packet aggregation Linus Lüssing
  2016-12-19 11:25 ` [B.A.T.M.A.N.] [RFC PATCH 1/6] batman-adv: Allow TVLVs greater than 128 bytes Linus Lüssing
  2016-12-19 11:25 ` [B.A.T.M.A.N.] [RFC PATCH 2/6] batman-adv: aggregation packet reception Linus Lüssing
@ 2016-12-19 11:25 ` Linus Lüssing
  2016-12-19 11:25 ` [B.A.T.M.A.N.] [RFC PATCH 4/6] batman-adv: privatize forw_packet skb assignment Linus Lüssing
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Linus Lüssing @ 2016-12-19 11:25 UTC (permalink / raw)
  To: b.a.t.m.a.n

This patch implements the queueing of any broadcast packet and its
following tranmission in an aggregation packet.

A broadcast packet is usually queued for up to 100ms (plus-minus
some jitter) or about 50ms on average.

However if the aggregation worker cannot keep up with emptying its
queue, a 10 to 20 times faster aggregation packet transmission rate is
used.

If an aggregation queue still runs full then broadcast packets are handed
over to the driver directly without aggregation, leaving it up to the
driver to either transmit or drop it, for instance due to congestion.

Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
---
 net/batman-adv/aggregation.c    | 475 ++++++++++++++++++++++++++++++++++++++++
 net/batman-adv/aggregation.h    |  31 +++
 net/batman-adv/bat_iv_ogm.c     |   6 +-
 net/batman-adv/hard-interface.c |   5 +
 net/batman-adv/main.c           |  10 +
 net/batman-adv/main.h           |   1 +
 net/batman-adv/originator.c     |   2 +
 net/batman-adv/send.c           |   9 +
 net/batman-adv/soft-interface.c |  11 +-
 net/batman-adv/sysfs.c          |   5 +-
 net/batman-adv/types.h          |  42 +++-
 11 files changed, 590 insertions(+), 7 deletions(-)

diff --git a/net/batman-adv/aggregation.c b/net/batman-adv/aggregation.c
index 2ee4dae..815da11 100644
--- a/net/batman-adv/aggregation.c
+++ b/net/batman-adv/aggregation.c
@@ -18,15 +18,430 @@
 #include "aggregation.h"
 #include "main.h"
 
+#include <linux/atomic.h>
+#include <linux/bitops.h>
 #include <linux/etherdevice.h>
 #include <linux/if_ether.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/random.h>
 #include <linux/skbuff.h>
+#include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/types.h>
+#include <linux/workqueue.h>
 
+#include "send.h"
 #include "tvlv.h"
 
 /**
+ * batadv_aggr_hardif_start - schedule aggregation packet transmission
+ * @hard_iface: the hard interface to schedule the transmission on
+ *
+ * Schedules an aggregation packet transmission for the next aggregation
+ * interval, plus/minus some jitter.
+ */
+void batadv_aggr_hardif_start(struct batadv_hard_iface *hard_iface)
+{
+	unsigned int msecs = BATADV_MAX_AGGREGATION_MS * 1000;
+
+	/* msecs * [0.9, 1.1] */
+	msecs += prandom_u32() % (msecs / 5) - (msecs / 10);
+	queue_delayed_work(batadv_event_workqueue, &hard_iface->aggr.work,
+			   msecs_to_jiffies(msecs / 1000));
+}
+
+/**
+ * batadv_aggr_hardif_start_urgent - schedule urgent aggregate transmission
+ * @hard_iface: the hard interface to schedule the transmission on
+ *
+ * Schedules an urgent aggregation packet transmission, plus/minus some jitter.
+ * That is at some time between an interval 10 to 20 times faster than the
+ * regular aggregation interval.
+ */
+static void
+batadv_aggr_hardif_start_urgent(struct batadv_hard_iface *hard_iface)
+{
+	unsigned int msecs = BATADV_MAX_AGGREGATION_MS * 1000;
+
+	/* msecs * [0.05, 0.1] */
+	msecs = (msecs / 20) + prandom_u32() % (msecs / 20);
+	queue_delayed_work(batadv_event_workqueue, &hard_iface->aggr.work,
+			   msecs_to_jiffies(msecs / 1000));
+}
+
+/**
+ * batadv_aggr_skb_queue_free - free all elements in an skb queue
+ * @head: the skb queue to empty
+ *
+ * Empties an skb queue and frees all the skbs it contained.
+ */
+static void batadv_aggr_skb_queue_free(struct sk_buff_head *head)
+{
+	struct sk_buff *skb;
+
+	while ((skb = skb_dequeue(head)))
+		kfree_skb(skb);
+}
+
+/**
+ * batadv_aggr_hardif_stop - shutdown an aggregation routine
+ * @hard_iface: the interface to stop aggregation on
+ *
+ * Stops an aggregation timer and destroys the packets queued
+ * on the given interface.
+ */
+void batadv_aggr_hardif_stop(struct batadv_hard_iface *hard_iface)
+{
+	cancel_delayed_work_sync(&hard_iface->aggr.work);
+
+	spin_lock_bh(&hard_iface->aggr.aggr_list_lock);
+	batadv_aggr_skb_queue_free(&hard_iface->aggr.aggr_list);
+	spin_unlock_bh(&hard_iface->aggr.aggr_list_lock);
+}
+
+/**
+ * batadv_aggr_chunk_reserve - reserve space in an aggregation packet
+ * @hard_iface: the interface to reserve on
+ * @skb: the to be aggregated packet to reserve for
+ * @size: size of the aggregation packet
+ *
+ * Tries to reserve space in the aggregation packet for the given skb.
+ * If reservation was successful, then the size of the to be allocated
+ * aggregation packet is increased accordingly.
+ *
+ * Return: True if there was enough space in the aggregation packet left,
+ * false otherwise.
+ */
+static bool batadv_aggr_chunk_reserve(struct batadv_hard_iface *hard_iface,
+				      struct sk_buff *skb,
+				      int *size)
+{
+	unsigned int len = skb->len + sizeof(struct batadv_tvlv_hdr);
+
+	len -= sizeof(((struct batadv_aggr_packet *)0)->packet_type);
+	len -= sizeof(((struct batadv_aggr_packet *)0)->version);
+
+	if (*size + len > hard_iface->net_dev->mtu)
+		return false;
+
+	*size += len;
+	return true;
+}
+
+/**
+ * batadv_aggr_get_chunk - gets a chunk of packets from the aggregation queue
+ * @hard_iface: the interface to get to be aggregated packets from
+ * @head: queue to stage a chunk of to be aggregated+transmitted packets on
+ * @size: size of the aggregation packet
+ *
+ * Tries to grab as many packets from the aggregation queue as fit into a
+ * single aggregation packet.
+ *
+ * Return: True if there are no packets in the aggregation queue
+ * of the provided interface left afterwards, false otherwise.
+ */
+static bool batadv_aggr_get_chunk(struct batadv_hard_iface *hard_iface,
+				  struct sk_buff_head *head,
+				  int *size)
+{
+	struct sk_buff *skb, *skb_tmp;
+	bool emptied = true;
+
+	*size = sizeof(struct batadv_aggr_packet);
+
+	if (skb_queue_empty(&hard_iface->aggr.aggr_list))
+		return emptied;
+
+	spin_lock_bh(&hard_iface->aggr.aggr_list_lock);
+	skb_queue_walk_safe(&hard_iface->aggr.aggr_list, skb, skb_tmp) {
+		if (!batadv_aggr_chunk_reserve(hard_iface, skb, size)) {
+			emptied = false;
+			break;
+		}
+
+		skb_unlink(skb, &hard_iface->aggr.aggr_list);
+		skb_queue_tail(head, skb);
+	}
+	spin_unlock_bh(&hard_iface->aggr.aggr_list_lock);
+
+	return emptied;
+}
+
+/**
+ * batadv_aggr_alloc_skb - allocate an aggregation packet
+ * @size: size of the to be allocated packet (excluding ethernet header)
+ *
+ * Allocates a broadcast aggregation packet.
+ *
+ * Return: An aggregation packet on success, NULL otherwise.
+ */
+static struct sk_buff *batadv_aggr_alloc_skb(int size)
+{
+	struct batadv_aggr_packet *aggr_packet;
+	struct sk_buff *skb;
+	unsigned char *skb_buff;
+	unsigned int offset;
+
+	skb = dev_alloc_skb(size + ETH_HLEN + NET_IP_ALIGN);
+	if (!skb)
+		return NULL;
+
+	skb_reserve(skb, ETH_HLEN + NET_IP_ALIGN);
+	skb_reset_network_header(skb);
+
+	skb_buff = skb_put(skb, sizeof(*aggr_packet));
+	aggr_packet = (struct batadv_aggr_packet *)skb_buff;
+	aggr_packet->packet_type = BATADV_BCAST_AGGR;
+	aggr_packet->version = BATADV_COMPAT_VERSION;
+
+	offset = skb_network_offset(skb) + sizeof(*aggr_packet);
+	skb_set_transport_header(skb, offset);
+
+	return skb;
+}
+
+/**
+ * batadv_aggr_get_pkttypes - get the packet type of a batman packet
+ * @skb: the packet to get the type from
+ *
+ * Return: The packet type of the provided batman packet.
+ */
+static u8 batadv_aggr_get_pkttype(struct sk_buff *skb)
+{
+	struct batadv_aggr_packet *packet;
+
+	packet = (struct batadv_aggr_packet *)skb_network_header(skb);
+
+	return packet->packet_type;
+}
+
+/**
+ * batadv_aggr_put_tvlvhdr - append a tvlv header to an skb
+ * @skb: the aggregation packet to append the tvlv header to
+ * @type: the packet (= tvlv) type to set in the tvlv header
+ * @len: the size of the to be added tvlv data
+ *
+ * Appends a tvlv header to the given aggregation packet and sets its type and
+ * length as provided.
+ */
+static void batadv_aggr_put_tvlvhdr(struct sk_buff *skb, u8 type,
+				    unsigned int len)
+{
+	struct batadv_tvlv_hdr *tvlv_hdr;
+
+	tvlv_hdr = (struct batadv_tvlv_hdr *)skb_put(skb, sizeof(*tvlv_hdr));
+
+	tvlv_hdr->type = type;
+	tvlv_hdr->version = 1;
+	tvlv_hdr->len = htons(len);
+}
+
+/**
+ * batadv_aggr_queue_is_full - check for slots left in aggregation queue
+ * @hard_iface: the interface to check
+ *
+ * Return: True if if the queue is full, false otherwise.
+ */
+static inline bool
+batadv_aggr_queue_is_full(struct batadv_hard_iface *hard_iface)
+{
+	struct sk_buff_head *head = &hard_iface->aggr.aggr_list;
+
+	return skb_queue_len(head) >= BATADV_AGGR_QUEUE_LEN;
+}
+
+/**
+ * batadv_aggr_squash_chunk - squash packets into an aggregate
+ * @head: a list of to be squashed packets
+ * @size: the size of the to be created aggregation packet
+ *  (excluding the ethernet header)
+ *
+ * Allocates an aggregation packet and squashes the provided list of broadcast
+ * packets into it. The provided list of packets is freed/consumed.
+ *
+ * Return: An aggregation packet ready for transmission on success, NULL
+ * otherwise.
+ */
+static struct sk_buff *
+batadv_aggr_squash_chunk(struct sk_buff_head *head,
+			 int size)
+{
+	struct sk_buff *skb, *skb_tmp, *skb_aggr;
+	struct batadv_aggr_packet *aggr_packet;
+	unsigned int len, offset, tvlv_len = 0;
+	unsigned char *to;
+	u8 type;
+
+	if (skb_queue_empty(head))
+		return NULL;
+
+	skb_aggr = batadv_aggr_alloc_skb(size);
+	if (!skb_aggr) {
+		batadv_aggr_skb_queue_free(head);
+		return NULL;
+	}
+
+	aggr_packet = (struct batadv_aggr_packet *)skb_network_header(skb_aggr);
+
+	skb_queue_walk_safe(head, skb, skb_tmp) {
+		offset = skb_network_offset(skb);
+		offset += sizeof(aggr_packet->packet_type);
+		offset += sizeof(aggr_packet->version);
+		len = skb->len - offset;
+		type = batadv_aggr_get_pkttype(skb);
+
+		batadv_aggr_put_tvlvhdr(skb_aggr, type, len);
+		to = skb_put(skb_aggr, len);
+		skb_copy_bits(skb, offset, to, len);
+		skb_unlink(skb, head);
+		consume_skb(skb);
+
+		tvlv_len += len + sizeof(struct batadv_tvlv_hdr);
+	}
+
+	aggr_packet->tvlv_len = htons(tvlv_len);
+
+	return skb_aggr;
+}
+
+/**
+ * __batadv_aggr_send_chunk - send a prepared aggregation packet
+ * @hard_iface: the interface to transmit on
+ * @skb: the prepared aggregation packet to send
+ */
+static void __batadv_aggr_send_chunk(struct batadv_hard_iface *hard_iface,
+				     struct sk_buff *skb)
+{
+	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
+
+	batadv_inc_counter(bat_priv, BATADV_CNT_AGGR_TX);
+	batadv_add_counter(bat_priv, BATADV_CNT_AGGR_TX_BYTES,
+			   skb->len + ETH_HLEN);
+
+	/* ToDo: Track transmission failures? */
+	batadv_send_skb_packet(skb, hard_iface, batadv_broadcast_addr);
+}
+
+/**
+ * batadv_aggr_send_chunk - prepare and transmit an aggregation packet
+ * @hard_iface: the interface to transmit on
+ *
+ * Fetches as many packets from the aggregation queue of the provided interface
+ * as fit into a single aggregation packet. Then aggregates them into such an
+ * aggregation packet and transmits the final aggregate.
+ *
+ * Return: True if there are no packets in the aggregation queue
+ * of the provided interface left afterwards, false otherwise.
+ */
+static bool batadv_aggr_send_chunk(struct batadv_hard_iface *hard_iface)
+{
+	struct sk_buff_head head;
+	struct sk_buff *skb;
+	int size = 0;
+	bool emptied;
+
+	skb_queue_head_init(&head);
+	emptied = batadv_aggr_get_chunk(hard_iface, &head, &size);
+
+	skb = batadv_aggr_squash_chunk(&head, size);
+	if (!skb)
+		goto out;
+
+	__batadv_aggr_send_chunk(hard_iface, skb);
+
+out:
+	return emptied;
+}
+
+/**
+ * batadv_aggr_work - periodic aggregation worker
+ * @work: work queue item
+ *
+ * Prepares and sends out an aggregation packet. In the end rearms the timer
+ * either to the next aggregation interval, or if there were still packets left
+ * in the aggregation queue, sets it to an earlier time.
+ */
+static void batadv_aggr_work(struct work_struct *work)
+{
+	struct batadv_hard_iface_aggr *aggr;
+	struct batadv_hard_iface *hard_iface;
+	struct batadv_priv *bat_priv;
+	bool emptied;
+
+	aggr = container_of(work, struct batadv_hard_iface_aggr, work.work);
+	hard_iface = container_of(aggr, struct batadv_hard_iface, aggr);
+	bat_priv = netdev_priv(hard_iface->soft_iface);
+
+	emptied = batadv_aggr_send_chunk(hard_iface);
+	if (emptied) {
+		batadv_aggr_hardif_start(hard_iface);
+	} else {
+		batadv_inc_counter(bat_priv, BATADV_CNT_AGGR_URGENT);
+		batadv_aggr_hardif_start_urgent(hard_iface);
+	}
+}
+
+/**
+ * batadv_aggr_queue - queue a broadcast packet for aggregation
+ * @skb: the packet to queue
+ * @hard_iface: the interface to queue on
+ *
+ * Return: NET_XMIT_SUCCESS if the skb was queued, NET_XMIT_DROP otherwise.
+ * The former consumes the skb.
+ */
+int batadv_aggr_queue(struct sk_buff *skb, struct batadv_hard_iface *hard_iface)
+{
+	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
+
+	if (!atomic_read(&bat_priv->aggregation))
+		return NET_XMIT_DROP;
+
+	if (atomic_read(&bat_priv->aggr_num_disabled))
+		return NET_XMIT_DROP;
+
+	if (batadv_aggr_queue_is_full(hard_iface)) {
+		batadv_inc_counter(bat_priv, BATADV_CNT_AGGR_QUEUE_FULL);
+		return NET_XMIT_DROP;
+	}
+
+	spin_lock_bh(&hard_iface->aggr.aggr_list_lock);
+	skb_queue_tail(&hard_iface->aggr.aggr_list, skb);
+	spin_unlock_bh(&hard_iface->aggr.aggr_list_lock);
+
+	batadv_inc_counter(bat_priv, BATADV_CNT_AGGR_PARTS_TX);
+	batadv_add_counter(bat_priv, BATADV_CNT_AGGR_PARTS_TX_BYTES,
+			   skb->len + ETH_HLEN);
+
+	return NET_XMIT_SUCCESS;
+}
+
+/**
+ * batadv_aggr_purge_orig - reset originator aggregation state modifications
+ * @orig: the originator which is going to get purged
+ */
+void batadv_aggr_purge_orig(struct batadv_orig_node *orig)
+{
+	struct batadv_priv *bat_priv = orig->bat_priv;
+
+	if (!test_bit(BATADV_ORIG_CAPA_HAS_AGGR, &orig->capabilities) &&
+	    test_bit(BATADV_ORIG_CAPA_HAS_AGGR, &orig->capa_initialized))
+		atomic_dec(&bat_priv->aggr_num_disabled);
+}
+
+/**
+ * batadv_aggr_hardif_init - initialize an interface for aggregation
+ * @hard_iface: the interface to initialize
+ */
+void batadv_aggr_hardif_init(struct batadv_hard_iface *hard_iface)
+{
+	INIT_DELAYED_WORK(&hard_iface->aggr.work, batadv_aggr_work);
+	skb_queue_head_init(&hard_iface->aggr.aggr_list);
+	spin_lock_init(&hard_iface->aggr.aggr_list_lock);
+}
+
+/**
  * batadv_aggr_unpack_ctx - unpack context received with a TVLV handler call
  * @ctx: handler specific context information
  *  (here: recv_if, h_source and packet type of aggregate)
@@ -167,6 +582,55 @@ static int batadv_aggr_tvlv_handler(struct batadv_priv *bat_priv,
 }
 
 /**
+ * batadv_aggr_ogm_handler - process incoming aggregation tvlv container
+ * @bat_priv: the bat priv with all the soft interface information
+ * @tvlv_value: tvlv buffer containing an aggregated broadcast packet
+ * @tvlv_value_len: tvlv buffer length
+ * @ctx: handler specific context information
+ *  (here: recv_if, h_source and packet type of aggregate)
+ *
+ * Parses an aggregation tvlv attached to an originator message and updates
+ * aggregation capabilities accordingly.
+ *
+ * Return: Always NET_RX_SUCCESS.
+ */
+static int batadv_aggr_ogm_handler(struct batadv_priv *bat_priv,
+				   void *tvlv_value, u16 tvlv_value_len,
+				   void *ctx)
+{
+	struct batadv_orig_node *orig = batadv_tvlv_ogm_unpack_ctx(ctx);
+	bool orig_aggr_enabled = !!tvlv_value;
+	bool orig_initialized;
+
+	orig_initialized = test_bit(BATADV_ORIG_CAPA_HAS_AGGR,
+				    &orig->capa_initialized);
+
+	/* If aggregation support is turned on decrease the disabled aggregation
+	 * node counter only if we had increased it for this node before. If
+	 * this is a completely new orig_node no need to decrease the counter.
+	 */
+	if (orig_aggr_enabled &&
+	    !test_bit(BATADV_ORIG_CAPA_HAS_AGGR, &orig->capabilities)) {
+		if (orig_initialized)
+			atomic_dec(&bat_priv->aggr_num_disabled);
+		set_bit(BATADV_ORIG_CAPA_HAS_AGGR, &orig->capabilities);
+	/* If aggregation support is being switched off or if this is an initial
+	 * OGM without aggregation support then increase the disabled
+	 * aggregation node counter.
+	 */
+	} else if (!orig_aggr_enabled &&
+		   (test_bit(BATADV_ORIG_CAPA_HAS_AGGR, &orig->capabilities) ||
+		    !orig_initialized)) {
+		atomic_inc(&bat_priv->aggr_num_disabled);
+		clear_bit(BATADV_ORIG_CAPA_HAS_AGGR, &orig->capabilities);
+	}
+
+	set_bit(BATADV_ORIG_CAPA_HAS_AGGR, &orig->capa_initialized);
+
+	return NET_RX_SUCCESS;
+}
+
+/**
  * batadv_aggr_mesh_init - initialise the generic aggregation engine
  * @bat_priv: the bat priv with all the soft interface information
  *
@@ -177,6 +641,13 @@ int batadv_aggr_mesh_init(struct batadv_priv *bat_priv)
 	batadv_tvlv_handler_register2(bat_priv, batadv_aggr_tvlv_handler,
 				      BATADV_BCAST_AGGR, BATADV_TVLV_ANY, 1,
 				      BATADV_TVLV_HANDLER_MORECTX);
+	batadv_tvlv_handler_register2(bat_priv, batadv_aggr_ogm_handler,
+				      BATADV_IV_OGM, BATADV_TVLV_AGGR, 1,
+				      BATADV_TVLV_HANDLER_CIFNOTFND);
+	batadv_tvlv_handler_register2(bat_priv, batadv_aggr_ogm_handler,
+				      BATADV_OGM2, BATADV_TVLV_AGGR, 1,
+				      BATADV_TVLV_HANDLER_CIFNOTFND);
+
 	batadv_tvlv_container_register(bat_priv, BATADV_TVLV_AGGR, 1, NULL, 0);
 
 	return 0;
@@ -189,6 +660,10 @@ int batadv_aggr_mesh_init(struct batadv_priv *bat_priv)
 void batadv_aggr_mesh_free(struct batadv_priv *bat_priv)
 {
 	batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_AGGR, 1);
+	batadv_tvlv_handler_unregister2(bat_priv, BATADV_OGM2, BATADV_TVLV_AGGR,
+					1);
+	batadv_tvlv_handler_unregister2(bat_priv, BATADV_IV_OGM,
+					BATADV_TVLV_AGGR, 1);
 	batadv_tvlv_handler_unregister2(bat_priv, BATADV_BCAST_AGGR,
 					BATADV_TVLV_ANY, 1);
 }
diff --git a/net/batman-adv/aggregation.h b/net/batman-adv/aggregation.h
index db3b06b..67a7fce 100644
--- a/net/batman-adv/aggregation.h
+++ b/net/batman-adv/aggregation.h
@@ -42,6 +42,14 @@ static inline void *batadv_aggr_pack_ctx(struct batadv_aggr_ctx *aggr_ctx)
 void batadv_aggr_add_counter_rx(struct batadv_priv *bat_priv,
 				struct sk_buff *skb);
 
+void batadv_aggr_hardif_start(struct batadv_hard_iface *hard_iface);
+void batadv_aggr_hardif_stop(struct batadv_hard_iface *hard_iface);
+
+int batadv_aggr_queue(struct sk_buff *skb,
+		      struct batadv_hard_iface *hard_iface);
+
+void batadv_aggr_purge_orig(struct batadv_orig_node *orig);
+void batadv_aggr_hardif_init(struct batadv_hard_iface *hard_iface);
 int batadv_aggr_mesh_init(struct batadv_priv *bat_priv);
 void batadv_aggr_mesh_free(struct batadv_priv *bat_priv);
 
@@ -52,6 +60,29 @@ static inline void batadv_aggr_add_counter_rx(struct batadv_priv *bat_priv,
 {
 }
 
+static inline void
+batadv_aggr_hardif_start(struct batadv_hard_iface *hard_iface)
+{
+}
+
+static inline void batadv_aggr_hardif_stop(struct batadv_hard_iface *hard_iface)
+{
+}
+
+static inline int batadv_aggr_queue(struct sk_buff *skb,
+				    struct batadv_hard_iface *hard_iface)
+{
+	return NET_XMIT_DROP;
+}
+
+static inline void batadv_aggr_purge_orig(struct batadv_orig_node *orig)
+{
+}
+
+static inline void batadv_aggr_hardif_init(struct batadv_hard_iface *hard_iface)
+{
+}
+
 static inline int batadv_aggr_mesh_init(struct batadv_priv *bat_priv)
 {
 	return 0;
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
index a1472ab..1b1c932 100644
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -688,7 +688,7 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
 	if (!forw_packet_aggr)
 		return;
 
-	if (atomic_read(&bat_priv->aggregated_ogms) &&
+	if (atomic_read(&bat_priv->aggregation) &&
 	    packet_len < BATADV_MAX_AGGREGATION_BYTES)
 		skb_size = BATADV_MAX_AGGREGATION_BYTES;
 	else
@@ -776,7 +776,7 @@ static void batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv,
 	/* find position for the packet in the forward queue */
 	spin_lock_bh(&bat_priv->forw_bat_list_lock);
 	/* own packets are not to be aggregated */
-	if (atomic_read(&bat_priv->aggregated_ogms) && !own_packet) {
+	if (atomic_read(&bat_priv->aggregation) && !own_packet) {
 		hlist_for_each_entry(forw_packet_pos,
 				     &bat_priv->forw_bat_list, list) {
 			if (batadv_iv_ogm_can_aggregate(batadv_ogm_packet,
@@ -802,7 +802,7 @@ static void batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv,
 		 * we hold it back for a while, so that it might be aggregated
 		 * later on
 		 */
-		if (!own_packet && atomic_read(&bat_priv->aggregated_ogms))
+		if (!own_packet && atomic_read(&bat_priv->aggregation))
 			send_time += max_aggregation_jiffies;
 
 		batadv_iv_ogm_aggregate_new(packet_buff, packet_len,
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index acdf9c2..2999d8e 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -38,6 +38,7 @@
 #include <net/net_namespace.h>
 #include <net/rtnetlink.h>
 
+#include "aggregation.h"
 #include "bat_v.h"
 #include "bridge_loop_avoidance.h"
 #include "debugfs.h"
@@ -759,6 +760,8 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
 	if (ret < 0)
 		goto err_upper;
 
+	batadv_aggr_hardif_start(hard_iface);
+
 	hard_iface->if_num = bat_priv->num_ifaces;
 	bat_priv->num_ifaces++;
 	hard_iface->if_status = BATADV_IF_INACTIVE;
@@ -845,6 +848,7 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface,
 			batadv_hardif_put(new_if);
 	}
 
+	batadv_aggr_hardif_stop(hard_iface);
 	bat_priv->algo_ops->iface.disable(hard_iface);
 	hard_iface->if_status = BATADV_IF_NOT_IN_USE;
 
@@ -914,6 +918,7 @@ batadv_hardif_add_interface(struct net_device *net_dev)
 		hard_iface->num_bcasts = BATADV_NUM_BCASTS_WIRELESS;
 
 	batadv_v_hardif_init(hard_iface);
+	batadv_aggr_hardif_init(hard_iface);
 
 	batadv_check_known_mac_addr(hard_iface->net_dev);
 	kref_get(&hard_iface->refcount);
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index fe6b904..286163d 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -350,6 +350,16 @@ int batadv_max_header_len(void)
 	header_len = max_t(int, header_len,
 			   sizeof(struct batadv_coded_packet));
 #endif
+#ifdef CONFIG_BATMAN_ADV_AGGR
+	header_len = max_t(int, header_len,
+			   sizeof(struct batadv_aggr_packet) +
+			   sizeof(struct batadv_tvlv_hdr) +
+			   sizeof(struct batadv_bcast_packet) -
+			   sizeof(((struct batadv_bcast_packet *)0)
+				   ->packet_type) -
+			   sizeof(((struct batadv_bcast_packet *)0)
+				   ->version));
+#endif
 
 	return header_len + ETH_HLEN;
 }
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h
index a6cc804..4491a98 100644
--- a/net/batman-adv/main.h
+++ b/net/batman-adv/main.h
@@ -148,6 +148,7 @@ enum batadv_mesh_state {
 
 #define BATADV_BCAST_QUEUE_LEN		256
 #define BATADV_BATMAN_QUEUE_LEN	256
+#define BATADV_AGGR_QUEUE_LEN	512
 
 enum batadv_uev_action {
 	BATADV_UEV_ADD = 0,
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index b002856..3c6144d 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -39,6 +39,7 @@
 #include <net/sock.h>
 #include <uapi/linux/batman_adv.h>
 
+#include "aggregation.h"
 #include "bat_algo.h"
 #include "distributed-arp-table.h"
 #include "fragmentation.h"
@@ -902,6 +903,7 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu)
 	batadv_mcast_purge_orig(orig_node);
 
 	batadv_frag_purge_orig(orig_node, NULL);
+	batadv_aggr_purge_orig(orig_node);
 
 	if (orig_node->bat_priv->algo_ops->orig.free)
 		orig_node->bat_priv->algo_ops->orig.free(orig_node);
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c
index 8e5baa0..731b807 100644
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@ -40,6 +40,7 @@
 #include <linux/stddef.h>
 #include <linux/workqueue.h>
 
+#include "aggregation.h"
 #include "distributed-arp-table.h"
 #include "fragmentation.h"
 #include "gateway_client.h"
@@ -124,6 +125,14 @@ send_skb_err:
 int batadv_send_broadcast_skb(struct sk_buff *skb,
 			      struct batadv_hard_iface *hard_iface)
 {
+	int ret;
+
+	skb_reset_network_header(skb);
+
+	ret = batadv_aggr_queue(skb, hard_iface);
+	if (ret == NET_XMIT_SUCCESS)
+		return ret;
+
 	return batadv_send_skb_packet(skb, hard_iface, batadv_broadcast_addr);
 }
 
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index fce69b7..c38805f 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -799,7 +799,10 @@ static int batadv_softif_init_late(struct net_device *dev)
 	if (!bat_priv->bat_counters)
 		return -ENOMEM;
 
-	atomic_set(&bat_priv->aggregated_ogms, 1);
+	atomic_set(&bat_priv->aggregation, 1);
+#ifdef CONFIG_BATMAN_ADV_AGGR
+	atomic_set(&bat_priv->aggr_num_disabled, 0);
+#endif
 	atomic_set(&bat_priv->bonding, 0);
 #ifdef CONFIG_BATMAN_ADV_BLA
 	atomic_set(&bat_priv->bridge_loop_avoidance, 1);
@@ -1151,10 +1154,16 @@ static const struct {
 	{ "frag_fwd" },
 	{ "frag_fwd_bytes" },
 #ifdef CONFIG_BATMAN_ADV_AGGR
+	{ "aggr_tx" },
+	{ "aggr_tx_bytes" },
 	{ "aggr_rx" },
 	{ "aggr_rx_bytes" },
+	{ "aggr_parts_tx" },
+	{ "aggr_parts_tx_bytes" },
 	{ "aggr_parts_rx" },
 	{ "aggr_parts_rx_bytes" },
+	{ "aggr_queue_full" },
+	{ "aggr_urgent" },
 #endif
 	{ "tt_request_tx" },
 	{ "tt_request_rx" },
diff --git a/net/batman-adv/sysfs.c b/net/batman-adv/sysfs.c
index 17c8441..5679e2f 100644
--- a/net/batman-adv/sysfs.c
+++ b/net/batman-adv/sysfs.c
@@ -665,7 +665,9 @@ static ssize_t batadv_store_isolation_mark(struct kobject *kobj,
 	return count;
 }
 
-BATADV_ATTR_SIF_BOOL(aggregated_ogms, 0644, NULL);
+BATADV_ATTR_SIF_BOOL(aggregation, 0644, NULL);
+static BATADV_ATTR(aggregated_ogms, 0644, batadv_show_aggregation,
+		   batadv_store_aggregation);
 BATADV_ATTR_SIF_BOOL(bonding, 0644, NULL);
 #ifdef CONFIG_BATMAN_ADV_BLA
 BATADV_ATTR_SIF_BOOL(bridge_loop_avoidance, 0644, batadv_bla_status_update);
@@ -698,6 +700,7 @@ static BATADV_ATTR(isolation_mark, 0644, batadv_show_isolation_mark,
 
 static struct batadv_attribute *batadv_mesh_attrs[] = {
 	&batadv_attr_aggregated_ogms,
+	&batadv_attr_aggregation,
 	&batadv_attr_bonding,
 #ifdef CONFIG_BATMAN_ADV_BLA
 	&batadv_attr_bridge_loop_avoidance,
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index e2dbb5a..8964d02 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -145,6 +145,20 @@ enum batadv_hard_iface_wifi_flags {
 	BATADV_HARDIF_WIFI_CFG80211_INDIRECT = BIT(3),
 };
 
+#ifdef CONFIG_BATMAN_ADV_AGGR
+/**
+ * struct batadv_hard_iface_aggr - per hard-interface aggregation data
+ * @aggr_list: list for to be aggregated broadcast packets
+ * @aggr_list_lock: lock protecting aggr_list
+ * @work: work item for periodic aggregation packet transmissions
+ */
+struct batadv_hard_iface_aggr {
+	struct sk_buff_head aggr_list;
+	spinlock_t aggr_list_lock; /* protects aggr_list */
+	struct delayed_work work;
+};
+#endif
+
 /**
  * struct batadv_hard_iface - network device known to batman-adv
  * @list: list node for batadv_hardif_list
@@ -161,6 +175,7 @@ enum batadv_hard_iface_wifi_flags {
  * @rcu: struct used for freeing in an RCU-safe manner
  * @bat_iv: per hard-interface B.A.T.M.A.N. IV data
  * @bat_v: per hard-interface B.A.T.M.A.N. V data
+ * @aggr: per hard-interface aggregation data
  * @debug_dir: dentry for nc subdir in batman-adv directory in debugfs
  * @neigh_list: list of unique single hop neighbors via this interface
  * @neigh_list_lock: lock protecting neigh_list
@@ -181,6 +196,9 @@ struct batadv_hard_iface {
 #ifdef CONFIG_BATMAN_ADV_BATMAN_V
 	struct batadv_hard_iface_bat_v bat_v;
 #endif
+#ifdef CONFIG_BATMAN_ADV_AGGR
+	struct batadv_hard_iface_aggr aggr;
+#endif
 	struct dentry *debug_dir;
 	struct hlist_head neigh_list;
 	/* neigh_list_lock protects: neigh_list */
@@ -388,12 +406,14 @@ struct batadv_orig_node {
  * @BATADV_ORIG_CAPA_HAS_TT: orig node has tt capability
  * @BATADV_ORIG_CAPA_HAS_MCAST: orig node has some multicast capability
  *  (= orig node announces a tvlv of type BATADV_TVLV_MCAST)
+ * @BATADV_ORIG_CAPA_HAS_AGGR: orig node has broadcast aggregation capability
  */
 enum batadv_orig_capabilities {
 	BATADV_ORIG_CAPA_HAS_DAT,
 	BATADV_ORIG_CAPA_HAS_NC,
 	BATADV_ORIG_CAPA_HAS_TT,
 	BATADV_ORIG_CAPA_HAS_MCAST,
+	BATADV_ORIG_CAPA_HAS_AGGR,
 };
 
 /**
@@ -575,10 +595,17 @@ struct batadv_bcast_duplist_entry {
  * @BATADV_CNT_FRAG_RX_BYTES: received fragment traffic bytes counter
  * @BATADV_CNT_FRAG_FWD: forwarded fragment traffic packet counter
  * @BATADV_CNT_FRAG_FWD_BYTES: forwarded fragment traffic bytes counter
+ * @BATADV_CNT_AGGR_TX: transmitted aggregation traffic packet count
+ * @BATADV_CNT_AGGR_TX_BYTES: transmitted aggregation traffic bytes counter
  * @BATADV_CNT_AGGR_RX: received aggregation traffic packet count
  * @BATADV_CNT_AGGR_RX_BYTES: received aggregation traffic bytes counter
+ * @BATADV_CNT_AGGR_PARTS_TX: transmitted aggregated traffic packet counter
+ * @BATADV_CNT_AGGR_PARTS_TX_BYTES: transmitted aggregated bytes counter
  * @BATADV_CNT_AGGR_PARTS_RX: received aggregated traffic packet counter
  * @BATADV_CNT_AGGR_PARTS_RX_BYTES: received aggregated bytes counter
+ * @BATADV_CNT_AGGR_QUEUE_FULL: counter for packets dismissed for aggregation
+ *  due to a full aggregation queue
+ * @BATADV_CNT_AGGR_URGENT: counter for early aggregation packet transmissions
  * @BATADV_CNT_TT_REQUEST_TX: transmitted tt req traffic packet counter
  * @BATADV_CNT_TT_REQUEST_RX: received tt req traffic packet counter
  * @BATADV_CNT_TT_RESPONSE_TX: transmitted tt resp traffic packet counter
@@ -623,10 +650,16 @@ enum batadv_counters {
 	BATADV_CNT_FRAG_FWD,
 	BATADV_CNT_FRAG_FWD_BYTES,
 #ifdef CONFIG_BATMAN_ADV_AGGR
+	BATADV_CNT_AGGR_TX,
+	BATADV_CNT_AGGR_TX_BYTES,
 	BATADV_CNT_AGGR_RX,
 	BATADV_CNT_AGGR_RX_BYTES,
+	BATADV_CNT_AGGR_PARTS_TX,
+	BATADV_CNT_AGGR_PARTS_TX_BYTES,
 	BATADV_CNT_AGGR_PARTS_RX,
 	BATADV_CNT_AGGR_PARTS_RX_BYTES,
+	BATADV_CNT_AGGR_QUEUE_FULL,
+	BATADV_CNT_AGGR_URGENT,
 #endif
 	BATADV_CNT_TT_REQUEST_TX,
 	BATADV_CNT_TT_REQUEST_RX,
@@ -1031,7 +1064,9 @@ struct batadv_priv_bat_v {
  * @soft_iface: net device which holds this struct as private data
  * @stats: structure holding the data for the ndo_get_stats() call
  * @bat_counters: mesh internal traffic statistic counters (see batadv_counters)
- * @aggregated_ogms: bool indicating whether OGM aggregation is enabled
+ * @aggregation: bool indicating whether aggregation is enabled
+ * @aggr_num_disabled: number of nodes that have no broadcast aggregation
+ *  capability
  * @bonding: bool indicating whether traffic bonding is enabled
  * @fragmentation: bool indicating whether traffic fragmentation is enabled
  * @packet_size_max: max packet size that can be transmitted via
@@ -1086,7 +1121,10 @@ struct batadv_priv {
 	struct net_device *soft_iface;
 	struct net_device_stats stats;
 	u64 __percpu *bat_counters; /* Per cpu counters */
-	atomic_t aggregated_ogms;
+	atomic_t aggregation;
+#ifdef CONFIG_BATMAN_ADV_AGGR
+	atomic_t aggr_num_disabled;
+#endif
 	atomic_t bonding;
 	atomic_t fragmentation;
 	atomic_t packet_size_max;
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [B.A.T.M.A.N.] [RFC PATCH 4/6] batman-adv: privatize forw_packet skb assignment
  2016-12-19 11:25 [B.A.T.M.A.N.] [RFC PATCH 0/6] batman-adv: broadcast packet aggregation Linus Lüssing
                   ` (2 preceding siblings ...)
  2016-12-19 11:25 ` [B.A.T.M.A.N.] [RFC PATCH 3/6] batman-adv: aggregation packet queueing and transmission Linus Lüssing
@ 2016-12-19 11:25 ` Linus Lüssing
  2016-12-19 11:25 ` [B.A.T.M.A.N.] [RFC PATCH 5/6] batman-adv: restructure rebroadcast counter into forw_packet API Linus Lüssing
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Linus Lüssing @ 2016-12-19 11:25 UTC (permalink / raw)
  To: b.a.t.m.a.n

An skb is assigned to a forw_packet only once, shortly after the
forw_packet allocation.

With this patch the assignment is moved into the this allocation
function.

Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
---
 net/batman-adv/bat_iv_ogm.c | 17 +++++++++--------
 net/batman-adv/send.c       | 21 ++++++++++++---------
 net/batman-adv/send.h       |  3 ++-
 3 files changed, 23 insertions(+), 18 deletions(-)

diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
index 1b1c932..86a874d 100644
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -679,15 +679,11 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
 {
 	struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
 	struct batadv_forw_packet *forw_packet_aggr;
+	struct sk_buff *skb;
 	unsigned char *skb_buff;
 	unsigned int skb_size;
 	atomic_t *queue_left = own_packet ? NULL : &bat_priv->batman_queue_left;
 
-	forw_packet_aggr = batadv_forw_packet_alloc(if_incoming, if_outgoing,
-						    queue_left, bat_priv);
-	if (!forw_packet_aggr)
-		return;
-
 	if (atomic_read(&bat_priv->aggregation) &&
 	    packet_len < BATADV_MAX_AGGREGATION_BYTES)
 		skb_size = BATADV_MAX_AGGREGATION_BYTES;
@@ -696,9 +692,14 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
 
 	skb_size += ETH_HLEN;
 
-	forw_packet_aggr->skb = netdev_alloc_skb_ip_align(NULL, skb_size);
-	if (!forw_packet_aggr->skb) {
-		batadv_forw_packet_free(forw_packet_aggr, true);
+	skb = netdev_alloc_skb_ip_align(NULL, skb_size);
+	if (!skb)
+		return;
+
+	forw_packet_aggr = batadv_forw_packet_alloc(if_incoming, if_outgoing,
+						    queue_left, bat_priv, skb);
+	if (!forw_packet_aggr) {
+		kfree_skb(skb);
 		return;
 	}
 
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c
index 731b807..b58f8a9 100644
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@ -489,6 +489,7 @@ void batadv_forw_packet_free(struct batadv_forw_packet *forw_packet,
  * @if_outgoing: The (optional) if_outgoing to be grabbed
  * @queue_left: The (optional) queue counter to decrease
  * @bat_priv: The bat_priv for the mesh of this forw_packet
+ * @skb: The raw packet this forwarding packet shall contain
  *
  * Allocates a forwarding packet and tries to get a reference to the
  * (optional) if_incoming, if_outgoing and queue_left. If queue_left
@@ -500,7 +501,8 @@ struct batadv_forw_packet *
 batadv_forw_packet_alloc(struct batadv_hard_iface *if_incoming,
 			 struct batadv_hard_iface *if_outgoing,
 			 atomic_t *queue_left,
-			 struct batadv_priv *bat_priv)
+			 struct batadv_priv *bat_priv,
+			 struct sk_buff *skb)
 {
 	struct batadv_forw_packet *forw_packet;
 	const char *qname;
@@ -532,7 +534,7 @@ batadv_forw_packet_alloc(struct batadv_hard_iface *if_incoming,
 
 	INIT_HLIST_NODE(&forw_packet->list);
 	INIT_HLIST_NODE(&forw_packet->cleanup_list);
-	forw_packet->skb = NULL;
+	forw_packet->skb = skb;
 	forw_packet->queue_left = queue_left;
 	forw_packet->if_incoming = if_incoming;
 	forw_packet->if_outgoing = if_outgoing;
@@ -763,22 +765,23 @@ int batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv,
 	if (!primary_if)
 		goto err;
 
+	newskb = skb_copy(skb, GFP_ATOMIC);
+	if (!newskb) {
+		batadv_hardif_put(primary_if);
+		goto err;
+	}
+
 	forw_packet = batadv_forw_packet_alloc(primary_if, NULL,
 					       &bat_priv->bcast_queue_left,
-					       bat_priv);
+					       bat_priv, newskb);
 	batadv_hardif_put(primary_if);
 	if (!forw_packet)
-		goto err;
-
-	newskb = skb_copy(skb, GFP_ATOMIC);
-	if (!newskb)
 		goto err_packet_free;
 
 	/* as we have a copy now, it is safe to decrease the TTL */
 	bcast_packet = (struct batadv_bcast_packet *)newskb->data;
 	bcast_packet->ttl--;
 
-	forw_packet->skb = newskb;
 	forw_packet->own = own_packet;
 
 	INIT_DELAYED_WORK(&forw_packet->delayed_work,
@@ -788,7 +791,7 @@ int batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv,
 	return NETDEV_TX_OK;
 
 err_packet_free:
-	batadv_forw_packet_free(forw_packet, true);
+	kfree_skb(newskb);
 err:
 	return NETDEV_TX_BUSY;
 }
diff --git a/net/batman-adv/send.h b/net/batman-adv/send.h
index a94e1e8..4506312 100644
--- a/net/batman-adv/send.h
+++ b/net/batman-adv/send.h
@@ -34,7 +34,8 @@ struct batadv_forw_packet *
 batadv_forw_packet_alloc(struct batadv_hard_iface *if_incoming,
 			 struct batadv_hard_iface *if_outgoing,
 			 atomic_t *queue_left,
-			 struct batadv_priv *bat_priv);
+			 struct batadv_priv *bat_priv,
+			 struct sk_buff *skb);
 bool batadv_forw_packet_steal(struct batadv_forw_packet *packet, spinlock_t *l);
 void batadv_forw_packet_ogmv1_queue(struct batadv_priv *bat_priv,
 				    struct batadv_forw_packet *forw_packet,
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [B.A.T.M.A.N.] [RFC PATCH 5/6] batman-adv: restructure rebroadcast counter into forw_packet API
  2016-12-19 11:25 [B.A.T.M.A.N.] [RFC PATCH 0/6] batman-adv: broadcast packet aggregation Linus Lüssing
                   ` (3 preceding siblings ...)
  2016-12-19 11:25 ` [B.A.T.M.A.N.] [RFC PATCH 4/6] batman-adv: privatize forw_packet skb assignment Linus Lüssing
@ 2016-12-19 11:25 ` Linus Lüssing
  2016-12-19 11:25 ` [B.A.T.M.A.N.] [RFC PATCH 6/6] batman-adv: do not aggregate rebroadcasts in the same packet Linus Lüssing
  2017-01-22 13:08 ` [B.A.T.M.A.N.] [RFC PATCH 0/6] batman-adv: broadcast packet aggregation Sven Eckelmann
  6 siblings, 0 replies; 10+ messages in thread
From: Linus Lüssing @ 2016-12-19 11:25 UTC (permalink / raw)
  To: b.a.t.m.a.n

This patch refactors the num_packets counter of a forw_packet in the
following three ways:

1) Removed dual-use of forw_packet::num_packets:
   -> now for aggregation purposes only
2) Using forw_packet::skb::cb::num_bcasts instead:
   -> for easier access in aggregation code later
3) make access to num_bcasts private to batadv_forw_packet_*()

Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
---
 net/batman-adv/distributed-arp-table.c |  2 +-
 net/batman-adv/main.c                  |  3 ++
 net/batman-adv/send.c                  | 50 ++++++++++++++++++++++++++++++++--
 net/batman-adv/send.h                  |  1 +
 net/batman-adv/types.h                 |  4 ++-
 5 files changed, 55 insertions(+), 5 deletions(-)

diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c
index 689278e..3c222de 100644
--- a/net/batman-adv/distributed-arp-table.c
+++ b/net/batman-adv/distributed-arp-table.c
@@ -1257,7 +1257,7 @@ bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv,
 	/* If this packet is an ARP_REQUEST and the node already has the
 	 * information that it is going to ask, then the packet can be dropped
 	 */
-	if (forw_packet->num_packets)
+	if (batadv_forw_packet_is_rebroadcast(forw_packet))
 		goto out;
 
 	vid = batadv_dat_get_vid(forw_packet->skb, &hdr_size);
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index 286163d..e4ee067 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -534,6 +534,9 @@ static void batadv_recv_handler_init(void)
 	BUILD_BUG_ON(sizeof(struct batadv_tvlv_tt_change) != 12);
 	BUILD_BUG_ON(sizeof(struct batadv_tvlv_roam_adv) != 8);
 
+	i = FIELD_SIZEOF(struct sk_buff, cb);
+	BUILD_BUG_ON(sizeof(struct batadv_skb_cb) > i);
+
 	/* broadcast packet */
 	batadv_rx_handler[BATADV_BCAST] = batadv_recv_bcast_packet;
 
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c
index b58f8a9..b3f05b4 100644
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@ -796,6 +796,50 @@ err:
 	return NETDEV_TX_BUSY;
 }
 
+/**
+ * batadv_forw_packet_bcasts_left - check if a retransmission is necessary
+ * @forw_packet: the forwarding packet to check
+ * @hard_iface: the interface to check on
+ *
+ * Checks whether a given packet has any (re)transmissions left on the provided
+ * interface.
+ *
+ * hard_iface may be NULL: In that case the number of transmissions this skb had
+ * so far is compared with the maximum amount of retransmissions independent of
+ * any interface instead.
+ *
+ * Return: True if (re)transmissions are left, false otherwise.
+ */
+static bool
+batadv_forw_packet_bcasts_left(struct batadv_forw_packet *forw_packet,
+			       struct batadv_hard_iface *hard_iface)
+{
+	int max = hard_iface ? hard_iface->num_bcasts : BATADV_NUM_BCASTS_MAX;
+
+	return BATADV_SKB_CB(forw_packet->skb)->num_bcasts < max;
+}
+
+/**
+ * batadv_forw_packet_bcasts_inc - increment retransmission counter of a packet
+ * @forw_packet: the packet to increase the counter for
+ */
+static void
+batadv_forw_packet_bcasts_inc(struct batadv_forw_packet *forw_packet)
+{
+	BATADV_SKB_CB(forw_packet->skb)->num_bcasts++;
+}
+
+/**
+ * batadv_forw_packet_is_rebroadcast - check packet for previous transmissions
+ * @forw_packet: the packet to check
+ *
+ * Return: True if this packet was transmitted before, false otherwise.
+ */
+bool batadv_forw_packet_is_rebroadcast(struct batadv_forw_packet *forw_packet)
+{
+	return BATADV_SKB_CB(forw_packet->skb)->num_bcasts > 0;
+}
+
 static void batadv_send_outstanding_bcast_packet(struct work_struct *work)
 {
 	struct batadv_hard_iface *hard_iface;
@@ -835,7 +879,7 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work)
 		if (hard_iface->soft_iface != soft_iface)
 			continue;
 
-		if (forw_packet->num_packets >= hard_iface->num_bcasts)
+		if (!batadv_forw_packet_bcasts_left(forw_packet, hard_iface))
 			continue;
 
 		if (forw_packet->own) {
@@ -894,10 +938,10 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work)
 	}
 	rcu_read_unlock();
 
-	forw_packet->num_packets++;
+	batadv_forw_packet_bcasts_inc(forw_packet);
 
 	/* if we still have some more bcasts to send */
-	if (forw_packet->num_packets < BATADV_NUM_BCASTS_MAX) {
+	if (batadv_forw_packet_bcasts_left(forw_packet, NULL)) {
 		batadv_forw_packet_bcast_queue(bat_priv, forw_packet,
 					       send_time);
 		return;
diff --git a/net/batman-adv/send.h b/net/batman-adv/send.h
index 4506312..ae0e1c4 100644
--- a/net/batman-adv/send.h
+++ b/net/batman-adv/send.h
@@ -40,6 +40,7 @@ bool batadv_forw_packet_steal(struct batadv_forw_packet *packet, spinlock_t *l);
 void batadv_forw_packet_ogmv1_queue(struct batadv_priv *bat_priv,
 				    struct batadv_forw_packet *forw_packet,
 				    unsigned long send_time);
+bool batadv_forw_packet_is_rebroadcast(struct batadv_forw_packet *forw_packet);
 
 int batadv_send_skb_to_orig(struct sk_buff *skb,
 			    struct batadv_orig_node *orig_node,
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 8964d02..e025452 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -1444,9 +1444,11 @@ struct batadv_nc_packet {
  *  relevant to batman-adv in the skb->cb buffer in skbs.
  * @decoded: Marks a skb as decoded, which is checked when searching for coding
  *  opportunities in network-coding.c
+ * @num_bcasts: Counter for broadcast packet retransmissions
  */
 struct batadv_skb_cb {
 	bool decoded;
+	int num_bcasts;
 };
 
 /**
@@ -1459,7 +1461,7 @@ struct batadv_skb_cb {
  * @skb: bcast packet's skb buffer
  * @packet_len: size of aggregated OGM packet inside the skb buffer
  * @direct_link_flags: direct link flags for aggregated OGM packets
- * @num_packets: counter for bcast packet retransmission
+ * @num_packets: counter for aggregated OGMv1 packets
  * @delayed_work: work queue callback item for packet sending
  * @if_incoming: pointer to incoming hard-iface or primary iface if
  *  locally generated packet
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [B.A.T.M.A.N.] [RFC PATCH 6/6] batman-adv: do not aggregate rebroadcasts in the same packet
  2016-12-19 11:25 [B.A.T.M.A.N.] [RFC PATCH 0/6] batman-adv: broadcast packet aggregation Linus Lüssing
                   ` (4 preceding siblings ...)
  2016-12-19 11:25 ` [B.A.T.M.A.N.] [RFC PATCH 5/6] batman-adv: restructure rebroadcast counter into forw_packet API Linus Lüssing
@ 2016-12-19 11:25 ` Linus Lüssing
  2017-01-22 13:08 ` [B.A.T.M.A.N.] [RFC PATCH 0/6] batman-adv: broadcast packet aggregation Sven Eckelmann
  6 siblings, 0 replies; 10+ messages in thread
From: Linus Lüssing @ 2016-12-19 11:25 UTC (permalink / raw)
  To: b.a.t.m.a.n

With this patch, aggregating a broadcast packet multiple times into the
same aggregation packet is avoided. Otherwise such aggregation would
defeat the purpose of retransmissions (i.e. increasing reliability).

Instead packets which are supposed to be retransmitted are just put
back into the aggregation queue and will be part of the next aggregation
packet again.

Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
---
 net/batman-adv/aggregation.c | 69 +++++++++++++++++++++++++++++++++++---------
 net/batman-adv/bat_iv_ogm.c  |  3 +-
 net/batman-adv/send.c        | 58 +++++++++++++++++++++++++++++++++----
 net/batman-adv/send.h        |  8 ++++-
 net/batman-adv/types.h       |  3 ++
 5 files changed, 120 insertions(+), 21 deletions(-)

diff --git a/net/batman-adv/aggregation.c b/net/batman-adv/aggregation.c
index 815da11..d13576e 100644
--- a/net/batman-adv/aggregation.c
+++ b/net/batman-adv/aggregation.c
@@ -253,7 +253,41 @@ batadv_aggr_queue_is_full(struct batadv_hard_iface *hard_iface)
 }
 
 /**
+ * batadv_aggr_queue_tail - add packet to tail of an aggregation queue
+ * @skb: the packet to queue
+ * @hard_iface: the interface to queue on
+ *
+ * Tries to add a broadcast packet to an aggregation queue. This might fail if
+ * the queue has no more free slots available. In that case, the caller needs to
+ * take care of freeing the skb.
+ *
+ * Return: True on successful queueing, false otherwise.
+ */
+static bool batadv_aggr_queue_tail(struct sk_buff *skb,
+				   struct batadv_hard_iface *hard_iface)
+{
+	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
+	bool ret = true;
+
+	spin_lock_bh(&hard_iface->aggr.aggr_list_lock);
+	if (batadv_aggr_queue_is_full(hard_iface)) {
+		batadv_inc_counter(bat_priv, BATADV_CNT_AGGR_QUEUE_FULL);
+		ret = false;
+	} else {
+		batadv_inc_counter(bat_priv, BATADV_CNT_AGGR_PARTS_TX);
+		batadv_add_counter(bat_priv, BATADV_CNT_AGGR_PARTS_TX_BYTES,
+				   skb->len + ETH_HLEN);
+
+		skb_queue_tail(&hard_iface->aggr.aggr_list, skb);
+	}
+	spin_unlock_bh(&hard_iface->aggr.aggr_list_lock);
+
+	return ret;
+}
+
+/**
  * batadv_aggr_squash_chunk - squash packets into an aggregate
+ * @hard_iface: the interface to potentially requeue on
  * @head: a list of to be squashed packets
  * @size: the size of the to be created aggregation packet
  *  (excluding the ethernet header)
@@ -261,11 +295,14 @@ batadv_aggr_queue_is_full(struct batadv_hard_iface *hard_iface)
  * Allocates an aggregation packet and squashes the provided list of broadcast
  * packets into it. The provided list of packets is freed/consumed.
  *
+ * Batman broadcast packets are potentially requeued.
+ *
  * Return: An aggregation packet ready for transmission on success, NULL
  * otherwise.
  */
 static struct sk_buff *
-batadv_aggr_squash_chunk(struct sk_buff_head *head,
+batadv_aggr_squash_chunk(struct batadv_hard_iface *hard_iface,
+			 struct sk_buff_head *head,
 			 int size)
 {
 	struct sk_buff *skb, *skb_tmp, *skb_aggr;
@@ -296,7 +333,15 @@ batadv_aggr_squash_chunk(struct sk_buff_head *head,
 		to = skb_put(skb_aggr, len);
 		skb_copy_bits(skb, offset, to, len);
 		skb_unlink(skb, head);
-		consume_skb(skb);
+
+		batadv_send_bcasts_inc(skb);
+
+		if (batadv_send_bcasts_left(skb, hard_iface)) {
+			if (!batadv_aggr_queue_tail(skb, hard_iface))
+				kfree_skb(skb);
+		} else {
+			consume_skb(skb);
+		}
 
 		tvlv_len += len + sizeof(struct batadv_tvlv_hdr);
 	}
@@ -345,7 +390,7 @@ static bool batadv_aggr_send_chunk(struct batadv_hard_iface *hard_iface)
 	skb_queue_head_init(&head);
 	emptied = batadv_aggr_get_chunk(hard_iface, &head, &size);
 
-	skb = batadv_aggr_squash_chunk(&head, size);
+	skb = batadv_aggr_squash_chunk(hard_iface, &head, size);
 	if (!skb)
 		goto out;
 
@@ -394,6 +439,7 @@ static void batadv_aggr_work(struct work_struct *work)
 int batadv_aggr_queue(struct sk_buff *skb, struct batadv_hard_iface *hard_iface)
 {
 	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
+	int ret;
 
 	if (!atomic_read(&bat_priv->aggregation))
 		return NET_XMIT_DROP;
@@ -401,18 +447,15 @@ int batadv_aggr_queue(struct sk_buff *skb, struct batadv_hard_iface *hard_iface)
 	if (atomic_read(&bat_priv->aggr_num_disabled))
 		return NET_XMIT_DROP;
 
-	if (batadv_aggr_queue_is_full(hard_iface)) {
-		batadv_inc_counter(bat_priv, BATADV_CNT_AGGR_QUEUE_FULL);
-		return NET_XMIT_DROP;
+	/* we handle rebroadcasts here instead of the forw_packet API */
+	if (batadv_send_is_rebroadcast(skb)) {
+		consume_skb(skb);
+		return NET_XMIT_SUCCESS;
 	}
 
-	spin_lock_bh(&hard_iface->aggr.aggr_list_lock);
-	skb_queue_tail(&hard_iface->aggr.aggr_list, skb);
-	spin_unlock_bh(&hard_iface->aggr.aggr_list_lock);
-
-	batadv_inc_counter(bat_priv, BATADV_CNT_AGGR_PARTS_TX);
-	batadv_add_counter(bat_priv, BATADV_CNT_AGGR_PARTS_TX_BYTES,
-			   skb->len + ETH_HLEN);
+	ret = batadv_aggr_queue_tail(skb, hard_iface);
+	if (!ret)
+		return NET_XMIT_DROP;
 
 	return NET_XMIT_SUCCESS;
 }
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
index 86a874d..fd4eeb3 100644
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -697,7 +697,8 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
 		return;
 
 	forw_packet_aggr = batadv_forw_packet_alloc(if_incoming, if_outgoing,
-						    queue_left, bat_priv, skb);
+						    queue_left, bat_priv, skb,
+						    false);
 	if (!forw_packet_aggr) {
 		kfree_skb(skb);
 		return;
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c
index b3f05b4..8462edd 100644
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@ -490,6 +490,8 @@ void batadv_forw_packet_free(struct batadv_forw_packet *forw_packet,
  * @queue_left: The (optional) queue counter to decrease
  * @bat_priv: The bat_priv for the mesh of this forw_packet
  * @skb: The raw packet this forwarding packet shall contain
+ * @resend: Whether this packet should be transmitted more than once on wireless
+ *  interfaces
  *
  * Allocates a forwarding packet and tries to get a reference to the
  * (optional) if_incoming, if_outgoing and queue_left. If queue_left
@@ -502,7 +504,8 @@ batadv_forw_packet_alloc(struct batadv_hard_iface *if_incoming,
 			 struct batadv_hard_iface *if_outgoing,
 			 atomic_t *queue_left,
 			 struct batadv_priv *bat_priv,
-			 struct sk_buff *skb)
+			 struct sk_buff *skb,
+			 bool resend)
 {
 	struct batadv_forw_packet *forw_packet;
 	const char *qname;
@@ -540,6 +543,8 @@ batadv_forw_packet_alloc(struct batadv_hard_iface *if_incoming,
 	forw_packet->if_outgoing = if_outgoing;
 	forw_packet->num_packets = 0;
 
+	BATADV_SKB_CB(forw_packet->skb)->resend = resend;
+
 	return forw_packet;
 
 err:
@@ -773,7 +778,7 @@ int batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv,
 
 	forw_packet = batadv_forw_packet_alloc(primary_if, NULL,
 					       &bat_priv->bcast_queue_left,
-					       bat_priv, newskb);
+					       bat_priv, newskb, true);
 	batadv_hardif_put(primary_if);
 	if (!forw_packet)
 		goto err_packet_free;
@@ -797,6 +802,29 @@ err:
 }
 
 /**
+ * batadv_send_bcasts_left - check if a retransmission is necessary
+ * @skb: the packet to check
+ * @hard_iface: the interface to check on
+ *
+ * Checks whether a given packet has any (re)transmissions left on the provided
+ * interface.
+ *
+ * hard_iface may be NULL: In that case the number of transmissions this skb had
+ * so far is compared with the maximum amount of retransmissions independent of
+ * any interface instead.
+ *
+ * Return: True if (re)transmissions are left, false otherwise.
+ */
+bool batadv_send_bcasts_left(struct sk_buff *skb,
+			     struct batadv_hard_iface *hard_iface)
+{
+	int max = hard_iface ? hard_iface->num_bcasts : BATADV_NUM_BCASTS_MAX;
+	bool resend = !hard_iface || BATADV_SKB_CB(skb)->resend;
+
+	return resend && BATADV_SKB_CB(skb)->num_bcasts < max;
+}
+
+/**
  * batadv_forw_packet_bcasts_left - check if a retransmission is necessary
  * @forw_packet: the forwarding packet to check
  * @hard_iface: the interface to check on
@@ -814,9 +842,16 @@ static bool
 batadv_forw_packet_bcasts_left(struct batadv_forw_packet *forw_packet,
 			       struct batadv_hard_iface *hard_iface)
 {
-	int max = hard_iface ? hard_iface->num_bcasts : BATADV_NUM_BCASTS_MAX;
+	return batadv_send_bcasts_left(forw_packet->skb, hard_iface);
+}
 
-	return BATADV_SKB_CB(forw_packet->skb)->num_bcasts < max;
+/**
+ * batadv_send_bcasts_inc - increment the retransmission counter of an skb
+ * @skb: the packet to increase the counter for
+ */
+void batadv_send_bcasts_inc(struct sk_buff *skb)
+{
+	BATADV_SKB_CB(skb)->num_bcasts++;
 }
 
 /**
@@ -826,7 +861,18 @@ batadv_forw_packet_bcasts_left(struct batadv_forw_packet *forw_packet,
 static void
 batadv_forw_packet_bcasts_inc(struct batadv_forw_packet *forw_packet)
 {
-	BATADV_SKB_CB(forw_packet->skb)->num_bcasts++;
+	batadv_send_bcasts_inc(forw_packet->skb);
+}
+
+/**
+ * batadv_send_is_rebroadcast - check whether this packet was transmitted before
+ * @skb: the packet to check
+ *
+ * Return: True if this packet was transmitted already, false otherwise.
+ */
+bool batadv_send_is_rebroadcast(struct sk_buff *skb)
+{
+	return BATADV_SKB_CB(skb)->num_bcasts > 0;
 }
 
 /**
@@ -837,7 +883,7 @@ batadv_forw_packet_bcasts_inc(struct batadv_forw_packet *forw_packet)
  */
 bool batadv_forw_packet_is_rebroadcast(struct batadv_forw_packet *forw_packet)
 {
-	return BATADV_SKB_CB(forw_packet->skb)->num_bcasts > 0;
+	return batadv_send_is_rebroadcast(forw_packet->skb);
 }
 
 static void batadv_send_outstanding_bcast_packet(struct work_struct *work)
diff --git a/net/batman-adv/send.h b/net/batman-adv/send.h
index ae0e1c4..c006f1e 100644
--- a/net/batman-adv/send.h
+++ b/net/batman-adv/send.h
@@ -35,13 +35,19 @@ batadv_forw_packet_alloc(struct batadv_hard_iface *if_incoming,
 			 struct batadv_hard_iface *if_outgoing,
 			 atomic_t *queue_left,
 			 struct batadv_priv *bat_priv,
-			 struct sk_buff *skb);
+			 struct sk_buff *skb,
+			 bool resend);
 bool batadv_forw_packet_steal(struct batadv_forw_packet *packet, spinlock_t *l);
 void batadv_forw_packet_ogmv1_queue(struct batadv_priv *bat_priv,
 				    struct batadv_forw_packet *forw_packet,
 				    unsigned long send_time);
 bool batadv_forw_packet_is_rebroadcast(struct batadv_forw_packet *forw_packet);
 
+bool batadv_send_bcasts_left(struct sk_buff *skb,
+			     struct batadv_hard_iface *hard_iface);
+void batadv_send_bcasts_inc(struct sk_buff *skb);
+bool batadv_send_is_rebroadcast(struct sk_buff *skb);
+
 int batadv_send_skb_to_orig(struct sk_buff *skb,
 			    struct batadv_orig_node *orig_node,
 			    struct batadv_hard_iface *recv_if);
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index e025452..e61108b 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -1445,10 +1445,13 @@ struct batadv_nc_packet {
  * @decoded: Marks a skb as decoded, which is checked when searching for coding
  *  opportunities in network-coding.c
  * @num_bcasts: Counter for broadcast packet retransmissions
+ * @resend: Whether this packet should be transmitted more than once on wireless
+ *  interfaces
  */
 struct batadv_skb_cb {
 	bool decoded;
 	int num_bcasts;
+	bool resend;
 };
 
 /**
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [B.A.T.M.A.N.] [RFC PATCH 0/6] batman-adv: broadcast packet aggregation
  2016-12-19 11:25 [B.A.T.M.A.N.] [RFC PATCH 0/6] batman-adv: broadcast packet aggregation Linus Lüssing
                   ` (5 preceding siblings ...)
  2016-12-19 11:25 ` [B.A.T.M.A.N.] [RFC PATCH 6/6] batman-adv: do not aggregate rebroadcasts in the same packet Linus Lüssing
@ 2017-01-22 13:08 ` Sven Eckelmann
  2017-01-29 13:10   ` Linus Lüssing
  6 siblings, 1 reply; 10+ messages in thread
From: Sven Eckelmann @ 2017-01-22 13:08 UTC (permalink / raw)
  To: b.a.t.m.a.n

[-- Attachment #1: Type: text/plain, Size: 1668 bytes --]

On Montag, 19. Dezember 2016 12:25:29 CET Linus Lüssing wrote:
> Hi,
> 
> Here is a first patchset to reintroduce aggregation support for BATMAN V, too.
> And while at it, for BATMAN VI, VII... etc, as well - in fact, it allows
> aggregating any batman packet with a broadcast destination ;).
> 
> I am sending it as an RFC for now as compat code is still missing. And although
> it was tested in VMs, I still need to do some stress testing on some
> embedded routers.

I have not actually looked at the code. But I would guess that your ultimate
goal is to reduce the overhead when sending broadcast either over wifi or
complex setups with things like VPNs (fastd). Did you do some captures on some
gluon supernodes (or actually only on a link to this supernode) and calculated
how many packets/bytes were sent over the DSL (up/down), how much overhead was
added, how many packets would potentially be aggregated by your approach and
how many packets/bytes would have been send over the DSL (up/down)?

Sounds to me at least like something which could be done on some existing
setups with some small script/program reading a pcap, creating some input
for some simulator and then sending this data through the actual simulator. 
And this all without having to actually break a working system :)

I think Simon (or I should also) have a very recent dump for a 2 1/2 days test
which captured (bcast/mcast/batman overhead) data from a spare Freifunk
Vogtland node (its ethernet port) without any clients attached. This would be
a potential source of test data (which we would have to anonymize for the
simulator input).

Kind regards,
	Sven

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [B.A.T.M.A.N.] [RFC PATCH 0/6] batman-adv: broadcast packet aggregation
  2017-01-22 13:08 ` [B.A.T.M.A.N.] [RFC PATCH 0/6] batman-adv: broadcast packet aggregation Sven Eckelmann
@ 2017-01-29 13:10   ` Linus Lüssing
  2017-01-29 13:15     ` Linus Lüssing
  0 siblings, 1 reply; 10+ messages in thread
From: Linus Lüssing @ 2017-01-29 13:10 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

On Sun, Jan 22, 2017 at 02:08:50PM +0100, Sven Eckelmann wrote:
> On Montag, 19. Dezember 2016 12:25:29 CET Linus Lüssing wrote:
> > Hi,
> > 
> > Here is a first patchset to reintroduce aggregation support for BATMAN V, too.
> > And while at it, for BATMAN VI, VII... etc, as well - in fact, it allows
> > aggregating any batman packet with a broadcast destination ;).
> > 
> > I am sending it as an RFC for now as compat code is still missing. And although
> > it was tested in VMs, I still need to do some stress testing on some
> > embedded routers.
> 
> I have not actually looked at the code. But I would guess that your ultimate
> goal is to reduce the overhead when sending broadcast either over wifi or
> complex setups with things like VPNs (fastd). Did you do some captures on some
> gluon supernodes (or actually only on a link to this supernode) and calculated
> how many packets/bytes were sent over the DSL (up/down), how much overhead was
> added, how many packets would potentially be aggregated by your approach and
> how many packets/bytes would have been send over the DSL (up/down)?

I've just recorded a 20min. capture from the Freifunk Lübeck
network with about 370 nodes and about 410 clients at the time of
recording. This capture is just multicast traffic and after decapsulation
(so from the soft- and not hard-interface). The firmware is Gluon based, so
most multicast from the clients is already filtered before it enters the mesh
(mDNS, LLMNR etc.).

The recording has the following characteristics:

# Input
Number of packets: 32260 pkts
Duration: 1259.047 sec
25.623 pkts/s ave.
78 B / pkt ave. (***)
0.016 MBit/s ave.


Then, in a VM I created a veth-pair and attached a bat0 and a bat1
to it. I disabled BLA, DAT and Multicast Optimizations and IPv6 on
bat0 and bat1. Then I used "tcpreplay" to replay the recording on
bat0. I checked that all 32260 packets came out of bat1 again.

For the aggregation measurement I was measuring on
hard-interfaces, so one end of the veth-pair. The characteristics
there were the following:

# Aggregation: Off
Number of packets: 37377 pkts (*)
Duration: 1301.274 sec (**)
28.723 pkts/s ave.
101 B / pkt ave. (***)
0.023 MBit/s ave.

And after turning aggregation on:

# Aggregation: On
13420 pkts
Duration: 1292.869 sec (**)
10.380 pkts/s
267 B / pkt 
0.022 MBit/s

(*): OGMs and ELP packets are included here, too.
(**): Seems like tcpreplay is a little inaccurate regarding it's
timings.
(***): Larger packet size due to additional batman-adv and
ethernet headers.


## Conclusion

In this example scenario, the number of packets could be reduced
by a factor of 2.79 (37377 vs. 13420) while increasing the average
packet size by a factor of 2.64 (101 bytes vs. 267 bytes). While
in this case the average bitrate stayed about the same
(0.023Mbit/s vs. 0.022MBit/s), in cases of additional
encapsulation (e.g. VPNs) or preambles (802.11), the 2.79  times
less packets should have a noticeable, positive performance
impact. I haven't measured it directly, but we can calculate an
example:

For instance the VPN tool "fastd", would add additional
headers in sizes of up to 86 bytes (40B IPv6 + 46B UDP+fastd) [1].
Therefore reducing the number of broadcast packets by 2.79 should
reduce the effective multicast bitrate of:

 of:	42.97 kbit/s = (101+86)*8*28.723/1000 kbit/s
 to:	29.31 kbit/s = (267+86)*10.380*8/1000)
 => 32% overhead reduction

Note that in practice the relative reduction should be even higher,
as this measurement only considered the aggregation of multicast
packets from 410 clients and OGM+ELP packets from two nodes. In
the real setup the factor of 2.79 should be slightly larger because
the OGMs from the 370 nodes would result in additional
aggregation opportunities.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [B.A.T.M.A.N.] [RFC PATCH 0/6] batman-adv: broadcast packet aggregation
  2017-01-29 13:10   ` Linus Lüssing
@ 2017-01-29 13:15     ` Linus Lüssing
  0 siblings, 0 replies; 10+ messages in thread
From: Linus Lüssing @ 2017-01-29 13:15 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

On Sun, Jan 29, 2017 at 02:10:00PM +0100, Linus Lüssing wrote:
> For instance the VPN tool "fastd", would add additional
> headers in sizes of up to 86 bytes (40B IPv6 + 46B UDP+fastd) [1].
> Therefore reducing the number of broadcast packets by 2.79 should
> reduce the effective multicast bitrate of:

[...]

[1]: https://twitter.com/ffhhnoc/status/787771192853798915
(Diagram regarding encapsulation overhead with fastd + batman-adv)

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2017-01-29 13:15 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-12-19 11:25 [B.A.T.M.A.N.] [RFC PATCH 0/6] batman-adv: broadcast packet aggregation Linus Lüssing
2016-12-19 11:25 ` [B.A.T.M.A.N.] [RFC PATCH 1/6] batman-adv: Allow TVLVs greater than 128 bytes Linus Lüssing
2016-12-19 11:25 ` [B.A.T.M.A.N.] [RFC PATCH 2/6] batman-adv: aggregation packet reception Linus Lüssing
2016-12-19 11:25 ` [B.A.T.M.A.N.] [RFC PATCH 3/6] batman-adv: aggregation packet queueing and transmission Linus Lüssing
2016-12-19 11:25 ` [B.A.T.M.A.N.] [RFC PATCH 4/6] batman-adv: privatize forw_packet skb assignment Linus Lüssing
2016-12-19 11:25 ` [B.A.T.M.A.N.] [RFC PATCH 5/6] batman-adv: restructure rebroadcast counter into forw_packet API Linus Lüssing
2016-12-19 11:25 ` [B.A.T.M.A.N.] [RFC PATCH 6/6] batman-adv: do not aggregate rebroadcasts in the same packet Linus Lüssing
2017-01-22 13:08 ` [B.A.T.M.A.N.] [RFC PATCH 0/6] batman-adv: broadcast packet aggregation Sven Eckelmann
2017-01-29 13:10   ` Linus Lüssing
2017-01-29 13:15     ` Linus Lüssing

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).