diff options
Diffstat (limited to 'freebsd/sys/net/if_lagg.c')
-rw-r--r-- | freebsd/sys/net/if_lagg.c | 84 |
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); |