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