summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/net/if_lagg.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/net/if_lagg.c')
-rw-r--r--freebsd/sys/net/if_lagg.c67
1 files changed, 59 insertions, 8 deletions
diff --git a/freebsd/sys/net/if_lagg.c b/freebsd/sys/net/if_lagg.c
index 632ea744..85099115 100644
--- a/freebsd/sys/net/if_lagg.c
+++ b/freebsd/sys/net/if_lagg.c
@@ -635,11 +635,18 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp)
{
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);
@@ -658,12 +665,25 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp)
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);
@@ -675,6 +695,9 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp)
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
@@ -683,6 +706,9 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp)
LAGG_MAX_STACKING) {
LAGG_LIST_UNLOCK();
free(lp, M_DEVBUF);
+ if (oldmtu != -1)
+ (*ifp->if_ioctl)(ifp, SIOCSIFMTU,
+ (caddr_t)&ifr);
return (E2BIG);
}
#endif
@@ -748,6 +774,8 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp)
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);
}
@@ -1466,8 +1494,31 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
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: