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 <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/ldc.h> 66 #include <sys/vsw_fdb.h> 67 #include <sys/vsw.h> 68 #include <sys/vio_mailbox.h> 69 #include <sys/vnet_mailbox.h> 70 #include <sys/vnet_common.h> 71 #include <sys/vio_util.h> 72 #include <sys/sdt.h> 73 #include <sys/atomic.h> 74 #include <sys/vlan.h> 75 76 /* Switching setup routines */ 77 void vsw_setup_switching_timeout(void *arg); 78 void vsw_stop_switching_timeout(vsw_t *vswp); 79 int vsw_setup_switching(vsw_t *); 80 void vsw_switch_frame_nop(vsw_t *vswp, mblk_t *mp, int caller, 81 vsw_port_t *port, mac_resource_handle_t mrh); 82 static int vsw_setup_layer2(vsw_t *); 83 static int vsw_setup_layer3(vsw_t *); 84 85 /* Switching/data transmit routines */ 86 static void vsw_switch_l2_frame(vsw_t *vswp, mblk_t *mp, int caller, 87 vsw_port_t *port, mac_resource_handle_t); 88 static void vsw_switch_l3_frame(vsw_t *vswp, mblk_t *mp, int caller, 89 vsw_port_t *port, mac_resource_handle_t); 90 static int vsw_forward_all(vsw_t *vswp, mblk_t *mp, 91 int caller, vsw_port_t *port); 92 static int vsw_forward_grp(vsw_t *vswp, mblk_t *mp, 93 int caller, vsw_port_t *port); 94 95 /* VLAN routines */ 96 void vsw_create_vlans(void *arg, int type); 97 void vsw_destroy_vlans(void *arg, int type); 98 void vsw_vlan_add_ids(void *arg, int type); 99 void vsw_vlan_remove_ids(void *arg, int type); 100 static void vsw_vlan_create_hash(void *arg, int type); 101 static void vsw_vlan_destroy_hash(void *arg, int type); 102 boolean_t vsw_frame_lookup_vid(void *arg, int caller, struct ether_header *ehp, 103 uint16_t *vidp); 104 mblk_t *vsw_vlan_frame_pretag(void *arg, int type, mblk_t *mp); 105 uint32_t vsw_vlan_frames_untag(void *arg, int type, mblk_t **np, mblk_t **npt); 106 boolean_t vsw_vlan_lookup(mod_hash_t *vlan_hashp, uint16_t vid); 107 108 /* Forwarding database (FDB) routines */ 109 void vsw_fdbe_add(vsw_t *vswp, void *port); 110 void vsw_fdbe_del(vsw_t *vswp, struct ether_addr *eaddr); 111 static vsw_fdbe_t *vsw_fdbe_find(vsw_t *vswp, struct ether_addr *); 112 static void vsw_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val); 113 114 int vsw_add_rem_mcst(vnet_mcast_msg_t *, vsw_port_t *); 115 int vsw_add_mcst(vsw_t *, uint8_t, uint64_t, void *); 116 int vsw_del_mcst(vsw_t *, uint8_t, uint64_t, void *); 117 void vsw_del_mcst_vsw(vsw_t *); 118 119 /* Support functions */ 120 static mblk_t *vsw_dupmsgchain(mblk_t *mp); 121 static uint32_t vsw_get_same_dest_list(struct ether_header *ehp, 122 mblk_t **rhead, mblk_t **rtail, mblk_t **mpp); 123 124 125 /* 126 * Functions imported from other files. 127 */ 128 extern mblk_t *vsw_tx_msg(vsw_t *, mblk_t *); 129 extern mcst_addr_t *vsw_del_addr(uint8_t, void *, uint64_t); 130 extern int vsw_mac_open(vsw_t *vswp); 131 extern void vsw_mac_close(vsw_t *vswp); 132 extern void vsw_mac_rx(vsw_t *vswp, mac_resource_handle_t mrh, 133 mblk_t *mp, vsw_macrx_flags_t flags); 134 extern void vsw_set_addrs(vsw_t *vswp); 135 extern int vsw_get_hw_maddr(vsw_t *); 136 extern int vsw_mac_attach(vsw_t *vswp); 137 extern int vsw_portsend(vsw_port_t *port, mblk_t *mp, mblk_t *mpt, 138 uint32_t count); 139 extern void vsw_hio_init(vsw_t *vswp); 140 extern void vsw_hio_start_ports(vsw_t *vswp); 141 142 /* 143 * Tunables used in this file. 144 */ 145 extern int vsw_setup_switching_delay; 146 extern uint32_t vsw_vlan_nchains; 147 extern uint32_t vsw_fdbe_refcnt_delay; 148 149 #define VSW_FDBE_REFHOLD(p) \ 150 { \ 151 atomic_inc_32(&(p)->refcnt); \ 152 ASSERT((p)->refcnt != 0); \ 153 } 154 155 #define VSW_FDBE_REFRELE(p) \ 156 { \ 157 ASSERT((p)->refcnt != 0); \ 158 atomic_dec_32(&(p)->refcnt); \ 159 } 160 161 /* 162 * Timeout routine to setup switching mode: 163 * vsw_setup_switching() is invoked from vsw_attach() or vsw_update_md_prop() 164 * initially. If it fails and the error is EAGAIN, then this timeout handler 165 * is started to retry vsw_setup_switching(). vsw_setup_switching() is retried 166 * until we successfully finish it; or the returned error is not EAGAIN. 167 */ 168 void 169 vsw_setup_switching_timeout(void *arg) 170 { 171 vsw_t *vswp = (vsw_t *)arg; 172 int rv; 173 174 if (vswp->swtmout_enabled == B_FALSE) 175 return; 176 177 rv = vsw_setup_switching(vswp); 178 179 if (rv == 0) { 180 /* 181 * Successfully setup switching mode. 182 * Program unicst, mcst addrs of vsw 183 * interface and ports in the physdev. 184 */ 185 vsw_set_addrs(vswp); 186 187 /* Start HIO for ports that have already connected */ 188 vsw_hio_start_ports(vswp); 189 } 190 191 mutex_enter(&vswp->swtmout_lock); 192 193 if (rv == EAGAIN && vswp->swtmout_enabled == B_TRUE) { 194 /* 195 * Reschedule timeout() if the error is EAGAIN and the 196 * timeout is still enabled. For errors other than EAGAIN, 197 * we simply return without rescheduling timeout(). 198 */ 199 vswp->swtmout_id = 200 timeout(vsw_setup_switching_timeout, vswp, 201 (vsw_setup_switching_delay * drv_usectohz(MICROSEC))); 202 goto exit; 203 } 204 205 /* timeout handler completed */ 206 vswp->swtmout_enabled = B_FALSE; 207 vswp->swtmout_id = 0; 208 209 exit: 210 mutex_exit(&vswp->swtmout_lock); 211 } 212 213 /* 214 * Cancel the timeout handler to setup switching mode. 215 */ 216 void 217 vsw_stop_switching_timeout(vsw_t *vswp) 218 { 219 timeout_id_t tid; 220 221 mutex_enter(&vswp->swtmout_lock); 222 223 tid = vswp->swtmout_id; 224 225 if (tid != 0) { 226 /* signal timeout handler to stop */ 227 vswp->swtmout_enabled = B_FALSE; 228 vswp->swtmout_id = 0; 229 mutex_exit(&vswp->swtmout_lock); 230 231 (void) untimeout(tid); 232 } else { 233 mutex_exit(&vswp->swtmout_lock); 234 } 235 236 (void) atomic_swap_32(&vswp->switching_setup_done, B_FALSE); 237 238 mutex_enter(&vswp->mac_lock); 239 vswp->mac_open_retries = 0; 240 mutex_exit(&vswp->mac_lock); 241 } 242 243 /* 244 * Setup the required switching mode. 245 * This routine is invoked from vsw_attach() or vsw_update_md_prop() 246 * initially. If it fails and the error is EAGAIN, then a timeout handler 247 * is started to retry vsw_setup_switching(), until it successfully finishes; 248 * or the returned error is not EAGAIN. 249 * 250 * Returns: 251 * 0 on success. 252 * EAGAIN if retry is needed. 253 * 1 on all other failures. 254 */ 255 int 256 vsw_setup_switching(vsw_t *vswp) 257 { 258 int i, rv = 1; 259 260 D1(vswp, "%s: enter", __func__); 261 262 /* 263 * Select best switching mode. 264 * Note that we start from the saved smode_idx. This is done as 265 * this routine can be called from the timeout handler to retry 266 * setting up a specific mode. Currently only the function which 267 * sets up layer2/promisc mode returns EAGAIN if the underlying 268 * physical device is not available yet, causing retries. 269 */ 270 for (i = vswp->smode_idx; i < vswp->smode_num; i++) { 271 vswp->smode_idx = i; 272 switch (vswp->smode[i]) { 273 case VSW_LAYER2: 274 case VSW_LAYER2_PROMISC: 275 rv = vsw_setup_layer2(vswp); 276 break; 277 278 case VSW_LAYER3: 279 rv = vsw_setup_layer3(vswp); 280 break; 281 282 default: 283 DERR(vswp, "unknown switch mode"); 284 break; 285 } 286 287 if ((rv == 0) || (rv == EAGAIN)) 288 break; 289 290 /* all other errors(rv != 0): continue & select the next mode */ 291 rv = 1; 292 } 293 294 if (rv && (rv != EAGAIN)) { 295 cmn_err(CE_WARN, "!vsw%d: Unable to setup specified " 296 "switching mode", vswp->instance); 297 } else if (rv == 0) { 298 (void) atomic_swap_32(&vswp->switching_setup_done, B_TRUE); 299 } 300 301 D2(vswp, "%s: Operating in mode %d", __func__, 302 vswp->smode[vswp->smode_idx]); 303 304 D1(vswp, "%s: exit", __func__); 305 306 return (rv); 307 } 308 309 /* 310 * Setup for layer 2 switching. 311 * 312 * Returns: 313 * 0 on success. 314 * EAGAIN if retry is needed. 315 * EIO on all other failures. 316 */ 317 static int 318 vsw_setup_layer2(vsw_t *vswp) 319 { 320 int rv; 321 322 D1(vswp, "%s: enter", __func__); 323 324 vswp->vsw_switch_frame = vsw_switch_l2_frame; 325 326 rv = strlen(vswp->physname); 327 if (rv == 0) { 328 /* 329 * Physical device name is NULL, which is 330 * required for layer 2. 331 */ 332 cmn_err(CE_WARN, "!vsw%d: no physical device name specified", 333 vswp->instance); 334 return (EIO); 335 } 336 337 mutex_enter(&vswp->mac_lock); 338 339 rv = vsw_mac_open(vswp); 340 if (rv != 0) { 341 if (rv != EAGAIN) { 342 cmn_err(CE_WARN, "!vsw%d: Unable to open physical " 343 "device: %s\n", vswp->instance, vswp->physname); 344 } 345 mutex_exit(&vswp->mac_lock); 346 return (rv); 347 } 348 349 if (vswp->smode[vswp->smode_idx] == VSW_LAYER2) { 350 /* 351 * Verify that underlying device can support multiple 352 * unicast mac addresses. 353 */ 354 rv = vsw_get_hw_maddr(vswp); 355 if (rv != 0) { 356 goto exit_error; 357 } 358 } 359 360 /* 361 * Attempt to link into the MAC layer so we can get 362 * and send packets out over the physical adapter. 363 */ 364 rv = vsw_mac_attach(vswp); 365 if (rv != 0) { 366 /* 367 * Registration with the MAC layer has failed, 368 * so return error so that can fall back to next 369 * prefered switching method. 370 */ 371 cmn_err(CE_WARN, "!vsw%d: Unable to setup physical device: " 372 "%s\n", vswp->instance, vswp->physname); 373 goto exit_error; 374 } 375 376 D1(vswp, "%s: exit", __func__); 377 378 mutex_exit(&vswp->mac_lock); 379 380 /* Initialize HybridIO related stuff */ 381 vsw_hio_init(vswp); 382 return (0); 383 384 exit_error: 385 vsw_mac_close(vswp); 386 mutex_exit(&vswp->mac_lock); 387 return (EIO); 388 } 389 390 static int 391 vsw_setup_layer3(vsw_t *vswp) 392 { 393 D1(vswp, "%s: enter", __func__); 394 395 D2(vswp, "%s: operating in layer 3 mode", __func__); 396 vswp->vsw_switch_frame = vsw_switch_l3_frame; 397 398 D1(vswp, "%s: exit", __func__); 399 400 return (0); 401 } 402 403 /* ARGSUSED */ 404 void 405 vsw_switch_frame_nop(vsw_t *vswp, mblk_t *mp, int caller, vsw_port_t *port, 406 mac_resource_handle_t mrh) 407 { 408 freemsgchain(mp); 409 } 410 411 /* 412 * Switch the given ethernet frame when operating in layer 2 mode. 413 * 414 * vswp: pointer to the vsw instance 415 * mp: pointer to chain of ethernet frame(s) to be switched 416 * caller: identifies the source of this frame as: 417 * 1. VSW_VNETPORT - a vsw port (connected to a vnet). 418 * 2. VSW_PHYSDEV - the physical ethernet device 419 * 3. VSW_LOCALDEV - vsw configured as a virtual interface 420 * arg: argument provided by the caller. 421 * 1. for VNETPORT - pointer to the corresponding vsw_port_t. 422 * 2. for PHYSDEV - NULL 423 * 3. for LOCALDEV - pointer to to this vsw_t(self) 424 */ 425 void 426 vsw_switch_l2_frame(vsw_t *vswp, mblk_t *mp, int caller, 427 vsw_port_t *arg, mac_resource_handle_t mrh) 428 { 429 struct ether_header *ehp; 430 mblk_t *bp, *ret_m; 431 mblk_t *mpt = NULL; 432 uint32_t count; 433 vsw_fdbe_t *fp; 434 435 D1(vswp, "%s: enter (caller %d)", __func__, caller); 436 437 /* 438 * PERF: rather than breaking up the chain here, scan it 439 * to find all mblks heading to same destination and then 440 * pass that sub-chain to the lower transmit functions. 441 */ 442 443 /* process the chain of packets */ 444 bp = mp; 445 while (bp) { 446 ehp = (struct ether_header *)bp->b_rptr; 447 count = vsw_get_same_dest_list(ehp, &mp, &mpt, &bp); 448 ASSERT(count != 0); 449 450 D2(vswp, "%s: mblk data buffer %lld : actual data size %lld", 451 __func__, MBLKSIZE(mp), MBLKL(mp)); 452 453 if (ether_cmp(&ehp->ether_dhost, &vswp->if_addr) == 0) { 454 /* 455 * If destination is VSW_LOCALDEV (vsw as an eth 456 * interface) and if the device is up & running, 457 * send the packet up the stack on this host. 458 * If the virtual interface is down, drop the packet. 459 */ 460 if (caller != VSW_LOCALDEV) { 461 vsw_mac_rx(vswp, mrh, mp, VSW_MACRX_FREEMSG); 462 } else { 463 freemsgchain(mp); 464 } 465 continue; 466 } 467 468 /* 469 * Find fdb entry for the destination 470 * and hold a reference to it. 471 */ 472 fp = vsw_fdbe_find(vswp, &ehp->ether_dhost); 473 if (fp != NULL) { 474 475 /* 476 * If plumbed and in promisc mode then copy msg 477 * and send up the stack. 478 */ 479 vsw_mac_rx(vswp, mrh, mp, 480 VSW_MACRX_PROMISC | VSW_MACRX_COPYMSG); 481 482 /* 483 * If the destination is in FDB, the packet 484 * should be forwarded to the correponding 485 * vsw_port (connected to a vnet device - 486 * VSW_VNETPORT) 487 */ 488 (void) vsw_portsend(fp->portp, mp, mpt, count); 489 490 /* Release the reference on the fdb entry */ 491 VSW_FDBE_REFRELE(fp); 492 } else { 493 /* 494 * Destination not in FDB. 495 * 496 * If the destination is broadcast or 497 * multicast forward the packet to all 498 * (VNETPORTs, PHYSDEV, LOCALDEV), 499 * except the caller. 500 */ 501 if (IS_BROADCAST(ehp)) { 502 D2(vswp, "%s: BROADCAST pkt", __func__); 503 (void) vsw_forward_all(vswp, mp, caller, arg); 504 } else if (IS_MULTICAST(ehp)) { 505 D2(vswp, "%s: MULTICAST pkt", __func__); 506 (void) vsw_forward_grp(vswp, mp, caller, arg); 507 } else { 508 /* 509 * If the destination is unicast, and came 510 * from either a logical network device or 511 * the switch itself when it is plumbed, then 512 * send it out on the physical device and also 513 * up the stack if the logical interface is 514 * in promiscious mode. 515 * 516 * NOTE: The assumption here is that if we 517 * cannot find the destination in our fdb, its 518 * a unicast address, and came from either a 519 * vnet or down the stack (when plumbed) it 520 * must be destinded for an ethernet device 521 * outside our ldoms. 522 */ 523 if (caller == VSW_VNETPORT) { 524 /* promisc check copy etc */ 525 vsw_mac_rx(vswp, mrh, mp, 526 VSW_MACRX_PROMISC | 527 VSW_MACRX_COPYMSG); 528 529 if ((ret_m = vsw_tx_msg(vswp, mp)) 530 != NULL) { 531 DERR(vswp, "%s: drop mblks to " 532 "phys dev", __func__); 533 freemsgchain(ret_m); 534 } 535 536 } else if (caller == VSW_PHYSDEV) { 537 /* 538 * Pkt seen because card in promisc 539 * mode. Send up stack if plumbed in 540 * promisc mode, else drop it. 541 */ 542 vsw_mac_rx(vswp, mrh, mp, 543 VSW_MACRX_PROMISC | 544 VSW_MACRX_FREEMSG); 545 546 } else if (caller == VSW_LOCALDEV) { 547 /* 548 * Pkt came down the stack, send out 549 * over physical device. 550 */ 551 if ((ret_m = vsw_tx_msg(vswp, mp)) 552 != NULL) { 553 DERR(vswp, "%s: drop mblks to " 554 "phys dev", __func__); 555 freemsgchain(ret_m); 556 } 557 } 558 } 559 } 560 } 561 D1(vswp, "%s: exit\n", __func__); 562 } 563 564 /* 565 * Switch ethernet frame when in layer 3 mode (i.e. using IP 566 * layer to do the routing). 567 * 568 * There is a large amount of overlap between this function and 569 * vsw_switch_l2_frame. At some stage we need to revisit and refactor 570 * both these functions. 571 */ 572 void 573 vsw_switch_l3_frame(vsw_t *vswp, mblk_t *mp, int caller, 574 vsw_port_t *arg, mac_resource_handle_t mrh) 575 { 576 struct ether_header *ehp; 577 mblk_t *bp = NULL; 578 mblk_t *mpt; 579 uint32_t count; 580 vsw_fdbe_t *fp; 581 582 D1(vswp, "%s: enter (caller %d)", __func__, caller); 583 584 /* 585 * In layer 3 mode should only ever be switching packets 586 * between IP layer and vnet devices. So make sure thats 587 * who is invoking us. 588 */ 589 if ((caller != VSW_LOCALDEV) && (caller != VSW_VNETPORT)) { 590 DERR(vswp, "%s: unexpected caller (%d)", __func__, caller); 591 freemsgchain(mp); 592 return; 593 } 594 595 /* process the chain of packets */ 596 bp = mp; 597 while (bp) { 598 ehp = (struct ether_header *)bp->b_rptr; 599 count = vsw_get_same_dest_list(ehp, &mp, &mpt, &bp); 600 ASSERT(count != 0); 601 602 D2(vswp, "%s: mblk data buffer %lld : actual data size %lld", 603 __func__, MBLKSIZE(mp), MBLKL(mp)); 604 605 /* 606 * Find fdb entry for the destination 607 * and hold a reference to it. 608 */ 609 fp = vsw_fdbe_find(vswp, &ehp->ether_dhost); 610 if (fp != NULL) { 611 612 D2(vswp, "%s: sending to target port", __func__); 613 (void) vsw_portsend(fp->portp, mp, mpt, count); 614 615 /* Release the reference on the fdb entry */ 616 VSW_FDBE_REFRELE(fp); 617 } else { 618 /* 619 * Destination not in FDB 620 * 621 * If the destination is broadcast or 622 * multicast forward the packet to all 623 * (VNETPORTs, PHYSDEV, LOCALDEV), 624 * except the caller. 625 */ 626 if (IS_BROADCAST(ehp)) { 627 D2(vswp, "%s: BROADCAST pkt", __func__); 628 (void) vsw_forward_all(vswp, mp, caller, arg); 629 } else if (IS_MULTICAST(ehp)) { 630 D2(vswp, "%s: MULTICAST pkt", __func__); 631 (void) vsw_forward_grp(vswp, mp, caller, arg); 632 } else { 633 /* 634 * Unicast pkt from vnet that we don't have 635 * an FDB entry for, so must be destinded for 636 * the outside world. Attempt to send up to the 637 * IP layer to allow it to deal with it. 638 */ 639 if (caller == VSW_VNETPORT) { 640 vsw_mac_rx(vswp, mrh, 641 mp, VSW_MACRX_FREEMSG); 642 } 643 } 644 } 645 } 646 647 D1(vswp, "%s: exit", __func__); 648 } 649 650 /* 651 * Forward the ethernet frame to all ports (VNETPORTs, PHYSDEV, LOCALDEV), 652 * except the caller (port on which frame arrived). 653 */ 654 static int 655 vsw_forward_all(vsw_t *vswp, mblk_t *mp, int caller, vsw_port_t *arg) 656 { 657 vsw_port_list_t *plist = &vswp->plist; 658 vsw_port_t *portp; 659 mblk_t *nmp = NULL; 660 mblk_t *ret_m = NULL; 661 int skip_port = 0; 662 663 D1(vswp, "vsw_forward_all: enter\n"); 664 665 /* 666 * Broadcast message from inside ldoms so send to outside 667 * world if in either of layer 2 modes. 668 */ 669 if (((vswp->smode[vswp->smode_idx] == VSW_LAYER2) || 670 (vswp->smode[vswp->smode_idx] == VSW_LAYER2_PROMISC)) && 671 ((caller == VSW_LOCALDEV) || (caller == VSW_VNETPORT))) { 672 673 nmp = vsw_dupmsgchain(mp); 674 if (nmp) { 675 if ((ret_m = vsw_tx_msg(vswp, nmp)) != NULL) { 676 DERR(vswp, "%s: dropping pkt(s) " 677 "consisting of %ld bytes of data for" 678 " physical device", __func__, MBLKL(ret_m)); 679 freemsgchain(ret_m); 680 } 681 } 682 } 683 684 if (caller == VSW_VNETPORT) 685 skip_port = 1; 686 687 /* 688 * Broadcast message from other vnet (layer 2 or 3) or outside 689 * world (layer 2 only), send up stack if plumbed. 690 */ 691 if ((caller == VSW_PHYSDEV) || (caller == VSW_VNETPORT)) { 692 vsw_mac_rx(vswp, NULL, mp, VSW_MACRX_COPYMSG); 693 } 694 695 /* send it to all VNETPORTs */ 696 READ_ENTER(&plist->lockrw); 697 for (portp = plist->head; portp != NULL; portp = portp->p_next) { 698 D2(vswp, "vsw_forward_all: port %d", portp->p_instance); 699 /* 700 * Caution ! - don't reorder these two checks as arg 701 * will be NULL if the caller is PHYSDEV. skip_port is 702 * only set if caller is VNETPORT. 703 */ 704 if ((skip_port) && (portp == arg)) { 705 continue; 706 } else { 707 nmp = vsw_dupmsgchain(mp); 708 if (nmp) { 709 mblk_t *mpt = nmp; 710 uint32_t count = 1; 711 712 /* Find tail */ 713 while (mpt->b_next != NULL) { 714 mpt = mpt->b_next; 715 count++; 716 } 717 /* 718 * The plist->lockrw is protecting the 719 * portp from getting destroyed here. 720 * So, no ref_cnt is incremented here. 721 */ 722 (void) vsw_portsend(portp, nmp, mpt, count); 723 } else { 724 DERR(vswp, "vsw_forward_all: nmp NULL"); 725 } 726 } 727 } 728 RW_EXIT(&plist->lockrw); 729 730 freemsgchain(mp); 731 732 D1(vswp, "vsw_forward_all: exit\n"); 733 return (0); 734 } 735 736 /* 737 * Forward pkts to any devices or interfaces which have registered 738 * an interest in them (i.e. multicast groups). 739 */ 740 static int 741 vsw_forward_grp(vsw_t *vswp, mblk_t *mp, int caller, vsw_port_t *arg) 742 { 743 struct ether_header *ehp = (struct ether_header *)mp->b_rptr; 744 mfdb_ent_t *entp = NULL; 745 mfdb_ent_t *tpp = NULL; 746 vsw_port_t *port; 747 uint64_t key = 0; 748 mblk_t *nmp = NULL; 749 mblk_t *ret_m = NULL; 750 boolean_t check_if = B_TRUE; 751 752 /* 753 * Convert address to hash table key 754 */ 755 KEY_HASH(key, &ehp->ether_dhost); 756 757 D1(vswp, "%s: key 0x%llx", __func__, key); 758 759 /* 760 * If pkt came from either a vnet or down the stack (if we are 761 * plumbed) and we are in layer 2 mode, then we send the pkt out 762 * over the physical adapter, and then check to see if any other 763 * vnets are interested in it. 764 */ 765 if (((vswp->smode[vswp->smode_idx] == VSW_LAYER2) || 766 (vswp->smode[vswp->smode_idx] == VSW_LAYER2_PROMISC)) && 767 ((caller == VSW_VNETPORT) || (caller == VSW_LOCALDEV))) { 768 nmp = vsw_dupmsgchain(mp); 769 if (nmp) { 770 if ((ret_m = vsw_tx_msg(vswp, nmp)) != NULL) { 771 DERR(vswp, "%s: dropping pkt(s) consisting of " 772 "%ld bytes of data for physical device", 773 __func__, MBLKL(ret_m)); 774 freemsgchain(ret_m); 775 } 776 } 777 } 778 779 READ_ENTER(&vswp->mfdbrw); 780 if (mod_hash_find(vswp->mfdb, (mod_hash_key_t)key, 781 (mod_hash_val_t *)&entp) != 0) { 782 D3(vswp, "%s: no table entry found for addr 0x%llx", 783 __func__, key); 784 } else { 785 /* 786 * Send to list of devices associated with this address... 787 */ 788 for (tpp = entp; tpp != NULL; tpp = tpp->nextp) { 789 790 /* dont send to ourselves */ 791 if ((caller == VSW_VNETPORT) && 792 (tpp->d_addr == (void *)arg)) { 793 port = (vsw_port_t *)tpp->d_addr; 794 D3(vswp, "%s: not sending to ourselves" 795 " : port %d", __func__, port->p_instance); 796 continue; 797 798 } else if ((caller == VSW_LOCALDEV) && 799 (tpp->d_type == VSW_LOCALDEV)) { 800 D2(vswp, "%s: not sending back up stack", 801 __func__); 802 continue; 803 } 804 805 if (tpp->d_type == VSW_VNETPORT) { 806 port = (vsw_port_t *)tpp->d_addr; 807 D3(vswp, "%s: sending to port %ld for addr " 808 "0x%llx", __func__, port->p_instance, key); 809 810 nmp = vsw_dupmsgchain(mp); 811 if (nmp) { 812 mblk_t *mpt = nmp; 813 uint32_t count = 1; 814 815 /* Find tail */ 816 while (mpt->b_next != NULL) { 817 mpt = mpt->b_next; 818 count++; 819 } 820 /* 821 * The vswp->mfdbrw is protecting the 822 * portp from getting destroyed here. 823 * So, no ref_cnt is incremented here. 824 */ 825 (void) vsw_portsend(port, nmp, mpt, 826 count); 827 } 828 } else { 829 vsw_mac_rx(vswp, NULL, 830 mp, VSW_MACRX_COPYMSG); 831 D2(vswp, "%s: sending up stack" 832 " for addr 0x%llx", __func__, key); 833 check_if = B_FALSE; 834 } 835 } 836 } 837 838 RW_EXIT(&vswp->mfdbrw); 839 840 /* 841 * If the pkt came from either a vnet or from physical device, 842 * and if we havent already sent the pkt up the stack then we 843 * check now if we can/should (i.e. the interface is plumbed 844 * and in promisc mode). 845 */ 846 if ((check_if) && 847 ((caller == VSW_VNETPORT) || (caller == VSW_PHYSDEV))) { 848 vsw_mac_rx(vswp, NULL, mp, 849 VSW_MACRX_PROMISC | VSW_MACRX_COPYMSG); 850 } 851 852 freemsgchain(mp); 853 854 D1(vswp, "%s: exit", __func__); 855 856 return (0); 857 } 858 859 /* 860 * This function creates the vlan id hash table for the given vsw device or 861 * port. It then adds each vlan that the device or port has been assigned, 862 * into this hash table. 863 * Arguments: 864 * arg: vsw device or port. 865 * type: type of arg; VSW_LOCALDEV(vsw device) or VSW_VNETPORT(port). 866 */ 867 void 868 vsw_create_vlans(void *arg, int type) 869 { 870 /* create vlan hash table */ 871 vsw_vlan_create_hash(arg, type); 872 873 /* add vlan ids of the vsw device into its hash table */ 874 vsw_vlan_add_ids(arg, type); 875 } 876 877 /* 878 * This function removes the vlan ids of the vsw device or port from its hash 879 * table. It then destroys the vlan hash table. 880 * Arguments: 881 * arg: vsw device or port. 882 * type: type of arg; VSW_LOCALDEV(vsw device) or VSW_VNETPORT(port). 883 */ 884 void 885 vsw_destroy_vlans(void *arg, int type) 886 { 887 /* remove vlan ids from the hash table */ 888 vsw_vlan_remove_ids(arg, type); 889 890 /* destroy vlan-hash-table */ 891 vsw_vlan_destroy_hash(arg, type); 892 } 893 894 /* 895 * Create a vlan-id hash table for the given vsw device or port. 896 */ 897 static void 898 vsw_vlan_create_hash(void *arg, int type) 899 { 900 char hashname[MAXNAMELEN]; 901 902 if (type == VSW_LOCALDEV) { 903 vsw_t *vswp = (vsw_t *)arg; 904 905 (void) snprintf(hashname, MAXNAMELEN, "vsw%d-vlan-hash", 906 vswp->instance); 907 908 vswp->vlan_nchains = vsw_vlan_nchains; 909 vswp->vlan_hashp = mod_hash_create_idhash(hashname, 910 vswp->vlan_nchains, mod_hash_null_valdtor); 911 912 } else if (type == VSW_VNETPORT) { 913 vsw_port_t *portp = (vsw_port_t *)arg; 914 915 (void) snprintf(hashname, MAXNAMELEN, "port%d-vlan-hash", 916 portp->p_instance); 917 918 portp->vlan_nchains = vsw_vlan_nchains; 919 portp->vlan_hashp = mod_hash_create_idhash(hashname, 920 portp->vlan_nchains, mod_hash_null_valdtor); 921 922 } else { 923 return; 924 } 925 } 926 927 /* 928 * Destroy the vlan-id hash table for the given vsw device or port. 929 */ 930 static void 931 vsw_vlan_destroy_hash(void *arg, int type) 932 { 933 if (type == VSW_LOCALDEV) { 934 vsw_t *vswp = (vsw_t *)arg; 935 936 mod_hash_destroy_hash(vswp->vlan_hashp); 937 vswp->vlan_nchains = 0; 938 } else if (type == VSW_VNETPORT) { 939 vsw_port_t *portp = (vsw_port_t *)arg; 940 941 mod_hash_destroy_hash(portp->vlan_hashp); 942 portp->vlan_nchains = 0; 943 } else { 944 return; 945 } 946 } 947 948 /* 949 * Add vlan ids of the given vsw device or port into its hash table. 950 */ 951 void 952 vsw_vlan_add_ids(void *arg, int type) 953 { 954 int rv; 955 int i; 956 957 if (type == VSW_LOCALDEV) { 958 vsw_t *vswp = (vsw_t *)arg; 959 960 rv = mod_hash_insert(vswp->vlan_hashp, 961 (mod_hash_key_t)VLAN_ID_KEY(vswp->pvid), 962 (mod_hash_val_t)B_TRUE); 963 ASSERT(rv == 0); 964 965 for (i = 0; i < vswp->nvids; i++) { 966 rv = mod_hash_insert(vswp->vlan_hashp, 967 (mod_hash_key_t)VLAN_ID_KEY(vswp->vids[i]), 968 (mod_hash_val_t)B_TRUE); 969 ASSERT(rv == 0); 970 } 971 972 } else if (type == VSW_VNETPORT) { 973 vsw_port_t *portp = (vsw_port_t *)arg; 974 975 rv = mod_hash_insert(portp->vlan_hashp, 976 (mod_hash_key_t)VLAN_ID_KEY(portp->pvid), 977 (mod_hash_val_t)B_TRUE); 978 ASSERT(rv == 0); 979 980 for (i = 0; i < portp->nvids; i++) { 981 rv = mod_hash_insert(portp->vlan_hashp, 982 (mod_hash_key_t)VLAN_ID_KEY(portp->vids[i]), 983 (mod_hash_val_t)B_TRUE); 984 ASSERT(rv == 0); 985 } 986 987 } else { 988 return; 989 } 990 } 991 992 /* 993 * Remove vlan ids of the given vsw device or port from its hash table. 994 */ 995 void 996 vsw_vlan_remove_ids(void *arg, int type) 997 { 998 mod_hash_val_t vp; 999 int rv; 1000 int i; 1001 1002 if (type == VSW_LOCALDEV) { 1003 vsw_t *vswp = (vsw_t *)arg; 1004 1005 rv = vsw_vlan_lookup(vswp->vlan_hashp, vswp->pvid); 1006 if (rv == B_TRUE) { 1007 rv = mod_hash_remove(vswp->vlan_hashp, 1008 (mod_hash_key_t)VLAN_ID_KEY(vswp->pvid), 1009 (mod_hash_val_t *)&vp); 1010 ASSERT(rv == 0); 1011 } 1012 1013 for (i = 0; i < vswp->nvids; i++) { 1014 rv = vsw_vlan_lookup(vswp->vlan_hashp, vswp->vids[i]); 1015 if (rv == B_TRUE) { 1016 rv = mod_hash_remove(vswp->vlan_hashp, 1017 (mod_hash_key_t)VLAN_ID_KEY(vswp->vids[i]), 1018 (mod_hash_val_t *)&vp); 1019 ASSERT(rv == 0); 1020 } 1021 } 1022 1023 } else if (type == VSW_VNETPORT) { 1024 vsw_port_t *portp = (vsw_port_t *)arg; 1025 1026 portp = (vsw_port_t *)arg; 1027 rv = vsw_vlan_lookup(portp->vlan_hashp, portp->pvid); 1028 if (rv == B_TRUE) { 1029 rv = mod_hash_remove(portp->vlan_hashp, 1030 (mod_hash_key_t)VLAN_ID_KEY(portp->pvid), 1031 (mod_hash_val_t *)&vp); 1032 ASSERT(rv == 0); 1033 } 1034 1035 for (i = 0; i < portp->nvids; i++) { 1036 rv = vsw_vlan_lookup(portp->vlan_hashp, portp->vids[i]); 1037 if (rv == B_TRUE) { 1038 rv = mod_hash_remove(portp->vlan_hashp, 1039 (mod_hash_key_t)VLAN_ID_KEY(portp->vids[i]), 1040 (mod_hash_val_t *)&vp); 1041 ASSERT(rv == 0); 1042 } 1043 } 1044 1045 } else { 1046 return; 1047 } 1048 } 1049 1050 /* 1051 * Find the given vlan id in the hash table. 1052 * Return: B_TRUE if the id is found; B_FALSE if not found. 1053 */ 1054 boolean_t 1055 vsw_vlan_lookup(mod_hash_t *vlan_hashp, uint16_t vid) 1056 { 1057 int rv; 1058 mod_hash_val_t vp; 1059 1060 rv = mod_hash_find(vlan_hashp, VLAN_ID_KEY(vid), (mod_hash_val_t *)&vp); 1061 1062 if (rv != 0) 1063 return (B_FALSE); 1064 1065 return (B_TRUE); 1066 } 1067 1068 /* 1069 * Add an entry into FDB for the given vsw. 1070 */ 1071 void 1072 vsw_fdbe_add(vsw_t *vswp, void *port) 1073 { 1074 uint64_t addr = 0; 1075 vsw_port_t *portp; 1076 vsw_fdbe_t *fp; 1077 int rv; 1078 1079 portp = (vsw_port_t *)port; 1080 KEY_HASH(addr, &portp->p_macaddr); 1081 1082 fp = kmem_zalloc(sizeof (vsw_fdbe_t), KM_SLEEP); 1083 fp->portp = port; 1084 1085 /* 1086 * Note: duplicate keys will be rejected by mod_hash. 1087 */ 1088 rv = mod_hash_insert(vswp->fdb_hashp, (mod_hash_key_t)addr, 1089 (mod_hash_val_t)fp); 1090 ASSERT(rv == 0); 1091 } 1092 1093 /* 1094 * Remove an entry from FDB. 1095 */ 1096 void 1097 vsw_fdbe_del(vsw_t *vswp, struct ether_addr *eaddr) 1098 { 1099 uint64_t addr = 0; 1100 vsw_fdbe_t *fp; 1101 int rv; 1102 1103 KEY_HASH(addr, eaddr); 1104 1105 /* 1106 * Remove the entry from fdb hash table. 1107 * This prevents further references to this fdb entry. 1108 */ 1109 rv = mod_hash_remove(vswp->fdb_hashp, (mod_hash_key_t)addr, 1110 (mod_hash_val_t *)&fp); 1111 if (rv != 0) { 1112 /* invalid key? */ 1113 return; 1114 } 1115 1116 /* 1117 * If there are threads already ref holding before the entry was 1118 * removed from hash table, then wait for ref count to drop to zero. 1119 */ 1120 while (fp->refcnt != 0) { 1121 delay(drv_usectohz(vsw_fdbe_refcnt_delay)); 1122 } 1123 1124 kmem_free(fp, sizeof (*fp)); 1125 } 1126 1127 /* 1128 * Search fdb for a given mac address. If an entry is found, hold 1129 * a reference to it and return the entry, else returns NULL. 1130 */ 1131 static vsw_fdbe_t * 1132 vsw_fdbe_find(vsw_t *vswp, struct ether_addr *addrp) 1133 { 1134 uint64_t key = 0; 1135 vsw_fdbe_t *fp; 1136 int rv; 1137 1138 KEY_HASH(key, addrp); 1139 1140 rv = mod_hash_find_cb(vswp->fdb_hashp, (mod_hash_key_t)key, 1141 (mod_hash_val_t *)&fp, vsw_fdbe_find_cb); 1142 1143 if (rv != 0) 1144 return (NULL); 1145 1146 return (fp); 1147 } 1148 1149 /* 1150 * Callback function provided to mod_hash_find_cb(). After finding the fdb 1151 * entry corresponding to the key (macaddr), this callback will be invoked by 1152 * mod_hash_find_cb() to atomically increment the reference count on the fdb 1153 * entry before returning the found entry. 1154 */ 1155 static void 1156 vsw_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val) 1157 { 1158 _NOTE(ARGUNUSED(key)) 1159 VSW_FDBE_REFHOLD((vsw_fdbe_t *)val); 1160 } 1161 1162 /* 1163 * A given frame must be always tagged with the appropriate vlan id (unless it 1164 * is in the default-vlan) before the mac address switching function is called. 1165 * Otherwise, after switching function determines the destination, we cannot 1166 * figure out if the destination belongs to the the same vlan that the frame 1167 * originated from and if it needs tag/untag. Frames which are inbound from 1168 * the external(physical) network over a vlan trunk link are always tagged. 1169 * However frames which are received from a vnet-port over ldc or frames which 1170 * are coming down the stack on the service domain over vsw interface may be 1171 * untagged. These frames must be tagged with the appropriate pvid of the 1172 * sender (vnet-port or vsw device), before invoking the switching function. 1173 * 1174 * Arguments: 1175 * arg: caller of the function. 1176 * type: type of arg(caller): VSW_LOCALDEV(vsw) or VSW_VNETPORT(port) 1177 * mp: frame(s) to be tagged. 1178 */ 1179 mblk_t * 1180 vsw_vlan_frame_pretag(void *arg, int type, mblk_t *mp) 1181 { 1182 vsw_t *vswp; 1183 vsw_port_t *portp; 1184 struct ether_header *ehp; 1185 mblk_t *bp; 1186 mblk_t *bpt; 1187 mblk_t *bph; 1188 mblk_t *bpn; 1189 uint16_t pvid; 1190 1191 ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT)); 1192 1193 if (type == VSW_LOCALDEV) { 1194 vswp = (vsw_t *)arg; 1195 pvid = vswp->pvid; 1196 portp = NULL; 1197 } else { 1198 /* VSW_VNETPORT */ 1199 portp = (vsw_port_t *)arg; 1200 pvid = portp->pvid; 1201 vswp = portp->p_vswp; 1202 } 1203 1204 bpn = bph = bpt = NULL; 1205 1206 for (bp = mp; bp != NULL; bp = bpn) { 1207 1208 bpn = bp->b_next; 1209 bp->b_next = bp->b_prev = NULL; 1210 1211 /* Determine if it is an untagged frame */ 1212 ehp = (struct ether_header *)bp->b_rptr; 1213 1214 if (ehp->ether_type != ETHERTYPE_VLAN) { /* untagged */ 1215 1216 /* no need to tag if the frame is in default vlan */ 1217 if (pvid != vswp->default_vlan_id) { 1218 bp = vnet_vlan_insert_tag(bp, pvid); 1219 if (bp == NULL) { 1220 continue; 1221 } 1222 } 1223 } 1224 1225 /* build a chain of processed packets */ 1226 if (bph == NULL) { 1227 bph = bpt = bp; 1228 } else { 1229 bpt->b_next = bp; 1230 bpt = bp; 1231 } 1232 1233 } 1234 1235 return (bph); 1236 } 1237 1238 /* 1239 * Frames destined to a vnet-port or to the local vsw interface, must be 1240 * untagged if necessary before sending. This function first checks that the 1241 * frame can be sent to the destination in the vlan identified by the frame 1242 * tag. Note that when this function is invoked the frame must have been 1243 * already tagged (unless it is in the default-vlan). Because, this function is 1244 * called when the switching function determines the destination and invokes 1245 * its send function (vnet-port or vsw interface) and all frames would have 1246 * been tagged by this time (see comments in vsw_vlan_frame_pretag()). 1247 * 1248 * Arguments: 1249 * arg: destination device. 1250 * type: type of arg(destination): VSW_LOCALDEV(vsw) or VSW_VNETPORT(port) 1251 * np: head of pkt chain to be validated and untagged. 1252 * npt: tail of pkt chain to be validated and untagged. 1253 * 1254 * Returns: 1255 * np: head of updated chain of packets 1256 * npt: tail of updated chain of packets 1257 * rv: count of any packets dropped 1258 */ 1259 uint32_t 1260 vsw_vlan_frame_untag(void *arg, int type, mblk_t **np, mblk_t **npt) 1261 { 1262 mblk_t *bp; 1263 mblk_t *bpt; 1264 mblk_t *bph; 1265 mblk_t *bpn; 1266 vsw_port_t *portp; 1267 vsw_t *vswp; 1268 uint32_t count; 1269 struct ether_header *ehp; 1270 boolean_t is_tagged; 1271 boolean_t rv; 1272 uint16_t vlan_id; 1273 uint16_t pvid; 1274 mod_hash_t *vlan_hashp; 1275 1276 ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT)); 1277 1278 if (type == VSW_LOCALDEV) { 1279 vswp = (vsw_t *)arg; 1280 pvid = vswp->pvid; 1281 vlan_hashp = vswp->vlan_hashp; 1282 portp = NULL; 1283 } else { 1284 /* type == VSW_VNETPORT */ 1285 portp = (vsw_port_t *)arg; 1286 vswp = portp->p_vswp; 1287 vlan_hashp = portp->vlan_hashp; 1288 pvid = portp->pvid; 1289 } 1290 1291 bpn = bph = bpt = NULL; 1292 count = 0; 1293 1294 for (bp = *np; bp != NULL; bp = bpn) { 1295 1296 bpn = bp->b_next; 1297 bp->b_next = bp->b_prev = NULL; 1298 1299 /* 1300 * Determine the vlan id that the frame belongs to. 1301 */ 1302 ehp = (struct ether_header *)bp->b_rptr; 1303 is_tagged = vsw_frame_lookup_vid(arg, type, ehp, &vlan_id); 1304 1305 /* 1306 * Check if the destination is in the same vlan. 1307 */ 1308 rv = vsw_vlan_lookup(vlan_hashp, vlan_id); 1309 if (rv == B_FALSE) { 1310 /* drop the packet */ 1311 freemsg(bp); 1312 count++; 1313 continue; 1314 } 1315 1316 /* 1317 * Check the frame header if tag/untag is needed. 1318 */ 1319 if (is_tagged == B_FALSE) { 1320 /* 1321 * Untagged frame. We shouldn't have an untagged 1322 * packet at this point, unless the destination's 1323 * vlan id is default-vlan-id; if it is not the 1324 * default-vlan-id, we drop the packet. 1325 */ 1326 if (vlan_id != vswp->default_vlan_id) { 1327 /* drop the packet */ 1328 freemsg(bp); 1329 count++; 1330 continue; 1331 } 1332 } else { 1333 /* 1334 * Tagged frame, untag if it's the destination's pvid. 1335 */ 1336 if (vlan_id == pvid) { 1337 1338 bp = vnet_vlan_remove_tag(bp); 1339 if (bp == NULL) { 1340 /* packet dropped */ 1341 count++; 1342 continue; 1343 } 1344 } 1345 } 1346 1347 /* build a chain of processed packets */ 1348 if (bph == NULL) { 1349 bph = bpt = bp; 1350 } else { 1351 bpt->b_next = bp; 1352 bpt = bp; 1353 } 1354 1355 } 1356 1357 *np = bph; 1358 *npt = bpt; 1359 1360 return (count); 1361 } 1362 1363 /* 1364 * Lookup the vlan id of the given frame. If it is a vlan-tagged frame, 1365 * then the vlan-id is available in the tag; otherwise, its vlan id is 1366 * implicitly obtained based on the caller (destination of the frame: 1367 * VSW_VNETPORT or VSW_LOCALDEV). 1368 * The vlan id determined is returned in vidp. 1369 * Returns: B_TRUE if it is a tagged frame; B_FALSE if it is untagged. 1370 */ 1371 boolean_t 1372 vsw_frame_lookup_vid(void *arg, int caller, struct ether_header *ehp, 1373 uint16_t *vidp) 1374 { 1375 struct ether_vlan_header *evhp; 1376 vsw_t *vswp; 1377 vsw_port_t *portp; 1378 1379 /* If it's a tagged frame, get the vid from vlan header */ 1380 if (ehp->ether_type == ETHERTYPE_VLAN) { 1381 1382 evhp = (struct ether_vlan_header *)ehp; 1383 *vidp = VLAN_ID(ntohs(evhp->ether_tci)); 1384 return (B_TRUE); 1385 } 1386 1387 /* Untagged frame; determine vlan id based on caller */ 1388 switch (caller) { 1389 1390 case VSW_VNETPORT: 1391 /* 1392 * packet destined to a vnet; vlan-id is pvid of vnet-port. 1393 */ 1394 portp = (vsw_port_t *)arg; 1395 *vidp = portp->pvid; 1396 break; 1397 1398 case VSW_LOCALDEV: 1399 1400 /* 1401 * packet destined to vsw interface; 1402 * vlan-id is port-vlan-id of vsw device. 1403 */ 1404 vswp = (vsw_t *)arg; 1405 *vidp = vswp->pvid; 1406 break; 1407 } 1408 1409 return (B_FALSE); 1410 } 1411 1412 /* 1413 * Add or remove multicast address(es). 1414 * 1415 * Returns 0 on success, 1 on failure. 1416 */ 1417 int 1418 vsw_add_rem_mcst(vnet_mcast_msg_t *mcst_pkt, vsw_port_t *port) 1419 { 1420 mcst_addr_t *mcst_p = NULL; 1421 vsw_t *vswp = port->p_vswp; 1422 uint64_t addr = 0x0; 1423 int i; 1424 1425 D1(vswp, "%s: enter", __func__); 1426 1427 D2(vswp, "%s: %d addresses", __func__, mcst_pkt->count); 1428 1429 for (i = 0; i < mcst_pkt->count; i++) { 1430 /* 1431 * Convert address into form that can be used 1432 * as hash table key. 1433 */ 1434 KEY_HASH(addr, &(mcst_pkt->mca[i])); 1435 1436 /* 1437 * Add or delete the specified address/port combination. 1438 */ 1439 if (mcst_pkt->set == 0x1) { 1440 D3(vswp, "%s: adding multicast address 0x%llx for " 1441 "port %ld", __func__, addr, port->p_instance); 1442 if (vsw_add_mcst(vswp, VSW_VNETPORT, addr, port) == 0) { 1443 /* 1444 * Update the list of multicast 1445 * addresses contained within the 1446 * port structure to include this new 1447 * one. 1448 */ 1449 mcst_p = kmem_zalloc(sizeof (mcst_addr_t), 1450 KM_NOSLEEP); 1451 if (mcst_p == NULL) { 1452 DERR(vswp, "%s: unable to alloc mem", 1453 __func__); 1454 (void) vsw_del_mcst(vswp, 1455 VSW_VNETPORT, addr, port); 1456 return (1); 1457 } 1458 1459 mcst_p->nextp = NULL; 1460 mcst_p->addr = addr; 1461 ether_copy(&mcst_pkt->mca[i], &mcst_p->mca); 1462 1463 /* 1464 * Program the address into HW. If the addr 1465 * has already been programmed then the MAC 1466 * just increments a ref counter (which is 1467 * used when the address is being deleted) 1468 */ 1469 mutex_enter(&vswp->mac_lock); 1470 if (vswp->mh != NULL) { 1471 if (mac_multicst_add(vswp->mh, 1472 (uchar_t *)&mcst_pkt->mca[i])) { 1473 mutex_exit(&vswp->mac_lock); 1474 cmn_err(CE_WARN, "!vsw%d: " 1475 "unable to add multicast " 1476 "address: %s\n", 1477 vswp->instance, 1478 ether_sprintf((void *) 1479 &mcst_p->mca)); 1480 (void) vsw_del_mcst(vswp, 1481 VSW_VNETPORT, addr, port); 1482 kmem_free(mcst_p, 1483 sizeof (*mcst_p)); 1484 return (1); 1485 } 1486 mcst_p->mac_added = B_TRUE; 1487 } 1488 mutex_exit(&vswp->mac_lock); 1489 1490 mutex_enter(&port->mca_lock); 1491 mcst_p->nextp = port->mcap; 1492 port->mcap = mcst_p; 1493 mutex_exit(&port->mca_lock); 1494 1495 } else { 1496 DERR(vswp, "%s: error adding multicast " 1497 "address 0x%llx for port %ld", 1498 __func__, addr, port->p_instance); 1499 return (1); 1500 } 1501 } else { 1502 /* 1503 * Delete an entry from the multicast hash 1504 * table and update the address list 1505 * appropriately. 1506 */ 1507 if (vsw_del_mcst(vswp, VSW_VNETPORT, addr, port) == 0) { 1508 D3(vswp, "%s: deleting multicast address " 1509 "0x%llx for port %ld", __func__, addr, 1510 port->p_instance); 1511 1512 mcst_p = vsw_del_addr(VSW_VNETPORT, port, addr); 1513 ASSERT(mcst_p != NULL); 1514 1515 /* 1516 * Remove the address from HW. The address 1517 * will actually only be removed once the ref 1518 * count within the MAC layer has dropped to 1519 * zero. I.e. we can safely call this fn even 1520 * if other ports are interested in this 1521 * address. 1522 */ 1523 mutex_enter(&vswp->mac_lock); 1524 if (vswp->mh != NULL && mcst_p->mac_added) { 1525 if (mac_multicst_remove(vswp->mh, 1526 (uchar_t *)&mcst_pkt->mca[i])) { 1527 mutex_exit(&vswp->mac_lock); 1528 cmn_err(CE_WARN, "!vsw%d: " 1529 "unable to remove mcast " 1530 "address: %s\n", 1531 vswp->instance, 1532 ether_sprintf((void *) 1533 &mcst_p->mca)); 1534 kmem_free(mcst_p, 1535 sizeof (*mcst_p)); 1536 return (1); 1537 } 1538 mcst_p->mac_added = B_FALSE; 1539 } 1540 mutex_exit(&vswp->mac_lock); 1541 kmem_free(mcst_p, sizeof (*mcst_p)); 1542 1543 } else { 1544 DERR(vswp, "%s: error deleting multicast " 1545 "addr 0x%llx for port %ld", 1546 __func__, addr, port->p_instance); 1547 return (1); 1548 } 1549 } 1550 } 1551 D1(vswp, "%s: exit", __func__); 1552 return (0); 1553 } 1554 1555 /* 1556 * Add a new multicast entry. 1557 * 1558 * Search hash table based on address. If match found then 1559 * update associated val (which is chain of ports), otherwise 1560 * create new key/val (addr/port) pair and insert into table. 1561 */ 1562 int 1563 vsw_add_mcst(vsw_t *vswp, uint8_t devtype, uint64_t addr, void *arg) 1564 { 1565 int dup = 0; 1566 int rv = 0; 1567 mfdb_ent_t *ment = NULL; 1568 mfdb_ent_t *tmp_ent = NULL; 1569 mfdb_ent_t *new_ent = NULL; 1570 void *tgt = NULL; 1571 1572 if (devtype == VSW_VNETPORT) { 1573 /* 1574 * Being invoked from a vnet. 1575 */ 1576 ASSERT(arg != NULL); 1577 tgt = arg; 1578 D2(NULL, "%s: port %d : address 0x%llx", __func__, 1579 ((vsw_port_t *)arg)->p_instance, addr); 1580 } else { 1581 /* 1582 * We are being invoked via the m_multicst mac entry 1583 * point. 1584 */ 1585 D2(NULL, "%s: address 0x%llx", __func__, addr); 1586 tgt = (void *)vswp; 1587 } 1588 1589 WRITE_ENTER(&vswp->mfdbrw); 1590 if (mod_hash_find(vswp->mfdb, (mod_hash_key_t)addr, 1591 (mod_hash_val_t *)&ment) != 0) { 1592 1593 /* address not currently in table */ 1594 ment = kmem_alloc(sizeof (mfdb_ent_t), KM_SLEEP); 1595 ment->d_addr = (void *)tgt; 1596 ment->d_type = devtype; 1597 ment->nextp = NULL; 1598 1599 if (mod_hash_insert(vswp->mfdb, (mod_hash_key_t)addr, 1600 (mod_hash_val_t)ment) != 0) { 1601 DERR(vswp, "%s: hash table insertion failed", __func__); 1602 kmem_free(ment, sizeof (mfdb_ent_t)); 1603 rv = 1; 1604 } else { 1605 D2(vswp, "%s: added initial entry for 0x%llx to " 1606 "table", __func__, addr); 1607 } 1608 } else { 1609 /* 1610 * Address in table. Check to see if specified port 1611 * is already associated with the address. If not add 1612 * it now. 1613 */ 1614 tmp_ent = ment; 1615 while (tmp_ent != NULL) { 1616 if (tmp_ent->d_addr == (void *)tgt) { 1617 if (devtype == VSW_VNETPORT) { 1618 DERR(vswp, "%s: duplicate port entry " 1619 "found for portid %ld and key " 1620 "0x%llx", __func__, 1621 ((vsw_port_t *)arg)->p_instance, 1622 addr); 1623 } else { 1624 DERR(vswp, "%s: duplicate entry found" 1625 "for key 0x%llx", __func__, addr); 1626 } 1627 rv = 1; 1628 dup = 1; 1629 break; 1630 } 1631 tmp_ent = tmp_ent->nextp; 1632 } 1633 1634 /* 1635 * Port not on list so add it to end now. 1636 */ 1637 if (0 == dup) { 1638 D2(vswp, "%s: added entry for 0x%llx to table", 1639 __func__, addr); 1640 new_ent = kmem_alloc(sizeof (mfdb_ent_t), KM_SLEEP); 1641 new_ent->d_addr = (void *)tgt; 1642 new_ent->d_type = devtype; 1643 new_ent->nextp = NULL; 1644 1645 tmp_ent = ment; 1646 while (tmp_ent->nextp != NULL) 1647 tmp_ent = tmp_ent->nextp; 1648 1649 tmp_ent->nextp = new_ent; 1650 } 1651 } 1652 1653 RW_EXIT(&vswp->mfdbrw); 1654 return (rv); 1655 } 1656 1657 /* 1658 * Remove a multicast entry from the hashtable. 1659 * 1660 * Search hash table based on address. If match found, scan 1661 * list of ports associated with address. If specified port 1662 * found remove it from list. 1663 */ 1664 int 1665 vsw_del_mcst(vsw_t *vswp, uint8_t devtype, uint64_t addr, void *arg) 1666 { 1667 mfdb_ent_t *ment = NULL; 1668 mfdb_ent_t *curr_p, *prev_p; 1669 void *tgt = NULL; 1670 1671 D1(vswp, "%s: enter", __func__); 1672 1673 if (devtype == VSW_VNETPORT) { 1674 tgt = (vsw_port_t *)arg; 1675 D2(vswp, "%s: removing port %d from mFDB for address" 1676 " 0x%llx", __func__, ((vsw_port_t *)tgt)->p_instance, addr); 1677 } else { 1678 D2(vswp, "%s: removing entry", __func__); 1679 tgt = (void *)vswp; 1680 } 1681 1682 WRITE_ENTER(&vswp->mfdbrw); 1683 if (mod_hash_find(vswp->mfdb, (mod_hash_key_t)addr, 1684 (mod_hash_val_t *)&ment) != 0) { 1685 D2(vswp, "%s: address 0x%llx not in table", __func__, addr); 1686 RW_EXIT(&vswp->mfdbrw); 1687 return (1); 1688 } 1689 1690 prev_p = curr_p = ment; 1691 1692 while (curr_p != NULL) { 1693 if (curr_p->d_addr == (void *)tgt) { 1694 if (devtype == VSW_VNETPORT) { 1695 D2(vswp, "%s: port %d found", __func__, 1696 ((vsw_port_t *)tgt)->p_instance); 1697 } else { 1698 D2(vswp, "%s: instance found", __func__); 1699 } 1700 1701 if (prev_p == curr_p) { 1702 /* 1703 * head of list, if no other element is in 1704 * list then destroy this entry, otherwise 1705 * just replace it with updated value. 1706 */ 1707 ment = curr_p->nextp; 1708 if (ment == NULL) { 1709 (void) mod_hash_destroy(vswp->mfdb, 1710 (mod_hash_val_t)addr); 1711 } else { 1712 (void) mod_hash_replace(vswp->mfdb, 1713 (mod_hash_key_t)addr, 1714 (mod_hash_val_t)ment); 1715 } 1716 } else { 1717 /* 1718 * Not head of list, no need to do 1719 * replacement, just adjust list pointers. 1720 */ 1721 prev_p->nextp = curr_p->nextp; 1722 } 1723 break; 1724 } 1725 1726 prev_p = curr_p; 1727 curr_p = curr_p->nextp; 1728 } 1729 1730 RW_EXIT(&vswp->mfdbrw); 1731 1732 D1(vswp, "%s: exit", __func__); 1733 1734 if (curr_p == NULL) 1735 return (1); 1736 kmem_free(curr_p, sizeof (mfdb_ent_t)); 1737 return (0); 1738 } 1739 1740 /* 1741 * Port is being deleted, but has registered an interest in one 1742 * or more multicast groups. Using the list of addresses maintained 1743 * within the port structure find the appropriate entry in the hash 1744 * table and remove this port from the list of interested ports. 1745 */ 1746 void 1747 vsw_del_mcst_port(vsw_port_t *port) 1748 { 1749 mcst_addr_t *mcap = NULL; 1750 vsw_t *vswp = port->p_vswp; 1751 1752 D1(vswp, "%s: enter", __func__); 1753 1754 mutex_enter(&port->mca_lock); 1755 1756 while ((mcap = port->mcap) != NULL) { 1757 1758 port->mcap = mcap->nextp; 1759 1760 mutex_exit(&port->mca_lock); 1761 1762 (void) vsw_del_mcst(vswp, VSW_VNETPORT, 1763 mcap->addr, port); 1764 1765 /* 1766 * Remove the address from HW. The address 1767 * will actually only be removed once the ref 1768 * count within the MAC layer has dropped to 1769 * zero. I.e. we can safely call this fn even 1770 * if other ports are interested in this 1771 * address. 1772 */ 1773 mutex_enter(&vswp->mac_lock); 1774 if (vswp->mh != NULL && mcap->mac_added) { 1775 (void) mac_multicst_remove(vswp->mh, 1776 (uchar_t *)&mcap->mca); 1777 } 1778 mutex_exit(&vswp->mac_lock); 1779 1780 kmem_free(mcap, sizeof (*mcap)); 1781 1782 mutex_enter(&port->mca_lock); 1783 1784 } 1785 1786 mutex_exit(&port->mca_lock); 1787 1788 D1(vswp, "%s: exit", __func__); 1789 } 1790 1791 /* 1792 * This vsw instance is detaching, but has registered an interest in one 1793 * or more multicast groups. Using the list of addresses maintained 1794 * within the vsw structure find the appropriate entry in the hash 1795 * table and remove this instance from the list of interested ports. 1796 */ 1797 void 1798 vsw_del_mcst_vsw(vsw_t *vswp) 1799 { 1800 mcst_addr_t *next_p = NULL; 1801 1802 D1(vswp, "%s: enter", __func__); 1803 1804 mutex_enter(&vswp->mca_lock); 1805 1806 while (vswp->mcap != NULL) { 1807 DERR(vswp, "%s: deleting addr 0x%llx", 1808 __func__, vswp->mcap->addr); 1809 (void) vsw_del_mcst(vswp, VSW_LOCALDEV, vswp->mcap->addr, NULL); 1810 1811 next_p = vswp->mcap->nextp; 1812 kmem_free(vswp->mcap, sizeof (mcst_addr_t)); 1813 vswp->mcap = next_p; 1814 } 1815 1816 vswp->mcap = NULL; 1817 mutex_exit(&vswp->mca_lock); 1818 1819 D1(vswp, "%s: exit", __func__); 1820 } 1821 1822 static uint32_t 1823 vsw_get_same_dest_list(struct ether_header *ehp, 1824 mblk_t **rhead, mblk_t **rtail, mblk_t **mpp) 1825 { 1826 uint32_t count = 0; 1827 mblk_t *bp; 1828 mblk_t *nbp; 1829 mblk_t *head = NULL; 1830 mblk_t *tail = NULL; 1831 mblk_t *prev = NULL; 1832 struct ether_header *behp; 1833 1834 /* process the chain of packets */ 1835 bp = *mpp; 1836 while (bp) { 1837 nbp = bp->b_next; 1838 behp = (struct ether_header *)bp->b_rptr; 1839 bp->b_prev = NULL; 1840 if (ether_cmp(&ehp->ether_dhost, &behp->ether_dhost) == 0) { 1841 if (prev == NULL) { 1842 *mpp = nbp; 1843 } else { 1844 prev->b_next = nbp; 1845 } 1846 bp->b_next = NULL; 1847 if (head == NULL) { 1848 head = tail = bp; 1849 } else { 1850 tail->b_next = bp; 1851 tail = bp; 1852 } 1853 count++; 1854 } else { 1855 prev = bp; 1856 } 1857 bp = nbp; 1858 } 1859 *rhead = head; 1860 *rtail = tail; 1861 DTRACE_PROBE1(vsw_same_dest, int, count); 1862 return (count); 1863 } 1864 1865 static mblk_t * 1866 vsw_dupmsgchain(mblk_t *mp) 1867 { 1868 mblk_t *nmp = NULL; 1869 mblk_t **nmpp = &nmp; 1870 1871 for (; mp != NULL; mp = mp->b_next) { 1872 if ((*nmpp = dupmsg(mp)) == NULL) { 1873 freemsgchain(nmp); 1874 return (NULL); 1875 } 1876 1877 nmpp = &((*nmpp)->b_next); 1878 } 1879 1880 return (nmp); 1881 } 1882