xref: /titanic_53/usr/src/uts/sun4v/io/vnet.c (revision d10e4ef2fabf16c3237c6d6592496df3eac6a1ef)
11ae08745Sheppo /*
21ae08745Sheppo  * CDDL HEADER START
31ae08745Sheppo  *
41ae08745Sheppo  * The contents of this file are subject to the terms of the
51ae08745Sheppo  * Common Development and Distribution License (the "License").
61ae08745Sheppo  * You may not use this file except in compliance with the License.
71ae08745Sheppo  *
81ae08745Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91ae08745Sheppo  * or http://www.opensolaris.org/os/licensing.
101ae08745Sheppo  * See the License for the specific language governing permissions
111ae08745Sheppo  * and limitations under the License.
121ae08745Sheppo  *
131ae08745Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
141ae08745Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151ae08745Sheppo  * If applicable, add the following below this CDDL HEADER, with the
161ae08745Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
171ae08745Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
181ae08745Sheppo  *
191ae08745Sheppo  * CDDL HEADER END
201ae08745Sheppo  */
211ae08745Sheppo 
221ae08745Sheppo /*
231ae08745Sheppo  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
241ae08745Sheppo  * Use is subject to license terms.
251ae08745Sheppo  */
261ae08745Sheppo 
271ae08745Sheppo #pragma ident	"%Z%%M%	%I%	%E% SMI"
281ae08745Sheppo 
291ae08745Sheppo #include <sys/types.h>
301ae08745Sheppo #include <sys/errno.h>
311ae08745Sheppo #include <sys/param.h>
321ae08745Sheppo #include <sys/stream.h>
331ae08745Sheppo #include <sys/kmem.h>
341ae08745Sheppo #include <sys/conf.h>
351ae08745Sheppo #include <sys/devops.h>
361ae08745Sheppo #include <sys/ksynch.h>
371ae08745Sheppo #include <sys/stat.h>
381ae08745Sheppo #include <sys/modctl.h>
391ae08745Sheppo #include <sys/debug.h>
401ae08745Sheppo #include <sys/ethernet.h>
411ae08745Sheppo #include <sys/dlpi.h>
421ae08745Sheppo #include <net/if.h>
431ae08745Sheppo #include <sys/mac.h>
44ba2e4443Sseb #include <sys/mac_ether.h>
451ae08745Sheppo #include <sys/ddi.h>
461ae08745Sheppo #include <sys/sunddi.h>
471ae08745Sheppo #include <sys/strsun.h>
481ae08745Sheppo #include <sys/note.h>
491ae08745Sheppo #include <sys/vnet.h>
501ae08745Sheppo 
511ae08745Sheppo /*
521ae08745Sheppo  * Function prototypes.
531ae08745Sheppo  */
541ae08745Sheppo 
551ae08745Sheppo /* DDI entrypoints */
561ae08745Sheppo static int vnetdevinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
571ae08745Sheppo static int vnetattach(dev_info_t *, ddi_attach_cmd_t);
581ae08745Sheppo static int vnetdetach(dev_info_t *, ddi_detach_cmd_t);
591ae08745Sheppo 
601ae08745Sheppo /* MAC entrypoints  */
61ba2e4443Sseb static int vnet_m_stat(void *, uint_t, uint64_t *);
621ae08745Sheppo static int vnet_m_start(void *);
631ae08745Sheppo static void vnet_m_stop(void *);
641ae08745Sheppo static int vnet_m_promisc(void *, boolean_t);
651ae08745Sheppo static int vnet_m_multicst(void *, boolean_t, const uint8_t *);
661ae08745Sheppo static int vnet_m_unicst(void *, const uint8_t *);
671ae08745Sheppo mblk_t *vnet_m_tx(void *, mblk_t *);
681ae08745Sheppo 
691ae08745Sheppo /* vnet internal functions */
701ae08745Sheppo static int vnet_mac_register(vnet_t *);
711ae08745Sheppo static int vnet_read_mac_address(vnet_t *vnetp);
721ae08745Sheppo static void vnet_add_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp);
731ae08745Sheppo static void vnet_del_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp);
741ae08745Sheppo static vp_tl_t *vnet_get_vptl(vnet_t *vnetp, const char *devname);
751ae08745Sheppo static fdb_t *vnet_lookup_fdb(fdb_fanout_t *fdbhp, uint8_t *macaddr);
761ae08745Sheppo 
771ae08745Sheppo /* exported functions */
781ae08745Sheppo void vnet_add_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg);
791ae08745Sheppo void vnet_del_fdb(void *arg, uint8_t *macaddr);
801ae08745Sheppo void vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg);
811ae08745Sheppo void vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg);
821ae08745Sheppo void vnet_del_def_rte(void *arg);
83ba2e4443Sseb void vnet_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp);
84ba2e4443Sseb void vnet_tx_update(void *arg);
851ae08745Sheppo 
861ae08745Sheppo /* externs */
87ba2e4443Sseb extern int vgen_init(void *vnetp, dev_info_t *vnetdip, const uint8_t *macaddr,
88ba2e4443Sseb 	mac_register_t **vgenmacp);
89*d10e4ef2Snarayan extern int vgen_uninit(void *arg);
901ae08745Sheppo 
91ba2e4443Sseb static mac_callbacks_t vnet_m_callbacks = {
92ba2e4443Sseb 	0,
93ba2e4443Sseb 	vnet_m_stat,
94ba2e4443Sseb 	vnet_m_start,
95ba2e4443Sseb 	vnet_m_stop,
96ba2e4443Sseb 	vnet_m_promisc,
97ba2e4443Sseb 	vnet_m_multicst,
98ba2e4443Sseb 	vnet_m_unicst,
99ba2e4443Sseb 	vnet_m_tx,
100ba2e4443Sseb 	NULL,
101ba2e4443Sseb 	NULL,
102ba2e4443Sseb 	NULL
103ba2e4443Sseb };
104ba2e4443Sseb 
1051ae08745Sheppo /*
1061ae08745Sheppo  * Linked list of "vnet_t" structures - one per instance.
1071ae08745Sheppo  */
1081ae08745Sheppo static vnet_t	*vnet_headp = NULL;
1091ae08745Sheppo static krwlock_t vnet_rw;
1101ae08745Sheppo 
1111ae08745Sheppo /* Tunables */
1121ae08745Sheppo uint32_t vnet_ntxds = VNET_NTXDS;	/* power of 2 transmit descriptors */
1131ae08745Sheppo uint32_t vnet_reclaim_lowat = VNET_RECLAIM_LOWAT;  /* tx recl low watermark */
1141ae08745Sheppo uint32_t vnet_reclaim_hiwat = VNET_RECLAIM_HIWAT;  /* tx recl high watermark */
1151ae08745Sheppo uint32_t vnet_ldcwd_interval = VNET_LDCWD_INTERVAL; /* watchdog freq in msec */
1161ae08745Sheppo uint32_t vnet_ldcwd_txtimeout = VNET_LDCWD_TXTIMEOUT;  /* tx timeout in msec */
1171ae08745Sheppo uint32_t vnet_ldc_qlen = VNET_LDC_QLEN;		/* ldc qlen */
1181ae08745Sheppo uint32_t vnet_nfdb_hash = VNET_NFDB_HASH;	/* size of fdb hash table */
119*d10e4ef2Snarayan uint32_t vnet_nrbufs = VNET_NRBUFS;	/* number of receive buffers */
1201ae08745Sheppo 
1211ae08745Sheppo /*
1221ae08745Sheppo  * Property names
1231ae08745Sheppo  */
1241ae08745Sheppo static char macaddr_propname[] = "local-mac-address";
1251ae08745Sheppo 
1261ae08745Sheppo /*
1271ae08745Sheppo  * This is the string displayed by modinfo(1m).
1281ae08745Sheppo  */
1298e6a2a04Slm66018 static char vnet_ident[] = "vnet driver v%I%";
1301ae08745Sheppo extern struct mod_ops mod_driverops;
1311ae08745Sheppo static struct cb_ops cb_vnetops = {
1321ae08745Sheppo 	nulldev,		/* cb_open */
1331ae08745Sheppo 	nulldev,		/* cb_close */
1341ae08745Sheppo 	nodev,			/* cb_strategy */
1351ae08745Sheppo 	nodev,			/* cb_print */
1361ae08745Sheppo 	nodev,			/* cb_dump */
1371ae08745Sheppo 	nodev,			/* cb_read */
1381ae08745Sheppo 	nodev,			/* cb_write */
1391ae08745Sheppo 	nodev,			/* cb_ioctl */
1401ae08745Sheppo 	nodev,			/* cb_devmap */
1411ae08745Sheppo 	nodev,			/* cb_mmap */
1421ae08745Sheppo 	nodev,			/* cb_segmap */
1431ae08745Sheppo 	nochpoll,		/* cb_chpoll */
1441ae08745Sheppo 	ddi_prop_op,		/* cb_prop_op */
1451ae08745Sheppo 	NULL,			/* cb_stream */
1461ae08745Sheppo 	(int)(D_MP)		/* cb_flag */
1471ae08745Sheppo };
1481ae08745Sheppo 
1491ae08745Sheppo static struct dev_ops vnetops = {
1501ae08745Sheppo 	DEVO_REV,		/* devo_rev */
1511ae08745Sheppo 	0,			/* devo_refcnt */
1521ae08745Sheppo 	NULL,			/* devo_getinfo */
1531ae08745Sheppo 	nulldev,		/* devo_identify */
1541ae08745Sheppo 	nulldev,		/* devo_probe */
1551ae08745Sheppo 	vnetattach,		/* devo_attach */
1561ae08745Sheppo 	vnetdetach,		/* devo_detach */
1571ae08745Sheppo 	nodev,			/* devo_reset */
1581ae08745Sheppo 	&cb_vnetops,		/* devo_cb_ops */
1591ae08745Sheppo 	(struct bus_ops *)NULL	/* devo_bus_ops */
1601ae08745Sheppo };
1611ae08745Sheppo 
1621ae08745Sheppo static struct modldrv modldrv = {
1631ae08745Sheppo 	&mod_driverops,		/* Type of module.  This one is a driver */
1641ae08745Sheppo 	vnet_ident,		/* ID string */
1651ae08745Sheppo 	&vnetops		/* driver specific ops */
1661ae08745Sheppo };
1671ae08745Sheppo 
1681ae08745Sheppo static struct modlinkage modlinkage = {
1691ae08745Sheppo 	MODREV_1, (void *)&modldrv, NULL
1701ae08745Sheppo };
1711ae08745Sheppo 
1721ae08745Sheppo 
1731ae08745Sheppo /*
1741ae08745Sheppo  * Print debug messages - set to 0xf to enable all msgs
1751ae08745Sheppo  */
1761ae08745Sheppo int _vnet_dbglevel = 0x8;
1771ae08745Sheppo 
1781ae08745Sheppo void
1791ae08745Sheppo _vnetdebug_printf(void *arg, const char *fmt, ...)
1801ae08745Sheppo {
1811ae08745Sheppo 	char    buf[512];
1821ae08745Sheppo 	va_list ap;
1831ae08745Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
1841ae08745Sheppo 
1851ae08745Sheppo 	va_start(ap, fmt);
1861ae08745Sheppo 	(void) vsprintf(buf, fmt, ap);
1871ae08745Sheppo 	va_end(ap);
1881ae08745Sheppo 
1891ae08745Sheppo 	if (vnetp == NULL)
1901ae08745Sheppo 		cmn_err(CE_CONT, "%s\n", buf);
1911ae08745Sheppo 	else
1921ae08745Sheppo 		cmn_err(CE_CONT, "vnet%d: %s\n", vnetp->instance, buf);
1931ae08745Sheppo }
1941ae08745Sheppo 
1951ae08745Sheppo #ifdef DEBUG
1961ae08745Sheppo 
1971ae08745Sheppo /*
1981ae08745Sheppo  * XXX: any changes to the definitions below need corresponding changes in
1991ae08745Sheppo  * vnet_gen.c
2001ae08745Sheppo  */
2011ae08745Sheppo 
2021ae08745Sheppo /*
2031ae08745Sheppo  * debug levels:
2041ae08745Sheppo  * DBG_LEVEL1:	Function entry/exit tracing
2051ae08745Sheppo  * DBG_LEVEL2:	Info messages
2061ae08745Sheppo  * DBG_LEVEL3:	Warning messages
2071ae08745Sheppo  * DBG_LEVEL4:	Error messages
2081ae08745Sheppo  */
2091ae08745Sheppo 
2101ae08745Sheppo enum	{ DBG_LEVEL1 = 0x01, DBG_LEVEL2 = 0x02, DBG_LEVEL3 = 0x04,
2111ae08745Sheppo 	    DBG_LEVEL4 = 0x08 };
2121ae08745Sheppo 
2131ae08745Sheppo #define	DBG1(_s)	do {						\
2141ae08745Sheppo 			    if ((_vnet_dbglevel & DBG_LEVEL1) != 0) {	\
2151ae08745Sheppo 					_vnetdebug_printf _s;		\
2161ae08745Sheppo 			    }					\
2171ae08745Sheppo 			_NOTE(CONSTCOND) } while (0)
2181ae08745Sheppo 
2191ae08745Sheppo #define	DBG2(_s)	do {						\
2201ae08745Sheppo 			    if ((_vnet_dbglevel & DBG_LEVEL2) != 0) {	\
2211ae08745Sheppo 					_vnetdebug_printf _s;		\
2221ae08745Sheppo 			    }					\
2231ae08745Sheppo 			_NOTE(CONSTCOND) } while (0)
2241ae08745Sheppo 
2251ae08745Sheppo #define	DWARN(_s)	do {						\
2261ae08745Sheppo 			    if ((_vnet_dbglevel & DBG_LEVEL3) != 0) {	\
2271ae08745Sheppo 					_vnetdebug_printf _s;		\
2281ae08745Sheppo 			    }					\
2291ae08745Sheppo 			_NOTE(CONSTCOND) } while (0)
2301ae08745Sheppo 
2311ae08745Sheppo #define	DERR(_s)	do {						\
2321ae08745Sheppo 			    if ((_vnet_dbglevel & DBG_LEVEL4) != 0) {	\
2331ae08745Sheppo 					_vnetdebug_printf _s;		\
2341ae08745Sheppo 			    }					\
2351ae08745Sheppo 			_NOTE(CONSTCOND) } while (0)
2361ae08745Sheppo 
2371ae08745Sheppo #else
2381ae08745Sheppo 
2391ae08745Sheppo #define	DBG1(_s)	if (0)	_vnetdebug_printf _s
2401ae08745Sheppo #define	DBG2(_s)	if (0)	_vnetdebug_printf _s
2411ae08745Sheppo #define	DWARN(_s)	if (0)	_vnetdebug_printf _s
2421ae08745Sheppo #define	DERR(_s)	if (0)	_vnetdebug_printf _s
2431ae08745Sheppo 
2441ae08745Sheppo #endif
2451ae08745Sheppo 
2461ae08745Sheppo /* _init(9E): initialize the loadable module */
2471ae08745Sheppo int
2481ae08745Sheppo _init(void)
2491ae08745Sheppo {
2501ae08745Sheppo 	int status;
2511ae08745Sheppo 
2521ae08745Sheppo 	DBG1((NULL, "_init: enter\n"));
2531ae08745Sheppo 
2541ae08745Sheppo 	mac_init_ops(&vnetops, "vnet");
2551ae08745Sheppo 	status = mod_install(&modlinkage);
2561ae08745Sheppo 	if (status != 0) {
2571ae08745Sheppo 		mac_fini_ops(&vnetops);
2581ae08745Sheppo 	}
2591ae08745Sheppo 
2601ae08745Sheppo 	DBG1((NULL, "_init: exit\n"));
2611ae08745Sheppo 	return (status);
2621ae08745Sheppo }
2631ae08745Sheppo 
2641ae08745Sheppo /* _fini(9E): prepare the module for unloading. */
2651ae08745Sheppo int
2661ae08745Sheppo _fini(void)
2671ae08745Sheppo {
2681ae08745Sheppo 	int status;
2691ae08745Sheppo 
2701ae08745Sheppo 	DBG1((NULL, "_fini: enter\n"));
2711ae08745Sheppo 
2721ae08745Sheppo 	status = mod_remove(&modlinkage);
2731ae08745Sheppo 	if (status != 0)
2741ae08745Sheppo 		return (status);
2751ae08745Sheppo 	mac_fini_ops(&vnetops);
2761ae08745Sheppo 
2771ae08745Sheppo 	DBG1((NULL, "_fini: exit\n"));
2781ae08745Sheppo 	return (status);
2791ae08745Sheppo }
2801ae08745Sheppo 
2811ae08745Sheppo /* _info(9E): return information about the loadable module */
2821ae08745Sheppo int
2831ae08745Sheppo _info(struct modinfo *modinfop)
2841ae08745Sheppo {
2851ae08745Sheppo 	return (mod_info(&modlinkage, modinfop));
2861ae08745Sheppo }
2871ae08745Sheppo 
2881ae08745Sheppo /*
2891ae08745Sheppo  * attach(9E): attach a device to the system.
2901ae08745Sheppo  * called once for each instance of the device on the system.
2911ae08745Sheppo  */
2921ae08745Sheppo static int
2931ae08745Sheppo vnetattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2941ae08745Sheppo {
2951ae08745Sheppo 	vnet_t		*vnetp;
2961ae08745Sheppo 	vp_tl_t		*vp_tlp;
2971ae08745Sheppo 	int		instance;
2981ae08745Sheppo 	int		status;
2991ae08745Sheppo 	enum		{ AST_init = 0x0, AST_vnet_alloc = 0x1,
300*d10e4ef2Snarayan 			    AST_mac_alloc = 0x2, AST_read_macaddr = 0x4,
301*d10e4ef2Snarayan 			    AST_vgen_init = 0x8, AST_vptl_alloc = 0x10,
302*d10e4ef2Snarayan 			    AST_fdbh_alloc = 0x20 }
3031ae08745Sheppo 			attach_state;
304ba2e4443Sseb 	mac_register_t	*vgenmacp = NULL;
3051ae08745Sheppo 	uint32_t	nfdbh = 0;
3061ae08745Sheppo 
3071ae08745Sheppo 	attach_state = AST_init;
3081ae08745Sheppo 
3091ae08745Sheppo 	switch (cmd) {
3101ae08745Sheppo 	case DDI_ATTACH:
3111ae08745Sheppo 		break;
3121ae08745Sheppo 	case DDI_RESUME:
3131ae08745Sheppo 	case DDI_PM_RESUME:
3141ae08745Sheppo 	default:
3151ae08745Sheppo 		goto vnet_attach_fail;
3161ae08745Sheppo 	}
3171ae08745Sheppo 
3181ae08745Sheppo 	instance = ddi_get_instance(dip);
3191ae08745Sheppo 	DBG1((NULL, "vnetattach: instance(%d) enter\n", instance));
3201ae08745Sheppo 
3211ae08745Sheppo 	/* allocate vnet_t and mac_t structures */
3221ae08745Sheppo 	vnetp = kmem_zalloc(sizeof (vnet_t), KM_SLEEP);
3231ae08745Sheppo 	attach_state |= AST_vnet_alloc;
3241ae08745Sheppo 
3251ae08745Sheppo 	/* setup links to vnet_t from both devinfo and mac_t */
3261ae08745Sheppo 	ddi_set_driver_private(dip, (caddr_t)vnetp);
3271ae08745Sheppo 	vnetp->dip = dip;
3281ae08745Sheppo 	vnetp->instance = instance;
3291ae08745Sheppo 
3301ae08745Sheppo 	/* read the mac address */
3311ae08745Sheppo 	status = vnet_read_mac_address(vnetp);
3321ae08745Sheppo 	if (status != DDI_SUCCESS) {
3331ae08745Sheppo 		goto vnet_attach_fail;
3341ae08745Sheppo 	}
3351ae08745Sheppo 	attach_state |= AST_read_macaddr;
3361ae08745Sheppo 
3371ae08745Sheppo 	/*
3381ae08745Sheppo 	 * Initialize the generic vnet proxy transport. This is the first
3391ae08745Sheppo 	 * and default transport used by vnet. The generic transport
3401ae08745Sheppo 	 * is provided by using sun4v LDC (logical domain channel). On success,
3411ae08745Sheppo 	 * vgen_init() provides a pointer to mac_t of generic transport.
3421ae08745Sheppo 	 * Currently, this generic layer provides network connectivity to other
3431ae08745Sheppo 	 * vnets within ldoms and also to remote hosts oustide ldoms through
3441ae08745Sheppo 	 * the virtual switch (vsw) device on domain0. In the future, when
3451ae08745Sheppo 	 * physical adapters that are able to share their resources (such as
3461ae08745Sheppo 	 * dma channels) with guest domains become available, the vnet device
3471ae08745Sheppo 	 * will use hardware specific driver to communicate directly over the
3481ae08745Sheppo 	 * physical device to reach remote hosts without going through vswitch.
3491ae08745Sheppo 	 */
350ba2e4443Sseb 	status = vgen_init(vnetp, vnetp->dip, (uint8_t *)vnetp->curr_macaddr,
351ba2e4443Sseb 	    &vgenmacp);
3521ae08745Sheppo 	if (status != DDI_SUCCESS) {
3531ae08745Sheppo 		DERR((vnetp, "vgen_init() failed\n"));
3541ae08745Sheppo 		goto vnet_attach_fail;
3551ae08745Sheppo 	}
3561ae08745Sheppo 	attach_state |= AST_vgen_init;
3571ae08745Sheppo 
3581ae08745Sheppo 	vp_tlp = kmem_zalloc(sizeof (vp_tl_t), KM_SLEEP);
3591ae08745Sheppo 	vp_tlp->macp = vgenmacp;
3601ae08745Sheppo 	(void) snprintf(vp_tlp->name, MAXNAMELEN, "%s%u", "vgen", instance);
3611ae08745Sheppo 	(void) strcpy(vnetp->vgen_name, vp_tlp->name);
3621ae08745Sheppo 
3631ae08745Sheppo 	/* add generic transport to the list of vnet proxy transports */
3641ae08745Sheppo 	vnet_add_vptl(vnetp, vp_tlp);
3651ae08745Sheppo 	attach_state |= AST_vptl_alloc;
3661ae08745Sheppo 
3671ae08745Sheppo 	nfdbh = vnet_nfdb_hash;
3681ae08745Sheppo 	if ((nfdbh < VNET_NFDB_HASH) || (nfdbh > VNET_NFDB_HASH_MAX)) {
3691ae08745Sheppo 		vnetp->nfdb_hash = VNET_NFDB_HASH;
3701ae08745Sheppo 	}
3711ae08745Sheppo 	else
3721ae08745Sheppo 		vnetp->nfdb_hash = nfdbh;
3731ae08745Sheppo 
3741ae08745Sheppo 	/* allocate fdb hash table, with an extra slot for default route */
3751ae08745Sheppo 	vnetp->fdbhp = kmem_zalloc(sizeof (fdb_fanout_t) *
3761ae08745Sheppo 	    (vnetp->nfdb_hash + 1), KM_SLEEP);
3771ae08745Sheppo 	attach_state |= AST_fdbh_alloc;
3781ae08745Sheppo 
3791ae08745Sheppo 	/* register with MAC layer */
3801ae08745Sheppo 	status = vnet_mac_register(vnetp);
3811ae08745Sheppo 	if (status != DDI_SUCCESS) {
3821ae08745Sheppo 		goto vnet_attach_fail;
3831ae08745Sheppo 	}
3841ae08745Sheppo 
3851ae08745Sheppo 	/* add to the list of vnet devices */
3861ae08745Sheppo 	WRITE_ENTER(&vnet_rw);
3871ae08745Sheppo 	vnetp->nextp = vnet_headp;
3881ae08745Sheppo 	vnet_headp = vnetp;
3891ae08745Sheppo 	RW_EXIT(&vnet_rw);
3901ae08745Sheppo 
3911ae08745Sheppo 	DBG1((NULL, "vnetattach: instance(%d) exit\n", instance));
3921ae08745Sheppo 	return (DDI_SUCCESS);
3931ae08745Sheppo 
3941ae08745Sheppo vnet_attach_fail:
3951ae08745Sheppo 	if (attach_state & AST_fdbh_alloc) {
3961ae08745Sheppo 		kmem_free(vnetp->fdbhp,
3971ae08745Sheppo 		    sizeof (fdb_fanout_t) * (vnetp->nfdb_hash + 1));
3981ae08745Sheppo 	}
3991ae08745Sheppo 	if (attach_state & AST_vptl_alloc) {
4001ae08745Sheppo 		WRITE_ENTER(&vnetp->trwlock);
4011ae08745Sheppo 		vnet_del_vptl(vnetp, vp_tlp);
4021ae08745Sheppo 		RW_EXIT(&vnetp->trwlock);
4031ae08745Sheppo 	}
4041ae08745Sheppo 	if (attach_state & AST_vgen_init) {
405*d10e4ef2Snarayan 		(void) vgen_uninit(vgenmacp->m_driver);
4061ae08745Sheppo 	}
4071ae08745Sheppo 	if (attach_state & AST_vnet_alloc) {
4081ae08745Sheppo 		KMEM_FREE(vnetp);
4091ae08745Sheppo 	}
4101ae08745Sheppo 	return (DDI_FAILURE);
4111ae08745Sheppo }
4121ae08745Sheppo 
4131ae08745Sheppo /*
4141ae08745Sheppo  * detach(9E): detach a device from the system.
4151ae08745Sheppo  */
4161ae08745Sheppo static int
4171ae08745Sheppo vnetdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
4181ae08745Sheppo {
4191ae08745Sheppo 	vnet_t		*vnetp;
4201ae08745Sheppo 	vnet_t		**vnetpp;
4211ae08745Sheppo 	vp_tl_t		*vp_tlp;
4221ae08745Sheppo 	int		instance;
423*d10e4ef2Snarayan 	int		rv;
4241ae08745Sheppo 
4251ae08745Sheppo 	instance = ddi_get_instance(dip);
4261ae08745Sheppo 	DBG1((NULL, "vnetdetach: instance(%d) enter\n", instance));
4271ae08745Sheppo 
4281ae08745Sheppo 	vnetp = ddi_get_driver_private(dip);
4291ae08745Sheppo 	if (vnetp == NULL) {
4301ae08745Sheppo 		goto vnet_detach_fail;
4311ae08745Sheppo 	}
4321ae08745Sheppo 
4331ae08745Sheppo 	switch (cmd) {
4341ae08745Sheppo 	case DDI_DETACH:
4351ae08745Sheppo 		break;
4361ae08745Sheppo 	case DDI_SUSPEND:
4371ae08745Sheppo 	case DDI_PM_SUSPEND:
4381ae08745Sheppo 	default:
4391ae08745Sheppo 		goto vnet_detach_fail;
4401ae08745Sheppo 	}
4411ae08745Sheppo 
442*d10e4ef2Snarayan 	/* uninit and free vnet proxy transports */
443*d10e4ef2Snarayan 	WRITE_ENTER(&vnetp->trwlock);
444*d10e4ef2Snarayan 	while ((vp_tlp = vnetp->tlp) != NULL) {
445*d10e4ef2Snarayan 		if (strcmp(vnetp->vgen_name, vp_tlp->name) == 0) {
446*d10e4ef2Snarayan 			/* uninitialize generic transport */
447*d10e4ef2Snarayan 			rv = vgen_uninit(vp_tlp->macp->m_driver);
448*d10e4ef2Snarayan 			if (rv != DDI_SUCCESS) {
449*d10e4ef2Snarayan 				RW_EXIT(&vnetp->trwlock);
450*d10e4ef2Snarayan 				goto vnet_detach_fail;
451*d10e4ef2Snarayan 			}
452*d10e4ef2Snarayan 		}
453*d10e4ef2Snarayan 		vnet_del_vptl(vnetp, vp_tlp);
454*d10e4ef2Snarayan 	}
455*d10e4ef2Snarayan 	RW_EXIT(&vnetp->trwlock);
456*d10e4ef2Snarayan 
4571ae08745Sheppo 	/*
4581ae08745Sheppo 	 * Unregister from the MAC subsystem.  This can fail, in
4591ae08745Sheppo 	 * particular if there are DLPI style-2 streams still open -
4601ae08745Sheppo 	 * in which case we just return failure.
4611ae08745Sheppo 	 */
462ba2e4443Sseb 	if (mac_unregister(vnetp->mh) != 0)
4631ae08745Sheppo 		goto vnet_detach_fail;
4641ae08745Sheppo 
4651ae08745Sheppo 	/* unlink from instance(vnet_t) list */
4661ae08745Sheppo 	WRITE_ENTER(&vnet_rw);
4671ae08745Sheppo 	for (vnetpp = &vnet_headp; *vnetpp; vnetpp = &(*vnetpp)->nextp) {
4681ae08745Sheppo 		if (*vnetpp == vnetp) {
4691ae08745Sheppo 			*vnetpp = vnetp->nextp;
4701ae08745Sheppo 			break;
4711ae08745Sheppo 		}
4721ae08745Sheppo 	}
4731ae08745Sheppo 	RW_EXIT(&vnet_rw);
4741ae08745Sheppo 
4751ae08745Sheppo 	KMEM_FREE(vnetp);
4761ae08745Sheppo 
4771ae08745Sheppo 	return (DDI_SUCCESS);
4781ae08745Sheppo 
4791ae08745Sheppo vnet_detach_fail:
4801ae08745Sheppo 	return (DDI_FAILURE);
4811ae08745Sheppo }
4821ae08745Sheppo 
4831ae08745Sheppo /* enable the device for transmit/receive */
4841ae08745Sheppo static int
4851ae08745Sheppo vnet_m_start(void *arg)
4861ae08745Sheppo {
4871ae08745Sheppo 	vnet_t		*vnetp = arg;
4881ae08745Sheppo 	vp_tl_t		*vp_tlp;
489ba2e4443Sseb 	mac_register_t	*vp_macp;
490ba2e4443Sseb 	mac_callbacks_t	*cbp;
4911ae08745Sheppo 
4921ae08745Sheppo 	DBG1((vnetp, "vnet_m_start: enter\n"));
4931ae08745Sheppo 
4941ae08745Sheppo 	/*
4951ae08745Sheppo 	 * XXX
4961ae08745Sheppo 	 * Currently, we only have generic transport. m_start() invokes
4971ae08745Sheppo 	 * vgen_start() which enables ports/channels in vgen and
4981ae08745Sheppo 	 * initiates handshake with peer vnets and vsw. In the future when we
4991ae08745Sheppo 	 * have support for hardware specific transports, this information
5001ae08745Sheppo 	 * needs to be propagted back to vnet from vgen and we need to revisit
5011ae08745Sheppo 	 * this code (see comments in vnet_attach()).
5021ae08745Sheppo 	 *
5031ae08745Sheppo 	 */
5041ae08745Sheppo 	WRITE_ENTER(&vnetp->trwlock);
5051ae08745Sheppo 	for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) {
5061ae08745Sheppo 		vp_macp = vp_tlp->macp;
507ba2e4443Sseb 		cbp = vp_macp->m_callbacks;
508ba2e4443Sseb 		cbp->mc_start(vp_macp->m_driver);
5091ae08745Sheppo 	}
5101ae08745Sheppo 	RW_EXIT(&vnetp->trwlock);
5111ae08745Sheppo 
5121ae08745Sheppo 	DBG1((vnetp, "vnet_m_start: exit\n"));
5131ae08745Sheppo 	return (VNET_SUCCESS);
5141ae08745Sheppo 
5151ae08745Sheppo }
5161ae08745Sheppo 
5171ae08745Sheppo /* stop transmit/receive for the device */
5181ae08745Sheppo static void
5191ae08745Sheppo vnet_m_stop(void *arg)
5201ae08745Sheppo {
5211ae08745Sheppo 	vnet_t		*vnetp = arg;
5221ae08745Sheppo 	vp_tl_t		*vp_tlp;
523ba2e4443Sseb 	mac_register_t	*vp_macp;
524ba2e4443Sseb 	mac_callbacks_t	*cbp;
5251ae08745Sheppo 
5261ae08745Sheppo 	DBG1((vnetp, "vnet_m_stop: enter\n"));
5271ae08745Sheppo 
5281ae08745Sheppo 	WRITE_ENTER(&vnetp->trwlock);
5291ae08745Sheppo 	for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) {
5301ae08745Sheppo 		vp_macp = vp_tlp->macp;
531ba2e4443Sseb 		cbp = vp_macp->m_callbacks;
532ba2e4443Sseb 		cbp->mc_stop(vp_macp->m_driver);
5331ae08745Sheppo 	}
5341ae08745Sheppo 	RW_EXIT(&vnetp->trwlock);
5351ae08745Sheppo 
5361ae08745Sheppo 	DBG1((vnetp, "vnet_m_stop: exit\n"));
5371ae08745Sheppo }
5381ae08745Sheppo 
5391ae08745Sheppo /* set the unicast mac address of the device */
5401ae08745Sheppo static int
5411ae08745Sheppo vnet_m_unicst(void *arg, const uint8_t *macaddr)
5421ae08745Sheppo {
5431ae08745Sheppo 	_NOTE(ARGUNUSED(macaddr))
5441ae08745Sheppo 
5451ae08745Sheppo 	vnet_t *vnetp = arg;
5461ae08745Sheppo 
5471ae08745Sheppo 	DBG1((vnetp, "vnet_m_unicst: enter\n"));
5481ae08745Sheppo 	/*
5491ae08745Sheppo 	 * XXX: setting mac address dynamically is not supported.
5501ae08745Sheppo 	 */
5511ae08745Sheppo 	DBG1((vnetp, "vnet_m_unicst: exit\n"));
5521ae08745Sheppo 
5538e6a2a04Slm66018 	return (VNET_FAILURE);
5541ae08745Sheppo }
5551ae08745Sheppo 
5561ae08745Sheppo /* enable/disable a multicast address */
5571ae08745Sheppo static int
5581ae08745Sheppo vnet_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
5591ae08745Sheppo {
5601ae08745Sheppo 	_NOTE(ARGUNUSED(add, mca))
5611ae08745Sheppo 
5621ae08745Sheppo 	vnet_t *vnetp = arg;
5631ae08745Sheppo 	vp_tl_t		*vp_tlp;
564ba2e4443Sseb 	mac_register_t	*vp_macp;
565ba2e4443Sseb 	mac_callbacks_t	*cbp;
5661ae08745Sheppo 	int rv = VNET_SUCCESS;
5671ae08745Sheppo 
5681ae08745Sheppo 	DBG1((vnetp, "vnet_m_multicst: enter\n"));
5691ae08745Sheppo 	READ_ENTER(&vnetp->trwlock);
5701ae08745Sheppo 	for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) {
5711ae08745Sheppo 		if (strcmp(vnetp->vgen_name, vp_tlp->name) == 0) {
5721ae08745Sheppo 			vp_macp = vp_tlp->macp;
573ba2e4443Sseb 			cbp = vp_macp->m_callbacks;
574ba2e4443Sseb 			rv = cbp->mc_multicst(vp_macp->m_driver, add, mca);
5751ae08745Sheppo 			break;
5761ae08745Sheppo 		}
5771ae08745Sheppo 	}
5781ae08745Sheppo 	RW_EXIT(&vnetp->trwlock);
5791ae08745Sheppo 	DBG1((vnetp, "vnet_m_multicst: exit\n"));
5801ae08745Sheppo 	return (rv);
5811ae08745Sheppo }
5821ae08745Sheppo 
5831ae08745Sheppo /* set or clear promiscuous mode on the device */
5841ae08745Sheppo static int
5851ae08745Sheppo vnet_m_promisc(void *arg, boolean_t on)
5861ae08745Sheppo {
5871ae08745Sheppo 	_NOTE(ARGUNUSED(on))
5881ae08745Sheppo 
5891ae08745Sheppo 	vnet_t *vnetp = arg;
5901ae08745Sheppo 	DBG1((vnetp, "vnet_m_promisc: enter\n"));
5911ae08745Sheppo 	/*
5921ae08745Sheppo 	 * XXX: setting promiscuous mode is not supported, just return success.
5931ae08745Sheppo 	 */
5941ae08745Sheppo 	DBG1((vnetp, "vnet_m_promisc: exit\n"));
5951ae08745Sheppo 	return (VNET_SUCCESS);
5961ae08745Sheppo }
5971ae08745Sheppo 
5981ae08745Sheppo /*
5991ae08745Sheppo  * Transmit a chain of packets. This function provides switching functionality
6001ae08745Sheppo  * based on the destination mac address to reach other guests (within ldoms) or
6011ae08745Sheppo  * external hosts.
6021ae08745Sheppo  */
6031ae08745Sheppo mblk_t *
6041ae08745Sheppo vnet_m_tx(void *arg, mblk_t *mp)
6051ae08745Sheppo {
6061ae08745Sheppo 	vnet_t *vnetp;
6071ae08745Sheppo 	mblk_t *next;
6081ae08745Sheppo 	uint32_t fdbhash;
6091ae08745Sheppo 	fdb_t *fdbp;
6101ae08745Sheppo 	fdb_fanout_t *fdbhp;
6111ae08745Sheppo 	struct ether_header *ehp;
6121ae08745Sheppo 	uint8_t *macaddr;
6131ae08745Sheppo 	mblk_t *resid_mp;
6141ae08745Sheppo 
6151ae08745Sheppo 	vnetp = (vnet_t *)arg;
6161ae08745Sheppo 	DBG1((vnetp, "vnet_m_tx: enter\n"));
6171ae08745Sheppo 	ASSERT(mp != NULL);
6181ae08745Sheppo 
6191ae08745Sheppo 	while (mp != NULL) {
6201ae08745Sheppo 		next = mp->b_next;
6211ae08745Sheppo 		mp->b_next = NULL;
6221ae08745Sheppo 
6231ae08745Sheppo 		/* get the destination mac address in the eth header */
6241ae08745Sheppo 		ehp = (struct ether_header *)mp->b_rptr;
6251ae08745Sheppo 		macaddr = (uint8_t *)&ehp->ether_dhost;
6261ae08745Sheppo 
6271ae08745Sheppo 		/* Calculate hash value and fdb fanout */
6281ae08745Sheppo 		fdbhash = MACHASH(macaddr, vnetp->nfdb_hash);
6291ae08745Sheppo 		fdbhp = &(vnetp->fdbhp[fdbhash]);
6301ae08745Sheppo 
6311ae08745Sheppo 		READ_ENTER(&fdbhp->rwlock);
6321ae08745Sheppo 		fdbp = vnet_lookup_fdb(fdbhp, macaddr);
6331ae08745Sheppo 		if (fdbp) {
6341ae08745Sheppo 			/*
6351ae08745Sheppo 			 * If the destination is in FDB, the destination is
6361ae08745Sheppo 			 * a vnet device within ldoms and directly reachable,
6371ae08745Sheppo 			 * invoke the tx function in the fdb entry.
6381ae08745Sheppo 			 */
6391ae08745Sheppo 			resid_mp = fdbp->m_tx(fdbp->txarg, mp);
6401ae08745Sheppo 			if (resid_mp != NULL) {
6411ae08745Sheppo 				/* m_tx failed */
6421ae08745Sheppo 				mp->b_next = next;
6431ae08745Sheppo 				RW_EXIT(&fdbhp->rwlock);
6441ae08745Sheppo 				break;
6451ae08745Sheppo 			}
6461ae08745Sheppo 			RW_EXIT(&fdbhp->rwlock);
6471ae08745Sheppo 		} else {
6481ae08745Sheppo 			/* destination is not in FDB */
6491ae08745Sheppo 			RW_EXIT(&fdbhp->rwlock);
6501ae08745Sheppo 			/*
6511ae08745Sheppo 			 * If the destination is broadcast/multicast
6521ae08745Sheppo 			 * or an unknown unicast address, forward the
6531ae08745Sheppo 			 * packet to vsw, using the last slot in fdb which is
6541ae08745Sheppo 			 * reserved for default route.
6551ae08745Sheppo 			 */
6561ae08745Sheppo 			fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]);
6571ae08745Sheppo 			READ_ENTER(&fdbhp->rwlock);
6581ae08745Sheppo 			fdbp = fdbhp->headp;
6591ae08745Sheppo 			if (fdbp) {
6601ae08745Sheppo 				resid_mp = fdbp->m_tx(fdbp->txarg, mp);
6611ae08745Sheppo 				if (resid_mp != NULL) {
6621ae08745Sheppo 					/* m_tx failed */
6631ae08745Sheppo 					mp->b_next = next;
6641ae08745Sheppo 					RW_EXIT(&fdbhp->rwlock);
6651ae08745Sheppo 					break;
6661ae08745Sheppo 				}
6671ae08745Sheppo 			} else {
6681ae08745Sheppo 				/* drop the packet */
6691ae08745Sheppo 				freemsg(mp);
6701ae08745Sheppo 			}
6711ae08745Sheppo 			RW_EXIT(&fdbhp->rwlock);
6721ae08745Sheppo 		}
6731ae08745Sheppo 
6741ae08745Sheppo 		mp = next;
6751ae08745Sheppo 	}
6761ae08745Sheppo 
6771ae08745Sheppo 	DBG1((vnetp, "vnet_m_tx: exit\n"));
6781ae08745Sheppo 	return (mp);
6791ae08745Sheppo }
6801ae08745Sheppo 
6811ae08745Sheppo /* get statistics from the device */
682ba2e4443Sseb int
683ba2e4443Sseb vnet_m_stat(void *arg, uint_t stat, uint64_t *val)
6841ae08745Sheppo {
6851ae08745Sheppo 	vnet_t *vnetp = arg;
6861ae08745Sheppo 	vp_tl_t	*vp_tlp;
687ba2e4443Sseb 	mac_register_t	*vp_macp;
688ba2e4443Sseb 	mac_callbacks_t	*cbp;
689ba2e4443Sseb 	uint64_t val_total = 0;
6901ae08745Sheppo 
6911ae08745Sheppo 	DBG1((vnetp, "vnet_m_stat: enter\n"));
6921ae08745Sheppo 
6931ae08745Sheppo 	/*
694ba2e4443Sseb 	 * get the specified statistic from each transport and return the
695ba2e4443Sseb 	 * aggregate val.  This obviously only works for counters.
6961ae08745Sheppo 	 */
697ba2e4443Sseb 	if ((IS_MAC_STAT(stat) && !MAC_STAT_ISACOUNTER(stat)) ||
698ba2e4443Sseb 	    (IS_MACTYPE_STAT(stat) && !ETHER_STAT_ISACOUNTER(stat))) {
699ba2e4443Sseb 		return (ENOTSUP);
700ba2e4443Sseb 	}
7011ae08745Sheppo 	READ_ENTER(&vnetp->trwlock);
7021ae08745Sheppo 	for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) {
7031ae08745Sheppo 		vp_macp = vp_tlp->macp;
704ba2e4443Sseb 		cbp = vp_macp->m_callbacks;
705ba2e4443Sseb 		if (cbp->mc_getstat(vp_macp->m_driver, stat, val) == 0)
706ba2e4443Sseb 			val_total += *val;
7071ae08745Sheppo 	}
7081ae08745Sheppo 	RW_EXIT(&vnetp->trwlock);
7091ae08745Sheppo 
710ba2e4443Sseb 	*val = val_total;
711ba2e4443Sseb 
7121ae08745Sheppo 	DBG1((vnetp, "vnet_m_stat: exit\n"));
713ba2e4443Sseb 	return (0);
7141ae08745Sheppo }
7151ae08745Sheppo 
7161ae08745Sheppo /* wrapper function for mac_register() */
7171ae08745Sheppo static int
7181ae08745Sheppo vnet_mac_register(vnet_t *vnetp)
7191ae08745Sheppo {
720ba2e4443Sseb 	mac_register_t	*macp;
721ba2e4443Sseb 	int		err;
7221ae08745Sheppo 
723ba2e4443Sseb 	if ((macp = mac_alloc(MAC_VERSION)) == NULL)
724ba2e4443Sseb 		return (DDI_FAILURE);
725ba2e4443Sseb 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
726ba2e4443Sseb 	macp->m_driver = vnetp;
7271ae08745Sheppo 	macp->m_dip = vnetp->dip;
728ba2e4443Sseb 	macp->m_src_addr = vnetp->curr_macaddr;
729ba2e4443Sseb 	macp->m_callbacks = &vnet_m_callbacks;
730ba2e4443Sseb 	macp->m_min_sdu = 0;
731ba2e4443Sseb 	macp->m_max_sdu = ETHERMTU;
7321ae08745Sheppo 
7331ae08745Sheppo 	/*
7341ae08745Sheppo 	 * Finally, we're ready to register ourselves with the MAC layer
7351ae08745Sheppo 	 * interface; if this succeeds, we're all ready to start()
7361ae08745Sheppo 	 */
737ba2e4443Sseb 	err = mac_register(macp, &vnetp->mh);
738ba2e4443Sseb 	mac_free(macp);
739ba2e4443Sseb 	return (err == 0 ? DDI_SUCCESS : DDI_FAILURE);
7401ae08745Sheppo }
7411ae08745Sheppo 
7421ae08745Sheppo /* add vp_tl to the list */
7431ae08745Sheppo static void
7441ae08745Sheppo vnet_add_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp)
7451ae08745Sheppo {
7461ae08745Sheppo 	vp_tl_t *ttlp;
7471ae08745Sheppo 
7481ae08745Sheppo 	WRITE_ENTER(&vnetp->trwlock);
7491ae08745Sheppo 	if (vnetp->tlp == NULL) {
7501ae08745Sheppo 		vnetp->tlp = vp_tlp;
7511ae08745Sheppo 	} else {
7521ae08745Sheppo 		ttlp = vnetp->tlp;
7531ae08745Sheppo 		while (ttlp->nextp)
7541ae08745Sheppo 			ttlp = ttlp->nextp;
7551ae08745Sheppo 		ttlp->nextp = vp_tlp;
7561ae08745Sheppo 	}
7571ae08745Sheppo 	RW_EXIT(&vnetp->trwlock);
7581ae08745Sheppo }
7591ae08745Sheppo 
7601ae08745Sheppo /* remove vp_tl from the list */
7611ae08745Sheppo static void
7621ae08745Sheppo vnet_del_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp)
7631ae08745Sheppo {
7641ae08745Sheppo 	vp_tl_t *ttlp, **pretlp;
7651ae08745Sheppo 	boolean_t found = B_FALSE;
7661ae08745Sheppo 
7671ae08745Sheppo 	pretlp = &vnetp->tlp;
7681ae08745Sheppo 	ttlp = *pretlp;
7691ae08745Sheppo 	while (ttlp) {
7701ae08745Sheppo 		if (ttlp == vp_tlp) {
7711ae08745Sheppo 			found = B_TRUE;
7721ae08745Sheppo 			(*pretlp) = ttlp->nextp;
7731ae08745Sheppo 			ttlp->nextp = NULL;
7741ae08745Sheppo 			break;
7751ae08745Sheppo 		}
7761ae08745Sheppo 		pretlp = &(ttlp->nextp);
7771ae08745Sheppo 		ttlp = *pretlp;
7781ae08745Sheppo 	}
7791ae08745Sheppo 
7801ae08745Sheppo 	if (found) {
7811ae08745Sheppo 		KMEM_FREE(vp_tlp);
7821ae08745Sheppo 	}
7831ae08745Sheppo }
7841ae08745Sheppo 
7851ae08745Sheppo /* get vp_tl corresponding to the given name */
7861ae08745Sheppo static vp_tl_t *
7871ae08745Sheppo vnet_get_vptl(vnet_t *vnetp, const char *name)
7881ae08745Sheppo {
7891ae08745Sheppo 	vp_tl_t *tlp;
7901ae08745Sheppo 
7911ae08745Sheppo 	tlp = vnetp->tlp;
7921ae08745Sheppo 	while (tlp) {
7931ae08745Sheppo 		if (strcmp(tlp->name, name) == 0) {
7941ae08745Sheppo 			return (tlp);
7951ae08745Sheppo 		}
7961ae08745Sheppo 		tlp = tlp->nextp;
7971ae08745Sheppo 	}
7981ae08745Sheppo 	DWARN((vnetp,
7991ae08745Sheppo 	    "vnet_get_vptl: can't find vp_tl with name (%s)\n", name));
8001ae08745Sheppo 	return (NULL);
8011ae08745Sheppo }
8021ae08745Sheppo 
8031ae08745Sheppo /* read the mac address of the device */
8041ae08745Sheppo static int
8051ae08745Sheppo vnet_read_mac_address(vnet_t *vnetp)
8061ae08745Sheppo {
8071ae08745Sheppo 	uchar_t 	*macaddr;
8081ae08745Sheppo 	uint32_t 	size;
8091ae08745Sheppo 	int 		rv;
8101ae08745Sheppo 
8111ae08745Sheppo 	rv = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, vnetp->dip,
8121ae08745Sheppo 		DDI_PROP_DONTPASS, macaddr_propname, &macaddr, &size);
8131ae08745Sheppo 	if ((rv != DDI_PROP_SUCCESS) || (size != ETHERADDRL)) {
8141ae08745Sheppo 		DWARN((vnetp,
8151ae08745Sheppo 		"vnet_read_mac_address: prop_lookup failed (%s) err (%d)\n",
8161ae08745Sheppo 		macaddr_propname, rv));
8171ae08745Sheppo 		return (DDI_FAILURE);
8181ae08745Sheppo 	}
8191ae08745Sheppo 	bcopy(macaddr, (caddr_t)vnetp->vendor_addr, ETHERADDRL);
8201ae08745Sheppo 	bcopy(macaddr, (caddr_t)vnetp->curr_macaddr, ETHERADDRL);
8211ae08745Sheppo 	ddi_prop_free(macaddr);
8221ae08745Sheppo 
8231ae08745Sheppo 	return (DDI_SUCCESS);
8241ae08745Sheppo }
8251ae08745Sheppo 
8261ae08745Sheppo 
8271ae08745Sheppo /*
8281ae08745Sheppo  * Functions below are called only by generic transport to add/remove/modify
8291ae08745Sheppo  * entries in forwarding database. See comments in vgen_port_init(vnet_gen.c).
8301ae08745Sheppo  */
8311ae08745Sheppo 
8321ae08745Sheppo /* add an entry into the forwarding database */
8331ae08745Sheppo void
8341ae08745Sheppo vnet_add_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg)
8351ae08745Sheppo {
8361ae08745Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
8371ae08745Sheppo 	uint32_t fdbhash;
8381ae08745Sheppo 	fdb_t *fdbp;
8391ae08745Sheppo 	fdb_fanout_t *fdbhp;
8401ae08745Sheppo 
8411ae08745Sheppo 	/* Calculate hash value and fdb fanout */
8421ae08745Sheppo 	fdbhash = MACHASH(macaddr, vnetp->nfdb_hash);
8431ae08745Sheppo 	fdbhp = &(vnetp->fdbhp[fdbhash]);
8441ae08745Sheppo 
8451ae08745Sheppo 	WRITE_ENTER(&fdbhp->rwlock);
8461ae08745Sheppo 
8471ae08745Sheppo 	fdbp = kmem_zalloc(sizeof (fdb_t), KM_NOSLEEP);
8481ae08745Sheppo 	if (fdbp == NULL) {
8491ae08745Sheppo 		RW_EXIT(&fdbhp->rwlock);
8501ae08745Sheppo 		return;
8511ae08745Sheppo 	}
8521ae08745Sheppo 	bcopy(macaddr, (caddr_t)fdbp->macaddr, ETHERADDRL);
8531ae08745Sheppo 	fdbp->m_tx = m_tx;
8541ae08745Sheppo 	fdbp->txarg = txarg;
8551ae08745Sheppo 	fdbp->nextp = fdbhp->headp;
8561ae08745Sheppo 	fdbhp->headp = fdbp;
8571ae08745Sheppo 
8581ae08745Sheppo 	RW_EXIT(&fdbhp->rwlock);
8591ae08745Sheppo }
8601ae08745Sheppo 
8611ae08745Sheppo /* delete an entry from the forwarding database */
8621ae08745Sheppo void
8631ae08745Sheppo vnet_del_fdb(void *arg, uint8_t *macaddr)
8641ae08745Sheppo {
8651ae08745Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
8661ae08745Sheppo 	uint32_t fdbhash;
8671ae08745Sheppo 	fdb_t *fdbp;
8681ae08745Sheppo 	fdb_t **pfdbp;
8691ae08745Sheppo 	fdb_fanout_t *fdbhp;
8701ae08745Sheppo 
8711ae08745Sheppo 	/* Calculate hash value and fdb fanout */
8721ae08745Sheppo 	fdbhash = MACHASH(macaddr, vnetp->nfdb_hash);
8731ae08745Sheppo 	fdbhp = &(vnetp->fdbhp[fdbhash]);
8741ae08745Sheppo 
8751ae08745Sheppo 	WRITE_ENTER(&fdbhp->rwlock);
8761ae08745Sheppo 
8771ae08745Sheppo 	for (pfdbp = &fdbhp->headp; (fdbp  = *pfdbp) != NULL;
8781ae08745Sheppo 	    pfdbp = &fdbp->nextp) {
8791ae08745Sheppo 		if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) {
8801ae08745Sheppo 			/* Unlink it from the list */
8811ae08745Sheppo 			*pfdbp = fdbp->nextp;
8821ae08745Sheppo 			KMEM_FREE(fdbp);
8831ae08745Sheppo 			break;
8841ae08745Sheppo 		}
8851ae08745Sheppo 	}
8861ae08745Sheppo 
8871ae08745Sheppo 	RW_EXIT(&fdbhp->rwlock);
8881ae08745Sheppo }
8891ae08745Sheppo 
8901ae08745Sheppo /* modify an existing entry in the forwarding database */
8911ae08745Sheppo void
8921ae08745Sheppo vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg)
8931ae08745Sheppo {
8941ae08745Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
8951ae08745Sheppo 	uint32_t fdbhash;
8961ae08745Sheppo 	fdb_t *fdbp;
8971ae08745Sheppo 	fdb_fanout_t *fdbhp;
8981ae08745Sheppo 
8991ae08745Sheppo 	/* Calculate hash value and fdb fanout */
9001ae08745Sheppo 	fdbhash = MACHASH(macaddr, vnetp->nfdb_hash);
9011ae08745Sheppo 	fdbhp = &(vnetp->fdbhp[fdbhash]);
9021ae08745Sheppo 
9031ae08745Sheppo 	WRITE_ENTER(&fdbhp->rwlock);
9041ae08745Sheppo 
9051ae08745Sheppo 	for (fdbp = fdbhp->headp; fdbp != NULL; fdbp = fdbp->nextp) {
9061ae08745Sheppo 		if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) {
9071ae08745Sheppo 			/* change the entry to have new tx params */
9081ae08745Sheppo 			fdbp->m_tx = m_tx;
9091ae08745Sheppo 			fdbp->txarg = txarg;
9101ae08745Sheppo 			break;
9111ae08745Sheppo 		}
9121ae08745Sheppo 	}
9131ae08745Sheppo 
9141ae08745Sheppo 	RW_EXIT(&fdbhp->rwlock);
9151ae08745Sheppo }
9161ae08745Sheppo 
9171ae08745Sheppo /* look up an fdb entry based on the mac address, caller holds lock */
9181ae08745Sheppo static fdb_t *
9191ae08745Sheppo vnet_lookup_fdb(fdb_fanout_t *fdbhp, uint8_t *macaddr)
9201ae08745Sheppo {
9211ae08745Sheppo 	fdb_t *fdbp = NULL;
9221ae08745Sheppo 
9231ae08745Sheppo 	for (fdbp = fdbhp->headp; fdbp != NULL; fdbp = fdbp->nextp) {
9241ae08745Sheppo 		if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) {
9251ae08745Sheppo 			break;
9261ae08745Sheppo 		}
9271ae08745Sheppo 	}
9281ae08745Sheppo 
9291ae08745Sheppo 	return (fdbp);
9301ae08745Sheppo }
9311ae08745Sheppo 
9321ae08745Sheppo /* add default route entry into the forwarding database */
9331ae08745Sheppo void
9341ae08745Sheppo vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg)
9351ae08745Sheppo {
9361ae08745Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
9371ae08745Sheppo 	fdb_t *fdbp;
9381ae08745Sheppo 	fdb_fanout_t *fdbhp;
9391ae08745Sheppo 
9401ae08745Sheppo 	/*
9411ae08745Sheppo 	 * The last hash list is reserved for default route entry,
9421ae08745Sheppo 	 * and for now, we have only one entry in this list.
9431ae08745Sheppo 	 */
9441ae08745Sheppo 	fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]);
9451ae08745Sheppo 
9461ae08745Sheppo 	WRITE_ENTER(&fdbhp->rwlock);
9471ae08745Sheppo 
9481ae08745Sheppo 	if (fdbhp->headp) {
9491ae08745Sheppo 		DWARN((vnetp,
9501ae08745Sheppo 		    "vnet_add_def_rte: default rte already exists\n"));
9511ae08745Sheppo 		RW_EXIT(&fdbhp->rwlock);
9521ae08745Sheppo 		return;
9531ae08745Sheppo 	}
9541ae08745Sheppo 	fdbp = kmem_zalloc(sizeof (fdb_t), KM_NOSLEEP);
9551ae08745Sheppo 	if (fdbp == NULL) {
9561ae08745Sheppo 		RW_EXIT(&fdbhp->rwlock);
9571ae08745Sheppo 		return;
9581ae08745Sheppo 	}
9591ae08745Sheppo 	bzero(fdbp->macaddr, ETHERADDRL);
9601ae08745Sheppo 	fdbp->m_tx = m_tx;
9611ae08745Sheppo 	fdbp->txarg = txarg;
9621ae08745Sheppo 	fdbp->nextp = NULL;
9631ae08745Sheppo 	fdbhp->headp = fdbp;
9641ae08745Sheppo 
9651ae08745Sheppo 	RW_EXIT(&fdbhp->rwlock);
9661ae08745Sheppo }
9671ae08745Sheppo 
9681ae08745Sheppo /* delete default route entry from the forwarding database */
9691ae08745Sheppo void
9701ae08745Sheppo vnet_del_def_rte(void *arg)
9711ae08745Sheppo {
9721ae08745Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
9731ae08745Sheppo 	fdb_t *fdbp;
9741ae08745Sheppo 	fdb_fanout_t *fdbhp;
9751ae08745Sheppo 
9761ae08745Sheppo 	/*
9771ae08745Sheppo 	 * The last hash list is reserved for default route entry,
9781ae08745Sheppo 	 * and for now, we have only one entry in this list.
9791ae08745Sheppo 	 */
9801ae08745Sheppo 	fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]);
9811ae08745Sheppo 
9821ae08745Sheppo 	WRITE_ENTER(&fdbhp->rwlock);
9831ae08745Sheppo 
9841ae08745Sheppo 	if (fdbhp->headp == NULL) {
9851ae08745Sheppo 		RW_EXIT(&fdbhp->rwlock);
9861ae08745Sheppo 		return;
9871ae08745Sheppo 	}
9881ae08745Sheppo 	fdbp = fdbhp->headp;
9891ae08745Sheppo 	KMEM_FREE(fdbp);
9901ae08745Sheppo 	fdbhp->headp = NULL;
9911ae08745Sheppo 
9921ae08745Sheppo 	RW_EXIT(&fdbhp->rwlock);
9931ae08745Sheppo }
994ba2e4443Sseb 
995ba2e4443Sseb void
996ba2e4443Sseb vnet_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp)
997ba2e4443Sseb {
998ba2e4443Sseb 	vnet_t *vnetp = arg;
999ba2e4443Sseb 	mac_rx(vnetp->mh, mrh, mp);
1000ba2e4443Sseb }
1001ba2e4443Sseb 
1002ba2e4443Sseb void
1003ba2e4443Sseb vnet_tx_update(void *arg)
1004ba2e4443Sseb {
1005ba2e4443Sseb 	vnet_t *vnetp = arg;
1006ba2e4443Sseb 	mac_tx_update(vnetp->mh);
1007ba2e4443Sseb }
1008