[ovs-dev] [CudaMailTagged] [RFC PATCH v2 2/5] NSH key attributes handling of kernel Netlink message

Johnson Li johnson.li at intel.com
Tue Jul 12 17:36:21 UTC 2016


The openvswitch exchange the key with key netlink message
between the kernel data path and user space flow tables.

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

diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c
index eafaca2..e6f42ea 100644
--- a/datapath/flow_netlink.c
+++ b/datapath/flow_netlink.c
@@ -279,6 +279,23 @@ size_t ovs_tun_key_attr_size(void)
 		+ nla_total_size(2);   /* OVS_TUNNEL_KEY_ATTR_TP_DST */
 }
 
+size_t ovs_nsh_key_attr_size(void)
+{
+	return    nla_total_size(1)    /* OVS_NSH_KEY_ATTR_FLAGS */
+		+ nla_total_size(1)    /* OVS_NSH_KEY_ATTR_MD_TYPE */
+		+ nla_total_size(1)    /* OVS_NSH_KEY_ATTR_NEXT_PROTO */
+		+ nla_total_size(1)    /* OVS_NSH_KEY_ATTR_NSI */
+		+ nla_total_size(4)    /* OVS_NSH_KEY_ATTR_NSP */
+		+ nla_total_size(256)  /* OVS_NSH_KEY_ATTR_METADATA */
+		/* OVS_NSH_KEY_ATTR_METADATA is mutually exclusive with
+		 * OVS_NSH_KEY_ATTR_NSHCx and covered by it.
+		 */
+		+ nla_total_size(0)    /* OVS_NSH_KEY_ATTR_NSHC1 */
+		+ nla_total_size(0)    /* OVS_NSH_KEY_ATTR_NSHC2 */
+		+ nla_total_size(0)    /* OVS_NSH_KEY_ATTR_NSHC3 */
+		+ nla_total_size(0);   /* OVS_NSH_KEY_ATTR_NSHC4 */
+}
+
 size_t ovs_key_attr_size(void)
 {
 	/* Whenever adding new OVS_KEY_ FIELDS, we should consider
@@ -300,6 +317,8 @@ size_t ovs_key_attr_size(void)
 		+ nla_total_size(12)  /* OVS_KEY_ATTR_ETHERNET */
 		+ nla_total_size(2)   /* OVS_KEY_ATTR_ETHERTYPE */
 		+ nla_total_size(4)   /* OVS_KEY_ATTR_VLAN */
+		+ nla_total_size(0)   /* OVS_KEY_ATTR_NSH */
+		+ ovs_nsh_key_attr_size()
 		+ nla_total_size(0)   /* OVS_KEY_ATTR_ENCAP */
 		+ nla_total_size(2)   /* OVS_KEY_ATTR_ETHERTYPE */
 		+ nla_total_size(40)  /* OVS_KEY_ATTR_IPV6 */
@@ -327,6 +346,19 @@ static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1]
 						.next = ovs_vxlan_ext_key_lens },
 };
 
+static const struct ovs_len_tbl ovs_nsh_key_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 = OVS_ATTR_VARIABLE },
+};
+
 /* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute.  */
 static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
 	[OVS_KEY_ATTR_ENCAP]	 = { .len = OVS_ATTR_NESTED },
@@ -335,6 +367,8 @@ static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
 	[OVS_KEY_ATTR_SKB_MARK]	 = { .len = sizeof(u32) },
 	[OVS_KEY_ATTR_ETHERNET]	 = { .len = sizeof(struct ovs_key_ethernet) },
 	[OVS_KEY_ATTR_VLAN]	 = { .len = sizeof(__be16) },
+	[OVS_KEY_ATTR_NSH]	 = { .len = OVS_ATTR_NESTED,
+				     .next = ovs_nsh_key_lens, },
 	[OVS_KEY_ATTR_ETHERTYPE] = { .len = sizeof(__be16) },
 	[OVS_KEY_ATTR_IPV4]	 = { .len = sizeof(struct ovs_key_ipv4) },
 	[OVS_KEY_ATTR_IPV6]	 = { .len = sizeof(struct ovs_key_ipv6) },
@@ -853,6 +887,159 @@ static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match,
 	return 0;
 }
 
+static int nsh_from_nlattr(const struct nlattr *attr,
+			   struct sw_flow_match *match, bool is_mask,
+			   bool log)
+{
+	struct nlattr *a;
+	int rem;
+
+	nla_for_each_nested(a, attr, rem) {
+		int type = nla_type(a);
+
+		if (type > OVS_NSH_KEY_ATTR_MAX) {
+			OVS_NLERR(log, "NSH attr %d out of range max %d",
+				  type, OVS_NSH_KEY_ATTR_MAX);
+			return -EINVAL;
+		}
+
+		if (!check_attr_len(nla_len(a),
+				    ovs_nsh_key_lens[type].len)) {
+			OVS_NLERR(log, "NSH attr %d has unexpected len %d"
+				  " expected %d", type, nla_len(a),
+				  ovs_nsh_key_lens[type].len);
+			return -EINVAL;
+		}
+
+		switch (type) {
+		case OVS_NSH_KEY_ATTR_FLAGS:
+			SW_FLOW_KEY_PUT(match, nsh.flags,
+					nla_get_u8(a), is_mask);
+			break;
+		case OVS_NSH_KEY_ATTR_MD_TYPE:
+			SW_FLOW_KEY_PUT(match, nsh.md_type,
+					nla_get_u8(a), is_mask);
+			break;
+		case OVS_NSH_KEY_ATTR_NEXT_PROTO:
+			SW_FLOW_KEY_PUT(match, nsh.next_proto,
+					nla_get_u8(a), is_mask);
+			break;
+		case OVS_NSH_KEY_ATTR_NSI:
+			SW_FLOW_KEY_PUT(match, nsh.nsi,
+					nla_get_u8(a), is_mask);
+			break;
+		case OVS_NSH_KEY_ATTR_NSP:
+			SW_FLOW_KEY_PUT(match, nsh.nsp,
+					nla_get_be32(a), is_mask);
+			break;
+		case OVS_NSH_KEY_ATTR_NSHC1:
+			SW_FLOW_KEY_PUT(match, nsh.nshc1,
+					nla_get_be32(a), is_mask);
+			break;
+		case OVS_NSH_KEY_ATTR_NSHC2:
+			SW_FLOW_KEY_PUT(match, nsh.nshc2,
+					nla_get_be32(a), is_mask);
+			break;
+		case OVS_NSH_KEY_ATTR_NSHC3:
+			SW_FLOW_KEY_PUT(match, nsh.nshc3,
+					nla_get_be32(a), is_mask);
+			break;
+		case OVS_NSH_KEY_ATTR_NSHC4:
+			SW_FLOW_KEY_PUT(match, nsh.nshc4,
+					nla_get_be32(a), is_mask);
+			break;
+		/* To be implemented for MD type 2 */
+		case OVS_NSH_KEY_ATTR_METADATA:
+			break;
+		default:
+			OVS_NLERR(log, "Unknown NSH attribute %d", type);
+			return -EINVAL;
+		}
+	}
+
+	if (rem > 0) {
+		OVS_NLERR(log, "NSH attribute has %d unknown bytes.", rem);
+		return -EINVAL;
+	}
+
+	if (!is_mask) {
+		if ((match->key->nsh.md_type != 0x1) &&
+		    (match->key->nsh.md_type != 0x2)) {
+			OVS_NLERR(log, "Invalid NSH Header MD Type!!!");
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int __nsh_to_nlattr(struct sk_buff *skb,
+			   const struct ovs_nsh_key *output)
+{
+	if (output->nsp) {
+		if (output->flags &&
+		    nla_put_u8(skb, OVS_NSH_KEY_ATTR_FLAGS,
+			       output->flags))
+			return -EMSGSIZE;
+		if (nla_put_u8(skb, OVS_NSH_KEY_ATTR_MD_TYPE,
+			       output->md_type))
+			return -EMSGSIZE;
+		if (output->next_proto &&
+		    nla_put_u8(skb, OVS_NSH_KEY_ATTR_NEXT_PROTO,
+			       output->next_proto))
+			return -EMSGSIZE;
+		if (output->nsi &&
+		    nla_put_u8(skb, OVS_NSH_KEY_ATTR_NSI,
+			       output->nsi))
+			return -EMSGSIZE;
+		if (output->nsp &&
+		    nla_put_be32(skb, OVS_NSH_KEY_ATTR_NSP,
+				 output->nsp))
+			return -EMSGSIZE;
+		if (output->md_type == 0x1) { /* NSH_M_TYPE1 */
+			if (output->nshc1 &&
+			    nla_put_be32(skb, OVS_NSH_KEY_ATTR_NSHC1,
+					 output->nshc1))
+				return -EMSGSIZE;
+			if (output->nshc2 &&
+			    nla_put_be32(skb, OVS_NSH_KEY_ATTR_NSHC2,
+					 output->nshc2))
+				return -EMSGSIZE;
+			if (output->nshc3 &&
+			    nla_put_be32(skb, OVS_NSH_KEY_ATTR_NSHC3,
+					 output->nshc3))
+				return -EMSGSIZE;
+			if (output->nshc4 &&
+			    nla_put_be32(skb, OVS_NSH_KEY_ATTR_NSHC4,
+					 output->nshc4))
+				return -EMSGSIZE;
+#if 0
+		} else if (output->md_type == 0x2) { /* NSH_M_TYPE2 */
+			/* To be implemented. */
+#endif
+		}
+	}
+	return 0;
+}
+
+static int nsh_to_nlattr(struct sk_buff *skb,
+			 const struct ovs_nsh_key *output)
+{
+	struct nlattr *nla;
+	int err;
+
+	nla = nla_nest_start(skb, OVS_KEY_ATTR_NSH);
+	if (!nla)
+		return -EMSGSIZE;
+
+	err = __nsh_to_nlattr(skb, output);
+	if (err)
+		return err;
+
+	nla_nest_end(skb, nla);
+	return 0;
+}
+
 static int ovs_key_from_nlattrs(struct net *net, struct sw_flow_match *match,
 				u64 attrs, const struct nlattr **a,
 				bool is_mask, bool log)
@@ -863,6 +1050,14 @@ static int ovs_key_from_nlattrs(struct net *net, struct sw_flow_match *match,
 	if (err)
 		return err;
 
+	if (attrs & (1ULL << OVS_KEY_ATTR_NSH)) {
+		if (nsh_from_nlattr(a[OVS_KEY_ATTR_NSH], match,
+				    is_mask, log) < 0) {
+			return -EINVAL;
+		}
+		attrs &= ~(1ULL << OVS_KEY_ATTR_NSH);
+	}
+
 	if (attrs & (1ULL << OVS_KEY_ATTR_ETHERNET)) {
 		const struct ovs_key_ethernet *eth_key;
 
@@ -1391,6 +1586,11 @@ static int __ovs_nla_put_key(const struct sw_flow_key *swkey,
 			goto nla_put_failure;
 	}
 
+	if (swkey->nsh.nsp) {
+		if (nsh_to_nlattr(skb, &output->nsh))
+			goto nla_put_failure;
+	}
+
 	if (swkey->phy.in_port == DP_MAX_PORTS) {
 		if (is_mask && (output->phy.in_port == 0xffff))
 			if (nla_put_u32(skb, OVS_KEY_ATTR_IN_PORT, 0xffffffff))
-- 
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