Signed-off-by: Marek Lindner <mareklind...@neomailbox.ch>
---
 net/batman-adv/bat_v_elp.c | 62 ++++++++++++++++++++++++++++++++++++--
 net/batman-adv/bat_v_elp.h | 19 ++++++++++++
 net/batman-adv/main.h      |  1 +
 net/batman-adv/tp_meter.c  | 25 +++++++++++++--
 net/batman-adv/types.h     |  9 ++++++
 5 files changed, 111 insertions(+), 5 deletions(-)

diff --git a/net/batman-adv/bat_v_elp.c b/net/batman-adv/bat_v_elp.c
index 28687493..028dc3ab 100644
--- a/net/batman-adv/bat_v_elp.c
+++ b/net/batman-adv/bat_v_elp.c
@@ -51,6 +51,7 @@
 #include "originator.h"
 #include "routing.h"
 #include "send.h"
+#include "tp_meter.h"
 
 /**
  * batadv_v_elp_start_timer() - restart timer for ELP periodic work
@@ -67,6 +68,41 @@ static void batadv_v_elp_start_timer(struct 
batadv_hard_iface *hard_iface)
                           msecs_to_jiffies(msecs));
 }
 
+/**
+ * batadv_v_elp_tp_start() - start a tp meter session for a neighbor
+ * @neigh: neighbor to run tp meter on
+ */
+static void batadv_v_elp_tp_start(struct batadv_hardif_neigh_node *neigh)
+{
+       struct batadv_hard_iface *hard_iface = neigh->if_incoming;
+       struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
+
+       neigh->bat_v.tp_meter_running = true;
+       batadv_tp_start(bat_priv, neigh->addr, neigh, 10, NULL, BATADV_TP_ELP);
+}
+
+/**
+ * batadv_v_elp_tp_fail() - handle tp meter session failure
+ * @neigh: neighbor to run tp meter on
+ */
+void batadv_v_elp_tp_fail(struct batadv_hardif_neigh_node *neigh)
+{
+       neigh->bat_v.tp_meter_running = false;
+}
+
+/**
+ * batadv_v_elp_tp_finish() - post-process tp meter results
+ * @neigh: neighbor tp meter on
+ * @throughput: tp meter throughput result
+ */
+void batadv_v_elp_tp_finish(struct batadv_hardif_neigh_node *neigh,
+                           u32 throughput)
+{
+       ewma_throughput_add(&neigh->bat_v.throughput, throughput);
+       neigh->bat_v.last_tp_meter_run = jiffies;
+       neigh->bat_v.tp_meter_running = false;
+}
+
 /**
  * batadv_v_elp_get_throughput() - get the throughput towards a neighbour
  * @neigh: the neighbour for which the throughput has to be obtained
@@ -80,6 +116,7 @@ static u32 batadv_v_elp_get_throughput(struct 
batadv_hardif_neigh_node *neigh)
        struct ethtool_link_ksettings link_settings;
        struct net_device *real_netdev;
        struct station_info sinfo;
+       u32 last_tp_run_msecs;
        u32 throughput;
        int ret;
 
@@ -112,10 +149,13 @@ static u32 batadv_v_elp_get_throughput(struct 
batadv_hardif_neigh_node *neigh)
                         */
                        return 0;
                }
+
+               /* unsupported WiFi driver */
                if (ret)
-                       goto default_throughput;
+                       goto fallback_throughput;
+
                if (!(sinfo.filled & BIT(NL80211_STA_INFO_EXPECTED_THROUGHPUT)))
-                       goto default_throughput;
+                       goto fallback_throughput;
 
                return sinfo.expected_throughput / 100;
        }
@@ -139,6 +179,24 @@ static u32 batadv_v_elp_get_throughput(struct 
batadv_hardif_neigh_node *neigh)
                        return throughput * 10;
        }
 
+fallback_throughput:
+       last_tp_run_msecs = jiffies_to_msecs(jiffies - 
neigh->bat_v.last_tp_meter_run);
+
+       /* check the tp_meter_running flag before checking the timestamp to
+        * avoid a race condition where a new tp meter session is scheduled
+        * right after the previous tp meter session has completed
+        */
+       if (!neigh->bat_v.tp_meter_running &&
+           last_tp_run_msecs > BATADV_ELP_TP_RUN_INTERVAL)
+               batadv_v_elp_tp_start(neigh);
+
+       /* discard too old tp test results */
+       if (last_tp_run_msecs > 2 * BATADV_ELP_TP_RUN_INTERVAL)
+               neigh->bat_v.tp_meter_throughput = 0;
+
+       if (!neigh->bat_v.tp_meter_throughput)
+               return neigh->bat_v.tp_meter_throughput;
+
 default_throughput:
        if (!(hard_iface->bat_v.flags & BATADV_WARNING_DEFAULT)) {
                batadv_info(hard_iface->soft_iface,
diff --git a/net/batman-adv/bat_v_elp.h b/net/batman-adv/bat_v_elp.h
index e8c7b7fd..d0605054 100644
--- a/net/batman-adv/bat_v_elp.h
+++ b/net/batman-adv/bat_v_elp.h
@@ -33,4 +33,23 @@ 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);
 
+#ifdef CONFIG_BATMAN_ADV_BATMAN_V
+
+void batadv_v_elp_tp_fail(struct batadv_hardif_neigh_node *neigh);
+void batadv_v_elp_tp_finish(struct batadv_hardif_neigh_node *neigh,
+                           u32 throughput);
+
+#else
+
+static inline void batadv_v_elp_tp_fail(struct batadv_hardif_neigh_node *neigh)
+{
+}
+
+static inline void
+batadv_v_elp_tp_finish(struct batadv_hardif_neigh_node *neigh, u32 throughput)
+{
+}
+
+#endif /* CONFIG_BATMAN_ADV_BATMAN_V */
+
 #endif /* _NET_BATMAN_ADV_BAT_V_ELP_H_ */
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h
index 89dfaf87..ed4ae913 100644
--- a/net/batman-adv/main.h
+++ b/net/batman-adv/main.h
@@ -69,6 +69,7 @@
 #define BATADV_ELP_MIN_PROBE_SIZE 200 /* bytes */
 #define BATADV_ELP_PROBE_MAX_TX_DIFF 100 /* milliseconds */
 #define BATADV_ELP_MAX_AGE 64
+#define BATADV_ELP_TP_RUN_INTERVAL 60000 /* milliseconds */
 #define BATADV_OGM_MAX_ORIGDIFF 5
 #define BATADV_OGM_MAX_AGE 64
 
diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c
index 1526286b..e7a3c24e 100644
--- a/net/batman-adv/tp_meter.c
+++ b/net/batman-adv/tp_meter.c
@@ -56,6 +56,7 @@
 #include "netlink.h"
 #include "originator.h"
 #include "send.h"
+#include "bat_v_elp.h"
 
 /**
  * BATADV_TP_DEF_TEST_LENGTH - Default test length if not specified by the user
@@ -225,6 +226,7 @@ static void batadv_tp_caller_notify(struct batadv_priv 
*bat_priv,
                                    enum batadv_tp_meter_reason reason)
 {
        u32 total_bytes;
+       u64 throughput;
        u32 test_time;
        u32 cookie;
        bool reason_is_error;
@@ -249,6 +251,21 @@ static void batadv_tp_caller_notify(struct batadv_priv 
*bat_priv,
 
                break;
        case BATADV_TP_ELP:
+               if (reason_is_error) {
+                       batadv_v_elp_tp_fail(tp_vars->hardif_neigh);
+                       return;
+               }
+
+               test_time = jiffies_to_msecs(jiffies - tp_vars->start_time);
+               total_bytes = atomic64_read(&tp_vars->tot_sent);
+
+               /* The following calculation includes these steps:
+                * - convert bytes to bits
+                * - divide bits by the test length (msecs)
+                * - convert result from bits/ms to 0.1Mb/s (* 1024 * 10 / 1000)
+                */
+               throughput = total_bytes * 8 >> ilog2(test_time) / 10;
+               batadv_v_elp_tp_finish(tp_vars->hardif_neigh, throughput);
                break;
        default:
                break;
@@ -266,13 +283,15 @@ static void batadv_tp_caller_notify(struct batadv_priv 
*bat_priv,
 static void batadv_tp_caller_init_error(struct batadv_priv *bat_priv,
                                        enum batadv_tp_meter_caller caller,
                                        enum batadv_tp_meter_reason reason,
-                                       const u8 *dst, u32 cookie)
+                                       const u8 *dst, u32 cookie,
+                                       struct batadv_hardif_neigh_node 
*hardif_neigh)
 {
        switch (caller) {
        case BATADV_TP_USERSPACE:
                batadv_netlink_tpmeter_notify(bat_priv, dst, reason, 0, 0, 
cookie);
                break;
        case BATADV_TP_ELP:
+               batadv_v_elp_tp_fail(hardif_neigh);
                break;
        default:
                break;
@@ -978,7 +997,7 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 
*dst,
                batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
                           "Meter: too many ongoing sessions, aborting 
(SEND)\n");
                batadv_tp_caller_init_error(bat_priv, caller, 
BATADV_TP_REASON_TOO_MANY,
-                                           dst, session_cookie);
+                                           dst, session_cookie, neigh);
                return;
        }
 
@@ -988,7 +1007,7 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const 
u8 *dst,
                           "Meter: %s cannot allocate list elements\n",
                           __func__);
                batadv_tp_caller_init_error(bat_priv, caller, 
BATADV_TP_REASON_MEMORY_ERROR,
-                                           dst, session_cookie);
+                                           dst, session_cookie, neigh);
                return;
        }
 
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 98dccc6c..54fabcb1 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -583,6 +583,15 @@ struct batadv_hardif_neigh_node_bat_v {
 
        /** @metric_work: work queue callback item for metric update */
        struct work_struct metric_work;
+
+       /** @tp_meter_running: tp meter measurements towards this neighbor in 
progress */
+       bool tp_meter_running;
+
+       /** @last_tp_meter_run: timestamp of last tp meter measurement 
completion */
+       unsigned long last_tp_meter_run;
+
+       /** @tp_meter_throughput: throughput information measured by tp meter */
+       unsigned long tp_meter_throughput;
 };
 
 /**
-- 
2.17.0

Reply via email to