On Thu, Apr 01, 2021 at 11:32:06AM +0200, Eelco Chaudron wrote:
> 
> 
> 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 <[email protected]>
> > > > > > > > > > 
> > > > > > > > > > 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@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

I could reproduce the problem. It has nothing to do with ARP or IP. Unlike my 
test scripts, in your test you are setting the mac address after the encap 
action

Ovs-vswitchd is programming a set(eth(dst) action between the  pop_mpls and  
recirc as it sees a difference in mac address in flow structure and  base_flow 
structure.

The mac address in flow structure is not cleared in PT_ETH handling of 
xlate_generic_decap_action but  it is cleared in base_flow in the   decap 
handling of PT_ETH in commit_encap_decap_action function

Due to this difference the set(eth(dst) action will be programmed to the 
datapath.

Also, I see that in  commit_set_ether_action Function  “flow->packet_type != 
htonl(PT_ETH)” is used to check if the packet is ethernet instead of 
base_flow->packet_type.

I assume check on base_flow->packet_type make more sense here ?

I tried to fix this issue in 2 different ways.

1   I have cleared the mac address in flow structure  in PT_ETH handling of 
xlate_generic_decap action.

2  In the  commit_set_ether action I changed the check from  “flow->packet_type 
!= htonl(PT_ETH)” to  “base_flow->packet_type != htonl(PT_ETH))”.

Though both of them solves this problem, couple of NSH regression tests are 
failing

2291: nsh - md1 encap over a veth link                FAILED (nsh.at:85)

58022292: nsh - md2 encap over a veth link                FAILED (nsh.at:213)

I see that they are failing as they are expecting a set(eth(dst)  between the 
the pop_nsh and the recirc.

Set(eth) action is because of the reasons explained above –

Datapath actions: 
push_nsh(flags=0,ttl=63,mdtype=1,np=3,spi=0x1234,si=255,c1=0x11223344,c2=0x0,c3=0x0,c4=0x0),push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),pop_eth,pop_nsh(),set(eth(dst=11:22:33:44:55:66)),recirc(0x1)

In my understanding set(eth) here  is wrong as there is no set ethernet action 
in the userspace rule
- Hide quoted text -

table=0,in_port=4,dl_type=0x894f,nsh_mdtype=1,nsh_spi=0x1234,nsh_c1=0x11223344,actions=decap(),decap(),2



Could someone comment ?

> > > > > > > 2021-04-01T06:53:36.056Z|00142|dpif(handler37)|WARN|system@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 <[email protected]>
> > > > > > > > > > ---
> > > > > > > > > >  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
> > > > > > > > > 
> > > > > > > 
> > > > > 
> > > 
> 
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to