batman-adv: Ignore neighbor throughput metrics in error case

commit e7e34ffc976aaae4f465b7898303241b81ceefc3 upstream.

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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Sven Eckelmann
2025-01-20 20:35:28 +01:00
committed by Greg Kroah-Hartman
parent 7eb5dd2016
commit 792a14c90d

View File

@@ -60,11 +60,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 * batadv_v_elp_get_throughput() - get the throughput towards a neighbour
* @neigh: the neighbour for which the throughput has to be obtained * @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 * Return: true when value behind @pthroughput was set
* (a value of '1' equals 0.1Mbps, '10' equals 1Mbps, etc).
*/ */
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 batadv_hard_iface *hard_iface = neigh->if_incoming;
struct net_device *soft_iface = hard_iface->soft_iface; struct net_device *soft_iface = hard_iface->soft_iface;
@@ -78,14 +80,16 @@ static u32 batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh)
* batman-adv interface * batman-adv interface
*/ */
if (!soft_iface) if (!soft_iface)
return BATADV_THROUGHPUT_DEFAULT_VALUE; return false;
/* if the user specified a customised value for this interface, then /* if the user specified a customised value for this interface, then
* return it directly * return it directly
*/ */
throughput = atomic_read(&hard_iface->bat_v.throughput_override); throughput = atomic_read(&hard_iface->bat_v.throughput_override);
if (throughput != 0) if (throughput != 0) {
return throughput; *pthroughput = throughput;
return true;
}
/* if this is a wireless device, then ask its throughput through /* if this is a wireless device, then ask its throughput through
* cfg80211 API * cfg80211 API
@@ -112,19 +116,24 @@ static u32 batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh)
* possible to delete this neighbor. For now set * possible to delete this neighbor. For now set
* the throughput metric to 0. * the throughput metric to 0.
*/ */
return 0; *pthroughput = 0;
return true;
} }
if (ret) if (ret)
goto default_throughput; goto default_throughput;
if (sinfo.filled & BIT(NL80211_STA_INFO_EXPECTED_THROUGHPUT)) if (sinfo.filled & BIT(NL80211_STA_INFO_EXPECTED_THROUGHPUT)) {
return sinfo.expected_throughput / 100; *pthroughput = sinfo.expected_throughput / 100;
return true;
}
/* try to estimate the expected throughput based on reported tx /* try to estimate the expected throughput based on reported tx
* rates * rates
*/ */
if (sinfo.filled & BIT(NL80211_STA_INFO_TX_BITRATE)) if (sinfo.filled & BIT(NL80211_STA_INFO_TX_BITRATE)) {
return cfg80211_calculate_bitrate(&sinfo.txrate) / 3; *pthroughput = cfg80211_calculate_bitrate(&sinfo.txrate) / 3;
return true;
}
goto default_throughput; goto default_throughput;
} }
@@ -143,8 +152,10 @@ static u32 batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh)
hard_iface->bat_v.flags &= ~BATADV_FULL_DUPLEX; hard_iface->bat_v.flags &= ~BATADV_FULL_DUPLEX;
throughput = link_settings.base.speed; throughput = link_settings.base.speed;
if (throughput && throughput != SPEED_UNKNOWN) if (throughput && throughput != SPEED_UNKNOWN) {
return throughput * 10; *pthroughput = throughput * 10;
return true;
}
} }
default_throughput: default_throughput:
@@ -158,7 +169,8 @@ default_throughput:
} }
/* if none of the above cases apply, return the base_throughput */ /* if none of the above cases apply, return the base_throughput */
return BATADV_THROUGHPUT_DEFAULT_VALUE; *pthroughput = BATADV_THROUGHPUT_DEFAULT_VALUE;
return true;
} }
/** /**
@@ -170,15 +182,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_bat_v *neigh_bat_v;
struct batadv_hardif_neigh_node *neigh; struct batadv_hardif_neigh_node *neigh;
u32 throughput;
bool valid;
neigh_bat_v = container_of(work, struct batadv_hardif_neigh_node_bat_v, neigh_bat_v = container_of(work, struct batadv_hardif_neigh_node_bat_v,
metric_work); metric_work);
neigh = container_of(neigh_bat_v, struct batadv_hardif_neigh_node, neigh = container_of(neigh_bat_v, struct batadv_hardif_neigh_node,
bat_v); bat_v);
ewma_throughput_add(&neigh->bat_v.throughput, valid = batadv_v_elp_get_throughput(neigh, &throughput);
batadv_v_elp_get_throughput(neigh)); if (!valid)
goto put_neigh;
ewma_throughput_add(&neigh->bat_v.throughput, throughput);
put_neigh:
/* decrement refcounter to balance increment performed before scheduling /* decrement refcounter to balance increment performed before scheduling
* this task * this task
*/ */