Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F140854077
D1986.id11321.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
D1986.id11321.diff
View Options
Index: sys/net/if_lagg.h
===================================================================
--- sys/net/if_lagg.h
+++ sys/net/if_lagg.h
@@ -208,9 +208,19 @@
/* 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;
+
+#define LAGG_ASYNC_SET_MAC_ADDR 0x0001
+#define LAGG_ASYNC_SET_MTU 0x0002
+#define LAGG_ASYNC_SET_MASK (LAGG_ASYNC_SET_MAC_ADDR | LAGG_ASYNC_SET_MTU)
+
+ uint16_t flags;
+ struct ifreq *ifr; /* Common to all lagg member ports */
+ uint32_t old_mtu;
+ int (*llq_ioctl)(struct ifnet *, u_long, caddr_t);
SLIST_ENTRY(lagg_llq) llq_entries;
};
@@ -235,9 +245,9 @@
SLIST_HEAD(__tplhd, lagg_port) sc_ports; /* list of interfaces */
SLIST_ENTRY(lagg_softc) sc_entries;
- struct task sc_lladdr_task;
+ struct task sc_llq_task; /* ASYNC ops enqueued here */
SLIST_HEAD(__llqhd, lagg_llq) sc_llq_head; /* interfaces to program
- the lladdr on */
+ the MAC, lladdr on */
eventhandler_tag vlan_attach;
eventhandler_tag vlan_detach;
struct callout sc_callout;
Index: sys/net/if_lagg.c
===================================================================
--- sys/net/if_lagg.c
+++ sys/net/if_lagg.c
@@ -101,7 +101,9 @@
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 void lagg_port_ops(void *, int);
+static void lagg_port_set_mtu(struct lagg_softc *, struct lagg_llq *);
+static void lagg_port_setlladdr(struct lagg_llq *);
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 *);
@@ -130,6 +132,10 @@
static void lagg_media_status(struct ifnet *, struct ifmediareq *);
static struct lagg_port *lagg_link_active(struct lagg_softc *,
struct lagg_port *);
+static int lagg_change_mtu(struct ifnet *ifp, struct ifreq *ifr);
+static struct lagg_llq *lagg_get_llq_entry(struct lagg_softc *,
+ struct ifnet *);
+static void lagg_llq_list_cleanup(struct lagg_softc *);
/* Simple round robin */
static void lagg_rr_attach(struct lagg_softc *);
@@ -487,7 +493,7 @@
LAGG_LOCK_INIT(sc);
SLIST_INIT(&sc->sc_ports);
- TASK_INIT(&sc->sc_lladdr_task, 0, lagg_port_setlladdr, sc);
+ TASK_INIT(&sc->sc_llq_task, 0, lagg_port_ops, sc);
/* Initialise pseudo media types */
ifmedia_init(&sc->sc_media, 0, lagg_media_change,
@@ -553,7 +559,7 @@
SLIST_REMOVE(&V_lagg_list, sc, lagg_softc, sc_entries);
LAGG_LIST_UNLOCK();
- taskqueue_drain(taskqueue_swi, &sc->sc_lladdr_task);
+ taskqueue_drain(taskqueue_swi, &sc->sc_llq_task);
LAGG_LOCK_DESTROY(sc);
free(sc, M_DEVBUF);
}
@@ -672,24 +678,24 @@
llq->llq_ifp = ifp;
llq->llq_type = llq_type;
+ llq->flags |= LAGG_ASYNC_SET_MAC_ADDR;
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);
+ taskqueue_enqueue(taskqueue_swi, &sc->sc_llq_task);
}
/*
- * Set the interface MAC address from a taskqueue to avoid a LOR.
+ * Set the interface MTU, 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)
+lagg_port_ops(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);
@@ -697,10 +703,172 @@
SLIST_FIRST(&sc->sc_llq_head) = NULL;
LAGG_WUNLOCK(sc);
+ if (!head)
+ return;
+
/*
* Traverse the queue and set the lladdr on each ifp. It is safe to do
* unlocked as we have the only reference to it.
*/
+
+ if (head->flags & LAGG_ASYNC_SET_MTU) {
+ /*
+ * Set the new MTU on the lagg port and its members.
+ * If failed, REVERT to the old MTU.
+ */
+ lagg_port_set_mtu(sc, head);
+ }
+
+ if (head->flags & LAGG_ASYNC_SET_MAC_ADDR) {
+ /*
+ * Set the MAC address.
+ */
+ lagg_port_setlladdr(head);
+ }
+
+ if (!(head->flags & LAGG_ASYNC_SET_MASK))
+ if_printf(sc->sc_ifp,
+ "Lagg port ops: flag (0x%x) not supported\n", head->flags);
+
+ /* Finally free the per port llq entry; DO THIS OPERATION LAST */
+ for (llq = head; llq != NULL; llq = head) {
+ head = SLIST_NEXT(llq, llq_entries);
+ free(llq, M_DEVBUF);
+ }
+}
+
+static void
+lagg_port_set_mtu(struct lagg_softc *sc, struct lagg_llq *head)
+{
+ struct lagg_llq *llq;
+ int err = 0;
+
+ /* Set the new MTU on the lagg interface */
+ LAGG_WLOCK(sc);
+ sc->sc_ifp->if_mtu = head->ifr->ifr_mtu;
+ LAGG_WUNLOCK(sc);
+
+ /* Set the new MTU on the physical interface */
+ for (llq = head; llq != NULL; llq = SLIST_NEXT(llq, llq_entries)) {
+ err = (*llq->llq_ioctl)(llq->llq_ifp, SIOCSIFMTU, (caddr_t)llq->ifr);
+ if (err) {
+ if_printf(llq->llq_ifp,
+ "Failed to change MTU from %d to %d (err %d)\n",
+ llq->old_mtu, llq->ifr->ifr_mtu, err);
+ break;
+ }
+ }
+
+ if (err) {
+ /* Restore the old MTU on the lagg interface */
+ LAGG_WLOCK(sc);
+ sc->sc_ifp->if_mtu = head->old_mtu;
+ LAGG_WUNLOCK(sc);
+
+ /* Restore the old MTU on the physical interface */
+ for (llq = head; llq != NULL; llq = SLIST_NEXT(llq, llq_entries)) {
+ llq->ifr->ifr_mtu = llq->old_mtu;
+ err = (*llq->llq_ioctl)
+ (llq->llq_ifp, SIOCSIFMTU, (caddr_t)llq->ifr);
+ if (err) {
+ if_printf(llq->llq_ifp,
+ "Failed to restore MTU to %d (err %d)\n",
+ llq->old_mtu, err);
+ }
+ }
+ }
+
+ /* Common to all lagg member ports */
+ free(head->ifr, M_DEVBUF);
+}
+
+static void lagg_llq_list_cleanup(struct lagg_softc *sc)
+{
+ struct lagg_llq *head, *llq;
+
+ LAGG_WLOCK_ASSERT(sc);
+
+ head = SLIST_FIRST(&sc->sc_llq_head);
+ SLIST_FIRST(&sc->sc_llq_head) = NULL;
+
+ for (llq = head; llq != NULL; llq = head) {
+ head = SLIST_NEXT(llq, llq_entries);
+ free(llq, M_DEVBUF);
+ }
+}
+
+static struct lagg_llq *
+lagg_get_llq_entry(struct lagg_softc *sc, struct ifnet *ifp)
+{
+ struct lagg_llq *llq;
+
+ LAGG_WLOCK_ASSERT(sc);
+
+ SLIST_FOREACH(llq, &sc->sc_llq_head, llq_entries) {
+ if (llq->llq_ifp == ifp) {
+ break;
+ }
+ }
+ return llq;
+}
+
+static int
+lagg_change_mtu(struct ifnet *ifp, struct ifreq *ifr)
+{
+ struct lagg_softc *sc = (struct lagg_softc *)ifp->if_softc;
+ struct lagg_port *lp;
+ struct lagg_llq *llq;
+ struct ifreq *ifr_copy, *old_ifr = NULL;
+
+ /* No change in MTU */
+ if (ifp->if_mtu == ifr->ifr_mtu)
+ return (0);
+
+ ifr_copy = malloc(sizeof(struct ifreq), M_DEVBUF, M_NOWAIT);
+ if (ifr_copy == NULL)
+ return (ENOMEM);
+
+ bcopy(ifr, ifr_copy, sizeof(struct ifreq));
+ LAGG_WLOCK(sc);
+ /* All lagg ports (MTU change) shall be queued atomic */
+ SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
+ /* Check to make sure its not already queued */
+ llq = lagg_get_llq_entry(sc, lp->lp_ifp);
+ if (!llq) {
+ llq = malloc(sizeof(struct lagg_llq), M_DEVBUF, M_NOWAIT);
+ if (llq == NULL) {
+ lagg_llq_list_cleanup(sc);
+ LAGG_WUNLOCK(sc);
+ free(ifr_copy, M_DEVBUF);
+ if (old_ifr)
+ free(old_ifr, M_DEVBUF);
+ return (ENOMEM);
+ }
+ SLIST_INSERT_HEAD(&sc->sc_llq_head, llq, llq_entries);
+ } else {
+ old_ifr = llq->ifr;
+ }
+
+ /* Update the llq even if pending, it might have updated */
+ llq->ifr = ifr_copy;
+ llq->old_mtu = ifp->if_mtu;
+ llq->llq_ifp = lp->lp_ifp;
+ llq->llq_ioctl = lp->lp_ioctl;
+ llq->flags |= LAGG_ASYNC_SET_MTU;
+ }
+ taskqueue_enqueue(taskqueue_swi, &sc->sc_llq_task);
+ LAGG_WUNLOCK(sc);
+ if (old_ifr)
+ free(old_ifr, M_DEVBUF);
+ return (0);
+}
+
+static void
+lagg_port_setlladdr(struct lagg_llq *head)
+{
+ struct lagg_llq *llq;
+ struct ifnet *ifp;
+
for (llq = head; llq != NULL; llq = head) {
ifp = llq->llq_ifp;
@@ -718,7 +886,6 @@
EVENTHANDLER_INVOKE(iflladdr_event, ifp);
CURVNET_RESTORE();
head = SLIST_NEXT(llq, llq_entries);
- free(llq, M_DEVBUF);
}
}
@@ -1529,10 +1696,12 @@
break;
case SIOCSIFCAP:
- case SIOCSIFMTU:
- /* Do not allow the MTU or caps to be directly changed */
+ /* Do not allow the CAPs to be directly changed. */
error = EINVAL;
break;
+ case SIOCSIFMTU:
+ error = lagg_change_mtu(ifp, ifr);
+ break;
default:
error = ether_ioctl(ifp, cmd, data);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Dec 29, 9:13 PM (14 h, 38 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27367786
Default Alt Text
D1986.id11321.diff (8 KB)
Attached To
Mode
D1986: Teach lagg(4) to change MTU
Attached
Detach File
Event Timeline
Log In to Comment