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