summaryrefslogtreecommitdiff
path: root/ofproto
diff options
context:
space:
mode:
authorMartin Varghese <martin.varghese@nokia.com>2021-11-29 11:52:05 +0530
committerIlya Maximets <i.maximets@ovn.org>2022-01-17 02:04:20 +0100
commit1917ace89364d366777b34467e952358d2d85b41 (patch)
tree109d821fbb510ed2df3cf8358d496af8d2830364 /ofproto
parent4a6a4734622e42367faf39cd3938bc8a57786282 (diff)
downloadopenvswitch-1917ace89364d366777b34467e952358d2d85b41.tar.gz
Encap & Decap actions for MPLS packet type.
The encap & decap actions are extended to support MPLS packet type. Encap & decap actions adds and removes MPLS header at start of the packet. The existing PUSH MPLS & POP MPLS actions inserts & removes 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 requirements. In L2 VPN the ethernet packets must be encapsulated inside MPLS tunnel. In this change the encap & decap actions are extended to support MPLS packet type. The encap & decap adds and removes MPLS header at the start of packet as depicted below. Encapsulation: Actions - encap(mpls),encap(ethernet) Incoming packet -> | ETH | IP | Payload | 1 Actions - encap(mpls) [Datapath action - ADD_MPLS:0x8847] Outgoing packet -> | MPLS | ETH | Payload| 2 Actions - encap(ethernet) [ Datapath action - push_eth ] Outgoing packet -> | ETH | MPLS | ETH | Payload| Decapsulation: Incoming packet -> | ETH | MPLS | ETH | IP | Payload | Actions - decap(),decap(packet_type(ns=0,type=0)) 1 Actions - decap() [Datapath action - pop_eth) Outgoing packet -> | MPLS | ETH | IP | Payload| 2 Actions - decap(packet_type(ns=0,type=0)) [Datapath action - POP_MPLS:0x6558] Outgoing packet -> | ETH | IP | Payload| Signed-off-by: Martin Varghese <martin.varghese@nokia.com> Acked-by: Eelco Chaudron <echaudro@redhat.com> Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
Diffstat (limited to 'ofproto')
-rw-r--r--ofproto/ofproto-dpif-ipfix.c1
-rw-r--r--ofproto/ofproto-dpif-sflow.c1
-rw-r--r--ofproto/ofproto-dpif-xlate.c85
-rw-r--r--ofproto/ofproto-dpif.c39
-rw-r--r--ofproto/ofproto-dpif.h5
5 files changed, 130 insertions, 1 deletions
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 864c136b5..30e7caf54 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 cafcd014a..6fb59e170 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -6457,6 +6457,47 @@ rewrite_flow_encap_ethernet(struct xlate_ctx *ctx,
}
}
+static void
+rewrite_flow_encap_mpls(struct xlate_ctx *ctx,
+ const struct ofpact_encap *encap,
+ struct flow *flow,
+ struct flow_wildcards *wc)
+{
+ ovs_be16 ether_type = pt_ns_type_be(encap->new_pkt_type);
+ int n;
+
+ n = flow_count_mpls_labels(flow, ctx->wc);
+ if (n < FLOW_MAX_MPLS_LABELS) {
+ wc->masks.packet_type = OVS_BE32_MAX;
+
+ /* If the current packet is already a MPLS packet with ethernet header
+ * the existing MPLS states must be cleared before the encap MPLS action
+ * is applied. */
+ if (flow->packet_type == htonl(PT_ETH) &&
+ flow->dl_type == htons(ETH_TYPE_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);
+ memset(&ctx->base_flow.mpls_lse, 0x0,
+ sizeof *ctx->base_flow.mpls_lse * FLOW_MAX_MPLS_LABELS);
+ }
+ flow->packet_type = encap->new_pkt_type;
+ flow_push_mpls(flow, n, ether_type, ctx->wc, true);
+ flow->dl_src = eth_addr_zero;
+ flow->dl_dst = eth_addr_zero;
+ } else {
+ if (ctx->xin->packet != NULL) {
+ xlate_report_error(ctx, "dropping packet on which an encap MPLS "
+ "action can't be performed as it would have "
+ "more MPLS LSEs than the %d supported.",
+ FLOW_MAX_MPLS_LABELS);
+ }
+ ctx->error = XLATE_TOO_MANY_MPLS_LABELS;
+ return;
+ }
+}
+
/* 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
* will be stored as encap_data in the ctx and copied into the push_nsh
@@ -6588,6 +6629,13 @@ 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:
+ case PT_MPLS_MC:
+ 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();
@@ -6659,6 +6707,43 @@ 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);
+ if (!ethertype) {
+ ethertype = htons(ETH_TYPE_TEB);
+ }
+ if (flow_pop_mpls(flow, n, ethertype, ctx->wc)) {
+ if (!ctx->xbridge->support.add_mpls) {
+ ctx->xout->slow |= SLOW_ACTION;
+ }
+ ctx->pending_decap = true;
+ if (n == 1) {
+ /* Trigger recirculation. */
+ return true;
+ } else {
+ return false;
+ }
+ } else if (n >= FLOW_MAX_MPLS_LABELS) {
+ if (ctx->xin->packet != NULL) {
+ xlate_report_error(ctx, "dropping packet on which an "
+ "MPLS decap can't be performed as "
+ "it has more MPLS LSEs than the %d "
+ "supported.",
+ FLOW_MAX_MPLS_LABELS);
+ }
+ ctx->error = XLATE_TOO_MANY_MPLS_LABELS;
+ ofpbuf_clear(ctx->odp_actions);
+ return false;
+ } else {
+ return false;
+ }
+ }
default:
/* Error handling: drop packet. */
xlate_report_debug(
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index bc3df8ea1..c711b99c7 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -1539,6 +1539,43 @@ 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 \
check_##NAME(struct dpif_backer *backer) \
@@ -1609,6 +1646,7 @@ check_support(struct dpif_backer *backer)
backer->rt_support.lb_output_action =
dpif_supports_lb_output_action(backer->dpif);
backer->rt_support.ct_zero_snat = dpif_supports_ct_zero_snat(backer);
+ backer->rt_support.add_mpls = check_add_mpls(backer);
/* Flow fields. */
backer->rt_support.odp.ct_state = check_ct_state(backer);
@@ -5625,6 +5663,7 @@ get_datapath_cap(const char *datapath_type, struct smap *cap)
s.explicit_drop_action ? "true" :"false");
smap_add(cap, "lb_output_action", s.lb_output_action ? "true" : "false");
smap_add(cap, "ct_zero_snat", s.ct_zero_snat ? "true" : "false");
+ smap_add(cap, "add_mpls", s.add_mpls ? "true" : "false");
}
/* Gets timeout policy name in 'backer' based on 'zone', 'dl_type' and
diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h
index 191cfcb0d..d8e0cd37a 100644
--- a/ofproto/ofproto-dpif.h
+++ b/ofproto/ofproto-dpif.h
@@ -207,7 +207,10 @@ struct group_dpif *group_dpif_lookup(struct ofproto_dpif *,
DPIF_SUPPORT_FIELD(bool, lb_output_action, "Optimized Balance TCP mode")\
\
/* True if the datapath supports all-zero IP SNAT. */ \
- DPIF_SUPPORT_FIELD(bool, ct_zero_snat, "Conntrack all-zero IP SNAT")
+ DPIF_SUPPORT_FIELD(bool, ct_zero_snat, "Conntrack all-zero IP SNAT") \
+ \
+ /* True if the datapath supports add_mpls action. */ \
+ DPIF_SUPPORT_FIELD(bool, add_mpls, "MPLS Label add")
/* Stores the various features which the corresponding backer supports. */