All of lore.kernel.org
 help / color / mirror / Atom feed
* [B.A.T.M.A.N.] [RFC 00/23] Introducing a new routing protocol: B.A.T.M.A.N. V
@ 2014-02-11 12:48 Antonio Quartulli
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 01/23] batman-adv: invoke ogm_schedule() only when the interface is activated Antonio Quartulli
                   ` (22 more replies)
  0 siblings, 23 replies; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 12:48 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

Hello list,

this is the first _RFC_ introducing a new routing protocol in the batman-adv
kernel module, namely B.A.T.M.A.N. V.

Basically this is the result of three major ideas:
1) separate link cost estimation and routing information spreading
   (B.A.T.M.A.N. IV performs the two operations by using OGMs only)
2) introduce a throughput based metric (B.A.T.M.A.N. IV metric is mainly
   based on packet loss)
3) create a new protocol that groups all the knowledge gained so far

For what concerns point 1) in this patchset we introduce the Echo Locating
Protocol (aka ELP), which is a standalone component aimed to only estimate
link costs. ELP was originally written by Linus Lüssing.

For point 2) we have already proposed an extension of the cfg80211 module (not
yet merged) which allows any kernel module to retrieve the expected throughput
towards another peer over a wireless link. ELP is the component in charge of
interacting with cfg80211 to retrieve the expected throughput.
For wired connections ELP directly reads the bandwidth advertised by the
Ethernet card (not optimal in case of complex topologies - but it is a first
attempt).

Point 3) gets concrete under the new OGMv2 protocol, which is the core of
B.A.T.M.A.N. V.


The documentation is not yet ready to be linked, because the draft we have on
the wiki needs to be adapted to reflect the last changes (in particular about
the metric change from TQ to expected throughput).

In the various patches some kerneldoc is still missing: I am working on that
now. But I wanted to throw the patchset out as soon as possible to let anybody
review this code (this is why this is an RFC).


Notes:
=======
1) yes,_this_patchset_is_not_yet_checkpatch_clean_
2) patch 1/23 is already pending on the ml as RFC but I am resending it here
since it is part of the whole batman v picture.



Cheers,


Antonio Quartulli (18):
  batman-adv: invoke ogm_schedule() only when the interface is activated
  batman-adv: OGMv2 - add basic infrastructure
  batman-adv: OGMv2 - implement originators logic
  batman-adv: OGMv2 - purge obsolete potential routers
  batman-adv: split name from variable for uint mesh attributes
  batman-adv: add throughput attribute to hard_ifaces
  batman-adv: add base throughput attribute
  batman-adv: add last_unicast_tx to struct neigh_node_elp
  batman-adv: ELP - compute the metric based on the estimated throughput
  batman-adv: ELP - send unicast ELP packets for throughput sampling
  batman-adv: ELP - read estimated throughput from cfg80211
  batman-adv: ELP - implement dead neigh node detection
  batman-adv: ELP - use phydev to determine link characteristics
  batman-adv: add bat_neigh_free() API
  batman-adv: B.A.T.M.A.N. V - implement bat_neigh_free() API
  batman-adv: B.A.T.M.A.N. V - implement neigh_is_equiv_or_better API
  batman-adv: B.A.T.M.A.N. V - implement bat_neigh_cmp API
  batman-adv: B.A.T.M.A.N. V - implement bat_orig_print API

Linus Luessing (5):
  batman-adv: Add hard_iface specific sysfs wrapper macros for UINT
  batman-adv: ELP - adding basic infrastructure
  batman-adv: ELP - creating neighbor structures
  batman-adv: ELP - exporting neighbor list via debugfs
  batman-adv: ELP - adding sysfs parameter for elp interval

 Makefile                   |   2 +
 Makefile.kbuild            |   3 +
 README.external            |   1 +
 bat_algo.h                 |  26 +-
 bat_iv_ogm.c               |   2 +-
 bat_v.c                    | 266 +++++++++++++++++
 bat_v_elp.c                | 718 +++++++++++++++++++++++++++++++++++++++++++++
 bat_v_elp.h                |  39 +++
 bat_v_ogm.c                | 716 ++++++++++++++++++++++++++++++++++++++++++++
 bat_v_ogm.h                |  32 ++
 compat.h                   |  20 ++
 debugfs.c                  |  17 ++
 distributed-arp-table.c    |   4 +-
 fragmentation.c            |   8 +-
 gen-compat-autoconf.sh     |   1 +
 hard-interface.c           |  24 +-
 icmp_socket.c              |   2 +-
 main.c                     |  32 +-
 main.h                     |  16 +
 network-coding.c           |  20 +-
 originator.c               |  69 +++--
 originator.h               |   2 +
 packet.h                   |  50 ++++
 send.c                     |  46 ++-
 send.h                     |  10 +-
 sysfs-class-net-batman-adv |   8 +-
 sysfs.c                    |  87 +++++-
 types.h                    | 113 +++++++
 28 files changed, 2260 insertions(+), 74 deletions(-)
 create mode 100644 bat_v.c
 create mode 100644 bat_v_elp.c
 create mode 100644 bat_v_elp.h
 create mode 100644 bat_v_ogm.c
 create mode 100644 bat_v_ogm.h

-- 
1.8.5.3


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

* [B.A.T.M.A.N.] [RFC 01/23] batman-adv: invoke ogm_schedule() only when the interface is activated
  2014-02-11 12:48 [B.A.T.M.A.N.] [RFC 00/23] Introducing a new routing protocol: B.A.T.M.A.N. V Antonio Quartulli
@ 2014-02-11 12:48 ` Antonio Quartulli
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 02/23] batman-adv: Add hard_iface specific sysfs wrapper macros for UINT Antonio Quartulli
                   ` (21 subsequent siblings)
  22 siblings, 0 replies; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 12:48 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

In the current implementation the first OGM is scheduled
when a new hard-interface is enabled, no matter if it is
active (thus ready for sending packets) or not.

However, the B.A.T.M.A.N. IV OGM scheduling mechanism works
in a way that reschedules the task forever even if the
interface is not yet ready and therefore everything works as
expected.

Unfortunately this behaviour is not fine in general and
other algorithms may pretend the interface to be active
before scheduling the first OGM.

Change this behaviour by scheduling the first OGM upon
interface activation.

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 hard-interface.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/hard-interface.c b/hard-interface.c
index b851cc5..2a04130 100644
--- a/hard-interface.c
+++ b/hard-interface.c
@@ -320,6 +320,8 @@ batadv_hardif_activate_interface(struct batadv_hard_iface *hard_iface)
 
 	batadv_update_min_mtu(hard_iface->soft_iface);
 
+	/* begin scheduling originator messages on that interface */
+	batadv_schedule_bat_ogm(hard_iface);
 out:
 	if (primary_if)
 		batadv_hardif_free_ref(primary_if);
@@ -459,9 +461,6 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
 			   "Not using interface %s (retrying later): interface not active\n",
 			   hard_iface->net_dev->name);
 
-	/* begin scheduling originator messages on that interface */
-	batadv_schedule_bat_ogm(hard_iface);
-
 out:
 	return 0;
 
-- 
1.8.5.3


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

* [B.A.T.M.A.N.] [RFC 02/23] batman-adv: Add hard_iface specific sysfs wrapper macros for UINT
  2014-02-11 12:48 [B.A.T.M.A.N.] [RFC 00/23] Introducing a new routing protocol: B.A.T.M.A.N. V Antonio Quartulli
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 01/23] batman-adv: invoke ogm_schedule() only when the interface is activated Antonio Quartulli
@ 2014-02-11 12:48 ` Antonio Quartulli
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 03/23] batman-adv: ELP - adding basic infrastructure Antonio Quartulli
                   ` (20 subsequent siblings)
  22 siblings, 0 replies; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 12:48 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Marek Lindner, Antonio Quartulli

From: Linus Luessing <linus.luessing@web.de>

This allows us to easily add a sysfs parameter for an
unsigned int later, which is not for a batman mesh interface
(e.g. bat0), but for a common interface instead. It allows
reading and writing an atomic_t in hard_iface (instead of
bat_priv compared to the mesh variant).

Developed by Linus during a 6 months trainee study period in
Ascom (Switzerland) AG.

Signed-off-by: Linus Luessing <linus.luessing@web.de>
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
[antonio@open-mesh.com: rename functions and move macros]
Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 sysfs.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/sysfs.c b/sysfs.c
index e456bf6..1e9ee3a 100644
--- a/sysfs.c
+++ b/sysfs.c
@@ -213,6 +213,55 @@ ssize_t batadv_show_vlan_##_name(struct kobject *kobj,			\
 	static BATADV_ATTR_VLAN(_name, _mode, batadv_show_vlan_##_name,	\
 				batadv_store_vlan_##_name)
 
+#define BATADV_ATTR_HIF_STORE_UINT(_name, _var, _min, _max, _post_func)	\
+ssize_t batadv_store_##_name(struct kobject *kobj,			\
+			     struct attribute *attr, char *buff,	\
+			     size_t count)				\
+{									\
+	struct net_device *net_dev = batadv_kobj_to_netdev(kobj);	\
+	struct batadv_hard_iface *hard_iface;					\
+	ssize_t length;							\
+									\
+	hard_iface = batadv_hardif_get_by_netdev(net_dev);		\
+	if (!hard_iface)						\
+		return 0;						\
+									\
+	length = __batadv_store_uint_attr(buff, count, _min, _max,	\
+					  _post_func, attr,		\
+					  &hard_iface->_var, net_dev);	\
+									\
+	batadv_hardif_free_ref(hard_iface);					\
+	return length;							\
+}
+
+#define BATADV_ATTR_HIF_SHOW_UINT(_name, _var)				\
+ssize_t batadv_show_##_name(struct kobject *kobj,			\
+			    struct attribute *attr, char *buff)		\
+{									\
+	struct net_device *net_dev = batadv_kobj_to_netdev(kobj);	\
+	struct batadv_hard_iface *hard_iface;				\
+	ssize_t length;							\
+									\
+	hard_iface = batadv_hardif_get_by_netdev(net_dev);		\
+	if (!hard_iface)						\
+		return 0;						\
+									\
+	length = sprintf(buff, "%i\n", atomic_read(&hard_iface->_var));	\
+									\
+	batadv_hardif_free_ref(hard_iface);					\
+	return length;							\
+}
+
+/* Use this, if you are going to set [name] in hard_iface to an
+ * unsigned integer value
+ */
+#define BATADV_ATTR_HIF_UINT(_name, _var, _mode, _min, _max, _post_func)\
+	static BATADV_ATTR_HIF_STORE_UINT(_name, _var, _min,		\
+					  _max, _post_func)		\
+	static BATADV_ATTR_HIF_SHOW_UINT(_name, _var)			\
+	static BATADV_ATTR(_name, _mode, batadv_show_##_name,		\
+			   batadv_store_##_name)
+
 static int batadv_store_bool_attr(char *buff, size_t count,
 				  struct net_device *net_dev,
 				  const char *attr_name, atomic_t *attr)
-- 
1.8.5.3


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

* [B.A.T.M.A.N.] [RFC 03/23] batman-adv: ELP - adding basic infrastructure
  2014-02-11 12:48 [B.A.T.M.A.N.] [RFC 00/23] Introducing a new routing protocol: B.A.T.M.A.N. V Antonio Quartulli
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 01/23] batman-adv: invoke ogm_schedule() only when the interface is activated Antonio Quartulli
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 02/23] batman-adv: Add hard_iface specific sysfs wrapper macros for UINT Antonio Quartulli
@ 2014-02-11 12:48 ` Antonio Quartulli
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 04/23] batman-adv: ELP - creating neighbor structures Antonio Quartulli
                   ` (19 subsequent siblings)
  22 siblings, 0 replies; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 12:48 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Marek Lindner, Antonio Quartulli

From: Linus Luessing <linus.luessing@web.de>

The B.A.T.M.A.N. protocol originally only used a single
message type (called OGM) to determine the link qualities to
the direct neighbors and spreading these link quality
information through the whole mesh. This procedure is
summarized on the BATMAN concept page and explained in
details in the RFC draft published in 2008.

This approach was chosen for its simplicity during the
protocol design phase and the implementation. However, it
also bears some drawbacks:

 *  Wireless interfaces usually come with some packet loss,
    therefore a higher broadcast rate is desirable to allow
    a fast reaction on flaky connections.
    Other interfaces of the same host might be connected to
    Ethernet LANs / VPNs / etc which rarely exhibit packet
    loss would benefit from a lower broadcast rate to reduce
    overhead.
 *  It generally is more desirable to detect local link
    quality changes at a faster rate than propagating all
    these changes through the entire mesh (the far end of
    the mesh does not need to care about local link quality
    changes that much). Other optimizations strategies, like
    reducing overhead, might be possible if OGMs weren't
    used for all tasks in the mesh at the same time.

As a result detecting local link qualities shall be handled
by an independent message type, ELP, whereas the OGM message
type remains responsible for flooding the mesh with these
link quality information and determining the overall path
transmit qualities.

Developed by Linus during a 6 months trainee study period in
Ascom (Switzerland) AG.

Signed-off-by: Linus Luessing <linus.luessing@web.de>
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 Makefile               |   2 +
 Makefile.kbuild        |   2 +
 README.external        |   1 +
 bat_algo.h             |  15 ++++-
 bat_v.c                |  65 ++++++++++++++++++
 bat_v_elp.c            | 179 +++++++++++++++++++++++++++++++++++++++++++++++++
 bat_v_elp.h            |  30 +++++++++
 gen-compat-autoconf.sh |   1 +
 main.c                 |   1 +
 packet.h               |  25 +++++++
 types.h                |  18 +++++
 11 files changed, 338 insertions(+), 1 deletion(-)
 create mode 100644 bat_v.c
 create mode 100644 bat_v_elp.c
 create mode 100644 bat_v_elp.h

diff --git a/Makefile b/Makefile
index 9a7cbae..405175d 100644
--- a/Makefile
+++ b/Makefile
@@ -25,6 +25,8 @@ export CONFIG_BATMAN_ADV_BLA=y
 export CONFIG_BATMAN_ADV_DAT=y
 # B.A.T.M.A.N network coding (catwoman):
 export CONFIG_BATMAN_ADV_NC=n
+# B.A.T.M.A.N. V routing algorithm (experimental):
+# export CONFIG_BATMAN_ADV_BATMAN_V=y
 
 PWD:=$(shell pwd)
 KERNELPATH ?= /lib/modules/$(shell uname -r)/build
diff --git a/Makefile.kbuild b/Makefile.kbuild
index 42df18f..ae9a6ca 100644
--- a/Makefile.kbuild
+++ b/Makefile.kbuild
@@ -18,6 +18,8 @@
 
 obj-$(CONFIG_BATMAN_ADV) += batman-adv.o
 batman-adv-y += bat_iv_ogm.o
+batman-adv-$(CONFIG_BATMAN_ADV_BATMAN_V) += bat_v.o
+batman-adv-$(CONFIG_BATMAN_ADV_BATMAN_V) += bat_v_elp.o
 batman-adv-y += bitarray.o
 batman-adv-$(CONFIG_BATMAN_ADV_BLA) += bridge_loop_avoidance.o
 batman-adv-y += debugfs.o
diff --git a/README.external b/README.external
index c8eac1a..6f0d18b 100644
--- a/README.external
+++ b/README.external
@@ -39,6 +39,7 @@ module).  Available  options  and  their    possible   values are
  * CONFIG_BATMAN_ADV_BLA=[y*|n] (B.A.T.M.A.N. bridge loop avoidance)
  * CONFIG_BATMAN_ADV_DAT=[y*|n] (B.A.T.M.A.N. Distributed ARP Table)
  * CONFIG_BATMAN_ADV_NC=[y|n*] (B.A.T.M.A.N. Network Coding)
+ * CONFIG_BATMAN_ADV_BATMAN_V=[y|n*] (B.A.T.M.A.N. V routing algorithm)
 
 e.g., debugging can be enabled by
 
diff --git a/bat_algo.h b/bat_algo.h
index 4e49666..7289336 100644
--- a/bat_algo.h
+++ b/bat_algo.h
@@ -1,6 +1,6 @@
 /* Copyright (C) 2011-2014 B.A.T.M.A.N. contributors:
  *
- * Marek Lindner
+ * Marek Lindner, Antonio Quartulli
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of version 2 of the GNU General Public
@@ -20,4 +20,17 @@
 
 int batadv_iv_init(void);
 
+#ifdef CONFIG_BATMAN_ADV_BATMAN_V
+
+int batadv_v_init(void);
+
+#else
+
+static inline int batadv_v_init(void)
+{
+	return 0;
+}
+
+#endif /* CONFIG_BATMAN_ADV_BATMAN_V */
+
 #endif /* _NET_BATMAN_ADV_BAT_ALGO_H_ */
diff --git a/bat_v.c b/bat_v.c
new file mode 100644
index 0000000..7247d7f
--- /dev/null
+++ b/bat_v.c
@@ -0,0 +1,65 @@
+/* Copyright (C) 2013-2014 B.A.T.M.A.N. contributors:
+ *
+ * Antonio Quartulli
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+#include "main.h"
+#include "bat_algo.h"
+#include "bat_v_elp.h"
+
+static int batadv_v_iface_enable(struct batadv_hard_iface *hard_iface)
+{
+	return batadv_v_elp_iface_enable(hard_iface);
+}
+
+static void batadv_v_iface_disable(struct batadv_hard_iface *hard_iface)
+{
+	batadv_v_elp_iface_disable(hard_iface);
+}
+
+static void batadv_v_iface_update_mac(struct batadv_hard_iface *hard_iface)
+{
+}
+
+static void batadv_v_primary_iface_set(struct batadv_hard_iface *hard_iface)
+{
+	batadv_v_elp_primary_iface_set(hard_iface);
+}
+
+static void batadv_v_ogm_schedule(struct batadv_hard_iface *hard_iface)
+{
+}
+
+static void batadv_v_ogm_emit(struct batadv_forw_packet *forw_packet)
+{
+}
+
+static struct batadv_algo_ops batadv_batman_v __read_mostly = {
+	.name = "BATMAN_V",
+	.bat_iface_enable = batadv_v_iface_enable,
+	.bat_iface_disable = batadv_v_iface_disable,
+	.bat_iface_update_mac = batadv_v_iface_update_mac,
+	.bat_primary_iface_set = batadv_v_primary_iface_set,
+	.bat_ogm_emit = batadv_v_ogm_emit,
+	.bat_ogm_schedule = batadv_v_ogm_schedule,
+};
+
+
+int __init batadv_v_init(void)
+{
+	return batadv_algo_register(&batadv_batman_v);
+}
diff --git a/bat_v_elp.c b/bat_v_elp.c
new file mode 100644
index 0000000..45b082b
--- /dev/null
+++ b/bat_v_elp.c
@@ -0,0 +1,179 @@
+/* Copyright (C) 2011-2014 B.A.T.M.A.N. contributors:
+ *
+ * Linus Lüssing, Marek Lindner, Antonio Quartulli
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ */
+
+#include "main.h"
+#include "hard-interface.h"
+#include "send.h"
+#include "bat_algo.h"
+#include "bat_v_elp.h"
+
+/**
+ * batadv_v_elp_start_timer - restart timer for ELP periodic work
+ * @hard_iface: the interface for which the timer has to be reset
+ */
+static void batadv_v_elp_start_timer(struct batadv_hard_iface *hard_iface)
+{
+	unsigned int msecs;
+
+	msecs = atomic_read(&hard_iface->bat_v.elp_interval) - BATADV_JITTER;
+	msecs += prandom_u32() % (2 * BATADV_JITTER);
+
+	queue_delayed_work(batadv_event_workqueue, &hard_iface->bat_v.elp_wq,
+			   msecs_to_jiffies(msecs));
+}
+
+/**
+ * batadv_v_elp_send_outstanding - ELP periodic broadcast sending
+ * @work: work queue item
+ *
+ * Sends a broadcast ELP message over the interface that this work item belongs
+ * to.
+ */
+static void batadv_v_elp_send_outstanding(struct work_struct *work)
+{
+	struct batadv_hard_iface *hard_iface;
+	struct batadv_hard_iface_bat_v *bat_v;
+	struct batadv_priv *bat_priv;
+	struct batadv_elp_packet *elp_packet;
+	uint32_t elp_interval;
+	struct sk_buff *skb;
+
+	bat_v = container_of(work, struct batadv_hard_iface_bat_v, elp_wq.work);
+	hard_iface = container_of(bat_v, struct batadv_hard_iface, bat_v);
+	bat_priv = netdev_priv(hard_iface->soft_iface);
+
+	if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING)
+		goto out;
+
+	/* we are in the process of shutting this interface down */
+	if ((hard_iface->if_status == BATADV_IF_NOT_IN_USE) ||
+	    (hard_iface->if_status == BATADV_IF_TO_BE_REMOVED))
+		goto out;
+
+	/* the interface was enabled but may not be ready yet */
+	if (hard_iface->if_status != BATADV_IF_ACTIVE)
+		goto restart_timer;
+
+	skb = skb_copy(hard_iface->bat_v.elp_skb, GFP_ATOMIC);
+	if (!skb)
+		goto out;
+
+	elp_packet = (struct batadv_elp_packet *)skb->data;
+	elp_packet->seqno = htonl(atomic_read(&hard_iface->bat_v.elp_seqno));
+	elp_packet->num_neighbors = 0;
+	elp_interval = atomic_read(&hard_iface->bat_v.elp_interval);
+	elp_packet->elp_interval = htonl(elp_interval);
+
+	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+		   "Sending ELP packet on interface %s, seqno %u\n",
+		   hard_iface->net_dev->name,
+		   atomic_read(&hard_iface->bat_v.elp_seqno));
+
+	batadv_send_skb_packet(skb, hard_iface, batadv_broadcast_addr);
+
+	atomic_inc(&hard_iface->bat_v.elp_seqno);
+
+restart_timer:
+	batadv_v_elp_start_timer(hard_iface);
+out:
+	return;
+}
+
+/**
+ * batadv_v_elp_iface_enable - setup the ELP interface private resources
+ * @hard_iface: interface for which the data has to be prepared
+ *
+ * Returns 0 on success or a -ENOMEM in case of failure.
+ */
+int batadv_v_elp_iface_enable(struct batadv_hard_iface *hard_iface)
+{
+	struct batadv_elp_packet *elp_packet;
+	unsigned char *elp_buff;
+	uint32_t random_seqno;
+	size_t size;
+	int res = -ENOMEM;
+
+	size = ETH_HLEN + NET_IP_ALIGN + BATADV_ELP_HLEN;
+	hard_iface->bat_v.elp_skb = dev_alloc_skb(size);
+	if (!hard_iface->bat_v.elp_skb)
+		goto out;
+
+	skb_reserve(hard_iface->bat_v.elp_skb, ETH_HLEN + NET_IP_ALIGN);
+	elp_buff = skb_push(hard_iface->bat_v.elp_skb, BATADV_ELP_HLEN);
+	elp_packet = (struct batadv_elp_packet *)elp_buff;
+	memset(elp_packet, 0, BATADV_ELP_HLEN);
+
+	elp_packet->packet_type = BATADV_ELP;
+	elp_packet->version = BATADV_COMPAT_VERSION;
+	elp_packet->ttl = 0;
+
+	/* randomize initial seqno to avoid collision */
+	get_random_bytes(&random_seqno, sizeof(random_seqno));
+	atomic_set(&hard_iface->bat_v.elp_seqno, random_seqno);
+	atomic_set(&hard_iface->bat_v.elp_interval, 500);
+
+	INIT_DELAYED_WORK(&hard_iface->bat_v.elp_wq,
+			  batadv_v_elp_send_outstanding);
+	batadv_v_elp_start_timer(hard_iface);
+	res = 0;
+
+out:
+	return res;
+}
+
+/**
+ * batadv_v_elp_iface_disable - release ELP interface private resources
+ * @hard_iface: interface for which the resources have to be released
+ */
+void batadv_v_elp_iface_disable(struct batadv_hard_iface *hard_iface)
+{
+	cancel_delayed_work_sync(&hard_iface->bat_v.elp_wq);
+
+	dev_kfree_skb(hard_iface->bat_v.elp_skb);
+	hard_iface->bat_v.elp_skb = NULL;
+}
+
+/**
+ * batadv_v_elp_primary_iface_set - change internal data to reflect the new
+ *  primary interface
+ * @hard_iface: the new primary interface
+ */
+void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *hard_iface)
+{
+	struct batadv_hard_iface *hard_iface_tmp;
+	struct batadv_elp_packet *elp_packet;
+	struct sk_buff *skb;
+
+	/* update orig field of every elp iface belonging to this mesh */
+	rcu_read_lock();
+	list_for_each_entry_rcu(hard_iface_tmp, &batadv_hardif_list, list) {
+		if (hard_iface->soft_iface != hard_iface_tmp->soft_iface)
+			continue;
+
+		if (!hard_iface_tmp->bat_v.elp_skb)
+			continue;
+
+		skb = hard_iface_tmp->bat_v.elp_skb;
+		elp_packet = (struct batadv_elp_packet *)skb->data;
+		memcpy(elp_packet->orig,
+		       hard_iface->net_dev->dev_addr, ETH_ALEN);
+	}
+	rcu_read_unlock();
+}
diff --git a/bat_v_elp.h b/bat_v_elp.h
new file mode 100644
index 0000000..06d2cb1
--- /dev/null
+++ b/bat_v_elp.h
@@ -0,0 +1,30 @@
+/* Copyright (C) 2013-2014 B.A.T.M.A.N. contributors:
+ *
+ * Antonio Quartulli
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ */
+
+#include "main.h"
+
+#ifndef _NET_BATMAN_ADV_BAT_V_ELP_H_
+#define _NET_BATMAN_ADV_BAT_V_ELP_H_
+
+int batadv_v_elp_iface_enable(struct batadv_hard_iface *hard_iface);
+void batadv_v_elp_iface_disable(struct batadv_hard_iface *hard_iface);
+void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *hard_iface);
+
+#endif /* _NET_BATMAN_ADV_BAT_V_ELP_H_ */
diff --git a/gen-compat-autoconf.sh b/gen-compat-autoconf.sh
index 78573e4..001707f 100755
--- a/gen-compat-autoconf.sh
+++ b/gen-compat-autoconf.sh
@@ -40,6 +40,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_NC' ${CONFIG_BATMAN_ADV_NC:="n"} >> "${TMP}"
+gen_config 'CONFIG_BATMAN_ADV_BATMAN_V' ${CONFIG_BATMAN_ADV_BATMAN_V:="n"} >> "${TMP}"
 
 # only regenerate compat-autoconf.h when config was changed
 diff "${TMP}" "${TARGET}" > /dev/null 2>&1 || cp "${TMP}" "${TARGET}"
diff --git a/main.c b/main.c
index fbeaebd..b7d9996 100644
--- a/main.c
+++ b/main.c
@@ -63,6 +63,7 @@ static int __init batadv_init(void)
 
 	batadv_recv_handler_init();
 
+	batadv_v_init();
 	batadv_iv_init();
 	batadv_nc_init();
 
diff --git a/packet.h b/packet.h
index 0a381d1..71b1aeb 100644
--- a/packet.h
+++ b/packet.h
@@ -37,6 +37,7 @@ enum batadv_packettype {
 	BATADV_IV_OGM           = 0x00,
 	BATADV_BCAST            = 0x01,
 	BATADV_CODED            = 0x02,
+	BATADV_ELP		= 0x03,
 	/* 0x40 - 0x7f: unicast */
 #define BATADV_UNICAST_MIN     0x40
 	BATADV_UNICAST          = 0x40,
@@ -192,6 +193,30 @@ struct batadv_ogm_packet {
 #define BATADV_OGM_HLEN sizeof(struct batadv_ogm_packet)
 
 /**
+ * struct batadv_elp_packet - elp (neighbor discovery) packet
+ * @packet_type: batman-adv packet type, part of the general header
+ * @version: batman-adv protocol version, part of the genereal header
+ * @ttl: time to live for this packet, part of the genereal header
+ * @num_neighbors: number of already discovered neighbors
+ * @seqno: sequence number
+ * @elp_interval: currently used ELP sending interval
+ * @orig: originator mac address
+ * @align: not used - useful for alignment purposes only
+ */
+struct batadv_elp_packet {
+	uint8_t  packet_type;
+	uint8_t  version;
+	uint8_t  ttl;
+	uint8_t  num_neighbors;
+	__be32	 seqno;
+	__be32	 elp_interval;
+	uint8_t  orig[ETH_ALEN];
+	uint8_t  align[2];
+};
+
+#define BATADV_ELP_HLEN sizeof(struct batadv_elp_packet)
+
+/**
  * batadv_icmp_header - common members among all the ICMP packets
  * @packet_type: batman-adv packet type, part of the general header
  * @version: batman-adv protocol version, part of the genereal header
diff --git a/types.h b/types.h
index 9f52517..518fa81 100644
--- a/types.h
+++ b/types.h
@@ -70,6 +70,20 @@ struct batadv_hard_iface_bat_iv {
 };
 
 /**
+ * struct batadv_hard_iface_bat_v - per hard interface B.A.T.M.A.N. V data
+ * @elp_interval: time interval between two ELP transmissions
+ * @elp_seqno: current ELP sequence number
+ * @elp_skb: base skb containing the ELP message to send
+ * @elp_wq: workqueue used to schedule ELP transmissions
+ */
+struct batadv_hard_iface_bat_v {
+	atomic_t elp_interval;
+	atomic_t elp_seqno;
+	struct sk_buff *elp_skb;
+	struct delayed_work elp_wq;
+};
+
+/**
  * struct batadv_hard_iface - network device known to batman-adv
  * @list: list node for batadv_hardif_list
  * @if_num: identificator of the interface
@@ -83,6 +97,7 @@ struct batadv_hard_iface_bat_iv {
  * @soft_iface: the batman-adv interface which uses this network interface
  * @rcu: struct used for freeing in an RCU-safe manner
  * @bat_iv: BATMAN IV specific per hard interface data
+ * @bat_v: BATMAN V specific per hard interface data
  * @cleanup_work: work queue callback item for hard interface deinit
  * @debug_dir: dentry for nc subdir in batman-adv directory in debugfs
  */
@@ -98,6 +113,9 @@ struct batadv_hard_iface {
 	struct net_device *soft_iface;
 	struct rcu_head rcu;
 	struct batadv_hard_iface_bat_iv bat_iv;
+#ifdef CONFIG_BATMAN_ADV_BATMAN_V
+	struct batadv_hard_iface_bat_v bat_v;
+#endif
 	struct work_struct cleanup_work;
 	struct dentry *debug_dir;
 };
-- 
1.8.5.3


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

* [B.A.T.M.A.N.] [RFC 04/23] batman-adv: ELP - creating neighbor structures
  2014-02-11 12:48 [B.A.T.M.A.N.] [RFC 00/23] Introducing a new routing protocol: B.A.T.M.A.N. V Antonio Quartulli
                   ` (2 preceding siblings ...)
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 03/23] batman-adv: ELP - adding basic infrastructure Antonio Quartulli
@ 2014-02-11 12:48 ` Antonio Quartulli
  2014-02-11 15:32   ` Andrew Lunn
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 05/23] batman-adv: ELP - exporting neighbor list via debugfs Antonio Quartulli
                   ` (18 subsequent siblings)
  22 siblings, 1 reply; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 12:48 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Marek Lindner, Antonio Quartulli

From: Linus Luessing <linus.luessing@web.de>

Initially developed by Linus during a 6 months trainee study
period in Ascom (Switzerland) AG.

Signed-off-by: Linus Luessing <linus.luessing@web.de>
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 bat_v.c     |  18 +++++-
 bat_v_elp.c | 204 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 bat_v_elp.h |   6 ++
 main.h      |   2 +
 types.h     |  53 ++++++++++++++++
 5 files changed, 281 insertions(+), 2 deletions(-)

diff --git a/bat_v.c b/bat_v.c
index 7247d7f..bed5e00 100644
--- a/bat_v.c
+++ b/bat_v.c
@@ -61,5 +61,21 @@ static struct batadv_algo_ops batadv_batman_v __read_mostly = {
 
 int __init batadv_v_init(void)
 {
-	return batadv_algo_register(&batadv_batman_v);
+	int ret;
+
+	/* batman v echo location protocol packet  */
+	ret = batadv_recv_handler_register(BATADV_ELP,
+					   batadv_v_elp_packet_recv);
+	if (ret < 0)
+		goto elp_unregister;
+
+	ret = batadv_algo_register(&batadv_batman_v);
+
+	return ret;
+
+elp_unregister:
+	if (ret < 0)
+		batadv_recv_handler_unregister(BATADV_ELP);
+
+	return ret;
 }
diff --git a/bat_v_elp.c b/bat_v_elp.c
index 45b082b..ee4207d 100644
--- a/bat_v_elp.c
+++ b/bat_v_elp.c
@@ -23,6 +23,8 @@
 #include "send.h"
 #include "bat_algo.h"
 #include "bat_v_elp.h"
+#include "originator.h"
+#include "routing.h"
 
 /**
  * batadv_v_elp_start_timer - restart timer for ELP periodic work
@@ -40,6 +42,111 @@ static void batadv_v_elp_start_timer(struct batadv_hard_iface *hard_iface)
 }
 
 /**
+ * batadv_elp_neigh_node_free_ref - release a ELP neighbour node
+ * @neigh: the neighbour object to release
+ */
+void batadv_elp_neigh_node_free_ref(struct batadv_elp_neigh_node *neigh)
+{
+	if (atomic_dec_and_test(&neigh->refcount))
+		kfree_rcu(neigh, rcu);
+}
+
+/**
+ * batadv_v_elp_neigh_new - create a new ELP neighbour node
+ * @hard_iface: the interface the neighbour is connected to
+ * @neigh_addr: the neighbour interface address
+ * @orig_addr: the neighbour originator address
+ * @seqno: the received sequence number to be used to initialize the object
+ *
+ * Returns a new ELP neighbour node or NULL in case of failure.
+ */
+static struct batadv_elp_neigh_node *
+batadv_v_elp_neigh_new(struct batadv_hard_iface *hard_iface,
+		       uint8_t *neigh_addr, uint8_t *orig_addr, uint32_t seqno)
+{
+	struct batadv_elp_neigh_node *neigh;
+
+	neigh = kzalloc(sizeof(*neigh), GFP_ATOMIC);
+	if (!neigh)
+		return NULL;
+
+	memcpy(neigh->orig, orig_addr, ETH_ALEN);
+	memcpy(neigh->addr, neigh_addr, ETH_ALEN);
+	neigh->last_recv_seqno = seqno - 1;
+	neigh->last_seen = jiffies;
+	ewma_init(&neigh->metric, 1024, 8);
+	/* recount initialised to 2 to simplify the caller function */
+	atomic_set(&neigh->refcount, 2);
+
+	spin_lock_bh(&hard_iface->bat_v.neigh_list_lock);
+	hlist_add_head_rcu(&neigh->list, &hard_iface->bat_v.neigh_list);
+	spin_unlock_bh(&hard_iface->bat_v.neigh_list_lock);
+	atomic_inc(&hard_iface->bat_v.num_neighbors);
+
+	return neigh;
+}
+
+/**
+ * batadv_v_elp_neigh_get - retrieve an ELP neighbour node
+ * @hard_iface: the interface this neighbour is connected to
+ * @neigh_addr: the interface address of the neighbour to retrieve
+ *
+ * Returns the ELP neighbour node if found or NULL otherwise.
+ */
+struct batadv_elp_neigh_node *
+batadv_v_elp_neigh_get(struct batadv_hard_iface *hard_iface,
+		       uint8_t *neigh_addr)
+{
+	struct batadv_elp_neigh_node *neigh = NULL, *neigh_tmp;
+
+	rcu_read_lock();
+	hlist_for_each_entry_rcu(neigh_tmp,
+				 &hard_iface->bat_v.neigh_list, list) {
+		if (!batadv_compare_eth(neigh_tmp->addr, neigh_addr))
+			continue;
+
+		if (!atomic_inc_not_zero(&neigh_tmp->refcount))
+			continue;
+
+		neigh = neigh_tmp;
+		break;
+	}
+	rcu_read_unlock();
+
+	return neigh;
+}
+
+/**
+ * batadv_v_elp_neigh_purge - purge obsolete neighbour nodes
+ *
+ * Deletes the ELP neighbour nodes that did not send any ELP message for a
+ * pre-defined amount of time.
+ */
+static void batadv_v_elp_neigh_purge(struct batadv_hard_iface *hard_iface)
+{
+	unsigned long timeout;
+	struct batadv_elp_neigh_node *neigh;
+	struct hlist_node *node;
+	bool has_timed_out;
+
+	spin_lock_bh(&hard_iface->bat_v.neigh_list_lock);
+	hlist_for_each_entry_safe(neigh, node, &hard_iface->bat_v.neigh_list,
+				  list) {
+		timeout = neigh->elp_interval * BATADV_ELP_OUTDATED_MAX;
+		has_timed_out = batadv_has_timed_out(neigh->last_seen, timeout);
+
+		if ((!has_timed_out) &&
+		    (hard_iface->if_status == BATADV_IF_ACTIVE))
+			continue;
+
+		hlist_del_rcu(&neigh->list);
+		atomic_dec(&hard_iface->bat_v.num_neighbors);
+		batadv_elp_neigh_node_free_ref(neigh);
+	}
+	spin_unlock_bh(&hard_iface->bat_v.neigh_list_lock);
+}
+
+/**
  * batadv_v_elp_send_outstanding - ELP periodic broadcast sending
  * @work: work queue item
  *
@@ -54,6 +161,7 @@ static void batadv_v_elp_send_outstanding(struct work_struct *work)
 	struct batadv_elp_packet *elp_packet;
 	uint32_t elp_interval;
 	struct sk_buff *skb;
+	uint8_t num_neighs;
 
 	bat_v = container_of(work, struct batadv_hard_iface_bat_v, elp_wq.work);
 	hard_iface = container_of(bat_v, struct batadv_hard_iface, bat_v);
@@ -75,9 +183,15 @@ static void batadv_v_elp_send_outstanding(struct work_struct *work)
 	if (!skb)
 		goto out;
 
+	/* purge outdated entries first */
+	batadv_v_elp_neigh_purge(hard_iface);
+
 	elp_packet = (struct batadv_elp_packet *)skb->data;
 	elp_packet->seqno = htonl(atomic_read(&hard_iface->bat_v.elp_seqno));
-	elp_packet->num_neighbors = 0;
+
+	num_neighs = atomic_read(&hard_iface->bat_v.num_neighbors);
+	elp_packet->num_neighbors = num_neighs;
+
 	elp_interval = atomic_read(&hard_iface->bat_v.elp_interval);
 	elp_packet->elp_interval = htonl(elp_interval);
 
@@ -110,6 +224,9 @@ int batadv_v_elp_iface_enable(struct batadv_hard_iface *hard_iface)
 	size_t size;
 	int res = -ENOMEM;
 
+	INIT_HLIST_HEAD(&hard_iface->bat_v.neigh_list);
+	spin_lock_init(&hard_iface->bat_v.neigh_list_lock);
+
 	size = ETH_HLEN + NET_IP_ALIGN + BATADV_ELP_HLEN;
 	hard_iface->bat_v.elp_skb = dev_alloc_skb(size);
 	if (!hard_iface->bat_v.elp_skb)
@@ -148,6 +265,8 @@ void batadv_v_elp_iface_disable(struct batadv_hard_iface *hard_iface)
 
 	dev_kfree_skb(hard_iface->bat_v.elp_skb);
 	hard_iface->bat_v.elp_skb = NULL;
+
+	batadv_v_elp_neigh_purge(hard_iface);
 }
 
 /**
@@ -177,3 +296,86 @@ void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *hard_iface)
 	}
 	rcu_read_unlock();
 }
+
+/**
+ * batadv_v_elp_neigh_update - update an ELP neighbour node
+ * @bat_priv: the bat priv with all the soft interface information
+ * @neigh_addr: the neighbour interface address
+ * @if_incoming: the interface the packet was received through
+ * @elp_packet: the received ELP packet
+ *
+ * Updates the ELP neighbour node state with the data received within the new
+ * ELP packet.
+ */
+static void batadv_v_elp_neigh_update(struct batadv_priv *bat_priv,
+				      uint8_t *neigh_addr,
+				      struct batadv_hard_iface *if_incoming,
+				      struct batadv_elp_packet *elp_packet)
+{
+	struct batadv_elp_neigh_node *neigh;
+
+	neigh = batadv_v_elp_neigh_get(if_incoming, neigh_addr);
+	if (!neigh) {
+		neigh = batadv_v_elp_neigh_new(if_incoming, neigh_addr,
+					       elp_packet->orig,
+					       ntohl(elp_packet->seqno));
+		if (!neigh)
+			goto out;
+	}
+
+	neigh->last_seen = jiffies;
+
+out:
+	if (neigh)
+		batadv_elp_neigh_node_free_ref(neigh);
+}
+
+/**
+ * batadv_v_elp_packet_recv - main ELP packet handler
+ * @skb: the received packet
+ * @if_incoming: the interface this packet was received through
+ *
+ * Returns NET_RX_SUCCESS and consumes the skb if the packet was peoperly
+ * processed or NET_RX_DROP in case of failure.
+ */
+int batadv_v_elp_packet_recv(struct sk_buff *skb,
+			     struct batadv_hard_iface *if_incoming)
+{
+	struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
+	struct batadv_elp_packet *elp_packet;
+	struct batadv_hard_iface *primary_if;
+	struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb);
+	bool ret;
+
+	ret = batadv_check_management_packet(skb, if_incoming, BATADV_ELP_HLEN);
+	if (!ret)
+		return NET_RX_DROP;
+
+	if (batadv_is_my_mac(bat_priv, ethhdr->h_source))
+		return NET_RX_DROP;
+
+	/* did we receive a B.A.T.M.A.N. V ELP packet on an interface
+	 * that does not have B.A.T.M.A.N. V ELP enabled ? */
+	if (strcmp(bat_priv->bat_algo_ops->name, "BATMAN_V") != 0)
+		return NET_RX_DROP;
+
+	elp_packet = (struct batadv_elp_packet *)skb->data;
+
+	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+		   "Received ELP packet from %pM seqno %u ORIG: %pM\n",
+		   ethhdr->h_source, ntohl(elp_packet->seqno),
+		   elp_packet->orig);
+
+	primary_if = batadv_primary_if_get_selected(bat_priv);
+	if (!primary_if)
+		goto out;
+
+	batadv_v_elp_neigh_update(bat_priv, ethhdr->h_source, if_incoming,
+				  elp_packet);
+
+out:
+	if (primary_if)
+		batadv_hardif_free_ref(primary_if);
+	consume_skb(skb);
+	return NET_RX_SUCCESS;
+}
diff --git a/bat_v_elp.h b/bat_v_elp.h
index 06d2cb1..186ff4b 100644
--- a/bat_v_elp.h
+++ b/bat_v_elp.h
@@ -23,8 +23,14 @@
 #ifndef _NET_BATMAN_ADV_BAT_V_ELP_H_
 #define _NET_BATMAN_ADV_BAT_V_ELP_H_
 
+struct batadv_elp_neigh_node *
+batadv_v_elp_neigh_get(struct batadv_hard_iface *hard_iface,
+		       uint8_t *neigh_addr);
+void batadv_elp_neigh_node_free_ref(struct batadv_elp_neigh_node *neigh);
 int batadv_v_elp_iface_enable(struct batadv_hard_iface *hard_iface);
 void batadv_v_elp_iface_disable(struct batadv_hard_iface *hard_iface);
 void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *hard_iface);
+int batadv_v_elp_packet_recv(struct sk_buff *skb,
+			     struct batadv_hard_iface *if_incoming);
 
 #endif /* _NET_BATMAN_ADV_BAT_V_ELP_H_ */
diff --git a/main.h b/main.h
index 34e85a2..4ab3216 100644
--- a/main.h
+++ b/main.h
@@ -45,6 +45,7 @@
 #define BATADV_TT_WORK_PERIOD 5000 /* 5 seconds */
 #define BATADV_ORIG_WORK_PERIOD 1000 /* 1 second */
 #define BATADV_DAT_ENTRY_TIMEOUT (5*60000) /* 5 mins in milliseconds */
+#define BATADV_ELP_OUTDATED_MAX 4
 /* sliding packet range of received originator messages in sequence numbers
  * (should be a multiple of our word size)
  */
@@ -180,6 +181,7 @@ enum batadv_uev_type {
 #include <linux/jiffies.h>
 #include <linux/seq_file.h>
 #include <linux/if_vlan.h>
+#include <linux/average.h>	/* ewma */
 #include "compat.h"
 
 #include "types.h"
diff --git a/types.h b/types.h
index 518fa81..be230b6 100644
--- a/types.h
+++ b/types.h
@@ -73,12 +73,18 @@ struct batadv_hard_iface_bat_iv {
  * struct batadv_hard_iface_bat_v - per hard interface B.A.T.M.A.N. V data
  * @elp_interval: time interval between two ELP transmissions
  * @elp_seqno: current ELP sequence number
+ * @neigh_list: list of ELP neighbour objects
+ * @neigh_list_lock: protects neigh_list
+ * @num_neighbours: number of neighbours in the neigh_list
  * @elp_skb: base skb containing the ELP message to send
  * @elp_wq: workqueue used to schedule ELP transmissions
  */
 struct batadv_hard_iface_bat_v {
 	atomic_t elp_interval;
 	atomic_t elp_seqno;
+	struct hlist_head neigh_list;
+	spinlock_t neigh_list_lock;
+	atomic_t num_neighbors;
 	struct sk_buff *elp_skb;
 	struct delayed_work elp_wq;
 };
@@ -327,6 +333,37 @@ struct batadv_gw_node {
 };
 
 /**
+ * struct batadv_elp_neigh - hard_iface ralated neighbor information
+ * @list: list node for batadv_hard_iface::neigh_list
+ * @orig: the MAC address of the corresponding orig_node
+ * @addr: the MAC address of the neighboring interface
+ * @metric: ewma link metric towards this neighbor
+ * @last_recv_seqno: last ELP received sequence number
+ * @lest_seen: last time this neigh has been seen
+ * @refcount: number of contexts the object is used
+ * @rcu: struct used for freeing in an RCU-safe manner
+ */
+struct batadv_elp_neigh_node {
+	struct hlist_node list;
+	uint8_t orig[ETH_ALEN];
+	uint8_t addr[ETH_ALEN];
+	struct ewma metric;
+	uint32_t last_recv_seqno;
+	unsigned long last_seen;
+	uint32_t elp_interval;
+	atomic_t refcount;
+	struct rcu_head rcu;
+};
+
+/**
+ * batadv_neigh_node_bat_v - B.A.T.M.A.N. V private neighbor information
+ * @elp_neigh: ELP private neighbour data
+ */
+struct batadv_neigh_node_bat_v {
+	struct batadv_elp_neigh_node *elp_neigh;
+};
+
+/**
  * struct batadv_neigh_node - structure for single hops neighbors
  * @list: list node for batadv_orig_node::neigh_list
  * @orig_node: pointer to corresponding orig_node
@@ -336,6 +373,7 @@ struct batadv_gw_node {
  * @if_incoming: pointer to incoming hard interface
  * @last_seen: when last packet via this neighbor was received
  * @last_ttl: last received ttl from this neigh node
+ * @elp_neigh: ELP private neighbour data
  * @rcu: struct used for freeing in an RCU-safe manner
  * @bat_iv: B.A.T.M.A.N. IV private structure
  */
@@ -347,6 +385,9 @@ struct batadv_neigh_node {
 	spinlock_t ifinfo_lock;	/* protects ifinfo_list and its members */
 	struct batadv_hard_iface *if_incoming;
 	unsigned long last_seen;
+#ifdef CONFIG_BATMAN_ADV_BATMAN_V
+	struct batadv_neigh_node_bat_v bat_v;
+#endif
 	atomic_t refcount;
 	struct rcu_head rcu;
 };
@@ -370,6 +411,15 @@ struct batadv_neigh_ifinfo_bat_iv {
 };
 
 /**
+ * struct batadv_neigh_ifinfo_bat_v - neighbor information per outgoing
+ *  interface for BATMAN V
+ * @metric: last metric received from an originator via this neigh
+ */
+struct batadv_neigh_ifinfo_bat_v {
+	uint32_t metric;
+};
+
+/**
  * struct batadv_neigh_ifinfo - neighbor information per outgoing interface
  * @list: list node for batadv_neigh_node::ifinfo_list
  * @if_outgoing: pointer to outgoing hard interface
@@ -382,6 +432,9 @@ struct batadv_neigh_ifinfo {
 	struct hlist_node list;
 	struct batadv_hard_iface *if_outgoing;
 	struct batadv_neigh_ifinfo_bat_iv bat_iv;
+#ifdef CONFIG_BATMAN_ADV_BATMAN_V
+	struct batadv_neigh_ifinfo_bat_v bat_v;
+#endif
 	uint8_t last_ttl;
 	atomic_t refcount;
 	struct rcu_head rcu;
-- 
1.8.5.3


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

* [B.A.T.M.A.N.] [RFC 05/23] batman-adv: ELP - exporting neighbor list via debugfs
  2014-02-11 12:48 [B.A.T.M.A.N.] [RFC 00/23] Introducing a new routing protocol: B.A.T.M.A.N. V Antonio Quartulli
                   ` (3 preceding siblings ...)
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 04/23] batman-adv: ELP - creating neighbor structures Antonio Quartulli
@ 2014-02-11 12:48 ` Antonio Quartulli
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 06/23] batman-adv: ELP - adding sysfs parameter for elp interval Antonio Quartulli
                   ` (17 subsequent siblings)
  22 siblings, 0 replies; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 12:48 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Marek Lindner, Antonio Quartulli

From: Linus Luessing <linus.luessing@web.de>

Lists all neighbours detected by the Echo Locating Protocol
(ELP) and their metric values.

Initially Developed by Linus during a 6 months trainee study
period in Ascom (Switzerland) AG.

Signed-off-by: Linus Luessing <linus.luessing@web.de>
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 bat_v_elp.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 bat_v_elp.h |  1 +
 debugfs.c   | 17 +++++++++++++
 3 files changed, 98 insertions(+)

diff --git a/bat_v_elp.c b/bat_v_elp.c
index ee4207d..9c40415 100644
--- a/bat_v_elp.c
+++ b/bat_v_elp.c
@@ -379,3 +379,83 @@ out:
 	consume_skb(skb);
 	return NET_RX_SUCCESS;
 }
+
+/**
+ * batadv_v_elp_seq_print_neigh - print a single ELP neighbour node
+ * @seq: neighbour table seq_file struct
+ * @hard_iface: interface the neighbour is connected to
+ * @neigh: the neighbour node to print
+ */
+static void batadv_v_elp_seq_print_neigh(struct seq_file *seq,
+					 struct batadv_hard_iface *hard_iface,
+					 struct batadv_elp_neigh_node *neigh)
+{
+	int last_secs, last_msecs;
+	uint32_t metric;
+
+	last_secs = jiffies_to_msecs(jiffies - neigh->last_seen) / 1000;
+	last_msecs = jiffies_to_msecs(jiffies - neigh->last_seen) % 1000;
+	metric = ewma_read(&neigh->metric);
+
+	seq_printf(seq, "%pM %4i.%03is (%9u.%1u) [%10s]\n",
+		   neigh->addr, last_secs, last_msecs, metric / 10,
+		   metric % 10, hard_iface->net_dev->name);
+}
+
+/**
+ * batadv_v_elp_seq_print_text - print the neighbour table
+ * @seq: neighbour table seq_file struct
+ * @offset: not used
+ *
+ * Returns always 0.
+ */
+int batadv_v_elp_seq_print_text(struct seq_file *seq, void *offset)
+{
+	struct net_device *net_dev = (struct net_device *)seq->private;
+	struct batadv_priv *bat_priv = netdev_priv(net_dev);
+	struct batadv_hard_iface *hard_iface, *primary_if;
+	struct batadv_elp_neigh_node *neigh;
+	int batman_count = 0;
+
+	primary_if = batadv_primary_if_get_selected(bat_priv);
+
+	if (!primary_if) {
+		seq_printf(seq,
+			   "BATMAN mesh %s disabled - please specify interfaces to enable it\n",
+			   net_dev->name);
+		goto out;
+	}
+
+	if (primary_if->if_status != BATADV_IF_ACTIVE) {
+		seq_printf(seq,
+			   "BATMAN mesh %s disabled - primary interface not active\n",
+			   net_dev->name);
+		goto out;
+	}
+
+	seq_printf(seq, "[B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%pM (%s)]\n",
+		   BATADV_SOURCE_VERSION, primary_if->net_dev->name,
+		   primary_if->net_dev->dev_addr, net_dev->name);
+	seq_printf(seq, "  %-15s %s (%11s) [%10s]\n", "Neighbor",
+		   "last-seen", "metric", "IF");
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
+		if (hard_iface->soft_iface != net_dev)
+			continue;
+
+		hlist_for_each_entry_rcu(neigh, &hard_iface->bat_v.neigh_list, list) {
+			batadv_v_elp_seq_print_neigh(seq, hard_iface, neigh);
+			batman_count++;
+		}
+	}
+	rcu_read_unlock();
+
+	if (batman_count == 0)
+		seq_printf(seq, "No batman nodes in range ...\n");
+
+out:
+	if (primary_if)
+		batadv_hardif_free_ref(primary_if);
+	return 0;
+}
diff --git a/bat_v_elp.h b/bat_v_elp.h
index 186ff4b..4f34ecb 100644
--- a/bat_v_elp.h
+++ b/bat_v_elp.h
@@ -32,5 +32,6 @@ void batadv_v_elp_iface_disable(struct batadv_hard_iface *hard_iface);
 void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *hard_iface);
 int batadv_v_elp_packet_recv(struct sk_buff *skb,
 			     struct batadv_hard_iface *if_incoming);
+int batadv_v_elp_seq_print_text(struct seq_file *seq, void *offset);
 
 #endif /* _NET_BATMAN_ADV_BAT_V_ELP_H_ */
diff --git a/debugfs.c b/debugfs.c
index b758881..23990cf 100644
--- a/debugfs.c
+++ b/debugfs.c
@@ -20,6 +20,7 @@
 #include <linux/debugfs.h>
 
 #include "debugfs.h"
+#include "bat_v_elp.h"
 #include "translation-table.h"
 #include "originator.h"
 #include "hard-interface.h"
@@ -242,6 +243,16 @@ static int batadv_algorithms_open(struct inode *inode, struct file *file)
 	return single_open(file, batadv_algo_seq_print_text, NULL);
 }
 
+#ifdef CONFIG_BATMAN_ADV_BATMAN_V
+int batadv_v_elp_seq_print_text(struct seq_file *seq, void *offset);
+
+static int neighbors_open(struct inode *inode, struct file *file)
+{
+	struct net_device *net_dev = (struct net_device *)inode->i_private;
+	return single_open(file, batadv_v_elp_seq_print_text, net_dev);
+}
+#endif
+
 static int batadv_originators_open(struct inode *inode, struct file *file)
 {
 	struct net_device *net_dev = (struct net_device *)inode->i_private;
@@ -346,6 +357,9 @@ static struct batadv_debuginfo *batadv_general_debuginfos[] = {
 };
 
 /* The following attributes are per soft interface */
+#ifdef CONFIG_BATMAN_ADV_BATMAN_V
+static BATADV_DEBUGINFO(neighbors, S_IRUGO, neighbors_open);
+#endif
 static BATADV_DEBUGINFO(originators, S_IRUGO, batadv_originators_open);
 static BATADV_DEBUGINFO(gateways, S_IRUGO, batadv_gateways_open);
 static BATADV_DEBUGINFO(transtable_global, S_IRUGO,
@@ -365,6 +379,9 @@ static BATADV_DEBUGINFO(nc_nodes, S_IRUGO, batadv_nc_nodes_open);
 #endif
 
 static struct batadv_debuginfo *batadv_mesh_debuginfos[] = {
+#ifdef CONFIG_BATMAN_ADV_BATMAN_V
+	&batadv_debuginfo_neighbors,
+#endif
 	&batadv_debuginfo_originators,
 	&batadv_debuginfo_gateways,
 	&batadv_debuginfo_transtable_global,
-- 
1.8.5.3


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

* [B.A.T.M.A.N.] [RFC 06/23] batman-adv: ELP - adding sysfs parameter for elp interval
  2014-02-11 12:48 [B.A.T.M.A.N.] [RFC 00/23] Introducing a new routing protocol: B.A.T.M.A.N. V Antonio Quartulli
                   ` (4 preceding siblings ...)
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 05/23] batman-adv: ELP - exporting neighbor list via debugfs Antonio Quartulli
@ 2014-02-11 12:48 ` Antonio Quartulli
  2014-02-11 16:59   ` Andrew Lunn
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 07/23] batman-adv: OGMv2 - add basic infrastructure Antonio Quartulli
                   ` (16 subsequent siblings)
  22 siblings, 1 reply; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 12:48 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Marek Lindner, Antonio Quartulli

From: Linus Luessing <linus.luessing@web.de>

This parameter can be set individually on each interface and
allows the configuration of the ndp interval for the link
quality measurements during runtime. Usually it is desirable
to set it to a higher (= slower) value on interfaces which
have a more static characteristic (e.g. wired interfaces)
or very dense neighbourhoods to reduce overhead.

Developed by Linus during a 6 months trainee study period in
Ascom (Switzerland) AG.

Signed-off-by: Linus Luessing <linus.luessing@web.de>
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
[antonio@open-mesh.com: respin on top of the latest master]
Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 sysfs-class-net-batman-adv | 8 +++++++-
 sysfs.c                    | 7 +++++++
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/sysfs-class-net-batman-adv b/sysfs-class-net-batman-adv
index 7f34a95..2884c98 100644
--- a/sysfs-class-net-batman-adv
+++ b/sysfs-class-net-batman-adv
@@ -1,4 +1,11 @@
 
+What:           /sys/class/net/<mesh_iface>/batman-adv/elp_interval
+Date:           Mar 2012
+Contact:        Linus Lüssing <linus.luessing@web.de>
+Description:
+                Defines the interval in milliseconds in which batman
+                sends its probing packets for link quality measurements.
+
 What:           /sys/class/net/<iface>/batman-adv/iface_status
 Date:           May 2010
 Contact:        Marek Lindner <mareklindner@neomailbox.ch>
@@ -12,4 +19,3 @@ Description:
                 The /sys/class/net/<iface>/batman-adv/mesh_iface file
                 displays the batman mesh interface this <iface>
                 currently is associated with.
-
diff --git a/sysfs.c b/sysfs.c
index 1e9ee3a..1d6653c 100644
--- a/sysfs.c
+++ b/sysfs.c
@@ -877,10 +877,17 @@ static ssize_t batadv_show_iface_status(struct kobject *kobj,
 static BATADV_ATTR(mesh_iface, S_IRUGO | S_IWUSR, batadv_show_mesh_iface,
 		   batadv_store_mesh_iface);
 static BATADV_ATTR(iface_status, S_IRUGO, batadv_show_iface_status, NULL);
+#ifdef CONFIG_BATMAN_ADV_BATMAN_V
+BATADV_ATTR_HIF_UINT(elp_interval, bat_v.elp_interval, S_IRUGO | S_IWUSR,
+		     2 * BATADV_JITTER, INT_MAX, NULL);
+#endif
 
 static struct batadv_attribute *batadv_batman_attrs[] = {
 	&batadv_attr_mesh_iface,
 	&batadv_attr_iface_status,
+#ifdef CONFIG_BATMAN_ADV_BATMAN_V
+	&batadv_attr_elp_interval,
+#endif
 	NULL,
 };
 
-- 
1.8.5.3


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

* [B.A.T.M.A.N.] [RFC 07/23] batman-adv: OGMv2 - add basic infrastructure
  2014-02-11 12:48 [B.A.T.M.A.N.] [RFC 00/23] Introducing a new routing protocol: B.A.T.M.A.N. V Antonio Quartulli
                   ` (5 preceding siblings ...)
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 06/23] batman-adv: ELP - adding sysfs parameter for elp interval Antonio Quartulli
@ 2014-02-11 12:48 ` Antonio Quartulli
  2014-02-11 17:12   ` Andrew Lunn
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 08/23] batman-adv: OGMv2 - implement originators logic Antonio Quartulli
                   ` (15 subsequent siblings)
  22 siblings, 1 reply; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 12:48 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

This is the initial implementation of the new OGM protocol
(version 2). It has been designed to work on top of the
newly added ELP.

In the previous version the OGM protocol was used to both
measure link qualities and flood the network with the metric
information. In this version the protocol is in charge of
the latter task only, leaving the former to ELP.

This means being able to decouple the interval used by the
neighbor discovery from the OGM broadcasting, which revealed
to be costly in dense networks and needed to be relaxed so
leading to a less responsive routing protocol.

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 Makefile.kbuild |   1 +
 bat_algo.h      |  11 +++
 bat_v.c         |  36 ++++++++-
 bat_v_elp.c     |  11 ++-
 bat_v_ogm.c     | 230 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 bat_v_ogm.h     |  32 ++++++++
 main.c          |  31 +++++++-
 main.h          |   1 +
 packet.h        |  25 ++++++
 types.h         |  15 ++++
 10 files changed, 385 insertions(+), 8 deletions(-)
 create mode 100644 bat_v_ogm.c
 create mode 100644 bat_v_ogm.h

diff --git a/Makefile.kbuild b/Makefile.kbuild
index ae9a6ca..8073940 100644
--- a/Makefile.kbuild
+++ b/Makefile.kbuild
@@ -20,6 +20,7 @@ obj-$(CONFIG_BATMAN_ADV) += batman-adv.o
 batman-adv-y += bat_iv_ogm.o
 batman-adv-$(CONFIG_BATMAN_ADV_BATMAN_V) += bat_v.o
 batman-adv-$(CONFIG_BATMAN_ADV_BATMAN_V) += bat_v_elp.o
+batman-adv-$(CONFIG_BATMAN_ADV_BATMAN_V) += bat_v_ogm.o
 batman-adv-y += bitarray.o
 batman-adv-$(CONFIG_BATMAN_ADV_BLA) += bridge_loop_avoidance.o
 batman-adv-y += debugfs.o
diff --git a/bat_algo.h b/bat_algo.h
index 7289336..14cf89f 100644
--- a/bat_algo.h
+++ b/bat_algo.h
@@ -23,6 +23,8 @@ int batadv_iv_init(void);
 #ifdef CONFIG_BATMAN_ADV_BATMAN_V
 
 int batadv_v_init(void);
+int batadv_v_mesh_init(struct batadv_priv *bat_priv);
+void batadv_v_mesh_free(struct batadv_priv *bat_priv);
 
 #else
 
@@ -31,6 +33,15 @@ static inline int batadv_v_init(void)
 	return 0;
 }
 
+static inline int batadv_v_mesh_init(struct batadv_priv *bat_priv)
+{
+	return 0;
+}
+
+static inline void batadv_v_mesh_free(struct batadv_priv *bat_priv)
+{
+}
+
 #endif /* CONFIG_BATMAN_ADV_BATMAN_V */
 
 #endif /* _NET_BATMAN_ADV_BAT_ALGO_H_ */
diff --git a/bat_v.c b/bat_v.c
index bed5e00..b4214c5 100644
--- a/bat_v.c
+++ b/bat_v.c
@@ -20,10 +20,21 @@
 #include "main.h"
 #include "bat_algo.h"
 #include "bat_v_elp.h"
+#include "bat_v_ogm.h"
 
 static int batadv_v_iface_enable(struct batadv_hard_iface *hard_iface)
 {
-	return batadv_v_elp_iface_enable(hard_iface);
+	int ret;
+
+	ret = batadv_v_elp_iface_enable(hard_iface);
+	if (ret < 0)
+		return ret;
+
+	ret = batadv_v_ogm_iface_enable(hard_iface);
+	if (ret < 0)
+		batadv_v_elp_iface_disable(hard_iface);
+
+	return ret;
 }
 
 static void batadv_v_iface_disable(struct batadv_hard_iface *hard_iface)
@@ -38,6 +49,7 @@ static void batadv_v_iface_update_mac(struct batadv_hard_iface *hard_iface)
 static void batadv_v_primary_iface_set(struct batadv_hard_iface *hard_iface)
 {
 	batadv_v_elp_primary_iface_set(hard_iface);
+	batadv_v_ogm_primary_iface_set(hard_iface);
 }
 
 static void batadv_v_ogm_schedule(struct batadv_hard_iface *hard_iface)
@@ -58,6 +70,15 @@ static struct batadv_algo_ops batadv_batman_v __read_mostly = {
 	.bat_ogm_schedule = batadv_v_ogm_schedule,
 };
 
+int batadv_v_mesh_init(struct batadv_priv *bat_priv)
+{
+	return batadv_v_ogm_init(bat_priv);
+}
+
+void batadv_v_mesh_free(struct batadv_priv *bat_priv)
+{
+	batadv_v_ogm_free(bat_priv);
+}
 
 int __init batadv_v_init(void)
 {
@@ -67,15 +88,24 @@ int __init batadv_v_init(void)
 	ret = batadv_recv_handler_register(BATADV_ELP,
 					   batadv_v_elp_packet_recv);
 	if (ret < 0)
+		return ret;
+
+	ret = batadv_recv_handler_register(BATADV_OGM2,
+					   batadv_v_ogm_packet_recv);
+	if (ret < 0)
 		goto elp_unregister;
 
 	ret = batadv_algo_register(&batadv_batman_v);
+	if (ret < 0)
+		goto ogm_unregister;
 
 	return ret;
 
+ogm_unregister:
+	batadv_recv_handler_unregister(BATADV_OGM2);
+
 elp_unregister:
-	if (ret < 0)
-		batadv_recv_handler_unregister(BATADV_ELP);
+	batadv_recv_handler_unregister(BATADV_ELP);
 
 	return ret;
 }
diff --git a/bat_v_elp.c b/bat_v_elp.c
index 9c40415..1c23951 100644
--- a/bat_v_elp.c
+++ b/bat_v_elp.c
@@ -25,6 +25,7 @@
 #include "bat_v_elp.h"
 #include "originator.h"
 #include "routing.h"
+#include "translation-table.h"
 
 /**
  * batadv_v_elp_start_timer - restart timer for ELP periodic work
@@ -276,11 +277,15 @@ void batadv_v_elp_iface_disable(struct batadv_hard_iface *hard_iface)
  */
 void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *hard_iface)
 {
+	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
 	struct batadv_hard_iface *hard_iface_tmp;
 	struct batadv_elp_packet *elp_packet;
+	struct batadv_ogm2_packet *ogm2;
 	struct sk_buff *skb;
 
-	/* update orig field of every elp iface belonging to this mesh */
+	/* update orig field of every elp and ogm iface belonging to this
+	 * mesh
+	 */
 	rcu_read_lock();
 	list_for_each_entry_rcu(hard_iface_tmp, &batadv_hardif_list, list) {
 		if (hard_iface->soft_iface != hard_iface_tmp->soft_iface)
@@ -293,6 +298,9 @@ void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *hard_iface)
 		elp_packet = (struct batadv_elp_packet *)skb->data;
 		memcpy(elp_packet->orig,
 		       hard_iface->net_dev->dev_addr, ETH_ALEN);
+
+		ogm2 = (struct batadv_ogm2_packet *)bat_priv->bat_v.ogm_buff;
+		memcpy(ogm2->orig, hard_iface->net_dev->dev_addr, ETH_ALEN);
 	}
 	rcu_read_unlock();
 }
@@ -311,6 +319,7 @@ static void batadv_v_elp_neigh_update(struct batadv_priv *bat_priv,
 				      uint8_t *neigh_addr,
 				      struct batadv_hard_iface *if_incoming,
 				      struct batadv_elp_packet *elp_packet)
+
 {
 	struct batadv_elp_neigh_node *neigh;
 
diff --git a/bat_v_ogm.c b/bat_v_ogm.c
new file mode 100644
index 0000000..f66dc02
--- /dev/null
+++ b/bat_v_ogm.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2013 B.A.T.M.A.N. contributors:
+ *
+ * Antonio Quartulli
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ */
+
+#include "main.h"
+
+#include "bat_v_ogm.h"
+#include "hard-interface.h"
+#include "originator.h"
+#include "routing.h"
+#include "send.h"
+#include "translation-table.h"
+
+static void batadv_v_ogm_start_timer(struct batadv_priv *bat_priv)
+{
+	unsigned long msecs;
+	/* this function may be invoked in different contexts (ogm rescheduling
+	 * or hard_iface activation), but the work timer should not be reset
+	 */
+	if (delayed_work_pending(&bat_priv->bat_v.ogm_wq))
+		return;
+
+	msecs = atomic_read(&bat_priv->orig_interval) - BATADV_JITTER;
+	msecs += prandom_u32() % (2 * BATADV_JITTER);
+	queue_delayed_work(batadv_event_workqueue, &bat_priv->bat_v.ogm_wq,
+			   msecs_to_jiffies(msecs));
+}
+
+/* send a batman ogm to a given interface */
+static void batadv_v_ogm_send_to_if(struct sk_buff *skb,
+				    struct batadv_hard_iface *hard_iface)
+{
+	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
+	struct sk_buff *tmp_skb;
+
+	if (hard_iface->if_status != BATADV_IF_ACTIVE)
+		return;
+
+	tmp_skb = skb_clone(skb, GFP_ATOMIC);
+	if (!tmp_skb)
+		return;
+
+	batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_TX);
+	batadv_add_counter(bat_priv, BATADV_CNT_MGMT_TX_BYTES,
+			   tmp_skb->len + ETH_HLEN);
+
+	batadv_send_skb_packet(tmp_skb, hard_iface, batadv_broadcast_addr);
+}
+
+static void batadv_v_ogm_send(struct work_struct *work)
+{
+	struct batadv_hard_iface *hard_iface;
+	struct batadv_priv_bat_v *bat_v;
+	struct batadv_priv *bat_priv;
+	struct batadv_ogm2_packet *ogm2;
+	struct sk_buff *skb;
+	unsigned char *ogm_buff, *pkt_buff;
+	int ogm_buff_len;
+	uint16_t tvlv_len = 0;
+
+	bat_v = container_of(work, struct batadv_priv_bat_v, ogm_wq.work);
+	bat_priv = container_of(bat_v, struct batadv_priv, bat_v);
+
+	if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING)
+		goto out;
+
+	ogm_buff = bat_priv->bat_v.ogm_buff;
+	ogm_buff_len = bat_priv->bat_v.ogm_buff_len;
+	/* tt changes have to be committed before the tvlv data is
+	 * appended as it may alter the tt tvlv container
+	 */
+	batadv_tt_local_commit_changes(bat_priv);
+	tvlv_len = batadv_tvlv_container_ogm_append(bat_priv, &ogm_buff,
+						    &ogm_buff_len,
+						    BATADV_OGM2_HLEN);
+
+	bat_priv->bat_v.ogm_buff = ogm_buff;
+	bat_priv->bat_v.ogm_buff_len = ogm_buff_len;
+
+	skb = netdev_alloc_skb_ip_align(NULL, ETH_HLEN + ogm_buff_len);
+	if (!skb)
+		goto out;
+
+	skb_reserve(skb, ETH_HLEN);
+	pkt_buff = skb_put(skb, ogm_buff_len);
+	memcpy(pkt_buff, ogm_buff, ogm_buff_len);
+
+	ogm2 = (struct batadv_ogm2_packet *)skb->data;
+	ogm2->seqno = htonl(atomic_read(&bat_priv->bat_v.ogm_seqno));
+	atomic_inc(&bat_priv->bat_v.ogm_seqno);
+	ogm2->tvlv_len = htons(tvlv_len);
+
+	/* broadcast on every interface */
+	rcu_read_lock();
+	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
+		if (hard_iface->soft_iface != bat_priv->soft_iface)
+			continue;
+
+		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+			   "Sending own OGM2 packet (originator %pM, seqno %u, metric %u, TTL %d) on interface %s [%pM]\n",
+			   ogm2->orig, ntohl(ogm2->seqno), ntohl(ogm2->metric),
+			   ogm2->ttl, hard_iface->net_dev->name,
+			   hard_iface->net_dev->dev_addr);
+
+		batadv_v_ogm_send_to_if(skb, hard_iface);
+	}
+	rcu_read_unlock();
+
+	consume_skb(skb);
+
+	batadv_v_ogm_start_timer(bat_priv);
+out:
+	return;
+}
+
+int batadv_v_ogm_iface_enable(struct batadv_hard_iface *hard_iface)
+{
+	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
+
+	batadv_v_ogm_start_timer(bat_priv);
+
+	return 0;
+}
+
+void batadv_v_ogm_primary_iface_set(struct batadv_hard_iface *hard_iface)
+{
+	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
+	struct batadv_hard_iface *hard_iface_tmp;
+	struct batadv_ogm2_packet *ogm2;
+
+	/* update orig field of every elp and ogm iface belonging to this
+	 * mesh
+	 */
+	rcu_read_lock();
+	list_for_each_entry_rcu(hard_iface_tmp, &batadv_hardif_list, list) {
+		if (hard_iface->soft_iface != hard_iface_tmp->soft_iface)
+			continue;
+
+		if (!hard_iface_tmp->bat_v.elp_skb)
+			continue;
+
+		ogm2 = (struct batadv_ogm2_packet *)bat_priv->bat_v.ogm_buff;
+		memcpy(ogm2->orig, hard_iface->net_dev->dev_addr, ETH_ALEN);
+	}
+	rcu_read_unlock();
+}
+
+int batadv_v_ogm_packet_recv(struct sk_buff *skb,
+			      struct batadv_hard_iface *if_incoming)
+{	struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
+	struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb);
+	struct batadv_ogm2_packet *ogm2;
+
+	/* did we receive a OGM2 packet on an interface that does not have
+	 * B.A.T.M.A.N. V enabled ?
+	 */
+	if (strcmp(bat_priv->bat_algo_ops->name, "BATMAN_V") != 0)
+		return NET_RX_DROP;
+
+	if (!batadv_check_management_packet(skb, if_incoming, BATADV_OGM2_HLEN))
+		return NET_RX_DROP;
+
+	if (batadv_is_my_mac(bat_priv, ethhdr->h_source))
+		return NET_RX_DROP;
+
+	ogm2 = (struct batadv_ogm2_packet *)skb->data;
+
+	if (batadv_is_my_mac(bat_priv, ogm2->orig))
+		return NET_RX_DROP;
+
+	batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_RX);
+	batadv_add_counter(bat_priv, BATADV_CNT_MGMT_RX_BYTES,
+			   skb->len + ETH_HLEN);
+
+	consume_skb(skb);
+	return NET_RX_SUCCESS;
+}
+
+int batadv_v_ogm_init(struct batadv_priv *bat_priv)
+{
+	struct batadv_ogm2_packet *ogm2;
+	unsigned char *ogm_buff;
+	uint32_t random_seqno;
+
+	bat_priv->bat_v.ogm_buff_len = BATADV_OGM2_HLEN;
+	ogm_buff = kmalloc(bat_priv->bat_v.ogm_buff_len, GFP_ATOMIC);
+	if (!ogm_buff)
+		return -ENOMEM;
+
+	bat_priv->bat_v.ogm_buff = ogm_buff;
+	ogm2 = (struct batadv_ogm2_packet *)ogm_buff;
+	ogm2->packet_type = BATADV_OGM2;
+	ogm2->version = BATADV_COMPAT_VERSION;
+	ogm2->ttl = BATADV_TTL;
+	ogm2->flags = BATADV_NO_FLAGS;
+	ogm2->metric = htonl(BATADV_MAX_METRIC);
+
+	/* randomize initial seqno to avoid collision */
+	get_random_bytes(&random_seqno, sizeof(random_seqno));
+	atomic_set(&bat_priv->bat_v.ogm_seqno, random_seqno);
+	INIT_DELAYED_WORK(&bat_priv->bat_v.ogm_wq, batadv_v_ogm_send);
+
+	return 0;
+}
+
+void batadv_v_ogm_free(struct batadv_priv *bat_priv)
+{
+	cancel_delayed_work_sync(&bat_priv->bat_v.ogm_wq);
+
+	kfree(bat_priv->bat_v.ogm_buff);
+	bat_priv->bat_v.ogm_buff = NULL;
+	bat_priv->bat_v.ogm_buff_len = 0;
+}
diff --git a/bat_v_ogm.h b/bat_v_ogm.h
new file mode 100644
index 0000000..7f7341e
--- /dev/null
+++ b/bat_v_ogm.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2013 B.A.T.M.A.N. contributors:
+ *
+ * Antonio Quartulli
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ */
+
+#ifndef _BATAMAN_ADV_BATADV_V_OGM_H_
+#define _BATAMAN_ADV_BATADV_V_OGM_H_
+
+int batadv_v_ogm_init(struct batadv_priv *bat_priv);
+void batadv_v_ogm_free(struct batadv_priv *bat_priv);
+int batadv_v_ogm_iface_enable(struct batadv_hard_iface *hard_iface);
+void batadv_v_ogm_primary_iface_set(struct batadv_hard_iface *hard_iface);
+int batadv_v_ogm_packet_recv(struct sk_buff *skb,
+			      struct batadv_hard_iface *if_incoming);
+
+#endif /* _BATAMAN_ADV_BATADV_V_OGM_H_ */
diff --git a/main.c b/main.c
index b7d9996..424fa82 100644
--- a/main.c
+++ b/main.c
@@ -35,6 +35,7 @@
 #include "bridge_loop_avoidance.h"
 #include "distributed-arp-table.h"
 #include "gateway_common.h"
+#include "hard-interface.h"
 #include "hash.h"
 #include "bat_algo.h"
 #include "network-coding.h"
@@ -125,6 +126,10 @@ int batadv_mesh_init(struct net_device *soft_iface)
 	INIT_HLIST_HEAD(&bat_priv->tvlv.handler_list);
 	INIT_HLIST_HEAD(&bat_priv->softif_vlan_list);
 
+	ret = batadv_v_mesh_init(bat_priv);
+	if (ret < 0)
+		goto err;
+
 	ret = batadv_originator_init(bat_priv);
 	if (ret < 0)
 		goto err;
@@ -165,6 +170,8 @@ void batadv_mesh_free(struct net_device *soft_iface)
 
 	batadv_purge_outstanding_packets(bat_priv, NULL);
 
+	batadv_v_mesh_free(bat_priv);
+
 	batadv_gw_node_purge(bat_priv);
 	batadv_nc_mesh_free(bat_priv);
 	batadv_dat_free(bat_priv);
@@ -835,21 +842,32 @@ uint16_t batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv,
 {
 	struct batadv_tvlv_container *tvlv;
 	struct batadv_tvlv_hdr *tvlv_hdr;
-	uint16_t tvlv_value_len;
+	uint16_t tvlv_value_len = 0;
 	void *tvlv_value;
 	bool ret;
+	struct batadv_hard_iface *primary_if;
+
+	primary_if = batadv_primary_if_get_selected(bat_priv);
+	if (!primary_if)
+		goto end;
 
 	spin_lock_bh(&bat_priv->tvlv.container_list_lock);
 	tvlv_value_len = batadv_tvlv_container_list_size(bat_priv);
 
+	if (packet_min_len + tvlv_value_len > primary_if->net_dev->mtu) {
+		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+			   "OGM size too big to fit the primary_if mtu\n");
+		goto unlock;
+	}
+
 	ret = batadv_tvlv_realloc_packet_buff(packet_buff, packet_buff_len,
 					      packet_min_len, tvlv_value_len);
 
 	if (!ret)
-		goto end;
+		goto unlock;
 
 	if (!tvlv_value_len)
-		goto end;
+		goto unlock;
 
 	tvlv_value = (*packet_buff) + packet_min_len;
 
@@ -863,8 +881,13 @@ uint16_t batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv,
 		tvlv_value = (uint8_t *)tvlv_value + ntohs(tvlv->tvlv_hdr.len);
 	}
 
-end:
+unlock:
 	spin_unlock_bh(&bat_priv->tvlv.container_list_lock);
+
+end:
+	if (primary_if)
+		batadv_hardif_free_ref(primary_if);
+
 	return tvlv_value_len;
 }
 
diff --git a/main.h b/main.h
index 4ab3216..4badd01 100644
--- a/main.h
+++ b/main.h
@@ -30,6 +30,7 @@
 /* B.A.T.M.A.N. parameters */
 
 #define BATADV_TQ_MAX_VALUE 255
+#define BATADV_MAX_METRIC 0xFFFFFFFF
 #define BATADV_JITTER 20
 
 /* Time To Live of broadcast messages */
diff --git a/packet.h b/packet.h
index 71b1aeb..a985802 100644
--- a/packet.h
+++ b/packet.h
@@ -38,6 +38,7 @@ enum batadv_packettype {
 	BATADV_BCAST            = 0x01,
 	BATADV_CODED            = 0x02,
 	BATADV_ELP		= 0x03,
+	BATADV_OGM2		= 0x0d,
 	/* 0x40 - 0x7f: unicast */
 #define BATADV_UNICAST_MIN     0x40
 	BATADV_UNICAST          = 0x40,
@@ -193,6 +194,30 @@ struct batadv_ogm_packet {
 #define BATADV_OGM_HLEN sizeof(struct batadv_ogm_packet)
 
 /**
+ * struct batadv_ogm2_packet - ogm2 (routing protocol) packet
+ * @packet_type: batman-adv packet type, part of the general header
+ * @version: batman-adv protocol version, part of the general header
+ * @ttl: time to live for this packet, part of the general header
+ * @flags:
+ * @seqno: sequence number
+ * @orig: originator mac address
+ * @tvlv_len: length of the appended tvlv buffer (in bytes)
+ * @metric: the currently flooded metric value
+ */
+struct batadv_ogm2_packet {
+	uint8_t  packet_type;
+	uint8_t  version;
+	uint8_t  ttl;
+	uint8_t flags;
+	__be32 seqno;
+	uint8_t orig[ETH_ALEN];
+	__be16 tvlv_len;
+	__be32 metric;
+};
+
+#define BATADV_OGM2_HLEN sizeof(struct batadv_ogm2_packet)
+
+/**
  * struct batadv_elp_packet - elp (neighbor discovery) packet
  * @packet_type: batman-adv packet type, part of the general header
  * @version: batman-adv protocol version, part of the genereal header
diff --git a/types.h b/types.h
index be230b6..e9149d1 100644
--- a/types.h
+++ b/types.h
@@ -728,6 +728,18 @@ struct batadv_softif_vlan {
 };
 
 /**
+ * struct batadv_priv_bat_v -
+ * @ogm_buff:
+ * @ogm_buff_len:
+ */
+struct batadv_priv_bat_v {
+	unsigned char *ogm_buff;
+	int ogm_buff_len;
+	struct delayed_work ogm_wq;
+	atomic_t ogm_seqno;
+};
+
+/**
  * struct batadv_priv - per mesh interface data
  * @mesh_state: current status of the mesh (inactive/active/deactivating)
  * @soft_iface: net device which holds this struct as private data
@@ -834,6 +846,9 @@ struct batadv_priv {
 	atomic_t network_coding;
 	struct batadv_priv_nc nc;
 #endif /* CONFIG_BATMAN_ADV_NC */
+#ifdef CONFIG_BATMAN_ADV_BATMAN_V
+	struct batadv_priv_bat_v bat_v;
+#endif
 };
 
 /**
-- 
1.8.5.3


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

* [B.A.T.M.A.N.] [RFC 08/23] batman-adv: OGMv2 - implement originators logic
  2014-02-11 12:48 [B.A.T.M.A.N.] [RFC 00/23] Introducing a new routing protocol: B.A.T.M.A.N. V Antonio Quartulli
                   ` (6 preceding siblings ...)
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 07/23] batman-adv: OGMv2 - add basic infrastructure Antonio Quartulli
@ 2014-02-11 12:48 ` Antonio Quartulli
  2014-02-11 17:22   ` Andrew Lunn
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 09/23] batman-adv: OGMv2 - purge obsolete potential routers Antonio Quartulli
                   ` (14 subsequent siblings)
  22 siblings, 1 reply; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 12:48 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

Add the support for recognising new originators in the
network and rebroadcast their OGMs.

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 bat_v_elp.c |   7 +-
 bat_v_ogm.c | 422 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 414 insertions(+), 15 deletions(-)

diff --git a/bat_v_elp.c b/bat_v_elp.c
index 1c23951..f9a6bfe 100644
--- a/bat_v_elp.c
+++ b/bat_v_elp.c
@@ -63,7 +63,7 @@ void batadv_elp_neigh_node_free_ref(struct batadv_elp_neigh_node *neigh)
  */
 static struct batadv_elp_neigh_node *
 batadv_v_elp_neigh_new(struct batadv_hard_iface *hard_iface,
-		       uint8_t *neigh_addr, uint8_t *orig_addr, uint32_t seqno)
+		       uint8_t *neigh_addr, uint8_t *orig_addr)
 {
 	struct batadv_elp_neigh_node *neigh;
 
@@ -73,7 +73,6 @@ batadv_v_elp_neigh_new(struct batadv_hard_iface *hard_iface,
 
 	memcpy(neigh->orig, orig_addr, ETH_ALEN);
 	memcpy(neigh->addr, neigh_addr, ETH_ALEN);
-	neigh->last_recv_seqno = seqno - 1;
 	neigh->last_seen = jiffies;
 	ewma_init(&neigh->metric, 1024, 8);
 	/* recount initialised to 2 to simplify the caller function */
@@ -326,13 +325,13 @@ static void batadv_v_elp_neigh_update(struct batadv_priv *bat_priv,
 	neigh = batadv_v_elp_neigh_get(if_incoming, neigh_addr);
 	if (!neigh) {
 		neigh = batadv_v_elp_neigh_new(if_incoming, neigh_addr,
-					       elp_packet->orig,
-					       ntohl(elp_packet->seqno));
+					       elp_packet->orig);
 		if (!neigh)
 			goto out;
 	}
 
 	neigh->last_seen = jiffies;
+	neigh->last_recv_seqno = ntohl(elp_packet->seqno);
 
 out:
 	if (neigh)
diff --git a/bat_v_ogm.c b/bat_v_ogm.c
index f66dc02..4981d7c 100644
--- a/bat_v_ogm.c
+++ b/bat_v_ogm.c
@@ -21,6 +21,7 @@
 
 #include "main.h"
 
+#include "bat_v_elp.h"
 #include "bat_v_ogm.h"
 #include "hard-interface.h"
 #include "originator.h"
@@ -28,6 +29,78 @@
 #include "send.h"
 #include "translation-table.h"
 
+static struct batadv_orig_node *
+batadv_v_ogm_orig_get(struct batadv_priv *bat_priv, const uint8_t *addr)
+{
+	struct batadv_orig_node *orig_node;
+	int hash_added;
+
+	orig_node = batadv_orig_hash_find(bat_priv, addr);
+	if (orig_node)
+		return orig_node;
+
+	orig_node = batadv_orig_node_new(bat_priv, addr);
+
+	hash_added = batadv_hash_add(bat_priv->orig_hash, batadv_compare_orig,
+				     batadv_choose_orig, orig_node,
+				     &orig_node->hash_entry);
+	if (hash_added != 0) {
+		batadv_orig_node_free_ref(orig_node);
+		batadv_orig_node_free_ref(orig_node);
+		orig_node = NULL;
+	}
+
+	return orig_node;
+}
+
+static struct batadv_neigh_node *
+batadv_v_ogm_neigh_new(struct batadv_priv *bat_priv,
+		       struct batadv_hard_iface *hard_iface,
+		       uint8_t *addr,
+		       struct batadv_orig_node *orig_node,
+		       struct batadv_orig_node *orig_neigh)
+{
+	struct batadv_neigh_node *neigh_node, *tmp_neigh_node;
+	struct batadv_elp_neigh_node *elp_neigh;
+
+	neigh_node = batadv_neigh_node_new(hard_iface, addr, orig_neigh);
+	if (!neigh_node)
+		return NULL;
+
+	if (!atomic_inc_not_zero(&hard_iface->refcount)) {
+		kfree(neigh_node);
+		return NULL;
+	}
+
+	elp_neigh = batadv_v_elp_neigh_get(hard_iface, addr);
+	if (!elp_neigh) {
+		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+			   "No ELP object for this neighbor!\n");
+		return NULL;
+	}
+
+	neigh_node->bat_v.elp_neigh = elp_neigh;
+
+	spin_lock_bh(&orig_node->neigh_list_lock);
+	tmp_neigh_node = batadv_neigh_node_get(orig_node, hard_iface, addr);
+	if (!tmp_neigh_node) {
+		hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list);
+	} else {
+		kfree(neigh_node);
+		batadv_hardif_free_ref(hard_iface);
+		batadv_elp_neigh_node_free_ref(elp_neigh);
+		neigh_node = tmp_neigh_node;
+	}
+	spin_unlock_bh(&orig_node->neigh_list_lock);
+
+	if (!tmp_neigh_node)
+		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+			   "Creating new neighbor %pM for orig_node %pM on interface %s\n",
+			   addr, orig_node->orig, hard_iface->net_dev->name);
+
+	return neigh_node;
+}
+
 static void batadv_v_ogm_start_timer(struct batadv_priv *bat_priv)
 {
 	unsigned long msecs;
@@ -48,20 +121,15 @@ static void batadv_v_ogm_send_to_if(struct sk_buff *skb,
 				    struct batadv_hard_iface *hard_iface)
 {
 	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
-	struct sk_buff *tmp_skb;
 
 	if (hard_iface->if_status != BATADV_IF_ACTIVE)
 		return;
 
-	tmp_skb = skb_clone(skb, GFP_ATOMIC);
-	if (!tmp_skb)
-		return;
-
 	batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_TX);
 	batadv_add_counter(bat_priv, BATADV_CNT_MGMT_TX_BYTES,
-			   tmp_skb->len + ETH_HLEN);
+			   skb->len + ETH_HLEN);
 
-	batadv_send_skb_packet(tmp_skb, hard_iface, batadv_broadcast_addr);
+	batadv_send_skb_packet(skb, hard_iface, batadv_broadcast_addr);
 }
 
 static void batadv_v_ogm_send(struct work_struct *work)
@@ -70,7 +138,7 @@ static void batadv_v_ogm_send(struct work_struct *work)
 	struct batadv_priv_bat_v *bat_v;
 	struct batadv_priv *bat_priv;
 	struct batadv_ogm2_packet *ogm2;
-	struct sk_buff *skb;
+	struct sk_buff *skb, *tmp_skb;
 	unsigned char *ogm_buff, *pkt_buff;
 	int ogm_buff_len;
 	uint16_t tvlv_len = 0;
@@ -119,7 +187,12 @@ static void batadv_v_ogm_send(struct work_struct *work)
 			   ogm2->ttl, hard_iface->net_dev->name,
 			   hard_iface->net_dev->dev_addr);
 
-		batadv_v_ogm_send_to_if(skb, hard_iface);
+		/* this skb gets consumed by batadv_v_ogm_send_to_if() */
+		tmp_skb = skb_clone(skb, GFP_ATOMIC);
+		if (!tmp_skb)
+			break;
+
+		batadv_v_ogm_send_to_if(tmp_skb, hard_iface);
 	}
 	rcu_read_unlock();
 
@@ -162,11 +235,259 @@ void batadv_v_ogm_primary_iface_set(struct batadv_hard_iface *hard_iface)
 	rcu_read_unlock();
 }
 
+static void
+batadv_v_ogm_orig_update(struct batadv_priv *bat_priv,
+			 struct batadv_orig_node *orig_node,
+			 struct batadv_neigh_node *neigh_node,
+			 const struct batadv_ogm2_packet *ogm2,
+			 struct batadv_hard_iface *if_outgoing)
+{
+	struct batadv_neigh_ifinfo *router_ifinfo = NULL, *neigh_ifinfo = NULL;
+	struct batadv_neigh_node *router = NULL;
+	struct batadv_orig_ifinfo *orig_ifinfo;
+
+	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+		   "update_originator(): Searching and updating originator entry of received packet\n");
+
+	/* get the TVLV container and process it */
+	batadv_tvlv_containers_process(bat_priv, true, orig_node, NULL, NULL,
+				       (unsigned char *)(ogm2 + 1),
+				       ntohs(ogm2->tvlv_len));
+
+	orig_node->last_seen = jiffies;
+
+	orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing);
+	orig_ifinfo->last_real_seqno = ntohl(ogm2->seqno);
+	orig_ifinfo->last_ttl = ogm2->ttl;
+	batadv_orig_ifinfo_free_ref(orig_ifinfo);
+
+	/* if this neighbor already is our next hop there is nothing
+	 * to change
+	 */
+	router = batadv_orig_router_get(orig_node, if_outgoing);
+	if (router == neigh_node)
+		goto out;
+
+	/* don't consider neighbours with worse metric */
+	if (router) {
+		router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing);
+		neigh_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
+		if (router_ifinfo && neigh_ifinfo &&
+		    router_ifinfo->bat_v.metric >= neigh_ifinfo->bat_v.metric)
+			goto out;
+	}
+
+	batadv_update_route(bat_priv, orig_node, if_outgoing, neigh_node);
+
+out:
+	if (router_ifinfo)
+		batadv_neigh_ifinfo_free_ref(router_ifinfo);
+	if (neigh_ifinfo)
+		batadv_neigh_ifinfo_free_ref(neigh_ifinfo);
+	if (router)
+		batadv_neigh_node_free_ref(router);
+}
+
+/**
+ * batadv_v_penalty - apply a penalty to the metric forwarded by the OGM
+ * @bat_priv: the bat priv with all the soft interface information
+ * @metric: the current metric value
+ * @link_metric: the metric of the last link traversed by the OGM
+ * @if_incoming: the interface where the OGM has been received
+ *
+ * Apply a penalty on the current metric value based on the characteristic of
+ * the interface where the OGM has been received. The return value is computed
+ * as follows:
+ * - metric * 50% if the incoming interface is wireless and the metric is not
+ *   less than 10% of the link throughput
+ * - metric * (100 - hop_penalty)% otherwise
+ *
+ * Return the penalised metric value
+ */
+static uint32_t batadv_v_penalty(struct batadv_priv *bat_priv,
+				 uint32_t metric, uint32_t link_metric,
+				 struct batadv_hard_iface *if_incoming)
+{
+	int hop_penalty = atomic_read(&bat_priv->hop_penalty);
+
+	/* proportion to use the same value used in batman iv (x * 128 / 256) */
+	hop_penalty = hop_penalty * 100 / 255;
+
+	if (batadv_is_wifi_netdev(if_incoming->net_dev) &&
+	    metric > link_metric / 10)
+		return metric / 2;
+
+	return metric * (100 - hop_penalty) / 100;
+}
+
+static void batadv_v_ogm_forward(struct batadv_priv *bat_priv,
+				 const struct batadv_ogm2_packet *ogm2,
+				 struct batadv_neigh_node *neigh_node,
+				 struct batadv_hard_iface *if_incoming,
+				 struct batadv_hard_iface *if_outgoing)
+{
+	struct batadv_ogm2_packet *ogm_new;
+	uint32_t link_metric, new_metric;
+	unsigned char *skb_buff;
+	struct sk_buff *skb;
+	uint16_t tvlv_len;
+	size_t packet_len;
+
+	if (ogm2->ttl <= 1) {
+		batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "ttl exceeded\n");
+		return;
+	}
+
+	tvlv_len = ntohs(ogm2->tvlv_len);
+
+	packet_len = BATADV_OGM2_HLEN + tvlv_len;
+	skb = netdev_alloc_skb_ip_align(if_outgoing->net_dev,
+					ETH_HLEN + packet_len);
+	if (!skb)
+		return;
+
+	skb_reserve(skb, ETH_HLEN);
+	skb_buff = skb_put(skb, packet_len);
+	memcpy(skb_buff, ogm2, packet_len);
+
+	/* apply hop penalty */
+	ogm_new = (struct batadv_ogm2_packet *)skb_buff;
+	link_metric = ewma_read(&neigh_node->bat_v.elp_neigh->metric);
+	new_metric = batadv_v_penalty(bat_priv, ntohl(ogm_new->metric),
+				      link_metric, if_incoming);
+	ogm_new->metric = htonl(new_metric);
+	ogm_new->ttl--;
+
+	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+		   "Forwarding OGM2 packet on %s: metric %u, ttl %u\n",
+		   if_outgoing->net_dev->name, new_metric, ogm_new->ttl);
+
+	batadv_v_ogm_send_to_if(skb, if_outgoing);
+}
+
+/**
+ * batadv_v_ogm_process_per_outif - process a batman iv OGM for an outgoing if
+ * @skb: the skb containing the OGM
+ * @if_incoming: the interface where this packet was received
+ * @if_outgoing: the interface for which the packet should be considered
+ */
+static void
+batadv_v_ogm_process_per_outif(struct batadv_priv *bat_priv,
+			       const struct ethhdr *ethhdr,
+			       const struct batadv_ogm2_packet *ogm2,
+			       struct batadv_orig_node *orig_node,
+			       struct batadv_neigh_node *neigh_node,
+			       struct batadv_hard_iface *if_incoming,
+			       struct batadv_hard_iface *if_outgoing)
+{
+	struct batadv_neigh_ifinfo *neigh_ifinfo = NULL, *router_ifinfo = NULL;
+	struct batadv_neigh_node *orig_neigh_router = NULL;
+	struct batadv_neigh_node *router = NULL, *router_router = NULL;
+	struct batadv_orig_node *orig_neigh_node;
+	struct batadv_orig_ifinfo *orig_ifinfo = NULL;
+	bool is_from_best_next_hop = false;
+	uint32_t new_metric;
+	int32_t seq_diff;
+
+	orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing);
+	seq_diff = ntohl(ogm2->seqno) - orig_ifinfo->last_real_seqno;
+	if (!hlist_empty(&orig_node->neigh_list) &&
+	    batadv_window_protected(bat_priv, seq_diff,
+				    &orig_ifinfo->batman_seqno_reset)) {
+		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+			   "Drop packet: packet within window protection time from %pM\n",
+			   ogm2->orig);
+		goto out;
+	}
+
+	new_metric = ntohl(ogm2->metric);
+	neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing);
+	if (seq_diff > 0 || new_metric > neigh_ifinfo->bat_v.metric) {
+		neigh_ifinfo->bat_v.metric = new_metric;
+		neigh_ifinfo->last_ttl = ogm2->ttl;
+	}
+
+	router = batadv_orig_router_get(orig_node, if_outgoing);
+	if (router) {
+		router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing);
+		if (router_ifinfo && (router_ifinfo->bat_v.metric != 0) &&
+		    (batadv_compare_eth(router->addr, ethhdr->h_source)))
+			is_from_best_next_hop = true;
+	}
+
+	orig_ifinfo->last_real_seqno = ntohl(ogm2->seqno);
+
+	/* if sender is a direct neighbor the sender mac equals
+	 * originator mac
+	 */
+	if (router && router->orig_node == orig_node)
+		orig_neigh_node = orig_node;
+	else
+		orig_neigh_node = batadv_v_ogm_orig_get(bat_priv,
+							ethhdr->h_source);
+
+	if (!orig_neigh_node)
+		goto out;
+
+	orig_neigh_router = batadv_orig_router_get(orig_neigh_node,
+						   if_outgoing);
+
+	/* drop packet if sender is not a direct neighbor and if we
+	 * don't route towards it
+	 */
+	if (router && router->orig_node != orig_node &&
+	    (!orig_neigh_router)) {
+		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+			   "Drop packet: OGM via unknown neighbor!\n");
+		goto out_neigh;
+	}
+
+	/* if there is a router and the sequence number is the same as the last
+	 * received from it, but the metric is worse, then drop the packet
+	 */
+	if (router && seq_diff == 0 && new_metric < router_ifinfo->bat_v.metric)
+		goto out_neigh;
+
+	batadv_v_ogm_orig_update(bat_priv, orig_node, neigh_node, ogm2,
+				 if_outgoing);
+
+	/* strict rule: forward packets coming from the best next hop only */
+	if (router && !is_from_best_next_hop)
+		goto out_neigh;
+
+	/* only forward for specific interface, not for the default one. */
+	if (if_outgoing != BATADV_IF_DEFAULT)
+		batadv_v_ogm_forward(bat_priv, ogm2, neigh_node, if_incoming,
+				     if_outgoing);
+
+out_neigh:
+	if (orig_neigh_node != orig_node && orig_neigh_node)
+		batadv_orig_node_free_ref(orig_neigh_node);
+out:
+	if (orig_ifinfo)
+		batadv_orig_ifinfo_free_ref(orig_ifinfo);
+	if (router)
+		batadv_neigh_node_free_ref(router);
+	if (router_ifinfo)
+		batadv_neigh_ifinfo_free_ref(router_ifinfo);
+	if (router_router)
+		batadv_neigh_node_free_ref(router_router);
+	if (orig_neigh_router)
+		batadv_neigh_node_free_ref(orig_neigh_router);
+	if (neigh_ifinfo)
+		batadv_neigh_ifinfo_free_ref(neigh_ifinfo);
+}
+
 int batadv_v_ogm_packet_recv(struct sk_buff *skb,
 			      struct batadv_hard_iface *if_incoming)
 {	struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
-	struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb);
+	struct batadv_orig_node *orig_node, *orig_neigh;
+	uint32_t ogm_metric, link_metric, new_metric;
+	struct batadv_neigh_node *neigh_node = NULL;
+	struct ethhdr *ethhdr = eth_hdr(skb);
+	struct batadv_hard_iface *hard_iface;
 	struct batadv_ogm2_packet *ogm2;
+	int ret = NET_RX_DROP;
 
 	/* did we receive a OGM2 packet on an interface that does not have
 	 * B.A.T.M.A.N. V enabled ?
@@ -189,8 +510,87 @@ int batadv_v_ogm_packet_recv(struct sk_buff *skb,
 	batadv_add_counter(bat_priv, BATADV_CNT_MGMT_RX_BYTES,
 			   skb->len + ETH_HLEN);
 
+	ogm_metric = ntohl(ogm2->metric);
+
+	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+		   "Received OGM2 packet via NB: %pM, IF: %s [%pM] (from OG: %pM, seqno %u, metric %u, TTL %u, V %u, tvlv_len %u)\n",
+		   ethhdr->h_source, if_incoming->net_dev->name,
+		   if_incoming->net_dev->dev_addr, ogm2->orig,
+		   ntohl(ogm2->seqno), ogm_metric, ogm2->ttl,
+		   ogm2->version, ntohs(ogm2->tvlv_len));
+
+	/* if the metric is 0, immediately drop the packet. no need to create
+	 * orig_node/neigh_node for a not usable route
+	 */
+	if (ogm_metric == 0) {
+		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+			   "Drop packet: originator packet with metric equal 0\n");
+		return NET_RX_DROP;
+	}
+
+	orig_node = batadv_v_ogm_orig_get(bat_priv, ogm2->orig);
+	if (!orig_node)
+		return NET_RX_DROP;
+
+	orig_neigh = batadv_v_ogm_orig_get(bat_priv, ethhdr->h_source);
+	if (!orig_neigh)
+		goto out;
+
+	neigh_node = batadv_v_ogm_neigh_new(bat_priv, if_incoming,
+					    ethhdr->h_source, orig_node,
+					    orig_neigh);
+	if (!neigh_node) {
+		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+			   "Could not create neigh node!\n");
+		goto out;
+	}
+
+	/* update the neigh_node information */
+	neigh_node->last_seen = jiffies;
+
+	/* update the received metric to match the node topology: if this node
+	 * is the first hop traversed by the OGM, then the metric is substituted
+	 * with the value of the traversed link. Otherwise the metric is
+	 * computed as the minimum between the metric of the traversed link and
+	 * the value contained in the OGM
+	 */
+	link_metric = ewma_read(&neigh_node->bat_v.elp_neigh->metric);
+	if (ogm_metric == BATADV_MAX_METRIC)
+		new_metric = link_metric;
+	else
+		new_metric = min_t(uint32_t, link_metric, ogm_metric);
+	ogm2->metric = htonl(new_metric);
+
+	batadv_v_ogm_process_per_outif(bat_priv, ethhdr, ogm2, orig_node,
+				       neigh_node, if_incoming,
+				       BATADV_IF_DEFAULT);
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
+		if (hard_iface->if_status != BATADV_IF_ACTIVE)
+			continue;
+
+		if (hard_iface->soft_iface != bat_priv->soft_iface)
+			continue;
+
+		batadv_v_ogm_process_per_outif(bat_priv, ethhdr, ogm2,
+					       orig_node, neigh_node,
+					       if_incoming, hard_iface);
+	}
+	rcu_read_unlock();
+
+	ret = NET_RX_SUCCESS;
 	consume_skb(skb);
-	return NET_RX_SUCCESS;
+
+out:
+	if (orig_node)
+		batadv_orig_node_free_ref(orig_node);
+	if (orig_neigh)
+		batadv_orig_node_free_ref(orig_neigh);
+	if (neigh_node)
+		batadv_neigh_node_free_ref(neigh_node);
+
+	return ret;
 }
 
 int batadv_v_ogm_init(struct batadv_priv *bat_priv)
-- 
1.8.5.3


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

* [B.A.T.M.A.N.] [RFC 09/23] batman-adv: OGMv2 - purge obsolete potential routers
  2014-02-11 12:48 [B.A.T.M.A.N.] [RFC 00/23] Introducing a new routing protocol: B.A.T.M.A.N. V Antonio Quartulli
                   ` (7 preceding siblings ...)
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 08/23] batman-adv: OGMv2 - implement originators logic Antonio Quartulli
@ 2014-02-11 12:48 ` Antonio Quartulli
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 10/23] batman-adv: split name from variable for uint mesh attributes Antonio Quartulli
                   ` (13 subsequent siblings)
  22 siblings, 0 replies; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 12:48 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

If a neighbor is not forwarding OGMs since OGM_SEQ_RANGE
sequence numbers then it can be considered obsolete and
removed from the potential routers list. This may lead to a
route switch.

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 bat_v_ogm.c  | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 main.h       |  3 ++
 originator.c | 63 +++++++++++++++++++++++------------------
 originator.h |  2 ++
 types.h      |  2 ++
 5 files changed, 131 insertions(+), 31 deletions(-)

diff --git a/bat_v_ogm.c b/bat_v_ogm.c
index 4981d7c..5876164 100644
--- a/bat_v_ogm.c
+++ b/bat_v_ogm.c
@@ -79,8 +79,6 @@ batadv_v_ogm_neigh_new(struct batadv_priv *bat_priv,
 		return NULL;
 	}
 
-	neigh_node->bat_v.elp_neigh = elp_neigh;
-
 	spin_lock_bh(&orig_node->neigh_list_lock);
 	tmp_neigh_node = batadv_neigh_node_get(orig_node, hard_iface, addr);
 	if (!tmp_neigh_node) {
@@ -98,6 +96,8 @@ batadv_v_ogm_neigh_new(struct batadv_priv *bat_priv,
 			   "Creating new neighbor %pM for orig_node %pM on interface %s\n",
 			   addr, orig_node->orig, hard_iface->net_dev->name);
 
+	neigh_node->bat_v.elp_neigh = elp_neigh;
+
 	return neigh_node;
 }
 
@@ -235,6 +235,86 @@ void batadv_v_ogm_primary_iface_set(struct batadv_hard_iface *hard_iface)
 	rcu_read_unlock();
 }
 
+static bool batadv_ogm_deselect_router(struct batadv_priv *bat_priv,
+				       struct batadv_orig_node *orig_node,
+				       struct batadv_neigh_node *neigh)
+{
+	struct batadv_hard_iface *if_outgoing;
+	struct batadv_neigh_node *router;
+	bool removed = false;
+
+	router = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT);
+	if (router == neigh)
+		batadv_update_route(bat_priv, orig_node, BATADV_IF_DEFAULT,
+				    NULL);
+	if (router)
+		batadv_neigh_node_free_ref(router);
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(if_outgoing, &batadv_hardif_list, list) {
+		if (if_outgoing->if_status != BATADV_IF_ACTIVE)
+			continue;
+
+		if (if_outgoing->soft_iface != bat_priv->soft_iface)
+			continue;
+
+		router = batadv_orig_router_get(orig_node, if_outgoing);
+		/* if this is the current router, unset it */
+		if (router == neigh) {
+			batadv_update_route(bat_priv, orig_node, if_outgoing,
+					    NULL);
+			removed = true;
+		}
+		if (router)
+			batadv_neigh_node_free_ref(router);
+	}
+	rcu_read_unlock();
+
+	return removed;
+}
+
+/**
+ * batadv_v_ogm_purge_neighs - purge obsolete potential routers
+ * @bat_priv:
+ * @orig_node:
+ * @seqno:
+ *
+ * Purge routers from which this node did not receive at least
+ * BATADV_OGM_SEQ_RANGE OGMs
+ */
+static void batadv_v_ogm_purge_neighs(struct batadv_priv *bat_priv,
+				      struct batadv_orig_node *orig_node,
+				      uint32_t seqno)
+{
+	struct batadv_neigh_node *neigh;
+	struct hlist_node *node_tmp;
+	int32_t diff;
+
+	rcu_read_lock();
+	spin_lock_bh(&orig_node->neigh_list_lock);
+	hlist_for_each_entry_safe(neigh, node_tmp, &orig_node->neigh_list,
+				  list) {
+		diff = seqno - neigh->bat_v.last_recv_seqno;
+		if (diff < BATADV_OGM_SEQ_RANGE)
+			continue;
+
+		hlist_del_rcu(&neigh->list);
+		batadv_neigh_node_free_ref(neigh);
+	}
+	spin_unlock_bh(&orig_node->neigh_list_lock);
+
+	/* check if this neighbour is a router for any outgoing
+	 * interface and possibly deselect it
+	 */
+	if (batadv_ogm_deselect_router(bat_priv, orig_node, neigh))
+		goto out;
+
+	batadv_router_selection(bat_priv, orig_node);
+out:
+	rcu_read_unlock();
+	return;
+}
+
 static void
 batadv_v_ogm_orig_update(struct batadv_priv *bat_priv,
 			 struct batadv_orig_node *orig_node,
@@ -262,7 +342,7 @@ batadv_v_ogm_orig_update(struct batadv_priv *bat_priv,
 	batadv_orig_ifinfo_free_ref(orig_ifinfo);
 
 	/* if this neighbor already is our next hop there is nothing
-	 * to change
+	 * to change. The router may have been changed by the purge routine
 	 */
 	router = batadv_orig_router_get(orig_node, if_outgoing);
 	if (router == neigh_node)
@@ -547,6 +627,7 @@ int batadv_v_ogm_packet_recv(struct sk_buff *skb,
 
 	/* update the neigh_node information */
 	neigh_node->last_seen = jiffies;
+	neigh_node->bat_v.last_recv_seqno = ntohl(ogm2->seqno);
 
 	/* update the received metric to match the node topology: if this node
 	 * is the first hop traversed by the OGM, then the metric is substituted
@@ -579,6 +660,11 @@ int batadv_v_ogm_packet_recv(struct sk_buff *skb,
 	}
 	rcu_read_unlock();
 
+	/* purge potential neighs not forwarding OGMs anymore.
+	 * This may lead to a router change
+	 */
+	batadv_v_ogm_purge_neighs(bat_priv, orig_node, ntohl(ogm2->seqno));
+
 	ret = NET_RX_SUCCESS;
 	consume_skb(skb);
 
diff --git a/main.h b/main.h
index 4badd01..47fb9ed 100644
--- a/main.h
+++ b/main.h
@@ -62,6 +62,9 @@
 /* number of OGMs sent with the last tt diff */
 #define BATADV_TT_OGM_APPEND_MAX 3
 
+/* number of missing OGMs to wait before considering a router unusable */
+#define BATADV_OGM_SEQ_RANGE	5
+
 /* Time in which a client can roam at most ROAMING_MAX_COUNT times in
  * milliseconds
  */
diff --git a/originator.c b/originator.c
index 9f2da37..447f417 100644
--- a/originator.c
+++ b/originator.c
@@ -837,6 +837,40 @@ batadv_find_best_neighbor(struct batadv_priv *bat_priv,
 	return best;
 }
 
+void batadv_router_selection(struct batadv_priv *bat_priv,
+				    struct batadv_orig_node *orig_node)
+{
+	struct batadv_neigh_node *best_neigh_node;
+	struct batadv_hard_iface *hard_iface;
+
+	 /* First for the default routing table ... */
+	best_neigh_node = batadv_find_best_neighbor(bat_priv, orig_node,
+						    BATADV_IF_DEFAULT);
+	batadv_update_route(bat_priv, orig_node, BATADV_IF_DEFAULT,
+			    best_neigh_node);
+	if (best_neigh_node)
+		batadv_neigh_node_free_ref(best_neigh_node);
+
+	/* ... then for all other outgoing interfaces. */
+	rcu_read_lock();
+	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
+		if (hard_iface->if_status != BATADV_IF_ACTIVE)
+			continue;
+
+		if (hard_iface->soft_iface != bat_priv->soft_iface)
+			continue;
+
+		best_neigh_node = batadv_find_best_neighbor(bat_priv,
+							    orig_node,
+							    hard_iface);
+		batadv_update_route(bat_priv, orig_node, hard_iface,
+				    best_neigh_node);
+		if (best_neigh_node)
+			batadv_neigh_node_free_ref(best_neigh_node);
+	}
+	rcu_read_unlock();
+}
+
 /**
  * batadv_purge_orig_node - purges obsolete information from an orig_node
  * @bat_priv: the bat priv with all the soft interface information
@@ -850,8 +884,6 @@ batadv_find_best_neighbor(struct batadv_priv *bat_priv,
 static bool batadv_purge_orig_node(struct batadv_priv *bat_priv,
 				   struct batadv_orig_node *orig_node)
 {
-	struct batadv_neigh_node *best_neigh_node;
-	struct batadv_hard_iface *hard_iface;
 	bool changed;
 
 	if (batadv_has_timed_out(orig_node->last_seen,
@@ -868,32 +900,7 @@ static bool batadv_purge_orig_node(struct batadv_priv *bat_priv,
 	if (!changed)
 		return false;
 
-	/* first for NULL ... */
-	best_neigh_node = batadv_find_best_neighbor(bat_priv, orig_node,
-						    BATADV_IF_DEFAULT);
-	batadv_update_route(bat_priv, orig_node, BATADV_IF_DEFAULT,
-			    best_neigh_node);
-	if (best_neigh_node)
-		batadv_neigh_node_free_ref(best_neigh_node);
-
-	/* ... then for all other interfaces. */
-	rcu_read_lock();
-	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
-		if (hard_iface->if_status != BATADV_IF_ACTIVE)
-			continue;
-
-		if (hard_iface->soft_iface != bat_priv->soft_iface)
-			continue;
-
-		best_neigh_node = batadv_find_best_neighbor(bat_priv,
-							    orig_node,
-							    hard_iface);
-		batadv_update_route(bat_priv, orig_node, hard_iface,
-				    best_neigh_node);
-		if (best_neigh_node)
-			batadv_neigh_node_free_ref(best_neigh_node);
-	}
-	rcu_read_unlock();
+	batadv_router_selection(bat_priv, orig_node);
 
 	return false;
 }
diff --git a/originator.h b/originator.h
index db3a9ed..62e8e68 100644
--- a/originator.h
+++ b/originator.h
@@ -55,6 +55,8 @@ struct batadv_orig_ifinfo *
 batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node,
 		       struct batadv_hard_iface *if_outgoing);
 void batadv_orig_ifinfo_free_ref(struct batadv_orig_ifinfo *orig_ifinfo);
+void batadv_router_selection(struct batadv_priv *bat_priv,
+				    struct batadv_orig_node *orig_node);
 
 int batadv_orig_seq_print_text(struct seq_file *seq, void *offset);
 int batadv_orig_hardif_seq_print_text(struct seq_file *seq, void *offset);
diff --git a/types.h b/types.h
index e9149d1..28f2b85 100644
--- a/types.h
+++ b/types.h
@@ -358,9 +358,11 @@ struct batadv_elp_neigh_node {
 /**
  * batadv_neigh_node_bat_v - B.A.T.M.A.N. V private neighbor information
  * @elp_neigh: ELP private neighbour data
+ * @last_recv_seqno: last OGM seqno received through this neighbour
  */
 struct batadv_neigh_node_bat_v {
 	struct batadv_elp_neigh_node *elp_neigh;
+	uint32_t last_recv_seqno;
 };
 
 /**
-- 
1.8.5.3


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

* [B.A.T.M.A.N.] [RFC 10/23] batman-adv: split name from variable for uint mesh attributes
  2014-02-11 12:48 [B.A.T.M.A.N.] [RFC 00/23] Introducing a new routing protocol: B.A.T.M.A.N. V Antonio Quartulli
                   ` (8 preceding siblings ...)
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 09/23] batman-adv: OGMv2 - purge obsolete potential routers Antonio Quartulli
@ 2014-02-11 12:48 ` Antonio Quartulli
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 11/23] batman-adv: add throughput attribute to hard_ifaces Antonio Quartulli
                   ` (12 subsequent siblings)
  22 siblings, 0 replies; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 12:48 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

Some mesh attributes are behind substructs in the
batadv_priv object and for this reason the name cannot be
used anymore to refer to them.

This patch allows to specify the variable name where the
attribute is stored inside batadv_priv instead of using the
name

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 sysfs.c | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/sysfs.c b/sysfs.c
index 1d6653c..9139319 100644
--- a/sysfs.c
+++ b/sysfs.c
@@ -148,7 +148,7 @@ ssize_t batadv_show_##_name(struct kobject *kobj,			\
 			   batadv_store_##_name)
 
 
-#define BATADV_ATTR_SIF_STORE_UINT(_name, _min, _max, _post_func)	\
+#define BATADV_ATTR_SIF_STORE_UINT(_name, _var, _min, _max, _post_func)	\
 ssize_t batadv_store_##_name(struct kobject *kobj,			\
 			     struct attribute *attr, char *buff,	\
 			     size_t count)				\
@@ -157,23 +157,32 @@ ssize_t batadv_store_##_name(struct kobject *kobj,			\
 	struct batadv_priv *bat_priv = netdev_priv(net_dev);		\
 	return __batadv_store_uint_attr(buff, count, _min, _max,	\
 					_post_func, attr,		\
-					&bat_priv->_name, net_dev);	\
+					&bat_priv->_var, net_dev);	\
 }
 
-#define BATADV_ATTR_SIF_SHOW_UINT(_name)				\
+#define BATADV_ATTR_SIF_SHOW_UINT(_name, _var)				\
 ssize_t batadv_show_##_name(struct kobject *kobj,			\
 			    struct attribute *attr, char *buff)		\
 {									\
 	struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj);	\
-	return sprintf(buff, "%i\n", atomic_read(&bat_priv->_name));	\
+	return sprintf(buff, "%i\n", atomic_read(&bat_priv->_var));	\
 }									\
 
 /* Use this, if you are going to set [name] in the soft-interface
  * (bat_priv) to an unsigned integer value
  */
 #define BATADV_ATTR_SIF_UINT(_name, _mode, _min, _max, _post_func)	\
-	static BATADV_ATTR_SIF_STORE_UINT(_name, _min, _max, _post_func)\
-	static BATADV_ATTR_SIF_SHOW_UINT(_name)				\
+	static BATADV_ATTR_SIF_STORE_UINT(_name, _name, _min, _max, _post_func)\
+	static BATADV_ATTR_SIF_SHOW_UINT(_name, _name)			\
+	static BATADV_ATTR(_name, _mode, batadv_show_##_name,		\
+			   batadv_store_##_name)
+
+/* Same as BATADV_ATTR_SIF_UINT, but allow to specify the variable name as
+ * second parameter so that it does not need to match the attribute name
+ */
+#define BATADV_ATTR_SIF_UINT2(_name, _var, _mode, _min, _max, _post_func)\
+	static BATADV_ATTR_SIF_STORE_UINT(_name, _var, _min, _max, _post_func)\
+	static BATADV_ATTR_SIF_SHOW_UINT(_name, _var)			\
 	static BATADV_ATTR(_name, _mode, batadv_show_##_name,		\
 			   batadv_store_##_name)
 
-- 
1.8.5.3


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

* [B.A.T.M.A.N.] [RFC 11/23] batman-adv: add throughput attribute to hard_ifaces
  2014-02-11 12:48 [B.A.T.M.A.N.] [RFC 00/23] Introducing a new routing protocol: B.A.T.M.A.N. V Antonio Quartulli
                   ` (9 preceding siblings ...)
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 10/23] batman-adv: split name from variable for uint mesh attributes Antonio Quartulli
@ 2014-02-11 12:48 ` Antonio Quartulli
  2014-02-12  8:42   ` Andrew Lunn
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 12/23] batman-adv: add base throughput attribute Antonio Quartulli
                   ` (11 subsequent siblings)
  22 siblings, 1 reply; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 12:48 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

This attribute is exported to the user which can manually
select its value. It is the throughput value to be used
by default when batman-adv is trying to compute the link
throughput towards a neighbour using this interface.

If the value is set to 0 then batman-adv will try to detect
the throughput by itself.

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 bat_v.c | 3 +++
 sysfs.c | 3 +++
 types.h | 2 ++
 3 files changed, 8 insertions(+)

diff --git a/bat_v.c b/bat_v.c
index b4214c5..d5457b3 100644
--- a/bat_v.c
+++ b/bat_v.c
@@ -34,6 +34,9 @@ static int batadv_v_iface_enable(struct batadv_hard_iface *hard_iface)
 	if (ret < 0)
 		batadv_v_elp_iface_disable(hard_iface);
 
+	/* disable user customised throughput by default */
+	atomic_set(&hard_iface->bat_v.user_throughput, 0);
+
 	return ret;
 }
 
diff --git a/sysfs.c b/sysfs.c
index 9139319..8bbbdfa 100644
--- a/sysfs.c
+++ b/sysfs.c
@@ -889,6 +889,8 @@ static BATADV_ATTR(iface_status, S_IRUGO, batadv_show_iface_status, NULL);
 #ifdef CONFIG_BATMAN_ADV_BATMAN_V
 BATADV_ATTR_HIF_UINT(elp_interval, bat_v.elp_interval, S_IRUGO | S_IWUSR,
 		     2 * BATADV_JITTER, INT_MAX, NULL);
+BATADV_ATTR_HIF_UINT(throughput, bat_v.user_throughput, S_IRUGO | S_IWUSR,
+		     0, UINT_MAX, NULL);
 #endif
 
 static struct batadv_attribute *batadv_batman_attrs[] = {
@@ -896,6 +898,7 @@ static struct batadv_attribute *batadv_batman_attrs[] = {
 	&batadv_attr_iface_status,
 #ifdef CONFIG_BATMAN_ADV_BATMAN_V
 	&batadv_attr_elp_interval,
+	&batadv_attr_throughput,
 #endif
 	NULL,
 };
diff --git a/types.h b/types.h
index 28f2b85..64316b9 100644
--- a/types.h
+++ b/types.h
@@ -78,6 +78,7 @@ struct batadv_hard_iface_bat_iv {
  * @num_neighbours: number of neighbours in the neigh_list
  * @elp_skb: base skb containing the ELP message to send
  * @elp_wq: workqueue used to schedule ELP transmissions
+ * @user_throughput: user specified throughput
  */
 struct batadv_hard_iface_bat_v {
 	atomic_t elp_interval;
@@ -87,6 +88,7 @@ struct batadv_hard_iface_bat_v {
 	atomic_t num_neighbors;
 	struct sk_buff *elp_skb;
 	struct delayed_work elp_wq;
+	atomic_t user_throughput;
 };
 
 /**
-- 
1.8.5.3


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

* [B.A.T.M.A.N.] [RFC 12/23] batman-adv: add base throughput attribute
  2014-02-11 12:48 [B.A.T.M.A.N.] [RFC 00/23] Introducing a new routing protocol: B.A.T.M.A.N. V Antonio Quartulli
                   ` (10 preceding siblings ...)
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 11/23] batman-adv: add throughput attribute to hard_ifaces Antonio Quartulli
@ 2014-02-11 12:48 ` Antonio Quartulli
  2014-02-12  8:40   ` Andrew Lunn
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 13/23] batman-adv: add last_unicast_tx to struct neigh_node_elp Antonio Quartulli
                   ` (10 subsequent siblings)
  22 siblings, 1 reply; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 12:48 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

when batman-adv is asked to estimate/compute the throughput
of an interface, but it fails for whatever reason, then the
value in this attribute is used

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 bat_v.c | 3 +++
 main.h  | 7 +++++++
 sysfs.c | 7 +++++++
 types.h | 1 +
 4 files changed, 18 insertions(+)

diff --git a/bat_v.c b/bat_v.c
index d5457b3..3aa42ec 100644
--- a/bat_v.c
+++ b/bat_v.c
@@ -75,6 +75,9 @@ static struct batadv_algo_ops batadv_batman_v __read_mostly = {
 
 int batadv_v_mesh_init(struct batadv_priv *bat_priv)
 {
+	atomic_set(&bat_priv->bat_v.base_throughput,
+		   BATADV_DEFAULT_BASE_THROUGHPUT);
+
 	return batadv_v_ogm_init(bat_priv);
 }
 
diff --git a/main.h b/main.h
index 47fb9ed..5699c9f 100644
--- a/main.h
+++ b/main.h
@@ -33,6 +33,13 @@
 #define BATADV_MAX_METRIC 0xFFFFFFFF
 #define BATADV_JITTER 20
 
+/**
+ * BATADV_DEFAULT_BASE_THROUGHPUT - default value used as throughput for
+ * hard_ifaces for which it is not possible to measure/estimate the real one.
+ * Value is expressed in Mbps/10
+ */
+#define BATADV_DEFAULT_BASE_THROUGHPUT 10
+
 /* Time To Live of broadcast messages */
 #define BATADV_TTL 50
 
diff --git a/sysfs.c b/sysfs.c
index 8bbbdfa..a670eeb 100644
--- a/sysfs.c
+++ b/sysfs.c
@@ -606,6 +606,10 @@ BATADV_ATTR_SIF_BOOL(network_coding, S_IRUGO | S_IWUSR,
 #endif
 static BATADV_ATTR(isolation_mark, S_IRUGO | S_IWUSR,
 		   batadv_show_isolation_mark, batadv_store_isolation_mark);
+#ifdef CONFIG_BATMAN_ADV_BATMAN_V
+BATADV_ATTR_SIF_UINT2(base_throughput, bat_v.base_throughput, S_IRUGO | S_IWUSR,
+		      1, UINT_MAX, NULL);
+#endif
 
 static struct batadv_attribute *batadv_mesh_attrs[] = {
 	&batadv_attr_aggregated_ogms,
@@ -630,6 +634,9 @@ static struct batadv_attribute *batadv_mesh_attrs[] = {
 	&batadv_attr_network_coding,
 #endif
 	&batadv_attr_isolation_mark,
+#ifdef CONFIG_BATMAN_ADV_BATMAN_V
+	&batadv_attr_base_throughput,
+#endif
 	NULL,
 };
 
diff --git a/types.h b/types.h
index 64316b9..22d621e 100644
--- a/types.h
+++ b/types.h
@@ -741,6 +741,7 @@ struct batadv_priv_bat_v {
 	int ogm_buff_len;
 	struct delayed_work ogm_wq;
 	atomic_t ogm_seqno;
+	atomic_t base_throughput;
 };
 
 /**
-- 
1.8.5.3


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

* [B.A.T.M.A.N.] [RFC 13/23] batman-adv: add last_unicast_tx to struct neigh_node_elp
  2014-02-11 12:48 [B.A.T.M.A.N.] [RFC 00/23] Introducing a new routing protocol: B.A.T.M.A.N. V Antonio Quartulli
                   ` (11 preceding siblings ...)
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 12/23] batman-adv: add base throughput attribute Antonio Quartulli
@ 2014-02-11 12:48 ` Antonio Quartulli
  2014-02-12  8:49   ` Andrew Lunn
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 14/23] batman-adv: ELP - compute the metric based on the estimated throughput Antonio Quartulli
                   ` (9 subsequent siblings)
  22 siblings, 1 reply; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 12:48 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

This timestamp registers the last time a unicast packet was
sent to a given neighbour

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 bat_iv_ogm.c            |  2 +-
 bat_v_elp.c             |  2 +-
 bat_v_ogm.c             |  2 +-
 distributed-arp-table.c |  4 +---
 fragmentation.c         |  8 +++-----
 icmp_socket.c           |  2 +-
 network-coding.c        | 20 +++++++++-----------
 send.c                  | 46 +++++++++++++++++++++++++++++++++++++++-------
 send.h                  | 10 +++++++---
 types.h                 |  2 ++
 10 files changed, 65 insertions(+), 33 deletions(-)

diff --git a/bat_iv_ogm.c b/bat_iv_ogm.c
index f92253a..e2069c9 100644
--- a/bat_iv_ogm.c
+++ b/bat_iv_ogm.c
@@ -469,7 +469,7 @@ static void batadv_iv_ogm_send_to_if(struct batadv_forw_packet *forw_packet,
 		batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_TX);
 		batadv_add_counter(bat_priv, BATADV_CNT_MGMT_TX_BYTES,
 				   skb->len + ETH_HLEN);
-		batadv_send_skb_packet(skb, hard_iface, batadv_broadcast_addr);
+		batadv_send_broadcast_skb(skb, hard_iface);
 	}
 }
 
diff --git a/bat_v_elp.c b/bat_v_elp.c
index f9a6bfe..4185d8c 100644
--- a/bat_v_elp.c
+++ b/bat_v_elp.c
@@ -200,7 +200,7 @@ static void batadv_v_elp_send_outstanding(struct work_struct *work)
 		   hard_iface->net_dev->name,
 		   atomic_read(&hard_iface->bat_v.elp_seqno));
 
-	batadv_send_skb_packet(skb, hard_iface, batadv_broadcast_addr);
+	batadv_send_broadcast_skb(skb, hard_iface);
 
 	atomic_inc(&hard_iface->bat_v.elp_seqno);
 
diff --git a/bat_v_ogm.c b/bat_v_ogm.c
index 5876164..fa3d1a1 100644
--- a/bat_v_ogm.c
+++ b/bat_v_ogm.c
@@ -129,7 +129,7 @@ static void batadv_v_ogm_send_to_if(struct sk_buff *skb,
 	batadv_add_counter(bat_priv, BATADV_CNT_MGMT_TX_BYTES,
 			   skb->len + ETH_HLEN);
 
-	batadv_send_skb_packet(skb, hard_iface, batadv_broadcast_addr);
+	batadv_send_broadcast_skb(skb, hard_iface);
 }
 
 static void batadv_v_ogm_send(struct work_struct *work)
diff --git a/distributed-arp-table.c b/distributed-arp-table.c
index 78803b8..bc37033 100644
--- a/distributed-arp-table.c
+++ b/distributed-arp-table.c
@@ -602,9 +602,7 @@ static bool batadv_dat_send_data(struct batadv_priv *bat_priv,
 			goto free_neigh;
 		}
 
-		send_status = batadv_send_skb_packet(tmp_skb,
-						     neigh_node->if_incoming,
-						     neigh_node->addr);
+		send_status = batadv_send_unicast_skb(tmp_skb, neigh_node);
 		if (send_status == NET_XMIT_SUCCESS) {
 			/* count the sent packet */
 			switch (packet_subtype) {
diff --git a/fragmentation.c b/fragmentation.c
index bcc4bea..12811e0 100644
--- a/fragmentation.c
+++ b/fragmentation.c
@@ -354,8 +354,7 @@ bool batadv_frag_skb_fwd(struct sk_buff *skb,
 				   skb->len + ETH_HLEN);
 
 		packet->ttl--;
-		batadv_send_skb_packet(skb, neigh_node->if_incoming,
-				       neigh_node->addr);
+		batadv_send_unicast_skb(skb, neigh_node);
 		ret = true;
 	}
 
@@ -461,8 +460,7 @@ bool batadv_frag_send_packet(struct sk_buff *skb,
 		batadv_inc_counter(bat_priv, BATADV_CNT_FRAG_TX);
 		batadv_add_counter(bat_priv, BATADV_CNT_FRAG_TX_BYTES,
 				   skb_fragment->len + ETH_HLEN);
-		batadv_send_skb_packet(skb_fragment, neigh_node->if_incoming,
-				       neigh_node->addr);
+		batadv_send_unicast_skb(skb_fragment, neigh_node);
 		frag_header.no++;
 
 		/* The initial check in this function should cover this case */
@@ -481,7 +479,7 @@ bool batadv_frag_send_packet(struct sk_buff *skb,
 	batadv_inc_counter(bat_priv, BATADV_CNT_FRAG_TX);
 	batadv_add_counter(bat_priv, BATADV_CNT_FRAG_TX_BYTES,
 			   skb->len + ETH_HLEN);
-	batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
+	batadv_send_unicast_skb(skb, neigh_node);
 
 	return true;
 out_err:
diff --git a/icmp_socket.c b/icmp_socket.c
index bf07dfd..4734e02 100644
--- a/icmp_socket.c
+++ b/icmp_socket.c
@@ -253,7 +253,7 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff,
 
 	ether_addr_copy(icmp_header->orig, primary_if->net_dev->dev_addr);
 
-	batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
+	batadv_send_unicast_skb(skb, neigh_node);
 	goto out;
 
 dst_unreach:
diff --git a/network-coding.c b/network-coding.c
index a9546fe..bbb4ac0 100644
--- a/network-coding.c
+++ b/network-coding.c
@@ -535,9 +535,7 @@ batadv_nc_hash_find(struct batadv_hashtable *hash,
  */
 static void batadv_nc_send_packet(struct batadv_nc_packet *nc_packet)
 {
-	batadv_send_skb_packet(nc_packet->skb,
-			       nc_packet->neigh_node->if_incoming,
-			       nc_packet->nc_path->next_hop);
+	batadv_send_unicast_skb(nc_packet->skb, nc_packet->neigh_node);
 	nc_packet->skb = NULL;
 	batadv_nc_packet_free(nc_packet);
 }
@@ -1018,11 +1016,11 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv,
 	struct batadv_unicast_packet *packet1;
 	struct batadv_unicast_packet *packet2;
 	struct batadv_coded_packet *coded_packet;
-	struct batadv_neigh_node *neigh_tmp, *router_neigh;
-	struct batadv_neigh_node *router_coding = NULL;
+	struct batadv_neigh_node *neigh_tmp, *router_neigh, *first_dest;
+	struct batadv_neigh_node *router_coding = NULL, *second_dest;
 	struct batadv_neigh_ifinfo *router_neigh_ifinfo = NULL;
 	struct batadv_neigh_ifinfo *router_coding_ifinfo = NULL;
-	uint8_t *first_source, *first_dest, *second_source, *second_dest;
+	uint8_t *first_source, *second_source;
 	__be32 packet_id1, packet_id2;
 	size_t count;
 	bool res = false;
@@ -1065,9 +1063,9 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv,
 	 */
 	if (tq_weighted_neigh >= tq_weighted_coding) {
 		/* Destination from nc_packet is selected for MAC-header */
-		first_dest = nc_packet->nc_path->next_hop;
+		first_dest = nc_packet->neigh_node;
 		first_source = nc_packet->nc_path->prev_hop;
-		second_dest = neigh_node->addr;
+		second_dest = neigh_node;
 		second_source = ethhdr->h_source;
 		packet1 = (struct batadv_unicast_packet *)nc_packet->skb->data;
 		packet2 = (struct batadv_unicast_packet *)skb->data;
@@ -1076,9 +1074,9 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv,
 					      skb->data + sizeof(*packet2));
 	} else {
 		/* Destination for skb is selected for MAC-header */
-		first_dest = neigh_node->addr;
+		first_dest = neigh_node;
 		first_source = ethhdr->h_source;
-		second_dest = nc_packet->nc_path->next_hop;
+		second_dest = nc_packet->neigh_node;
 		second_source = nc_packet->nc_path->prev_hop;
 		packet1 = (struct batadv_unicast_packet *)skb->data;
 		packet2 = (struct batadv_unicast_packet *)nc_packet->skb->data;
@@ -1175,7 +1173,7 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv,
 	batadv_nc_packet_free(nc_packet);
 
 	/* Send the coded packet and return true */
-	batadv_send_skb_packet(skb_dest, neigh_node->if_incoming, first_dest);
+	batadv_send_unicast_skb(skb_dest, first_dest);
 	res = true;
 out:
 	if (router_neigh)
diff --git a/send.c b/send.c
index 63a46c3..734b24e 100644
--- a/send.c
+++ b/send.c
@@ -30,16 +30,30 @@
 
 static void batadv_send_outstanding_bcast_packet(struct work_struct *work);
 
-/* send out an already prepared packet to the given address via the
- * specified batman interface
+/**
+ * batadv_send_skb_packet - send an already prepared packet
+ * @skb: the packet to send
+ * @hard_iface: the interface to use to send the broadcast packet
+ * @neigh_node: the destination node. If not NULL packet is sent as unicast
+ *
+ * Send out an already prepared packet to the given neighbor or broadcast it
+ * using the specified interface. Either hard_iface or neigh_node must be not
+ * NULL.
+ * If neigh_node is NULL, then the packet is broadcasted using hard_iface,
+ * otherwise it is sent as unicast to the given neighbor.
+ *
+ * Return NET_TX_DROP in case of error or the result of dev_queue_xmit(skb)
+ * otherwise
  */
 int batadv_send_skb_packet(struct sk_buff *skb,
 			   struct batadv_hard_iface *hard_iface,
 			   const uint8_t *dst_addr)
 {
-	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
+	struct batadv_priv *bat_priv;
 	struct ethhdr *ethhdr;
 
+	bat_priv = netdev_priv(hard_iface->soft_iface);
+
 	if (hard_iface->if_status != BATADV_IF_ACTIVE)
 		goto send_skb_err;
 
@@ -81,6 +95,26 @@ send_skb_err:
 	return NET_XMIT_DROP;
 }
 
+int batadv_send_broadcast_skb(struct sk_buff *skb,
+			      struct batadv_hard_iface *hard_iface)
+{
+	return batadv_send_skb_packet(skb, hard_iface, batadv_broadcast_addr);
+}
+
+int batadv_send_unicast_skb(struct sk_buff *skb,
+			    struct batadv_neigh_node *neigh)
+{
+	int ret;
+
+	ret = batadv_send_skb_packet(skb, neigh->if_incoming, neigh->addr);
+#ifdef CONFIG_BATMAN_ADV_BATMAN_V
+	if (ret != NET_XMIT_DROP && neigh->elp_neigh)
+		neigh->elp_neigh->last_unicast_tx = jiffies;
+#endif
+
+	return ret;
+}
+
 /**
  * batadv_send_skb_to_orig - Lookup next-hop and transmit skb.
  * @skb: Packet to be transmitted.
@@ -127,8 +161,7 @@ int batadv_send_skb_to_orig(struct sk_buff *skb,
 	if (recv_if && batadv_nc_skb_forward(skb, neigh_node)) {
 		ret = NET_XMIT_POLICED;
 	} else {
-		batadv_send_skb_packet(skb, neigh_node->if_incoming,
-				       neigh_node->addr);
+		batadv_send_unicast_skb(skb, neigh_node);
 		ret = NET_XMIT_SUCCESS;
 	}
 
@@ -516,8 +549,7 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work)
 		/* send a copy of the saved skb */
 		skb1 = skb_clone(forw_packet->skb, GFP_ATOMIC);
 		if (skb1)
-			batadv_send_skb_packet(skb1, hard_iface,
-					       batadv_broadcast_addr);
+			batadv_send_broadcast_skb(skb1, hard_iface);
 	}
 	rcu_read_unlock();
 
diff --git a/send.h b/send.h
index 20e1668..f510dee 100644
--- a/send.h
+++ b/send.h
@@ -18,12 +18,16 @@
 #ifndef _NET_BATMAN_ADV_SEND_H_
 #define _NET_BATMAN_ADV_SEND_H_
 
-int batadv_send_skb_packet(struct sk_buff *skb,
-			   struct batadv_hard_iface *hard_iface,
-			   const uint8_t *dst_addr);
 int batadv_send_skb_to_orig(struct sk_buff *skb,
 			    struct batadv_orig_node *orig_node,
 			    struct batadv_hard_iface *recv_if);
+int batadv_send_skb_packet(struct sk_buff *skb,
+			   struct batadv_hard_iface *hard_iface,
+			   const uint8_t *dst_addr);
+int batadv_send_broadcast_skb(struct sk_buff *skb,
+			      struct batadv_hard_iface *hard_iface);
+int batadv_send_unicast_skb(struct sk_buff *skb,
+			    struct batadv_neigh_node *neigh_node);
 void batadv_schedule_bat_ogm(struct batadv_hard_iface *hard_iface);
 int batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv,
 				    const struct sk_buff *skb,
diff --git a/types.h b/types.h
index 22d621e..54fae29 100644
--- a/types.h
+++ b/types.h
@@ -342,6 +342,7 @@ struct batadv_gw_node {
  * @metric: ewma link metric towards this neighbor
  * @last_recv_seqno: last ELP received sequence number
  * @lest_seen: last time this neigh has been seen
+ * @last_unicast_tx: when the last unicast packet has been sent to this neighbor
  * @refcount: number of contexts the object is used
  * @rcu: struct used for freeing in an RCU-safe manner
  */
@@ -353,6 +354,7 @@ struct batadv_elp_neigh_node {
 	uint32_t last_recv_seqno;
 	unsigned long last_seen;
 	uint32_t elp_interval;
+	unsigned long last_unicast_tx;
 	atomic_t refcount;
 	struct rcu_head rcu;
 };
-- 
1.8.5.3


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

* [B.A.T.M.A.N.] [RFC 14/23] batman-adv: ELP - compute the metric based on the estimated throughput
  2014-02-11 12:48 [B.A.T.M.A.N.] [RFC 00/23] Introducing a new routing protocol: B.A.T.M.A.N. V Antonio Quartulli
                   ` (12 preceding siblings ...)
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 13/23] batman-adv: add last_unicast_tx to struct neigh_node_elp Antonio Quartulli
@ 2014-02-11 12:48 ` Antonio Quartulli
  2014-02-12  8:58   ` Andrew Lunn
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 15/23] batman-adv: ELP - send unicast ELP packets for throughput sampling Antonio Quartulli
                   ` (8 subsequent siblings)
  22 siblings, 1 reply; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 12:48 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

Implement a stub get_throughput() function which returns the
estimated throughput towards a given neighbour.
Its result is then used to compute the metric value.

The metric is updated each time a new ELP packet is sent,
this way it is possible to timely react to a metric
variation which can imply (for example) a neighbour
disconnection.

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 bat_v_elp.c | 49 +++++++++++++++++++++++++++++++++++++++++++------
 types.h     |  2 ++
 2 files changed, 45 insertions(+), 6 deletions(-)

diff --git a/bat_v_elp.c b/bat_v_elp.c
index 4185d8c..ef4e476 100644
--- a/bat_v_elp.c
+++ b/bat_v_elp.c
@@ -53,6 +53,29 @@ void batadv_elp_neigh_node_free_ref(struct batadv_elp_neigh_node *neigh)
 }
 
 /**
+ * batadv_v_elp_get_throughput - get the throughput towards a neighbour
+ * @neigh: the neighbour for which the throughput has to be obtained
+ *
+ * Returns the throughput towards the given neighbour.
+ */
+static uint32_t
+batadv_v_elp_get_throughput(struct batadv_elp_neigh_node *neigh)
+{
+	struct batadv_hard_iface *hard_iface = neigh->hard_iface;
+	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
+	uint32_t throughput;
+
+	/* get the customised user value for the throughput */
+	throughput = atomic_read(&hard_iface->bat_v.user_throughput);
+	/* if the user specified a value, let's return it */
+	if (throughput != 0)
+		return throughput;
+
+	/* throughput cannot be computed right now. Return base value */
+	return atomic_read(&bat_priv->bat_v.base_throughput);
+}
+
+/**
  * batadv_v_elp_neigh_new - create a new ELP neighbour node
  * @hard_iface: the interface the neighbour is connected to
  * @neigh_addr: the neighbour interface address
@@ -75,6 +98,7 @@ batadv_v_elp_neigh_new(struct batadv_hard_iface *hard_iface,
 	memcpy(neigh->addr, neigh_addr, ETH_ALEN);
 	neigh->last_seen = jiffies;
 	ewma_init(&neigh->metric, 1024, 8);
+	neigh->hard_iface = hard_iface;
 	/* recount initialised to 2 to simplify the caller function */
 	atomic_set(&neigh->refcount, 2);
 
@@ -147,19 +171,20 @@ static void batadv_v_elp_neigh_purge(struct batadv_hard_iface *hard_iface)
 }
 
 /**
- * batadv_v_elp_send_outstanding - ELP periodic broadcast sending
+ * batadv_v_elp_periodic_work - ELP periodic task per interface
  * @work: work queue item
  *
- * Sends a broadcast ELP message over the interface that this work item belongs
- * to.
+ * Sends a broadcast ELP message and reads the metric for all the neighbours
+ * connected to the interface that this work item belongs to.
  */
-static void batadv_v_elp_send_outstanding(struct work_struct *work)
+static void batadv_v_elp_periodic_work(struct work_struct *work)
 {
 	struct batadv_hard_iface *hard_iface;
 	struct batadv_hard_iface_bat_v *bat_v;
 	struct batadv_priv *bat_priv;
 	struct batadv_elp_packet *elp_packet;
 	uint32_t elp_interval;
+	struct batadv_elp_neigh_node *neigh;
 	struct sk_buff *skb;
 	uint8_t num_neighs;
 
@@ -181,7 +206,7 @@ static void batadv_v_elp_send_outstanding(struct work_struct *work)
 
 	skb = skb_copy(hard_iface->bat_v.elp_skb, GFP_ATOMIC);
 	if (!skb)
-		goto out;
+		goto update_metric;
 
 	/* purge outdated entries first */
 	batadv_v_elp_neigh_purge(hard_iface);
@@ -204,6 +229,17 @@ static void batadv_v_elp_send_outstanding(struct work_struct *work)
 
 	atomic_inc(&hard_iface->bat_v.elp_seqno);
 
+update_metric:
+	/* Instead of updating the metric each "received" ELP packet, it is
+	 * better to do it on each ELP sending. This way, if a node is dead and
+	 * does not send packets anymore, batman-adv is still able to timely
+	 * react to its death.
+	 */
+	rcu_read_lock();
+	hlist_for_each_entry_rcu(neigh, &hard_iface->bat_v.neigh_list, list)
+		ewma_add(&neigh->metric, batadv_v_elp_get_throughput(neigh));
+	rcu_read_unlock();
+
 restart_timer:
 	batadv_v_elp_start_timer(hard_iface);
 out:
@@ -247,7 +283,7 @@ int batadv_v_elp_iface_enable(struct batadv_hard_iface *hard_iface)
 	atomic_set(&hard_iface->bat_v.elp_interval, 500);
 
 	INIT_DELAYED_WORK(&hard_iface->bat_v.elp_wq,
-			  batadv_v_elp_send_outstanding);
+			  batadv_v_elp_periodic_work);
 	batadv_v_elp_start_timer(hard_iface);
 	res = 0;
 
@@ -332,6 +368,7 @@ static void batadv_v_elp_neigh_update(struct batadv_priv *bat_priv,
 
 	neigh->last_seen = jiffies;
 	neigh->last_recv_seqno = ntohl(elp_packet->seqno);
+	ewma_add(&neigh->metric, batadv_v_elp_get_throughput(neigh));
 
 out:
 	if (neigh)
diff --git a/types.h b/types.h
index 54fae29..948d5dc 100644
--- a/types.h
+++ b/types.h
@@ -345,6 +345,7 @@ struct batadv_gw_node {
  * @last_unicast_tx: when the last unicast packet has been sent to this neighbor
  * @refcount: number of contexts the object is used
  * @rcu: struct used for freeing in an RCU-safe manner
+ * @hard_iface: the interface where this neighbor is connected to
  */
 struct batadv_elp_neigh_node {
 	struct hlist_node list;
@@ -357,6 +358,7 @@ struct batadv_elp_neigh_node {
 	unsigned long last_unicast_tx;
 	atomic_t refcount;
 	struct rcu_head rcu;
+	struct batadv_hard_iface *hard_iface;
 };
 
 /**
-- 
1.8.5.3


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

* [B.A.T.M.A.N.] [RFC 15/23] batman-adv: ELP - send unicast ELP packets for throughput sampling
  2014-02-11 12:48 [B.A.T.M.A.N.] [RFC 00/23] Introducing a new routing protocol: B.A.T.M.A.N. V Antonio Quartulli
                   ` (13 preceding siblings ...)
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 14/23] batman-adv: ELP - compute the metric based on the estimated throughput Antonio Quartulli
@ 2014-02-11 12:48 ` Antonio Quartulli
  2014-02-12  9:12   ` Andrew Lunn
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 16/23] batman-adv: ELP - read estimated throughput from cfg80211 Antonio Quartulli
                   ` (7 subsequent siblings)
  22 siblings, 1 reply; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 12:48 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

In case of a unused link, the throughput estimation will
get stuck to the last sampled value and therefore the
reported metric will becomes obsolete.

Send unicast ELP packets to each neighbor to trigger throughput
sampling on unused links.

These packets will fill an entire frame so that the
measurement is as much reliable as possible

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 bat_v_elp.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 main.h      |  3 +++
 send.c      |  4 +--
 3 files changed, 85 insertions(+), 8 deletions(-)

diff --git a/bat_v_elp.c b/bat_v_elp.c
index ef4e476..14a1e15 100644
--- a/bat_v_elp.c
+++ b/bat_v_elp.c
@@ -25,6 +25,7 @@
 #include "bat_v_elp.h"
 #include "originator.h"
 #include "routing.h"
+#include "soft-interface.h"
 #include "translation-table.h"
 
 /**
@@ -171,6 +172,67 @@ static void batadv_v_elp_neigh_purge(struct batadv_hard_iface *hard_iface)
 }
 
 /**
+ * batadv_v_elp_wifi_neigh_probe - send link probing packets to a neighbour
+ * @hard_iface: the interface to use while sending the probing packets
+ * @neigh: the neighbour to probe
+ *
+ * Sends a predefined number of unicast wifi packets to a given neighbour in
+ * order to trigger the throughput estimation on this link by the RC algorithm.
+ * Packets are sent only if there there is not enough payload unicast traffic
+ * towards this neighbour..
+ *
+ * Returns 0 on success and -1 in case of error during skb preparation.
+ */
+static int batadv_v_elp_wifi_neigh_probe(struct batadv_hard_iface *hard_iface,
+					 struct batadv_elp_neigh_node *neigh)
+{
+	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
+	unsigned long last_tx_diff;
+	struct sk_buff *skb;
+	int probe_len, i;
+
+	/* this probing routine is for Wifi neighbours only */
+	if (batadv_is_wifi_netdev(hard_iface->net_dev))
+		return 0;
+
+	/* probe the neighbor only if no unicast packets have been sent
+	 * to it in the last 100 milliseconds: this is the rate control
+	 * algorithm sampling interval (minstrel). In this way, if not
+	 * enough traffic has been sent to the neighbor, batman-adv can
+	 * generate 2 probe packets and push the RC algorithm to perform
+	 * the sampling
+	 */
+	last_tx_diff = jiffies_to_msecs(jiffies - neigh->last_unicast_tx);
+	if (last_tx_diff <= BATADV_ELP_PROBE_MAX_TX_DIFF)
+		return 0;
+
+	probe_len = max_t(int, sizeof(struct batadv_elp_packet),
+			  BATADV_ELP_MIN_PROBE_SIZE);
+
+	for (i = 0; i < BATADV_ELP_PROBES_PER_NODE; i++) {
+		skb = skb_copy_expand(hard_iface->bat_v.elp_skb, 0,
+				      probe_len - hard_iface->bat_v.elp_skb->len,
+				      GFP_ATOMIC);
+		if (!skb)
+			return -1;
+
+		/* Tell the skb to get as bigger as the allocated space (we want
+		 * the packet to be exactly of that size to make the link
+		 * throughput estimation effective.
+		 */
+		skb_put(skb, probe_len - hard_iface->bat_v.elp_skb->len);
+
+		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+			   "Sending unicast (probe) ELP packet on interface %s to %pM\n",
+			   hard_iface->net_dev->name, neigh->addr);
+
+		batadv_send_skb_packet(skb, hard_iface, neigh->addr);
+	}
+
+	return 0;
+}
+
+/**
  * batadv_v_elp_periodic_work - ELP periodic task per interface
  * @work: work queue item
  *
@@ -181,11 +243,11 @@ static void batadv_v_elp_periodic_work(struct work_struct *work)
 {
 	struct batadv_hard_iface *hard_iface;
 	struct batadv_hard_iface_bat_v *bat_v;
-	struct batadv_priv *bat_priv;
 	struct batadv_elp_packet *elp_packet;
-	uint32_t elp_interval;
 	struct batadv_elp_neigh_node *neigh;
+	struct batadv_priv *bat_priv;
 	struct sk_buff *skb;
+	uint32_t elp_interval;
 	uint8_t num_neighs;
 
 	bat_v = container_of(work, struct batadv_hard_iface_bat_v, elp_wq.work);
@@ -206,7 +268,7 @@ static void batadv_v_elp_periodic_work(struct work_struct *work)
 
 	skb = skb_copy(hard_iface->bat_v.elp_skb, GFP_ATOMIC);
 	if (!skb)
-		goto update_metric;
+		goto restart_timer;
 
 	/* purge outdated entries first */
 	batadv_v_elp_neigh_purge(hard_iface);
@@ -221,7 +283,7 @@ static void batadv_v_elp_periodic_work(struct work_struct *work)
 	elp_packet->elp_interval = htonl(elp_interval);
 
 	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
-		   "Sending ELP packet on interface %s, seqno %u\n",
+		   "Sending broadcast ELP packet on interface %s, seqno %u\n",
 		   hard_iface->net_dev->name,
 		   atomic_read(&hard_iface->bat_v.elp_seqno));
 
@@ -229,15 +291,27 @@ static void batadv_v_elp_periodic_work(struct work_struct *work)
 
 	atomic_inc(&hard_iface->bat_v.elp_seqno);
 
-update_metric:
 	/* Instead of updating the metric each "received" ELP packet, it is
 	 * better to do it on each ELP sending. This way, if a node is dead and
 	 * does not send packets anymore, batman-adv is still able to timely
 	 * react to its death.
+	 *
+	 * The metric is updated by following these steps:
+	 * 1) if the hard_iface if wifi => send a unicast ELP for
+	 * probing/sampling to each neighbor
+	 * 2) update the metric value of each neighbor
+	 *
 	 */
 	rcu_read_lock();
-	hlist_for_each_entry_rcu(neigh, &hard_iface->bat_v.neigh_list, list)
+	hlist_for_each_entry_rcu(neigh, &hard_iface->bat_v.neigh_list, list) {
+		if (batadv_v_elp_wifi_neigh_probe(hard_iface, neigh) < 0)
+			/* if something goes wrong while probing, better to stop
+			 * sending packets immediately and reschedule the task
+			 */
+			break;
+
 		ewma_add(&neigh->metric, batadv_v_elp_get_throughput(neigh));
+	}
 	rcu_read_unlock();
 
 restart_timer:
diff --git a/main.h b/main.h
index 5699c9f..9cfdbb3 100644
--- a/main.h
+++ b/main.h
@@ -54,6 +54,9 @@
 #define BATADV_ORIG_WORK_PERIOD 1000 /* 1 second */
 #define BATADV_DAT_ENTRY_TIMEOUT (5*60000) /* 5 mins in milliseconds */
 #define BATADV_ELP_OUTDATED_MAX 4
+#define BATADV_ELP_PROBES_PER_NODE 2
+#define BATADV_ELP_MIN_PROBE_SIZE 200 /* bytes */
+#define BATADV_ELP_PROBE_MAX_TX_DIFF 100 /* milliseconds */
 /* sliding packet range of received originator messages in sequence numbers
  * (should be a multiple of our word size)
  */
diff --git a/send.c b/send.c
index 734b24e..20b60d7 100644
--- a/send.c
+++ b/send.c
@@ -108,8 +108,8 @@ int batadv_send_unicast_skb(struct sk_buff *skb,
 
 	ret = batadv_send_skb_packet(skb, neigh->if_incoming, neigh->addr);
 #ifdef CONFIG_BATMAN_ADV_BATMAN_V
-	if (ret != NET_XMIT_DROP && neigh->elp_neigh)
-		neigh->elp_neigh->last_unicast_tx = jiffies;
+	if (ret != NET_XMIT_DROP && neigh->bat_v.elp_neigh)
+		neigh->bat_v.elp_neigh->last_unicast_tx = jiffies;
 #endif
 
 	return ret;
-- 
1.8.5.3


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

* [B.A.T.M.A.N.] [RFC 16/23] batman-adv: ELP - read estimated throughput from cfg80211
  2014-02-11 12:48 [B.A.T.M.A.N.] [RFC 00/23] Introducing a new routing protocol: B.A.T.M.A.N. V Antonio Quartulli
                   ` (14 preceding siblings ...)
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 15/23] batman-adv: ELP - send unicast ELP packets for throughput sampling Antonio Quartulli
@ 2014-02-11 12:48 ` Antonio Quartulli
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 17/23] batman-adv: ELP - implement dead neigh node detection Antonio Quartulli
                   ` (6 subsequent siblings)
  22 siblings, 0 replies; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 12:48 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

In case of wireless interface retrieve the throughput by
querying cfg80211. To perform this call a separate work
must be scheduled because the function may sleep and this
is not allowed within an RCU protected context (RCU in this
case is used to iterate over all the neighbours).

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 bat_v_elp.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 compat.h    | 20 ++++++++++++++++++++
 types.h     |  2 ++
 3 files changed, 76 insertions(+), 7 deletions(-)

diff --git a/bat_v_elp.c b/bat_v_elp.c
index 14a1e15..31190af 100644
--- a/bat_v_elp.c
+++ b/bat_v_elp.c
@@ -18,6 +18,8 @@
  *
  */
 
+#include <net/cfg80211.h>
+
 #include "main.h"
 #include "hard-interface.h"
 #include "send.h"
@@ -64,19 +66,56 @@ batadv_v_elp_get_throughput(struct batadv_elp_neigh_node *neigh)
 {
 	struct batadv_hard_iface *hard_iface = neigh->hard_iface;
 	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
+	struct station_info sinfo;
 	uint32_t throughput;
+	int r;
 
-	/* get the customised user value for the throughput */
-	throughput = atomic_read(&hard_iface->bat_v.user_throughput);
-	/* if the user specified a value, let's return it */
+	/* if the user specified a customised value for this interface, then
+	 * return it directly
+	 */
+	throughput =  atomic_read(&hard_iface->bat_v.user_throughput);
 	if (throughput != 0)
 		return throughput;
 
-	/* throughput cannot be computed right now. Return base value */
+	/* if this is a wireless device, then ask its throughput through
+	 * cfg80211 API
+	 */
+	if (hard_iface->net_dev->ieee80211_ptr) {
+		r = cfg80211_get_station(hard_iface->net_dev, neigh->addr,
+					 &sinfo);
+		if (r == -ENOENT) {
+			/* node is not associated anymore! it would be possible
+			 * to delete this neighbor. for now set metric to 0
+			 */
+			return 0;
+		}
+		if (!r)
+			return sinfo.expected_throughput;
+	}
+
+	/* if none of the above cases apply, return the base_throughput */
 	return atomic_read(&bat_priv->bat_v.base_throughput);
 }
 
 /**
+ * batadv_v_elp_metric_update - worker updating the metric of one neighbour
+ * @work: the work queue item
+ */
+static void batadv_v_elp_metric_update(struct work_struct *work)
+{
+	struct batadv_elp_neigh_node *neigh;
+
+	neigh = container_of(work, struct batadv_elp_neigh_node, metric_work);
+
+	ewma_add(&neigh->metric, batadv_v_elp_get_throughput(neigh));
+
+	/* decrement refcounter to balance increment performed before scheduling
+	 * this task
+	 */
+	batadv_elp_neigh_node_free_ref(neigh);
+}
+
+/**
  * batadv_v_elp_neigh_new - create a new ELP neighbour node
  * @hard_iface: the interface the neighbour is connected to
  * @neigh_addr: the neighbour interface address
@@ -108,6 +147,8 @@ batadv_v_elp_neigh_new(struct batadv_hard_iface *hard_iface,
 	spin_unlock_bh(&hard_iface->bat_v.neigh_list_lock);
 	atomic_inc(&hard_iface->bat_v.num_neighbors);
 
+	INIT_WORK(&neigh->metric_work, batadv_v_elp_metric_update);
+
 	return neigh;
 }
 
@@ -192,7 +233,7 @@ static int batadv_v_elp_wifi_neigh_probe(struct batadv_hard_iface *hard_iface,
 	int probe_len, i;
 
 	/* this probing routine is for Wifi neighbours only */
-	if (batadv_is_wifi_netdev(hard_iface->net_dev))
+	if (!batadv_is_wifi_netdev(hard_iface->net_dev))
 		return 0;
 
 	/* probe the neighbor only if no unicast packets have been sent
@@ -310,7 +351,14 @@ static void batadv_v_elp_periodic_work(struct work_struct *work)
 			 */
 			break;
 
-		ewma_add(&neigh->metric, batadv_v_elp_get_throughput(neigh));
+		if (!atomic_inc_not_zero(&neigh->refcount))
+			continue;
+
+		/* reading the estimated throughput from cfg80211 is a task that
+		 * may sleep and that is not allowed in an rcu protected
+		 * context. Therefore schedule a task for that.
+		 */
+		queue_work(batadv_event_workqueue, &neigh->metric_work);
 	}
 	rcu_read_unlock();
 
@@ -442,7 +490,6 @@ static void batadv_v_elp_neigh_update(struct batadv_priv *bat_priv,
 
 	neigh->last_seen = jiffies;
 	neigh->last_recv_seqno = ntohl(elp_packet->seqno);
-	ewma_add(&neigh->metric, batadv_v_elp_get_throughput(neigh));
 
 out:
 	if (neigh)
diff --git a/compat.h b/compat.h
index 12bc8d8..9f71f51 100644
--- a/compat.h
+++ b/compat.h
@@ -407,4 +407,24 @@ static int __batadv_interface_kill_vid(struct net_device *dev, __be16 proto,\
 
 #endif /* < KERNEL_VERSION(3, 14, 0) */
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0)
+
+/* NOTE: shall I put this ifndef outside of every #if block ? */
+#ifndef cfg80211_get_station
+
+/* the expected behaviour of this function is to return 0 on success, therefore
+ * it is possible to define it as 1 so that batman-adv thinks like something
+ * went wrong. It will then decide what to do.
+ */
+#define cfg80211_get_station(_a, _b, _c) (1)
+/* the following define substitute the expected_throughput field with a random
+ * one existing in the station_info struct. It can be random because due to the
+ * define above it will never be used. We need it only to make the code compile
+ */
+#define expected_throughput filled
+
+#endif /* cfg80211_get_station */
+
+#endif /* < KERNEL_VERSION(3, 15, 0) */
+
 #endif /* _NET_BATMAN_ADV_COMPAT_H_ */
diff --git a/types.h b/types.h
index 948d5dc..6f05d99 100644
--- a/types.h
+++ b/types.h
@@ -346,6 +346,7 @@ struct batadv_gw_node {
  * @refcount: number of contexts the object is used
  * @rcu: struct used for freeing in an RCU-safe manner
  * @hard_iface: the interface where this neighbor is connected to
+ * @metric_work: work queue callback item for metric update
  */
 struct batadv_elp_neigh_node {
 	struct hlist_node list;
@@ -359,6 +360,7 @@ struct batadv_elp_neigh_node {
 	atomic_t refcount;
 	struct rcu_head rcu;
 	struct batadv_hard_iface *hard_iface;
+	struct work_struct metric_work;
 };
 
 /**
-- 
1.8.5.3


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

* [B.A.T.M.A.N.] [RFC 17/23] batman-adv: ELP - implement dead neigh node detection
  2014-02-11 12:48 [B.A.T.M.A.N.] [RFC 00/23] Introducing a new routing protocol: B.A.T.M.A.N. V Antonio Quartulli
                   ` (15 preceding siblings ...)
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 16/23] batman-adv: ELP - read estimated throughput from cfg80211 Antonio Quartulli
@ 2014-02-11 12:48 ` Antonio Quartulli
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 18/23] batman-adv: ELP - use phydev to determine link characteristics Antonio Quartulli
                   ` (5 subsequent siblings)
  22 siblings, 0 replies; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 12:48 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

Improve the neighbour purging routine to timely detect when
a neighbour is not sending data anymore without waiting for
a real timeout. This detection system can be used by the
B.A.T.M.A.N. V routing algorithm to trigger an on-demand
route reconstruction.

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 bat_v.c     |  7 +++++
 bat_v_elp.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 bat_v_elp.h |  2 ++
 types.h     |  2 ++
 4 files changed, 98 insertions(+), 4 deletions(-)

diff --git a/bat_v.c b/bat_v.c
index 3aa42ec..5681d19 100644
--- a/bat_v.c
+++ b/bat_v.c
@@ -75,14 +75,21 @@ static struct batadv_algo_ops batadv_batman_v __read_mostly = {
 
 int batadv_v_mesh_init(struct batadv_priv *bat_priv)
 {
+	int r;
+
 	atomic_set(&bat_priv->bat_v.base_throughput,
 		   BATADV_DEFAULT_BASE_THROUGHPUT);
 
+	r = batadv_v_elp_init(bat_priv);
+	if (r)
+		return r;
+
 	return batadv_v_ogm_init(bat_priv);
 }
 
 void batadv_v_mesh_free(struct batadv_priv *bat_priv)
 {
+	batadv_v_elp_free(bat_priv);
 	batadv_v_ogm_free(bat_priv);
 }
 
diff --git a/bat_v_elp.c b/bat_v_elp.c
index 31190af..763113e 100644
--- a/bat_v_elp.c
+++ b/bat_v_elp.c
@@ -25,6 +25,7 @@
 #include "send.h"
 #include "bat_algo.h"
 #include "bat_v_elp.h"
+#include "bat_v_ogm.h"
 #include "originator.h"
 #include "routing.h"
 #include "soft-interface.h"
@@ -186,30 +187,55 @@ batadv_v_elp_neigh_get(struct batadv_hard_iface *hard_iface,
  * batadv_v_elp_neigh_purge - purge obsolete neighbour nodes
  *
  * Deletes the ELP neighbour nodes that did not send any ELP message for a
- * pre-defined amount of time.
+ * pre-defined amount of time and returns the minimum ELP interval among all the
+ * remaining neighbours.
  */
-static void batadv_v_elp_neigh_purge(struct batadv_hard_iface *hard_iface)
+static uint32_t batadv_v_elp_neigh_purge(struct batadv_hard_iface *hard_iface)
 {
+	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
 	unsigned long timeout;
 	struct batadv_elp_neigh_node *neigh;
 	struct hlist_node *node;
 	bool has_timed_out;
+	uint32_t tmp_interval, min_interval = UINT_MAX;
 
 	spin_lock_bh(&hard_iface->bat_v.neigh_list_lock);
 	hlist_for_each_entry_safe(neigh, node, &hard_iface->bat_v.neigh_list,
 				  list) {
-		timeout = neigh->elp_interval * BATADV_ELP_OUTDATED_MAX;
+		tmp_interval = neigh->elp_interval;
+
+		timeout = tmp_interval * BATADV_ELP_OUTDATED_MAX;
 		has_timed_out = batadv_has_timed_out(neigh->last_seen, timeout);
+		if (has_timed_out) {
+			/* this neigh is dead! the node could react somehow.
+			 * TODO: implement dead node reaction mechanism
+			 */
+			batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+				   "Node %pM is dead.\n", neigh->addr);
 
+			/* this node is not sending ELP packets anymore. Don't
+			 * consider it in the minimum ELP interval research
+			 */
+			tmp_interval = UINT_MAX;
+		}
+
+		has_timed_out = batadv_has_timed_out(neigh->last_seen,
+						     BATADV_PURGE_TIMEOUT);
 		if ((!has_timed_out) &&
-		    (hard_iface->if_status == BATADV_IF_ACTIVE))
+		    (hard_iface->if_status == BATADV_IF_ACTIVE)) {
+			if (tmp_interval < min_interval)
+				min_interval = tmp_interval;
 			continue;
+		}
 
 		hlist_del_rcu(&neigh->list);
 		atomic_dec(&hard_iface->bat_v.num_neighbors);
 		batadv_elp_neigh_node_free_ref(neigh);
+
 	}
 	spin_unlock_bh(&hard_iface->bat_v.neigh_list_lock);
+
+	return min_interval;
 }
 
 /**
@@ -479,6 +505,7 @@ static void batadv_v_elp_neigh_update(struct batadv_priv *bat_priv,
 
 {
 	struct batadv_elp_neigh_node *neigh;
+	uint32_t interval;
 
 	neigh = batadv_v_elp_neigh_get(if_incoming, neigh_addr);
 	if (!neigh) {
@@ -490,6 +517,16 @@ static void batadv_v_elp_neigh_update(struct batadv_priv *bat_priv,
 
 	neigh->last_seen = jiffies;
 	neigh->last_recv_seqno = ntohl(elp_packet->seqno);
+	neigh->elp_interval = ntohl(elp_packet->elp_interval);
+
+	interval = atomic_read(&bat_priv->bat_v.neigh_interval);
+	if (neigh->elp_interval >= interval)
+		goto out;
+
+	/* got a shorter elp interval: reschedule the neigh check */
+	atomic_set(&bat_priv->bat_v.neigh_interval, neigh->elp_interval);
+	queue_delayed_work(batadv_event_workqueue, &bat_priv->bat_v.neigh_wq,
+			   msecs_to_jiffies(neigh->elp_interval));
 
 out:
 	if (neigh)
@@ -625,3 +662,49 @@ out:
 		batadv_hardif_free_ref(primary_if);
 	return 0;
 }
+
+static void batadv_v_elp_check_neigh(struct work_struct *work)
+{
+	struct batadv_priv_bat_v *bat_v;
+	struct batadv_priv *bat_priv;
+	struct batadv_hard_iface *hard_iface;
+	uint32_t tmp_interval, min_interval = UINT_MAX;
+
+	bat_v = container_of(work, struct batadv_priv_bat_v, neigh_wq.work);
+	bat_priv = container_of(bat_v, struct batadv_priv, bat_v);
+
+	list_for_each_entry(hard_iface, &batadv_hardif_list, list) {
+		if (hard_iface->soft_iface != bat_priv->soft_iface)
+			continue;
+
+		tmp_interval = batadv_v_elp_neigh_purge(hard_iface);
+		/* while iterating over all the ELP neighbors, find the smallest
+		 * ELP interval to use to schedule the next check
+		 */
+		if (tmp_interval < min_interval)
+			min_interval = tmp_interval;
+	}
+
+	/* if there are no more ELP neighbors the work does not need to be
+	 * rescheduled
+	 */
+	if (min_interval == UINT_MAX)
+		return;
+
+	atomic_set(&bat_priv->bat_v.neigh_interval, min_interval);
+	queue_delayed_work(batadv_event_workqueue, &bat_priv->bat_v.neigh_wq,
+			   msecs_to_jiffies(min_interval));
+}
+
+int batadv_v_elp_init(struct batadv_priv *bat_priv)
+{
+	INIT_DELAYED_WORK(&bat_priv->bat_v.neigh_wq, batadv_v_elp_check_neigh);
+	atomic_set(&bat_priv->bat_v.neigh_interval, UINT_MAX);
+
+	return 0;
+}
+
+void batadv_v_elp_free(struct batadv_priv *bat_priv)
+{
+	cancel_delayed_work_sync(&bat_priv->bat_v.neigh_wq);
+}
diff --git a/bat_v_elp.h b/bat_v_elp.h
index 4f34ecb..5dd0568 100644
--- a/bat_v_elp.h
+++ b/bat_v_elp.h
@@ -33,5 +33,7 @@ void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *hard_iface);
 int batadv_v_elp_packet_recv(struct sk_buff *skb,
 			     struct batadv_hard_iface *if_incoming);
 int batadv_v_elp_seq_print_text(struct seq_file *seq, void *offset);
+int batadv_v_elp_init(struct batadv_priv *bat_priv);
+void batadv_v_elp_free(struct batadv_priv *bat_priv);
 
 #endif /* _NET_BATMAN_ADV_BAT_V_ELP_H_ */
diff --git a/types.h b/types.h
index 6f05d99..2ba27ab 100644
--- a/types.h
+++ b/types.h
@@ -748,6 +748,8 @@ struct batadv_priv_bat_v {
 	struct delayed_work ogm_wq;
 	atomic_t ogm_seqno;
 	atomic_t base_throughput;
+	atomic_t neigh_interval;
+	struct delayed_work neigh_wq;
 };
 
 /**
-- 
1.8.5.3


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

* [B.A.T.M.A.N.] [RFC 18/23] batman-adv: ELP - use phydev to determine link characteristics
  2014-02-11 12:48 [B.A.T.M.A.N.] [RFC 00/23] Introducing a new routing protocol: B.A.T.M.A.N. V Antonio Quartulli
                   ` (16 preceding siblings ...)
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 17/23] batman-adv: ELP - implement dead neigh node detection Antonio Quartulli
@ 2014-02-11 12:48 ` Antonio Quartulli
  2014-02-13  8:17   ` Antonio Quartulli
  2014-02-13 10:52   ` Andrew Lunn
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 19/23] batman-adv: add bat_neigh_free() API Antonio Quartulli
                   ` (4 subsequent siblings)
  22 siblings, 2 replies; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 12:48 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

The phydev member of a net_device can be used to get
information about an ethernet link like HALF/FULL_DUPLEX
and advertised bandwidth (e.g. 100/10Mbps).

This information are then stored in the hard_iface object
to be used during the metric computation routine.

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 bat_v_elp.c      |  8 ++++++++
 bat_v_ogm.c      |  4 ++--
 hard-interface.c | 19 +++++++++++++++++++
 types.h          | 12 ++++++++++++
 4 files changed, 41 insertions(+), 2 deletions(-)

diff --git a/bat_v_elp.c b/bat_v_elp.c
index 763113e..958843c 100644
--- a/bat_v_elp.c
+++ b/bat_v_elp.c
@@ -78,6 +78,14 @@ batadv_v_elp_get_throughput(struct batadv_elp_neigh_node *neigh)
 	if (throughput != 0)
 		return throughput;
 
+	/* In case of Ethernet interface, the throughput has already been
+	 * obtained from the phydev object in the net_device struct (see
+	 * batadv_hardif_activate_interface()). So return this value.
+	 */
+	throughput = hard_iface->bat_v.eth_throughput;
+	if (throughput != 0)
+		return throughput;
+
 	/* if this is a wireless device, then ask its throughput through
 	 * cfg80211 API
 	 */
diff --git a/bat_v_ogm.c b/bat_v_ogm.c
index fa3d1a1..060ce80 100644
--- a/bat_v_ogm.c
+++ b/bat_v_ogm.c
@@ -393,8 +393,8 @@ static uint32_t batadv_v_penalty(struct batadv_priv *bat_priv,
 	/* proportion to use the same value used in batman iv (x * 128 / 256) */
 	hop_penalty = hop_penalty * 100 / 255;
 
-	if (batadv_is_wifi_netdev(if_incoming->net_dev) &&
-	    metric > link_metric / 10)
+	if ((if_incoming->bat_v.flags & BATADV_FULL_DUPLEX) &&
+	    (metric > link_metric / 10))
 		return metric / 2;
 
 	return metric * (100 - hop_penalty) / 100;
diff --git a/hard-interface.c b/hard-interface.c
index 2a04130..58c8669 100644
--- a/hard-interface.c
+++ b/hard-interface.c
@@ -31,6 +31,8 @@
 
 #include <linux/if_arp.h>
 #include <linux/if_ether.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
 
 void batadv_hardif_free_rcu(struct rcu_head *rcu)
 {
@@ -297,6 +299,7 @@ void batadv_update_min_mtu(struct net_device *soft_iface)
 static void
 batadv_hardif_activate_interface(struct batadv_hard_iface *hard_iface)
 {
+	struct net_device *dev = hard_iface->net_dev;
 	struct batadv_priv *bat_priv;
 	struct batadv_hard_iface *primary_if = NULL;
 
@@ -315,6 +318,22 @@ batadv_hardif_activate_interface(struct batadv_hard_iface *hard_iface)
 	if (!primary_if)
 		batadv_primary_if_select(bat_priv, hard_iface);
 
+	/* set the default values */
+	hard_iface->bat_v.flags &= ~BATADV_FULL_DUPLEX;
+	hard_iface->bat_v.eth_throughput = 0;
+	if (dev->phydev) {
+		if (dev->phydev->duplex == DUPLEX_FULL)
+			hard_iface->bat_v.flags |= BATADV_FULL_DUPLEX;
+
+		/* set the speed according to the phydev setting. Store the
+		 * value in Kbps (as done for the other throughput variables)
+		 */
+		if (dev->phydev->speed != SPEED_UNKNOWN) {
+			hard_iface->bat_v.eth_throughput = dev->phydev->speed;
+			hard_iface->bat_v.eth_throughput *= 10;
+		}
+	}
+
 	batadv_info(hard_iface->soft_iface, "Interface activated: %s\n",
 		    hard_iface->net_dev->name);
 
diff --git a/types.h b/types.h
index 2ba27ab..a51921e 100644
--- a/types.h
+++ b/types.h
@@ -70,6 +70,14 @@ struct batadv_hard_iface_bat_iv {
 };
 
 /**
+ * enum batadv_v_hard_iface_flags - interface flags useful to B.A.T.M.A.N. V
+ * @BATADV_FULL_DUPLEX: tells if the connection over this link is full-duplex
+ */
+enum batadv_v_hard_iface_flags {
+	BATADV_FULL_DUPLEX	= BIT(0),
+};
+
+/**
  * struct batadv_hard_iface_bat_v - per hard interface B.A.T.M.A.N. V data
  * @elp_interval: time interval between two ELP transmissions
  * @elp_seqno: current ELP sequence number
@@ -79,6 +87,8 @@ struct batadv_hard_iface_bat_iv {
  * @elp_skb: base skb containing the ELP message to send
  * @elp_wq: workqueue used to schedule ELP transmissions
  * @user_throughput: user specified throughput
+ * @eth_throughput: throughput for wired interfaces (obtained from phydev)
+ * @flags: interface specific flags
  */
 struct batadv_hard_iface_bat_v {
 	atomic_t elp_interval;
@@ -89,6 +99,8 @@ struct batadv_hard_iface_bat_v {
 	struct sk_buff *elp_skb;
 	struct delayed_work elp_wq;
 	atomic_t user_throughput;
+	uint32_t eth_throughput;
+	uint8_t flags;
 };
 
 /**
-- 
1.8.5.3


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

* [B.A.T.M.A.N.] [RFC 19/23] batman-adv: add bat_neigh_free() API
  2014-02-11 12:48 [B.A.T.M.A.N.] [RFC 00/23] Introducing a new routing protocol: B.A.T.M.A.N. V Antonio Quartulli
                   ` (17 preceding siblings ...)
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 18/23] batman-adv: ELP - use phydev to determine link characteristics Antonio Quartulli
@ 2014-02-11 12:48 ` Antonio Quartulli
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 20/23] batman-adv: B.A.T.M.A.N. V - implement " Antonio Quartulli
                   ` (3 subsequent siblings)
  22 siblings, 0 replies; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 12:48 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

This API has to be used to let any routing protocol free
neighbor specific allocated resources

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 originator.c | 6 ++++++
 types.h      | 2 ++
 2 files changed, 8 insertions(+)

diff --git a/originator.c b/originator.c
index 447f417..5670df8 100644
--- a/originator.c
+++ b/originator.c
@@ -196,13 +196,19 @@ static void batadv_neigh_node_free_rcu(struct rcu_head *rcu)
 	struct hlist_node *node_tmp;
 	struct batadv_neigh_node *neigh_node;
 	struct batadv_neigh_ifinfo *neigh_ifinfo;
+	struct batadv_algo_ops *bao;
 
 	neigh_node = container_of(rcu, struct batadv_neigh_node, rcu);
+	bao = neigh_node->orig_node->bat_priv->bat_algo_ops;
 
 	hlist_for_each_entry_safe(neigh_ifinfo, node_tmp,
 				  &neigh_node->ifinfo_list, list) {
 		batadv_neigh_ifinfo_free_ref_now(neigh_ifinfo);
 	}
+
+	if (bao->bat_neigh_free)
+		bao->bat_neigh_free(neigh_node);
+
 	batadv_hardif_free_ref_now(neigh_node->if_incoming);
 
 	kfree(neigh_node);
diff --git a/types.h b/types.h
index a51921e..df1479e 100644
--- a/types.h
+++ b/types.h
@@ -1203,6 +1203,8 @@ struct batadv_algo_ops {
 			       int max_if_num);
 	int (*bat_orig_del_if)(struct batadv_orig_node *orig_node,
 			       int max_if_num, int del_if_num);
+	/* neigh_node handling API */
+	void (*bat_neigh_free)(struct batadv_neigh_node *neigh);
 };
 
 /**
-- 
1.8.5.3


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

* [B.A.T.M.A.N.] [RFC 20/23] batman-adv: B.A.T.M.A.N. V - implement bat_neigh_free() API
  2014-02-11 12:48 [B.A.T.M.A.N.] [RFC 00/23] Introducing a new routing protocol: B.A.T.M.A.N. V Antonio Quartulli
                   ` (18 preceding siblings ...)
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 19/23] batman-adv: add bat_neigh_free() API Antonio Quartulli
@ 2014-02-11 12:48 ` Antonio Quartulli
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 21/23] batman-adv: B.A.T.M.A.N. V - implement neigh_is_equiv_or_better API Antonio Quartulli
                   ` (2 subsequent siblings)
  22 siblings, 0 replies; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 12:48 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 bat_v.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/bat_v.c b/bat_v.c
index 5681d19..3e4575d 100644
--- a/bat_v.c
+++ b/bat_v.c
@@ -63,6 +63,12 @@ static void batadv_v_ogm_emit(struct batadv_forw_packet *forw_packet)
 {
 }
 
+static void batadv_v_neigh_free(struct batadv_neigh_node *neigh)
+{
+	batadv_elp_neigh_node_free_ref(neigh->bat_v.elp_neigh);
+	neigh->bat_v.elp_neigh = NULL;
+}
+
 static struct batadv_algo_ops batadv_batman_v __read_mostly = {
 	.name = "BATMAN_V",
 	.bat_iface_enable = batadv_v_iface_enable,
@@ -71,6 +77,7 @@ static struct batadv_algo_ops batadv_batman_v __read_mostly = {
 	.bat_primary_iface_set = batadv_v_primary_iface_set,
 	.bat_ogm_emit = batadv_v_ogm_emit,
 	.bat_ogm_schedule = batadv_v_ogm_schedule,
+	.bat_neigh_free = batadv_v_neigh_free,
 };
 
 int batadv_v_mesh_init(struct batadv_priv *bat_priv)
-- 
1.8.5.3


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

* [B.A.T.M.A.N.] [RFC 21/23] batman-adv: B.A.T.M.A.N. V - implement neigh_is_equiv_or_better API
  2014-02-11 12:48 [B.A.T.M.A.N.] [RFC 00/23] Introducing a new routing protocol: B.A.T.M.A.N. V Antonio Quartulli
                   ` (19 preceding siblings ...)
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 20/23] batman-adv: B.A.T.M.A.N. V - implement " Antonio Quartulli
@ 2014-02-11 12:48 ` Antonio Quartulli
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 22/23] batman-adv: B.A.T.M.A.N. V - implement bat_neigh_cmp API Antonio Quartulli
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 23/23] batman-adv: B.A.T.M.A.N. V - implement bat_orig_print API Antonio Quartulli
  22 siblings, 0 replies; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 12:48 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 bat_v.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/bat_v.c b/bat_v.c
index 3e4575d..70ff9e9 100644
--- a/bat_v.c
+++ b/bat_v.c
@@ -21,6 +21,7 @@
 #include "bat_algo.h"
 #include "bat_v_elp.h"
 #include "bat_v_ogm.h"
+#include "originator.h"
 
 static int batadv_v_iface_enable(struct batadv_hard_iface *hard_iface)
 {
@@ -63,6 +64,23 @@ static void batadv_v_ogm_emit(struct batadv_forw_packet *forw_packet)
 {
 }
 
+static bool batadv_v_neigh_is_eob(struct batadv_neigh_node *neigh1,
+				  struct batadv_hard_iface *if_outgoing1,
+				  struct batadv_neigh_node *neigh2,
+				  struct batadv_hard_iface *if_outgoing2)
+{
+	struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2;
+	uint32_t threshold;
+
+	ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
+	ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
+
+	threshold = ifinfo1->bat_v.metric << 8 >> 10;
+	threshold = ifinfo1->bat_v.metric - threshold;
+
+	return ifinfo2->bat_v.metric > threshold;
+}
+
 static void batadv_v_neigh_free(struct batadv_neigh_node *neigh)
 {
 	batadv_elp_neigh_node_free_ref(neigh->bat_v.elp_neigh);
@@ -77,6 +95,7 @@ static struct batadv_algo_ops batadv_batman_v __read_mostly = {
 	.bat_primary_iface_set = batadv_v_primary_iface_set,
 	.bat_ogm_emit = batadv_v_ogm_emit,
 	.bat_ogm_schedule = batadv_v_ogm_schedule,
+	.bat_neigh_is_equiv_or_better = batadv_v_neigh_is_eob,
 	.bat_neigh_free = batadv_v_neigh_free,
 };
 
-- 
1.8.5.3


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

* [B.A.T.M.A.N.] [RFC 22/23] batman-adv: B.A.T.M.A.N. V - implement bat_neigh_cmp API
  2014-02-11 12:48 [B.A.T.M.A.N.] [RFC 00/23] Introducing a new routing protocol: B.A.T.M.A.N. V Antonio Quartulli
                   ` (20 preceding siblings ...)
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 21/23] batman-adv: B.A.T.M.A.N. V - implement neigh_is_equiv_or_better API Antonio Quartulli
@ 2014-02-11 12:48 ` Antonio Quartulli
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 23/23] batman-adv: B.A.T.M.A.N. V - implement bat_orig_print API Antonio Quartulli
  22 siblings, 0 replies; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 12:48 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

Signed-off-by: Antonio Quartulli <antonio@meshcoding.com>
---
 bat_v.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/bat_v.c b/bat_v.c
index 70ff9e9..d05d548 100644
--- a/bat_v.c
+++ b/bat_v.c
@@ -64,6 +64,23 @@ static void batadv_v_ogm_emit(struct batadv_forw_packet *forw_packet)
 {
 }
 
+static int batadv_v_neigh_cmp(struct batadv_neigh_node *neigh1,
+			      struct batadv_hard_iface *if_outgoing1,
+			      struct batadv_neigh_node *neigh2,
+			      struct batadv_hard_iface *if_outgoing2)
+{
+	struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2;
+
+	ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
+	ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
+
+	if (WARN_ON(!ifinfo1 || !ifinfo2))
+		return 0;
+
+	return ifinfo1->bat_v.metric - ifinfo2->bat_v.metric;
+
+}
+
 static bool batadv_v_neigh_is_eob(struct batadv_neigh_node *neigh1,
 				  struct batadv_hard_iface *if_outgoing1,
 				  struct batadv_neigh_node *neigh2,
@@ -95,6 +112,7 @@ static struct batadv_algo_ops batadv_batman_v __read_mostly = {
 	.bat_primary_iface_set = batadv_v_primary_iface_set,
 	.bat_ogm_emit = batadv_v_ogm_emit,
 	.bat_ogm_schedule = batadv_v_ogm_schedule,
+	.bat_neigh_cmp = batadv_v_neigh_cmp,
 	.bat_neigh_is_equiv_or_better = batadv_v_neigh_is_eob,
 	.bat_neigh_free = batadv_v_neigh_free,
 };
-- 
1.8.5.3


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

* [B.A.T.M.A.N.] [RFC 23/23] batman-adv: B.A.T.M.A.N. V - implement bat_orig_print API
  2014-02-11 12:48 [B.A.T.M.A.N.] [RFC 00/23] Introducing a new routing protocol: B.A.T.M.A.N. V Antonio Quartulli
                   ` (21 preceding siblings ...)
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 22/23] batman-adv: B.A.T.M.A.N. V - implement bat_neigh_cmp API Antonio Quartulli
@ 2014-02-11 12:48 ` Antonio Quartulli
  22 siblings, 0 replies; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 12:48 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 bat_v.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 98 insertions(+)

diff --git a/bat_v.c b/bat_v.c
index d05d548..6b21afe 100644
--- a/bat_v.c
+++ b/bat_v.c
@@ -64,6 +64,103 @@ static void batadv_v_ogm_emit(struct batadv_forw_packet *forw_packet)
 {
 }
 
+/**
+ * batadv_v_orig_print_neigh - print neighbors for the originator table
+ * @orig_node: the orig_node for which the neighbors are printed
+ * @if_outgoing: outgoing interface for these entries
+ * @seq: debugfs table seq_file struct
+ *
+ * Must be called while holding an rcu lock.
+ */
+static void
+batadv_v_orig_print_neigh(struct batadv_orig_node *orig_node,
+			  struct batadv_hard_iface *if_outgoing,
+			  struct seq_file *seq)
+{
+	struct batadv_neigh_node *neigh_node;
+	struct batadv_neigh_ifinfo *n_ifinfo;
+
+	hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) {
+		n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
+		if (!n_ifinfo)
+			continue;
+
+		seq_printf(seq, " %pM (%9u.%1u)",
+			   neigh_node->addr,
+			   n_ifinfo->bat_v.metric / 10,
+			   n_ifinfo->bat_v.metric % 10);
+
+		batadv_neigh_ifinfo_free_ref(n_ifinfo);
+	}
+}
+
+/**
+ * batadv_v_orig_print - print the originator table
+ * @bat_priv: the bat priv with all the soft interface information
+ * @seq: debugfs table seq_file struct
+ * @if_outgoing: the outgoing interface for which this should be printed
+ */
+static void batadv_v_orig_print(struct batadv_priv *bat_priv,
+				struct seq_file *seq,
+				struct batadv_hard_iface *if_outgoing)
+{
+	struct batadv_neigh_node *neigh_node;
+	struct batadv_hashtable *hash = bat_priv->orig_hash;
+	int last_seen_msecs, last_seen_secs;
+	struct batadv_orig_node *orig_node;
+	struct batadv_neigh_ifinfo *n_ifinfo;
+	unsigned long last_seen_jiffies;
+	struct hlist_head *head;
+	int batman_count = 0;
+	uint32_t i;
+
+	seq_printf(seq, "  %-15s %s (%11s) %17s [%10s]: %20s ...\n",
+		   "Originator", "last-seen", "metric", "Nexthop",
+		   "outgoingIF", "Potential nexthops");
+
+	for (i = 0; i < hash->size; i++) {
+		head = &hash->table[i];
+
+		rcu_read_lock();
+		hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
+			neigh_node = batadv_orig_router_get(orig_node,
+							    if_outgoing);
+			if (!neigh_node)
+				continue;
+
+			n_ifinfo = batadv_neigh_ifinfo_get(neigh_node,
+							   if_outgoing);
+			if (!n_ifinfo)
+				goto next;
+
+			last_seen_jiffies = jiffies - orig_node->last_seen;
+			last_seen_msecs = jiffies_to_msecs(last_seen_jiffies);
+			last_seen_secs = last_seen_msecs / 1000;
+			last_seen_msecs = last_seen_msecs % 1000;
+
+			seq_printf(seq, "%pM %4i.%03is (%9u.%1u) %pM [%10s]:",
+				   orig_node->orig, last_seen_secs,
+				   last_seen_msecs, n_ifinfo->bat_v.metric / 10,
+				   n_ifinfo->bat_v.metric % 10,
+				   neigh_node->addr,
+				   neigh_node->if_incoming->net_dev->name);
+
+			batadv_v_orig_print_neigh(orig_node, if_outgoing, seq);
+			seq_puts(seq, "\n");
+			batman_count++;
+
+next:
+			batadv_neigh_node_free_ref(neigh_node);
+			if (n_ifinfo)
+				batadv_neigh_ifinfo_free_ref(n_ifinfo);
+		}
+		rcu_read_unlock();
+	}
+
+	if (batman_count == 0)
+		seq_puts(seq, "No batman nodes in range ...\n");
+}
+
 static int batadv_v_neigh_cmp(struct batadv_neigh_node *neigh1,
 			      struct batadv_hard_iface *if_outgoing1,
 			      struct batadv_neigh_node *neigh2,
@@ -112,6 +209,7 @@ static struct batadv_algo_ops batadv_batman_v __read_mostly = {
 	.bat_primary_iface_set = batadv_v_primary_iface_set,
 	.bat_ogm_emit = batadv_v_ogm_emit,
 	.bat_ogm_schedule = batadv_v_ogm_schedule,
+	.bat_orig_print = batadv_v_orig_print,
 	.bat_neigh_cmp = batadv_v_neigh_cmp,
 	.bat_neigh_is_equiv_or_better = batadv_v_neigh_is_eob,
 	.bat_neigh_free = batadv_v_neigh_free,
-- 
1.8.5.3


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

* Re: [B.A.T.M.A.N.] [RFC 04/23] batman-adv: ELP - creating neighbor structures
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 04/23] batman-adv: ELP - creating neighbor structures Antonio Quartulli
@ 2014-02-11 15:32   ` Andrew Lunn
  2014-02-11 16:02     ` Antonio Quartulli
  0 siblings, 1 reply; 68+ messages in thread
From: Andrew Lunn @ 2014-02-11 15:32 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking
  Cc: Marek Lindner, Antonio Quartulli

On Tue, Feb 11, 2014 at 01:48:04PM +0100, Antonio Quartulli wrote:
> From: Linus Luessing <linus.luessing@web.de>
> 
> Initially developed by Linus during a 6 months trainee study
> period in Ascom (Switzerland) AG.
> 
> Signed-off-by: Linus Luessing <linus.luessing@web.de>
> Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
> Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
> ---
>  bat_v.c     |  18 +++++-
>  bat_v_elp.c | 204 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  bat_v_elp.h |   6 ++
>  main.h      |   2 +
>  types.h     |  53 ++++++++++++++++
>  5 files changed, 281 insertions(+), 2 deletions(-)
> 
> diff --git a/bat_v.c b/bat_v.c
> index 7247d7f..bed5e00 100644
> --- a/bat_v.c
> +++ b/bat_v.c
> @@ -61,5 +61,21 @@ static struct batadv_algo_ops batadv_batman_v __read_mostly = {
>  
>  int __init batadv_v_init(void)
>  {
> -	return batadv_algo_register(&batadv_batman_v);
> +	int ret;
> +
> +	/* batman v echo location protocol packet  */
> +	ret = batadv_recv_handler_register(BATADV_ELP,
> +					   batadv_v_elp_packet_recv);
> +	if (ret < 0)
> +		goto elp_unregister;
> +
> +	ret = batadv_algo_register(&batadv_batman_v);
> +
> +	return ret;
> +
> +elp_unregister:
> +	if (ret < 0)
> +		batadv_recv_handler_unregister(BATADV_ELP);

No need to check ret here. If we are here, it has to be < 0.

It also seems odd to me you are unregistering the handler when the
registration of the handler fails!

I suspect the first if (ret < 0) should be followed by a plain return
ret; and there should be a second test for the return value of
batadv_algo_register() which should goto the label and unregister the
handler.

	Andrew

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

* Re: [B.A.T.M.A.N.] [RFC 04/23] batman-adv: ELP - creating neighbor structures
  2014-02-11 15:32   ` Andrew Lunn
@ 2014-02-11 16:02     ` Antonio Quartulli
  2014-02-11 16:11       ` Lew Pitcher
  0 siblings, 1 reply; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 16:02 UTC (permalink / raw)
  To: Andrew Lunn, The list for a Better Approach To Mobile Ad-hoc Networking
  Cc: Marek Lindner

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

On 11/02/14 16:32, Andrew Lunn wrote:
> On Tue, Feb 11, 2014 at 01:48:04PM +0100, Antonio Quartulli wrote:
>> From: Linus Luessing <linus.luessing@web.de>
>>
>> Initially developed by Linus during a 6 months trainee study
>> period in Ascom (Switzerland) AG.
>>
>> Signed-off-by: Linus Luessing <linus.luessing@web.de>
>> Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
>> Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
>> ---
>>  bat_v.c     |  18 +++++-
>>  bat_v_elp.c | 204 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>>  bat_v_elp.h |   6 ++
>>  main.h      |   2 +
>>  types.h     |  53 ++++++++++++++++
>>  5 files changed, 281 insertions(+), 2 deletions(-)
>>
>> diff --git a/bat_v.c b/bat_v.c
>> index 7247d7f..bed5e00 100644
>> --- a/bat_v.c
>> +++ b/bat_v.c
>> @@ -61,5 +61,21 @@ static struct batadv_algo_ops batadv_batman_v __read_mostly = {
>>  
>>  int __init batadv_v_init(void)
>>  {
>> -	return batadv_algo_register(&batadv_batman_v);
>> +	int ret;
>> +
>> +	/* batman v echo location protocol packet  */
>> +	ret = batadv_recv_handler_register(BATADV_ELP,
>> +					   batadv_v_elp_packet_recv);
>> +	if (ret < 0)
>> +		goto elp_unregister;
>> +
>> +	ret = batadv_algo_register(&batadv_batman_v);
>> +
>> +	return ret;
>> +
>> +elp_unregister:
>> +	if (ret < 0)
>> +		batadv_recv_handler_unregister(BATADV_ELP);
> 
> No need to check ret here. If we are here, it has to be < 0.
> 
> It also seems odd to me you are unregistering the handler when the
> registration of the handler fails!
> 
> I suspect the first if (ret < 0) should be followed by a plain return
> ret; and there should be a second test for the return value of
> batadv_algo_register() which should goto the label and unregister the
> handler.

I totally agree with what you said.
We should jump to elp_unregister if batadv_algo_register() fails.

Thanks!

-- 
Antonio Quartulli


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [B.A.T.M.A.N.] [RFC 04/23] batman-adv: ELP - creating neighbor structures
  2014-02-11 16:02     ` Antonio Quartulli
@ 2014-02-11 16:11       ` Lew Pitcher
  2014-02-11 16:26         ` Antonio Quartulli
  0 siblings, 1 reply; 68+ messages in thread
From: Lew Pitcher @ 2014-02-11 16:11 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

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

On Tuesday 11 February 2014 11:02:11 Antonio Quartulli wrote:
> On 11/02/14 16:32, Andrew Lunn wrote:
> > On Tue, Feb 11, 2014 at 01:48:04PM +0100, Antonio Quartulli wrote:
> >> From: Linus Luessing <linus.luessing@web.de>
> >>
> >> Initially developed by Linus during a 6 months trainee study
> >> period in Ascom (Switzerland) AG.
> >>
> >> Signed-off-by: Linus Luessing <linus.luessing@web.de>
> >> Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
> >> Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
> >> ---
> >>  bat_v.c     |  18 +++++-
> >>  bat_v_elp.c | 204 
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> >>  bat_v_elp.h |   6 ++
> >>  main.h      |   2 +
> >>  types.h     |  53 ++++++++++++++++
> >>  5 files changed, 281 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/bat_v.c b/bat_v.c
> >> index 7247d7f..bed5e00 100644
> >> --- a/bat_v.c
> >> +++ b/bat_v.c
> >> @@ -61,5 +61,21 @@ static struct batadv_algo_ops batadv_batman_v 
__read_mostly = {
> >>  
> >>  int __init batadv_v_init(void)
> >>  {
> >> -	return batadv_algo_register(&batadv_batman_v);
> >> +	int ret;
> >> +
> >> +	/* batman v echo location protocol packet  */
> >> +	ret = batadv_recv_handler_register(BATADV_ELP,
> >> +					   batadv_v_elp_packet_recv);
> >> +	if (ret < 0)
> >> +		goto elp_unregister;
> >> +
> >> +	ret = batadv_algo_register(&batadv_batman_v);
> >> +
> >> +	return ret;
> >> +
> >> +elp_unregister:
> >> +	if (ret < 0)
> >> +		batadv_recv_handler_unregister(BATADV_ELP);
> > 
> > No need to check ret here. If we are here, it has to be < 0.
> > 
> > It also seems odd to me you are unregistering the handler when the
> > registration of the handler fails!
> > 
> > I suspect the first if (ret < 0) should be followed by a plain return
> > ret; and there should be a second test for the return value of
> > batadv_algo_register() which should goto the label and unregister the
> > handler.
> 
> I totally agree with what you said.
> We should jump to elp_unregister if batadv_algo_register() fails.

Sorry to break in here, but the (ex) professional programmer in me just /has/ 
to comment.

Why not just
  int __init batadv_v_init(void)
  {
 -	return batadv_algo_register(&batadv_batman_v);
 +	int ret;
 +
 +	/* batman v echo location protocol packet  */
 +	ret = batadv_recv_handler_register(BATADV_ELP,
 +					   batadv_v_elp_packet_recv);
 +
 +	if (ret >= 0)
 +	  ret = batadv_algo_register(&batadv_batman_v);
 +	else
 +	  batadv_recv_handler_unregister(BATADV_ELP);
 +
 +	return ret;
?
-- 
Lew Pitcher
"In Skills, We Trust"
PGP public key available upon request


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

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

* Re: [B.A.T.M.A.N.] [RFC 04/23] batman-adv: ELP - creating neighbor structures
  2014-02-11 16:11       ` Lew Pitcher
@ 2014-02-11 16:26         ` Antonio Quartulli
  0 siblings, 0 replies; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 16:26 UTC (permalink / raw)
  To: b.a.t.m.a.n

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

On 11/02/14 17:11, Lew Pitcher wrote:
> On Tuesday 11 February 2014 11:02:11 Antonio Quartulli wrote:
>> On 11/02/14 16:32, Andrew Lunn wrote:
>>> On Tue, Feb 11, 2014 at 01:48:04PM +0100, Antonio Quartulli wrote:
>>>> From: Linus Luessing <linus.luessing@web.de>
>>>>
>>>> Initially developed by Linus during a 6 months trainee study
>>>> period in Ascom (Switzerland) AG.
>>>>
>>>> Signed-off-by: Linus Luessing <linus.luessing@web.de>
>>>> Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
>>>> Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
>>>> ---
>>>>  bat_v.c     |  18 +++++-
>>>>  bat_v_elp.c | 204 
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>>>>  bat_v_elp.h |   6 ++
>>>>  main.h      |   2 +
>>>>  types.h     |  53 ++++++++++++++++
>>>>  5 files changed, 281 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/bat_v.c b/bat_v.c
>>>> index 7247d7f..bed5e00 100644
>>>> --- a/bat_v.c
>>>> +++ b/bat_v.c
>>>> @@ -61,5 +61,21 @@ static struct batadv_algo_ops batadv_batman_v 
> __read_mostly = {
>>>>  
>>>>  int __init batadv_v_init(void)
>>>>  {
>>>> -	return batadv_algo_register(&batadv_batman_v);
>>>> +	int ret;
>>>> +
>>>> +	/* batman v echo location protocol packet  */
>>>> +	ret = batadv_recv_handler_register(BATADV_ELP,
>>>> +					   batadv_v_elp_packet_recv);
>>>> +	if (ret < 0)
>>>> +		goto elp_unregister;
>>>> +
>>>> +	ret = batadv_algo_register(&batadv_batman_v);
>>>> +
>>>> +	return ret;
>>>> +
>>>> +elp_unregister:
>>>> +	if (ret < 0)
>>>> +		batadv_recv_handler_unregister(BATADV_ELP);
>>>
>>> No need to check ret here. If we are here, it has to be < 0.
>>>
>>> It also seems odd to me you are unregistering the handler when the
>>> registration of the handler fails!
>>>
>>> I suspect the first if (ret < 0) should be followed by a plain return
>>> ret; and there should be a second test for the return value of
>>> batadv_algo_register() which should goto the label and unregister the
>>> handler.
>>
>> I totally agree with what you said.
>> We should jump to elp_unregister if batadv_algo_register() fails.
> 
> Sorry to break in here, but the (ex) professional programmer in me just /has/ 
> to comment.

Everybody is welcome! :)

> 
> Why not just
>   int __init batadv_v_init(void)
>   {
>  -	return batadv_algo_register(&batadv_batman_v);
>  +	int ret;
>  +
>  +	/* batman v echo location protocol packet  */
>  +	ret = batadv_recv_handler_register(BATADV_ELP,
>  +					   batadv_v_elp_packet_recv);
>  +
>  +	if (ret >= 0)
>  +	  ret = batadv_algo_register(&batadv_batman_v);
>  +	else
>  +	  batadv_recv_handler_unregister(BATADV_ELP);
>  +
>  +	return ret;
> ?
> 


Actually I already fixed it like this:

 int __init batadv_v_init(void)
 {
-       return batadv_algo_register(&batadv_batman_v);
+       int ret;
+
+       /* batman v echo location protocol packet  */
+       ret = batadv_recv_handler_register(BATADV_ELP,
+                                          batadv_v_elp_packet_recv);
+       if (ret < 0)
+               return ret;
+
+       ret = batadv_algo_register(&batadv_batman_v);
+       if (ret < 0)
+               batadv_recv_handler_unregister(BATADV_ELP);
+
+       return ret;


I think it is easier to read, no?
Anyway, this chunk is changed later b patch 7/23 because we add the OGM2
registration.

Cheers,


-- 
Antonio Quartulli


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [B.A.T.M.A.N.] [RFC 06/23] batman-adv: ELP - adding sysfs parameter for elp interval
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 06/23] batman-adv: ELP - adding sysfs parameter for elp interval Antonio Quartulli
@ 2014-02-11 16:59   ` Andrew Lunn
  2014-02-11 17:08     ` Antonio Quartulli
  0 siblings, 1 reply; 68+ messages in thread
From: Andrew Lunn @ 2014-02-11 16:59 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking
  Cc: Marek Lindner, Antonio Quartulli

On Tue, Feb 11, 2014 at 01:48:06PM +0100, Antonio Quartulli wrote:
> From: Linus Luessing <linus.luessing@web.de>
> 
> This parameter can be set individually on each interface and
> allows the configuration of the ndp interval for the link

s/ndp/elp

> quality measurements during runtime. Usually it is desirable
> to set it to a higher (= slower) value on interfaces which
> have a more static characteristic (e.g. wired interfaces)
> or very dense neighbourhoods to reduce overhead.
> 
> Developed by Linus during a 6 months trainee study period in
> Ascom (Switzerland) AG.
> 
> Signed-off-by: Linus Luessing <linus.luessing@web.de>
> Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
> [antonio@open-mesh.com: respin on top of the latest master]
> Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
> ---
>  sysfs-class-net-batman-adv | 8 +++++++-
>  sysfs.c                    | 7 +++++++
>  2 files changed, 14 insertions(+), 1 deletion(-)
> 
> diff --git a/sysfs-class-net-batman-adv b/sysfs-class-net-batman-adv
> index 7f34a95..2884c98 100644
> --- a/sysfs-class-net-batman-adv
> +++ b/sysfs-class-net-batman-adv
> @@ -1,4 +1,11 @@
>  
> +What:           /sys/class/net/<mesh_iface>/batman-adv/elp_interval
> +Date:           Mar 2012

Might make sense to update this to 2014?

      Andrew

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

* Re: [B.A.T.M.A.N.] [RFC 06/23] batman-adv: ELP - adding sysfs parameter for elp interval
  2014-02-11 16:59   ` Andrew Lunn
@ 2014-02-11 17:08     ` Antonio Quartulli
  0 siblings, 0 replies; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 17:08 UTC (permalink / raw)
  To: b.a.t.m.a.n

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

On 11/02/14 17:59, Andrew Lunn wrote:
> On Tue, Feb 11, 2014 at 01:48:06PM +0100, Antonio Quartulli wrote:
>> From: Linus Luessing <linus.luessing@web.de>
>>
>> This parameter can be set individually on each interface and
>> allows the configuration of the ndp interval for the link
> 
> s/ndp/elp

thanks!

> 
>> quality measurements during runtime. Usually it is desirable
>> to set it to a higher (= slower) value on interfaces which
>> have a more static characteristic (e.g. wired interfaces)
>> or very dense neighbourhoods to reduce overhead.
>>
>> Developed by Linus during a 6 months trainee study period in
>> Ascom (Switzerland) AG.
>>
>> Signed-off-by: Linus Luessing <linus.luessing@web.de>
>> Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
>> [antonio@open-mesh.com: respin on top of the latest master]
>> Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
>> ---
>>  sysfs-class-net-batman-adv | 8 +++++++-
>>  sysfs.c                    | 7 +++++++
>>  2 files changed, 14 insertions(+), 1 deletion(-)
>>
>> diff --git a/sysfs-class-net-batman-adv b/sysfs-class-net-batman-adv
>> index 7f34a95..2884c98 100644
>> --- a/sysfs-class-net-batman-adv
>> +++ b/sysfs-class-net-batman-adv
>> @@ -1,4 +1,11 @@
>>  
>> +What:           /sys/class/net/<mesh_iface>/batman-adv/elp_interval
>> +Date:           Mar 2012
> 
> Might make sense to update this to 2014?

I kept it as it was when the patch got merged in our repo.
But I think it should match the month it gets introduced in the kernel.

Thanks²!

-- 
Antonio Quartulli


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [B.A.T.M.A.N.] [RFC 07/23] batman-adv: OGMv2 - add basic infrastructure
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 07/23] batman-adv: OGMv2 - add basic infrastructure Antonio Quartulli
@ 2014-02-11 17:12   ` Andrew Lunn
  2014-02-11 17:52     ` Antonio Quartulli
  0 siblings, 1 reply; 68+ messages in thread
From: Andrew Lunn @ 2014-02-11 17:12 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking
  Cc: Antonio Quartulli

> +static void batadv_v_ogm_send(struct work_struct *work)
> +{
> +	struct batadv_hard_iface *hard_iface;
> +	struct batadv_priv_bat_v *bat_v;
> +	struct batadv_priv *bat_priv;
> +	struct batadv_ogm2_packet *ogm2;
> +	struct sk_buff *skb;
> +	unsigned char *ogm_buff, *pkt_buff;
> +	int ogm_buff_len;
> +	uint16_t tvlv_len = 0;
> +
> +	bat_v = container_of(work, struct batadv_priv_bat_v, ogm_wq.work);
> +	bat_priv = container_of(bat_v, struct batadv_priv, bat_v);
> +
> +	if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING)
> +		goto out;
> +
> +	ogm_buff = bat_priv->bat_v.ogm_buff;
> +	ogm_buff_len = bat_priv->bat_v.ogm_buff_len;
> +	/* tt changes have to be committed before the tvlv data is
> +	 * appended as it may alter the tt tvlv container
> +	 */
> +	batadv_tt_local_commit_changes(bat_priv);
> +	tvlv_len = batadv_tvlv_container_ogm_append(bat_priv, &ogm_buff,
> +						    &ogm_buff_len,
> +						    BATADV_OGM2_HLEN);
> +
> +	bat_priv->bat_v.ogm_buff = ogm_buff;
> +	bat_priv->bat_v.ogm_buff_len = ogm_buff_len;
> +
> +	skb = netdev_alloc_skb_ip_align(NULL, ETH_HLEN + ogm_buff_len);
> +	if (!skb)
> +		goto out;
> +
> +	skb_reserve(skb, ETH_HLEN);
> +	pkt_buff = skb_put(skb, ogm_buff_len);
> +	memcpy(pkt_buff, ogm_buff, ogm_buff_len);
> +
> +	ogm2 = (struct batadv_ogm2_packet *)skb->data;
> +	ogm2->seqno = htonl(atomic_read(&bat_priv->bat_v.ogm_seqno));
> +	atomic_inc(&bat_priv->bat_v.ogm_seqno);
> +	ogm2->tvlv_len = htons(tvlv_len);
> +
> +	/* broadcast on every interface */
> +	rcu_read_lock();
> +	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
> +		if (hard_iface->soft_iface != bat_priv->soft_iface)
> +			continue;
> +
> +		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
> +			   "Sending own OGM2 packet (originator %pM, seqno %u, metric %u, TTL %d) on interface %s [%pM]\n",
> +			   ogm2->orig, ntohl(ogm2->seqno), ntohl(ogm2->metric),
> +			   ogm2->ttl, hard_iface->net_dev->name,
> +			   hard_iface->net_dev->dev_addr);
> +
> +		batadv_v_ogm_send_to_if(skb, hard_iface);
> +	}
> +	rcu_read_unlock();
> +
> +	consume_skb(skb);
> +
> +	batadv_v_ogm_start_timer(bat_priv);
> +out:
> +	return;

If you jump to out because netdev_alloc_skb_ip_align() failed, don't
you want to start the timer again? I would assume it is a transient
problem not being able to get memory for the skb, and the next time
the timer goes off it might work?

> +	bat_priv->bat_v.ogm_buff_len = BATADV_OGM2_HLEN;
> +	ogm_buff = kmalloc(bat_priv->bat_v.ogm_buff_len, GFP_ATOMIC);

Maybe use kzalloc to ensure it is zero?

      Andrew

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

* Re: [B.A.T.M.A.N.] [RFC 08/23] batman-adv: OGMv2 - implement originators logic
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 08/23] batman-adv: OGMv2 - implement originators logic Antonio Quartulli
@ 2014-02-11 17:22   ` Andrew Lunn
  2014-02-11 17:30     ` Antonio Quartulli
  0 siblings, 1 reply; 68+ messages in thread
From: Andrew Lunn @ 2014-02-11 17:22 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking
  Cc: Antonio Quartulli

> +static struct batadv_orig_node *
> +batadv_v_ogm_orig_get(struct batadv_priv *bat_priv, const uint8_t *addr)
> +{
> +	struct batadv_orig_node *orig_node;
> +	int hash_added;
> +
> +	orig_node = batadv_orig_hash_find(bat_priv, addr);
> +	if (orig_node)
> +		return orig_node;
> +
> +	orig_node = batadv_orig_node_new(bat_priv, addr);

Can this fail and return NULL?

> +
> +	hash_added = batadv_hash_add(bat_priv->orig_hash, batadv_compare_orig,
> +				     batadv_choose_orig, orig_node,
> +				     &orig_node->hash_entry);
> +	if (hash_added != 0) {
> +		batadv_orig_node_free_ref(orig_node);
> +		batadv_orig_node_free_ref(orig_node);

Looks odd. If it is correct, it should have a comment why it is
correct.

	Andrew

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

* Re: [B.A.T.M.A.N.] [RFC 08/23] batman-adv: OGMv2 - implement originators logic
  2014-02-11 17:22   ` Andrew Lunn
@ 2014-02-11 17:30     ` Antonio Quartulli
  0 siblings, 0 replies; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 17:30 UTC (permalink / raw)
  To: b.a.t.m.a.n

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

On 11/02/14 18:22, Andrew Lunn wrote:
>> +static struct batadv_orig_node *
>> +batadv_v_ogm_orig_get(struct batadv_priv *bat_priv, const uint8_t *addr)
>> +{
>> +	struct batadv_orig_node *orig_node;
>> +	int hash_added;
>> +
>> +	orig_node = batadv_orig_hash_find(bat_priv, addr);
>> +	if (orig_node)
>> +		return orig_node;
>> +
>> +	orig_node = batadv_orig_node_new(bat_priv, addr);
> 
> Can this fail and return NULL?

Yes it can. Better to check.

> 
>> +
>> +	hash_added = batadv_hash_add(bat_priv->orig_hash, batadv_compare_orig,
>> +				     batadv_choose_orig, orig_node,
>> +				     &orig_node->hash_entry);
>> +	if (hash_added != 0) {
>> +		batadv_orig_node_free_ref(orig_node);
>> +		batadv_orig_node_free_ref(orig_node);
> 
> Looks odd. If it is correct, it should have a comment why it is
> correct.

We have a similar problem in the current (B.A.T.M.A.N. IV) code too.
The point is that orig_node->refcounter is initialised to 2, therefore
if we want to free the object in this early phase we need to invoke the
free_ref() twice.

By the way...I was just thinking that we could invoke kfree() directly
here (the orig_node is not referenced in any other context since it has
been just allocated).

Cheers,


-- 
Antonio Quartulli


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [B.A.T.M.A.N.] [RFC 07/23] batman-adv: OGMv2 - add basic infrastructure
  2014-02-11 17:12   ` Andrew Lunn
@ 2014-02-11 17:52     ` Antonio Quartulli
  2014-02-12  7:44       ` Andrew Lunn
  0 siblings, 1 reply; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-11 17:52 UTC (permalink / raw)
  To: b.a.t.m.a.n

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

On 11/02/14 18:12, Andrew Lunn wrote:
>> +
>> +	batadv_v_ogm_start_timer(bat_priv);
>> +out:
>> +	return;
> 
> If you jump to out because netdev_alloc_skb_ip_align() failed, don't
> you want to start the timer again? I would assume it is a transient
> problem not being able to get memory for the skb, and the next time
> the timer goes off it might work?

Now that I think about it I agree with you. If
netdev_alloc_skb_ip_align() fails either:
- the situation is permanent -> OOM soon
- or the situation is transient -> we should try re-scheduling the task.

> 
>> +	bat_priv->bat_v.ogm_buff_len = BATADV_OGM2_HLEN;
>> +	ogm_buff = kmalloc(bat_priv->bat_v.ogm_buff_len, GFP_ATOMIC);
> 
> Maybe use kzalloc to ensure it is zero?

Not really needed because each field is explicitly assigned later. But
to be sure we sit on the safe side we can do that: in the end we are not
in the fastpath here.

Cheers,



-- 
Antonio Quartulli


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [B.A.T.M.A.N.] [RFC 07/23] batman-adv: OGMv2 - add basic infrastructure
  2014-02-11 17:52     ` Antonio Quartulli
@ 2014-02-12  7:44       ` Andrew Lunn
  2014-02-12  7:58         ` Antonio Quartulli
  0 siblings, 1 reply; 68+ messages in thread
From: Andrew Lunn @ 2014-02-12  7:44 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

> >> +	bat_priv->bat_v.ogm_buff_len = BATADV_OGM2_HLEN;
> >> +	ogm_buff = kmalloc(bat_priv->bat_v.ogm_buff_len, GFP_ATOMIC);
> > 
> > Maybe use kzalloc to ensure it is zero?
> 
> Not really needed because each field is explicitly assigned later. But
> to be sure we sit on the safe side we can do that: in the end we are not
> in the fastpath here.

I know some of your structures have explicit align bytes. It would be
good to ensure they are zero so that they could be used in the future
without having a protocol version bump. So i think it is a good
patterns to follow in general when not on the fast path.

	Andrew

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

* Re: [B.A.T.M.A.N.] [RFC 07/23] batman-adv: OGMv2 - add basic infrastructure
  2014-02-12  7:44       ` Andrew Lunn
@ 2014-02-12  7:58         ` Antonio Quartulli
  0 siblings, 0 replies; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-12  7:58 UTC (permalink / raw)
  To: b.a.t.m.a.n

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

On 12/02/14 08:44, Andrew Lunn wrote:
>>>> +	bat_priv->bat_v.ogm_buff_len = BATADV_OGM2_HLEN;
>>>> +	ogm_buff = kmalloc(bat_priv->bat_v.ogm_buff_len, GFP_ATOMIC);
>>>
>>> Maybe use kzalloc to ensure it is zero?
>>
>> Not really needed because each field is explicitly assigned later. But
>> to be sure we sit on the safe side we can do that: in the end we are not
>> in the fastpath here.
> 
> I know some of your structures have explicit align bytes. It would be
> good to ensure they are zero so that they could be used in the future
> without having a protocol version bump. So i think it is a good
> patterns to follow in general when not on the fast path.

True. _I_ had this problem in the past already :-)
I'll use kzalloc then!

Thanks!


> 
> 	Andrew
> 


-- 
Antonio Quartulli


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [B.A.T.M.A.N.] [RFC 12/23] batman-adv: add base throughput attribute
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 12/23] batman-adv: add base throughput attribute Antonio Quartulli
@ 2014-02-12  8:40   ` Andrew Lunn
  2014-02-12 12:20     ` Antonio Quartulli
  0 siblings, 1 reply; 68+ messages in thread
From: Andrew Lunn @ 2014-02-12  8:40 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking
  Cc: Antonio Quartulli

On Tue, Feb 11, 2014 at 01:48:12PM +0100, Antonio Quartulli wrote:
> From: Antonio Quartulli <antonio@open-mesh.com>
> 
> when batman-adv is asked to estimate/compute the throughput
> of an interface, but it fails for whatever reason, then the
> value in this attribute is used
> 
> Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
> ---
>  bat_v.c | 3 +++
>  main.h  | 7 +++++++
>  sysfs.c | 7 +++++++
>  types.h | 1 +
>  4 files changed, 18 insertions(+)
> 
> diff --git a/bat_v.c b/bat_v.c
> index d5457b3..3aa42ec 100644
> --- a/bat_v.c
> +++ b/bat_v.c
> @@ -75,6 +75,9 @@ static struct batadv_algo_ops batadv_batman_v __read_mostly = {
>  
>  int batadv_v_mesh_init(struct batadv_priv *bat_priv)
>  {
> +	atomic_set(&bat_priv->bat_v.base_throughput,
> +		   BATADV_DEFAULT_BASE_THROUGHPUT);
> +
>  	return batadv_v_ogm_init(bat_priv);
>  }
>  
> diff --git a/main.h b/main.h
> index 47fb9ed..5699c9f 100644
> --- a/main.h
> +++ b/main.h
> @@ -33,6 +33,13 @@
>  #define BATADV_MAX_METRIC 0xFFFFFFFF
>  #define BATADV_JITTER 20
>  
> +/**
> + * BATADV_DEFAULT_BASE_THROUGHPUT - default value used as throughput for
> + * hard_ifaces for which it is not possible to measure/estimate the real one.
> + * Value is expressed in Mbps/10

Mbps/10 is a rather odd unit. How about just Kbps?

	Andrew

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

* Re: [B.A.T.M.A.N.] [RFC 11/23] batman-adv: add throughput attribute to hard_ifaces
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 11/23] batman-adv: add throughput attribute to hard_ifaces Antonio Quartulli
@ 2014-02-12  8:42   ` Andrew Lunn
  0 siblings, 0 replies; 68+ messages in thread
From: Andrew Lunn @ 2014-02-12  8:42 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking
  Cc: Antonio Quartulli

On Tue, Feb 11, 2014 at 01:48:11PM +0100, Antonio Quartulli wrote:
> From: Antonio Quartulli <antonio@open-mesh.com>
> 
> This attribute is exported to the user which can manually
> select its value. It is the throughput value to be used
> by default when batman-adv is trying to compute the link
> throughput towards a neighbour using this interface.
> 
> If the value is set to 0 then batman-adv will try to detect
> the throughput by itself.

sysfs documentation is missing, but i guess you know what.

      Andrew

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

* Re: [B.A.T.M.A.N.] [RFC 13/23] batman-adv: add last_unicast_tx to struct neigh_node_elp
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 13/23] batman-adv: add last_unicast_tx to struct neigh_node_elp Antonio Quartulli
@ 2014-02-12  8:49   ` Andrew Lunn
  2014-02-12 12:25     ` Antonio Quartulli
  0 siblings, 1 reply; 68+ messages in thread
From: Andrew Lunn @ 2014-02-12  8:49 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking
  Cc: Antonio Quartulli

On Tue, Feb 11, 2014 at 01:48:13PM +0100, Antonio Quartulli wrote:
> From: Antonio Quartulli <antonio@open-mesh.com>
> 
> This timestamp registers the last time a unicast packet was
> sent to a given neighbour

I think this changelog needs improving. 95% of the patch is about
refactoring a send function into a unicast send and a broadcast send
function. The counter makes up the other 5% of the patch.

	  Andrew

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

* Re: [B.A.T.M.A.N.] [RFC 14/23] batman-adv: ELP - compute the metric based on the estimated throughput
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 14/23] batman-adv: ELP - compute the metric based on the estimated throughput Antonio Quartulli
@ 2014-02-12  8:58   ` Andrew Lunn
  2014-02-12 12:27     ` Antonio Quartulli
  0 siblings, 1 reply; 68+ messages in thread
From: Andrew Lunn @ 2014-02-12  8:58 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking
  Cc: Antonio Quartulli

On Tue, Feb 11, 2014 at 01:48:14PM +0100, Antonio Quartulli wrote:
> From: Antonio Quartulli <antonio@open-mesh.com>
> 
> Implement a stub get_throughput() function which returns the
> estimated throughput towards a given neighbour.
> Its result is then used to compute the metric value.
> 
> The metric is updated each time a new ELP packet is sent,
> this way it is possible to timely react to a metric
> variation which can imply (for example) a neighbour
> disconnection.

It is very much a style issue, but i would probably split this into
two patches. Updating the metric at send time rather than receive
should have nothing to do with estimated bandwidth.

       Andrew

> 
> Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
> ---
>  bat_v_elp.c | 49 +++++++++++++++++++++++++++++++++++++++++++------
>  types.h     |  2 ++
>  2 files changed, 45 insertions(+), 6 deletions(-)
> 
> diff --git a/bat_v_elp.c b/bat_v_elp.c
> index 4185d8c..ef4e476 100644
> --- a/bat_v_elp.c
> +++ b/bat_v_elp.c
> @@ -53,6 +53,29 @@ void batadv_elp_neigh_node_free_ref(struct batadv_elp_neigh_node *neigh)
>  }
>  
>  /**
> + * batadv_v_elp_get_throughput - get the throughput towards a neighbour
> + * @neigh: the neighbour for which the throughput has to be obtained
> + *
> + * Returns the throughput towards the given neighbour.
> + */
> +static uint32_t
> +batadv_v_elp_get_throughput(struct batadv_elp_neigh_node *neigh)
> +{
> +	struct batadv_hard_iface *hard_iface = neigh->hard_iface;
> +	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
> +	uint32_t throughput;
> +
> +	/* get the customised user value for the throughput */
> +	throughput = atomic_read(&hard_iface->bat_v.user_throughput);
> +	/* if the user specified a value, let's return it */
> +	if (throughput != 0)
> +		return throughput;
> +
> +	/* throughput cannot be computed right now. Return base value */
> +	return atomic_read(&bat_priv->bat_v.base_throughput);
> +}
> +
> +/**
>   * batadv_v_elp_neigh_new - create a new ELP neighbour node
>   * @hard_iface: the interface the neighbour is connected to
>   * @neigh_addr: the neighbour interface address
> @@ -75,6 +98,7 @@ batadv_v_elp_neigh_new(struct batadv_hard_iface *hard_iface,
>  	memcpy(neigh->addr, neigh_addr, ETH_ALEN);
>  	neigh->last_seen = jiffies;
>  	ewma_init(&neigh->metric, 1024, 8);
> +	neigh->hard_iface = hard_iface;
>  	/* recount initialised to 2 to simplify the caller function */
>  	atomic_set(&neigh->refcount, 2);
>  
> @@ -147,19 +171,20 @@ static void batadv_v_elp_neigh_purge(struct batadv_hard_iface *hard_iface)
>  }
>  
>  /**
> - * batadv_v_elp_send_outstanding - ELP periodic broadcast sending
> + * batadv_v_elp_periodic_work - ELP periodic task per interface
>   * @work: work queue item
>   *
> - * Sends a broadcast ELP message over the interface that this work item belongs
> - * to.
> + * Sends a broadcast ELP message and reads the metric for all the neighbours
> + * connected to the interface that this work item belongs to.
>   */
> -static void batadv_v_elp_send_outstanding(struct work_struct *work)
> +static void batadv_v_elp_periodic_work(struct work_struct *work)
>  {
>  	struct batadv_hard_iface *hard_iface;
>  	struct batadv_hard_iface_bat_v *bat_v;
>  	struct batadv_priv *bat_priv;
>  	struct batadv_elp_packet *elp_packet;
>  	uint32_t elp_interval;
> +	struct batadv_elp_neigh_node *neigh;
>  	struct sk_buff *skb;
>  	uint8_t num_neighs;
>  
> @@ -181,7 +206,7 @@ static void batadv_v_elp_send_outstanding(struct work_struct *work)
>  
>  	skb = skb_copy(hard_iface->bat_v.elp_skb, GFP_ATOMIC);
>  	if (!skb)
> -		goto out;
> +		goto update_metric;
>  
>  	/* purge outdated entries first */
>  	batadv_v_elp_neigh_purge(hard_iface);
> @@ -204,6 +229,17 @@ static void batadv_v_elp_send_outstanding(struct work_struct *work)
>  
>  	atomic_inc(&hard_iface->bat_v.elp_seqno);
>  
> +update_metric:
> +	/* Instead of updating the metric each "received" ELP packet, it is
> +	 * better to do it on each ELP sending. This way, if a node is dead and
> +	 * does not send packets anymore, batman-adv is still able to timely
> +	 * react to its death.
> +	 */
> +	rcu_read_lock();
> +	hlist_for_each_entry_rcu(neigh, &hard_iface->bat_v.neigh_list, list)
> +		ewma_add(&neigh->metric, batadv_v_elp_get_throughput(neigh));
> +	rcu_read_unlock();
> +
>  restart_timer:
>  	batadv_v_elp_start_timer(hard_iface);
>  out:
> @@ -247,7 +283,7 @@ int batadv_v_elp_iface_enable(struct batadv_hard_iface *hard_iface)
>  	atomic_set(&hard_iface->bat_v.elp_interval, 500);
>  
>  	INIT_DELAYED_WORK(&hard_iface->bat_v.elp_wq,
> -			  batadv_v_elp_send_outstanding);
> +			  batadv_v_elp_periodic_work);
>  	batadv_v_elp_start_timer(hard_iface);
>  	res = 0;
>  
> @@ -332,6 +368,7 @@ static void batadv_v_elp_neigh_update(struct batadv_priv *bat_priv,
>  
>  	neigh->last_seen = jiffies;
>  	neigh->last_recv_seqno = ntohl(elp_packet->seqno);
> +	ewma_add(&neigh->metric, batadv_v_elp_get_throughput(neigh));
>  
>  out:
>  	if (neigh)
> diff --git a/types.h b/types.h
> index 54fae29..948d5dc 100644
> --- a/types.h
> +++ b/types.h
> @@ -345,6 +345,7 @@ struct batadv_gw_node {
>   * @last_unicast_tx: when the last unicast packet has been sent to this neighbor
>   * @refcount: number of contexts the object is used
>   * @rcu: struct used for freeing in an RCU-safe manner
> + * @hard_iface: the interface where this neighbor is connected to
>   */
>  struct batadv_elp_neigh_node {
>  	struct hlist_node list;
> @@ -357,6 +358,7 @@ struct batadv_elp_neigh_node {
>  	unsigned long last_unicast_tx;
>  	atomic_t refcount;
>  	struct rcu_head rcu;
> +	struct batadv_hard_iface *hard_iface;
>  };
>  
>  /**
> -- 
> 1.8.5.3
> 

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

* Re: [B.A.T.M.A.N.] [RFC 15/23] batman-adv: ELP - send unicast ELP packets for throughput sampling
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 15/23] batman-adv: ELP - send unicast ELP packets for throughput sampling Antonio Quartulli
@ 2014-02-12  9:12   ` Andrew Lunn
  2014-02-12 12:12     ` Antonio Quartulli
  0 siblings, 1 reply; 68+ messages in thread
From: Andrew Lunn @ 2014-02-12  9:12 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking
  Cc: Antonio Quartulli

On Tue, Feb 11, 2014 at 01:48:15PM +0100, Antonio Quartulli wrote:
> From: Antonio Quartulli <antonio@open-mesh.com>
> 
> In case of a unused link, the throughput estimation will
> get stuck to the last sampled value and therefore the
> reported metric will becomes obsolete.
> 
> Send unicast ELP packets to each neighbor to trigger throughput
> sampling on unused links.

Humm, i can understand the need for this, but i really think the rate
control code should be sending the probes, not batman. What do the
wifi people say about this? Have they tried submitting patches to
them?

>  	/* Instead of updating the metric each "received" ELP packet, it is
>  	 * better to do it on each ELP sending. This way, if a node is dead and
>  	 * does not send packets anymore, batman-adv is still able to timely
>  	 * react to its death.
> +	 *
> +	 * The metric is updated by following these steps:
> +	 * 1) if the hard_iface if wifi => send a unicast ELP for
> +	 * probing/sampling to each neighbor
> +	 * 2) update the metric value of each neighbor

Might be worth pointing out here, that because of queuing, there is no
guarantee the ELP packets have been send yet and the RC estimated
bandwidth could be up to 100ms old.

> +	 *
>  	 */
>  	rcu_read_lock();
> -	hlist_for_each_entry_rcu(neigh, &hard_iface->bat_v.neigh_list, list)
> +	hlist_for_each_entry_rcu(neigh, &hard_iface->bat_v.neigh_list, list) {
> +		if (batadv_v_elp_wifi_neigh_probe(hard_iface, neigh) < 0)
> +			/* if something goes wrong while probing, better to stop
> +			 * sending packets immediately and reschedule the task
> +			 */
> +			break;
> +
>  		ewma_add(&neigh->metric, batadv_v_elp_get_throughput(neigh));
> +	}
>  	rcu_read_unlock();
>  

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

* Re: [B.A.T.M.A.N.] [RFC 15/23] batman-adv: ELP - send unicast ELP packets for throughput sampling
  2014-02-12  9:12   ` Andrew Lunn
@ 2014-02-12 12:12     ` Antonio Quartulli
  2014-02-12 12:54       ` Felix Fietkau
  0 siblings, 1 reply; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-12 12:12 UTC (permalink / raw)
  To: Andrew Lunn, The list for a Better Approach To Mobile Ad-hoc Networking
  Cc: Felix Fietkau

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

On 12/02/14 10:12, Andrew Lunn wrote:
> On Tue, Feb 11, 2014 at 01:48:15PM +0100, Antonio Quartulli wrote:
>> From: Antonio Quartulli <antonio@open-mesh.com>
>>
>> In case of a unused link, the throughput estimation will
>> get stuck to the last sampled value and therefore the
>> reported metric will becomes obsolete.
>>
>> Send unicast ELP packets to each neighbor to trigger throughput
>> sampling on unused links.
> 
> Humm, i can understand the need for this, but i really think the rate
> control code should be sending the probes, not batman. What do the
> wifi people say about this? Have they tried submitting patches to
> them?

I am CC'ing Felix so that he can give his opinion.
But last time I checked Minstrel I realised that it uses data packets to
probe rates (there is not a specific probing packet), meaning that if
there is no data packet to send, then no probing is performed.

Sending this ELP packets (when there is no unicast traffic) is a way to
trigger this mechanism in Minstrel.


> 
>>  	/* Instead of updating the metric each "received" ELP packet, it is
>>  	 * better to do it on each ELP sending. This way, if a node is dead and
>>  	 * does not send packets anymore, batman-adv is still able to timely
>>  	 * react to its death.
>> +	 *
>> +	 * The metric is updated by following these steps:
>> +	 * 1) if the hard_iface if wifi => send a unicast ELP for
>> +	 * probing/sampling to each neighbor
>> +	 * 2) update the metric value of each neighbor
> 
> Might be worth pointing out here, that because of queuing, there is no
> guarantee the ELP packets have been send yet and the RC estimated
> bandwidth could be up to 100ms old.

OK, I'll make it explicit. Actually this routine is no meant to get a
"real time estimation", also because the routing algorithm would not be
that fast to react on time.


Cheers,


-- 
Antonio Quartulli


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [B.A.T.M.A.N.] [RFC 12/23] batman-adv: add base throughput attribute
  2014-02-12  8:40   ` Andrew Lunn
@ 2014-02-12 12:20     ` Antonio Quartulli
  2014-02-13  9:36       ` Andrew Lunn
  0 siblings, 1 reply; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-12 12:20 UTC (permalink / raw)
  To: b.a.t.m.a.n

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

On 12/02/14 09:40, Andrew Lunn wrote:
> On Tue, Feb 11, 2014 at 01:48:12PM +0100, Antonio Quartulli wrote:
>> From: Antonio Quartulli <antonio@open-mesh.com>
>>
>> when batman-adv is asked to estimate/compute the throughput
>> of an interface, but it fails for whatever reason, then the
>> value in this attribute is used
>>
>> Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
>> ---
>>  bat_v.c | 3 +++
>>  main.h  | 7 +++++++
>>  sysfs.c | 7 +++++++
>>  types.h | 1 +
>>  4 files changed, 18 insertions(+)
>>
>> diff --git a/bat_v.c b/bat_v.c
>> index d5457b3..3aa42ec 100644
>> --- a/bat_v.c
>> +++ b/bat_v.c
>> @@ -75,6 +75,9 @@ static struct batadv_algo_ops batadv_batman_v __read_mostly = {
>>  
>>  int batadv_v_mesh_init(struct batadv_priv *bat_priv)
>>  {
>> +	atomic_set(&bat_priv->bat_v.base_throughput,
>> +		   BATADV_DEFAULT_BASE_THROUGHPUT);
>> +
>>  	return batadv_v_ogm_init(bat_priv);
>>  }
>>  
>> diff --git a/main.h b/main.h
>> index 47fb9ed..5699c9f 100644
>> --- a/main.h
>> +++ b/main.h
>> @@ -33,6 +33,13 @@
>>  #define BATADV_MAX_METRIC 0xFFFFFFFF
>>  #define BATADV_JITTER 20
>>  
>> +/**
>> + * BATADV_DEFAULT_BASE_THROUGHPUT - default value used as throughput for
>> + * hard_ifaces for which it is not possible to measure/estimate the real one.
>> + * Value is expressed in Mbps/10
> 
> Mbps/10 is a rather odd unit. How about just Kbps?

This is the unit used in cfg/mac80211 because most of the rates are
either in the form of XX.0Mbps of XX.YMbps (so just one decimal number
needs to be saved).
Moreover I thought that having an higher precision is not very useful
because the routing decision cannot be taken on such a fine grained value.
Actually the originator table prints the metric in Mbps (XX.YMbps).

Do you think we should really go for the Kbps? this means losing one
order of magnitude on the highest value we can store (yeah, it's large
enough right now..but in the future who knows!)

Cheers,




-- 
Antonio Quartulli


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [B.A.T.M.A.N.] [RFC 13/23] batman-adv: add last_unicast_tx to struct neigh_node_elp
  2014-02-12  8:49   ` Andrew Lunn
@ 2014-02-12 12:25     ` Antonio Quartulli
  0 siblings, 0 replies; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-12 12:25 UTC (permalink / raw)
  To: b.a.t.m.a.n

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

On 12/02/14 09:49, Andrew Lunn wrote:
> On Tue, Feb 11, 2014 at 01:48:13PM +0100, Antonio Quartulli wrote:
>> From: Antonio Quartulli <antonio@open-mesh.com>
>>
>> This timestamp registers the last time a unicast packet was
>> sent to a given neighbour
> 
> I think this changelog needs improving. 95% of the patch is about
> refactoring a send function into a unicast send and a broadcast send
> function. The counter makes up the other 5% of the patch.

Yeah I should definitely improve it. Actually the refactoring has been
done to allow batman-adv to easily save the last_unicast_tx time. But
you are right, I should explain it better.


Thanks!


-- 
Antonio Quartulli


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [B.A.T.M.A.N.] [RFC 14/23] batman-adv: ELP - compute the metric based on the estimated throughput
  2014-02-12  8:58   ` Andrew Lunn
@ 2014-02-12 12:27     ` Antonio Quartulli
  2014-02-12 15:44       ` Antonio Quartulli
  0 siblings, 1 reply; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-12 12:27 UTC (permalink / raw)
  To: b.a.t.m.a.n

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

On 12/02/14 09:58, Andrew Lunn wrote:
> On Tue, Feb 11, 2014 at 01:48:14PM +0100, Antonio Quartulli wrote:
>> From: Antonio Quartulli <antonio@open-mesh.com>
>>
>> Implement a stub get_throughput() function which returns the
>> estimated throughput towards a given neighbour.
>> Its result is then used to compute the metric value.
>>
>> The metric is updated each time a new ELP packet is sent,
>> this way it is possible to timely react to a metric
>> variation which can imply (for example) a neighbour
>> disconnection.
> 
> It is very much a style issue, but i would probably split this into
> two patches. Updating the metric at send time rather than receive
> should have nothing to do with estimated bandwidth.

Yes, to make it easier I will first move the reading at sending time and
then I'll introduce the throughput estimation.


Thanks!

-- 
Antonio Quartulli


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [B.A.T.M.A.N.] [RFC 15/23] batman-adv: ELP - send unicast ELP packets for throughput sampling
  2014-02-12 12:12     ` Antonio Quartulli
@ 2014-02-12 12:54       ` Felix Fietkau
  2014-02-12 12:56         ` Antonio Quartulli
  0 siblings, 1 reply; 68+ messages in thread
From: Felix Fietkau @ 2014-02-12 12:54 UTC (permalink / raw)
  To: Antonio Quartulli, Andrew Lunn,
	The list for a Better Approach To Mobile Ad-hoc Networking

On 2014-02-12 13:12, Antonio Quartulli wrote:
> On 12/02/14 10:12, Andrew Lunn wrote:
>> On Tue, Feb 11, 2014 at 01:48:15PM +0100, Antonio Quartulli wrote:
>>> From: Antonio Quartulli <antonio@open-mesh.com>
>>>
>>> In case of a unused link, the throughput estimation will
>>> get stuck to the last sampled value and therefore the
>>> reported metric will becomes obsolete.
>>>
>>> Send unicast ELP packets to each neighbor to trigger throughput
>>> sampling on unused links.
>> 
>> Humm, i can understand the need for this, but i really think the rate
>> control code should be sending the probes, not batman. What do the
>> wifi people say about this? Have they tried submitting patches to
>> them?
> 
> I am CC'ing Felix so that he can give his opinion.
> But last time I checked Minstrel I realised that it uses data packets to
> probe rates (there is not a specific probing packet), meaning that if
> there is no data packet to send, then no probing is performed.
Correct. Minstrel never sends dedicated probing packets. Changing
minstrel to send active probing packets to serve the needs of batman
would be a very bad idea, because pretty much all regular users do not
have any need for extra probing.

> Sending this ELP packets (when there is no unicast traffic) is a way to
> trigger this mechanism in Minstrel.
Right. If I remember correctly, if you send less than 1 packet per 100
ms, then all packets should end up being probing packets. If that
doesn't work, we can change minstrel's probing pattern to allow things
like batman to get a desirable amount of rate control probing simply by
sending unicast packets.

- Felix

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

* Re: [B.A.T.M.A.N.] [RFC 15/23] batman-adv: ELP - send unicast ELP packets for throughput sampling
  2014-02-12 12:54       ` Felix Fietkau
@ 2014-02-12 12:56         ` Antonio Quartulli
  2014-02-12 13:02           ` Antonio Quartulli
  2014-02-13  9:55           ` Andrew Lunn
  0 siblings, 2 replies; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-12 12:56 UTC (permalink / raw)
  To: b.a.t.m.a.n, Felix Fietkau, Andrew Lunn

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

On 12/02/14 13:54, Felix Fietkau wrote:
> On 2014-02-12 13:12, Antonio Quartulli wrote:
>> On 12/02/14 10:12, Andrew Lunn wrote:
>>> On Tue, Feb 11, 2014 at 01:48:15PM +0100, Antonio Quartulli wrote:
>>>> From: Antonio Quartulli <antonio@open-mesh.com>
>>>>
>>>> In case of a unused link, the throughput estimation will
>>>> get stuck to the last sampled value and therefore the
>>>> reported metric will becomes obsolete.
>>>>
>>>> Send unicast ELP packets to each neighbor to trigger throughput
>>>> sampling on unused links.
>>>
>>> Humm, i can understand the need for this, but i really think the rate
>>> control code should be sending the probes, not batman. What do the
>>> wifi people say about this? Have they tried submitting patches to
>>> them?
>>
>> I am CC'ing Felix so that he can give his opinion.
>> But last time I checked Minstrel I realised that it uses data packets to
>> probe rates (there is not a specific probing packet), meaning that if
>> there is no data packet to send, then no probing is performed.
> Correct. Minstrel never sends dedicated probing packets. Changing
> minstrel to send active probing packets to serve the needs of batman
> would be a very bad idea, because pretty much all regular users do not
> have any need for extra probing.
> 
>> Sending this ELP packets (when there is no unicast traffic) is a way to
>> trigger this mechanism in Minstrel.
> Right. If I remember correctly, if you send less than 1 packet per 100
> ms, then all packets should end up being probing packets. If that
> doesn't work, we can change minstrel's probing pattern to allow things
> like batman to get a desirable amount of rate control probing simply by
> sending unicast packets.

This is what I am trying to achieve here: if no unicast packets have
been sent for the last 100ms (at least) then send N probing packets in a
row (with N = 2 at the moment - it is a define in main.h).


Thanks Felix!

Cheers,


-- 
Antonio Quartulli


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [B.A.T.M.A.N.] [RFC 15/23] batman-adv: ELP - send unicast ELP packets for throughput sampling
  2014-02-12 12:56         ` Antonio Quartulli
@ 2014-02-12 13:02           ` Antonio Quartulli
  2014-02-13  9:55           ` Andrew Lunn
  1 sibling, 0 replies; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-12 13:02 UTC (permalink / raw)
  To: b.a.t.m.a.n, Felix Fietkau, Andrew Lunn

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

On 12/02/14 13:56, Antonio Quartulli wrote:
> On 12/02/14 13:54, Felix Fietkau wrote:
>> On 2014-02-12 13:12, Antonio Quartulli wrote:
>>> On 12/02/14 10:12, Andrew Lunn wrote:
>>>> On Tue, Feb 11, 2014 at 01:48:15PM +0100, Antonio Quartulli wrote:
>>>>> From: Antonio Quartulli <antonio@open-mesh.com>
>>>>>
>>>>> In case of a unused link, the throughput estimation will
>>>>> get stuck to the last sampled value and therefore the
>>>>> reported metric will becomes obsolete.
>>>>>
>>>>> Send unicast ELP packets to each neighbor to trigger throughput
>>>>> sampling on unused links.
>>>>
>>>> Humm, i can understand the need for this, but i really think the rate
>>>> control code should be sending the probes, not batman. What do the
>>>> wifi people say about this? Have they tried submitting patches to
>>>> them?
>>>
>>> I am CC'ing Felix so that he can give his opinion.
>>> But last time I checked Minstrel I realised that it uses data packets to
>>> probe rates (there is not a specific probing packet), meaning that if
>>> there is no data packet to send, then no probing is performed.
>> Correct. Minstrel never sends dedicated probing packets. Changing
>> minstrel to send active probing packets to serve the needs of batman
>> would be a very bad idea, because pretty much all regular users do not
>> have any need for extra probing.
>>
>>> Sending this ELP packets (when there is no unicast traffic) is a way to
>>> trigger this mechanism in Minstrel.
>> Right. If I remember correctly, if you send less than 1 packet per 100
>> ms, then all packets should end up being probing packets. If that
>> doesn't work, we can change minstrel's probing pattern to allow things
>> like batman to get a desirable amount of rate control probing simply by
>> sending unicast packets.
> 
> This is what I am trying to achieve here: if no unicast packets have
> been sent for the last 100ms (at least) then send N probing packets in a
> row (with N = 2 at the moment - it is a define in main.h).
> 

However, from the experiments performed so far it looked like Minstrel
was behaving properly under these batman probing packets.


As soon as we move on with this project I am sure we will get some more
feedback from other users (perhaps this is something we can test at the
WBM? - this code should be ready and usable by then - cross fingers)


Cheers,


-- 
Antonio Quartulli


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [B.A.T.M.A.N.] [RFC 14/23] batman-adv: ELP - compute the metric based on the estimated throughput
  2014-02-12 12:27     ` Antonio Quartulli
@ 2014-02-12 15:44       ` Antonio Quartulli
  2014-02-13  9:45         ` Andrew Lunn
  0 siblings, 1 reply; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-12 15:44 UTC (permalink / raw)
  To: b.a.t.m.a.n, Andrew Lunn

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

On 12/02/14 13:27, Antonio Quartulli wrote:
> On 12/02/14 09:58, Andrew Lunn wrote:
>> On Tue, Feb 11, 2014 at 01:48:14PM +0100, Antonio Quartulli wrote:
>>> From: Antonio Quartulli <antonio@open-mesh.com>
>>>
>>> Implement a stub get_throughput() function which returns the
>>> estimated throughput towards a given neighbour.
>>> Its result is then used to compute the metric value.
>>>
>>> The metric is updated each time a new ELP packet is sent,
>>> this way it is possible to timely react to a metric
>>> variation which can imply (for example) a neighbour
>>> disconnection.
>>
>> It is very much a style issue, but i would probably split this into
>> two patches. Updating the metric at send time rather than receive
>> should have nothing to do with estimated bandwidth.
> 
> Yes, to make it easier I will first move the reading at sending time and
> then I'll introduce the throughput estimation.
> 
> 


Andrew,

I just rechecked the code and I realised that these "2 changes" are one
only because there is no "second change".

Before this patch ELP does not perform any metric estimation.

This patch adds the estimation mechanism and in particular adds it along
the ELP message sending path.


Maybe this was not clear? Maybe some previous patch gave you the
impression that a sort of metric estimation was already performed in the
receiving routine?


Cheers,

-- 
Antonio Quartulli


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [B.A.T.M.A.N.] [RFC 18/23] batman-adv: ELP - use phydev to determine link characteristics
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 18/23] batman-adv: ELP - use phydev to determine link characteristics Antonio Quartulli
@ 2014-02-13  8:17   ` Antonio Quartulli
  2014-02-13  8:19     ` Antonio Quartulli
  2014-02-13 10:52   ` Andrew Lunn
  1 sibling, 1 reply; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-13  8:17 UTC (permalink / raw)
  To: b.a.t.m.a.n

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

On 11/02/14 13:48, Antonio Quartulli wrote:
> @@ -297,6 +299,7 @@ void batadv_update_min_mtu(struct net_device *soft_iface)
>  static void
>  batadv_hardif_activate_interface(struct batadv_hard_iface *hard_iface)
>  {
> +	struct net_device *dev = hard_iface->net_dev;
>  	struct batadv_priv *bat_priv;
>  	struct batadv_hard_iface *primary_if = NULL;
>  
> @@ -315,6 +318,22 @@ batadv_hardif_activate_interface(struct batadv_hard_iface *hard_iface)
>  	if (!primary_if)
>  		batadv_primary_if_select(bat_priv, hard_iface);
>  
> +	/* set the default values */
> +	hard_iface->bat_v.flags &= ~BATADV_FULL_DUPLEX;
> +	hard_iface->bat_v.eth_throughput = 0;
> +	if (dev->phydev) {
> +		if (dev->phydev->duplex == DUPLEX_FULL)
> +			hard_iface->bat_v.flags |= BATADV_FULL_DUPLEX;
> +
> +		/* set the speed according to the phydev setting. Store the
> +		 * value in Kbps (as done for the other throughput variables)
> +		 */
> +		if (dev->phydev->speed != SPEED_UNKNOWN) {
> +			hard_iface->bat_v.eth_throughput = dev->phydev->speed;
> +			hard_iface->bat_v.eth_throughput *= 10;
> +		}
> +	}
> +

For the record: I just moved this chunk into a proper
bat_algo_ops->bat_iface_activate() API.

This initialisation is obviously B.A.T.M.A.N. V specific and cannot live
in the batadv_hardif_activate_interface() function.


Cheers,


-- 
Antonio Quartulli


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [B.A.T.M.A.N.] [RFC 18/23] batman-adv: ELP - use phydev to determine link characteristics
  2014-02-13  8:17   ` Antonio Quartulli
@ 2014-02-13  8:19     ` Antonio Quartulli
  0 siblings, 0 replies; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-13  8:19 UTC (permalink / raw)
  To: b.a.t.m.a.n

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

On 13/02/14 09:17, Antonio Quartulli wrote:
> On 11/02/14 13:48, Antonio Quartulli wrote:
>> @@ -297,6 +299,7 @@ void batadv_update_min_mtu(struct net_device *soft_iface)
>>  static void
>>  batadv_hardif_activate_interface(struct batadv_hard_iface *hard_iface)
>>  {
>> +	struct net_device *dev = hard_iface->net_dev;
>>  	struct batadv_priv *bat_priv;
>>  	struct batadv_hard_iface *primary_if = NULL;
>>  
>> @@ -315,6 +318,22 @@ batadv_hardif_activate_interface(struct batadv_hard_iface *hard_iface)
>>  	if (!primary_if)
>>  		batadv_primary_if_select(bat_priv, hard_iface);
>>  
>> +	/* set the default values */
>> +	hard_iface->bat_v.flags &= ~BATADV_FULL_DUPLEX;
>> +	hard_iface->bat_v.eth_throughput = 0;
>> +	if (dev->phydev) {
>> +		if (dev->phydev->duplex == DUPLEX_FULL)
>> +			hard_iface->bat_v.flags |= BATADV_FULL_DUPLEX;
>> +
>> +		/* set the speed according to the phydev setting. Store the
>> +		 * value in Kbps (as done for the other throughput variables)
>> +		 */

And of course this is not Kbps but Mbps/10 (like everywhere else)..


>> +		if (dev->phydev->speed != SPEED_UNKNOWN) {
>> +			hard_iface->bat_v.eth_throughput = dev->phydev->speed;
>> +			hard_iface->bat_v.eth_throughput *= 10;
>> +		}
>> +	}
>> +
> 
> For the record: I just moved this chunk into a proper
> bat_algo_ops->bat_iface_activate() API.
> 
> This initialisation is obviously B.A.T.M.A.N. V specific and cannot live
> in the batadv_hardif_activate_interface() function.
> 
> 
> Cheers,
> 
> 


-- 
Antonio Quartulli


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [B.A.T.M.A.N.] [RFC 12/23] batman-adv: add base throughput attribute
  2014-02-12 12:20     ` Antonio Quartulli
@ 2014-02-13  9:36       ` Andrew Lunn
  2014-02-13  9:53         ` Antonio Quartulli
  0 siblings, 1 reply; 68+ messages in thread
From: Andrew Lunn @ 2014-02-13  9:36 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

On Wed, Feb 12, 2014 at 01:20:17PM +0100, Antonio Quartulli wrote:
> On 12/02/14 09:40, Andrew Lunn wrote:
> > On Tue, Feb 11, 2014 at 01:48:12PM +0100, Antonio Quartulli wrote:
> >> From: Antonio Quartulli <antonio@open-mesh.com>
> >>
> >> when batman-adv is asked to estimate/compute the throughput
> >> of an interface, but it fails for whatever reason, then the
> >> value in this attribute is used
> >>
> >> Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
> >> ---
> >>  bat_v.c | 3 +++
> >>  main.h  | 7 +++++++
> >>  sysfs.c | 7 +++++++
> >>  types.h | 1 +
> >>  4 files changed, 18 insertions(+)
> >>
> >> diff --git a/bat_v.c b/bat_v.c
> >> index d5457b3..3aa42ec 100644
> >> --- a/bat_v.c
> >> +++ b/bat_v.c
> >> @@ -75,6 +75,9 @@ static struct batadv_algo_ops batadv_batman_v __read_mostly = {
> >>  
> >>  int batadv_v_mesh_init(struct batadv_priv *bat_priv)
> >>  {
> >> +	atomic_set(&bat_priv->bat_v.base_throughput,
> >> +		   BATADV_DEFAULT_BASE_THROUGHPUT);
> >> +
> >>  	return batadv_v_ogm_init(bat_priv);
> >>  }
> >>  
> >> diff --git a/main.h b/main.h
> >> index 47fb9ed..5699c9f 100644
> >> --- a/main.h
> >> +++ b/main.h
> >> @@ -33,6 +33,13 @@
> >>  #define BATADV_MAX_METRIC 0xFFFFFFFF
> >>  #define BATADV_JITTER 20
> >>  
> >> +/**
> >> + * BATADV_DEFAULT_BASE_THROUGHPUT - default value used as throughput for
> >> + * hard_ifaces for which it is not possible to measure/estimate the real one.
> >> + * Value is expressed in Mbps/10
> > 
> > Mbps/10 is a rather odd unit. How about just Kbps?
> 
> This is the unit used in cfg/mac80211 because most of the rates are
> either in the form of XX.0Mbps of XX.YMbps (so just one decimal number
> needs to be saved).
> Moreover I thought that having an higher precision is not very useful
> because the routing decision cannot be taken on such a fine grained value.
> Actually the originator table prints the metric in Mbps (XX.YMbps).

It is not precision which i think is important, it is having a unit a
user expects. Networking people work in Kbps, or MBps. If it is
printed in the originator table as XX.YMBps, then i think this sysfs
file also needs to be XX.YMBps. That does however make your parsing
more complex, since it is no longer an int. I suppose there is the use
case of an ADSL link, with bandwidth of say 2Mbps down, 256Kbps up,
and then you do need the decimal point in XX.YMBps.

    Andrew

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

* Re: [B.A.T.M.A.N.] [RFC 14/23] batman-adv: ELP - compute the metric based on the estimated throughput
  2014-02-12 15:44       ` Antonio Quartulli
@ 2014-02-13  9:45         ` Andrew Lunn
  2014-02-13  9:46           ` Antonio Quartulli
  0 siblings, 1 reply; 68+ messages in thread
From: Andrew Lunn @ 2014-02-13  9:45 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

On Wed, Feb 12, 2014 at 04:44:18PM +0100, Antonio Quartulli wrote:
> On 12/02/14 13:27, Antonio Quartulli wrote:
> > On 12/02/14 09:58, Andrew Lunn wrote:
> >> On Tue, Feb 11, 2014 at 01:48:14PM +0100, Antonio Quartulli wrote:
> >>> From: Antonio Quartulli <antonio@open-mesh.com>
> >>>
> >>> Implement a stub get_throughput() function which returns the
> >>> estimated throughput towards a given neighbour.
> >>> Its result is then used to compute the metric value.
> >>>
> >>> The metric is updated each time a new ELP packet is sent,
> >>> this way it is possible to timely react to a metric
> >>> variation which can imply (for example) a neighbour
> >>> disconnection.
> >>
> >> It is very much a style issue, but i would probably split this into
> >> two patches. Updating the metric at send time rather than receive
> >> should have nothing to do with estimated bandwidth.
> > 
> > Yes, to make it easier I will first move the reading at sending time and
> > then I'll introduce the throughput estimation.
> > 
> > 
> 
> 
> Andrew,
> 
> I just rechecked the code and I realised that these "2 changes" are one
> only because there is no "second change".
> 
> Before this patch ELP does not perform any metric estimation.
> 
> This patch adds the estimation mechanism and in particular adds it along
> the ELP message sending path.
> 
> 
> Maybe this was not clear? Maybe some previous patch gave you the
> impression that a sort of metric estimation was already performed in the
> receiving routine?

Ah, ok, it was this comment which confused me:

+       /* Instead of updating the metric each "received" ELP packet, it is
+        * better to do it on each ELP sending. This way, if a node is dead and
+        * does not send packets anymore, batman-adv is still able to timely
+        * react to its death.

The "instead of" suggests it was previously done differently. The
BATMAN philosophy has been in the past to react on received packets,
so i can understand where this came from. But i think this comment
could be worded:

/* The metric is updated on each sent packet.  This way, if a node is
* dead and no longer sends packets, batman-adv is still able to 
* react timely to its death. */

  Andrew

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

* Re: [B.A.T.M.A.N.] [RFC 14/23] batman-adv: ELP - compute the metric based on the estimated throughput
  2014-02-13  9:45         ` Andrew Lunn
@ 2014-02-13  9:46           ` Antonio Quartulli
  0 siblings, 0 replies; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-13  9:46 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

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

On 13/02/14 10:45, Andrew Lunn wrote:
> On Wed, Feb 12, 2014 at 04:44:18PM +0100, Antonio Quartulli wrote:
>> On 12/02/14 13:27, Antonio Quartulli wrote:
>>> On 12/02/14 09:58, Andrew Lunn wrote:
>>>> On Tue, Feb 11, 2014 at 01:48:14PM +0100, Antonio Quartulli wrote:
>>>>> From: Antonio Quartulli <antonio@open-mesh.com>
>>>>>
>>>>> Implement a stub get_throughput() function which returns the
>>>>> estimated throughput towards a given neighbour.
>>>>> Its result is then used to compute the metric value.
>>>>>
>>>>> The metric is updated each time a new ELP packet is sent,
>>>>> this way it is possible to timely react to a metric
>>>>> variation which can imply (for example) a neighbour
>>>>> disconnection.
>>>>
>>>> It is very much a style issue, but i would probably split this into
>>>> two patches. Updating the metric at send time rather than receive
>>>> should have nothing to do with estimated bandwidth.
>>>
>>> Yes, to make it easier I will first move the reading at sending time and
>>> then I'll introduce the throughput estimation.
>>>
>>>
>>
>>
>> Andrew,
>>
>> I just rechecked the code and I realised that these "2 changes" are one
>> only because there is no "second change".
>>
>> Before this patch ELP does not perform any metric estimation.
>>
>> This patch adds the estimation mechanism and in particular adds it along
>> the ELP message sending path.
>>
>>
>> Maybe this was not clear? Maybe some previous patch gave you the
>> impression that a sort of metric estimation was already performed in the
>> receiving routine?
> 
> Ah, ok, it was this comment which confused me:
> 
> +       /* Instead of updating the metric each "received" ELP packet, it is
> +        * better to do it on each ELP sending. This way, if a node is dead and
> +        * does not send packets anymore, batman-adv is still able to timely
> +        * react to its death.
> 

Yeah...it is a refusal from a previous approach that has been changed
during the development phase, but of course I forgot to reword the comment.

> The "instead of" suggests it was previously done differently. The
> BATMAN philosophy has been in the past to react on received packets,
> so i can understand where this came from. But i think this comment
> could be worded:
> 
> /* The metric is updated on each sent packet.  This way, if a node is
> * dead and no longer sends packets, batman-adv is still able to 
> * react timely to its death. */

Thanks for the suggestion!


Cheers,

-- 
Antonio Quartulli


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [B.A.T.M.A.N.] [RFC 12/23] batman-adv: add base throughput attribute
  2014-02-13  9:36       ` Andrew Lunn
@ 2014-02-13  9:53         ` Antonio Quartulli
  2014-02-13  9:57           ` Andrew Lunn
  0 siblings, 1 reply; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-13  9:53 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking, Andrew Lunn

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

On 13/02/14 10:36, Andrew Lunn wrote:
>>>> +/**
>>>> + * BATADV_DEFAULT_BASE_THROUGHPUT - default value used as throughput for
>>>> + * hard_ifaces for which it is not possible to measure/estimate the real one.
>>>> + * Value is expressed in Mbps/10
>>>
>>> Mbps/10 is a rather odd unit. How about just Kbps?
>>
>> This is the unit used in cfg/mac80211 because most of the rates are
>> either in the form of XX.0Mbps of XX.YMbps (so just one decimal number
>> needs to be saved).
>> Moreover I thought that having an higher precision is not very useful
>> because the routing decision cannot be taken on such a fine grained value.
>> Actually the originator table prints the metric in Mbps (XX.YMbps).
> 
> It is not precision which i think is important, it is having a unit a
> user expects. Networking people work in Kbps, or MBps. If it is
> printed in the originator table as XX.YMBps, then i think this sysfs
> file also needs to be XX.YMBps. That does however make your parsing
> more complex, since it is no longer an int. I suppose there is the use
> case of an ADSL link, with bandwidth of say 2Mbps down, 256Kbps up,
> and then you do need the decimal point in XX.YMBps.

I just checked what we do in the "improved GW bandwidth advertisement"
introduced not so much time ago:

- we store the bandwidth value in Mbps/10
- we print it in the form XX.YMbps
+ but we allow the user to specify the unit when entering the value in
the sysfs interface: "xxxMbps" or "yyyKbps".

This way the user can pick the favourite unit, but of course the value
is truncated (in the case of Kbps) to fit the internal representation.

What do you think about this approach?
I also think we have to keep the two consistent with each other (it
would allow me to re-use the same parsing function).


Cheers,


-- 
Antonio Quartulli


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [B.A.T.M.A.N.] [RFC 15/23] batman-adv: ELP - send unicast ELP packets for throughput sampling
  2014-02-12 12:56         ` Antonio Quartulli
  2014-02-12 13:02           ` Antonio Quartulli
@ 2014-02-13  9:55           ` Andrew Lunn
  2014-02-13 10:02             ` Antonio Quartulli
  1 sibling, 1 reply; 68+ messages in thread
From: Andrew Lunn @ 2014-02-13  9:55 UTC (permalink / raw)
  To: Antonio Quartulli; +Cc: Felix Fietkau, b.a.t.m.a.n

> > Right. If I remember correctly, if you send less than 1 packet per 100
> > ms, then all packets should end up being probing packets. If that
> > doesn't work, we can change minstrel's probing pattern to allow things
> > like batman to get a desirable amount of rate control probing simply by
> > sending unicast packets.
> 
> This is what I am trying to achieve here: if no unicast packets have
> been sent for the last 100ms (at least) then send N probing packets in a
> row (with N = 2 at the moment - it is a define in main.h).

Hi Antonio

One minor thing to consider is that your statement is actually:

if no _batman_ unicast packets have been sent for the last 100ms ...

I've used batman in setups where it has not been the exclusive user of
the hard interface. So there could be other traffic which is keeping
the RC algorithm up to date. So maybe it would be better to use the
hard interface statistic counters rather than last time batman sent a
packet?

	Andrew

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

* Re: [B.A.T.M.A.N.] [RFC 12/23] batman-adv: add base throughput attribute
  2014-02-13  9:53         ` Antonio Quartulli
@ 2014-02-13  9:57           ` Andrew Lunn
  0 siblings, 0 replies; 68+ messages in thread
From: Andrew Lunn @ 2014-02-13  9:57 UTC (permalink / raw)
  To: Antonio Quartulli
  Cc: The list for a Better Approach To Mobile Ad-hoc Networking

> I just checked what we do in the "improved GW bandwidth advertisement"
> introduced not so much time ago:
> 
> - we store the bandwidth value in Mbps/10
> - we print it in the form XX.YMbps
> + but we allow the user to specify the unit when entering the value in
> the sysfs interface: "xxxMbps" or "yyyKbps".
> 
> This way the user can pick the favourite unit, but of course the value
> is truncated (in the case of Kbps) to fit the internal representation.
> 
> What do you think about this approach?

I think that is good.

Thanks
	Andrew

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

* Re: [B.A.T.M.A.N.] [RFC 15/23] batman-adv: ELP - send unicast ELP packets for throughput sampling
  2014-02-13  9:55           ` Andrew Lunn
@ 2014-02-13 10:02             ` Antonio Quartulli
  2014-02-13 10:09               ` Andrew Lunn
  0 siblings, 1 reply; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-13 10:02 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking; +Cc: Felix Fietkau

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

On 13/02/14 10:55, Andrew Lunn wrote:
>>> Right. If I remember correctly, if you send less than 1 packet per 100
>>> ms, then all packets should end up being probing packets. If that
>>> doesn't work, we can change minstrel's probing pattern to allow things
>>> like batman to get a desirable amount of rate control probing simply by
>>> sending unicast packets.
>>
>> This is what I am trying to achieve here: if no unicast packets have
>> been sent for the last 100ms (at least) then send N probing packets in a
>> row (with N = 2 at the moment - it is a define in main.h).
> 
> Hi Antonio
> 
> One minor thing to consider is that your statement is actually:
> 
> if no _batman_ unicast packets have been sent for the last 100ms ...
> 
> I've used batman in setups where it has not been the exclusive user of
> the hard interface. So there could be other traffic which is keeping
> the RC algorithm up to date. So maybe it would be better to use the
> hard interface statistic counters rather than last time batman sent a
> packet?

We can't use the hard_iface statistics because we need to know where
that traffic has been sent to.
The same interface might connected to several neighbours and the rates
are selected/probed on a per-peer base.

However, to go in the direction that you are suggesting, I could use the
same API I use to read the throughput (cfg80211_get_station()) to also
read when the last packet was sent to a given peer.
This information should be good for our purposes, but it means that we
probe the neighbours right after having read the throughput.

This should not be a problem because as we said in a previous email we
do not require real time throughput updates.


Cheers,


-- 
Antonio Quartulli


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [B.A.T.M.A.N.] [RFC 15/23] batman-adv: ELP - send unicast ELP packets for throughput sampling
  2014-02-13 10:02             ` Antonio Quartulli
@ 2014-02-13 10:09               ` Andrew Lunn
  2014-02-13 10:13                 ` Antonio Quartulli
  0 siblings, 1 reply; 68+ messages in thread
From: Andrew Lunn @ 2014-02-13 10:09 UTC (permalink / raw)
  To: Antonio Quartulli
  Cc: Felix Fietkau,
	The list for a Better Approach To Mobile Ad-hoc Networking

> We can't use the hard_iface statistics because we need to know where
> that traffic has been sent to.

Oh, yes, my error.

> However, to go in the direction that you are suggesting, I could use the
> same API I use to read the throughput (cfg80211_get_station()) to also
> read when the last packet was sent to a given peer.
> This information should be good for our purposes, but it means that we
> probe the neighbours right after having read the throughput.

My guess is, there are not many use cases where the hard interface is
used for other traffic as well as BATMAN. So i don't see it as being a
big issue. Maybe put it onto a TODO list once the code has been
merged, to swap to using statistics from lower down in the stack.

   Andrew

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

* Re: [B.A.T.M.A.N.] [RFC 15/23] batman-adv: ELP - send unicast ELP packets for throughput sampling
  2014-02-13 10:09               ` Andrew Lunn
@ 2014-02-13 10:13                 ` Antonio Quartulli
  0 siblings, 0 replies; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-13 10:13 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Felix Fietkau,
	The list for a Better Approach To Mobile Ad-hoc Networking

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

On 13/02/14 11:09, Andrew Lunn wrote:
>> We can't use the hard_iface statistics because we need to know where
>> that traffic has been sent to.
> 
> Oh, yes, my error.
> 
>> However, to go in the direction that you are suggesting, I could use the
>> same API I use to read the throughput (cfg80211_get_station()) to also
>> read when the last packet was sent to a given peer.
>> This information should be good for our purposes, but it means that we
>> probe the neighbours right after having read the throughput.
> 
> My guess is, there are not many use cases where the hard interface is
> used for other traffic as well as BATMAN. So i don't see it as being a
> big issue. Maybe put it onto a TODO list once the code has been
> merged, to swap to using statistics from lower down in the stack.
> 

Yes, note taken ;)

Thanks!


-- 
Antonio Quartulli


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [B.A.T.M.A.N.] [RFC 18/23] batman-adv: ELP - use phydev to determine link characteristics
  2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 18/23] batman-adv: ELP - use phydev to determine link characteristics Antonio Quartulli
  2014-02-13  8:17   ` Antonio Quartulli
@ 2014-02-13 10:52   ` Andrew Lunn
  2014-02-13 11:02     ` Antonio Quartulli
  1 sibling, 1 reply; 68+ messages in thread
From: Andrew Lunn @ 2014-02-13 10:52 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking
  Cc: Antonio Quartulli

On Tue, Feb 11, 2014 at 01:48:18PM +0100, Antonio Quartulli wrote:
> From: Antonio Quartulli <antonio@open-mesh.com>
> 
> The phydev member of a net_device can be used to get
> information about an ethernet link like HALF/FULL_DUPLEX
> and advertised bandwidth (e.g. 100/10Mbps).
> 
> This information are then stored in the hard_iface object
> to be used during the metric computation routine.
> 
> Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
> ---
>  bat_v_elp.c      |  8 ++++++++
>  bat_v_ogm.c      |  4 ++--
>  hard-interface.c | 19 +++++++++++++++++++
>  types.h          | 12 ++++++++++++
>  4 files changed, 41 insertions(+), 2 deletions(-)
> 
> diff --git a/bat_v_elp.c b/bat_v_elp.c
> index 763113e..958843c 100644
> --- a/bat_v_elp.c
> +++ b/bat_v_elp.c
> @@ -78,6 +78,14 @@ batadv_v_elp_get_throughput(struct batadv_elp_neigh_node *neigh)
>  	if (throughput != 0)
>  		return throughput;
>  
> +	/* In case of Ethernet interface, the throughput has already been
> +	 * obtained from the phydev object in the net_device struct (see
> +	 * batadv_hardif_activate_interface()). So return this value.
> +	 */
> +	throughput = hard_iface->bat_v.eth_throughput;
> +	if (throughput != 0)
> +		return throughput;
> +
>  	/* if this is a wireless device, then ask its throughput through
>  	 * cfg80211 API
>  	 */
> diff --git a/bat_v_ogm.c b/bat_v_ogm.c
> index fa3d1a1..060ce80 100644
> --- a/bat_v_ogm.c
> +++ b/bat_v_ogm.c
> @@ -393,8 +393,8 @@ static uint32_t batadv_v_penalty(struct batadv_priv *bat_priv,
>  	/* proportion to use the same value used in batman iv (x * 128 / 256) */
>  	hop_penalty = hop_penalty * 100 / 255;
>  
> -	if (batadv_is_wifi_netdev(if_incoming->net_dev) &&
> -	    metric > link_metric / 10)
> +	if ((if_incoming->bat_v.flags & BATADV_FULL_DUPLEX) &&
> +	    (metric > link_metric / 10))
>  		return metric / 2;
>  
>  	return metric * (100 - hop_penalty) / 100;
> diff --git a/hard-interface.c b/hard-interface.c
> index 2a04130..58c8669 100644
> --- a/hard-interface.c
> +++ b/hard-interface.c
> @@ -31,6 +31,8 @@
>  
>  #include <linux/if_arp.h>
>  #include <linux/if_ether.h>
> +#include <linux/netdevice.h>
> +#include <linux/phy.h>
>  
>  void batadv_hardif_free_rcu(struct rcu_head *rcu)
>  {
> @@ -297,6 +299,7 @@ void batadv_update_min_mtu(struct net_device *soft_iface)
>  static void
>  batadv_hardif_activate_interface(struct batadv_hard_iface *hard_iface)
>  {
> +	struct net_device *dev = hard_iface->net_dev;
>  	struct batadv_priv *bat_priv;
>  	struct batadv_hard_iface *primary_if = NULL;
>  
> @@ -315,6 +318,22 @@ batadv_hardif_activate_interface(struct batadv_hard_iface *hard_iface)
>  	if (!primary_if)
>  		batadv_primary_if_select(bat_priv, hard_iface);
>  
> +	/* set the default values */
> +	hard_iface->bat_v.flags &= ~BATADV_FULL_DUPLEX;
> +	hard_iface->bat_v.eth_throughput = 0;
> +	if (dev->phydev) {
> +		if (dev->phydev->duplex == DUPLEX_FULL)
> +			hard_iface->bat_v.flags |= BATADV_FULL_DUPLEX;
> +
> +		/* set the speed according to the phydev setting. Store the
> +		 * value in Kbps (as done for the other throughput variables)
> +		 */
> +		if (dev->phydev->speed != SPEED_UNKNOWN) {
> +			hard_iface->bat_v.eth_throughput = dev->phydev->speed;
> +			hard_iface->bat_v.eth_throughput *= 10;
> +		}
> +	}
> +

Hi Antonio

If i'm reading this correctly, you get the bandwidth once when the
interface is added to bat0? Are we sure that auto-negotiation has
finished? It can take a few seconds to complete after the interface is
brought up. It would not be good to have batman use 10Mbps/Half Duplex
on my gigabit links...

Is there a notification mechanism which could be used to keep these
values up to date? Or is that in a patch i have not yet got to?

       Andrew

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

* Re: [B.A.T.M.A.N.] [RFC 18/23] batman-adv: ELP - use phydev to determine link characteristics
  2014-02-13 10:52   ` Andrew Lunn
@ 2014-02-13 11:02     ` Antonio Quartulli
  2014-02-13 11:44       ` Andrew Lunn
  0 siblings, 1 reply; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-13 11:02 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking, Andrew Lunn

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

On 13/02/14 11:52, Andrew Lunn wrote:
> On Tue, Feb 11, 2014 at 01:48:18PM +0100, Antonio Quartulli wrote:
>> From: Antonio Quartulli <antonio@open-mesh.com>
>>
>> The phydev member of a net_device can be used to get
>> information about an ethernet link like HALF/FULL_DUPLEX
>> and advertised bandwidth (e.g. 100/10Mbps).
>>
>> This information are then stored in the hard_iface object
>> to be used during the metric computation routine.
>>
>> Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
>> ---
>>  bat_v_elp.c      |  8 ++++++++
>>  bat_v_ogm.c      |  4 ++--
>>  hard-interface.c | 19 +++++++++++++++++++
>>  types.h          | 12 ++++++++++++
>>  4 files changed, 41 insertions(+), 2 deletions(-)
>>
>> diff --git a/bat_v_elp.c b/bat_v_elp.c
>> index 763113e..958843c 100644
>> --- a/bat_v_elp.c
>> +++ b/bat_v_elp.c
>> @@ -78,6 +78,14 @@ batadv_v_elp_get_throughput(struct batadv_elp_neigh_node *neigh)
>>  	if (throughput != 0)
>>  		return throughput;
>>  
>> +	/* In case of Ethernet interface, the throughput has already been
>> +	 * obtained from the phydev object in the net_device struct (see
>> +	 * batadv_hardif_activate_interface()). So return this value.
>> +	 */
>> +	throughput = hard_iface->bat_v.eth_throughput;
>> +	if (throughput != 0)
>> +		return throughput;
>> +
>>  	/* if this is a wireless device, then ask its throughput through
>>  	 * cfg80211 API
>>  	 */
>> diff --git a/bat_v_ogm.c b/bat_v_ogm.c
>> index fa3d1a1..060ce80 100644
>> --- a/bat_v_ogm.c
>> +++ b/bat_v_ogm.c
>> @@ -393,8 +393,8 @@ static uint32_t batadv_v_penalty(struct batadv_priv *bat_priv,
>>  	/* proportion to use the same value used in batman iv (x * 128 / 256) */
>>  	hop_penalty = hop_penalty * 100 / 255;
>>  
>> -	if (batadv_is_wifi_netdev(if_incoming->net_dev) &&
>> -	    metric > link_metric / 10)
>> +	if ((if_incoming->bat_v.flags & BATADV_FULL_DUPLEX) &&
>> +	    (metric > link_metric / 10))
>>  		return metric / 2;
>>  
>>  	return metric * (100 - hop_penalty) / 100;
>> diff --git a/hard-interface.c b/hard-interface.c
>> index 2a04130..58c8669 100644
>> --- a/hard-interface.c
>> +++ b/hard-interface.c
>> @@ -31,6 +31,8 @@
>>  
>>  #include <linux/if_arp.h>
>>  #include <linux/if_ether.h>
>> +#include <linux/netdevice.h>
>> +#include <linux/phy.h>
>>  
>>  void batadv_hardif_free_rcu(struct rcu_head *rcu)
>>  {
>> @@ -297,6 +299,7 @@ void batadv_update_min_mtu(struct net_device *soft_iface)
>>  static void
>>  batadv_hardif_activate_interface(struct batadv_hard_iface *hard_iface)
>>  {
>> +	struct net_device *dev = hard_iface->net_dev;
>>  	struct batadv_priv *bat_priv;
>>  	struct batadv_hard_iface *primary_if = NULL;
>>  
>> @@ -315,6 +318,22 @@ batadv_hardif_activate_interface(struct batadv_hard_iface *hard_iface)
>>  	if (!primary_if)
>>  		batadv_primary_if_select(bat_priv, hard_iface);
>>  
>> +	/* set the default values */
>> +	hard_iface->bat_v.flags &= ~BATADV_FULL_DUPLEX;
>> +	hard_iface->bat_v.eth_throughput = 0;
>> +	if (dev->phydev) {
>> +		if (dev->phydev->duplex == DUPLEX_FULL)
>> +			hard_iface->bat_v.flags |= BATADV_FULL_DUPLEX;
>> +
>> +		/* set the speed according to the phydev setting. Store the
>> +		 * value in Kbps (as done for the other throughput variables)
>> +		 */
>> +		if (dev->phydev->speed != SPEED_UNKNOWN) {
>> +			hard_iface->bat_v.eth_throughput = dev->phydev->speed;
>> +			hard_iface->bat_v.eth_throughput *= 10;
>> +		}
>> +	}
>> +
> 
> Hi Antonio
> 
> If i'm reading this correctly, you get the bandwidth once when the
> interface is added to bat0? 

it is invoked every time the interface is brought up. So if you
disconnect and then reconnect the cable (e.g. to connect the NIC to a
faster switch) this function is invoked again and the bandwidth is updated.

> Are we sure that auto-negotiation has
> finished? It can take a few seconds to complete after the interface is
> brought up. It would not be good to have batman use 10Mbps/Half Duplex
> on my gigabit links...

So it can take up to "few" seconds? I did not expect such a delay!

However this function if invoked when the NETDEV_UP event is issued by
the underlying system. I expect the event to be thrown when the
interface is ready to be used, not when the auto-negotiatin is still
going on. I will double check.

> 
> Is there a notification mechanism which could be used to keep these
> values up to date? Or is that in a patch i have not yet got to.

No there is no notification mechanism.

I see only two ways of changing this value at runtime:

1) NIC disconnected and re-connected to a different "thing" -> NETDEV_UP
is issued, we re-read the values

2) the user manually changes the bandwidth (e.g. using ethtool) -> not
handled right now (I would also not consider it a high priority item),
but maybe the NETDEV_CHANGE event is fired up in this case?


Cheers,

-- 
Antonio Quartulli


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [B.A.T.M.A.N.] [RFC 18/23] batman-adv: ELP - use phydev to determine link characteristics
  2014-02-13 11:02     ` Antonio Quartulli
@ 2014-02-13 11:44       ` Andrew Lunn
  2014-02-14  8:24         ` Antonio Quartulli
  0 siblings, 1 reply; 68+ messages in thread
From: Andrew Lunn @ 2014-02-13 11:44 UTC (permalink / raw)
  To: Antonio Quartulli
  Cc: The list for a Better Approach To Mobile Ad-hoc Networking

> it is invoked every time the interface is brought up. So if you
> disconnect and then reconnect the cable (e.g. to connect the NIC to a
> faster switch) this function is invoked again and the bandwidth is updated.
> 
> > Are we sure that auto-negotiation has
> > finished? It can take a few seconds to complete after the interface is
> > brought up. It would not be good to have batman use 10Mbps/Half Duplex
> > on my gigabit links...
> 
> So it can take up to "few" seconds? I did not expect such a delay!

It varies a lot between devices. I have a NAS box which i use for
kernel hacking. I TFTP boot the kernel, using u-boot configuration
variables. I found that for a cold boot it works great, but a warm
boot seems to be faster and the TFTP GET command is sent while the phy
is still auto-negotiating, and it gets lost. This then triggers a bug
in u-boot, it never re-transmits the GET command, and then whole TFTP
boot times out eventually.

So i'm just cautious about making assumptions here, especially
assumptions which might be mostly true, but in some odd edge case turn
out to be false.

> However this function if invoked when the NETDEV_UP event is issued by
> the underlying system. I expect the event to be thrown when the
> interface is ready to be used, not when the auto-negotiatin is still
> going on. I will double check.

I had a quick look at the code. It seems like NETDEV_UP is issued
directly after the device is opened. There does not seem to be any
waiting around for auto-neg.

	Andrew

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

* Re: [B.A.T.M.A.N.] [RFC 18/23] batman-adv: ELP - use phydev to determine link characteristics
  2014-02-13 11:44       ` Andrew Lunn
@ 2014-02-14  8:24         ` Antonio Quartulli
  2014-02-14 17:38           ` Andrew Lunn
  0 siblings, 1 reply; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-14  8:24 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking, Andrew Lunn

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

On 13/02/14 12:44, Andrew Lunn wrote:
>> it is invoked every time the interface is brought up. So if you
>> disconnect and then reconnect the cable (e.g. to connect the NIC to a
>> faster switch) this function is invoked again and the bandwidth is updated.
>>
>>> Are we sure that auto-negotiation has
>>> finished? It can take a few seconds to complete after the interface is
>>> brought up. It would not be good to have batman use 10Mbps/Half Duplex
>>> on my gigabit links...
>>
>> So it can take up to "few" seconds? I did not expect such a delay!
> 
> It varies a lot between devices. I have a NAS box which i use for
> kernel hacking. I TFTP boot the kernel, using u-boot configuration
> variables. I found that for a cold boot it works great, but a warm
> boot seems to be faster and the TFTP GET command is sent while the phy
> is still auto-negotiating, and it gets lost. This then triggers a bug
> in u-boot, it never re-transmits the GET command, and then whole TFTP
> boot times out eventually.
> 
> So i'm just cautious about making assumptions here, especially
> assumptions which might be mostly true, but in some odd edge case turn
> out to be false.
> 
>> However this function if invoked when the NETDEV_UP event is issued by
>> the underlying system. I expect the event to be thrown when the
>> interface is ready to be used, not when the auto-negotiatin is still
>> going on. I will double check.
> 
> I had a quick look at the code. It seems like NETDEV_UP is issued
> directly after the device is opened. There does not seem to be any
> waiting around for auto-neg.


Hi Andrew,

This morning I've been trying to dig into the tg3 Ethernet driver to get
an idea of what happens before the NETDEV_UP event is fired.

The network stack invokes the ndo_open() callback implemented by the
driver and, as far as I can see, this function does not return until
having set speed and half/full_duplex state.
Thus it looks like that when NETDEV_UP is fired the speed and the
full_duplex attribute have already a meaningful value.

Of course this may vary depending on the driver, so this may not be the
case everywhere.

I think that we can keep this approach for now and then perform some
tests on a couple of platforms before merging the code.
This way we should be "sure" about this particular behaviour.

I think that your NAS might also be a good testing platform, assuming
that the owner is willing to insmod batman-adv on that machine :-)



Cheers,

-- 
Antonio Quartulli


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [B.A.T.M.A.N.] [RFC 18/23] batman-adv: ELP - use phydev to determine link characteristics
  2014-02-14  8:24         ` Antonio Quartulli
@ 2014-02-14 17:38           ` Andrew Lunn
  2014-02-14 17:46             ` Antonio Quartulli
  0 siblings, 1 reply; 68+ messages in thread
From: Andrew Lunn @ 2014-02-14 17:38 UTC (permalink / raw)
  To: Antonio Quartulli
  Cc: The list for a Better Approach To Mobile Ad-hoc Networking

> Hi Andrew,
> 
> This morning I've been trying to dig into the tg3 Ethernet driver to get
> an idea of what happens before the NETDEV_UP event is fired.
> 
> The network stack invokes the ndo_open() callback implemented by the
> driver and, as far as I can see, this function does not return until
> having set speed and half/full_duplex state.
> Thus it looks like that when NETDEV_UP is fired the speed and the
> full_duplex attribute have already a meaningful value.
> 
> Of course this may vary depending on the driver, so this may not be the
> case everywhere.

Hi Antonio

I just looked at mv643xx_eth.c, the ethernet driver for my NAS box.
Its ndo_open() function calls phy_start(), but does not wait around
for the auto-negotiation to complete.

I hacked together a quick test.

#!/bin/bash
ifconfig eth0 down
sleep 2
ifconfig eth0 up
cat /sys/class/net/eth0/duplex
cat /sys/class/net/eth0/speed
sleep 0.5
cat /sys/class/net/eth0/duplex
cat /sys/class/net/eth0/speed
sleep 0.5
cat /sys/class/net/eth0/duplex
cat /sys/class/net/eth0/speed
sleep 0.5
cat /sys/class/net/eth0/duplex
cat /sys/class/net/eth0/speed
sleep 0.5
cat /sys/class/net/eth0/duplex
cat /sys/class/net/eth0/speed
sleep 0.5
cat /sys/class/net/eth0/duplex
cat /sys/class/net/eth0/speed
sleep 0.5
cat /sys/class/net/eth0/duplex
cat /sys/class/net/eth0/speed

Which when run gives:

half
1000
half
1000
half
1000
half
1000
half
1000
half
1000
full
1000

So it is taking 3 seconds after ifconfig returns before it has the
right duplex mode.

> I think that your NAS might also be a good testing platform, assuming
> that the owner is willing to insmod batman-adv on that machine :-)

I've no problems with batman on this NAS box. It is a box dedicated to
kernel hacking and experienced many an opps. I currently have 3.13-rc1
on it, which happens to break the ethernet PHY on reboot :-(

   Andrew

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

* Re: [B.A.T.M.A.N.] [RFC 18/23] batman-adv: ELP - use phydev to determine link characteristics
  2014-02-14 17:38           ` Andrew Lunn
@ 2014-02-14 17:46             ` Antonio Quartulli
  2014-02-14 18:18               ` Andrew Lunn
  0 siblings, 1 reply; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-14 17:46 UTC (permalink / raw)
  To: Andrew Lunn; +Cc: The list for a Better Approach To Mobile Ad-hoc Networking

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

On 14/02/14 18:38, Andrew Lunn wrote:
>> Hi Andrew,
>>
>> This morning I've been trying to dig into the tg3 Ethernet driver to get
>> an idea of what happens before the NETDEV_UP event is fired.
>>
>> The network stack invokes the ndo_open() callback implemented by the
>> driver and, as far as I can see, this function does not return until
>> having set speed and half/full_duplex state.
>> Thus it looks like that when NETDEV_UP is fired the speed and the
>> full_duplex attribute have already a meaningful value.
>>
>> Of course this may vary depending on the driver, so this may not be the
>> case everywhere.
> 
> Hi Antonio
> 

Hi Andrew,

> I just looked at mv643xx_eth.c, the ethernet driver for my NAS box.
> Its ndo_open() function calls phy_start(), but does not wait around
> for the auto-negotiation to complete.

oh ok..then it seems we really need to get some kind of notification for
this..


> 
> I hacked together a quick test.
> 
> #!/bin/bash
> ifconfig eth0 down
> sleep 2
> ifconfig eth0 up
> cat /sys/class/net/eth0/duplex
> cat /sys/class/net/eth0/speed
> sleep 0.5
> cat /sys/class/net/eth0/duplex
> cat /sys/class/net/eth0/speed
> sleep 0.5
> cat /sys/class/net/eth0/duplex
> cat /sys/class/net/eth0/speed
> sleep 0.5
> cat /sys/class/net/eth0/duplex
> cat /sys/class/net/eth0/speed
> sleep 0.5
> cat /sys/class/net/eth0/duplex
> cat /sys/class/net/eth0/speed
> sleep 0.5
> cat /sys/class/net/eth0/duplex
> cat /sys/class/net/eth0/speed
> sleep 0.5
> cat /sys/class/net/eth0/duplex
> cat /sys/class/net/eth0/speed
> 
> Which when run gives:
> 
> half
> 1000
> half
> 1000
> half
> 1000
> half
> 1000
> half
> 1000
> half
> 1000
> full
> 1000
> 
> So it is taking 3 seconds after ifconfig returns before it has the
> right duplex mode.

Are you 100% sure that the NETDEV_UP event was sent within those 3
seconds and not after?
If you use a serial console you should see the kernel output mixed with
your test. (just to be 100% sure..)



> 
>> I think that your NAS might also be a good testing platform, assuming
>> that the owner is willing to insmod batman-adv on that machine :-)
> 
> I've no problems with batman on this NAS box. It is a box dedicated to
> kernel hacking and experienced many an opps. I currently have 3.13-rc1
> on it, which happens to break the ethernet PHY on reboot :-(
> 

you shoul dmove to 3.13.3 ;)

Cheers,

-- 
Antonio Quartulli


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [B.A.T.M.A.N.] [RFC 18/23] batman-adv: ELP - use phydev to determine link characteristics
  2014-02-14 17:46             ` Antonio Quartulli
@ 2014-02-14 18:18               ` Andrew Lunn
  2014-02-14 19:18                 ` Antonio Quartulli
  0 siblings, 1 reply; 68+ messages in thread
From: Andrew Lunn @ 2014-02-14 18:18 UTC (permalink / raw)
  To: Antonio Quartulli
  Cc: The list for a Better Approach To Mobile Ad-hoc Networking

> Are you 100% sure that the NETDEV_UP event was sent within those 3
> seconds and not after?
> If you use a serial console you should see the kernel output mixed with
> your test. (just to be 100% sure..)

http://lxr.free-electrons.com/source/net/core/dev.c#L1286

1286 int dev_open(struct net_device *dev)
1287 {
1288         int ret;
1289 
1290         if (dev->flags & IFF_UP)
1291                 return 0;
1292 
1293         ret = __dev_open(dev);
1294         if (ret < 0)
1295                 return ret;
1296 
1297         rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING, GFP_KERNEL);
1298         call_netdevice_notifiers(NETDEV_UP, dev);
1299 
1300         return ret;
1301 }


So the NETDEV_UP is sent as soon as __dev_open() returns,
i.e. ndo_open().

What i do see is:

half
1000
half
1000
half
1000
half
1000
half
1000
half
1000
mv643xx_eth_port mv643xx_eth_port.0 eth0: link up, 1000 Mb/s, full duplex, flowd
full
1000

The link up is from:

http://lxr.free-electrons.com/source/drivers/net/ethernet/marvell/mv643xx_eth.c#L1990

There is no sign of a call_netdevice_notifiers() here, but i think a
netlink message will be sent to userspace because of the
netif_carrier_on() call.

   Andrew

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

* Re: [B.A.T.M.A.N.] [RFC 18/23] batman-adv: ELP - use phydev to determine link characteristics
  2014-02-14 18:18               ` Andrew Lunn
@ 2014-02-14 19:18                 ` Antonio Quartulli
  0 siblings, 0 replies; 68+ messages in thread
From: Antonio Quartulli @ 2014-02-14 19:18 UTC (permalink / raw)
  To: Andrew Lunn; +Cc: The list for a Better Approach To Mobile Ad-hoc Networking

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

On 14/02/14 19:18, Andrew Lunn wrote:
>> Are you 100% sure that the NETDEV_UP event was sent within those 3
>> seconds and not after?
>> If you use a serial console you should see the kernel output mixed with
>> your test. (just to be 100% sure..)
> 
> http://lxr.free-electrons.com/source/net/core/dev.c#L1286
> 
> 1286 int dev_open(struct net_device *dev)
> 1287 {
> 1288         int ret;
> 1289 
> 1290         if (dev->flags & IFF_UP)
> 1291                 return 0;
> 1292 
> 1293         ret = __dev_open(dev);
> 1294         if (ret < 0)
> 1295                 return ret;
> 1296 
> 1297         rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING, GFP_KERNEL);
> 1298         call_netdevice_notifiers(NETDEV_UP, dev);
> 1299 
> 1300         return ret;
> 1301 }
> 
> 
> So the NETDEV_UP is sent as soon as __dev_open() returns,
> i.e. ndo_open().

Yeah, I hoped that the negotiation was performed within dev_open() :-(

> 
> What i do see is:
> 
> half
> 1000
> half
> 1000
> half
> 1000
> half
> 1000
> half
> 1000
> half
> 1000
> mv643xx_eth_port mv643xx_eth_port.0 eth0: link up, 1000 Mb/s, full duplex, flowd
> full
> 1000
> 
> The link up is from:
> 
> http://lxr.free-electrons.com/source/drivers/net/ethernet/marvell/mv643xx_eth.c#L1990
> 
> There is no sign of a call_netdevice_notifiers() here, but i think a
> netlink message will be sent to userspace because of the
> netif_carrier_on() call.

I tried to follow netif_carrier_on() but I couldn't find any particular
function firing any event.

Maybe I should simply make it simple and read the Ethernet card
properties inside get_throughput() upon ELP sending (like I do for the
wifi throughput)?

I did put it in iface_activate() because I expected this values to be
rather static, but now you convinced me that this is not the case :-)


Cheers,

-- 
Antonio Quartulli


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

end of thread, other threads:[~2014-02-14 19:18 UTC | newest]

Thread overview: 68+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-11 12:48 [B.A.T.M.A.N.] [RFC 00/23] Introducing a new routing protocol: B.A.T.M.A.N. V Antonio Quartulli
2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 01/23] batman-adv: invoke ogm_schedule() only when the interface is activated Antonio Quartulli
2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 02/23] batman-adv: Add hard_iface specific sysfs wrapper macros for UINT Antonio Quartulli
2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 03/23] batman-adv: ELP - adding basic infrastructure Antonio Quartulli
2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 04/23] batman-adv: ELP - creating neighbor structures Antonio Quartulli
2014-02-11 15:32   ` Andrew Lunn
2014-02-11 16:02     ` Antonio Quartulli
2014-02-11 16:11       ` Lew Pitcher
2014-02-11 16:26         ` Antonio Quartulli
2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 05/23] batman-adv: ELP - exporting neighbor list via debugfs Antonio Quartulli
2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 06/23] batman-adv: ELP - adding sysfs parameter for elp interval Antonio Quartulli
2014-02-11 16:59   ` Andrew Lunn
2014-02-11 17:08     ` Antonio Quartulli
2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 07/23] batman-adv: OGMv2 - add basic infrastructure Antonio Quartulli
2014-02-11 17:12   ` Andrew Lunn
2014-02-11 17:52     ` Antonio Quartulli
2014-02-12  7:44       ` Andrew Lunn
2014-02-12  7:58         ` Antonio Quartulli
2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 08/23] batman-adv: OGMv2 - implement originators logic Antonio Quartulli
2014-02-11 17:22   ` Andrew Lunn
2014-02-11 17:30     ` Antonio Quartulli
2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 09/23] batman-adv: OGMv2 - purge obsolete potential routers Antonio Quartulli
2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 10/23] batman-adv: split name from variable for uint mesh attributes Antonio Quartulli
2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 11/23] batman-adv: add throughput attribute to hard_ifaces Antonio Quartulli
2014-02-12  8:42   ` Andrew Lunn
2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 12/23] batman-adv: add base throughput attribute Antonio Quartulli
2014-02-12  8:40   ` Andrew Lunn
2014-02-12 12:20     ` Antonio Quartulli
2014-02-13  9:36       ` Andrew Lunn
2014-02-13  9:53         ` Antonio Quartulli
2014-02-13  9:57           ` Andrew Lunn
2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 13/23] batman-adv: add last_unicast_tx to struct neigh_node_elp Antonio Quartulli
2014-02-12  8:49   ` Andrew Lunn
2014-02-12 12:25     ` Antonio Quartulli
2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 14/23] batman-adv: ELP - compute the metric based on the estimated throughput Antonio Quartulli
2014-02-12  8:58   ` Andrew Lunn
2014-02-12 12:27     ` Antonio Quartulli
2014-02-12 15:44       ` Antonio Quartulli
2014-02-13  9:45         ` Andrew Lunn
2014-02-13  9:46           ` Antonio Quartulli
2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 15/23] batman-adv: ELP - send unicast ELP packets for throughput sampling Antonio Quartulli
2014-02-12  9:12   ` Andrew Lunn
2014-02-12 12:12     ` Antonio Quartulli
2014-02-12 12:54       ` Felix Fietkau
2014-02-12 12:56         ` Antonio Quartulli
2014-02-12 13:02           ` Antonio Quartulli
2014-02-13  9:55           ` Andrew Lunn
2014-02-13 10:02             ` Antonio Quartulli
2014-02-13 10:09               ` Andrew Lunn
2014-02-13 10:13                 ` Antonio Quartulli
2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 16/23] batman-adv: ELP - read estimated throughput from cfg80211 Antonio Quartulli
2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 17/23] batman-adv: ELP - implement dead neigh node detection Antonio Quartulli
2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 18/23] batman-adv: ELP - use phydev to determine link characteristics Antonio Quartulli
2014-02-13  8:17   ` Antonio Quartulli
2014-02-13  8:19     ` Antonio Quartulli
2014-02-13 10:52   ` Andrew Lunn
2014-02-13 11:02     ` Antonio Quartulli
2014-02-13 11:44       ` Andrew Lunn
2014-02-14  8:24         ` Antonio Quartulli
2014-02-14 17:38           ` Andrew Lunn
2014-02-14 17:46             ` Antonio Quartulli
2014-02-14 18:18               ` Andrew Lunn
2014-02-14 19:18                 ` Antonio Quartulli
2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 19/23] batman-adv: add bat_neigh_free() API Antonio Quartulli
2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 20/23] batman-adv: B.A.T.M.A.N. V - implement " Antonio Quartulli
2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 21/23] batman-adv: B.A.T.M.A.N. V - implement neigh_is_equiv_or_better API Antonio Quartulli
2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 22/23] batman-adv: B.A.T.M.A.N. V - implement bat_neigh_cmp API Antonio Quartulli
2014-02-11 12:48 ` [B.A.T.M.A.N.] [RFC 23/23] batman-adv: B.A.T.M.A.N. V - implement bat_orig_print API Antonio Quartulli

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.