[ovs-dev] [RFC PATCH v2 07/13] Userspace: Parse NSH header in flow_extract

Johnson Li johnson.li at intel.com
Tue Jul 12 17:28:09 UTC 2016


Signed-off-by: Johnson Li <johnson.li at intel.com>

diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
index 52e33f6..896fa68 100644
--- a/datapath/linux/compat/include/linux/openvswitch.h
+++ b/datapath/linux/compat/include/linux/openvswitch.h
@@ -652,6 +652,17 @@ struct ovs_action_push_vlan {
 	__be16 vlan_tci;	/* 802.1Q TCI (VLAN ID and priority). */
 };
 
+/**
+ * struct ovs_action_push_nsh - %OVS_ACTION_ATTR_PUSH_NSH action argument.
+ * @len: length of NSH header. Differs since different metadata type.
+ * @header: RAW value for the NSH header.
+ */
+#define NSH_HEADER_LEN_MAX	256
+struct ovs_action_push_nsh {
+	uint16_t len;
+	uint8_t header[NSH_HEADER_LEN_MAX]; /* NSH header */
+};
+
 /* Data path hash algorithm for computing Datapath hash.
  *
  * The algorithm type only specifies the fields in a flow
@@ -807,6 +818,9 @@ enum ovs_nat_attr {
  * ovs_action_push_tnl.
  * @OVS_ACTION_ATTR_TUNNEL_POP: Lookup tunnel port by port-no passed and pop
  * tunnel header.
+ * @OVS_ACTION_ATTR_PUSH_NSH: Append a Network Service Header before
+ * original packet.
+ * @OVS_ACTION_ATTR_POP_NSH: Strip the Network Service Header from packet.
  */
 
 enum ovs_action_attr {
@@ -827,6 +841,8 @@ enum ovs_action_attr {
 				       * bits. */
 	OVS_ACTION_ATTR_CT,           /* Nested OVS_CT_ATTR_* . */
 	OVS_ACTION_ATTR_TRUNC,        /* u32 struct ovs_action_trunc. */
+	OVS_ACTION_ATTR_PUSH_NSH,     /* struct ovs_action_push_nsh. */
+	OVS_ACTION_ATTR_POP_NSH,      /* No argument. */
 
 #ifndef __KERNEL__
 	OVS_ACTION_ATTR_TUNNEL_PUSH,   /* struct ovs_action_push_tnl*/
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index ff4227c..d2bd64f 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -4197,6 +4197,8 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
     case OVS_ACTION_ATTR_HASH:
     case OVS_ACTION_ATTR_UNSPEC:
     case OVS_ACTION_ATTR_TRUNC:
+    case OVS_ACTION_ATTR_PUSH_NSH:
+    case OVS_ACTION_ATTR_POP_NSH:
     case __OVS_ACTION_ATTR_MAX:
         OVS_NOT_REACHED();
     }
diff --git a/lib/dpif.c b/lib/dpif.c
index 5f1be41..cff453e 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -1169,6 +1169,8 @@ dpif_execute_helper_cb(void *aux_, struct dp_packet_batch *packets_,
     case OVS_ACTION_ATTR_SET_MASKED:
     case OVS_ACTION_ATTR_SAMPLE:
     case OVS_ACTION_ATTR_TRUNC:
+    case OVS_ACTION_ATTR_PUSH_NSH:
+    case OVS_ACTION_ATTR_POP_NSH:
     case OVS_ACTION_ATTR_UNSPEC:
     case __OVS_ACTION_ATTR_MAX:
         OVS_NOT_REACHED();
diff --git a/lib/odp-execute.c b/lib/odp-execute.c
index 12f2b12..8b2d989 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -506,6 +506,8 @@ requires_datapath_assistance(const struct nlattr *a)
     case OVS_ACTION_ATTR_PUSH_MPLS:
     case OVS_ACTION_ATTR_POP_MPLS:
     case OVS_ACTION_ATTR_TRUNC:
+    case OVS_ACTION_ATTR_PUSH_NSH:
+    case OVS_ACTION_ATTR_POP_NSH:
         return false;
 
     case OVS_ACTION_ATTR_UNSPEC:
@@ -639,6 +641,10 @@ odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal,
             break;
         }
 
+        case OVS_ACTION_ATTR_PUSH_NSH:
+        case OVS_ACTION_ATTR_POP_NSH:
+            break;
+
         case OVS_ACTION_ATTR_OUTPUT:
         case OVS_ACTION_ATTR_TUNNEL_PUSH:
         case OVS_ACTION_ATTR_TUNNEL_POP:
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 5b2b355..e8213c0 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -121,6 +121,8 @@ odp_action_len(uint16_t type)
     case OVS_ACTION_ATTR_SET_MASKED: return ATTR_LEN_VARIABLE;
     case OVS_ACTION_ATTR_SAMPLE: return ATTR_LEN_VARIABLE;
     case OVS_ACTION_ATTR_CT: return ATTR_LEN_VARIABLE;
+    case OVS_ACTION_ATTR_PUSH_NSH: return sizeof(struct ovs_action_push_nsh);
+    case OVS_ACTION_ATTR_POP_NSH: return 0;
 
     case OVS_ACTION_ATTR_UNSPEC:
     case __OVS_ACTION_ATTR_MAX:
@@ -551,6 +553,69 @@ format_odp_tnl_push_action(struct ds *ds, const struct nlattr *attr)
     ds_put_format(ds, ",out_port(%"PRIu32"))", data->out_port);
 }
 
+static void
+format_push_nsh_header(struct ds *ds, const struct ovs_action_push_nsh * nsh)
+{
+    const struct nsh_header *nsh_hdr = (struct nsh_header *) (nsh->header);
+
+    ds_put_format(ds, "flags=0x%"PRIx8",md_type=%"PRIu8
+                  ",next_proto=%"PRIu8",nsp=0x%"PRIx32",nsi=0x%"PRIx8",",
+                  nsh_hdr->base.flags,
+                  nsh_hdr->base.md_type,
+                  nsh_hdr->base.next_proto,
+                  ntohl(nsh_hdr->base.sfp << 8),
+                  (nsh_hdr->base.sfp >> 24));
+
+    if (nsh_hdr->base.md_type == NSH_MD_TYPE1) {
+        const struct nsh_md1_ctx *ctx = (struct nsh_md1_ctx *)(nsh_hdr + 1);
+        ds_put_format(ds, "nshc1=0x%"PRIx32",nshc2=0x%"PRIx32
+                      ",nshc3=0x%"PRIx32",nshc4=0x%"PRIx32,
+                      ntohl(ctx->nshc1),
+                      ntohl(ctx->nshc2),
+                      ntohl(ctx->nshc3),
+                      ntohl(ctx->nshc4));
+#if 0
+    } else if (nsh_hdr->base.md_type == NSH_MD_TYPE2) {
+        /* MD type 2 prototype with TUN_METADATA APIs. */
+        const struct nsh_md2_ctx *ctx = (struct nsh_md2_ctx *)(nsh_hdr + 1);
+        int md_len = (nsh_hdr->base.length << 2) - sizeof(struct nsh_header);
+
+        while (md_len > 0) {
+            unsigned int len;
+            uint8_t data_len;
+
+            if (md_len < sizeof *ctx)
+                return;
+
+            data_len = ctx->length << 2;
+            len = data_len + sizeof *ctx;
+            if (len > md_len)
+                return;
+
+            ds_put_char(ds, '{');
+            ds_put_format(ds, "class=0x%"PRIx16",type=0x%"PRIx8",len=%"PRIu8",",
+                          ctx->md_class, ctx->type, data_len);
+            ds_put_hex(ds, ctx + 1, data_len);
+            ds_put_char(ds, '}');
+
+            ctx += len / sizeof(*ctx);
+            md_len -= len;
+        }
+#endif
+    }
+}
+
+static void
+format_push_nsh_action(struct ds *ds, const struct nlattr *attr)
+{
+    struct ovs_action_push_nsh *data;
+
+    data = (struct ovs_action_push_nsh *)nl_attr_get(attr);
+    ds_put_cstr(ds, "push_nsh(");
+    format_push_nsh_header(ds, data);
+    ds_put_char(ds, ')');
+}
+
 static const struct nl_policy ovs_nat_policy[] = {
     [OVS_NAT_ATTR_SRC] = { .type = NL_A_FLAG, .optional = true, },
     [OVS_NAT_ATTR_DST] = { .type = NL_A_FLAG, .optional = true, },
@@ -860,6 +925,14 @@ format_odp_action(struct ds *ds, const struct nlattr *a)
     case OVS_ACTION_ATTR_CT:
         format_odp_conntrack_action(ds, a);
         break;
+
+    case OVS_ACTION_ATTR_PUSH_NSH:
+        format_push_nsh_action(ds, a);
+        break;
+    case OVS_ACTION_ATTR_POP_NSH:
+        ds_put_cstr(ds, "pop_nsh");
+        break;
+
     case OVS_ACTION_ATTR_UNSPEC:
     case __OVS_ACTION_ATTR_MAX:
     default:
@@ -1647,6 +1720,72 @@ parse_odp_action(const char *s, const struct simap *port_names,
     }
 
     {
+        struct ovs_action_push_nsh push;
+        struct nsh_header *nsh_hdr = (struct nsh_header *)push.header;
+        ovs_be32 nsp = 0;
+        int n = -1, m = -1;
+        uint16_t length = 0;
+        uint8_t flags = 0, nsi = 0, md_type = 0, next_proto = 0;
+
+        if (ovs_scan_len(s, &n, "push_nsh(flags=0x%"SCNx8
+                         ",md_type=%"SCNi8",next_proto=%"SCNi8
+                         ",nsp=0x%"SCNx32",nsi=0x%"SCNx8,
+                         &flags, &md_type, &next_proto, &nsp, &nsi)) {
+
+            if (md_type == NSH_MD_TYPE1) {
+                struct nsh_md1_ctx *ctx = NULL;
+                ovs_be32 nshc1 = 0, nshc2 = 0, nshc3 = 0, nshc4 = 0;
+
+                if (!ovs_scan_len(s, &m, ",nshc1=0x%"SCNx32",nshc2=0x%"SCNx32
+                        ",nshc3=0x%"SCNx32",nshc4=0x%"SCNx32")",
+                        &nshc1, &nshc2, &nshc3, &nshc4)) {
+                        nshc1 = 0;
+                        nshc2 = 0;
+                        nshc3 = 0;
+                        nshc4 = 0;
+                }
+
+                nsh_hdr->base.flags = flags;
+                nsh_hdr->base.md_type = NSH_MD_TYPE1;
+                nsh_hdr->base.next_proto = next_proto;
+                nsh_hdr->base.sfp = (nsp >> 8) | (nsi << 24);
+
+                ctx = (struct nsh_md1_ctx *)(nsh_hdr + 1);
+                ctx->nshc1 = nshc1;
+                ctx->nshc2 = nshc2;
+                ctx->nshc3 = nshc3;
+                ctx->nshc4 = nshc4;
+                length = NSH_TYPE1_LEN;
+#if 0
+            } else if (md_type == NSH_MD_TYPE2) {
+                /* MD type 2 prototype with TUN_METADATA APIs. */
+                struct geneve_scan options;
+                struct nsh_md2_ctx *ctx = NULL;
+                nsh_hdr->base.flags = flags;
+                nsh_hdr->base.md_type = NSH_MD_TYPE2;
+                nsh_hdr->base.next_proto = next_proto;
+                nsh_hdr->base.sfp = (nsp >> 8) | (nsi << 24);
+
+                m = scan_geneve(s + n, &options, NULL);
+                ctx = (struct nsh_md2_ctx *)(nsh_hdr + 1);
+                memcpy(ctx, options.d, options.len);
+                length = options.len + sizeof *nsh_hdr;
+#endif
+            }
+
+            nsh_hdr->base.length = length >> 2;
+            push.len = length;
+            nl_msg_put_unspec(actions, OVS_ACTION_ATTR_PUSH_NSH,
+                          &push, sizeof push);
+            return n + m;
+        }
+    }
+
+    if (!strncmp(s, "pop_nsh", 7)) {
+        nl_msg_put_flag(actions, OVS_ACTION_ATTR_POP_NSH);
+        return 7;
+    }
+    {
         double percentage;
         int n = -1;
 
diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c
index ad277c6..86ffdd5 100644
--- a/ofproto/ofproto-dpif-sflow.c
+++ b/ofproto/ofproto-dpif-sflow.c
@@ -1177,6 +1177,8 @@ dpif_sflow_read_actions(const struct flow *flow,
 	}
 	case OVS_ACTION_ATTR_SAMPLE:
 	case OVS_ACTION_ATTR_UNSPEC:
+	case OVS_ACTION_ATTR_PUSH_NSH:
+	case OVS_ACTION_ATTR_POP_NSH:
 	case __OVS_ACTION_ATTR_MAX:
 	default:
 	    break;
-- 
1.8.4.2

--------------------------------------------------------------
Intel Research and Development Ireland Limited
Registered in Ireland
Registered Office: Collinstown Industrial Park, Leixlip, County Kildare
Registered Number: 308263


This e-mail and any attachments may contain confidential material for the sole
use of the intended recipient(s). Any review or distribution by others is
strictly prohibited. If you are not the intended recipient, please contact the
sender and delete all copies.




More information about the dev mailing list