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.c84
1 files changed, 58 insertions, 26 deletions
diff --git a/freebsd/sys/net/if_lagg.c b/freebsd/sys/net/if_lagg.c
index af6f1667..2d133ec4 100644
--- a/freebsd/sys/net/if_lagg.c
+++ b/freebsd/sys/net/if_lagg.c
@@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$");
#include <net/if_types.h>
#include <net/if_var.h>
#include <net/bpf.h>
+#include <net/route.h>
#include <net/vnet.h>
#if defined(INET) || defined(INET6)
@@ -75,6 +76,14 @@ __FBSDID("$FreeBSD$");
#include <net/if_lagg.h>
#include <net/ieee8023ad_lacp.h>
+#ifdef INET6
+/*
+ * XXX: declare here to avoid to include many inet6 related files..
+ * should be more generalized?
+ */
+extern void nd6_setmtu(struct ifnet *);
+#endif
+
#define LAGG_RLOCK() struct epoch_tracker lagg_et; epoch_enter_preempt(net_epoch_preempt, &lagg_et)
#define LAGG_RUNLOCK() epoch_exit_preempt(net_epoch_preempt, &lagg_et)
#define LAGG_RLOCK_ASSERT() MPASS(in_epoch(net_epoch_preempt))
@@ -1154,7 +1163,7 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
struct ifnet *tpif;
struct thread *td = curthread;
char *buf, *outbuf;
- int count, buflen, len, error = 0;
+ int count, buflen, len, error = 0, oldmtu;
bzero(&rpbuf, sizeof(rpbuf));
@@ -1221,23 +1230,35 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries)
ro->ro_active += LAGG_PORTACTIVE(lp);
}
- ro->ro_bkt = sc->sc_bkt;
+ ro->ro_bkt = sc->sc_stride;
ro->ro_flapping = sc->sc_flapping;
ro->ro_flowid_shift = sc->flowid_shift;
LAGG_XUNLOCK(sc);
break;
case SIOCSLAGGOPTS:
- if (sc->sc_proto == LAGG_PROTO_ROUNDROBIN) {
- if (ro->ro_bkt == 0)
- sc->sc_bkt = 1; // Minimum 1 packet per iface.
- else
- sc->sc_bkt = ro->ro_bkt;
- }
error = priv_check(td, PRIV_NET_LAGG);
if (error)
break;
- if (ro->ro_opts == 0)
+
+ /*
+ * The stride option was added without defining a corresponding
+ * LAGG_OPT flag, so handle a non-zero value before checking
+ * anything else to preserve compatibility.
+ */
+ LAGG_XLOCK(sc);
+ if (ro->ro_opts == 0 && ro->ro_bkt != 0) {
+ if (sc->sc_proto != LAGG_PROTO_ROUNDROBIN) {
+ LAGG_XUNLOCK(sc);
+ error = EINVAL;
+ break;
+ }
+ sc->sc_stride = ro->ro_bkt;
+ }
+ if (ro->ro_opts == 0) {
+ LAGG_XUNLOCK(sc);
break;
+ }
+
/*
* Set options. LACP options are stored in sc->sc_psc,
* not in sc_opts.
@@ -1248,6 +1269,7 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
case LAGG_OPT_USE_FLOWID:
case -LAGG_OPT_USE_FLOWID:
case LAGG_OPT_FLOWIDSHIFT:
+ case LAGG_OPT_RR_LIMIT:
valid = 1;
lacp = 0;
break;
@@ -1266,8 +1288,6 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
break;
}
- LAGG_XLOCK(sc);
-
if (valid == 0 ||
(lacp == 1 && sc->sc_proto != LAGG_PROTO_LACP)) {
/* Invalid combination of options specified. */
@@ -1275,14 +1295,23 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
LAGG_XUNLOCK(sc);
break; /* Return from SIOCSLAGGOPTS. */
}
+
/*
* Store new options into sc->sc_opts except for
- * FLOWIDSHIFT and LACP options.
+ * FLOWIDSHIFT, RR and LACP options.
*/
if (lacp == 0) {
if (ro->ro_opts == LAGG_OPT_FLOWIDSHIFT)
sc->flowid_shift = ro->ro_flowid_shift;
- else if (ro->ro_opts > 0)
+ else if (ro->ro_opts == LAGG_OPT_RR_LIMIT) {
+ if (sc->sc_proto != LAGG_PROTO_ROUNDROBIN ||
+ ro->ro_bkt == 0) {
+ error = EINVAL;
+ LAGG_XUNLOCK(sc);
+ break;
+ }
+ sc->sc_stride = ro->ro_bkt;
+ } else if (ro->ro_opts > 0)
sc->sc_opts |= ro->ro_opts;
else
sc->sc_opts &= ~ro->ro_opts;
@@ -1407,10 +1436,23 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
tpif->if_xname);
}
#endif
+ oldmtu = ifp->if_mtu;
LAGG_XLOCK(sc);
error = lagg_port_create(sc, tpif);
LAGG_XUNLOCK(sc);
if_rele(tpif);
+
+ /*
+ * LAGG MTU may change during addition of the first port.
+ * If it did, do network layer specific procedure.
+ */
+ if (ifp->if_mtu != oldmtu) {
+#ifdef INET6
+ nd6_setmtu(ifp);
+#endif
+ rt_updatemtu(ifp);
+ }
+
VLAN_CAPABILITIES(ifp);
break;
case SIOCSLAGGDELPORT:
@@ -1904,7 +1946,7 @@ static void
lagg_rr_attach(struct lagg_softc *sc)
{
sc->sc_seq = 0;
- sc->sc_bkt_count = sc->sc_bkt;
+ sc->sc_stride = 1;
}
static int
@@ -1913,18 +1955,8 @@ lagg_rr_start(struct lagg_softc *sc, struct mbuf *m)
struct lagg_port *lp;
uint32_t p;
- if (sc->sc_bkt_count == 0 && sc->sc_bkt > 0)
- sc->sc_bkt_count = sc->sc_bkt;
-
- if (sc->sc_bkt > 0) {
- atomic_subtract_int(&sc->sc_bkt_count, 1);
- if (atomic_cmpset_int(&sc->sc_bkt_count, 0, sc->sc_bkt))
- p = atomic_fetchadd_32(&sc->sc_seq, 1);
- else
- p = sc->sc_seq;
- } else
- p = atomic_fetchadd_32(&sc->sc_seq, 1);
-
+ p = atomic_fetchadd_32(&sc->sc_seq, 1);
+ p /= sc->sc_stride;
p %= sc->sc_count;
lp = CK_SLIST_FIRST(&sc->sc_ports);