Commit 80b2fa46 authored by Sarika Sharma's avatar Sarika Sharma Committed by Johannes Berg
Browse files

wifi: mac80211: add support to accumulate removed link statistics



Currently, if a link gets removed in between for a station then
directly accumulated data will fall down to sum of other active links.
This will bring inconsistency in station dump statistics.

For instance, let's take Tx packets
- at t=0-> link-0:2 link-1:3 Tx packets => accumulated = 5
- at t=1-> link-0:4 link-1:6 Tx packets => accumulated = 10
let say at t=2, link-0 went down => link-0:0 link-1:7 => accumulated = 7
Here, suddenly accumulated Tx packets will come down to 7 from 10.
This is showing inconsistency.

Therefore, store link-0 data when it went down and add to accumulated
Tx packet = 11.

Hence, store the removed link statistics data in sta structure and
add it in accumulated statistics for consistency.

Signed-off-by: default avatarSarika Sharma <quic_sarishar@quicinc.com>
Link: https://patch.msgid.link/20250528054420.3050133-7-quic_sarishar@quicinc.com


Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 49e47223
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -886,6 +886,13 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
		ret = 0;
		memcpy(mac, sta->sta.addr, ETH_ALEN);
		sta_set_sinfo(sta, sinfo, true);

		/* Add accumulated removed link data to sinfo data for
		 * consistency for MLO
		 */
		if (sinfo->valid_links)
			sta_set_accumulated_removed_links_sinfo(sta, sinfo);

	}

	return ret;
@@ -913,6 +920,12 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
	if (sta) {
		ret = 0;
		sta_set_sinfo(sta, sinfo, true);

		/* Add accumulated removed link data to sinfo data for
		 * consistency for MLO
		 */
		if (sinfo->valid_links)
			sta_set_accumulated_removed_links_sinfo(sta, sinfo);
	}

	return ret;
+74 −0
Original line number Diff line number Diff line
@@ -355,6 +355,50 @@ static void sta_info_free_link(struct link_sta_info *link_sta)
	free_percpu(link_sta->pcpu_rx_stats);
}

static void sta_accumulate_removed_link_stats(struct sta_info *sta, int link_id)
{
	struct link_sta_info *link_sta = wiphy_dereference(sta->local->hw.wiphy,
							   sta->link[link_id]);
	struct ieee80211_link_data *link;
	int ac, tid;
	u32 thr;

	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
		sta->rem_link_stats.tx_packets +=
			link_sta->tx_stats.packets[ac];
		sta->rem_link_stats.tx_bytes += link_sta->tx_stats.bytes[ac];
	}

	sta->rem_link_stats.rx_packets += link_sta->rx_stats.packets;
	sta->rem_link_stats.rx_bytes += link_sta->rx_stats.bytes;
	sta->rem_link_stats.tx_retries += link_sta->status_stats.retry_count;
	sta->rem_link_stats.tx_failed += link_sta->status_stats.retry_failed;
	sta->rem_link_stats.rx_dropped_misc += link_sta->rx_stats.dropped;

	thr = sta_get_expected_throughput(sta);
	if (thr != 0)
		sta->rem_link_stats.expected_throughput += thr;

	for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) {
		sta->rem_link_stats.pertid_stats.rx_msdu +=
			link_sta->rx_stats.msdu[tid];
		sta->rem_link_stats.pertid_stats.tx_msdu +=
			link_sta->tx_stats.msdu[tid];
		sta->rem_link_stats.pertid_stats.tx_msdu_retries +=
			link_sta->status_stats.msdu_retries[tid];
		sta->rem_link_stats.pertid_stats.tx_msdu_failed +=
			link_sta->status_stats.msdu_failed[tid];
	}

	if (sta->sdata->vif.type == NL80211_IFTYPE_STATION) {
		link = wiphy_dereference(sta->sdata->local->hw.wiphy,
					 sta->sdata->link[link_id]);
		if (link)
			sta->rem_link_stats.beacon_loss_count +=
				link->u.mgd.beacon_loss_count;
	}
}

static void sta_remove_link(struct sta_info *sta, unsigned int link_id,
			    bool unhash)
{
@@ -377,6 +421,10 @@ static void sta_remove_link(struct sta_info *sta, unsigned int link_id,
		alloc = container_of(link_sta, typeof(*alloc), info);

	sta->sta.valid_links &= ~BIT(link_id);

	/* store removed link info for accumulated stats consistency */
	sta_accumulate_removed_link_stats(sta, link_id);

	RCU_INIT_POINTER(sta->link[link_id], NULL);
	RCU_INIT_POINTER(sta->sta.link[link_id], NULL);
	if (alloc) {
@@ -2645,6 +2693,32 @@ static void sta_set_mesh_sinfo(struct sta_info *sta,
}
#endif

void sta_set_accumulated_removed_links_sinfo(struct sta_info *sta,
					     struct station_info *sinfo)
{
	/* Accumulating the removed link statistics. */
	sinfo->tx_packets = sta->rem_link_stats.tx_packets;
	sinfo->rx_packets = sta->rem_link_stats.rx_packets;
	sinfo->tx_bytes = sta->rem_link_stats.tx_bytes;
	sinfo->rx_bytes = sta->rem_link_stats.rx_bytes;
	sinfo->tx_retries = sta->rem_link_stats.tx_retries;
	sinfo->tx_failed = sta->rem_link_stats.tx_failed;
	sinfo->rx_dropped_misc = sta->rem_link_stats.rx_dropped_misc;
	sinfo->beacon_loss_count = sta->rem_link_stats.beacon_loss_count;
	sinfo->expected_throughput = sta->rem_link_stats.expected_throughput;

	if (sinfo->pertid) {
		sinfo->pertid->rx_msdu =
			sta->rem_link_stats.pertid_stats.rx_msdu;
		sinfo->pertid->tx_msdu =
			sta->rem_link_stats.pertid_stats.tx_msdu;
		sinfo->pertid->tx_msdu_retries =
			sta->rem_link_stats.pertid_stats.tx_msdu_retries;
		sinfo->pertid->tx_msdu_failed =
			sta->rem_link_stats.pertid_stats.tx_msdu_failed;
	}
}

void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
		   bool tidstats)
{
+57 −0
Original line number Diff line number Diff line
@@ -568,6 +568,58 @@ struct link_sta_info {
	struct ieee80211_link_sta *pub;
};

/**
 * struct ieee80211_sta_removed_link_stats - Removed link sta data
 *
 * keep required accumulated removed link data for stats
 *
 * @rx_packets: accumulated packets (MSDUs & MMPDUs) received from
 *	this station for removed links
 * @tx_packets: accumulated packets (MSDUs & MMPDUs) transmitted to
 *	this station for removed links
 * @rx_bytes: accumulated bytes (size of MPDUs) received from this
 *	station for removed links
 * @tx_bytes: accumulated bytes (size of MPDUs) transmitted to this
 *	station for removed links
 * @tx_retries: cumulative retry counts (MPDUs) for removed links
 * @tx_failed: accumulated number of failed transmissions (MPDUs)
 *	(retries exceeded, no ACK) for removed links
 * @rx_dropped_misc: accumulated dropped packets for un-specified reason
 *	from this station for removed links
 * @beacon_loss_count: Number of times beacon loss event has triggered
 *	from this station for removed links.
 * @expected_throughput: expected throughput in kbps (including 802.11
 *	headers) towards this station for removed links
 * @pertid_stats: accumulated per-TID statistics for removed link of
 *	station
 * @pertid_stats.rx_msdu : accumulated number of received MSDUs towards
 *	this station for removed links.
 * @pertid_stats.tx_msdu: accumulated number of (attempted) transmitted
 *	MSDUs towards this station for removed links
 * @pertid_stats.tx_msdu_retries: accumulated number of retries (not
 *	counting the first) for transmitted MSDUs towards this station
 *	for removed links
 * @pertid_stats.tx_msdu_failed: accumulated number of failed transmitted
 *	MSDUs towards this station for removed links
 */
struct ieee80211_sta_removed_link_stats {
	u32 rx_packets;
	u32 tx_packets;
	u64 rx_bytes;
	u64 tx_bytes;
	u32 tx_retries;
	u32 tx_failed;
	u32 rx_dropped_misc;
	u32 beacon_loss_count;
	u32 expected_throughput;
	struct {
		u64 rx_msdu;
		u64 tx_msdu;
		u64 tx_msdu_retries;
		u64 tx_msdu_failed;
	} pertid_stats;
};

/**
 * struct sta_info - STA information
 *
@@ -644,6 +696,7 @@ struct link_sta_info {
 *	@deflink address and remaining would be allocated and the address
 *	would be assigned to link[link_id] where link_id is the id assigned
 *	by the AP.
 * @rem_link_stats: accumulated removed link stats
 */
struct sta_info {
	/* General information, mostly static */
@@ -718,6 +771,7 @@ struct sta_info {
	struct ieee80211_sta_aggregates cur;
	struct link_sta_info deflink;
	struct link_sta_info __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS];
	struct ieee80211_sta_removed_link_stats rem_link_stats;

	/* keep last! */
	struct ieee80211_sta sta;
@@ -922,6 +976,9 @@ void sta_set_rate_info_tx(struct sta_info *sta,
void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
		   bool tidstats);

void sta_set_accumulated_removed_links_sinfo(struct sta_info *sta,
					     struct station_info *sinfo);

u32 sta_get_expected_throughput(struct sta_info *sta);

void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,