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 072b278732
commit 96405e2c49
1 changed files with 34 additions and 16 deletions

View 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
*/