On Sat, Mar 04, 2017 at 10:04:51PM +0100, Stefan Sperling wrote:
> This diff makes the RTS threshold dynamic in 11n mode.
> It flips the RTS threshold between DEFAULT (512 bytes) and MAX (the
> maximum size of a non-aggregated 802.11 frame).
Things have been working fine for me with this diff.
Any concerns about putting it in?
> The decision whether to use RTS is implemented as a heuristic described
> in the MiRA paper.
>
> MiRa enables RTS if there are retries with almost no loss, indicating
> competition with other APs and clients. It leaves RTS disabled if
> there is a lot of loss, indicating we are too far away from the AP
> or using a bad Tx rate which won't cover the distance.
>
> Because an athn(4) hostap needs a per-client threshold I am introducing
> ni_rtsthreshold in struct ieee80211_node. This could completely replace
> the ic_rtsthreshold in struct ieee80211com eventually. For now I am only
> switching 11n capable drivers over to ni_rtsthreshold.
>
> I am interested in test reports.
> When testing this please look for changes in both latency and throughput
> and let me know if you think it behaves better or worse with this diff.
>
> Index: dev/ic/ar5008.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/ic/ar5008.c,v
> retrieving revision 1.42
> diff -u -p -r1.42 ar5008.c
> --- dev/ic/ar5008.c 1 Feb 2017 12:45:56 -0000 1.42
> +++ dev/ic/ar5008.c 4 Mar 2017 15:29:02 -0000
> @@ -1513,7 +1513,7 @@ ar5008_tx(struct athn_softc *sc, struct
>
> htprot = (ic->ic_bss->ni_htop1 & IEEE80211_HTOP1_PROT_MASK);
> /* NB: Group frames are sent using CCK in 802.11b/g. */
> - if (totlen > ic->ic_rtsthreshold) {
> + if (totlen > ni->ni_rtsthreshold) {
> ds->ds_ctl0 |= AR_TXC0_RTS_ENABLE;
> } else if (((ic->ic_flags & IEEE80211_F_USEPROT) &&
> athn_rates[ridx[0]].phy == IEEE80211_T_OFDM) ||
> Index: dev/ic/ath.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/ic/ath.c,v
> retrieving revision 1.112
> diff -u -p -r1.112 ath.c
> --- dev/ic/ath.c 22 Jan 2017 10:17:37 -0000 1.112
> +++ dev/ic/ath.c 4 Mar 2017 15:29:23 -0000
> @@ -2259,7 +2259,7 @@ ath_tx_start(struct ath_softc *sc, struc
> if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
> flags |= HAL_TXDESC_NOACK; /* no ack on broad/multicast */
> sc->sc_stats.ast_tx_noack++;
> - } else if (pktlen > ic->ic_rtsthreshold) {
> + } else if (pktlen > ni->ni_rtsthreshold) {
> flags |= HAL_TXDESC_RTSENA; /* RTS based on frame length */
> sc->sc_stats.ast_tx_rts++;
> }
> Index: dev/pci/if_iwm.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/pci/if_iwm.c,v
> retrieving revision 1.165
> diff -u -p -r1.165 if_iwm.c
> --- dev/pci/if_iwm.c 20 Feb 2017 15:38:04 -0000 1.165
> +++ dev/pci/if_iwm.c 4 Mar 2017 15:30:11 -0000
> @@ -4038,7 +4038,7 @@ iwm_tx(struct iwm_softc *sc, struct mbuf
>
> if (type == IEEE80211_FC0_TYPE_DATA &&
> !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
> - (totlen + IEEE80211_CRC_LEN > ic->ic_rtsthreshold ||
> + (totlen + IEEE80211_CRC_LEN > ni->ni_rtsthreshold ||
> (ic->ic_flags & IEEE80211_F_USEPROT)))
> flags |= IWM_TX_CMD_FLG_PROT_REQUIRE;
>
> Index: dev/pci/if_iwn.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/pci/if_iwn.c,v
> retrieving revision 1.184
> diff -u -p -r1.184 if_iwn.c
> --- dev/pci/if_iwn.c 20 Feb 2017 15:38:04 -0000 1.184
> +++ dev/pci/if_iwn.c 4 Mar 2017 15:30:02 -0000
> @@ -2992,7 +2992,7 @@ iwn_tx(struct iwn_softc *sc, struct mbuf
> /* Check if frame must be protected using RTS/CTS or CTS-to-self. */
> if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
> /* NB: Group frames are sent using CCK in 802.11b/g/n (2GHz). */
> - if (totlen + IEEE80211_CRC_LEN > ic->ic_rtsthreshold) {
> + if (totlen + IEEE80211_CRC_LEN > ni->ni_rtsthreshold) {
> flags |= IWN_TX_NEED_RTS;
> } else if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
> ridx >= IWN_RIDX_OFDM6) {
> Index: net80211/ieee80211_mira.c
> ===================================================================
> RCS file: /cvs/src/sys/net80211/ieee80211_mira.c,v
> retrieving revision 1.10
> diff -u -p -r1.10 ieee80211_mira.c
> --- net80211/ieee80211_mira.c 28 Jan 2017 16:01:36 -0000 1.10
> +++ net80211/ieee80211_mira.c 4 Mar 2017 16:55:00 -0000
> @@ -84,6 +84,9 @@ void ieee80211_mira_probe_next_rate(stru
> uint32_t ieee80211_mira_valid_rates(struct ieee80211com *,
> struct ieee80211_node *);
> uint32_t ieee80211_mira_mcs_below(struct ieee80211_mira_node *, int);
> +void ieee80211_mira_set_rts_threshold(struct ieee80211_mira_node *,
> + struct ieee80211com *, struct ieee80211_node *);
> +void ieee80211_mira_reset_interference_stats(struct ieee80211_mira_node *);
>
> /* We use fixed point arithmetic with 64 bit integers. */
> #define MIRA_FP_SHIFT 21
> @@ -381,7 +384,7 @@ ieee80211_mira_toverhead(struct ieee8021
> (ic->ic_htcaps & IEEE80211_HTCAP_CBW20_40))
> rts = 1;
> else
> - rts = (mn->ampdu_size > ic->ic_rtsthreshold);
> + rts = (mn->ampdu_size > ni->ni_rtsthreshold);
>
> if (rts) {
> /* Assume RTS/CTS were sent at a basic rate. */
> @@ -1024,6 +1027,82 @@ ieee80211_mira_mcs_below(struct ieee8021
> return mcs_mask;
> }
>
> +/* Constants involved in detecting suspected frame collisions. */
> +#define MIRA_COLLISION_MIN_FRAMES 11 /* XXX magic number */
> +#define MIRA_COLLISION_LOSS_PERCENTAGE 10
> +#define MIRA_COLLISION_DETECTED 3
> +
> +/*
> + * Set the RTS threshold based on suspected interference from other STAs.
> + * Note that HT protection settings may enforce RTS regardless of threshold.
> + *
> + * See section 5.2 in MiRa paper.
> + * XXX The paper's algorithm assumes aggregated frames. We run the algorithm
> + * over the result of several individual frames instead since we do not yet
> + * support Tx aggregation.
> + */
> +void
> +ieee80211_mira_set_rts_threshold(struct ieee80211_mira_node *mn,
> + struct ieee80211com *ic, struct ieee80211_node *ni)
> +{
> + uint16_t rtsthreshold = IEEE80211_RTS_MAX; /* disable RTS by default */
> + uint32_t loss;
> + /* Magic number from MiRA paper ("cost/benefit ratio"). */
> + static const uint64_t k = MIRA_FP_1 + (MIRA_FP_1 / 2); /* 1.5 */
> +
> + /* Update interference window stats. */
> + mn->ifwnd_frames += mn->frames;
> + mn->ifwnd_retries += mn->retries;
> + mn->ifwnd_txfail += mn->txfail;
> + mn->ifwnd_size += mn->ampdu_size;
> + if (mn->ifwnd_frames < MIRA_COLLISION_MIN_FRAMES)
> + return; /* not enough frames yet */
> +
> + /* Check whether the loss pattern indicates frame collisions. */
> + loss = (mn->ifwnd_txfail * 100) / mn->ifwnd_frames;
> + if (mn->ifwnd_retries >= 1 && loss < MIRA_COLLISION_LOSS_PERCENTAGE) {
> + if (mn->ifwnd == 0) {
> + /* First frame collision confirmed. */
> + mn->ifwnd = MIRA_COLLISION_DETECTED;
> + } else if (mn->ifwnd == MIRA_COLLISION_DETECTED) {
> + /* Successive frame collision confirmed. */
> + int rate = ieee80211_mira_best_basic_rate(ni);
> + uint64_t txtime, rtsoverhead;
> + txtime = ieee80211_mira_ht_txtime(mn->ifwnd_size,
> + ni->ni_txmcs, IEEE80211_IS_CHAN_2GHZ(ni->ni_chan));
> + rtsoverhead = ieee80211_mira_legacy_txtime(MIRA_RTSLEN,
> + rate, ic);
> + rtsoverhead += ieee80211_mira_legacy_txtime(MIRA_CTSLEN,
> + rate, ic);
> + /* convert to fixed-point */
> + txtime <<= MIRA_FP_SHIFT;
> + rtsoverhead <<= MIRA_FP_SHIFT;
> + /* Enable RTS if potential gains outweigh overhead. */
> + if (txtime >= MIRA_FP_MUL(k, rtsoverhead))
> + rtsthreshold = IEEE80211_RTS_DEFAULT;
> + }
> + } else if (mn->ifwnd > 0)
> + mn->ifwnd--;
> +
> +#ifdef MIRA_DEBUG
> + if (ni->ni_rtsthreshold != rtsthreshold)
> + DPRINTF(("%s RTS threshold %d (%d retries, %d%% loss)\n",
> + ether_sprintf(ni->ni_macaddr), rtsthreshold,
> + mn->ifwnd_retries, loss));
> +#endif
> + ni->ni_rtsthreshold = rtsthreshold;
> + ieee80211_mira_reset_interference_stats(mn);
> +}
> +
> +void
> +ieee80211_mira_reset_interference_stats(struct ieee80211_mira_node *mn)
> +{
> + mn->ifwnd_frames = 0;
> + mn->ifwnd_retries = 0;
> + mn->ifwnd_txfail = 0;
> + mn->ifwnd_size = 0;
> +}
> +
> void
> ieee80211_mira_choose(struct ieee80211_mira_node *mn, struct ieee80211com
> *ic,
> struct ieee80211_node *ni)
> @@ -1060,6 +1139,7 @@ ieee80211_mira_choose(struct ieee80211_m
> IEEE80211_MIRA_PROBE_TIMEOUT_MIN;
> mn->g[best].nprobes = 0;
> mn->g[best].nprobe_bytes = 0;
> + ieee80211_mira_reset_interference_stats(mn);
> } else
> ni->ni_txmcs = mn->best_mcs;
> ieee80211_mira_probe_done(mn);
> @@ -1068,6 +1148,7 @@ ieee80211_mira_choose(struct ieee80211_m
> splx(s);
> return;
> } else {
> + ieee80211_mira_set_rts_threshold(mn, ic, ni);
> ieee80211_mira_reset_driver_stats(mn);
> ieee80211_mira_schedule_probe_timers(mn, ni);
> }
> Index: net80211/ieee80211_mira.h
> ===================================================================
> RCS file: /cvs/src/sys/net80211/ieee80211_mira.h,v
> retrieving revision 1.3
> diff -u -p -r1.3 ieee80211_mira.h
> --- net80211/ieee80211_mira.h 12 Jan 2017 18:06:57 -0000 1.3
> +++ net80211/ieee80211_mira.h 4 Mar 2017 16:30:29 -0000
> @@ -89,6 +89,13 @@ struct ieee80211_mira_node {
>
> /* Goodput statistics for each MCS. */
> struct ieee80211_mira_goodput_stats g[IEEE80211_MIRA_NUM_RATES];
> +
> + /* Interference observation window (see MiRa paper section 5.2). */
> + int ifwnd;
> + uint32_t ifwnd_frames;
> + uint32_t ifwnd_retries;
> + uint32_t ifwnd_txfail;
> + uint32_t ifwnd_size;
> };
>
> /* Initialize rate control state. */
> Index: net80211/ieee80211_node.c
> ===================================================================
> RCS file: /cvs/src/sys/net80211/ieee80211_node.c,v
> retrieving revision 1.115
> diff -u -p -r1.115 ieee80211_node.c
> --- net80211/ieee80211_node.c 4 Mar 2017 12:44:27 -0000 1.115
> +++ net80211/ieee80211_node.c 4 Mar 2017 16:54:10 -0000
> @@ -184,6 +184,7 @@ ieee80211_node_lateattach(struct ifnet *
> if (ni == NULL)
> panic("unable to setup inital BSS node");
> ni->ni_chan = IEEE80211_CHAN_ANYC;
> + ni->ni_rtsthreshold = IEEE80211_RTS_DEFAULT;
> ic->ic_bss = ieee80211_ref_node(ni);
> ic->ic_txpower = IEEE80211_TXPOWER_MAX;
> #ifndef IEEE80211_STA_ONLY
> Index: net80211/ieee80211_node.h
> ===================================================================
> RCS file: /cvs/src/sys/net80211/ieee80211_node.h,v
> retrieving revision 1.67
> diff -u -p -r1.67 ieee80211_node.h
> --- net80211/ieee80211_node.h 4 Mar 2017 12:44:27 -0000 1.67
> +++ net80211/ieee80211_node.h 4 Mar 2017 16:54:10 -0000
> @@ -277,6 +277,7 @@ struct ieee80211_node {
> int ni_inact; /* inactivity mark count */
> int ni_txrate; /* index to ni_rates[] */
> int ni_state;
> + uint16_t ni_rtsthreshold;
>
> u_int16_t ni_flags; /* special-purpose state */
> #define IEEE80211_NODE_ERP 0x0001
>
>
>
>