Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F135024278
D4004.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D4004.diff
View Options
Index: head/sys/net/if.c
===================================================================
--- head/sys/net/if.c
+++ head/sys/net/if.c
@@ -3314,8 +3314,10 @@
*
* At this time we only support certain types of interfaces,
* and we don't allow the length of the address to change.
+ *
+ * Set noinline to be dtrace-friendly
*/
-int
+__noinline int
if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len)
{
struct sockaddr_dl *sdl;
Index: head/sys/net/if_lagg.h
===================================================================
--- head/sys/net/if_lagg.h
+++ head/sys/net/if_lagg.h
@@ -201,11 +201,16 @@
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];
- uint8_t llq_primary;
+ lagg_llqtype llq_type;
SLIST_ENTRY(lagg_llq) llq_entries;
};
@@ -273,6 +278,7 @@
#define LAGG_WUNLOCK(_sc) rm_wunlock(&(_sc)->sc_mtx)
#define LAGG_RLOCK_ASSERT(_sc) rm_assert(&(_sc)->sc_mtx, RA_RLOCKED)
#define LAGG_WLOCK_ASSERT(_sc) rm_assert(&(_sc)->sc_mtx, RA_WLOCKED)
+#define LAGG_UNLOCK_ASSERT(_sc) rm_assert(&(_sc)->sc_mtx, RA_UNLOCKED)
extern struct mbuf *(*lagg_input_p)(struct ifnet *, struct mbuf *);
extern void (*lagg_linkstate_p)(struct ifnet *, int );
Index: head/sys/net/if_lagg.c
===================================================================
--- head/sys/net/if_lagg.c
+++ head/sys/net/if_lagg.c
@@ -100,7 +100,7 @@
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 *);
+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);
@@ -543,6 +543,7 @@
lagg_port_destroy(lp, 1);
/* Unhook the aggregation protocol */
lagg_proto_detach(sc);
+ LAGG_UNLOCK_ASSERT(sc);
ifmedia_removeall(&sc->sc_media);
ether_ifdetach(ifp);
@@ -557,7 +558,12 @@
free(sc, M_DEVBUF);
}
-static void
+/*
+ * 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;
@@ -577,11 +583,16 @@
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;
- lagg_port_lladdr(&lp, lladdr);
+ /* Do not request lladdr change */
+ lagg_port_lladdr(&lp, lladdr, LAGG_LLQTYPE_VIRT);
}
static void
@@ -622,51 +633,58 @@
}
}
-static void
-lagg_port_lladdr(struct lagg_port *lp, uint8_t *lladdr)
+/*
+ * 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;
- int pending = 0;
- int primary;
LAGG_WLOCK_ASSERT(sc);
- primary = (sc->sc_primary->lp_ifp == ifp) ? 1 : 0;
- if (primary == 0 && (lp->lp_detaching ||
- memcmp(lladdr, IF_LLADDR(ifp), ETHER_ADDR_LEN) == 0))
+ /*
+ * 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 && llq->llq_primary == primary) {
- pending = 1;
- break;
+ if (llq->llq_ifp == ifp) {
+ /* Update lladdr, it may have changed */
+ bcopy(lladdr, llq->llq_lladdr, ETHER_ADDR_LEN);
+ return;
}
}
- if (!pending) {
- llq = malloc(sizeof(struct lagg_llq), M_DEVBUF, M_NOWAIT);
- if (llq == NULL) /* XXX what to do */
- return;
- }
+ llq = malloc(sizeof(struct lagg_llq), M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (llq == NULL) /* XXX what to do */
+ return;
- /* Update the lladdr even if pending, it may have changed */
llq->llq_ifp = ifp;
- llq->llq_primary = primary;
+ llq->llq_type = llq_type;
bcopy(lladdr, llq->llq_lladdr, ETHER_ADDR_LEN);
-
- if (!pending)
- SLIST_INSERT_HEAD(&sc->sc_llq_head, llq, llq_entries);
+ /* XXX: We should insert to tail */
+ SLIST_INSERT_HEAD(&sc->sc_llq_head, llq, llq_entries);
taskqueue_enqueue(taskqueue_swi, &sc->sc_lladdr_task);
}
/*
* Set the interface MAC address from a taskqueue to avoid a LOR.
+ *
+ * Set noinline to be dtrace-friendly
*/
-static void
+static __noinline void
lagg_port_setlladdr(void *arg, int pending)
{
struct lagg_softc *sc = (struct lagg_softc *)arg;
@@ -688,17 +706,20 @@
ifp = llq->llq_ifp;
CURVNET_SET(ifp->if_vnet);
- if (llq->llq_primary == 0) {
- /*
- * Set the link layer address on the laggport interface.
- * if_setlladdr() triggers gratuitous ARPs for INET.
- */
+ error = 0;
+
+ /*
+ * 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)
error = if_setlladdr(ifp, llq->llq_lladdr,
ETHER_ADDR_LEN);
- if (error)
- printf("%s: setlladdr failed on %s\n", __func__,
- ifp->if_xname);
- } else
+ if (error)
+ printf("%s: setlladdr failed on %s\n", __func__,
+ ifp->if_xname);
+ else
EVENTHANDLER_INVOKE(iflladdr_event, ifp);
CURVNET_RESTORE();
head = SLIST_NEXT(llq, llq_entries);
@@ -730,7 +751,7 @@
}
/* XXX Disallow non-ethernet interfaces (this should be any of 802) */
- if (ifp->if_type != IFT_ETHER)
+ if (ifp->if_type != IFT_ETHER && ifp->if_type != IFT_L2VLAN)
return (EPROTONOSUPPORT);
/* Allow the first Ethernet member to define the MTU */
@@ -784,10 +805,15 @@
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 */
- lagg_port_lladdr(lp, IF_LLADDR(sc->sc_ifp));
+
+ /*
+ * 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);
}
/*
@@ -873,7 +899,7 @@
if (!lp->lp_detaching) {
lagg_ether_cmdmulti(lp, 0);
lagg_setflags(lp, 0);
- lagg_port_lladdr(lp, lp->lp_lladdr);
+ lagg_port_lladdr(lp, lp->lp_lladdr, LAGG_LLQTYPE_PHYS);
}
/* Restore interface */
@@ -905,19 +931,16 @@
}
lagg_lladdr(sc, lladdr);
+ /* Mark lp0 as new primary */
+ sc->sc_primary = lp0;
+
/*
- * Update link layer address for each port. No port is
- * marked as primary at this moment.
+ * Enqueue lladdr update/notification 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);
- /*
- * Mark lp0 as the new primary. This invokes an
- * iflladdr_event.
- */
- sc->sc_primary = lp0;
- if (lp0 != NULL)
- lagg_port_lladdr(lp0, lladdr);
+ lagg_port_lladdr(lp_ptr, lladdr, LAGG_LLQTYPE_PHYS);
}
/* Remove any pending lladdr changes from the queue */
@@ -1149,8 +1172,8 @@
lagg_init(void *xsc)
{
struct lagg_softc *sc = (struct lagg_softc *)xsc;
- struct lagg_port *lp;
struct ifnet *ifp = sc->sc_ifp;
+ struct lagg_port *lp;
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
return;
@@ -1158,9 +1181,14 @@
LAGG_WLOCK(sc);
ifp->if_drv_flags |= IFF_DRV_RUNNING;
- /* Update the port lladdrs */
+
+ /*
+ * Update the port lladdrs if needed.
+ * 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_port_lladdr(lp, IF_LLADDR(ifp), LAGG_LLQTYPE_PHYS);
lagg_proto_init(sc);
@@ -1244,6 +1272,7 @@
LAGG_WLOCK(sc);
lagg_proto_detach(sc);
+ LAGG_UNLOCK_ASSERT(sc);
lagg_proto_attach(sc, ra->ra_proto);
break;
case SIOCGLAGGOPTS:
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Nov 6, 10:18 PM (15 h, 1 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24960942
Default Alt Text
D4004.diff (8 KB)
Attached To
Mode
D4004: Yet another if_lagg lladdr/eventhandler fix.
Attached
Detach File
Event Timeline
Log In to Comment