[openib-general] [PATCH] Add vendor OUI support to MAD layer

Hal Rosenstock halr at voltaire.com
Thu Dec 2 20:08:58 PST 2004


mad: Add vendor OUI support to MAD layer
Also, in ib_register_mad_agent, if registration request supplied, make
sure that class supplied in request is consistent with the QP type.

On sending, it is the responsibility of the client to put the OUI in
the MAD when sending a vendor MAD with OUI (despite this being available
in the mad_agent). This seems consistent with the way we have been doing
things up to now. (This could be changed if someone strongly objects).

Also, I didn't compress ib_mad_mgmt_class_table (to eliminate the vendor
with OUI classes. That's 32 pointers per version (I think there are 2
versions in play right now). That's an optimization that could be made
but I'm not sure it is worth it.

Index: include/ib_mad.h
===================================================================
--- include/ib_mad.h	(revision 1308)
+++ include/ib_mad.h	(working copy)
@@ -42,6 +42,8 @@
 #define IB_MGMT_CLASS_DEVICE_MGMT		0x06
 #define IB_MGMT_CLASS_CM			0x07
 #define IB_MGMT_CLASS_SNMP			0x08
+#define IB_MGMT_CLASS_VENDOR_RANGE2_START	0x30
+#define IB_MGMT_CLASS_VENDOR_RANGE2_END		0x4F
 
 /* Management methods */
 #define IB_MGMT_METHOD_GET			0x01
@@ -55,7 +57,6 @@
 
 #define IB_MGMT_METHOD_RESP			0x80
 
-
 #define IB_MGMT_MAX_METHODS			128
 
 #define IB_QP0		0
@@ -104,6 +105,14 @@
 	u8			data[220];
 } __attribute__ ((packed));
 
+struct ib_vendor_mad {
+	struct ib_mad_hdr	mad_hdr;
+	struct ib_rmpp_hdr	rmpp_hdr;
+	u8			reserved;
+	u8			oui[3];
+	u8			data[216];
+} __attribute__ ((packed));
+
 struct ib_mad_agent;
 struct ib_mad_send_wc;
 struct ib_mad_recv_wc;
@@ -199,12 +208,15 @@
  *   receive unsolicited MADs, otherwise it should be 0.
  * @mgmt_class_version: Indicates which version of MADs for the given
  *   management class to receive.
+ * @oui: Indicates IEEE OUI when mgmt_class is a vendor class
+ *   in the range from 0x30 to 0x4f. Otherwise not used.
  * @method_mask: The caller will receive unsolicited MADs for any method
  *   where @method_mask = 1.
  */
 struct ib_mad_reg_req {
 	u8	mgmt_class;
 	u8	mgmt_class_version;
+	u8	oui[3];
 	DECLARE_BITMAP(method_mask, IB_MGMT_MAX_METHODS);
 };
 
Index: core/mad_priv.h
===================================================================
--- core/mad_priv.h	(revision 1308)
+++ core/mad_priv.h	(working copy)
@@ -78,6 +78,9 @@
 /* Registration table sizes */
 #define MAX_MGMT_CLASS		80	
 #define MAX_MGMT_VERSION	8
+#define MAX_MGMT_OUI		8
+#define MAX_MGMT_VENDOR_RANGE2	IB_MGMT_CLASS_VENDOR_RANGE2_END - \
+				IB_MGMT_CLASS_VENDOR_RANGE2_START + 1
 
 struct ib_mad_list_head {
 	struct list_head list;
@@ -140,6 +143,20 @@
 	struct ib_mad_mgmt_method_table *method_table[MAX_MGMT_CLASS];
 };
 
+struct ib_mad_mgmt_vendor_class {
+	u8	oui[MAX_MGMT_OUI][3];
+	struct ib_mad_mgmt_method_table *method_table[MAX_MGMT_OUI];	
+};
+
+struct ib_mad_mgmt_vendor_class_table {
+	struct ib_mad_mgmt_vendor_class *vendor_class[MAX_MGMT_VENDOR_RANGE2];
+};
+
+struct ib_mad_mgmt_version_table {
+	struct ib_mad_mgmt_class_table *class;
+	struct ib_mad_mgmt_vendor_class_table *vendor;
+};
+
 struct ib_mad_queue {
 	spinlock_t lock;
 	struct list_head list;
@@ -165,7 +182,7 @@
 	struct ib_mr *mr;
 
 	spinlock_t reg_lock;
-	struct ib_mad_mgmt_class_table *version[MAX_MGMT_VERSION];
+	struct ib_mad_mgmt_version_table version[MAX_MGMT_VERSION];
 	struct list_head agent_list;
 	struct workqueue_struct *wq;
 	struct work_struct work;
Index: core/mad.c
===================================================================
--- core/mad.c	(revision 1308)
+++ core/mad.c	(working copy)
@@ -144,6 +144,47 @@
 	}
 }
 
+static int vendor_class_index(u8 mgmt_class)
+{
+	return mgmt_class - IB_MGMT_CLASS_VENDOR_RANGE2_START;
+}
+
+static int is_vendor_class(u8 mgmt_class)
+{
+	if ((mgmt_class < IB_MGMT_CLASS_VENDOR_RANGE2_START) ||
+	    (mgmt_class > IB_MGMT_CLASS_VENDOR_RANGE2_END))
+		return 0;
+	return 1;
+}
+
+static int is_vendor_oui(char *oui)
+{
+	if (oui[0] || oui[1] || oui[2])
+		return 1;
+	return 0;
+}
+
+static int is_vendor_method_in_use(
+		struct ib_mad_mgmt_vendor_class *vendor_class,
+		struct ib_mad_reg_req *mad_reg_req)
+{
+	struct ib_mad_mgmt_method_table *method;
+	int i;
+
+	for (i = 0; i < MAX_MGMT_OUI; i++) {
+		if (!memcmp(vendor_class->oui[i], mad_reg_req->oui, 3)) {
+			method = vendor_class->method_table[i];
+			if (method) {
+				if (method_in_use(&method, mad_reg_req))
+					return 1;
+				else
+					break;
+			}
+		}
+	}
+	return 0;
+}
+
 /*
  * ib_register_mad_agent - Register to send/receive MADs
  */
@@ -157,61 +198,71 @@
 					   void *context)
 {
 	struct ib_mad_port_private *port_priv;
-	struct ib_mad_agent *ret;
+	struct ib_mad_agent *ret = ERR_PTR(-EINVAL);
 	struct ib_mad_agent_private *mad_agent_priv;
 	struct ib_mad_reg_req *reg_req = NULL;
 	struct ib_mad_mgmt_class_table *class;
+	struct ib_mad_mgmt_vendor_class_table *vendor;
+	struct ib_mad_mgmt_vendor_class *vendor_class;
 	struct ib_mad_mgmt_method_table *method;
 	int ret2, qpn;
 	unsigned long flags;
-	u8 mgmt_class;
+	u8 mgmt_class, vclass;
 
 	/* Validate parameters */
 	qpn = get_spl_qp_index(qp_type);
-	if (qpn == -1) {
-		ret = ERR_PTR(-EINVAL);
+	if (qpn == -1)
 		goto error1;
-	}
 
-	if (rmpp_version) {
-		ret = ERR_PTR(-EINVAL);	/* XXX: until RMPP implemented */
-		goto error1;
-	}
+	if (rmpp_version)
+		goto error1;	/* XXX: until RMPP implemented */
 
 	/* Validate MAD registration request if supplied */
 	if (mad_reg_req) {
-		if (mad_reg_req->mgmt_class_version >= MAX_MGMT_VERSION) {
-			ret = ERR_PTR(-EINVAL);
+		if (mad_reg_req->mgmt_class_version >= MAX_MGMT_VERSION)
 			goto error1;
-		}
-		if (!recv_handler) {
-			ret = ERR_PTR(-EINVAL);
+		if (!recv_handler)
 			goto error1;
-		}
 		if (mad_reg_req->mgmt_class >= MAX_MGMT_CLASS) {
 			/*
 			 * IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE is the only
 			 * one in this range currently allowed
 			 */
 			if (mad_reg_req->mgmt_class !=
-			    IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) {
-				ret = ERR_PTR(-EINVAL);
+			    IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
 				goto error1;
-			}
 		} else if (mad_reg_req->mgmt_class == 0) {
 			/* 
 			 * Class 0 is reserved in IBA and is used for 
 			 * aliasing of IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE
 			 */
-			ret = ERR_PTR(-EINVAL);
 			goto error1;
+		} else if (is_vendor_class(mad_reg_req->mgmt_class)) {
+			/*
+			 * If class is in "new" vendor range,
+			 * ensure supplied OUI is not zero
+			 */
+			if (!is_vendor_oui(mad_reg_req->oui))
+				goto error1;
 		}
+		/* Make sure class supplied is consistent with QP type */
+		if (qp_type == IB_QPT_SMI) {
+			if ((mad_reg_req->mgmt_class !=
+					IB_MGMT_CLASS_SUBN_LID_ROUTED) &&
+			    (mad_reg_req->mgmt_class !=
+					IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE))
+				goto error1;
+		} else {
+			if ((mad_reg_req->mgmt_class ==
+					IB_MGMT_CLASS_SUBN_LID_ROUTED) ||
+			    (mad_reg_req->mgmt_class ==
+					IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE))
+				goto error1;
+		}
 	} else {
 		/* No registration request supplied */
-		if (!send_handler) {
-			ret = ERR_PTR(-EINVAL);
+		if (!send_handler)
 			goto error1;
-		}
 	}
 
 	/* Validate device and port */
@@ -258,17 +309,32 @@
 	 * is non overlapping with any existing ones
 	 */
 	if (mad_reg_req) {
-		class = port_priv->version[mad_reg_req->mgmt_class_version];
-		if (class) {
-			mgmt_class = convert_mgmt_class(
-						mad_reg_req->mgmt_class);
-			method = class->method_table[mgmt_class];
-			if (method) {
-				if (method_in_use(&method, mad_reg_req)) {
-					ret = ERR_PTR(-EINVAL);
-					goto error3;
+		mgmt_class = convert_mgmt_class(mad_reg_req->mgmt_class);
+		if (!is_vendor_class(mgmt_class)) {
+			class = port_priv->version[mad_reg_req->
+						   mgmt_class_version].class;
+			if (class) {
+				method = class->method_table[mgmt_class];
+				if (method) {
+					if (method_in_use(&method,
+							   mad_reg_req))
+						goto error3;
 				}
 			}
+		} else {
+			/* "New" vendor class range */
+			vendor = port_priv->version[mad_reg_req->
+						    mgmt_class_version].vendor;
+			if (vendor) {
+				vclass = vendor_class_index(mgmt_class);
+				vendor_class = vendor->vendor_class[vclass];
+				if (vendor_class) {
+					if (is_vendor_method_in_use(
+							vendor_class,
+							mad_reg_req))
+						goto error3;
+				}
+			}
 		}
 	}
 
@@ -721,6 +787,40 @@
 	return 0;
 }
 
+static int check_vendor_class(struct ib_mad_mgmt_vendor_class *vendor_class)
+{
+	int i;
+
+	for (i = 0; i < MAX_MGMT_OUI; i++)
+		if (vendor_class->method_table[i])
+			return 1;
+	return 0;
+}
+
+static int find_vendor_oui(struct ib_mad_mgmt_vendor_class *vendor_class,
+			   char *oui)
+{
+	int i;
+
+	for (i = 0; i < MAX_MGMT_OUI; i++)
+                /* Is there matching OUI for this vendor class ? */
+                if (!memcmp(vendor_class->oui[i], oui, 3))
+			return i;
+
+	return -1;
+}
+
+static int check_vendor_table(struct ib_mad_mgmt_vendor_class_table *vendor)
+{
+	int i;
+
+	for (i = 0; i < MAX_MGMT_VENDOR_RANGE2; i++)
+		if (vendor->vendor_class[i])
+			return 1;
+
+	return 0;
+}
+
 static void remove_methods_mad_agent(struct ib_mad_mgmt_method_table *method,
 				     struct ib_mad_agent_private *agent)
 {
@@ -734,23 +834,17 @@
 	}
 }
 
-static int add_mad_reg_req(struct ib_mad_reg_req *mad_reg_req,
-			   struct ib_mad_agent_private *priv)
+static int add_nonoui_reg_req(struct ib_mad_reg_req *mad_reg_req,
+			      struct ib_mad_agent_private *agent_priv,
+			      u8 mgmt_class)
 {
-	struct ib_mad_port_private *private;
+	struct ib_mad_port_private *port_priv;
 	struct ib_mad_mgmt_class_table **class;
 	struct ib_mad_mgmt_method_table **method;
-
 	int i, ret;
-	u8 mgmt_class;
 
-	/* Make sure MAD registration request supplied */
-	if (!mad_reg_req)
-		return 0;
-
-	private = priv->qp_info->port_priv;
-	mgmt_class = convert_mgmt_class(mad_reg_req->mgmt_class);
-	class = &private->version[mad_reg_req->mgmt_class_version];
+	port_priv = agent_priv->qp_info->port_priv;
+	class = &port_priv->version[mad_reg_req->mgmt_class_version].class; 
 	if (!*class) {
 		/* Allocate management class table for "new" class version */
 		*class = kmalloc(sizeof **class, GFP_ATOMIC);
@@ -760,9 +854,8 @@
 			ret = -ENOMEM;
 			goto error1;
 		}
-		/* Clear management class table for this class version */
-		memset((*class)->method_table, 0,
-		       sizeof((*class)->method_table));
+		/* Clear management class table */
+		memset(*class, 0, sizeof(**class));
 		/* Allocate method table for this management class */
 		method = &(*class)->method_table[mgmt_class];
 		if ((ret = allocate_method_table(method)))
@@ -782,17 +875,17 @@
 
 	/* Finally, add in methods being registered */
 	for (i = find_first_bit(mad_reg_req->method_mask,
-				IB_MGMT_MAX_METHODS); 
+				IB_MGMT_MAX_METHODS);
 	     i < IB_MGMT_MAX_METHODS;
 	     i = find_next_bit(mad_reg_req->method_mask, IB_MGMT_MAX_METHODS,
 			       1+i)) {
-		(*method)->agent[i] = priv;
+		(*method)->agent[i] = agent_priv;
 	}
 	return 0;
 
 error3:
 	/* Remove any methods for this mad agent */
-	remove_methods_mad_agent(*method, priv);
+	remove_methods_mad_agent(*method, agent_priv);
 	/* Now, check to see if there are any methods in use */
 	if (!check_method_table(*method)) {
 		/* If not, release management method table */
@@ -808,11 +901,138 @@
 	return ret;
 }
 
+static int add_oui_reg_req(struct ib_mad_reg_req *mad_reg_req,
+			   struct ib_mad_agent_private *agent_priv)
+{
+	struct ib_mad_port_private *port_priv;
+	struct ib_mad_mgmt_vendor_class_table **vendor_table;
+	struct ib_mad_mgmt_vendor_class_table *vendor = NULL;
+	struct ib_mad_mgmt_vendor_class *vendor_class = NULL;
+	struct ib_mad_mgmt_method_table **method;
+	int i, ret = -ENOMEM;
+	u8 vclass;
+
+	/* "New" vendor (with OUI) class */
+	vclass = vendor_class_index(mad_reg_req->mgmt_class);
+	port_priv = agent_priv->qp_info->port_priv;
+	vendor_table = &port_priv->version[
+				mad_reg_req->mgmt_class_version].vendor;
+	if (!*vendor_table) {
+		/* Allocate mgmt vendor class table for "new" class version */
+		vendor = kmalloc(sizeof *vendor, GFP_ATOMIC);
+		if (!vendor) {
+			printk(KERN_ERR PFX "No memory for "
+			       "ib_mad_mgmt_vendor_class_table\n");
+			goto error1;
+		}
+		/* Clear management vendor class table */
+		memset(vendor, 0, sizeof(*vendor));
+		*vendor_table = vendor;
+	}
+	if (!(*vendor_table)->vendor_class[vclass]) {
+		/* Allocate table for this management vendor class */
+		vendor_class = kmalloc(sizeof *vendor_class, GFP_ATOMIC);
+		if (!vendor_class) {
+			printk(KERN_ERR PFX "No memory for "
+			       "ib_mad_mgmt_vendor_class\n");
+			goto error2;
+		}
+		memset(vendor_class, 0, sizeof(*vendor_class));
+		(*vendor_table)->vendor_class[vclass] = vendor_class; 
+	}
+	for (i = 0; i < MAX_MGMT_OUI; i++) {
+		/* Is there matching OUI for this vendor class ? */
+		if (!memcmp((*vendor_table)->vendor_class[vclass]->oui[i],
+			    mad_reg_req->oui, 3)) {
+			method = &(*vendor_table)->vendor_class[
+						vclass]->method_table[i];
+			BUG_ON(!*method);
+			goto check_in_use;
+		}
+	}
+	for (i = 0; i < MAX_MGMT_OUI; i++) {
+		/* OUI slot available ? */
+		if (!is_vendor_oui((*vendor_table)->vendor_class[
+				vclass]->oui[i])) {
+			method = &(*vendor_table)->vendor_class[
+				vclass]->method_table[i];
+			BUG_ON(*method);
+			/* Allocate method table for this OUI */
+			if ((ret = allocate_method_table(method)))
+				goto error3;
+			memcpy((*vendor_table)->vendor_class[vclass]->oui[i],
+			       mad_reg_req->oui, 3);
+			goto check_in_use;
+		}
+	}
+	printk(KERN_ERR PFX "All OUI slots in use\n");
+	goto error3;
+
+check_in_use:
+	/* Now, make sure methods are not already in use */
+	if (method_in_use(method, mad_reg_req))
+		goto error4;
+
+	/* Finally, add in methods being registered */
+	for (i = find_first_bit(mad_reg_req->method_mask,
+				IB_MGMT_MAX_METHODS); 
+	     i < IB_MGMT_MAX_METHODS;
+	     i = find_next_bit(mad_reg_req->method_mask, IB_MGMT_MAX_METHODS,
+			       1+i)) {
+		(*method)->agent[i] = agent_priv;
+	}
+	return 0;
+
+error4:
+	/* Remove any methods for this mad agent */
+	remove_methods_mad_agent(*method, agent_priv);
+	/* Now, check to see if there are any methods in use */
+	if (!check_method_table(*method)) {
+		/* If not, release management method table */
+		kfree(*method);
+		*method = NULL;
+	}
+	ret = -EINVAL;
+error3:
+	if (vendor_class) {
+		(*vendor_table)->vendor_class[vclass] = NULL;	
+		kfree(vendor_class);
+	}
+error2:
+	if (vendor) {
+		*vendor_table = NULL;
+		kfree(vendor);
+	}
+error1:
+	return ret;
+}
+
+static int add_mad_reg_req(struct ib_mad_reg_req *mad_reg_req,
+			   struct ib_mad_agent_private *priv)
+{
+	int ret;
+	u8 mgmt_class;
+
+	/* Make sure MAD registration request supplied */
+	if (!mad_reg_req)
+		return 0;
+
+	mgmt_class = convert_mgmt_class(mad_reg_req->mgmt_class);
+	if (!is_vendor_class(mgmt_class))
+		ret = add_nonoui_reg_req(mad_reg_req, priv, mgmt_class);
+	else
+		ret = add_oui_reg_req(mad_reg_req, priv);
+	return ret;
+}
+
 static void remove_mad_reg_req(struct ib_mad_agent_private *agent_priv)
 {
 	struct ib_mad_port_private *port_priv;
 	struct ib_mad_mgmt_class_table *class;
 	struct ib_mad_mgmt_method_table *method;
+	struct ib_mad_mgmt_vendor_class_table *vendor;
+	struct ib_mad_mgmt_vendor_class *vendor_class;
+	int index;
 	u8 mgmt_class;
 
 	/*
@@ -824,12 +1044,10 @@
 	}
 
 	port_priv = agent_priv->qp_info->port_priv;
-	class = port_priv->version[agent_priv->reg_req->mgmt_class_version];
-	if (!class) {
-		printk(KERN_ERR PFX "No class table yet MAD registration "
-		       "request supplied\n");
-		goto out;
-	}
+	class = port_priv->version[
+			agent_priv->reg_req->mgmt_class_version].class;
+	if (!class)
+		goto vendor_check;
 
 	mgmt_class = convert_mgmt_class(agent_priv->reg_req->mgmt_class);
 	method = class->method_table[mgmt_class];
@@ -845,12 +1063,56 @@
 			if (!check_class_table(class)) {
 				/* If not, release management class table */
 				kfree(class);
-				port_priv->version[agent_priv->reg_req->
-						   mgmt_class_version]= NULL;
+				port_priv->version[
+					agent_priv->reg_req->
+					mgmt_class_version].class = NULL;
 			}
 		}
 	}
 
+vendor_check:
+	vendor = port_priv->version[
+			agent_priv->reg_req->mgmt_class_version].vendor;
+	if (!vendor)
+		goto out;
+
+	mgmt_class = vendor_class_index(agent_priv->reg_req->mgmt_class);
+	vendor_class = vendor->vendor_class[mgmt_class];
+	if (vendor_class) {
+		index = find_vendor_oui(vendor_class, agent_priv->reg_req->oui);
+		if (index == -1)
+			goto out;
+		method = vendor_class->method_table[index];
+		if (method) {
+			/* Remove any methods for this mad agent */
+			remove_methods_mad_agent(method, agent_priv);
+			/*
+			 * Now, check to see if there are
+			 * any methods still in use
+			 */
+			if (!check_method_table(method)) {
+				/* If not, release management method table */
+				kfree(method);
+				vendor_class->method_table[index] = NULL;
+				memset(vendor_class->oui[index], 0, 3);
+				/* Any OUIs left ? */
+				if (!check_vendor_class(vendor_class)) {
+					/* If not, release vendor class table */
+					kfree(vendor_class);
+					vendor->vendor_class[mgmt_class] = NULL;
+					/* Any other vendor classes left ? */
+					if (!check_vendor_table(vendor)) {
+						kfree(vendor); 
+						port_priv->version[
+							agent_priv->reg_req->
+							mgmt_class_version].
+							vendor = NULL;
+					}
+				}
+			}
+		}
+	}
+
 out:
 	return;
 }
@@ -907,20 +1169,49 @@
 			}
 		}
 	} else {
-		struct ib_mad_mgmt_class_table *version;
-		struct ib_mad_mgmt_method_table *class;
+		struct ib_mad_mgmt_class_table *class;
+		struct ib_mad_mgmt_method_table *method;
+		struct ib_mad_mgmt_vendor_class_table *vendor;
+		struct ib_mad_mgmt_vendor_class *vendor_class;
+		struct ib_vendor_mad *vendor_mad;
+		int index;
 
-		/* Routing is based on version, class, and method */
+		/*
+		 * Routing is based on version, class, and method
+		 * For "newer" vendor MADs, also based on OUI
+		 */
 		if (mad->mad_hdr.class_version >= MAX_MGMT_VERSION)
 			goto out;
-		version = port_priv->version[mad->mad_hdr.class_version];
-		if (!version)
-			goto out;
-		class = version->method_table[convert_mgmt_class(
+		if (!is_vendor_class(mad->mad_hdr.mgmt_class)) {
+			class = port_priv->version[
+					mad->mad_hdr.class_version].class;
+			if (!class)
+				goto out;
+			method = class->method_table[convert_mgmt_class(
+							mad->mad_hdr.mgmt_class)];
+			if (method)
+				mad_agent = method->agent[mad->mad_hdr.method &
+							  ~IB_MGMT_METHOD_RESP];
+		} else {
+			vendor = port_priv->version[
+					mad->mad_hdr.class_version].vendor;
+			if (!vendor)
+				goto out;
+			vendor_class = vendor->vendor_class[vendor_class_index(
 						mad->mad_hdr.mgmt_class)];
-		if (class)
-			mad_agent = class->agent[mad->mad_hdr.method &
-						 ~IB_MGMT_METHOD_RESP];
+			if (!vendor_class)
+				goto out;
+			/* Find matching OUI */
+			vendor_mad = (struct ib_vendor_mad *)mad;
+			index = find_vendor_oui(vendor_class, vendor_mad->oui);
+			if (index == -1)
+				goto out;
+			method = vendor_class->method_table[index];
+			if (method) {
+				mad_agent = method->agent[mad->mad_hdr.method &
+							  ~IB_MGMT_METHOD_RESP];
+			}
+		}
 	}
 
 	if (mad_agent) {



More information about the general mailing list