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).

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




Reply via email to