diff options
author | thompsa <thompsa@FreeBSD.org> | 2012-03-06 22:58:13 +0000 |
---|---|---|
committer | thompsa <thompsa@FreeBSD.org> | 2012-03-06 22:58:13 +0000 |
commit | b1fbb40a93a6965db74bad2d0e41c6213a2449c5 (patch) | |
tree | a66e0f4d01b37baeb77069cd3e0375ba9fedb6b6 /sys | |
parent | 10e68a3224291be36c3e534197c59fd26a9f2dbb (diff) | |
download | FreeBSD-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')
-rw-r--r-- | sys/net/ieee8023ad_lacp.c | 2 | ||||
-rw-r--r-- | sys/net/if_lagg.c | 78 | ||||
-rw-r--r-- | sys/net/if_lagg.h | 17 |
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 */ |