@@ -6704,7 +6704,8 @@ odp_put_decap_nsh_action(struct ofpbuf *odp_actions)
static void
odp_put_encap_nsh_action(struct ofpbuf *odp_actions,
- const struct flow *flow)
+ const struct flow *flow,
+ struct ofpbuf *encap_data)
{
struct ovs_action_encap_nsh encap_nsh;
@@ -6724,8 +6725,13 @@ odp_put_encap_nsh_action(struct ofpbuf *odp_actions,
break;
}
case NSH_M_TYPE2:
- /* TODO */
- encap_nsh.mdlen = 0;
+ if (encap_data) {
+ ovs_assert(encap_data->size < OVS_ENCAP_NSH_MAX_MD_LEN);
+ encap_nsh.mdlen = encap_data->size;
+ memcpy(encap_nsh.metadata, encap_data->data, encap_data->size);
+ } else {
+ encap_nsh.mdlen = 0;
+ }
break;
default:
encap_nsh.mdlen = 0;
@@ -6740,7 +6746,8 @@ commit_packet_type_change(const struct flow *flow,
struct flow *base_flow,
struct ofpbuf *odp_actions,
struct flow_wildcards *wc,
- bool pending_encap)
+ bool pending_encap,
+ struct ofpbuf *encap_data)
{
if (flow->packet_type == base_flow->packet_type) {
return;
@@ -6759,7 +6766,7 @@ commit_packet_type_change(const struct flow *flow,
}
case PT_NSH:
/* encap_nsh */
- odp_put_encap_nsh_action(odp_actions, flow);
+ odp_put_encap_nsh_action(odp_actions, flow, encap_data);
base_flow->packet_type = flow->packet_type;
memcpy(&base_flow->nsh, &flow->nsh, sizeof base_flow->nsh);
/* TODO: Do we need to copy all the other fields too? */
@@ -6808,12 +6815,14 @@ commit_packet_type_change(const struct flow *flow,
enum slow_path_reason
commit_odp_actions(const struct flow *flow, struct flow *base,
struct ofpbuf *odp_actions, struct flow_wildcards *wc,
- bool use_masked, bool pending_encap)
+ bool use_masked, bool pending_encap,
+ struct ofpbuf *encap_data)
{
enum slow_path_reason slow1, slow2;
bool mpls_done = false;
- commit_packet_type_change(flow, base, odp_actions, wc, pending_encap);
+ commit_packet_type_change(flow, base, odp_actions, wc,
+ pending_encap, encap_data);
commit_set_ether_action(flow, base, odp_actions, wc, use_masked);
/* Make packet a non-MPLS packet before committing L3/4 actions,
* which would otherwise do nothing. */
@@ -275,7 +275,8 @@ enum slow_path_reason commit_odp_actions(const struct flow *,
struct ofpbuf *odp_actions,
struct flow_wildcards *wc,
bool use_masked,
- bool pending_encap);
+ bool pending_encap,
+ struct ofpbuf *encap_data);
^L
/* ofproto-dpif interface.
*
@@ -433,11 +433,14 @@ encap_nsh(struct dp_packet *packet, const struct ovs_action_encap_nsh *encap)
nsh->md_type = encap->mdtype;
switch (nsh->md_type) {
case NSH_M_TYPE1:
- nsh->md1 = *(struct nsh_md1_ctx *) encap->metadata;
+ nsh->md1 = *ALIGNED_CAST(struct nsh_md1_ctx *, encap->metadata);
break;
- case NSH_M_TYPE2:
- /* TODO */
+ case NSH_M_TYPE2: {
+ /* The MD2 metadata in encap is already padded to 4 bytes. */
+ size_t len = ROUND_UP(encap->mdlen, 4);
+ memcpy(nsh->md2, encap->metadata, len);
break;
+ }
default:
OVS_NOT_REACHED();
}
@@ -235,8 +235,10 @@ 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. */
+ bool pending_encap; /* True when waiting to commit a pending
+ * encap action. */
+ struct ofpbuf *encap_data; /* May contain a pointer to an ofpbuf with
+ * context for the datapath encap action.*/
uint8_t table_id; /* OpenFlow table ID where flow was found. */
ovs_be64 rule_cookie; /* Cookie of the rule being translated. */
@@ -3236,8 +3238,11 @@ 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, ctx->pending_encap);
+ use_masked, ctx->pending_encap,
+ ctx->encap_data);
ctx->pending_encap = false;
+ ofpbuf_delete(ctx->encap_data);
+ ctx->encap_data = NULL;
}
static void
@@ -5467,22 +5472,25 @@ rewrite_flow_encap_ethernet(struct xlate_ctx *ctx,
}
}
-static void
+/* 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 encap_nsh
+ * action at the next commit. */
+static struct ofpbuf *
rewrite_flow_encap_nsh(struct xlate_ctx *ctx,
const struct ofpact_encap *encap,
struct flow *flow,
struct flow_wildcards *wc)
{
ovs_be32 packet_type = flow->packet_type;
- const uint8_t *ptr = (uint8_t *) encap->props;
- size_t len, padding;
+ const char *ptr = (char *) encap->props;
+ struct ofpbuf *buf = ofpbuf_new(256);
uint8_t md_type = 1;
uint8_t np = 0;
- uint8_t buf[512], *p = buf;
int i;
- /* Parse the optional NSH encap TLV properties, if any. */
- for (i=0; i<encap->n_props; i++) {
+ /* Scan the optional NSH encap TLV properties, if any. */
+ for (i = 0; i < encap->n_props; i++) {
struct ofpact_ed_prop *prop_ptr = (struct ofpact_ed_prop *) ptr;
if (prop_ptr->prop_class == OFPPPC_NSH) {
switch (prop_ptr->type) {
@@ -5493,20 +5501,17 @@ rewrite_flow_encap_nsh(struct xlate_ctx *ctx,
break;
}
case OFPPPT_PROP_NSH_TLV: {
- struct nsh_md2_tlv *md2_ctx = (struct nsh_md2_tlv *) p;
struct ofpact_ed_prop_nsh_tlv *tlv_prop =
(struct ofpact_ed_prop_nsh_tlv *) prop_ptr;
+ struct nsh_md2_tlv *md2_ctx =
+ ofpbuf_put_uninit(buf, sizeof(*md2_ctx));
md2_ctx->md_class = tlv_prop->tlv_class;
md2_ctx->type = tlv_prop->tlv_type;
md2_ctx->length = tlv_prop->tlv_len;
- len = ROUND_UP(md2_ctx->length, 4);
- padding = len - md2_ctx->length;
- if (p + len < buf + 512) {
- memcpy(md2_ctx->md_value, tlv_prop->data, md2_ctx->length);
- p += md2_ctx->length;
- memset(p, 0, padding);
- p += padding;
- }
+ size_t len = ROUND_UP(md2_ctx->length, 4);
+ size_t padding = len - md2_ctx->length;
+ ofpbuf_put(buf, tlv_prop->data, md2_ctx->length);
+ ofpbuf_put_zeros(buf, padding);
break;
}
default:
@@ -5516,6 +5521,10 @@ rewrite_flow_encap_nsh(struct xlate_ctx *ctx,
}
ptr += ROUND_UP(prop_ptr->len, 8);
}
+ if (buf->size == 0 || buf->size >= OVS_ENCAP_NSH_MAX_MD_LEN) {
+ ofpbuf_delete(buf);
+ buf = NULL;
+ }
/* Determine the Next Protocol field for NSH header. */
switch (ntohl(packet_type)) {
@@ -5538,7 +5547,7 @@ rewrite_flow_encap_nsh(struct xlate_ctx *ctx,
"supported for packet type (%d,0x%x)",
pt_ns(packet_type), pt_ns_type(packet_type));
ctx->error = 1;
- return;
+ return buf;
}
/* Note that we have matched on packet_type! */
wc->masks.packet_type = OVS_BE32_MAX;
@@ -5560,10 +5569,16 @@ rewrite_flow_encap_nsh(struct xlate_ctx *ctx,
flow->nsh.c2 = 0;
flow->nsh.c3 = 0;
flow->nsh.c4 = 0;
+ if (buf) {
+ /* Drop any MD2 context TLVs. */
+ ofpbuf_delete(buf);
+ buf = NULL;
+ }
} else if (md_type == NSH_M_TYPE2) {
- flow->nsh.mdtype = NSH_M_TYPE1;
- /* TODO: Deal with TLV context headers stored in buf[512]. */
+ flow->nsh.mdtype = NSH_M_TYPE2;
}
+
+ return buf;
}
static void
@@ -5572,6 +5587,7 @@ xlate_generic_encap_action(struct xlate_ctx *ctx,
{
struct flow *flow = &ctx->xin->flow;
struct flow_wildcards *wc = ctx->wc;
+ struct ofpbuf *encap_data = NULL;
/* Ensure that any pending actions on the inner packet are applied before
* rewriting the flow */
@@ -5583,7 +5599,7 @@ xlate_generic_encap_action(struct xlate_ctx *ctx,
rewrite_flow_encap_ethernet(ctx, flow, wc);
break;
case PT_NSH:
- rewrite_flow_encap_nsh(ctx, encap, flow, wc);
+ encap_data = rewrite_flow_encap_nsh(ctx, encap, flow, wc);
break;
default:
/* New packet type was checked during decoding. */
@@ -5594,6 +5610,7 @@ xlate_generic_encap_action(struct xlate_ctx *ctx,
if (!ctx->error) {
/* The actual encap datapath action will be generated at next commit. */
ctx->pending_encap = true;
+ ctx->encap_data = encap_data;
}
}
@@ -6495,6 +6512,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
.in_action_set = false,
.in_packet_out = xin->in_packet_out,
.pending_encap = false,
+ .encap_data = NULL,
.table_id = 0,
.rule_cookie = OVS_BE64_MAX,
@@ -6841,6 +6859,7 @@ exit:
ofpbuf_uninit(&ctx.action_set);
ofpbuf_uninit(&ctx.frozen_actions);
ofpbuf_uninit(&scratch_actions);
+ ofpbuf_delete(ctx.encap_data);
/* Make sure we return a "drop flow" in case of an error. */
if (ctx.error) {