aboutsummaryrefslogtreecommitdiff
path: root/sys/net
diff options
context:
space:
mode:
authorAndrew Thompson <thompsa@FreeBSD.org>2007-08-05 21:00:31 +0000
committerAndrew Thompson <thompsa@FreeBSD.org>2007-08-05 21:00:31 +0000
commit3ba493198721a1d73cc29445e02ebede454e88d7 (patch)
treeecbf9acd450221025b05c1448ac76b8efe48d309 /sys/net
parent372309105d99c75a7e4b5bf2d7c16241efba237c (diff)
Notes
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/if_lagg.c152
-rw-r--r--sys/net/if_lagg.h1
2 files changed, 109 insertions, 44 deletions
diff --git a/sys/net/if_lagg.c b/sys/net/if_lagg.c
index 80f8edf73079..db8fc9015eb9 100644
--- a/sys/net/if_lagg.c
+++ b/sys/net/if_lagg.c
@@ -78,7 +78,7 @@ eventhandler_tag lagg_detach_cookie = NULL;
static int lagg_clone_create(struct if_clone *, int);
static void lagg_clone_destroy(struct ifnet *);
static void lagg_lladdr(struct lagg_softc *, uint8_t *);
-static int lagg_capabilities(struct lagg_softc *);
+static void lagg_capabilities(struct lagg_softc *);
static void lagg_port_lladdr(struct lagg_port *, uint8_t *);
static void lagg_port_setlladdr(void *, int);
static int lagg_port_create(struct lagg_softc *, struct ifnet *);
@@ -326,27 +326,32 @@ lagg_lladdr(struct lagg_softc *sc, uint8_t *lladdr)
(*sc->sc_lladdr)(sc);
}
-static int
+static void
lagg_capabilities(struct lagg_softc *sc)
{
struct lagg_port *lp;
- int cap = ~0, priv;
+ int cap = ~0, ena = ~0;
LAGG_LOCK_ASSERT(sc);
- /* Preserve private capabilities */
- priv = sc->sc_capabilities & IFCAP_LAGG_MASK;
-
/* Get capabilities from the lagg ports */
- SLIST_FOREACH(lp, &sc->sc_ports, lp_entries)
- cap &= lp->lp_capabilities;
-
- if (sc->sc_ifflags & IFF_DEBUG) {
- printf("%s: capabilities 0x%08x\n",
- sc->sc_ifname, cap == ~0 ? priv : (cap | priv));
+ SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
+ cap &= lp->lp_ifp->if_capabilities;
+ ena &= lp->lp_ifp->if_capenable;
}
+ cap = (cap == ~0 ? 0 : cap);
+ ena = (ena == ~0 ? 0 : ena);
+
+ if (sc->sc_ifp->if_capabilities != cap ||
+ sc->sc_ifp->if_capenable != ena) {
+ sc->sc_ifp->if_capabilities = cap;
+ sc->sc_ifp->if_capenable = ena;
+ getmicrotime(&sc->sc_ifp->if_lastchange);
- return (cap == ~0 ? priv : (cap | priv));
+ if (sc->sc_ifflags & IFF_DEBUG)
+ if_printf(sc->sc_ifp,
+ "capabilities 0x%08x enabled 0x%08x\n", cap, ena);
+ }
}
static void
@@ -447,6 +452,15 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp)
if (ifp->if_type != IFT_ETHER)
return (EPROTONOSUPPORT);
+ /* Allow the first Ethernet member to define the MTU */
+ if (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);
+ }
+
if ((lp = malloc(sizeof(struct lagg_port),
M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
return (ENOMEM);
@@ -499,7 +513,7 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp)
sc->sc_count++;
/* Update lagg capabilities */
- sc->sc_capabilities = lagg_capabilities(sc);
+ lagg_capabilities(sc);
/* Add multicast addresses and interface flags to this port */
lagg_ether_cmdmulti(lp, 1);
@@ -604,7 +618,7 @@ lagg_port_destroy(struct lagg_port *lp, int runpd)
free(lp, M_DEVBUF);
/* Update lagg capabilities */
- sc->sc_capabilities = lagg_capabilities(sc);
+ lagg_capabilities(sc);
return (0);
}
@@ -624,21 +638,43 @@ lagg_port_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
switch (cmd) {
case SIOCGLAGGPORT:
- LAGG_LOCK(sc);
if (rp->rp_portname[0] == '\0' ||
ifunit(rp->rp_portname) != ifp) {
error = EINVAL;
break;
}
- if (lp->lp_softc != sc) {
+ LAGG_LOCK(sc);
+ if ((lp = ifp->if_lagg) == NULL || lp->lp_softc != sc) {
error = ENOENT;
+ LAGG_UNLOCK(sc);
break;
}
lagg_port2req(lp, rp);
LAGG_UNLOCK(sc);
break;
+
+ case SIOCSIFCAP:
+ if (lp->lp_ioctl == NULL) {
+ error = EINVAL;
+ break;
+ }
+ error = (*lp->lp_ioctl)(ifp, cmd, data);
+ if (error)
+ break;
+
+ /* Update lagg interface capabilities */
+ LAGG_LOCK(sc);
+ lagg_capabilities(sc);
+ LAGG_UNLOCK(sc);
+ break;
+
+ case SIOCSIFMTU:
+ /* Do not allow the MTU to be changed once joined */
+ error = EINVAL;
+ break;
+
default:
goto fallback;
}
@@ -781,30 +817,45 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
struct lagg_port *lp;
struct ifnet *tpif;
struct thread *td = curthread;
- int i, error = 0, unlock = 1;
-
- LAGG_LOCK(sc);
+ char *buf, *outbuf;
+ int count, buflen, len, error = 0;
bzero(&rpbuf, sizeof(rpbuf));
switch (cmd) {
case SIOCGLAGG:
+ LAGG_LOCK(sc);
+ count = 0;
+ SLIST_FOREACH(lp, &sc->sc_ports, lp_entries)
+ count++;
+ buflen = count * sizeof(struct lagg_reqport);
+ LAGG_UNLOCK(sc);
+
+ outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO);
+
+ LAGG_LOCK(sc);
ra->ra_proto = sc->sc_proto;
- ra->ra_ports = i = 0;
if (sc->sc_req != NULL)
(*sc->sc_req)(sc, (caddr_t)&ra->ra_psc);
- lp = SLIST_FIRST(&sc->sc_ports);
- while (lp && ra->ra_size >=
- i + sizeof(struct lagg_reqport)) {
- lagg_port2req(lp, &rpbuf);
- error = copyout(&rpbuf, (caddr_t)ra->ra_port + i,
- sizeof(struct lagg_reqport));
- if (error)
+
+ count = 0;
+ buf = outbuf;
+ len = min(ra->ra_size, buflen);
+ SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
+ if (len < sizeof(rpbuf))
break;
- i += sizeof(struct lagg_reqport);
- ra->ra_ports++;
- lp = SLIST_NEXT(lp, lp_entries);
+
+ lagg_port2req(lp, &rpbuf);
+ memcpy(buf, &rpbuf, sizeof(rpbuf));
+ count++;
+ buf += sizeof(rpbuf);
+ len -= sizeof(rpbuf);
}
+ LAGG_UNLOCK(sc);
+ ra->ra_ports = count;
+ ra->ra_size = count * sizeof(rpbuf);
+ error = copyout(outbuf, ra->ra_port, ra->ra_size);
+ free(outbuf, M_TEMP);
break;
case SIOCSLAGG:
error = suser(td);
@@ -815,6 +866,7 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
break;
}
if (sc->sc_proto != LAGG_PROTO_NONE) {
+ LAGG_LOCK(sc);
error = sc->sc_detach(sc);
/* Reset protocol and pointers */
sc->sc_proto = LAGG_PROTO_NONE;
@@ -829,20 +881,23 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
sc->sc_lladdr = NULL;
sc->sc_req = NULL;
sc->sc_portreq = NULL;
+ LAGG_UNLOCK(sc);
}
if (error != 0)
break;
- for (i = 0; i < (sizeof(lagg_protos) /
+ for (int i = 0; i < (sizeof(lagg_protos) /
sizeof(lagg_protos[0])); i++) {
if (lagg_protos[i].ti_proto == ra->ra_proto) {
if (sc->sc_ifflags & IFF_DEBUG)
printf("%s: using proto %u\n",
sc->sc_ifname,
lagg_protos[i].ti_proto);
+ LAGG_LOCK(sc);
sc->sc_proto = lagg_protos[i].ti_proto;
if (sc->sc_proto != LAGG_PROTO_NONE)
error = lagg_protos[i].ti_attach(sc);
- goto out;
+ LAGG_UNLOCK(sc);
+ return (error);
}
}
error = EPROTONOSUPPORT;
@@ -854,13 +909,16 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
break;
}
+ LAGG_LOCK(sc);
if ((lp = (struct lagg_port *)tpif->if_lagg) == NULL ||
lp->lp_softc != sc) {
error = ENOENT;
+ LAGG_UNLOCK(sc);
break;
}
lagg_port2req(lp, rp);
+ LAGG_UNLOCK(sc);
break;
case SIOCSLAGGPORT:
error = suser(td);
@@ -871,7 +929,9 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
error = EINVAL;
break;
}
+ LAGG_LOCK(sc);
error = lagg_port_create(sc, tpif);
+ LAGG_UNLOCK(sc);
break;
case SIOCSLAGGDELPORT:
error = suser(td);
@@ -883,19 +943,24 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
break;
}
+ LAGG_LOCK(sc);
if ((lp = (struct lagg_port *)tpif->if_lagg) == NULL ||
lp->lp_softc != sc) {
error = ENOENT;
+ LAGG_UNLOCK(sc);
break;
}
error = lagg_port_destroy(lp, 1);
+ LAGG_UNLOCK(sc);
break;
case SIOCSIFFLAGS:
/* Set flags on ports too */
+ LAGG_LOCK(sc);
SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
lagg_setflags(lp, 1);
}
+ LAGG_UNLOCK(sc);
if (!(ifp->if_flags & IFF_UP) &&
(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
@@ -903,38 +968,39 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
* If interface is marked down and it is running,
* then stop and disable it.
*/
+ LAGG_LOCK(sc);
lagg_stop(sc);
+ LAGG_UNLOCK(sc);
} else if ((ifp->if_flags & IFF_UP) &&
!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
/*
* If interface is marked up and it is stopped, then
* start it.
*/
- LAGG_UNLOCK(sc);
- unlock = 0;
(*ifp->if_init)(sc);
}
break;
case SIOCADDMULTI:
case SIOCDELMULTI:
+ LAGG_LOCK(sc);
error = lagg_ether_setmulti(sc);
+ LAGG_UNLOCK(sc);
break;
case SIOCSIFMEDIA:
case SIOCGIFMEDIA:
- LAGG_UNLOCK(sc);
- unlock = 0;
error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
break;
+
+ case SIOCSIFCAP:
+ case SIOCSIFMTU:
+ /* Do not allow the MTU or caps to be directly changed */
+ error = EINVAL;
+ break;
+
default:
- LAGG_UNLOCK(sc);
- unlock = 0;
error = ether_ioctl(ifp, cmd, data);
break;
}
-
-out:
- if (unlock)
- LAGG_UNLOCK(sc);
return (error);
}
diff --git a/sys/net/if_lagg.h b/sys/net/if_lagg.h
index 4f77d4a1b509..1cb0a481dab1 100644
--- a/sys/net/if_lagg.h
+++ b/sys/net/if_lagg.h
@@ -127,7 +127,6 @@ struct lagg_reqall {
#define lp_ifname lp_ifp->if_xname /* interface name */
#define lp_link_state lp_ifp->if_link_state /* link state */
-#define lp_capabilities lp_ifp->if_capabilities /* capabilities */
#define LAGG_PORTACTIVE(_tp) ( \
((_tp)->lp_link_state == LINK_STATE_UP) && \