diff options
author | Martin Varghese <martin.varghese@nokia.com> | 2021-11-29 11:52:05 +0530 |
---|---|---|
committer | Ilya Maximets <i.maximets@ovn.org> | 2022-01-17 02:04:20 +0100 |
commit | 1917ace89364d366777b34467e952358d2d85b41 (patch) | |
tree | 109d821fbb510ed2df3cf8358d496af8d2830364 /ofproto | |
parent | 4a6a4734622e42367faf39cd3938bc8a57786282 (diff) | |
download | openvswitch-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.c | 1 | ||||
-rw-r--r-- | ofproto/ofproto-dpif-sflow.c | 1 | ||||
-rw-r--r-- | ofproto/ofproto-dpif-xlate.c | 85 | ||||
-rw-r--r-- | ofproto/ofproto-dpif.c | 39 | ||||
-rw-r--r-- | ofproto/ofproto-dpif.h | 5 |
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. */ |