summaryrefslogtreecommitdiffstats
path: root/sys/net
diff options
context:
space:
mode:
authorthompsa <thompsa@FreeBSD.org>2012-03-06 22:58:13 +0000
committerthompsa <thompsa@FreeBSD.org>2012-03-06 22:58:13 +0000
commitb1fbb40a93a6965db74bad2d0e41c6213a2449c5 (patch)
treea66e0f4d01b37baeb77069cd3e0375ba9fedb6b6 /sys/net
parent10e68a3224291be36c3e534197c59fd26a9f2dbb (diff)
downloadFreeBSD-src-b1fbb40a93a6965db74bad2d0e41c6213a2449c5.zip
FreeBSD-src-b1fbb40a93a6965db74bad2d0e41c6213a2449c5.tar.gz
Add the ability to set which packet layers are used for the load balance hash
calculation.
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/ieee8023ad_lacp.c2
-rw-r--r--sys/net/if_lagg.c78
-rw-r--r--sys/net/if_lagg.h17
3 files changed, 82 insertions, 15 deletions
diff --git a/sys/net/ieee8023ad_lacp.c b/sys/net/ieee8023ad_lacp.c
index ea83866..137e273 100644
--- a/sys/net/ieee8023ad_lacp.c
+++ b/sys/net/ieee8023ad_lacp.c
@@ -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];
diff --git a/sys/net/if_lagg.c b/sys/net/if_lagg.c
index 5d12187..892a256 100644
--- a/sys/net/if_lagg.c
+++ b/sys/net/if_lagg.c
@@ -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];
diff --git a/sys/net/if_lagg.h b/sys/net/if_lagg.h
index 8231764..27ab46f 100644
--- a/sys/net/if_lagg.h
+++ b/sys/net/if_lagg.h
@@ -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 */
OpenPOWER on IntegriCloud