@@ -51,7 +51,7 @@ TC_INDIRECT_SCOPE int tcf_vlan_act(struct sk_buff *skb,
case TCA_VLAN_ACT_PUSH:
err = skb_vlan_push(skb, p->tcfv_push_proto, p->tcfv_push_vid |
(p->tcfv_push_prio << VLAN_PRIO_SHIFT),
- VLAN_HLEN);
+ 0);
if (err)
goto drop;
break;
@@ -94,8 +94,11 @@ TC_INDIRECT_SCOPE int tcf_vlan_act(struct sk_buff *skb,
}
out:
- if (skb_at_tc_ingress(skb))
+ if (skb_at_tc_ingress(skb)) {
skb_pull_rcsum(skb, skb->mac_len);
+ skb_reset_network_header(skb);
+ skb_reset_mac_len(skb);
+ }
return action;
When double-tagged VLAN packet enters Linux network stack the outer vlan is stripped and copied to the skb. As a result, skb->data points to the inner vlan. When second vlan is pushed by tcf_vlan_act, skb->mac_len will be advanced by skb_vlan_push. As a result, the final skb_pull_rcsum will have network header pointing to the inner protocol header (e.g. IP) rather than inner vlan as expected. This causes a problem with further TC processing as __skb_flow_dissect expects the network header to point to the inner vlan. To fix this problem, we disable skb->mac_len advancement and reset network header and mac_len at the end of tcf_vlan_act. Signed-off-by: Boris Sukholitko <boris.sukholitko@broadcom.com> --- net/sched/act_vlan.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)