From patchwork Fri May 8 04:31:26 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Varghese X-Patchwork-Id: 1285775 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.136; helo=silver.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=TmEbq+D9; dkim-atps=neutral Received: from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 49JHTr6BzQz9sSk for ; Fri, 8 May 2020 14:31:44 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id D2CC020770; Fri, 8 May 2020 04:31:40 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from silver.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id vbEdUisA4+Ns; Fri, 8 May 2020 04:31:36 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by silver.osuosl.org (Postfix) with ESMTP id 6B3D22052E; Fri, 8 May 2020 04:31:36 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 548B0C0865; Fri, 8 May 2020 04:31:36 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by lists.linuxfoundation.org (Postfix) with ESMTP id BE71CC07FF for ; Fri, 8 May 2020 04:31:34 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id AD71A882B1 for ; Fri, 8 May 2020 04:31:34 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from whitealder.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id aUgM2EWg12ev for ; Fri, 8 May 2020 04:31:33 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mail-pg1-f195.google.com (mail-pg1-f195.google.com [209.85.215.195]) by whitealder.osuosl.org (Postfix) with ESMTPS id BD24F8829F for ; Fri, 8 May 2020 04:31:33 +0000 (UTC) Received: by mail-pg1-f195.google.com with SMTP id o18so285025pgg.8 for ; Thu, 07 May 2020 21:31:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=udXAcUfQvMEBNR3wRF8g9ZRLhxMaNS1Qx/SEh0kI2ts=; b=TmEbq+D9ndun5GRcBfe/1LRhoZzum6WW+P9TBkDUPIn/4o7hrmabjYbEb9564uioTB c6/Z6ffZ+J5j7P2rlZtSOC1xQAiTUMpt8Nwgu3Fl4eSmQkmKw6GKJBOlEYGY+y3Ipmm5 ncm6IfWvrf2kNRJ67uL6uW4QRJz12dEcTH1p+sJO/pHkS95JdpTI/HYGw+u4qLN5aVP4 I2uaawDP5ioTxtfUguX2IktbXm7cbhOpPG/N8OGOzWBQDvIEUtpbzd96+ZuUM7/fcy7x hwe9OAYat7QWL3wa7iv70g0pW5WPFSiMFh4N65NUa8n9AmlyQvV6DzDy1dxp0BG8O+OV a0SQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=udXAcUfQvMEBNR3wRF8g9ZRLhxMaNS1Qx/SEh0kI2ts=; b=tDayt4zE7l/8RyJYe3PpbbMbgaxuSTxLz5WmTdbULI5v8FL56LLrcAdqPZ3e3owA5c 4ZTKXVqt7IA8tIQRyw/YdEp3Oag68mQUmAO5i2wzNnZoKhJNhhwW1oaT15jePNxGMume U5/JzoTO0goEK9lXLFNTpE2nNx0RNBqDWCMQEvWdEV/9PTiQItdlcR6ijTaQ/IuaPvQQ pq0nXmfSEaBRfPM5Q/aB6mXn9Gvh2mhv4tb1ezyqVw46bHT5/URF8iucvnLPFmMibknm I7m+KaeqPgtlXD+xDf77XQVUEaQH0qNJ0EWND44KTXLwlJGLn1q/5kV4kJDdfvDs9aRq 35jQ== X-Gm-Message-State: AGi0PuZlw8cim3CdS8sI5BGxX77XbNhPUcCy83yd0/mV6pdjwmJC3t28 INFtzW3pGcH7HAYJlHmBqKNmyYS/ X-Google-Smtp-Source: APiQypKgasG6twy4fl8zcuEetVh5WjVlEM5N39Sj00k8kEuhTlKZPLH+HFvddq8ZatpLMnqV4u+vJw== X-Received: by 2002:a63:5345:: with SMTP id t5mr494313pgl.401.1588912292942; Thu, 07 May 2020 21:31:32 -0700 (PDT) Received: from martin-VirtualBox.apac.nsn-net.net ([117.202.93.227]) by smtp.gmail.com with ESMTPSA id y3sm1181151pjb.41.2020.05.07.21.31.30 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Thu, 07 May 2020 21:31:32 -0700 (PDT) From: Martin Varghese To: dev@openvswitch.org, pshelar@ovn.org Date: Fri, 8 May 2020 10:01:26 +0530 Message-Id: <7d1b81bf82976cbc894763fe628a3a281a392e09.1588869591.git.martin.varghese@nokia.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: References: Cc: Martin Varghese Subject: [ovs-dev] [PATCH v3 1/2] Datapath: New MPLS actions for layer 2 tunnelling X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Martin Varghese Upstream commit: commit f66b53fdbb22ced1a323b22b9de84a61aacd8d18 Author: Martin Varghese Date: Sat Dec 21 08:50:46 2019 +0530 openvswitch: New MPLS actions for layer 2 tunnelling The existing PUSH MPLS action inserts MPLS header between ethernet header and the IP header. Though this behaviour is fine for L3 VPN where an IP packet is encapsulated inside a MPLS tunnel, it does not suffice the L2 VPN (l2 tunnelling) requirements. In L2 VPN the MPLS header should encapsulate the ethernet packet. The new mpls action ADD_MPLS inserts MPLS header at the start of the packet or at the start of the l3 header depending on the value of l3 tunnel flag in the ADD_MPLS arguments. POP_MPLS action is extended to support ethertype 0x6558. Signed-off-by: Martin Varghese Acked-by: Pravin B Shelar Signed-off-by: David S. Miller Signed-off-by: Martin Varghese --- datapath/actions.c | 42 ++++++++++++++++++----- datapath/flow_netlink.c | 33 ++++++++++++++++++ datapath/linux/compat/include/linux/openvswitch.h | 35 +++++++++++++++++-- 3 files changed, 98 insertions(+), 12 deletions(-) diff --git a/datapath/actions.c b/datapath/actions.c index fbf4457..65266e4 100644 --- a/datapath/actions.c +++ b/datapath/actions.c @@ -185,7 +185,7 @@ static void update_ethertype(struct sk_buff *skb, struct ethhdr *hdr, } static int push_mpls(struct sk_buff *skb, struct sw_flow_key *key, - const struct ovs_action_push_mpls *mpls) + __be32 mpls_lse, __be16 mpls_ethertype, __u16 mac_len) { struct mpls_shim_hdr *new_mpls_lse; @@ -197,26 +197,30 @@ static int push_mpls(struct sk_buff *skb, struct sw_flow_key *key, return -ENOMEM; if (!ovs_skb_get_inner_protocol(skb)) { - skb_set_inner_network_header(skb, skb->mac_len); + skb_set_inner_network_header(skb, skb_network_offset(skb)); ovs_skb_set_inner_protocol(skb, skb->protocol); } skb_push(skb, MPLS_HLEN); memmove(skb_mac_header(skb) - MPLS_HLEN, skb_mac_header(skb), - skb->mac_len); + mac_len); skb_reset_mac_header(skb); #ifdef MPLS_HEADER_IS_L3 - skb_set_network_header(skb, skb->mac_len); + skb_set_network_header(skb, mac_len); #endif + skb_reset_mac_len(skb); new_mpls_lse = mpls_hdr(skb); - new_mpls_lse->label_stack_entry = mpls->mpls_lse; + new_mpls_lse->label_stack_entry = mpls_lse; skb_postpush_rcsum(skb, new_mpls_lse, MPLS_HLEN); + if (!mac_len) + key->mac_proto = MAC_PROTO_NONE; + if (ovs_key_mac_proto(key) == MAC_PROTO_ETHERNET) - update_ethertype(skb, eth_hdr(skb), mpls->mpls_ethertype); - skb->protocol = mpls->mpls_ethertype; + update_ethertype(skb, eth_hdr(skb), mpls_ethertype); + skb->protocol = mpls_ethertype; invalidate_flow_key(key); return 0; @@ -252,6 +256,9 @@ static int pop_mpls(struct sk_buff *skb, struct sw_flow_key *key, if (eth_p_mpls(skb->protocol)) skb->protocol = ethertype; + if (ethertype == htons(ETH_P_TEB)) + key->mac_proto = MAC_PROTO_ETHERNET; + invalidate_flow_key(key); return 0; } @@ -1309,9 +1316,26 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, execute_hash(skb, key, a); break; - case OVS_ACTION_ATTR_PUSH_MPLS: - err = push_mpls(skb, key, nla_data(a)); + case OVS_ACTION_ATTR_PUSH_MPLS: { + struct ovs_action_push_mpls *mpls = nla_data(a); + + err = push_mpls(skb, key, mpls->mpls_lse, + mpls->mpls_ethertype, skb->mac_len); break; + } + + case OVS_ACTION_ATTR_ADD_MPLS: { + struct ovs_action_add_mpls *mpls = nla_data(a); + __u16 mac_len = 0; + + if (mpls->tun_flags & OVS_MPLS_L3_TUNNEL_FLAG_MASK) + mac_len = skb->mac_len; + + err = push_mpls(skb, key, mpls->mpls_lse, + mpls->mpls_ethertype, mac_len); + break; + } + case OVS_ACTION_ATTR_POP_MPLS: err = pop_mpls(skb, key, nla_get_be16(a)); diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c index d3fd771..3d54d4d 100644 --- a/datapath/flow_netlink.c +++ b/datapath/flow_netlink.c @@ -94,6 +94,7 @@ static bool actions_may_change_flow(const struct nlattr *actions) case OVS_ACTION_ATTR_SET_MASKED: case OVS_ACTION_ATTR_METER: case OVS_ACTION_ATTR_CHECK_PKT_LEN: + case OVS_ACTION_ATTR_ADD_MPLS: default: return true; } @@ -3002,6 +3003,7 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, [OVS_ACTION_ATTR_METER] = sizeof(u32), [OVS_ACTION_ATTR_CLONE] = (u32)-1, [OVS_ACTION_ATTR_CHECK_PKT_LEN] = (u32)-1, + [OVS_ACTION_ATTR_ADD_MPLS] = sizeof(struct ovs_action_add_mpls), }; const struct ovs_action_push_vlan *vlan; int type = nla_type(a); @@ -3069,6 +3071,33 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, case OVS_ACTION_ATTR_RECIRC: break; + case OVS_ACTION_ATTR_ADD_MPLS: { + const struct ovs_action_add_mpls *mpls = nla_data(a); + + if (!eth_p_mpls(mpls->mpls_ethertype)) + return -EINVAL; + + if (mpls->tun_flags & OVS_MPLS_L3_TUNNEL_FLAG_MASK) { + if (vlan_tci & htons(VLAN_CFI_MASK) || + (eth_type != htons(ETH_P_IP) && + eth_type != htons(ETH_P_IPV6) && + eth_type != htons(ETH_P_ARP) && + eth_type != htons(ETH_P_RARP) && + !eth_p_mpls(eth_type))) + return -EINVAL; + mpls_label_count++; + } else { + if (mac_proto == MAC_PROTO_ETHERNET) { + mpls_label_count = 1; + mac_proto = MAC_PROTO_NONE; + } else { + mpls_label_count++; + } + } + eth_type = mpls->mpls_ethertype; + break; + } + case OVS_ACTION_ATTR_PUSH_MPLS: { const struct ovs_action_push_mpls *mpls = nla_data(a); @@ -3108,6 +3137,10 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, proto = nla_get_be16(a); mpls_label_count--; + if (proto == htons(ETH_P_TEB) && + mac_proto != MAC_PROTO_NONE) + return -EINVAL; + if (!eth_p_mpls(proto) || !mpls_label_count) eth_type = htons(0); else diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h index f7c3b2e..d5723ea 100644 --- a/datapath/linux/compat/include/linux/openvswitch.h +++ b/datapath/linux/compat/include/linux/openvswitch.h @@ -798,8 +798,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 @@ -989,7 +1013,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 { @@ -1018,6 +1046,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*/ From patchwork Fri May 8 04:32:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Varghese X-Patchwork-Id: 1285776 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.137; helo=fraxinus.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=uG7NqJiL; dkim-atps=neutral Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 49JHVV2g5Dz9sRf for ; Fri, 8 May 2020 14:32:18 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id DD20A87A5F; Fri, 8 May 2020 04:32:16 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id B3aE-bZ69JSm; Fri, 8 May 2020 04:32:15 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by fraxinus.osuosl.org (Postfix) with ESMTP id 43AB287A09; Fri, 8 May 2020 04:32:15 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 27BE7C0865; Fri, 8 May 2020 04:32:15 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id F2C06C07FF for ; Fri, 8 May 2020 04:32:13 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id EEB1487A0F for ; Fri, 8 May 2020 04:32:13 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ZwrMTrogbc_Z for ; Fri, 8 May 2020 04:32:12 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mail-pf1-f182.google.com (mail-pf1-f182.google.com [209.85.210.182]) by fraxinus.osuosl.org (Postfix) with ESMTPS id 4B32C87A09 for ; Fri, 8 May 2020 04:32:12 +0000 (UTC) Received: by mail-pf1-f182.google.com with SMTP id x77so309880pfc.0 for ; Thu, 07 May 2020 21:32:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=3j/jQpZuayz6y+JlzhcA+5w2qzfrjyq3nAxlaaaz0dQ=; b=uG7NqJiLxHvWPf5aHQ9HPUeipMwKhMWnPgOK35XcWxSNJW+HL/FtNLwgZmVDdZR4+j 9MKmMhdRCiKFJD8cZ74h5nody5A+lcPzeku8ltwFIN4DWzXHeleVCxY8PzlbQVxTj4Yl keycY5cHVIGNNqgqg/UHdp3vTwQjAWTmUjD331B6ArGNdyIkZvjOrW/4ezu3W1mynJcc yqGpLt+9Pw9zF3SRXY4zTkaubof3OdYqVhoo0/O2cb9AlSTRvCucMK2cy3lS8YZ8Beyx OaTU7XpAMZjQyeJRX2aXXeg9YV2mzINYHOVwx0leMbgMVz6wP0IBPlBYA1OrOqp/LODP pOJA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=3j/jQpZuayz6y+JlzhcA+5w2qzfrjyq3nAxlaaaz0dQ=; b=bdK37/HfhydVdZ2XB5uhYhy+hPRKT2LX0P2vhgKJ1fs6zJIze7dXqEmAImifUVz+Kd aBJvRZCIZZuy8qArjU9oCOAhFB9yxgjKx8d+E8d/h14pLhtTsYNYn7TK6JHqbv8QR14X prL4HfchBEi0MZxTHS2g13s5t99+OCF9RvpDDnF4E+k56wkEw0FU2LejkZn0lyxRfJ6M 9PB2Nvxo2V44/065aaq5tEvwT9PYXeW5xrzqmGyqW2TfENj/YeDYfMJgySRm9GopTcnO ec60VbHWV3w8ZqIwOGQn8MNKPtNh+u0qsluF+vS26G53evyJuZC+0AAgj1KitbGKD/Kl EYug== X-Gm-Message-State: AGi0PubzFJYnf2DNKlTeaRv+OQjIugyuVT+M6k4D3BHT0XSstIjrMghn ntOKSV/uyj7aC5v2VLMfR1AMHiWB X-Google-Smtp-Source: APiQypLs2TBDvheVe5WSXWXwBwAr9Pi+IbZETYPf7LEdcOUS6PdNG297gwt1cIKcT4IXhKBMGY5rqw== X-Received: by 2002:a63:e60a:: with SMTP id g10mr554145pgh.51.1588912330845; Thu, 07 May 2020 21:32:10 -0700 (PDT) Received: from martin-VirtualBox.apac.nsn-net.net ([117.202.93.227]) by smtp.gmail.com with ESMTPSA id y8sm381448pfg.216.2020.05.07.21.32.08 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Thu, 07 May 2020 21:32:10 -0700 (PDT) From: Martin Varghese To: dev@openvswitch.org, pshelar@ovn.org Date: Fri, 8 May 2020 10:02:04 +0530 Message-Id: X-Mailer: git-send-email 1.9.1 In-Reply-To: References: Cc: Martin Varghese Subject: [ovs-dev] [PATCH v3 2/2] Encap & Decap actions for MPLS packet type X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Martin Varghese The encap & decap actions are extended to support MPLS packet type. Encap & decap actions adds and removes MPLS header at start of the packet. Signed-off-by: Martin Varghese --- NEWS | 1 + 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 | 38 +++++++++++++--- lib/ofp-actions.c | 5 +++ lib/ofp-ed-props.c | 89 ++++++++++++++++++++++++++++++++++++++ lib/ovs-actions.xml | 32 +++++++++++--- 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 | 54 +++++++++++++++++++++++ tests/system-traffic.at | 34 +++++++++++++++ 15 files changed, 312 insertions(+), 13 deletions(-) diff --git a/NEWS b/NEWS index 3dbd8ec..60ed5fe 100644 --- a/NEWS +++ b/NEWS @@ -16,6 +16,7 @@ Post-v2.13.0 by enabling interrupt mode. - Userspace datapath: * Add support for conntrack zone-based timeout policy. + - Encap & Decap action support for MPLS packet type. v2.13.0 - 14 Feb 2020 diff --git a/include/openvswitch/ofp-ed-props.h b/include/openvswitch/ofp-ed-props.h index 306c6fe..9ddfaec 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 2 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 51c8885..39a38cc 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -7496,6 +7496,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 9d9c716..e94a966 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -1268,6 +1268,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 42d3335..de13301 100644 --- a/lib/odp-execute.c +++ b/lib/odp-execute.c @@ -817,6 +817,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; @@ -1059,6 +1060,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 b66d266..3cf4e0b 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -141,6 +141,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_push_mpls); case OVS_ACTION_ATTR_DROP: return sizeof(uint32_t); case OVS_ACTION_ATTR_UNSPEC: @@ -1249,6 +1251,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; @@ -7807,7 +7817,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); @@ -7844,7 +7855,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)); @@ -7855,13 +7870,16 @@ 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; + struct ovs_action_add_mpls *mpls; mpls = nl_msg_put_unspec_zero(odp_actions, - OVS_ACTION_ATTR_PUSH_MPLS, + OVS_ACTION_ATTR_ADD_MPLS, sizeof *mpls); mpls->mpls_ethertype = flow->dl_type; mpls->mpls_lse = flow->mpls_lse[flow_n - base_n - 1]; + if (!pending_encap) { + mpls->tun_flags |= OVS_MPLS_L3_TUNNEL_FLAG_MASK; + } /* 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. */ @@ -8506,6 +8524,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. */ @@ -8528,6 +8550,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(); @@ -8573,7 +8599,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); @@ -8581,7 +8607,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 be08a53..2a02fe2 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -4440,6 +4440,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: @@ -4490,6 +4491,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; } @@ -4571,6 +4574,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 28382e0..6338e7c 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; } @@ -133,6 +154,27 @@ encode_ed_prop(const struct ofpact_ed_prop **prop, } break; } + case OFPPPC_MPLS: { + switch ((*prop)->type) { + case OFPPPT_PROP_MPLS_ETHERTYPE: { + struct ofp_ed_prop_mpls_ethertype *pnmt = + ALIGNED_CAST(struct ofp_ed_prop_mpls_ethertype *, *prop); + struct ofpact_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; } @@ -180,6 +222,11 @@ 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; + } default: return false; } @@ -258,6 +305,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(); @@ -299,6 +368,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(); } @@ -331,6 +408,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 060a079..8f3a730 100644 --- a/lib/ovs-actions.xml +++ b/lib/ovs-actions.xml @@ -265,13 +265,14 @@

- When a decap action decapsulates a packet, Open vSwitch - raises this error if it does not support the type of inner packet. - decap of an Ethernet header raises this error if a VLAN - header is present, decap of a NSH packet raises this error - if the NSH inner packet is not Ethernet, IPv4, IPv6, or NSH, and - decap of other types of packets is unsupported and also - raises this error. + The decap action is supported only for packet types + ethernet, NSH and MPLS. decap of other types of packets is + unsupported and also raises this error. When a decap + action decapsulates a packet, Open vSwitch raises this error if it + does not support the type of inner packet. decap of an + Ethernet header raises this error if a VLAN header is present, + decap of a NSH packet raises this error if the NSH inner + packet is not Ethernet, IPv4, IPv6, or NSH.

@@ -1096,6 +1097,8 @@ for i in [1,n_slaves]:

The encap action

encap(nsh([md_type=md_type], [tlv(class,type,value)]...)) encap(ethernet) + encap(mpls(ether_type=ether_type)) +

The encap action encapsulates a packet with a specified @@ -1134,6 +1137,12 @@ for i in [1,n_slaves]: source and destination are initially zeroed.

+

+ The encap(mpls(ethertype=....)) variant encapsulates an + ethernet or L3 packet with a MPLS header. The ethertype + could be MPLS unicast (0x8847) or multicast (0x8848) ethertypes. +

+ This action is an Open vSwitch extension to OpenFlow 1.3 and later, introduced in Open vSwitch 2.8. @@ -1143,6 +1152,9 @@ for i in [1,n_slaves]:

The decap action

decap + decap(packet_type(ns=name_space, + type=ethertype)) for decapsulating MPLS + packets.

Removes an outermost encapsulation from the packet: @@ -1164,6 +1176,12 @@ for i in [1,n_slaves]:

  • + 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. +
  • + +
  • Otherwise, raises an unsupported packet type error.
  • diff --git a/lib/packets.c b/lib/packets.c index 9d7cc50..cb2f204 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -395,6 +395,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 @@ -406,6 +438,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 447e6f6..b6aad04 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -358,6 +358,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 b413768..d530537 100644 --- a/ofproto/ofproto-dpif-ipfix.c +++ b/ofproto/ofproto-dpif-ipfix.c @@ -3017,6 +3017,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 f9ea47a..f04dbaa 100644 --- a/ofproto/ofproto-dpif-sflow.c +++ b/ofproto/ofproto-dpif-sflow.c @@ -1225,6 +1225,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 80fba84..d3e89d9 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -6368,6 +6368,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 @@ -6500,6 +6539,9 @@ 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); + break; default: /* New packet type was checked during decoding. */ OVS_NOT_REACHED(); @@ -6569,6 +6611,18 @@ 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); + ctx->pending_decap = true; + return true; + } default: /* Error handling: drop packet. */ xlate_report_debug( diff --git a/tests/system-traffic.at b/tests/system-traffic.at index 2a0fbad..a3b3aef 100644 --- a/tests/system-traffic.at +++ b/tests/system-traffic.at @@ -1034,6 +1034,40 @@ AT_CHECK([ovs-ofctl 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 ]) +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