]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
batman-adv: Ignore neighbor throughput metrics in error case
authorSven Eckelmann <sven@narfation.org>
Mon, 20 Jan 2025 19:35:28 +0000 (20:35 +0100)
committerSimon Wunderlich <sw@simonwunderlich.de>
Wed, 22 Jan 2025 20:38:19 +0000 (21:38 +0100)
If a temporary error happened in the evaluation of the neighbor throughput
information, then the invalid throughput result should not be stored in the
throughtput EWMA.

Cc: stable@vger.kernel.org
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
net/batman-adv/bat_v_elp.c

index fbf499bcc6718c677bf0e34c50576612927d0d9d..65e52de52bcd2688e0ed33cd8605821b17f5a63b 100644 (file)
@@ -59,11 +59,13 @@ static void batadv_v_elp_start_timer(struct batadv_hard_iface *hard_iface)
 /**
  * batadv_v_elp_get_throughput() - get the throughput towards a neighbour
  * @neigh: the neighbour for which the throughput has to be obtained
+ * @pthroughput: calculated throughput towards the given neighbour in multiples
+ *  of 100kpbs (a value of '1' equals 0.1Mbps, '10' equals 1Mbps, etc).
  *
- * Return: The throughput towards the given neighbour in multiples of 100kpbs
- *         (a value of '1' equals 0.1Mbps, '10' equals 1Mbps, etc).
+ * Return: true when value behind @pthroughput was set
  */
-static u32 batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh)
+static bool batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh,
+                                       u32 *pthroughput)
 {
        struct batadv_hard_iface *hard_iface = neigh->if_incoming;
        struct net_device *soft_iface = hard_iface->soft_iface;
@@ -77,14 +79,16 @@ static u32 batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh)
         * batman-adv interface
         */
        if (!soft_iface)
-               return BATADV_THROUGHPUT_DEFAULT_VALUE;
+               return false;
 
        /* 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 (throughput != 0) {
+               *pthroughput = throughput;
+               return true;
+       }
 
        /* if this is a wireless device, then ask its throughput through
         * cfg80211 API
@@ -111,19 +115,24 @@ static u32 batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh)
                         * possible to delete this neighbor. For now set
                         * the throughput metric to 0.
                         */
-                       return 0;
+                       *pthroughput = 0;
+                       return true;
                }
                if (ret)
                        goto default_throughput;
 
-               if (sinfo.filled & BIT(NL80211_STA_INFO_EXPECTED_THROUGHPUT))
-                       return sinfo.expected_throughput / 100;
+               if (sinfo.filled & BIT(NL80211_STA_INFO_EXPECTED_THROUGHPUT)) {
+                       *pthroughput = sinfo.expected_throughput / 100;
+                       return true;
+               }
 
                /* try to estimate the expected throughput based on reported tx
                 * rates
                 */
-               if (sinfo.filled & BIT(NL80211_STA_INFO_TX_BITRATE))
-                       return cfg80211_calculate_bitrate(&sinfo.txrate) / 3;
+               if (sinfo.filled & BIT(NL80211_STA_INFO_TX_BITRATE)) {
+                       *pthroughput = cfg80211_calculate_bitrate(&sinfo.txrate) / 3;
+                       return true;
+               }
 
                goto default_throughput;
        }
@@ -142,8 +151,10 @@ static u32 batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh)
                        hard_iface->bat_v.flags &= ~BATADV_FULL_DUPLEX;
 
                throughput = link_settings.base.speed;
-               if (throughput && throughput != SPEED_UNKNOWN)
-                       return throughput * 10;
+               if (throughput && throughput != SPEED_UNKNOWN) {
+                       *pthroughput = throughput * 10;
+                       return true;
+               }
        }
 
 default_throughput:
@@ -157,7 +168,8 @@ default_throughput:
        }
 
        /* if none of the above cases apply, return the base_throughput */
-       return BATADV_THROUGHPUT_DEFAULT_VALUE;
+       *pthroughput = BATADV_THROUGHPUT_DEFAULT_VALUE;
+       return true;
 }
 
 /**
@@ -169,15 +181,21 @@ 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;
+       u32 throughput;
+       bool valid;
 
        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));
+       valid = batadv_v_elp_get_throughput(neigh, &throughput);
+       if (!valid)
+               goto put_neigh;
+
+       ewma_throughput_add(&neigh->bat_v.throughput, throughput);
 
+put_neigh:
        /* decrement refcounter to balance increment performed before scheduling
         * this task
         */