net/sched: act_mpls: Add action to push MPLS LSE before Ethernet header
authorGuillaume Nault <gnault@redhat.com>
Fri, 2 Oct 2020 22:44:31 +0000 (00:44 +0200)
committerDavid S. Miller <davem@davemloft.net>
Sun, 4 Oct 2020 00:28:45 +0000 (17:28 -0700)
Define the MAC_PUSH action which pushes an MPLS LSE before the mac
header (instead of between the mac and the network headers as the
plain PUSH action does).

The only special case is when the skb has an offloaded VLAN. In that
case, it has to be inlined before pushing the MPLS header.

Signed-off-by: Guillaume Nault <gnault@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/uapi/linux/tc_act/tc_mpls.h
net/sched/act_mpls.c

index 9360e95273c791c17a2c3097416ded2d6e95650a..9e4e8f52a779fc8b383aad0f95dfe0a3ef7a14f5 100644 (file)
@@ -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. */
index 8118e26409796aff8ccfe8569470b829dd6e6ad0..bb6b715636db4d6ab640716544e5eb63964c6478 100644 (file)
@@ -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;