diff mbox

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

Message ID 1468344489-11392-1-git-send-email-johnson.li@intel.com
State Changes Requested
Headers show

Commit Message

Johnson.Li July 12, 2016, 5:28 p.m. UTC
Signed-off-by: Johnson Li <johnson.li@intel.com>
diff mbox

Patch

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;