diff mbox

[ovs-dev,5/6] Generic encap and decap support for NSH

Message ID CFF8EF42F1132E4CBE2BF0AB6C21C58D6FD2EF73@ESESSMB110.ericsson.se
State Not Applicable
Headers show

Commit Message

Jan Scheurich July 17, 2017, 4:34 p.m. UTC
Hi Yi,

The following incremental fills the gaps to support NSH TLV properties in encap(nsh) for MD2 format

BR, Jan

    Encap properties of type OFPPPT_PROP_NSH_TLV are mapped to structs
    nsh_md2_tlv during translation and concatenated in a new struct ofpbuf
    *encap_data in the translation ctx.

    At generation of the encap_nsh action, the sequence of MD2 TLVs is
    copied as byte array from *encap_data into the datapath action. In the
    datapath, encap_nsh copies the TLV metadata verbatim into the NSH MD2
    packet header.

    The decap_nsh action already skipped any metadata behind the basic NSH
    header based on the NSH header length attribute.

    Note: There is no support yet for parsing, matching and manipulating
    NSH MD2 TLVs as OXM fields. This will be added in a future contribution.
diff mbox

Patch

diff --git a/lib/odp-util.c b/lib/odp-util.c
index 57c6ec8..1d8e24b 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -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. */
diff --git a/lib/odp-util.h b/lib/odp-util.h
index ed16f96..ef55501 100644
--- a/lib/odp-util.h
+++ b/lib/odp-util.h
@@ -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.
  *
diff --git a/lib/packets.c b/lib/packets.c
index 45ddfee..ba4334a 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -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();
     }
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 9ebfd30..0ade20d 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -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) {