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 }
|