[ovs-dev] [PATCH v4 1/2] Encap & Decap actions for MPLS packet type.

Eelco Chaudron echaudro at redhat.com
Thu Apr 1 09:32:06 UTC 2021



On 1 Apr 2021, at 11:28, Martin Varghese wrote:

> On Thu, Apr 01, 2021 at 11:17:14AM +0200, Eelco Chaudron wrote:
>>
>>
>> On 1 Apr 2021, at 11:09, Martin Varghese wrote:
>>
>>> On Thu, Apr 01, 2021 at 10:54:42AM +0200, Eelco Chaudron wrote:
>>>>
>>>>
>>>> On 1 Apr 2021, at 10:35, Martin Varghese wrote:
>>>>
>>>>> On Thu, Apr 01, 2021 at 08:59:27AM +0200, Eelco Chaudron wrote:
>>>>>>
>>>>>>
>>>>>> On 1 Apr 2021, at 6:10, Martin Varghese wrote:
>>>>>>
>>>>>>> On Wed, Mar 31, 2021 at 03:59:40PM +0200, Eelco Chaudron wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>> On 26 Mar 2021, at 7:21, Martin Varghese wrote:
>>>>>>>>
>>>>>>>>> From: Martin Varghese <martin.varghese at nokia.com>
>>>>>>>>>
>>>>>>>>> The encap & decap actions are extended to support MPLS
>>>>>>>>> packet type.
>>>>>>>>> Encap & decap actions adds and removes MPLS
>>>>>>>>> header at start of the
>>>>>>>>> packet.
>>>>>>>>
>>>>>>>> Hi Martin,
>>>>>>>>
>>>>>>>> I’m trying to do some real-life testing, and I’m running 
>>>>>>>> into
>>>>>>>> issues. This
>>>>>>>> might be me setting it up wrongly but just wanting to 
>>>>>>>> confirm…
>>>>>>>>
>>>>>>>> I’m sending an MPLS packet that contains an ARP packet into a
>>>>>>>> physical port.
>>>>>>>> This is the packet:
>>>>>>>>
>>>>>>>> Frame 4: 64 bytes on wire (512 bits), 64 bytes
>>>>>>>> captured (512 bits)
>>>>>>>>     Encapsulation type: Ethernet (1)
>>>>>>>>     [Protocols in frame: eth:ethertype:mpls:data]
>>>>>>>> Ethernet II, Src: 00:00:00_00:00:01 (00:00:00:00:00:01), Dst:
>>>>>>>> 00:00:00_00:00:02 (00:00:00:00:00:02)
>>>>>>>>     Destination: 00:00:00_00:00:02 (00:00:00:00:00:02)
>>>>>>>>         Address: 00:00:00_00:00:02 (00:00:00:00:00:02)
>>>>>>>>         .... ..0. .... .... .... .... = LG bit: Globally unique
>>>>>>>> address
>>>>>>>> (factory default)
>>>>>>>>         .... ...0 .... .... .... .... = IG bit:
>>>>>>>> Individual address
>>>>>>>> (unicast)
>>>>>>>>     Source: 00:00:00_00:00:01 (00:00:00:00:00:01)
>>>>>>>>         Address: 00:00:00_00:00:01 (00:00:00:00:00:01)
>>>>>>>>         .... ..0. .... .... .... .... = LG bit: Globally unique
>>>>>>>> address
>>>>>>>> (factory default)
>>>>>>>>         .... ...0 .... .... .... .... = IG bit:
>>>>>>>> Individual address
>>>>>>>> (unicast)
>>>>>>>>     Type: MPLS label switched packet (0x8847)
>>>>>>>> MultiProtocol Label Switching Header, Label: 100, Exp: 0, S:
>>>>>>>> 1, TTL:
>>>>>>>> 64
>>>>>>>>     0000 0000 0000 0110 0100 .... .... .... = MPLS Label: 100
>>>>>>>>     .... .... .... .... .... 000. .... .... = MPLS Experimental
>>>>>>>> Bits: 0
>>>>>>>>     .... .... .... .... .... ...1 .... .... = MPLS
>>>>>>>> Bottom Of Label
>>>>>>>> Stack: 1
>>>>>>>>     .... .... .... .... .... .... 0100 0000 = MPLS TTL: 64
>>>>>>>> Data (46 bytes)
>>>>>>>>
>>>>>>>> 0000  ff ff ff ff ff ff 52 54 00 88 51 38 08 06 00 01
>>>>>>>> ......RT..Q8....
>>>>>>>> 0010  08 00 06 04 00 01 52 54 00 88 51 38 01 01 01 65
>>>>>>>> ......RT..Q8...e
>>>>>>>> 0020  00 00 00 00 00 00 01 01 01 64 27 98 a0 47
>>>>>>>> .........d'..G
>>>>>>>>     Data:
>>>>>>>> ffffffffffff525400885138080600010800060400015254008851380101016500000000?
>>>>>>>>
>>>>>>>>
>>>>>>>> I’m trying to use the following rules:
>>>>>>>>
>>>>>>>>   ovs-ofctl del-flows ovs_pvp_br0
>>>>>>>>   ovs-ofctl add-flow -O OpenFlow13 ovs_pvp_br0
>>>>>>>> "priority=100,dl_type=0x8847,mpls_label=100
>>>>>>>> actions=decap(),decap(packet_type(ns=0,type=0x806)),resubmit(,3)"
>>>>>>>>   ovs-ofctl add-flow -O OpenFlow13 ovs_pvp_br0
>>>>>>>> "table=3,priority=10
>>>>>>>> actions=normal"
>>>>>>>>
>>>>>>>> With these, I expect the packet to be sent to vnet0, but
>>>>>>>> it’s not.
>>>>>>>> Actually,
>>>>>>>> the datapath rule looks odd, while the userspace rules seem
>>>>>>>> to match:
>>>>>>>>
>>>>>>>>   $ ovs-dpctl dump-flows
>>>>>>>>   recirc_id(0),in_port(1),eth(),eth_type(0x8847),mpls(label=100/0xfffff,tc=0/0,ttl=0/0x0,bos=1/1),
>>>>>>>> packets:13, bytes:1118, used:0.322s,
>>>>>>>> actions:pop_eth,pop_mpls(eth_type=0x806),recirc(0x19a)
>>>>>>>>   recirc_id(0x19a),in_port(1),eth_type(0x0806), packets:13,
>>>>>>>> bytes:884,
>>>>>>>> used:0.322s, actions:drop
>>>>>>>>
>>>>>>>>   $ ovs-ofctl dump-flows ovs_pvp_br0 -O OpenFlow13
>>>>>>>>   cookie=0x0, duration=85.007s, table=0, n_packets=51,
>>>>>>>> n_bytes=4386,
>>>>>>>> priority=100,mpls,mpls_label=100
>>>>>>>> actions=decap(),decap(packet_type(ns=0,type=0x806)),resubmit(,3)
>>>>>>>>   cookie=0x0, duration=84.990s, table=3, n_packets=51,
>>>>>>>> n_bytes=3468,
>>>>>>>> priority=10 actions=NORMAL
>>>>>>>>
>>>>>>> The inner packet is ethernet. So the packet type should be
>>>>>>> (ns=0,type=0)
>>>>>>> ?
>>>>>>
>>>>>> Forgot to add that I already tried that to start with, based on 
>>>>>> the
>>>>>> example,
>>>>>> but as that did not work I tried 0x806.
>>>>>>
>>>>>> PS: I have this as a remark in my review notes, i.e., to
>>>>>> explain the
>>>>>> ns and
>>>>>> type usage here.
>>>>>>
>>>>>>
>>>>>> This resulted in packets being counted at the open flow
>>>>>> level, but it
>>>>>> results in NO data path rules. Do get an error though:
>>>>>>
>>>>>> 2021-04-01T06:53:36.056Z|00141|dpif(handler37)|WARN|system at ovs-system:
>>>>>> failed to put[create] (Invalid argument)
>>>>>> ufid:3d2d6f6d-5a66-4ace-8b09-7cdcfa5efc8e 
>>>>>> recirc_id(0),dp_hash(0/0),skb_priority(0/0),in_port(1),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),eth(src=00:00:00:00:00:01/00:00:00:00:00:00,dst=00:00:00:00:00:02/00:00:00:00:00:00),eth_type(0x8847),mpls(label=100/0xfffff,tc=0/0,ttl=64/0x0,bos=1/1),
>>>>>> actions:pop_eth,pop_mpls(eth_type=0x6558),set(eth()),recirc(0x4c)
>>>>>
>>>>> This set(eth) before the recirc is the problem i guesss. I need
>>>>> to check
>>>>>> 2021-04-01T06:53:36.056Z|00142|dpif(handler37)|WARN|system at ovs-system:
>>>>>> execute pop_eth,pop_mpls(eth_type=0x6558),set(eth()),recirc(0x4c)
>>>>>> failed
>>>>>> (Invalid argument) on packet 
>>>>>> mpls,vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,mpls_label=100,mpls_tc=0,mpls_ttl=64,mpls_bos=1
>>>>>>  with metadata skb_priority(0),skb_mark(0),in_port(1) mtu 0
>>>>>>
>>>>>> Are there missing parts in my kernel that do not get properly
>>>>>> detected by
>>>>>> the feature detection?
>>>>>>
>>>>>> $ ovs-appctl dpif/show-dp-features ovs_pvp_br0
>>>>>> Masked set action: Yes
>>>>>> Tunnel push pop: No
>>>>>> Ufid: Yes
>>>>>> Truncate action: Yes
>>>>>> Clone action: Yes
>>>>>> Sample nesting: 10
>>>>>> Conntrack eventmask: Yes
>>>>>> Conntrack clear: Yes
>>>>>> Max dp_hash algorithm: 0
>>>>>> Check pkt length action: Yes
>>>>>> Conntrack timeout policy: Yes
>>>>>> Explicit Drop action: No
>>>>>> Optimized Balance TCP mode: No
>>>>>> l2 MPLS tunnelling: Yes
>>>>>> Max VLAN headers: 2
>>>>>> Max MPLS depth: 3
>>>>>> Recirc: Yes
>>>>>> CT state: Yes
>>>>>> CT zone: Yes
>>>>>> CT mark: Yes
>>>>>> CT label: Yes
>>>>>> CT state NAT: Yes
>>>>>> CT orig tuple: Yes
>>>>>> CT orig tuple for IPv6: Yes
>>>>>> IPv6 ND Extension: No
>>>>>>
>>>>> You are good
>>>>>
>>>>> I am not sure what is going wrong. Your test case looks same as
>>>>> the unit
>>>>> test i added.
>>>>>
>>>>> I tried myself again and this is i get
>>>>>
>>>>> ovs-ofctl -O OpenFlow13 add-flow br_mpls2
>>>>> "in_port=$egress_port,dl_type=0x8847
>>>>> +actions=decap(),decap(packet_type(ns=0,type=0),goto_table:1"
>>>>> ovs-ofctl -O OpenFlow13 add-flow br_mpls2
>>>>> +"table=1,in_port=$egress_port,dl_type=0x0800,nw_dst=1.1.1.2
>>>>> +actions=set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_sr
>>>>> +c output:$ingress_port"
>>>>>
>>>>> recirc_id(0x3),in_port(6),eth(src=36:b1:ee:7c:01:03,dst=36:b1:ee:7c:01:02),eth_
>>>>> +type(0x0800),ipv4(dst=1.1.1.2,frag=no), packets:3, bytes:294,
>>>>> used:0.837s,
>>>>> +actions:set(eth(src=00:00:00:00:00:01,dst=00:00:00:00:00:02)),4
>>>>> recirc_id(0),in_port(6),eth(),eth_type(0x8847),mpls(label=0/0x0,tc=0/0,ttl=0/0x
>>>>> +0,bos=1/1), packets:3, bytes:348, used:0.837s,
>>>>> +actions:pop_eth,pop_mpls(eth_type=0x6558),recirc(0x3)
>>>>>
>>>>> The packet to the ovs is
>>>>> ETH|MPLS|ETH|IP ?
>>>>> How it is differnt from you test case?
>>>>
>>>> Mine is ETH|MPLS|ETH|ARP, which works fine with pop_mpls
>>>>
>>> I am wondering how old mpls pop  action works
>>> could you please put down the userspace and datapath rules when you 
>>> used
>>> pop_mpls.
>>>
>>> In my understanding it can never work as what you have after MPLS is
>>> ethernet and not ARP.
>>
>> It’s ethernet + ARP, but here are my rules:
>
> To clarify
>
> The test vector for Decap Test case
> ETH|MPLS|ETH|ARP
> The test vector for pop mpls test case
> ETH|MPLS|ARP|
>
> The above understanding correct?

Guess our emails crossed ;)  I was sending in the same packet for both 
the test cases, so

ETH|MPLS|ETH|ARP

Which with decap() is resulting in the rules not being programmed

With popmpls I saw the packets in being received, but did not notice the 
incorrect use of popmpls so my packet after popmpls looks like 
ETH|ETH|ARP.

So I guess all that remains is why the data path rules is not accepted 
for ARP with the decap.

>>
>> dpctl:
>>
>> recirc_id(0),in_port(2),eth(),eth_type(0x8847),mpls(label=100/0xfffff,tc=0/0,ttl=0/0x0,bos=1/1),
>> packets:64, bytes:5504, used:0.444s,
>> actions:pop_mpls(eth_type=0x806),recirc(0x80d)
>> recirc_id(0x80d),in_port(2),eth(src=00:00:00:00:00:01,dst=00:00:00:00:00:02),eth_type(0x0806),
>> packets:64, bytes:5248, used:0.444s, actions:3,1
>>
>> ofctl:
>>
>> OFPST_FLOW reply (OF1.5) (xid=0x2):
>>  cookie=0x0, duration=178.890s, table=0, n_packets=127, 
>> n_bytes=10922,
>> idle_age=0, priority=100,mpls,mpls_label=100
>> actions=pop_mpls:0x0806,resubmit(,3)
>>  cookie=0x0, duration=178.873s, table=3, n_packets=127, 
>> n_bytes=10414,
>> idle_age=0, priority=10 actions=NORMAL
>>
>>
>>>>> Thanks for your time.
>>>>
>>>> Your welcome
>>>>
>>>>>>>>
>>>>>>>> If I use the old way, doing pop_mpls, it works fine:
>>>>>>>>
>>>>>>>>
>>>>>>>> ovs-ofctl del-flows ovs_pvp_br0
>>>>>>>> ovs-ofctl add-flow -O OpenFlow13 ovs_pvp_br0
>>>>>>>> "priority=100,dl_type=0x8847,mpls_label=100
>>>>>>>> actions=pop_mpls:0x0806,resubmit(,3)"
>>>>>>>> ovs-ofctl add-flow -O OpenFlow13 ovs_pvp_br0 
>>>>>>>> "table=3,priority=10
>>>>>>>> actions=normal"
>>>>>>>>
>>>>>>>>
>>>>>>>> I also noticed (despite the test example) to make
>>>>>>>> encap work, I had
>>>>>>>> to set
>>>>>>>> the ethernet MAC addresses, or else the packets were not
>>>>>>>> getting out.
>>>>>>>> So something like:
>>>>>>>>
>>>>>>>>   ovs-ofctl add-flow -O OpenFlow13 ovs_pvp_br0 
>>>>>>>> "priority=100,in_port=vnet0,actions=encap(mpls(ether_type=0x8847)),set_mpls_label:100,encap(ethernet),,set_field:00:00:00:00:00:02->dl_dst,set_field:00:00:00:00:00:01->dl_src,output:enp5s0f0
>>>>>>>>
>>>>>
>>>>>>>
>>>>>>> The packets are not going out because you are sending the packet
>>>>>>> on a
>>>>>>> real nic and not on a virtual inerface (veth pair) ?
>>>>>>
>>>>>> So for a real NIC we need to set the MAC addresses, maybe
>>>>>> some where
>>>>>> in the
>>>>>> documentation we should add an example on how to use this 
>>>>>> feature?
>>>>>>
>>>>>>>> Maybe the test case can be made more realistic? Once I
>>>>>>>> understand the
>>>>>>>> failure, I can continue with the review.
>>>>>>>>
>>>>>>>>
>>>>>>>> Cheers,
>>>>>>>>
>>>>>>>> Eelco
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>> Signed-off-by: Martin Varghese <martin.varghese at nokia.com>
>>>>>>>>> ---
>>>>>>>>>  NEWS                                          |  2 +-
>>>>>>>>>  .../linux/compat/include/linux/openvswitch.h  | 35 ++++++-
>>>>>>>>>  include/openvswitch/ofp-ed-props.h            | 18 ++++
>>>>>>>>>  lib/dpif-netdev.c                             |  1 +
>>>>>>>>>  lib/dpif.c                                    |  1 +
>>>>>>>>>  lib/odp-execute.c                             | 12 +++
>>>>>>>>>  lib/odp-util.c                                | 58 
>>>>>>>>> +++++++++---
>>>>>>>>>  lib/ofp-actions.c                             |  5 +
>>>>>>>>>  lib/ofp-ed-props.c                            | 91
>>>>>>>>> +++++++++++++++++++
>>>>>>>>>  lib/ovs-actions.xml                           | 31 +++++--
>>>>>>>>>  lib/packets.c                                 | 36 ++++++++
>>>>>>>>>  lib/packets.h                                 |  2 +
>>>>>>>>>  ofproto/ofproto-dpif-ipfix.c                  |  1 +
>>>>>>>>>  ofproto/ofproto-dpif-sflow.c                  |  1 +
>>>>>>>>>  ofproto/ofproto-dpif-xlate.c                  | 60 
>>>>>>>>> ++++++++++++
>>>>>>>>>  ofproto/ofproto-dpif.c                        | 39 ++++++++
>>>>>>>>>  ofproto/ofproto-dpif.h                        |  5 +-
>>>>>>>>>  tests/system-traffic.at                       | 36 ++++++++
>>>>>>>>>  18 files changed, 410 insertions(+), 24 deletions(-)
>>>>>>>>>
>>>>>>>>> diff --git a/NEWS b/NEWS
>>>>>>>>> index 95cf922aa..4bf4e9e7b 100644
>>>>>>>>> --- a/NEWS
>>>>>>>>> +++ b/NEWS
>>>>>>>>> @@ -120,7 +120,7 @@ v2.14.0 - 17 Aug 2020
>>>>>>>>>     - GTP-U Tunnel Protocol
>>>>>>>>>       * Add two new fields: tun_gtpu_flags, tun_gtpu_msgtype.
>>>>>>>>>       * Only support for userspace datapath.
>>>>>>>>> -
>>>>>>>>> +   - Encap & Decap action support for MPLS packet type.
>>>>>>>>>
>>>>>>>>>  v2.13.0 - 14 Feb 2020
>>>>>>>>>  ---------------------
>>>>>>>>> diff --git a/datapath/linux/compat/include/linux/openvswitch.h
>>>>>>>>> b/datapath/linux/compat/include/linux/openvswitch.h
>>>>>>>>> index 875de2025..8feea7dd4 100644
>>>>>>>>> --- a/datapath/linux/compat/include/linux/openvswitch.h
>>>>>>>>> +++ b/datapath/linux/compat/include/linux/openvswitch.h
>>>>>>>>> @@ -810,8 +810,32 @@ struct ovs_action_push_tnl {
>>>>>>>>>  };
>>>>>>>>>  #endif
>>>>>>>>>
>>>>>>>>> -/**
>>>>>>>>> - * enum ovs_ct_attr - Attributes for
>>>>>>>>> %OVS_ACTION_ATTR_CT action.
>>>>>>>>> +/* 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.
>>>>>>>>> +						*/
>>>>>>>>> +
>>>>>>>>> +/* enum ovs_ct_attr - Attributes for
>>>>>>>>> %OVS_ACTION_ATTR_CT action.
>>>>>>>>>   * @OVS_CT_ATTR_COMMIT: If present, commits the
>>>>>>>>> connection to the
>>>>>>>>> conntrack
>>>>>>>>>   * table. This allows future packets for the same
>>>>>>>>> connection to be
>>>>>>>>> identified
>>>>>>>>>   * as 'established' or 'related'. The flow key for the 
>>>>>>>>> current
>>>>>>>>> packet
>>>>>>>>> will
>>>>>>>>> @@ -1001,7 +1025,11 @@ struct check_pkt_len_arg {
>>>>>>>>>   * @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
>>>>>>>>>   * another set of actions.
>>>>>>>>> - * @OVS_ACTION_ATTR_DROP: Explicit drop action.
>>>>>>>>> + * @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.
>>>>>>>>> +  * @OVS_ACTION_ATTR_DROP: Explicit drop action.
>>>>>>>>>   */
>>>>>>>>>
>>>>>>>>>  enum ovs_action_attr {
>>>>>>>>> @@ -1030,6 +1058,7 @@ enum ovs_action_attr {
>>>>>>>>>  	OVS_ACTION_ATTR_METER,        /* u32 meter number. */
>>>>>>>>>  	OVS_ACTION_ATTR_CLONE,        /* Nested OVS_CLONE_ATTR_*.  
>>>>>>>>> */
>>>>>>>>>  	OVS_ACTION_ATTR_CHECK_PKT_LEN, /* Nested
>>>>>>>>> OVS_CHECK_PKT_LEN_ATTR_*. */
>>>>>>>>> +	OVS_ACTION_ATTR_ADD_MPLS,     /* struct
>>>>>>>>> ovs_action_add_mpls. */
>>>>>>>>>
>>>>>>>>>  #ifndef __KERNEL__
>>>>>>>>>  	OVS_ACTION_ATTR_TUNNEL_PUSH,   /* struct 
>>>>>>>>> ovs_action_push_tnl*/
>>>>>>>>> diff --git a/include/openvswitch/ofp-ed-props.h
>>>>>>>>> b/include/openvswitch/ofp-ed-props.h
>>>>>>>>> index 306c6fe73..c85f3c283 100644
>>>>>>>>> --- a/include/openvswitch/ofp-ed-props.h
>>>>>>>>> +++ b/include/openvswitch/ofp-ed-props.h
>>>>>>>>> @@ -46,6 +46,11 @@ enum ofp_ed_nsh_prop_type {
>>>>>>>>>      OFPPPT_PROP_NSH_TLV = 2,     /* property TLV in NSH */
>>>>>>>>>  };
>>>>>>>>>
>>>>>>>>> +enum ofp_ed_mpls_prop_type {
>>>>>>>>> +    OFPPPT_PROP_MPLS_NONE = 0,    /* unused */
>>>>>>>>> +    OFPPPT_PROP_MPLS_ETHERTYPE = 1,  /* MPLS Ethertype */
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>>  /*
>>>>>>>>>   * External representation of encap/decap properties.
>>>>>>>>>   * These must be padded to a multiple of 8 bytes.
>>>>>>>>> @@ -72,6 +77,13 @@ struct ofp_ed_prop_nsh_tlv {
>>>>>>>>>      uint8_t data[0];
>>>>>>>>>  };
>>>>>>>>>
>>>>>>>>> +struct ofp_ed_prop_mpls_ethertype {
>>>>>>>>> +    struct ofp_ed_prop_header header;
>>>>>>>>> +    uint16_t ether_type;         /* MPLS ethertype .*/
>>>>>>>>> +    uint8_t pad[2];          /* Padding to 8 bytes. */
>>>>>>>>> +};
>>>>>>>>> +
>>>>>>>>> +
>>>>>>>>>  /*
>>>>>>>>>   * Internal representation of encap/decap properties
>>>>>>>>>   */
>>>>>>>>> @@ -96,6 +108,12 @@ struct ofpact_ed_prop_nsh_tlv {
>>>>>>>>>      /* tlv_len octets of metadata value, padded to a
>>>>>>>>> multiple of 8
>>>>>>>>> bytes. */
>>>>>>>>>      uint8_t data[0];
>>>>>>>>>  };
>>>>>>>>> +
>>>>>>>>> +struct ofpact_ed_prop_mpls_ethertype {
>>>>>>>>> +    struct ofpact_ed_prop header;
>>>>>>>>> +    uint16_t ether_type;         /* MPLS ethertype .*/
>>>>>>>>> +    uint8_t pad[2];          /* Padding to 8 bytes. */
>>>>>>>>> +};
>>>>>>>>>  enum ofperr decode_ed_prop(const struct ofp_ed_prop_header
>>>>>>>>> **ofp_prop,
>>>>>>>>>                             struct ofpbuf *out, size_t
>>>>>>>>> *remaining);
>>>>>>>>>  enum ofperr encode_ed_prop(const struct ofpact_ed_prop 
>>>>>>>>> **prop,
>>>>>>>>> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
>>>>>>>>> index 94cc9b80c..bbdea5603 100644
>>>>>>>>> --- a/lib/dpif-netdev.c
>>>>>>>>> +++ b/lib/dpif-netdev.c
>>>>>>>>> @@ -8044,6 +8044,7 @@ dp_execute_cb(void *aux_, struct
>>>>>>>>> dp_packet_batch
>>>>>>>>> *packets_,
>>>>>>>>>      case OVS_ACTION_ATTR_CT_CLEAR:
>>>>>>>>>      case OVS_ACTION_ATTR_CHECK_PKT_LEN:
>>>>>>>>>      case OVS_ACTION_ATTR_DROP:
>>>>>>>>> +    case OVS_ACTION_ATTR_ADD_MPLS:
>>>>>>>>>      case __OVS_ACTION_ATTR_MAX:
>>>>>>>>>          OVS_NOT_REACHED();
>>>>>>>>>      }
>>>>>>>>> diff --git a/lib/dpif.c b/lib/dpif.c
>>>>>>>>> index 56d0b4a65..bbd1296e3 100644
>>>>>>>>> --- a/lib/dpif.c
>>>>>>>>> +++ b/lib/dpif.c
>>>>>>>>> @@ -1273,6 +1273,7 @@ dpif_execute_helper_cb(void *aux_, 
>>>>>>>>> struct
>>>>>>>>> dp_packet_batch *packets_,
>>>>>>>>>      case OVS_ACTION_ATTR_UNSPEC:
>>>>>>>>>      case OVS_ACTION_ATTR_CHECK_PKT_LEN:
>>>>>>>>>      case OVS_ACTION_ATTR_DROP:
>>>>>>>>> +    case OVS_ACTION_ATTR_ADD_MPLS:
>>>>>>>>>      case __OVS_ACTION_ATTR_MAX:
>>>>>>>>>          OVS_NOT_REACHED();
>>>>>>>>>      }
>>>>>>>>> diff --git a/lib/odp-execute.c b/lib/odp-execute.c
>>>>>>>>> index 6eeda2a61..2f4cdd92c 100644
>>>>>>>>> --- a/lib/odp-execute.c
>>>>>>>>> +++ b/lib/odp-execute.c
>>>>>>>>> @@ -819,6 +819,7 @@ requires_datapath_assistance(const struct
>>>>>>>>> nlattr *a)
>>>>>>>>>      case OVS_ACTION_ATTR_POP_NSH:
>>>>>>>>>      case OVS_ACTION_ATTR_CT_CLEAR:
>>>>>>>>>      case OVS_ACTION_ATTR_CHECK_PKT_LEN:
>>>>>>>>> +    case OVS_ACTION_ATTR_ADD_MPLS:
>>>>>>>>>      case OVS_ACTION_ATTR_DROP:
>>>>>>>>>          return false;
>>>>>>>>>
>>>>>>>>> @@ -1061,6 +1062,17 @@ odp_execute_actions(void *dp, struct
>>>>>>>>> dp_packet_batch *batch, bool steal,
>>>>>>>>>              }
>>>>>>>>>              break;
>>>>>>>>>
>>>>>>>>> +        case OVS_ACTION_ATTR_ADD_MPLS: {
>>>>>>>>> +            const struct ovs_action_add_mpls *mpls =
>>>>>>>>> nl_attr_get(a);
>>>>>>>>> +            bool l3_flag =  mpls->tun_flags &
>>>>>>>>> OVS_MPLS_L3_TUNNEL_FLAG_MASK;
>>>>>>>>> +
>>>>>>>>> +            DP_PACKET_BATCH_FOR_EACH (i, packet, batch) {
>>>>>>>>> +                add_mpls(packet, mpls->mpls_ethertype,
>>>>>>>>> mpls->mpls_lse,
>>>>>>>>> +                         l3_flag);
>>>>>>>>> +            }
>>>>>>>>> +            break;
>>>>>>>>> +        }
>>>>>>>>> +
>>>>>>>>>          case OVS_ACTION_ATTR_DROP:{
>>>>>>>>>              const enum xlate_error *drop_reason
>>>>>>>>> = nl_attr_get(a);
>>>>>>>>>
>>>>>>>>> diff --git a/lib/odp-util.c b/lib/odp-util.c
>>>>>>>>> index a8598d52a..f24e16d08 100644
>>>>>>>>> --- a/lib/odp-util.c
>>>>>>>>> +++ b/lib/odp-util.c
>>>>>>>>> @@ -142,6 +142,8 @@ odp_action_len(uint16_t type)
>>>>>>>>>      case OVS_ACTION_ATTR_PUSH_NSH: return ATTR_LEN_VARIABLE;
>>>>>>>>>      case OVS_ACTION_ATTR_POP_NSH: return 0;
>>>>>>>>>      case OVS_ACTION_ATTR_CHECK_PKT_LEN: return
>>>>>>>>> ATTR_LEN_VARIABLE;
>>>>>>>>> +    case OVS_ACTION_ATTR_ADD_MPLS:
>>>>>>>>> +         return sizeof(struct ovs_action_add_mpls);
>>>>>>>>>      case OVS_ACTION_ATTR_DROP: return sizeof(uint32_t);
>>>>>>>>>
>>>>>>>>>      case OVS_ACTION_ATTR_UNSPEC:
>>>>>>>>> @@ -1254,6 +1256,14 @@ format_odp_action(struct ds *ds,
>>>>>>>>> const struct
>>>>>>>>> nlattr *a,
>>>>>>>>>      case OVS_ACTION_ATTR_CHECK_PKT_LEN:
>>>>>>>>>          format_odp_check_pkt_len_action(ds, a, portno_names);
>>>>>>>>>          break;
>>>>>>>>> +    case OVS_ACTION_ATTR_ADD_MPLS: {
>>>>>>>>> +        const struct ovs_action_push_mpls *mpls
>>>>>>>>> = nl_attr_get(a);
>>>>>>>>> +        ds_put_cstr(ds, "add_mpls(");
>>>>>>>>> +        format_mpls_lse(ds, mpls->mpls_lse);
>>>>>>>>> +        ds_put_format(ds, ",eth_type=0x%"PRIx16")",
>>>>>>>>> +                      ntohs(mpls->mpls_ethertype));
>>>>>>>>> +        break;
>>>>>>>>> +    }
>>>>>>>>>      case OVS_ACTION_ATTR_DROP:
>>>>>>>>>          ds_put_cstr(ds, "drop");
>>>>>>>>>          break;
>>>>>>>>> @@ -7876,7 +7886,8 @@ commit_vlan_action(const struct flow*
>>>>>>>>> flow, struct
>>>>>>>>> flow *base,
>>>>>>>>>  /* Wildcarding already done at action translation time. */
>>>>>>>>>  static void
>>>>>>>>>  commit_mpls_action(const struct flow *flow, struct flow 
>>>>>>>>> *base,
>>>>>>>>> -                   struct ofpbuf *odp_actions)
>>>>>>>>> +                   struct ofpbuf *odp_actions, bool
>>>>>>>>> pending_encap,
>>>>>>>>> +                   bool pending_decap)
>>>>>>>>>  {
>>>>>>>>>      int base_n = flow_count_mpls_labels(base, NULL);
>>>>>>>>>      int flow_n = flow_count_mpls_labels(flow, NULL);
>>>>>>>>> @@ -7913,7 +7924,11 @@ commit_mpls_action(const
>>>>>>>>> struct flow *flow,
>>>>>>>>> struct flow *base,
>>>>>>>>>              if ((!eth_type_mpls(flow->dl_type))
>>>>>>>>> && base_n > 1) {
>>>>>>>>>                  dl_type = htons(ETH_TYPE_MPLS);
>>>>>>>>>              } else {
>>>>>>>>> -                dl_type = flow->dl_type;
>>>>>>>>> +                if ((flow->packet_type == PT_ETH) &&
>>>>>>>>> pending_decap) {
>>>>>>>>> +                    dl_type =  htons(ETH_TYPE_TEB);
>>>>>>>>> +                } else {
>>>>>>>>> +                    dl_type = flow->dl_type;
>>>>>>>>> +                }
>>>>>>>>>              }
>>>>>>>>>              nl_msg_put_be16(odp_actions,
>>>>>>>>> OVS_ACTION_ATTR_POP_MPLS,
>>>>>>>>> dl_type);
>>>>>>>>>              ovs_assert(flow_pop_mpls(base,
>>>>>>>>> base_n, flow->dl_type,
>>>>>>>>> NULL));
>>>>>>>>> @@ -7924,18 +7939,29 @@ commit_mpls_action(const struct
>>>>>>>>> flow *flow,
>>>>>>>>> struct flow *base,
>>>>>>>>>      /* If, after the above popping and setting, there are 
>>>>>>>>> more
>>>>>>>>> LSEs in
>>>>>>>>> flow
>>>>>>>>>       * than base then some LSEs need to be pushed. */
>>>>>>>>>      while (base_n < flow_n) {
>>>>>>>>> -        struct ovs_action_push_mpls *mpls;
>>>>>>>>>
>>>>>>>>> -        mpls = nl_msg_put_unspec_zero(odp_actions,
>>>>>>>>> -
>>>>>>>>> OVS_ACTION_ATTR_PUSH_MPLS,
>>>>>>>>> -                                      sizeof *mpls);
>>>>>>>>> -        mpls->mpls_ethertype = flow->dl_type;
>>>>>>>>> -        mpls->mpls_lse = flow->mpls_lse[flow_n - base_n - 1];
>>>>>>>>> +        if (pending_encap) {
>>>>>>>>> +             struct ovs_action_add_mpls *mpls;
>>>>>>>>> +
>>>>>>>>> +             mpls = nl_msg_put_unspec_zero(odp_actions,
>>>>>>>>> +
>>>>>>>>> OVS_ACTION_ATTR_ADD_MPLS,
>>>>>>>>> +                                           sizeof *mpls);
>>>>>>>>> +             mpls->mpls_ethertype = flow->dl_type;
>>>>>>>>> +             mpls->mpls_lse = flow->mpls_lse[flow_n -
>>>>>>>>> base_n - 1];
>>>>>>>>> +        } else {
>>>>>>>>> +             struct ovs_action_push_mpls *mpls;
>>>>>>>>> +
>>>>>>>>> +             mpls = nl_msg_put_unspec_zero(odp_actions,
>>>>>>>>> +
>>>>>>>>> OVS_ACTION_ATTR_PUSH_MPLS,
>>>>>>>>> +                                           sizeof *mpls);
>>>>>>>>> +             mpls->mpls_ethertype = flow->dl_type;
>>>>>>>>> +             mpls->mpls_lse = flow->mpls_lse[flow_n -
>>>>>>>>> base_n - 1];
>>>>>>>>> +        }
>>>>>>>>>          /* Update base flow's MPLS stack, but do not clear 
>>>>>>>>> L3.
>>>>>>>>> We need
>>>>>>>>> the L3
>>>>>>>>>           * headers if the flow is restored later due to
>>>>>>>>> returning from
>>>>>>>>> a patch
>>>>>>>>>           * port or group bucket. */
>>>>>>>>> -        flow_push_mpls(base, base_n,
>>>>>>>>> mpls->mpls_ethertype, NULL,
>>>>>>>>> false);
>>>>>>>>> -        flow_set_mpls_lse(base, 0, mpls->mpls_lse);
>>>>>>>>> +        flow_push_mpls(base, base_n,
>>>>>>>>> flow->dl_type, NULL, false);
>>>>>>>>> +        flow_set_mpls_lse(base, 0,
>>>>>>>>> flow->mpls_lse[flow_n - base_n -
>>>>>>>>> 1]);
>>>>>>>>>          base_n++;
>>>>>>>>>      }
>>>>>>>>>  }
>>>>>>>>> @@ -8586,6 +8612,10 @@
>>>>>>>>> commit_encap_decap_action(const struct flow
>>>>>>>>> *flow,
>>>>>>>>>              memcpy(&base_flow->dl_dst, &flow->dl_dst,
>>>>>>>>>                     sizeof(*flow) - offsetof(struct
>>>>>>>>> flow, dl_dst));
>>>>>>>>>              break;
>>>>>>>>> +        case PT_MPLS:
>>>>>>>>> +            commit_mpls_action(flow, base_flow, odp_actions,
>>>>>>>>> pending_encap,
>>>>>>>>> +                               pending_decap);
>>>>>>>>> +            break;
>>>>>>>>>          default:
>>>>>>>>>              /* Only the above protocols are
>>>>>>>>> supported for encap.
>>>>>>>>>               * The check is done at action translation. */
>>>>>>>>> @@ -8608,6 +8638,10 @@
>>>>>>>>> commit_encap_decap_action(const struct flow
>>>>>>>>> *flow,
>>>>>>>>>                  /* pop_nsh. */
>>>>>>>>>                  odp_put_pop_nsh_action(odp_actions);
>>>>>>>>>                  break;
>>>>>>>>> +            case PT_MPLS:
>>>>>>>>> +                commit_mpls_action(flow,
>>>>>>>>> base_flow, odp_actions,
>>>>>>>>> pending_encap,
>>>>>>>>> +                                   pending_decap);
>>>>>>>>> +                break;
>>>>>>>>>              default:
>>>>>>>>>                  /* Checks are done during translation. */
>>>>>>>>>                  OVS_NOT_REACHED();
>>>>>>>>> @@ -8653,7 +8687,7 @@ commit_odp_actions(const struct flow
>>>>>>>>> *flow, struct
>>>>>>>>> flow *base,
>>>>>>>>>      /* Make packet a non-MPLS packet before committing L3/4
>>>>>>>>> actions,
>>>>>>>>>       * which would otherwise do nothing. */
>>>>>>>>>      if (eth_type_mpls(base->dl_type) &&
>>>>>>>>> !eth_type_mpls(flow->dl_type))
>>>>>>>>> {
>>>>>>>>> -        commit_mpls_action(flow, base, odp_actions);
>>>>>>>>> +        commit_mpls_action(flow, base, odp_actions,
>>>>>>>>> false, false);
>>>>>>>>>          mpls_done = true;
>>>>>>>>>      }
>>>>>>>>>      commit_set_nsh_action(flow, base, odp_actions, wc,
>>>>>>>>> use_masked);
>>>>>>>>> @@ -8661,7 +8695,7 @@ commit_odp_actions(const struct flow
>>>>>>>>> *flow, struct
>>>>>>>>> flow *base,
>>>>>>>>>      commit_set_port_action(flow, base, odp_actions, wc,
>>>>>>>>> use_masked);
>>>>>>>>>      slow2 = commit_set_icmp_action(flow, base,
>>>>>>>>> odp_actions, wc);
>>>>>>>>>      if (!mpls_done) {
>>>>>>>>> -        commit_mpls_action(flow, base, odp_actions);
>>>>>>>>> +        commit_mpls_action(flow, base, odp_actions,
>>>>>>>>> false, false);
>>>>>>>>>      }
>>>>>>>>>      commit_vlan_action(flow, base, odp_actions, wc);
>>>>>>>>>      commit_set_priority_action(flow, base, odp_actions, wc,
>>>>>>>>> use_masked);
>>>>>>>>> diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
>>>>>>>>> index 0342a228b..28a12a569 100644
>>>>>>>>> --- a/lib/ofp-actions.c
>>>>>>>>> +++ b/lib/ofp-actions.c
>>>>>>>>> @@ -4441,6 +4441,7 @@ decode_NXAST_RAW_ENCAP(const struct
>>>>>>>>> nx_action_encap *nae,
>>>>>>>>>      switch (ntohl(nae->new_pkt_type)) {
>>>>>>>>>      case PT_ETH:
>>>>>>>>>      case PT_NSH:
>>>>>>>>> +    case PT_MPLS:
>>>>>>>>>          /* Add supported encap header types here. */
>>>>>>>>>          break;
>>>>>>>>>      default:
>>>>>>>>> @@ -4492,6 +4493,8 @@ parse_encap_header(const
>>>>>>>>> char *hdr, ovs_be32
>>>>>>>>> *packet_type)
>>>>>>>>>          *packet_type = htonl(PT_ETH);
>>>>>>>>>      } else if (strcmp(hdr, "nsh") == 0) {
>>>>>>>>>          *packet_type = htonl(PT_NSH);
>>>>>>>>> +    } else if (strcmp(hdr, "mpls") == 0) {
>>>>>>>>> +        *packet_type = htonl(PT_MPLS);
>>>>>>>>>      } else {
>>>>>>>>>          return false;
>>>>>>>>>      }
>>>>>>>>> @@ -4573,6 +4576,8 @@ format_encap_pkt_type(const
>>>>>>>>> ovs_be32 pkt_type)
>>>>>>>>>          return "ethernet";
>>>>>>>>>      case PT_NSH:
>>>>>>>>>          return "nsh";
>>>>>>>>> +    case PT_MPLS:
>>>>>>>>> +        return "mpls";
>>>>>>>>>      default:
>>>>>>>>>          return "UNKNOWN";
>>>>>>>>>      }
>>>>>>>>> diff --git a/lib/ofp-ed-props.c b/lib/ofp-ed-props.c
>>>>>>>>> index 02a9235d5..fc261e4c6 100644
>>>>>>>>> --- a/lib/ofp-ed-props.c
>>>>>>>>> +++ b/lib/ofp-ed-props.c
>>>>>>>>> @@ -79,6 +79,27 @@ decode_ed_prop(const struct
>>>>>>>>> ofp_ed_prop_header
>>>>>>>>> **ofp_prop,
>>>>>>>>>          }
>>>>>>>>>          break;
>>>>>>>>>      }
>>>>>>>>> +    case OFPPPC_MPLS: {
>>>>>>>>> +       switch (prop_type) {
>>>>>>>>> +        case OFPPPT_PROP_MPLS_ETHERTYPE: {
>>>>>>>>> +            struct ofp_ed_prop_mpls_ethertype *opnmt =
>>>>>>>>> +                ALIGNED_CAST(struct
>>>>>>>>> ofp_ed_prop_mpls_ethertype *,
>>>>>>>>> *ofp_prop);
>>>>>>>>> +            if (len > sizeof(*opnmt) || len > *remaining) {
>>>>>>>>> +                return OFPERR_NXBAC_BAD_ED_PROP;
>>>>>>>>> +            }
>>>>>>>>> +            struct ofpact_ed_prop_mpls_ethertype *pnmt =
>>>>>>>>> +                    ofpbuf_put_uninit(out, sizeof(*pnmt));
>>>>>>>>> +            pnmt->header.prop_class = prop_class;
>>>>>>>>> +            pnmt->header.type = prop_type;
>>>>>>>>> +            pnmt->header.len = len;
>>>>>>>>> +            pnmt->ether_type = opnmt->ether_type;
>>>>>>>>> +            break;
>>>>>>>>> +        }
>>>>>>>>> +        default:
>>>>>>>>> +            return OFPERR_NXBAC_UNKNOWN_ED_PROP;
>>>>>>>>> +        }
>>>>>>>>> +        break;
>>>>>>>>> +    }
>>>>>>>>>      default:
>>>>>>>>>          return OFPERR_NXBAC_UNKNOWN_ED_PROP;
>>>>>>>>>      }
>>>>>>>>> @@ -134,6 +155,27 @@ encode_ed_prop(const struct 
>>>>>>>>> ofpact_ed_prop
>>>>>>>>> **prop,
>>>>>>>>>          }
>>>>>>>>>          break;
>>>>>>>>>      }
>>>>>>>>> +    case OFPPPC_MPLS: {
>>>>>>>>> +       switch ((*prop)->type) {
>>>>>>>>> +       case OFPPPT_PROP_MPLS_ETHERTYPE: {
>>>>>>>>> +           struct ofpact_ed_prop_mpls_ethertype *pnmt =
>>>>>>>>> +                ALIGNED_CAST(struct
>>>>>>>>> ofpact_ed_prop_mpls_ethertype *,
>>>>>>>>> *prop);
>>>>>>>>> +            struct ofp_ed_prop_mpls_ethertype *opnmt =
>>>>>>>>> +                    ofpbuf_put_uninit(out, sizeof(*opnmt));
>>>>>>>>> +            opnmt->header.prop_class =
>>>>>>>>> htons((*prop)->prop_class);
>>>>>>>>> +            opnmt->header.type = (*prop)->type;
>>>>>>>>> +            opnmt->header.len =
>>>>>>>>> +                    offsetof(struct
>>>>>>>>> ofpact_ed_prop_mpls_ethertype,
>>>>>>>>> pad);
>>>>>>>>> +            opnmt->ether_type = pnmt->ether_type;
>>>>>>>>> +            prop_len = sizeof(*pnmt);
>>>>>>>>> +            break;
>>>>>>>>> +
>>>>>>>>> +       }
>>>>>>>>> +       default:
>>>>>>>>> +            return OFPERR_OFPBAC_BAD_ARGUMENT;
>>>>>>>>> +       }
>>>>>>>>> +       break;
>>>>>>>>> +    }
>>>>>>>>>      default:
>>>>>>>>>          return OFPERR_OFPBAC_BAD_ARGUMENT;
>>>>>>>>>      }
>>>>>>>>> @@ -181,6 +223,13 @@ parse_ed_prop_type(uint16_t prop_class,
>>>>>>>>>          } else {
>>>>>>>>>              return false;
>>>>>>>>>          }
>>>>>>>>> +    case OFPPPC_MPLS:
>>>>>>>>> +        if (!strcmp(str, "ether_type")) {
>>>>>>>>> +            *type = OFPPPT_PROP_MPLS_ETHERTYPE;
>>>>>>>>> +            return true;
>>>>>>>>> +        } else {
>>>>>>>>> +            return false;
>>>>>>>>> +        }
>>>>>>>>>      default:
>>>>>>>>>          return false;
>>>>>>>>>      }
>>>>>>>>> @@ -259,6 +308,28 @@ parse_ed_prop_value(uint16_t prop_class,
>>>>>>>>> uint8_t
>>>>>>>>> prop_type OVS_UNUSED,
>>>>>>>>>              OVS_NOT_REACHED();
>>>>>>>>>          }
>>>>>>>>>          break;
>>>>>>>>> +    case OFPPPC_MPLS:
>>>>>>>>> +        switch (prop_type) {
>>>>>>>>> +        case OFPPPT_PROP_MPLS_ETHERTYPE: {
>>>>>>>>> +            uint16_t ethertype;
>>>>>>>>> +            error = str_to_u16(value,
>>>>>>>>> "ether_type", &ethertype);
>>>>>>>>> +            if (error != NULL) {
>>>>>>>>> +                return error;
>>>>>>>>> +            }
>>>>>>>>> +            struct ofpact_ed_prop_mpls_ethertype *pnmt =
>>>>>>>>> +                    ofpbuf_put_uninit(out, sizeof(*pnmt));
>>>>>>>>> +            pnmt->header.prop_class = prop_class;
>>>>>>>>> +            pnmt->header.type = prop_type;
>>>>>>>>> +            pnmt->header.len =
>>>>>>>>> +                    offsetof(struct
>>>>>>>>> ofpact_ed_prop_mpls_ethertype,
>>>>>>>>> pad);
>>>>>>>>> +            pnmt->ether_type = ethertype;
>>>>>>>>> +
>>>>>>>>> +            break;
>>>>>>>>> +        }
>>>>>>>>> +        default:
>>>>>>>>> +            break;
>>>>>>>>> +      }
>>>>>>>>> +      break;
>>>>>>>>>      default:
>>>>>>>>>          /* Unsupported property classes rejected before. */
>>>>>>>>>          OVS_NOT_REACHED();
>>>>>>>>> @@ -300,6 +371,14 @@ format_ed_prop_type(const struct
>>>>>>>>> ofpact_ed_prop
>>>>>>>>> *prop)
>>>>>>>>>              OVS_NOT_REACHED();
>>>>>>>>>          }
>>>>>>>>>          break;
>>>>>>>>> +    case OFPPPC_MPLS:
>>>>>>>>> +         switch (prop->type) {
>>>>>>>>> +         case OFPPPT_PROP_MPLS_ETHERTYPE:
>>>>>>>>> +              return "ether_type";
>>>>>>>>> +         default:
>>>>>>>>> +               OVS_NOT_REACHED();
>>>>>>>>> +         }
>>>>>>>>> +         break;
>>>>>>>>>      default:
>>>>>>>>>          OVS_NOT_REACHED();
>>>>>>>>>      }
>>>>>>>>> @@ -332,6 +411,18 @@ format_ed_prop(struct ds *s OVS_UNUSED,
>>>>>>>>>          default:
>>>>>>>>>              OVS_NOT_REACHED();
>>>>>>>>>          }
>>>>>>>>> +     case OFPPPC_MPLS:
>>>>>>>>> +        switch (prop->type) {
>>>>>>>>> +        case OFPPPT_PROP_MPLS_ETHERTYPE: {
>>>>>>>>> +          struct ofpact_ed_prop_mpls_ethertype *pnmt =
>>>>>>>>> +                ALIGNED_CAST(struct
>>>>>>>>> ofpact_ed_prop_mpls_ethertype *,
>>>>>>>>> prop);
>>>>>>>>> +            ds_put_format(s, "%s=%d",
>>>>>>>>> format_ed_prop_type(prop),
>>>>>>>>> +                          pnmt->ether_type);
>>>>>>>>> +            return;
>>>>>>>>> +        }
>>>>>>>>> +        default:
>>>>>>>>> +            OVS_NOT_REACHED();
>>>>>>>>> +        }
>>>>>>>>>      default:
>>>>>>>>>          OVS_NOT_REACHED();
>>>>>>>>>      }
>>>>>>>>> diff --git a/lib/ovs-actions.xml b/lib/ovs-actions.xml
>>>>>>>>> index a2778de4b..e97f818d9 100644
>>>>>>>>> --- a/lib/ovs-actions.xml
>>>>>>>>> +++ b/lib/ovs-actions.xml
>>>>>>>>> @@ -265,13 +265,13 @@
>>>>>>>>>        </p>
>>>>>>>>>
>>>>>>>>>        <p>
>>>>>>>>> -        When a <code>decap</code> action decapsulates a 
>>>>>>>>> packet,
>>>>>>>>> Open
>>>>>>>>> vSwitch
>>>>>>>>> -        raises this error if it does not support the
>>>>>>>>> type of inner
>>>>>>>>> packet.
>>>>>>>>> -        <code>decap</code> of an Ethernet header raises this
>>>>>>>>> error if a
>>>>>>>>> VLAN
>>>>>>>>> -        header is present, <code>decap</code> of a NSH packet
>>>>>>>>> raises
>>>>>>>>> this error
>>>>>>>>> -        if the NSH inner packet is not Ethernet, IPv4, IPv6, 
>>>>>>>>> or
>>>>>>>>> NSH,
>>>>>>>>> and
>>>>>>>>> -        <code>decap</code> of other types of packets is
>>>>>>>>> unsupported and
>>>>>>>>> also
>>>>>>>>> -        raises this error.
>>>>>>>>> +        The <code>decap</code> action is supported only
>>>>>>>>> for packet
>>>>>>>>> types
>>>>>>>>> +        ethernet, NSH and MPLS. Openvswitch raises this error
>>>>>>>>> for other
>>>>>>>>> +        packet types. When a <code>decap</code> action
>>>>>>>>> decapsulates a
>>>>>>>>> packet,
>>>>>>>>> +        Open vSwitch raises this error if it does not support
>>>>>>>>> the type
>>>>>>>>> of inner
>>>>>>>>> +        packet. <code>decap</code> of an Ethernet header 
>>>>>>>>> raises
>>>>>>>>> this
>>>>>>>>> error if a
>>>>>>>>> +        VLAN header is present, <code>decap</code> of a
>>>>>>>>> NSH packet
>>>>>>>>> raises this
>>>>>>>>> +        error if the NSH inner packet is not Ethernet, IPv4,
>>>>>>>>> IPv6, or
>>>>>>>>> NSH.
>>>>>>>>>        </p>
>>>>>>>>>
>>>>>>>>>        <p>
>>>>>>>>> @@ -1097,6 +1097,8 @@ for <var>i</var> in
>>>>>>>>> [1,<var>n_members</var>]:
>>>>>>>>>        <h2>The <code>encap</code> action</h2>
>>>>>>>>>        <syntax><code>encap(nsh(</code>[<code>md_type=<var>md_type</var></code>]<code>, 
>>>>>>>>> </code>[<code>tlv(<var>class</var>,<var>type</var>,<var>value</var>)</code>]...<code>))</code></syntax>
>>>>>>>>>        <syntax><code>encap(ethernet)</code></syntax>
>>>>>>>>> +
>>>>>>>>> <syntax><code>encap(mpls(ether_type=<var>ether_type</var>))</code>
>>>>>>>>> +      </syntax>
>>>>>>>>>
>>>>>>>>>        <p>
>>>>>>>>>          The <code>encap</code> action encapsulates a
>>>>>>>>> packet with a
>>>>>>>>> specified
>>>>>>>>> @@ -1135,6 +1137,12 @@ for <var>i</var> in
>>>>>>>>> [1,<var>n_members</var>]:
>>>>>>>>>          source and destination are initially zeroed.
>>>>>>>>>        </p>
>>>>>>>>>
>>>>>>>>> +      <p>
>>>>>>>>> +        The <code>encap(mpls(ethertype=....))</code> variant
>>>>>>>>> encapsulates an
>>>>>>>>> +        ethernet or L3 packet with a MPLS header. The
>>>>>>>>> <var>ethertype</var>
>>>>>>>>> +        could be MPLS unicast (0x8847) or multicast (0x8848)
>>>>>>>>> ethertypes.
>>>>>>>>> +      </p>
>>>>>>>>> +
>>>>>>>>>        <conformance>
>>>>>>>>>          This action is an Open vSwitch extension to OpenFlow
>>>>>>>>> 1.3 and
>>>>>>>>> later,
>>>>>>>>>          introduced in Open vSwitch 2.8.
>>>>>>>>> @@ -1144,6 +1152,9 @@ for <var>i</var> in
>>>>>>>>> [1,<var>n_members</var>]:
>>>>>>>>>      <action name="DECAP">
>>>>>>>>>        <h2>The <code>decap</code> action</h2>
>>>>>>>>>        <syntax><code>decap</code></syntax>
>>>>>>>>> +      
>>>>>>>>> <syntax><code>decap(packet_type(ns=<var>name_space</var>,
>>>>>>>>> +      type=<var>ethertype</var>))</code></syntax> for
>>>>>>>>> decapsulating
>>>>>>>>> MPLS
>>>>>>>>> +      packets.
>>>>>>>>>
>>>>>>>>>        <p>
>>>>>>>>>          Removes an outermost encapsulation from the packet:
>>>>>>>>> @@ -1164,6 +1175,12 @@ for <var>i</var> in
>>>>>>>>> [1,<var>n_members</var>]:
>>>>>>>>>            packet type errors.
>>>>>>>>>          </li>
>>>>>>>>>
>>>>>>>>> +        <li>
>>>>>>>>> +          Otherwise, if the packet is a MPLS packet, removes
>>>>>>>>> the MPLS
>>>>>>>>> header
>>>>>>>>> +          and classifies the inner packet as mentioned in the
>>>>>>>>> packet
>>>>>>>>> type
>>>>>>>>> +          argument of the decap.
>>>>>>>>> +        </li>
>>>>>>>>> +
>>>>>>>>>          <li>
>>>>>>>>>            Otherwise, raises an unsupported packet type error.
>>>>>>>>>          </li>
>>>>>>>>> diff --git a/lib/packets.c b/lib/packets.c
>>>>>>>>> index 4a7643c5d..5e3c3900f 100644
>>>>>>>>> --- a/lib/packets.c
>>>>>>>>> +++ b/lib/packets.c
>>>>>>>>> @@ -418,6 +418,38 @@ push_mpls(struct dp_packet
>>>>>>>>> *packet, ovs_be16
>>>>>>>>> ethtype, ovs_be32 lse)
>>>>>>>>>      pkt_metadata_init_conn(&packet->md);
>>>>>>>>>  }
>>>>>>>>>
>>>>>>>>> +void
>>>>>>>>> +add_mpls(struct dp_packet *packet, ovs_be16 ethtype, ovs_be32
>>>>>>>>> lse, bool
>>>>>>>>> l3)
>>>>>>>>> +{
>>>>>>>>> +    char * header;
>>>>>>>>> +
>>>>>>>>> +    if (!eth_type_mpls(ethtype)) {
>>>>>>>>> +        return;
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    if (!l3) {
>>>>>>>>> +        header =  dp_packet_push_uninit(packet, MPLS_HLEN);
>>>>>>>>> +        memcpy(header, &lse, sizeof lse);
>>>>>>>>> +        packet->l2_5_ofs = 0;
>>>>>>>>> +        packet->packet_type = htonl(PT_MPLS);
>>>>>>>>> +    } else {
>>>>>>>>> +        size_t len;
>>>>>>>>> +
>>>>>>>>> +        if (!is_mpls(packet)) {
>>>>>>>>> +            /* Set MPLS label stack offset. */
>>>>>>>>> +            packet->l2_5_ofs = packet->l3_ofs;
>>>>>>>>> +        }
>>>>>>>>> +        set_ethertype(packet, ethtype);
>>>>>>>>> +
>>>>>>>>> +        /* Push new MPLS shim header onto packet. */
>>>>>>>>> +        len = packet->l2_5_ofs;
>>>>>>>>> +        header = dp_packet_resize_l2_5(packet, MPLS_HLEN);
>>>>>>>>> +        memmove(header, header + MPLS_HLEN, len);
>>>>>>>>> +        memcpy(header + len, &lse, sizeof lse);
>>>>>>>>> +    }
>>>>>>>>> +    pkt_metadata_init_conn(&packet->md);
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>>  /* If 'packet' is an MPLS packet, removes its outermost
>>>>>>>>> MPLS label
>>>>>>>>> stack entry.
>>>>>>>>>   * If the label that was removed was the only
>>>>>>>>> MPLS label, changes
>>>>>>>>> 'packet''s
>>>>>>>>>   * Ethertype to 'ethtype' (which ordinarily
>>>>>>>>> should not be an MPLS
>>>>>>>>> @@ -429,6 +461,10 @@ pop_mpls(struct dp_packet *packet, 
>>>>>>>>> ovs_be16
>>>>>>>>> ethtype)
>>>>>>>>>          struct mpls_hdr *mh = dp_packet_l2_5(packet);
>>>>>>>>>          size_t len = packet->l2_5_ofs;
>>>>>>>>>
>>>>>>>>> +        if (ethtype == htons(ETH_TYPE_TEB)) {
>>>>>>>>> +             packet->packet_type = htonl(PT_ETH);
>>>>>>>>> +        }
>>>>>>>>> +
>>>>>>>>>          set_ethertype(packet, ethtype);
>>>>>>>>>          if (get_16aligned_be32(&mh->mpls_lse) &
>>>>>>>>> htonl(MPLS_BOS_MASK)) {
>>>>>>>>>              dp_packet_set_l2_5(packet, NULL);
>>>>>>>>> diff --git a/lib/packets.h b/lib/packets.h
>>>>>>>>> index 481bc22fa..3f5862e08 100644
>>>>>>>>> --- a/lib/packets.h
>>>>>>>>> +++ b/lib/packets.h
>>>>>>>>> @@ -350,6 +350,8 @@ void set_mpls_lse_label(ovs_be32
>>>>>>>>> *lse, ovs_be32
>>>>>>>>> label);
>>>>>>>>>  void set_mpls_lse_bos(ovs_be32 *lse, uint8_t bos);
>>>>>>>>>  ovs_be32 set_mpls_lse_values(uint8_t ttl, uint8_t tc,
>>>>>>>>> uint8_t bos,
>>>>>>>>>                               ovs_be32 label);
>>>>>>>>> +void add_mpls(struct dp_packet *packet, ovs_be16 ethtype,
>>>>>>>>> ovs_be32 lse,
>>>>>>>>> +              bool l3_flag);
>>>>>>>>>
>>>>>>>>>  /* Example:
>>>>>>>>>   *
>>>>>>>>> diff --git a/ofproto/ofproto-dpif-ipfix.c
>>>>>>>>> b/ofproto/ofproto-dpif-ipfix.c
>>>>>>>>> index 796eb6f88..9280e008e 100644
>>>>>>>>> --- a/ofproto/ofproto-dpif-ipfix.c
>>>>>>>>> +++ b/ofproto/ofproto-dpif-ipfix.c
>>>>>>>>> @@ -3018,6 +3018,7 @@ dpif_ipfix_read_actions(const struct 
>>>>>>>>> flow
>>>>>>>>> *flow,
>>>>>>>>>          case OVS_ACTION_ATTR_CHECK_PKT_LEN:
>>>>>>>>>          case OVS_ACTION_ATTR_UNSPEC:
>>>>>>>>>          case OVS_ACTION_ATTR_DROP:
>>>>>>>>> +        case OVS_ACTION_ATTR_ADD_MPLS:
>>>>>>>>>          case __OVS_ACTION_ATTR_MAX:
>>>>>>>>>          default:
>>>>>>>>>              break;
>>>>>>>>> diff --git a/ofproto/ofproto-dpif-sflow.c
>>>>>>>>> b/ofproto/ofproto-dpif-sflow.c
>>>>>>>>> index fdcb9eabb..ca46a9bc4 100644
>>>>>>>>> --- a/ofproto/ofproto-dpif-sflow.c
>>>>>>>>> +++ b/ofproto/ofproto-dpif-sflow.c
>>>>>>>>> @@ -1226,6 +1226,7 @@ dpif_sflow_read_actions(const struct 
>>>>>>>>> flow
>>>>>>>>> *flow,
>>>>>>>>>          case OVS_ACTION_ATTR_UNSPEC:
>>>>>>>>>          case OVS_ACTION_ATTR_CHECK_PKT_LEN:
>>>>>>>>>          case OVS_ACTION_ATTR_DROP:
>>>>>>>>> +        case OVS_ACTION_ATTR_ADD_MPLS:
>>>>>>>>>          case __OVS_ACTION_ATTR_MAX:
>>>>>>>>>          default:
>>>>>>>>>              break;
>>>>>>>>> diff --git a/ofproto/ofproto-dpif-xlate.c
>>>>>>>>> b/ofproto/ofproto-dpif-xlate.c
>>>>>>>>> index 7108c8a30..a97534233 100644
>>>>>>>>> --- a/ofproto/ofproto-dpif-xlate.c
>>>>>>>>> +++ b/ofproto/ofproto-dpif-xlate.c
>>>>>>>>> @@ -6381,6 +6381,45 @@
>>>>>>>>> rewrite_flow_encap_ethernet(struct xlate_ctx
>>>>>>>>> *ctx,
>>>>>>>>>          ctx->error = XLATE_UNSUPPORTED_PACKET_TYPE;
>>>>>>>>>      }
>>>>>>>>>  }
>>>>>>>>> +static void
>>>>>>>>> +rewrite_flow_encap_mpls(struct xlate_ctx *ctx,
>>>>>>>>> +                        const struct ofpact_encap *encap,
>>>>>>>>> +                        struct flow *flow,
>>>>>>>>> +                        struct flow_wildcards *wc)
>>>>>>>>> +{
>>>>>>>>> +    int n;
>>>>>>>>> +    uint32_t i;
>>>>>>>>> +    uint16_t ether_type;
>>>>>>>>> +    const char *ptr = (char *) encap->props;
>>>>>>>>> +
>>>>>>>>> +     for (i = 0; i < encap->n_props; i++) {
>>>>>>>>> +        struct ofpact_ed_prop *prop_ptr =
>>>>>>>>> +            ALIGNED_CAST(struct ofpact_ed_prop *, ptr);
>>>>>>>>> +        if (prop_ptr->prop_class == OFPPPC_MPLS) {
>>>>>>>>> +            switch (prop_ptr->type) {
>>>>>>>>> +                case OFPPPT_PROP_MPLS_ETHERTYPE: {
>>>>>>>>> +                     struct ofpact_ed_prop_mpls_ethertype
>>>>>>>>> *prop_ether_type =
>>>>>>>>> +                        ALIGNED_CAST(struct
>>>>>>>>> ofpact_ed_prop_mpls_ethertype *,
>>>>>>>>> +                                     prop_ptr);
>>>>>>>>> +                    ether_type = prop_ether_type->ether_type;
>>>>>>>>> +                    break;
>>>>>>>>> +                 }
>>>>>>>>> +            }
>>>>>>>>> +        }
>>>>>>>>> +     }
>>>>>>>>> +
>>>>>>>>> +    wc->masks.packet_type = OVS_BE32_MAX;
>>>>>>>>> +    if (flow->packet_type != htonl(PT_MPLS)) {
>>>>>>>>> +        memset(&ctx->wc->masks.mpls_lse, 0x0,
>>>>>>>>> +               sizeof *wc->masks.mpls_lse *
>>>>>>>>> FLOW_MAX_MPLS_LABELS);
>>>>>>>>> +        memset(&flow->mpls_lse, 0x0, sizeof *flow->mpls_lse *
>>>>>>>>> +               FLOW_MAX_MPLS_LABELS);
>>>>>>>>> +    }
>>>>>>>>> +    flow->packet_type = htonl(PT_MPLS);
>>>>>>>>> +    n = flow_count_mpls_labels(flow, ctx->wc);
>>>>>>>>> +    flow_push_mpls(flow, n, htons(ether_type), ctx->wc, 
>>>>>>>>> true);
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>>
>>>>>>>>>  /* For an MD2 NSH header returns a pointer to
>>>>>>>>> an ofpbuf with the
>>>>>>>>> encoded
>>>>>>>>>   * MD2 TLVs provided as encap properties to the encap
>>>>>>>>> operation. This
>>>>>>>>> @@ -6513,6 +6552,12 @@ xlate_generic_encap_action(struct
>>>>>>>>> xlate_ctx *ctx,
>>>>>>>>>          case PT_NSH:
>>>>>>>>>              encap_data = rewrite_flow_push_nsh(ctx, encap,
>>>>>>>>> flow, wc);
>>>>>>>>>              break;
>>>>>>>>> +        case PT_MPLS:
>>>>>>>>> +            rewrite_flow_encap_mpls(ctx, encap,  flow, wc);
>>>>>>>>> +            if (!ctx->xbridge->support.add_mpls) {
>>>>>>>>> +                ctx->xout->slow |= SLOW_ACTION;
>>>>>>>>> +            }
>>>>>>>>> +            break;
>>>>>>>>>          default:
>>>>>>>>>              /* New packet type was checked during decoding. 
>>>>>>>>> */
>>>>>>>>>              OVS_NOT_REACHED();
>>>>>>>>> @@ -6582,6 +6627,21 @@ xlate_generic_decap_action(struct
>>>>>>>>> xlate_ctx *ctx,
>>>>>>>>>              ctx->pending_decap = true;
>>>>>>>>>              /* Trigger recirculation. */
>>>>>>>>>              return true;
>>>>>>>>> +        case PT_MPLS: {
>>>>>>>>> +             int n;
>>>>>>>>> +             ovs_be16 ethertype;
>>>>>>>>> +
>>>>>>>>> +             flow->packet_type = decap->new_pkt_type;
>>>>>>>>> +             ethertype = pt_ns_type_be(flow->packet_type);
>>>>>>>>> +
>>>>>>>>> +             n = flow_count_mpls_labels(flow, ctx->wc);
>>>>>>>>> +             flow_pop_mpls(flow, n, ethertype, ctx->wc);
>>>>>>>>> +             if (!ctx->xbridge->support.add_mpls) {
>>>>>>>>> +                ctx->xout->slow |= SLOW_ACTION;
>>>>>>>>> +             }
>>>>>>>>> +             ctx->pending_decap = true;
>>>>>>>>> +             return true;
>>>>>>>>> +        }
>>>>>>>>>          default:
>>>>>>>>>              /* Error handling: drop packet. */
>>>>>>>>>              xlate_report_debug(
>>>>>>>>> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
>>>>>>>>> index fd0b2fdea..d9a2922e7 100644
>>>>>>>>> --- a/ofproto/ofproto-dpif.c
>>>>>>>>> +++ b/ofproto/ofproto-dpif.c
>>>>>>>>> @@ -1520,6 +1520,44 @@ check_nd_extensions(struct dpif_backer
>>>>>>>>> *backer)
>>>>>>>>>
>>>>>>>>>      return !error;
>>>>>>>>>  }
>>>>>>>>> +/* Tests whether 'backer''s datapath supports the
>>>>>>>>> + * OVS_ACTION_ATTR_ADD_MPLS action. */
>>>>>>>>> +static bool
>>>>>>>>> +check_add_mpls(struct dpif_backer *backer)
>>>>>>>>> +{
>>>>>>>>> +    struct odputil_keybuf keybuf;
>>>>>>>>> +    struct ofpbuf actions;
>>>>>>>>> +    struct ofpbuf key;
>>>>>>>>> +    struct flow flow;
>>>>>>>>> +    bool supported;
>>>>>>>>> +
>>>>>>>>> +    struct odp_flow_key_parms odp_parms = {
>>>>>>>>> +        .flow = &flow,
>>>>>>>>> +        .probe = true,
>>>>>>>>> +    };
>>>>>>>>> +
>>>>>>>>> +    memset(&flow, 0, sizeof flow);
>>>>>>>>> +    ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
>>>>>>>>> +    odp_flow_key_from_flow(&odp_parms, &key);
>>>>>>>>> +    ofpbuf_init(&actions, 64);
>>>>>>>>> +
>>>>>>>>> +    struct ovs_action_add_mpls *mpls;
>>>>>>>>> +
>>>>>>>>> +    mpls = nl_msg_put_unspec_zero(&actions,
>>>>>>>>> +                                  OVS_ACTION_ATTR_ADD_MPLS,
>>>>>>>>> +                                  sizeof *mpls);
>>>>>>>>> +    mpls->mpls_ethertype = htons(ETH_TYPE_MPLS);
>>>>>>>>> +
>>>>>>>>> +    supported = dpif_probe_feature(backer->dpif,
>>>>>>>>> "add_mpls", &key,
>>>>>>>>> +                                   &actions, NULL);
>>>>>>>>> +    ofpbuf_uninit(&actions);
>>>>>>>>> +    VLOG_INFO("%s: Datapath %s add_mpls action",
>>>>>>>>> +              dpif_name(backer->dpif), supported ? "supports"
>>>>>>>>> +                                                 : "does not
>>>>>>>>> support");
>>>>>>>>> +    return supported;
>>>>>>>>> +
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>>
>>>>>>>>>  #define CHECK_FEATURE__(NAME, SUPPORT, FIELD, VALUE, ETHTYPE)
>>>>>>>>> \
>>>>>>>>>  static bool
>>>>>>>>> \
>>>>>>>>> @@ -1590,6 +1628,7 @@ check_support(struct dpif_backer 
>>>>>>>>> *backer)
>>>>>>>>>          dpif_supports_explicit_drop_action(backer->dpif);
>>>>>>>>>      backer->rt_support.lb_output_action=
>>>>>>>>>          dpif_supports_lb_output_action(backer->dpif);
>>>>>>>>> +    backer->rt_support.add_mpls = check_add_mpls(backer);
>>>>>>>>>
>>>>>>>>>      /* Flow fields. */
>>>>>>>>>      backer->rt_support.odp.ct_state = check_ct_state(backer);
>>>>>>>>> diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h
>>>>>>>>> index b41c3d82a..c04bfff8d 100644
>>>>>>>>> --- a/ofproto/ofproto-dpif.h
>>>>>>>>> +++ b/ofproto/ofproto-dpif.h
>>>>>>>>> @@ -204,7 +204,10 @@ struct group_dpif 
>>>>>>>>> *group_dpif_lookup(struct
>>>>>>>>> ofproto_dpif *,
>>>>>>>>>      DPIF_SUPPORT_FIELD(bool,
>>>>>>>>> explicit_drop_action, "Explicit Drop
>>>>>>>>> action")  \
>>>>>>>>>                                                                              \
>>>>>>>>>      /* True if the datapath supports
>>>>>>>>> balance_tcp optimization */
>>>>>>>>> \
>>>>>>>>> -    DPIF_SUPPORT_FIELD(bool, lb_output_action, "Optimized
>>>>>>>>> Balance TCP
>>>>>>>>> mode")
>>>>>>>>> +    DPIF_SUPPORT_FIELD(bool, lb_output_action, "Optimized
>>>>>>>>> Balance TCP
>>>>>>>>> mode")\
>>>>>>>>> +
>>>>>>>>> \
>>>>>>>>> +    /* True if the datapath supports layer 2 MPLS tunnelling 
>>>>>>>>> */
>>>>>>>>> \
>>>>>>>>> +    DPIF_SUPPORT_FIELD(bool, add_mpls, "l2 MPLS tunnelling")
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>  /* Stores the various features which the corresponding backer
>>>>>>>>> supports.
>>>>>>>>> */
>>>>>>>>> diff --git a/tests/system-traffic.at b/tests/system-traffic.at
>>>>>>>>> index fb5b9a36d..b865b5210 100644
>>>>>>>>> --- a/tests/system-traffic.at
>>>>>>>>> +++ b/tests/system-traffic.at
>>>>>>>>> @@ -1027,9 +1027,45 @@ NS_CHECK_EXEC([at_ns0], [ping -q -c 3 
>>>>>>>>> -i
>>>>>>>>> 0.3 -w 2
>>>>>>>>> 10.1.1.2 | FORMAT_PING], [0],
>>>>>>>>>  3 packets transmitted, 3 received, 0% packet loss, time 0ms
>>>>>>>>>  ])
>>>>>>>>>
>>>>>>>>> +OVS_TRAFFIC_VSWITCHD_STOP
>>>>>>>>> +AT_CLEANUP
>>>>>>>>> +
>>>>>>>>> +
>>>>>>>>> +AT_SETUP([datapath - ptap mpls actions])
>>>>>>>>> +OVS_TRAFFIC_VSWITCHD_START([_ADD_BR([br1])])
>>>>>>>>> +
>>>>>>>>> +ADD_NAMESPACES(at_ns0, at_ns1)
>>>>>>>>> +
>>>>>>>>> +ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
>>>>>>>>> +ADD_VETH(p1, at_ns1, br1, "10.1.1.2/24")
>>>>>>>>> +
>>>>>>>>> +AT_CHECK([ip link add patch0 type veth peer name patch1])
>>>>>>>>> +on_exit 'ip link del patch0'
>>>>>>>>> +
>>>>>>>>> +AT_CHECK([ip link set dev patch0 up])
>>>>>>>>> +AT_CHECK([ip link set dev patch1 up])
>>>>>>>>> +AT_CHECK([ovs-vsctl add-port br0 patch0 -- set interface 
>>>>>>>>> patch0
>>>>>>>>> ofport_request=100])
>>>>>>>>> +AT_CHECK([ovs-vsctl add-port br1 patch1 -- set interface 
>>>>>>>>> patch1
>>>>>>>>> ofport_request=100])
>>>>>>>>> +
>>>>>>>>> +AT_DATA([flows.txt], [dnl
>>>>>>>>> +table=0,priority=100,dl_type=0x0800 
>>>>>>>>> actions=encap(mpls(ether_type=0x8847)),set_mpls_label:2,encap(ethernet),output:100
>>>>>>>>> +table=0,priority=100,dl_type=0x8847,mpls_label=2
>>>>>>>>> actions=decap(),decap(packet_type(ns=0,type=0)),resubmit(,3)
>>>>>>>>> +table=0,priority=10 actions=resubmit(,3)
>>>>>>>>> +table=3,priority=10 actions=normal
>>>>>>>>> +])
>>>>>>>>> +
>>>>>>>>> +AT_CHECK([ovs-ofctl  -Oopenflow13 add-flows br0 flows.txt])
>>>>>>>>> +AT_CHECK([ovs-ofctl  -Oopenflow13 add-flows br1 flows.txt])
>>>>>>>>> +
>>>>>>>>> +NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -w 2 10.1.1.2 |
>>>>>>>>> FORMAT_PING], [0], [dnl
>>>>>>>>> +3 packets transmitted, 3 received, 0% packet loss, time 0ms
>>>>>>>>> +])
>>>>>>>>> +
>>>>>>>>> +
>>>>>>>>>  NS_CHECK_EXEC([at_ns1], [ping -q -c 3 -i 0.3 -w 2 10.1.1.1 |
>>>>>>>>> FORMAT_PING], [0], [dnl
>>>>>>>>>  3 packets transmitted, 3 received, 0% packet loss, time 0ms
>>>>>>>>>  ])
>>>>>>>>> +
>>>>>>>>>  OVS_TRAFFIC_VSWITCHD_STOP
>>>>>>>>>  AT_CLEANUP
>>>>>>>>>
>>>>>>>>> -- 
>>>>>>>>> 2.18.4
>>>>>>>>
>>>>>>
>>>>
>>



More information about the dev mailing list