Page MenuHomeFreeBSD

D10514.id27759.diff
No OneTemporary

D10514.id27759.diff

Index: sys/net/if_lagg.h
===================================================================
--- sys/net/if_lagg.h
+++ sys/net/if_lagg.h
@@ -202,19 +202,6 @@
SLIST_ENTRY(lagg_mc) mc_entries;
};
-typedef enum {
- LAGG_LLQTYPE_PHYS = 0, /* Task related to physical (underlying) port */
- LAGG_LLQTYPE_VIRT, /* Task related to lagg interface itself */
-} lagg_llqtype;
-
-/* List of interfaces to have the MAC address modified */
-struct lagg_llq {
- struct ifnet *llq_ifp;
- uint8_t llq_lladdr[ETHER_ADDR_LEN];
- lagg_llqtype llq_type;
- SLIST_ENTRY(lagg_llq) llq_entries;
-};
-
struct lagg_counters {
uint64_t val[IFCOUNTERS];
};
@@ -222,6 +209,7 @@
struct lagg_softc {
struct ifnet *sc_ifp; /* virtual interface */
struct rmlock sc_mtx;
+ struct sx sc_sx;
int sc_proto; /* lagg protocol */
u_int sc_count; /* number of ports */
u_int sc_active; /* active port count */
@@ -232,13 +220,11 @@
void *sc_psc; /* protocol data */
uint32_t sc_seq; /* sequence counter */
uint32_t sc_flags;
+ int sc_destroying; /* destroying lagg */
SLIST_HEAD(__tplhd, lagg_port) sc_ports; /* list of interfaces */
SLIST_ENTRY(lagg_softc) sc_entries;
- struct task sc_lladdr_task;
- SLIST_HEAD(__llqhd, lagg_llq) sc_llq_head; /* interfaces to program
- the lladdr on */
eventhandler_tag vlan_attach;
eventhandler_tag vlan_detach;
struct callout sc_callout;
@@ -258,12 +244,10 @@
uint32_t lp_prio; /* port priority */
uint32_t lp_flags; /* port flags */
int lp_ifflags; /* saved ifp flags */
+ int lp_ifcapenable; /* saved ifp capenable */
void *lh_cookie; /* if state hook */
void *lp_psc; /* protocol data */
int lp_detaching; /* ifnet is detaching */
-#define LAGG_PORT_DETACH 0x01 /* detach lagg port */
-#define LAGG_CLONE_DESTROY 0x02 /* destroy lagg clone */
-
SLIST_HEAD(__mclhd, lagg_mc) lp_mc_head; /* multicast addresses */
/* Redirected callbacks */
@@ -285,6 +269,16 @@
#define LAGG_WLOCK_ASSERT(_sc) rm_assert(&(_sc)->sc_mtx, RA_WLOCKED)
#define LAGG_UNLOCK_ASSERT(_sc) rm_assert(&(_sc)->sc_mtx, RA_UNLOCKED)
+#define LAGG_SX_INIT(_sc) sx_init(&(_sc)->sc_sx, "if_lagg sx")
+#define LAGG_SX_DESTROY(_sc) sx_destroy(&(_sc)->sc_sx)
+#define LAGG_SLOCK(_sc) sx_slock(&(_sc)->sc_sx)
+#define LAGG_XLOCK(_sc) sx_xlock(&(_sc)->sc_sx)
+#define LAGG_SUNLOCK(_sc) sx_sunlock(&(_sc)->sc_sx)
+#define LAGG_XUNLOCK(_sc) sx_xunlock(&(_sc)->sc_sx)
+#define LAGG_SXLOCK_ASSERT(_sc) sx_assert(&(_sc)->sc_sx, SA_LOCKED)
+#define LAGG_SLOCK_ASSERT(_sc) sx_assert(&(_sc)->sc_sx, SA_SLOCKED)
+#define LAGG_XLOCK_ASSERT(_sc) sx_assert(&(_sc)->sc_sx, SA_XLOCKED)
+
extern struct mbuf *(*lagg_input_p)(struct ifnet *, struct mbuf *);
extern void (*lagg_linkstate_p)(struct ifnet *, int );
Index: sys/net/if_lagg.c
===================================================================
--- sys/net/if_lagg.c
+++ sys/net/if_lagg.c
@@ -39,6 +39,7 @@
#include <sys/proc.h>
#include <sys/lock.h>
#include <sys/rmlock.h>
+#include <sys/sx.h>
#include <sys/taskqueue.h>
#include <sys/eventhandler.h>
@@ -99,10 +100,7 @@
#define V_lagg_cloner VNET(lagg_cloner)
static const char laggname[] = "lagg";
-static void lagg_lladdr(struct lagg_softc *, uint8_t *);
static void lagg_capabilities(struct lagg_softc *);
-static void lagg_port_lladdr(struct lagg_port *, uint8_t *, lagg_llqtype);
-static void lagg_port_setlladdr(void *, int);
static int lagg_port_create(struct lagg_softc *, struct ifnet *);
static int lagg_port_destroy(struct lagg_port *, int);
static struct mbuf *lagg_input(struct ifnet *, struct mbuf *);
@@ -124,8 +122,9 @@
union if_snd_tag_alloc_params *,
struct m_snd_tag **);
#endif
-static int lagg_ether_setmulti(struct lagg_softc *);
-static int lagg_ether_cmdmulti(struct lagg_port *, int);
+static int lagg_setmulti(struct lagg_port *);
+static int lagg_clrmulti(struct lagg_port *);
+static int lagg_setcaps(struct lagg_port *, int cap);
static int lagg_setflag(struct lagg_port *, int, int,
int (*func)(struct ifnet *, int));
static int lagg_setflags(struct lagg_port *, int status);
@@ -317,6 +316,7 @@
lagg_proto_attach(struct lagg_softc *sc, lagg_proto pr)
{
+ LAGG_XLOCK_ASSERT(sc);
KASSERT(sc->sc_proto == LAGG_PROTO_NONE, ("%s: sc %p has proto",
__func__, sc));
@@ -333,8 +333,8 @@
{
lagg_proto pr;
+ LAGG_XLOCK_ASSERT(sc);
LAGG_WLOCK_ASSERT(sc);
-
pr = sc->sc_proto;
sc->sc_proto = LAGG_PROTO_NONE;
@@ -433,15 +433,14 @@
{
struct lagg_softc *sc = ifp->if_softc;
struct lagg_port *lp;
- struct rm_priotracker tracker;
if (ifp->if_softc != arg) /* Not our event */
return;
- LAGG_RLOCK(sc, &tracker);
+ LAGG_SLOCK(sc);
SLIST_FOREACH(lp, &sc->sc_ports, lp_entries)
EVENTHANDLER_INVOKE(vlan_config, lp->lp_ifp, vtag);
- LAGG_RUNLOCK(sc, &tracker);
+ LAGG_SUNLOCK(sc);
}
/*
@@ -453,15 +452,14 @@
{
struct lagg_softc *sc = ifp->if_softc;
struct lagg_port *lp;
- struct rm_priotracker tracker;
if (ifp->if_softc != arg) /* Not our event */
return;
- LAGG_RLOCK(sc, &tracker);
+ LAGG_SLOCK(sc);
SLIST_FOREACH(lp, &sc->sc_ports, lp_entries)
EVENTHANDLER_INVOKE(vlan_unconfig, lp->lp_ifp, vtag);
- LAGG_RUNLOCK(sc, &tracker);
+ LAGG_SUNLOCK(sc);
}
static int
@@ -477,7 +475,10 @@
free(sc, M_DEVBUF);
return (ENOSPC);
}
+ LAGG_LOCK_INIT(sc);
+ LAGG_SX_INIT(sc);
+ LAGG_XLOCK(sc);
if (V_def_use_flowid)
sc->sc_opts |= LAGG_OPT_USE_FLOWID;
sc->flowid_shift = V_def_flowid_shift;
@@ -487,9 +488,7 @@
lagg_proto_attach(sc, LAGG_PROTO_DEFAULT);
- LAGG_LOCK_INIT(sc);
SLIST_INIT(&sc->sc_ports);
- TASK_INIT(&sc->sc_lladdr_task, 0, lagg_port_setlladdr, sc);
/* Initialise pseudo media types */
ifmedia_init(&sc->sc_media, 0, lagg_media_change,
@@ -527,6 +526,7 @@
LAGG_LIST_LOCK();
SLIST_INSERT_HEAD(&V_lagg_list, sc, sc_entries);
LAGG_LIST_UNLOCK();
+ LAGG_XUNLOCK(sc);
return (0);
}
@@ -537,8 +537,8 @@
struct lagg_softc *sc = (struct lagg_softc *)ifp->if_softc;
struct lagg_port *lp;
- LAGG_WLOCK(sc);
-
+ LAGG_XLOCK(sc);
+ sc->sc_destroying = 1;
lagg_stop(sc);
ifp->if_flags &= ~IFF_UP;
@@ -546,15 +546,14 @@
EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach);
/* Shutdown and remove lagg ports */
- while ((lp = SLIST_FIRST(&sc->sc_ports)) != NULL) {
- lp->lp_detaching = LAGG_CLONE_DESTROY;
+ while ((lp = SLIST_FIRST(&sc->sc_ports)) != NULL)
lagg_port_destroy(lp, 1);
- }
+
/* Unhook the aggregation protocol */
+ LAGG_WLOCK(sc);
lagg_proto_detach(sc);
LAGG_UNLOCK_ASSERT(sc);
- taskqueue_drain(taskqueue_swi, &sc->sc_lladdr_task);
ifmedia_removeall(&sc->sc_media);
ether_ifdetach(ifp);
if_free(ifp);
@@ -562,48 +561,13 @@
LAGG_LIST_LOCK();
SLIST_REMOVE(&V_lagg_list, sc, lagg_softc, sc_entries);
LAGG_LIST_UNLOCK();
+ LAGG_XUNLOCK(sc);
+ LAGG_SX_DESTROY(sc);
LAGG_LOCK_DESTROY(sc);
free(sc, M_DEVBUF);
}
-/*
- * Set link-layer address on the lagg interface itself.
- *
- * Set noinline to be dtrace-friendly
- */
-static __noinline void
-lagg_lladdr(struct lagg_softc *sc, uint8_t *lladdr)
-{
- struct ifnet *ifp = sc->sc_ifp;
- struct lagg_port lp;
-
- if (memcmp(lladdr, IF_LLADDR(ifp), ETHER_ADDR_LEN) == 0)
- return;
-
- LAGG_WLOCK_ASSERT(sc);
- /*
- * Set the link layer address on the lagg interface.
- * lagg_proto_lladdr() notifies the MAC change to
- * the aggregation protocol. iflladdr_event handler which
- * may trigger gratuitous ARPs for INET will be handled in
- * a taskqueue.
- */
- bcopy(lladdr, IF_LLADDR(ifp), ETHER_ADDR_LEN);
- lagg_proto_lladdr(sc);
-
- /*
- * Send notification request for lagg interface
- * itself. Note that new lladdr is already set.
- */
- bzero(&lp, sizeof(lp));
- lp.lp_ifp = sc->sc_ifp;
- lp.lp_softc = sc;
-
- /* Do not request lladdr change */
- lagg_port_lladdr(&lp, lladdr, LAGG_LLQTYPE_VIRT);
-}
-
static void
lagg_capabilities(struct lagg_softc *sc)
{
@@ -612,7 +576,7 @@
u_long hwa = ~0UL;
struct ifnet_hw_tsomax hw_tsomax;
- LAGG_WLOCK_ASSERT(sc);
+ LAGG_XLOCK_ASSERT(sc);
memset(&hw_tsomax, 0, sizeof(hw_tsomax));
@@ -640,99 +604,12 @@
if_printf(sc->sc_ifp,
"capabilities 0x%08x enabled 0x%08x\n", cap, ena);
}
-}
-/*
- * Enqueue interface lladdr notification.
- * If request is already queued, it is updated.
- * If setting lladdr is also desired, @do_change has to be set to 1.
- *
- * Set noinline to be dtrace-friendly
- */
-static __noinline void
-lagg_port_lladdr(struct lagg_port *lp, uint8_t *lladdr, lagg_llqtype llq_type)
-{
- struct lagg_softc *sc = lp->lp_softc;
- struct ifnet *ifp = lp->lp_ifp;
- struct lagg_llq *llq;
-
- LAGG_WLOCK_ASSERT(sc);
-
- /*
- * Do not enqueue requests where lladdr is the same for
- * "physical" interfaces (e.g. ports in lagg)
- */
- if (llq_type == LAGG_LLQTYPE_PHYS &&
- memcmp(IF_LLADDR(ifp), lladdr, ETHER_ADDR_LEN) == 0)
- return;
-
- /* Check to make sure its not already queued to be changed */
- SLIST_FOREACH(llq, &sc->sc_llq_head, llq_entries) {
- if (llq->llq_ifp == ifp) {
- /* Update lladdr, it may have changed */
- bcopy(lladdr, llq->llq_lladdr, ETHER_ADDR_LEN);
- return;
- }
- }
-
- llq = malloc(sizeof(struct lagg_llq), M_DEVBUF, M_NOWAIT | M_ZERO);
- if (llq == NULL) /* XXX what to do */
- return;
-
- if_ref(ifp);
- llq->llq_ifp = ifp;
- llq->llq_type = llq_type;
- bcopy(lladdr, llq->llq_lladdr, ETHER_ADDR_LEN);
- /* XXX: We should insert to tail */
- SLIST_INSERT_HEAD(&sc->sc_llq_head, llq, llq_entries);
-
- taskqueue_enqueue(taskqueue_swi, &sc->sc_lladdr_task);
+ /* Apply unified capabilities back to the lagg ports. */
+ SLIST_FOREACH(lp, &sc->sc_ports, lp_entries)
+ lagg_setcaps(lp, ena);
}
-/*
- * Set the interface MAC address from a taskqueue to avoid a LOR.
- *
- * Set noinline to be dtrace-friendly
- */
-static __noinline void
-lagg_port_setlladdr(void *arg, int pending)
-{
- struct lagg_softc *sc = (struct lagg_softc *)arg;
- struct lagg_llq *llq, *head;
- struct ifnet *ifp;
-
- /* Grab a local reference of the queue and remove it from the softc */
- LAGG_WLOCK(sc);
- head = SLIST_FIRST(&sc->sc_llq_head);
- SLIST_FIRST(&sc->sc_llq_head) = NULL;
- LAGG_WUNLOCK(sc);
-
- /*
- * Traverse the queue and set the lladdr on each ifp. It is safe to do
- * unlocked as we have the only reference to it.
- */
- for (llq = head; llq != NULL; llq = head) {
- ifp = llq->llq_ifp;
-
- CURVNET_SET(ifp->if_vnet);
-
- /*
- * Set the link layer address on the laggport interface.
- * Note that if_setlladdr() or iflladdr_event handler
- * may result in arp transmission / lltable updates.
- */
- if (llq->llq_type == LAGG_LLQTYPE_PHYS)
- if_setlladdr(ifp, llq->llq_lladdr,
- ETHER_ADDR_LEN);
- else
- EVENTHANDLER_INVOKE(iflladdr_event, ifp);
- CURVNET_RESTORE();
- head = SLIST_NEXT(llq, llq_entries);
- if_rele(ifp);
- free(llq, M_DEVBUF);
- }
-}
-
static int
lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp)
{
@@ -741,7 +618,7 @@
int error, i;
uint64_t *pval;
- LAGG_WLOCK_ASSERT(sc);
+ LAGG_XLOCK_ASSERT(sc);
/* Limit the maximal number of lagg ports */
if (sc->sc_count >= LAGG_MAX_PORTS)
@@ -769,9 +646,8 @@
return (EINVAL);
}
- if ((lp = malloc(sizeof(struct lagg_port),
- M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
- return (ENOMEM);
+ lp = malloc(sizeof(struct lagg_port), M_DEVBUF, M_WAITOK|M_ZERO);
+ lp->lp_softc = sc;
/* Check if port is a stacked lagg */
LAGG_LIST_LOCK();
@@ -794,6 +670,26 @@
}
LAGG_LIST_UNLOCK();
+ if_ref(ifp);
+ lp->lp_ifp = ifp;
+
+ bcopy(IF_LLADDR(ifp), lp->lp_lladdr, ETHER_ADDR_LEN);
+ lp->lp_ifcapenable = ifp->if_capenable;
+ if (SLIST_EMPTY(&sc->sc_ports)) {
+ LAGG_WLOCK(sc);
+ bcopy(IF_LLADDR(ifp), IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN);
+ lagg_proto_lladdr(sc);
+ LAGG_WUNLOCK(sc);
+ EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp);
+ } else {
+ if_setlladdr(ifp, IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN);
+ }
+ lagg_setflags(lp, 1);
+
+ LAGG_WLOCK(sc);
+ if (SLIST_EMPTY(&sc->sc_ports))
+ sc->sc_primary = lp;
+
/* Change the interface type */
lp->lp_iftype = ifp->if_type;
ifp->if_type = IFT_IEEE8023ADLAG;
@@ -803,26 +699,11 @@
lp->lp_output = ifp->if_output;
ifp->if_output = lagg_port_output;
- if_ref(ifp);
- lp->lp_ifp = ifp;
- lp->lp_softc = sc;
+ /* Read port counters */
+ pval = lp->port_counters.val;
+ for (i = 0; i < IFCOUNTERS; i++, pval++)
+ *pval = ifp->if_get_counter(ifp, i);
- /* Save port link layer address */
- bcopy(IF_LLADDR(ifp), lp->lp_lladdr, ETHER_ADDR_LEN);
-
- if (SLIST_EMPTY(&sc->sc_ports)) {
- sc->sc_primary = lp;
- /* First port in lagg. Update/notify lagg lladdress */
- lagg_lladdr(sc, IF_LLADDR(ifp));
- } else {
-
- /*
- * Update link layer address for this port and
- * send notifications to other subsystems.
- */
- lagg_port_lladdr(lp, IF_LLADDR(sc->sc_ifp), LAGG_LLQTYPE_PHYS);
- }
-
/*
* Insert into the list of ports.
* Keep ports sorted by if_index. It is handy, when configuration
@@ -842,24 +723,21 @@
SLIST_INSERT_HEAD(&sc->sc_ports, lp, lp_entries);
sc->sc_count++;
- /* Update lagg capabilities */
- lagg_capabilities(sc);
- lagg_linkstate(sc);
+ lagg_setmulti(lp);
- /* Read port counters */
- pval = lp->port_counters.val;
- for (i = 0; i < IFCOUNTERS; i++, pval++)
- *pval = ifp->if_get_counter(ifp, i);
- /* Add multicast addresses and interface flags to this port */
- lagg_ether_cmdmulti(lp, 1);
- lagg_setflags(lp, 1);
-
if ((error = lagg_proto_addport(sc, lp)) != 0) {
/* Remove the port, without calling pr_delport. */
lagg_port_destroy(lp, 0);
+ LAGG_UNLOCK_ASSERT(sc);
return (error);
}
+ LAGG_WUNLOCK(sc);
+
+ /* Update lagg capabilities */
+ lagg_capabilities(sc);
+ lagg_linkstate(sc);
+
return (0);
}
@@ -871,8 +749,7 @@
struct lagg_port *lp;
int m = 0;
- LAGG_WLOCK_ASSERT(sc);
-
+ LAGG_SXLOCK_ASSERT(sc);
SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
if (lp->lp_flags & LAGG_PORT_STACK) {
sc_ptr = (struct lagg_softc *)lp->lp_ifp->if_softc;
@@ -889,25 +766,20 @@
{
struct lagg_softc *sc = lp->lp_softc;
struct lagg_port *lp_ptr, *lp0;
- struct lagg_llq *llq;
struct ifnet *ifp = lp->lp_ifp;
uint64_t *pval, vdiff;
int i;
- LAGG_WLOCK_ASSERT(sc);
+ LAGG_XLOCK_ASSERT(sc);
- if (rundelport)
+ if (rundelport) {
+ LAGG_WLOCK(sc);
lagg_proto_delport(sc, lp);
+ } else
+ LAGG_WLOCK_ASSERT(sc);
- /*
- * Remove multicast addresses and interface flags from this port and
- * reset the MAC address, skip if the interface is being detached.
- */
- if (lp->lp_detaching == 0) {
- lagg_ether_cmdmulti(lp, 0);
- lagg_setflags(lp, 0);
- lagg_port_lladdr(lp, lp->lp_lladdr, LAGG_LLQTYPE_PHYS);
- }
+ if (lp->lp_detaching == 0)
+ lagg_clrmulti(lp);
/* Restore interface */
ifp->if_type = lp->lp_iftype;
@@ -930,43 +802,37 @@
if (lp == sc->sc_primary) {
uint8_t lladdr[ETHER_ADDR_LEN];
- if ((lp0 = SLIST_FIRST(&sc->sc_ports)) == NULL) {
+ if ((lp0 = SLIST_FIRST(&sc->sc_ports)) == NULL)
bzero(&lladdr, ETHER_ADDR_LEN);
- } else {
- bcopy(lp0->lp_lladdr,
- lladdr, ETHER_ADDR_LEN);
- }
- if (lp->lp_detaching != LAGG_CLONE_DESTROY)
- lagg_lladdr(sc, lladdr);
-
- /* Mark lp0 as new primary */
+ else
+ bcopy(lp0->lp_lladdr, lladdr, ETHER_ADDR_LEN);
sc->sc_primary = lp0;
+ if (sc->sc_destroying == 0) {
+ bcopy(lladdr, IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN);
+ lagg_proto_lladdr(sc);
+ LAGG_WUNLOCK(sc);
+ EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp);
+ } else
+ LAGG_WUNLOCK(sc);
/*
- * Enqueue lladdr update/notification for each port
- * (new primary needs update as well, to switch from
- * old lladdr to its 'real' one).
+ * Update lladdr for each port (new primary needs update
+ * as well, to switch from old lladdr to its 'real' one)
*/
SLIST_FOREACH(lp_ptr, &sc->sc_ports, lp_entries)
- lagg_port_lladdr(lp_ptr, lladdr, LAGG_LLQTYPE_PHYS);
- }
+ if_setlladdr(ifp, lladdr, ETHER_ADDR_LEN);
+ } else
+ LAGG_WUNLOCK(sc);
- /* Remove any pending lladdr changes from the queue */
- if (lp->lp_detaching != 0) {
- SLIST_FOREACH(llq, &sc->sc_llq_head, llq_entries) {
- if (llq->llq_ifp == ifp) {
- SLIST_REMOVE(&sc->sc_llq_head, llq, lagg_llq,
- llq_entries);
- if_rele(llq->llq_ifp);
- free(llq, M_DEVBUF);
- break; /* Only appears once */
- }
- }
- }
-
if (lp->lp_ifflags)
if_printf(ifp, "%s: lp_ifflags unclean\n", __func__);
+ if (lp->lp_detaching == 0) {
+ lagg_setflags(lp, 0);
+ lagg_setcaps(lp, lp->lp_ifcapenable);
+ if_setlladdr(ifp, lp->lp_lladdr, ETHER_ADDR_LEN);
+ }
+
if_rele(ifp);
free(lp, M_DEVBUF);
@@ -984,7 +850,6 @@
struct lagg_softc *sc;
struct lagg_port *lp = NULL;
int error = 0;
- struct rm_priotracker tracker;
/* Should be checked by the caller */
if (ifp->if_type != IFT_IEEE8023ADLAG ||
@@ -999,15 +864,15 @@
break;
}
- LAGG_RLOCK(sc, &tracker);
+ LAGG_SLOCK(sc);
if ((lp = ifp->if_lagg) == NULL || lp->lp_softc != sc) {
error = ENOENT;
- LAGG_RUNLOCK(sc, &tracker);
+ LAGG_SUNLOCK(sc);
break;
}
lagg_port2req(lp, rp);
- LAGG_RUNLOCK(sc, &tracker);
+ LAGG_SUNLOCK(sc);
break;
case SIOCSIFCAP:
@@ -1020,9 +885,9 @@
break;
/* Update lagg interface capabilities */
- LAGG_WLOCK(sc);
+ LAGG_XLOCK(sc);
lagg_capabilities(sc);
- LAGG_WUNLOCK(sc);
+ LAGG_XUNLOCK(sc);
break;
case SIOCSIFMTU:
@@ -1132,10 +997,10 @@
sc = lp->lp_softc;
- LAGG_WLOCK(sc);
- lp->lp_detaching = LAGG_PORT_DETACH;
+ LAGG_XLOCK(sc);
+ lp->lp_detaching = 1;
lagg_port_destroy(lp, 1);
- LAGG_WUNLOCK(sc);
+ LAGG_XUNLOCK(sc);
}
static void
@@ -1185,11 +1050,12 @@
struct ifnet *ifp = sc->sc_ifp;
struct lagg_port *lp;
- if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ LAGG_XLOCK(sc);
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+ LAGG_XUNLOCK(sc);
return;
+ }
- LAGG_WLOCK(sc);
-
ifp->if_drv_flags |= IFF_DRV_RUNNING;
/*
@@ -1197,12 +1063,15 @@
* This might be if_setlladdr() notification
* that lladdr has been changed.
*/
- SLIST_FOREACH(lp, &sc->sc_ports, lp_entries)
- lagg_port_lladdr(lp, IF_LLADDR(ifp), LAGG_LLQTYPE_PHYS);
+ SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
+ if (memcmp(IF_LLADDR(ifp), IF_LLADDR(lp->lp_ifp),
+ ETHER_ADDR_LEN) != 0)
+ if_setlladdr(lp->lp_ifp, IF_LLADDR(ifp), ETHER_ADDR_LEN);
+ }
lagg_proto_init(sc);
- LAGG_WUNLOCK(sc);
+ LAGG_XUNLOCK(sc);
}
static void
@@ -1210,7 +1079,7 @@
{
struct ifnet *ifp = sc->sc_ifp;
- LAGG_WLOCK_ASSERT(sc);
+ LAGG_XLOCK_ASSERT(sc);
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
return;
@@ -1234,22 +1103,14 @@
struct thread *td = curthread;
char *buf, *outbuf;
int count, buflen, len, error = 0;
- struct rm_priotracker tracker;
bzero(&rpbuf, sizeof(rpbuf));
switch (cmd) {
case SIOCGLAGG:
- LAGG_RLOCK(sc, &tracker);
- count = 0;
- SLIST_FOREACH(lp, &sc->sc_ports, lp_entries)
- count++;
- buflen = count * sizeof(struct lagg_reqport);
- LAGG_RUNLOCK(sc, &tracker);
-
+ LAGG_SLOCK(sc);
+ buflen = sc->sc_count * sizeof(struct lagg_reqport);
outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO);
-
- LAGG_RLOCK(sc, &tracker);
ra->ra_proto = sc->sc_proto;
lagg_proto_request(sc, &ra->ra_psc);
count = 0;
@@ -1265,7 +1126,7 @@
buf += sizeof(rpbuf);
len -= sizeof(rpbuf);
}
- LAGG_RUNLOCK(sc, &tracker);
+ LAGG_SUNLOCK(sc);
ra->ra_ports = count;
ra->ra_size = count * sizeof(rpbuf);
error = copyout(outbuf, ra->ra_port, ra->ra_size);
@@ -1280,12 +1141,15 @@
break;
}
+ LAGG_XLOCK(sc);
LAGG_WLOCK(sc);
lagg_proto_detach(sc);
LAGG_UNLOCK_ASSERT(sc);
lagg_proto_attach(sc, ra->ra_proto);
+ LAGG_XUNLOCK(sc);
break;
case SIOCGLAGGOPTS:
+ LAGG_SLOCK(sc);
ro->ro_opts = sc->sc_opts;
if (sc->sc_proto == LAGG_PROTO_LACP) {
struct lacp_softc *lsc;
@@ -1309,6 +1173,7 @@
ro->ro_bkt = sc->sc_bkt;
ro->ro_flapping = sc->sc_flapping;
ro->ro_flowid_shift = sc->flowid_shift;
+ LAGG_SUNLOCK(sc);
break;
case SIOCSLAGGOPTS:
if (sc->sc_proto == LAGG_PROTO_ROUNDROBIN) {
@@ -1350,13 +1215,13 @@
break;
}
- LAGG_WLOCK(sc);
+ LAGG_XLOCK(sc);
if (valid == 0 ||
(lacp == 1 && sc->sc_proto != LAGG_PROTO_LACP)) {
/* Invalid combination of options specified. */
error = EINVAL;
- LAGG_WUNLOCK(sc);
+ LAGG_XUNLOCK(sc);
break; /* Return from SIOCSLAGGOPTS. */
}
/*
@@ -1411,11 +1276,11 @@
break;
}
}
- LAGG_WUNLOCK(sc);
+ LAGG_XUNLOCK(sc);
break;
case SIOCGLAGGFLAGS:
rf->rf_flags = 0;
- LAGG_RLOCK(sc, &tracker);
+ LAGG_SLOCK(sc);
if (sc->sc_flags & MBUF_HASHFLAG_L2)
rf->rf_flags |= LAGG_F_HASHL2;
if (sc->sc_flags & MBUF_HASHFLAG_L3)
@@ -1422,7 +1287,7 @@
rf->rf_flags |= LAGG_F_HASHL3;
if (sc->sc_flags & MBUF_HASHFLAG_L4)
rf->rf_flags |= LAGG_F_HASHL4;
- LAGG_RUNLOCK(sc, &tracker);
+ LAGG_SUNLOCK(sc);
break;
case SIOCSLAGGHASH:
error = priv_check(td, PRIV_NET_LAGG);
@@ -1432,7 +1297,7 @@
error = EINVAL;
break;
}
- LAGG_WLOCK(sc);
+ LAGG_XLOCK(sc);
sc->sc_flags = 0;
if (rf->rf_flags & LAGG_F_HASHL2)
sc->sc_flags |= MBUF_HASHFLAG_L2;
@@ -1440,7 +1305,7 @@
sc->sc_flags |= MBUF_HASHFLAG_L3;
if (rf->rf_flags & LAGG_F_HASHL4)
sc->sc_flags |= MBUF_HASHFLAG_L4;
- LAGG_WUNLOCK(sc);
+ LAGG_XUNLOCK(sc);
break;
case SIOCGLAGGPORT:
if (rp->rp_portname[0] == '\0' ||
@@ -1449,17 +1314,17 @@
break;
}
- LAGG_RLOCK(sc, &tracker);
+ LAGG_SLOCK(sc);
if ((lp = (struct lagg_port *)tpif->if_lagg) == NULL ||
lp->lp_softc != sc) {
error = ENOENT;
- LAGG_RUNLOCK(sc, &tracker);
+ LAGG_SUNLOCK(sc);
if_rele(tpif);
break;
}
lagg_port2req(lp, rp);
- LAGG_RUNLOCK(sc, &tracker);
+ LAGG_SUNLOCK(sc);
if_rele(tpif);
break;
case SIOCSLAGGPORT:
@@ -1491,9 +1356,9 @@
tpif->if_xname);
}
#endif
- LAGG_WLOCK(sc);
+ LAGG_XLOCK(sc);
error = lagg_port_create(sc, tpif);
- LAGG_WUNLOCK(sc);
+ LAGG_XUNLOCK(sc);
if_rele(tpif);
break;
case SIOCSLAGGDELPORT:
@@ -1506,26 +1371,25 @@
break;
}
- LAGG_WLOCK(sc);
+ LAGG_XLOCK(sc);
if ((lp = (struct lagg_port *)tpif->if_lagg) == NULL ||
lp->lp_softc != sc) {
error = ENOENT;
- LAGG_WUNLOCK(sc);
+ LAGG_XUNLOCK(sc);
if_rele(tpif);
break;
}
error = lagg_port_destroy(lp, 1);
- LAGG_WUNLOCK(sc);
+ LAGG_XUNLOCK(sc);
if_rele(tpif);
break;
case SIOCSIFFLAGS:
/* Set flags on ports too */
- LAGG_WLOCK(sc);
+ LAGG_XLOCK(sc);
SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
lagg_setflags(lp, 1);
}
- LAGG_WUNLOCK(sc);
if (!(ifp->if_flags & IFF_UP) &&
(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
@@ -1533,9 +1397,8 @@
* If interface is marked down and it is running,
* then stop and disable it.
*/
- LAGG_WLOCK(sc);
lagg_stop(sc);
- LAGG_WUNLOCK(sc);
+ LAGG_XUNLOCK(sc);
} else if ((ifp->if_flags & IFF_UP) &&
!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
/*
@@ -1542,14 +1405,20 @@
* If interface is marked up and it is stopped, then
* start it.
*/
+ LAGG_XUNLOCK(sc);
(*ifp->if_init)(sc);
- }
+ } else
+ LAGG_XUNLOCK(sc);
break;
case SIOCADDMULTI:
case SIOCDELMULTI:
LAGG_WLOCK(sc);
- error = lagg_ether_setmulti(sc);
+ SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
+ lagg_clrmulti(lp);
+ lagg_setmulti(lp);
+ }
LAGG_WUNLOCK(sc);
+ error = 0;
break;
case SIOCSIFMEDIA:
case SIOCGIFMEDIA:
@@ -1557,8 +1426,18 @@
break;
case SIOCSIFCAP:
+ LAGG_XLOCK(sc);
+ SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
+ if (lp->lp_ioctl != NULL)
+ (*lp->lp_ioctl)(lp->lp_ifp, cmd, data);
+ }
+ lagg_capabilities(sc);
+ LAGG_XUNLOCK(sc);
+ error = 0;
+ break;
+
case SIOCSIFMTU:
- /* Do not allow the MTU or caps to be directly changed */
+ /* Do not allow the MTU to be directly changed */
error = EINVAL;
break;
@@ -1616,67 +1495,70 @@
#endif
static int
-lagg_ether_setmulti(struct lagg_softc *sc)
+lagg_setmulti(struct lagg_port *lp)
{
- struct lagg_port *lp;
+ struct lagg_softc *sc = lp->lp_softc;
+ struct ifnet *ifp = lp->lp_ifp;
+ struct ifnet *scifp = sc->sc_ifp;
+ struct lagg_mc *mc;
+ struct ifmultiaddr *ifma;
+ int error;
LAGG_WLOCK_ASSERT(sc);
-
- SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
- /* First, remove any existing filter entries. */
- lagg_ether_cmdmulti(lp, 0);
- /* copy all addresses from the lagg interface to the port */
- lagg_ether_cmdmulti(lp, 1);
+ IF_ADDR_WLOCK(scifp);
+ TAILQ_FOREACH(ifma, &scifp->if_multiaddrs, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ mc = malloc(sizeof(struct lagg_mc), M_DEVBUF, M_NOWAIT);
+ if (mc == NULL) {
+ IF_ADDR_WUNLOCK(scifp);
+ return (ENOMEM);
+ }
+ bcopy(ifma->ifma_addr, &mc->mc_addr,
+ ifma->ifma_addr->sa_len);
+ mc->mc_addr.sdl_index = ifp->if_index;
+ mc->mc_ifma = NULL;
+ SLIST_INSERT_HEAD(&lp->lp_mc_head, mc, mc_entries);
}
+ IF_ADDR_WUNLOCK(scifp);
+ SLIST_FOREACH (mc, &lp->lp_mc_head, mc_entries) {
+ error = if_addmulti(ifp,
+ (struct sockaddr *)&mc->mc_addr, &mc->mc_ifma);
+ if (error)
+ return (error);
+ }
return (0);
}
static int
-lagg_ether_cmdmulti(struct lagg_port *lp, int set)
+lagg_clrmulti(struct lagg_port *lp)
{
struct lagg_softc *sc = lp->lp_softc;
- struct ifnet *ifp = lp->lp_ifp;
- struct ifnet *scifp = sc->sc_ifp;
struct lagg_mc *mc;
- struct ifmultiaddr *ifma;
- int error;
LAGG_WLOCK_ASSERT(sc);
-
- if (set) {
- IF_ADDR_WLOCK(scifp);
- TAILQ_FOREACH(ifma, &scifp->if_multiaddrs, ifma_link) {
- if (ifma->ifma_addr->sa_family != AF_LINK)
- continue;
- mc = malloc(sizeof(struct lagg_mc), M_DEVBUF, M_NOWAIT);
- if (mc == NULL) {
- IF_ADDR_WUNLOCK(scifp);
- return (ENOMEM);
- }
- bcopy(ifma->ifma_addr, &mc->mc_addr,
- ifma->ifma_addr->sa_len);
- mc->mc_addr.sdl_index = ifp->if_index;
- mc->mc_ifma = NULL;
- SLIST_INSERT_HEAD(&lp->lp_mc_head, mc, mc_entries);
- }
- IF_ADDR_WUNLOCK(scifp);
- SLIST_FOREACH (mc, &lp->lp_mc_head, mc_entries) {
- error = if_addmulti(ifp,
- (struct sockaddr *)&mc->mc_addr, &mc->mc_ifma);
- if (error)
- return (error);
- }
- } else {
- while ((mc = SLIST_FIRST(&lp->lp_mc_head)) != NULL) {
- SLIST_REMOVE(&lp->lp_mc_head, mc, lagg_mc, mc_entries);
- if (mc->mc_ifma && lp->lp_detaching == 0)
- if_delmulti_ifma(mc->mc_ifma);
- free(mc, M_DEVBUF);
- }
+ while ((mc = SLIST_FIRST(&lp->lp_mc_head)) != NULL) {
+ SLIST_REMOVE(&lp->lp_mc_head, mc, lagg_mc, mc_entries);
+ if (mc->mc_ifma && lp->lp_detaching == 0)
+ if_delmulti_ifma(mc->mc_ifma);
+ free(mc, M_DEVBUF);
}
return (0);
}
+static int
+lagg_setcaps(struct lagg_port *lp, int cap)
+{
+ struct ifreq ifr;
+
+ if (lp->lp_ifp->if_capenable == cap)
+ return (0);
+ if (lp->lp_ioctl == NULL)
+ return (ENXIO);
+ ifr.ifr_reqcap = cap;
+ return ((*lp->lp_ioctl)(lp->lp_ifp, SIOCSIFCAP, (caddr_t)&ifr));
+}
+
/* Handle a ref counted flag that should be set on the lagg port as well */
static int
lagg_setflag(struct lagg_port *lp, int flag, int status,
@@ -1687,7 +1569,7 @@
struct ifnet *ifp = lp->lp_ifp;
int error;
- LAGG_WLOCK_ASSERT(sc);
+ LAGG_XLOCK_ASSERT(sc);
status = status ? (scifp->if_flags & flag) : 0;
/* Now "status" contains the flag value or 0 */
@@ -1821,17 +1703,16 @@
{
struct lagg_softc *sc = (struct lagg_softc *)ifp->if_softc;
struct lagg_port *lp;
- struct rm_priotracker tracker;
imr->ifm_status = IFM_AVALID;
imr->ifm_active = IFM_ETHER | IFM_AUTO;
- LAGG_RLOCK(sc, &tracker);
+ LAGG_SLOCK(sc);
SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
if (LAGG_PORTACTIVE(lp))
imr->ifm_status |= IFM_ACTIVE;
}
- LAGG_RUNLOCK(sc, &tracker);
+ LAGG_SUNLOCK(sc);
}
static void
@@ -1841,6 +1722,8 @@
int new_link = LINK_STATE_DOWN;
uint64_t speed;
+ LAGG_XLOCK_ASSERT(sc);
+
/* Our link is considered up if at least one of our ports is active */
SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
if (lp->lp_ifp->if_link_state == LINK_STATE_UP) {
@@ -1881,10 +1764,10 @@
if (sc == NULL)
return;
- LAGG_WLOCK(sc);
+ LAGG_XLOCK(sc);
lagg_linkstate(sc);
lagg_proto_linkstate(sc, lp);
- LAGG_WUNLOCK(sc);
+ LAGG_XUNLOCK(sc);
}
struct lagg_port *
@@ -1893,7 +1776,6 @@
struct lagg_port *lp_next, *rval = NULL;
// int new_link = LINK_STATE_DOWN;
- LAGG_RLOCK_ASSERT(sc);
/*
* Search a port which reports an active link state.
*/
@@ -2250,6 +2132,8 @@
{
struct lagg_port *lp;
+ LAGG_SXLOCK_ASSERT(sc);
+
/* purge all the lacp ports */
SLIST_FOREACH(lp, &sc->sc_ports, lp_entries)
lacp_port_destroy(lp);

File Metadata

Mime Type
text/plain
Expires
Sun, Mar 9, 11:50 PM (8 h, 23 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17077467
Default Alt Text
D10514.id27759.diff (28 KB)

Event Timeline