mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 10:04:04 +02:00
net/sched: Fix ethx:ingress -> ethy:egress -> ethx:ingress mirred loop
When mirred redirects to ingress (from either ingress or egress) the loop
state from sched_mirred_dev array dev is lost because of 1) the packet
deferral into the backlog and 2) the fact the sched_mirred_dev array is
cleared. In such cases, if there was a loop we won't discover it.
Here's a simple test to reproduce:
ip a add dev port0 10.10.10.11/24
tc qdisc add dev port0 clsact
tc filter add dev port0 egress protocol ip \
prio 10 matchall action mirred ingress redirect dev port1
tc qdisc add dev port1 clsact
tc filter add dev port1 ingress protocol ip \
prio 10 matchall action mirred egress redirect dev port0
ping -c 1 -W0.01 10.10.10.10
Fixes: fe946a751d ("net/sched: act_mirred: add loop detection")
Tested-by: Victor Nogueira <victor@mojatatu.com>
Reviewed-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
Link: https://patch.msgid.link/20260525122556.973584-6-jhs@mojatatu.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
parent
9552b11e3e
commit
db875221ab
|
|
@ -26,6 +26,10 @@
|
|||
#include <net/tc_act/tc_mirred.h>
|
||||
#include <net/tc_wrapper.h>
|
||||
|
||||
#define MIRRED_DEFER_LIMIT 3
|
||||
_Static_assert(MIRRED_DEFER_LIMIT <= 3,
|
||||
"MIRRED_DEFER_LIMIT exceeds tc_depth bitfield width");
|
||||
|
||||
static LIST_HEAD(mirred_list);
|
||||
static DEFINE_SPINLOCK(mirred_list_lock);
|
||||
|
||||
|
|
@ -234,12 +238,15 @@ tcf_mirred_forward(bool at_ingress, bool want_ingress, struct sk_buff *skb)
|
|||
{
|
||||
int err;
|
||||
|
||||
if (!want_ingress)
|
||||
if (!want_ingress) {
|
||||
err = tcf_dev_queue_xmit(skb, dev_queue_xmit);
|
||||
else if (!at_ingress)
|
||||
err = netif_rx(skb);
|
||||
else
|
||||
err = netif_receive_skb(skb);
|
||||
} else {
|
||||
skb->tc_depth++;
|
||||
if (!at_ingress)
|
||||
err = netif_rx(skb);
|
||||
else
|
||||
err = netif_receive_skb(skb);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
@ -426,6 +433,7 @@ TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb,
|
|||
struct netdev_xmit *xmit;
|
||||
bool m_mac_header_xmit;
|
||||
struct net_device *dev;
|
||||
bool want_ingress;
|
||||
int i, m_eaction;
|
||||
u32 blockid;
|
||||
|
||||
|
|
@ -434,7 +442,8 @@ TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb,
|
|||
#else
|
||||
xmit = this_cpu_ptr(&softnet_data.xmit);
|
||||
#endif
|
||||
if (unlikely(xmit->sched_mirred_nest >= MIRRED_NEST_LIMIT)) {
|
||||
if (unlikely(xmit->sched_mirred_nest >= MIRRED_NEST_LIMIT ||
|
||||
skb->tc_depth >= MIRRED_DEFER_LIMIT)) {
|
||||
net_warn_ratelimited("Packet exceeded mirred recursion limit on dev %s\n",
|
||||
netdev_name(skb->dev));
|
||||
return TC_ACT_SHOT;
|
||||
|
|
@ -453,23 +462,27 @@ TC_INDIRECT_SCOPE int tcf_mirred_act(struct sk_buff *skb,
|
|||
tcf_action_inc_overlimit_qstats(&m->common);
|
||||
return retval;
|
||||
}
|
||||
for (i = 0; i < xmit->sched_mirred_nest; i++) {
|
||||
if (xmit->sched_mirred_dev[i] != dev)
|
||||
continue;
|
||||
pr_notice_once("tc mirred: loop on device %s\n",
|
||||
netdev_name(dev));
|
||||
tcf_action_inc_overlimit_qstats(&m->common);
|
||||
return retval;
|
||||
|
||||
m_eaction = READ_ONCE(m->tcfm_eaction);
|
||||
want_ingress = tcf_mirred_act_wants_ingress(m_eaction);
|
||||
if (!want_ingress) {
|
||||
for (i = 0; i < xmit->sched_mirred_nest; i++) {
|
||||
if (xmit->sched_mirred_dev[i] != dev)
|
||||
continue;
|
||||
pr_notice_once("tc mirred: loop on device %s\n",
|
||||
netdev_name(dev));
|
||||
tcf_action_inc_overlimit_qstats(&m->common);
|
||||
return retval;
|
||||
}
|
||||
xmit->sched_mirred_dev[xmit->sched_mirred_nest++] = dev;
|
||||
}
|
||||
|
||||
xmit->sched_mirred_dev[xmit->sched_mirred_nest++] = dev;
|
||||
|
||||
m_mac_header_xmit = READ_ONCE(m->tcfm_mac_header_xmit);
|
||||
m_eaction = READ_ONCE(m->tcfm_eaction);
|
||||
|
||||
retval = tcf_mirred_to_dev(skb, m, dev, m_mac_header_xmit, m_eaction,
|
||||
retval);
|
||||
xmit->sched_mirred_nest--;
|
||||
if (!want_ingress)
|
||||
xmit->sched_mirred_nest--;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user