I'm wondering what reception this will get. It feeds TCP/UDP port
numbers into the hash for trunk(4) load balancing, so connections
between a single pair of hosts will get distributed across NICs.
Taken from FreeBSD r232629, they also added SIOC[CS]LAGGHASH ioctls
so that the hash type can be configured in ifconfig (l2/l3/l4),
I haven't done that but could if there's no general objection to
this.

This method is used on some switches too (e.g. "trunk-load-balance
L4-based" on HP 2530 and 5400zl).

Index: if_trunk.c
===================================================================
RCS file: /cvs/src/sys/net/if_trunk.c,v
retrieving revision 1.93
diff -u -p -r1.93 if_trunk.c
--- if_trunk.c  4 Dec 2014 00:01:53 -0000       1.93
+++ if_trunk.c  11 Dec 2014 23:45:20 -0000
@@ -978,12 +978,23 @@ trunk_hashmbuf(struct mbuf *m, SIPHASH_K
        int off;
        struct ether_header *eh;
 #ifdef INET
-       struct ip *ip, ipbuf;
+       struct ip *ip;
+       u_int32_t *ports;
+       int iphlen;
 #endif
 #ifdef INET6
        u_int32_t flow;
        struct ip6_hdr *ip6, ip6buf;
 #endif
+       union {
+#ifdef INET
+               struct ip ip;
+#endif
+#ifdef INET6
+               struct ip6_hdr ip6;
+#endif
+               uint32_t port;
+        } buf;
        SIPHASH_CTX ctx;
 
        SipHash24_Init(&ctx, key);
@@ -1013,10 +1024,25 @@ trunk_hashmbuf(struct mbuf *m, SIPHASH_K
 #ifdef INET
        case ETHERTYPE_IP:
                if ((ip = (struct ip *)
-                   trunk_gethdr(m, off, sizeof(*ip), &ipbuf)) == NULL)
+                   trunk_gethdr(m, off, sizeof(*ip), &buf)) == NULL)
                        return (p);
                SipHash24_Update(&ctx, &ip->ip_src, sizeof(struct in_addr));
                SipHash24_Update(&ctx, &ip->ip_dst, sizeof(struct in_addr));
+
+               /* l4 hash */
+               switch (ip->ip_p) {
+               case IPPROTO_TCP:
+               case IPPROTO_UDP:
+                       iphlen = ip->ip_hl << 2;
+                       if (iphlen < sizeof(*ip))
+                               break;
+                       off += iphlen;
+                       ports = (u_int32_t *) trunk_gethdr(m, off, 
sizeof(*ports), &buf);
+                       if (ports == NULL)
+                               break;
+                       SipHash24_Update(&ctx, ports, sizeof(*ports));
+                       break;
+               }
                break;
 #endif
 #ifdef INET6

Reply via email to