Lines 98-107
Link Here
|
98 |
#define V_lagg_cloner VNET(lagg_cloner) |
100 |
#define V_lagg_cloner VNET(lagg_cloner) |
99 |
static const char laggname[] = "lagg"; |
101 |
static const char laggname[] = "lagg"; |
100 |
|
102 |
|
101 |
static void lagg_lladdr(struct lagg_softc *, uint8_t *); |
103 |
static void lagg_lladdr(struct lagg_softc *, uint8_t *, bool); |
102 |
static void lagg_capabilities(struct lagg_softc *); |
104 |
static void lagg_capabilities(struct lagg_softc *); |
103 |
static void lagg_port_lladdr(struct lagg_port *, uint8_t *, lagg_llqtype); |
105 |
static void lagg_port_lladdr(struct lagg_port *, uint8_t *, lagg_llqtype); |
104 |
static void lagg_port_setlladdr(void *, int); |
|
|
105 |
static int lagg_port_create(struct lagg_softc *, struct ifnet *); |
106 |
static int lagg_port_create(struct lagg_softc *, struct ifnet *); |
106 |
static int lagg_port_destroy(struct lagg_port *, int); |
107 |
static int lagg_port_destroy(struct lagg_port *, int); |
107 |
static struct mbuf *lagg_input(struct ifnet *, struct mbuf *); |
108 |
static struct mbuf *lagg_input(struct ifnet *, struct mbuf *); |
Lines 487-493
Link Here
|
487 |
|
488 |
|
488 |
LAGG_LOCK_INIT(sc); |
489 |
LAGG_LOCK_INIT(sc); |
489 |
SLIST_INIT(&sc->sc_ports); |
490 |
SLIST_INIT(&sc->sc_ports); |
490 |
TASK_INIT(&sc->sc_lladdr_task, 0, lagg_port_setlladdr, sc); |
|
|
491 |
|
491 |
|
492 |
/* Initialise pseudo media types */ |
492 |
/* Initialise pseudo media types */ |
493 |
ifmedia_init(&sc->sc_media, 0, lagg_media_change, |
493 |
ifmedia_init(&sc->sc_media, 0, lagg_media_change, |
Lines 553-559
Link Here
|
553 |
SLIST_REMOVE(&V_lagg_list, sc, lagg_softc, sc_entries); |
553 |
SLIST_REMOVE(&V_lagg_list, sc, lagg_softc, sc_entries); |
554 |
LAGG_LIST_UNLOCK(); |
554 |
LAGG_LIST_UNLOCK(); |
555 |
|
555 |
|
556 |
taskqueue_drain(taskqueue_swi, &sc->sc_lladdr_task); |
|
|
557 |
LAGG_LOCK_DESTROY(sc); |
556 |
LAGG_LOCK_DESTROY(sc); |
558 |
free(sc, M_DEVBUF); |
557 |
free(sc, M_DEVBUF); |
559 |
} |
558 |
} |
Lines 564-570
Link Here
|
564 |
* Set noinline to be dtrace-friendly |
563 |
* Set noinline to be dtrace-friendly |
565 |
*/ |
564 |
*/ |
566 |
static __noinline void |
565 |
static __noinline void |
567 |
lagg_lladdr(struct lagg_softc *sc, uint8_t *lladdr) |
566 |
lagg_lladdr(struct lagg_softc *sc, uint8_t *lladdr, bool detaching) |
568 |
{ |
567 |
{ |
569 |
struct ifnet *ifp = sc->sc_ifp; |
568 |
struct ifnet *ifp = sc->sc_ifp; |
570 |
struct lagg_port lp; |
569 |
struct lagg_port lp; |
Lines 590-595
Link Here
|
590 |
bzero(&lp, sizeof(lp)); |
589 |
bzero(&lp, sizeof(lp)); |
591 |
lp.lp_ifp = sc->sc_ifp; |
590 |
lp.lp_ifp = sc->sc_ifp; |
592 |
lp.lp_softc = sc; |
591 |
lp.lp_softc = sc; |
|
|
592 |
lp.lp_detaching = detaching; |
593 |
|
593 |
|
594 |
/* Do not request lladdr change */ |
594 |
/* Do not request lladdr change */ |
595 |
lagg_port_lladdr(&lp, lladdr, LAGG_LLQTYPE_VIRT); |
595 |
lagg_port_lladdr(&lp, lladdr, LAGG_LLQTYPE_VIRT); |
Lines 645-651
Link Here
|
645 |
{ |
645 |
{ |
646 |
struct lagg_softc *sc = lp->lp_softc; |
646 |
struct lagg_softc *sc = lp->lp_softc; |
647 |
struct ifnet *ifp = lp->lp_ifp; |
647 |
struct ifnet *ifp = lp->lp_ifp; |
648 |
struct lagg_llq *llq; |
648 |
int error = 0; |
649 |
|
649 |
|
650 |
LAGG_WLOCK_ASSERT(sc); |
650 |
LAGG_WLOCK_ASSERT(sc); |
651 |
|
651 |
|
Lines 653-727
Link Here
|
653 |
* Do not enqueue requests where lladdr is the same for |
653 |
* Do not enqueue requests where lladdr is the same for |
654 |
* "physical" interfaces (e.g. ports in lagg) |
654 |
* "physical" interfaces (e.g. ports in lagg) |
655 |
*/ |
655 |
*/ |
656 |
if (llq_type == LAGG_LLQTYPE_PHYS && |
656 |
if (lp->lp_detaching || (llq_type == LAGG_LLQTYPE_PHYS && |
657 |
memcmp(IF_LLADDR(ifp), lladdr, ETHER_ADDR_LEN) == 0) |
657 |
memcmp(IF_LLADDR(ifp), lladdr, ETHER_ADDR_LEN) == 0)) |
658 |
return; |
658 |
return; |
659 |
|
659 |
|
660 |
/* Check to make sure its not already queued to be changed */ |
660 |
/* Set the link layer address */ |
661 |
SLIST_FOREACH(llq, &sc->sc_llq_head, llq_entries) { |
661 |
CURVNET_SET(ifp->if_vnet); |
662 |
if (llq->llq_ifp == ifp) { |
662 |
if (llq_type == LAGG_LLQTYPE_PHYS) |
663 |
/* Update lladdr, it may have changed */ |
663 |
error = if_setlladdr(ifp, lladdr, ETHER_ADDR_LEN); |
664 |
bcopy(lladdr, llq->llq_lladdr, ETHER_ADDR_LEN); |
664 |
else |
665 |
return; |
665 |
EVENTHANDLER_INVOKE(iflladdr_event, ifp); |
666 |
} |
666 |
CURVNET_RESTORE(); |
667 |
} |
667 |
if (error) |
668 |
|
668 |
if_printf(sc->sc_ifp, "%s: setlladdr failed on %s\n", __func__, |
669 |
llq = malloc(sizeof(struct lagg_llq), M_DEVBUF, M_NOWAIT | M_ZERO); |
669 |
ifp->if_xname); |
670 |
if (llq == NULL) /* XXX what to do */ |
|
|
671 |
return; |
672 |
|
673 |
llq->llq_ifp = ifp; |
674 |
llq->llq_type = llq_type; |
675 |
bcopy(lladdr, llq->llq_lladdr, ETHER_ADDR_LEN); |
676 |
/* XXX: We should insert to tail */ |
677 |
SLIST_INSERT_HEAD(&sc->sc_llq_head, llq, llq_entries); |
678 |
|
679 |
taskqueue_enqueue(taskqueue_swi, &sc->sc_lladdr_task); |
680 |
} |
670 |
} |
681 |
|
671 |
|
682 |
/* |
|
|
683 |
* Set the interface MAC address from a taskqueue to avoid a LOR. |
684 |
* |
685 |
* Set noinline to be dtrace-friendly |
686 |
*/ |
687 |
static __noinline void |
688 |
lagg_port_setlladdr(void *arg, int pending) |
689 |
{ |
690 |
struct lagg_softc *sc = (struct lagg_softc *)arg; |
691 |
struct lagg_llq *llq, *head; |
692 |
struct ifnet *ifp; |
693 |
|
694 |
/* Grab a local reference of the queue and remove it from the softc */ |
695 |
LAGG_WLOCK(sc); |
696 |
head = SLIST_FIRST(&sc->sc_llq_head); |
697 |
SLIST_FIRST(&sc->sc_llq_head) = NULL; |
698 |
LAGG_WUNLOCK(sc); |
699 |
|
700 |
/* |
701 |
* Traverse the queue and set the lladdr on each ifp. It is safe to do |
702 |
* unlocked as we have the only reference to it. |
703 |
*/ |
704 |
for (llq = head; llq != NULL; llq = head) { |
705 |
ifp = llq->llq_ifp; |
706 |
|
707 |
CURVNET_SET(ifp->if_vnet); |
708 |
|
709 |
/* |
710 |
* Set the link layer address on the laggport interface. |
711 |
* Note that if_setlladdr() or iflladdr_event handler |
712 |
* may result in arp transmission / lltable updates. |
713 |
*/ |
714 |
if (llq->llq_type == LAGG_LLQTYPE_PHYS) |
715 |
if_setlladdr(ifp, llq->llq_lladdr, |
716 |
ETHER_ADDR_LEN); |
717 |
else |
718 |
EVENTHANDLER_INVOKE(iflladdr_event, ifp); |
719 |
CURVNET_RESTORE(); |
720 |
head = SLIST_NEXT(llq, llq_entries); |
721 |
free(llq, M_DEVBUF); |
722 |
} |
723 |
} |
724 |
|
725 |
static int |
672 |
static int |
726 |
lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp) |
673 |
lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp) |
727 |
{ |
674 |
{ |
Lines 801-807
Link Here
|
801 |
if (SLIST_EMPTY(&sc->sc_ports)) { |
748 |
if (SLIST_EMPTY(&sc->sc_ports)) { |
802 |
sc->sc_primary = lp; |
749 |
sc->sc_primary = lp; |
803 |
/* First port in lagg. Update/notify lagg lladdress */ |
750 |
/* First port in lagg. Update/notify lagg lladdress */ |
804 |
lagg_lladdr(sc, IF_LLADDR(ifp)); |
751 |
lagg_lladdr(sc, IF_LLADDR(ifp), false); |
805 |
} else { |
752 |
} else { |
806 |
|
753 |
|
807 |
/* |
754 |
/* |
Lines 877-883
Link Here
|
877 |
{ |
824 |
{ |
878 |
struct lagg_softc *sc = lp->lp_softc; |
825 |
struct lagg_softc *sc = lp->lp_softc; |
879 |
struct lagg_port *lp_ptr, *lp0; |
826 |
struct lagg_port *lp_ptr, *lp0; |
880 |
struct lagg_llq *llq; |
|
|
881 |
struct ifnet *ifp = lp->lp_ifp; |
827 |
struct ifnet *ifp = lp->lp_ifp; |
882 |
uint64_t *pval, vdiff; |
828 |
uint64_t *pval, vdiff; |
883 |
int i; |
829 |
int i; |
Lines 924-930
Link Here
|
924 |
bcopy(lp0->lp_lladdr, |
870 |
bcopy(lp0->lp_lladdr, |
925 |
lladdr, ETHER_ADDR_LEN); |
871 |
lladdr, ETHER_ADDR_LEN); |
926 |
} |
872 |
} |
927 |
lagg_lladdr(sc, lladdr); |
873 |
lagg_lladdr(sc, lladdr, true); |
928 |
|
874 |
|
929 |
/* Mark lp0 as new primary */ |
875 |
/* Mark lp0 as new primary */ |
930 |
sc->sc_primary = lp0; |
876 |
sc->sc_primary = lp0; |
Lines 938-955
Link Here
|
938 |
lagg_port_lladdr(lp_ptr, lladdr, LAGG_LLQTYPE_PHYS); |
884 |
lagg_port_lladdr(lp_ptr, lladdr, LAGG_LLQTYPE_PHYS); |
939 |
} |
885 |
} |
940 |
|
886 |
|
941 |
/* Remove any pending lladdr changes from the queue */ |
|
|
942 |
if (lp->lp_detaching) { |
943 |
SLIST_FOREACH(llq, &sc->sc_llq_head, llq_entries) { |
944 |
if (llq->llq_ifp == ifp) { |
945 |
SLIST_REMOVE(&sc->sc_llq_head, llq, lagg_llq, |
946 |
llq_entries); |
947 |
free(llq, M_DEVBUF); |
948 |
break; /* Only appears once */ |
949 |
} |
950 |
} |
951 |
} |
952 |
|
953 |
if (lp->lp_ifflags) |
887 |
if (lp->lp_ifflags) |
954 |
if_printf(ifp, "%s: lp_ifflags unclean\n", __func__); |
888 |
if_printf(ifp, "%s: lp_ifflags unclean\n", __func__); |
955 |
|
889 |
|
Lines 1472-1477
Link Here
|
1472 |
"before adding it as a member to prevent " |
1406 |
"before adding it as a member to prevent " |
1473 |
"IPv6 address scope violation.\n", |
1407 |
"IPv6 address scope violation.\n", |
1474 |
tpif->if_xname); |
1408 |
tpif->if_xname); |
|
|
1409 |
} else { |
1410 |
if_printf(sc->sc_ifp, "No IPv6 link-local address found on %s\n", tpif->if_xname); |
1475 |
} |
1411 |
} |
1476 |
#endif |
1412 |
#endif |
1477 |
LAGG_WLOCK(sc); |
1413 |
LAGG_WLOCK(sc); |