/* * User-space test harness for the Toeplitz/RSS code */ #include #include #include #include #include #include #include #define RSS_KEYSIZE 40 #if 0 static uint8_t rss_key[RSS_KEYSIZE] = { 0xbe, 0xac, 0x01, 0xfa, 0x6a, 0x42, 0xb7, 0x3b, 0x80, 0x30, 0xf2, 0x0c, 0x77, 0xcb, 0x2d, 0xa3, 0xae, 0x7b, 0x30, 0xb4, 0xd0, 0xca, 0x2b, 0xcb, 0x43, 0xa3, 0x8f, 0xb0, 0x41, 0x67, 0x25, 0x3d, 0x25, 0x5b, 0x0e, 0xc2, 0x6d, 0x5a, 0x56, 0xda, }; #else static uint8_t rss_key[RSS_KEYSIZE] = { 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2, 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0, 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4, 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c, 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa, }; #endif uint32_t toeplitz_hash(u_int keylen, const uint8_t *key, u_int datalen, const uint8_t *data) { uint32_t hash = 0, v; u_int i, b; /* XXXRW: Perhaps an assertion about key length vs. data length? */ v = (key[0]<<24) + (key[1]<<16) + (key[2] <<8) + key[3]; for (i = 0; i < datalen; i++) { for (b = 0; b < 8; b++) { if (data[i] & (1<<(7-b))) hash ^= v; v <<= 1; if ((i + 4) < RSS_KEYSIZE && (key[i+4] & (1<<(7-b)))) v |= 1; } } return (hash); } static uint32_t rss_hash(u_int datalen, const uint8_t *data) { return (toeplitz_hash(sizeof(rss_key), rss_key, datalen, data)); } /* * Hash an IPv4 2-tuple. */ uint32_t rss_hash_ip4_2tuple(struct in_addr src, struct in_addr dst) { uint8_t data[sizeof(src) + sizeof(dst)]; u_int datalen; datalen = 0; bcopy(&src, &data[datalen], sizeof(src)); datalen += sizeof(src); bcopy(&dst, &data[datalen], sizeof(dst)); datalen += sizeof(dst); return (rss_hash(datalen, data)); } /* * Hash an IPv4 4-tuple. */ uint32_t rss_hash_ip4_4tuple(struct in_addr src, u_short srcport, struct in_addr dst, u_short dstport) { uint8_t data[sizeof(src) + sizeof(dst) + sizeof(srcport) + sizeof(dstport)]; u_int datalen; datalen = 0; bcopy(&src, &data[datalen], sizeof(src)); datalen += sizeof(src); bcopy(&dst, &data[datalen], sizeof(dst)); datalen += sizeof(dst); bcopy(&srcport, &data[datalen], sizeof(srcport)); datalen += sizeof(srcport); bcopy(&dstport, &data[datalen], sizeof(dstport)); datalen += sizeof(dstport); return (rss_hash(datalen, data)); } uint32_t rss_hash_ip6_2tuple(struct in6_addr src, struct in6_addr dst) { uint8_t data[sizeof(src) + sizeof(dst)]; u_int datalen; datalen = 0; bcopy(&src, &data[datalen], sizeof(src)); datalen += sizeof(src); bcopy(&dst, &data[datalen], sizeof(dst)); datalen += sizeof(dst); return (rss_hash(datalen, data)); } /* * Hash an IPv6 4-tuple. */ uint32_t rss_hash_ip6_4tuple(struct in6_addr src, u_short srcport, struct in6_addr dst, u_short dstport) { uint8_t data[sizeof(src) + sizeof(dst) + sizeof(srcport) + sizeof(dstport)]; u_int datalen; datalen = 0; bcopy(&src, &data[datalen], sizeof(src)); datalen += sizeof(src); bcopy(&dst, &data[datalen], sizeof(dst)); datalen += sizeof(dst); bcopy(&srcport, &data[datalen], sizeof(srcport)); datalen += sizeof(srcport); bcopy(&dstport, &data[datalen], sizeof(dstport)); datalen += sizeof(dstport); return (rss_hash(datalen, data)); } struct test_vectors { char *dst; uint16_t dport; char *src; uint16_t sport; uint32_t hash; uint32_t hash_tcp; int v6; } tests[] = { /* IPv4 tests */ { "161.142.100.80", 1766, "66.9.149.187", 2794, 0x323e8fc2, 0x51ccc178 }, { "65.69.140.83", 4739, "199.92.111.2", 14230, 0xd718262a, 0xc626b0ea }, { "12.22.207.184", 38024, "24.19.198.95", 12898, 0xd2d0a5de, 0x5c2b394a }, { "209.142.163.6", 2217, "38.27.205.30", 48228, 0x82989176, 0xafc7327f }, { "202.188.127.2", 1303, "153.39.163.191", 44251, 0x5d1809c5, 0x10e828a2 }, /* IPv6 tests */ { "3ffe:2501:200:3::1", 1766, "3ffe:2501:200:1fff::7", 2794, 0x2cc18cd5, 0x40207d3d , 1}, { "ff02::1", 4739, "3ffe:501:8::260:97ff:fe40:efab", 14230, 0x0f0c461c, 0xdde51bbf, 1 }, { "fe80::200:f8ff:fe21:67cf", 38024, "3ffe:1900:4545:3:200:f8ff:fe21:67cf", 44251, 0x4b61e985, 0x02d1feef, 1 }, }; int main(int argc, char **argv) { struct in_addr v4dst, v4src; struct in6_addr v6dst, v6src; uint32_t hash, thash; uint16_t dport, sport; int i; for (i = 0; i < nitems(tests); i++) { dport = ntohs(tests[i].dport); sport = ntohs(tests[i].sport); if (tests[i].v6) { inet_pton(AF_INET6, tests[i].dst, &v6dst); inet_pton(AF_INET6, tests[i].src, &v6src); hash = rss_hash_ip6_2tuple(v6src, v6dst); thash = rss_hash_ip6_4tuple(v6src, sport, v6dst, dport); } else { inet_aton(tests[i].dst, &v4dst); inet_aton(tests[i].src, &v4src); hash = rss_hash_ip4_2tuple(v4src, v4dst); thash = rss_hash_ip4_4tuple(v4src, sport, v4dst, dport); } if (hash != tests[i].hash) printf("Test %d failed: %x != expected %x\n", i, hash, tests[i].hash); if (thash != tests[i].hash_tcp) printf("Test %d.a failed: %x != expected %x\n", i, thash, tests[i].hash_tcp); } }