Message ID | 20191225085101.19696-1-sladkani@proofpoint.com |
---|---|
State | Accepted |
Delegated to: | David Miller |
Headers | show |
Series | [net] net/sched: act_mirred: Pull mac prior redir to non mac_header_xmit device | expand |
From: shmulik@metanetworks.com Date: Wed, 25 Dec 2019 10:51:01 +0200 > From: Shmulik Ladkani <sladkani@proofpoint.com> > > There's no skb_pull performed when a mirred action is set at egress of a > mac device, with a target device/action that expects skb->data to point > at the network header. > > As a result, either the target device is errornously given an skb with > data pointing to the mac (egress case), or the net stack receives the > skb with data pointing to the mac (ingress case). > > E.g: > # tc qdisc add dev eth9 root handle 1: prio > # tc filter add dev eth9 parent 1: prio 9 protocol ip handle 9 basic \ > action mirred egress redirect dev tun0 > > (tun0 is a tun device. result: tun0 errornously gets the eth header > instead of the iph) > > Revise the push/pull logic of tcf_mirred_act() to not rely on the > skb_at_tc_ingress() vs tcf_mirred_act_wants_ingress() comparison, as it > does not cover all "pull" cases. > > Instead, calculate whether the required action on the target device > requires the data to point at the network header, and compare this to > whether skb->data points to network header - and make the push/pull > adjustments as necessary. > > Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") > Signed-off-by: Shmulik Ladkani <sladkani@proofpoint.com> > Tested-by: Jamal Hadi Salim <jhs@mojatatu.com> > Acked-by: Jamal Hadi Salim <jhs@mojatatu.com> Applied and queued up for -stable.
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index 1e3eb3a97532..1ad300e6dbc0 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -219,8 +219,10 @@ static int tcf_mirred_act(struct sk_buff *skb, const struct tc_action *a, bool use_reinsert; bool want_ingress; bool is_redirect; + bool expects_nh; int m_eaction; int mac_len; + bool at_nh; rec_level = __this_cpu_inc_return(mirred_rec_level); if (unlikely(rec_level > MIRRED_RECURSION_LIMIT)) { @@ -261,19 +263,19 @@ static int tcf_mirred_act(struct sk_buff *skb, const struct tc_action *a, goto out; } - /* If action's target direction differs than filter's direction, - * and devices expect a mac header on xmit, then mac push/pull is - * needed. - */ want_ingress = tcf_mirred_act_wants_ingress(m_eaction); - if (skb_at_tc_ingress(skb) != want_ingress && m_mac_header_xmit) { - if (!skb_at_tc_ingress(skb)) { - /* caught at egress, act ingress: pull mac */ - mac_len = skb_network_header(skb) - skb_mac_header(skb); + + expects_nh = want_ingress || !m_mac_header_xmit; + at_nh = skb->data == skb_network_header(skb); + if (at_nh != expects_nh) { + mac_len = skb_at_tc_ingress(skb) ? skb->mac_len : + skb_network_header(skb) - skb_mac_header(skb); + if (expects_nh) { + /* target device/action expect data at nh */ skb_pull_rcsum(skb2, mac_len); } else { - /* caught at ingress, act egress: push mac */ - skb_push_rcsum(skb2, skb->mac_len); + /* target device/action expect data at mac */ + skb_push_rcsum(skb2, mac_len); } }