xref: /titanic_44/usr/src/uts/sun4v/io/vsw_phys.c (revision 903a11ebdc8df157c4700150f41f1f262f4a8ae8)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/errno.h>
31 #include <sys/debug.h>
32 #include <sys/time.h>
33 #include <sys/sysmacros.h>
34 #include <sys/systm.h>
35 #include <sys/user.h>
36 #include <sys/stropts.h>
37 #include <sys/stream.h>
38 #include <sys/strlog.h>
39 #include <sys/strsubr.h>
40 #include <sys/cmn_err.h>
41 #include <sys/cpu.h>
42 #include <sys/kmem.h>
43 #include <sys/conf.h>
44 #include <sys/ddi.h>
45 #include <sys/sunddi.h>
46 #include <sys/ksynch.h>
47 #include <sys/stat.h>
48 #include <sys/kstat.h>
49 #include <sys/vtrace.h>
50 #include <sys/strsun.h>
51 #include <sys/dlpi.h>
52 #include <sys/ethernet.h>
53 #include <net/if.h>
54 #include <netinet/arp.h>
55 #include <inet/arp.h>
56 #include <sys/varargs.h>
57 #include <sys/machsystm.h>
58 #include <sys/modctl.h>
59 #include <sys/modhash.h>
60 #include <sys/mac.h>
61 #include <sys/mac_ether.h>
62 #include <sys/taskq.h>
63 #include <sys/note.h>
64 #include <sys/mach_descrip.h>
65 #include <sys/mac.h>
66 #include <sys/mdeg.h>
67 #include <sys/vsw.h>
68 
69 /* MAC Ring table functions. */
70 static void vsw_mac_ring_tbl_init(vsw_t *vswp);
71 static void vsw_mac_ring_tbl_destroy(vsw_t *vswp);
72 static void vsw_queue_worker(vsw_mac_ring_t *rrp);
73 static void vsw_queue_stop(vsw_queue_t *vqp);
74 static vsw_queue_t *vsw_queue_create();
75 static void vsw_queue_destroy(vsw_queue_t *vqp);
76 static void vsw_rx_queue_cb(void *, mac_resource_handle_t, mblk_t *);
77 static void vsw_rx_cb(void *, mac_resource_handle_t, mblk_t *);
78 
79 /* MAC layer routines */
80 static mac_resource_handle_t vsw_mac_ring_add_cb(void *arg,
81 		mac_resource_t *mrp);
82 static	int vsw_set_hw_addr(vsw_t *, mac_multi_addr_t *);
83 static	int vsw_set_hw_promisc(vsw_t *, vsw_port_t *, int);
84 static	int vsw_unset_hw_addr(vsw_t *, int);
85 static	int vsw_unset_hw_promisc(vsw_t *, vsw_port_t *, int);
86 static int vsw_prog_if(vsw_t *);
87 
88 /* Support functions */
89 static int vsw_prog_ports(vsw_t *);
90 int vsw_set_hw(vsw_t *, vsw_port_t *, int);
91 int vsw_unset_hw(vsw_t *, vsw_port_t *, int);
92 void vsw_reconfig_hw(vsw_t *);
93 int vsw_mac_attach(vsw_t *vswp);
94 void vsw_mac_detach(vsw_t *vswp);
95 int vsw_mac_open(vsw_t *vswp);
96 void vsw_mac_close(vsw_t *vswp);
97 void vsw_unset_addrs(vsw_t *vswp);
98 void vsw_set_addrs(vsw_t *vswp);
99 int vsw_get_hw_maddr(vsw_t *);
100 mblk_t *vsw_tx_msg(vsw_t *, mblk_t *);
101 void vsw_publish_macaddr(vsw_t *vswp, uint8_t *addr);
102 
103 /*
104  * Tunables used in this file.
105  */
106 extern int vsw_mac_open_retries;
107 extern boolean_t vsw_multi_ring_enable;
108 extern int vsw_mac_rx_rings;
109 extern uint32_t vsw_publish_macaddr_count;
110 
111 /*
112  * Check to see if the card supports the setting of multiple unicst
113  * addresses.
114  *
115  * Returns 0 if card supports the programming of multiple unicast addresses,
116  * otherwise returns 1.
117  */
118 int
119 vsw_get_hw_maddr(vsw_t *vswp)
120 {
121 	D1(vswp, "%s: enter", __func__);
122 
123 	ASSERT(RW_LOCK_HELD(&vswp->mac_rwlock));
124 
125 	if (vswp->mh == NULL)
126 		return (1);
127 
128 	if (!mac_capab_get(vswp->mh, MAC_CAPAB_MULTIADDRESS, &vswp->maddr)) {
129 		cmn_err(CE_NOTE, "!vsw%d: device (%s) does not support "
130 		    "programming multiple addresses", vswp->instance,
131 		    vswp->physname);
132 		return (1);
133 	}
134 
135 	D2(vswp, "%s: %d addrs : %d free", __func__,
136 	    vswp->maddr.maddr_naddr, vswp->maddr.maddr_naddrfree);
137 
138 	D1(vswp, "%s: exit", __func__);
139 
140 	return (0);
141 }
142 
143 /*
144  * Program unicast and multicast addresses of vsw interface and the ports
145  * into the physical device.
146  */
147 void
148 vsw_set_addrs(vsw_t *vswp)
149 {
150 	vsw_port_list_t	*plist = &vswp->plist;
151 	vsw_port_t	*port;
152 	mcst_addr_t	*mcap;
153 	int		rv;
154 
155 	READ_ENTER(&vswp->if_lockrw);
156 
157 	if (vswp->if_state & VSW_IF_UP) {
158 
159 		/* program unicst addr of vsw interface in the physdev */
160 		if (vswp->addr_set == VSW_ADDR_UNSET) {
161 			mutex_enter(&vswp->hw_lock);
162 			rv = vsw_set_hw(vswp, NULL, VSW_LOCALDEV);
163 			mutex_exit(&vswp->hw_lock);
164 			if (rv != 0) {
165 				cmn_err(CE_NOTE,
166 				    "!vsw%d: failed to program interface "
167 				    "unicast address\n", vswp->instance);
168 			}
169 			/*
170 			 * Notify the MAC layer of the changed address.
171 			 */
172 			mac_unicst_update(vswp->if_mh,
173 			    (uint8_t *)&vswp->if_addr);
174 		}
175 
176 		/* program mcast addrs of vsw interface in the physdev */
177 		mutex_enter(&vswp->mca_lock);
178 		WRITE_ENTER(&vswp->mac_rwlock);
179 		for (mcap = vswp->mcap; mcap != NULL; mcap = mcap->nextp) {
180 			if (mcap->mac_added)
181 				continue;
182 			rv = mac_multicst_add(vswp->mh, (uchar_t *)&mcap->mca);
183 			if (rv == 0) {
184 				mcap->mac_added = B_TRUE;
185 			} else {
186 				cmn_err(CE_NOTE, "!vsw%d: unable to add "
187 				    "multicast address: %s\n", vswp->instance,
188 				    ether_sprintf((void *)&mcap->mca));
189 			}
190 		}
191 		RW_EXIT(&vswp->mac_rwlock);
192 		mutex_exit(&vswp->mca_lock);
193 
194 	}
195 
196 	RW_EXIT(&vswp->if_lockrw);
197 
198 	WRITE_ENTER(&plist->lockrw);
199 
200 	/* program unicast address of ports in the physical device */
201 	mutex_enter(&vswp->hw_lock);
202 	for (port = plist->head; port != NULL; port = port->p_next) {
203 		if (port->addr_set != VSW_ADDR_UNSET) /* addr already set */
204 			continue;
205 		if (vsw_set_hw(vswp, port, VSW_VNETPORT)) {
206 			cmn_err(CE_NOTE,
207 			    "!vsw%d: port:%d failed to set unicast address\n",
208 			    vswp->instance, port->p_instance);
209 		}
210 	}
211 	mutex_exit(&vswp->hw_lock);
212 
213 	/* program multicast addresses of ports in the physdev */
214 	for (port = plist->head; port != NULL; port = port->p_next) {
215 		mutex_enter(&port->mca_lock);
216 		WRITE_ENTER(&vswp->mac_rwlock);
217 		for (mcap = port->mcap; mcap != NULL; mcap = mcap->nextp) {
218 			if (mcap->mac_added)
219 				continue;
220 			rv = mac_multicst_add(vswp->mh, (uchar_t *)&mcap->mca);
221 			if (rv == 0) {
222 				mcap->mac_added = B_TRUE;
223 			} else {
224 				cmn_err(CE_NOTE, "!vsw%d: unable to add "
225 				    "multicast address: %s\n", vswp->instance,
226 				    ether_sprintf((void *)&mcap->mca));
227 			}
228 		}
229 		RW_EXIT(&vswp->mac_rwlock);
230 		mutex_exit(&port->mca_lock);
231 	}
232 
233 	/* announce macaddr of vnets to the physical switch */
234 	if (vsw_publish_macaddr_count != 0) {	/* enabled */
235 		for (port = plist->head; port != NULL; port = port->p_next) {
236 			vsw_publish_macaddr(vswp, (uint8_t *)&port->p_macaddr);
237 		}
238 	}
239 
240 	RW_EXIT(&plist->lockrw);
241 }
242 
243 /*
244  * Remove unicast and multicast addresses of vsw interface and the ports
245  * from the physical device.
246  */
247 void
248 vsw_unset_addrs(vsw_t *vswp)
249 {
250 	vsw_port_list_t	*plist = &vswp->plist;
251 	vsw_port_t	*port;
252 	mcst_addr_t	*mcap;
253 
254 	READ_ENTER(&vswp->if_lockrw);
255 
256 	if (vswp->if_state & VSW_IF_UP) {
257 
258 		/*
259 		 * Remove unicast addr of vsw interfce
260 		 * from current physdev
261 		 */
262 		mutex_enter(&vswp->hw_lock);
263 		(void) vsw_unset_hw(vswp, NULL, VSW_LOCALDEV);
264 		mutex_exit(&vswp->hw_lock);
265 
266 		/*
267 		 * Remove mcast addrs of vsw interface
268 		 * from current physdev
269 		 */
270 		mutex_enter(&vswp->mca_lock);
271 		WRITE_ENTER(&vswp->mac_rwlock);
272 		for (mcap = vswp->mcap; mcap != NULL; mcap = mcap->nextp) {
273 			if (!mcap->mac_added)
274 				continue;
275 			(void) mac_multicst_remove(vswp->mh,
276 			    (uchar_t *)&mcap->mca);
277 			mcap->mac_added = B_FALSE;
278 		}
279 		RW_EXIT(&vswp->mac_rwlock);
280 		mutex_exit(&vswp->mca_lock);
281 
282 	}
283 
284 	RW_EXIT(&vswp->if_lockrw);
285 
286 	WRITE_ENTER(&plist->lockrw);
287 
288 	/*
289 	 * Remove unicast address of ports from the current physical device
290 	 */
291 	mutex_enter(&vswp->hw_lock);
292 	for (port = plist->head; port != NULL; port = port->p_next) {
293 		/* Remove address if was programmed into HW. */
294 		if (port->addr_set == VSW_ADDR_UNSET)
295 			continue;
296 		(void) vsw_unset_hw(vswp, port, VSW_VNETPORT);
297 	}
298 	mutex_exit(&vswp->hw_lock);
299 
300 	/* Remove multicast addresses of ports from the current physdev */
301 	for (port = plist->head; port != NULL; port = port->p_next) {
302 		mutex_enter(&port->mca_lock);
303 		WRITE_ENTER(&vswp->mac_rwlock);
304 		for (mcap = port->mcap; mcap != NULL; mcap = mcap->nextp) {
305 			if (!mcap->mac_added)
306 				continue;
307 			(void) mac_multicst_remove(vswp->mh,
308 			    (uchar_t *)&mcap->mca);
309 			mcap->mac_added = B_FALSE;
310 		}
311 		RW_EXIT(&vswp->mac_rwlock);
312 		mutex_exit(&port->mca_lock);
313 	}
314 
315 	RW_EXIT(&plist->lockrw);
316 }
317 
318 /*
319  * Open the underlying physical device for access in layer2 mode.
320  * Returns:
321  * 0 on success
322  * EAGAIN if mac_open() fails due to the device being not available yet.
323  * EIO on any other failures.
324  */
325 int
326 vsw_mac_open(vsw_t *vswp)
327 {
328 	int	rv;
329 
330 	ASSERT(RW_LOCK_HELD(&vswp->mac_rwlock));
331 
332 	if (vswp->mh != NULL) {
333 		/* already open */
334 		return (0);
335 	}
336 
337 	if (vswp->mac_open_retries++ >= vsw_mac_open_retries) {
338 		/* exceeded max retries */
339 		return (EIO);
340 	}
341 
342 	if ((rv = mac_open_by_linkname(vswp->physname, &vswp->mh)) != 0) {
343 		/*
344 		 * If mac_open() failed and the error indicates that either
345 		 * the dlmgmtd door or the device is not available yet, we
346 		 * return EAGAIN to indicate that mac_open() needs to be
347 		 * retried. For example, this may happen during boot up, if
348 		 * the required link aggregation groups(devices) have not
349 		 * been created yet.
350 		 */
351 		if (rv == ENOENT || rv == EBADF) {
352 			return (EAGAIN);
353 		} else {
354 			cmn_err(CE_WARN, "vsw%d: device (%s) open failed rv:%x",
355 			    vswp->instance, vswp->physname, rv);
356 			return (EIO);
357 		}
358 	}
359 
360 	vswp->mac_open_retries = 0;
361 
362 	return (0);
363 }
364 
365 /*
366  * Close the underlying physical device.
367  */
368 void
369 vsw_mac_close(vsw_t *vswp)
370 {
371 	ASSERT(RW_LOCK_HELD(&vswp->mac_rwlock));
372 
373 	if (vswp->mh != NULL) {
374 		mac_close(vswp->mh);
375 		vswp->mh = NULL;
376 	}
377 }
378 
379 /*
380  * Link into the MAC layer to gain access to the services provided by
381  * the underlying physical device driver (which should also have
382  * registered with the MAC layer).
383  *
384  * Only when in layer 2 mode.
385  */
386 int
387 vsw_mac_attach(vsw_t *vswp)
388 {
389 	D1(vswp, "%s: enter", __func__);
390 
391 	ASSERT(vswp->mrh == NULL);
392 	ASSERT(vswp->mstarted == B_FALSE);
393 	ASSERT(vswp->mresources == B_FALSE);
394 
395 	ASSERT(RW_LOCK_HELD(&vswp->mac_rwlock));
396 
397 	ASSERT(vswp->mh != NULL);
398 
399 	D2(vswp, "vsw_mac_attach: using device %s", vswp->physname);
400 
401 	if (vsw_multi_ring_enable) {
402 		/*
403 		 * Initialize the ring table.
404 		 */
405 		vsw_mac_ring_tbl_init(vswp);
406 
407 		/*
408 		 * Register our rx callback function.
409 		 */
410 		vswp->mrh = mac_rx_add(vswp->mh,
411 		    vsw_rx_queue_cb, (void *)vswp);
412 		ASSERT(vswp->mrh != NULL);
413 
414 		/*
415 		 * Register our mac resource callback.
416 		 */
417 		mac_resource_set(vswp->mh, vsw_mac_ring_add_cb, (void *)vswp);
418 		vswp->mresources = B_TRUE;
419 
420 		/*
421 		 * Get the ring resources available to us from
422 		 * the mac below us.
423 		 */
424 		mac_resources(vswp->mh);
425 	} else {
426 		/*
427 		 * Just register our rx callback function
428 		 */
429 		vswp->mrh = mac_rx_add(vswp->mh, vsw_rx_cb, (void *)vswp);
430 		ASSERT(vswp->mrh != NULL);
431 	}
432 
433 	/* Get the MAC tx fn */
434 	vswp->txinfo = mac_tx_get(vswp->mh);
435 
436 	/* start the interface */
437 	if (mac_start(vswp->mh) != 0) {
438 		cmn_err(CE_WARN, "!vsw%d: Could not start mac interface",
439 		    vswp->instance);
440 		goto mac_fail_exit;
441 	}
442 
443 	vswp->mstarted = B_TRUE;
444 
445 	D1(vswp, "%s: exit", __func__);
446 	return (0);
447 
448 mac_fail_exit:
449 	vsw_mac_detach(vswp);
450 
451 	D1(vswp, "%s: exit", __func__);
452 	return (1);
453 }
454 
455 void
456 vsw_mac_detach(vsw_t *vswp)
457 {
458 	D1(vswp, "vsw_mac_detach: enter");
459 
460 	ASSERT(vswp != NULL);
461 	ASSERT(RW_LOCK_HELD(&vswp->mac_rwlock));
462 
463 	if (vsw_multi_ring_enable) {
464 		vsw_mac_ring_tbl_destroy(vswp);
465 	}
466 
467 	if (vswp->mh != NULL) {
468 		if (vswp->mstarted)
469 			mac_stop(vswp->mh);
470 		if (vswp->mrh != NULL)
471 			mac_rx_remove(vswp->mh, vswp->mrh, B_TRUE);
472 		if (vswp->mresources)
473 			mac_resource_set(vswp->mh, NULL, NULL);
474 	}
475 
476 	vswp->mrh = NULL;
477 	vswp->txinfo = NULL;
478 	vswp->mstarted = B_FALSE;
479 
480 	D1(vswp, "vsw_mac_detach: exit");
481 }
482 
483 /*
484  * Depending on the mode specified, the capabilites and capacity
485  * of the underlying device setup the physical device.
486  *
487  * If in layer 3 mode, then do nothing.
488  *
489  * If in layer 2 programmed mode attempt to program the unicast address
490  * associated with the port into the physical device. If this is not
491  * possible due to resource exhaustion or simply because the device does
492  * not support multiple unicast addresses then if required fallback onto
493  * putting the card into promisc mode.
494  *
495  * If in promisc mode then simply set the card into promisc mode.
496  *
497  * Returns 0 success, 1 on failure.
498  */
499 int
500 vsw_set_hw(vsw_t *vswp, vsw_port_t *port, int type)
501 {
502 	mac_multi_addr_t	mac_addr;
503 	int			err;
504 
505 	D1(vswp, "%s: enter", __func__);
506 
507 	ASSERT(MUTEX_HELD(&vswp->hw_lock));
508 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
509 
510 	if (vswp->smode[vswp->smode_idx] == VSW_LAYER3)
511 		return (0);
512 
513 	if (vswp->smode[vswp->smode_idx] == VSW_LAYER2_PROMISC) {
514 		return (vsw_set_hw_promisc(vswp, port, type));
515 	}
516 
517 	/*
518 	 * Attempt to program the unicast address into the HW.
519 	 */
520 	mac_addr.mma_addrlen = ETHERADDRL;
521 	if (type == VSW_VNETPORT) {
522 		ASSERT(port != NULL);
523 		ether_copy(&port->p_macaddr, &mac_addr.mma_addr);
524 	} else {
525 		ether_copy(&vswp->if_addr, &mac_addr.mma_addr);
526 	}
527 
528 	err = vsw_set_hw_addr(vswp, &mac_addr);
529 	if (err == ENOSPC) {
530 		/*
531 		 * Mark that attempt should be made to re-config sometime
532 		 * in future if a port is deleted.
533 		 */
534 		vswp->recfg_reqd = B_TRUE;
535 
536 		/*
537 		 * Only 1 mode specified, nothing more to do.
538 		 */
539 		if (vswp->smode_num == 1)
540 			return (err);
541 
542 		/*
543 		 * If promiscuous was next mode specified try to
544 		 * set the card into that mode.
545 		 */
546 		if ((vswp->smode_idx <= (vswp->smode_num - 2)) &&
547 		    (vswp->smode[vswp->smode_idx + 1] ==
548 		    VSW_LAYER2_PROMISC)) {
549 			vswp->smode_idx += 1;
550 			return (vsw_set_hw_promisc(vswp, port, type));
551 		}
552 		return (err);
553 	}
554 
555 	if (err != 0)
556 		return (err);
557 
558 	if (type == VSW_VNETPORT) {
559 		port->addr_slot = mac_addr.mma_slot;
560 		port->addr_set = VSW_ADDR_HW;
561 	} else {
562 		vswp->addr_slot = mac_addr.mma_slot;
563 		vswp->addr_set = VSW_ADDR_HW;
564 	}
565 
566 	D2(vswp, "programmed addr %s into slot %d "
567 	"of device %s", ether_sprintf((void *)mac_addr.mma_addr),
568 	    mac_addr.mma_slot, vswp->physname);
569 
570 	D1(vswp, "%s: exit", __func__);
571 
572 	return (0);
573 }
574 
575 /*
576  * If in layer 3 mode do nothing.
577  *
578  * If in layer 2 switched mode remove the address from the physical
579  * device.
580  *
581  * If in layer 2 promiscuous mode disable promisc mode.
582  *
583  * Returns 0 on success.
584  */
585 int
586 vsw_unset_hw(vsw_t *vswp, vsw_port_t *port, int type)
587 {
588 	mac_addr_slot_t	slot;
589 	int		rv;
590 
591 	D1(vswp, "%s: enter", __func__);
592 
593 	ASSERT(MUTEX_HELD(&vswp->hw_lock));
594 
595 	if (vswp->smode[vswp->smode_idx] == VSW_LAYER3)
596 		return (0);
597 
598 	switch (type) {
599 	case VSW_VNETPORT:
600 		ASSERT(port != NULL);
601 
602 		if (port->addr_set == VSW_ADDR_PROMISC) {
603 			return (vsw_unset_hw_promisc(vswp, port, type));
604 
605 		} else if (port->addr_set == VSW_ADDR_HW) {
606 			slot = port->addr_slot;
607 			if ((rv = vsw_unset_hw_addr(vswp, slot)) == 0)
608 				port->addr_set = VSW_ADDR_UNSET;
609 		}
610 
611 		break;
612 
613 	case VSW_LOCALDEV:
614 		if (vswp->addr_set == VSW_ADDR_PROMISC) {
615 			return (vsw_unset_hw_promisc(vswp, NULL, type));
616 
617 		} else if (vswp->addr_set == VSW_ADDR_HW) {
618 			slot = vswp->addr_slot;
619 			if ((rv = vsw_unset_hw_addr(vswp, slot)) == 0)
620 				vswp->addr_set = VSW_ADDR_UNSET;
621 		}
622 
623 		break;
624 
625 	default:
626 		/* should never happen */
627 		DERR(vswp, "%s: unknown type %d", __func__, type);
628 		ASSERT(0);
629 		return (1);
630 	}
631 
632 	D1(vswp, "%s: exit", __func__);
633 	return (rv);
634 }
635 
636 /*
637  * Attempt to program a unicast address into HW.
638  *
639  * Returns 0 on sucess, 1 on failure.
640  */
641 static int
642 vsw_set_hw_addr(vsw_t *vswp, mac_multi_addr_t *mac)
643 {
644 	void	*mah;
645 	int	rv = EINVAL;
646 
647 	D1(vswp, "%s: enter", __func__);
648 
649 	ASSERT(MUTEX_HELD(&vswp->hw_lock));
650 
651 	if (vswp->maddr.maddr_handle == NULL)
652 		return (rv);
653 
654 	mah = vswp->maddr.maddr_handle;
655 
656 	rv = vswp->maddr.maddr_add(mah, mac);
657 
658 	if (rv == 0)
659 		return (rv);
660 
661 	/*
662 	 * Its okay for the add to fail because we have exhausted
663 	 * all the resouces in the hardware device. Any other error
664 	 * we want to flag.
665 	 */
666 	if (rv != ENOSPC) {
667 		cmn_err(CE_NOTE, "!vsw%d: error programming "
668 		    "address %s into HW err (%d)",
669 		    vswp->instance, ether_sprintf((void *)mac->mma_addr), rv);
670 	}
671 	D1(vswp, "%s: exit", __func__);
672 	return (rv);
673 }
674 
675 /*
676  * Remove a unicast mac address which has previously been programmed
677  * into HW.
678  *
679  * Returns 0 on sucess, 1 on failure.
680  */
681 static int
682 vsw_unset_hw_addr(vsw_t *vswp, int slot)
683 {
684 	void	*mah;
685 	int	rv;
686 
687 	D1(vswp, "%s: enter", __func__);
688 
689 	ASSERT(MUTEX_HELD(&vswp->hw_lock));
690 	ASSERT(slot >= 0);
691 
692 	if (vswp->maddr.maddr_handle == NULL)
693 		return (1);
694 
695 	mah = vswp->maddr.maddr_handle;
696 
697 	rv = vswp->maddr.maddr_remove(mah, slot);
698 	if (rv != 0) {
699 		DWARN(vswp, "%s: unable to remove address "
700 		    "from slot %d in device %s (err %d)",
701 		    __func__, slot, vswp->physname, rv);
702 		return (1);
703 	}
704 
705 	D2(vswp, "removed addr from slot %d in device %s",
706 	    slot, vswp->physname);
707 
708 	D1(vswp, "%s: exit", __func__);
709 	return (0);
710 }
711 
712 /*
713  * Set network card into promisc mode.
714  *
715  * Returns 0 on success, 1 on failure.
716  */
717 static int
718 vsw_set_hw_promisc(vsw_t *vswp, vsw_port_t *port, int type)
719 {
720 	D1(vswp, "%s: enter", __func__);
721 
722 	ASSERT(MUTEX_HELD(&vswp->hw_lock));
723 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
724 
725 	WRITE_ENTER(&vswp->mac_rwlock);
726 	if (vswp->mh == NULL) {
727 		RW_EXIT(&vswp->mac_rwlock);
728 		return (1);
729 	}
730 
731 	if (vswp->promisc_cnt++ == 0) {
732 		if (mac_promisc_set(vswp->mh, B_TRUE, MAC_DEVPROMISC) != 0) {
733 			vswp->promisc_cnt--;
734 			RW_EXIT(&vswp->mac_rwlock);
735 			return (1);
736 		}
737 		cmn_err(CE_NOTE, "!vsw%d: switching device %s into "
738 		    "promiscuous mode", vswp->instance, vswp->physname);
739 	}
740 	RW_EXIT(&vswp->mac_rwlock);
741 
742 	if (type == VSW_VNETPORT) {
743 		ASSERT(port != NULL);
744 		port->addr_set = VSW_ADDR_PROMISC;
745 	} else {
746 		vswp->addr_set = VSW_ADDR_PROMISC;
747 	}
748 
749 	D1(vswp, "%s: exit", __func__);
750 
751 	return (0);
752 }
753 
754 /*
755  * Turn off promiscuous mode on network card.
756  *
757  * Returns 0 on success, 1 on failure.
758  */
759 static int
760 vsw_unset_hw_promisc(vsw_t *vswp, vsw_port_t *port, int type)
761 {
762 	vsw_port_list_t 	*plist = &vswp->plist;
763 
764 	D2(vswp, "%s: enter", __func__);
765 
766 	ASSERT(MUTEX_HELD(&vswp->hw_lock));
767 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
768 
769 	WRITE_ENTER(&vswp->mac_rwlock);
770 	if (vswp->mh == NULL) {
771 		RW_EXIT(&vswp->mac_rwlock);
772 		return (1);
773 	}
774 
775 	if (--vswp->promisc_cnt == 0) {
776 		if (mac_promisc_set(vswp->mh, B_FALSE, MAC_DEVPROMISC) != 0) {
777 			vswp->promisc_cnt++;
778 			RW_EXIT(&vswp->mac_rwlock);
779 			return (1);
780 		}
781 
782 		/*
783 		 * We are exiting promisc mode either because we were
784 		 * only in promisc mode because we had failed over from
785 		 * switched mode due to HW resource issues, or the user
786 		 * wanted the card in promisc mode for all the ports and
787 		 * the last port is now being deleted. Tweak the message
788 		 * accordingly.
789 		 */
790 		if (plist->num_ports != 0) {
791 			cmn_err(CE_NOTE, "!vsw%d: switching device %s back to "
792 			    "programmed mode", vswp->instance, vswp->physname);
793 		} else {
794 			cmn_err(CE_NOTE, "!vsw%d: switching device %s out of "
795 			    "promiscuous mode", vswp->instance, vswp->physname);
796 		}
797 	}
798 	RW_EXIT(&vswp->mac_rwlock);
799 
800 	if (type == VSW_VNETPORT) {
801 		ASSERT(port != NULL);
802 		ASSERT(port->addr_set == VSW_ADDR_PROMISC);
803 		port->addr_set = VSW_ADDR_UNSET;
804 	} else {
805 		ASSERT(vswp->addr_set == VSW_ADDR_PROMISC);
806 		vswp->addr_set = VSW_ADDR_UNSET;
807 	}
808 
809 	D1(vswp, "%s: exit", __func__);
810 	return (0);
811 }
812 
813 /*
814  * Determine whether or not we are operating in our prefered
815  * mode and if not whether the physical resources now allow us
816  * to operate in it.
817  *
818  * If a port is being removed should only be invoked after port has been
819  * removed from the port list.
820  */
821 void
822 vsw_reconfig_hw(vsw_t *vswp)
823 {
824 	int			s_idx;
825 
826 	D1(vswp, "%s: enter", __func__);
827 
828 	ASSERT(MUTEX_HELD(&vswp->hw_lock));
829 
830 	if (vswp->maddr.maddr_handle == NULL) {
831 		return;
832 	}
833 
834 	/*
835 	 * If we are in layer 2 (i.e. switched) or would like to be
836 	 * in layer 2 then check if any ports or the vswitch itself
837 	 * need to be programmed into the HW.
838 	 *
839 	 * This can happen in two cases - switched was specified as
840 	 * the prefered mode of operation but we exhausted the HW
841 	 * resources and so failed over to the next specifed mode,
842 	 * or switched was the only mode specified so after HW
843 	 * resources were exhausted there was nothing more we
844 	 * could do.
845 	 */
846 	if (vswp->smode_idx > 0)
847 		s_idx = vswp->smode_idx - 1;
848 	else
849 		s_idx = vswp->smode_idx;
850 
851 	if (vswp->smode[s_idx] != VSW_LAYER2) {
852 		return;
853 	}
854 
855 	D2(vswp, "%s: attempting reconfig..", __func__);
856 
857 	/*
858 	 * First, attempt to set the vswitch mac address into HW,
859 	 * if required.
860 	 */
861 	if (vsw_prog_if(vswp)) {
862 		return;
863 	}
864 
865 	/*
866 	 * Next, attempt to set any ports which have not yet been
867 	 * programmed into HW.
868 	 */
869 	if (vsw_prog_ports(vswp)) {
870 		return;
871 	}
872 
873 	/*
874 	 * By now we know that have programmed all desired ports etc
875 	 * into HW, so safe to mark reconfiguration as complete.
876 	 */
877 	vswp->recfg_reqd = B_FALSE;
878 
879 	vswp->smode_idx = s_idx;
880 
881 	D1(vswp, "%s: exit", __func__);
882 }
883 
884 /*
885  * Check to see if vsw itself is plumbed, and if so whether or not
886  * its mac address should be written into HW.
887  *
888  * Returns 0 if could set address, or didn't have to set it.
889  * Returns 1 if failed to set address.
890  */
891 static int
892 vsw_prog_if(vsw_t *vswp)
893 {
894 	mac_multi_addr_t	addr;
895 
896 	D1(vswp, "%s: enter", __func__);
897 
898 	ASSERT(MUTEX_HELD(&vswp->hw_lock));
899 
900 	READ_ENTER(&vswp->if_lockrw);
901 	if ((vswp->if_state & VSW_IF_UP) &&
902 	    (vswp->addr_set != VSW_ADDR_HW)) {
903 
904 		addr.mma_addrlen = ETHERADDRL;
905 		ether_copy(&vswp->if_addr, &addr.mma_addr);
906 
907 		if (vsw_set_hw_addr(vswp, &addr) != 0) {
908 			RW_EXIT(&vswp->if_lockrw);
909 			return (1);
910 		}
911 
912 		vswp->addr_slot = addr.mma_slot;
913 
914 		/*
915 		 * If previously when plumbed had had to place
916 		 * interface into promisc mode, now reverse that.
917 		 *
918 		 * Note that interface will only actually be set into
919 		 * non-promisc mode when last port/interface has been
920 		 * programmed into HW.
921 		 */
922 		if (vswp->addr_set == VSW_ADDR_PROMISC)
923 			(void) vsw_unset_hw_promisc(vswp, NULL, VSW_LOCALDEV);
924 
925 		vswp->addr_set = VSW_ADDR_HW;
926 	}
927 	RW_EXIT(&vswp->if_lockrw);
928 
929 	D1(vswp, "%s: exit", __func__);
930 	return (0);
931 }
932 
933 /*
934  * Scan the port list for any ports which have not yet been set
935  * into HW. For those found attempt to program their mac addresses
936  * into the physical device.
937  *
938  * Returns 0 if able to program all required ports (can be 0) into HW.
939  * Returns 1 if failed to set at least one mac address.
940  */
941 static int
942 vsw_prog_ports(vsw_t *vswp)
943 {
944 	mac_multi_addr_t	addr;
945 	vsw_port_list_t		*plist = &vswp->plist;
946 	vsw_port_t		*tp;
947 	int			rv = 0;
948 
949 	D1(vswp, "%s: enter", __func__);
950 
951 	ASSERT(MUTEX_HELD(&vswp->hw_lock));
952 
953 	READ_ENTER(&plist->lockrw);
954 	for (tp = plist->head; tp != NULL; tp = tp->p_next) {
955 		if (tp->addr_set != VSW_ADDR_HW) {
956 			addr.mma_addrlen = ETHERADDRL;
957 			ether_copy(&tp->p_macaddr, &addr.mma_addr);
958 
959 			if (vsw_set_hw_addr(vswp, &addr) != 0) {
960 				rv = 1;
961 				break;
962 			}
963 
964 			tp->addr_slot = addr.mma_slot;
965 
966 			/*
967 			 * If when this port had first attached we had
968 			 * had to place the interface into promisc mode,
969 			 * then now reverse that.
970 			 *
971 			 * Note that the interface will not actually
972 			 * change to non-promisc mode until all ports
973 			 * have been programmed.
974 			 */
975 			if (tp->addr_set == VSW_ADDR_PROMISC)
976 				(void) vsw_unset_hw_promisc(vswp,
977 				    tp, VSW_VNETPORT);
978 
979 			tp->addr_set = VSW_ADDR_HW;
980 		}
981 	}
982 	RW_EXIT(&plist->lockrw);
983 
984 	D1(vswp, "%s: exit", __func__);
985 	return (rv);
986 }
987 
988 static void
989 vsw_mac_ring_tbl_entry_init(vsw_t *vswp, vsw_mac_ring_t *ringp)
990 {
991 	ringp->ring_state = VSW_MAC_RING_FREE;
992 	ringp->ring_arg = NULL;
993 	ringp->ring_blank = NULL;
994 	ringp->ring_vqp = NULL;
995 	ringp->ring_vswp = vswp;
996 }
997 
998 static void
999 vsw_mac_ring_tbl_init(vsw_t *vswp)
1000 {
1001 	int		i;
1002 
1003 	mutex_init(&vswp->mac_ring_lock, NULL, MUTEX_DRIVER, NULL);
1004 
1005 	vswp->mac_ring_tbl_sz = vsw_mac_rx_rings;
1006 	vswp->mac_ring_tbl  =
1007 	    kmem_alloc(vsw_mac_rx_rings * sizeof (vsw_mac_ring_t), KM_SLEEP);
1008 
1009 	for (i = 0; i < vswp->mac_ring_tbl_sz; i++)
1010 		vsw_mac_ring_tbl_entry_init(vswp, &vswp->mac_ring_tbl[i]);
1011 }
1012 
1013 static void
1014 vsw_mac_ring_tbl_destroy(vsw_t *vswp)
1015 {
1016 	int		i;
1017 	vsw_mac_ring_t	*ringp;
1018 
1019 	mutex_enter(&vswp->mac_ring_lock);
1020 	for (i = 0; i < vswp->mac_ring_tbl_sz; i++) {
1021 		ringp = &vswp->mac_ring_tbl[i];
1022 
1023 		if (ringp->ring_state != VSW_MAC_RING_FREE) {
1024 			/*
1025 			 * Destroy the queue.
1026 			 */
1027 			vsw_queue_stop(ringp->ring_vqp);
1028 			vsw_queue_destroy(ringp->ring_vqp);
1029 
1030 			/*
1031 			 * Re-initialize the structure.
1032 			 */
1033 			vsw_mac_ring_tbl_entry_init(vswp, ringp);
1034 		}
1035 	}
1036 	mutex_exit(&vswp->mac_ring_lock);
1037 
1038 	mutex_destroy(&vswp->mac_ring_lock);
1039 	kmem_free(vswp->mac_ring_tbl,
1040 	    vswp->mac_ring_tbl_sz * sizeof (vsw_mac_ring_t));
1041 	vswp->mac_ring_tbl_sz = 0;
1042 }
1043 
1044 /*
1045  * Handle resource add callbacks from the driver below.
1046  */
1047 static mac_resource_handle_t
1048 vsw_mac_ring_add_cb(void *arg, mac_resource_t *mrp)
1049 {
1050 	vsw_t		*vswp = (vsw_t *)arg;
1051 	mac_rx_fifo_t	*mrfp = (mac_rx_fifo_t *)mrp;
1052 	vsw_mac_ring_t	*ringp;
1053 	vsw_queue_t	*vqp;
1054 	int		i;
1055 
1056 	ASSERT(vswp != NULL);
1057 	ASSERT(mrp != NULL);
1058 	ASSERT(vswp->mac_ring_tbl != NULL);
1059 
1060 	D1(vswp, "%s: enter", __func__);
1061 
1062 	/*
1063 	 * Check to make sure we have the correct resource type.
1064 	 */
1065 	if (mrp->mr_type != MAC_RX_FIFO)
1066 		return (NULL);
1067 
1068 	/*
1069 	 * Find a open entry in the ring table.
1070 	 */
1071 	mutex_enter(&vswp->mac_ring_lock);
1072 	for (i = 0; i < vswp->mac_ring_tbl_sz; i++) {
1073 		ringp = &vswp->mac_ring_tbl[i];
1074 
1075 		/*
1076 		 * Check for an empty slot, if found, then setup queue
1077 		 * and thread.
1078 		 */
1079 		if (ringp->ring_state == VSW_MAC_RING_FREE) {
1080 			/*
1081 			 * Create the queue for this ring.
1082 			 */
1083 			vqp = vsw_queue_create();
1084 
1085 			/*
1086 			 * Initialize the ring data structure.
1087 			 */
1088 			ringp->ring_vqp = vqp;
1089 			ringp->ring_arg = mrfp->mrf_arg;
1090 			ringp->ring_blank = mrfp->mrf_blank;
1091 			ringp->ring_state = VSW_MAC_RING_INUSE;
1092 
1093 			/*
1094 			 * Create the worker thread.
1095 			 */
1096 			vqp->vq_worker = thread_create(NULL, 0,
1097 			    vsw_queue_worker, ringp, 0, &p0,
1098 			    TS_RUN, minclsyspri);
1099 			if (vqp->vq_worker == NULL) {
1100 				vsw_queue_destroy(vqp);
1101 				vsw_mac_ring_tbl_entry_init(vswp, ringp);
1102 				ringp = NULL;
1103 			}
1104 
1105 			if (ringp != NULL) {
1106 				/*
1107 				 * Make sure thread get's running state for
1108 				 * this ring.
1109 				 */
1110 				mutex_enter(&vqp->vq_lock);
1111 				while ((vqp->vq_state != VSW_QUEUE_RUNNING) &&
1112 				    (vqp->vq_state != VSW_QUEUE_DRAINED)) {
1113 					cv_wait(&vqp->vq_cv, &vqp->vq_lock);
1114 				}
1115 
1116 				/*
1117 				 * If the thread is not running, cleanup.
1118 				 */
1119 				if (vqp->vq_state == VSW_QUEUE_DRAINED) {
1120 					vsw_queue_destroy(vqp);
1121 					vsw_mac_ring_tbl_entry_init(vswp,
1122 					    ringp);
1123 					ringp = NULL;
1124 				}
1125 				mutex_exit(&vqp->vq_lock);
1126 			}
1127 
1128 			mutex_exit(&vswp->mac_ring_lock);
1129 			D1(vswp, "%s: exit", __func__);
1130 			return ((mac_resource_handle_t)ringp);
1131 		}
1132 	}
1133 	mutex_exit(&vswp->mac_ring_lock);
1134 
1135 	/*
1136 	 * No slots in the ring table available.
1137 	 */
1138 	D1(vswp, "%s: exit", __func__);
1139 	return (NULL);
1140 }
1141 
1142 static void
1143 vsw_queue_stop(vsw_queue_t *vqp)
1144 {
1145 	mutex_enter(&vqp->vq_lock);
1146 
1147 	if (vqp->vq_state == VSW_QUEUE_RUNNING) {
1148 		vqp->vq_state = VSW_QUEUE_STOP;
1149 		cv_signal(&vqp->vq_cv);
1150 
1151 		while (vqp->vq_state != VSW_QUEUE_DRAINED)
1152 			cv_wait(&vqp->vq_cv, &vqp->vq_lock);
1153 	}
1154 
1155 	vqp->vq_state = VSW_QUEUE_STOPPED;
1156 
1157 	mutex_exit(&vqp->vq_lock);
1158 }
1159 
1160 static vsw_queue_t *
1161 vsw_queue_create()
1162 {
1163 	vsw_queue_t *vqp;
1164 
1165 	vqp = kmem_zalloc(sizeof (vsw_queue_t), KM_SLEEP);
1166 
1167 	mutex_init(&vqp->vq_lock, NULL, MUTEX_DRIVER, NULL);
1168 	cv_init(&vqp->vq_cv, NULL, CV_DRIVER, NULL);
1169 	vqp->vq_first = NULL;
1170 	vqp->vq_last = NULL;
1171 	vqp->vq_state = VSW_QUEUE_STOPPED;
1172 
1173 	return (vqp);
1174 }
1175 
1176 static void
1177 vsw_queue_destroy(vsw_queue_t *vqp)
1178 {
1179 	cv_destroy(&vqp->vq_cv);
1180 	mutex_destroy(&vqp->vq_lock);
1181 	kmem_free(vqp, sizeof (vsw_queue_t));
1182 }
1183 
1184 static void
1185 vsw_queue_worker(vsw_mac_ring_t *rrp)
1186 {
1187 	mblk_t		*mp;
1188 	vsw_queue_t	*vqp = rrp->ring_vqp;
1189 	vsw_t		*vswp = rrp->ring_vswp;
1190 
1191 	mutex_enter(&vqp->vq_lock);
1192 
1193 	ASSERT(vqp->vq_state == VSW_QUEUE_STOPPED);
1194 
1195 	/*
1196 	 * Set the state to running, since the thread is now active.
1197 	 */
1198 	vqp->vq_state = VSW_QUEUE_RUNNING;
1199 	cv_signal(&vqp->vq_cv);
1200 
1201 	while (vqp->vq_state == VSW_QUEUE_RUNNING) {
1202 		/*
1203 		 * Wait for work to do or the state has changed
1204 		 * to not running.
1205 		 */
1206 		while ((vqp->vq_state == VSW_QUEUE_RUNNING) &&
1207 		    (vqp->vq_first == NULL)) {
1208 			cv_wait(&vqp->vq_cv, &vqp->vq_lock);
1209 		}
1210 
1211 		/*
1212 		 * Process packets that we received from the interface.
1213 		 */
1214 		if (vqp->vq_first != NULL) {
1215 			mp = vqp->vq_first;
1216 
1217 			vqp->vq_first = NULL;
1218 			vqp->vq_last = NULL;
1219 
1220 			mutex_exit(&vqp->vq_lock);
1221 
1222 			/* switch the chain of packets received */
1223 			vswp->vsw_switch_frame(vswp, mp,
1224 			    VSW_PHYSDEV, NULL, NULL);
1225 
1226 			mutex_enter(&vqp->vq_lock);
1227 		}
1228 	}
1229 
1230 	/*
1231 	 * We are drained and signal we are done.
1232 	 */
1233 	vqp->vq_state = VSW_QUEUE_DRAINED;
1234 	cv_signal(&vqp->vq_cv);
1235 
1236 	/*
1237 	 * Exit lock and drain the remaining packets.
1238 	 */
1239 	mutex_exit(&vqp->vq_lock);
1240 
1241 	/*
1242 	 * Exit the thread
1243 	 */
1244 	thread_exit();
1245 }
1246 
1247 /*
1248  * static void
1249  * vsw_rx_queue_cb() - Receive callback routine when
1250  *	vsw_multi_ring_enable is non-zero.  Queue the packets
1251  *	to a packet queue for a worker thread to process.
1252  */
1253 static void
1254 vsw_rx_queue_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp)
1255 {
1256 	vsw_mac_ring_t	*ringp = (vsw_mac_ring_t *)mrh;
1257 	vsw_t		*vswp = (vsw_t *)arg;
1258 	vsw_queue_t	*vqp;
1259 	mblk_t		*bp, *last;
1260 
1261 	ASSERT(mrh != NULL);
1262 	ASSERT(vswp != NULL);
1263 	ASSERT(mp != NULL);
1264 
1265 	D1(vswp, "%s: enter", __func__);
1266 
1267 	/*
1268 	 * Find the last element in the mblk chain.
1269 	 */
1270 	bp = mp;
1271 	do {
1272 		last = bp;
1273 		bp = bp->b_next;
1274 	} while (bp != NULL);
1275 
1276 	/* Get the queue for the packets */
1277 	vqp = ringp->ring_vqp;
1278 
1279 	/*
1280 	 * Grab the lock such we can queue the packets.
1281 	 */
1282 	mutex_enter(&vqp->vq_lock);
1283 
1284 	if (vqp->vq_state != VSW_QUEUE_RUNNING) {
1285 		freemsgchain(mp);
1286 		mutex_exit(&vqp->vq_lock);
1287 		goto vsw_rx_queue_cb_exit;
1288 	}
1289 
1290 	/*
1291 	 * Add the mblk chain to the queue.  If there
1292 	 * is some mblks in the queue, then add the new
1293 	 * chain to the end.
1294 	 */
1295 	if (vqp->vq_first == NULL)
1296 		vqp->vq_first = mp;
1297 	else
1298 		vqp->vq_last->b_next = mp;
1299 
1300 	vqp->vq_last = last;
1301 
1302 	/*
1303 	 * Signal the worker thread that there is work to
1304 	 * do.
1305 	 */
1306 	cv_signal(&vqp->vq_cv);
1307 
1308 	/*
1309 	 * Let go of the lock and exit.
1310 	 */
1311 	mutex_exit(&vqp->vq_lock);
1312 
1313 vsw_rx_queue_cb_exit:
1314 	D1(vswp, "%s: exit", __func__);
1315 }
1316 
1317 /*
1318  * receive callback routine. Invoked by MAC layer when there
1319  * are pkts being passed up from physical device.
1320  *
1321  * PERF: It may be more efficient when the card is in promisc
1322  * mode to check the dest address of the pkts here (against
1323  * the FDB) rather than checking later. Needs to be investigated.
1324  */
1325 static void
1326 vsw_rx_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp)
1327 {
1328 	_NOTE(ARGUNUSED(mrh))
1329 
1330 	vsw_t		*vswp = (vsw_t *)arg;
1331 
1332 	ASSERT(vswp != NULL);
1333 
1334 	D1(vswp, "vsw_rx_cb: enter");
1335 
1336 	/* switch the chain of packets received */
1337 	vswp->vsw_switch_frame(vswp, mp, VSW_PHYSDEV, NULL, NULL);
1338 
1339 	D1(vswp, "vsw_rx_cb: exit");
1340 }
1341 
1342 /*
1343  * Send a message out over the physical device via the MAC layer.
1344  *
1345  * Returns any mblks that it was unable to transmit.
1346  */
1347 mblk_t *
1348 vsw_tx_msg(vsw_t *vswp, mblk_t *mp)
1349 {
1350 	const mac_txinfo_t	*mtp;
1351 
1352 	READ_ENTER(&vswp->mac_rwlock);
1353 	if ((vswp->mh == NULL) || (vswp->mstarted == B_FALSE)) {
1354 
1355 		DERR(vswp, "vsw_tx_msg: dropping pkts: no tx routine avail");
1356 		RW_EXIT(&vswp->mac_rwlock);
1357 		return (mp);
1358 	} else {
1359 		mtp = vswp->txinfo;
1360 		mp = mtp->mt_fn(mtp->mt_arg, mp);
1361 	}
1362 	RW_EXIT(&vswp->mac_rwlock);
1363 
1364 	return (mp);
1365 }
1366 
1367 #define	ARH_FIXED_LEN	8    /* Length of fixed part of ARP header(see arp.h) */
1368 
1369 /*
1370  * Send a gratuitous RARP packet to notify the physical switch to update its
1371  * Layer2 forwarding table for the given mac address. This is done to allow the
1372  * switch to quickly learn the macaddr-port association when a guest is live
1373  * migrated or when vsw's physical device is changed dynamically. Any protocol
1374  * packet would serve this purpose, but we choose RARP, as it allows us to
1375  * accomplish this within L2 (ie, no need to specify IP addr etc in the packet)
1376  * The macaddr of vnet is retained across migration. Hence, we don't need to
1377  * update the arp cache of other hosts within the broadcast domain. Note that
1378  * it is harmless to send these RARP packets during normal port attach of a
1379  * client vnet. This can can be turned off if needed, by setting
1380  * vsw_publish_macaddr_count to zero in /etc/system.
1381  */
1382 void
1383 vsw_publish_macaddr(vsw_t *vswp, uint8_t *addr)
1384 {
1385 	mblk_t			*mp;
1386 	mblk_t			*bp;
1387 	struct arphdr		*arh;
1388 	struct	ether_header 	*ehp;
1389 	int			count = 0;
1390 	int			plen = 4;
1391 	uint8_t			*cp;
1392 
1393 	mp = allocb(ETHERMIN, BPRI_MED);
1394 	if (mp == NULL) {
1395 		return;
1396 	}
1397 
1398 	/* Initialize eth header */
1399 	ehp = (struct  ether_header *)mp->b_rptr;
1400 	bcopy(&etherbroadcastaddr, &ehp->ether_dhost, ETHERADDRL);
1401 	bcopy(addr, &ehp->ether_shost, ETHERADDRL);
1402 	ehp->ether_type = htons(ETHERTYPE_REVARP);
1403 
1404 	/* Initialize arp packet */
1405 	arh = (struct arphdr *)(mp->b_rptr + sizeof (struct ether_header));
1406 	cp = (uint8_t *)arh;
1407 
1408 	arh->ar_hrd = htons(ARPHRD_ETHER);	/* Hardware type:  ethernet */
1409 	arh->ar_pro = htons(ETHERTYPE_IP);	/* Protocol type:  IP */
1410 	arh->ar_hln = ETHERADDRL;	/* Length of hardware address:  6 */
1411 	arh->ar_pln = plen;		/* Length of protocol address:  4 */
1412 	arh->ar_op = htons(REVARP_REQUEST);	/* Opcode: REVARP Request */
1413 
1414 	cp += ARH_FIXED_LEN;
1415 
1416 	/* Sender's hardware address and protocol address */
1417 	bcopy(addr, cp, ETHERADDRL);
1418 	cp += ETHERADDRL;
1419 	bzero(cp, plen);	/* INADDR_ANY */
1420 	cp += plen;
1421 
1422 	/* Target hardware address and protocol address */
1423 	bcopy(addr, cp, ETHERADDRL);
1424 	cp += ETHERADDRL;
1425 	bzero(cp, plen);	/* INADDR_ANY */
1426 	cp += plen;
1427 
1428 	mp->b_wptr += ETHERMIN;	/* total size is 42; round up to ETHERMIN */
1429 
1430 	for (count = 0; count < vsw_publish_macaddr_count; count++) {
1431 
1432 		bp = dupmsg(mp);
1433 		if (bp == NULL) {
1434 			continue;
1435 		}
1436 
1437 		/* transmit the packet */
1438 		bp = vsw_tx_msg(vswp, bp);
1439 		if (bp != NULL) {
1440 			freemsg(bp);
1441 		}
1442 	}
1443 
1444 	freemsg(mp);
1445 }
1446