xref: /onnv-gate/usr/src/uts/sun4v/io/vnet.c (revision 2109:06c56c8205d6)
11991Sheppo /*
21991Sheppo  * CDDL HEADER START
31991Sheppo  *
41991Sheppo  * The contents of this file are subject to the terms of the
51991Sheppo  * Common Development and Distribution License (the "License").
61991Sheppo  * You may not use this file except in compliance with the License.
71991Sheppo  *
81991Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91991Sheppo  * or http://www.opensolaris.org/os/licensing.
101991Sheppo  * See the License for the specific language governing permissions
111991Sheppo  * and limitations under the License.
121991Sheppo  *
131991Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
141991Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151991Sheppo  * If applicable, add the following below this CDDL HEADER, with the
161991Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
171991Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
181991Sheppo  *
191991Sheppo  * CDDL HEADER END
201991Sheppo  */
211991Sheppo 
221991Sheppo /*
231991Sheppo  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
241991Sheppo  * Use is subject to license terms.
251991Sheppo  */
261991Sheppo 
271991Sheppo #pragma ident	"%Z%%M%	%I%	%E% SMI"
281991Sheppo 
291991Sheppo #include <sys/types.h>
301991Sheppo #include <sys/errno.h>
311991Sheppo #include <sys/param.h>
321991Sheppo #include <sys/stream.h>
331991Sheppo #include <sys/kmem.h>
341991Sheppo #include <sys/conf.h>
351991Sheppo #include <sys/devops.h>
361991Sheppo #include <sys/ksynch.h>
371991Sheppo #include <sys/stat.h>
381991Sheppo #include <sys/modctl.h>
391991Sheppo #include <sys/debug.h>
401991Sheppo #include <sys/ethernet.h>
411991Sheppo #include <sys/dlpi.h>
421991Sheppo #include <net/if.h>
431991Sheppo #include <sys/mac.h>
441991Sheppo #include <sys/ddi.h>
451991Sheppo #include <sys/sunddi.h>
461991Sheppo #include <sys/strsun.h>
471991Sheppo #include <sys/note.h>
481991Sheppo #include <sys/vnet.h>
491991Sheppo 
501991Sheppo /*
511991Sheppo  * Function prototypes.
521991Sheppo  */
531991Sheppo 
541991Sheppo /* DDI entrypoints */
551991Sheppo static int vnetdevinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
561991Sheppo static int vnetattach(dev_info_t *, ddi_attach_cmd_t);
571991Sheppo static int vnetdetach(dev_info_t *, ddi_detach_cmd_t);
581991Sheppo 
591991Sheppo /* MAC entrypoints  */
601991Sheppo static uint64_t vnet_m_stat(void *arg, enum mac_stat stat);
611991Sheppo static int vnet_m_start(void *);
621991Sheppo static void vnet_m_stop(void *);
631991Sheppo static int vnet_m_promisc(void *, boolean_t);
641991Sheppo static int vnet_m_multicst(void *, boolean_t, const uint8_t *);
651991Sheppo static int vnet_m_unicst(void *, const uint8_t *);
661991Sheppo static void vnet_m_resources(void *);
671991Sheppo static void vnet_m_ioctl(void *, queue_t *, mblk_t *);
681991Sheppo mblk_t *vnet_m_tx(void *, mblk_t *);
691991Sheppo 
701991Sheppo /* vnet internal functions */
711991Sheppo static int vnet_mac_register(vnet_t *);
721991Sheppo static int vnet_read_mac_address(vnet_t *vnetp);
731991Sheppo static void vnet_add_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp);
741991Sheppo static void vnet_del_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp);
751991Sheppo static vp_tl_t *vnet_get_vptl(vnet_t *vnetp, const char *devname);
761991Sheppo static fdb_t *vnet_lookup_fdb(fdb_fanout_t *fdbhp, uint8_t *macaddr);
771991Sheppo 
781991Sheppo /* exported functions */
791991Sheppo void vnet_add_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg);
801991Sheppo void vnet_del_fdb(void *arg, uint8_t *macaddr);
811991Sheppo void vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg);
821991Sheppo void vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg);
831991Sheppo void vnet_del_def_rte(void *arg);
841991Sheppo 
851991Sheppo /* externs */
861991Sheppo extern int vgen_init(void *vnetp, dev_info_t *vnetdip, void *vnetmacp,
871991Sheppo 	const uint8_t *macaddr, mac_t **vgenmacp);
881991Sheppo extern void vgen_uninit(void *arg);
891991Sheppo 
901991Sheppo /*
911991Sheppo  * Linked list of "vnet_t" structures - one per instance.
921991Sheppo  */
931991Sheppo static vnet_t	*vnet_headp = NULL;
941991Sheppo static krwlock_t vnet_rw;
951991Sheppo 
961991Sheppo /* Tunables */
971991Sheppo uint32_t vnet_ntxds = VNET_NTXDS;	/* power of 2 transmit descriptors */
981991Sheppo uint32_t vnet_reclaim_lowat = VNET_RECLAIM_LOWAT;  /* tx recl low watermark */
991991Sheppo uint32_t vnet_reclaim_hiwat = VNET_RECLAIM_HIWAT;  /* tx recl high watermark */
1001991Sheppo uint32_t vnet_ldcwd_interval = VNET_LDCWD_INTERVAL; /* watchdog freq in msec */
1011991Sheppo uint32_t vnet_ldcwd_txtimeout = VNET_LDCWD_TXTIMEOUT;  /* tx timeout in msec */
1021991Sheppo uint32_t vnet_ldc_qlen = VNET_LDC_QLEN;		/* ldc qlen */
1031991Sheppo uint32_t vnet_nfdb_hash = VNET_NFDB_HASH;	/* size of fdb hash table */
1041991Sheppo 
1051991Sheppo /*
1061991Sheppo  * Property names
1071991Sheppo  */
1081991Sheppo static char macaddr_propname[] = "local-mac-address";
1091991Sheppo 
1101991Sheppo static struct ether_addr etherbroadcastaddr = {
1111991Sheppo 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1121991Sheppo };
1131991Sheppo 
1141991Sheppo /*
1151991Sheppo  * MIB II broadcast/multicast packets
1161991Sheppo  */
1171991Sheppo #define	IS_BROADCAST(ehp) \
1181991Sheppo 		(ether_cmp(&ehp->ether_dhost, &etherbroadcastaddr) == 0)
1191991Sheppo #define	IS_MULTICAST(ehp) \
1201991Sheppo 		((ehp->ether_dhost.ether_addr_octet[0] & 01) == 1)
1211991Sheppo 
1221991Sheppo /*
1231991Sheppo  * This is the string displayed by modinfo(1m).
1241991Sheppo  */
125*2109Slm66018 static char vnet_ident[] = "vnet driver v%I%";
1261991Sheppo extern struct mod_ops mod_driverops;
1271991Sheppo static struct cb_ops cb_vnetops = {
1281991Sheppo 	nulldev,		/* cb_open */
1291991Sheppo 	nulldev,		/* cb_close */
1301991Sheppo 	nodev,			/* cb_strategy */
1311991Sheppo 	nodev,			/* cb_print */
1321991Sheppo 	nodev,			/* cb_dump */
1331991Sheppo 	nodev,			/* cb_read */
1341991Sheppo 	nodev,			/* cb_write */
1351991Sheppo 	nodev,			/* cb_ioctl */
1361991Sheppo 	nodev,			/* cb_devmap */
1371991Sheppo 	nodev,			/* cb_mmap */
1381991Sheppo 	nodev,			/* cb_segmap */
1391991Sheppo 	nochpoll,		/* cb_chpoll */
1401991Sheppo 	ddi_prop_op,		/* cb_prop_op */
1411991Sheppo 	NULL,			/* cb_stream */
1421991Sheppo 	(int)(D_MP)		/* cb_flag */
1431991Sheppo };
1441991Sheppo 
1451991Sheppo static struct dev_ops vnetops = {
1461991Sheppo 	DEVO_REV,		/* devo_rev */
1471991Sheppo 	0,			/* devo_refcnt */
1481991Sheppo 	NULL,			/* devo_getinfo */
1491991Sheppo 	nulldev,		/* devo_identify */
1501991Sheppo 	nulldev,		/* devo_probe */
1511991Sheppo 	vnetattach,		/* devo_attach */
1521991Sheppo 	vnetdetach,		/* devo_detach */
1531991Sheppo 	nodev,			/* devo_reset */
1541991Sheppo 	&cb_vnetops,		/* devo_cb_ops */
1551991Sheppo 	(struct bus_ops *)NULL	/* devo_bus_ops */
1561991Sheppo };
1571991Sheppo 
1581991Sheppo static struct modldrv modldrv = {
1591991Sheppo 	&mod_driverops,		/* Type of module.  This one is a driver */
1601991Sheppo 	vnet_ident,		/* ID string */
1611991Sheppo 	&vnetops		/* driver specific ops */
1621991Sheppo };
1631991Sheppo 
1641991Sheppo static struct modlinkage modlinkage = {
1651991Sheppo 	MODREV_1, (void *)&modldrv, NULL
1661991Sheppo };
1671991Sheppo 
1681991Sheppo 
1691991Sheppo /*
1701991Sheppo  * Print debug messages - set to 0xf to enable all msgs
1711991Sheppo  */
1721991Sheppo int _vnet_dbglevel = 0x8;
1731991Sheppo 
1741991Sheppo void
1751991Sheppo _vnetdebug_printf(void *arg, const char *fmt, ...)
1761991Sheppo {
1771991Sheppo 	char    buf[512];
1781991Sheppo 	va_list ap;
1791991Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
1801991Sheppo 
1811991Sheppo 	va_start(ap, fmt);
1821991Sheppo 	(void) vsprintf(buf, fmt, ap);
1831991Sheppo 	va_end(ap);
1841991Sheppo 
1851991Sheppo 	if (vnetp == NULL)
1861991Sheppo 		cmn_err(CE_CONT, "%s\n", buf);
1871991Sheppo 	else
1881991Sheppo 		cmn_err(CE_CONT, "vnet%d: %s\n", vnetp->instance, buf);
1891991Sheppo }
1901991Sheppo 
1911991Sheppo #ifdef DEBUG
1921991Sheppo 
1931991Sheppo /*
1941991Sheppo  * XXX: any changes to the definitions below need corresponding changes in
1951991Sheppo  * vnet_gen.c
1961991Sheppo  */
1971991Sheppo 
1981991Sheppo /*
1991991Sheppo  * debug levels:
2001991Sheppo  * DBG_LEVEL1:	Function entry/exit tracing
2011991Sheppo  * DBG_LEVEL2:	Info messages
2021991Sheppo  * DBG_LEVEL3:	Warning messages
2031991Sheppo  * DBG_LEVEL4:	Error messages
2041991Sheppo  */
2051991Sheppo 
2061991Sheppo enum	{ DBG_LEVEL1 = 0x01, DBG_LEVEL2 = 0x02, DBG_LEVEL3 = 0x04,
2071991Sheppo 	    DBG_LEVEL4 = 0x08 };
2081991Sheppo 
2091991Sheppo #define	DBG1(_s)	do {						\
2101991Sheppo 			    if ((_vnet_dbglevel & DBG_LEVEL1) != 0) {	\
2111991Sheppo 					_vnetdebug_printf _s;		\
2121991Sheppo 			    }					\
2131991Sheppo 			_NOTE(CONSTCOND) } while (0)
2141991Sheppo 
2151991Sheppo #define	DBG2(_s)	do {						\
2161991Sheppo 			    if ((_vnet_dbglevel & DBG_LEVEL2) != 0) {	\
2171991Sheppo 					_vnetdebug_printf _s;		\
2181991Sheppo 			    }					\
2191991Sheppo 			_NOTE(CONSTCOND) } while (0)
2201991Sheppo 
2211991Sheppo #define	DWARN(_s)	do {						\
2221991Sheppo 			    if ((_vnet_dbglevel & DBG_LEVEL3) != 0) {	\
2231991Sheppo 					_vnetdebug_printf _s;		\
2241991Sheppo 			    }					\
2251991Sheppo 			_NOTE(CONSTCOND) } while (0)
2261991Sheppo 
2271991Sheppo #define	DERR(_s)	do {						\
2281991Sheppo 			    if ((_vnet_dbglevel & DBG_LEVEL4) != 0) {	\
2291991Sheppo 					_vnetdebug_printf _s;		\
2301991Sheppo 			    }					\
2311991Sheppo 			_NOTE(CONSTCOND) } while (0)
2321991Sheppo 
2331991Sheppo #else
2341991Sheppo 
2351991Sheppo #define	DBG1(_s)	if (0)	_vnetdebug_printf _s
2361991Sheppo #define	DBG2(_s)	if (0)	_vnetdebug_printf _s
2371991Sheppo #define	DWARN(_s)	if (0)	_vnetdebug_printf _s
2381991Sheppo #define	DERR(_s)	if (0)	_vnetdebug_printf _s
2391991Sheppo 
2401991Sheppo #endif
2411991Sheppo 
2421991Sheppo /* _init(9E): initialize the loadable module */
2431991Sheppo int
2441991Sheppo _init(void)
2451991Sheppo {
2461991Sheppo 	int status;
2471991Sheppo 
2481991Sheppo 	DBG1((NULL, "_init: enter\n"));
2491991Sheppo 
2501991Sheppo 	mac_init_ops(&vnetops, "vnet");
2511991Sheppo 	status = mod_install(&modlinkage);
2521991Sheppo 	if (status != 0) {
2531991Sheppo 		mac_fini_ops(&vnetops);
2541991Sheppo 	}
2551991Sheppo 
2561991Sheppo 	DBG1((NULL, "_init: exit\n"));
2571991Sheppo 	return (status);
2581991Sheppo }
2591991Sheppo 
2601991Sheppo /* _fini(9E): prepare the module for unloading. */
2611991Sheppo int
2621991Sheppo _fini(void)
2631991Sheppo {
2641991Sheppo 	int status;
2651991Sheppo 
2661991Sheppo 	DBG1((NULL, "_fini: enter\n"));
2671991Sheppo 
2681991Sheppo 	status = mod_remove(&modlinkage);
2691991Sheppo 	if (status != 0)
2701991Sheppo 		return (status);
2711991Sheppo 	mac_fini_ops(&vnetops);
2721991Sheppo 
2731991Sheppo 	DBG1((NULL, "_fini: exit\n"));
2741991Sheppo 	return (status);
2751991Sheppo }
2761991Sheppo 
2771991Sheppo /* _info(9E): return information about the loadable module */
2781991Sheppo int
2791991Sheppo _info(struct modinfo *modinfop)
2801991Sheppo {
2811991Sheppo 	return (mod_info(&modlinkage, modinfop));
2821991Sheppo }
2831991Sheppo 
2841991Sheppo /*
2851991Sheppo  * attach(9E): attach a device to the system.
2861991Sheppo  * called once for each instance of the device on the system.
2871991Sheppo  */
2881991Sheppo static int
2891991Sheppo vnetattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2901991Sheppo {
2911991Sheppo 	mac_t		*macp;
2921991Sheppo 	vnet_t		*vnetp;
2931991Sheppo 	vp_tl_t		*vp_tlp;
2941991Sheppo 	int		instance;
2951991Sheppo 	int		status;
2961991Sheppo 	enum		{ AST_init = 0x0, AST_vnet_alloc = 0x1,
2971991Sheppo 			    AST_mac_alloc = 0x2, AST_read_macaddr = 0x4,
2981991Sheppo 			    AST_vgen_init = 0x8, AST_vptl_alloc = 0x10,
2991991Sheppo 			    AST_fdbh_alloc = 0x20 }
3001991Sheppo 			attach_state;
3011991Sheppo 	mac_t		*vgenmacp = NULL;
3021991Sheppo 	uint32_t	nfdbh = 0;
3031991Sheppo 
3041991Sheppo 	attach_state = AST_init;
3051991Sheppo 
3061991Sheppo 	switch (cmd) {
3071991Sheppo 	case DDI_ATTACH:
3081991Sheppo 		break;
3091991Sheppo 	case DDI_RESUME:
3101991Sheppo 	case DDI_PM_RESUME:
3111991Sheppo 	default:
3121991Sheppo 		goto vnet_attach_fail;
3131991Sheppo 	}
3141991Sheppo 
3151991Sheppo 	instance = ddi_get_instance(dip);
3161991Sheppo 	DBG1((NULL, "vnetattach: instance(%d) enter\n", instance));
3171991Sheppo 
3181991Sheppo 	/* allocate vnet_t and mac_t structures */
3191991Sheppo 	vnetp = kmem_zalloc(sizeof (vnet_t), KM_SLEEP);
3201991Sheppo 	attach_state |= AST_vnet_alloc;
3211991Sheppo 
3221991Sheppo 	macp = kmem_zalloc(sizeof (mac_t), KM_SLEEP);
3231991Sheppo 	attach_state |= AST_mac_alloc;
3241991Sheppo 
3251991Sheppo 	/* setup links to vnet_t from both devinfo and mac_t */
3261991Sheppo 	ddi_set_driver_private(dip, (caddr_t)vnetp);
3271991Sheppo 	macp->m_driver = vnetp;
3281991Sheppo 	vnetp->dip = dip;
3291991Sheppo 	vnetp->macp = macp;
3301991Sheppo 	vnetp->instance = instance;
3311991Sheppo 
3321991Sheppo 	/* read the mac address */
3331991Sheppo 	status = vnet_read_mac_address(vnetp);
3341991Sheppo 	if (status != DDI_SUCCESS) {
3351991Sheppo 		goto vnet_attach_fail;
3361991Sheppo 	}
3371991Sheppo 	attach_state |= AST_read_macaddr;
3381991Sheppo 
3391991Sheppo 	/*
3401991Sheppo 	 * Initialize the generic vnet proxy transport. This is the first
3411991Sheppo 	 * and default transport used by vnet. The generic transport
3421991Sheppo 	 * is provided by using sun4v LDC (logical domain channel). On success,
3431991Sheppo 	 * vgen_init() provides a pointer to mac_t of generic transport.
3441991Sheppo 	 * Currently, this generic layer provides network connectivity to other
3451991Sheppo 	 * vnets within ldoms and also to remote hosts oustide ldoms through
3461991Sheppo 	 * the virtual switch (vsw) device on domain0. In the future, when
3471991Sheppo 	 * physical adapters that are able to share their resources (such as
3481991Sheppo 	 * dma channels) with guest domains become available, the vnet device
3491991Sheppo 	 * will use hardware specific driver to communicate directly over the
3501991Sheppo 	 * physical device to reach remote hosts without going through vswitch.
3511991Sheppo 	 */
3521991Sheppo 	status = vgen_init(vnetp, vnetp->dip, vnetp->macp,
3531991Sheppo 	    (uint8_t *)vnetp->curr_macaddr, &vgenmacp);
3541991Sheppo 	if (status != DDI_SUCCESS) {
3551991Sheppo 		DERR((vnetp, "vgen_init() failed\n"));
3561991Sheppo 		goto vnet_attach_fail;
3571991Sheppo 	}
3581991Sheppo 	attach_state |= AST_vgen_init;
3591991Sheppo 
3601991Sheppo 	vp_tlp = kmem_zalloc(sizeof (vp_tl_t), KM_SLEEP);
3611991Sheppo 	vp_tlp->macp = vgenmacp;
3621991Sheppo 	(void) snprintf(vp_tlp->name, MAXNAMELEN, "%s%u", "vgen", instance);
3631991Sheppo 	(void) strcpy(vnetp->vgen_name, vp_tlp->name);
3641991Sheppo 
3651991Sheppo 	/* add generic transport to the list of vnet proxy transports */
3661991Sheppo 	vnet_add_vptl(vnetp, vp_tlp);
3671991Sheppo 	attach_state |= AST_vptl_alloc;
3681991Sheppo 
3691991Sheppo 	nfdbh = vnet_nfdb_hash;
3701991Sheppo 	if ((nfdbh < VNET_NFDB_HASH) || (nfdbh > VNET_NFDB_HASH_MAX)) {
3711991Sheppo 		vnetp->nfdb_hash = VNET_NFDB_HASH;
3721991Sheppo 	}
3731991Sheppo 	else
3741991Sheppo 		vnetp->nfdb_hash = nfdbh;
3751991Sheppo 
3761991Sheppo 	/* allocate fdb hash table, with an extra slot for default route */
3771991Sheppo 	vnetp->fdbhp = kmem_zalloc(sizeof (fdb_fanout_t) *
3781991Sheppo 	    (vnetp->nfdb_hash + 1), KM_SLEEP);
3791991Sheppo 	attach_state |= AST_fdbh_alloc;
3801991Sheppo 
3811991Sheppo 	/* register with MAC layer */
3821991Sheppo 	status = vnet_mac_register(vnetp);
3831991Sheppo 	if (status != DDI_SUCCESS) {
3841991Sheppo 		goto vnet_attach_fail;
3851991Sheppo 	}
3861991Sheppo 
3871991Sheppo 	/* add to the list of vnet devices */
3881991Sheppo 	WRITE_ENTER(&vnet_rw);
3891991Sheppo 	vnetp->nextp = vnet_headp;
3901991Sheppo 	vnet_headp = vnetp;
3911991Sheppo 	RW_EXIT(&vnet_rw);
3921991Sheppo 
3931991Sheppo 	DBG1((NULL, "vnetattach: instance(%d) exit\n", instance));
3941991Sheppo 	return (DDI_SUCCESS);
3951991Sheppo 
3961991Sheppo vnet_attach_fail:
3971991Sheppo 	if (attach_state & AST_fdbh_alloc) {
3981991Sheppo 		kmem_free(vnetp->fdbhp,
3991991Sheppo 		    sizeof (fdb_fanout_t) * (vnetp->nfdb_hash + 1));
4001991Sheppo 	}
4011991Sheppo 	if (attach_state & AST_vptl_alloc) {
4021991Sheppo 		WRITE_ENTER(&vnetp->trwlock);
4031991Sheppo 		vnet_del_vptl(vnetp, vp_tlp);
4041991Sheppo 		RW_EXIT(&vnetp->trwlock);
4051991Sheppo 	}
4061991Sheppo 	if (attach_state & AST_vgen_init) {
4071991Sheppo 		vgen_uninit(vgenmacp->m_driver);
4081991Sheppo 	}
4091991Sheppo 	if (attach_state & AST_mac_alloc) {
4101991Sheppo 		KMEM_FREE(macp);
4111991Sheppo 	}
4121991Sheppo 	if (attach_state & AST_vnet_alloc) {
4131991Sheppo 		KMEM_FREE(vnetp);
4141991Sheppo 	}
4151991Sheppo 	return (DDI_FAILURE);
4161991Sheppo }
4171991Sheppo 
4181991Sheppo /*
4191991Sheppo  * detach(9E): detach a device from the system.
4201991Sheppo  */
4211991Sheppo static int
4221991Sheppo vnetdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
4231991Sheppo {
4241991Sheppo 	vnet_t		*vnetp;
4251991Sheppo 	vnet_t		**vnetpp;
4261991Sheppo 	vp_tl_t		*vp_tlp;
4271991Sheppo 	int		instance;
4281991Sheppo 
4291991Sheppo 	instance = ddi_get_instance(dip);
4301991Sheppo 	DBG1((NULL, "vnetdetach: instance(%d) enter\n", instance));
4311991Sheppo 
4321991Sheppo 	vnetp = ddi_get_driver_private(dip);
4331991Sheppo 	if (vnetp == NULL) {
4341991Sheppo 		goto vnet_detach_fail;
4351991Sheppo 	}
4361991Sheppo 
4371991Sheppo 	switch (cmd) {
4381991Sheppo 	case DDI_DETACH:
4391991Sheppo 		break;
4401991Sheppo 	case DDI_SUSPEND:
4411991Sheppo 	case DDI_PM_SUSPEND:
4421991Sheppo 	default:
4431991Sheppo 		goto vnet_detach_fail;
4441991Sheppo 	}
4451991Sheppo 
4461991Sheppo 	/*
4471991Sheppo 	 * Unregister from the MAC subsystem.  This can fail, in
4481991Sheppo 	 * particular if there are DLPI style-2 streams still open -
4491991Sheppo 	 * in which case we just return failure.
4501991Sheppo 	 */
4511991Sheppo 	if (mac_unregister(vnetp->macp) != 0)
4521991Sheppo 		goto vnet_detach_fail;
4531991Sheppo 
4541991Sheppo 	/* unlink from instance(vnet_t) list */
4551991Sheppo 	WRITE_ENTER(&vnet_rw);
4561991Sheppo 	for (vnetpp = &vnet_headp; *vnetpp; vnetpp = &(*vnetpp)->nextp) {
4571991Sheppo 		if (*vnetpp == vnetp) {
4581991Sheppo 			*vnetpp = vnetp->nextp;
4591991Sheppo 			break;
4601991Sheppo 		}
4611991Sheppo 	}
4621991Sheppo 	RW_EXIT(&vnet_rw);
4631991Sheppo 
4641991Sheppo 	/* uninit and free vnet proxy transports */
4651991Sheppo 	WRITE_ENTER(&vnetp->trwlock);
4661991Sheppo 	while ((vp_tlp = vnetp->tlp) != NULL) {
4671991Sheppo 		if (strcmp(vnetp->vgen_name, vp_tlp->name) == 0) {
4681991Sheppo 			/* uninitialize generic transport */
4691991Sheppo 			vgen_uninit(vp_tlp->macp->m_driver);
4701991Sheppo 		}
4711991Sheppo 		vnet_del_vptl(vnetp, vp_tlp);
4721991Sheppo 	}
4731991Sheppo 	RW_EXIT(&vnetp->trwlock);
4741991Sheppo 
4751991Sheppo 	KMEM_FREE(vnetp->macp);
4761991Sheppo 	KMEM_FREE(vnetp);
4771991Sheppo 
4781991Sheppo 	return (DDI_SUCCESS);
4791991Sheppo 
4801991Sheppo vnet_detach_fail:
4811991Sheppo 	return (DDI_FAILURE);
4821991Sheppo }
4831991Sheppo 
4841991Sheppo /* enable the device for transmit/receive */
4851991Sheppo static int
4861991Sheppo vnet_m_start(void *arg)
4871991Sheppo {
4881991Sheppo 	vnet_t		*vnetp = arg;
4891991Sheppo 	vp_tl_t		*vp_tlp;
4901991Sheppo 	mac_t		*vp_macp;
4911991Sheppo 
4921991Sheppo 	DBG1((vnetp, "vnet_m_start: enter\n"));
4931991Sheppo 
4941991Sheppo 	/*
4951991Sheppo 	 * XXX
4961991Sheppo 	 * Currently, we only have generic transport. m_start() invokes
4971991Sheppo 	 * vgen_start() which enables ports/channels in vgen and
4981991Sheppo 	 * initiates handshake with peer vnets and vsw. In the future when we
4991991Sheppo 	 * have support for hardware specific transports, this information
5001991Sheppo 	 * needs to be propagted back to vnet from vgen and we need to revisit
5011991Sheppo 	 * this code (see comments in vnet_attach()).
5021991Sheppo 	 *
5031991Sheppo 	 */
5041991Sheppo 	WRITE_ENTER(&vnetp->trwlock);
5051991Sheppo 	for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) {
5061991Sheppo 		vp_macp = vp_tlp->macp;
5071991Sheppo 		vp_macp->m_start(vp_macp->m_driver);
5081991Sheppo 	}
5091991Sheppo 	RW_EXIT(&vnetp->trwlock);
5101991Sheppo 
5111991Sheppo 	DBG1((vnetp, "vnet_m_start: exit\n"));
5121991Sheppo 	return (VNET_SUCCESS);
5131991Sheppo 
5141991Sheppo }
5151991Sheppo 
5161991Sheppo /* stop transmit/receive for the device */
5171991Sheppo static void
5181991Sheppo vnet_m_stop(void *arg)
5191991Sheppo {
5201991Sheppo 	vnet_t		*vnetp = arg;
5211991Sheppo 	vp_tl_t		*vp_tlp;
5221991Sheppo 	mac_t		*vp_macp;
5231991Sheppo 
5241991Sheppo 	DBG1((vnetp, "vnet_m_stop: enter\n"));
5251991Sheppo 
5261991Sheppo 	WRITE_ENTER(&vnetp->trwlock);
5271991Sheppo 	for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) {
5281991Sheppo 		vp_macp = vp_tlp->macp;
5291991Sheppo 		vp_macp->m_stop(vp_macp->m_driver);
5301991Sheppo 	}
5311991Sheppo 	RW_EXIT(&vnetp->trwlock);
5321991Sheppo 
5331991Sheppo 	DBG1((vnetp, "vnet_m_stop: exit\n"));
5341991Sheppo }
5351991Sheppo 
5361991Sheppo /* set the unicast mac address of the device */
5371991Sheppo static int
5381991Sheppo vnet_m_unicst(void *arg, const uint8_t *macaddr)
5391991Sheppo {
5401991Sheppo 	_NOTE(ARGUNUSED(macaddr))
5411991Sheppo 
5421991Sheppo 	vnet_t *vnetp = arg;
5431991Sheppo 
5441991Sheppo 	DBG1((vnetp, "vnet_m_unicst: enter\n"));
5451991Sheppo 	/*
5461991Sheppo 	 * XXX: setting mac address dynamically is not supported.
5471991Sheppo 	 */
5481991Sheppo 	DBG1((vnetp, "vnet_m_unicst: exit\n"));
5491991Sheppo 
550*2109Slm66018 	return (VNET_FAILURE);
5511991Sheppo }
5521991Sheppo 
5531991Sheppo /* enable/disable a multicast address */
5541991Sheppo static int
5551991Sheppo vnet_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
5561991Sheppo {
5571991Sheppo 	_NOTE(ARGUNUSED(add, mca))
5581991Sheppo 
5591991Sheppo 	vnet_t *vnetp = arg;
5601991Sheppo 	vp_tl_t		*vp_tlp;
5611991Sheppo 	mac_t		*vp_macp;
5621991Sheppo 	int rv = VNET_SUCCESS;
5631991Sheppo 
5641991Sheppo 	DBG1((vnetp, "vnet_m_multicst: enter\n"));
5651991Sheppo 	READ_ENTER(&vnetp->trwlock);
5661991Sheppo 	for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) {
5671991Sheppo 		if (strcmp(vnetp->vgen_name, vp_tlp->name) == 0) {
5681991Sheppo 			vp_macp = vp_tlp->macp;
5691991Sheppo 			rv = vp_macp->m_multicst(vp_macp->m_driver, add, mca);
5701991Sheppo 			break;
5711991Sheppo 		}
5721991Sheppo 	}
5731991Sheppo 	RW_EXIT(&vnetp->trwlock);
5741991Sheppo 	DBG1((vnetp, "vnet_m_multicst: exit\n"));
5751991Sheppo 	return (rv);
5761991Sheppo }
5771991Sheppo 
5781991Sheppo /* set or clear promiscuous mode on the device */
5791991Sheppo static int
5801991Sheppo vnet_m_promisc(void *arg, boolean_t on)
5811991Sheppo {
5821991Sheppo 	_NOTE(ARGUNUSED(on))
5831991Sheppo 
5841991Sheppo 	vnet_t *vnetp = arg;
5851991Sheppo 	DBG1((vnetp, "vnet_m_promisc: enter\n"));
5861991Sheppo 	/*
5871991Sheppo 	 * XXX: setting promiscuous mode is not supported, just return success.
5881991Sheppo 	 */
5891991Sheppo 	DBG1((vnetp, "vnet_m_promisc: exit\n"));
5901991Sheppo 	return (VNET_SUCCESS);
5911991Sheppo }
5921991Sheppo 
5931991Sheppo /*
5941991Sheppo  * Transmit a chain of packets. This function provides switching functionality
5951991Sheppo  * based on the destination mac address to reach other guests (within ldoms) or
5961991Sheppo  * external hosts.
5971991Sheppo  */
5981991Sheppo mblk_t *
5991991Sheppo vnet_m_tx(void *arg, mblk_t *mp)
6001991Sheppo {
6011991Sheppo 	vnet_t *vnetp;
6021991Sheppo 	mblk_t *next;
6031991Sheppo 	uint32_t fdbhash;
6041991Sheppo 	fdb_t *fdbp;
6051991Sheppo 	fdb_fanout_t *fdbhp;
6061991Sheppo 	struct ether_header *ehp;
6071991Sheppo 	uint8_t *macaddr;
6081991Sheppo 	mblk_t *resid_mp;
6091991Sheppo 
6101991Sheppo 	vnetp = (vnet_t *)arg;
6111991Sheppo 	DBG1((vnetp, "vnet_m_tx: enter\n"));
6121991Sheppo 	ASSERT(mp != NULL);
6131991Sheppo 
6141991Sheppo 	while (mp != NULL) {
6151991Sheppo 		next = mp->b_next;
6161991Sheppo 		mp->b_next = NULL;
6171991Sheppo 
6181991Sheppo 		/* get the destination mac address in the eth header */
6191991Sheppo 		ehp = (struct ether_header *)mp->b_rptr;
6201991Sheppo 		macaddr = (uint8_t *)&ehp->ether_dhost;
6211991Sheppo 
6221991Sheppo 		/* Calculate hash value and fdb fanout */
6231991Sheppo 		fdbhash = MACHASH(macaddr, vnetp->nfdb_hash);
6241991Sheppo 		fdbhp = &(vnetp->fdbhp[fdbhash]);
6251991Sheppo 
6261991Sheppo 		READ_ENTER(&fdbhp->rwlock);
6271991Sheppo 		fdbp = vnet_lookup_fdb(fdbhp, macaddr);
6281991Sheppo 		if (fdbp) {
6291991Sheppo 			/*
6301991Sheppo 			 * If the destination is in FDB, the destination is
6311991Sheppo 			 * a vnet device within ldoms and directly reachable,
6321991Sheppo 			 * invoke the tx function in the fdb entry.
6331991Sheppo 			 */
6341991Sheppo 			resid_mp = fdbp->m_tx(fdbp->txarg, mp);
6351991Sheppo 			if (resid_mp != NULL) {
6361991Sheppo 				/* m_tx failed */
6371991Sheppo 				mp->b_next = next;
6381991Sheppo 				RW_EXIT(&fdbhp->rwlock);
6391991Sheppo 				break;
6401991Sheppo 			}
6411991Sheppo 			RW_EXIT(&fdbhp->rwlock);
6421991Sheppo 		} else {
6431991Sheppo 			/* destination is not in FDB */
6441991Sheppo 			RW_EXIT(&fdbhp->rwlock);
6451991Sheppo 			/*
6461991Sheppo 			 * If the destination is broadcast/multicast
6471991Sheppo 			 * or an unknown unicast address, forward the
6481991Sheppo 			 * packet to vsw, using the last slot in fdb which is
6491991Sheppo 			 * reserved for default route.
6501991Sheppo 			 */
6511991Sheppo 			fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]);
6521991Sheppo 			READ_ENTER(&fdbhp->rwlock);
6531991Sheppo 			fdbp = fdbhp->headp;
6541991Sheppo 			if (fdbp) {
6551991Sheppo 				resid_mp = fdbp->m_tx(fdbp->txarg, mp);
6561991Sheppo 				if (resid_mp != NULL) {
6571991Sheppo 					/* m_tx failed */
6581991Sheppo 					mp->b_next = next;
6591991Sheppo 					RW_EXIT(&fdbhp->rwlock);
6601991Sheppo 					break;
6611991Sheppo 				}
6621991Sheppo 			} else {
6631991Sheppo 				/* drop the packet */
6641991Sheppo 				freemsg(mp);
6651991Sheppo 			}
6661991Sheppo 			RW_EXIT(&fdbhp->rwlock);
6671991Sheppo 		}
6681991Sheppo 
6691991Sheppo 		mp = next;
6701991Sheppo 	}
6711991Sheppo 
6721991Sheppo 	DBG1((vnetp, "vnet_m_tx: exit\n"));
6731991Sheppo 	return (mp);
6741991Sheppo }
6751991Sheppo 
6761991Sheppo /* register resources with mac layer */
6771991Sheppo static void
6781991Sheppo vnet_m_resources(void *arg)
6791991Sheppo {
6801991Sheppo 	vnet_t *vnetp = arg;
6811991Sheppo 	vp_tl_t	*vp_tlp;
6821991Sheppo 	mac_t	*vp_macp;
6831991Sheppo 
6841991Sheppo 	DBG1((vnetp, "vnet_m_resources: enter\n"));
6851991Sheppo 
6861991Sheppo 	WRITE_ENTER(&vnetp->trwlock);
6871991Sheppo 	for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) {
6881991Sheppo 		vp_macp = vp_tlp->macp;
6891991Sheppo 		vp_macp->m_resources(vp_macp->m_driver);
6901991Sheppo 	}
6911991Sheppo 	RW_EXIT(&vnetp->trwlock);
6921991Sheppo 
6931991Sheppo 	DBG1((vnetp, "vnet_m_resources: exit\n"));
6941991Sheppo }
6951991Sheppo 
6961991Sheppo /*
6971991Sheppo  * vnet specific ioctls
6981991Sheppo  */
6991991Sheppo static void
7001991Sheppo vnet_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
7011991Sheppo {
7021991Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
7031991Sheppo 	struct iocblk *iocp;
7041991Sheppo 	int cmd;
7051991Sheppo 
7061991Sheppo 	DBG1((vnetp, "vnet_m_ioctl: enter\n"));
7071991Sheppo 
7081991Sheppo 	iocp = (struct iocblk *)mp->b_rptr;
7091991Sheppo 	iocp->ioc_error = 0;
7101991Sheppo 	cmd = iocp->ioc_cmd;
7111991Sheppo 	switch (cmd) {
7121991Sheppo 	default:
7131991Sheppo 		miocnak(wq, mp, 0, EINVAL);
7141991Sheppo 		break;
7151991Sheppo 	}
7161991Sheppo 	DBG1((vnetp, "vnet_m_ioctl: exit\n"));
7171991Sheppo }
7181991Sheppo 
7191991Sheppo /* get statistics from the device */
7201991Sheppo uint64_t
7211991Sheppo vnet_m_stat(void *arg, enum mac_stat stat)
7221991Sheppo {
7231991Sheppo 	vnet_t *vnetp = arg;
7241991Sheppo 	vp_tl_t	*vp_tlp;
7251991Sheppo 	mac_t	*vp_macp;
7261991Sheppo 	uint64_t val = 0;
7271991Sheppo 
7281991Sheppo 	DBG1((vnetp, "vnet_m_stat: enter\n"));
7291991Sheppo 
7301991Sheppo 	/*
7311991Sheppo 	 * get the specified statistic from each transport
7321991Sheppo 	 * and return the aggregate val
7331991Sheppo 	 */
7341991Sheppo 	READ_ENTER(&vnetp->trwlock);
7351991Sheppo 	for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) {
7361991Sheppo 		vp_macp = vp_tlp->macp;
7371991Sheppo 		val += vp_macp->m_stat(vp_macp->m_driver, stat);
7381991Sheppo 	}
7391991Sheppo 	RW_EXIT(&vnetp->trwlock);
7401991Sheppo 
7411991Sheppo 	DBG1((vnetp, "vnet_m_stat: exit\n"));
7421991Sheppo 	return (val);
7431991Sheppo }
7441991Sheppo 
7451991Sheppo /* wrapper function for mac_register() */
7461991Sheppo static int
7471991Sheppo vnet_mac_register(vnet_t *vnetp)
7481991Sheppo {
7491991Sheppo 	mac_info_t *mip;
7501991Sheppo 	mac_t *macp;
7511991Sheppo 
7521991Sheppo 	macp = vnetp->macp;
7531991Sheppo 
7541991Sheppo 	mip = &(macp->m_info);
7551991Sheppo 	mip->mi_media = DL_ETHER;
7561991Sheppo 	mip->mi_sdu_min = 0;
7571991Sheppo 	mip->mi_sdu_max = ETHERMTU;
7581991Sheppo 	mip->mi_cksum = 0;
7591991Sheppo 	mip->mi_poll = 0; /* DL_CAPAB_POLL ? */
7601991Sheppo 	mip->mi_addr_length = ETHERADDRL;
7611991Sheppo 	bcopy(&etherbroadcastaddr, mip->mi_brdcst_addr, ETHERADDRL);
7621991Sheppo 	bcopy(vnetp->curr_macaddr, mip->mi_unicst_addr, ETHERADDRL);
7631991Sheppo 
7641991Sheppo 	MAC_STAT_MIB(mip->mi_stat);
7651991Sheppo 	mip->mi_stat[MAC_STAT_UNKNOWNS] = B_FALSE;
7661991Sheppo 	MAC_STAT_ETHER(mip->mi_stat);
7671991Sheppo 	mip->mi_stat[MAC_STAT_SQE_ERRORS] = B_FALSE;
7681991Sheppo 	mip->mi_stat[MAC_STAT_MACRCV_ERRORS] = B_FALSE;
7691991Sheppo 
7701991Sheppo 	macp->m_stat = vnet_m_stat;
7711991Sheppo 	macp->m_start = vnet_m_start;
7721991Sheppo 	macp->m_stop = vnet_m_stop;
7731991Sheppo 	macp->m_promisc = vnet_m_promisc;
7741991Sheppo 	macp->m_multicst = vnet_m_multicst;
7751991Sheppo 	macp->m_unicst = vnet_m_unicst;
7761991Sheppo 	macp->m_resources = vnet_m_resources;
7771991Sheppo 	macp->m_ioctl = vnet_m_ioctl;
7781991Sheppo 	macp->m_tx = vnet_m_tx;
7791991Sheppo 
7801991Sheppo 	macp->m_dip = vnetp->dip;
7811991Sheppo 	macp->m_ident = MAC_IDENT;
7821991Sheppo 
7831991Sheppo 	/*
7841991Sheppo 	 * Finally, we're ready to register ourselves with the MAC layer
7851991Sheppo 	 * interface; if this succeeds, we're all ready to start()
7861991Sheppo 	 */
7871991Sheppo 	if (mac_register(macp) != 0) {
7881991Sheppo 		KMEM_FREE(macp);
7891991Sheppo 		return (DDI_FAILURE);
7901991Sheppo 	}
7911991Sheppo 
7921991Sheppo 	return (DDI_SUCCESS);
7931991Sheppo }
7941991Sheppo 
7951991Sheppo /* add vp_tl to the list */
7961991Sheppo static void
7971991Sheppo vnet_add_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp)
7981991Sheppo {
7991991Sheppo 	vp_tl_t *ttlp;
8001991Sheppo 
8011991Sheppo 	WRITE_ENTER(&vnetp->trwlock);
8021991Sheppo 	if (vnetp->tlp == NULL) {
8031991Sheppo 		vnetp->tlp = vp_tlp;
8041991Sheppo 	} else {
8051991Sheppo 		ttlp = vnetp->tlp;
8061991Sheppo 		while (ttlp->nextp)
8071991Sheppo 			ttlp = ttlp->nextp;
8081991Sheppo 		ttlp->nextp = vp_tlp;
8091991Sheppo 	}
8101991Sheppo 	RW_EXIT(&vnetp->trwlock);
8111991Sheppo }
8121991Sheppo 
8131991Sheppo /* remove vp_tl from the list */
8141991Sheppo static void
8151991Sheppo vnet_del_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp)
8161991Sheppo {
8171991Sheppo 	vp_tl_t *ttlp, **pretlp;
8181991Sheppo 	boolean_t found = B_FALSE;
8191991Sheppo 
8201991Sheppo 	pretlp = &vnetp->tlp;
8211991Sheppo 	ttlp = *pretlp;
8221991Sheppo 	while (ttlp) {
8231991Sheppo 		if (ttlp == vp_tlp) {
8241991Sheppo 			found = B_TRUE;
8251991Sheppo 			(*pretlp) = ttlp->nextp;
8261991Sheppo 			ttlp->nextp = NULL;
8271991Sheppo 			break;
8281991Sheppo 		}
8291991Sheppo 		pretlp = &(ttlp->nextp);
8301991Sheppo 		ttlp = *pretlp;
8311991Sheppo 	}
8321991Sheppo 
8331991Sheppo 	if (found) {
8341991Sheppo 		KMEM_FREE(vp_tlp);
8351991Sheppo 	}
8361991Sheppo }
8371991Sheppo 
8381991Sheppo /* get vp_tl corresponding to the given name */
8391991Sheppo static vp_tl_t *
8401991Sheppo vnet_get_vptl(vnet_t *vnetp, const char *name)
8411991Sheppo {
8421991Sheppo 	vp_tl_t *tlp;
8431991Sheppo 
8441991Sheppo 	tlp = vnetp->tlp;
8451991Sheppo 	while (tlp) {
8461991Sheppo 		if (strcmp(tlp->name, name) == 0) {
8471991Sheppo 			return (tlp);
8481991Sheppo 		}
8491991Sheppo 		tlp = tlp->nextp;
8501991Sheppo 	}
8511991Sheppo 	DWARN((vnetp,
8521991Sheppo 	    "vnet_get_vptl: can't find vp_tl with name (%s)\n", name));
8531991Sheppo 	return (NULL);
8541991Sheppo }
8551991Sheppo 
8561991Sheppo /* read the mac address of the device */
8571991Sheppo static int
8581991Sheppo vnet_read_mac_address(vnet_t *vnetp)
8591991Sheppo {
8601991Sheppo 	uchar_t 	*macaddr;
8611991Sheppo 	uint32_t 	size;
8621991Sheppo 	int 		rv;
8631991Sheppo 
8641991Sheppo 	rv = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, vnetp->dip,
8651991Sheppo 		DDI_PROP_DONTPASS, macaddr_propname, &macaddr, &size);
8661991Sheppo 	if ((rv != DDI_PROP_SUCCESS) || (size != ETHERADDRL)) {
8671991Sheppo 		DWARN((vnetp,
8681991Sheppo 		"vnet_read_mac_address: prop_lookup failed (%s) err (%d)\n",
8691991Sheppo 		macaddr_propname, rv));
8701991Sheppo 		return (DDI_FAILURE);
8711991Sheppo 	}
8721991Sheppo 	bcopy(macaddr, (caddr_t)vnetp->vendor_addr, ETHERADDRL);
8731991Sheppo 	bcopy(macaddr, (caddr_t)vnetp->curr_macaddr, ETHERADDRL);
8741991Sheppo 	ddi_prop_free(macaddr);
8751991Sheppo 
8761991Sheppo 	return (DDI_SUCCESS);
8771991Sheppo }
8781991Sheppo 
8791991Sheppo 
8801991Sheppo /*
8811991Sheppo  * Functions below are called only by generic transport to add/remove/modify
8821991Sheppo  * entries in forwarding database. See comments in vgen_port_init(vnet_gen.c).
8831991Sheppo  */
8841991Sheppo 
8851991Sheppo /* add an entry into the forwarding database */
8861991Sheppo void
8871991Sheppo vnet_add_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg)
8881991Sheppo {
8891991Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
8901991Sheppo 	uint32_t fdbhash;
8911991Sheppo 	fdb_t *fdbp;
8921991Sheppo 	fdb_fanout_t *fdbhp;
8931991Sheppo 
8941991Sheppo 	/* Calculate hash value and fdb fanout */
8951991Sheppo 	fdbhash = MACHASH(macaddr, vnetp->nfdb_hash);
8961991Sheppo 	fdbhp = &(vnetp->fdbhp[fdbhash]);
8971991Sheppo 
8981991Sheppo 	WRITE_ENTER(&fdbhp->rwlock);
8991991Sheppo 
9001991Sheppo 	fdbp = kmem_zalloc(sizeof (fdb_t), KM_NOSLEEP);
9011991Sheppo 	if (fdbp == NULL) {
9021991Sheppo 		RW_EXIT(&fdbhp->rwlock);
9031991Sheppo 		return;
9041991Sheppo 	}
9051991Sheppo 	bcopy(macaddr, (caddr_t)fdbp->macaddr, ETHERADDRL);
9061991Sheppo 	fdbp->m_tx = m_tx;
9071991Sheppo 	fdbp->txarg = txarg;
9081991Sheppo 	fdbp->nextp = fdbhp->headp;
9091991Sheppo 	fdbhp->headp = fdbp;
9101991Sheppo 
9111991Sheppo 	RW_EXIT(&fdbhp->rwlock);
9121991Sheppo }
9131991Sheppo 
9141991Sheppo /* delete an entry from the forwarding database */
9151991Sheppo void
9161991Sheppo vnet_del_fdb(void *arg, uint8_t *macaddr)
9171991Sheppo {
9181991Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
9191991Sheppo 	uint32_t fdbhash;
9201991Sheppo 	fdb_t *fdbp;
9211991Sheppo 	fdb_t **pfdbp;
9221991Sheppo 	fdb_fanout_t *fdbhp;
9231991Sheppo 
9241991Sheppo 	/* Calculate hash value and fdb fanout */
9251991Sheppo 	fdbhash = MACHASH(macaddr, vnetp->nfdb_hash);
9261991Sheppo 	fdbhp = &(vnetp->fdbhp[fdbhash]);
9271991Sheppo 
9281991Sheppo 	WRITE_ENTER(&fdbhp->rwlock);
9291991Sheppo 
9301991Sheppo 	for (pfdbp = &fdbhp->headp; (fdbp  = *pfdbp) != NULL;
9311991Sheppo 	    pfdbp = &fdbp->nextp) {
9321991Sheppo 		if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) {
9331991Sheppo 			/* Unlink it from the list */
9341991Sheppo 			*pfdbp = fdbp->nextp;
9351991Sheppo 			KMEM_FREE(fdbp);
9361991Sheppo 			break;
9371991Sheppo 		}
9381991Sheppo 	}
9391991Sheppo 
9401991Sheppo 	RW_EXIT(&fdbhp->rwlock);
9411991Sheppo }
9421991Sheppo 
9431991Sheppo /* modify an existing entry in the forwarding database */
9441991Sheppo void
9451991Sheppo vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg)
9461991Sheppo {
9471991Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
9481991Sheppo 	uint32_t fdbhash;
9491991Sheppo 	fdb_t *fdbp;
9501991Sheppo 	fdb_fanout_t *fdbhp;
9511991Sheppo 
9521991Sheppo 	/* Calculate hash value and fdb fanout */
9531991Sheppo 	fdbhash = MACHASH(macaddr, vnetp->nfdb_hash);
9541991Sheppo 	fdbhp = &(vnetp->fdbhp[fdbhash]);
9551991Sheppo 
9561991Sheppo 	WRITE_ENTER(&fdbhp->rwlock);
9571991Sheppo 
9581991Sheppo 	for (fdbp = fdbhp->headp; fdbp != NULL; fdbp = fdbp->nextp) {
9591991Sheppo 		if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) {
9601991Sheppo 			/* change the entry to have new tx params */
9611991Sheppo 			fdbp->m_tx = m_tx;
9621991Sheppo 			fdbp->txarg = txarg;
9631991Sheppo 			break;
9641991Sheppo 		}
9651991Sheppo 	}
9661991Sheppo 
9671991Sheppo 	RW_EXIT(&fdbhp->rwlock);
9681991Sheppo }
9691991Sheppo 
9701991Sheppo /* look up an fdb entry based on the mac address, caller holds lock */
9711991Sheppo static fdb_t *
9721991Sheppo vnet_lookup_fdb(fdb_fanout_t *fdbhp, uint8_t *macaddr)
9731991Sheppo {
9741991Sheppo 	fdb_t *fdbp = NULL;
9751991Sheppo 
9761991Sheppo 	for (fdbp = fdbhp->headp; fdbp != NULL; fdbp = fdbp->nextp) {
9771991Sheppo 		if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) {
9781991Sheppo 			break;
9791991Sheppo 		}
9801991Sheppo 	}
9811991Sheppo 
9821991Sheppo 	return (fdbp);
9831991Sheppo }
9841991Sheppo 
9851991Sheppo /* add default route entry into the forwarding database */
9861991Sheppo void
9871991Sheppo vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg)
9881991Sheppo {
9891991Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
9901991Sheppo 	fdb_t *fdbp;
9911991Sheppo 	fdb_fanout_t *fdbhp;
9921991Sheppo 
9931991Sheppo 	/*
9941991Sheppo 	 * The last hash list is reserved for default route entry,
9951991Sheppo 	 * and for now, we have only one entry in this list.
9961991Sheppo 	 */
9971991Sheppo 	fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]);
9981991Sheppo 
9991991Sheppo 	WRITE_ENTER(&fdbhp->rwlock);
10001991Sheppo 
10011991Sheppo 	if (fdbhp->headp) {
10021991Sheppo 		DWARN((vnetp,
10031991Sheppo 		    "vnet_add_def_rte: default rte already exists\n"));
10041991Sheppo 		RW_EXIT(&fdbhp->rwlock);
10051991Sheppo 		return;
10061991Sheppo 	}
10071991Sheppo 	fdbp = kmem_zalloc(sizeof (fdb_t), KM_NOSLEEP);
10081991Sheppo 	if (fdbp == NULL) {
10091991Sheppo 		RW_EXIT(&fdbhp->rwlock);
10101991Sheppo 		return;
10111991Sheppo 	}
10121991Sheppo 	bzero(fdbp->macaddr, ETHERADDRL);
10131991Sheppo 	fdbp->m_tx = m_tx;
10141991Sheppo 	fdbp->txarg = txarg;
10151991Sheppo 	fdbp->nextp = NULL;
10161991Sheppo 	fdbhp->headp = fdbp;
10171991Sheppo 
10181991Sheppo 	RW_EXIT(&fdbhp->rwlock);
10191991Sheppo }
10201991Sheppo 
10211991Sheppo /* delete default route entry from the forwarding database */
10221991Sheppo void
10231991Sheppo vnet_del_def_rte(void *arg)
10241991Sheppo {
10251991Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
10261991Sheppo 	fdb_t *fdbp;
10271991Sheppo 	fdb_fanout_t *fdbhp;
10281991Sheppo 
10291991Sheppo 	/*
10301991Sheppo 	 * The last hash list is reserved for default route entry,
10311991Sheppo 	 * and for now, we have only one entry in this list.
10321991Sheppo 	 */
10331991Sheppo 	fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]);
10341991Sheppo 
10351991Sheppo 	WRITE_ENTER(&fdbhp->rwlock);
10361991Sheppo 
10371991Sheppo 	if (fdbhp->headp == NULL) {
10381991Sheppo 		RW_EXIT(&fdbhp->rwlock);
10391991Sheppo 		return;
10401991Sheppo 	}
10411991Sheppo 	fdbp = fdbhp->headp;
10421991Sheppo 	KMEM_FREE(fdbp);
10431991Sheppo 	fdbhp->headp = NULL;
10441991Sheppo 
10451991Sheppo 	RW_EXIT(&fdbhp->rwlock);
10461991Sheppo }
1047