d133ed91eb1784fb26afb4f8cb4e007614a40c33
[openwrt/staging/jow.git] /
1 From: Felix Fietkau <nbd@nbd.name>
2 Date: Sun, 9 Oct 2022 20:15:46 +0200
3 Subject: [PATCH] mac80211: add support for restricting netdev features per vif
4
5 This can be used to selectively disable feature flags for checksum offload,
6 scatter/gather or GSO by changing vif->netdev_features.
7 Removing features from vif->netdev_features does not affect the netdev
8 features themselves, but instead fixes up skbs in the tx path so that the
9 offloads are not needed in the driver.
10
11 Aside from making it easier to deal with vif type based hardware limitations,
12 this also makes it possible to optimize performance on hardware without native
13 GSO support by declaring GSO support in hw->netdev_features and removing it
14 from vif->netdev_features. This allows mac80211 to handle GSO segmentation
15 after the sta lookup, but before itxq enqueue, thus reducing the number of
16 unnecessary sta lookups, as well as some other per-packet processing.
17
18 Signed-off-by: Felix Fietkau <nbd@nbd.name>
19 ---
20
21 --- a/include/net/fq_impl.h
22 +++ b/include/net/fq_impl.h
23 @@ -200,6 +200,7 @@ static void fq_tin_enqueue(struct fq *fq
24 fq_skb_free_t free_func)
25 {
26 struct fq_flow *flow;
27 + struct sk_buff *next;
28 bool oom;
29
30 lockdep_assert_held(&fq->lock);
31 @@ -214,11 +215,15 @@ static void fq_tin_enqueue(struct fq *fq
32 }
33
34 flow->tin = tin;
35 - flow->backlog += skb->len;
36 - tin->backlog_bytes += skb->len;
37 - tin->backlog_packets++;
38 - fq->memory_usage += skb->truesize;
39 - fq->backlog++;
40 + skb_list_walk_safe(skb, skb, next) {
41 + skb_mark_not_on_list(skb);
42 + flow->backlog += skb->len;
43 + tin->backlog_bytes += skb->len;
44 + tin->backlog_packets++;
45 + fq->memory_usage += skb->truesize;
46 + fq->backlog++;
47 + __skb_queue_tail(&flow->queue, skb);
48 + }
49
50 if (list_empty(&flow->flowchain)) {
51 flow->deficit = fq->quantum;
52 @@ -226,7 +231,6 @@ static void fq_tin_enqueue(struct fq *fq
53 &tin->new_flows);
54 }
55
56 - __skb_queue_tail(&flow->queue, skb);
57 oom = (fq->memory_usage > fq->memory_limit);
58 while (fq->backlog > fq->limit || oom) {
59 flow = fq_find_fattest_flow(fq);
60 --- a/include/net/mac80211.h
61 +++ b/include/net/mac80211.h
62 @@ -1685,6 +1685,10 @@ enum ieee80211_offload_flags {
63 * write-protected by sdata_lock and local->mtx so holding either is fine
64 * for read access.
65 * @mu_mimo_owner: indicates interface owns MU-MIMO capability
66 + * @netdev_features: tx netdev features supported by the hardware for this
67 + * vif. mac80211 initializes this to hw->netdev_features, and the driver
68 + * can mask out specific tx features. mac80211 will handle software fixup
69 + * for masked offloads (GSO, CSUM)
70 * @driver_flags: flags/capabilities the driver has for this interface,
71 * these need to be set (or cleared) when the interface is added
72 * or, if supported by the driver, the interface type is changed
73 @@ -1736,6 +1740,7 @@ struct ieee80211_vif {
74
75 struct ieee80211_chanctx_conf __rcu *chanctx_conf;
76
77 + netdev_features_t netdev_features;
78 u32 driver_flags;
79 u32 offload_flags;
80
81 --- a/net/mac80211/iface.c
82 +++ b/net/mac80211/iface.c
83 @@ -2209,6 +2209,7 @@ int ieee80211_if_add(struct ieee80211_lo
84 ndev->features |= local->hw.netdev_features;
85 ndev->hw_features |= ndev->features &
86 MAC80211_SUPPORTED_FEATURES_TX;
87 + sdata->vif.netdev_features = local->hw.netdev_features;
88
89 netdev_set_default_ethtool_ops(ndev, &ieee80211_ethtool_ops);
90
91 --- a/net/mac80211/tx.c
92 +++ b/net/mac80211/tx.c
93 @@ -1310,7 +1310,11 @@ static struct txq_info *ieee80211_get_tx
94
95 static void ieee80211_set_skb_enqueue_time(struct sk_buff *skb)
96 {
97 - IEEE80211_SKB_CB(skb)->control.enqueue_time = codel_get_time();
98 + struct sk_buff *next;
99 + codel_time_t now = codel_get_time();
100 +
101 + skb_list_walk_safe(skb, skb, next)
102 + IEEE80211_SKB_CB(skb)->control.enqueue_time = now;
103 }
104
105 static u32 codel_skb_len_func(const struct sk_buff *skb)
106 @@ -3499,47 +3503,71 @@ ieee80211_xmit_fast_finish(struct ieee80
107 return TX_CONTINUE;
108 }
109
110 -static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
111 - struct sta_info *sta,
112 - struct ieee80211_fast_tx *fast_tx,
113 - struct sk_buff *skb)
114 +static netdev_features_t
115 +ieee80211_sdata_netdev_features(struct ieee80211_sub_if_data *sdata)
116 {
117 - struct ieee80211_local *local = sdata->local;
118 - u16 ethertype = (skb->data[12] << 8) | skb->data[13];
119 - int extra_head = fast_tx->hdr_len - (ETH_HLEN - 2);
120 - int hw_headroom = sdata->local->hw.extra_tx_headroom;
121 - struct ethhdr eth;
122 - struct ieee80211_tx_info *info;
123 - struct ieee80211_hdr *hdr = (void *)fast_tx->hdr;
124 - struct ieee80211_tx_data tx;
125 - ieee80211_tx_result r;
126 - struct tid_ampdu_tx *tid_tx = NULL;
127 - u8 tid = IEEE80211_NUM_TIDS;
128 + if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN)
129 + return sdata->vif.netdev_features;
130
131 - /* control port protocol needs a lot of special handling */
132 - if (cpu_to_be16(ethertype) == sdata->control_port_protocol)
133 - return false;
134 + if (!sdata->bss)
135 + return 0;
136
137 - /* only RFC 1042 SNAP */
138 - if (ethertype < ETH_P_802_3_MIN)
139 - return false;
140 + sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap);
141 + return sdata->vif.netdev_features;
142 +}
143
144 - /* don't handle TX status request here either */
145 - if (skb->sk && skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)
146 - return false;
147 +static struct sk_buff *
148 +ieee80211_tx_skb_fixup(struct sk_buff *skb, netdev_features_t features)
149 +{
150 + if (skb_is_gso(skb)) {
151 + struct sk_buff *segs;
152
153 - if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
154 - tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
155 - tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
156 - if (tid_tx) {
157 - if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state))
158 - return false;
159 - if (tid_tx->timeout)
160 - tid_tx->last_tx = jiffies;
161 - }
162 + segs = skb_gso_segment(skb, features);
163 + if (!segs)
164 + return skb;
165 + if (IS_ERR(segs))
166 + goto free;
167 +
168 + consume_skb(skb);
169 + return segs;
170 + }
171 +
172 + if (skb_needs_linearize(skb, features) && __skb_linearize(skb))
173 + goto free;
174 +
175 + if (skb->ip_summed == CHECKSUM_PARTIAL) {
176 + int ofs = skb_checksum_start_offset(skb);
177 +
178 + if (skb->encapsulation)
179 + skb_set_inner_transport_header(skb, ofs);
180 + else
181 + skb_set_transport_header(skb, ofs);
182 +
183 + if (skb_csum_hwoffload_help(skb, features))
184 + goto free;
185 }
186
187 - /* after this point (skb is modified) we cannot return false */
188 + skb_mark_not_on_list(skb);
189 + return skb;
190 +
191 +free:
192 + kfree_skb(skb);
193 + return NULL;
194 +}
195 +
196 +static void __ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
197 + struct sta_info *sta,
198 + struct ieee80211_fast_tx *fast_tx,
199 + struct sk_buff *skb, u8 tid, bool ampdu)
200 +{
201 + struct ieee80211_local *local = sdata->local;
202 + struct ieee80211_hdr *hdr = (void *)fast_tx->hdr;
203 + struct ieee80211_tx_info *info;
204 + struct ieee80211_tx_data tx;
205 + ieee80211_tx_result r;
206 + int hw_headroom = sdata->local->hw.extra_tx_headroom;
207 + int extra_head = fast_tx->hdr_len - (ETH_HLEN - 2);
208 + struct ethhdr eth;
209
210 if (skb_shared(skb)) {
211 struct sk_buff *tmp_skb = skb;
212 @@ -3548,12 +3576,12 @@ static bool ieee80211_xmit_fast(struct i
213 kfree_skb(tmp_skb);
214
215 if (!skb)
216 - return true;
217 + return;
218 }
219
220 if ((hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) &&
221 ieee80211_amsdu_aggregate(sdata, sta, fast_tx, skb))
222 - return true;
223 + return;
224
225 /* will not be crypto-handled beyond what we do here, so use false
226 * as the may-encrypt argument for the resize to not account for
227 @@ -3562,10 +3590,8 @@ static bool ieee80211_xmit_fast(struct i
228 if (unlikely(ieee80211_skb_resize(sdata, skb,
229 max_t(int, extra_head + hw_headroom -
230 skb_headroom(skb), 0),
231 - ENCRYPT_NO))) {
232 - kfree_skb(skb);
233 - return true;
234 - }
235 + ENCRYPT_NO)))
236 + goto free;
237
238 memcpy(&eth, skb->data, ETH_HLEN - 2);
239 hdr = skb_push(skb, extra_head);
240 @@ -3579,7 +3605,7 @@ static bool ieee80211_xmit_fast(struct i
241 info->control.vif = &sdata->vif;
242 info->flags = IEEE80211_TX_CTL_FIRST_FRAGMENT |
243 IEEE80211_TX_CTL_DONTFRAG |
244 - (tid_tx ? IEEE80211_TX_CTL_AMPDU : 0);
245 + (ampdu ? IEEE80211_TX_CTL_AMPDU : 0);
246 info->control.flags = IEEE80211_TX_CTRL_FAST_XMIT;
247
248 #ifdef CPTCFG_MAC80211_DEBUGFS
249 @@ -3601,16 +3627,14 @@ static bool ieee80211_xmit_fast(struct i
250 tx.key = fast_tx->key;
251
252 if (ieee80211_queue_skb(local, sdata, sta, skb))
253 - return true;
254 + return;
255
256 tx.skb = skb;
257 r = ieee80211_xmit_fast_finish(sdata, sta, fast_tx->pn_offs,
258 fast_tx->key, &tx);
259 tx.skb = NULL;
260 - if (r == TX_DROP) {
261 - kfree_skb(skb);
262 - return true;
263 - }
264 + if (r == TX_DROP)
265 + goto free;
266
267 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
268 sdata = container_of(sdata->bss,
269 @@ -3618,6 +3642,55 @@ static bool ieee80211_xmit_fast(struct i
270
271 __skb_queue_tail(&tx.skbs, skb);
272 ieee80211_tx_frags(local, &sdata->vif, sta, &tx.skbs, false);
273 + return;
274 +
275 +free:
276 + kfree_skb(skb);
277 +}
278 +
279 +static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
280 + struct sta_info *sta,
281 + struct ieee80211_fast_tx *fast_tx,
282 + struct sk_buff *skb)
283 +{
284 + u16 ethertype = (skb->data[12] << 8) | skb->data[13];
285 + struct ieee80211_hdr *hdr = (void *)fast_tx->hdr;
286 + struct tid_ampdu_tx *tid_tx = NULL;
287 + struct sk_buff *next;
288 + u8 tid = IEEE80211_NUM_TIDS;
289 +
290 + /* control port protocol needs a lot of special handling */
291 + if (cpu_to_be16(ethertype) == sdata->control_port_protocol)
292 + return false;
293 +
294 + /* only RFC 1042 SNAP */
295 + if (ethertype < ETH_P_802_3_MIN)
296 + return false;
297 +
298 + /* don't handle TX status request here either */
299 + if (skb->sk && skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)
300 + return false;
301 +
302 + if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
303 + tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
304 + tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
305 + if (tid_tx) {
306 + if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state))
307 + return false;
308 + if (tid_tx->timeout)
309 + tid_tx->last_tx = jiffies;
310 + }
311 + }
312 +
313 + skb = ieee80211_tx_skb_fixup(skb, ieee80211_sdata_netdev_features(sdata));
314 + if (!skb)
315 + return true;
316 +
317 + skb_list_walk_safe(skb, skb, next) {
318 + skb_mark_not_on_list(skb);
319 + __ieee80211_xmit_fast(sdata, sta, fast_tx, skb, tid, tid_tx);
320 + }
321 +
322 return true;
323 }
324
325 @@ -4123,31 +4196,14 @@ void __ieee80211_subif_start_xmit(struct
326 goto out;
327 }
328
329 - if (skb_is_gso(skb)) {
330 - struct sk_buff *segs;
331 -
332 - segs = skb_gso_segment(skb, 0);
333 - if (IS_ERR(segs)) {
334 - goto out_free;
335 - } else if (segs) {
336 - consume_skb(skb);
337 - skb = segs;
338 - }
339 - } else {
340 - /* we cannot process non-linear frames on this path */
341 - if (skb_linearize(skb))
342 - goto out_free;
343 -
344 - /* the frame could be fragmented, software-encrypted, and other
345 - * things so we cannot really handle checksum offload with it -
346 - * fix it up in software before we handle anything else.
347 - */
348 - if (skb->ip_summed == CHECKSUM_PARTIAL) {
349 - skb_set_transport_header(skb,
350 - skb_checksum_start_offset(skb));
351 - if (skb_checksum_help(skb))
352 - goto out_free;
353 - }
354 + /* the frame could be fragmented, software-encrypted, and other
355 + * things so we cannot really handle checksum or GSO offload.
356 + * fix it up in software before we handle anything else.
357 + */
358 + skb = ieee80211_tx_skb_fixup(skb, 0);
359 + if (!skb) {
360 + len = 0;
361 + goto out;
362 }
363
364 skb_list_walk_safe(skb, skb, next) {
365 @@ -4310,9 +4366,11 @@ netdev_tx_t ieee80211_subif_start_xmit(s
366 return NETDEV_TX_OK;
367 }
368
369 -static bool ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
370 - struct sk_buff *skb, struct sta_info *sta,
371 - bool txpending)
372 +
373 +
374 +static bool __ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
375 + struct sk_buff *skb, struct sta_info *sta,
376 + bool txpending)
377 {
378 struct ieee80211_local *local = sdata->local;
379 struct ieee80211_tx_control control = {};
380 @@ -4321,14 +4379,6 @@ static bool ieee80211_tx_8023(struct iee
381 unsigned long flags;
382 int q = info->hw_queue;
383
384 - if (sta)
385 - sk_pacing_shift_update(skb->sk, local->hw.tx_sk_pacing_shift);
386 -
387 - ieee80211_tpt_led_trig_tx(local, skb->len);
388 -
389 - if (ieee80211_queue_skb(local, sdata, sta, skb))
390 - return true;
391 -
392 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
393
394 if (local->queue_stop_reasons[q] ||
395 @@ -4355,27 +4405,50 @@ static bool ieee80211_tx_8023(struct iee
396 return true;
397 }
398
399 +static bool ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
400 + struct sk_buff *skb, struct sta_info *sta,
401 + bool txpending)
402 +{
403 + struct ieee80211_local *local = sdata->local;
404 + struct sk_buff *next;
405 + bool ret = true;
406 +
407 + if (ieee80211_queue_skb(local, sdata, sta, skb))
408 + return true;
409 +
410 + skb_list_walk_safe(skb, skb, next) {
411 + skb_mark_not_on_list(skb);
412 + if (!__ieee80211_tx_8023(sdata, skb, sta, txpending))
413 + ret = false;
414 + }
415 +
416 + return ret;
417 +}
418 +
419 static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
420 struct net_device *dev, struct sta_info *sta,
421 struct ieee80211_key *key, struct sk_buff *skb)
422 {
423 - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
424 + struct ieee80211_tx_info *info;
425 struct ieee80211_local *local = sdata->local;
426 struct tid_ampdu_tx *tid_tx;
427 + struct sk_buff *seg, *next;
428 + unsigned int skbs = 0, len = 0;
429 + u16 queue;
430 u8 tid;
431
432 if (local->ops->wake_tx_queue) {
433 - u16 queue = __ieee80211_select_queue(sdata, sta, skb);
434 + queue = __ieee80211_select_queue(sdata, sta, skb);
435 skb_set_queue_mapping(skb, queue);
436 skb_get_hash(skb);
437 + } else {
438 + queue = skb_get_queue_mapping(skb);
439 }
440
441 if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning)) &&
442 test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
443 goto out_free;
444
445 - memset(info, 0, sizeof(*info));
446 -
447 ieee80211_aggr_check(sdata, sta, skb);
448
449 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
450 @@ -4387,22 +4460,20 @@ static void ieee80211_8023_xmit(struct i
451 return;
452 }
453
454 - info->flags |= IEEE80211_TX_CTL_AMPDU;
455 if (tid_tx->timeout)
456 tid_tx->last_tx = jiffies;
457 }
458
459 - if (unlikely(skb->sk &&
460 - skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS))
461 - info->ack_frame_id = ieee80211_store_ack_skb(local, skb,
462 - &info->flags, NULL);
463 + skb = ieee80211_tx_skb_fixup(skb, ieee80211_sdata_netdev_features(sdata));
464 + if (!skb)
465 + return;
466
467 - info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
468 + info = IEEE80211_SKB_CB(skb);
469 + memset(info, 0, sizeof(*info));
470 + if (tid_tx)
471 + info->flags |= IEEE80211_TX_CTL_AMPDU;
472
473 - dev_sw_netstats_tx_add(dev, 1, skb->len);
474 -
475 - sta->tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len;
476 - sta->tx_stats.packets[skb_get_queue_mapping(skb)]++;
477 + info->hw_queue = sdata->vif.hw_queue[queue];
478
479 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
480 sdata = container_of(sdata->bss,
481 @@ -4414,6 +4485,24 @@ static void ieee80211_8023_xmit(struct i
482 if (key)
483 info->control.hw_key = &key->conf;
484
485 + skb_list_walk_safe(skb, seg, next) {
486 + skbs++;
487 + len += seg->len;
488 + if (seg != skb)
489 + memcpy(IEEE80211_SKB_CB(seg), info, sizeof(*info));
490 + }
491 +
492 + if (unlikely(skb->sk &&
493 + skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS))
494 + info->ack_frame_id = ieee80211_store_ack_skb(local, skb,
495 + &info->flags, NULL);
496 +
497 + dev_sw_netstats_tx_add(dev, skbs, len);
498 + sta->tx_stats.packets[queue] += skbs;
499 + sta->tx_stats.bytes[queue] += len;
500 +
501 + ieee80211_tpt_led_trig_tx(local, len);
502 +
503 ieee80211_tx_8023(sdata, skb, sta, false);
504
505 return;
506 @@ -4455,6 +4544,7 @@ netdev_tx_t ieee80211_subif_start_xmit_8
507 key->conf.cipher == WLAN_CIPHER_SUITE_TKIP))
508 goto skip_offload;
509
510 + sk_pacing_shift_update(skb->sk, sdata->local->hw.tx_sk_pacing_shift);
511 ieee80211_8023_xmit(sdata, dev, sta, key, skb);
512 goto out;
513