Index: head/sys/net/if_lagg.c =================================================================== --- head/sys/net/if_lagg.c +++ head/sys/net/if_lagg.c @@ -633,11 +633,18 @@ { struct lagg_softc *sc_ptr; struct lagg_port *lp, *tlp; - int error, i; + struct ifreq ifr; + int error, i, oldmtu; uint64_t *pval; LAGG_XLOCK_ASSERT(sc); + if (sc->sc_ifp == ifp) { + if_printf(sc->sc_ifp, + "cannot add a lagg to itself as a port\n"); + return (EINVAL); + } + /* Limit the maximal number of lagg ports */ if (sc->sc_count >= LAGG_MAX_PORTS) return (ENOSPC); @@ -656,12 +663,25 @@ return (EPROTONOSUPPORT); /* Allow the first Ethernet member to define the MTU */ - if (CK_SLIST_EMPTY(&sc->sc_ports)) + oldmtu = -1; + if (CK_SLIST_EMPTY(&sc->sc_ports)) { sc->sc_ifp->if_mtu = ifp->if_mtu; - else if (sc->sc_ifp->if_mtu != ifp->if_mtu) { - if_printf(sc->sc_ifp, "invalid MTU for %s\n", - ifp->if_xname); - return (EINVAL); + } else if (sc->sc_ifp->if_mtu != ifp->if_mtu) { + if (ifp->if_ioctl == NULL) { + if_printf(sc->sc_ifp, "cannot change MTU for %s\n", + ifp->if_xname); + return (EINVAL); + } + oldmtu = ifp->if_mtu; + strlcpy(ifr.ifr_name, ifp->if_xname, sizeof(ifr.ifr_name)); + ifr.ifr_mtu = sc->sc_ifp->if_mtu; + error = (*ifp->if_ioctl)(ifp, SIOCSIFMTU, (caddr_t)&ifr); + if (error != 0) { + if_printf(sc->sc_ifp, "invalid MTU for %s\n", + ifp->if_xname); + return (error); + } + ifr.ifr_mtu = oldmtu; } lp = malloc(sizeof(struct lagg_port), M_DEVBUF, M_WAITOK|M_ZERO); @@ -673,6 +693,9 @@ if (ifp == sc_ptr->sc_ifp) { LAGG_LIST_UNLOCK(); free(lp, M_DEVBUF); + if (oldmtu != -1) + (*ifp->if_ioctl)(ifp, SIOCSIFMTU, + (caddr_t)&ifr); return (EINVAL); /* XXX disable stacking for the moment, its untested */ #ifdef LAGG_PORT_STACKING @@ -681,6 +704,9 @@ LAGG_MAX_STACKING) { LAGG_LIST_UNLOCK(); free(lp, M_DEVBUF); + if (oldmtu != -1) + (*ifp->if_ioctl)(ifp, SIOCSIFMTU, + (caddr_t)&ifr); return (E2BIG); } #endif @@ -746,6 +772,8 @@ if ((error = lagg_proto_addport(sc, lp)) != 0) { /* Remove the port, without calling pr_delport. */ lagg_port_destroy(lp, 0); + if (oldmtu != -1) + (*ifp->if_ioctl)(ifp, SIOCSIFMTU, (caddr_t)&ifr); return (error); } @@ -1464,8 +1492,31 @@ break; case SIOCSIFMTU: - /* Do not allow the MTU to be directly changed */ - error = EINVAL; + LAGG_XLOCK(sc); + CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { + if (lp->lp_ioctl != NULL) + error = (*lp->lp_ioctl)(lp->lp_ifp, cmd, data); + else + error = EINVAL; + if (error != 0) { + if_printf(ifp, + "failed to change MTU to %d on port %s, " + "reverting all ports to original MTU (%d)\n", + ifr->ifr_mtu, lp->lp_ifp->if_xname, ifp->if_mtu); + break; + } + } + if (error == 0) { + ifp->if_mtu = ifr->ifr_mtu; + } else { + /* set every port back to the original MTU */ + ifr->ifr_mtu = ifp->if_mtu; + CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { + if (lp->lp_ioctl != NULL) + (*lp->lp_ioctl)(lp->lp_ifp, cmd, data); + } + } + LAGG_XUNLOCK(sc); break; default: