Index: share/man/man4/lagg.4 =================================================================== --- share/man/man4/lagg.4 +++ share/man/man4/lagg.4 @@ -1,6 +1,7 @@ .\" $OpenBSD: trunk.4,v 1.18 2006/06/09 13:53:34 jmc Exp $ .\" .\" Copyright (c) 2005, 2006 Reyk Floeter +.\" Copyright (c) 2014 Marcelo Araujo .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -110,9 +111,12 @@ The hash includes the Ethernet source and destination address, and, if available, the VLAN tag, and the IP source and destination address. .It Ic roundrobin -Distributes outgoing traffic using a round-robin scheduler -through all active ports and accepts incoming traffic from -any active port. +Distributes outgoing traffic using a round-robin scheduler through all active +ports and accepts incoming traffic from any active port. +This mode can cause unordered packet arrival at the client. This has a side +effect of limiting the throughput as reordering packets can be CPU intensive +on the client. +Requires a switch which supports IEEE 802.3ad static link aggregation. .It Ic none This protocol is intended to do nothing: it disables any traffic without disabling the @@ -149,6 +153,14 @@ The default for new interfaces is set via the .Va net.link.lagg.default_use_flowid .Xr sysctl 8 . +.Pp +Additionally, the +.Ic roundrobin +mode can have the number of packets sent per interface fine tuned via +.Va net.link.lagg.rr_packets +.Xr sysctl 8 . +Its default value is 0, where only one packet will be send per interface +every round. .Sh EXAMPLES Create a link aggregation using LACP with two .Xr bge 4 Index: sys/net/if_lagg.h =================================================================== --- sys/net/if_lagg.h +++ sys/net/if_lagg.h @@ -197,7 +197,6 @@ struct lagg_port *sc_primary; /* primary port */ struct ifmedia sc_media; /* media config */ caddr_t sc_psc; /* protocol data */ - uint32_t sc_seq; /* sequence counter */ uint32_t sc_flags; counter_u64_t sc_ipackets; @@ -232,6 +231,9 @@ struct sysctl_oid *sc_oid; /* sysctl tree oid */ int use_flowid; /* use M_FLOWID */ int flowid_shift; /* shift the flowid */ + uint32_t sc_pkt_count; /* use for count packates per ifp */ + int sc_ifp_count; /* counter reference of interfaces on rr */ + char sc_ref_ifp[IFNAMSIZ]; /* name of the ifp */ }; struct lagg_port { Index: sys/net/if_lagg.c =================================================================== --- sys/net/if_lagg.c +++ sys/net/if_lagg.c @@ -3,6 +3,7 @@ /* * Copyright (c) 2005, 2006 Reyk Floeter * Copyright (c) 2007 Andrew Thompson + * Copyright (c) 2014 Marcelo Araujo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -187,6 +188,10 @@ SYSCTL_INT(_net_link_lagg, OID_AUTO, default_flowid_shift, CTLFLAG_RWTUN, &def_flowid_shift, 0, "Default setting for flowid shift for load sharing"); +static int lagg_rr_packets = 0; /* Default value for using rr_packets */ +SYSCTL_INT(_net_link_lagg, OID_AUTO, rr_packets, CTLFLAG_RW, + &lagg_rr_packets, 0, + "How many packets to be send per interface"); static int lagg_modevent(module_t mod, int type, void *data) @@ -1671,7 +1676,6 @@ sc->sc_input = lagg_rr_input; sc->sc_port_create = NULL; sc->sc_capabilities = IFCAP_LAGG_FULLDUPLEX; - sc->sc_seq = 0; return (0); } @@ -1687,12 +1691,70 @@ { struct lagg_port *lp; uint32_t p; + uint32_t pkt_sysctl_count; + int ifp_count = 1; - p = atomic_fetchadd_32(&sc->sc_seq, 1); - p %= sc->sc_count; + p = sc->sc_count; lp = SLIST_FIRST(&sc->sc_ports); - while (p--) - lp = SLIST_NEXT(lp, lp_entries); + + /* + * If there is no reference for the IFP, we must + * copy it. + */ + if (strlen(sc->sc_ref_ifp) == 0) + strncpy(sc->sc_ref_ifp, lp->lp_ifp->if_xname, sizeof(sc->sc_ref_ifp)); + + /* + * If ifp_count was not yet initialized, we must + * initialize. + */ + if (sc->sc_ifp_count == 0) + sc->sc_ifp_count = 1; + + /* + * To avoid users set the rr_packets to negatie values and/or + * to 0, in this case will set to 1. + */ + if(lagg_rr_packets <= 0) + lagg_rr_packets = 1; + + /* + * If change the rr_packets to a lower value than specified + * before, let sc_pkt_count know about it. + */ + if(sc->sc_pkt_count > lagg_rr_packets) + sc->sc_pkt_count = 1; + + /* + * Here we start to apply the round robin based on the value + * specified by the sysctl(8) net.link.lagg.rr_packets. + */ + pkt_sysctl_count = atomic_fetchadd_32(&sc->sc_pkt_count, 1); + if (pkt_sysctl_count == lagg_rr_packets) { + if (sc->sc_ifp_count <= sc->sc_count) { + while (ifp_count < sc->sc_ifp_count) { + lp = SLIST_NEXT(lp, lp_entries); + ifp_count++; + } + sc->sc_ifp_count++; + if (sc->sc_ifp_count > sc->sc_count) + sc->sc_ifp_count = 0; + } + strncpy(sc->sc_ref_ifp, lp->lp_ifp->if_xname, sizeof(sc->sc_ref_ifp)); + sc->sc_pkt_count = 1; + } + + /* + * Check if the current interface to be enqueue is not the + * same used in the last round. + */ + lp = SLIST_FIRST(&sc->sc_ports); + while (p--) { + if (strcmp(lp->lp_ifp->if_xname, sc->sc_ref_ifp) == 0) + break; + else + lp = SLIST_NEXT(lp, lp_entries); + } /* * Check the port's link state. This will return the next active