diff options
-rw-r--r-- | include/uapi/linux/tc_act/tc_mpls.h | 1 | ||||
-rw-r--r-- | net/sched/act_mpls.c | 18 |
2 files changed, 19 insertions, 0 deletions
diff --git a/include/uapi/linux/tc_act/tc_mpls.h b/include/uapi/linux/tc_act/tc_mpls.h index 9360e95273c7..9e4e8f52a779 100644 --- a/include/uapi/linux/tc_act/tc_mpls.h +++ b/include/uapi/linux/tc_act/tc_mpls.h @@ -10,6 +10,7 @@ #define TCA_MPLS_ACT_PUSH 2 #define TCA_MPLS_ACT_MODIFY 3 #define TCA_MPLS_ACT_DEC_TTL 4 +#define TCA_MPLS_ACT_MAC_PUSH 5 struct tc_mpls { tc_gen; /* generic TC action fields. */ diff --git a/net/sched/act_mpls.c b/net/sched/act_mpls.c index 8118e2640979..bb6b715636db 100644 --- a/net/sched/act_mpls.c +++ b/net/sched/act_mpls.c @@ -87,6 +87,23 @@ static int tcf_mpls_act(struct sk_buff *skb, const struct tc_action *a, skb->dev && skb->dev->type == ARPHRD_ETHER)) goto drop; break; + case TCA_MPLS_ACT_MAC_PUSH: + if (skb_vlan_tag_present(skb)) { + if (__vlan_insert_inner_tag(skb, skb->vlan_proto, + skb_vlan_tag_get(skb), + ETH_HLEN) < 0) + goto drop; + + skb->protocol = skb->vlan_proto; + __vlan_hwaccel_clear_tag(skb); + } + + new_lse = tcf_mpls_get_lse(NULL, p, mac_len || + !eth_p_mpls(skb->protocol)); + + if (skb_mpls_push(skb, new_lse, p->tcfm_proto, 0, false)) + goto drop; + break; case TCA_MPLS_ACT_MODIFY: new_lse = tcf_mpls_get_lse(mpls_hdr(skb), p, false); if (skb_mpls_update_lse(skb, new_lse)) @@ -188,6 +205,7 @@ static int tcf_mpls_init(struct net *net, struct nlattr *nla, } break; case TCA_MPLS_ACT_PUSH: + case TCA_MPLS_ACT_MAC_PUSH: if (!tb[TCA_MPLS_LABEL]) { NL_SET_ERR_MSG_MOD(extack, "Label is required for MPLS push"); return -EINVAL; |