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 > > > 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. > > 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", ðertype); > > > > > > + 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
