View | Details | Raw Unified | Return to bug 211689 | Differences between
and this patch

Collapse All | Expand All

(-)sys/net/if_lagg.c (-86 / +20 lines)
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);
(-)sys/net/if_lagg.h (-11 lines)
Lines 207-220 Link Here
207
	LAGG_LLQTYPE_VIRT,	/* Task related to lagg interface itself */
207
	LAGG_LLQTYPE_VIRT,	/* Task related to lagg interface itself */
208
} lagg_llqtype;
208
} lagg_llqtype;
209
209
210
/* List of interfaces to have the MAC address modified */
211
struct lagg_llq {
212
	struct ifnet		*llq_ifp;
213
	uint8_t			llq_lladdr[ETHER_ADDR_LEN];
214
	lagg_llqtype		llq_type;
215
	SLIST_ENTRY(lagg_llq)	llq_entries;
216
};
217
218
struct lagg_counters {
210
struct lagg_counters {
219
	uint64_t	val[IFCOUNTERS];
211
	uint64_t	val[IFCOUNTERS];
220
};
212
};
Lines 236-244 Link Here
236
	SLIST_HEAD(__tplhd, lagg_port)	sc_ports;	/* list of interfaces */
228
	SLIST_HEAD(__tplhd, lagg_port)	sc_ports;	/* list of interfaces */
237
	SLIST_ENTRY(lagg_softc)	sc_entries;
229
	SLIST_ENTRY(lagg_softc)	sc_entries;
238
230
239
	struct task			sc_lladdr_task;
240
	SLIST_HEAD(__llqhd, lagg_llq)	sc_llq_head;	/* interfaces to program
241
							   the lladdr on */
242
	eventhandler_tag vlan_attach;
231
	eventhandler_tag vlan_attach;
243
	eventhandler_tag vlan_detach;
232
	eventhandler_tag vlan_detach;
244
	struct callout			sc_callout;
233
	struct callout			sc_callout;
(-)sys/netinet6/in6.c (-2 / +5 lines)
Lines 1493-1498 Link Here
1493
	return ((struct in6_ifaddr *)ifa);
1493
	return ((struct in6_ifaddr *)ifa);
1494
}
1494
}
1495
1495
1496
SDT_PROVIDER_DEFINE(in6);
1497
SDT_PROBE_DEFINE2(in6, kernel, in6ifa_llaonifp, addr, "struct ifnet*", "struct sockaddr*");
1496
/*
1498
/*
1497
 * Find a link-local scoped address on ifp and return it if any.
1499
 * Find a link-local scoped address on ifp and return it if any.
1498
 */
1500
 */
Lines 1502-1511 Link Here
1502
	struct sockaddr_in6 *sin6;
1504
	struct sockaddr_in6 *sin6;
1503
	struct ifaddr *ifa;
1505
	struct ifaddr *ifa;
1504
1506
1505
	if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)
1507
/*        if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)*/
1506
		return (NULL);
1508
/*                return (NULL);*/
1507
	IF_ADDR_RLOCK(ifp);
1509
	IF_ADDR_RLOCK(ifp);
1508
	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
1510
	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
1511
		SDT_PROBE2(in6, kernel, in6ifa_llaonifp, addr, ifp, ifa->ifa_addr);
1509
		if (ifa->ifa_addr->sa_family != AF_INET6)
1512
		if (ifa->ifa_addr->sa_family != AF_INET6)
1510
			continue;
1513
			continue;
1511
		sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
1514
		sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;

Return to bug 211689