xref: /onnv-gate/usr/src/uts/sun4v/io/vnet.c (revision 5641:a615f141f7a0)
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 /*
234647Sraghuram  * Copyright 2007 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>
442311Sseb #include <sys/mac_ether.h>
451991Sheppo #include <sys/ddi.h>
461991Sheppo #include <sys/sunddi.h>
471991Sheppo #include <sys/strsun.h>
481991Sheppo #include <sys/note.h>
491991Sheppo #include <sys/vnet.h>
501991Sheppo 
511991Sheppo /*
521991Sheppo  * Function prototypes.
531991Sheppo  */
541991Sheppo 
551991Sheppo /* DDI entrypoints */
561991Sheppo static int vnetdevinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
571991Sheppo static int vnetattach(dev_info_t *, ddi_attach_cmd_t);
581991Sheppo static int vnetdetach(dev_info_t *, ddi_detach_cmd_t);
591991Sheppo 
601991Sheppo /* MAC entrypoints  */
612311Sseb static int vnet_m_stat(void *, uint_t, uint64_t *);
621991Sheppo static int vnet_m_start(void *);
631991Sheppo static void vnet_m_stop(void *);
641991Sheppo static int vnet_m_promisc(void *, boolean_t);
651991Sheppo static int vnet_m_multicst(void *, boolean_t, const uint8_t *);
661991Sheppo static int vnet_m_unicst(void *, const uint8_t *);
671991Sheppo mblk_t *vnet_m_tx(void *, mblk_t *);
681991Sheppo 
691991Sheppo /* vnet internal functions */
701991Sheppo static int vnet_mac_register(vnet_t *);
711991Sheppo static int vnet_read_mac_address(vnet_t *vnetp);
721991Sheppo static void vnet_add_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp);
731991Sheppo static void vnet_del_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp);
741991Sheppo static vp_tl_t *vnet_get_vptl(vnet_t *vnetp, const char *devname);
75*5641Swentaoy static void vnet_fdb_alloc(vnet_t *vnetp);
76*5641Swentaoy static void vnet_fdb_free(vnet_t *vnetp);
771991Sheppo static fdb_t *vnet_lookup_fdb(fdb_fanout_t *fdbhp, uint8_t *macaddr);
781991Sheppo 
791991Sheppo /* exported functions */
801991Sheppo void vnet_add_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg);
811991Sheppo void vnet_del_fdb(void *arg, uint8_t *macaddr);
822793Slm66018 void vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx,
832793Slm66018 	void *txarg, boolean_t upgrade);
841991Sheppo void vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg);
851991Sheppo void vnet_del_def_rte(void *arg);
862311Sseb void vnet_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp);
872311Sseb void vnet_tx_update(void *arg);
881991Sheppo 
891991Sheppo /* externs */
902311Sseb extern int vgen_init(void *vnetp, dev_info_t *vnetdip, const uint8_t *macaddr,
912311Sseb 	mac_register_t **vgenmacp);
922336Snarayan extern int vgen_uninit(void *arg);
931991Sheppo 
942311Sseb static mac_callbacks_t vnet_m_callbacks = {
952311Sseb 	0,
962311Sseb 	vnet_m_stat,
972311Sseb 	vnet_m_start,
982311Sseb 	vnet_m_stop,
992311Sseb 	vnet_m_promisc,
1002311Sseb 	vnet_m_multicst,
1012311Sseb 	vnet_m_unicst,
1022311Sseb 	vnet_m_tx,
1032311Sseb 	NULL,
1042311Sseb 	NULL,
1052311Sseb 	NULL
1062311Sseb };
1072311Sseb 
1081991Sheppo /*
1091991Sheppo  * Linked list of "vnet_t" structures - one per instance.
1101991Sheppo  */
1111991Sheppo static vnet_t	*vnet_headp = NULL;
1121991Sheppo static krwlock_t vnet_rw;
1131991Sheppo 
1141991Sheppo /* Tunables */
1151991Sheppo uint32_t vnet_ntxds = VNET_NTXDS;	/* power of 2 transmit descriptors */
1161991Sheppo uint32_t vnet_ldcwd_interval = VNET_LDCWD_INTERVAL; /* watchdog freq in msec */
1171991Sheppo uint32_t vnet_ldcwd_txtimeout = VNET_LDCWD_TXTIMEOUT;  /* tx timeout in msec */
1182410Slm66018 uint32_t vnet_ldc_mtu = VNET_LDC_MTU;		/* ldc mtu */
1191991Sheppo uint32_t vnet_nfdb_hash = VNET_NFDB_HASH;	/* size of fdb hash table */
1201991Sheppo 
1211991Sheppo /*
1221991Sheppo  * Property names
1231991Sheppo  */
1241991Sheppo static char macaddr_propname[] = "local-mac-address";
1251991Sheppo 
1261991Sheppo /*
1271991Sheppo  * This is the string displayed by modinfo(1m).
1281991Sheppo  */
1292109Slm66018 static char vnet_ident[] = "vnet driver v%I%";
1301991Sheppo extern struct mod_ops mod_driverops;
1311991Sheppo static struct cb_ops cb_vnetops = {
1321991Sheppo 	nulldev,		/* cb_open */
1331991Sheppo 	nulldev,		/* cb_close */
1341991Sheppo 	nodev,			/* cb_strategy */
1351991Sheppo 	nodev,			/* cb_print */
1361991Sheppo 	nodev,			/* cb_dump */
1371991Sheppo 	nodev,			/* cb_read */
1381991Sheppo 	nodev,			/* cb_write */
1391991Sheppo 	nodev,			/* cb_ioctl */
1401991Sheppo 	nodev,			/* cb_devmap */
1411991Sheppo 	nodev,			/* cb_mmap */
1421991Sheppo 	nodev,			/* cb_segmap */
1431991Sheppo 	nochpoll,		/* cb_chpoll */
1441991Sheppo 	ddi_prop_op,		/* cb_prop_op */
1451991Sheppo 	NULL,			/* cb_stream */
1461991Sheppo 	(int)(D_MP)		/* cb_flag */
1471991Sheppo };
1481991Sheppo 
1491991Sheppo static struct dev_ops vnetops = {
1501991Sheppo 	DEVO_REV,		/* devo_rev */
1511991Sheppo 	0,			/* devo_refcnt */
1521991Sheppo 	NULL,			/* devo_getinfo */
1531991Sheppo 	nulldev,		/* devo_identify */
1541991Sheppo 	nulldev,		/* devo_probe */
1551991Sheppo 	vnetattach,		/* devo_attach */
1561991Sheppo 	vnetdetach,		/* devo_detach */
1571991Sheppo 	nodev,			/* devo_reset */
1581991Sheppo 	&cb_vnetops,		/* devo_cb_ops */
1591991Sheppo 	(struct bus_ops *)NULL	/* devo_bus_ops */
1601991Sheppo };
1611991Sheppo 
1621991Sheppo static struct modldrv modldrv = {
1631991Sheppo 	&mod_driverops,		/* Type of module.  This one is a driver */
1641991Sheppo 	vnet_ident,		/* ID string */
1651991Sheppo 	&vnetops		/* driver specific ops */
1661991Sheppo };
1671991Sheppo 
1681991Sheppo static struct modlinkage modlinkage = {
1691991Sheppo 	MODREV_1, (void *)&modldrv, NULL
1701991Sheppo };
1711991Sheppo 
1724647Sraghuram #ifdef DEBUG
1731991Sheppo 
1741991Sheppo /*
1751991Sheppo  * Print debug messages - set to 0xf to enable all msgs
1761991Sheppo  */
1774647Sraghuram int vnet_dbglevel = 0x8;
1781991Sheppo 
1794647Sraghuram static void
1804647Sraghuram debug_printf(const char *fname, void *arg, const char *fmt, ...)
1811991Sheppo {
1821991Sheppo 	char    buf[512];
1831991Sheppo 	va_list ap;
1841991Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
1854647Sraghuram 	char    *bufp = buf;
1861991Sheppo 
1874647Sraghuram 	if (vnetp == NULL) {
1884647Sraghuram 		(void) sprintf(bufp, "%s: ", fname);
1894647Sraghuram 		bufp += strlen(bufp);
1904647Sraghuram 	} else {
1914647Sraghuram 		(void) sprintf(bufp, "vnet%d:%s: ", vnetp->instance, fname);
1924647Sraghuram 		bufp += strlen(bufp);
1934647Sraghuram 	}
1944647Sraghuram 	va_start(ap, fmt);
1954647Sraghuram 	(void) vsprintf(bufp, fmt, ap);
1964647Sraghuram 	va_end(ap);
1974647Sraghuram 	cmn_err(CE_CONT, "%s\n", buf);
1984647Sraghuram }
1991991Sheppo 
2001991Sheppo #endif
2011991Sheppo 
2021991Sheppo /* _init(9E): initialize the loadable module */
2031991Sheppo int
2041991Sheppo _init(void)
2051991Sheppo {
2061991Sheppo 	int status;
2071991Sheppo 
2084647Sraghuram 	DBG1(NULL, "enter\n");
2091991Sheppo 
2101991Sheppo 	mac_init_ops(&vnetops, "vnet");
2111991Sheppo 	status = mod_install(&modlinkage);
2121991Sheppo 	if (status != 0) {
2131991Sheppo 		mac_fini_ops(&vnetops);
2141991Sheppo 	}
2151991Sheppo 
2164647Sraghuram 	DBG1(NULL, "exit(%d)\n", status);
2171991Sheppo 	return (status);
2181991Sheppo }
2191991Sheppo 
2201991Sheppo /* _fini(9E): prepare the module for unloading. */
2211991Sheppo int
2221991Sheppo _fini(void)
2231991Sheppo {
2241991Sheppo 	int status;
2251991Sheppo 
2264647Sraghuram 	DBG1(NULL, "enter\n");
2271991Sheppo 
2281991Sheppo 	status = mod_remove(&modlinkage);
2291991Sheppo 	if (status != 0)
2301991Sheppo 		return (status);
2311991Sheppo 	mac_fini_ops(&vnetops);
2321991Sheppo 
2334647Sraghuram 	DBG1(NULL, "exit(%d)\n", status);
2341991Sheppo 	return (status);
2351991Sheppo }
2361991Sheppo 
2371991Sheppo /* _info(9E): return information about the loadable module */
2381991Sheppo int
2391991Sheppo _info(struct modinfo *modinfop)
2401991Sheppo {
2411991Sheppo 	return (mod_info(&modlinkage, modinfop));
2421991Sheppo }
2431991Sheppo 
2441991Sheppo /*
2451991Sheppo  * attach(9E): attach a device to the system.
2461991Sheppo  * called once for each instance of the device on the system.
2471991Sheppo  */
2481991Sheppo static int
2491991Sheppo vnetattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2501991Sheppo {
2511991Sheppo 	vnet_t		*vnetp;
2521991Sheppo 	vp_tl_t		*vp_tlp;
2531991Sheppo 	int		instance;
2541991Sheppo 	int		status;
2552311Sseb 	mac_register_t	*vgenmacp = NULL;
2564647Sraghuram 	enum	{ AST_init = 0x0, AST_vnet_alloc = 0x1,
2574647Sraghuram 		AST_mac_alloc = 0x2, AST_read_macaddr = 0x4,
2584647Sraghuram 		AST_vgen_init = 0x8, AST_vptl_alloc = 0x10,
2594647Sraghuram 		AST_fdbh_alloc = 0x20 } attach_state;
2601991Sheppo 
2611991Sheppo 	attach_state = AST_init;
2621991Sheppo 
2631991Sheppo 	switch (cmd) {
2641991Sheppo 	case DDI_ATTACH:
2651991Sheppo 		break;
2661991Sheppo 	case DDI_RESUME:
2671991Sheppo 	case DDI_PM_RESUME:
2681991Sheppo 	default:
2691991Sheppo 		goto vnet_attach_fail;
2701991Sheppo 	}
2711991Sheppo 
2721991Sheppo 	instance = ddi_get_instance(dip);
2734647Sraghuram 	DBG1(NULL, "instance(%d) enter\n", instance);
2741991Sheppo 
2751991Sheppo 	/* allocate vnet_t and mac_t structures */
2761991Sheppo 	vnetp = kmem_zalloc(sizeof (vnet_t), KM_SLEEP);
2771991Sheppo 	attach_state |= AST_vnet_alloc;
2781991Sheppo 
2791991Sheppo 	/* setup links to vnet_t from both devinfo and mac_t */
2801991Sheppo 	ddi_set_driver_private(dip, (caddr_t)vnetp);
2811991Sheppo 	vnetp->dip = dip;
2821991Sheppo 	vnetp->instance = instance;
2831991Sheppo 
2841991Sheppo 	/* read the mac address */
2851991Sheppo 	status = vnet_read_mac_address(vnetp);
2861991Sheppo 	if (status != DDI_SUCCESS) {
2871991Sheppo 		goto vnet_attach_fail;
2881991Sheppo 	}
2891991Sheppo 	attach_state |= AST_read_macaddr;
2901991Sheppo 
2911991Sheppo 	/*
2921991Sheppo 	 * Initialize the generic vnet proxy transport. This is the first
2931991Sheppo 	 * and default transport used by vnet. The generic transport
2941991Sheppo 	 * is provided by using sun4v LDC (logical domain channel). On success,
2951991Sheppo 	 * vgen_init() provides a pointer to mac_t of generic transport.
2961991Sheppo 	 * Currently, this generic layer provides network connectivity to other
2971991Sheppo 	 * vnets within ldoms and also to remote hosts oustide ldoms through
2981991Sheppo 	 * the virtual switch (vsw) device on domain0. In the future, when
2991991Sheppo 	 * physical adapters that are able to share their resources (such as
3001991Sheppo 	 * dma channels) with guest domains become available, the vnet device
3011991Sheppo 	 * will use hardware specific driver to communicate directly over the
3021991Sheppo 	 * physical device to reach remote hosts without going through vswitch.
3031991Sheppo 	 */
3042311Sseb 	status = vgen_init(vnetp, vnetp->dip, (uint8_t *)vnetp->curr_macaddr,
3052311Sseb 	    &vgenmacp);
3061991Sheppo 	if (status != DDI_SUCCESS) {
3074647Sraghuram 		DERR(vnetp, "vgen_init() failed\n");
3081991Sheppo 		goto vnet_attach_fail;
3091991Sheppo 	}
310*5641Swentaoy 	rw_init(&vnetp->trwlock, NULL, RW_DRIVER, NULL);
3111991Sheppo 	attach_state |= AST_vgen_init;
3121991Sheppo 
3131991Sheppo 	vp_tlp = kmem_zalloc(sizeof (vp_tl_t), KM_SLEEP);
3141991Sheppo 	vp_tlp->macp = vgenmacp;
3151991Sheppo 	(void) snprintf(vp_tlp->name, MAXNAMELEN, "%s%u", "vgen", instance);
3161991Sheppo 	(void) strcpy(vnetp->vgen_name, vp_tlp->name);
3171991Sheppo 
3181991Sheppo 	/* add generic transport to the list of vnet proxy transports */
3191991Sheppo 	vnet_add_vptl(vnetp, vp_tlp);
3201991Sheppo 	attach_state |= AST_vptl_alloc;
3211991Sheppo 
322*5641Swentaoy 	vnet_fdb_alloc(vnetp);
3231991Sheppo 	attach_state |= AST_fdbh_alloc;
3241991Sheppo 
3251991Sheppo 	/* register with MAC layer */
3261991Sheppo 	status = vnet_mac_register(vnetp);
3271991Sheppo 	if (status != DDI_SUCCESS) {
3281991Sheppo 		goto vnet_attach_fail;
3291991Sheppo 	}
3301991Sheppo 
3311991Sheppo 	/* add to the list of vnet devices */
3321991Sheppo 	WRITE_ENTER(&vnet_rw);
3331991Sheppo 	vnetp->nextp = vnet_headp;
3341991Sheppo 	vnet_headp = vnetp;
3351991Sheppo 	RW_EXIT(&vnet_rw);
3361991Sheppo 
3374647Sraghuram 	DBG1(NULL, "instance(%d) exit\n", instance);
3381991Sheppo 	return (DDI_SUCCESS);
3391991Sheppo 
3401991Sheppo vnet_attach_fail:
3411991Sheppo 	if (attach_state & AST_fdbh_alloc) {
342*5641Swentaoy 		vnet_fdb_free(vnetp);
3431991Sheppo 	}
3441991Sheppo 	if (attach_state & AST_vptl_alloc) {
3451991Sheppo 		WRITE_ENTER(&vnetp->trwlock);
3461991Sheppo 		vnet_del_vptl(vnetp, vp_tlp);
3471991Sheppo 		RW_EXIT(&vnetp->trwlock);
3481991Sheppo 	}
3491991Sheppo 	if (attach_state & AST_vgen_init) {
3502336Snarayan 		(void) vgen_uninit(vgenmacp->m_driver);
351*5641Swentaoy 		rw_destroy(&vnetp->trwlock);
3521991Sheppo 	}
3531991Sheppo 	if (attach_state & AST_vnet_alloc) {
3541991Sheppo 		KMEM_FREE(vnetp);
3551991Sheppo 	}
3561991Sheppo 	return (DDI_FAILURE);
3571991Sheppo }
3581991Sheppo 
3591991Sheppo /*
3601991Sheppo  * detach(9E): detach a device from the system.
3611991Sheppo  */
3621991Sheppo static int
3631991Sheppo vnetdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
3641991Sheppo {
3651991Sheppo 	vnet_t		*vnetp;
3661991Sheppo 	vnet_t		**vnetpp;
3671991Sheppo 	vp_tl_t		*vp_tlp;
3681991Sheppo 	int		instance;
3692336Snarayan 	int		rv;
3701991Sheppo 
3711991Sheppo 	instance = ddi_get_instance(dip);
3724647Sraghuram 	DBG1(NULL, "instance(%d) enter\n", instance);
3731991Sheppo 
3741991Sheppo 	vnetp = ddi_get_driver_private(dip);
3751991Sheppo 	if (vnetp == NULL) {
3761991Sheppo 		goto vnet_detach_fail;
3771991Sheppo 	}
3781991Sheppo 
3791991Sheppo 	switch (cmd) {
3801991Sheppo 	case DDI_DETACH:
3811991Sheppo 		break;
3821991Sheppo 	case DDI_SUSPEND:
3831991Sheppo 	case DDI_PM_SUSPEND:
3841991Sheppo 	default:
3851991Sheppo 		goto vnet_detach_fail;
3861991Sheppo 	}
3871991Sheppo 
3882336Snarayan 	/* uninit and free vnet proxy transports */
3892336Snarayan 	WRITE_ENTER(&vnetp->trwlock);
3902336Snarayan 	while ((vp_tlp = vnetp->tlp) != NULL) {
3912336Snarayan 		if (strcmp(vnetp->vgen_name, vp_tlp->name) == 0) {
3922336Snarayan 			/* uninitialize generic transport */
3932336Snarayan 			rv = vgen_uninit(vp_tlp->macp->m_driver);
3942336Snarayan 			if (rv != DDI_SUCCESS) {
3952336Snarayan 				RW_EXIT(&vnetp->trwlock);
3962336Snarayan 				goto vnet_detach_fail;
3972336Snarayan 			}
3982336Snarayan 		}
3992336Snarayan 		vnet_del_vptl(vnetp, vp_tlp);
4002336Snarayan 	}
4012336Snarayan 	RW_EXIT(&vnetp->trwlock);
4022336Snarayan 
4031991Sheppo 	/*
4041991Sheppo 	 * Unregister from the MAC subsystem.  This can fail, in
4051991Sheppo 	 * particular if there are DLPI style-2 streams still open -
4061991Sheppo 	 * in which case we just return failure.
4071991Sheppo 	 */
4082311Sseb 	if (mac_unregister(vnetp->mh) != 0)
4091991Sheppo 		goto vnet_detach_fail;
4101991Sheppo 
4111991Sheppo 	/* unlink from instance(vnet_t) list */
4121991Sheppo 	WRITE_ENTER(&vnet_rw);
4131991Sheppo 	for (vnetpp = &vnet_headp; *vnetpp; vnetpp = &(*vnetpp)->nextp) {
4141991Sheppo 		if (*vnetpp == vnetp) {
4151991Sheppo 			*vnetpp = vnetp->nextp;
4161991Sheppo 			break;
4171991Sheppo 		}
4181991Sheppo 	}
4191991Sheppo 	RW_EXIT(&vnet_rw);
4201991Sheppo 
421*5641Swentaoy 	vnet_fdb_free(vnetp);
4223297Ssb155480 
423*5641Swentaoy 	rw_destroy(&vnetp->trwlock);
4241991Sheppo 	KMEM_FREE(vnetp);
4251991Sheppo 
4261991Sheppo 	return (DDI_SUCCESS);
4271991Sheppo 
4281991Sheppo vnet_detach_fail:
4291991Sheppo 	return (DDI_FAILURE);
4301991Sheppo }
4311991Sheppo 
4321991Sheppo /* enable the device for transmit/receive */
4331991Sheppo static int
4341991Sheppo vnet_m_start(void *arg)
4351991Sheppo {
4361991Sheppo 	vnet_t		*vnetp = arg;
4371991Sheppo 	vp_tl_t		*vp_tlp;
4382311Sseb 	mac_register_t	*vp_macp;
4392311Sseb 	mac_callbacks_t	*cbp;
4401991Sheppo 
4414647Sraghuram 	DBG1(vnetp, "enter\n");
4421991Sheppo 
4431991Sheppo 	/*
4442793Slm66018 	 * NOTE:
4451991Sheppo 	 * Currently, we only have generic transport. m_start() invokes
4461991Sheppo 	 * vgen_start() which enables ports/channels in vgen and
4471991Sheppo 	 * initiates handshake with peer vnets and vsw. In the future when we
4481991Sheppo 	 * have support for hardware specific transports, this information
4491991Sheppo 	 * needs to be propagted back to vnet from vgen and we need to revisit
4501991Sheppo 	 * this code (see comments in vnet_attach()).
4511991Sheppo 	 *
4521991Sheppo 	 */
4531991Sheppo 	WRITE_ENTER(&vnetp->trwlock);
4541991Sheppo 	for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) {
4551991Sheppo 		vp_macp = vp_tlp->macp;
4562311Sseb 		cbp = vp_macp->m_callbacks;
4572311Sseb 		cbp->mc_start(vp_macp->m_driver);
4581991Sheppo 	}
4591991Sheppo 	RW_EXIT(&vnetp->trwlock);
4601991Sheppo 
4614647Sraghuram 	DBG1(vnetp, "exit\n");
4621991Sheppo 	return (VNET_SUCCESS);
4631991Sheppo 
4641991Sheppo }
4651991Sheppo 
4661991Sheppo /* stop transmit/receive for the device */
4671991Sheppo static void
4681991Sheppo vnet_m_stop(void *arg)
4691991Sheppo {
4701991Sheppo 	vnet_t		*vnetp = arg;
4711991Sheppo 	vp_tl_t		*vp_tlp;
4722311Sseb 	mac_register_t	*vp_macp;
4732311Sseb 	mac_callbacks_t	*cbp;
4741991Sheppo 
4754647Sraghuram 	DBG1(vnetp, "enter\n");
4761991Sheppo 
4771991Sheppo 	WRITE_ENTER(&vnetp->trwlock);
4781991Sheppo 	for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) {
4791991Sheppo 		vp_macp = vp_tlp->macp;
4802311Sseb 		cbp = vp_macp->m_callbacks;
4812311Sseb 		cbp->mc_stop(vp_macp->m_driver);
4821991Sheppo 	}
4831991Sheppo 	RW_EXIT(&vnetp->trwlock);
4841991Sheppo 
4854647Sraghuram 	DBG1(vnetp, "exit\n");
4861991Sheppo }
4871991Sheppo 
4881991Sheppo /* set the unicast mac address of the device */
4891991Sheppo static int
4901991Sheppo vnet_m_unicst(void *arg, const uint8_t *macaddr)
4911991Sheppo {
4921991Sheppo 	_NOTE(ARGUNUSED(macaddr))
4931991Sheppo 
4941991Sheppo 	vnet_t *vnetp = arg;
4951991Sheppo 
4964647Sraghuram 	DBG1(vnetp, "enter\n");
4971991Sheppo 	/*
4982793Slm66018 	 * NOTE: setting mac address dynamically is not supported.
4991991Sheppo 	 */
5004647Sraghuram 	DBG1(vnetp, "exit\n");
5011991Sheppo 
5022109Slm66018 	return (VNET_FAILURE);
5031991Sheppo }
5041991Sheppo 
5051991Sheppo /* enable/disable a multicast address */
5061991Sheppo static int
5071991Sheppo vnet_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
5081991Sheppo {
5091991Sheppo 	_NOTE(ARGUNUSED(add, mca))
5101991Sheppo 
5111991Sheppo 	vnet_t *vnetp = arg;
5121991Sheppo 	vp_tl_t		*vp_tlp;
5132311Sseb 	mac_register_t	*vp_macp;
5142311Sseb 	mac_callbacks_t	*cbp;
5151991Sheppo 	int rv = VNET_SUCCESS;
5161991Sheppo 
5174647Sraghuram 	DBG1(vnetp, "enter\n");
5181991Sheppo 	READ_ENTER(&vnetp->trwlock);
5191991Sheppo 	for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) {
5201991Sheppo 		if (strcmp(vnetp->vgen_name, vp_tlp->name) == 0) {
5211991Sheppo 			vp_macp = vp_tlp->macp;
5222311Sseb 			cbp = vp_macp->m_callbacks;
5232311Sseb 			rv = cbp->mc_multicst(vp_macp->m_driver, add, mca);
5241991Sheppo 			break;
5251991Sheppo 		}
5261991Sheppo 	}
5271991Sheppo 	RW_EXIT(&vnetp->trwlock);
5284647Sraghuram 	DBG1(vnetp, "exit(%d)\n", rv);
5291991Sheppo 	return (rv);
5301991Sheppo }
5311991Sheppo 
5321991Sheppo /* set or clear promiscuous mode on the device */
5331991Sheppo static int
5341991Sheppo vnet_m_promisc(void *arg, boolean_t on)
5351991Sheppo {
5361991Sheppo 	_NOTE(ARGUNUSED(on))
5371991Sheppo 
5381991Sheppo 	vnet_t *vnetp = arg;
5394647Sraghuram 	DBG1(vnetp, "enter\n");
5401991Sheppo 	/*
5412793Slm66018 	 * NOTE: setting promiscuous mode is not supported, just return success.
5421991Sheppo 	 */
5434647Sraghuram 	DBG1(vnetp, "exit\n");
5441991Sheppo 	return (VNET_SUCCESS);
5451991Sheppo }
5461991Sheppo 
5471991Sheppo /*
5481991Sheppo  * Transmit a chain of packets. This function provides switching functionality
5491991Sheppo  * based on the destination mac address to reach other guests (within ldoms) or
5501991Sheppo  * external hosts.
5511991Sheppo  */
5521991Sheppo mblk_t *
5531991Sheppo vnet_m_tx(void *arg, mblk_t *mp)
5541991Sheppo {
5551991Sheppo 	vnet_t *vnetp;
5561991Sheppo 	mblk_t *next;
5571991Sheppo 	uint32_t fdbhash;
5581991Sheppo 	fdb_t *fdbp;
5591991Sheppo 	fdb_fanout_t *fdbhp;
5601991Sheppo 	struct ether_header *ehp;
5611991Sheppo 	uint8_t *macaddr;
5621991Sheppo 	mblk_t *resid_mp;
5631991Sheppo 
5641991Sheppo 	vnetp = (vnet_t *)arg;
5654647Sraghuram 	DBG1(vnetp, "enter\n");
5661991Sheppo 	ASSERT(mp != NULL);
5671991Sheppo 
5681991Sheppo 	while (mp != NULL) {
5691991Sheppo 		next = mp->b_next;
5701991Sheppo 		mp->b_next = NULL;
5711991Sheppo 
5721991Sheppo 		/* get the destination mac address in the eth header */
5731991Sheppo 		ehp = (struct ether_header *)mp->b_rptr;
5741991Sheppo 		macaddr = (uint8_t *)&ehp->ether_dhost;
5751991Sheppo 
5761991Sheppo 		/* Calculate hash value and fdb fanout */
5771991Sheppo 		fdbhash = MACHASH(macaddr, vnetp->nfdb_hash);
5781991Sheppo 		fdbhp = &(vnetp->fdbhp[fdbhash]);
5791991Sheppo 
5801991Sheppo 		READ_ENTER(&fdbhp->rwlock);
5811991Sheppo 		fdbp = vnet_lookup_fdb(fdbhp, macaddr);
5821991Sheppo 		if (fdbp) {
5831991Sheppo 			/*
5841991Sheppo 			 * If the destination is in FDB, the destination is
5851991Sheppo 			 * a vnet device within ldoms and directly reachable,
5861991Sheppo 			 * invoke the tx function in the fdb entry.
5871991Sheppo 			 */
5881991Sheppo 			resid_mp = fdbp->m_tx(fdbp->txarg, mp);
5891991Sheppo 			if (resid_mp != NULL) {
5901991Sheppo 				/* m_tx failed */
5911991Sheppo 				mp->b_next = next;
5921991Sheppo 				RW_EXIT(&fdbhp->rwlock);
5931991Sheppo 				break;
5941991Sheppo 			}
5951991Sheppo 			RW_EXIT(&fdbhp->rwlock);
5961991Sheppo 		} else {
5971991Sheppo 			/* destination is not in FDB */
5981991Sheppo 			RW_EXIT(&fdbhp->rwlock);
5991991Sheppo 			/*
6001991Sheppo 			 * If the destination is broadcast/multicast
6011991Sheppo 			 * or an unknown unicast address, forward the
6021991Sheppo 			 * packet to vsw, using the last slot in fdb which is
6031991Sheppo 			 * reserved for default route.
6041991Sheppo 			 */
6051991Sheppo 			fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]);
6061991Sheppo 			READ_ENTER(&fdbhp->rwlock);
6071991Sheppo 			fdbp = fdbhp->headp;
6081991Sheppo 			if (fdbp) {
6091991Sheppo 				resid_mp = fdbp->m_tx(fdbp->txarg, mp);
6101991Sheppo 				if (resid_mp != NULL) {
6111991Sheppo 					/* m_tx failed */
6121991Sheppo 					mp->b_next = next;
6131991Sheppo 					RW_EXIT(&fdbhp->rwlock);
6141991Sheppo 					break;
6151991Sheppo 				}
6161991Sheppo 			} else {
6171991Sheppo 				/* drop the packet */
6181991Sheppo 				freemsg(mp);
6191991Sheppo 			}
6201991Sheppo 			RW_EXIT(&fdbhp->rwlock);
6211991Sheppo 		}
6221991Sheppo 
6231991Sheppo 		mp = next;
6241991Sheppo 	}
6251991Sheppo 
6264647Sraghuram 	DBG1(vnetp, "exit\n");
6271991Sheppo 	return (mp);
6281991Sheppo }
6291991Sheppo 
6302311Sseb /* get statistics from the device */
6312311Sseb int
6322311Sseb vnet_m_stat(void *arg, uint_t stat, uint64_t *val)
6331991Sheppo {
6341991Sheppo 	vnet_t *vnetp = arg;
6351991Sheppo 	vp_tl_t	*vp_tlp;
6362311Sseb 	mac_register_t	*vp_macp;
6372311Sseb 	mac_callbacks_t	*cbp;
6382311Sseb 	uint64_t val_total = 0;
6391991Sheppo 
6404647Sraghuram 	DBG1(vnetp, "enter\n");
6411991Sheppo 
6421991Sheppo 	/*
6432311Sseb 	 * get the specified statistic from each transport and return the
6442311Sseb 	 * aggregate val.  This obviously only works for counters.
6451991Sheppo 	 */
6462311Sseb 	if ((IS_MAC_STAT(stat) && !MAC_STAT_ISACOUNTER(stat)) ||
6472311Sseb 	    (IS_MACTYPE_STAT(stat) && !ETHER_STAT_ISACOUNTER(stat))) {
6482311Sseb 		return (ENOTSUP);
6492311Sseb 	}
6501991Sheppo 	READ_ENTER(&vnetp->trwlock);
6511991Sheppo 	for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) {
6521991Sheppo 		vp_macp = vp_tlp->macp;
6532311Sseb 		cbp = vp_macp->m_callbacks;
6542311Sseb 		if (cbp->mc_getstat(vp_macp->m_driver, stat, val) == 0)
6552311Sseb 			val_total += *val;
6561991Sheppo 	}
6571991Sheppo 	RW_EXIT(&vnetp->trwlock);
6581991Sheppo 
6592311Sseb 	*val = val_total;
6602311Sseb 
6614647Sraghuram 	DBG1(vnetp, "exit\n");
6622311Sseb 	return (0);
6631991Sheppo }
6641991Sheppo 
6651991Sheppo /* wrapper function for mac_register() */
6661991Sheppo static int
6671991Sheppo vnet_mac_register(vnet_t *vnetp)
6681991Sheppo {
6692311Sseb 	mac_register_t	*macp;
6702311Sseb 	int		err;
6711991Sheppo 
6722311Sseb 	if ((macp = mac_alloc(MAC_VERSION)) == NULL)
6732311Sseb 		return (DDI_FAILURE);
6742311Sseb 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
6752311Sseb 	macp->m_driver = vnetp;
6761991Sheppo 	macp->m_dip = vnetp->dip;
6772311Sseb 	macp->m_src_addr = vnetp->curr_macaddr;
6782311Sseb 	macp->m_callbacks = &vnet_m_callbacks;
6792311Sseb 	macp->m_min_sdu = 0;
6802311Sseb 	macp->m_max_sdu = ETHERMTU;
6811991Sheppo 
6821991Sheppo 	/*
6831991Sheppo 	 * Finally, we're ready to register ourselves with the MAC layer
6841991Sheppo 	 * interface; if this succeeds, we're all ready to start()
6851991Sheppo 	 */
6862311Sseb 	err = mac_register(macp, &vnetp->mh);
6872311Sseb 	mac_free(macp);
6882311Sseb 	return (err == 0 ? DDI_SUCCESS : DDI_FAILURE);
6891991Sheppo }
6901991Sheppo 
6911991Sheppo /* add vp_tl to the list */
6921991Sheppo static void
6931991Sheppo vnet_add_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp)
6941991Sheppo {
6951991Sheppo 	vp_tl_t *ttlp;
6961991Sheppo 
6971991Sheppo 	WRITE_ENTER(&vnetp->trwlock);
6981991Sheppo 	if (vnetp->tlp == NULL) {
6991991Sheppo 		vnetp->tlp = vp_tlp;
7001991Sheppo 	} else {
7011991Sheppo 		ttlp = vnetp->tlp;
7021991Sheppo 		while (ttlp->nextp)
7031991Sheppo 			ttlp = ttlp->nextp;
7041991Sheppo 		ttlp->nextp = vp_tlp;
7051991Sheppo 	}
7061991Sheppo 	RW_EXIT(&vnetp->trwlock);
7071991Sheppo }
7081991Sheppo 
7091991Sheppo /* remove vp_tl from the list */
7101991Sheppo static void
7111991Sheppo vnet_del_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp)
7121991Sheppo {
7131991Sheppo 	vp_tl_t *ttlp, **pretlp;
7141991Sheppo 	boolean_t found = B_FALSE;
7151991Sheppo 
7161991Sheppo 	pretlp = &vnetp->tlp;
7171991Sheppo 	ttlp = *pretlp;
7181991Sheppo 	while (ttlp) {
7191991Sheppo 		if (ttlp == vp_tlp) {
7201991Sheppo 			found = B_TRUE;
7211991Sheppo 			(*pretlp) = ttlp->nextp;
7221991Sheppo 			ttlp->nextp = NULL;
7231991Sheppo 			break;
7241991Sheppo 		}
7251991Sheppo 		pretlp = &(ttlp->nextp);
7261991Sheppo 		ttlp = *pretlp;
7271991Sheppo 	}
7281991Sheppo 
7291991Sheppo 	if (found) {
7301991Sheppo 		KMEM_FREE(vp_tlp);
7311991Sheppo 	}
7321991Sheppo }
7331991Sheppo 
7341991Sheppo /* get vp_tl corresponding to the given name */
7351991Sheppo static vp_tl_t *
7361991Sheppo vnet_get_vptl(vnet_t *vnetp, const char *name)
7371991Sheppo {
7381991Sheppo 	vp_tl_t *tlp;
7391991Sheppo 
7401991Sheppo 	tlp = vnetp->tlp;
7411991Sheppo 	while (tlp) {
7421991Sheppo 		if (strcmp(tlp->name, name) == 0) {
7431991Sheppo 			return (tlp);
7441991Sheppo 		}
7451991Sheppo 		tlp = tlp->nextp;
7461991Sheppo 	}
7474647Sraghuram 	DWARN(vnetp, "can't find vp_tl with name (%s)\n", name);
7481991Sheppo 	return (NULL);
7491991Sheppo }
7501991Sheppo 
7511991Sheppo /* read the mac address of the device */
7521991Sheppo static int
7531991Sheppo vnet_read_mac_address(vnet_t *vnetp)
7541991Sheppo {
7551991Sheppo 	uchar_t 	*macaddr;
7561991Sheppo 	uint32_t 	size;
7571991Sheppo 	int 		rv;
7581991Sheppo 
7591991Sheppo 	rv = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, vnetp->dip,
7604650Sraghuram 	    DDI_PROP_DONTPASS, macaddr_propname, &macaddr, &size);
7611991Sheppo 	if ((rv != DDI_PROP_SUCCESS) || (size != ETHERADDRL)) {
7624647Sraghuram 		DWARN(vnetp, "prop_lookup failed(%s) err(%d)\n",
7634647Sraghuram 		    macaddr_propname, rv);
7641991Sheppo 		return (DDI_FAILURE);
7651991Sheppo 	}
7661991Sheppo 	bcopy(macaddr, (caddr_t)vnetp->vendor_addr, ETHERADDRL);
7671991Sheppo 	bcopy(macaddr, (caddr_t)vnetp->curr_macaddr, ETHERADDRL);
7681991Sheppo 	ddi_prop_free(macaddr);
7691991Sheppo 
7701991Sheppo 	return (DDI_SUCCESS);
7711991Sheppo }
7721991Sheppo 
7731991Sheppo 
7741991Sheppo /*
7751991Sheppo  * Functions below are called only by generic transport to add/remove/modify
7761991Sheppo  * entries in forwarding database. See comments in vgen_port_init(vnet_gen.c).
7771991Sheppo  */
7781991Sheppo 
7791991Sheppo /* add an entry into the forwarding database */
7801991Sheppo void
7811991Sheppo vnet_add_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg)
7821991Sheppo {
7831991Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
7841991Sheppo 	uint32_t fdbhash;
7851991Sheppo 	fdb_t *fdbp;
7861991Sheppo 	fdb_fanout_t *fdbhp;
7871991Sheppo 
7881991Sheppo 	/* Calculate hash value and fdb fanout */
7891991Sheppo 	fdbhash = MACHASH(macaddr, vnetp->nfdb_hash);
7901991Sheppo 	fdbhp = &(vnetp->fdbhp[fdbhash]);
7911991Sheppo 
7921991Sheppo 	WRITE_ENTER(&fdbhp->rwlock);
7931991Sheppo 
7941991Sheppo 	fdbp = kmem_zalloc(sizeof (fdb_t), KM_NOSLEEP);
7951991Sheppo 	if (fdbp == NULL) {
7961991Sheppo 		RW_EXIT(&fdbhp->rwlock);
7971991Sheppo 		return;
7981991Sheppo 	}
7991991Sheppo 	bcopy(macaddr, (caddr_t)fdbp->macaddr, ETHERADDRL);
8001991Sheppo 	fdbp->m_tx = m_tx;
8011991Sheppo 	fdbp->txarg = txarg;
8021991Sheppo 	fdbp->nextp = fdbhp->headp;
8031991Sheppo 	fdbhp->headp = fdbp;
8041991Sheppo 
8051991Sheppo 	RW_EXIT(&fdbhp->rwlock);
8061991Sheppo }
8071991Sheppo 
8081991Sheppo /* delete an entry from the forwarding database */
8091991Sheppo void
8101991Sheppo vnet_del_fdb(void *arg, uint8_t *macaddr)
8111991Sheppo {
8121991Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
8131991Sheppo 	uint32_t fdbhash;
8141991Sheppo 	fdb_t *fdbp;
8151991Sheppo 	fdb_t **pfdbp;
8161991Sheppo 	fdb_fanout_t *fdbhp;
8171991Sheppo 
8181991Sheppo 	/* Calculate hash value and fdb fanout */
8191991Sheppo 	fdbhash = MACHASH(macaddr, vnetp->nfdb_hash);
8201991Sheppo 	fdbhp = &(vnetp->fdbhp[fdbhash]);
8211991Sheppo 
8221991Sheppo 	WRITE_ENTER(&fdbhp->rwlock);
8231991Sheppo 
8241991Sheppo 	for (pfdbp = &fdbhp->headp; (fdbp  = *pfdbp) != NULL;
8251991Sheppo 	    pfdbp = &fdbp->nextp) {
8261991Sheppo 		if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) {
8271991Sheppo 			/* Unlink it from the list */
8281991Sheppo 			*pfdbp = fdbp->nextp;
8291991Sheppo 			KMEM_FREE(fdbp);
8301991Sheppo 			break;
8311991Sheppo 		}
8321991Sheppo 	}
8331991Sheppo 
8341991Sheppo 	RW_EXIT(&fdbhp->rwlock);
8351991Sheppo }
8361991Sheppo 
8371991Sheppo /* modify an existing entry in the forwarding database */
8381991Sheppo void
8392793Slm66018 vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg,
8402793Slm66018 	boolean_t upgrade)
8411991Sheppo {
8421991Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
8431991Sheppo 	uint32_t fdbhash;
8441991Sheppo 	fdb_t *fdbp;
8451991Sheppo 	fdb_fanout_t *fdbhp;
8461991Sheppo 
8471991Sheppo 	/* Calculate hash value and fdb fanout */
8481991Sheppo 	fdbhash = MACHASH(macaddr, vnetp->nfdb_hash);
8491991Sheppo 	fdbhp = &(vnetp->fdbhp[fdbhash]);
8501991Sheppo 
8512793Slm66018 	if (upgrade == B_TRUE) {
8522793Slm66018 		/*
8532793Slm66018 		 * Caller already holds the lock as a reader. This can
8542793Slm66018 		 * occur if this function is invoked in the context
8552793Slm66018 		 * of transmit routine - vnet_m_tx(), where the lock
8562793Slm66018 		 * is held as a reader before calling the transmit
8572793Slm66018 		 * function of an fdb entry (fdbp->m_tx).
8582793Slm66018 		 * See comments in vgen_ldcsend() in vnet_gen.c
8592793Slm66018 		 */
8602793Slm66018 		if (!rw_tryupgrade(&fdbhp->rwlock)) {
8612793Slm66018 			RW_EXIT(&fdbhp->rwlock);
8622793Slm66018 			WRITE_ENTER(&fdbhp->rwlock);
8632793Slm66018 		}
8642793Slm66018 	} else {
8652793Slm66018 		/* Caller does not hold the lock */
8662793Slm66018 		WRITE_ENTER(&fdbhp->rwlock);
8672793Slm66018 	}
8681991Sheppo 
8691991Sheppo 	for (fdbp = fdbhp->headp; fdbp != NULL; fdbp = fdbp->nextp) {
8701991Sheppo 		if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) {
8711991Sheppo 			/* change the entry to have new tx params */
8721991Sheppo 			fdbp->m_tx = m_tx;
8731991Sheppo 			fdbp->txarg = txarg;
8741991Sheppo 			break;
8751991Sheppo 		}
8761991Sheppo 	}
8771991Sheppo 
8782793Slm66018 	if (upgrade == B_TRUE) {
8792793Slm66018 		/* restore the caller as a reader */
8802793Slm66018 		rw_downgrade(&fdbhp->rwlock);
8812793Slm66018 	} else {
8822793Slm66018 		RW_EXIT(&fdbhp->rwlock);
8832793Slm66018 	}
8841991Sheppo }
8851991Sheppo 
886*5641Swentaoy /* allocate the forwarding database */
887*5641Swentaoy static void
888*5641Swentaoy vnet_fdb_alloc(vnet_t *vnetp)
889*5641Swentaoy {
890*5641Swentaoy 	int		i;
891*5641Swentaoy 	uint32_t	nfdbh = 0;
892*5641Swentaoy 
893*5641Swentaoy 	nfdbh = vnet_nfdb_hash;
894*5641Swentaoy 	if ((nfdbh < VNET_NFDB_HASH) || (nfdbh > VNET_NFDB_HASH_MAX)) {
895*5641Swentaoy 		vnetp->nfdb_hash = VNET_NFDB_HASH;
896*5641Swentaoy 	} else {
897*5641Swentaoy 		vnetp->nfdb_hash = nfdbh;
898*5641Swentaoy 	}
899*5641Swentaoy 
900*5641Swentaoy 	/* allocate fdb hash table, with an extra slot for default route */
901*5641Swentaoy 	vnetp->fdbhp = kmem_zalloc(sizeof (fdb_fanout_t) *
902*5641Swentaoy 	    (vnetp->nfdb_hash + 1), KM_SLEEP);
903*5641Swentaoy 
904*5641Swentaoy 	for (i = 0; i <= vnetp->nfdb_hash; i++) {
905*5641Swentaoy 		rw_init(&vnetp->fdbhp[i].rwlock, NULL, RW_DRIVER, NULL);
906*5641Swentaoy 	}
907*5641Swentaoy }
908*5641Swentaoy 
909*5641Swentaoy /* free the forwarding database */
910*5641Swentaoy static void
911*5641Swentaoy vnet_fdb_free(vnet_t *vnetp)
912*5641Swentaoy {
913*5641Swentaoy 	int i;
914*5641Swentaoy 
915*5641Swentaoy 	for (i = 0; i <= vnetp->nfdb_hash; i++) {
916*5641Swentaoy 		rw_destroy(&vnetp->fdbhp[i].rwlock);
917*5641Swentaoy 	}
918*5641Swentaoy 
919*5641Swentaoy 	/*
920*5641Swentaoy 	 * deallocate fdb hash table, including an extra slot for default
921*5641Swentaoy 	 * route.
922*5641Swentaoy 	 */
923*5641Swentaoy 	kmem_free(vnetp->fdbhp, sizeof (fdb_fanout_t) * (vnetp->nfdb_hash + 1));
924*5641Swentaoy 	vnetp->fdbhp = NULL;
925*5641Swentaoy }
926*5641Swentaoy 
9271991Sheppo /* look up an fdb entry based on the mac address, caller holds lock */
9281991Sheppo static fdb_t *
9291991Sheppo vnet_lookup_fdb(fdb_fanout_t *fdbhp, uint8_t *macaddr)
9301991Sheppo {
9311991Sheppo 	fdb_t *fdbp = NULL;
9321991Sheppo 
9331991Sheppo 	for (fdbp = fdbhp->headp; fdbp != NULL; fdbp = fdbp->nextp) {
9341991Sheppo 		if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) {
9351991Sheppo 			break;
9361991Sheppo 		}
9371991Sheppo 	}
9381991Sheppo 
9391991Sheppo 	return (fdbp);
9401991Sheppo }
9411991Sheppo 
9421991Sheppo /* add default route entry into the forwarding database */
9431991Sheppo void
9441991Sheppo vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg)
9451991Sheppo {
9461991Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
9471991Sheppo 	fdb_t *fdbp;
9481991Sheppo 	fdb_fanout_t *fdbhp;
9491991Sheppo 
9501991Sheppo 	/*
9511991Sheppo 	 * The last hash list is reserved for default route entry,
9521991Sheppo 	 * and for now, we have only one entry in this list.
9531991Sheppo 	 */
9541991Sheppo 	fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]);
9551991Sheppo 
9561991Sheppo 	WRITE_ENTER(&fdbhp->rwlock);
9571991Sheppo 
9581991Sheppo 	if (fdbhp->headp) {
9594647Sraghuram 		DWARN(vnetp, "default rte already exists\n");
9601991Sheppo 		RW_EXIT(&fdbhp->rwlock);
9611991Sheppo 		return;
9621991Sheppo 	}
9631991Sheppo 	fdbp = kmem_zalloc(sizeof (fdb_t), KM_NOSLEEP);
9641991Sheppo 	if (fdbp == NULL) {
9651991Sheppo 		RW_EXIT(&fdbhp->rwlock);
9661991Sheppo 		return;
9671991Sheppo 	}
9681991Sheppo 	bzero(fdbp->macaddr, ETHERADDRL);
9691991Sheppo 	fdbp->m_tx = m_tx;
9701991Sheppo 	fdbp->txarg = txarg;
9711991Sheppo 	fdbp->nextp = NULL;
9721991Sheppo 	fdbhp->headp = fdbp;
9731991Sheppo 
9741991Sheppo 	RW_EXIT(&fdbhp->rwlock);
9751991Sheppo }
9761991Sheppo 
9771991Sheppo /* delete default route entry from the forwarding database */
9781991Sheppo void
9791991Sheppo vnet_del_def_rte(void *arg)
9801991Sheppo {
9811991Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
9821991Sheppo 	fdb_t *fdbp;
9831991Sheppo 	fdb_fanout_t *fdbhp;
9841991Sheppo 
9851991Sheppo 	/*
9861991Sheppo 	 * The last hash list is reserved for default route entry,
9871991Sheppo 	 * and for now, we have only one entry in this list.
9881991Sheppo 	 */
9891991Sheppo 	fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]);
9901991Sheppo 
9911991Sheppo 	WRITE_ENTER(&fdbhp->rwlock);
9921991Sheppo 
9931991Sheppo 	if (fdbhp->headp == NULL) {
9941991Sheppo 		RW_EXIT(&fdbhp->rwlock);
9951991Sheppo 		return;
9961991Sheppo 	}
9971991Sheppo 	fdbp = fdbhp->headp;
9981991Sheppo 	KMEM_FREE(fdbp);
9991991Sheppo 	fdbhp->headp = NULL;
10001991Sheppo 
10011991Sheppo 	RW_EXIT(&fdbhp->rwlock);
10021991Sheppo }
10032311Sseb 
10042311Sseb void
10052311Sseb vnet_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp)
10062311Sseb {
10072311Sseb 	vnet_t *vnetp = arg;
10082311Sseb 	mac_rx(vnetp->mh, mrh, mp);
10092311Sseb }
10102311Sseb 
10112311Sseb void
10122311Sseb vnet_tx_update(void *arg)
10132311Sseb {
10142311Sseb 	vnet_t *vnetp = arg;
10152311Sseb 	mac_tx_update(vnetp->mh);
10162311Sseb }
1017