From d6f94d91f766b4205e5b0aa4b11f96271c793f6d Mon Sep 17 00:00:00 2001 From: Linus Luessing Date: Sat, 16 Jan 2016 16:40:09 +0800 Subject: batman-adv: ELP - adding basic infrastructure The B.A.T.M.A.N. protocol originally only used a single message type (called OGM) to determine the link qualities to the direct neighbors and spreading these link quality information through the whole mesh. This procedure is summarized on the BATMAN concept page and explained in details in the RFC draft published in 2008. This approach was chosen for its simplicity during the protocol design phase and the implementation. However, it also bears some drawbacks: * Wireless interfaces usually come with some packet loss, therefore a higher broadcast rate is desirable to allow a fast reaction on flaky connections. Other interfaces of the same host might be connected to Ethernet LANs / VPNs / etc which rarely exhibit packet loss would benefit from a lower broadcast rate to reduce overhead. * It generally is more desirable to detect local link quality changes at a faster rate than propagating all these changes through the entire mesh (the far end of the mesh does not need to care about local link quality changes that much). Other optimizations strategies, like reducing overhead, might be possible if OGMs weren't used for all tasks in the mesh at the same time. As a result detecting local link qualities shall be handled by an independent message type, ELP, whereas the OGM message type remains responsible for flooding the mesh with these link quality information and determining the overall path transmit qualities. Developed by Linus during a 6 months trainee study period in Ascom (Switzerland) AG. Signed-off-by: Linus Luessing Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli --- net/batman-adv/bat_v_elp.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 net/batman-adv/bat_v_elp.h (limited to 'net/batman-adv/bat_v_elp.h') diff --git a/net/batman-adv/bat_v_elp.h b/net/batman-adv/bat_v_elp.h new file mode 100644 index 000000000000..7a584d1f055b --- /dev/null +++ b/net/batman-adv/bat_v_elp.h @@ -0,0 +1,27 @@ +/* Copyright (C) 2013-2016 B.A.T.M.A.N. contributors: + * + * Linus Lüssing, Marek Lindner + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "main.h" + +#ifndef _NET_BATMAN_ADV_BAT_V_ELP_H_ +#define _NET_BATMAN_ADV_BAT_V_ELP_H_ + +int batadv_v_elp_iface_enable(struct batadv_hard_iface *hard_iface); +void batadv_v_elp_iface_disable(struct batadv_hard_iface *hard_iface); +void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *primary_iface); + +#endif /* _NET_BATMAN_ADV_BAT_V_ELP_H_ */ -- cgit v1.2.3 From 162bd64c24aba8efe68948e95e61628403106cd7 Mon Sep 17 00:00:00 2001 From: Linus Luessing Date: Sat, 16 Jan 2016 16:40:10 +0800 Subject: batman-adv: ELP - creating neighbor structures Initially developed by Linus during a 6 months trainee study period in Ascom (Switzerland) AG. Signed-off-by: Linus Luessing Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli --- net/batman-adv/bat_v.c | 23 ++++++- net/batman-adv/bat_v_elp.c | 152 +++++++++++++++++++++++++++++++++++++++++++++ net/batman-adv/bat_v_elp.h | 4 ++ net/batman-adv/main.h | 3 + net/batman-adv/types.h | 33 ++++++++++ 5 files changed, 214 insertions(+), 1 deletion(-) (limited to 'net/batman-adv/bat_v_elp.h') diff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c index 01327f627a08..0fea894855ff 100644 --- a/net/batman-adv/bat_v.c +++ b/net/batman-adv/bat_v.c @@ -22,6 +22,7 @@ #include #include "bat_v_elp.h" +#include "packet.h" static int batadv_v_iface_enable(struct batadv_hard_iface *hard_iface) { @@ -42,6 +43,12 @@ static void batadv_v_primary_iface_set(struct batadv_hard_iface *hard_iface) batadv_v_elp_primary_iface_set(hard_iface); } +static void +batadv_v_hardif_neigh_init(struct batadv_hardif_neigh_node *hardif_neigh) +{ + ewma_throughput_init(&hardif_neigh->bat_v.throughput); +} + static void batadv_v_ogm_schedule(struct batadv_hard_iface *hard_iface) { } @@ -56,6 +63,7 @@ static struct batadv_algo_ops batadv_batman_v __read_mostly = { .bat_iface_disable = batadv_v_iface_disable, .bat_iface_update_mac = batadv_v_iface_update_mac, .bat_primary_iface_set = batadv_v_primary_iface_set, + .bat_hardif_neigh_init = batadv_v_hardif_neigh_init, .bat_ogm_emit = batadv_v_ogm_emit, .bat_ogm_schedule = batadv_v_ogm_schedule, }; @@ -70,5 +78,18 @@ static struct batadv_algo_ops batadv_batman_v __read_mostly = { */ int __init batadv_v_init(void) { - return batadv_algo_register(&batadv_batman_v); + int ret; + + /* 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; + + ret = batadv_algo_register(&batadv_batman_v); + + if (ret < 0) + batadv_recv_handler_unregister(BATADV_ELP); + + return ret; } diff --git a/net/batman-adv/bat_v_elp.c b/net/batman-adv/bat_v_elp.c index bc6e046c614c..dac88fad2697 100644 --- a/net/batman-adv/bat_v_elp.c +++ b/net/batman-adv/bat_v_elp.c @@ -38,7 +38,10 @@ #include "bat_algo.h" #include "hard-interface.h" +#include "hash.h" +#include "originator.h" #include "packet.h" +#include "routing.h" #include "send.h" /** @@ -191,3 +194,152 @@ void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *primary_iface) } rcu_read_unlock(); } + +/** + * batadv_v_ogm_orig_get - retrieve and possibly create an originator node + * @bat_priv: the bat priv with all the soft interface information + * @addr: the address of the originator + * + * Return: the orig_node corresponding to the specified address. If such object + * does not exist it is allocated here. In case of allocation failure returns + * NULL. + */ +static struct batadv_orig_node * +batadv_v_ogm_orig_get(struct batadv_priv *bat_priv, + const u8 *addr) +{ + struct batadv_orig_node *orig_node; + int hash_added; + + orig_node = batadv_orig_hash_find(bat_priv, addr); + if (orig_node) + return orig_node; + + orig_node = batadv_orig_node_new(bat_priv, addr); + if (!orig_node) + return NULL; + + hash_added = batadv_hash_add(bat_priv->orig_hash, batadv_compare_orig, + batadv_choose_orig, orig_node, + &orig_node->hash_entry); + if (hash_added != 0) { + /* orig_node->refcounter is initialised to 2 by + * batadv_orig_node_new() + */ + batadv_orig_node_put(orig_node); + batadv_orig_node_put(orig_node); + orig_node = NULL; + } + + return orig_node; +} + +/** + * batadv_v_elp_neigh_update - update an ELP neighbour node + * @bat_priv: the bat priv with all the soft interface information + * @neigh_addr: the neighbour interface address + * @if_incoming: the interface the packet was received through + * @elp_packet: the received ELP packet + * + * Updates the ELP neighbour node state with the data received within the new + * ELP packet. + */ +static void batadv_v_elp_neigh_update(struct batadv_priv *bat_priv, + u8 *neigh_addr, + struct batadv_hard_iface *if_incoming, + struct batadv_elp_packet *elp_packet) + +{ + struct batadv_neigh_node *neigh; + struct batadv_orig_node *orig_neigh; + struct batadv_hardif_neigh_node *hardif_neigh; + s32 seqno_diff; + s32 elp_latest_seqno; + + orig_neigh = batadv_v_ogm_orig_get(bat_priv, elp_packet->orig); + if (!orig_neigh) + return; + + neigh = batadv_neigh_node_new(orig_neigh, if_incoming, neigh_addr); + if (!neigh) + goto orig_free; + + hardif_neigh = batadv_hardif_neigh_get(if_incoming, neigh_addr); + if (!hardif_neigh) + goto neigh_free; + + elp_latest_seqno = hardif_neigh->bat_v.elp_latest_seqno; + seqno_diff = ntohl(elp_packet->seqno) - elp_latest_seqno; + + /* known or older sequence numbers are ignored. However always adopt + * if the router seems to have been restarted. + */ + if (seqno_diff < 1 && seqno_diff > -BATADV_ELP_MAX_AGE) + goto hardif_free; + + neigh->last_seen = jiffies; + hardif_neigh->last_seen = jiffies; + hardif_neigh->bat_v.elp_latest_seqno = ntohl(elp_packet->seqno); + hardif_neigh->bat_v.elp_interval = ntohl(elp_packet->elp_interval); + +hardif_free: + if (hardif_neigh) + batadv_hardif_neigh_put(hardif_neigh); +neigh_free: + if (neigh) + batadv_neigh_node_put(neigh); +orig_free: + if (orig_neigh) + batadv_orig_node_put(orig_neigh); +} + +/** + * batadv_v_elp_packet_recv - main ELP packet handler + * @skb: the received packet + * @if_incoming: the interface this packet was received through + * + * Return: NET_RX_SUCCESS and consumes the skb if the packet was peoperly + * processed or NET_RX_DROP in case of failure. + */ +int batadv_v_elp_packet_recv(struct sk_buff *skb, + struct batadv_hard_iface *if_incoming) +{ + struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); + struct batadv_elp_packet *elp_packet; + struct batadv_hard_iface *primary_if; + struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb); + bool ret; + + ret = batadv_check_management_packet(skb, if_incoming, BATADV_ELP_HLEN); + if (!ret) + return NET_RX_DROP; + + if (batadv_is_my_mac(bat_priv, ethhdr->h_source)) + return NET_RX_DROP; + + /* did we receive a B.A.T.M.A.N. V ELP packet on an interface + * that does not have B.A.T.M.A.N. V ELP enabled ? + */ + if (strcmp(bat_priv->bat_algo_ops->name, "BATMAN_V") != 0) + return NET_RX_DROP; + + elp_packet = (struct batadv_elp_packet *)skb->data; + + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Received ELP packet from %pM seqno %u ORIG: %pM\n", + ethhdr->h_source, ntohl(elp_packet->seqno), + elp_packet->orig); + + primary_if = batadv_primary_if_get_selected(bat_priv); + if (!primary_if) + goto out; + + batadv_v_elp_neigh_update(bat_priv, ethhdr->h_source, if_incoming, + elp_packet); + +out: + if (primary_if) + batadv_hardif_put(primary_if); + consume_skb(skb); + return NET_RX_SUCCESS; +} diff --git a/net/batman-adv/bat_v_elp.h b/net/batman-adv/bat_v_elp.h index 7a584d1f055b..5a7bc398a9ef 100644 --- a/net/batman-adv/bat_v_elp.h +++ b/net/batman-adv/bat_v_elp.h @@ -20,8 +20,12 @@ #ifndef _NET_BATMAN_ADV_BAT_V_ELP_H_ #define _NET_BATMAN_ADV_BAT_V_ELP_H_ +struct sk_buff; + int batadv_v_elp_iface_enable(struct batadv_hard_iface *hard_iface); void batadv_v_elp_iface_disable(struct batadv_hard_iface *hard_iface); void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *primary_iface); +int batadv_v_elp_packet_recv(struct sk_buff *skb, + struct batadv_hard_iface *if_incoming); #endif /* _NET_BATMAN_ADV_BAT_V_ELP_H_ */ diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index 8c01f54c61f3..d91bae270f42 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h @@ -60,6 +60,9 @@ #define BATADV_TQ_LOCAL_BIDRECT_RECV_MINIMUM 1 #define BATADV_TQ_TOTAL_BIDRECT_LIMIT 1 +/* B.A.T.M.A.N. V */ +#define BATADV_ELP_MAX_AGE 64 + /* number of OGMs sent with the last tt diff */ #define BATADV_TT_OGM_APPEND_MAX 3 diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 992d5fd5554e..7fc82a5d4ac4 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 #include #include #include @@ -364,12 +365,28 @@ struct batadv_gw_node { struct rcu_head rcu; }; +DECLARE_EWMA(throughput, 1024, 8) + +/** + * struct batadv_hardif_neigh_node_bat_v - B.A.T.M.A.N. V private neighbor + * information + * @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 + */ +struct batadv_hardif_neigh_node_bat_v { + struct ewma_throughput throughput; + u32 elp_interval; + u32 elp_latest_seqno; +}; + /** * struct batadv_hardif_neigh_node - unique neighbor per hard-interface * @list: list node for batadv_hard_iface::neigh_list * @addr: the MAC address of the neighboring interface * @if_incoming: pointer to incoming hard-interface * @last_seen: when last packet via this neighbor was received + * @bat_v: B.A.T.M.A.N. V private data * @refcount: number of contexts the object is used * @rcu: struct used for freeing in a RCU-safe manner */ @@ -378,6 +395,9 @@ struct batadv_hardif_neigh_node { u8 addr[ETH_ALEN]; struct batadv_hard_iface *if_incoming; unsigned long last_seen; +#ifdef CONFIG_BATMAN_ADV_BATMAN_V + struct batadv_hardif_neigh_node_bat_v bat_v; +#endif struct kref refcount; struct rcu_head rcu; }; @@ -424,11 +444,21 @@ struct batadv_neigh_ifinfo_bat_iv { u8 real_packet_count; }; +/** + * struct batadv_neigh_ifinfo_bat_v - neighbor information per outgoing + * interface for B.A.T.M.A.N. V + * @throughput: last throughput metric received from originator via this neigh + */ +struct batadv_neigh_ifinfo_bat_v { + u32 throughput; +}; + /** * struct batadv_neigh_ifinfo - neighbor information per outgoing interface * @list: list node for batadv_neigh_node::ifinfo_list * @if_outgoing: pointer to outgoing hard-interface * @bat_iv: B.A.T.M.A.N. IV private structure + * @bat_v: B.A.T.M.A.N. V private data * @last_ttl: last received ttl from this neigh node * @refcount: number of contexts the object is used * @rcu: struct used for freeing in a RCU-safe manner @@ -437,6 +467,9 @@ struct batadv_neigh_ifinfo { struct hlist_node list; struct batadv_hard_iface *if_outgoing; struct batadv_neigh_ifinfo_bat_iv bat_iv; +#ifdef CONFIG_BATMAN_ADV_BATMAN_V + struct batadv_neigh_ifinfo_bat_v bat_v; +#endif u8 last_ttl; struct kref refcount; struct rcu_head rcu; -- cgit v1.2.3 From c833484e5f3872a38fe232c663586069d5ad9645 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Tue, 10 Nov 2015 18:50:51 +0100 Subject: batman-adv: ELP - compute the metric based on the estimated throughput In case of wireless interface retrieve the throughput by querying cfg80211. To perform this call a separate work must be scheduled because the function may sleep and this is not allowed within an RCU protected context (RCU in this case is used to iterate over all the neighbours). Use ethtool to retrieve information about an Ethernet link like HALF/FULL_DUPLEX and advertised bandwidth (e.g. 100/10Mbps). The metric is updated each time a new ELP packet is sent, this way it is possible to timely react to a metric variation which can imply (for example) a neighbour disconnection. Signed-off-by: Antonio Quartulli Signed-off-by: Marek Lindner --- net/batman-adv/Kconfig | 2 +- net/batman-adv/bat_v.c | 3 + net/batman-adv/bat_v_elp.c | 140 +++++++++++++++++++++++++++++++++++++++++++++ net/batman-adv/bat_v_elp.h | 2 + net/batman-adv/bat_v_ogm.c | 2 +- net/batman-adv/main.h | 1 + net/batman-adv/types.h | 16 ++++++ 7 files changed, 164 insertions(+), 2 deletions(-) (limited to 'net/batman-adv/bat_v_elp.h') diff --git a/net/batman-adv/Kconfig b/net/batman-adv/Kconfig index 5c148a8489da..e651dc927bfd 100644 --- a/net/batman-adv/Kconfig +++ b/net/batman-adv/Kconfig @@ -17,7 +17,7 @@ config BATMAN_ADV config BATMAN_ADV_BATMAN_V bool "B.A.T.M.A.N. V protocol (experimental)" - depends on BATMAN_ADV + depends on BATMAN_ADV && CFG80211 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 d9cb5c4922c1..ff31f2af9cfe 100644 --- a/net/batman-adv/bat_v.c +++ b/net/batman-adv/bat_v.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "bat_v_elp.h" #include "bat_v_ogm.h" @@ -65,6 +66,8 @@ static void batadv_v_hardif_neigh_init(struct batadv_hardif_neigh_node *hardif_neigh) { ewma_throughput_init(&hardif_neigh->bat_v.throughput); + INIT_WORK(&hardif_neigh->bat_v.metric_work, + batadv_v_elp_throughput_metric_update); } static void batadv_v_ogm_schedule(struct batadv_hard_iface *hard_iface) diff --git a/net/batman-adv/bat_v_elp.c b/net/batman-adv/bat_v_elp.c index 1e4d13cc267f..8376730ebd69 100644 --- a/net/batman-adv/bat_v_elp.c +++ b/net/batman-adv/bat_v_elp.c @@ -22,19 +22,23 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include #include +#include #include #include #include #include #include +#include #include "bat_algo.h" #include "bat_v_ogm.h" @@ -59,6 +63,107 @@ static void batadv_v_elp_start_timer(struct batadv_hard_iface *hard_iface) msecs_to_jiffies(msecs)); } +/** + * batadv_v_elp_get_throughput - get the throughput towards a neighbour + * @neigh: the neighbour for which the throughput has to be obtained + * + * Return: The throughput towards the given neighbour in multiples of 100kpbs + * (a value of '1' equals to 0.1Mbps, '10' equals 1Mbps, etc). + */ +static u32 batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh) +{ + struct batadv_hard_iface *hard_iface = neigh->if_incoming; + struct ethtool_link_ksettings link_settings; + struct station_info sinfo; + u32 throughput; + int ret; + + /* if the user specified a customised value for this interface, then + * return it directly + */ + throughput = atomic_read(&hard_iface->bat_v.throughput_override); + if (throughput != 0) + return throughput; + + /* if this is a wireless device, then ask its throughput through + * cfg80211 API + */ + if (batadv_is_wifi_netdev(hard_iface->net_dev)) { + if (hard_iface->net_dev->ieee80211_ptr) { + ret = cfg80211_get_station(hard_iface->net_dev, + neigh->addr, &sinfo); + if (ret == -ENOENT) { + /* Node is not associated anymore! It would be + * possible to delete this neighbor. For now set + * the throughput metric to 0. + */ + return 0; + } + if (!ret) + return sinfo.expected_throughput / 100; + } + + /* unsupported WiFi driver version */ + goto default_throughput; + } + + /* if not a wifi interface, check if this device provides data via + * ethtool (e.g. an Ethernet adapter) + */ + memset(&link_settings, 0, sizeof(link_settings)); + rtnl_lock(); + ret = __ethtool_get_link_ksettings(hard_iface->net_dev, &link_settings); + rtnl_unlock(); + if (ret == 0) { + /* link characteristics might change over time */ + if (link_settings.base.duplex == DUPLEX_FULL) + hard_iface->bat_v.flags |= BATADV_FULL_DUPLEX; + else + hard_iface->bat_v.flags &= ~BATADV_FULL_DUPLEX; + + throughput = link_settings.base.speed; + if (throughput && (throughput != SPEED_UNKNOWN)) + return throughput * 10; + } + +default_throughput: + if (!(hard_iface->bat_v.flags & BATADV_WARNING_DEFAULT)) { + batadv_info(hard_iface->soft_iface, + "WiFi driver or ethtool info does not provide information about link speeds on interface %s, therefore defaulting to hardcoded throughput values of %u.%1u Mbps. Consider overriding the throughput manually or checking your driver.\n", + hard_iface->net_dev->name, + BATADV_THROUGHPUT_DEFAULT_VALUE / 10, + BATADV_THROUGHPUT_DEFAULT_VALUE % 10); + hard_iface->bat_v.flags |= BATADV_WARNING_DEFAULT; + } + + /* if none of the above cases apply, return the base_throughput */ + return BATADV_THROUGHPUT_DEFAULT_VALUE; +} + +/** + * batadv_v_elp_throughput_metric_update - worker updating the throughput metric + * of a single hop neighbour + * @work: the work queue item + */ +void batadv_v_elp_throughput_metric_update(struct work_struct *work) +{ + struct batadv_hardif_neigh_node_bat_v *neigh_bat_v; + struct batadv_hardif_neigh_node *neigh; + + neigh_bat_v = container_of(work, struct batadv_hardif_neigh_node_bat_v, + metric_work); + neigh = container_of(neigh_bat_v, struct batadv_hardif_neigh_node, + bat_v); + + ewma_throughput_add(&neigh->bat_v.throughput, + batadv_v_elp_get_throughput(neigh)); + + /* decrement refcounter to balance increment performed before scheduling + * this task + */ + batadv_hardif_neigh_put(neigh); +} + /** * batadv_v_elp_periodic_work - ELP periodic task per interface * @work: work queue item @@ -67,6 +172,7 @@ static void batadv_v_elp_start_timer(struct batadv_hard_iface *hard_iface) */ static void batadv_v_elp_periodic_work(struct work_struct *work) { + struct batadv_hardif_neigh_node *hardif_neigh; struct batadv_hard_iface *hard_iface; struct batadv_hard_iface_bat_v *bat_v; struct batadv_elp_packet *elp_packet; @@ -108,6 +214,31 @@ static void batadv_v_elp_periodic_work(struct work_struct *work) atomic_inc(&hard_iface->bat_v.elp_seqno); + /* The throughput metric is updated on each sent packet. This way, if a + * node is dead and no longer sends packets, batman-adv is still able to + * react timely to its death. + * + * The throughput metric is updated by following these steps: + * 1) if the hard_iface is wifi => send a number of unicast ELPs for + * probing/sampling to each neighbor + * 2) update the throughput metric value of each neighbor (note that the + * value retrieved in this step might be 100ms old because the + * probing packets at point 1) could still be in the HW queue) + */ + rcu_read_lock(); + hlist_for_each_entry_rcu(hardif_neigh, &hard_iface->neigh_list, list) { + if (!kref_get_unless_zero(&hardif_neigh->refcount)) + continue; + + /* Reading the estimated throughput from cfg80211 is a task that + * may sleep and that is not allowed in an rcu protected + * context. Therefore schedule a task for that. + */ + queue_work(batadv_event_workqueue, + &hardif_neigh->bat_v.metric_work); + } + rcu_read_unlock(); + restart_timer: batadv_v_elp_start_timer(hard_iface); out: @@ -146,6 +277,15 @@ int batadv_v_elp_iface_enable(struct batadv_hard_iface *hard_iface) atomic_set(&hard_iface->bat_v.elp_seqno, random_seqno); atomic_set(&hard_iface->bat_v.elp_interval, 500); + /* assume full-duplex by default */ + hard_iface->bat_v.flags |= BATADV_FULL_DUPLEX; + + /* warn the user (again) if there is no throughput data is available */ + hard_iface->bat_v.flags &= ~BATADV_WARNING_DEFAULT; + + if (batadv_is_wifi_netdev(hard_iface->net_dev)) + hard_iface->bat_v.flags &= ~BATADV_FULL_DUPLEX; + INIT_DELAYED_WORK(&hard_iface->bat_v.elp_wq, batadv_v_elp_periodic_work); batadv_v_elp_start_timer(hard_iface); diff --git a/net/batman-adv/bat_v_elp.h b/net/batman-adv/bat_v_elp.h index 5a7bc398a9ef..e95f1bca0785 100644 --- a/net/batman-adv/bat_v_elp.h +++ b/net/batman-adv/bat_v_elp.h @@ -21,11 +21,13 @@ #define _NET_BATMAN_ADV_BAT_V_ELP_H_ struct sk_buff; +struct work_struct; int batadv_v_elp_iface_enable(struct batadv_hard_iface *hard_iface); void batadv_v_elp_iface_disable(struct batadv_hard_iface *hard_iface); void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *primary_iface); int batadv_v_elp_packet_recv(struct sk_buff *skb, struct batadv_hard_iface *if_incoming); +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 c8000962a266..d9bcbe6e7d65 100644 --- a/net/batman-adv/bat_v_ogm.c +++ b/net/batman-adv/bat_v_ogm.c @@ -339,7 +339,7 @@ static u32 batadv_v_forward_penalty(struct batadv_priv *bat_priv, */ if ((throughput > 10) && (if_incoming == if_outgoing) && - (batadv_is_wifi_netdev(if_incoming->net_dev))) + !(if_incoming->bat_v.flags & BATADV_FULL_DUPLEX)) return throughput / 2; /* hop penalty of 255 equals 100% */ diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index 2e795446208f..5c68bf2618c7 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h @@ -62,6 +62,7 @@ #define BATADV_TQ_TOTAL_BIDRECT_LIMIT 1 /* B.A.T.M.A.N. V */ +#define BATADV_THROUGHPUT_DEFAULT_VALUE 10 /* 1 Mbps */ #define BATADV_ELP_MAX_AGE 64 #define BATADV_OGM_MAX_ORIGDIFF 5 #define BATADV_OGM_MAX_AGE 64 diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index c56bb8835e60..9abfb3e73c34 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -86,6 +86,18 @@ struct batadv_hard_iface_bat_iv { atomic_t ogm_seqno; }; +/** + * enum batadv_v_hard_iface_flags - interface flags useful to B.A.T.M.A.N. V + * @BATADV_FULL_DUPLEX: tells if the connection over this link is full-duplex + * @BATADV_WARNING_DEFAULT: tells whether we have warned the user that no + * throughput data is available for this interface and that default values are + * assumed. + */ +enum batadv_v_hard_iface_flags { + BATADV_FULL_DUPLEX = BIT(0), + BATADV_WARNING_DEFAULT = BIT(1), +}; + /** * struct batadv_hard_iface_bat_v - per hard-interface B.A.T.M.A.N. V data * @elp_interval: time interval between two ELP transmissions @@ -93,6 +105,7 @@ struct batadv_hard_iface_bat_iv { * @elp_skb: base skb containing the ELP message to send * @elp_wq: workqueue used to schedule ELP transmissions * @throughput_override: throughput override to disable link auto-detection + * @flags: interface specific flags */ struct batadv_hard_iface_bat_v { atomic_t elp_interval; @@ -100,6 +113,7 @@ struct batadv_hard_iface_bat_v { struct sk_buff *elp_skb; struct delayed_work elp_wq; atomic_t throughput_override; + u8 flags; }; /** @@ -378,12 +392,14 @@ DECLARE_EWMA(throughput, 1024, 8) * @elp_interval: time interval between two ELP transmissions * @elp_latest_seqno: latest and best known ELP sequence number * @last_unicast_tx: when the last unicast packet has been sent to this neighbor + * @metric_work: work queue callback item for metric update */ struct batadv_hardif_neigh_node_bat_v { struct ewma_throughput throughput; u32 elp_interval; u32 elp_latest_seqno; unsigned long last_unicast_tx; + struct work_struct metric_work; }; /** -- cgit v1.2.3