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 2009 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_client.h> 59 #include <sys/mac_provider.h> 60 #include <sys/mac_client_priv.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/mac_flow.h> 67 #include <sys/mdeg.h> 68 #include <sys/vsw.h> 69 #include <sys/vlan.h> 70 71 /* MAC Ring table functions. */ 72 static void vsw_port_rx_cb(void *, mac_resource_handle_t, mblk_t *, 73 boolean_t); 74 static void vsw_if_rx_cb(void *, mac_resource_handle_t, mblk_t *, boolean_t); 75 76 /* MAC layer routines */ 77 static int vsw_set_port_hw_addr(vsw_port_t *port); 78 static int vsw_set_if_hw_addr(vsw_t *vswp); 79 static void vsw_unset_hw_addr(vsw_t *, vsw_port_t *, int); 80 static int vsw_maccl_open(vsw_t *vswp, vsw_port_t *port, int type); 81 static void vsw_maccl_close(vsw_t *vswp, vsw_port_t *port, int type); 82 static void vsw_mac_multicast_add_all(vsw_t *vswp, vsw_port_t *portp, int type); 83 static void vsw_mac_multicast_remove_all(vsw_t *vswp, 84 vsw_port_t *portp, int type); 85 static void vsw_mac_add_vlans(vsw_t *vswp, mac_client_handle_t mch, 86 uint8_t *macaddr, uint16_t flags, vsw_vlanid_t *vids, int nvids); 87 static void vsw_mac_remove_vlans(mac_client_handle_t mch, vsw_vlanid_t *vids, 88 int nvids); 89 static void vsw_mac_set_mtu(vsw_t *vswp, uint32_t mtu); 90 static void vsw_maccl_set_bandwidth(vsw_t *vswp, vsw_port_t *port, int type, 91 uint64_t maxbw); 92 static int vsw_notify_add(vsw_t *vswp); 93 static int vsw_notify_rem(vsw_t *vswp); 94 static void vsw_notify_cb(void *arg, mac_notify_type_t type); 95 static void vsw_notify_link(vsw_t *vswp); 96 97 /* Support functions */ 98 int vsw_set_hw(vsw_t *, vsw_port_t *, int); 99 void vsw_unset_hw(vsw_t *, vsw_port_t *, int); 100 void vsw_reconfig_hw(vsw_t *); 101 int vsw_mac_open(vsw_t *vswp); 102 void vsw_mac_close(vsw_t *vswp); 103 int vsw_mac_multicast_add(vsw_t *vswp, vsw_port_t *port, mcst_addr_t *mcst_p, 104 int type); 105 void vsw_mac_multicast_remove(vsw_t *vswp, vsw_port_t *port, 106 mcst_addr_t *mcst_p, int type); 107 int vsw_mac_client_init(vsw_t *vswp, vsw_port_t *port, int type); 108 void vsw_mac_client_cleanup(vsw_t *vswp, vsw_port_t *port, int type); 109 void vsw_mac_cleanup_ports(vsw_t *vswp); 110 void vsw_unset_addrs(vsw_t *vswp); 111 void vsw_set_addrs(vsw_t *vswp); 112 mblk_t *vsw_tx_msg(vsw_t *, mblk_t *, int, vsw_port_t *); 113 void vsw_publish_macaddr(vsw_t *vswp, vsw_port_t *portp); 114 void vsw_port_mac_reconfig(vsw_port_t *portp, boolean_t update_vlans, 115 uint16_t new_pvid, vsw_vlanid_t *new_vids, int new_nvids); 116 void vsw_mac_port_reconfig_vlans(vsw_port_t *portp, uint16_t new_pvid, 117 vsw_vlanid_t *new_vids, int new_nvids); 118 void vsw_if_mac_reconfig(vsw_t *vswp, boolean_t update_vlans, 119 uint16_t new_pvid, vsw_vlanid_t *new_vids, int new_nvids); 120 void vsw_update_bandwidth(vsw_t *vswp, vsw_port_t *port, int type, 121 uint64_t maxbw); 122 123 /* 124 * Functions imported from other files. 125 */ 126 extern int vsw_portsend(vsw_port_t *port, mblk_t *mp); 127 extern void vsw_hio_stop_port(vsw_port_t *portp); 128 extern void vsw_hio_port_reset(vsw_port_t *portp, boolean_t immediate); 129 extern uint32_t vsw_publish_macaddr_count; 130 extern uint32_t vsw_vlan_frame_untag(void *arg, int type, mblk_t **np, 131 mblk_t **npt); 132 extern void vsw_physlink_state_update(vsw_t *vswp); 133 static char mac_mtu_propname[] = "mtu"; 134 135 /* 136 * Tunables used in this file. 137 */ 138 extern int vsw_mac_open_retries; 139 140 #define WRITE_MACCL_ENTER(vswp, port, type) \ 141 (type == VSW_LOCALDEV) ? rw_enter(&vswp->maccl_rwlock, RW_WRITER) :\ 142 rw_enter(&port->maccl_rwlock, RW_WRITER) 143 144 #define READ_MACCL_ENTER(vswp, port, type) \ 145 (type == VSW_LOCALDEV) ? rw_enter(&vswp->maccl_rwlock, RW_READER) :\ 146 rw_enter(&port->maccl_rwlock, RW_READER) 147 148 #define RW_MACCL_EXIT(vswp, port, type) \ 149 (type == VSW_LOCALDEV) ? rw_exit(&vswp->maccl_rwlock) : \ 150 rw_exit(&port->maccl_rwlock) 151 152 153 /* 154 * Locking strategy in this file is explained as follows: 155 * - A global lock(vswp->mac_lock) is used to protect the 156 * MAC calls that deal with entire device. That is, the 157 * operations that deal with mac_handle which include 158 * mac_open()/close() and mac_client_open(). 159 * 160 * - A per port/interface RW lock(maccl_rwlock) is used protect 161 * the operations that deal with the MAC client. 162 * 163 * When both mac_lock and maccl_rwlock need to be held, the 164 * mac_lock need be acquired first and then maccl_rwlock. That is, 165 * mac_lock---->maccl_rwlock 166 * 167 * The 'mca_lock' that protects the mcast list is also acquired 168 * within the context of maccl_rwlock. The hierarchy for this 169 * one is as below: 170 * maccl_rwlock---->mca_lock 171 */ 172 173 174 /* 175 * Program unicast and multicast addresses of vsw interface and the ports 176 * into the network device. 177 */ 178 void 179 vsw_set_addrs(vsw_t *vswp) 180 { 181 vsw_port_list_t *plist = &vswp->plist; 182 vsw_port_t *port; 183 int rv; 184 185 READ_ENTER(&vswp->if_lockrw); 186 187 if (vswp->if_state & VSW_IF_UP) { 188 189 /* Open a mac client and program addresses */ 190 rv = vsw_mac_client_init(vswp, NULL, VSW_LOCALDEV); 191 if (rv != 0) { 192 cmn_err(CE_NOTE, 193 "!vsw%d: failed to program interface " 194 "unicast address\n", vswp->instance); 195 } 196 197 /* 198 * Notify the MAC layer of the changed address. 199 */ 200 if (rv == 0) { 201 mac_unicst_update(vswp->if_mh, 202 (uint8_t *)&vswp->if_addr); 203 } 204 205 } 206 207 RW_EXIT(&vswp->if_lockrw); 208 209 WRITE_ENTER(&plist->lockrw); 210 211 /* program unicast address of ports in the network device */ 212 for (port = plist->head; port != NULL; port = port->p_next) { 213 if (port->addr_set) /* addr already set */ 214 continue; 215 216 /* Open a mac client and program addresses */ 217 rv = vsw_mac_client_init(vswp, port, VSW_VNETPORT); 218 if (rv != 0) { 219 cmn_err(CE_NOTE, 220 "!vsw%d: failed to program port(%d) " 221 "unicast address\n", vswp->instance, 222 port->p_instance); 223 } 224 } 225 /* announce macaddr of vnets to the physical switch */ 226 if (vsw_publish_macaddr_count != 0) { /* enabled */ 227 for (port = plist->head; port != NULL; port = port->p_next) { 228 vsw_publish_macaddr(vswp, port); 229 } 230 } 231 232 RW_EXIT(&plist->lockrw); 233 } 234 235 /* 236 * Remove unicast, multicast addresses and close mac clients 237 * for the vsw interface and all ports. 238 */ 239 void 240 vsw_unset_addrs(vsw_t *vswp) 241 { 242 READ_ENTER(&vswp->if_lockrw); 243 if (vswp->if_state & VSW_IF_UP) { 244 245 /* Cleanup and close the mac client for the interface */ 246 vsw_mac_client_cleanup(vswp, NULL, VSW_LOCALDEV); 247 } 248 RW_EXIT(&vswp->if_lockrw); 249 250 /* Cleanup and close the mac clients for all ports */ 251 vsw_mac_cleanup_ports(vswp); 252 } 253 254 /* 255 * Open the underlying network device for access in layer2 mode. 256 * Returns: 257 * 0 on success 258 * EAGAIN if mac_open() fails due to the device being not available yet. 259 * EIO on any other failures. 260 */ 261 int 262 vsw_mac_open(vsw_t *vswp) 263 { 264 int rv; 265 266 ASSERT(MUTEX_HELD(&vswp->mac_lock)); 267 268 if (vswp->mh != NULL) { 269 /* already open */ 270 return (0); 271 } 272 273 if (vswp->mac_open_retries++ >= vsw_mac_open_retries) { 274 /* exceeded max retries */ 275 return (EIO); 276 } 277 278 if ((rv = mac_open_by_linkname(vswp->physname, &vswp->mh)) != 0) { 279 /* 280 * If mac_open() failed and the error indicates that either 281 * the dlmgmtd door or the device is not available yet, we 282 * return EAGAIN to indicate that mac_open() needs to be 283 * retried. For example, this may happen during boot up, if 284 * the required link aggregation groups(devices) have not 285 * been created yet. 286 */ 287 if (rv == ENOENT || rv == EBADF) { 288 return (EAGAIN); 289 } else { 290 cmn_err(CE_WARN, "!vsw%d: mac_open %s failed rv:%x\n", 291 vswp->instance, vswp->physname, rv); 292 return (EIO); 293 } 294 } 295 vswp->mac_open_retries = 0; 296 297 vsw_mac_set_mtu(vswp, vswp->mtu); 298 299 rv = vsw_notify_add(vswp); 300 if (rv != 0) { 301 cmn_err(CE_CONT, "!vsw%d: mac_notify_add %s failed rv:%x\n", 302 vswp->instance, vswp->physname, rv); 303 } 304 305 return (0); 306 } 307 308 /* 309 * Close the underlying physical device. 310 */ 311 void 312 vsw_mac_close(vsw_t *vswp) 313 { 314 ASSERT(MUTEX_HELD(&vswp->mac_lock)); 315 316 if (vswp->mh != NULL) { 317 if (vswp->mnh != 0) { 318 (void) vsw_notify_rem(vswp); 319 vswp->mnh = 0; 320 } 321 if (vswp->mtu != vswp->mtu_physdev_orig) { 322 vsw_mac_set_mtu(vswp, vswp->mtu_physdev_orig); 323 } 324 mac_close(vswp->mh); 325 vswp->mh = NULL; 326 } 327 } 328 329 /* 330 * Add multicast addr. 331 */ 332 int 333 vsw_mac_multicast_add(vsw_t *vswp, vsw_port_t *port, mcst_addr_t *mcst_p, 334 int type) 335 { 336 int ret = 0; 337 mac_client_handle_t mch; 338 339 WRITE_MACCL_ENTER(vswp, port, type); 340 341 mch = (type == VSW_LOCALDEV) ? vswp->mch : port->p_mch; 342 343 if (mch != NULL) { 344 ret = mac_multicast_add(mch, mcst_p->mca.ether_addr_octet); 345 if (ret != 0) { 346 cmn_err(CE_WARN, "!vsw%d: unable to " 347 "program multicast address(%s) err=%d", 348 vswp->instance, 349 ether_sprintf((void *)&mcst_p->mca), ret); 350 RW_MACCL_EXIT(vswp, port, type); 351 return (ret); 352 } 353 mcst_p->mac_added = B_TRUE; 354 } 355 356 RW_MACCL_EXIT(vswp, port, type); 357 return (ret); 358 } 359 360 /* 361 * Remove multicast addr. 362 */ 363 void 364 vsw_mac_multicast_remove(vsw_t *vswp, vsw_port_t *port, mcst_addr_t *mcst_p, 365 int type) 366 { 367 mac_client_handle_t mch; 368 369 WRITE_MACCL_ENTER(vswp, port, type); 370 mch = (type == VSW_LOCALDEV) ? vswp->mch : port->p_mch; 371 372 if (mch != NULL && mcst_p->mac_added) { 373 mac_multicast_remove(mch, mcst_p->mca.ether_addr_octet); 374 mcst_p->mac_added = B_FALSE; 375 } 376 RW_MACCL_EXIT(vswp, port, type); 377 } 378 379 380 /* 381 * Add all multicast addresses of the port. 382 */ 383 static void 384 vsw_mac_multicast_add_all(vsw_t *vswp, vsw_port_t *portp, int type) 385 { 386 mcst_addr_t *mcap; 387 mac_client_handle_t mch; 388 kmutex_t *mca_lockp; 389 int rv; 390 391 ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT)); 392 if (type == VSW_LOCALDEV) { 393 ASSERT(RW_WRITE_HELD(&vswp->maccl_rwlock)); 394 mch = vswp->mch; 395 mcap = vswp->mcap; 396 mca_lockp = &vswp->mca_lock; 397 } else { 398 ASSERT(RW_WRITE_HELD(&portp->maccl_rwlock)); 399 mch = portp->p_mch; 400 mcap = portp->mcap; 401 mca_lockp = &portp->mca_lock; 402 } 403 404 if (mch == NULL) 405 return; 406 407 mutex_enter(mca_lockp); 408 for (mcap = mcap; mcap != NULL; mcap = mcap->nextp) { 409 if (mcap->mac_added) 410 continue; 411 rv = mac_multicast_add(mch, (uchar_t *)&mcap->mca); 412 if (rv == 0) { 413 mcap->mac_added = B_TRUE; 414 } else { 415 cmn_err(CE_WARN, "!vsw%d: unable to program " 416 "multicast address(%s) err=%d", vswp->instance, 417 ether_sprintf((void *)&mcap->mca), rv); 418 } 419 } 420 mutex_exit(mca_lockp); 421 } 422 423 /* 424 * Remove all multicast addresses of the port. 425 */ 426 static void 427 vsw_mac_multicast_remove_all(vsw_t *vswp, vsw_port_t *portp, int type) 428 { 429 mac_client_handle_t mch; 430 mcst_addr_t *mcap; 431 kmutex_t *mca_lockp; 432 433 ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT)); 434 if (type == VSW_LOCALDEV) { 435 ASSERT(RW_WRITE_HELD(&vswp->maccl_rwlock)); 436 mch = vswp->mch; 437 mcap = vswp->mcap; 438 mca_lockp = &vswp->mca_lock; 439 } else { 440 ASSERT(RW_WRITE_HELD(&portp->maccl_rwlock)); 441 mch = portp->p_mch; 442 mcap = portp->mcap; 443 mca_lockp = &portp->mca_lock; 444 } 445 446 if (mch == NULL) 447 return; 448 449 mutex_enter(mca_lockp); 450 for (; mcap != NULL; mcap = mcap->nextp) { 451 if (!mcap->mac_added) 452 continue; 453 (void) mac_multicast_remove(mch, (uchar_t *)&mcap->mca); 454 mcap->mac_added = B_FALSE; 455 } 456 mutex_exit(mca_lockp); 457 } 458 459 void 460 vsw_update_bandwidth(vsw_t *vswp, vsw_port_t *port, int type, uint64_t maxbw) 461 { 462 ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT)); 463 464 WRITE_MACCL_ENTER(vswp, port, type); 465 vsw_maccl_set_bandwidth(vswp, port, type, maxbw); 466 RW_MACCL_EXIT(vswp, port, type); 467 } 468 469 /* 470 * Open a mac client and program uncast and multicast addresses 471 * for a port or the interface. 472 * Returns: 473 * 0 on success 474 * non-zero for failure. 475 */ 476 int 477 vsw_mac_client_init(vsw_t *vswp, vsw_port_t *port, int type) 478 { 479 int rv; 480 481 mutex_enter(&vswp->mac_lock); 482 WRITE_MACCL_ENTER(vswp, port, type); 483 rv = vsw_maccl_open(vswp, port, type); 484 485 /* Release mac_lock now */ 486 mutex_exit(&vswp->mac_lock); 487 488 if (rv == 0) { 489 (void) vsw_set_hw(vswp, port, type); 490 vsw_mac_multicast_add_all(vswp, port, type); 491 } 492 RW_MACCL_EXIT(vswp, port, type); 493 return (rv); 494 } 495 496 /* 497 * Open a MAC client for a port or an interface. 498 * The flags and their purpose as below: 499 * 500 * MAC_OPEN_FLAGS_NO_HWRINGS -- This flag is used by default 501 * for all ports/interface so that they are associated with 502 * default group & resources. It will not be used for the 503 * ports that have HybridIO is enabled so that the h/w resources 504 * assigned to it. 505 * 506 * MAC_OPEN_FLAGS_SHARES_DESIRED -- This flag is used to indicate 507 * that a port desires a Share. This will be the case with the 508 * the ports that have hybrid mode enabled. This will only cause 509 * MAC layer to allocate a share and corresponding resources 510 * ahead of time. 511 * 512 * MAC_UNICAST_TAG_DISABLE -- This flag is used for VLAN 513 * support. It will cause MAC to not add any tags, but expect 514 * vsw to tag the packets. 515 * 516 * MAC_UNICAST_STRIP_DISABLE -- This flag is used for VLAN 517 * support. It will case the MAC layer to not strip the tags. 518 * Vsw may have to strip the tag for pvid case. 519 */ 520 static int 521 vsw_maccl_open(vsw_t *vswp, vsw_port_t *port, int type) 522 { 523 int rv = 0; 524 int instance; 525 char mac_cl_name[MAXNAMELEN]; 526 const char *dev_name; 527 mac_client_handle_t *mchp; 528 uint64_t flags = MAC_OPEN_FLAGS_NO_HWRINGS; 529 530 ASSERT(MUTEX_HELD(&vswp->mac_lock)); 531 if (vswp->mh == NULL) { 532 /* 533 * In case net-dev is changed (either set to nothing or 534 * using aggregation device), return success here as the 535 * timeout mechanism will handle it. 536 */ 537 return (0); 538 } 539 540 mchp = (type == VSW_LOCALDEV) ? &vswp->mch : &port->p_mch; 541 if (*mchp != NULL) { 542 /* already open */ 543 return (0); 544 } 545 dev_name = ddi_driver_name(vswp->dip); 546 instance = ddi_get_instance(vswp->dip); 547 if (type == VSW_VNETPORT) { 548 if (port->p_hio_enabled == B_TRUE) { 549 flags &= ~MAC_OPEN_FLAGS_NO_HWRINGS; 550 flags |= MAC_OPEN_FLAGS_SHARES_DESIRED; 551 } 552 (void) snprintf(mac_cl_name, MAXNAMELEN, "%s%d%s%d", dev_name, 553 instance, "_port", port->p_instance); 554 } else { 555 (void) snprintf(mac_cl_name, MAXNAMELEN, "%s%s%d", 556 dev_name, "_if", instance); 557 } 558 559 rv = mac_client_open(vswp->mh, mchp, mac_cl_name, flags); 560 if (rv != 0) { 561 cmn_err(CE_NOTE, "!vsw%d:%s mac_client_open() failed\n", 562 vswp->instance, mac_cl_name); 563 } 564 return (rv); 565 } 566 567 /* 568 * Clean up by removing uncast, multicast addresses and 569 * closing the MAC client for a port or the interface. 570 */ 571 void 572 vsw_mac_client_cleanup(vsw_t *vswp, vsw_port_t *port, int type) 573 { 574 WRITE_MACCL_ENTER(vswp, port, type); 575 vsw_mac_multicast_remove_all(vswp, port, type); 576 vsw_unset_hw(vswp, port, type); 577 vsw_maccl_close(vswp, port, type); 578 RW_MACCL_EXIT(vswp, port, type); 579 } 580 581 /* 582 * Close a MAC client for a port or an interface. 583 */ 584 static void 585 vsw_maccl_close(vsw_t *vswp, vsw_port_t *port, int type) 586 { 587 mac_client_handle_t *mchp; 588 589 ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT)); 590 591 mchp = (type == VSW_LOCALDEV) ? &vswp->mch : &port->p_mch; 592 if (*mchp != NULL) { 593 mac_client_close(*mchp, 0); 594 *mchp = NULL; 595 } 596 } 597 598 /* 599 * Cleanup MAC client related stuff for all ports. 600 */ 601 void 602 vsw_mac_cleanup_ports(vsw_t *vswp) 603 { 604 vsw_port_list_t *plist = &vswp->plist; 605 vsw_port_t *port; 606 607 READ_ENTER(&plist->lockrw); 608 for (port = plist->head; port != NULL; port = port->p_next) { 609 vsw_mac_client_cleanup(vswp, port, VSW_VNETPORT); 610 } 611 RW_EXIT(&plist->lockrw); 612 } 613 614 /* 615 * Depending on the mode specified, the capabilites and capacity 616 * of the underlying device setup the physical device. 617 * 618 * If in layer 3 mode, then do nothing. 619 * 620 * If in layer 2 mode, open a mac client and program the mac-address 621 * and vlan-ids. The MAC layer will take care of programming 622 * the address into h/w or set the h/w into promiscuous mode. 623 * 624 * Returns 0 success, 1 on failure. 625 */ 626 int 627 vsw_set_hw(vsw_t *vswp, vsw_port_t *port, int type) 628 { 629 int err = 1; 630 631 D1(vswp, "%s: enter", __func__); 632 633 ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT)); 634 635 if (vswp->smode == VSW_LAYER3) 636 return (0); 637 638 if (type == VSW_VNETPORT) { 639 ASSERT(port != NULL); 640 err = vsw_set_port_hw_addr(port); 641 } else { 642 err = vsw_set_if_hw_addr(vswp); 643 } 644 645 D1(vswp, "%s: exit", __func__); 646 return (err); 647 } 648 649 /* 650 * If in layer 3 mode do nothing. 651 * 652 * If in layer 2 switched mode remove the address from the physical 653 * device. 654 * 655 * If in layer 2 promiscuous mode disable promisc mode. 656 * 657 * Returns 0 on success. 658 */ 659 void 660 vsw_unset_hw(vsw_t *vswp, vsw_port_t *port, int type) 661 { 662 D1(vswp, "%s: enter", __func__); 663 664 ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT)); 665 666 if (vswp->smode == VSW_LAYER3) 667 return; 668 669 if (type == VSW_VNETPORT) { 670 ASSERT(port != NULL); 671 vsw_unset_hw_addr(vswp, port, type); 672 } else { 673 vsw_unset_hw_addr(vswp, NULL, type); 674 } 675 676 D1(vswp, "%s: exit", __func__); 677 } 678 679 /* 680 * Program the macaddress and vlans of a port. 681 * 682 * Returns 0 on sucess, 1 on failure. 683 */ 684 static int 685 vsw_set_port_hw_addr(vsw_port_t *port) 686 { 687 vsw_t *vswp = port->p_vswp; 688 mac_diag_t diag; 689 uint8_t *macaddr; 690 uint16_t vid = VLAN_ID_NONE; 691 int rv; 692 uint16_t mac_flags = MAC_UNICAST_TAG_DISABLE | 693 MAC_UNICAST_STRIP_DISABLE; 694 695 D1(vswp, "%s: enter", __func__); 696 697 ASSERT(RW_WRITE_HELD(&port->maccl_rwlock)); 698 if (port->p_mch == NULL) 699 return (0); 700 701 /* 702 * If the port has a specific 'pvid', then 703 * register with that vlan-id, otherwise register 704 * with VLAN_ID_NONE. 705 */ 706 if (port->pvid != vswp->default_vlan_id) { 707 vid = port->pvid; 708 } 709 macaddr = (uint8_t *)port->p_macaddr.ether_addr_octet; 710 711 if (!(vswp->smode & VSW_LAYER2_PROMISC)) { 712 mac_flags |= MAC_UNICAST_HW; 713 } 714 715 if (port->addr_set == B_FALSE) { 716 port->p_muh = NULL; 717 rv = mac_unicast_add(port->p_mch, macaddr, mac_flags, 718 &port->p_muh, vid, &diag); 719 720 if (rv != 0) { 721 cmn_err(CE_WARN, "vsw%d: Failed to program" 722 "macaddr,vid(%s, %d) err=%d", 723 vswp->instance, ether_sprintf((void *)macaddr), 724 vid, rv); 725 return (rv); 726 } 727 port->addr_set = B_TRUE; 728 729 D2(vswp, "%s:programmed macaddr(%s) vid(%d) into device %s", 730 __func__, ether_sprintf((void *)macaddr), vid, 731 vswp->physname); 732 } 733 734 /* Add vlans to the MAC layer */ 735 vsw_mac_add_vlans(vswp, port->p_mch, macaddr, 736 mac_flags, port->vids, port->nvids); 737 738 /* Configure bandwidth to the MAC layer */ 739 vsw_maccl_set_bandwidth(NULL, port, VSW_VNETPORT, port->p_bandwidth); 740 741 mac_rx_set(port->p_mch, vsw_port_rx_cb, (void *)port); 742 743 D1(vswp, "%s: exit", __func__); 744 return (rv); 745 } 746 747 /* 748 * Program the macaddress and vlans of a port. 749 * 750 * Returns 0 on sucess, 1 on failure. 751 */ 752 static int 753 vsw_set_if_hw_addr(vsw_t *vswp) 754 { 755 mac_diag_t diag; 756 uint8_t *macaddr; 757 uint8_t primary_addr[ETHERADDRL]; 758 uint16_t vid = VLAN_ID_NONE; 759 int rv; 760 uint16_t mac_flags = MAC_UNICAST_TAG_DISABLE | 761 MAC_UNICAST_STRIP_DISABLE; 762 763 D1(vswp, "%s: enter", __func__); 764 765 ASSERT(RW_WRITE_HELD(&vswp->maccl_rwlock)); 766 if (vswp->mch == NULL) 767 return (0); 768 769 macaddr = (uint8_t *)vswp->if_addr.ether_addr_octet; 770 771 /* check if it is the primary macaddr of the card. */ 772 mac_unicast_primary_get(vswp->mh, primary_addr); 773 if (ether_cmp((void *)primary_addr, (void*)macaddr) == 0) { 774 mac_flags |= MAC_UNICAST_PRIMARY; 775 } 776 777 /* 778 * If the interface has a specific 'pvid', then 779 * register with that vlan-id, otherwise register 780 * with VLAN_ID_NONE. 781 */ 782 if (vswp->pvid != vswp->default_vlan_id) { 783 vid = vswp->pvid; 784 } 785 786 if (!(vswp->smode & VSW_LAYER2_PROMISC)) { 787 mac_flags |= MAC_UNICAST_HW; 788 } 789 790 if (vswp->addr_set == B_FALSE) { 791 vswp->muh = NULL; 792 rv = mac_unicast_add(vswp->mch, macaddr, mac_flags, 793 &vswp->muh, vid, &diag); 794 795 if (rv != 0) { 796 cmn_err(CE_WARN, "vsw%d: Failed to program" 797 "macaddr,vid(%s, %d) err=%d", 798 vswp->instance, ether_sprintf((void *)macaddr), 799 vid, rv); 800 return (rv); 801 } 802 vswp->addr_set = B_TRUE; 803 804 D2(vswp, "%s:programmed macaddr(%s) vid(%d) into device %s", 805 __func__, ether_sprintf((void *)macaddr), vid, 806 vswp->physname); 807 } 808 809 vsw_mac_add_vlans(vswp, vswp->mch, macaddr, mac_flags, 810 vswp->vids, vswp->nvids); 811 812 vsw_maccl_set_bandwidth(vswp, NULL, VSW_LOCALDEV, vswp->bandwidth); 813 814 mac_rx_set(vswp->mch, vsw_if_rx_cb, (void *)vswp); 815 816 D1(vswp, "%s: exit", __func__); 817 return (rv); 818 } 819 820 /* 821 * Remove a unicast mac address which has previously been programmed 822 * into HW. 823 * 824 * Returns 0 on sucess, 1 on failure. 825 */ 826 static void 827 vsw_unset_hw_addr(vsw_t *vswp, vsw_port_t *port, int type) 828 { 829 vsw_vlanid_t *vids; 830 int nvids; 831 mac_client_handle_t mch = NULL; 832 833 D1(vswp, "%s: enter", __func__); 834 835 ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT)); 836 837 if (type == VSW_VNETPORT) { 838 ASSERT(port != NULL); 839 ASSERT(RW_WRITE_HELD(&port->maccl_rwlock)); 840 vids = port->vids; 841 nvids = port->nvids; 842 } else { 843 ASSERT(RW_WRITE_HELD(&vswp->maccl_rwlock)); 844 vids = vswp->vids; 845 nvids = vswp->nvids; 846 } 847 848 /* First clear the callback */ 849 if (type == VSW_LOCALDEV) { 850 mch = vswp->mch; 851 } else if (type == VSW_VNETPORT) { 852 mch = port->p_mch; 853 } 854 855 856 if (mch == NULL) { 857 return; 858 } 859 860 mac_rx_clear(mch); 861 862 /* Remove vlans */ 863 vsw_mac_remove_vlans(mch, vids, nvids); 864 865 if ((type == VSW_LOCALDEV) && (vswp->addr_set == B_TRUE)) { 866 (void) mac_unicast_remove(vswp->mch, vswp->muh); 867 vswp->muh = NULL; 868 D2(vswp, "removed vsw interface mac-addr from " 869 "the device %s", vswp->physname); 870 vswp->addr_set = B_FALSE; 871 872 } else if ((type == VSW_VNETPORT) && (port->addr_set == B_TRUE)) { 873 (void) mac_unicast_remove(port->p_mch, port->p_muh); 874 port->p_muh = NULL; 875 D2(vswp, "removed port(0x%p) mac-addr from " 876 "the device %s", port, vswp->physname); 877 port->addr_set = B_FALSE; 878 } 879 880 D1(vswp, "%s: exit", __func__); 881 } 882 883 /* 884 * receive callback routine for vsw interface. Invoked by MAC layer when there 885 * are pkts being passed up from physical device for this vsw interface. 886 */ 887 /* ARGSUSED */ 888 static void 889 vsw_if_rx_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp, 890 boolean_t loopback) 891 { 892 _NOTE(ARGUNUSED(mrh)) 893 894 vsw_t *vswp = (vsw_t *)arg; 895 mblk_t *mpt; 896 int count; 897 898 ASSERT(vswp != NULL); 899 900 D1(vswp, "%s: enter", __func__); 901 902 READ_ENTER(&vswp->if_lockrw); 903 if (vswp->if_state & VSW_IF_UP) { 904 RW_EXIT(&vswp->if_lockrw); 905 count = vsw_vlan_frame_untag(vswp, VSW_LOCALDEV, &mp, &mpt); 906 if (count != 0) { 907 mac_rx(vswp->if_mh, NULL, mp); 908 } 909 } else { 910 RW_EXIT(&vswp->if_lockrw); 911 freemsgchain(mp); 912 } 913 914 D1(vswp, "%s: exit", __func__); 915 } 916 917 /* 918 * receive callback routine for port. Invoked by MAC layer when there 919 * are pkts being passed up from physical device for this port. 920 */ 921 /* ARGSUSED */ 922 static void 923 vsw_port_rx_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp, 924 boolean_t loopback) 925 { 926 _NOTE(ARGUNUSED(mrh)) 927 928 vsw_t *vswp; 929 vsw_port_t *port = arg; 930 931 ASSERT(port != NULL); 932 933 vswp = port->p_vswp; 934 935 D1(vswp, "vsw_port_rx_cb: enter"); 936 937 /* 938 * Send the packets to the peer directly. 939 */ 940 (void) vsw_portsend(port, mp); 941 942 D1(vswp, "vsw_port_rx_cb: exit"); 943 } 944 945 /* 946 * Send a message out over the physical device 947 * via the MAC layer. 948 * 949 * Returns any mblks that it was unable to transmit. 950 */ 951 mblk_t * 952 vsw_tx_msg(vsw_t *vswp, mblk_t *mp, int caller, vsw_port_t *port) 953 { 954 mac_client_handle_t mch; 955 mac_unicast_handle_t muh; 956 957 READ_MACCL_ENTER(vswp, port, caller); 958 959 mch = (caller == VSW_LOCALDEV) ? vswp->mch : port->p_mch; 960 muh = (caller == VSW_LOCALDEV) ? vswp->muh : port->p_muh; 961 962 if (mch == NULL || muh == NULL) { 963 RW_MACCL_EXIT(vswp, port, caller); 964 return (mp); 965 } 966 967 /* packets are sent or dropped */ 968 (void) mac_tx(mch, mp, 0, MAC_DROP_ON_NO_DESC, NULL); 969 RW_MACCL_EXIT(vswp, port, caller); 970 return (NULL); 971 } 972 973 /* 974 * vsw_port_mac_reconfig -- Cleanup and close the MAC client 975 * and reopen and re-configure the MAC client with new flags etc. 976 * This function is useful for two different purposes: 977 * 1) To update the MAC client with new vlan-ids. This is done 978 * by freeing the existing vlan-ids and reopen with the new 979 * vlan-ids. 980 * 981 * 2) If the Hybrid mode status of a port changes, then the 982 * MAC client need to be closed and re-opened, otherwise, 983 * Share related resources may not be freed(hybird mode disabled) 984 * or assigned(hybrid mode enabled). To accomplish this, 985 * this function simply closes and reopens the MAC client. 986 * The reopen will result in using the flags based on the 987 * new hybrid mode of the port. 988 */ 989 void 990 vsw_port_mac_reconfig(vsw_port_t *portp, boolean_t update_vlans, 991 uint16_t new_pvid, vsw_vlanid_t *new_vids, int new_nvids) 992 { 993 vsw_t *vswp = portp->p_vswp; 994 int rv; 995 996 D1(vswp, "%s: enter", __func__); 997 /* 998 * Remove the multi-cast addresses, unicast address 999 * and close the mac-client. 1000 */ 1001 mutex_enter(&vswp->mac_lock); 1002 WRITE_ENTER(&portp->maccl_rwlock); 1003 vsw_mac_multicast_remove_all(vswp, portp, VSW_VNETPORT); 1004 vsw_unset_hw(vswp, portp, VSW_VNETPORT); 1005 vsw_maccl_close(vswp, portp, VSW_VNETPORT); 1006 1007 if (update_vlans == B_TRUE) { 1008 if (portp->nvids != 0) { 1009 kmem_free(portp->vids, 1010 sizeof (vsw_vlanid_t) * portp->nvids); 1011 portp->vids = NULL; 1012 portp->nvids = 0; 1013 } 1014 portp->vids = new_vids; 1015 portp->nvids = new_nvids; 1016 portp->pvid = new_pvid; 1017 } 1018 1019 /* 1020 * Now re-open the mac-client and 1021 * configure unicast addr and multicast addrs. 1022 */ 1023 rv = vsw_maccl_open(vswp, portp, VSW_VNETPORT); 1024 if (rv != 0) { 1025 goto recret; 1026 } 1027 1028 if (vsw_set_hw(vswp, portp, VSW_VNETPORT)) { 1029 cmn_err(CE_NOTE, "!vsw%d: port:%d failed to " 1030 "set unicast address\n", vswp->instance, portp->p_instance); 1031 goto recret; 1032 } 1033 1034 vsw_mac_multicast_add_all(vswp, portp, VSW_VNETPORT); 1035 1036 recret: 1037 RW_EXIT(&portp->maccl_rwlock); 1038 mutex_exit(&vswp->mac_lock); 1039 D1(vswp, "%s: exit", __func__); 1040 } 1041 1042 /* 1043 * vsw_if_mac_reconfig -- Reconfigure the vsw interfaace's mac-client 1044 * by closing and re-opening it. This function is used handle the 1045 * following two cases: 1046 * 1047 * 1) Handle the MAC address change for the interface. 1048 * 2) Handle vlan update. 1049 */ 1050 void 1051 vsw_if_mac_reconfig(vsw_t *vswp, boolean_t update_vlans, 1052 uint16_t new_pvid, vsw_vlanid_t *new_vids, int new_nvids) 1053 { 1054 int rv; 1055 1056 D1(vswp, "%s: enter", __func__); 1057 /* 1058 * Remove the multi-cast addresses, unicast address 1059 * and close the mac-client. 1060 */ 1061 mutex_enter(&vswp->mac_lock); 1062 WRITE_ENTER(&vswp->maccl_rwlock); 1063 vsw_mac_multicast_remove_all(vswp, NULL, VSW_LOCALDEV); 1064 vsw_unset_hw(vswp, NULL, VSW_LOCALDEV); 1065 vsw_maccl_close(vswp, NULL, VSW_LOCALDEV); 1066 1067 if (update_vlans == B_TRUE) { 1068 if (vswp->nvids != 0) { 1069 kmem_free(vswp->vids, 1070 sizeof (vsw_vlanid_t) * vswp->nvids); 1071 vswp->vids = NULL; 1072 vswp->nvids = 0; 1073 } 1074 vswp->vids = new_vids; 1075 vswp->nvids = new_nvids; 1076 vswp->pvid = new_pvid; 1077 } 1078 1079 /* 1080 * Now re-open the mac-client and 1081 * configure unicast addr and multicast addrs. 1082 */ 1083 rv = vsw_maccl_open(vswp, NULL, VSW_LOCALDEV); 1084 if (rv != 0) { 1085 goto ifrecret; 1086 } 1087 1088 if (vsw_set_hw(vswp, NULL, VSW_LOCALDEV)) { 1089 cmn_err(CE_NOTE, "!vsw%d:failed to set unicast address\n", 1090 vswp->instance); 1091 goto ifrecret; 1092 } 1093 1094 vsw_mac_multicast_add_all(vswp, NULL, VSW_LOCALDEV); 1095 1096 ifrecret: 1097 RW_EXIT(&vswp->maccl_rwlock); 1098 mutex_exit(&vswp->mac_lock); 1099 D1(vswp, "%s: exit", __func__); 1100 } 1101 1102 /* 1103 * vsw_mac_port_reconfig_vlans -- Reconfigure a port to handle 1104 * vlan configuration update. As the removal of the last unicast-address,vid 1105 * from the MAC client results in releasing all resources, it expects 1106 * no Shares to be associated with such MAC client. 1107 * 1108 * To handle vlan configuration update for a port that already has 1109 * a Share bound, then we need to free that share prior to reconfiguration. 1110 * Initiate the hybrdIO setup again after the completion of reconfiguration. 1111 */ 1112 void 1113 vsw_mac_port_reconfig_vlans(vsw_port_t *portp, uint16_t new_pvid, 1114 vsw_vlanid_t *new_vids, int new_nvids) 1115 { 1116 /* 1117 * As the reconfiguration involves the close of 1118 * mac client, cleanup HybridIO and later restart 1119 * HybridIO setup again. 1120 */ 1121 if (portp->p_hio_enabled == B_TRUE) { 1122 vsw_hio_stop_port(portp); 1123 } 1124 vsw_port_mac_reconfig(portp, B_TRUE, new_pvid, new_vids, new_nvids); 1125 if (portp->p_hio_enabled == B_TRUE) { 1126 /* reset to setup the HybridIO again. */ 1127 vsw_hio_port_reset(portp, B_FALSE); 1128 } 1129 } 1130 1131 /* Add vlans to MAC client */ 1132 static void 1133 vsw_mac_add_vlans(vsw_t *vswp, mac_client_handle_t mch, uint8_t *macaddr, 1134 uint16_t flags, vsw_vlanid_t *vids, int nvids) 1135 { 1136 vsw_vlanid_t *vidp; 1137 mac_diag_t diag; 1138 int rv; 1139 int i; 1140 1141 flags |= MAC_UNICAST_TAG_DISABLE | MAC_UNICAST_STRIP_DISABLE; 1142 1143 /* Add vlans to the MAC layer */ 1144 for (i = 0; i < nvids; i++) { 1145 vidp = &vids[i]; 1146 1147 if (vidp->vl_set == B_TRUE) { 1148 continue; 1149 } 1150 1151 rv = mac_unicast_add(mch, macaddr, flags, 1152 &vidp->vl_muh, vidp->vl_vid, &diag); 1153 if (rv != 0) { 1154 cmn_err(CE_WARN, "vsw%d: Failed to program" 1155 "macaddr,vid(%s, %d) err=%d", 1156 vswp->instance, ether_sprintf((void *)macaddr), 1157 vidp->vl_vid, rv); 1158 } else { 1159 vidp->vl_set = B_TRUE; 1160 D2(vswp, "%s:programmed macaddr(%s) vid(%d) " 1161 "into device %s", __func__, 1162 ether_sprintf((void *)macaddr), 1163 vidp->vl_vid, vswp->physname); 1164 } 1165 } 1166 } 1167 1168 /* Remove vlans from the MAC client */ 1169 static void 1170 vsw_mac_remove_vlans(mac_client_handle_t mch, vsw_vlanid_t *vids, int nvids) 1171 { 1172 int i; 1173 vsw_vlanid_t *vidp; 1174 1175 for (i = 0; i < nvids; i++) { 1176 vidp = &vids[i]; 1177 if (vidp->vl_set == B_FALSE) { 1178 continue; 1179 } 1180 (void) mac_unicast_remove(mch, vidp->vl_muh); 1181 vidp->vl_set = B_FALSE; 1182 } 1183 } 1184 1185 #define ARH_FIXED_LEN 8 /* Length of fixed part of ARP header(see arp.h) */ 1186 1187 /* 1188 * Send a gratuitous RARP packet to notify the physical switch to update its 1189 * Layer2 forwarding table for the given mac address. This is done to allow the 1190 * switch to quickly learn the macaddr-port association when a guest is live 1191 * migrated or when vsw's physical device is changed dynamically. Any protocol 1192 * packet would serve this purpose, but we choose RARP, as it allows us to 1193 * accomplish this within L2 (ie, no need to specify IP addr etc in the packet) 1194 * The macaddr of vnet is retained across migration. Hence, we don't need to 1195 * update the arp cache of other hosts within the broadcast domain. Note that 1196 * it is harmless to send these RARP packets during normal port attach of a 1197 * client vnet. This can can be turned off if needed, by setting 1198 * vsw_publish_macaddr_count to zero in /etc/system. 1199 */ 1200 void 1201 vsw_publish_macaddr(vsw_t *vswp, vsw_port_t *portp) 1202 { 1203 mblk_t *mp; 1204 mblk_t *bp; 1205 struct arphdr *arh; 1206 struct ether_header *ehp; 1207 int count = 0; 1208 int plen = 4; 1209 uint8_t *cp; 1210 1211 mp = allocb(ETHERMIN, BPRI_MED); 1212 if (mp == NULL) { 1213 return; 1214 } 1215 1216 /* Initialize eth header */ 1217 ehp = (struct ether_header *)mp->b_rptr; 1218 bcopy(ðerbroadcastaddr, &ehp->ether_dhost, ETHERADDRL); 1219 bcopy(&portp->p_macaddr, &ehp->ether_shost, ETHERADDRL); 1220 ehp->ether_type = htons(ETHERTYPE_REVARP); 1221 1222 /* Initialize arp packet */ 1223 arh = (struct arphdr *)(mp->b_rptr + sizeof (struct ether_header)); 1224 cp = (uint8_t *)arh; 1225 1226 arh->ar_hrd = htons(ARPHRD_ETHER); /* Hardware type: ethernet */ 1227 arh->ar_pro = htons(ETHERTYPE_IP); /* Protocol type: IP */ 1228 arh->ar_hln = ETHERADDRL; /* Length of hardware address: 6 */ 1229 arh->ar_pln = plen; /* Length of protocol address: 4 */ 1230 arh->ar_op = htons(REVARP_REQUEST); /* Opcode: REVARP Request */ 1231 1232 cp += ARH_FIXED_LEN; 1233 1234 /* Sender's hardware address and protocol address */ 1235 bcopy(&portp->p_macaddr, cp, ETHERADDRL); 1236 cp += ETHERADDRL; 1237 bzero(cp, plen); /* INADDR_ANY */ 1238 cp += plen; 1239 1240 /* Target hardware address and protocol address */ 1241 bcopy(&portp->p_macaddr, cp, ETHERADDRL); 1242 cp += ETHERADDRL; 1243 bzero(cp, plen); /* INADDR_ANY */ 1244 cp += plen; 1245 1246 mp->b_wptr += ETHERMIN; /* total size is 42; round up to ETHERMIN */ 1247 1248 for (count = 0; count < vsw_publish_macaddr_count; count++) { 1249 1250 bp = dupmsg(mp); 1251 if (bp == NULL) { 1252 continue; 1253 } 1254 1255 /* transmit the packet */ 1256 bp = vsw_tx_msg(vswp, bp, VSW_VNETPORT, portp); 1257 if (bp != NULL) { 1258 freemsg(bp); 1259 } 1260 } 1261 1262 freemsg(mp); 1263 } 1264 1265 static void 1266 vsw_mac_set_mtu(vsw_t *vswp, uint32_t mtu) 1267 { 1268 uint_t mtu_orig; 1269 int rv; 1270 1271 rv = mac_set_mtu(vswp->mh, mtu, &mtu_orig); 1272 if (rv != 0) { 1273 cmn_err(CE_NOTE, 1274 "!vsw%d: Unable to set the mtu:%d, in the " 1275 "physical device:%s\n", 1276 vswp->instance, mtu, vswp->physname); 1277 return; 1278 } 1279 1280 /* save the original mtu of physdev to reset it back later if needed */ 1281 vswp->mtu_physdev_orig = mtu_orig; 1282 } 1283 1284 /* 1285 * Register a callback with underlying mac layer for notifications. 1286 * We are currently interested in only link-state events. 1287 */ 1288 static int 1289 vsw_notify_add(vsw_t *vswp) 1290 { 1291 mac_notify_handle_t mnh; 1292 uint32_t note; 1293 1294 /* 1295 * Check if the underlying MAC supports link update notification. 1296 */ 1297 note = mac_no_notification(vswp->mh); 1298 if ((note & (DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN)) != 0) { 1299 vswp->phys_no_link_update = B_TRUE; 1300 } else { 1301 vswp->phys_no_link_update = B_FALSE; 1302 } 1303 1304 /* 1305 * Read the current link state of the device and cache it. 1306 */ 1307 vswp->phys_link_state = vswp->phys_no_link_update ? LINK_STATE_UP : 1308 mac_stat_get(vswp->mh, MAC_STAT_LINK_STATE); 1309 1310 /* 1311 * Add notify callback function, if link update is supported. 1312 */ 1313 if (vswp->phys_no_link_update == B_TRUE) { 1314 return (0); 1315 } 1316 1317 mnh = mac_notify_add(vswp->mh, vsw_notify_cb, vswp); 1318 if (mnh == 0) { 1319 /* failed */ 1320 return (1); 1321 } 1322 1323 vswp->mnh = mnh; 1324 return (0); 1325 } 1326 1327 /* 1328 * Remove notify callback. 1329 */ 1330 static int 1331 vsw_notify_rem(vsw_t *vswp) 1332 { 1333 int rv; 1334 1335 rv = mac_notify_remove(vswp->mnh, B_FALSE); 1336 return (rv); 1337 } 1338 1339 /* 1340 * Notification callback invoked by the MAC service 1341 * module. Note that we process only link state updates. 1342 */ 1343 static void 1344 vsw_notify_cb(void *arg, mac_notify_type_t type) 1345 { 1346 vsw_t *vswp = arg; 1347 1348 switch (type) { 1349 1350 case MAC_NOTE_LINK: 1351 vsw_notify_link(vswp); 1352 break; 1353 1354 default: 1355 break; 1356 1357 } 1358 } 1359 1360 /* 1361 * Invoked upon receiving a MAC_NOTE_LINK 1362 * notification for the underlying physical device. 1363 */ 1364 static void 1365 vsw_notify_link(vsw_t *vswp) 1366 { 1367 link_state_t link_state; 1368 1369 /* link state change notification */ 1370 link_state = mac_stat_get(vswp->mh, MAC_STAT_LINK_STATE); 1371 1372 if (vswp->phys_link_state != link_state) { 1373 D3(vswp, "%s: phys_link_state(%d)\n", 1374 __func__, vswp->phys_link_state); 1375 1376 vswp->phys_link_state = link_state; 1377 vsw_physlink_state_update(vswp); 1378 } 1379 } 1380 1381 /* 1382 * Configure the bandwidth limit on the vsw or vnet devices via the MAC layer. 1383 * Note that bandwidth limit is not supported on a HybridIO enabled 1384 * vnet, as the HybridIO assigns a specific unit of hardware resource 1385 * that cannot be changed to limit bandwidth. 1386 */ 1387 static void 1388 vsw_maccl_set_bandwidth(vsw_t *vswp, vsw_port_t *port, int type, uint64_t maxbw) 1389 { 1390 int rv = 0; 1391 uint64_t *bw; 1392 mac_resource_props_t mrp; 1393 mac_client_handle_t mch; 1394 1395 ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT)); 1396 1397 if (type == VSW_VNETPORT) { 1398 ASSERT(RW_WRITE_HELD(&port->maccl_rwlock)); 1399 mch = port->p_mch; 1400 bw = &port->p_bandwidth; 1401 } else { 1402 ASSERT(RW_WRITE_HELD(&vswp->maccl_rwlock)); 1403 mch = vswp->mch; 1404 bw = &vswp->bandwidth; 1405 } 1406 1407 if (mch == NULL) { 1408 return; 1409 } 1410 1411 if (maxbw >= MRP_MAXBW_MINVAL || maxbw == 0) { 1412 bzero(&mrp, sizeof (mac_resource_props_t)); 1413 if (maxbw == 0) { 1414 mrp.mrp_maxbw = MRP_MAXBW_RESETVAL; 1415 } else { 1416 mrp.mrp_maxbw = maxbw; 1417 } 1418 mrp.mrp_mask |= MRP_MAXBW; 1419 1420 rv = mac_client_set_resources(mch, &mrp); 1421 if (rv != 0) { 1422 if (type == VSW_VNETPORT) { 1423 cmn_err(CE_NOTE, "!port%d: cannot set " 1424 "bandwidth limit to (%ld), error(%d)\n", 1425 port->p_instance, maxbw, rv); 1426 } else { 1427 cmn_err(CE_NOTE, "!vsw%d: cannot set " 1428 "bandwidth limit to (%ld), error(%d)\n", 1429 vswp->instance, maxbw, rv); 1430 } 1431 } else { 1432 /* 1433 * update with successfully configured bandwidth. 1434 */ 1435 *bw = maxbw; 1436 } 1437 } 1438 } 1439