Print this page
11490 SRS ring polling disabled for VLANs
11491 Want DLS bypass for VLAN traffic
11492 add VLVF bypass to ixgbe core
2869 duplicate packets with vnics over aggrs
11489 DLS stat delete and aggr kstat can deadlock
Portions contributed by: Theo Schlossnagle <jesus@omniti.com>
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Dan McDonald <danmcd@joyent.com>


   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  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.


  24  */
  25 
  26 /*
  27  * IEEE 802.3ad Link Aggregation - Link Aggregation MAC ports.
  28  *
  29  * Implements the functions needed to manage the MAC ports that are
  30  * part of Link Aggregation groups.
  31  */
  32 
  33 #include <sys/types.h>
  34 #include <sys/sysmacros.h>
  35 #include <sys/conf.h>
  36 #include <sys/cmn_err.h>
  37 #include <sys/id_space.h>
  38 #include <sys/list.h>
  39 #include <sys/ksynch.h>
  40 #include <sys/kmem.h>
  41 #include <sys/stream.h>
  42 #include <sys/modctl.h>
  43 #include <sys/ddi.h>


 356                 if (link_state == LINK_STATE_UP)
 357                         do_attach = (port->lp_link_state != LINK_STATE_UP);
 358                 else
 359                         do_detach = (port->lp_link_state == LINK_STATE_UP);
 360         }
 361         port->lp_link_state = link_state;
 362 
 363         /* link duplex change? */
 364         link_duplex = aggr_port_stat(port, ETHER_STAT_LINK_DUPLEX);
 365         if (port->lp_link_duplex != link_duplex) {
 366                 if (link_duplex == LINK_DUPLEX_FULL)
 367                         do_attach |= (port->lp_link_duplex != LINK_DUPLEX_FULL);
 368                 else
 369                         do_detach |= (port->lp_link_duplex == LINK_DUPLEX_FULL);
 370         }
 371         port->lp_link_duplex = link_duplex;
 372 
 373         /* link speed changes? */
 374         ifspeed = aggr_port_stat(port, MAC_STAT_IFSPEED);
 375         if (port->lp_ifspeed != ifspeed) {


 376                 if (port->lp_state == AGGR_PORT_STATE_ATTACHED)
 377                         do_detach |= (ifspeed != grp->lg_ifspeed);
 378                 else
 379                         do_attach |= (ifspeed == grp->lg_ifspeed);


 380         }
 381         port->lp_ifspeed = ifspeed;
 382 
 383         if (do_attach) {
 384                 /* attempt to attach the port to the aggregation */
 385                 link_state_changed = aggr_grp_attach_port(grp, port);
 386         } else if (do_detach) {
 387                 /* detach the port from the aggregation */
 388                 link_state_changed = aggr_grp_detach_port(grp, port);
 389         }
 390 
 391         mac_perim_exit(mph);
 392         return (link_state_changed);
 393 }
 394 
 395 /*
 396  * Invoked upon receiving a MAC_NOTE_UNICST for one of the constituent
 397  * ports of a group.
 398  */
 399 static void


 511 
 512         aggr_grp_multicst_port(port, B_FALSE);
 513 
 514         /* update the port state */
 515         port->lp_started = B_FALSE;
 516 }
 517 
 518 int
 519 aggr_port_promisc(aggr_port_t *port, boolean_t on)
 520 {
 521         int rc;
 522 
 523         ASSERT(MAC_PERIM_HELD(port->lp_mh));
 524 
 525         if (on == port->lp_promisc_on)
 526                 /* already in desired promiscous mode */
 527                 return (0);
 528 
 529         if (on) {
 530                 mac_rx_clear(port->lp_mch);







 531                 rc = mac_promisc_add(port->lp_mch, MAC_CLIENT_PROMISC_ALL,
 532                     aggr_recv_cb, port, &port->lp_mphp,
 533                     MAC_PROMISC_FLAGS_NO_TX_LOOP);
 534                 if (rc != 0) {
 535                         mac_rx_set(port->lp_mch, aggr_recv_cb, port);
 536                         return (rc);
 537                 }
 538         } else {
 539                 mac_promisc_remove(port->lp_mphp);
 540                 port->lp_mphp = NULL;
 541                 mac_rx_set(port->lp_mch, aggr_recv_cb, port);
 542         }
 543 
 544         port->lp_promisc_on = on;
 545 
 546         return (0);
 547 }
 548 
 549 /*
 550  * Set the MAC address of a port.
 551  */
 552 int


 661                 if (bcmp(mac_addr, addr->aua_addr, ETHERADDRL) == 0)
 662                         break;
 663                 pprev = &addr->aua_next;
 664         }
 665         if (addr != NULL) {
 666                 /*
 667                  * This unicast address put the port into the promiscous mode,
 668                  * delete this address from the lp_prom_addr list. If this is
 669                  * the last address in that list, disable the promiscous mode
 670                  * if the aggregation is not in promiscous mode.
 671                  */
 672                 *pprev = addr->aua_next;
 673                 kmem_free(addr, sizeof (aggr_unicst_addr_t));
 674                 if (port->lp_prom_addr == NULL && !grp->lg_promisc)
 675                         (void) aggr_port_promisc(port, B_FALSE);
 676         } else {
 677                 ASSERT(port->lp_hwgh != NULL);
 678                 (void) mac_hwgroup_remmac(port->lp_hwgh, mac_addr);
 679         }
 680         mac_perim_exit(pmph);








































 681 }


   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  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  * Copyright 2012 OmniTI Computer Consulting, Inc  All rights reserved.
  25  * Copyright 2018 Joyent, Inc.
  26  */
  27 
  28 /*
  29  * IEEE 802.3ad Link Aggregation - Link Aggregation MAC ports.
  30  *
  31  * Implements the functions needed to manage the MAC ports that are
  32  * part of Link Aggregation groups.
  33  */
  34 
  35 #include <sys/types.h>
  36 #include <sys/sysmacros.h>
  37 #include <sys/conf.h>
  38 #include <sys/cmn_err.h>
  39 #include <sys/id_space.h>
  40 #include <sys/list.h>
  41 #include <sys/ksynch.h>
  42 #include <sys/kmem.h>
  43 #include <sys/stream.h>
  44 #include <sys/modctl.h>
  45 #include <sys/ddi.h>


 358                 if (link_state == LINK_STATE_UP)
 359                         do_attach = (port->lp_link_state != LINK_STATE_UP);
 360                 else
 361                         do_detach = (port->lp_link_state == LINK_STATE_UP);
 362         }
 363         port->lp_link_state = link_state;
 364 
 365         /* link duplex change? */
 366         link_duplex = aggr_port_stat(port, ETHER_STAT_LINK_DUPLEX);
 367         if (port->lp_link_duplex != link_duplex) {
 368                 if (link_duplex == LINK_DUPLEX_FULL)
 369                         do_attach |= (port->lp_link_duplex != LINK_DUPLEX_FULL);
 370                 else
 371                         do_detach |= (port->lp_link_duplex == LINK_DUPLEX_FULL);
 372         }
 373         port->lp_link_duplex = link_duplex;
 374 
 375         /* link speed changes? */
 376         ifspeed = aggr_port_stat(port, MAC_STAT_IFSPEED);
 377         if (port->lp_ifspeed != ifspeed) {
 378                 mutex_enter(&grp->lg_stat_lock);
 379 
 380                 if (port->lp_state == AGGR_PORT_STATE_ATTACHED)
 381                         do_detach |= (ifspeed != grp->lg_ifspeed);
 382                 else
 383                         do_attach |= (ifspeed == grp->lg_ifspeed);
 384 
 385                 mutex_exit(&grp->lg_stat_lock);
 386         }
 387         port->lp_ifspeed = ifspeed;
 388 
 389         if (do_attach) {
 390                 /* attempt to attach the port to the aggregation */
 391                 link_state_changed = aggr_grp_attach_port(grp, port);
 392         } else if (do_detach) {
 393                 /* detach the port from the aggregation */
 394                 link_state_changed = aggr_grp_detach_port(grp, port);
 395         }
 396 
 397         mac_perim_exit(mph);
 398         return (link_state_changed);
 399 }
 400 
 401 /*
 402  * Invoked upon receiving a MAC_NOTE_UNICST for one of the constituent
 403  * ports of a group.
 404  */
 405 static void


 517 
 518         aggr_grp_multicst_port(port, B_FALSE);
 519 
 520         /* update the port state */
 521         port->lp_started = B_FALSE;
 522 }
 523 
 524 int
 525 aggr_port_promisc(aggr_port_t *port, boolean_t on)
 526 {
 527         int rc;
 528 
 529         ASSERT(MAC_PERIM_HELD(port->lp_mh));
 530 
 531         if (on == port->lp_promisc_on)
 532                 /* already in desired promiscous mode */
 533                 return (0);
 534 
 535         if (on) {
 536                 mac_rx_clear(port->lp_mch);
 537 
 538                 /*
 539                  * We use the promisc callback because without hardware
 540                  * rings, we deliver through flows that will cause duplicate
 541                  * delivery of packets when we've flipped into this mode
 542                  * to compensate for the lack of hardware MAC matching
 543                  */
 544                 rc = mac_promisc_add(port->lp_mch, MAC_CLIENT_PROMISC_ALL,
 545                     aggr_recv_promisc_cb, port, &port->lp_mphp,
 546                     MAC_PROMISC_FLAGS_NO_TX_LOOP);
 547                 if (rc != 0) {
 548                         mac_rx_set(port->lp_mch, aggr_recv_cb, port);
 549                         return (rc);
 550                 }
 551         } else {
 552                 mac_promisc_remove(port->lp_mphp);
 553                 port->lp_mphp = NULL;
 554                 mac_rx_set(port->lp_mch, aggr_recv_cb, port);
 555         }
 556 
 557         port->lp_promisc_on = on;
 558 
 559         return (0);
 560 }
 561 
 562 /*
 563  * Set the MAC address of a port.
 564  */
 565 int


 674                 if (bcmp(mac_addr, addr->aua_addr, ETHERADDRL) == 0)
 675                         break;
 676                 pprev = &addr->aua_next;
 677         }
 678         if (addr != NULL) {
 679                 /*
 680                  * This unicast address put the port into the promiscous mode,
 681                  * delete this address from the lp_prom_addr list. If this is
 682                  * the last address in that list, disable the promiscous mode
 683                  * if the aggregation is not in promiscous mode.
 684                  */
 685                 *pprev = addr->aua_next;
 686                 kmem_free(addr, sizeof (aggr_unicst_addr_t));
 687                 if (port->lp_prom_addr == NULL && !grp->lg_promisc)
 688                         (void) aggr_port_promisc(port, B_FALSE);
 689         } else {
 690                 ASSERT(port->lp_hwgh != NULL);
 691                 (void) mac_hwgroup_remmac(port->lp_hwgh, mac_addr);
 692         }
 693         mac_perim_exit(pmph);
 694 }
 695 
 696 int
 697 aggr_port_addvlan(aggr_port_t *port, uint16_t vid)
 698 {
 699         mac_perim_handle_t      pmph;
 700         int                     err;
 701 
 702         ASSERT(MAC_PERIM_HELD(port->lp_grp->lg_mh));
 703         mac_perim_enter_by_mh(port->lp_mh, &pmph);
 704 
 705         /*
 706          * Add the VLAN filter to the HW group if the port has a HW
 707          * group. If the port doesn't have a HW group, then it will
 708          * implicitly allow tagged traffic to pass and there is
 709          * nothing to do.
 710          */
 711         if (port->lp_hwgh == NULL)
 712                 return (0);
 713 
 714         err = mac_hwgroup_addvlan(port->lp_hwgh, vid);
 715         mac_perim_exit(pmph);
 716         return (err);
 717 }
 718 
 719 int
 720 aggr_port_remvlan(aggr_port_t *port, uint16_t vid)
 721 {
 722         mac_perim_handle_t      pmph;
 723         int                     err;
 724 
 725         ASSERT(MAC_PERIM_HELD(port->lp_grp->lg_mh));
 726         mac_perim_enter_by_mh(port->lp_mh, &pmph);
 727 
 728         if (port->lp_hwgh == NULL)
 729                 return (0);
 730 
 731         err = mac_hwgroup_remvlan(port->lp_hwgh, vid);
 732         mac_perim_exit(pmph);
 733         return (err);
 734 }