Commit ab5d4bb2 authored by David S. Miller's avatar David S. Miller

Merge branch 'ovs-mpls-actions'

Martin Varghese says:

====================
New openvswitch MPLS actions for layer 2 tunnelling

The existing PUSH MPLS action inserts MPLS header between ethernet header
and the IP header. Though this behaviour is fine for L3 VPN where an IP
packet is encapsulated inside a MPLS tunnel, it does not suffice the L2
VPN (l2 tunnelling) requirements. In L2 VPN the MPLS header should
encapsulate the ethernet packet.

The new mpls action ADD_MPLS inserts MPLS header at the start of the
packet or at the start of the l3 header depending on the value of l3 tunnel
flag in the ADD_MPLS arguments.

POP_MPLS action is extended to support ethertype 0x6558

OVS userspace changes -
---------------------
Encap & Decap ovs actions are extended to support MPLS packet type. The encap & decap
adds and removes MPLS header at the start of packet as depicted below.

Actions - encap(mpls(ether_type=0x8847)),encap(ethernet)

Incoming packet -> | ETH | IP | Payload |

1 Actions -  encap(mpls(ether_type=0x8847)) [Kernel action - add_mpls:0x8847]

        Outgoing packet -> | MPLS | ETH | Payload|

2 Actions - encap(ethernet) [ Kernel action - push_eth ]

        Outgoing packet -> | ETH | MPLS | ETH | Payload|

Decapsulation:

Incoming packet -> | ETH | MPLS | ETH | IP | Payload |

Actions - decap(),decap(packet_type(ns=0,type=0)

1 Actions -  decap() [Kernel action - pop_eth)

        Outgoing packet -> | MPLS | ETH | IP | Payload|

2 Actions - decap(packet_type(ns=0,type=0) [Kernel action - pop_mpls:0x6558]

        Outgoing packet -> | ETH  | IP | Payload
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents ac80010f f66b53fd
...@@ -672,6 +672,32 @@ struct ovs_action_push_mpls { ...@@ -672,6 +672,32 @@ struct ovs_action_push_mpls {
__be16 mpls_ethertype; /* Either %ETH_P_MPLS_UC or %ETH_P_MPLS_MC */ __be16 mpls_ethertype; /* Either %ETH_P_MPLS_UC or %ETH_P_MPLS_MC */
}; };
/**
* struct ovs_action_add_mpls - %OVS_ACTION_ATTR_ADD_MPLS action
* argument.
* @mpls_lse: MPLS label stack entry to push.
* @mpls_ethertype: Ethertype to set in the encapsulating ethernet frame.
* @tun_flags: MPLS tunnel attributes.
*
* The only values @mpls_ethertype should ever be given are %ETH_P_MPLS_UC and
* %ETH_P_MPLS_MC, indicating MPLS unicast or multicast. Other are rejected.
*/
struct ovs_action_add_mpls {
__be32 mpls_lse;
__be16 mpls_ethertype; /* Either %ETH_P_MPLS_UC or %ETH_P_MPLS_MC */
__u16 tun_flags;
};
#define OVS_MPLS_L3_TUNNEL_FLAG_MASK (1 << 0) /* Flag to specify the place of
* insertion of MPLS header.
* When false, the MPLS header
* will be inserted at the start
* of the packet.
* When true, the MPLS header
* will be inserted at the start
* of the l3 header.
*/
/** /**
* struct ovs_action_push_vlan - %OVS_ACTION_ATTR_PUSH_VLAN action argument. * struct ovs_action_push_vlan - %OVS_ACTION_ATTR_PUSH_VLAN action argument.
* @vlan_tpid: Tag protocol identifier (TPID) to push. * @vlan_tpid: Tag protocol identifier (TPID) to push.
...@@ -892,6 +918,10 @@ struct check_pkt_len_arg { ...@@ -892,6 +918,10 @@ struct check_pkt_len_arg {
* @OVS_ACTION_ATTR_CHECK_PKT_LEN: Check the packet length and execute a set * @OVS_ACTION_ATTR_CHECK_PKT_LEN: Check the packet length and execute a set
* of actions if greater than the specified packet length, else execute * of actions if greater than the specified packet length, else execute
* another set of actions. * another set of actions.
* @OVS_ACTION_ATTR_ADD_MPLS: Push a new MPLS label stack entry at the
* start of the packet or at the start of the l3 header depending on the value
* of l3 tunnel flag in the tun_flags field of OVS_ACTION_ATTR_ADD_MPLS
* argument.
* *
* Only a single header can be set with a single %OVS_ACTION_ATTR_SET. Not all * Only a single header can be set with a single %OVS_ACTION_ATTR_SET. Not all
* fields within a header are modifiable, e.g. the IPv4 protocol and fragment * fields within a header are modifiable, e.g. the IPv4 protocol and fragment
...@@ -927,6 +957,7 @@ enum ovs_action_attr { ...@@ -927,6 +957,7 @@ enum ovs_action_attr {
OVS_ACTION_ATTR_METER, /* u32 meter ID. */ OVS_ACTION_ATTR_METER, /* u32 meter ID. */
OVS_ACTION_ATTR_CLONE, /* Nested OVS_CLONE_ATTR_*. */ OVS_ACTION_ATTR_CLONE, /* Nested OVS_CLONE_ATTR_*. */
OVS_ACTION_ATTR_CHECK_PKT_LEN, /* Nested OVS_CHECK_PKT_LEN_ATTR_*. */ OVS_ACTION_ATTR_CHECK_PKT_LEN, /* Nested OVS_CHECK_PKT_LEN_ATTR_*. */
OVS_ACTION_ATTR_ADD_MPLS, /* struct ovs_action_add_mpls. */
__OVS_ACTION_ATTR_MAX, /* Nothing past this will be accepted __OVS_ACTION_ATTR_MAX, /* Nothing past this will be accepted
* from userspace. */ * from userspace. */
......
...@@ -5472,12 +5472,15 @@ static void skb_mod_eth_type(struct sk_buff *skb, struct ethhdr *hdr, ...@@ -5472,12 +5472,15 @@ static void skb_mod_eth_type(struct sk_buff *skb, struct ethhdr *hdr,
} }
/** /**
* skb_mpls_push() - push a new MPLS header after the mac header * skb_mpls_push() - push a new MPLS header after mac_len bytes from start of
* the packet
* *
* @skb: buffer * @skb: buffer
* @mpls_lse: MPLS label stack entry to push * @mpls_lse: MPLS label stack entry to push
* @mpls_proto: ethertype of the new MPLS header (expects 0x8847 or 0x8848) * @mpls_proto: ethertype of the new MPLS header (expects 0x8847 or 0x8848)
* @mac_len: length of the MAC header * @mac_len: length of the MAC header
* @ethernet: flag to indicate if the resulting packet after skb_mpls_push is
* ethernet
* *
* Expects skb->data at mac header. * Expects skb->data at mac header.
* *
...@@ -5501,7 +5504,7 @@ int skb_mpls_push(struct sk_buff *skb, __be32 mpls_lse, __be16 mpls_proto, ...@@ -5501,7 +5504,7 @@ int skb_mpls_push(struct sk_buff *skb, __be32 mpls_lse, __be16 mpls_proto,
return err; return err;
if (!skb->inner_protocol) { if (!skb->inner_protocol) {
skb_set_inner_network_header(skb, mac_len); skb_set_inner_network_header(skb, skb_network_offset(skb));
skb_set_inner_protocol(skb, skb->protocol); skb_set_inner_protocol(skb, skb->protocol);
} }
...@@ -5510,6 +5513,7 @@ int skb_mpls_push(struct sk_buff *skb, __be32 mpls_lse, __be16 mpls_proto, ...@@ -5510,6 +5513,7 @@ int skb_mpls_push(struct sk_buff *skb, __be32 mpls_lse, __be16 mpls_proto,
mac_len); mac_len);
skb_reset_mac_header(skb); skb_reset_mac_header(skb);
skb_set_network_header(skb, mac_len); skb_set_network_header(skb, mac_len);
skb_reset_mac_len(skb);
lse = mpls_hdr(skb); lse = mpls_hdr(skb);
lse->label_stack_entry = mpls_lse; lse->label_stack_entry = mpls_lse;
...@@ -5529,7 +5533,7 @@ EXPORT_SYMBOL_GPL(skb_mpls_push); ...@@ -5529,7 +5533,7 @@ EXPORT_SYMBOL_GPL(skb_mpls_push);
* @skb: buffer * @skb: buffer
* @next_proto: ethertype of header after popped MPLS header * @next_proto: ethertype of header after popped MPLS header
* @mac_len: length of the MAC header * @mac_len: length of the MAC header
* @ethernet: flag to indicate if ethernet header is present in packet * @ethernet: flag to indicate if the packet is ethernet
* *
* Expects skb->data at mac header. * Expects skb->data at mac header.
* *
......
...@@ -161,16 +161,17 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, ...@@ -161,16 +161,17 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
const struct nlattr *attr, int len); const struct nlattr *attr, int len);
static int push_mpls(struct sk_buff *skb, struct sw_flow_key *key, static int push_mpls(struct sk_buff *skb, struct sw_flow_key *key,
const struct ovs_action_push_mpls *mpls) __be32 mpls_lse, __be16 mpls_ethertype, __u16 mac_len)
{ {
int err; int err;
err = skb_mpls_push(skb, mpls->mpls_lse, mpls->mpls_ethertype, err = skb_mpls_push(skb, mpls_lse, mpls_ethertype, mac_len, !!mac_len);
skb->mac_len,
ovs_key_mac_proto(key) == MAC_PROTO_ETHERNET);
if (err) if (err)
return err; return err;
if (!mac_len)
key->mac_proto = MAC_PROTO_NONE;
invalidate_flow_key(key); invalidate_flow_key(key);
return 0; return 0;
} }
...@@ -185,6 +186,9 @@ static int pop_mpls(struct sk_buff *skb, struct sw_flow_key *key, ...@@ -185,6 +186,9 @@ static int pop_mpls(struct sk_buff *skb, struct sw_flow_key *key,
if (err) if (err)
return err; return err;
if (ethertype == htons(ETH_P_TEB))
key->mac_proto = MAC_PROTO_ETHERNET;
invalidate_flow_key(key); invalidate_flow_key(key);
return 0; return 0;
} }
...@@ -1229,10 +1233,24 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, ...@@ -1229,10 +1233,24 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
execute_hash(skb, key, a); execute_hash(skb, key, a);
break; break;
case OVS_ACTION_ATTR_PUSH_MPLS: case OVS_ACTION_ATTR_PUSH_MPLS: {
err = push_mpls(skb, key, nla_data(a)); struct ovs_action_push_mpls *mpls = nla_data(a);
err = push_mpls(skb, key, mpls->mpls_lse,
mpls->mpls_ethertype, skb->mac_len);
break; break;
}
case OVS_ACTION_ATTR_ADD_MPLS: {
struct ovs_action_add_mpls *mpls = nla_data(a);
__u16 mac_len = 0;
if (mpls->tun_flags & OVS_MPLS_L3_TUNNEL_FLAG_MASK)
mac_len = skb->mac_len;
err = push_mpls(skb, key, mpls->mpls_lse,
mpls->mpls_ethertype, mac_len);
break;
}
case OVS_ACTION_ATTR_POP_MPLS: case OVS_ACTION_ATTR_POP_MPLS:
err = pop_mpls(skb, key, nla_get_be16(a)); err = pop_mpls(skb, key, nla_get_be16(a));
break; break;
......
...@@ -79,6 +79,7 @@ static bool actions_may_change_flow(const struct nlattr *actions) ...@@ -79,6 +79,7 @@ static bool actions_may_change_flow(const struct nlattr *actions)
case OVS_ACTION_ATTR_SET_MASKED: case OVS_ACTION_ATTR_SET_MASKED:
case OVS_ACTION_ATTR_METER: case OVS_ACTION_ATTR_METER:
case OVS_ACTION_ATTR_CHECK_PKT_LEN: case OVS_ACTION_ATTR_CHECK_PKT_LEN:
case OVS_ACTION_ATTR_ADD_MPLS:
default: default:
return true; return true;
} }
...@@ -3005,6 +3006,7 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, ...@@ -3005,6 +3006,7 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
[OVS_ACTION_ATTR_METER] = sizeof(u32), [OVS_ACTION_ATTR_METER] = sizeof(u32),
[OVS_ACTION_ATTR_CLONE] = (u32)-1, [OVS_ACTION_ATTR_CLONE] = (u32)-1,
[OVS_ACTION_ATTR_CHECK_PKT_LEN] = (u32)-1, [OVS_ACTION_ATTR_CHECK_PKT_LEN] = (u32)-1,
[OVS_ACTION_ATTR_ADD_MPLS] = sizeof(struct ovs_action_add_mpls),
}; };
const struct ovs_action_push_vlan *vlan; const struct ovs_action_push_vlan *vlan;
int type = nla_type(a); int type = nla_type(a);
...@@ -3072,6 +3074,33 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, ...@@ -3072,6 +3074,33 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
case OVS_ACTION_ATTR_RECIRC: case OVS_ACTION_ATTR_RECIRC:
break; break;
case OVS_ACTION_ATTR_ADD_MPLS: {
const struct ovs_action_add_mpls *mpls = nla_data(a);
if (!eth_p_mpls(mpls->mpls_ethertype))
return -EINVAL;
if (mpls->tun_flags & OVS_MPLS_L3_TUNNEL_FLAG_MASK) {
if (vlan_tci & htons(VLAN_CFI_MASK) ||
(eth_type != htons(ETH_P_IP) &&
eth_type != htons(ETH_P_IPV6) &&
eth_type != htons(ETH_P_ARP) &&
eth_type != htons(ETH_P_RARP) &&
!eth_p_mpls(eth_type)))
return -EINVAL;
mpls_label_count++;
} else {
if (mac_proto == MAC_PROTO_ETHERNET) {
mpls_label_count = 1;
mac_proto = MAC_PROTO_NONE;
} else {
mpls_label_count++;
}
}
eth_type = mpls->mpls_ethertype;
break;
}
case OVS_ACTION_ATTR_PUSH_MPLS: { case OVS_ACTION_ATTR_PUSH_MPLS: {
const struct ovs_action_push_mpls *mpls = nla_data(a); const struct ovs_action_push_mpls *mpls = nla_data(a);
...@@ -3109,6 +3138,11 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, ...@@ -3109,6 +3138,11 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
* recirculation. * recirculation.
*/ */
proto = nla_get_be16(a); proto = nla_get_be16(a);
if (proto == htons(ETH_P_TEB) &&
mac_proto != MAC_PROTO_NONE)
return -EINVAL;
mpls_label_count--; mpls_label_count--;
if (!eth_p_mpls(proto) || !mpls_label_count) if (!eth_p_mpls(proto) || !mpls_label_count)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment