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