diff options
author | rrs <rrs@FreeBSD.org> | 2007-03-19 11:11:16 +0000 |
---|---|---|
committer | rrs <rrs@FreeBSD.org> | 2007-03-19 11:11:16 +0000 |
commit | 56faff0a7452b39fd328d13e20d96518124918ad (patch) | |
tree | a8df83dcc65a165ded6c77be172e14119f46ab38 /sys/netinet/sctputil.c | |
parent | d9b60cf6fa9667eb83a9934de16d3be1db0033a4 (diff) | |
download | FreeBSD-src-56faff0a7452b39fd328d13e20d96518124918ad.zip FreeBSD-src-56faff0a7452b39fd328d13e20d96518124918ad.tar.gz |
Adds a hash table to speed local address lookup
on a per VRF basis (BSD has only one VRF currently).
Hash table is sized to 16 but may need to be adjusted
for machines with large numbers of addresses.
Reviewed by: gnn
Diffstat (limited to 'sys/netinet/sctputil.c')
-rw-r--r-- | sys/netinet/sctputil.c | 56 |
1 files changed, 49 insertions, 7 deletions
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index e3c240c..ea7a830 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -4271,26 +4271,68 @@ sctp_find_ifa_in_ifn(struct sctp_ifn *sctp_ifnp, struct sockaddr *addr, return (NULL); } +uint32_t +sctp_get_ifa_hash_val(struct sockaddr *addr) +{ + + if (addr->sa_family == AF_INET) { + struct sockaddr_in *sin; + + sin = (struct sockaddr_in *)addr; + return (sin->sin_addr.s_addr ^ (sin->sin_addr.s_addr >> 16)); + } else if (addr->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6; + uint32_t hash_of_addr; + + sin6 = (struct sockaddr_in6 *)addr; + hash_of_addr = (sin6->sin6_addr.s6_addr32[0] + + sin6->sin6_addr.s6_addr32[1] + + sin6->sin6_addr.s6_addr32[2] + + sin6->sin6_addr.s6_addr32[3]); + hash_of_addr = (hash_of_addr ^ (hash_of_addr >> 16)); + return (hash_of_addr); + } + return (0); +} + struct sctp_ifa * sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock) { struct sctp_ifa *sctp_ifap; - struct sctp_ifn *sctp_ifnp = NULL; struct sctp_vrf *vrf; + struct sctp_ifalist *hash_head; + uint32_t hash_of_addr; vrf = sctp_find_vrf(vrf_id); if (vrf == NULL) return (NULL); + hash_of_addr = sctp_get_ifa_hash_val(addr); if (holds_lock == 0) SCTP_IPI_ADDR_LOCK(); - LIST_FOREACH(sctp_ifnp, &vrf->ifnlist, next_ifn) { - sctp_ifap = sctp_find_ifa_in_ifn(sctp_ifnp, addr, 1); - if (sctp_ifap) { - if (holds_lock == 0) - SCTP_IPI_ADDR_UNLOCK(); - return (sctp_ifap); + hash_head = &vrf->vrf_addr_hash[(hash_of_addr & vrf->vrf_hashmark)]; + LIST_FOREACH(sctp_ifap, hash_head, next_bucket) { + if (addr->sa_family != sctp_ifap->address.sa.sa_family) + continue; + if (addr->sa_family == AF_INET) { + if (((struct sockaddr_in *)addr)->sin_addr.s_addr == + sctp_ifap->address.sin.sin_addr.s_addr) { + /* found him. */ + if (holds_lock == 0) + SCTP_IPI_ADDR_UNLOCK(); + return (sctp_ifap); + break; + } + } else if (addr->sa_family == AF_INET6) { + if (SCTP6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)addr)->sin6_addr, + &sctp_ifap->address.sin6.sin6_addr)) { + /* found him. */ + if (holds_lock == 0) + SCTP_IPI_ADDR_UNLOCK(); + return (sctp_ifap); + break; + } } } if (holds_lock == 0) |