summaryrefslogtreecommitdiff
path: root/net/sched/act_ife.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-08-27 13:53:43 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-08-27 13:53:43 -0700
commit1b78070aaef63512688aebfbc82365ef9d6660f1 (patch)
tree691c0aeaa3d92278ceeb6ace56bc8cd56a7f2ae8 /net/sched/act_ife.c
parent3ba13f5e7180c034b0a1ef7e052fb780856b134e (diff)
parent4a9d62a8774f130a5b8de26ca9f415e6050a9d51 (diff)
downloadlinux-next-stable.tar.gz
linux-next-stable.zip
Merge tag 'net-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/netstable
Pull networking fixes from Jakub Kicinski: "Including fixes from Bluetooth, IPSec and Netfilter. Current release - fix to a fix: - netfilter: ipset: remove need to allocate memory on delete operations Current release - regressions: - macb: drop CONFIG_OF #if block, fix build Previous releases - always broken: - stream of fixes for SCTP continues - inet: frags: strip GSO state from fragments before reassembly - virtio-net: ensure that TCP packets don't overflow gso_segs - tcp-ao: fix use-after-free of current_key on reconnect to another peer - page_pool: remove zone/policy GFP flags when allocating XArray entries - Bluetooth: L2CAP: reject accept queue add unless BT_LISTEN - tls: device: fix out-of-bounds write in tls_append_frag() - eth: bnxt: - ring the doorbell when SW USO exits early, avoid packets stuck in Tx - gate TPH enablement behind BNXT_SUPPORTS_QUEUE_API check, avoid users of older NICs seeing non-actionable warning messages - eth: qede: fix NULL pointer dereference in TPA fragment processing" * tag 'net-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (216 commits) inet: frags: strip GSO state from fragments before reassembly net/sched: sch_htb: limit htb_classify inner-class filter hops selftests/net: packetdrill: add tcp_urg_ptr_retransmit tcp: fix corruption of urgent data on multi-segment retransmit usb: atm: usbatm: fix invalid ci_range initialization net: fec: only stop PTP if it was initialized slip: remove slip_hangup() to fix use-after-free in slip_receive_buf() net: bridge: mcast: fix use-after-free of a master VLAN's multicast context net/sched: bound qdisc_pkt_len to prevent qdisc soft lockup net: dsa: mxl862xx: enable assisted learning on CPU port net: stmmac: restore NET_IP_ALIGN in the RX DMA offset net: stmmac: drop gso_enabled_types and rely on netdev features net: stmmac: selftests: Don't test flow control for small rx fifos net: stmmac: selftests: Account for the UC filter list for filtering tests net: stmmac: dwxgmac: Account for the primary MAC address for UC filtering net: stmmac: dwmac4: Account for the primary MAC address for UC filtering net: stmmac: dwmac1000: Account for the primary MAC address for UC filtering net: stmmac: selftests: Check multiple MMC counters selftests: net: Fix slow configurations in big_tcp_tunnels.sh selftests: net: Lower threshold with csum offload off in big_tcp_tunnels.sh ...
Diffstat (limited to 'net/sched/act_ife.c')
-rw-r--r--net/sched/act_ife.c55
1 files changed, 51 insertions, 4 deletions
diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c
index 065228026c58..9cea71fc1db3 100644
--- a/net/sched/act_ife.c
+++ b/net/sched/act_ife.c
@@ -28,6 +28,7 @@
#include <uapi/linux/tc_act/tc_ife.h>
#include <net/tc_act/tc_ife.h>
#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
#include <net/ife.h>
#include <net/tc_wrapper.h>
@@ -723,7 +724,7 @@ static int tcf_ife_decode(struct sk_buff *skb, const struct tc_action *a,
tcf_lastuse_update(&ife->tcf_tm);
if (skb_at_tc_ingress(skb))
- skb_push(skb, skb->dev->hard_header_len);
+ skb_push(skb, ETH_HLEN);
tlv_data = ife_decode(skb, &metalen);
if (unlikely(!tlv_data)) {
@@ -795,7 +796,7 @@ static int tcf_ife_encode(struct sk_buff *skb, const struct tc_action *a,
where ORIGDATA = original ethernet header ...
*/
u16 metalen = ife_get_sz(skb, p);
- int hdrm = metalen + skb->dev->hard_header_len + IFE_METAHDRLEN;
+ int hdrm = metalen + ETH_HLEN + IFE_METAHDRLEN;
unsigned int skboff = 0;
int new_len = skb->len + hdrm;
bool exceed_mtu = false;
@@ -826,7 +827,7 @@ drop:
}
if (skb_at_tc_ingress(skb))
- skb_push(skb, skb->dev->hard_header_len);
+ skb_push(skb, ETH_HLEN);
ife_meta = ife_encode(skb, metalen);
if (!ife_meta)
@@ -856,11 +857,27 @@ drop:
oethh->h_proto = htons(p->eth_type);
if (skb_at_tc_ingress(skb))
- skb_pull(skb, skb->dev->hard_header_len);
+ skb_pull(skb, ETH_HLEN);
return action;
}
+/* IFE encapsulates the original Ethernet header and, on decode, expects to
+ * find one, so it can only ever work on skbs that carry one. Loopback carries
+ * Ethernet header as well, so it qualifies here.
+ * At ingress, also verify that the L2 header about to be pushed back really
+ * is an Ethernet header because the skb could've been redirected with mirred
+ * from a non-Ethernet device.
+ */
+static bool tcf_ife_is_eth_skb(const struct sk_buff *skb)
+{
+ if (skb->dev->type != ARPHRD_ETHER &&
+ skb->dev->type != ARPHRD_LOOPBACK)
+ return false;
+
+ return !skb_at_tc_ingress(skb) || skb->mac_len == ETH_HLEN;
+}
+
TC_INDIRECT_SCOPE int tcf_ife_act(struct sk_buff *skb,
const struct tc_action *a,
struct tcf_result *res)
@@ -869,6 +886,13 @@ TC_INDIRECT_SCOPE int tcf_ife_act(struct sk_buff *skb,
struct tcf_ife_params *p;
int ret;
+ if (unlikely(!tcf_ife_is_eth_skb(skb))) {
+ bstats_update(this_cpu_ptr(ife->common.cpu_bstats), skb);
+ tcf_lastuse_update(&ife->tcf_tm);
+ qstats_cpu_drop_inc(ife->common.cpu_qstats);
+ return TC_ACT_SHOT;
+ }
+
p = rcu_dereference_bh(ife->params);
if (p->flags & IFE_ENCODE) {
ret = tcf_ife_encode(skb, a, res, p);
@@ -878,6 +902,28 @@ TC_INDIRECT_SCOPE int tcf_ife_act(struct sk_buff *skb,
return tcf_ife_decode(skb, a, res);
}
+static size_t tcf_ife_get_fill_size(const struct tc_action *act)
+{
+ struct tcf_ife_info *ife = to_ife(act);
+ const struct tcf_ife_params *p;
+ struct tcf_meta_info *e;
+ size_t size = nla_total_size(sizeof(struct tc_ife)) /* TCA_IFE_PARMS */
+ + nla_total_size(ETH_ALEN) /* TCA_IFE_DMAC */
+ + nla_total_size(ETH_ALEN) /* TCA_IFE_SMAC */
+ + nla_total_size(2) /* TCA_IFE_TYPE */
+ + nla_total_size(0); /* TCA_IFE_METALST */
+
+ rcu_read_lock();
+ p = rcu_dereference(ife->params);
+ if (p) {
+ list_for_each_entry_rcu(e, &p->metalist, metalist)
+ size += nla_total_size(sizeof(u32));
+ }
+ rcu_read_unlock();
+
+ return size;
+}
+
static struct tc_action_ops act_ife_ops = {
.kind = "ife",
.id = TCA_ID_IFE,
@@ -886,6 +932,7 @@ static struct tc_action_ops act_ife_ops = {
.dump = tcf_ife_dump,
.cleanup = tcf_ife_cleanup,
.init = tcf_ife_init,
+ .get_fill_size = tcf_ife_get_fill_size,
.size = sizeof(struct tcf_ife_info),
};
MODULE_ALIAS_NET_ACT("ife");