diff --git a/package/kernel/mac80211/patches/subsys/357-mac80211-optimize-skb-resizing.patch b/package/kernel/mac80211/patches/subsys/357-mac80211-optimize-skb-resizing.patch new file mode 100644 index 0000000000..8fd85fedcc --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/357-mac80211-optimize-skb-resizing.patch @@ -0,0 +1,198 @@ +From: Felix Fietkau +Date: Sun, 17 Mar 2019 18:11:30 +0100 +Subject: [PATCH] mac80211: optimize skb resizing + +When forwarding unicast packets from ethernet to batman-adv over 802.11s +(with forwarding disabled), the typical required headroom to transmit +encrypted packets on mt76 is 32 (802.11) + 6 (802.11s) + 8 (CCMP) + +2 (padding) + 6 (LLC) + 18 (batman-adv) - 14 (old ethernet header) = 58 bytes. + +On systems where NET_SKB_PAD is 64 this leads to a call to pskb_expand_head +for every packet, since mac80211 also tries to allocate 16 bytes status +headroom for radiotap headers. + +This patch fixes these unnecessary reallocations by only requiring the extra +status headroom in ieee80211_tx_monitor() +If however a reallocation happens before that call, the status headroom gets +added there as well, in order to avoid double reallocation. + +The patch also cleans up the code by moving the headroom calculation to +ieee80211_skb_resize. + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -1761,6 +1761,8 @@ void ieee80211_clear_fast_xmit(struct st + int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, + const u8 *buf, size_t len, + const u8 *dest, __be16 proto, bool unencrypted); ++int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata, ++ struct sk_buff *skb, int hdrlen, int hdr_add); + + /* HT */ + void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, +--- a/net/mac80211/status.c ++++ b/net/mac80211/status.c +@@ -672,6 +672,11 @@ void ieee80211_tx_monitor(struct ieee802 + } + } + ++ if (ieee80211_skb_resize(NULL, skb, 0, 0)) { ++ dev_kfree_skb(skb); ++ return; ++ } ++ + /* send frame to monitor interfaces now */ + rtap_len = ieee80211_tx_radiotap_len(info); + if (WARN_ON_ONCE(skb_headroom(skb) < rtap_len)) { +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -1914,37 +1914,53 @@ static bool ieee80211_tx(struct ieee8021 + } + + /* device xmit handlers */ +- +-static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata, +- struct sk_buff *skb, +- int head_need, bool may_encrypt) ++int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata, ++ struct sk_buff *skb, int hdr_len, int hdr_extra) + { + struct ieee80211_local *local = sdata->local; ++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr; +- bool enc_tailroom; +- int tail_need = 0; ++ int head_need, head_max; ++ int tail_need, tail_max; ++ bool enc_tailroom = false; + +- hdr = (struct ieee80211_hdr *) skb->data; +- enc_tailroom = may_encrypt && +- (sdata->crypto_tx_tailroom_needed_cnt || +- ieee80211_is_mgmt(hdr->frame_control)); ++ if (sdata && !hdr_len && ++ !(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) { ++ hdr = (struct ieee80211_hdr *) skb->data; ++ enc_tailroom = (sdata->crypto_tx_tailroom_needed_cnt || ++ ieee80211_is_mgmt(hdr->frame_control)); ++ hdr_len += sdata->encrypt_headroom; ++ } + +- if (enc_tailroom) { +- tail_need = IEEE80211_ENCRYPT_TAILROOM; +- tail_need -= skb_tailroom(skb); +- tail_need = max_t(int, tail_need, 0); ++ head_need = head_max = hdr_len; ++ tail_need = tail_max = 0; ++ if (!sdata) { ++ head_need = head_max = local->tx_headroom; ++ } else { ++ head_max += hdr_extra; ++ head_max += max_t(int, local->tx_headroom, ++ local->hw.extra_tx_headroom); ++ head_need += local->hw.extra_tx_headroom; ++ ++ tail_max = IEEE80211_ENCRYPT_TAILROOM; ++ if (enc_tailroom) ++ tail_need = tail_max; + } + + if (skb_cloned(skb) && + (!ieee80211_hw_check(&local->hw, SUPPORTS_CLONED_SKBS) || + !skb_clone_writable(skb, ETH_HLEN) || enc_tailroom)) + I802_DEBUG_INC(local->tx_expand_skb_head_cloned); +- else if (head_need || tail_need) ++ else if (head_need > skb_headroom(skb) || ++ tail_need > skb_tailroom(skb)) + I802_DEBUG_INC(local->tx_expand_skb_head); + else + return 0; + +- if (pskb_expand_head(skb, head_need, tail_need, GFP_ATOMIC)) { ++ head_max = max_t(int, 0, head_max - skb_headroom(skb)); ++ tail_max = max_t(int, 0, tail_max - skb_tailroom(skb)); ++ ++ if (pskb_expand_head(skb, head_max, tail_max, GFP_ATOMIC)) { + wiphy_debug(local->hw.wiphy, + "failed to reallocate TX buffer\n"); + return -ENOMEM; +@@ -1960,18 +1976,8 @@ void ieee80211_xmit(struct ieee80211_sub + struct ieee80211_local *local = sdata->local; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr; +- int headroom; +- bool may_encrypt; +- +- may_encrypt = !(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT); +- +- headroom = local->tx_headroom; +- if (may_encrypt) +- headroom += sdata->encrypt_headroom; +- headroom -= skb_headroom(skb); +- headroom = max_t(int, 0, headroom); + +- if (ieee80211_skb_resize(sdata, skb, headroom, may_encrypt)) { ++ if (ieee80211_skb_resize(sdata, skb, 0, 0)) { + ieee80211_free_txskb(&local->hw, skb); + return; + } +@@ -2740,30 +2746,14 @@ static struct sk_buff *ieee80211_build_h + + skb_pull(skb, skip_header_bytes); + padsize = ieee80211_hdr_padsize(&local->hw, hdrlen); +- head_need = hdrlen + encaps_len + meshhdrlen - skb_headroom(skb); ++ head_need = hdrlen + encaps_len + meshhdrlen; + head_need += padsize; + +- /* +- * So we need to modify the skb header and hence need a copy of +- * that. The head_need variable above doesn't, so far, include +- * the needed header space that we don't need right away. If we +- * can, then we don't reallocate right now but only after the +- * frame arrives at the master device (if it does...) +- * +- * If we cannot, however, then we will reallocate to include all +- * the ever needed space. Also, if we need to reallocate it anyway, +- * make it big enough for everything we may ever need. +- */ +- +- if (head_need > 0 || skb_cloned(skb)) { +- head_need += sdata->encrypt_headroom; +- head_need += local->tx_headroom; +- head_need = max_t(int, 0, head_need); +- if (ieee80211_skb_resize(sdata, skb, head_need, true)) { +- ieee80211_free_txskb(&local->hw, skb); +- skb = NULL; +- return ERR_PTR(-ENOMEM); +- } ++ if (ieee80211_skb_resize(sdata, skb, head_need, ++ sdata->encrypt_headroom)) { ++ ieee80211_free_txskb(&local->hw, skb); ++ skb = NULL; ++ return ERR_PTR(-ENOMEM); + } + + if (encaps_data) +@@ -3377,7 +3367,6 @@ static bool ieee80211_xmit_fast(struct i + struct ieee80211_local *local = sdata->local; + u16 ethertype = (skb->data[12] << 8) | skb->data[13]; + int extra_head = fast_tx->hdr_len - (ETH_HLEN - 2); +- int hw_headroom = sdata->local->hw.extra_tx_headroom; + struct ethhdr eth; + struct ieee80211_tx_info *info; + struct ieee80211_hdr *hdr = (void *)fast_tx->hdr; +@@ -3429,10 +3418,7 @@ static bool ieee80211_xmit_fast(struct i + * as the may-encrypt argument for the resize to not account for + * more room than we already have in 'extra_head' + */ +- if (unlikely(ieee80211_skb_resize(sdata, skb, +- max_t(int, extra_head + hw_headroom - +- skb_headroom(skb), 0), +- false))) { ++ if (unlikely(ieee80211_skb_resize(sdata, skb, extra_head, 0))) { + kfree_skb(skb); + return true; + }