lagg: Clean up handling of the rr_limit option.

- Don't allow an unprivileged user to set the stride. [1]
- Only set the stride under the softc lock.
- Rename the internal fields to accurately reflect their use.  Keep
  ro_bkt to avoid changing the user API.
- Simplify the implementation.  The port index is just sc_seq / stride.
- Document rr_limit in ifconfig.8.

Reported by:	Ilja Van Sprundel <ivansprundel@ioactive.com> [1]
MFC after:	1 week
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D22857
This commit is contained in:
Mark Johnston 2019-12-22 21:56:47 +00:00
parent b649c2ac34
commit c104c2990d
4 changed files with 33 additions and 27 deletions

View File

@ -28,7 +28,7 @@
.\" From: @(#)ifconfig.8 8.3 (Berkeley) 1/5/94
.\" $FreeBSD$
.\"
.Dd August 26, 2019
.Dd December 17, 2019
.Dt IFCONFIG 8
.Os
.Sh NAME
@ -2567,6 +2567,9 @@ means
.Dq enabled .
.It Cm -lacp_strict
Disable lacp strict compliance on the interface.
.It Cm rr_limit Ar number
Configure a stride for an interface in round-robin mode.
The default stride is 1.
.El
.Pp
The following parameters apply to IP tunnel interfaces,

View File

@ -166,7 +166,7 @@ Gigabit Ethernet interfaces:
.Pp
Create a link aggregation using ROUNDROBIN with two
.Xr bge 4
Gigabit Ethernet interfaces and set the limit of 500 packets
Gigabit Ethernet interfaces and set a stride of 500 packets
per interface:
.Bd -literal -offset indent
# ifconfig bge0 up

View File

@ -1245,23 +1245,38 @@ 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 we must handle it before processing any
* remaining options.
*/
LAGG_XLOCK(sc);
if (ro->ro_bkt != 0) {
if (sc->sc_proto != LAGG_PROTO_ROUNDROBIN) {
LAGG_XUNLOCK(sc);
error = EINVAL;
break;
}
sc->sc_stride = ro->ro_bkt;
} else {
sc->sc_stride = 0;
}
if (ro->ro_opts == 0) {
LAGG_XUNLOCK(sc);
break;
}
/*
* Set options. LACP options are stored in sc->sc_psc,
* not in sc_opts.
@ -1292,8 +1307,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. */
@ -2033,7 +2046,6 @@ static void
lagg_rr_attach(struct lagg_softc *sc)
{
sc->sc_seq = 0;
sc->sc_bkt_count = sc->sc_bkt;
}
static int
@ -2042,17 +2054,9 @@ 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);
if (sc->sc_stride > 0)
p /= sc->sc_stride;
p %= sc->sc_count;
lp = CK_SLIST_FIRST(&sc->sc_ports);

View File

@ -153,7 +153,7 @@ struct lagg_reqopts {
u_int ro_active; /* active port count */
u_int ro_flapping; /* number of flapping */
int ro_flowid_shift; /* shift the flowid */
uint32_t ro_bkt; /* packet bucket for roundrobin */
uint32_t ro_bkt; /* stride for RR */
};
#define SIOCGLAGGOPTS _IOWR('i', 152, struct lagg_reqopts)
@ -216,6 +216,7 @@ struct lagg_softc {
struct ifmedia sc_media; /* media config */
void *sc_psc; /* protocol data */
uint32_t sc_seq; /* sequence counter */
uint32_t sc_stride; /* stride for RR */
uint32_t sc_flags;
int sc_destroying; /* destroying lagg */
@ -227,8 +228,6 @@ struct lagg_softc {
struct callout sc_callout;
u_int sc_opts;
int flowid_shift; /* shift the flowid */
uint32_t sc_bkt; /* packates bucket for roundrobin */
uint32_t sc_bkt_count; /* packates bucket count for roundrobin */
struct lagg_counters detached_counters; /* detached ports sum */
};