2017-01-31 20:11:14

by Rajkumar Manoharan

[permalink] [raw]
Subject: [PATCH v2 1/3] mac80211: fix mesh moving average stuck

As moving average is not considering fractional part after
certain ratio, it will stuck at the same state. For example
with current values, moving average stuck at 96 and it will
not move forward. Fortunately current threshold is matching
against 95%. If thresold is increased more than 96, mesh path
never be deactivated under worst case. Fix failure average
movement by bumping up average at stuck state.

Signed-off-by: Rajkumar Manoharan <[email protected]>
---
net/mac80211/mesh_hwmp.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index b747c9645e43..f0aa1da15bd0 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -300,6 +300,7 @@ void ieee80211s_update_metric(struct ieee80211_local *local,
{
struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ u32 fail_avg = sta->mesh->fail_avg;
int failed;

if (!ieee80211_is_data(hdr->frame_control))
@@ -308,8 +309,17 @@ void ieee80211s_update_metric(struct ieee80211_local *local,
failed = !(txinfo->flags & IEEE80211_TX_STAT_ACK);

/* moving average, scaled to 100 */
- sta->mesh->fail_avg =
- ((80 * sta->mesh->fail_avg + 5) / 100 + 20 * failed);
+ fail_avg = ((80 * fail_avg + 5) / 100 + 20 * failed);
+
+ /* bump up fail average since fractional part of average is ignored.
+ * Otherwise fail average always stuck at the same level and
+ * never moves forward.
+ */
+ if (fail_avg && fail_avg == sta->mesh->fail_avg)
+ fail_avg++;
+
+ sta->mesh->fail_avg = fail_avg;
+
if (sta->mesh->fail_avg > 95)
mesh_plink_broken(sta);
}
--
1.9.1


2017-01-31 20:11:12

by Rajkumar Manoharan

[permalink] [raw]
Subject: [PATCH v2 3/3] mac80211: clear failure average upon mesh path deactivation

Mesh moving average should be cleared, whenever mesh paths
to the given station are deactivated due to bad link. It makes
path deactivation logic more robust by considering more tx
status before terminating mesh link.

Signed-off-by: Rajkumar Manoharan <[email protected]>
---
v2:
* removed paths_deactivated check
* updated commit log

net/mac80211/mesh_pathtbl.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index f0e6175a9821..bab443e5284d 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -537,6 +537,7 @@ void mesh_plink_broken(struct sta_info *sta)
WLAN_REASON_MESH_PATH_DEST_UNREACHABLE, bcast);
}
}
+ sta->mesh->fail_avg = 0;
out:
rhashtable_walk_stop(&iter);
rhashtable_walk_exit(&iter);
--
1.9.1

2017-01-31 20:11:11

by Rajkumar Manoharan

[permalink] [raw]
Subject: [PATCH v2 2/3] mac80211: Make mesh failure moving average configurable

Currently mesh moving fail average is calculated based on constant
weight factor. In worst case moving average reaches threshold by
considering 16 msdu tx ack status and deactivates mesh path. Having
a constant weight factor might not be suitable for all environments.
So make it tunable parameter and also lower default weight to 10 so
that mesh broken link calculation will consider more packet status
(32 msdus ack status) before dropping mesh path.

In OTA 2-hop topolgy (MP1 <-> MP2 <-> MP3), while running TCP traffic
of window size of 2M where each nodes are operating in VHT80 mode,
mesh path between forwarding node (MP2) and border nodes (MP1/MP3) is
deactivated more often when average weight is 20.

Signed-off-by: Rajkumar Manoharan <[email protected]>
---
net/mac80211/debugfs_netdev.c | 27 +++++++++++++++++++++++++++
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/mesh.c | 1 +
net/mac80211/mesh.h | 3 +++
net/mac80211/mesh_hwmp.c | 4 +++-
5 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 8f5fff8b2040..3923401a85dd 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -586,6 +586,32 @@ static ssize_t ieee80211_if_parse_tsf(
#ifdef CONFIG_MAC80211_MESH
IEEE80211_IF_FILE(estab_plinks, u.mesh.estab_plinks, ATOMIC);

+static ssize_t ieee80211_if_fmt_fail_avg_weight(
+ const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
+{
+ return snprintf(buf, buflen, "%d\n", sdata->u.mesh.fail_avg_weight);
+}
+
+static ssize_t ieee80211_if_parse_fail_avg_weight(
+ struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
+{
+ u8 val;
+ int ret;
+
+ ret = kstrtou8(buf, 0, &val);
+ if (ret)
+ return ret;
+
+ if (val > 100)
+ return -ERANGE;
+
+ sdata->u.mesh.fail_avg_weight = val;
+
+ return buflen;
+}
+
+IEEE80211_IF_FILE_RW(fail_avg_weight);
+
/* Mesh stats attributes */
IEEE80211_IF_FILE(fwded_mcast, u.mesh.mshstats.fwded_mcast, DEC);
IEEE80211_IF_FILE(fwded_unicast, u.mesh.mshstats.fwded_unicast, DEC);
@@ -711,6 +737,7 @@ static void add_mesh_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_ADD_MODE(tsf, 0600);
DEBUGFS_ADD_MODE(estab_plinks, 0400);
+ DEBUGFS_ADD_MODE(fail_avg_weight, 0600);
}

static void add_mesh_stats(struct ieee80211_sub_if_data *sdata)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 159a1a733725..30babcea3e06 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -711,6 +711,7 @@ struct ieee80211_if_mesh {
struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */
int mesh_paths_generation;
int mpp_paths_generation;
+ u8 fail_avg_weight;
};

#ifdef CONFIG_MAC80211_MESH
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 9c23172feba0..491fd76f91bd 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -1368,6 +1368,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
ifmsh->last_preq = jiffies;
ifmsh->next_perr = jiffies;
ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE;
+ ifmsh->fail_avg_weight = MESH_FAIL_AVG_WEIGHT;
/* Allocate all mesh structures when creating the first mesh interface. */
if (!mesh_allocated)
ieee80211s_init();
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 7e5f271e3c30..887746022cc6 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -185,6 +185,9 @@ struct mesh_rmc {
/* Number of frames buffered per destination for unresolved destinations */
#define MESH_FRAME_QUEUE_LEN 10

+/* Moving failure average weight of mesh peer link (in percent) */
+#define MESH_FAIL_AVG_WEIGHT 10
+
/* Public interfaces */
/* Various */
int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index f0aa1da15bd0..61a824eb2c73 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -301,6 +301,7 @@ void ieee80211s_update_metric(struct ieee80211_local *local,
struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
u32 fail_avg = sta->mesh->fail_avg;
+ u8 fail_avg_weight = sta->sdata->u.mesh.fail_avg_weight;
int failed;

if (!ieee80211_is_data(hdr->frame_control))
@@ -309,7 +310,8 @@ void ieee80211s_update_metric(struct ieee80211_local *local,
failed = !(txinfo->flags & IEEE80211_TX_STAT_ACK);

/* moving average, scaled to 100 */
- fail_avg = ((80 * fail_avg + 5) / 100 + 20 * failed);
+ fail_avg = (((100 - fail_avg_weight) * fail_avg + 5) / 100 +
+ fail_avg_weight * failed);

/* bump up fail average since fractional part of average is ignored.
* Otherwise fail average always stuck at the same level and
--
1.9.1

2017-02-08 08:31:25

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH v2 2/3] mac80211: Make mesh failure moving average configurable

On Tue, 2017-01-31 at 12:07 -0800, Rajkumar Manoharan wrote:
> Currently mesh moving fail average is calculated based on constant
> weight factor. In worst case moving average reaches threshold by
> considering 16 msdu tx ack status and deactivates mesh path. Having
> a constant weight factor might not be suitable for all environments.
> So make it tunable parameter and also lower default weight to 10 so
> that mesh broken link calculation will consider more packet status
> (32 msdus ack status) before dropping mesh path.

I don't think this makes a lot of sense, and with a conversion to the
EWMA helpers it would probably not really be possible anyway.

johannes

2017-02-08 08:30:37

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] mac80211: fix mesh moving average stuck

On Tue, 2017-01-31 at 12:07 -0800, Rajkumar Manoharan wrote:
> As moving average is not considering fractional part after
> certain ratio, it will stuck at the same state. For example
> with current values, moving average stuck at 96 and it will
> not move forward. Fortunately current threshold is matching
> against 95%. If thresold is increased more than 96, mesh path
> never be deactivated under worst case. Fix failure average
> movement by bumping up average at stuck state.

This is ... really strange to me.

Can't we just actually take into account fractional parts instead?

I think you should instead convert this to the EMWA helpers (see
include/linux/average.h).

johannes