summaryrefslogtreecommitdiff
path: root/ofproto
diff options
context:
space:
mode:
authorJan Scheurich <jan.scheurich@ericsson.com>2017-08-02 16:04:12 +0800
committerBen Pfaff <blp@ovn.org>2017-08-02 11:17:22 -0700
commitf839892a206abd7adbc0845f772b9f3c58945af5 (patch)
tree73a81773461a93e1c0495952eb54bed21fddd4e4 /ofproto
parent46a54ce7114f2caf9367dbc142d37c813adf9db6 (diff)
downloadopenvswitch-f839892a206abd7adbc0845f772b9f3c58945af5.tar.gz
OF support and translation of generic encap and decap
This commit adds support for the OpenFlow actions generic encap and decap (as specified in ONF EXT-382) to the OVS control plane. CLI syntax for encap action with properties: encap(<header>) encap(<header>(<prop>=<value>,<tlv>(<class>,<type>,<value>),...)) For example: encap(ethernet) encap(nsh(md_type=1)) encap(nsh(md_type=2,tlv(0x1000,10,0x12345678),tlv(0x2000,20,0xfedcba9876543210))) CLI syntax for decap action: decap() decap(packet_type(ns=<pt_ns>,type=<pt_type>)) For example: decap() decap(packet_type(ns=0,type=0xfffe)) decap(packet_type(ns=1,type=0x894f)) The first header supported for encap and decap is "ethernet" to convert packets between packet_type (1,Ethertype) and (0,0). This commit also implements a skeleton for the translation of generic encap and decap actions in ofproto-dpif and adds support to encap and decap an Ethernet header. In general translation of encap commits pending actions and then rewrites struct flow in accordance with the new packet type and header. In the case of encap(ethernet) it suffices to change the packet type from (1, Ethertype) to (0,0) and set the dl_type accordingly. A new pending_encap flag in xlate ctx is set to mark that an corresponding datapath encap action must be triggered at the next commit. In the case of encap(ethernet) ofproto generetas a push_eth action. The general case for translation of decap() is to emit a datapath action to decap the current outermost header and then recirculate the packet to reparse the inner headers. In the special case of an Ethernet packet, decap() just changes the packet type from (0,0) to (1, dl_type) without a need to recirculate. The emission of the pop_eth action for the datapath is postponed to the next commit. Hence encap(ethernet) and decap() on an Ethernet packet are OF octions that only incur a cost in the dataplane when a modifed packet is actually committed, e.g. because it is sent out. They can freely be used for normalizing the packet type in the OF pipeline without degrading performance. Signed-off-by: Jan Scheurich <jan.scheurich@ericsson.com> Signed-off-by: Yi Yang <yi.y.yang@intel.com> Signed-off-by: Zoltan Balogh <zoltan.balogh@ericsson.com> Co-authored-by: Zoltan Balogh <zoltan.balogh@ericsson.com> Signed-off-by: Ben Pfaff <blp@ovn.org>
Diffstat (limited to 'ofproto')
-rw-r--r--ofproto/ofproto-dpif-xlate.c116
1 files changed, 114 insertions, 2 deletions
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index c10379367..a2f5dc7df 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -234,6 +234,8 @@ struct xlate_ctx {
bool in_action_set; /* Currently translating action_set, if true. */
bool in_packet_out; /* Currently translating a packet_out msg, if
* true. */
+ bool pending_encap; /* Waiting to commit a pending encap
+ * action, if true. */
uint8_t table_id; /* OpenFlow table ID where flow was found. */
ovs_be64 rule_cookie; /* Cookie of the rule being translated. */
@@ -3465,7 +3467,8 @@ xlate_commit_actions(struct xlate_ctx *ctx)
ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
ctx->odp_actions, ctx->wc,
- use_masked);
+ use_masked, ctx->pending_encap);
+ ctx->pending_encap = false;
}
static void
@@ -5503,6 +5506,8 @@ freeze_unroll_actions(const struct ofpact *a, const struct ofpact *end,
case OFPACT_METER:
case OFPACT_SAMPLE:
case OFPACT_CLONE:
+ case OFPACT_ENCAP:
+ case OFPACT_DECAP:
case OFPACT_DEBUG_RECIRC:
case OFPACT_CT:
case OFPACT_CT_CLEAR:
@@ -5692,6 +5697,93 @@ compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc)
}
static void
+rewrite_flow_encap_ethernet(struct xlate_ctx *ctx,
+ struct flow *flow,
+ struct flow_wildcards *wc)
+{
+ wc->masks.packet_type = OVS_BE32_MAX;
+ if (pt_ns(flow->packet_type) == OFPHTN_ETHERTYPE) {
+ /* Only adjust the packet_type and zero the dummy Ethernet addresses. */
+ ovs_be16 ethertype = pt_ns_type_be(flow->packet_type);
+ flow->packet_type = htonl(PT_ETH);
+ flow->dl_src = eth_addr_zero;
+ flow->dl_dst = eth_addr_zero;
+ flow->dl_type = ethertype;
+ } else {
+ xlate_report_debug(ctx, OFT_ACTION,
+ "encap(ethernet) unsupported for packet type "
+ "ethernet");
+ /* TODO: Error handling: drop packet. */
+ ctx->error = 1;
+ }
+}
+
+static void
+xlate_generic_encap_action(struct xlate_ctx *ctx,
+ const struct ofpact_encap *encap)
+{
+ struct flow *flow = &ctx->xin->flow;
+ struct flow_wildcards *wc = ctx->wc;
+
+ /* Ensure that any pending actions on the inner packet are applied before
+ * rewriting the flow */
+ xlate_commit_actions(ctx);
+
+ /* Rewrite the flow to reflect the effect of pushing the new encap header. */
+ switch (ntohl(encap->new_pkt_type)) {
+ case PT_ETH:
+ rewrite_flow_encap_ethernet(ctx, flow, wc);
+ break;
+ default:
+ /* TODO: Error handling: Should not happen if the PT is checked
+ * at decoding */
+ break;
+ }
+
+ if (!ctx->error) {
+ /* The actual encap datapath action will be generated at next commit. */
+ ctx->pending_encap = true;
+ }
+}
+
+/* Returns true if packet must be recirculated after decapsulation. */
+static bool
+xlate_generic_decap_action(struct xlate_ctx *ctx,
+ const struct ofpact_decap *decap OVS_UNUSED)
+{
+ struct flow *flow = &ctx->xin->flow;
+
+ /* Ensure that any pending actions on the current packet are applied
+ * before generating the decap action. */
+ xlate_commit_actions(ctx);
+
+ /* We assume for now that the new_pkt_type is PT_USE_NEXT_PROTO. */
+ switch (ntohl(flow->packet_type)) {
+ case PT_ETH:
+ if (flow->vlans[0].tci & htons(VLAN_CFI)) {
+ /* Error handling: drop packet. */
+ xlate_report_debug(ctx, OFT_ACTION, "Dropping packet, cannot "
+ "decap Ethernet if VLAN is present.");
+ ctx->error = 1;
+ } else {
+ /* Just change the packet_type.
+ * Delay generating pop_eth to the next commit. */
+ flow->packet_type = htonl(PACKET_TYPE(OFPHTN_ETHERTYPE,
+ ntohs(flow->dl_type)));
+ ctx->wc->masks.dl_type = OVS_BE16_MAX;
+ }
+ return false;
+ default:
+ xlate_report_debug(ctx, OFT_ACTION,
+ "decap() for unsupported packet type %x",
+ ntohl(flow->packet_type));
+ /* TODO: Error handling: drop packet. */
+ ctx->error = 1;
+ return false;
+ }
+}
+
+static void
recirc_for_mpls(const struct ofpact *a, struct xlate_ctx *ctx)
{
/* No need to recirculate if already exiting. */
@@ -5765,6 +5857,8 @@ recirc_for_mpls(const struct ofpact *a, struct xlate_ctx *ctx)
case OFPACT_EXIT:
case OFPACT_SAMPLE:
case OFPACT_CLONE:
+ case OFPACT_ENCAP:
+ case OFPACT_DECAP:
case OFPACT_UNROLL_XLATE:
case OFPACT_CT:
case OFPACT_CT_CLEAR:
@@ -6181,6 +6275,22 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
xlate_clone(ctx, ofpact_get_CLONE(a));
break;
+ case OFPACT_ENCAP:
+ xlate_generic_encap_action(ctx, ofpact_get_ENCAP(a));
+ break;
+
+ case OFPACT_DECAP: {
+ bool recirc_needed =
+ xlate_generic_decap_action(ctx, ofpact_get_DECAP(a));
+ if (!ctx->error && recirc_needed) {
+ /* Recirculate for parsing of inner packet. */
+ ctx_trigger_freeze(ctx);
+ /* Then continue with next action. */
+ a = ofpact_next(a);
+ }
+ break;
+ }
+
case OFPACT_CT:
compose_conntrack_action(ctx, ofpact_get_CT(a));
break;
@@ -6423,7 +6533,7 @@ xlate_wc_finish(struct xlate_ctx *ctx)
* use non-header fields as part of the cache. */
flow_wildcards_clear_non_packet_fields(ctx->wc);
- /* Wildcard ethernet addresses if the original packet type was not
+ /* Wildcard ethernet fields if the original packet type was not
* Ethernet. */
if (ctx->xin->upcall_flow->packet_type != htonl(PT_ETH)) {
ctx->wc->masks.dl_dst = eth_addr_zero;
@@ -6512,6 +6622,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
.in_group = false,
.in_action_set = false,
.in_packet_out = xin->in_packet_out,
+ .pending_encap = false,
.table_id = 0,
.rule_cookie = OVS_BE64_MAX,
@@ -6672,6 +6783,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
flow->packet_type = htonl(PT_ETH);
flow->dl_src = eth_addr_zero;
flow->dl_dst = eth_addr_zero;
+ ctx.pending_encap = true;
}
if (!xin->ofpacts && !ctx.rule) {