Add the ability to set which packet layers are used for the load balance hash
calculation.
This commit is contained in:
parent
10e68a3224
commit
b1fbb40a93
@ -2309,6 +2309,21 @@ Set the aggregation protocol.
|
||||
The default is failover.
|
||||
The available options are failover, fec, lacp, loadbalance, roundrobin and
|
||||
none.
|
||||
.It Cm lagghash Ar option Ns Oo , Ns Ar option Oc
|
||||
Set the packet layers to hash for aggregation protocols which load balance.
|
||||
The default is
|
||||
.Dq l2,l3,l4 .
|
||||
The options can be combined using commas.
|
||||
.Pp
|
||||
.Bl -tag -width ".Cm l2" -compact
|
||||
.It Cm l2
|
||||
src/dst mac address and optional vlan number.
|
||||
.It Cm l3
|
||||
src/dst address for IPv4 or IPv6.
|
||||
.It Cm l4
|
||||
src/dst port for TCP/UCP/SCTP.
|
||||
.El
|
||||
.Pp
|
||||
.El
|
||||
.Pp
|
||||
The following parameters are specific to IP tunnel interfaces,
|
||||
|
@ -81,6 +81,36 @@ setlaggproto(const char *val, int d, int s, const struct afswtch *afp)
|
||||
err(1, "SIOCSLAGG");
|
||||
}
|
||||
|
||||
static void
|
||||
setlagghash(const char *val, int d, int s, const struct afswtch *afp)
|
||||
{
|
||||
struct lagg_reqflags rf;
|
||||
char *str, *tmp, *tok;
|
||||
|
||||
|
||||
rf.rf_flags = 0;
|
||||
str = tmp = strdup(val);
|
||||
while ((tok = strsep(&tmp, ",")) != NULL) {
|
||||
if (strcmp(tok, "l2") == 0)
|
||||
rf.rf_flags |= LAGG_F_HASHL2;
|
||||
else if (strcmp(tok, "l3") == 0)
|
||||
rf.rf_flags |= LAGG_F_HASHL3;
|
||||
else if (strcmp(tok, "l4") == 0)
|
||||
rf.rf_flags |= LAGG_F_HASHL4;
|
||||
else {
|
||||
free(str);
|
||||
errx(1, "Invalid lagghash option: %s", tok);
|
||||
}
|
||||
}
|
||||
free(str);
|
||||
if (rf.rf_flags == 0)
|
||||
errx(1, "No lagghash options supplied");
|
||||
|
||||
strlcpy(rf.rf_ifname, name, sizeof(rf.rf_ifname));
|
||||
if (ioctl(s, SIOCSLAGGHASH, &rf))
|
||||
err(1, "SIOCSLAGGHASH");
|
||||
}
|
||||
|
||||
static char *
|
||||
lacp_format_mac(const uint8_t *mac, char *buf, size_t buflen)
|
||||
{
|
||||
@ -115,6 +145,7 @@ lagg_status(int s)
|
||||
struct lagg_protos lpr[] = LAGG_PROTOS;
|
||||
struct lagg_reqport rp, rpbuf[LAGG_MAX_PORTS];
|
||||
struct lagg_reqall ra;
|
||||
struct lagg_reqflags rf;
|
||||
struct lacp_opreq *lp;
|
||||
const char *proto = "<unknown>";
|
||||
int i, isport = 0;
|
||||
@ -132,6 +163,10 @@ lagg_status(int s)
|
||||
ra.ra_size = sizeof(rpbuf);
|
||||
ra.ra_port = rpbuf;
|
||||
|
||||
strlcpy(rf.rf_ifname, name, sizeof(rf.rf_ifname));
|
||||
if (ioctl(s, SIOCGLAGGFLAGS, &rf) != 0)
|
||||
rf.rf_flags = 0;
|
||||
|
||||
if (ioctl(s, SIOCGLAGG, &ra) == 0) {
|
||||
lp = (struct lacp_opreq *)&ra.ra_lacpreq;
|
||||
|
||||
@ -143,6 +178,23 @@ lagg_status(int s)
|
||||
}
|
||||
|
||||
printf("\tlaggproto %s", proto);
|
||||
if (rf.rf_flags & LAGG_F_HASHMASK) {
|
||||
const char *sep = "";
|
||||
|
||||
printf(" lagghash ");
|
||||
if (rf.rf_flags & LAGG_F_HASHL2) {
|
||||
printf("%sl2", sep);
|
||||
sep = ",";
|
||||
}
|
||||
if (rf.rf_flags & LAGG_F_HASHL3) {
|
||||
printf("%sl3", sep);
|
||||
sep = ",";
|
||||
}
|
||||
if (rf.rf_flags & LAGG_F_HASHL4) {
|
||||
printf("%sl4", sep);
|
||||
sep = ",";
|
||||
}
|
||||
}
|
||||
if (isport)
|
||||
printf(" laggdev %s", rp.rp_ifname);
|
||||
putchar('\n');
|
||||
@ -174,6 +226,7 @@ static struct cmd lagg_cmds[] = {
|
||||
DEF_CMD_ARG("laggport", setlaggport),
|
||||
DEF_CMD_ARG("-laggport", unsetlaggport),
|
||||
DEF_CMD_ARG("laggproto", setlaggproto),
|
||||
DEF_CMD_ARG("lagghash", setlagghash),
|
||||
};
|
||||
static struct afswtch af_lagg = {
|
||||
.af_name = "af_lagg",
|
||||
|
@ -815,7 +815,7 @@ lacp_select_tx_port(struct lagg_softc *sc, struct mbuf *m)
|
||||
if (sc->use_flowid && (m->m_flags & M_FLOWID))
|
||||
hash = m->m_pkthdr.flowid;
|
||||
else
|
||||
hash = lagg_hashmbuf(m, lsc->lsc_hashkey);
|
||||
hash = lagg_hashmbuf(sc, m, lsc->lsc_hashkey);
|
||||
hash %= pm->pm_count;
|
||||
lp = pm->pm_map[hash];
|
||||
|
||||
|
@ -285,6 +285,8 @@ lagg_clone_create(struct if_clone *ifc, int unit, caddr_t params)
|
||||
SYSCTL_ADD_INT(&sc->ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
|
||||
"use_flowid", CTLTYPE_INT|CTLFLAG_RW, &sc->use_flowid, sc->use_flowid,
|
||||
"Use flow id for load sharing");
|
||||
/* Hash all layers by default */
|
||||
sc->sc_flags = LAGG_F_HASHL2|LAGG_F_HASHL3|LAGG_F_HASHL4;
|
||||
|
||||
sc->sc_proto = LAGG_PROTO_NONE;
|
||||
for (i = 0; lagg_protos[i].ti_proto != LAGG_PROTO_NONE; i++) {
|
||||
@ -895,6 +897,7 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
struct lagg_softc *sc = (struct lagg_softc *)ifp->if_softc;
|
||||
struct lagg_reqall *ra = (struct lagg_reqall *)data;
|
||||
struct lagg_reqport *rp = (struct lagg_reqport *)data, rpbuf;
|
||||
struct lagg_reqflags *rf = (struct lagg_reqflags *)data;
|
||||
struct ifreq *ifr = (struct ifreq *)data;
|
||||
struct lagg_port *lp;
|
||||
struct ifnet *tpif;
|
||||
@ -984,6 +987,22 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
}
|
||||
error = EPROTONOSUPPORT;
|
||||
break;
|
||||
case SIOCGLAGGFLAGS:
|
||||
rf->rf_flags = sc->sc_flags;
|
||||
break;
|
||||
case SIOCSLAGGHASH:
|
||||
error = priv_check(td, PRIV_NET_LAGG);
|
||||
if (error)
|
||||
break;
|
||||
if ((rf->rf_flags & LAGG_F_HASHMASK) == 0) {
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
LAGG_WLOCK(sc);
|
||||
sc->sc_flags &= ~LAGG_F_HASHMASK;
|
||||
sc->sc_flags |= rf->rf_flags & LAGG_F_HASHMASK;
|
||||
LAGG_WUNLOCK(sc);
|
||||
break;
|
||||
case SIOCGLAGGPORT:
|
||||
if (rp->rp_portname[0] == '\0' ||
|
||||
(tpif = ifunit(rp->rp_portname)) == NULL) {
|
||||
@ -1413,34 +1432,46 @@ lagg_gethdr(struct mbuf *m, u_int off, u_int len, void *buf)
|
||||
}
|
||||
|
||||
uint32_t
|
||||
lagg_hashmbuf(struct mbuf *m, uint32_t key)
|
||||
lagg_hashmbuf(struct lagg_softc *sc, struct mbuf *m, uint32_t key)
|
||||
{
|
||||
uint16_t etype;
|
||||
uint32_t p = 0;
|
||||
uint32_t p = key;
|
||||
int off;
|
||||
struct ether_header *eh;
|
||||
struct ether_vlan_header vlanbuf;
|
||||
const struct ether_vlan_header *vlan;
|
||||
#ifdef INET
|
||||
const struct ip *ip;
|
||||
struct ip ipbuf;
|
||||
const uint32_t *ports;
|
||||
int iphlen;
|
||||
#endif
|
||||
#ifdef INET6
|
||||
const struct ip6_hdr *ip6;
|
||||
struct ip6_hdr ip6buf;
|
||||
uint32_t flow;
|
||||
#endif
|
||||
union {
|
||||
#ifdef INET
|
||||
struct ip ip;
|
||||
#endif
|
||||
#ifdef INET6
|
||||
struct ip6_hdr ip6;
|
||||
#endif
|
||||
uint32_t port;
|
||||
} buf;
|
||||
|
||||
|
||||
off = sizeof(*eh);
|
||||
if (m->m_len < off)
|
||||
goto out;
|
||||
eh = mtod(m, struct ether_header *);
|
||||
etype = ntohs(eh->ether_type);
|
||||
p = hash32_buf(&eh->ether_shost, ETHER_ADDR_LEN, key);
|
||||
p = hash32_buf(&eh->ether_dhost, ETHER_ADDR_LEN, p);
|
||||
if (sc->sc_flags & LAGG_F_HASHL2) {
|
||||
p = hash32_buf(&eh->ether_shost, ETHER_ADDR_LEN, p);
|
||||
p = hash32_buf(&eh->ether_dhost, ETHER_ADDR_LEN, p);
|
||||
}
|
||||
|
||||
/* Special handling for encapsulating VLAN frames */
|
||||
if (m->m_flags & M_VLANTAG) {
|
||||
if ((m->m_flags & M_VLANTAG) && (sc->sc_flags & LAGG_F_HASHL2)) {
|
||||
p = hash32_buf(&m->m_pkthdr.ether_vtag,
|
||||
sizeof(m->m_pkthdr.ether_vtag), p);
|
||||
} else if (etype == ETHERTYPE_VLAN) {
|
||||
@ -1448,7 +1479,8 @@ lagg_hashmbuf(struct mbuf *m, uint32_t key)
|
||||
if (vlan == NULL)
|
||||
goto out;
|
||||
|
||||
p = hash32_buf(&vlan->evl_tag, sizeof(vlan->evl_tag), p);
|
||||
if (sc->sc_flags & LAGG_F_HASHL2)
|
||||
p = hash32_buf(&vlan->evl_tag, sizeof(vlan->evl_tag), p);
|
||||
etype = ntohs(vlan->evl_proto);
|
||||
off += sizeof(*vlan) - sizeof(*eh);
|
||||
}
|
||||
@ -1456,17 +1488,37 @@ lagg_hashmbuf(struct mbuf *m, uint32_t key)
|
||||
switch (etype) {
|
||||
#ifdef INET
|
||||
case ETHERTYPE_IP:
|
||||
ip = lagg_gethdr(m, off, sizeof(*ip), &ipbuf);
|
||||
ip = lagg_gethdr(m, off, sizeof(*ip), &buf);
|
||||
if (ip == NULL)
|
||||
goto out;
|
||||
|
||||
p = hash32_buf(&ip->ip_src, sizeof(struct in_addr), p);
|
||||
p = hash32_buf(&ip->ip_dst, sizeof(struct in_addr), p);
|
||||
if (sc->sc_flags & LAGG_F_HASHL3) {
|
||||
p = hash32_buf(&ip->ip_src, sizeof(struct in_addr), p);
|
||||
p = hash32_buf(&ip->ip_dst, sizeof(struct in_addr), p);
|
||||
}
|
||||
if (!(sc->sc_flags & LAGG_F_HASHL4))
|
||||
break;
|
||||
switch (ip->ip_p) {
|
||||
case IPPROTO_TCP:
|
||||
case IPPROTO_UDP:
|
||||
case IPPROTO_SCTP:
|
||||
iphlen = ip->ip_hl << 2;
|
||||
if (iphlen < sizeof(*ip))
|
||||
break;
|
||||
off += iphlen;
|
||||
ports = lagg_gethdr(m, off, sizeof(*ports), &buf);
|
||||
if (ports == NULL)
|
||||
break;
|
||||
p = hash32_buf(ports, sizeof(*ports), p);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef INET6
|
||||
case ETHERTYPE_IPV6:
|
||||
ip6 = lagg_gethdr(m, off, sizeof(*ip6), &ip6buf);
|
||||
if (!(sc->sc_flags & LAGG_F_HASHL3))
|
||||
break;
|
||||
ip6 = lagg_gethdr(m, off, sizeof(*ip6), &buf);
|
||||
if (ip6 == NULL)
|
||||
goto out;
|
||||
|
||||
@ -1696,7 +1748,7 @@ lagg_lb_start(struct lagg_softc *sc, struct mbuf *m)
|
||||
if (sc->use_flowid && (m->m_flags & M_FLOWID))
|
||||
p = m->m_pkthdr.flowid;
|
||||
else
|
||||
p = lagg_hashmbuf(m, lb->lb_key);
|
||||
p = lagg_hashmbuf(sc, m, lb->lb_key);
|
||||
p %= sc->sc_count;
|
||||
lp = lb->lb_ports[p];
|
||||
|
||||
|
@ -31,6 +31,12 @@
|
||||
#define LAGG_MAX_NAMESIZE 32 /* name of a protocol */
|
||||
#define LAGG_MAX_STACKING 4 /* maximum number of stacked laggs */
|
||||
|
||||
/* Lagg flags */
|
||||
#define LAGG_F_HASHL2 0x00000001 /* hash layer 2 */
|
||||
#define LAGG_F_HASHL3 0x00000002 /* hash layer 3 */
|
||||
#define LAGG_F_HASHL4 0x00000004 /* hash layer 4 */
|
||||
#define LAGG_F_HASHMASK 0x00000007
|
||||
|
||||
/* Port flags */
|
||||
#define LAGG_PORT_SLAVE 0x00000000 /* normal enslaved port */
|
||||
#define LAGG_PORT_MASTER 0x00000001 /* primary port */
|
||||
@ -122,6 +128,14 @@ struct lagg_reqall {
|
||||
#define SIOCGLAGG _IOWR('i', 143, struct lagg_reqall)
|
||||
#define SIOCSLAGG _IOW('i', 144, struct lagg_reqall)
|
||||
|
||||
struct lagg_reqflags {
|
||||
char rf_ifname[IFNAMSIZ]; /* name of the lagg */
|
||||
uint32_t rf_flags; /* lagg protocol */
|
||||
};
|
||||
|
||||
#define SIOCGLAGGFLAGS _IOWR('i', 145, struct lagg_reqflags)
|
||||
#define SIOCSLAGGHASH _IOW('i', 146, struct lagg_reqflags)
|
||||
|
||||
#ifdef _KERNEL
|
||||
/*
|
||||
* Internal kernel part
|
||||
@ -179,6 +193,7 @@ struct lagg_softc {
|
||||
struct ifmedia sc_media; /* media config */
|
||||
caddr_t sc_psc; /* protocol data */
|
||||
uint32_t sc_seq; /* sequence counter */
|
||||
uint32_t sc_flags;
|
||||
|
||||
SLIST_HEAD(__tplhd, lagg_port) sc_ports; /* list of interfaces */
|
||||
SLIST_ENTRY(lagg_softc) sc_entries;
|
||||
@ -244,7 +259,7 @@ extern struct mbuf *(*lagg_input_p)(struct ifnet *, struct mbuf *);
|
||||
extern void (*lagg_linkstate_p)(struct ifnet *, int );
|
||||
|
||||
int lagg_enqueue(struct ifnet *, struct mbuf *);
|
||||
uint32_t lagg_hashmbuf(struct mbuf *, uint32_t);
|
||||
uint32_t lagg_hashmbuf(struct lagg_softc *, struct mbuf *, uint32_t);
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user