Hi,
Here's the second broadcast avoidance patchset (rebased on the former one).
Hopefully, those two patchsets together should be an automatic approach and replacement for the (non-upstream) no-rebroadcast flag patch and the cases it is currently used for.
Documentation: * https://www.open-mesh.org/projects/batman-adv/wiki/Broadcast-Avoidances
Branch: * https://git.open-mesh.org/batman-adv.git/shortlog/refs/heads/linus/neighhash
Regards, Linus
The upcoming neighborhood hashing will compute a hash over the MAC address of all neighbors on an interface, from the smallest to the largest one.
This patch keeps the hard interface neighbor list in order to ease the hash computation later.
Signed-off-by: Linus Lüssing linus.luessing@c0d3.blue
---
Changes in v2: * Moved sorted storing of hardif neighbors to this separate patch * fix rcu bug: use hlist_add_{head,behind}_rcu() instead of their non-rcu variants (and rebase on top of Sven's maint patch for the original hlist_add_head() ) (thanks Sven!) --- net/batman-adv/originator.c | 48 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-)
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 8e1ea27..9aaebaf 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -509,6 +509,43 @@ batadv_neigh_node_get(const struct batadv_orig_node *orig_node, }
/** + * batadv_hardif_neigh_get_pre - get the predecessor of a neighbor node + * @hard_iface: the interface this neighbour is connected to + * @neigh_addr: address of the neighbour to retrieve the predecessor for + * + * Tries to find the neighbor node which has an address closest to but + * smaller than the neigh_addr provided. In other words, tries to + * find a potential predecessor of a given MAC address. + * + * Return: The alphabetical predecessor of a neighbor node. Returns NULL + * if no such predecessor exists. + */ +static struct batadv_hardif_neigh_node * +batadv_hardif_neigh_get_pre(struct batadv_hard_iface *hard_iface, + const u8 *neigh_addr) +{ + struct batadv_hardif_neigh_node *tmp_hardif_neigh, *hardif_neigh = NULL; + + rcu_read_lock(); + hlist_for_each_entry_rcu(tmp_hardif_neigh, &hard_iface->neigh_list, + list) { + if (memcmp(tmp_hardif_neigh->addr, neigh_addr, ETH_ALEN) >= 0) + break; + + if (!kref_get_unless_zero(&tmp_hardif_neigh->refcount)) + continue; + + if (hardif_neigh) + batadv_hardif_neigh_put(hardif_neigh); + + hardif_neigh = tmp_hardif_neigh; + } + rcu_read_unlock(); + + return hardif_neigh; +} + +/** * batadv_hardif_neigh_create - create a hardif neighbour node * @hard_iface: the interface this neighbour is connected to * @neigh_addr: the interface address of the neighbour to retrieve @@ -522,7 +559,7 @@ batadv_hardif_neigh_create(struct batadv_hard_iface *hard_iface, struct batadv_orig_node *orig_node) { struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); - struct batadv_hardif_neigh_node *hardif_neigh = NULL; + struct batadv_hardif_neigh_node *hardif_neigh = NULL, *pre_neigh;
spin_lock_bh(&hard_iface->neigh_list_lock);
@@ -547,7 +584,14 @@ batadv_hardif_neigh_create(struct batadv_hard_iface *hard_iface, if (bat_priv->algo_ops->neigh.hardif_init) bat_priv->algo_ops->neigh.hardif_init(hardif_neigh);
- hlist_add_head_rcu(&hardif_neigh->list, &hard_iface->neigh_list); + pre_neigh = batadv_hardif_neigh_get_pre(hard_iface, neigh_addr); + if (!pre_neigh) { + hlist_add_head_rcu(&hardif_neigh->list, + &hard_iface->neigh_list); + } else { + hlist_add_behind_rcu(&hardif_neigh->list, &pre_neigh->list); + batadv_hardif_neigh_put(pre_neigh); + }
out: spin_unlock_bh(&hard_iface->neigh_list_lock);
On Donnerstag, 6. Oktober 2016 08:41:38 CET Linus Lüssing wrote:
hlist_add_behind_rcu(&hardif_neigh->list, &pre_neigh->list);
Compat code is missing for this function
ecsv/pu: sparse linux-3.16 cfg: BLA=n DAT=n DEBUGFS=y DEBUG=y NC=n MCAST=n BATMAN_V=y ---------------------------------------------------------------------------
/home/build_test/build_env/tmp.YwQkM10Q6k/build/net/batman-adv/bat_v_elp.c:96:9: warning: Variable length array is used. /home/build_test/build_env/tmp.YwQkM10Q6k/build/net/batman-adv/originator.c:594:17: error: undefined identifier 'hlist_add_behind_rcu' /home/build_test/build_env/tmp.YwQkM10Q6k/build/net/batman-adv/originator.c: In function 'batadv_hardif_neigh_create': /home/build_test/build_env/tmp.YwQkM10Q6k/build/net/batman-adv/originator.c:594:3: error: implicit declaration of function 'hlist_add_behind_rcu' [-Werror=implicit-function-declaration] hlist_add_behind_rcu(&hardif_neigh->list, &pre_neigh->list);
Kind regards, Sven
On Mittwoch, 14. Dezember 2016 19:48:19 CET Sven Eckelmann wrote:
On Donnerstag, 6. Oktober 2016 08:41:38 CET Linus Lüssing wrote:
hlist_add_behind_rcu(&hardif_neigh->list, &pre_neigh->list);
Compat code is missing for this function
ecsv/pu: sparse linux-3.16 cfg: BLA=n DAT=n DEBUGFS=y DEBUG=y NC=n MCAST=n BATMAN_V=y
/home/build_test/build_env/tmp.YwQkM10Q6k/build/net/batman-adv/bat_v_elp.c:96:9: warning: Variable length array is used. /home/build_test/build_env/tmp.YwQkM10Q6k/build/net/batman-adv/originator.c:594:17: error: undefined identifier 'hlist_add_behind_rcu' /home/build_test/build_env/tmp.YwQkM10Q6k/build/net/batman-adv/originator.c: In function 'batadv_hardif_neigh_create': /home/build_test/build_env/tmp.YwQkM10Q6k/build/net/batman-adv/originator.c:594:3: error: implicit declaration of function 'hlist_add_behind_rcu' [-Werror=implicit-function-declaration] hlist_add_behind_rcu(&hardif_neigh->list, &pre_neigh->list);
I have now added the compat code together with some include fixes to ecsv/pu
diff --git a/compat-include/linux/rculist.h b/compat-include/linux/rculist.h index d432bc65..3c7ae76b 100644 --- a/compat-include/linux/rculist.h +++ b/compat-include/linux/rculist.h @@ -36,4 +36,10 @@
#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) + +#define hlist_add_behind_rcu(n, prev) hlist_add_after_rcu(prev, n) + +#endif /* < KERNEL_VERSION(3, 17, 0) */ + #endif /* _NET_BATMAN_ADV_COMPAT_LINUX_RCULIST_H_ */ diff --git a/net/batman-adv/bat_v_elp.c b/net/batman-adv/bat_v_elp.c index 712bd428..a69614f5 100644 --- a/net/batman-adv/bat_v_elp.c +++ b/net/batman-adv/bat_v_elp.c @@ -19,10 +19,10 @@ #include "main.h"
#include <crypto/hash.h> -#include <crypto/sha.h> #include <linux/atomic.h> +#include <linux/bug.h> #include <linux/byteorder/generic.h> -#include <linux/err.h> +#include <linux/device.h> #include <linux/errno.h> #include <linux/etherdevice.h> #include <linux/ethtool.h>
Kind regards, Sven
On Wed, Dec 14, 2016 at 08:23:19PM +0100, Sven Eckelmann wrote:
diff --git a/net/batman-adv/bat_v_elp.c b/net/batman-adv/bat_v_elp.c index 712bd428..a69614f5 100644 --- a/net/batman-adv/bat_v_elp.c +++ b/net/batman-adv/bat_v_elp.c @@ -19,10 +19,10 @@ #include "main.h" #include <crypto/hash.h> -#include <crypto/sha.h> #include <linux/atomic.h> +#include <linux/bug.h> #include <linux/byteorder/generic.h> -#include <linux/err.h> +#include <linux/device.h> #include <linux/errno.h> #include <linux/etherdevice.h> #include <linux/ethtool.h>
Hm, do you remember what you were adding bug.h and device.h for? Also, err.h seems to be needed for IS_ERR() and PTR_ERR().
Regards, Linus
On Sat, Jan 28, 2017 at 04:13:11AM +0100, Linus Lüssing wrote:
On Wed, Dec 14, 2016 at 08:23:19PM +0100, Sven Eckelmann wrote:
diff --git a/net/batman-adv/bat_v_elp.c b/net/batman-adv/bat_v_elp.c index 712bd428..a69614f5 100644 --- a/net/batman-adv/bat_v_elp.c +++ b/net/batman-adv/bat_v_elp.c @@ -19,10 +19,10 @@ #include "main.h" #include <crypto/hash.h> -#include <crypto/sha.h> #include <linux/atomic.h> +#include <linux/bug.h> #include <linux/byteorder/generic.h> -#include <linux/err.h> +#include <linux/device.h> #include <linux/errno.h> #include <linux/etherdevice.h> #include <linux/ethtool.h>
Hm, do you remember what you were adding bug.h and device.h for? Also, err.h seems to be needed for IS_ERR() and PTR_ERR().
Ok, found bug.h is needed for WARN_ON() in the third patch. The device.h addition and err.h removal still leave me clueless though.
On Samstag, 28. Januar 2017 04:40:50 CET Linus Lüssing wrote: [...]
Ok, found bug.h is needed for WARN_ON() in the third patch. The device.h addition and err.h removal still leave me clueless though.
Looks like an copy + paste error in testhelpers/kernel_mappings.iwyu [1]. Your version was therefore correct and my change was incorrect.
Thanks for checking the headers and reporting the problem.
Kind regards, Sven
[1] https://git.open-mesh.org/build_test.git/commit/cc571792fca7a4d15def67d33598...
Adds a sha512 hash as a TVLV to an ELP packet. Hash is the "sum" of all neighbors (ordered alphabetically, concatenated, binary) a node sees on a specific interface.
Furthermore, the best and worst TX metric of all these neighbors on an interface are added to the TVLV.
Signed-off-by: Linus Lüssing linus.luessing@c0d3.blue
---
Note: This patch throws two checkpatch warnings which are faulty, though.
Changes in v2: * Moved sorted storing of hardif neighbors to a separate patch * Kconfig: switched "depends on CRYPTO_SHA512" to "select CRYPTO_SHA512" * compat: for SHASH_DESC_ON_STACK() macro * kerneldoc: added "struct" prefix in kerneldoc of batadv_tvlv_nhh_data * added includes: - linux/string.h in bat_v.c - linux/{printk.h,err.h} in bat_v_elp.c - linux/string.h in originator.c (thanks Sven!) --- compat-include/crypto/hash.h | 16 ++++ net/batman-adv/Kconfig | 1 + net/batman-adv/bat_v.c | 28 ++++++- net/batman-adv/bat_v.h | 5 ++ net/batman-adv/bat_v_elp.c | 177 +++++++++++++++++++++++++++++++++++++++++++ net/batman-adv/bat_v_elp.h | 2 + net/batman-adv/log.c | 4 +- net/batman-adv/main.c | 1 + net/batman-adv/originator.c | 1 + net/batman-adv/packet.h | 26 +++++++ net/batman-adv/types.h | 8 ++ 11 files changed, 264 insertions(+), 5 deletions(-) create mode 100644 compat-include/crypto/hash.h
diff --git a/compat-include/crypto/hash.h b/compat-include/crypto/hash.h new file mode 100644 index 0000000..2dd72ea --- /dev/null +++ b/compat-include/crypto/hash.h @@ -0,0 +1,16 @@ +#ifndef _NET_BATMAN_ADV_COMPAT_CRYPTO_HASH_H_ +#define _NET_BATMAN_ADV_COMPAT_CRYPTO_HASH_H_ + +#include <linux/version.h> +#include_next <crypto/hash.h> + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0) + +#define SHASH_DESC_ON_STACK(shash, ctx) \ + char __##shash##_desc[sizeof(struct shash_desc) + \ + crypto_shash_descsize(ctx)] CRYPTO_MINALIGN_ATTR; \ + struct shash_desc *shash = (struct shash_desc *)__##shash##_desc + +#endif /* < KERNEL_VERSION(3, 18, 0) */ + +#endif /* _NET_BATMAN_ADV_COMPAT_CRYPTO_HASH_H_ */ diff --git a/net/batman-adv/Kconfig b/net/batman-adv/Kconfig index f20742c..66ef502 100644 --- a/net/batman-adv/Kconfig +++ b/net/batman-adv/Kconfig @@ -18,6 +18,7 @@ config BATMAN_ADV config BATMAN_ADV_BATMAN_V bool "B.A.T.M.A.N. V protocol (experimental)" depends on BATMAN_ADV && CFG80211=y || (CFG80211=m && BATMAN_ADV=m) + select CRYPTO_SHA512 default n help This option enables the B.A.T.M.A.N. V protocol, the successor diff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c index e79f6f0..c93b589 100644 --- a/net/batman-adv/bat_v.c +++ b/net/batman-adv/bat_v.c @@ -33,6 +33,7 @@ #include <linux/rcupdate.h> #include <linux/seq_file.h> #include <linux/stddef.h> +#include <linux/string.h> #include <linux/types.h> #include <linux/workqueue.h> #include <net/genetlink.h> @@ -1070,11 +1071,17 @@ static struct batadv_algo_ops batadv_batman_v __read_mostly = { */ void batadv_v_hardif_init(struct batadv_hard_iface *hard_iface) { + struct batadv_hard_iface_bat_v *bat_v = &hard_iface->bat_v; + /* enable link throughput auto-detection by setting the throughput * override to zero */ - atomic_set(&hard_iface->bat_v.throughput_override, 0); - atomic_set(&hard_iface->bat_v.elp_interval, 500); + atomic_set(&bat_v->throughput_override, 0); + atomic_set(&bat_v->elp_interval, 500); + + bat_v->min_throughput = 0; + bat_v->max_throughput = (~(u32)0); + memset(bat_v->neigh_hash, 0, sizeof(bat_v->neigh_hash)); }
/** @@ -1108,6 +1115,14 @@ void batadv_v_mesh_free(struct batadv_priv *bat_priv) }
/** + * batadv_v_free - free the B.A.T.M.A.N. V global, mesh independent resources + */ +void batadv_v_free(void) +{ + batadv_v_elp_free(); +} + +/** * batadv_v_init - B.A.T.M.A.N. V initialization function * * Description: Takes care of initializing all the subcomponents. @@ -1119,11 +1134,15 @@ int __init batadv_v_init(void) { int ret;
+ ret = batadv_v_elp_init(); + if (ret < 0) + return ret; + /* B.A.T.M.A.N. V echo location protocol packet */ ret = batadv_recv_handler_register(BATADV_ELP, batadv_v_elp_packet_recv); if (ret < 0) - return ret; + goto elp_free;
ret = batadv_recv_handler_register(BATADV_OGM2, batadv_v_ogm_packet_recv); @@ -1136,6 +1155,9 @@ int __init batadv_v_init(void)
return ret;
+elp_free: + batadv_v_elp_free(); + ogm_unregister: batadv_recv_handler_unregister(BATADV_OGM2);
diff --git a/net/batman-adv/bat_v.h b/net/batman-adv/bat_v.h index 83b7763..e2645b8 100644 --- a/net/batman-adv/bat_v.h +++ b/net/batman-adv/bat_v.h @@ -23,6 +23,7 @@ #ifdef CONFIG_BATMAN_ADV_BATMAN_V
int batadv_v_init(void); +void batadv_v_free(void); void batadv_v_hardif_init(struct batadv_hard_iface *hardif); int batadv_v_mesh_init(struct batadv_priv *bat_priv); void batadv_v_mesh_free(struct batadv_priv *bat_priv); @@ -34,6 +35,10 @@ static inline int batadv_v_init(void) return 0; }
+static inline void batadv_v_free(void) +{ +} + static inline void batadv_v_hardif_init(struct batadv_hard_iface *hardif) { } diff --git a/net/batman-adv/bat_v_elp.c b/net/batman-adv/bat_v_elp.c index ee08540..931dd2e 100644 --- a/net/batman-adv/bat_v_elp.c +++ b/net/batman-adv/bat_v_elp.c @@ -18,8 +18,11 @@ #include "bat_v_elp.h" #include "main.h"
+#include <crypto/hash.h> +#include <crypto/sha.h> #include <linux/atomic.h> #include <linux/byteorder/generic.h> +#include <linux/err.h> #include <linux/errno.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> @@ -29,6 +32,7 @@ #include <linux/kernel.h> #include <linux/kref.h> #include <linux/netdevice.h> +#include <linux/printk.h> #include <linux/random.h> #include <linux/rculist.h> #include <linux/rcupdate.h> @@ -49,6 +53,8 @@ #include "routing.h" #include "send.h"
+static struct crypto_shash *tfm; + /** * batadv_v_elp_start_timer - restart timer for ELP periodic work * @hard_iface: the interface for which the timer has to be reset @@ -65,6 +71,133 @@ static void batadv_v_elp_start_timer(struct batadv_hard_iface *hard_iface) }
/** + * batadv_v_elp_update_neigh_hash - updates neighborhood hash related data + * @hard_iface: interface which the data has to be prepared for + * + * Firstly, this function updates the neighborhood hash of a hard interface. + * That is it resummarizes the present neighborhood into one compact hash + * representation. + * + * Secondly, minimum and maximum throughput values within this neighorhood are + * updated. + */ +static void batadv_v_elp_update_neigh_hash(struct batadv_hard_iface *hard_iface) +{ + struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); + struct batadv_hardif_neigh_node *hardif_neigh; + struct ewma_throughput *ewma_throughput; + u8 *own_addr = hard_iface->net_dev->dev_addr; + u32 min_throughput = ~((u32)0), max_throughput = 0; + u32 throughput; + int ret; + + SHASH_DESC_ON_STACK(shash, tfm); + + shash->flags = 0; + shash->tfm = tfm; + + ret = crypto_shash_init(shash); + if (ret) + goto err; + + rcu_read_lock(); + hlist_for_each_entry_rcu(hardif_neigh, + &hard_iface->neigh_list, list) { + /* insert own address at the right spot */ + if (own_addr && (memcmp(own_addr, hardif_neigh->addr, + ETH_ALEN) < 0)) { + ret = crypto_shash_update(shash, own_addr, ETH_ALEN); + if (ret) { + rcu_read_unlock(); + goto err; + } + + own_addr = NULL; + } + + ret = crypto_shash_update(shash, hardif_neigh->addr, ETH_ALEN); + if (ret) { + rcu_read_unlock(); + goto err; + } + + ewma_throughput = &hardif_neigh->bat_v.throughput; + throughput = ewma_throughput_read(ewma_throughput); + + if (throughput < min_throughput) + min_throughput = throughput; + + if (throughput > max_throughput) + max_throughput = throughput; + } + rcu_read_unlock(); + + if (own_addr) { + ret = crypto_shash_update(shash, own_addr, ETH_ALEN); + if (ret) + goto err; + } + + ret = crypto_shash_final(shash, hard_iface->bat_v.neigh_hash); + if (ret) + goto err; + + hard_iface->bat_v.min_throughput = min_throughput; + hard_iface->bat_v.max_throughput = max_throughput; + + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Updated neighbor hash on interface %s: %*phN, min_through: %u kbit/s, max_through: %u kbit/s\n", + hard_iface->net_dev->name, + (int)sizeof(hard_iface->bat_v.neigh_hash), + hard_iface->bat_v.neigh_hash, + hard_iface->bat_v.min_throughput * 100, + hard_iface->bat_v.max_throughput * 100); + + return; + +err: + memset(hard_iface->bat_v.neigh_hash, 0, + sizeof(hard_iface->bat_v.neigh_hash)); + hard_iface->bat_v.min_throughput = 0; + hard_iface->bat_v.max_throughput = ~((u32)0); + + pr_warn_once("An error occurred while calculating neighbor hash for %s\n", + hard_iface->net_dev->name); +} + +/** + * batadv_v_elp_update_neigh_hash_tvlv - updates a neighborhood hash tvlv + * @hard_iface: interface which the tvlv is updated for + * @skb: the to be transmitted ELP packet containing the neighborhood tvlv + * + * Prepares the neighborhood hash tvlv of an ELP packet by updating its + * hash as well as minimum and maximum throughput values. + */ +static void +batadv_v_elp_update_neigh_hash_tvlv(struct batadv_hard_iface *hard_iface, + struct sk_buff *skb) +{ + struct batadv_hard_iface_bat_v *hard_iface_v = &hard_iface->bat_v; + struct batadv_elp_packet *elp_packet; + struct batadv_tvlv_hdr *tvlv_hdr; + struct batadv_tvlv_nhh_data *nhh_data; + + elp_packet = (struct batadv_elp_packet *)skb_network_header(skb); + tvlv_hdr = (struct batadv_tvlv_hdr *)(elp_packet + 1); + nhh_data = (struct batadv_tvlv_nhh_data *)(tvlv_hdr + 1); + + if (!hard_iface_v->min_throughput) { + elp_packet->tvlv_len = 0; + skb_trim(skb, skb->len - sizeof(*tvlv_hdr) - sizeof(*nhh_data)); + } else { + nhh_data->min_throughput = htonl(hard_iface_v->min_throughput); + nhh_data->max_throughput = htonl(hard_iface_v->max_throughput); + memcpy(nhh_data->neigh_hash, hard_iface_v->neigh_hash, + sizeof(hard_iface_v->neigh_hash)); + } +} + +/** * batadv_v_elp_get_throughput - get the throughput towards a neighbour * @neigh: the neighbour for which the throughput has to be obtained * @@ -269,6 +402,9 @@ static void batadv_v_elp_periodic_work(struct work_struct *work) elp_interval = atomic_read(&hard_iface->bat_v.elp_interval); elp_packet->elp_interval = htonl(elp_interval);
+ batadv_v_elp_update_neigh_hash(hard_iface); + batadv_v_elp_update_neigh_hash_tvlv(hard_iface, skb); + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Sending broadcast ELP packet on interface %s, seqno %u\n", hard_iface->net_dev->name, @@ -324,23 +460,42 @@ out: int batadv_v_elp_iface_enable(struct batadv_hard_iface *hard_iface) { struct batadv_elp_packet *elp_packet; + struct batadv_tvlv_hdr *tvlv_hdr; + struct batadv_tvlv_nhh_data *nhh_data; unsigned char *elp_buff; u32 random_seqno; size_t size; int res = -ENOMEM;
size = ETH_HLEN + NET_IP_ALIGN + BATADV_ELP_HLEN; + size += sizeof(*nhh_data) + sizeof(*tvlv_hdr); + 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); + skb_reset_network_header(hard_iface->bat_v.elp_skb); + elp_buff = skb_put(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->tvlv_len = htons(sizeof(*nhh_data) + sizeof(*tvlv_hdr)); + + elp_buff = skb_put(hard_iface->bat_v.elp_skb, sizeof(*tvlv_hdr)); + tvlv_hdr = (struct batadv_tvlv_hdr *)elp_buff; + tvlv_hdr->type = BATADV_TVLV_NHH; + tvlv_hdr->version = 1; + tvlv_hdr->len = htons(sizeof(*nhh_data)); + + size = sizeof(*nhh_data); + elp_buff = skb_put(hard_iface->bat_v.elp_skb, size); + nhh_data = (struct batadv_tvlv_nhh_data *)elp_buff; + nhh_data->min_throughput = htonl(0); + memset(nhh_data, 0, size);
/* randomize initial seqno to avoid collision */ get_random_bytes(&random_seqno, sizeof(random_seqno)); @@ -527,3 +682,25 @@ out: consume_skb(skb); return NET_RX_SUCCESS; } + +/** + * batadv_v_elp_init - initialize global ELP structures + * + * Return: A negative value on error, zero on success. + */ +int batadv_v_elp_init(void) +{ + tfm = crypto_alloc_shash("sha512", 0, 0); + if (IS_ERR(tfm)) + return PTR_ERR(tfm); + + return 0; +} + +/** + * batadv_v_elp_free - free global ELP structures + */ +void batadv_v_elp_free(void) +{ + crypto_free_shash(tfm); +} diff --git a/net/batman-adv/bat_v_elp.h b/net/batman-adv/bat_v_elp.h index be17c0b..ed5936c 100644 --- a/net/batman-adv/bat_v_elp.h +++ b/net/batman-adv/bat_v_elp.h @@ -23,6 +23,8 @@ struct sk_buff; struct work_struct;
+int batadv_v_elp_init(void); +void batadv_v_elp_free(void); 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_iface_activate(struct batadv_hard_iface *primary_iface, diff --git a/net/batman-adv/log.c b/net/batman-adv/log.c index 56dc532..099524e 100644 --- a/net/batman-adv/log.c +++ b/net/batman-adv/log.c @@ -66,7 +66,7 @@ static int batadv_fdebug_log(struct batadv_priv_debug_log *debug_log, const char *fmt, ...) { va_list args; - static char debug_log_buf[256]; + static char debug_log_buf[512]; char *p;
if (!debug_log) @@ -90,7 +90,7 @@ static int batadv_fdebug_log(struct batadv_priv_debug_log *debug_log, int batadv_debug_log(struct batadv_priv *bat_priv, const char *fmt, ...) { va_list args; - char tmp_log_buf[256]; + char tmp_log_buf[512];
va_start(args, fmt); vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args); diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index 2c017ab..2570463 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -135,6 +135,7 @@ static void __exit batadv_exit(void) rcu_barrier();
batadv_tt_cache_destroy(); + batadv_v_free(); }
int batadv_mesh_init(struct net_device *soft_iface) diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 9aaebaf..708cf57 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -34,6 +34,7 @@ #include <linux/skbuff.h> #include <linux/slab.h> #include <linux/spinlock.h> +#include <linux/string.h> #include <linux/workqueue.h> #include <net/sock.h> #include <uapi/linux/batman_adv.h> diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h index 6afc0b8..4d8c8ea 100644 --- a/net/batman-adv/packet.h +++ b/net/batman-adv/packet.h @@ -19,6 +19,7 @@ #define _NET_BATMAN_ADV_PACKET_H_
#include <asm/byteorder.h> +#include <crypto/sha.h> #include <linux/types.h>
#define batadv_tp_is_error(n) ((u8)n > 127 ? 1 : 0) @@ -163,6 +164,14 @@ enum batadv_tvlv_type { BATADV_TVLV_MCAST = 0x06, };
+/** + * enum batadv_tvlv_elp_type - tvlv type definitions for ELP messages + * @BATADV_TVLV_NHH: neighborhood hash + */ +enum batadv_tvlv_elp_type { + BATADV_TVLV_NHH = 0x01, +}; + #pragma pack(2) /* the destination hardware field in the ARP frame is used to * transport the claim type and the group id @@ -240,6 +249,8 @@ struct batadv_ogm2_packet { * @orig: originator mac address * @seqno: sequence number * @elp_interval: currently used ELP sending interval in ms + * @reserved: reserved bytes for alignment + * @tvlv_len: length of tvlv data following the elp header */ struct batadv_elp_packet { u8 packet_type; @@ -247,6 +258,8 @@ struct batadv_elp_packet { u8 orig[ETH_ALEN]; __be32 seqno; __be32 elp_interval; + __be16 reserved; + __be16 tvlv_len; };
#define BATADV_ELP_HLEN sizeof(struct batadv_elp_packet) @@ -628,4 +641,17 @@ struct batadv_tvlv_mcast_data { u8 reserved[3]; };
+/** + * struct batadv_tvlv_nhh_data - neighborhood hash data + * @min_throughput: worst of all TX throughputs this neighbor has to others + * @max_throughput: best of all TX throughputs this neighbor has to others + * @neigh_hash: a sha512 hash of all neighbors this neighbor sees + * (hash over the alphabetically ordered, concatenated, binary representation) + */ +struct batadv_tvlv_nhh_data { + __be32 min_throughput; + __be32 max_throughput; + u8 neigh_hash[SHA512_DIGEST_SIZE]; +}; + #endif /* _NET_BATMAN_ADV_PACKET_H_ */ diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index b540cd3..731bdf5 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -22,6 +22,7 @@ #error only "main.h" can be included directly #endif
+#include <crypto/sha.h> #include <linux/average.h> #include <linux/bitops.h> #include <linux/compiler.h> @@ -108,6 +109,10 @@ enum batadv_v_hard_iface_flags { * @elp_wq: workqueue used to schedule ELP transmissions * @throughput_override: throughput override to disable link auto-detection * @flags: interface specific flags + * @min_throughput: worst of all TX throughputs this neighbor has to others + * @max_throughput: best of all TX throughputs this neighbor has to others + * @neigh_hash: a sha512 hash of all neighbors this neighbor sees + * (hash over the alphabetically ordered, concatenated, binary representation) */ struct batadv_hard_iface_bat_v { atomic_t elp_interval; @@ -116,6 +121,9 @@ struct batadv_hard_iface_bat_v { struct delayed_work elp_wq; atomic_t throughput_override; u8 flags; + u32 min_throughput; + u32 max_throughput; + u8 neigh_hash[SHA512_DIGEST_SIZE]; };
/**
On Donnerstag, 6. Oktober 2016 08:41:39 CET Linus Lüssing wrote:
struct batadv_elp_packet { u8 packet_type; @@ -247,6 +258,8 @@ struct batadv_elp_packet { u8 orig[ETH_ALEN]; __be32 seqno; __be32 elp_interval;
__be16 reserved;
__be16 tvlv_len;
};
Um, you simply increase the size of the elp_packet? Isn't this potentially breaking compat with older versions? batadv_v_elp_packet_recv is using BATADV_ELP_HLEN (sizeof(struct batadv_elp_packet)) as minimal size/header_len in batadv_check_management_packet.
Only thing saving you here is the padding on some links. But this padding could cause some odd behaviour in batadv_tvlv_containers_process2 when tvlv_len is bogus/padding.
Kind regards, Sven
On Wed, Dec 14, 2016 at 09:28:33PM +0100, Sven Eckelmann wrote:
On Donnerstag, 6. Oktober 2016 08:41:39 CET Linus Lüssing wrote:
struct batadv_elp_packet { u8 packet_type; @@ -247,6 +258,8 @@ struct batadv_elp_packet { u8 orig[ETH_ALEN]; __be32 seqno; __be32 elp_interval;
__be16 reserved;
__be16 tvlv_len;
};
Um, you simply increase the size of the elp_packet? Isn't this potentially breaking compat with older versions? batadv_v_elp_packet_recv is using BATADV_ELP_HLEN (sizeof(struct batadv_elp_packet)) as minimal size/header_len in batadv_check_management_packet.
Only thing saving you here is the padding on some links. But this padding could cause some odd behaviour in batadv_tvlv_containers_process2 when tvlv_len is bogus/padding.
Urgh, could catch, you're right.
Luckily, it seems like it's only breaking compatibility in one direction. And it's the direction where a non-compatibility breaking solution is possible.
On Donnerstag, 6. Oktober 2016 08:41:39 CET Linus Lüssing wrote:
~((u32)0);
I already saw this multiple times. Maybe you could use U32_MAX from linux/kernel.h.
u32 min_throughput = ~((u32)0), max_throughput = 0;
I personally don't like multiple assignments in one line. Makes it harder to check what is assigned and what is actually the next statement.
Kind regards, Sven
On Donnerstag, 6. Oktober 2016 08:41:39 CET Linus Lüssing wrote:
nhh_data = (struct batadv_tvlv_nhh_data *)elp_buff;
nhh_data->min_throughput = htonl(0);
memset(nhh_data, 0, size);
Why do you set min_throughput and then use memset to overwrite it again?
Kind regards, Sven
Instead of having one TVLV registration function for OGMs and one for unicast packets, this patch adds a new, generic tvlv handler registratiorn function, which simply uses a packet type as parameter.
For now, this patch only migrates the multicast and gateway tvlv handlers to this new API, as these two have been tested and verified to work by the author.
The benefits of this new API:
* A more unified TVLV handling * Easier to add TVLV capabilities to any new, upcoming packet type * Does not rely on linearized skb data
Further ToDos (for later patches):
* Insert handler hooks for unicast_tvlv packets too and migrate BATADV_TVLV_{DAT,NC,TT,ROAM} to new API after further testing. * Remove old TVLV handler API
Signed-off-by: Linus Lüssing linus.luessing@c0d3.blue
---
Changes in v2: * add includes for linux/{bug,printk}.h * update forward declaration to "struct sk_buff;" in tvlv.h * kerneldoc: - change a "@tvlv_type" to "@packet_type", - fixed batadv_tvlv_ogm_unpack_ctx() parameter kerneldoc (thanks Sven!) --- net/batman-adv/bat_iv_ogm.c | 8 +- net/batman-adv/bat_v_ogm.c | 17 +- net/batman-adv/distributed-arp-table.c | 4 +- net/batman-adv/gateway_common.c | 44 +++-- net/batman-adv/multicast.c | 37 ++-- net/batman-adv/network-coding.c | 4 +- net/batman-adv/tvlv.c | 326 ++++++++++++++++++++++++++++++--- net/batman-adv/tvlv.h | 24 ++- net/batman-adv/types.h | 24 ++- 9 files changed, 408 insertions(+), 80 deletions(-)
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index 9c723cf..4f09b70 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -1491,7 +1491,7 @@ batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset, }
if (if_outgoing == BATADV_IF_DEFAULT) - batadv_tvlv_ogm_receive(bat_priv, ogm_packet, orig_node); + batadv_tvlv_ogm_receive(bat_priv, skb, orig_node);
/* if sender is a direct neighbor the sender mac equals * originator mac @@ -1832,6 +1832,8 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb, ogm_offset = 0; ogm_packet = (struct batadv_ogm_packet *)skb->data;
+ WARN_ON(skb_network_offset(skb) != 0); + /* unpack the aggregated packets and process them one by one */ while (batadv_iv_ogm_aggr_packet(ogm_offset, skb_headlen(skb), ogm_packet->tvlv_len)) { @@ -1842,8 +1844,12 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb,
packet_pos = skb->data + ogm_offset; ogm_packet = (struct batadv_ogm_packet *)packet_pos; + + skb_set_network_header(skb, ogm_offset); }
+ skb_reset_network_header(skb); + kfree_skb(skb); return NET_RX_SUCCESS; } diff --git a/net/batman-adv/bat_v_ogm.c b/net/batman-adv/bat_v_ogm.c index eaa2e2d..606f899 100644 --- a/net/batman-adv/bat_v_ogm.c +++ b/net/batman-adv/bat_v_ogm.c @@ -594,7 +594,7 @@ out: /** * batadv_v_ogm_process_per_outif - process a batman v OGM for an outgoing if * @bat_priv: the bat priv with all the soft interface information - * @ethhdr: the Ethernet header of the OGM2 + * @skb: the skb containing the OGM2 * @ogm2: OGM2 structure * @orig_node: Originator structure for which the OGM has been received * @neigh_node: the neigh_node through with the OGM has been received @@ -603,13 +603,16 @@ out: */ static void batadv_v_ogm_process_per_outif(struct batadv_priv *bat_priv, - const struct ethhdr *ethhdr, + const struct sk_buff *skb, 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) { + void *ctx = batadv_tvlv_ogm_pack_ctx(orig_node); + const struct ethhdr *ethhdr = eth_hdr(skb); + unsigned int tvlv_offset = sizeof(*ogm2); int seqno_age; bool forward;
@@ -623,11 +626,15 @@ batadv_v_ogm_process_per_outif(struct batadv_priv *bat_priv, return;
/* only unknown & newer OGMs contain TVLVs we are interested in */ - if ((seqno_age > 0) && (if_outgoing == BATADV_IF_DEFAULT)) + if ((seqno_age > 0) && (if_outgoing == BATADV_IF_DEFAULT)) { + batadv_tvlv_containers_process2(bat_priv, skb, BATADV_OGM2, + tvlv_offset, + ntohs(ogm2->tvlv_len), ctx); batadv_tvlv_containers_process(bat_priv, true, orig_node, NULL, NULL, (unsigned char *)(ogm2 + 1), ntohs(ogm2->tvlv_len)); + }
/* if the metric update went through, update routes if needed */ forward = batadv_v_ogm_route_update(bat_priv, ethhdr, ogm2, orig_node, @@ -728,7 +735,7 @@ static void batadv_v_ogm_process(const struct sk_buff *skb, int ogm_offset, path_throughput = min_t(u32, link_throughput, ogm_throughput); ogm_packet->throughput = htonl(path_throughput);
- batadv_v_ogm_process_per_outif(bat_priv, ethhdr, ogm_packet, orig_node, + batadv_v_ogm_process_per_outif(bat_priv, skb, ogm_packet, orig_node, neigh_node, if_incoming, BATADV_IF_DEFAULT);
@@ -772,7 +779,7 @@ static void batadv_v_ogm_process(const struct sk_buff *skb, int ogm_offset, continue; }
- batadv_v_ogm_process_per_outif(bat_priv, ethhdr, ogm_packet, + batadv_v_ogm_process_per_outif(bat_priv, skb, ogm_packet, orig_node, neigh_node, if_incoming, hard_iface);
diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index e257efd..4fd912c 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@ -734,7 +734,7 @@ static void batadv_dat_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, u8 flags, void *tvlv_value, u16 tvlv_value_len) { - if (flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND) + if (flags & BATADV_TVLV_HANDLER_CIFNOTFND) clear_bit(BATADV_ORIG_CAPA_HAS_DAT, &orig->capabilities); else set_bit(BATADV_ORIG_CAPA_HAS_DAT, &orig->capabilities); @@ -776,7 +776,7 @@ int batadv_dat_init(struct batadv_priv *bat_priv)
batadv_tvlv_handler_register(bat_priv, batadv_dat_tvlv_ogm_handler_v1, NULL, BATADV_TVLV_DAT, 1, - BATADV_TVLV_HANDLER_OGM_CIFNOTFND); + BATADV_TVLV_HANDLER_CIFNOTFND); batadv_dat_tvlv_container_update(bat_priv); return 0; } diff --git a/net/batman-adv/gateway_common.c b/net/batman-adv/gateway_common.c index 2118481..6f7cb51 100644 --- a/net/batman-adv/gateway_common.c +++ b/net/batman-adv/gateway_common.c @@ -207,25 +207,26 @@ ssize_t batadv_gw_bandwidth_set(struct net_device *net_dev, char *buff, }
/** - * batadv_gw_tvlv_ogm_handler_v1 - process incoming gateway tvlv container + * batadv_gw_tvlv_ogm_handler - process incoming gateway tvlv container * @bat_priv: the bat priv with all the soft interface information - * @orig: the orig_node of the ogm - * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags) * @tvlv_value: tvlv buffer containing the gateway data * @tvlv_value_len: tvlv buffer length + * @ctx: handler specific context information (here: orig_node) + * + * Return: Always NET_RX_SUCCESS. */ -static void batadv_gw_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, - struct batadv_orig_node *orig, - u8 flags, - void *tvlv_value, u16 tvlv_value_len) +static int batadv_gw_tvlv_ogm_handler(struct batadv_priv *bat_priv, + void *tvlv_value, + u16 tvlv_value_len, + void *ctx) { + struct batadv_orig_node *orig_node = batadv_tvlv_ogm_unpack_ctx(ctx); struct batadv_tvlv_gateway_data gateway, *gateway_ptr;
- /* only fetch the tvlv value if the handler wasn't called via the - * CIFNOTFND flag and if there is data to fetch + /* might either be too small due to a broken packet, + * or zero because no matching TVLV was found in the provided OGM */ - if ((flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND) || - (tvlv_value_len < sizeof(gateway))) { + if (tvlv_value_len < sizeof(gateway)) { gateway.bandwidth_down = 0; gateway.bandwidth_up = 0; } else { @@ -239,12 +240,14 @@ static void batadv_gw_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, } }
- batadv_gw_node_update(bat_priv, orig, &gateway); + batadv_gw_node_update(bat_priv, orig_node, &gateway);
/* restart gateway selection */ if ((gateway.bandwidth_down != 0) && (atomic_read(&bat_priv->gw.mode) == BATADV_GW_MODE_CLIENT)) - batadv_gw_check_election(bat_priv, orig); + batadv_gw_check_election(bat_priv, orig_node); + + return NET_RX_SUCCESS; }
/** @@ -253,9 +256,12 @@ static void batadv_gw_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, */ void batadv_gw_init(struct batadv_priv *bat_priv) { - batadv_tvlv_handler_register(bat_priv, batadv_gw_tvlv_ogm_handler_v1, - NULL, BATADV_TVLV_GW, 1, - BATADV_TVLV_HANDLER_OGM_CIFNOTFND); + batadv_tvlv_handler_register2(bat_priv, batadv_gw_tvlv_ogm_handler, + BATADV_IV_OGM, BATADV_TVLV_GW, 1, + BATADV_TVLV_HANDLER_CIFNOTFND); + batadv_tvlv_handler_register2(bat_priv, batadv_gw_tvlv_ogm_handler, + BATADV_OGM2, BATADV_TVLV_GW, 1, + BATADV_TVLV_HANDLER_CIFNOTFND); }
/** @@ -265,5 +271,9 @@ void batadv_gw_init(struct batadv_priv *bat_priv) void batadv_gw_free(struct batadv_priv *bat_priv) { batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_GW, 1); - batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_GW, 1); + + batadv_tvlv_handler_unregister2(bat_priv, BATADV_IV_OGM, BATADV_TVLV_GW, + 1); + batadv_tvlv_handler_unregister2(bat_priv, BATADV_OGM2, BATADV_TVLV_GW, + 1); } diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c index 13661f4..9a962eb 100644 --- a/net/batman-adv/multicast.c +++ b/net/batman-adv/multicast.c @@ -1070,23 +1070,23 @@ static void batadv_mcast_want_ipv6_update(struct batadv_priv *bat_priv, /** * batadv_mcast_tvlv_ogm_handler - process incoming multicast tvlv container * @bat_priv: the bat priv with all the soft interface information - * @orig: the orig_node of the ogm - * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags) * @tvlv_value: tvlv buffer containing the multicast data * @tvlv_value_len: tvlv buffer length + * @ctx: handler specific context information (here: orig_node) + * + * Return: Always NET_RX_SUCCESS. */ -static void batadv_mcast_tvlv_ogm_handler(struct batadv_priv *bat_priv, - struct batadv_orig_node *orig, - u8 flags, - void *tvlv_value, - u16 tvlv_value_len) +static int batadv_mcast_tvlv_ogm_handler(struct batadv_priv *bat_priv, + void *tvlv_value, + u16 tvlv_value_len, + void *ctx) { - bool orig_mcast_enabled = !(flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND); + struct batadv_orig_node *orig = batadv_tvlv_ogm_unpack_ctx(ctx); + bool orig_mcast_enabled = !!tvlv_value; u8 mcast_flags = BATADV_NO_FLAGS; bool orig_initialized;
- if (orig_mcast_enabled && tvlv_value && - (tvlv_value_len >= sizeof(mcast_flags))) + if (orig_mcast_enabled && (tvlv_value_len >= sizeof(mcast_flags))) mcast_flags = *(u8 *)tvlv_value;
spin_lock_bh(&orig->mcast_handler_lock); @@ -1121,6 +1121,8 @@ static void batadv_mcast_tvlv_ogm_handler(struct batadv_priv *bat_priv,
orig->mcast_flags = mcast_flags; spin_unlock_bh(&orig->mcast_handler_lock); + + return NET_RX_SUCCESS; }
/** @@ -1129,9 +1131,12 @@ static void batadv_mcast_tvlv_ogm_handler(struct batadv_priv *bat_priv, */ void batadv_mcast_init(struct batadv_priv *bat_priv) { - batadv_tvlv_handler_register(bat_priv, batadv_mcast_tvlv_ogm_handler, - NULL, BATADV_TVLV_MCAST, 2, - BATADV_TVLV_HANDLER_OGM_CIFNOTFND); + batadv_tvlv_handler_register2(bat_priv, batadv_mcast_tvlv_ogm_handler, + BATADV_IV_OGM, BATADV_TVLV_MCAST, 2, + BATADV_TVLV_HANDLER_CIFNOTFND); + batadv_tvlv_handler_register2(bat_priv, batadv_mcast_tvlv_ogm_handler, + BATADV_OGM2, BATADV_TVLV_MCAST, 2, + BATADV_TVLV_HANDLER_CIFNOTFND); }
#ifdef CONFIG_BATMAN_ADV_DEBUGFS @@ -1244,7 +1249,11 @@ int batadv_mcast_flags_seq_print_text(struct seq_file *seq, void *offset) void batadv_mcast_free(struct batadv_priv *bat_priv) { batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_MCAST, 2); - batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_MCAST, 2); + + batadv_tvlv_handler_unregister2(bat_priv, BATADV_IV_OGM, + BATADV_TVLV_MCAST, 2); + batadv_tvlv_handler_unregister2(bat_priv, BATADV_OGM2, + BATADV_TVLV_MCAST, 2);
spin_lock_bh(&bat_priv->tt.commit_lock); batadv_mcast_mla_tt_retract(bat_priv, NULL); diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c index e3baf69..2fe44d8 100644 --- a/net/batman-adv/network-coding.c +++ b/net/batman-adv/network-coding.c @@ -138,7 +138,7 @@ static void batadv_nc_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, u8 flags, void *tvlv_value, u16 tvlv_value_len) { - if (flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND) + if (flags & BATADV_TVLV_HANDLER_CIFNOTFND) clear_bit(BATADV_ORIG_CAPA_HAS_NC, &orig->capabilities); else set_bit(BATADV_ORIG_CAPA_HAS_NC, &orig->capabilities); @@ -177,7 +177,7 @@ int batadv_nc_mesh_init(struct batadv_priv *bat_priv)
batadv_tvlv_handler_register(bat_priv, batadv_nc_tvlv_ogm_handler_v1, NULL, BATADV_TVLV_NC, 1, - BATADV_TVLV_HANDLER_OGM_CIFNOTFND); + BATADV_TVLV_HANDLER_CIFNOTFND); batadv_nc_tvlv_container_update(bat_priv); return 0;
diff --git a/net/batman-adv/tvlv.c b/net/batman-adv/tvlv.c index 77654f0..8c097c3 100644 --- a/net/batman-adv/tvlv.c +++ b/net/batman-adv/tvlv.c @@ -17,6 +17,7 @@
#include "main.h"
+#include <linux/bug.h> #include <linux/byteorder/generic.h> #include <linux/etherdevice.h> #include <linux/fs.h> @@ -27,6 +28,7 @@ #include <linux/lockdep.h> #include <linux/netdevice.h> #include <linux/pkt_sched.h> +#include <linux/printk.h> #include <linux/rculist.h> #include <linux/rcupdate.h> #include <linux/skbuff.h> @@ -68,23 +70,28 @@ static void batadv_tvlv_handler_put(struct batadv_tvlv_handler *tvlv_handler) * batadv_tvlv_handler_get - retrieve tvlv handler from the tvlv handler list * based on the provided type and version (both need to match) * @bat_priv: the bat priv with all the soft interface information - * @type: tvlv handler type to look for - * @version: tvlv handler version to look for + * @packet_type: packet type to look for + * @tvlv_type: tvlv handler type to look for + * @tvlv_version: tvlv handler version to look for * * Return: tvlv handler if found or NULL otherwise. */ static struct batadv_tvlv_handler * -batadv_tvlv_handler_get(struct batadv_priv *bat_priv, u8 type, u8 version) +batadv_tvlv_handler_get(struct batadv_priv *bat_priv, int packet_type, + u8 tvlv_type, u8 tvlv_version) { struct batadv_tvlv_handler *tvlv_handler_tmp, *tvlv_handler = NULL;
rcu_read_lock(); hlist_for_each_entry_rcu(tvlv_handler_tmp, &bat_priv->tvlv.handler_list, list) { - if (tvlv_handler_tmp->type != type) + if (tvlv_handler_tmp->packet_type != packet_type) continue;
- if (tvlv_handler_tmp->version != version) + if (tvlv_handler_tmp->tvlv_type != tvlv_type) + continue; + + if (tvlv_handler_tmp->tvlv_version != tvlv_version) continue;
if (!kref_get_unless_zero(&tvlv_handler_tmp->refcount)) @@ -387,7 +394,7 @@ static int batadv_tvlv_call_handler(struct batadv_priv *bat_priv, tvlv_handler->ogm_handler(bat_priv, orig_node, BATADV_NO_FLAGS, tvlv_value, tvlv_value_len); - tvlv_handler->flags |= BATADV_TVLV_HANDLER_OGM_CALLED; + tvlv_handler->flags |= BATADV_TVLV_HANDLER_CALLED; } else { if (!src) return NET_RX_SUCCESS; @@ -407,6 +414,139 @@ static int batadv_tvlv_call_handler(struct batadv_priv *bat_priv, }
/** + * batadv_tvlv_call_handler2 - call the appropriate tvlv handler + * @bat_priv: the bat priv with all the soft interface information + * @packet_type: packet type to look and call for + * @tvlv_type: tvlv handler type to look and call for + * @tvlv_version: tvlv handler version to look and call for + * @tvlv_value: tvlv content + * @tvlv_value_len: tvlv content length + * @ctx: handler specific context information + * + * Return: NET_RX_SUCCESS if handler was found and called successfully, + * NET_RX_DROP otherwise. + */ +static int batadv_tvlv_call_handler2(struct batadv_priv *bat_priv, + u8 packet_type, u8 tvlv_type, + u8 tvlv_version, void *tvlv_value, + u16 tvlv_value_len, void *ctx) +{ + struct batadv_tvlv_handler *tvlv_handler; + int ret; + + tvlv_handler = batadv_tvlv_handler_get(bat_priv, packet_type, tvlv_type, + tvlv_version); + if (!tvlv_handler) + return NET_RX_DROP; + + ret = tvlv_handler->handler(bat_priv, tvlv_value, tvlv_value_len, ctx); + tvlv_handler->flags |= BATADV_TVLV_HANDLER_CALLED; + + batadv_tvlv_handler_put(tvlv_handler); + + return ret; +} + +/** + * batadv_tvlv_call_unfound_handlers - call any handler not called yet + * @bat_priv: the bat priv with all the soft interface information + * @packet_type: the packet type to call handlers of unfound TVLVs for + * @ctx: handler specific context information + * + * For any registered TVLV handler with a CIFNOTFND flag: If a matching + * tvlv type was not found in a specific packet (type) then this calls the + * according handler with an empty (NULL) tvlv_value and tvlv_value_len of + * zero now. + */ +static void batadv_tvlv_call_unfound_handlers(struct batadv_priv *bat_priv, + int packet_type, void *ctx) +{ + struct batadv_tvlv_handler *tvlv_handler; + + rcu_read_lock(); + hlist_for_each_entry_rcu(tvlv_handler, + &bat_priv->tvlv.handler_list, list) { + if (tvlv_handler->packet_type != packet_type) + continue; + + if ((tvlv_handler->flags & BATADV_TVLV_HANDLER_CIFNOTFND) && + !(tvlv_handler->flags & BATADV_TVLV_HANDLER_CALLED)) + tvlv_handler->handler(bat_priv, NULL, 0, ctx); + + tvlv_handler->flags &= ~BATADV_TVLV_HANDLER_CALLED; + } + rcu_read_unlock(); +} + +/** + * batadv_tvlv_containers_process2 - parse and process TVLV content of a packet + * @bat_priv: the bat priv with all the soft interface information + * @skb: the packet to parse and process TVLV data from + * @packet_type: the packet type to call handlers for + * @tvlv_offset: offset from the skb data pointer to the first tvlv header + * @tvlv_value_len: total tvlv content length (sum of all tvlv headers+values) + * @ctx: handler specific context information + * + * This function parses TVLV options of the given skb and tries to call the + * appropriate, registered handlers. + * + * In the end, all not yet called handlers (because no appropriate TVLV was + * found in the packet) which were registered with a CIFNOTFND flag are + * called with empty tvlv_value pointers. + * + * Return: NET_RX_SUCCESS if all TVLVs were known and parsed, as well as + * any TVLV handler called successfully. Returns NET_RX_DROP otherwise. + */ +int batadv_tvlv_containers_process2(struct batadv_priv *bat_priv, + const struct sk_buff *skb, u8 packet_type, + unsigned int tvlv_offset, + u16 tvlv_value_len, void *ctx) +{ + struct batadv_tvlv_hdr *tvlv_hdr, tvlv_hdr_buff; + u8 *tvlv_value, tvlv_value_buff[128]; + u16 tvlv_value_cont_len; + int ret = NET_RX_SUCCESS; + + while (tvlv_value_len >= sizeof(*tvlv_hdr)) { + tvlv_hdr = skb_header_pointer(skb, tvlv_offset, + sizeof(tvlv_hdr_buff), + &tvlv_hdr_buff); + if (!tvlv_hdr) + return NET_RX_DROP; + + tvlv_value_cont_len = ntohs(tvlv_hdr->len); + tvlv_offset += sizeof(*tvlv_hdr); + tvlv_value_len -= sizeof(*tvlv_hdr); + + if (tvlv_value_cont_len > sizeof(tvlv_value_buff)) { + pr_warn_once("batman-adv: TVLVs greater than 128 bytes unsupported for now, ignoring\n"); + goto skip_handler_call; + } + + if (tvlv_value_cont_len > tvlv_value_len) + return NET_RX_DROP; + + tvlv_value = skb_header_pointer(skb, tvlv_offset, + tvlv_value_cont_len, + tvlv_value_buff); + if (!tvlv_value) + return NET_RX_DROP; + + ret |= batadv_tvlv_call_handler2(bat_priv, packet_type, + tvlv_hdr->type, + tvlv_hdr->version, tvlv_value, + tvlv_value_cont_len, ctx); +skip_handler_call: + tvlv_offset += tvlv_value_cont_len; + tvlv_value_len -= tvlv_value_cont_len; + } + + batadv_tvlv_call_unfound_handlers(bat_priv, packet_type, ctx); + + return ret; +} + +/** * batadv_tvlv_containers_process - parse the given tvlv buffer to call the * appropriate handlers * @bat_priv: the bat priv with all the soft interface information @@ -429,7 +569,7 @@ int batadv_tvlv_containers_process(struct batadv_priv *bat_priv, struct batadv_tvlv_handler *tvlv_handler; struct batadv_tvlv_hdr *tvlv_hdr; u16 tvlv_value_cont_len; - u8 cifnotfound = BATADV_TVLV_HANDLER_OGM_CIFNOTFND; + u8 cifnotfound = BATADV_TVLV_HANDLER_CIFNOTFND; int ret = NET_RX_SUCCESS;
while (tvlv_value_len >= sizeof(*tvlv_hdr)) { @@ -441,7 +581,7 @@ int batadv_tvlv_containers_process(struct batadv_priv *bat_priv, if (tvlv_value_cont_len > tvlv_value_len) break;
- tvlv_handler = batadv_tvlv_handler_get(bat_priv, + tvlv_handler = batadv_tvlv_handler_get(bat_priv, -1, tvlv_hdr->type, tvlv_hdr->version);
@@ -461,12 +601,15 @@ int batadv_tvlv_containers_process(struct batadv_priv *bat_priv, rcu_read_lock(); hlist_for_each_entry_rcu(tvlv_handler, &bat_priv->tvlv.handler_list, list) { - if ((tvlv_handler->flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND) && - !(tvlv_handler->flags & BATADV_TVLV_HANDLER_OGM_CALLED)) + if (tvlv_handler->packet_type != -1) + continue; + + if ((tvlv_handler->flags & BATADV_TVLV_HANDLER_CIFNOTFND) && + !(tvlv_handler->flags & BATADV_TVLV_HANDLER_CALLED)) tvlv_handler->ogm_handler(bat_priv, orig_node, cifnotfound, NULL, 0);
- tvlv_handler->flags &= ~BATADV_TVLV_HANDLER_OGM_CALLED; + tvlv_handler->flags &= ~BATADV_TVLV_HANDLER_CALLED; } rcu_read_unlock();
@@ -474,30 +617,128 @@ int batadv_tvlv_containers_process(struct batadv_priv *bat_priv, }
/** + * batadv_tvlv_ogm_pack_ctx - pack context to be passed to OGM TVLV handlers + * @orig_node: An orig_node to pack (mandatory, may *not* be NULL!) + * + * This packs the context, here the orig_node the packet came from, so that + * it is later available to the to be called OGM TVLV handlers. + * + * Return: The wrapped context. + */ +void *batadv_tvlv_ogm_pack_ctx(struct batadv_orig_node *orig_node) +{ + WARN_ON(!orig_node); + return (void *)orig_node; +} + +/** + * batadv_tvlv_ogm_unpack_ctx - unpack context received with a TVLV handler call + * @ctx: handler specific context information (here: orig_node) + * + * This unpacks the context received within an OGM TVLV handler, here the + * orig_node the packet came from. + * + * Return: The orig_node the packet came from. + */ +struct batadv_orig_node *batadv_tvlv_ogm_unpack_ctx(void *ctx) +{ + return (struct batadv_orig_node *)ctx; +} + +/** * batadv_tvlv_ogm_receive - process an incoming ogm and call the appropriate * handlers * @bat_priv: the bat priv with all the soft interface information - * @batadv_ogm_packet: ogm packet containing the tvlv containers + * @skb: ogm packet containing the tvlv containers * @orig_node: orig node emitting the ogm packet + * + * Caller needs to ensure that the skb network header points to the appropriate + * OGM header. */ void batadv_tvlv_ogm_receive(struct batadv_priv *bat_priv, - struct batadv_ogm_packet *batadv_ogm_packet, + const struct sk_buff *skb, struct batadv_orig_node *orig_node) { + void *ctx = batadv_tvlv_ogm_pack_ctx(orig_node); + struct batadv_ogm_packet *ogm_packet; + unsigned int tvlv_offset; void *tvlv_value; u16 tvlv_value_len;
- if (!batadv_ogm_packet) + ogm_packet = (struct batadv_ogm_packet *)skb_network_header(skb); + if (!ogm_packet) return;
- tvlv_value_len = ntohs(batadv_ogm_packet->tvlv_len); + tvlv_value_len = ntohs(ogm_packet->tvlv_len); if (!tvlv_value_len) return;
- tvlv_value = batadv_ogm_packet + 1; + tvlv_offset = skb_network_offset(skb) + sizeof(*ogm_packet); + tvlv_value = ogm_packet + 1;
batadv_tvlv_containers_process(bat_priv, true, orig_node, NULL, NULL, tvlv_value, tvlv_value_len); + batadv_tvlv_containers_process2(bat_priv, skb, BATADV_IV_OGM, + tvlv_offset, tvlv_value_len, ctx); +} + +/** + * batadv_tvlv_handler_register - register a tvlv handler + * @bat_priv: the bat priv with all the soft interface information + * @handler: TVLV handler callback function + * @packet_type: packet type to register this handler for + * @tvlv_type: tvlv handler type to be registered + * @tvlv_version: tvlv handler version to be registered + * @flags: flags to enable or disable TVLV API behavior + * + * Registers a handler for incoming packets of the provided packet type. + * When a packet of this type with a matching TVLV (both tvlv type and version) + * is received then the registered handler is called with the according TVLV + * value, length and packet context. + * + * If 'flags' is set to BATADV_TVLV_HANDLER_CIFNOTFND: + * Then the handler might be called with an empty tvlv_value (NULL) and + * tvlv_value_len (zero) if a packet with a matching packet type but no + * matching TVLV was received. + */ +void batadv_tvlv_handler_register2(struct batadv_priv *bat_priv, + int (*handler)(struct batadv_priv *bat_priv, + void *tvlv_value, + u16 tvlv_value_len, + void *ctx), + u8 packet_type, u8 tvlv_type, + u8 tvlv_version, u8 flags) +{ + struct batadv_tvlv_handler *tvlv_handler; + + tvlv_handler = batadv_tvlv_handler_get(bat_priv, packet_type, tvlv_type, + tvlv_version); + if (tvlv_handler) { + batadv_tvlv_handler_put(tvlv_handler); + return; + } + + tvlv_handler = kzalloc(sizeof(*tvlv_handler), GFP_ATOMIC); + if (!tvlv_handler) + return; + + tvlv_handler->ogm_handler = NULL; + tvlv_handler->unicast_handler = NULL; + tvlv_handler->handler = handler; + tvlv_handler->packet_type = packet_type; + tvlv_handler->tvlv_type = tvlv_type; + tvlv_handler->tvlv_version = tvlv_version; + tvlv_handler->flags = flags; + kref_init(&tvlv_handler->refcount); + INIT_HLIST_NODE(&tvlv_handler->list); + + spin_lock_bh(&bat_priv->tvlv.handler_list_lock); + kref_get(&tvlv_handler->refcount); + hlist_add_head_rcu(&tvlv_handler->list, &bat_priv->tvlv.handler_list); + spin_unlock_bh(&bat_priv->tvlv.handler_list_lock); + + /* don't return reference to new tvlv_handler */ + batadv_tvlv_handler_put(tvlv_handler); }
/** @@ -510,8 +751,8 @@ void batadv_tvlv_ogm_receive(struct batadv_priv *bat_priv, * @uptr: unicast tvlv handler callback function. This function receives the * source & destination of the unicast packet as well as the tvlv content * to process. - * @type: tvlv handler type to be registered - * @version: tvlv handler version to be registered + * @tvlv_type: tvlv handler type to be registered + * @tvlv_version: tvlv handler version to be registered * @flags: flags to enable or disable TVLV API behavior */ void batadv_tvlv_handler_register(struct batadv_priv *bat_priv, @@ -524,11 +765,13 @@ void batadv_tvlv_handler_register(struct batadv_priv *bat_priv, u8 *src, u8 *dst, void *tvlv_value, u16 tvlv_value_len), - u8 type, u8 version, u8 flags) + u8 tvlv_type, u8 tvlv_version, + u8 flags) { struct batadv_tvlv_handler *tvlv_handler;
- tvlv_handler = batadv_tvlv_handler_get(bat_priv, type, version); + tvlv_handler = batadv_tvlv_handler_get(bat_priv, -1, tvlv_type, + tvlv_version); if (tvlv_handler) { batadv_tvlv_handler_put(tvlv_handler); return; @@ -540,8 +783,10 @@ void batadv_tvlv_handler_register(struct batadv_priv *bat_priv,
tvlv_handler->ogm_handler = optr; tvlv_handler->unicast_handler = uptr; - tvlv_handler->type = type; - tvlv_handler->version = version; + tvlv_handler->handler = NULL; + tvlv_handler->packet_type = -1; + tvlv_handler->tvlv_type = tvlv_type; + tvlv_handler->tvlv_version = tvlv_version; tvlv_handler->flags = flags; kref_init(&tvlv_handler->refcount); INIT_HLIST_NODE(&tvlv_handler->list); @@ -556,18 +801,47 @@ void batadv_tvlv_handler_register(struct batadv_priv *bat_priv, }
/** + * batadv_tvlv_handler_unregister2 - unregister a tvlv handler + * @bat_priv: the bat priv with all the soft interface information + * @packet_type: packet type to unregister for + * @tvlv_type: tvlv handler type to be unregistered + * @tvlv_version: tvlv handler version to be unregistered + * + * Unregisters a TVLV handler based on the provided packet type, tvlv type + * and version (all need to match). + */ +void batadv_tvlv_handler_unregister2(struct batadv_priv *bat_priv, + u8 packet_type, u8 tvlv_type, + u8 tvlv_version) +{ + struct batadv_tvlv_handler *tvlv_handler; + + tvlv_handler = batadv_tvlv_handler_get(bat_priv, packet_type, tvlv_type, + tvlv_version); + if (!tvlv_handler) + return; + + batadv_tvlv_handler_put(tvlv_handler); + spin_lock_bh(&bat_priv->tvlv.handler_list_lock); + hlist_del_rcu(&tvlv_handler->list); + spin_unlock_bh(&bat_priv->tvlv.handler_list_lock); + batadv_tvlv_handler_put(tvlv_handler); +} + +/** * batadv_tvlv_handler_unregister - unregister tvlv handler based on the * provided type and version (both need to match) * @bat_priv: the bat priv with all the soft interface information - * @type: tvlv handler type to be unregistered - * @version: tvlv handler version to be unregistered + * @tvlv_type: tvlv handler type to be unregistered + * @tvlv_version: tvlv handler version to be unregistered */ void batadv_tvlv_handler_unregister(struct batadv_priv *bat_priv, - u8 type, u8 version) + u8 tvlv_type, u8 tvlv_version) { struct batadv_tvlv_handler *tvlv_handler;
- tvlv_handler = batadv_tvlv_handler_get(bat_priv, type, version); + tvlv_handler = batadv_tvlv_handler_get(bat_priv, -1, tvlv_type, + tvlv_version); if (!tvlv_handler) return;
diff --git a/net/batman-adv/tvlv.h b/net/batman-adv/tvlv.h index e4369b5..0d2d586 100644 --- a/net/batman-adv/tvlv.h +++ b/net/batman-adv/tvlv.h @@ -22,7 +22,7 @@
#include <linux/types.h>
-struct batadv_ogm_packet; +struct sk_buff;
void batadv_tvlv_container_register(struct batadv_priv *bat_priv, u8 type, u8 version, @@ -30,12 +30,21 @@ void batadv_tvlv_container_register(struct batadv_priv *bat_priv, u16 batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv, unsigned char **packet_buff, int *packet_buff_len, int packet_min_len); +void *batadv_tvlv_ogm_pack_ctx(struct batadv_orig_node *orig_node); +struct batadv_orig_node *batadv_tvlv_ogm_unpack_ctx(void *ctx); void batadv_tvlv_ogm_receive(struct batadv_priv *bat_priv, - struct batadv_ogm_packet *batadv_ogm_packet, + const struct sk_buff *skb, struct batadv_orig_node *orig_node); void batadv_tvlv_container_unregister(struct batadv_priv *bat_priv, u8 type, u8 version);
+void batadv_tvlv_handler_register2(struct batadv_priv *bat_priv, + int (*handler)(struct batadv_priv *bat_priv, + void *tvlv_value, + u16 tvlv_value_len, + void *ctx), + u8 packet_type, u8 tvlv_type, + u8 tvlv_version, u8 flags); void batadv_tvlv_handler_register(struct batadv_priv *bat_priv, void (*optr)(struct batadv_priv *bat_priv, struct batadv_orig_node *orig, @@ -46,14 +55,21 @@ void batadv_tvlv_handler_register(struct batadv_priv *bat_priv, u8 *src, u8 *dst, void *tvlv_value, u16 tvlv_value_len), - u8 type, u8 version, u8 flags); + u8 tvlv_type, u8 tvlv_version, u8 flags); +void batadv_tvlv_handler_unregister2(struct batadv_priv *bat_priv, + u8 packet_type, u8 tvlv_type, + u8 tvlv_version); void batadv_tvlv_handler_unregister(struct batadv_priv *bat_priv, - u8 type, u8 version); + u8 tvlv_type, u8 tvlv_version); int batadv_tvlv_containers_process(struct batadv_priv *bat_priv, bool ogm_source, struct batadv_orig_node *orig_node, u8 *src, u8 *dst, void *tvlv_buff, u16 tvlv_buff_len); +int batadv_tvlv_containers_process2(struct batadv_priv *bat_priv, + const struct sk_buff *skb, u8 packet_type, + unsigned int tvlv_offset, + u16 tvlv_value_len, void *ctx); void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, u8 *src, u8 *dst, u8 type, u8 version, void *tvlv_value, u16 tvlv_value_len); diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 731bdf5..6a71522 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -1584,8 +1584,11 @@ struct batadv_tvlv_container { * incoming OGM packets * @unicast_handler: handler callback which is given the tvlv payload to process * on incoming unicast tvlv packets - * @type: tvlv type this handler feels responsible for - * @version: tvlv version this handler feels responsible for + * @handler: handler callback which is given the tvlv payload to process on + * incoming packets of the given packet type + * @packet_type: packet type this handler feels responsible for + * @tvlv_type: tvlv type this handler feels responsible for + * @tvlv_version: tvlv version this handler feels responsible for * @flags: tvlv handler flags * @refcount: number of contexts the object is used * @rcu: struct used for freeing in an RCU-safe manner @@ -1598,8 +1601,11 @@ struct batadv_tvlv_handler { int (*unicast_handler)(struct batadv_priv *bat_priv, u8 *src, u8 *dst, void *tvlv_value, u16 tvlv_value_len); - u8 type; - u8 version; + int (*handler)(struct batadv_priv *bat_priv, void *tvlv_value, + u16 tvlv_value_len, void *ctx); + int packet_type; + u8 tvlv_type; + u8 tvlv_version; u8 flags; struct kref refcount; struct rcu_head rcu; @@ -1607,15 +1613,15 @@ struct batadv_tvlv_handler {
/** * enum batadv_tvlv_handler_flags - tvlv handler flags definitions - * @BATADV_TVLV_HANDLER_OGM_CIFNOTFND: tvlv ogm processing function will call + * @BATADV_TVLV_HANDLER_CIFNOTFND: tvlv processing function will call * this handler even if its type was not found (with no data) - * @BATADV_TVLV_HANDLER_OGM_CALLED: interval tvlv handling flag - the API marks + * @BATADV_TVLV_HANDLER_CALLED: internal tvlv handling flag - the API marks * a handler as being called, so it won't be called if the - * BATADV_TVLV_HANDLER_OGM_CIFNOTFND flag was set + * BATADV_TVLV_HANDLER_CIFNOTFND flag was set */ enum batadv_tvlv_handler_flags { - BATADV_TVLV_HANDLER_OGM_CIFNOTFND = BIT(1), - BATADV_TVLV_HANDLER_OGM_CALLED = BIT(2), + BATADV_TVLV_HANDLER_CIFNOTFND = BIT(1), + BATADV_TVLV_HANDLER_CALLED = BIT(2), };
/**
On Donnerstag, 6. Oktober 2016 08:41:40 CET Linus Lüssing wrote:
@@ -1842,8 +1844,12 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb,
packet_pos = skb->data + ogm_offset; ogm_packet = (struct batadv_ogm_packet *)packet_pos;
skb_set_network_header(skb, ogm_offset); }
skb_reset_network_header(skb);
kfree_skb(skb); return NET_RX_SUCCESS;
}
Why must we skb_reset_network_header before the kfree?
Kind regards, Sven
On Wed, Dec 14, 2016 at 03:50:38PM +0100, Sven Eckelmann wrote:
On Donnerstag, 6. Oktober 2016 08:41:40 CET Linus Lüssing wrote:
@@ -1842,8 +1844,12 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb,
packet_pos = skb->data + ogm_offset; ogm_packet = (struct batadv_ogm_packet *)packet_pos;
skb_set_network_header(skb, ogm_offset); }
skb_reset_network_header(skb);
kfree_skb(skb); return NET_RX_SUCCESS;
}
Why must we skb_reset_network_header before the kfree?
Technically, yes, there's no need for it.
Usually I would have prefered keeping the skb network header pointer just after the ethernet header just like anything else on the receive path does right now. Would be messy if you could never be sure where that pointer actually points at.
On the other hand it was too convenient to use it here :).
What do you think about wrapping the WARN_ON, while loop and skb_reset_network_header() into a new function with a functional, non-modifying touch regarding the input skb?
Or do you think I should just remove the skb_reset_network_header() here?
@@ -1842,8 +1844,12 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb,
packet_pos = skb->data + ogm_offset; ogm_packet = (struct batadv_ogm_packet *)packet_pos;
skb_set_network_header(skb, ogm_offset); }
skb_reset_network_header(skb);
kfree_skb(skb); return NET_RX_SUCCESS;
}
[...] On Donnerstag, 6. Oktober 2016 08:41:40 CET Linus Lüssing wrote:
What do you think about wrapping the WARN_ON, while loop and skb_reset_network_header() into a new function with a functional, non-modifying touch regarding the input skb?
Or do you think I should just remove the skb_reset_network_header() here?
Hm, my point was not actually about the loop or the skb_set_network_header or the WARN_ON. I only don't know why a skb_reset_network_header would be necessary before a kfree_skb/consume_skb.
It also doesn't seem to be used in a later patch.
Kind regards, Sven
On Donnerstag, 6. Oktober 2016 08:41:40 CET Linus Lüssing wrote:
void *ctx = batadv_tvlv_ogm_pack_ctx(orig_node);
const struct ethhdr *ethhdr = eth_hdr(skb);
unsigned int tvlv_offset = sizeof(*ogm2);
Haven't checked the complete code yet but isn't an increase of the reference counter for orig_node missing here? Things like batadv_gw_tvlv_ogm_handler would then have to take care of dropping the reference.
Kind regards, Sven
On Mittwoch, 14. Dezember 2016 21:03:05 CET Sven Eckelmann wrote:
On Donnerstag, 6. Oktober 2016 08:41:40 CET Linus Lüssing wrote:
void *ctx = batadv_tvlv_ogm_pack_ctx(orig_node);
const struct ethhdr *ethhdr = eth_hdr(skb);
unsigned int tvlv_offset = sizeof(*ogm2);
Haven't checked the complete code yet but isn't an increase of the reference counter for orig_node missing here? Things like batadv_gw_tvlv_ogm_handler would then have to take care of dropping the reference.
Ok, forget that. batadv_tvlv_containers_process2 (which is the only user of ctx) is directly calling the function and not delaying anything. I was under the impression that their might be an delay.
But I am really not sure why you are using batadv_tvlv_ogm_pack_ctx anyway. You should be able to use "void *ctx" in batadv_tvlv_ogm_pack_ctx parameter and then give it an struct batadv_orig_node *. Or is is just for the WARN_ON?
Same for batadv_tvlv_ogm_unpack_ctx
Kind regards, Sven
On Wed, Dec 14, 2016 at 09:12:00PM +0100, Sven Eckelmann wrote:
On Mittwoch, 14. Dezember 2016 21:03:05 CET Sven Eckelmann wrote:
On Donnerstag, 6. Oktober 2016 08:41:40 CET Linus Lüssing wrote:
void *ctx = batadv_tvlv_ogm_pack_ctx(orig_node);
const struct ethhdr *ethhdr = eth_hdr(skb);
unsigned int tvlv_offset = sizeof(*ogm2);
Haven't checked the complete code yet but isn't an increase of the reference counter for orig_node missing here? Things like batadv_gw_tvlv_ogm_handler would then have to take care of dropping the reference.
Ok, forget that. batadv_tvlv_containers_process2 (which is the only user of ctx) is directly calling the function and not delaying anything. I was under the impression that their might be an delay.
But I am really not sure why you are using batadv_tvlv_ogm_pack_ctx anyway. You should be able to use "void *ctx" in batadv_tvlv_ogm_pack_ctx parameter and then give it an struct batadv_orig_node *. Or is is just for the WARN_ON?
Hm, no, had nothing to do with the WARN_ON. The idea was to have the nasty (void *) casting at least at some well-defined place.
And didn't use "void *ctx" as a parameter of _pack_ctx() directly, to have at least some compile-time verification regarding the types.
I wanted to have something a little similar to the way icmp_hdr(), icmp6_hdr(), ipv6_hdr() etc. do the casting, for instance, hm.
(or maybe I should add something like a "struct batadv_tvlv_ctx { void *ctx };" then, to really get rid of the void pointers in the functions calling the _pack()/_unpack() ones?)
On Montag, 19. Dezember 2016 11:50:27 CET Linus Lüssing wrote:
And didn't use "void *ctx" as a parameter of _pack_ctx() directly, to have at least some compile-time verification regarding the types.
I was not talking about the packing functions. I was talking about the function which is used to trigger the handlers. It is not necessary (unless I miss something) to have some explicit void * casting when its parameter type is already void *.
I wanted to have something a little similar to the way icmp_hdr(), icmp6_hdr(), ipv6_hdr() etc. do the casting, for instance, hm.
I think these functions cast from char * to something like struct icmphdr * by first retrieving the transport header from the skb. So they do a lot more than your more-than-necessary-explicit casting function.
Kind regards, Sven
On Montag, 19. Dezember 2016 12:37:43 CET Sven Eckelmann wrote:
I was not talking about the packing functions.
Just read my initial mails. Looks like I've copied the wrong function name "batadv_tvlv_ogm_pack_ctx". But I was talking about the parameter in of "batadv_tvlv_containers_process2". So I am the reason for the confusion :)
Kind regards, Sven
On Mon, Dec 19, 2016 at 12:43:49PM +0100, Sven Eckelmann wrote:
On Montag, 19. Dezember 2016 12:37:43 CET Sven Eckelmann wrote:
I was not talking about the packing functions.
Just read my initial mails. Looks like I've copied the wrong function name "batadv_tvlv_ogm_pack_ctx". But I was talking about the parameter in of "batadv_tvlv_containers_process2". So I am the reason for the confusion :)
Just to check, you suggest removing this line: https://git.open-mesh.org/batman-adv.git/blob/1ddd189528fc332bf286ffd56b629d...
And to replace the passing of "ctx" with an "orig_node" here: https://git.open-mesh.org/batman-adv.git/blob/1ddd189528fc332bf286ffd56b629d...
(which works as a "void *" parameter accepts any type, without the need of casting explicitly)
If that's what you mean, hm, not sure. Feels dangerous, such automatic casting, doesn't it?
I'm really wondering whether I should go for the approach of hiding the "void *" in a new type. And only having the "void *" fiddeling inside _pack()/_unpack() functions.
On Dienstag, 20. Dezember 2016 12:55:50 CET Linus Lüssing wrote:
On Mon, Dec 19, 2016 at 12:43:49PM +0100, Sven Eckelmann wrote:
On Montag, 19. Dezember 2016 12:37:43 CET Sven Eckelmann wrote:
I was not talking about the packing functions.
Just read my initial mails. Looks like I've copied the wrong function name "batadv_tvlv_ogm_pack_ctx". But I was talking about the parameter in of "batadv_tvlv_containers_process2". So I am the reason for the confusion :)
Just to check, you suggest removing this line: https://git.open-mesh.org/batman-adv.git/blob/1ddd189528fc332bf286ffd56b629d...
Yes
And to replace the passing of "ctx" with an "orig_node" here: https://git.open-mesh.org/batman-adv.git/blob/1ddd189528fc332bf286ffd56b629d...
Yes
(which works as a "void *" parameter accepts any type, without the need of casting explicitly)
Yes
If that's what you mean, hm, not sure. Feels dangerous, such automatic casting, doesn't it?
It is not perfect but it is the way it is already done for many things in the kernel and also in userspace. Think for example about "the argument" when you generate (k)threads and which you can then then retrieve again inside this thread.
Your current extra functions also don't prevent that there is a wrong argument added to this perticular function. They just introduce some weird extra functions. (At least this is how feel about it - their might be different opinions about that)
I'm really wondering whether I should go for the approach of hiding the "void *" in a new type. And only having the "void *" fiddeling inside _pack()/_unpack() functions.
Hm, I personally don't see a reason for a new type at the moment. But when you find a good one... at least their could be plenty of reasons which might make everything a little bit cleaner.
Just keep in mind that there are already many other things in the kernel like container_of and similar things. So don't try to overengineer it :)
Kind regards, Sven
This patch aims to reduce protocol overhead for BATMAN V by avoiding rebroadcasts of OGM2 and broadcast packets in neighborhoods where every neighbor "sees" another.
This is done by parsing and storing the new information provided by the ELP specific neighborhood hash TVLV.
We then use this new information to detect certain scenarios where a rebroadcast of OGM2 and broadcast packets on the incoming interface is unncessary.
In a nutshell the detection checks whether all neighbors see each other by comparing their with a neighbors hash. If so, then a node deciding to rebroadcast will check whether either the ingress side or the egress side might be a bottleneck metric wise. In other words, whether a rebroadcast might not enhance any throughput.
Signed-off-by: Linus Lüssing linus.luessing@c0d3.blue
---
Changes in v2: * added kerneldoc for new @skb in batadv_v_elp_neigh_update() * added include for linux/types.h in bat_v_elp.h * removed a duplicate bat_v_ogm.h include in bat_v_ogm.c * adjusted alignment for new function in algo_iface_ops (thanks Sven!) --- net/batman-adv/bat_v.c | 40 ++++- net/batman-adv/bat_v_elp.c | 316 +++++++++++++++++++++++++++++++++++++++- net/batman-adv/bat_v_elp.h | 12 ++ net/batman-adv/bat_v_ogm.c | 18 ++- net/batman-adv/bat_v_ogm.h | 4 + net/batman-adv/hard-interface.c | 47 +++--- net/batman-adv/hard-interface.h | 6 +- net/batman-adv/send.c | 8 +- net/batman-adv/types.h | 17 +++ 9 files changed, 433 insertions(+), 35 deletions(-)
diff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c index c93b589..91f8395 100644 --- a/net/batman-adv/bat_v.c +++ b/net/batman-adv/bat_v.c @@ -126,6 +126,9 @@ static void batadv_v_hardif_neigh_init(struct batadv_hardif_neigh_node *hardif_neigh) { ewma_throughput_init(&hardif_neigh->bat_v.throughput); + hardif_neigh->bat_v.min_throughput = 0; + memset(hardif_neigh->bat_v.neigh_hash, 0, + sizeof(hardif_neigh->bat_v.neigh_hash)); INIT_WORK(&hardif_neigh->bat_v.metric_work, batadv_v_elp_throughput_metric_update); } @@ -172,14 +175,33 @@ batadv_v_hardif_neigh_print(struct seq_file *seq, { int last_secs, last_msecs; u32 throughput; + char nhh_avoid_ogm = '.', nhh_avoid_bcast = '.'; + bool same_hash; + + same_hash = batadv_v_elp_nhh_cmp(hardif_neigh); + + if (same_hash) { + if (batadv_v_elp_rx_ingress_bad(hardif_neigh)) + nhh_avoid_ogm = 'A'; + + if (batadv_v_elp_rx_egress_bad(hardif_neigh)) + nhh_avoid_ogm = (nhh_avoid_ogm == '.') ? 'B' : 'C'; + + if (batadv_v_elp_tx_ingress_bad(hardif_neigh)) + nhh_avoid_bcast = 'X'; + + if (batadv_v_elp_tx_egress_bad(hardif_neigh)) + nhh_avoid_bcast = (nhh_avoid_bcast == '.') ? 'Y' : 'Z'; + }
last_secs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen) / 1000; last_msecs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen) % 1000; throughput = ewma_throughput_read(&hardif_neigh->bat_v.throughput);
- seq_printf(seq, "%pM %4i.%03is (%9u.%1u) [%10s]\n", + seq_printf(seq, "%pM %4i.%03is (%9u.%1u) [%10s] [%c%c%c]\n", hardif_neigh->addr, last_secs, last_msecs, throughput / 10, - throughput % 10, hardif_neigh->if_incoming->net_dev->name); + throughput % 10, hardif_neigh->if_incoming->net_dev->name, + same_hash ? 'H' : '.', nhh_avoid_ogm, nhh_avoid_bcast); }
/** @@ -196,7 +218,7 @@ static void batadv_v_neigh_print(struct batadv_priv *bat_priv, int batman_count = 0;
seq_puts(seq, - " Neighbor last-seen ( throughput) [ IF]\n"); + " Neighbor last-seen ( throughput) [ IF] NHH-flags\n");
rcu_read_lock(); list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { @@ -1039,6 +1061,7 @@ static struct batadv_algo_ops batadv_batman_v __read_mostly = { }, .neigh = { .hardif_init = batadv_v_hardif_neigh_init, + .hardif_no_broadcast = batadv_v_elp_no_broadcast, .cmp = batadv_v_neigh_cmp, .is_similar_or_better = batadv_v_neigh_is_sob, #ifdef CONFIG_BATMAN_ADV_DEBUGFS @@ -1081,6 +1104,9 @@ void batadv_v_hardif_init(struct batadv_hard_iface *hard_iface)
bat_v->min_throughput = 0; bat_v->max_throughput = (~(u32)0); + bat_v->min_throughput_other = 0; + bat_v->max_throughput_other = ~((u32)0); + memset(bat_v->neigh_hash, 0, sizeof(bat_v->neigh_hash)); }
@@ -1095,9 +1121,15 @@ int batadv_v_mesh_init(struct batadv_priv *bat_priv) { int ret = 0;
+ ret = batadv_v_elp_mesh_init(bat_priv); + if (ret < 0) + return ret; + ret = batadv_v_ogm_init(bat_priv); - if (ret < 0) + if (ret < 0) { + batadv_v_elp_mesh_free(bat_priv); return ret; + }
/* set default throughput difference threshold to 5Mbps */ atomic_set(&bat_priv->gw.sel_class, 50); diff --git a/net/batman-adv/bat_v_elp.c b/net/batman-adv/bat_v_elp.c index 931dd2e..ab54344 100644 --- a/net/batman-adv/bat_v_elp.c +++ b/net/batman-adv/bat_v_elp.c @@ -52,6 +52,7 @@ #include "packet.h" #include "routing.h" #include "send.h" +#include "tvlv.h"
static struct crypto_shash *tfm;
@@ -88,6 +89,7 @@ static void batadv_v_elp_update_neigh_hash(struct batadv_hard_iface *hard_iface) struct ewma_throughput *ewma_throughput; u8 *own_addr = hard_iface->net_dev->dev_addr; u32 min_throughput = ~((u32)0), max_throughput = 0; + u32 min_throughput_other = ~((u32)0), max_throughput_other = 0; u32 throughput; int ret;
@@ -129,6 +131,16 @@ static void batadv_v_elp_update_neigh_hash(struct batadv_hard_iface *hard_iface)
if (throughput > max_throughput) max_throughput = throughput; + + throughput = hardif_neigh->bat_v.min_throughput; + + if (throughput < min_throughput_other) + min_throughput_other = throughput; + + throughput = hardif_neigh->bat_v.max_throughput; + + if (throughput > max_throughput_other) + max_throughput_other = throughput; } rcu_read_unlock();
@@ -144,14 +156,18 @@ static void batadv_v_elp_update_neigh_hash(struct batadv_hard_iface *hard_iface)
hard_iface->bat_v.min_throughput = min_throughput; hard_iface->bat_v.max_throughput = max_throughput; + hard_iface->bat_v.min_throughput_other = min_throughput_other; + hard_iface->bat_v.max_throughput_other = max_throughput_other;
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, - "Updated neighbor hash on interface %s: %*phN, min_through: %u kbit/s, max_through: %u kbit/s\n", + "Updated neighbor hash on interface %s: %*phN, min_through: %u kbit/s, max_through: %u kbit/s, min_through_other: %u kbit/s, max_through_other: %u kbit/s\n", hard_iface->net_dev->name, (int)sizeof(hard_iface->bat_v.neigh_hash), hard_iface->bat_v.neigh_hash, hard_iface->bat_v.min_throughput * 100, - hard_iface->bat_v.max_throughput * 100); + hard_iface->bat_v.max_throughput * 100, + hard_iface->bat_v.min_throughput_other * 100, + hard_iface->bat_v.max_throughput_other * 100);
return;
@@ -160,6 +176,8 @@ err: sizeof(hard_iface->bat_v.neigh_hash)); hard_iface->bat_v.min_throughput = 0; hard_iface->bat_v.max_throughput = ~((u32)0); + hard_iface->bat_v.min_throughput_other = 0; + hard_iface->bat_v.max_throughput_other = ~((u32)0);
pr_warn_once("An error occurred while calculating neighbor hash for %s\n", hard_iface->net_dev->name); @@ -573,8 +591,38 @@ void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *primary_iface) }
/** + * batadv_v_elp_pack_ctx - pack context to be passed to an ELP TVLV handler + * @hardif_neigh: An hardif_neigh to pack (mandatory, may *not* be NULL!) + * + * This packs the context, here the hardif_neigh the packet came from, so that + * it is later available to the to be called ELP TVLV handler. + * + * Return: The wrapped context. + */ +static void * +batadv_v_elp_pack_ctx(struct batadv_hardif_neigh_node *hardif_neigh) +{ + return (void *)hardif_neigh; +} + +/** + * batadv_v_elp_unpack_ctx - unpack context received with a TVLV handler call + * @ctx: The context container to unpack + * + * This unpacks the context received within an ELP TVLV handler, here the + * hardif_neigh the packet came from. + * + * Return: The hardif_neigh the packet came from. + */ +static struct batadv_hardif_neigh_node *batadv_v_elp_unpack_ctx(void *ctx) +{ + return (struct batadv_hardif_neigh_node *)ctx; +} + +/** * batadv_v_elp_neigh_update - update an ELP neighbour node * @bat_priv: the bat priv with all the soft interface information + * @skb: the received packet * @neigh_addr: the neighbour interface address * @if_incoming: the interface the packet was received through * @elp_packet: the received ELP packet @@ -583,6 +631,7 @@ void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *primary_iface) * ELP packet. */ static void batadv_v_elp_neigh_update(struct batadv_priv *bat_priv, + struct sk_buff *skb, u8 *neigh_addr, struct batadv_hard_iface *if_incoming, struct batadv_elp_packet *elp_packet) @@ -591,6 +640,8 @@ static void batadv_v_elp_neigh_update(struct batadv_priv *bat_priv, struct batadv_neigh_node *neigh; struct batadv_orig_node *orig_neigh; struct batadv_hardif_neigh_node *hardif_neigh; + unsigned int tvlv_offset = sizeof(*elp_packet); + void *ctx; s32 seqno_diff; s32 elp_latest_seqno;
@@ -607,6 +658,11 @@ static void batadv_v_elp_neigh_update(struct batadv_priv *bat_priv, if (!hardif_neigh) goto neigh_free;
+ ctx = batadv_v_elp_pack_ctx(hardif_neigh); + + batadv_tvlv_containers_process2(bat_priv, skb, BATADV_ELP, tvlv_offset, + ntohs(elp_packet->tvlv_len), ctx); + elp_latest_seqno = hardif_neigh->bat_v.elp_latest_seqno; seqno_diff = ntohl(elp_packet->seqno) - elp_latest_seqno;
@@ -673,7 +729,7 @@ int batadv_v_elp_packet_recv(struct sk_buff *skb, if (!primary_if) goto out;
- batadv_v_elp_neigh_update(bat_priv, ethhdr->h_source, if_incoming, + batadv_v_elp_neigh_update(bat_priv, skb, ethhdr->h_source, if_incoming, elp_packet);
out: @@ -684,6 +740,260 @@ out: }
/** + * batadv_v_elp_nhh_cmp - compares a neighbor's hash with the own one + * @hardif_neigh: the hardif_neigh to compare with + * + * Checks whether the neighbor hash a neighbor advertised matches our own + * hash, the one we computed for the same interface. + * + * Return: True, if the hashes match, false otherwise. + */ +bool batadv_v_elp_nhh_cmp(struct batadv_hardif_neigh_node *hardif_neigh) +{ + return !memcmp(hardif_neigh->if_incoming->bat_v.neigh_hash, + hardif_neigh->bat_v.neigh_hash, + sizeof(hardif_neigh->bat_v.neigh_hash)); +} + +/** + * batadv_v_elp_rx_ingress_bad - check for ingress RX-metric bottlenecks + * @hardif_neigh: the hardif_neigh a packet was received from + * + * Checks whether we could potentially be a better path for packets + * coming from the given hardif_neigh to any neighbor on the same interface. + * Or whether there is some bottleneck making us unfavourable to become + * a forwarder for packets from this hardif_neigh. + * + * More specifically, this function checks whether our ingress side, that + * is the connection from us to the given hardif_neigh, is worse than the + * direct transmission any other neighbor to this hardif_neigh. + * + * Return: True if our incoming side a bottleneck, false otherwise. + */ + +bool batadv_v_elp_rx_ingress_bad(struct batadv_hardif_neigh_node *hardif_neigh) +{ + struct batadv_hard_iface *iface = hardif_neigh->if_incoming; + struct batadv_priv *bat_priv = netdev_priv(iface->soft_iface); + u32 throughput = ewma_throughput_read(&hardif_neigh->bat_v.throughput); + u32 limit = iface->bat_v.min_throughput_other; + + throughput = batadv_v_forward_penalty(bat_priv, iface, iface, + throughput); + + return throughput < limit; +} + +/** + * batadv_v_elp_rx_egress_bad - check for egress RX-metric bottlenecks + * @hardif_neigh: the hardif_neigh a packet was received from + * + * Checks whether we could potentially be a better path for packets + * coming from the given hardif_neigh to any neighbor on the same interface. + * Or whether there is some bottleneck making us unfavourable to become + * a forwarder for packets from this hardif_neigh. + * + * More specifically, this function checks whether our egress side, that is + * the connection from from any neighbor other than hardif_neigh to us, is + * worse than the direct transmission of any other neighbor to this + * hardif_neigh. + * + * Return: True if our outgoing side a bottleneck, false otherwise. + */ +bool batadv_v_elp_rx_egress_bad(struct batadv_hardif_neigh_node *hardif_neigh) +{ + struct batadv_hard_iface *iface = hardif_neigh->if_incoming; + struct batadv_priv *bat_priv = netdev_priv(iface->soft_iface); + u32 throughput = iface->bat_v.max_throughput_other; + u32 limit = iface->bat_v.min_throughput_other; + + throughput = batadv_v_forward_penalty(bat_priv, iface, iface, + throughput); + + return throughput < limit; +} + +/** + * batadv_v_elp_tx_ingress_bad - check for ingress TX-metric bottlenecks + * @hardif_neigh: the hardif_neigh a packet was received from + * + * Checks whether we could potentially be a better path for packets + * coming from the given hardif_neigh to any neighbor on the same interface. + * Or whether there is some bottleneck making us unfavourable to become + * a forwarder for packets from this hardif_neigh. + * + * More specifically, this function checks whether our ingress side, that + * is the connection from the given hardif_neigh to us, is worse than the + * direct transmission of the hardif_neigh to any other neighbor. + * + * Return: True if our incoming side a bottleneck, false otherwise. + */ +bool batadv_v_elp_tx_ingress_bad(struct batadv_hardif_neigh_node *hardif_neigh) +{ + struct batadv_hard_iface *iface = hardif_neigh->if_incoming; + struct batadv_priv *bat_priv = netdev_priv(iface->soft_iface); + u32 throughput = hardif_neigh->bat_v.max_throughput; + u32 limit = hardif_neigh->bat_v.min_throughput; + + throughput = batadv_v_forward_penalty(bat_priv, iface, iface, + throughput); + + return throughput < limit; +} + +/** + * batadv_v_elp_tx_egress_bad - check for egress TX-metric bottlenecks + * @hardif_neigh: the hardif_neigh a packet was received from + * + * Checks whether we could potentially be a better path for packets + * coming from the given hardif_neigh to any neighbor on the same interface. + * Or whether there is some bottleneck making us unfavourable to become + * a forwarder for packets from this hardif_neigh. + * + * More specifically, this function checks whether our egress side, that is + * the connection from us to any neighbor other than hardif_neigh, is + * worse than the direct transmission of the hardif_neigh to any other neighbor. + * + * Return: True if our outgoing side a bottleneck, false otherwise. + */ +bool batadv_v_elp_tx_egress_bad(struct batadv_hardif_neigh_node *hardif_neigh) +{ + struct batadv_hard_iface *iface = hardif_neigh->if_incoming; + struct batadv_priv *bat_priv = netdev_priv(iface->soft_iface); + u32 throughput = iface->bat_v.max_throughput; + u32 limit = hardif_neigh->bat_v.min_throughput; + + throughput = batadv_v_forward_penalty(bat_priv, iface, iface, + throughput); + + return throughput < limit; +} + +/** + * batadv_v_elp_no_broadcast - checks whether a rebroadcast can be avoided + * @if_outgoing: the outgoing interface to be considered for rebroadcast + * @hardif_neigh: the hardif_neigh the packet came from + * @inverse_metric: the metric direction to use (e.g. "true" for OGMs, "false" + * for broadcast packets + * + * This function checks whether with the information available to/from ELP, a + * rebroadcast of an OGM2 or broadcast packet on an interface can be + * avoided. + * + * The inverse_metric parameter indicates whether the considered packet + * should follow the best RX (inverse_metric = "true", e.g. OGMs) or TX + * path (inverse_metric = "false", e.g. broadcast packets). + * + * Return: True, if a rebroadcast can be avoided, false otherwise. + */ +bool batadv_v_elp_no_broadcast(struct batadv_hard_iface *if_outgoing, + struct batadv_hardif_neigh_node *hardif_neigh, + bool inverse_metric) +{ + if (!if_outgoing || !hardif_neigh) + return false; + + /* ELP does not provide information across inferface domains */ + if (if_outgoing != hardif_neigh->if_incoming) + return false; + + if (!batadv_v_elp_nhh_cmp(hardif_neigh)) + return false; + + /* same neighborhood, is a better path possible? */ + if (inverse_metric) { + /* OGM2 check */ + if (batadv_v_elp_rx_ingress_bad(hardif_neigh) || + batadv_v_elp_rx_egress_bad(hardif_neigh)) + return true; + } else { + /* broadcast packet check */ + if (batadv_v_elp_tx_ingress_bad(hardif_neigh) || + batadv_v_elp_tx_egress_bad(hardif_neigh)) + return true; + } + + return false; +} + +/** + * batadv_v_elp_tvlv_handler_nhh - process incoming NHH tvlv container + * @bat_priv: the bat priv with all the soft interface information + * @tvlv_value: tvlv buffer containing the neighborhood hash data + * @tvlv_value_len: tvlv buffer length + * @ctx: handler specific context information (here: hardif_neigh) + * + * Return: NET_RX_DROP on parsing errors, NET_RX_SUCCESS otherwise. + */ +static int batadv_v_elp_tvlv_handler_nhh(struct batadv_priv *bat_priv, + void *tvlv_value, u16 tvlv_value_len, + void *ctx) +{ + struct batadv_hardif_neigh_node *hardif_neigh; + struct batadv_tvlv_nhh_data *nhh_data; + u32 min_throughput = 0; + u32 max_throughput = (~(u32)0); + + hardif_neigh = batadv_v_elp_unpack_ctx(ctx); + if (WARN_ON(!hardif_neigh)) + return NET_RX_DROP; + + if (tvlv_value) { + if (tvlv_value_len < sizeof(*nhh_data)) + return NET_RX_DROP; + + nhh_data = (struct batadv_tvlv_nhh_data *)tvlv_value; + + memcpy(hardif_neigh->bat_v.neigh_hash, nhh_data->neigh_hash, + sizeof(hardif_neigh->bat_v.neigh_hash)); + min_throughput = ntohl(nhh_data->min_throughput); + max_throughput = ntohl(nhh_data->max_throughput); + } else { + memset(hardif_neigh->bat_v.neigh_hash, 0, + sizeof(hardif_neigh->bat_v.neigh_hash)); + } + + hardif_neigh->bat_v.min_throughput = min_throughput; + hardif_neigh->bat_v.max_throughput = max_throughput; + + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Got neighbor hash on interface %s from %pM: %*phN, min_through: %u kbit/s, max_through: %u kbit/s\n", + hardif_neigh->if_incoming->net_dev->name, + hardif_neigh->addr, + (int)sizeof(hardif_neigh->bat_v.neigh_hash), + hardif_neigh->bat_v.neigh_hash, + hardif_neigh->bat_v.min_throughput * 100, + hardif_neigh->bat_v.max_throughput * 100); + + return NET_RX_SUCCESS; +} + +/** + * batadv_v_elp_mesh_init - initialize the ELP private resources for a mesh + * @bat_priv: the object representing the mesh interface to initialise + * + * Return: Always returns 0. + */ +int batadv_v_elp_mesh_init(struct batadv_priv *bat_priv) +{ + batadv_tvlv_handler_register2(bat_priv, batadv_v_elp_tvlv_handler_nhh, + BATADV_ELP, BATADV_TVLV_NHH, 1, + BATADV_TVLV_HANDLER_CIFNOTFND); + + return 0; +} + +/** + * batadv_v_elp_mesh_free - free the ELP private resources for a mesh + * @bat_priv: the object representing the mesh interface to free + */ +void batadv_v_elp_mesh_free(struct batadv_priv *bat_priv) +{ + batadv_tvlv_handler_unregister2(bat_priv, BATADV_ELP, BATADV_TVLV_NHH, + 1); +} + +/** * batadv_v_elp_init - initialize global ELP structures * * Return: A negative value on error, zero on success. diff --git a/net/batman-adv/bat_v_elp.h b/net/batman-adv/bat_v_elp.h index ed5936c..7029f5a 100644 --- a/net/batman-adv/bat_v_elp.h +++ b/net/batman-adv/bat_v_elp.h @@ -20,9 +20,13 @@
#include "main.h"
+#include <linux/types.h> + struct sk_buff; struct work_struct;
+int batadv_v_elp_mesh_init(struct batadv_priv *bat_priv); +void batadv_v_elp_mesh_free(struct batadv_priv *bat_priv); int batadv_v_elp_init(void); void batadv_v_elp_free(void); int batadv_v_elp_iface_enable(struct batadv_hard_iface *hard_iface); @@ -32,6 +36,14 @@ void batadv_v_elp_iface_activate(struct batadv_hard_iface *primary_iface, void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *primary_iface); int batadv_v_elp_packet_recv(struct sk_buff *skb, struct batadv_hard_iface *if_incoming); +bool batadv_v_elp_nhh_cmp(struct batadv_hardif_neigh_node *hardif_neigh); +bool batadv_v_elp_rx_ingress_bad(struct batadv_hardif_neigh_node *hardif_neigh); +bool batadv_v_elp_rx_egress_bad(struct batadv_hardif_neigh_node *hardif_neigh); +bool batadv_v_elp_tx_ingress_bad(struct batadv_hardif_neigh_node *hardif_neigh); +bool batadv_v_elp_tx_egress_bad(struct batadv_hardif_neigh_node *hardif_neigh); +bool batadv_v_elp_no_broadcast(struct batadv_hard_iface *if_outgoing, + struct batadv_hardif_neigh_node *hardif_neigh, + bool inverse_metric); void batadv_v_elp_throughput_metric_update(struct work_struct *work);
#endif /* _NET_BATMAN_ADV_BAT_V_ELP_H_ */ diff --git a/net/batman-adv/bat_v_ogm.c b/net/batman-adv/bat_v_ogm.c index 606f899..2c1d5b4 100644 --- a/net/batman-adv/bat_v_ogm.c +++ b/net/batman-adv/bat_v_ogm.c @@ -183,7 +183,7 @@ static void batadv_v_ogm_send(struct work_struct *work) if (!kref_get_unless_zero(&hard_iface->refcount)) continue;
- ret = batadv_hardif_no_broadcast(hard_iface, NULL, NULL); + ret = batadv_hardif_no_broadcast(hard_iface, NULL, NULL, true); if (ret) { char *type;
@@ -197,6 +197,9 @@ static void batadv_v_ogm_send(struct work_struct *work) case BATADV_HARDIF_BCAST_DUPORIG: type = "single neighbor is originator"; break; + case BATADV_HARDIF_BCAST_WORSENHH: + type = "worse neighborhood metric"; + break; default: type = "unknown"; } @@ -289,10 +292,10 @@ void batadv_v_ogm_primary_iface_set(struct batadv_hard_iface *primary_iface) * * Return: the penalised throughput metric. */ -static u32 batadv_v_forward_penalty(struct batadv_priv *bat_priv, - struct batadv_hard_iface *if_incoming, - struct batadv_hard_iface *if_outgoing, - u32 throughput) +u32 batadv_v_forward_penalty(struct batadv_priv *bat_priv, + struct batadv_hard_iface *if_incoming, + struct batadv_hard_iface *if_outgoing, + u32 throughput) { int hop_penalty = atomic_read(&bat_priv->hop_penalty); int hop_penalty_max = BATADV_TQ_MAX_VALUE; @@ -752,7 +755,7 @@ static void batadv_v_ogm_process(const struct sk_buff *skb, int ogm_offset,
ret = batadv_hardif_no_broadcast(hard_iface, ogm_packet->orig, - hardif_neigh->orig); + hardif_neigh, true);
if (ret) { char *type; @@ -767,6 +770,9 @@ static void batadv_v_ogm_process(const struct sk_buff *skb, int ogm_offset, case BATADV_HARDIF_BCAST_DUPORIG: type = "single neighbor is originator"; break; + case BATADV_HARDIF_BCAST_WORSENHH: + type = "worse neighborhood metric"; + break; default: type = "unknown"; } diff --git a/net/batman-adv/bat_v_ogm.h b/net/batman-adv/bat_v_ogm.h index 4c4d45c..de01593 100644 --- a/net/batman-adv/bat_v_ogm.h +++ b/net/batman-adv/bat_v_ogm.h @@ -30,6 +30,10 @@ int batadv_v_ogm_iface_enable(struct batadv_hard_iface *hard_iface); struct batadv_orig_node *batadv_v_ogm_orig_get(struct batadv_priv *bat_priv, const u8 *addr); void batadv_v_ogm_primary_iface_set(struct batadv_hard_iface *primary_iface); +u32 batadv_v_forward_penalty(struct batadv_priv *bat_priv, + struct batadv_hard_iface *if_incoming, + struct batadv_hard_iface *if_outgoing, + u32 throughput); int batadv_v_ogm_packet_recv(struct sk_buff *skb, struct batadv_hard_iface *if_incoming);
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index dc1816e..7037910 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -232,8 +232,9 @@ bool batadv_is_wifi_netdev(struct net_device *net_device) * batadv_hardif_no_broadcast - check whether (re)broadcast is necessary * @if_outgoing: the outgoing interface checked and considered for (re)broadcast * @orig_addr: the originator of this packet - * @orig_neigh: originator address of the forwarder we just got the packet from - * (NULL if we originated) + * @hardif_neigh: the neighbor we got this packet from (NULL if we originated) + * @inverse_metric: the metric direction to use (e.g. "true" for OGMs, "false" + * for broadcast packets * * Checks whether a packet needs to be (re)broadcasted on the given interface. * @@ -241,12 +242,16 @@ bool batadv_is_wifi_netdev(struct net_device *net_device) * BATADV_HARDIF_BCAST_NORECIPIENT: No neighbor on interface * BATADV_HARDIF_BCAST_DUPFWD: Just one neighbor, but it is the forwarder * BATADV_HARDIF_BCAST_DUPORIG: Just one neighbor, but it is the originator + * BATADV_HARDIF_BCAST_WORSENHH: ELP detected a worse neighborhood metric * BATADV_HARDIF_BCAST_OK: Several neighbors, must broadcast */ int batadv_hardif_no_broadcast(struct batadv_hard_iface *if_outgoing, - u8 *orig_addr, u8 *orig_neigh) + u8 *orig_addr, + struct batadv_hardif_neigh_node *hardif_neigh, + bool inverse_metric) { - struct batadv_hardif_neigh_node *hardif_neigh; + struct batadv_priv *bat_priv = netdev_priv(if_outgoing->soft_iface); + struct batadv_hardif_neigh_node *hardif_neigh_cmp; struct hlist_node *first; int ret = BATADV_HARDIF_BCAST_OK;
@@ -259,22 +264,30 @@ int batadv_hardif_no_broadcast(struct batadv_hard_iface *if_outgoing, goto out; }
- /* >1 neighbors -> (re)brodcast */ - if (rcu_dereference(hlist_next_rcu(first))) - goto out; + /* single neighbor checks */ + if (!rcu_dereference(hlist_next_rcu(first)) && hardif_neigh) { + hardif_neigh_cmp = hlist_entry(first, + struct batadv_hardif_neigh_node, + list);
- hardif_neigh = hlist_entry(first, struct batadv_hardif_neigh_node, - list); - - /* 1 neighbor, is the originator -> no rebroadcast */ - if (orig_addr && batadv_compare_eth(hardif_neigh->orig, orig_addr)) { - ret = BATADV_HARDIF_BCAST_DUPORIG; - /* 1 neighbor, is the one we received from -> no rebroadcast */ - } else if (orig_neigh && - batadv_compare_eth(hardif_neigh->orig, orig_neigh)) { - ret = BATADV_HARDIF_BCAST_DUPFWD; + /* 1 neighbor, is the originator -> no rebroadcast */ + if (batadv_compare_eth(hardif_neigh_cmp->orig, orig_addr)) { + ret = BATADV_HARDIF_BCAST_DUPORIG; + goto out; + /* 1 neighbor, is the one we received from -> no rebroadcast */ + } else if (batadv_compare_eth(hardif_neigh_cmp->orig, + hardif_neigh->orig)) { + ret = BATADV_HARDIF_BCAST_DUPFWD; + goto out; + } }
+ if (bat_priv->algo_ops->neigh.hardif_no_broadcast && + bat_priv->algo_ops->neigh.hardif_no_broadcast(if_outgoing, + hardif_neigh, + inverse_metric)) + ret = BATADV_HARDIF_BCAST_WORSENHH; + out: rcu_read_unlock(); return ret; diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h index a043182..d75b767 100644 --- a/net/batman-adv/hard-interface.h +++ b/net/batman-adv/hard-interface.h @@ -45,12 +45,14 @@ enum batadv_hard_if_state { * @BATADV_HARDIF_BCAST_NORECIPIENT: Broadcast not needed, there is no recipient * @BATADV_HARDIF_BCAST_DUPFWD: There is just the neighbor we got it from * @BATADV_HARDIF_BCAST_DUPORIG: There is just the originator + * @BATADV_HARDIF_BCAST_WORSENHH: ELP detected a worse neighborhood metric */ enum batadv_hard_if_bcast { BATADV_HARDIF_BCAST_OK = 0, BATADV_HARDIF_BCAST_NORECIPIENT, BATADV_HARDIF_BCAST_DUPFWD, BATADV_HARDIF_BCAST_DUPORIG, + BATADV_HARDIF_BCAST_WORSENHH, };
/** @@ -78,7 +80,9 @@ int batadv_hardif_min_mtu(struct net_device *soft_iface); void batadv_update_min_mtu(struct net_device *soft_iface); void batadv_hardif_release(struct kref *ref); int batadv_hardif_no_broadcast(struct batadv_hard_iface *if_outgoing, - u8 *orig_addr, u8 *orig_neigh); + u8 *orig_addr, + struct batadv_hardif_neigh_node *hardif_neigh, + bool inverse_metric);
/** * batadv_hardif_put - decrement the hard interface refcounter and possibly diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index 041de77..56bf8eb 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -788,7 +788,6 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work) struct net_device *soft_iface; struct batadv_priv *bat_priv; u8 *neigh_addr; - u8 *orig_neigh; unsigned long send_time = jiffies + msecs_to_jiffies(5); int ret = 0;
@@ -823,10 +822,8 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work) neigh_addr); }
- orig_neigh = neigh_node ? neigh_node->orig : NULL; - ret = batadv_hardif_no_broadcast(hard_iface, bcast_packet->orig, - orig_neigh); + neigh_node, false);
if (ret) { char *type; @@ -841,6 +838,9 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work) case BATADV_HARDIF_BCAST_DUPORIG: type = "single neighbor is originator"; break; + case BATADV_HARDIF_BCAST_WORSENHH: + type = "worse neighborhood metric"; + break; default: type = "unknown"; } diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 6a71522..2f35a97 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -111,6 +111,8 @@ enum batadv_v_hard_iface_flags { * @flags: interface specific flags * @min_throughput: worst of all TX throughputs this neighbor has to others * @max_throughput: best of all TX throughputs this neighbor has to others + * @min_throughput_other: worst of all min_throughput's of other neighbors + * @max_throughput_other: worst of all max_throughput's of other neighbors * @neigh_hash: a sha512 hash of all neighbors this neighbor sees * (hash over the alphabetically ordered, concatenated, binary representation) */ @@ -123,6 +125,8 @@ struct batadv_hard_iface_bat_v { u8 flags; u32 min_throughput; u32 max_throughput; + u32 min_throughput_other; + u32 max_throughput_other; u8 neigh_hash[SHA512_DIGEST_SIZE]; };
@@ -401,6 +405,10 @@ DECLARE_EWMA(throughput, 1024, 8) * @throughput: ewma link throughput towards this neighbor * @elp_interval: time interval between two ELP transmissions * @elp_latest_seqno: latest and best known ELP sequence number + * @min_throughput: worst of all TX throughputs this neighbor has to others + * @max_throughput: best of all TX throughputs this neighbor has to others + * @neigh_hash: a sha512 hash of all neighbors this neighbor sees + * (hash over the alphabetically ordered, concatenated, binary representation) * @last_unicast_tx: when the last unicast packet has been sent to this neighbor * @metric_work: work queue callback item for metric update */ @@ -408,6 +416,9 @@ struct batadv_hardif_neigh_node_bat_v { struct ewma_throughput throughput; u32 elp_interval; u32 elp_latest_seqno; + u32 min_throughput; + u32 max_throughput; + u8 neigh_hash[SHA512_DIGEST_SIZE]; unsigned long last_unicast_tx; struct work_struct metric_work; }; @@ -1426,6 +1437,8 @@ struct batadv_algo_iface_ops { * struct batadv_algo_neigh_ops - mesh algorithm callbacks (neighbour specific) * @hardif_init: called on creation of single hop entry * (optional) + * @hardif_no_broadcast: algorithm specific check(s) regarding rebroadcasts + * (optional) * @cmp: compare the metrics of two neighbors for their respective outgoing * interfaces * @is_similar_or_better: check if neigh1 is equally similar or better than @@ -1435,6 +1448,10 @@ struct batadv_algo_iface_ops { */ struct batadv_algo_neigh_ops { void (*hardif_init)(struct batadv_hardif_neigh_node *neigh); + bool (*hardif_no_broadcast) + (struct batadv_hard_iface *if_outgoing, + struct batadv_hardif_neigh_node *hardif_neigh, + bool inverse_metric); int (*cmp)(struct batadv_neigh_node *neigh1, struct batadv_hard_iface *if_outgoing1, struct batadv_neigh_node *neigh2,
On Donnerstag, 6. Oktober 2016 08:41:37 CET Linus Lüssing wrote:
Hi,
Here's the second broadcast avoidance patchset (rebased on the former one).
Hopefully, those two patchsets together should be an automatic approach and replacement for the (non-upstream) no-rebroadcast flag patch and the cases it is currently used for.
All patches had conflicts when I tried to apply them. Please check if the branch ecsv/pu [1] solved the conflicts correctly.
Here are the conflicts (according to rerere diff):
Patch 1 =======
--- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -559,11 +559,8 @@ struct batadv_orig_node *orig_node) { struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); -<<<<<<< - struct batadv_hardif_neigh_node *hardif_neigh = NULL, *pre_neigh; -======= struct batadv_hardif_neigh_node *hardif_neigh; ->>>>>>> + struct batadv_hardif_neigh_node *pre_neigh;
spin_lock_bh(&hard_iface->neigh_list_lock);
Patch 2 =======
--- a/net/batman-adv/Kconfig +++ b/net/batman-adv/Kconfig @@ -17,12 +17,8 @@
config BATMAN_ADV_BATMAN_V bool "B.A.T.M.A.N. V protocol (experimental)" -<<<<<<< depends on BATMAN_ADV && !(CFG80211=m && BATMAN_ADV=y) -======= - depends on BATMAN_ADV && CFG80211=y || (CFG80211=m && BATMAN_ADV=m) select CRYPTO_SHA512 ->>>>>>> default n help This option enables the B.A.T.M.A.N. V protocol, the successor
Patch 3 =======
--- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -1852,22 +1852,17 @@ skb_set_network_header(skb, ogm_offset); }
-<<<<<<< ret = NET_RX_SUCCESS;
free_skb: + skb_reset_network_header(skb); + if (ret == NET_RX_SUCCESS) consume_skb(skb); else kfree_skb(skb);
return ret; -======= - skb_reset_network_header(skb); - - kfree_skb(skb); - return NET_RX_SUCCESS; ->>>>>>> }
#ifdef CONFIG_BATMAN_ADV_DEBUGFS --- a/net/batman-adv/multicast.c +++ b/net/batman-adv/multicast.c @@ -1173,21 +1173,15 @@ */ void batadv_mcast_init(struct batadv_priv *bat_priv) { -<<<<<<< - batadv_tvlv_handler_register(bat_priv, batadv_mcast_tvlv_ogm_handler, - NULL, BATADV_TVLV_MCAST, 2, - BATADV_TVLV_HANDLER_OGM_CIFNOTFND); - - INIT_DELAYED_WORK(&bat_priv->mcast.work, batadv_mcast_mla_update); - batadv_mcast_start_timer(bat_priv); -======= batadv_tvlv_handler_register2(bat_priv, batadv_mcast_tvlv_ogm_handler, BATADV_IV_OGM, BATADV_TVLV_MCAST, 2, BATADV_TVLV_HANDLER_CIFNOTFND); batadv_tvlv_handler_register2(bat_priv, batadv_mcast_tvlv_ogm_handler, BATADV_OGM2, BATADV_TVLV_MCAST, 2, BATADV_TVLV_HANDLER_CIFNOTFND); ->>>>>>> + + INIT_DELAYED_WORK(&bat_priv->mcast.work, batadv_mcast_mla_update); + batadv_mcast_start_timer(bat_priv); }
#ifdef CONFIG_BATMAN_ADV_DEBUGFS
Patch 4 =======
--- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -797,11 +797,6 @@ unsigned long send_time = jiffies + msecs_to_jiffies(5); bool dropped = false; u8 *neigh_addr; -<<<<<<< - u8 *orig_neigh; -======= - unsigned long send_time = jiffies + msecs_to_jiffies(5); ->>>>>>> int ret = 0;
delayed_work = to_delayed_work(work);
Kind regards, Sven
[1] https://git.open-mesh.org/batman-adv.git/shortlog/refs/heads/ecsv/pu
b.a.t.m.a.n@lists.open-mesh.org