The openvswitch exchange the key with key netlink message
between the kernel data path and user space flow tables.
The key fields are defined as key attributes.

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

diff --git a/datapath/linux/compat/include/linux/openvswitch.h 
b/datapath/linux/compat/include/linux/openvswitch.h
index f1e80db..52e33f6 100644
--- a/datapath/linux/compat/include/linux/openvswitch.h
+++ b/datapath/linux/compat/include/linux/openvswitch.h
@@ -342,6 +342,7 @@ enum ovs_key_attr {
        OVS_KEY_ATTR_ND,        /* struct ovs_key_nd */
        OVS_KEY_ATTR_SKB_MARK,  /* u32 skb mark */
        OVS_KEY_ATTR_TUNNEL,    /* Nested set of ovs_tunnel attributes */
+       OVS_KEY_ATTR_NSH,       /* Nested set of ovs_nsh attributes */
        OVS_KEY_ATTR_SCTP,      /* struct ovs_key_sctp */
        OVS_KEY_ATTR_TCP_FLAGS, /* be16 TCP flags. */
        OVS_KEY_ATTR_DP_HASH,   /* u32 hash value. Value 0 indicates the hash
@@ -384,6 +385,22 @@ enum ovs_tunnel_key_attr {
 
 #define OVS_TUNNEL_KEY_ATTR_MAX (__OVS_TUNNEL_KEY_ATTR_MAX - 1)
 
+enum ovs_nsh_key_attr {
+       OVS_NSH_KEY_ATTR_FLAGS,                 /* u8 NSH header flags */
+       OVS_NSH_KEY_ATTR_MD_TYPE,               /* u8 Metadata Type */
+       OVS_NSH_KEY_ATTR_NEXT_PROTO,            /* u8 Next Protocol */
+       OVS_NSH_KEY_ATTR_NSI,                   /* u8 Service Index */
+       OVS_NSH_KEY_ATTR_NSP,                   /* be32 Service Path ID */
+       OVS_NSH_KEY_ATTR_NSHC1,                 /* be32 NSH Context Header 1 */
+       OVS_NSH_KEY_ATTR_NSHC2,                 /* be32 NSH Context Header 2 */
+       OVS_NSH_KEY_ATTR_NSHC3,                 /* be32 NSH Context Header 3 */
+       OVS_NSH_KEY_ATTR_NSHC4,                 /* be32 NSH Context Header 4 */
+       OVS_NSH_KEY_ATTR_METADATA,              /* Array of Metadata options. */
+       __OVS_NSH_KEY_ATTR_MAX
+};
+
+#define OVS_NSH_KEY_ATTR_MAX (__OVS_NSH_KEY_ATTR_MAX - 1)
+
 /**
  * enum ovs_frag_type - IPv4 and IPv6 fragment type
  * @OVS_FRAG_TYPE_NONE: Packet is not a fragment.
diff --git a/lib/odp-execute.c b/lib/odp-execute.c
index 5a43904..12f2b12 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -336,6 +336,7 @@ odp_execute_set_action(struct dp_packet *packet, const 
struct nlattr *a)
     case OVS_KEY_ATTR_CT_ZONE:
     case OVS_KEY_ATTR_CT_MARK:
     case OVS_KEY_ATTR_CT_LABELS:
+    case OVS_KEY_ATTR_NSH:
     case __OVS_KEY_ATTR_MAX:
     default:
         OVS_NOT_REACHED();
@@ -435,6 +436,7 @@ odp_execute_masked_set_action(struct dp_packet *packet,
     case OVS_KEY_ATTR_ICMP:
     case OVS_KEY_ATTR_ICMPV6:
     case OVS_KEY_ATTR_TCP_FLAGS:
+    case OVS_KEY_ATTR_NSH:
     case __OVS_KEY_ATTR_MAX:
     default:
         OVS_NOT_REACHED();
diff --git a/lib/odp-util.c b/lib/odp-util.c
index d7b6a2d..5b2b355 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -164,6 +164,7 @@ ovs_key_attr_to_string(enum ovs_key_attr attr, char 
*namebuf, size_t bufsize)
     case OVS_KEY_ATTR_MPLS: return "mpls";
     case OVS_KEY_ATTR_DP_HASH: return "dp_hash";
     case OVS_KEY_ATTR_RECIRC_ID: return "recirc_id";
+    case OVS_KEY_ATTR_NSH: return "nsh";
 
     case __OVS_KEY_ATTR_MAX:
     default:
@@ -1776,6 +1777,19 @@ static const struct attr_len_tbl 
ovs_tun_key_attr_lens[OVS_TUNNEL_KEY_ATTR_MAX +
     [OVS_TUNNEL_KEY_ATTR_IPV6_DST]      = { .len = 16 },
 };
 
+static const struct attr_len_tbl ovs_nsh_key_attr_lens[OVS_NSH_KEY_ATTR_MAX + 
1] = {
+    [OVS_NSH_KEY_ATTR_FLAGS]            = { .len = 1 },
+    [OVS_NSH_KEY_ATTR_MD_TYPE]          = { .len = 1 },
+    [OVS_NSH_KEY_ATTR_NEXT_PROTO]       = { .len = 1 },
+    [OVS_NSH_KEY_ATTR_NSI]              = { .len = 1 },
+    [OVS_NSH_KEY_ATTR_NSP]              = { .len = 4 },
+    [OVS_NSH_KEY_ATTR_NSHC1]            = { .len = 4 },
+    [OVS_NSH_KEY_ATTR_NSHC2]            = { .len = 4 },
+    [OVS_NSH_KEY_ATTR_NSHC3]            = { .len = 4 },
+    [OVS_NSH_KEY_ATTR_NSHC4]            = { .len = 4 },
+    [OVS_NSH_KEY_ATTR_METADATA]         = { .len = ATTR_LEN_VARIABLE },
+};
+
 static const struct attr_len_tbl ovs_flow_key_attr_lens[OVS_KEY_ATTR_MAX + 1] 
= {
     [OVS_KEY_ATTR_ENCAP]     = { .len = ATTR_LEN_NESTED },
     [OVS_KEY_ATTR_PRIORITY]  = { .len = 4 },
@@ -1788,6 +1802,9 @@ static const struct attr_len_tbl 
ovs_flow_key_attr_lens[OVS_KEY_ATTR_MAX + 1] =
     [OVS_KEY_ATTR_IN_PORT]   = { .len = 4  },
     [OVS_KEY_ATTR_ETHERNET]  = { .len = sizeof(struct ovs_key_ethernet) },
     [OVS_KEY_ATTR_VLAN]      = { .len = 2 },
+    [OVS_KEY_ATTR_NSH]       = { .len = ATTR_LEN_NESTED,
+                                 .next = ovs_nsh_key_attr_lens,
+                                 .next_max = OVS_NSH_KEY_ATTR_MAX },
     [OVS_KEY_ATTR_ETHERTYPE] = { .len = 2 },
     [OVS_KEY_ATTR_MPLS]      = { .len = ATTR_LEN_VARIABLE },
     [OVS_KEY_ATTR_IPV4]      = { .len = sizeof(struct ovs_key_ipv4) },
@@ -2022,6 +2039,115 @@ tun_key_to_attr(struct ofpbuf *a, const struct flow_tnl 
*tun_key,
     nl_msg_end_nested(a, tun_key_ofs);
 }
 
+static void
+nsh_key_to_attr(struct ofpbuf *a, const struct flow *key)
+{
+    size_t nsh_key_ofs = 0;
+
+    if (key->nsh.nsp) {
+        nsh_key_ofs = nl_msg_start_nested(a, OVS_KEY_ATTR_NSH);
+
+        if (key->nsh.flags) {
+            nl_msg_put_u8(a, OVS_NSH_KEY_ATTR_FLAGS, key->nsh.flags);
+        }
+        if (key->nsh.md_type) {
+            nl_msg_put_u8(a, OVS_NSH_KEY_ATTR_MD_TYPE, key->nsh.md_type);
+        }
+        if (key->nsh.next_proto) {
+            nl_msg_put_u8(a, OVS_NSH_KEY_ATTR_NEXT_PROTO, key->nsh.next_proto);
+        }
+
+        nl_msg_put_u8(a, OVS_NSH_KEY_ATTR_NSI, key->nsh.nsi);
+        nl_msg_put_be32(a, OVS_NSH_KEY_ATTR_NSP, key->nsh.nsp);
+
+        if (key->nsh.md_type == 0x1) { /* NSH_MD_TYPE1 */
+            if (key->nsh.nshc1) {
+                nl_msg_put_be32(a, OVS_NSH_KEY_ATTR_NSHC1, key->nsh.nshc1);
+            }
+            if (key->nsh.nshc2) {
+                nl_msg_put_be32(a, OVS_NSH_KEY_ATTR_NSHC2, key->nsh.nshc2);
+            }
+            if (key->nsh.nshc3) {
+                nl_msg_put_be32(a, OVS_NSH_KEY_ATTR_NSHC3, key->nsh.nshc3);
+            }
+            if (key->nsh.nshc4) {
+                nl_msg_put_be32(a, OVS_NSH_KEY_ATTR_NSHC4, key->nsh.nshc4);
+            }
+#if 0
+        } else if (key->nsh.md_type == 0x2) { /* NSH_MD_TYPE2 */
+            /* To be implemented. */
+#endif
+        }
+        nl_msg_end_nested(a, nsh_key_ofs);
+    }
+}
+
+static enum odp_key_fitness
+odp_nsh_key_from_attr__(const struct nlattr *attr,
+                        const struct nlattr *flow_attrs OVS_UNUSED,
+                        size_t flow_attr_len OVS_UNUSED,
+                        const struct flow *src_key OVS_UNUSED,
+                        struct flow *key,
+                        bool udpif OVS_UNUSED)
+{
+    unsigned int left;
+    const struct nlattr *a;
+    bool unknown = false;
+
+    NL_NESTED_FOR_EACH(a, left, attr) {
+        uint16_t type = nl_attr_type(a);
+        size_t len = nl_attr_get_size(a);
+        int expected_len = odp_key_attr_len(ovs_nsh_key_attr_lens,
+                                            OVS_NSH_KEY_ATTR_MAX, type);
+
+        if (len != expected_len && expected_len >= 0) {
+            return ODP_FIT_ERROR;
+        }
+
+        switch (type) {
+        case OVS_NSH_KEY_ATTR_FLAGS:
+            key->nsh.flags = nl_attr_get_u8(a);
+            break;
+        case OVS_NSH_KEY_ATTR_MD_TYPE:
+            key->nsh.md_type = nl_attr_get_u8(a);
+            break;
+        case OVS_NSH_KEY_ATTR_NEXT_PROTO:
+            key->nsh.next_proto = nl_attr_get_u8(a);
+            break;
+        case OVS_NSH_KEY_ATTR_NSI:
+            key->nsh.nsi = nl_attr_get_u8(a);
+            break;
+        case OVS_NSH_KEY_ATTR_NSP:
+            key->nsh.nsp = nl_attr_get_be32(a);
+            break;
+        case OVS_NSH_KEY_ATTR_NSHC1:
+            key->nsh.nshc1 = nl_attr_get_be32(a);
+            break;
+        case OVS_NSH_KEY_ATTR_NSHC2:
+            key->nsh.nshc2 = nl_attr_get_be32(a);
+            break;
+        case OVS_NSH_KEY_ATTR_NSHC3:
+            key->nsh.nshc3 = nl_attr_get_be32(a);
+            break;
+        case OVS_NSH_KEY_ATTR_NSHC4:
+            key->nsh.nshc4 = nl_attr_get_be32(a);
+            break;
+       case OVS_NSH_KEY_ATTR_METADATA:
+            break;
+        default:
+            /* Allow this to show up as unexpected, if there are unknown
+             * NSH attribute, eventually resulting in ODP_FIT_TOO_MUCH. */
+            unknown = true;
+            break;
+        }
+    }
+
+    if (unknown) {
+        return ODP_FIT_TOO_MUCH;
+    }
+    return ODP_FIT_PERFECT;
+}
+
 static bool
 odp_mask_attr_is_wildcard(const struct nlattr *ma)
 {
@@ -2047,7 +2173,8 @@ odp_mask_is_exact(enum ovs_key_attr attr, const void 
*mask, size_t size)
             && ipv6_mask_is_exact((const struct in6_addr *)ipv6_mask->ipv6_src)
             && ipv6_mask_is_exact((const struct in6_addr 
*)ipv6_mask->ipv6_dst);
     }
-    if (attr == OVS_KEY_ATTR_TUNNEL) {
+    if (attr == OVS_KEY_ATTR_TUNNEL
+        || attr == OVS_KEY_ATTR_NSH) {
         return false;
     }
 
@@ -2069,7 +2196,8 @@ odp_mask_attr_is_exact(const struct nlattr *ma)
     const void *mask;
     size_t size;
 
-    if (attr == OVS_KEY_ATTR_TUNNEL) {
+    if (attr == OVS_KEY_ATTR_TUNNEL
+        || attr == OVS_KEY_ATTR_NSH) {
         return false;
     } else {
         mask = nl_attr_get(ma);
@@ -2156,6 +2284,23 @@ format_be64(struct ds *ds, const char *name, ovs_be64 
key,
 }
 
 static void
+format_be32(struct ds *ds, const char *name, ovs_be32 key,
+            const ovs_be32 *mask, bool verbose)
+{
+    bool mask_empty = mask && !*mask;
+
+    if (verbose || !mask_empty) {
+        bool mask_full = !mask || *mask == OVS_BE32_MAX;
+
+        ds_put_format(ds, "%s=0x%"PRIx32, name, ntohl(key));
+        if (!mask_full) { /* Partially masked. */
+            ds_put_format(ds, "/%#"PRIx32, ntohl(*mask));
+        }
+        ds_put_char(ds, ',');
+    }
+}
+
+static void
 format_ipv4(struct ds *ds, const char *name, ovs_be32 key,
             const ovs_be32 *mask, bool verbose)
 {
@@ -2624,6 +2769,87 @@ format_odp_tun_attr(const struct nlattr *attr, const 
struct nlattr *mask_attr,
     ofpbuf_uninit(&ofp);
 }
 
+static void
+format_odp_nsh_attr(const struct nlattr *attr, const struct nlattr *mask_attr,
+                    struct ds *ds, bool verbose)
+{
+    unsigned int left;
+    const struct nlattr *a;
+    struct ofpbuf ofp;
+
+    ofpbuf_init(&ofp, 100);
+    NL_NESTED_FOR_EACH(a, left, attr) {
+        enum ovs_nsh_key_attr type = nl_attr_type(a);
+        const struct nlattr *ma = NULL;
+
+        if (mask_attr) {
+            ma = nl_attr_find__(nl_attr_get(mask_attr),
+                                nl_attr_get_size(mask_attr), type);
+            if (!ma) {
+                ma = generate_all_wildcard_mask(ovs_nsh_key_attr_lens,
+                                                OVS_NSH_KEY_ATTR_MAX,
+                                                &ofp, a);
+            }
+        }
+
+        if (!check_attr_len(ds, a, ma, ovs_nsh_key_attr_lens,
+                            OVS_NSH_KEY_ATTR_MAX, true)) {
+            continue;
+        }
+
+        switch (type) {
+        case OVS_NSH_KEY_ATTR_FLAGS:
+            format_u8x(ds, "flags", nl_attr_get_u8(a),
+                        ma ? nl_attr_get(ma) : NULL, verbose);
+            break;
+        case OVS_NSH_KEY_ATTR_MD_TYPE:
+            format_u8u(ds, "nsh_mdtype", nl_attr_get_u8(a),
+                        ma ? nl_attr_get(ma) : NULL, verbose);
+            break;
+        case OVS_NSH_KEY_ATTR_NEXT_PROTO:
+            format_u8u(ds, "nsh_np", nl_attr_get_u8(a),
+                        ma ? nl_attr_get(ma) : NULL, verbose);
+            break;
+        case OVS_NSH_KEY_ATTR_NSI:
+            format_u8x(ds, "nsi", nl_attr_get_u8(a),
+                        ma ? nl_attr_get(ma) : NULL, verbose);
+            break;
+        case OVS_NSH_KEY_ATTR_NSP:
+            format_be32(ds, "nsp", nl_attr_get_be32(a),
+                        ma ? nl_attr_get(ma) : NULL, verbose);
+            break;
+        case OVS_NSH_KEY_ATTR_NSHC1:
+            format_be32(ds, "nshc1", nl_attr_get_be32(a),
+                        ma ? nl_attr_get(ma) : NULL, verbose);
+            break;
+        case OVS_NSH_KEY_ATTR_NSHC2:
+            format_be32(ds, "nshc2", nl_attr_get_be32(a),
+                        ma ? nl_attr_get(ma) : NULL, verbose);
+            break;
+        case OVS_NSH_KEY_ATTR_NSHC3:
+            format_be32(ds, "nshc3", nl_attr_get_be32(a),
+                        ma ? nl_attr_get(ma) : NULL, verbose);
+            break;
+        case OVS_NSH_KEY_ATTR_NSHC4:
+            format_be32(ds, "nshc4", nl_attr_get_be32(a),
+                        ma ? nl_attr_get(ma) : NULL, verbose);
+            break;
+        case OVS_NSH_KEY_ATTR_METADATA:
+            ds_put_cstr(ds, "metadata(");
+            //format_odp_tun_geneve(a, ma, ds, verbose);
+            ds_put_cstr(ds, "),");
+            break;
+        case __OVS_NSH_KEY_ATTR_MAX:
+        default:
+            format_unknown_key(ds, a, ma);
+        }
+        ofpbuf_clear(&ofp);
+    }
+
+    ds_chomp(ds, ',');
+    ofpbuf_uninit(&ofp);
+}
+
 static const char *
 odp_ct_state_to_string(uint32_t flag)
 {
@@ -2932,6 +3158,9 @@ format_odp_key_attr(const struct nlattr *a, const struct 
nlattr *ma,
         ds_chomp(ds, ',');
         break;
     }
+    case OVS_KEY_ATTR_NSH:
+        format_odp_nsh_attr(a, ma, ds, verbose);
+        break;
     case OVS_KEY_ATTR_UNSPEC:
     case __OVS_KEY_ATTR_MAX:
     default:
@@ -4063,6 +4292,20 @@ parse_odp_key_mask_attr(const char *s, const struct 
simap *port_names,
         SCAN_FIELD_NESTED_FUNC("flags(", uint16_t, tun_flags, 
tun_flags_to_attr);
     } SCAN_END_NESTED();
 
+    SCAN_BEGIN_NESTED("nsh(", OVS_KEY_ATTR_NSH) {
+        SCAN_FIELD_NESTED("flags=", uint8_t, u8, OVS_NSH_KEY_ATTR_FLAGS);
+        SCAN_FIELD_NESTED("nsh_mdtype=", uint8_t, u8, 
OVS_NSH_KEY_ATTR_MD_TYPE);
+        SCAN_FIELD_NESTED("nsh_np=", uint8_t, u8, OVS_NSH_KEY_ATTR_NEXT_PROTO);
+        SCAN_FIELD_NESTED("nsi=", uint8_t, u8, OVS_NSH_KEY_ATTR_NSI);
+        SCAN_FIELD_NESTED("nsp=", uint32_t, u32, OVS_NSH_KEY_ATTR_NSP);
+        SCAN_FIELD_NESTED("nshc1=", uint32_t, u32, OVS_NSH_KEY_ATTR_NSHC1);
+        SCAN_FIELD_NESTED("nshc2=", uint32_t, u32, OVS_NSH_KEY_ATTR_NSHC2);
+        SCAN_FIELD_NESTED("nshc3=", uint32_t, u32, OVS_NSH_KEY_ATTR_NSHC3);
+        SCAN_FIELD_NESTED("nshc4=", uint32_t, u32, OVS_NSH_KEY_ATTR_NSHC4);
+        SCAN_FIELD_NESTED_FUNC("metadata(", struct geneve_scan, geneve,
+                               geneve_to_attr);
+    } SCAN_END_NESTED();
+
     SCAN_SINGLE_PORT("in_port(", uint32_t, OVS_KEY_ATTR_IN_PORT);
 
     SCAN_BEGIN("eth(", struct ovs_key_ethernet) {
@@ -4281,6 +4524,10 @@ odp_flow_key_from_flow__(const struct odp_flow_key_parms 
*parms,
                         parms->key_buf);
     }
 
+    if (flow->nsh.nsp) {
+        nsh_key_to_attr(buf, data);
+    }
+
     nl_msg_put_u32(buf, OVS_KEY_ATTR_SKB_MARK, data->pkt_mark);
 
     if (parms->support.ct_state) {
@@ -5157,6 +5404,21 @@ odp_flow_key_to_flow__(const struct nlattr *key, size_t 
key_len,
         }
     }
 
+    /* Network Service Header. */
+    if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_NSH)) {
+        enum odp_key_fitness res;
+
+        res = odp_nsh_key_from_attr__(attrs[OVS_KEY_ATTR_NSH],
+                                      is_mask ? src_key : NULL,
+                                      src_key_len, src_flow,
+                                      flow, udpif);
+        if (res == ODP_FIT_ERROR) {
+            return ODP_FIT_ERROR;
+        } else if (res == ODP_FIT_PERFECT) {
+            expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_NSH;
+        }
+    }
+
     if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_IN_PORT)) {
         flow->in_port.odp_port
             = nl_attr_get_odp_port(attrs[OVS_KEY_ATTR_IN_PORT]);
diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c
index 7d0aa36..ad277c6 100644
--- a/ofproto/ofproto-dpif-sflow.c
+++ b/ofproto/ofproto-dpif-sflow.c
@@ -1036,6 +1036,7 @@ sflow_read_set_action(const struct nlattr *attr,
     case OVS_KEY_ATTR_CT_MARK:
     case OVS_KEY_ATTR_CT_LABELS:
     case OVS_KEY_ATTR_UNSPEC:
+    case OVS_KEY_ATTR_NSH:
     case __OVS_KEY_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.

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to