diff mbox

[ovs-dev,RFC,v2,06/13] Parse NSH header in function flow_extract in user space

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

Commit Message

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

Comments

Simon Horman Aug. 9, 2016, 2:53 p.m. UTC | #1
On Wed, Jul 13, 2016 at 01:27:53AM +0800, Johnson Li wrote:
> Signed-off-by: Johnson Li <johnson.li@intel.com>
> 
> diff --git a/lib/flow.c b/lib/flow.c
> index a4c1215..cdeccfc 100644
> --- a/lib/flow.c
> +++ b/lib/flow.c
> @@ -439,6 +439,46 @@ invalid:
>      arp_buf[1] = eth_addr_zero;
>  }
>  
> +static int
> +parse_nsh(const void **datap, size_t *sizep,
> +          struct flow_nsh *key, struct tun_metadata *md OVS_UNUSED)
> +{
> +    const struct nsh_header *nsh = (const struct nsh_header *) *datap;
> +    uint16_t length = 0;
> +
> +    memset(key, 0, sizeof(struct flow_nsh));
> +
> +    length = nsh->base.length << 2;
> +    if (length > NSH_LEN_MAX)
> +        return -EINVAL;
> +
> +    key->flags = nsh->base.flags;
> +    key->md_type = nsh->base.md_type;
> +    key->next_proto = nsh->base.next_proto;
> +    key->nsi = nsh->base.nsi;
> +    key->nsp = nsh->base.sfp << 8;
> +
> +    if (nsh->base.md_type == NSH_MD_TYPE1) {
> +        const struct nsh_md1_ctx *ctx = (struct nsh_md1_ctx *)(nsh + 1);
> +        key->nshc1 = ctx->nshc1;
> +        key->nshc2 = ctx->nshc2;
> +        key->nshc3 = ctx->nshc3;
> +        key->nshc4 = ctx->nshc4;
> +#if 0
> +    } else if (nsh->base.md_type == NSH_MD_TYPE2) {
> +        const struct nsh_md2_ctx *ctx = (struct nsh_md2_ctx *)(nsh + 1);
> +
> +        /* Prototype with TUN_METADATA APIs. */
> +        tun_metadata_from_nsh_ctx((struct geneve_opt *)ctx,
> +                                   md, length - sizeof *nsh);
> +#endif

Please use or remove unused code.

> +    }
> +
> +    data_pull(datap, sizep, length);
> +
> +    return 0;
> +}
> +
>  /* Initializes 'flow' members from 'packet' and 'md'
>   *
>   * Initializes 'packet' header l2 pointer to the start of the Ethernet
> @@ -563,6 +603,27 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
>      /* Network layer. */
>      packet->l3_ofs = (char *)data - l2;
>  
> +    /* Network Service Header */
> +    if (dl_type == htons(ETH_TYPE_NSH)) {
> +        struct flow_nsh nsh;
> +        struct tun_metadata metadata;
> +
> +        if (OVS_LIKELY(!parse_nsh(&data, &size, &nsh, &metadata))) {
> +            miniflow_push_words(mf, nsh, &nsh, sizeof(struct flow_nsh) /
> +                                sizeof(uint64_t));
> +#if 0
> +            if (nsh.md_type == NSH_MD_TYPE2) {
> +                /* MD type 2 is not fully implemented yet. */
> +                if (metadata.present.map) {
> +                    miniflow_push_words(mf, tunnel.metadata, &metadata,
> +                                        sizeof(metadata) / sizeof(uint64_t));
> +                }
> +            }
> +#endif

Ditto.

> +        }
> +        goto out;
> +    }
> +
>      nw_frag = 0;
>      if (OVS_LIKELY(dl_type == htons(ETH_TYPE_IP))) {
>          const struct ip_header *nh = data;
> @@ -1293,6 +1354,18 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc,
>      WC_MASK_FIELD(wc, dp_hash);
>      WC_MASK_FIELD(wc, in_port);
>  
> +    if (flow->nsh.nsp) {
> +        WC_MASK_FIELD(wc, nsh.flags);
> +        WC_MASK_FIELD(wc, nsh.md_type);
> +        WC_MASK_FIELD(wc, nsh.next_proto);
> +        WC_MASK_FIELD(wc, nsh.nsi);
> +        WC_MASK_FIELD(wc, nsh.nsp);
> +        WC_MASK_FIELD(wc, nsh.nshc1);
> +        WC_MASK_FIELD(wc, nsh.nshc2);
> +        WC_MASK_FIELD(wc, nsh.nshc3);
> +        WC_MASK_FIELD(wc, nsh.nshc4);
> +    }
> +

Probably the above works but as I understand things the above is encoding a
TYPE 1 NSH header so I wonder if (flow->base.mt_type == NS_MD_TYPE1) would
be a more appropriate condition.

>      /* actset_output wildcarded. */
>  
>      WC_MASK_FIELD(wc, dl_dst);
> @@ -1397,6 +1470,18 @@ flow_wc_map(const struct flow *flow, struct flowmap *map)
>      FLOWMAP_SET(map, ct_mark);
>      FLOWMAP_SET(map, ct_label);
>  
> +    if (flow->nsh.nsp) {
> +        FLOWMAP_SET(map, nsh.flags);
> +        FLOWMAP_SET(map, nsh.md_type);
> +        FLOWMAP_SET(map, nsh.next_proto);
> +        FLOWMAP_SET(map, nsh.nsi);
> +        FLOWMAP_SET(map, nsh.nsp);
> +        FLOWMAP_SET(map, nsh.nshc1);
> +        FLOWMAP_SET(map, nsh.nshc2);
> +        FLOWMAP_SET(map, nsh.nshc3);
> +        FLOWMAP_SET(map, nsh.nshc4);
> +    }
> +

Ditto.

[...]
diff mbox

Patch

diff --git a/lib/flow.c b/lib/flow.c
index a4c1215..cdeccfc 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -439,6 +439,46 @@  invalid:
     arp_buf[1] = eth_addr_zero;
 }
 
+static int
+parse_nsh(const void **datap, size_t *sizep,
+          struct flow_nsh *key, struct tun_metadata *md OVS_UNUSED)
+{
+    const struct nsh_header *nsh = (const struct nsh_header *) *datap;
+    uint16_t length = 0;
+
+    memset(key, 0, sizeof(struct flow_nsh));
+
+    length = nsh->base.length << 2;
+    if (length > NSH_LEN_MAX)
+        return -EINVAL;
+
+    key->flags = nsh->base.flags;
+    key->md_type = nsh->base.md_type;
+    key->next_proto = nsh->base.next_proto;
+    key->nsi = nsh->base.nsi;
+    key->nsp = nsh->base.sfp << 8;
+
+    if (nsh->base.md_type == NSH_MD_TYPE1) {
+        const struct nsh_md1_ctx *ctx = (struct nsh_md1_ctx *)(nsh + 1);
+        key->nshc1 = ctx->nshc1;
+        key->nshc2 = ctx->nshc2;
+        key->nshc3 = ctx->nshc3;
+        key->nshc4 = ctx->nshc4;
+#if 0
+    } else if (nsh->base.md_type == NSH_MD_TYPE2) {
+        const struct nsh_md2_ctx *ctx = (struct nsh_md2_ctx *)(nsh + 1);
+
+        /* Prototype with TUN_METADATA APIs. */
+        tun_metadata_from_nsh_ctx((struct geneve_opt *)ctx,
+                                   md, length - sizeof *nsh);
+#endif
+    }
+
+    data_pull(datap, sizep, length);
+
+    return 0;
+}
+
 /* Initializes 'flow' members from 'packet' and 'md'
  *
  * Initializes 'packet' header l2 pointer to the start of the Ethernet
@@ -563,6 +603,27 @@  miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
     /* Network layer. */
     packet->l3_ofs = (char *)data - l2;
 
+    /* Network Service Header */
+    if (dl_type == htons(ETH_TYPE_NSH)) {
+        struct flow_nsh nsh;
+        struct tun_metadata metadata;
+
+        if (OVS_LIKELY(!parse_nsh(&data, &size, &nsh, &metadata))) {
+            miniflow_push_words(mf, nsh, &nsh, sizeof(struct flow_nsh) /
+                                sizeof(uint64_t));
+#if 0
+            if (nsh.md_type == NSH_MD_TYPE2) {
+                /* MD type 2 is not fully implemented yet. */
+                if (metadata.present.map) {
+                    miniflow_push_words(mf, tunnel.metadata, &metadata,
+                                        sizeof(metadata) / sizeof(uint64_t));
+                }
+            }
+#endif
+        }
+        goto out;
+    }
+
     nw_frag = 0;
     if (OVS_LIKELY(dl_type == htons(ETH_TYPE_IP))) {
         const struct ip_header *nh = data;
@@ -1293,6 +1354,18 @@  void flow_wildcards_init_for_packet(struct flow_wildcards *wc,
     WC_MASK_FIELD(wc, dp_hash);
     WC_MASK_FIELD(wc, in_port);
 
+    if (flow->nsh.nsp) {
+        WC_MASK_FIELD(wc, nsh.flags);
+        WC_MASK_FIELD(wc, nsh.md_type);
+        WC_MASK_FIELD(wc, nsh.next_proto);
+        WC_MASK_FIELD(wc, nsh.nsi);
+        WC_MASK_FIELD(wc, nsh.nsp);
+        WC_MASK_FIELD(wc, nsh.nshc1);
+        WC_MASK_FIELD(wc, nsh.nshc2);
+        WC_MASK_FIELD(wc, nsh.nshc3);
+        WC_MASK_FIELD(wc, nsh.nshc4);
+    }
+
     /* actset_output wildcarded. */
 
     WC_MASK_FIELD(wc, dl_dst);
@@ -1397,6 +1470,18 @@  flow_wc_map(const struct flow *flow, struct flowmap *map)
     FLOWMAP_SET(map, ct_mark);
     FLOWMAP_SET(map, ct_label);
 
+    if (flow->nsh.nsp) {
+        FLOWMAP_SET(map, nsh.flags);
+        FLOWMAP_SET(map, nsh.md_type);
+        FLOWMAP_SET(map, nsh.next_proto);
+        FLOWMAP_SET(map, nsh.nsi);
+        FLOWMAP_SET(map, nsh.nsp);
+        FLOWMAP_SET(map, nsh.nshc1);
+        FLOWMAP_SET(map, nsh.nshc2);
+        FLOWMAP_SET(map, nsh.nshc3);
+        FLOWMAP_SET(map, nsh.nshc4);
+    }
+
     /* Ethertype-dependent fields. */
     if (OVS_LIKELY(flow->dl_type == htons(ETH_TYPE_IP))) {
         FLOWMAP_SET(map, nw_src);
diff --git a/lib/packets.h b/lib/packets.h
index 5945940..6b3e2ae 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -334,6 +334,7 @@  ovs_be32 set_mpls_lse_values(uint8_t ttl, uint8_t tc, uint8_t bos,
 #define ETH_TYPE_RARP          0x8035
 #define ETH_TYPE_MPLS          0x8847
 #define ETH_TYPE_MPLS_MCAST    0x8848
+#define ETH_TYPE_NSH           0x894F
 
 static inline bool eth_type_mpls(ovs_be16 eth_type)
 {
@@ -1018,6 +1019,53 @@  struct vxlanhdr {
 
 #define VXLAN_FLAGS 0x08000000  /* struct vxlanhdr.vx_flags required value. */
 
+/* Network service header */
+struct nsh_base_hdr {
+    uint8_t flags;
+    uint8_t length;
+    uint8_t md_type;
+    uint8_t next_proto;
+    union {
+        struct {
+            uint8_t nsp[3];
+            uint8_t nsi;
+        };
+        ovs_be32 sfp;
+    };
+};
+
+struct nsh_md1_ctx {
+    ovs_be32 nshc1;
+    ovs_be32 nshc2;
+    ovs_be32 nshc3;
+    ovs_be32 nshc4;
+};
+
+struct nsh_md2_ctx {
+    ovs_be16 md_class;
+    uint8_t type;
+    uint8_t length;
+    uint8_t md_value[];
+};
+
+struct nsh_header {
+    struct nsh_base_hdr base;
+    uint8_t ctx[];
+};
+
+#define NSH_P_IPV4        0x01
+#define NSH_P_IPV6        0x02
+#define NSH_P_ETHERNET    0x03
+
+#define NSH_MD_TYPE_NONE  0x00
+#define NSH_MD_TYPE1      0x01
+#define NSH_MD_TYPE2      0x02
+#define NSH_MD_EXP1       0xFE
+#define NSH_MD_EXP2       0xFF
+
+#define NSH_TYPE1_LEN     24
+#define NSH_LEN_MAX       256
+
 void ipv6_format_addr(const struct in6_addr *addr, struct ds *);
 void ipv6_format_addr_bracket(const struct in6_addr *addr, struct ds *,
                               bool bracket);