diff mbox

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

Message ID 79BBBFE6CB6C9B488C1A45ACD284F51961BFF7B4@SHSMSX103.ccr.corp.intel.com
State Not Applicable
Headers show

Commit Message

Yang, Yi July 18, 2017, 6:03 a.m. UTC
Thanks Jan, I have folded it to my local branch and will include it in next version.

-----Original Message-----
From: Jan Scheurich [mailto:jan.scheurich@ericsson.com] 
Sent: Tuesday, July 18, 2017 12:34 AM
To: Yang, Yi Y <yi.y.yang@intel.com>; dev@openvswitch.org
Subject: RE: [PATCH 5/6] Generic encap and decap support for NSH

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.

                     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) {
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,