summaryrefslogtreecommitdiff
path: root/sys/net80211
diff options
context:
space:
mode:
authorStefan Sperling <stsp@cvs.openbsd.org>2019-09-12 12:55:08 +0000
committerStefan Sperling <stsp@cvs.openbsd.org>2019-09-12 12:55:08 +0000
commitbf1d600d09a5e6bd03f65236695ceb27eee54583 (patch)
tree61b19e1ac5df4f2d3e59772380c88bda5b54db33 /sys/net80211
parentcdd78b5d4dc581ea298f7e14e7b2403c27de216f (diff)
Make wireless drivers call if_input() only once per interrupt.
This reduces drops caused by the ifq pressure drop mechanism and hence increases throughput. Such drops are visible with e.g. 'netstat -dnI iwm0'. Not all affected drivers have been tested yet but these changes are largely mechanical and should be safe. As usual, please report any regressions. With help from dlg@ and mpi@ Problem found by robert@ Tested by robert, jmc, Tracey Emer, Matthias Schmidt, florian, Björn Ketelaars ok mpi@
Diffstat (limited to 'sys/net80211')
-rw-r--r--sys/net80211/ieee80211_input.c111
-rw-r--r--sys/net80211/ieee80211_proto.h5
2 files changed, 72 insertions, 44 deletions
diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c
index 73a9d522950..becb5da6b21 100644
--- a/sys/net80211/ieee80211_input.c
+++ b/sys/net80211/ieee80211_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_input.c,v 1.208 2019/08/29 09:13:56 stsp Exp $ */
+/* $OpenBSD: ieee80211_input.c,v 1.209 2019/09/12 12:55:07 stsp Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
@@ -61,21 +61,22 @@
struct mbuf *ieee80211_defrag(struct ieee80211com *, struct mbuf *, int);
void ieee80211_defrag_timeout(void *);
void ieee80211_input_ba(struct ieee80211com *, struct mbuf *,
- struct ieee80211_node *, int, struct ieee80211_rxinfo *);
+ struct ieee80211_node *, int, struct ieee80211_rxinfo *,
+ struct mbuf_list *);
void ieee80211_input_ba_flush(struct ieee80211com *, struct ieee80211_node *,
- struct ieee80211_rx_ba *);
+ struct ieee80211_rx_ba *, struct mbuf_list *);
void ieee80211_input_ba_gap_timeout(void *arg);
void ieee80211_ba_move_window(struct ieee80211com *,
- struct ieee80211_node *, u_int8_t, u_int16_t);
+ struct ieee80211_node *, u_int8_t, u_int16_t, struct mbuf_list *);
void ieee80211_input_ba_seq(struct ieee80211com *,
- struct ieee80211_node *, uint8_t, uint16_t);
+ struct ieee80211_node *, uint8_t, uint16_t, struct mbuf_list *);
struct mbuf *ieee80211_align_mbuf(struct mbuf *);
void ieee80211_decap(struct ieee80211com *, struct mbuf *,
- struct ieee80211_node *, int);
+ struct ieee80211_node *, int, struct mbuf_list *);
void ieee80211_amsdu_decap(struct ieee80211com *, struct mbuf *,
- struct ieee80211_node *, int);
-void ieee80211_deliver_data(struct ieee80211com *, struct mbuf *,
- struct ieee80211_node *, int);
+ struct ieee80211_node *, int, struct mbuf_list *);
+void ieee80211_enqueue_data(struct ieee80211com *, struct mbuf *,
+ struct ieee80211_node *, int, struct mbuf_list *);
int ieee80211_parse_edca_params_body(struct ieee80211com *,
const u_int8_t *);
int ieee80211_parse_edca_params(struct ieee80211com *, const u_int8_t *);
@@ -155,10 +156,16 @@ ieee80211_get_hdrlen(const struct ieee80211_frame *wh)
* any units so long as values have consistent units and higher values
* mean ``better signal''. The receive timestamp is currently not used
* by the 802.11 layer.
+ *
+ * This function acts on management frames immediately and queues data frames
+ * on the specified mbuf list. Delivery of queued data frames to upper layers
+ * must be triggered with if_input(). Drivers should call if_input() only once
+ * per Rx interrupt to avoid triggering the input ifq pressure drop mechanism
+ * unnecessarily.
*/
void
-ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
- struct ieee80211_rxinfo *rxi)
+ieee80211_inputm(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
+ struct ieee80211_rxinfo *rxi, struct mbuf_list *ml)
{
struct ieee80211com *ic = (void *)ifp;
struct ieee80211_frame *wh;
@@ -259,7 +266,7 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
(qos & IEEE80211_QOS_ACK_POLICY_MASK) ==
IEEE80211_QOS_ACK_POLICY_NORMAL)) {
/* go through A-MPDU reordering */
- ieee80211_input_ba(ic, m, ni, tid, rxi);
+ ieee80211_input_ba(ic, m, ni, tid, rxi, ml);
return; /* don't free m! */
}
}
@@ -463,9 +470,9 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
if ((ni->ni_flags & IEEE80211_NODE_HT) &&
hasqos && (qos & IEEE80211_QOS_AMSDU))
- ieee80211_amsdu_decap(ic, m, ni, hdrlen);
+ ieee80211_amsdu_decap(ic, m, ni, hdrlen, ml);
else
- ieee80211_decap(ic, m, ni, hdrlen);
+ ieee80211_decap(ic, m, ni, hdrlen, ml);
return;
case IEEE80211_FC0_TYPE_MGT:
@@ -560,6 +567,17 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
}
}
+/* Input handler for drivers which only receive one frame per interrupt. */
+void
+ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
+ struct ieee80211_rxinfo *rxi)
+{
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
+
+ ieee80211_inputm(ifp, m, ni, rxi, &ml);
+ if_input(ifp, &ml);
+}
+
/*
* Handle defragmentation (see 9.5 and Annex C). We support the concurrent
* reception of fragments of three fragmented MSDUs or MMPDUs.
@@ -656,7 +674,8 @@ ieee80211_defrag_timeout(void *arg)
*/
void
ieee80211_input_ba(struct ieee80211com *ic, struct mbuf *m,
- struct ieee80211_node *ni, int tid, struct ieee80211_rxinfo *rxi)
+ struct ieee80211_node *ni, int tid, struct ieee80211_rxinfo *rxi,
+ struct mbuf_list *ml)
{
struct ifnet *ifp = &ic->ic_if;
struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid];
@@ -699,12 +718,12 @@ ieee80211_input_ba(struct ieee80211com *ic, struct mbuf *m,
ic->ic_stats.is_ht_rx_ba_window_jump++;
ba->ba_winmiss = 0;
ba->ba_missedsn = 0;
- ieee80211_ba_move_window(ic, ni, tid, sn);
+ ieee80211_ba_move_window(ic, ni, tid, sn, ml);
} else {
ic->ic_stats.is_ht_rx_ba_window_slide++;
ieee80211_input_ba_seq(ic, ni, tid,
- (ba->ba_winstart + count) & 0xfff);
- ieee80211_input_ba_flush(ic, ni, ba);
+ (ba->ba_winstart + count) & 0xfff, ml);
+ ieee80211_input_ba_flush(ic, ni, ba, ml);
}
}
/* WinStartB <= SN <= WinEndB */
@@ -730,7 +749,7 @@ ieee80211_input_ba(struct ieee80211com *ic, struct mbuf *m,
else if (timeout_pending(&ba->ba_gap_to))
timeout_del(&ba->ba_gap_to);
- ieee80211_input_ba_flush(ic, ni, ba);
+ ieee80211_input_ba_flush(ic, ni, ba, ml);
}
/*
@@ -739,7 +758,7 @@ ieee80211_input_ba(struct ieee80211com *ic, struct mbuf *m,
*/
void
ieee80211_input_ba_seq(struct ieee80211com *ic, struct ieee80211_node *ni,
- uint8_t tid, uint16_t max_seq)
+ uint8_t tid, uint16_t max_seq, struct mbuf_list *ml)
{
struct ifnet *ifp = &ic->ic_if;
struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid];
@@ -757,8 +776,8 @@ ieee80211_input_ba_seq(struct ieee80211com *ic, struct ieee80211_node *ni,
IEEE80211_SEQ_SEQ_SHIFT;
if (!SEQ_LT(seq, max_seq))
return;
- ieee80211_input(ifp, ba->ba_buf[ba->ba_head].m,
- ni, &ba->ba_buf[ba->ba_head].rxi);
+ ieee80211_inputm(ifp, ba->ba_buf[ba->ba_head].m,
+ ni, &ba->ba_buf[ba->ba_head].rxi, ml);
ba->ba_buf[ba->ba_head].m = NULL;
} else
ic->ic_stats.is_ht_rx_ba_frame_lost++;
@@ -769,15 +788,15 @@ ieee80211_input_ba_seq(struct ieee80211com *ic, struct ieee80211_node *ni,
/* Flush a consecutive sequence of frames from the reorder buffer. */
void
ieee80211_input_ba_flush(struct ieee80211com *ic, struct ieee80211_node *ni,
- struct ieee80211_rx_ba *ba)
+ struct ieee80211_rx_ba *ba, struct mbuf_list *ml)
{
struct ifnet *ifp = &ic->ic_if;
/* pass reordered MPDUs up to the next MAC process */
while (ba->ba_buf[ba->ba_head].m != NULL) {
- ieee80211_input(ifp, ba->ba_buf[ba->ba_head].m, ni,
- &ba->ba_buf[ba->ba_head].rxi);
+ ieee80211_inputm(ifp, ba->ba_buf[ba->ba_head].m, ni,
+ &ba->ba_buf[ba->ba_head].rxi, ml);
ba->ba_buf[ba->ba_head].m = NULL;
ba->ba_head = (ba->ba_head + 1) % IEEE80211_BA_MAX_WINSZ;
@@ -796,6 +815,7 @@ ieee80211_input_ba_flush(struct ieee80211com *ic, struct ieee80211_node *ni,
void
ieee80211_input_ba_gap_timeout(void *arg)
{
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
struct ieee80211_rx_ba *ba = arg;
struct ieee80211_node *ni = ba->ba_ni;
struct ieee80211com *ic = ni->ni_ic;
@@ -816,7 +836,8 @@ ieee80211_input_ba_gap_timeout(void *arg)
if (skipped > 0)
ba->ba_winend = (ba->ba_winstart + ba->ba_winsize - 1) & 0xfff;
- ieee80211_input_ba_flush(ic, ni, ba);
+ ieee80211_input_ba_flush(ic, ni, ba, &ml);
+ if_input(&ic->ic_if, &ml);
splx(s);
}
@@ -828,7 +849,7 @@ ieee80211_input_ba_gap_timeout(void *arg)
*/
void
ieee80211_ba_move_window(struct ieee80211com *ic, struct ieee80211_node *ni,
- u_int8_t tid, u_int16_t ssn)
+ u_int8_t tid, u_int16_t ssn, struct mbuf_list *ml)
{
struct ifnet *ifp = &ic->ic_if;
struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid];
@@ -842,8 +863,8 @@ ieee80211_ba_move_window(struct ieee80211com *ic, struct ieee80211_node *ni,
while (count-- > 0) {
/* gaps may exist */
if (ba->ba_buf[ba->ba_head].m != NULL) {
- ieee80211_input(ifp, ba->ba_buf[ba->ba_head].m, ni,
- &ba->ba_buf[ba->ba_head].rxi);
+ ieee80211_inputm(ifp, ba->ba_buf[ba->ba_head].m, ni,
+ &ba->ba_buf[ba->ba_head].rxi, ml);
ba->ba_buf[ba->ba_head].m = NULL;
} else
ic->ic_stats.is_ht_rx_ba_frame_lost++;
@@ -852,12 +873,12 @@ ieee80211_ba_move_window(struct ieee80211com *ic, struct ieee80211_node *ni,
/* move window forward */
ba->ba_winstart = ssn;
- ieee80211_input_ba_flush(ic, ni, ba);
+ ieee80211_input_ba_flush(ic, ni, ba, ml);
}
void
-ieee80211_deliver_data(struct ieee80211com *ic, struct mbuf *m,
- struct ieee80211_node *ni, int mcast)
+ieee80211_enqueue_data(struct ieee80211com *ic, struct mbuf *m,
+ struct ieee80211_node *ni, int mcast, struct mbuf_list *ml)
{
struct ifnet *ifp = &ic->ic_if;
struct ether_header *eh;
@@ -920,16 +941,14 @@ ieee80211_deliver_data(struct ieee80211com *ic, struct mbuf *m,
#endif
ieee80211_eapol_key_input(ic, m, ni);
} else {
- struct mbuf_list ml = MBUF_LIST_INITIALIZER();
- ml_enqueue(&ml, m);
- if_input(ifp, &ml);
+ ml_enqueue(ml, m);
}
}
}
void
ieee80211_decap(struct ieee80211com *ic, struct mbuf *m,
- struct ieee80211_node *ni, int hdrlen)
+ struct ieee80211_node *ni, int hdrlen, struct mbuf_list *ml)
{
struct ether_header eh;
struct ieee80211_frame *wh;
@@ -985,7 +1004,7 @@ ieee80211_decap(struct ieee80211com *ic, struct mbuf *m,
return;
}
}
- ieee80211_deliver_data(ic, m, ni, mcast);
+ ieee80211_enqueue_data(ic, m, ni, mcast, ml);
}
/*
@@ -993,7 +1012,7 @@ ieee80211_decap(struct ieee80211com *ic, struct mbuf *m,
*/
void
ieee80211_amsdu_decap(struct ieee80211com *ic, struct mbuf *m,
- struct ieee80211_node *ni, int hdrlen)
+ struct ieee80211_node *ni, int hdrlen, struct mbuf_list *ml)
{
struct mbuf *n;
struct ether_header *eh;
@@ -1059,7 +1078,7 @@ ieee80211_amsdu_decap(struct ieee80211com *ic, struct mbuf *m,
m_freem(m);
break;
}
- ieee80211_deliver_data(ic, m, ni, mcast);
+ ieee80211_enqueue_data(ic, m, ni, mcast, ml);
if (n->m_pkthdr.len == 0) {
m_freem(n);
@@ -2564,8 +2583,11 @@ ieee80211_recv_addba_req(struct ieee80211com *ic, struct mbuf *m,
return; /* not a PBAC, ignore */
/* PBAC: treat the ADDBA Request like a BlockAckReq */
- if (SEQ_LT(ba->ba_winstart, ssn))
- ieee80211_ba_move_window(ic, ni, tid, ssn);
+ if (SEQ_LT(ba->ba_winstart, ssn)) {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
+ ieee80211_ba_move_window(ic, ni, tid, ssn, &ml);
+ if_input(&ic->ic_if, &ml);
+ }
return;
}
@@ -3174,6 +3196,9 @@ ieee80211_bar_tid(struct ieee80211com *ic, struct ieee80211_node *ni,
if (ba->ba_timeout_val != 0)
timeout_add_usec(&ba->ba_to, ba->ba_timeout_val);
- if (SEQ_LT(ba->ba_winstart, ssn))
- ieee80211_ba_move_window(ic, ni, tid, ssn);
+ if (SEQ_LT(ba->ba_winstart, ssn)) {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
+ ieee80211_ba_move_window(ic, ni, tid, ssn, &ml);
+ if_input(&ic->ic_if, &ml);
+ }
}
diff --git a/sys/net80211/ieee80211_proto.h b/sys/net80211/ieee80211_proto.h
index e622d35f4dc..7208e5dc0be 100644
--- a/sys/net80211/ieee80211_proto.h
+++ b/sys/net80211/ieee80211_proto.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_proto.h,v 1.45 2019/07/29 10:50:09 stsp Exp $ */
+/* $OpenBSD: ieee80211_proto.h,v 1.46 2019/09/12 12:55:07 stsp Exp $ */
/* $NetBSD: ieee80211_proto.h,v 1.3 2003/10/13 04:23:56 dyoung Exp $ */
/*-
@@ -66,6 +66,9 @@ struct ieee80211_rsnparams;
extern void ieee80211_set_link_state(struct ieee80211com *, int);
extern u_int ieee80211_get_hdrlen(const struct ieee80211_frame *);
extern int ieee80211_classify(struct ieee80211com *, struct mbuf *);
+extern void ieee80211_inputm(struct ifnet *, struct mbuf *,
+ struct ieee80211_node *, struct ieee80211_rxinfo *,
+ struct mbuf_list *);
extern void ieee80211_input(struct ifnet *, struct mbuf *,
struct ieee80211_node *, struct ieee80211_rxinfo *);
extern int ieee80211_output(struct ifnet *, struct mbuf *, struct sockaddr *,