summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctputil.c
diff options
context:
space:
mode:
authorrrs <rrs@FreeBSD.org>2007-03-19 11:11:16 +0000
committerrrs <rrs@FreeBSD.org>2007-03-19 11:11:16 +0000
commit56faff0a7452b39fd328d13e20d96518124918ad (patch)
treea8df83dcc65a165ded6c77be172e14119f46ab38 /sys/netinet/sctputil.c
parentd9b60cf6fa9667eb83a9934de16d3be1db0033a4 (diff)
downloadFreeBSD-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.c56
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)
OpenPOWER on IntegriCloud