svn commit: r217179 - in projects/ofed/head/sys/ofed: drivers/infiniband/hw/mlx4 drivers/infiniband/ulp/ipoib include/linux include/rdma

Jeff Roberson jeff at FreeBSD.org
Sun Jan 9 04:48:50 UTC 2011


Author: jeff
Date: Sun Jan  9 04:48:50 2011
New Revision: 217179
URL: http://svn.freebsd.org/changeset/base/217179

Log:
   - Add support for VLANs to ipoib.  A seperate softc is allocated for
     each vlan and cached along with the virtual interface.
   - Fixup vlan support for IBOE in ib_addr.h.
  
  Sponsored by:	Isilon Systems, iX Systems, and Panasas.

Modified:
  projects/ofed/head/sys/ofed/drivers/infiniband/hw/mlx4/main.c
  projects/ofed/head/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c
  projects/ofed/head/sys/ofed/include/linux/if_vlan.h
  projects/ofed/head/sys/ofed/include/rdma/ib_addr.h

Modified: projects/ofed/head/sys/ofed/drivers/infiniband/hw/mlx4/main.c
==============================================================================
--- projects/ofed/head/sys/ofed/drivers/infiniband/hw/mlx4/main.c	Sun Jan  9 04:47:34 2011	(r217178)
+++ projects/ofed/head/sys/ofed/drivers/infiniband/hw/mlx4/main.c	Sun Jan  9 04:48:50 2011	(r217179)
@@ -1124,15 +1124,14 @@ static int update_ipv6_gids(struct mlx4_
 		goto out;
 	}
 
-	/* XXX vlan */
 #ifdef __linux__
 	read_lock(&dev_base_lock);
 	for_each_netdev(&init_net, tmp) {
-		if (ndev && (tmp == ndev || rdma_vlan_dev_real_dev(tmp) == ndev)) {
 #else
-		tmp = ndev;
-		if (ndev) {
+	IFNET_RLOCK();
+	TAILQ_FOREACH(tmp, &V_ifnet, if_link) {
 #endif
+		if (ndev && (tmp == ndev || rdma_vlan_dev_real_dev(tmp) == ndev)) {
 			gid.global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL);
 			vid = rdma_vlan_dev_vlan_id(tmp);
 			mlx4_addrconf_ifid_eui48(&gid.raw[8], vid, ndev);
@@ -1164,6 +1163,9 @@ static int update_ipv6_gids(struct mlx4_
 #ifdef __linux__
 	}
 	read_unlock(&dev_base_lock);
+#else
+	}
+	IFNET_RUNLOCK();
 #endif
 
 	for (i = 0; i < MLX4_MAX_EFF_VLANS + 1; ++i)

Modified: projects/ofed/head/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c
==============================================================================
--- projects/ofed/head/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c	Sun Jan  9 04:47:34 2011	(r217178)
+++ projects/ofed/head/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c	Sun Jan  9 04:48:50 2011	(r217179)
@@ -46,6 +46,7 @@ static	int ipoib_resolvemulti(struct ifn
 #include <linux/vmalloc.h>
 
 #include <linux/if_arp.h>	/* For ARPHRD_xxx */
+#include <linux/if_vlan.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
 
@@ -115,24 +116,16 @@ ipoib_open(struct ipoib_dev_priv *priv)
 	if (ipoib_ib_dev_up(priv))
 		goto err_stop;
 
-#if 0 /* XXX */
 	if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) {
 		struct ipoib_dev_priv *cpriv;
 
 		/* Bring up any child interfaces too */
 		mutex_lock(&priv->vlan_mutex);
-		list_for_each_entry(cpriv, &priv->child_intfs, list) {
-			int flags;
-
-			flags = cpriv->dev->flags;
-			if (flags & IFF_UP)
-				continue;
-
-			dev_change_flags(cpriv->dev, flags | IFF_UP);
-		}
+		list_for_each_entry(cpriv, &priv->child_intfs, list)
+			if ((cpriv->dev->if_drv_flags & IFF_DRV_RUNNING) == 0)
+				ipoib_open(cpriv);
 		mutex_unlock(&priv->vlan_mutex);
 	}
-#endif
 	dev->if_drv_flags |= IFF_DRV_RUNNING;
 	dev->if_drv_flags &= ~IFF_DRV_OACTIVE;
 
@@ -175,24 +168,16 @@ ipoib_stop(struct ipoib_dev_priv *priv)
 	ipoib_ib_dev_down(priv, 0);
 	ipoib_ib_dev_stop(priv, 0);
 
-#if 0 /* XXX */
 	if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) {
 		struct ipoib_dev_priv *cpriv;
 
 		/* Bring down any child interfaces too */
 		mutex_lock(&priv->vlan_mutex);
-		list_for_each_entry(cpriv, &priv->child_intfs, list) {
-			int flags;
-
-			flags = cpriv->dev->if_flags;
-			if (!(flags & IFF_UP))
-				continue;
-
-			dev_change_flags(cpriv->dev, flags & ~IFF_UP);
-		}
+		list_for_each_entry(cpriv, &priv->child_intfs, list)
+			if ((cpriv->dev->if_drv_flags & IFF_DRV_RUNNING) != 0)
+				ipoib_stop(cpriv);
 		mutex_unlock(&priv->vlan_mutex);
 	}
-#endif
 
 	return 0;
 }
@@ -235,13 +220,6 @@ ipoib_ioctl(struct ifnet *ifp, u_long co
 	struct ifreq *ifr = (struct ifreq *) data;
 	int error = 0;
 
-	/*
-	 * We may be called if if_vlan.c doesn't handle something however,
-	 * if_softc is not our softc in this case.
-	 */
-	if (ifp->if_type != IFT_INFINIBAND)
-		return (EINVAL);
-
 	switch (command) {
 	case SIOCSIFFLAGS:
 		if (ifp->if_flags & IFF_UP) {
@@ -687,30 +665,52 @@ ipoib_send_one(struct ipoib_dev_priv *pr
 	return 0;
 }
 
+
 static void
-ipoib_start(struct ifnet *dev)
+_ipoib_start(struct ifnet *dev, struct ipoib_dev_priv *priv)
 {
-	struct ipoib_dev_priv *priv;
 	struct mbuf *mb;
 
 	if ((dev->if_drv_flags & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) !=
 	    IFF_DRV_RUNNING)
 		return;
 
-	priv = dev->if_softc;
 	spin_lock(&priv->lock);
 	while (!IFQ_DRV_IS_EMPTY(&dev->if_snd) &&
 	    (dev->if_drv_flags & IFF_DRV_OACTIVE) == 0) {
 		IFQ_DRV_DEQUEUE(&dev->if_snd, mb);
 		if (mb == NULL)
 			break;
-
 		BPF_MTAP(dev, mb);
 		ipoib_send_one(priv, mb);
 	}
 	spin_unlock(&priv->lock);
 }
 
+static void
+ipoib_start(struct ifnet *dev)
+{
+	_ipoib_start(dev, dev->if_softc);
+}
+
+static void
+ipoib_vlan_start(struct ifnet *dev)
+{
+	struct ipoib_dev_priv *priv;
+	struct mbuf *mb;
+
+	priv = VLAN_COOKIE(dev);
+	if (priv != NULL)
+		return _ipoib_start(dev, priv);
+	while (!IFQ_DRV_IS_EMPTY(&dev->if_snd)) {
+		IFQ_DRV_DEQUEUE(&dev->if_snd, mb);
+		if (mb == NULL)
+			break;
+		m_freem(mb);
+		dev->if_oerrors++;
+	}
+}
+
 int
 ipoib_dev_init(struct ipoib_dev_priv *priv, struct ib_device *ca, int port)
 {
@@ -750,13 +750,18 @@ out:
 }
 
 static void
-ipoib_detach(struct ifnet *dev)
+ipoib_detach(struct ipoib_dev_priv *priv)
 {
-	struct ipoib_dev_priv *priv = dev->if_softc;
+	struct ifnet *dev;
+
+	dev = priv->dev;
+	if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) {
+		bpfdetach(dev);
+		if_detach(dev);
+		if_free(dev);
+	} else
+		VLAN_SETCOOKIE(priv->dev, NULL);
 
-	bpfdetach(dev);
-	if_detach(dev);
-	if_free(dev);
 	free(priv, M_TEMP);
 }
 
@@ -768,7 +773,7 @@ ipoib_dev_cleanup(struct ipoib_dev_priv 
 	/* Delete any child interfaces first */
 	list_for_each_entry_safe(cpriv, tcpriv, &priv->child_intfs, list) {
 		ipoib_dev_cleanup(cpriv);
-		ipoib_detach(cpriv->dev);
+		ipoib_detach(cpriv);
 	}
 
 	ipoib_ib_dev_cleanup(priv);
@@ -821,6 +826,31 @@ static int get_mb_hdr(struct mbuf *mb, v
 
 static volatile int ipoib_unit;
 
+static struct ipoib_dev_priv *
+ipoib_priv_alloc(void)
+{
+	struct ipoib_dev_priv *priv;
+
+	priv = malloc(sizeof(struct ipoib_dev_priv), M_TEMP, M_ZERO|M_WAITOK);
+	spin_lock_init(&priv->lock);
+	mutex_init(&priv->vlan_mutex);
+	INIT_LIST_HEAD(&priv->path_list);
+	INIT_LIST_HEAD(&priv->child_intfs);
+	INIT_LIST_HEAD(&priv->dead_ahs);
+	INIT_LIST_HEAD(&priv->multicast_list);
+	INIT_DELAYED_WORK(&priv->pkey_poll_task, ipoib_pkey_poll);
+	INIT_DELAYED_WORK(&priv->mcast_task,   ipoib_mcast_join_task);
+	INIT_WORK(&priv->carrier_on_task, ipoib_mcast_carrier_on_task);
+	INIT_WORK(&priv->flush_light,   ipoib_ib_dev_flush_light);
+	INIT_WORK(&priv->flush_normal,   ipoib_ib_dev_flush_normal);
+	INIT_WORK(&priv->flush_heavy,   ipoib_ib_dev_flush_heavy);
+	INIT_WORK(&priv->restart_task, ipoib_mcast_restart_task);
+	INIT_DELAYED_WORK(&priv->ah_reap_task, ipoib_reap_ah);
+	memcpy(priv->broadcastaddr, ipv4_bcast_addr, INFINIBAND_ALEN);
+
+	return (priv);
+}
+
 struct ipoib_dev_priv *
 ipoib_intf_alloc(const char *name)
 {
@@ -828,7 +858,7 @@ ipoib_intf_alloc(const char *name)
 	struct sockaddr_dl *sdl;
 	struct ifnet *dev;
 
-	priv = malloc(sizeof(struct ipoib_dev_priv), M_TEMP, M_ZERO|M_WAITOK);
+	priv = ipoib_priv_alloc();
 	dev = priv->dev = if_alloc(IFT_INFINIBAND);
 	if (!dev) {
 		free(priv, M_TEMP);
@@ -848,35 +878,14 @@ ipoib_intf_alloc(const char *name)
 	dev->if_resolvemulti = ipoib_resolvemulti;
 	dev->if_baudrate = IF_Gbps(10LL);
 	dev->if_broadcastaddr = priv->broadcastaddr;
-	memcpy(priv->broadcastaddr, ipv4_bcast_addr, INFINIBAND_ALEN);
 	dev->if_snd.ifq_maxlen = ipoib_sendq_size * 2;
 	sdl = (struct sockaddr_dl *)dev->if_addr->ifa_addr;
 	sdl->sdl_type = IFT_INFINIBAND;
 	sdl->sdl_alen = dev->if_addrlen;
 	priv->dev = dev;
 	if_link_state_change(dev, LINK_STATE_DOWN);
-
 	bpfattach(dev, DLT_EN10MB, IPOIB_HEADER_LEN);
 
-	spin_lock_init(&priv->lock);
-
-	mutex_init(&priv->vlan_mutex);
-
-	INIT_LIST_HEAD(&priv->path_list);
-	INIT_LIST_HEAD(&priv->child_intfs);
-	INIT_LIST_HEAD(&priv->dead_ahs);
-	INIT_LIST_HEAD(&priv->multicast_list);
-
-	INIT_DELAYED_WORK(&priv->pkey_poll_task, ipoib_pkey_poll);
-	INIT_DELAYED_WORK(&priv->mcast_task,   ipoib_mcast_join_task);
-	INIT_WORK(&priv->carrier_on_task, ipoib_mcast_carrier_on_task);
-	INIT_WORK(&priv->flush_light,   ipoib_ib_dev_flush_light);
-	INIT_WORK(&priv->flush_normal,   ipoib_ib_dev_flush_normal);
-	INIT_WORK(&priv->flush_heavy,   ipoib_ib_dev_flush_heavy);
-	INIT_WORK(&priv->restart_task, ipoib_mcast_restart_task);
-	INIT_DELAYED_WORK(&priv->ah_reap_task, ipoib_reap_ah);
-
-
 	return dev->if_softc;
 }
 
@@ -999,7 +1008,7 @@ event_failed:
 	ipoib_dev_cleanup(priv);
 
 device_init_failed:
-	ipoib_detach(priv->dev);
+	ipoib_detach(priv);
 
 alloc_mem_failed:
 	return ERR_PTR(result);
@@ -1065,12 +1074,110 @@ ipoib_remove_one(struct ib_device *devic
 		flush_workqueue(ipoib_workqueue);
 
 		ipoib_dev_cleanup(priv);
-		ipoib_detach(priv->dev);
+		ipoib_detach(priv);
 	}
 
 	kfree(dev_list);
 }
 
+static void
+ipoib_config_vlan(void *arg, struct ifnet *ifp, u_int16_t vtag)
+{
+	struct ipoib_dev_priv *parent;
+	struct ipoib_dev_priv *priv;
+	struct ifnet *dev;
+	uint16_t pkey;
+	int error;
+
+	if (ifp->if_type != IFT_INFINIBAND)
+		return;
+	dev = VLAN_DEVAT(ifp, vtag);
+	if (dev == NULL)
+		return;
+	priv = NULL;
+	error = 0;
+	parent = ifp->if_softc;
+	/* We only support 15 bits of pkey. */
+	if (vtag & 0x8000)
+		return;
+	pkey = vtag | 0x8000;	/* Set full membership bit. */
+	if (pkey == parent->pkey)
+		return;
+	/* Check for dups */
+	mutex_lock(&parent->vlan_mutex);
+	list_for_each_entry(priv, &parent->child_intfs, list) {
+		if (priv->pkey == pkey) {
+			priv = NULL;
+			error = EBUSY;
+			goto out;
+		}
+	}
+	priv = ipoib_priv_alloc();
+	priv->dev = dev;
+	priv->max_ib_mtu = parent->max_ib_mtu;
+	priv->mcast_mtu = priv->admin_mtu = parent->dev->if_mtu;
+	set_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags);
+	error = ipoib_set_dev_features(priv, parent->ca);
+	if (error)
+		goto out;
+	priv->pkey = pkey;
+	priv->broadcastaddr[8] = pkey >> 8;
+	priv->broadcastaddr[9] = pkey & 0xff;
+	dev->if_broadcastaddr = priv->broadcastaddr;
+	error = ipoib_dev_init(priv, parent->ca, parent->port);
+	if (error)
+		goto out;
+	priv->parent = parent->dev;
+	list_add_tail(&priv->list, &parent->child_intfs);
+	VLAN_SETCOOKIE(dev, priv);
+	dev->if_start = ipoib_vlan_start;
+	dev->if_drv_flags &= ~IFF_DRV_RUNNING;
+	dev->if_hdrlen = IPOIB_HEADER_LEN;
+	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+		ipoib_open(priv);
+	mutex_unlock(&parent->vlan_mutex);
+	return;
+out:
+	mutex_unlock(&parent->vlan_mutex);
+	if (priv)
+		free(priv, M_TEMP);
+	if (error)
+		ipoib_warn(parent,
+		    "failed to initialize subinterface: device %s, port %d vtag 0x%X",
+		    parent->ca->name, parent->port, vtag);
+	return;
+}
+
+static void
+ipoib_unconfig_vlan(void *arg, struct ifnet *ifp, u_int16_t vtag)
+{
+	struct ipoib_dev_priv *parent;
+	struct ipoib_dev_priv *priv;
+	struct ifnet *dev;
+	uint16_t pkey;
+
+	if (ifp->if_type != IFT_INFINIBAND)
+		return;
+
+	dev = VLAN_DEVAT(ifp, vtag);
+	if (dev)
+		VLAN_SETCOOKIE(dev, NULL);
+	pkey = vtag | 0x8000;
+	parent = ifp->if_softc;
+	mutex_lock(&parent->vlan_mutex);
+	list_for_each_entry(priv, &parent->child_intfs, list) {
+		if (priv->pkey == pkey) {
+			ipoib_dev_cleanup(priv);
+			list_del(&priv->list);
+			break;
+		}
+	}
+	mutex_unlock(&parent->vlan_mutex);
+}
+
+eventhandler_tag ipoib_vlan_attach;
+eventhandler_tag ipoib_vlan_detach;
+
 static int __init
 ipoib_init_module(void)
 {
@@ -1088,6 +1195,11 @@ ipoib_init_module(void)
 	ipoib_max_conn_qp = min(ipoib_max_conn_qp, IPOIB_CM_MAX_CONN_QP);
 #endif
 
+	ipoib_vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
+		ipoib_config_vlan, NULL, EVENTHANDLER_PRI_FIRST);
+	ipoib_vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
+		ipoib_unconfig_vlan, NULL, EVENTHANDLER_PRI_FIRST);
+
 	/*
 	 * We create our own workqueue mainly because we want to be
 	 * able to flush it when devices are being removed.  We can't
@@ -1121,6 +1233,9 @@ err_fs:
 static void __exit
 ipoib_cleanup_module(void)
 {
+
+	EVENTHANDLER_DEREGISTER(vlan_config, ipoib_vlan_attach);
+	EVENTHANDLER_DEREGISTER(vlan_unconfig, ipoib_vlan_detach);
 	ib_unregister_client(&ipoib_client);
 	ib_sa_unregister_client(&ipoib_sa_client);
 	destroy_workqueue(ipoib_workqueue);

Modified: projects/ofed/head/sys/ofed/include/linux/if_vlan.h
==============================================================================
--- projects/ofed/head/sys/ofed/include/linux/if_vlan.h	Sun Jan  9 04:47:34 2011	(r217178)
+++ projects/ofed/head/sys/ofed/include/linux/if_vlan.h	Sun Jan  9 04:48:50 2011	(r217179)
@@ -28,4 +28,8 @@
 
 #ifndef	_LINUX_IF_VLAN_H_
 #define	_LINUX_IF_VLAN_H_
+
+#include <net/ethernet.h>
+#include <net/if_vlan_var.h>
+
 #endif	/* _LINUX_IF_VLAN_H_ */

Modified: projects/ofed/head/sys/ofed/include/rdma/ib_addr.h
==============================================================================
--- projects/ofed/head/sys/ofed/include/rdma/ib_addr.h	Sun Jan  9 04:47:34 2011	(r217178)
+++ projects/ofed/head/sys/ofed/include/rdma/ib_addr.h	Sun Jan  9 04:48:50 2011	(r217179)
@@ -154,8 +154,11 @@ static inline u16 rdma_vlan_dev_vlan_id(
 	return dev->priv_flags & IFF_802_1Q_VLAN ?
 		vlan_dev_vlan_id(dev) : 0xffff;
 #else
-	/* XXX vlan */
-	return 0xffff;
+	int tag;
+
+	if (VLAN_TAG(__DECONST(struct ifnet *, dev), &tag) != 0)
+		return 0xffff;
+	return tag;
 #endif
 }
 
@@ -302,7 +305,7 @@ static inline struct net_device *rdma_vl
 	return dev->priv_flags & IFF_802_1Q_VLAN ?
 		vlan_dev_real_dev(dev) : 0;
 #else
-	return __DECONST(struct net_device *, dev);
+	return VLAN_TRUNKDEV(__DECONST(struct ifnet *, dev));
 #endif
 }
 


More information about the svn-src-projects mailing list