net/sched: Add actions for MPLS L2 VPNs
Subsystems (4)
cover net/sched: Add actions for MPLS L2 VPNs
This patch series adds the necessary TC actions for supporting layer 2 MPLS VPNs (VPLS).
The objective is to give the possibility to add an MPLS header right before an skb's mac header, then to prepend this MPLS packet with a new Ethernet header with the MAC address of the next hop.
Patch 1 implements the actions for adding and removing the external Ethernet header.
Patch 2 adds the possibility to push an MPLS header before the mac header.
Most of the code already exists as these operations were first implemented in openvswitch.
Practical example, with encap on Host-A and decap on Host-B:
Host-A# tc filter add dev ethAx ingress matchall \
action mpls mac_push label 20 \
action vlan push_eth dst_mac 02:00:00:00:00:02 \
src_mac 02:00:00:00:00:01 \
action mirred egress redirect dev ethAy Host-B# tc filter add dev ethBx ingress protocol mpls_uc \
flower mpls_label 20 mpls_bos 1 \
action vlan pop_eth \
action mpls pop proto teb \action mirred egress redirect dev ethBy
Guillaume Nault (2):
net/sched: act_vlan: Add {POP,PUSH}_ETH actions net/sched: act_mpls: Add action to push MPLS LSE before Ethernet
header
include/linux/skbuff.h | 3 ++ include/net/tc_act/tc_vlan.h | 2 + include/uapi/linux/tc_act/tc_mpls.h | 1 + include/uapi/linux/tc_act/tc_vlan.h | 4 ++ net/core/skbuff.c | 67 +++++++++++++++++++++++++++++ net/openvswitch/actions.c | 28 +++++------- net/sched/act_mpls.c | 18 ++++++++ net/sched/act_vlan.c | 40 +++++++++++++++++ 8 files changed, 145 insertions(+), 18 deletions(-)
Signature · 1 line
2.21.3
PATCH 1/2 net/sched: act_vlan: Add {POP,PUSH}_ETH actions
Implement TCA_VLAN_ACT_POP_ETH and TCA_VLAN_ACT_PUSH_ETH, to respectively pop and push a base Ethernet header at the beginning of a frame.
POP_ETH is just a matter of pulling ETH_HLEN bytes. VLAN tags, if any, must be stripped before calling POP_ETH.
PUSH_ETH is restricted to skbs with no mac_header, and only the MAC addresses can be configured. The Ethertype is automatically set from skb->protocol. These restrictions ensure that all skb's fields remain consistent, so that this action can't confuse other part of the networking stack (like GSO).
Since openvswitch already had these actions, consolidate the code in skbuff.c (like for vlan and mpls push/pop).
--- include/linux/skbuff.h | 3 ++ include/net/tc_act/tc_vlan.h | 2 + include/uapi/linux/tc_act/tc_vlan.h | 4 ++ net/core/skbuff.c | 67 +++++++++++++++++++++++++++++ net/openvswitch/actions.c | 28 +++++------- net/sched/act_vlan.c | 40 +++++++++++++++++ 6 files changed, 126 insertions(+), 18 deletions(-)
include/linux/skbuff.h +3 -0
@@ -3573,6 +3573,9 @@ int skb_ensure_writable(struct sk_buff *skb, int write_len);int __skb_vlan_pop (struct sk_buff *skb,u16 *vlan_tci);int skb_vlan_pop (struct sk_buff *skb);int skb_vlan_push (struct sk_buff *skb,__be16 vlan_proto,u16 vlan_tci); +int skb_eth_pop (struct sk_buff *skb); +int skb_eth_push (struct sk_buff *skb,const unsigned char *dst, +const unsigned char *src);int skb_mpls_push (struct sk_buff *skb,__be32 mpls_lse,__be16 mpls_proto,int mac_len,bool ethernet); int skb_mpls_pop(struct sk_buff *skb, __be16 next_proto, int mac_len,
include/net/tc_act/tc_vlan.h +2 -0
@@ -11,6 +11,8 @@struct tcf_vlan_params {int tcfv_action; +unsigned char tcfv_push_dst[ETH_ALEN ]; +unsigned char tcfv_push_src[ETH_ALEN ];u16 tcfv_push_vid;__be16 tcfv_push_proto;u8 tcfv_push_prio;
include/uapi/linux/tc_act/tc_vlan.h +4 -0
@@ -16,6 +16,8 @@#define TCA_VLAN_ACT_POP 1#define TCA_VLAN_ACT_PUSH 2#define TCA_VLAN_ACT_MODIFY 3 +#define TCA_VLAN_ACT_POP_ETH 4 +#define TCA_VLAN_ACT_PUSH_ETH 5struct tc_vlan {tc_gen ;
@@ -30,6 +32,8 @@ enum {TCA_VLAN_PUSH_VLAN_PROTOCOL ,TCA_VLAN_PAD ,TCA_VLAN_PUSH_VLAN_PRIORITY , +TCA_VLAN_PUSH_ETH_DST , +TCA_VLAN_PUSH_ETH_SRC , __TCA_VLAN_MAX, };#define TCA_VLAN_MAX (__TCA_VLAN_MAX - 1)
net/core/skbuff.c +67 -0
73 lines not on this page · raw message
net/openvswitch/actions.c +10 -18
@@ -277,9 +277,11 @@ static int set_eth_addr(struct sk_buff *skb, struct sw_flow_key *flow_key,*/ static int pop_eth (struct sk_buff *skb,struct sw_flow_key *key) { -skb_pull_rcsum (skb,ETH_HLEN ); -skb_reset_mac_header (skb); -skb_reset_mac_len (skb); +int err; + + err =skb_eth_pop (skb); +if (err) +return err;/* safe right before invalidate_flow_key */ key->mac_proto =MAC_PROTO_NONE ;
@@ -290,22 +292,12 @@ static int pop_eth(struct sk_buff *skb, struct sw_flow_key *key)static int push_eth (struct sk_buff *skb,struct sw_flow_key *key,const struct ovs_action_push_eth *ethh) { -struct ethhdr *hdr; - -/* Add the new Ethernet header */ -if (skb_cow_head (skb,ETH_HLEN ) <0 ) -return -ENOMEM ; - -skb_push (skb,ETH_HLEN ); -skb_reset_mac_header (skb); -skb_reset_mac_len (skb); - - hdr =eth_hdr (skb); -ether_addr_copy (hdr->h_source, ethh->addresses.eth_src); -ether_addr_copy (hdr->h_dest, ethh->addresses.eth_dst); - hdr->h_proto = skb->protocol; +int err; -skb_postpush_rcsum (skb, hdr,ETH_HLEN ); + err =skb_eth_push (skb, ethh->addresses.eth_dst, + ethh->addresses.eth_src); +if (err) +return err;/* safe right before invalidate_flow_key */ key->mac_proto =MAC_PROTO_ETHERNET ;
net/sched/act_vlan.c +40 -0
@@ -77,6 +77,16 @@ static int tcf_vlan_act(struct sk_buff *skb, const struct tc_action *a,/* put updated tci as hwaccel tag */ __vlan_hwaccel_put_tag (skb, p->tcfv_push_proto, tci);break ; +case TCA_VLAN_ACT_POP_ETH : + err =skb_eth_pop (skb); +if (err) + goto drop; +break ; +case TCA_VLAN_ACT_PUSH_ETH : + err =skb_eth_push (skb, p->tcfv_push_dst, p->tcfv_push_src); +if (err) + goto drop; +break ;default :BUG (); }
@@ -93,10 +103,13 @@ static int tcf_vlan_act(struct sk_buff *skb, const struct tc_action *a, }static const struct nla_policy vlan_policy[TCA_VLAN_MAX +1 ] = { + [TCA_VLAN_UNSPEC ] = { .strict_start_type =TCA_VLAN_PUSH_ETH_DST }, [TCA_VLAN_PARMS ] = { .len =sizeof (struct tc_vlan ) }, [TCA_VLAN_PUSH_VLAN_ID ] = { .type =NLA_U16 }, [TCA_VLAN_PUSH_VLAN_PROTOCOL ] = { .type =NLA_U16 }, [TCA_VLAN_PUSH_VLAN_PRIORITY ] = { .type =NLA_U8 }, + [TCA_VLAN_PUSH_ETH_DST ] =NLA_POLICY_ETH_ADDR , + [TCA_VLAN_PUSH_ETH_SRC ] =NLA_POLICY_ETH_ADDR , }; static int tcf_vlan_init(struct net *net, struct nlattr *nla,
@@ -179,6 +192,17 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,if (tb[TCA_VLAN_PUSH_VLAN_PRIORITY ]) push_prio =nla_get_u8 (tb[TCA_VLAN_PUSH_VLAN_PRIORITY ]);break ; +case TCA_VLAN_ACT_POP_ETH : +break ; +case TCA_VLAN_ACT_PUSH_ETH : +if (!tb[TCA_VLAN_PUSH_ETH_DST ] || !tb[TCA_VLAN_PUSH_ETH_SRC ]) { +if (exists) +tcf_idr_release (*a, bind); +else +tcf_idr_cleanup (tn, index); +return -EINVAL ; + } +break ;default :if (exists)tcf_idr_release (*a, bind);
@@ -219,6 +243,13 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla, p->tcfv_push_prio = push_prio; p->tcfv_push_proto = push_proto; +if (action ==TCA_VLAN_ACT_PUSH_ETH ) { +nla_memcpy (&p->tcfv_push_dst, tb[TCA_VLAN_PUSH_ETH_DST ], +ETH_ALEN ); +nla_memcpy (&p->tcfv_push_src, tb[TCA_VLAN_PUSH_ETH_SRC ], +ETH_ALEN ); + } +spin_lock_bh (&v->tcf_lock); goto_ch =tcf_action_set_ctrlact (*a, parm->action, goto_ch); p =rcu_replace_pointer (v->vlan_p, p,lockdep_is_held (&v->tcf_lock));
@@ -279,6 +310,15 @@ static int tcf_vlan_dump(struct sk_buff *skb, struct tc_action *a, p->tcfv_push_prio)))) goto nla_put_failure; +if (p->tcfv_action ==TCA_VLAN_ACT_PUSH_ETH ) { +if (nla_put (skb,TCA_VLAN_PUSH_ETH_DST ,ETH_ALEN , + p->tcfv_push_dst)) + goto nla_put_failure; +if (nla_put (skb,TCA_VLAN_PUSH_ETH_SRC ,ETH_ALEN , + p->tcfv_push_src)) + goto nla_put_failure; + } +tcf_tm_dump (&t, &v->tcf_tm);if (nla_put_64bit (skb,TCA_VLAN_TM ,sizeof (t), &t,TCA_VLAN_PAD )) goto nla_put_failure;
Signature · 1 line
2.21.3
PATCH 2/2 net/sched: act_mpls: Add action to push MPLS LSE before Ethernet header
In reply to Guillaume NaultDefine 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.
--- include/uapi/linux/tc_act/tc_mpls.h | 1 + net/sched/act_mpls.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+)
include/uapi/linux/tc_act/tc_mpls.h +1 -0
@@ -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 5struct tc_mpls {tc_gen ;/* generic TC action fields. */
net/sched/act_mpls.c +18 -0
@@ -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 ;
Signature · 1 line
2.21.3
David Miller
maintainerFrom: Guillaume Nault <[email protected]>
Date: Sat, 3 Oct 2020 00:44:25 +0200
Quoted 2 lines
This patch series adds the necessary TC actions for supporting layer 2 MPLS VPNs (VPLS).
...
Series applied, thank you.