xref: /titanic_53/usr/src/uts/sun4v/io/vnet.c (revision 1ae0874509b6811fdde1dfd46f0d93fd09867a3f)
1*1ae08745Sheppo /*
2*1ae08745Sheppo  * CDDL HEADER START
3*1ae08745Sheppo  *
4*1ae08745Sheppo  * The contents of this file are subject to the terms of the
5*1ae08745Sheppo  * Common Development and Distribution License (the "License").
6*1ae08745Sheppo  * You may not use this file except in compliance with the License.
7*1ae08745Sheppo  *
8*1ae08745Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*1ae08745Sheppo  * or http://www.opensolaris.org/os/licensing.
10*1ae08745Sheppo  * See the License for the specific language governing permissions
11*1ae08745Sheppo  * and limitations under the License.
12*1ae08745Sheppo  *
13*1ae08745Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
14*1ae08745Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*1ae08745Sheppo  * If applicable, add the following below this CDDL HEADER, with the
16*1ae08745Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
17*1ae08745Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
18*1ae08745Sheppo  *
19*1ae08745Sheppo  * CDDL HEADER END
20*1ae08745Sheppo  */
21*1ae08745Sheppo 
22*1ae08745Sheppo /*
23*1ae08745Sheppo  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*1ae08745Sheppo  * Use is subject to license terms.
25*1ae08745Sheppo  */
26*1ae08745Sheppo 
27*1ae08745Sheppo #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*1ae08745Sheppo 
29*1ae08745Sheppo #include <sys/types.h>
30*1ae08745Sheppo #include <sys/errno.h>
31*1ae08745Sheppo #include <sys/param.h>
32*1ae08745Sheppo #include <sys/stream.h>
33*1ae08745Sheppo #include <sys/kmem.h>
34*1ae08745Sheppo #include <sys/conf.h>
35*1ae08745Sheppo #include <sys/devops.h>
36*1ae08745Sheppo #include <sys/ksynch.h>
37*1ae08745Sheppo #include <sys/stat.h>
38*1ae08745Sheppo #include <sys/modctl.h>
39*1ae08745Sheppo #include <sys/debug.h>
40*1ae08745Sheppo #include <sys/ethernet.h>
41*1ae08745Sheppo #include <sys/dlpi.h>
42*1ae08745Sheppo #include <net/if.h>
43*1ae08745Sheppo #include <sys/mac.h>
44*1ae08745Sheppo #include <sys/ddi.h>
45*1ae08745Sheppo #include <sys/sunddi.h>
46*1ae08745Sheppo #include <sys/strsun.h>
47*1ae08745Sheppo #include <sys/note.h>
48*1ae08745Sheppo #include <sys/vnet.h>
49*1ae08745Sheppo 
50*1ae08745Sheppo /*
51*1ae08745Sheppo  * Function prototypes.
52*1ae08745Sheppo  */
53*1ae08745Sheppo 
54*1ae08745Sheppo /* DDI entrypoints */
55*1ae08745Sheppo static int vnetdevinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
56*1ae08745Sheppo static int vnetattach(dev_info_t *, ddi_attach_cmd_t);
57*1ae08745Sheppo static int vnetdetach(dev_info_t *, ddi_detach_cmd_t);
58*1ae08745Sheppo 
59*1ae08745Sheppo /* MAC entrypoints  */
60*1ae08745Sheppo static uint64_t vnet_m_stat(void *arg, enum mac_stat stat);
61*1ae08745Sheppo static int vnet_m_start(void *);
62*1ae08745Sheppo static void vnet_m_stop(void *);
63*1ae08745Sheppo static int vnet_m_promisc(void *, boolean_t);
64*1ae08745Sheppo static int vnet_m_multicst(void *, boolean_t, const uint8_t *);
65*1ae08745Sheppo static int vnet_m_unicst(void *, const uint8_t *);
66*1ae08745Sheppo static void vnet_m_resources(void *);
67*1ae08745Sheppo static void vnet_m_ioctl(void *, queue_t *, mblk_t *);
68*1ae08745Sheppo mblk_t *vnet_m_tx(void *, mblk_t *);
69*1ae08745Sheppo 
70*1ae08745Sheppo /* vnet internal functions */
71*1ae08745Sheppo static int vnet_mac_register(vnet_t *);
72*1ae08745Sheppo static int vnet_read_mac_address(vnet_t *vnetp);
73*1ae08745Sheppo static void vnet_add_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp);
74*1ae08745Sheppo static void vnet_del_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp);
75*1ae08745Sheppo static vp_tl_t *vnet_get_vptl(vnet_t *vnetp, const char *devname);
76*1ae08745Sheppo static fdb_t *vnet_lookup_fdb(fdb_fanout_t *fdbhp, uint8_t *macaddr);
77*1ae08745Sheppo 
78*1ae08745Sheppo /* exported functions */
79*1ae08745Sheppo void vnet_add_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg);
80*1ae08745Sheppo void vnet_del_fdb(void *arg, uint8_t *macaddr);
81*1ae08745Sheppo void vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg);
82*1ae08745Sheppo void vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg);
83*1ae08745Sheppo void vnet_del_def_rte(void *arg);
84*1ae08745Sheppo 
85*1ae08745Sheppo /* externs */
86*1ae08745Sheppo extern int vgen_init(void *vnetp, dev_info_t *vnetdip, void *vnetmacp,
87*1ae08745Sheppo 	const uint8_t *macaddr, mac_t **vgenmacp);
88*1ae08745Sheppo extern void vgen_uninit(void *arg);
89*1ae08745Sheppo 
90*1ae08745Sheppo /*
91*1ae08745Sheppo  * Linked list of "vnet_t" structures - one per instance.
92*1ae08745Sheppo  */
93*1ae08745Sheppo static vnet_t	*vnet_headp = NULL;
94*1ae08745Sheppo static krwlock_t vnet_rw;
95*1ae08745Sheppo 
96*1ae08745Sheppo /* Tunables */
97*1ae08745Sheppo uint32_t vnet_ntxds = VNET_NTXDS;	/* power of 2 transmit descriptors */
98*1ae08745Sheppo uint32_t vnet_reclaim_lowat = VNET_RECLAIM_LOWAT;  /* tx recl low watermark */
99*1ae08745Sheppo uint32_t vnet_reclaim_hiwat = VNET_RECLAIM_HIWAT;  /* tx recl high watermark */
100*1ae08745Sheppo uint32_t vnet_ldcwd_interval = VNET_LDCWD_INTERVAL; /* watchdog freq in msec */
101*1ae08745Sheppo uint32_t vnet_ldcwd_txtimeout = VNET_LDCWD_TXTIMEOUT;  /* tx timeout in msec */
102*1ae08745Sheppo uint32_t vnet_ldc_qlen = VNET_LDC_QLEN;		/* ldc qlen */
103*1ae08745Sheppo uint32_t vnet_nfdb_hash = VNET_NFDB_HASH;	/* size of fdb hash table */
104*1ae08745Sheppo 
105*1ae08745Sheppo /*
106*1ae08745Sheppo  * Property names
107*1ae08745Sheppo  */
108*1ae08745Sheppo static char macaddr_propname[] = "local-mac-address";
109*1ae08745Sheppo 
110*1ae08745Sheppo static struct ether_addr etherbroadcastaddr = {
111*1ae08745Sheppo 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
112*1ae08745Sheppo };
113*1ae08745Sheppo 
114*1ae08745Sheppo /*
115*1ae08745Sheppo  * MIB II broadcast/multicast packets
116*1ae08745Sheppo  */
117*1ae08745Sheppo #define	IS_BROADCAST(ehp) \
118*1ae08745Sheppo 		(ether_cmp(&ehp->ether_dhost, &etherbroadcastaddr) == 0)
119*1ae08745Sheppo #define	IS_MULTICAST(ehp) \
120*1ae08745Sheppo 		((ehp->ether_dhost.ether_addr_octet[0] & 01) == 1)
121*1ae08745Sheppo 
122*1ae08745Sheppo /*
123*1ae08745Sheppo  * This is the string displayed by modinfo(1m).
124*1ae08745Sheppo  */
125*1ae08745Sheppo static char vnet_ident[] = "vnet driver v1.0";
126*1ae08745Sheppo extern struct mod_ops mod_driverops;
127*1ae08745Sheppo static struct cb_ops cb_vnetops = {
128*1ae08745Sheppo 	nulldev,		/* cb_open */
129*1ae08745Sheppo 	nulldev,		/* cb_close */
130*1ae08745Sheppo 	nodev,			/* cb_strategy */
131*1ae08745Sheppo 	nodev,			/* cb_print */
132*1ae08745Sheppo 	nodev,			/* cb_dump */
133*1ae08745Sheppo 	nodev,			/* cb_read */
134*1ae08745Sheppo 	nodev,			/* cb_write */
135*1ae08745Sheppo 	nodev,			/* cb_ioctl */
136*1ae08745Sheppo 	nodev,			/* cb_devmap */
137*1ae08745Sheppo 	nodev,			/* cb_mmap */
138*1ae08745Sheppo 	nodev,			/* cb_segmap */
139*1ae08745Sheppo 	nochpoll,		/* cb_chpoll */
140*1ae08745Sheppo 	ddi_prop_op,		/* cb_prop_op */
141*1ae08745Sheppo 	NULL,			/* cb_stream */
142*1ae08745Sheppo 	(int)(D_MP)		/* cb_flag */
143*1ae08745Sheppo };
144*1ae08745Sheppo 
145*1ae08745Sheppo static struct dev_ops vnetops = {
146*1ae08745Sheppo 	DEVO_REV,		/* devo_rev */
147*1ae08745Sheppo 	0,			/* devo_refcnt */
148*1ae08745Sheppo 	NULL,			/* devo_getinfo */
149*1ae08745Sheppo 	nulldev,		/* devo_identify */
150*1ae08745Sheppo 	nulldev,		/* devo_probe */
151*1ae08745Sheppo 	vnetattach,		/* devo_attach */
152*1ae08745Sheppo 	vnetdetach,		/* devo_detach */
153*1ae08745Sheppo 	nodev,			/* devo_reset */
154*1ae08745Sheppo 	&cb_vnetops,		/* devo_cb_ops */
155*1ae08745Sheppo 	(struct bus_ops *)NULL	/* devo_bus_ops */
156*1ae08745Sheppo };
157*1ae08745Sheppo 
158*1ae08745Sheppo static struct modldrv modldrv = {
159*1ae08745Sheppo 	&mod_driverops,		/* Type of module.  This one is a driver */
160*1ae08745Sheppo 	vnet_ident,		/* ID string */
161*1ae08745Sheppo 	&vnetops		/* driver specific ops */
162*1ae08745Sheppo };
163*1ae08745Sheppo 
164*1ae08745Sheppo static struct modlinkage modlinkage = {
165*1ae08745Sheppo 	MODREV_1, (void *)&modldrv, NULL
166*1ae08745Sheppo };
167*1ae08745Sheppo 
168*1ae08745Sheppo 
169*1ae08745Sheppo /*
170*1ae08745Sheppo  * Print debug messages - set to 0xf to enable all msgs
171*1ae08745Sheppo  */
172*1ae08745Sheppo int _vnet_dbglevel = 0x8;
173*1ae08745Sheppo 
174*1ae08745Sheppo void
175*1ae08745Sheppo _vnetdebug_printf(void *arg, const char *fmt, ...)
176*1ae08745Sheppo {
177*1ae08745Sheppo 	char    buf[512];
178*1ae08745Sheppo 	va_list ap;
179*1ae08745Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
180*1ae08745Sheppo 
181*1ae08745Sheppo 	va_start(ap, fmt);
182*1ae08745Sheppo 	(void) vsprintf(buf, fmt, ap);
183*1ae08745Sheppo 	va_end(ap);
184*1ae08745Sheppo 
185*1ae08745Sheppo 	if (vnetp == NULL)
186*1ae08745Sheppo 		cmn_err(CE_CONT, "%s\n", buf);
187*1ae08745Sheppo 	else
188*1ae08745Sheppo 		cmn_err(CE_CONT, "vnet%d: %s\n", vnetp->instance, buf);
189*1ae08745Sheppo }
190*1ae08745Sheppo 
191*1ae08745Sheppo #ifdef DEBUG
192*1ae08745Sheppo 
193*1ae08745Sheppo /*
194*1ae08745Sheppo  * XXX: any changes to the definitions below need corresponding changes in
195*1ae08745Sheppo  * vnet_gen.c
196*1ae08745Sheppo  */
197*1ae08745Sheppo 
198*1ae08745Sheppo /*
199*1ae08745Sheppo  * debug levels:
200*1ae08745Sheppo  * DBG_LEVEL1:	Function entry/exit tracing
201*1ae08745Sheppo  * DBG_LEVEL2:	Info messages
202*1ae08745Sheppo  * DBG_LEVEL3:	Warning messages
203*1ae08745Sheppo  * DBG_LEVEL4:	Error messages
204*1ae08745Sheppo  */
205*1ae08745Sheppo 
206*1ae08745Sheppo enum	{ DBG_LEVEL1 = 0x01, DBG_LEVEL2 = 0x02, DBG_LEVEL3 = 0x04,
207*1ae08745Sheppo 	    DBG_LEVEL4 = 0x08 };
208*1ae08745Sheppo 
209*1ae08745Sheppo #define	DBG1(_s)	do {						\
210*1ae08745Sheppo 			    if ((_vnet_dbglevel & DBG_LEVEL1) != 0) {	\
211*1ae08745Sheppo 					_vnetdebug_printf _s;		\
212*1ae08745Sheppo 			    }					\
213*1ae08745Sheppo 			_NOTE(CONSTCOND) } while (0)
214*1ae08745Sheppo 
215*1ae08745Sheppo #define	DBG2(_s)	do {						\
216*1ae08745Sheppo 			    if ((_vnet_dbglevel & DBG_LEVEL2) != 0) {	\
217*1ae08745Sheppo 					_vnetdebug_printf _s;		\
218*1ae08745Sheppo 			    }					\
219*1ae08745Sheppo 			_NOTE(CONSTCOND) } while (0)
220*1ae08745Sheppo 
221*1ae08745Sheppo #define	DWARN(_s)	do {						\
222*1ae08745Sheppo 			    if ((_vnet_dbglevel & DBG_LEVEL3) != 0) {	\
223*1ae08745Sheppo 					_vnetdebug_printf _s;		\
224*1ae08745Sheppo 			    }					\
225*1ae08745Sheppo 			_NOTE(CONSTCOND) } while (0)
226*1ae08745Sheppo 
227*1ae08745Sheppo #define	DERR(_s)	do {						\
228*1ae08745Sheppo 			    if ((_vnet_dbglevel & DBG_LEVEL4) != 0) {	\
229*1ae08745Sheppo 					_vnetdebug_printf _s;		\
230*1ae08745Sheppo 			    }					\
231*1ae08745Sheppo 			_NOTE(CONSTCOND) } while (0)
232*1ae08745Sheppo 
233*1ae08745Sheppo #else
234*1ae08745Sheppo 
235*1ae08745Sheppo #define	DBG1(_s)	if (0)	_vnetdebug_printf _s
236*1ae08745Sheppo #define	DBG2(_s)	if (0)	_vnetdebug_printf _s
237*1ae08745Sheppo #define	DWARN(_s)	if (0)	_vnetdebug_printf _s
238*1ae08745Sheppo #define	DERR(_s)	if (0)	_vnetdebug_printf _s
239*1ae08745Sheppo 
240*1ae08745Sheppo #endif
241*1ae08745Sheppo 
242*1ae08745Sheppo /* _init(9E): initialize the loadable module */
243*1ae08745Sheppo int
244*1ae08745Sheppo _init(void)
245*1ae08745Sheppo {
246*1ae08745Sheppo 	int status;
247*1ae08745Sheppo 
248*1ae08745Sheppo 	DBG1((NULL, "_init: enter\n"));
249*1ae08745Sheppo 
250*1ae08745Sheppo 	mac_init_ops(&vnetops, "vnet");
251*1ae08745Sheppo 	status = mod_install(&modlinkage);
252*1ae08745Sheppo 	if (status != 0) {
253*1ae08745Sheppo 		mac_fini_ops(&vnetops);
254*1ae08745Sheppo 	}
255*1ae08745Sheppo 
256*1ae08745Sheppo 	DBG1((NULL, "_init: exit\n"));
257*1ae08745Sheppo 	return (status);
258*1ae08745Sheppo }
259*1ae08745Sheppo 
260*1ae08745Sheppo /* _fini(9E): prepare the module for unloading. */
261*1ae08745Sheppo int
262*1ae08745Sheppo _fini(void)
263*1ae08745Sheppo {
264*1ae08745Sheppo 	int status;
265*1ae08745Sheppo 
266*1ae08745Sheppo 	DBG1((NULL, "_fini: enter\n"));
267*1ae08745Sheppo 
268*1ae08745Sheppo 	status = mod_remove(&modlinkage);
269*1ae08745Sheppo 	if (status != 0)
270*1ae08745Sheppo 		return (status);
271*1ae08745Sheppo 	mac_fini_ops(&vnetops);
272*1ae08745Sheppo 
273*1ae08745Sheppo 	DBG1((NULL, "_fini: exit\n"));
274*1ae08745Sheppo 	return (status);
275*1ae08745Sheppo }
276*1ae08745Sheppo 
277*1ae08745Sheppo /* _info(9E): return information about the loadable module */
278*1ae08745Sheppo int
279*1ae08745Sheppo _info(struct modinfo *modinfop)
280*1ae08745Sheppo {
281*1ae08745Sheppo 	return (mod_info(&modlinkage, modinfop));
282*1ae08745Sheppo }
283*1ae08745Sheppo 
284*1ae08745Sheppo /*
285*1ae08745Sheppo  * attach(9E): attach a device to the system.
286*1ae08745Sheppo  * called once for each instance of the device on the system.
287*1ae08745Sheppo  */
288*1ae08745Sheppo static int
289*1ae08745Sheppo vnetattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
290*1ae08745Sheppo {
291*1ae08745Sheppo 	mac_t		*macp;
292*1ae08745Sheppo 	vnet_t		*vnetp;
293*1ae08745Sheppo 	vp_tl_t		*vp_tlp;
294*1ae08745Sheppo 	int		instance;
295*1ae08745Sheppo 	int		status;
296*1ae08745Sheppo 	enum		{ AST_init = 0x0, AST_vnet_alloc = 0x1,
297*1ae08745Sheppo 			    AST_mac_alloc = 0x2, AST_read_macaddr = 0x4,
298*1ae08745Sheppo 			    AST_vgen_init = 0x8, AST_vptl_alloc = 0x10,
299*1ae08745Sheppo 			    AST_fdbh_alloc = 0x20 }
300*1ae08745Sheppo 			attach_state;
301*1ae08745Sheppo 	mac_t		*vgenmacp = NULL;
302*1ae08745Sheppo 	uint32_t	nfdbh = 0;
303*1ae08745Sheppo 
304*1ae08745Sheppo 	attach_state = AST_init;
305*1ae08745Sheppo 
306*1ae08745Sheppo 	switch (cmd) {
307*1ae08745Sheppo 	case DDI_ATTACH:
308*1ae08745Sheppo 		break;
309*1ae08745Sheppo 	case DDI_RESUME:
310*1ae08745Sheppo 	case DDI_PM_RESUME:
311*1ae08745Sheppo 	default:
312*1ae08745Sheppo 		goto vnet_attach_fail;
313*1ae08745Sheppo 	}
314*1ae08745Sheppo 
315*1ae08745Sheppo 	instance = ddi_get_instance(dip);
316*1ae08745Sheppo 	DBG1((NULL, "vnetattach: instance(%d) enter\n", instance));
317*1ae08745Sheppo 
318*1ae08745Sheppo 	/* allocate vnet_t and mac_t structures */
319*1ae08745Sheppo 	vnetp = kmem_zalloc(sizeof (vnet_t), KM_SLEEP);
320*1ae08745Sheppo 	attach_state |= AST_vnet_alloc;
321*1ae08745Sheppo 
322*1ae08745Sheppo 	macp = kmem_zalloc(sizeof (mac_t), KM_SLEEP);
323*1ae08745Sheppo 	attach_state |= AST_mac_alloc;
324*1ae08745Sheppo 
325*1ae08745Sheppo 	/* setup links to vnet_t from both devinfo and mac_t */
326*1ae08745Sheppo 	ddi_set_driver_private(dip, (caddr_t)vnetp);
327*1ae08745Sheppo 	macp->m_driver = vnetp;
328*1ae08745Sheppo 	vnetp->dip = dip;
329*1ae08745Sheppo 	vnetp->macp = macp;
330*1ae08745Sheppo 	vnetp->instance = instance;
331*1ae08745Sheppo 
332*1ae08745Sheppo 	/* read the mac address */
333*1ae08745Sheppo 	status = vnet_read_mac_address(vnetp);
334*1ae08745Sheppo 	if (status != DDI_SUCCESS) {
335*1ae08745Sheppo 		goto vnet_attach_fail;
336*1ae08745Sheppo 	}
337*1ae08745Sheppo 	attach_state |= AST_read_macaddr;
338*1ae08745Sheppo 
339*1ae08745Sheppo 	/*
340*1ae08745Sheppo 	 * Initialize the generic vnet proxy transport. This is the first
341*1ae08745Sheppo 	 * and default transport used by vnet. The generic transport
342*1ae08745Sheppo 	 * is provided by using sun4v LDC (logical domain channel). On success,
343*1ae08745Sheppo 	 * vgen_init() provides a pointer to mac_t of generic transport.
344*1ae08745Sheppo 	 * Currently, this generic layer provides network connectivity to other
345*1ae08745Sheppo 	 * vnets within ldoms and also to remote hosts oustide ldoms through
346*1ae08745Sheppo 	 * the virtual switch (vsw) device on domain0. In the future, when
347*1ae08745Sheppo 	 * physical adapters that are able to share their resources (such as
348*1ae08745Sheppo 	 * dma channels) with guest domains become available, the vnet device
349*1ae08745Sheppo 	 * will use hardware specific driver to communicate directly over the
350*1ae08745Sheppo 	 * physical device to reach remote hosts without going through vswitch.
351*1ae08745Sheppo 	 */
352*1ae08745Sheppo 	status = vgen_init(vnetp, vnetp->dip, vnetp->macp,
353*1ae08745Sheppo 	    (uint8_t *)vnetp->curr_macaddr, &vgenmacp);
354*1ae08745Sheppo 	if (status != DDI_SUCCESS) {
355*1ae08745Sheppo 		DERR((vnetp, "vgen_init() failed\n"));
356*1ae08745Sheppo 		goto vnet_attach_fail;
357*1ae08745Sheppo 	}
358*1ae08745Sheppo 	attach_state |= AST_vgen_init;
359*1ae08745Sheppo 
360*1ae08745Sheppo 	vp_tlp = kmem_zalloc(sizeof (vp_tl_t), KM_SLEEP);
361*1ae08745Sheppo 	vp_tlp->macp = vgenmacp;
362*1ae08745Sheppo 	(void) snprintf(vp_tlp->name, MAXNAMELEN, "%s%u", "vgen", instance);
363*1ae08745Sheppo 	(void) strcpy(vnetp->vgen_name, vp_tlp->name);
364*1ae08745Sheppo 
365*1ae08745Sheppo 	/* add generic transport to the list of vnet proxy transports */
366*1ae08745Sheppo 	vnet_add_vptl(vnetp, vp_tlp);
367*1ae08745Sheppo 	attach_state |= AST_vptl_alloc;
368*1ae08745Sheppo 
369*1ae08745Sheppo 	nfdbh = vnet_nfdb_hash;
370*1ae08745Sheppo 	if ((nfdbh < VNET_NFDB_HASH) || (nfdbh > VNET_NFDB_HASH_MAX)) {
371*1ae08745Sheppo 		vnetp->nfdb_hash = VNET_NFDB_HASH;
372*1ae08745Sheppo 	}
373*1ae08745Sheppo 	else
374*1ae08745Sheppo 		vnetp->nfdb_hash = nfdbh;
375*1ae08745Sheppo 
376*1ae08745Sheppo 	/* allocate fdb hash table, with an extra slot for default route */
377*1ae08745Sheppo 	vnetp->fdbhp = kmem_zalloc(sizeof (fdb_fanout_t) *
378*1ae08745Sheppo 	    (vnetp->nfdb_hash + 1), KM_SLEEP);
379*1ae08745Sheppo 	attach_state |= AST_fdbh_alloc;
380*1ae08745Sheppo 
381*1ae08745Sheppo 	/* register with MAC layer */
382*1ae08745Sheppo 	status = vnet_mac_register(vnetp);
383*1ae08745Sheppo 	if (status != DDI_SUCCESS) {
384*1ae08745Sheppo 		goto vnet_attach_fail;
385*1ae08745Sheppo 	}
386*1ae08745Sheppo 
387*1ae08745Sheppo 	/* add to the list of vnet devices */
388*1ae08745Sheppo 	WRITE_ENTER(&vnet_rw);
389*1ae08745Sheppo 	vnetp->nextp = vnet_headp;
390*1ae08745Sheppo 	vnet_headp = vnetp;
391*1ae08745Sheppo 	RW_EXIT(&vnet_rw);
392*1ae08745Sheppo 
393*1ae08745Sheppo 	DBG1((NULL, "vnetattach: instance(%d) exit\n", instance));
394*1ae08745Sheppo 	return (DDI_SUCCESS);
395*1ae08745Sheppo 
396*1ae08745Sheppo vnet_attach_fail:
397*1ae08745Sheppo 	if (attach_state & AST_fdbh_alloc) {
398*1ae08745Sheppo 		kmem_free(vnetp->fdbhp,
399*1ae08745Sheppo 		    sizeof (fdb_fanout_t) * (vnetp->nfdb_hash + 1));
400*1ae08745Sheppo 	}
401*1ae08745Sheppo 	if (attach_state & AST_vptl_alloc) {
402*1ae08745Sheppo 		WRITE_ENTER(&vnetp->trwlock);
403*1ae08745Sheppo 		vnet_del_vptl(vnetp, vp_tlp);
404*1ae08745Sheppo 		RW_EXIT(&vnetp->trwlock);
405*1ae08745Sheppo 	}
406*1ae08745Sheppo 	if (attach_state & AST_vgen_init) {
407*1ae08745Sheppo 		vgen_uninit(vgenmacp->m_driver);
408*1ae08745Sheppo 	}
409*1ae08745Sheppo 	if (attach_state & AST_mac_alloc) {
410*1ae08745Sheppo 		KMEM_FREE(macp);
411*1ae08745Sheppo 	}
412*1ae08745Sheppo 	if (attach_state & AST_vnet_alloc) {
413*1ae08745Sheppo 		KMEM_FREE(vnetp);
414*1ae08745Sheppo 	}
415*1ae08745Sheppo 	return (DDI_FAILURE);
416*1ae08745Sheppo }
417*1ae08745Sheppo 
418*1ae08745Sheppo /*
419*1ae08745Sheppo  * detach(9E): detach a device from the system.
420*1ae08745Sheppo  */
421*1ae08745Sheppo static int
422*1ae08745Sheppo vnetdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
423*1ae08745Sheppo {
424*1ae08745Sheppo 	vnet_t		*vnetp;
425*1ae08745Sheppo 	vnet_t		**vnetpp;
426*1ae08745Sheppo 	vp_tl_t		*vp_tlp;
427*1ae08745Sheppo 	int		instance;
428*1ae08745Sheppo 
429*1ae08745Sheppo 	instance = ddi_get_instance(dip);
430*1ae08745Sheppo 	DBG1((NULL, "vnetdetach: instance(%d) enter\n", instance));
431*1ae08745Sheppo 
432*1ae08745Sheppo 	vnetp = ddi_get_driver_private(dip);
433*1ae08745Sheppo 	if (vnetp == NULL) {
434*1ae08745Sheppo 		goto vnet_detach_fail;
435*1ae08745Sheppo 	}
436*1ae08745Sheppo 
437*1ae08745Sheppo 	switch (cmd) {
438*1ae08745Sheppo 	case DDI_DETACH:
439*1ae08745Sheppo 		break;
440*1ae08745Sheppo 	case DDI_SUSPEND:
441*1ae08745Sheppo 	case DDI_PM_SUSPEND:
442*1ae08745Sheppo 	default:
443*1ae08745Sheppo 		goto vnet_detach_fail;
444*1ae08745Sheppo 	}
445*1ae08745Sheppo 
446*1ae08745Sheppo 	/*
447*1ae08745Sheppo 	 * Unregister from the MAC subsystem.  This can fail, in
448*1ae08745Sheppo 	 * particular if there are DLPI style-2 streams still open -
449*1ae08745Sheppo 	 * in which case we just return failure.
450*1ae08745Sheppo 	 */
451*1ae08745Sheppo 	if (mac_unregister(vnetp->macp) != 0)
452*1ae08745Sheppo 		goto vnet_detach_fail;
453*1ae08745Sheppo 
454*1ae08745Sheppo 	/* unlink from instance(vnet_t) list */
455*1ae08745Sheppo 	WRITE_ENTER(&vnet_rw);
456*1ae08745Sheppo 	for (vnetpp = &vnet_headp; *vnetpp; vnetpp = &(*vnetpp)->nextp) {
457*1ae08745Sheppo 		if (*vnetpp == vnetp) {
458*1ae08745Sheppo 			*vnetpp = vnetp->nextp;
459*1ae08745Sheppo 			break;
460*1ae08745Sheppo 		}
461*1ae08745Sheppo 	}
462*1ae08745Sheppo 	RW_EXIT(&vnet_rw);
463*1ae08745Sheppo 
464*1ae08745Sheppo 	/* uninit and free vnet proxy transports */
465*1ae08745Sheppo 	WRITE_ENTER(&vnetp->trwlock);
466*1ae08745Sheppo 	while ((vp_tlp = vnetp->tlp) != NULL) {
467*1ae08745Sheppo 		if (strcmp(vnetp->vgen_name, vp_tlp->name) == 0) {
468*1ae08745Sheppo 			/* uninitialize generic transport */
469*1ae08745Sheppo 			vgen_uninit(vp_tlp->macp->m_driver);
470*1ae08745Sheppo 		}
471*1ae08745Sheppo 		vnet_del_vptl(vnetp, vp_tlp);
472*1ae08745Sheppo 	}
473*1ae08745Sheppo 	RW_EXIT(&vnetp->trwlock);
474*1ae08745Sheppo 
475*1ae08745Sheppo 	KMEM_FREE(vnetp->macp);
476*1ae08745Sheppo 	KMEM_FREE(vnetp);
477*1ae08745Sheppo 
478*1ae08745Sheppo 	return (DDI_SUCCESS);
479*1ae08745Sheppo 
480*1ae08745Sheppo vnet_detach_fail:
481*1ae08745Sheppo 	return (DDI_FAILURE);
482*1ae08745Sheppo }
483*1ae08745Sheppo 
484*1ae08745Sheppo /* enable the device for transmit/receive */
485*1ae08745Sheppo static int
486*1ae08745Sheppo vnet_m_start(void *arg)
487*1ae08745Sheppo {
488*1ae08745Sheppo 	vnet_t		*vnetp = arg;
489*1ae08745Sheppo 	vp_tl_t		*vp_tlp;
490*1ae08745Sheppo 	mac_t		*vp_macp;
491*1ae08745Sheppo 
492*1ae08745Sheppo 	DBG1((vnetp, "vnet_m_start: enter\n"));
493*1ae08745Sheppo 
494*1ae08745Sheppo 	/*
495*1ae08745Sheppo 	 * XXX
496*1ae08745Sheppo 	 * Currently, we only have generic transport. m_start() invokes
497*1ae08745Sheppo 	 * vgen_start() which enables ports/channels in vgen and
498*1ae08745Sheppo 	 * initiates handshake with peer vnets and vsw. In the future when we
499*1ae08745Sheppo 	 * have support for hardware specific transports, this information
500*1ae08745Sheppo 	 * needs to be propagted back to vnet from vgen and we need to revisit
501*1ae08745Sheppo 	 * this code (see comments in vnet_attach()).
502*1ae08745Sheppo 	 *
503*1ae08745Sheppo 	 */
504*1ae08745Sheppo 	WRITE_ENTER(&vnetp->trwlock);
505*1ae08745Sheppo 	for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) {
506*1ae08745Sheppo 		vp_macp = vp_tlp->macp;
507*1ae08745Sheppo 		vp_macp->m_start(vp_macp->m_driver);
508*1ae08745Sheppo 	}
509*1ae08745Sheppo 	RW_EXIT(&vnetp->trwlock);
510*1ae08745Sheppo 
511*1ae08745Sheppo 	DBG1((vnetp, "vnet_m_start: exit\n"));
512*1ae08745Sheppo 	return (VNET_SUCCESS);
513*1ae08745Sheppo 
514*1ae08745Sheppo }
515*1ae08745Sheppo 
516*1ae08745Sheppo /* stop transmit/receive for the device */
517*1ae08745Sheppo static void
518*1ae08745Sheppo vnet_m_stop(void *arg)
519*1ae08745Sheppo {
520*1ae08745Sheppo 	vnet_t		*vnetp = arg;
521*1ae08745Sheppo 	vp_tl_t		*vp_tlp;
522*1ae08745Sheppo 	mac_t		*vp_macp;
523*1ae08745Sheppo 
524*1ae08745Sheppo 	DBG1((vnetp, "vnet_m_stop: enter\n"));
525*1ae08745Sheppo 
526*1ae08745Sheppo 	WRITE_ENTER(&vnetp->trwlock);
527*1ae08745Sheppo 	for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) {
528*1ae08745Sheppo 		vp_macp = vp_tlp->macp;
529*1ae08745Sheppo 		vp_macp->m_stop(vp_macp->m_driver);
530*1ae08745Sheppo 	}
531*1ae08745Sheppo 	RW_EXIT(&vnetp->trwlock);
532*1ae08745Sheppo 
533*1ae08745Sheppo 	DBG1((vnetp, "vnet_m_stop: exit\n"));
534*1ae08745Sheppo }
535*1ae08745Sheppo 
536*1ae08745Sheppo /* set the unicast mac address of the device */
537*1ae08745Sheppo static int
538*1ae08745Sheppo vnet_m_unicst(void *arg, const uint8_t *macaddr)
539*1ae08745Sheppo {
540*1ae08745Sheppo 	_NOTE(ARGUNUSED(macaddr))
541*1ae08745Sheppo 
542*1ae08745Sheppo 	vnet_t *vnetp = arg;
543*1ae08745Sheppo 
544*1ae08745Sheppo 	DBG1((vnetp, "vnet_m_unicst: enter\n"));
545*1ae08745Sheppo 	/*
546*1ae08745Sheppo 	 * XXX: setting mac address dynamically is not supported.
547*1ae08745Sheppo 	 */
548*1ae08745Sheppo #if 0
549*1ae08745Sheppo 	bcopy(macaddr, vnetp->curr_macaddr, ETHERADDRL);
550*1ae08745Sheppo #endif
551*1ae08745Sheppo 	DBG1((vnetp, "vnet_m_unicst: exit\n"));
552*1ae08745Sheppo 
553*1ae08745Sheppo 	return (VNET_SUCCESS);
554*1ae08745Sheppo }
555*1ae08745Sheppo 
556*1ae08745Sheppo /* enable/disable a multicast address */
557*1ae08745Sheppo static int
558*1ae08745Sheppo vnet_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
559*1ae08745Sheppo {
560*1ae08745Sheppo 	_NOTE(ARGUNUSED(add, mca))
561*1ae08745Sheppo 
562*1ae08745Sheppo 	vnet_t *vnetp = arg;
563*1ae08745Sheppo 	vp_tl_t		*vp_tlp;
564*1ae08745Sheppo 	mac_t		*vp_macp;
565*1ae08745Sheppo 	int rv = VNET_SUCCESS;
566*1ae08745Sheppo 
567*1ae08745Sheppo 	DBG1((vnetp, "vnet_m_multicst: enter\n"));
568*1ae08745Sheppo 	READ_ENTER(&vnetp->trwlock);
569*1ae08745Sheppo 	for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) {
570*1ae08745Sheppo 		if (strcmp(vnetp->vgen_name, vp_tlp->name) == 0) {
571*1ae08745Sheppo 			vp_macp = vp_tlp->macp;
572*1ae08745Sheppo 			rv = vp_macp->m_multicst(vp_macp->m_driver, add, mca);
573*1ae08745Sheppo 			break;
574*1ae08745Sheppo 		}
575*1ae08745Sheppo 	}
576*1ae08745Sheppo 	RW_EXIT(&vnetp->trwlock);
577*1ae08745Sheppo 	DBG1((vnetp, "vnet_m_multicst: exit\n"));
578*1ae08745Sheppo 	return (rv);
579*1ae08745Sheppo }
580*1ae08745Sheppo 
581*1ae08745Sheppo /* set or clear promiscuous mode on the device */
582*1ae08745Sheppo static int
583*1ae08745Sheppo vnet_m_promisc(void *arg, boolean_t on)
584*1ae08745Sheppo {
585*1ae08745Sheppo 	_NOTE(ARGUNUSED(on))
586*1ae08745Sheppo 
587*1ae08745Sheppo 	vnet_t *vnetp = arg;
588*1ae08745Sheppo 	DBG1((vnetp, "vnet_m_promisc: enter\n"));
589*1ae08745Sheppo 	/*
590*1ae08745Sheppo 	 * XXX: setting promiscuous mode is not supported, just return success.
591*1ae08745Sheppo 	 */
592*1ae08745Sheppo 	DBG1((vnetp, "vnet_m_promisc: exit\n"));
593*1ae08745Sheppo 	return (VNET_SUCCESS);
594*1ae08745Sheppo }
595*1ae08745Sheppo 
596*1ae08745Sheppo /*
597*1ae08745Sheppo  * Transmit a chain of packets. This function provides switching functionality
598*1ae08745Sheppo  * based on the destination mac address to reach other guests (within ldoms) or
599*1ae08745Sheppo  * external hosts.
600*1ae08745Sheppo  */
601*1ae08745Sheppo mblk_t *
602*1ae08745Sheppo vnet_m_tx(void *arg, mblk_t *mp)
603*1ae08745Sheppo {
604*1ae08745Sheppo 	vnet_t *vnetp;
605*1ae08745Sheppo 	mblk_t *next;
606*1ae08745Sheppo 	uint32_t fdbhash;
607*1ae08745Sheppo 	fdb_t *fdbp;
608*1ae08745Sheppo 	fdb_fanout_t *fdbhp;
609*1ae08745Sheppo 	struct ether_header *ehp;
610*1ae08745Sheppo 	uint8_t *macaddr;
611*1ae08745Sheppo 	mblk_t *resid_mp;
612*1ae08745Sheppo 
613*1ae08745Sheppo 	vnetp = (vnet_t *)arg;
614*1ae08745Sheppo 	DBG1((vnetp, "vnet_m_tx: enter\n"));
615*1ae08745Sheppo 	ASSERT(mp != NULL);
616*1ae08745Sheppo 
617*1ae08745Sheppo 	while (mp != NULL) {
618*1ae08745Sheppo 		next = mp->b_next;
619*1ae08745Sheppo 		mp->b_next = NULL;
620*1ae08745Sheppo 
621*1ae08745Sheppo 		/* get the destination mac address in the eth header */
622*1ae08745Sheppo 		ehp = (struct ether_header *)mp->b_rptr;
623*1ae08745Sheppo 		macaddr = (uint8_t *)&ehp->ether_dhost;
624*1ae08745Sheppo 
625*1ae08745Sheppo 		/* Calculate hash value and fdb fanout */
626*1ae08745Sheppo 		fdbhash = MACHASH(macaddr, vnetp->nfdb_hash);
627*1ae08745Sheppo 		fdbhp = &(vnetp->fdbhp[fdbhash]);
628*1ae08745Sheppo 
629*1ae08745Sheppo 		READ_ENTER(&fdbhp->rwlock);
630*1ae08745Sheppo 		fdbp = vnet_lookup_fdb(fdbhp, macaddr);
631*1ae08745Sheppo 		if (fdbp) {
632*1ae08745Sheppo 			/*
633*1ae08745Sheppo 			 * If the destination is in FDB, the destination is
634*1ae08745Sheppo 			 * a vnet device within ldoms and directly reachable,
635*1ae08745Sheppo 			 * invoke the tx function in the fdb entry.
636*1ae08745Sheppo 			 */
637*1ae08745Sheppo 			resid_mp = fdbp->m_tx(fdbp->txarg, mp);
638*1ae08745Sheppo 			if (resid_mp != NULL) {
639*1ae08745Sheppo 				/* m_tx failed */
640*1ae08745Sheppo 				mp->b_next = next;
641*1ae08745Sheppo 				RW_EXIT(&fdbhp->rwlock);
642*1ae08745Sheppo 				break;
643*1ae08745Sheppo 			}
644*1ae08745Sheppo 			RW_EXIT(&fdbhp->rwlock);
645*1ae08745Sheppo 		} else {
646*1ae08745Sheppo 			/* destination is not in FDB */
647*1ae08745Sheppo 			RW_EXIT(&fdbhp->rwlock);
648*1ae08745Sheppo 			/*
649*1ae08745Sheppo 			 * If the destination is broadcast/multicast
650*1ae08745Sheppo 			 * or an unknown unicast address, forward the
651*1ae08745Sheppo 			 * packet to vsw, using the last slot in fdb which is
652*1ae08745Sheppo 			 * reserved for default route.
653*1ae08745Sheppo 			 */
654*1ae08745Sheppo 			fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]);
655*1ae08745Sheppo 			READ_ENTER(&fdbhp->rwlock);
656*1ae08745Sheppo 			fdbp = fdbhp->headp;
657*1ae08745Sheppo 			if (fdbp) {
658*1ae08745Sheppo 				resid_mp = fdbp->m_tx(fdbp->txarg, mp);
659*1ae08745Sheppo 				if (resid_mp != NULL) {
660*1ae08745Sheppo 					/* m_tx failed */
661*1ae08745Sheppo 					mp->b_next = next;
662*1ae08745Sheppo 					RW_EXIT(&fdbhp->rwlock);
663*1ae08745Sheppo 					break;
664*1ae08745Sheppo 				}
665*1ae08745Sheppo 			} else {
666*1ae08745Sheppo 				/* drop the packet */
667*1ae08745Sheppo 				freemsg(mp);
668*1ae08745Sheppo 			}
669*1ae08745Sheppo 			RW_EXIT(&fdbhp->rwlock);
670*1ae08745Sheppo 		}
671*1ae08745Sheppo 
672*1ae08745Sheppo 		mp = next;
673*1ae08745Sheppo 	}
674*1ae08745Sheppo 
675*1ae08745Sheppo 	DBG1((vnetp, "vnet_m_tx: exit\n"));
676*1ae08745Sheppo 	return (mp);
677*1ae08745Sheppo }
678*1ae08745Sheppo 
679*1ae08745Sheppo /* register resources with mac layer */
680*1ae08745Sheppo static void
681*1ae08745Sheppo vnet_m_resources(void *arg)
682*1ae08745Sheppo {
683*1ae08745Sheppo 	vnet_t *vnetp = arg;
684*1ae08745Sheppo 	vp_tl_t	*vp_tlp;
685*1ae08745Sheppo 	mac_t	*vp_macp;
686*1ae08745Sheppo 
687*1ae08745Sheppo 	DBG1((vnetp, "vnet_m_resources: enter\n"));
688*1ae08745Sheppo 
689*1ae08745Sheppo 	WRITE_ENTER(&vnetp->trwlock);
690*1ae08745Sheppo 	for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) {
691*1ae08745Sheppo 		vp_macp = vp_tlp->macp;
692*1ae08745Sheppo 		vp_macp->m_resources(vp_macp->m_driver);
693*1ae08745Sheppo 	}
694*1ae08745Sheppo 	RW_EXIT(&vnetp->trwlock);
695*1ae08745Sheppo 
696*1ae08745Sheppo 	DBG1((vnetp, "vnet_m_resources: exit\n"));
697*1ae08745Sheppo }
698*1ae08745Sheppo 
699*1ae08745Sheppo /*
700*1ae08745Sheppo  * vnet specific ioctls
701*1ae08745Sheppo  */
702*1ae08745Sheppo static void
703*1ae08745Sheppo vnet_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
704*1ae08745Sheppo {
705*1ae08745Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
706*1ae08745Sheppo 	struct iocblk *iocp;
707*1ae08745Sheppo 	int cmd;
708*1ae08745Sheppo 
709*1ae08745Sheppo 	DBG1((vnetp, "vnet_m_ioctl: enter\n"));
710*1ae08745Sheppo 
711*1ae08745Sheppo 	iocp = (struct iocblk *)mp->b_rptr;
712*1ae08745Sheppo 	iocp->ioc_error = 0;
713*1ae08745Sheppo 	cmd = iocp->ioc_cmd;
714*1ae08745Sheppo 	switch (cmd) {
715*1ae08745Sheppo 	default:
716*1ae08745Sheppo 		miocnak(wq, mp, 0, EINVAL);
717*1ae08745Sheppo 		break;
718*1ae08745Sheppo 	}
719*1ae08745Sheppo 	DBG1((vnetp, "vnet_m_ioctl: exit\n"));
720*1ae08745Sheppo }
721*1ae08745Sheppo 
722*1ae08745Sheppo /* get statistics from the device */
723*1ae08745Sheppo uint64_t
724*1ae08745Sheppo vnet_m_stat(void *arg, enum mac_stat stat)
725*1ae08745Sheppo {
726*1ae08745Sheppo 	vnet_t *vnetp = arg;
727*1ae08745Sheppo 	vp_tl_t	*vp_tlp;
728*1ae08745Sheppo 	mac_t	*vp_macp;
729*1ae08745Sheppo 	uint64_t val = 0;
730*1ae08745Sheppo 
731*1ae08745Sheppo 	DBG1((vnetp, "vnet_m_stat: enter\n"));
732*1ae08745Sheppo 
733*1ae08745Sheppo 	/*
734*1ae08745Sheppo 	 * get the specified statistic from each transport
735*1ae08745Sheppo 	 * and return the aggregate val
736*1ae08745Sheppo 	 */
737*1ae08745Sheppo 	READ_ENTER(&vnetp->trwlock);
738*1ae08745Sheppo 	for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) {
739*1ae08745Sheppo 		vp_macp = vp_tlp->macp;
740*1ae08745Sheppo 		val += vp_macp->m_stat(vp_macp->m_driver, stat);
741*1ae08745Sheppo 	}
742*1ae08745Sheppo 	RW_EXIT(&vnetp->trwlock);
743*1ae08745Sheppo 
744*1ae08745Sheppo 	DBG1((vnetp, "vnet_m_stat: exit\n"));
745*1ae08745Sheppo 	return (val);
746*1ae08745Sheppo }
747*1ae08745Sheppo 
748*1ae08745Sheppo /* wrapper function for mac_register() */
749*1ae08745Sheppo static int
750*1ae08745Sheppo vnet_mac_register(vnet_t *vnetp)
751*1ae08745Sheppo {
752*1ae08745Sheppo 	mac_info_t *mip;
753*1ae08745Sheppo 	mac_t *macp;
754*1ae08745Sheppo 
755*1ae08745Sheppo 	macp = vnetp->macp;
756*1ae08745Sheppo 
757*1ae08745Sheppo 	mip = &(macp->m_info);
758*1ae08745Sheppo 	mip->mi_media = DL_ETHER;
759*1ae08745Sheppo 	mip->mi_sdu_min = 0;
760*1ae08745Sheppo 	mip->mi_sdu_max = ETHERMTU;
761*1ae08745Sheppo 	mip->mi_cksum = 0;
762*1ae08745Sheppo 	mip->mi_poll = 0; /* DL_CAPAB_POLL ? */
763*1ae08745Sheppo 	mip->mi_addr_length = ETHERADDRL;
764*1ae08745Sheppo 	bcopy(&etherbroadcastaddr, mip->mi_brdcst_addr, ETHERADDRL);
765*1ae08745Sheppo 	bcopy(vnetp->curr_macaddr, mip->mi_unicst_addr, ETHERADDRL);
766*1ae08745Sheppo 
767*1ae08745Sheppo 	MAC_STAT_MIB(mip->mi_stat);
768*1ae08745Sheppo 	mip->mi_stat[MAC_STAT_UNKNOWNS] = B_FALSE;
769*1ae08745Sheppo 	MAC_STAT_ETHER(mip->mi_stat);
770*1ae08745Sheppo 	mip->mi_stat[MAC_STAT_SQE_ERRORS] = B_FALSE;
771*1ae08745Sheppo 	mip->mi_stat[MAC_STAT_MACRCV_ERRORS] = B_FALSE;
772*1ae08745Sheppo 
773*1ae08745Sheppo 	macp->m_stat = vnet_m_stat;
774*1ae08745Sheppo 	macp->m_start = vnet_m_start;
775*1ae08745Sheppo 	macp->m_stop = vnet_m_stop;
776*1ae08745Sheppo 	macp->m_promisc = vnet_m_promisc;
777*1ae08745Sheppo 	macp->m_multicst = vnet_m_multicst;
778*1ae08745Sheppo 	macp->m_unicst = vnet_m_unicst;
779*1ae08745Sheppo 	macp->m_resources = vnet_m_resources;
780*1ae08745Sheppo 	macp->m_ioctl = vnet_m_ioctl;
781*1ae08745Sheppo 	macp->m_tx = vnet_m_tx;
782*1ae08745Sheppo 
783*1ae08745Sheppo 	macp->m_dip = vnetp->dip;
784*1ae08745Sheppo 	macp->m_ident = MAC_IDENT;
785*1ae08745Sheppo 
786*1ae08745Sheppo 	/*
787*1ae08745Sheppo 	 * Finally, we're ready to register ourselves with the MAC layer
788*1ae08745Sheppo 	 * interface; if this succeeds, we're all ready to start()
789*1ae08745Sheppo 	 */
790*1ae08745Sheppo 	if (mac_register(macp) != 0) {
791*1ae08745Sheppo 		KMEM_FREE(macp);
792*1ae08745Sheppo 		return (DDI_FAILURE);
793*1ae08745Sheppo 	}
794*1ae08745Sheppo 
795*1ae08745Sheppo 	return (DDI_SUCCESS);
796*1ae08745Sheppo }
797*1ae08745Sheppo 
798*1ae08745Sheppo /* add vp_tl to the list */
799*1ae08745Sheppo static void
800*1ae08745Sheppo vnet_add_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp)
801*1ae08745Sheppo {
802*1ae08745Sheppo 	vp_tl_t *ttlp;
803*1ae08745Sheppo 
804*1ae08745Sheppo 	WRITE_ENTER(&vnetp->trwlock);
805*1ae08745Sheppo 	if (vnetp->tlp == NULL) {
806*1ae08745Sheppo 		vnetp->tlp = vp_tlp;
807*1ae08745Sheppo 	} else {
808*1ae08745Sheppo 		ttlp = vnetp->tlp;
809*1ae08745Sheppo 		while (ttlp->nextp)
810*1ae08745Sheppo 			ttlp = ttlp->nextp;
811*1ae08745Sheppo 		ttlp->nextp = vp_tlp;
812*1ae08745Sheppo 	}
813*1ae08745Sheppo 	RW_EXIT(&vnetp->trwlock);
814*1ae08745Sheppo }
815*1ae08745Sheppo 
816*1ae08745Sheppo /* remove vp_tl from the list */
817*1ae08745Sheppo static void
818*1ae08745Sheppo vnet_del_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp)
819*1ae08745Sheppo {
820*1ae08745Sheppo 	vp_tl_t *ttlp, **pretlp;
821*1ae08745Sheppo 	boolean_t found = B_FALSE;
822*1ae08745Sheppo 
823*1ae08745Sheppo 	pretlp = &vnetp->tlp;
824*1ae08745Sheppo 	ttlp = *pretlp;
825*1ae08745Sheppo 	while (ttlp) {
826*1ae08745Sheppo 		if (ttlp == vp_tlp) {
827*1ae08745Sheppo 			found = B_TRUE;
828*1ae08745Sheppo 			(*pretlp) = ttlp->nextp;
829*1ae08745Sheppo 			ttlp->nextp = NULL;
830*1ae08745Sheppo 			break;
831*1ae08745Sheppo 		}
832*1ae08745Sheppo 		pretlp = &(ttlp->nextp);
833*1ae08745Sheppo 		ttlp = *pretlp;
834*1ae08745Sheppo 	}
835*1ae08745Sheppo 
836*1ae08745Sheppo 	if (found) {
837*1ae08745Sheppo 		KMEM_FREE(vp_tlp);
838*1ae08745Sheppo 	}
839*1ae08745Sheppo }
840*1ae08745Sheppo 
841*1ae08745Sheppo /* get vp_tl corresponding to the given name */
842*1ae08745Sheppo static vp_tl_t *
843*1ae08745Sheppo vnet_get_vptl(vnet_t *vnetp, const char *name)
844*1ae08745Sheppo {
845*1ae08745Sheppo 	vp_tl_t *tlp;
846*1ae08745Sheppo 
847*1ae08745Sheppo 	tlp = vnetp->tlp;
848*1ae08745Sheppo 	while (tlp) {
849*1ae08745Sheppo 		if (strcmp(tlp->name, name) == 0) {
850*1ae08745Sheppo 			return (tlp);
851*1ae08745Sheppo 		}
852*1ae08745Sheppo 		tlp = tlp->nextp;
853*1ae08745Sheppo 	}
854*1ae08745Sheppo 	DWARN((vnetp,
855*1ae08745Sheppo 	    "vnet_get_vptl: can't find vp_tl with name (%s)\n", name));
856*1ae08745Sheppo 	return (NULL);
857*1ae08745Sheppo }
858*1ae08745Sheppo 
859*1ae08745Sheppo /* read the mac address of the device */
860*1ae08745Sheppo static int
861*1ae08745Sheppo vnet_read_mac_address(vnet_t *vnetp)
862*1ae08745Sheppo {
863*1ae08745Sheppo 	uchar_t 	*macaddr;
864*1ae08745Sheppo 	uint32_t 	size;
865*1ae08745Sheppo 	int 		rv;
866*1ae08745Sheppo 
867*1ae08745Sheppo 	rv = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, vnetp->dip,
868*1ae08745Sheppo 		DDI_PROP_DONTPASS, macaddr_propname, &macaddr, &size);
869*1ae08745Sheppo 	if ((rv != DDI_PROP_SUCCESS) || (size != ETHERADDRL)) {
870*1ae08745Sheppo 		DWARN((vnetp,
871*1ae08745Sheppo 		"vnet_read_mac_address: prop_lookup failed (%s) err (%d)\n",
872*1ae08745Sheppo 		macaddr_propname, rv));
873*1ae08745Sheppo 		return (DDI_FAILURE);
874*1ae08745Sheppo 	}
875*1ae08745Sheppo 	bcopy(macaddr, (caddr_t)vnetp->vendor_addr, ETHERADDRL);
876*1ae08745Sheppo 	bcopy(macaddr, (caddr_t)vnetp->curr_macaddr, ETHERADDRL);
877*1ae08745Sheppo 	ddi_prop_free(macaddr);
878*1ae08745Sheppo 
879*1ae08745Sheppo 	return (DDI_SUCCESS);
880*1ae08745Sheppo }
881*1ae08745Sheppo 
882*1ae08745Sheppo 
883*1ae08745Sheppo /*
884*1ae08745Sheppo  * Functions below are called only by generic transport to add/remove/modify
885*1ae08745Sheppo  * entries in forwarding database. See comments in vgen_port_init(vnet_gen.c).
886*1ae08745Sheppo  */
887*1ae08745Sheppo 
888*1ae08745Sheppo /* add an entry into the forwarding database */
889*1ae08745Sheppo void
890*1ae08745Sheppo vnet_add_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg)
891*1ae08745Sheppo {
892*1ae08745Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
893*1ae08745Sheppo 	uint32_t fdbhash;
894*1ae08745Sheppo 	fdb_t *fdbp;
895*1ae08745Sheppo 	fdb_fanout_t *fdbhp;
896*1ae08745Sheppo 
897*1ae08745Sheppo 	/* Calculate hash value and fdb fanout */
898*1ae08745Sheppo 	fdbhash = MACHASH(macaddr, vnetp->nfdb_hash);
899*1ae08745Sheppo 	fdbhp = &(vnetp->fdbhp[fdbhash]);
900*1ae08745Sheppo 
901*1ae08745Sheppo 	WRITE_ENTER(&fdbhp->rwlock);
902*1ae08745Sheppo 
903*1ae08745Sheppo 	fdbp = kmem_zalloc(sizeof (fdb_t), KM_NOSLEEP);
904*1ae08745Sheppo 	if (fdbp == NULL) {
905*1ae08745Sheppo 		RW_EXIT(&fdbhp->rwlock);
906*1ae08745Sheppo 		return;
907*1ae08745Sheppo 	}
908*1ae08745Sheppo 	bcopy(macaddr, (caddr_t)fdbp->macaddr, ETHERADDRL);
909*1ae08745Sheppo 	fdbp->m_tx = m_tx;
910*1ae08745Sheppo 	fdbp->txarg = txarg;
911*1ae08745Sheppo 	fdbp->nextp = fdbhp->headp;
912*1ae08745Sheppo 	fdbhp->headp = fdbp;
913*1ae08745Sheppo 
914*1ae08745Sheppo 	RW_EXIT(&fdbhp->rwlock);
915*1ae08745Sheppo }
916*1ae08745Sheppo 
917*1ae08745Sheppo /* delete an entry from the forwarding database */
918*1ae08745Sheppo void
919*1ae08745Sheppo vnet_del_fdb(void *arg, uint8_t *macaddr)
920*1ae08745Sheppo {
921*1ae08745Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
922*1ae08745Sheppo 	uint32_t fdbhash;
923*1ae08745Sheppo 	fdb_t *fdbp;
924*1ae08745Sheppo 	fdb_t **pfdbp;
925*1ae08745Sheppo 	fdb_fanout_t *fdbhp;
926*1ae08745Sheppo 
927*1ae08745Sheppo 	/* Calculate hash value and fdb fanout */
928*1ae08745Sheppo 	fdbhash = MACHASH(macaddr, vnetp->nfdb_hash);
929*1ae08745Sheppo 	fdbhp = &(vnetp->fdbhp[fdbhash]);
930*1ae08745Sheppo 
931*1ae08745Sheppo 	WRITE_ENTER(&fdbhp->rwlock);
932*1ae08745Sheppo 
933*1ae08745Sheppo 	for (pfdbp = &fdbhp->headp; (fdbp  = *pfdbp) != NULL;
934*1ae08745Sheppo 	    pfdbp = &fdbp->nextp) {
935*1ae08745Sheppo 		if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) {
936*1ae08745Sheppo 			/* Unlink it from the list */
937*1ae08745Sheppo 			*pfdbp = fdbp->nextp;
938*1ae08745Sheppo 			KMEM_FREE(fdbp);
939*1ae08745Sheppo 			break;
940*1ae08745Sheppo 		}
941*1ae08745Sheppo 	}
942*1ae08745Sheppo 
943*1ae08745Sheppo 	RW_EXIT(&fdbhp->rwlock);
944*1ae08745Sheppo }
945*1ae08745Sheppo 
946*1ae08745Sheppo /* modify an existing entry in the forwarding database */
947*1ae08745Sheppo void
948*1ae08745Sheppo vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg)
949*1ae08745Sheppo {
950*1ae08745Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
951*1ae08745Sheppo 	uint32_t fdbhash;
952*1ae08745Sheppo 	fdb_t *fdbp;
953*1ae08745Sheppo 	fdb_fanout_t *fdbhp;
954*1ae08745Sheppo 
955*1ae08745Sheppo 	/* Calculate hash value and fdb fanout */
956*1ae08745Sheppo 	fdbhash = MACHASH(macaddr, vnetp->nfdb_hash);
957*1ae08745Sheppo 	fdbhp = &(vnetp->fdbhp[fdbhash]);
958*1ae08745Sheppo 
959*1ae08745Sheppo 	WRITE_ENTER(&fdbhp->rwlock);
960*1ae08745Sheppo 
961*1ae08745Sheppo 	for (fdbp = fdbhp->headp; fdbp != NULL; fdbp = fdbp->nextp) {
962*1ae08745Sheppo 		if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) {
963*1ae08745Sheppo 			/* change the entry to have new tx params */
964*1ae08745Sheppo 			fdbp->m_tx = m_tx;
965*1ae08745Sheppo 			fdbp->txarg = txarg;
966*1ae08745Sheppo 			break;
967*1ae08745Sheppo 		}
968*1ae08745Sheppo 	}
969*1ae08745Sheppo 
970*1ae08745Sheppo 	RW_EXIT(&fdbhp->rwlock);
971*1ae08745Sheppo }
972*1ae08745Sheppo 
973*1ae08745Sheppo /* look up an fdb entry based on the mac address, caller holds lock */
974*1ae08745Sheppo static fdb_t *
975*1ae08745Sheppo vnet_lookup_fdb(fdb_fanout_t *fdbhp, uint8_t *macaddr)
976*1ae08745Sheppo {
977*1ae08745Sheppo 	fdb_t *fdbp = NULL;
978*1ae08745Sheppo 
979*1ae08745Sheppo 	for (fdbp = fdbhp->headp; fdbp != NULL; fdbp = fdbp->nextp) {
980*1ae08745Sheppo 		if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) {
981*1ae08745Sheppo 			break;
982*1ae08745Sheppo 		}
983*1ae08745Sheppo 	}
984*1ae08745Sheppo 
985*1ae08745Sheppo 	return (fdbp);
986*1ae08745Sheppo }
987*1ae08745Sheppo 
988*1ae08745Sheppo /* add default route entry into the forwarding database */
989*1ae08745Sheppo void
990*1ae08745Sheppo vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg)
991*1ae08745Sheppo {
992*1ae08745Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
993*1ae08745Sheppo 	fdb_t *fdbp;
994*1ae08745Sheppo 	fdb_fanout_t *fdbhp;
995*1ae08745Sheppo 
996*1ae08745Sheppo 	/*
997*1ae08745Sheppo 	 * The last hash list is reserved for default route entry,
998*1ae08745Sheppo 	 * and for now, we have only one entry in this list.
999*1ae08745Sheppo 	 */
1000*1ae08745Sheppo 	fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]);
1001*1ae08745Sheppo 
1002*1ae08745Sheppo 	WRITE_ENTER(&fdbhp->rwlock);
1003*1ae08745Sheppo 
1004*1ae08745Sheppo 	if (fdbhp->headp) {
1005*1ae08745Sheppo 		DWARN((vnetp,
1006*1ae08745Sheppo 		    "vnet_add_def_rte: default rte already exists\n"));
1007*1ae08745Sheppo 		RW_EXIT(&fdbhp->rwlock);
1008*1ae08745Sheppo 		return;
1009*1ae08745Sheppo 	}
1010*1ae08745Sheppo 	fdbp = kmem_zalloc(sizeof (fdb_t), KM_NOSLEEP);
1011*1ae08745Sheppo 	if (fdbp == NULL) {
1012*1ae08745Sheppo 		RW_EXIT(&fdbhp->rwlock);
1013*1ae08745Sheppo 		return;
1014*1ae08745Sheppo 	}
1015*1ae08745Sheppo 	bzero(fdbp->macaddr, ETHERADDRL);
1016*1ae08745Sheppo 	fdbp->m_tx = m_tx;
1017*1ae08745Sheppo 	fdbp->txarg = txarg;
1018*1ae08745Sheppo 	fdbp->nextp = NULL;
1019*1ae08745Sheppo 	fdbhp->headp = fdbp;
1020*1ae08745Sheppo 
1021*1ae08745Sheppo 	RW_EXIT(&fdbhp->rwlock);
1022*1ae08745Sheppo }
1023*1ae08745Sheppo 
1024*1ae08745Sheppo /* delete default route entry from the forwarding database */
1025*1ae08745Sheppo void
1026*1ae08745Sheppo vnet_del_def_rte(void *arg)
1027*1ae08745Sheppo {
1028*1ae08745Sheppo 	vnet_t *vnetp = (vnet_t *)arg;
1029*1ae08745Sheppo 	fdb_t *fdbp;
1030*1ae08745Sheppo 	fdb_fanout_t *fdbhp;
1031*1ae08745Sheppo 
1032*1ae08745Sheppo 	/*
1033*1ae08745Sheppo 	 * The last hash list is reserved for default route entry,
1034*1ae08745Sheppo 	 * and for now, we have only one entry in this list.
1035*1ae08745Sheppo 	 */
1036*1ae08745Sheppo 	fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]);
1037*1ae08745Sheppo 
1038*1ae08745Sheppo 	WRITE_ENTER(&fdbhp->rwlock);
1039*1ae08745Sheppo 
1040*1ae08745Sheppo 	if (fdbhp->headp == NULL) {
1041*1ae08745Sheppo 		RW_EXIT(&fdbhp->rwlock);
1042*1ae08745Sheppo 		return;
1043*1ae08745Sheppo 	}
1044*1ae08745Sheppo 	fdbp = fdbhp->headp;
1045*1ae08745Sheppo 	KMEM_FREE(fdbp);
1046*1ae08745Sheppo 	fdbhp->headp = NULL;
1047*1ae08745Sheppo 
1048*1ae08745Sheppo 	RW_EXIT(&fdbhp->rwlock);
1049*1ae08745Sheppo }
1050