--- //SpectraBSD/stable/sys/net/if_lagg.c 2013-02-18 03:17:28.000000000 -0700 +++ //SpectraBSD/stable/sys/net/if_lagg.c 2013-03-28 21:27:00.000000000 -0600 @@ -102,6 +102,7 @@ static int lagg_port_checkstacking(struct lagg_softc *); #endif static void lagg_port2req(struct lagg_port *, struct lagg_reqport *); +static void lagg_if_updown(struct lagg_softc *, int); static void lagg_init(void *); static void lagg_stop(struct lagg_softc *); static int lagg_ioctl(struct ifnet *, u_long, caddr_t); @@ -589,6 +590,7 @@ /* Insert into the list of ports */ SLIST_INSERT_HEAD(&sc->sc_ports, lp, lp_entries); sc->sc_count++; + sc->sc_generation++; /* Update lagg capabilities */ lagg_capabilities(sc); @@ -662,6 +664,7 @@ /* Finally, remove the port from the lagg */ SLIST_REMOVE(&sc->sc_ports, lp, lagg_port, lp_entries); sc->sc_count--; + sc->sc_generation++; /* Update the primary interface */ if (lp == sc->sc_primary) { @@ -753,7 +756,11 @@ break; case SIOCSIFMTU: - /* Do not allow the MTU to be changed once joined */ + /* + * We don't allow changing the MTU on a per-port basis once + * the port is part of a lagg. The user must change the + * MTU of the lagg as a whole. + */ error = EINVAL; break; @@ -852,6 +859,40 @@ } static void +lagg_if_updown(struct lagg_softc *sc, int up) +{ + struct lagg_port *lp; + + LAGG_WLOCK_ASSERT(sc); + +startover: + + SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { + struct ifreq ifr; + uint64_t cur_generation; + int error; + + if (up != 0) + if_up(lp->lp_ifp); + else + if_down(lp->lp_ifp); + + if (lp->lp_ioctl == NULL) + continue; + bzero(&ifr, sizeof(ifr)); + + cur_generation = sc->sc_generation; + + LAGG_WUNLOCK(sc); + error = lp->lp_ioctl(lp->lp_ifp, SIOCSIFFLAGS, (caddr_t)&ifr); + LAGG_WLOCK(sc); + + if (cur_generation != sc->sc_generation) + goto startover; + } +} + +static void lagg_init(void *xsc) { struct lagg_softc *sc = (struct lagg_softc *)xsc; @@ -868,6 +909,8 @@ SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) lagg_port_lladdr(lp, IF_LLADDR(ifp)); + lagg_if_updown(sc, /*up*/ 1); + if (sc->sc_init != NULL) (*sc->sc_init)(sc); @@ -888,6 +931,8 @@ if (sc->sc_stop != NULL) (*sc->sc_stop)(sc); + + lagg_if_updown(sc, /*up*/ 0); } static int @@ -1096,11 +1141,78 @@ break; case SIOCSIFCAP: - case SIOCSIFMTU: - /* Do not allow the MTU or caps to be directly changed */ + /* Do not allow caps to be directly changed */ error = EINVAL; break; + case SIOCSIFMTU: { + struct ifreq *ifr; + int new_mtu, old_mtu; + int error2 = 0; + + ifr = (struct ifreq *)data; + + new_mtu = ifr->ifr_mtu; + + old_mtu = sc->sc_ifp->if_mtu; + /* Nothing to do if there is no change */ + if (new_mtu == old_mtu) + break; + LAGG_WLOCK(sc); + SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { + if (lp->lp_ioctl == NULL) { + printf("%s: SIOCSIFMTU: unable to change " + "MTU for %s because it has no ioctl " + "routine\n", __func__, + lp->lp_ifp->if_xname); + error = EINVAL; + break; + } + error = lp->lp_ioctl(lp->lp_ifp, cmd, data); + /* + * If we get an error setting the MTU for this + * component interface, just exit, and below we'll + * try to reset all of the ports to the previous + * value. + */ + if (error != 0) { + printf("%s: SIOCSIFMTU: error %d changing MTU " + "for %s from %d to %d\n", __func__, error, + lp->lp_ifp->if_xname, old_mtu, new_mtu); + break; + } + } + if (error == 0) { + /* We were successful, so update our saved MTU. */ + sc->sc_ifp->if_mtu = new_mtu; + LAGG_WUNLOCK(sc); + break; + } + /* + * In the error case, try to reset all of the ports to + * their previous value. + */ + SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { + if (lp->lp_ioctl == NULL) + continue; + + error2 = lp->lp_ioctl(lp->lp_ifp, cmd, + (caddr_t)&old_mtu); + /* + * This shouldn't fail, because the port was + * previously at this MTU. If it does for some + * reason, continue on to get as many ports as + * possible back to the old MTU. + */ + if (error2 != 0) { + printf("%s: SIOCSIFMTU: error %d changing MTU " + "for %s back to %d\n", __func__, error, + lp->lp_ifp->if_xname, old_mtu); + } + } + LAGG_WUNLOCK(sc); + break; + } default: error = ether_ioctl(ifp, cmd, data); break; --- //SpectraBSD/stable/sys/net/if_lagg.h 2012-08-29 22:35:04.000000000 -0600 +++ //SpectraBSD/stable/sys/net/if_lagg.h 2013-03-28 21:27:00.000000000 -0600 @@ -189,6 +189,7 @@ struct rwlock sc_mtx; int sc_proto; /* lagg protocol */ u_int sc_count; /* number of ports */ + uint64_t sc_generation; /* generation count */ struct lagg_port *sc_primary; /* primary port */ struct ifmedia sc_media; /* media config */ caddr_t sc_psc; /* protocol data */