Add a hash table that contains the list of internet addresses, and use

this in place of the in_ifaddr list when appropriate.  This improves
performance on hosts which have a large number of IP aliases.
This commit is contained in:
Jonathan Lemon 2001-09-29 04:34:11 +00:00
parent 9a10980e2a
commit ca925d9c17
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=84102
6 changed files with 113 additions and 63 deletions

View File

@ -526,7 +526,8 @@ in_arpinput(m)
struct iso88025_header *th = (struct iso88025_header *)0;
register struct llinfo_arp *la = 0;
register struct rtentry *rt;
struct in_ifaddr *ia, *maybe_ia = 0;
struct ifaddr *ifa;
struct in_ifaddr *ia;
struct sockaddr_dl *sdl;
struct sockaddr sa;
struct in_addr isaddr, itaddr, myaddr;
@ -542,30 +543,36 @@ in_arpinput(m)
op = ntohs(ea->arp_op);
(void)memcpy(&isaddr, ea->arp_spa, sizeof (isaddr));
(void)memcpy(&itaddr, ea->arp_tpa, sizeof (itaddr));
TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
/*
* For a bridge, we want to check the address irrespective
* of the receive interface. (This will change slightly
* when we have clusters of interfaces).
*/
#ifdef BRIDGE
#define BRIDGE_TEST (do_bridge)
#else
#define BRIDGE_TEST (0) /* cc will optimise the test away */
#endif
if ((BRIDGE_TEST) || (ia->ia_ifp == &ac->ac_if)) {
maybe_ia = ia;
if ((itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) ||
(isaddr.s_addr == ia->ia_addr.sin_addr.s_addr)) {
break;
}
}
}
if (maybe_ia == 0) {
/*
* For a bridge, we want to check the address irrespective
* of the receive interface. (This will change slightly
* when we have clusters of interfaces).
*/
LIST_FOREACH(ia, INADDR_HASH(itaddr.s_addr), ia_hash)
if ((BRIDGE_TEST || (ia->ia_ifp == &ac->ac_if)) &&
itaddr.s_addr == ia->ia_addr.sin_addr.s_addr)
goto match;
LIST_FOREACH(ia, INADDR_HASH(isaddr.s_addr), ia_hash)
if ((BRIDGE_TEST || (ia->ia_ifp == &ac->ac_if)) &&
isaddr.s_addr == ia->ia_addr.sin_addr.s_addr)
goto match;
/*
* No match, use the first address on the receive interface
* as a dummy address for the rest of the function.
*/
ifa = TAILQ_FIRST(&ac->ac_if.if_addrhead);
if (ifa == NULL) {
m_freem(m);
return;
}
myaddr = ia ? ia->ia_addr.sin_addr : maybe_ia->ia_addr.sin_addr;
ia = ifatoia(ifa);
match:
myaddr = ia->ia_addr.sin_addr;
if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr,
sizeof (ea->arp_sha))) {
m_freem(m); /* it's from me, ignore it. */

View File

@ -193,6 +193,7 @@ in_control(so, cmd, data, ifp, td)
register struct ifreq *ifr = (struct ifreq *)data;
register struct in_ifaddr *ia = 0, *iap;
register struct ifaddr *ifa;
struct in_addr dst;
struct in_ifaddr *oia;
struct in_aliasreq *ifra = (struct in_aliasreq *)data;
struct sockaddr_in oldaddr;
@ -215,21 +216,25 @@ in_control(so, cmd, data, ifp, td)
* Find address for this interface, if it exists.
*
* If an alias address was specified, find that one instead of
* the first one on the interface.
* the first one on the interface, if possible.
*/
if (ifp)
TAILQ_FOREACH(iap, &in_ifaddrhead, ia_link)
if (iap->ia_ifp == ifp) {
if (((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr.s_addr ==
iap->ia_addr.sin_addr.s_addr) {
if (ifp) {
dst = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
LIST_FOREACH(iap, INADDR_HASH(dst.s_addr), ia_hash)
if (iap->ia_ifp == ifp &&
iap->ia_addr.sin_addr.s_addr == dst.s_addr) {
ia = iap;
break;
}
if (ia == NULL)
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
iap = ifatoia(ifa);
if (iap->ia_addr.sin_family == AF_INET) {
ia = iap;
break;
} else if (ia == NULL) {
ia = iap;
if (ifr->ifr_addr.sa_family != AF_INET)
break;
}
}
}
switch (cmd) {
@ -423,9 +428,9 @@ in_control(so, cmd, data, ifp, td)
ifa = &ia->ia_ifa;
TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
oia = ia;
TAILQ_REMOVE(&in_ifaddrhead, oia, ia_link);
IFAFREE(&oia->ia_ifa);
TAILQ_REMOVE(&in_ifaddrhead, ia, ia_link);
LIST_REMOVE(ia, ia_hash);
IFAFREE(&ia->ia_ifa);
splx(s);
break;
@ -650,6 +655,7 @@ in_ifinit(ifp, ia, sin, scrub)
oldaddr = ia->ia_addr;
ia->ia_addr = *sin;
LIST_INSERT_HEAD(INADDR_HASH(ia->ia_addr.sin_addr.s_addr), ia, ia_hash);
/*
* Give the interface a chance to initialize
* if this is its first address,

View File

@ -38,6 +38,7 @@
#define _NETINET_IN_VAR_H_
#include <sys/queue.h>
#include <sys/fnv_hash.h>
/*
* Interface address, Internet version. One of these structures
@ -55,7 +56,8 @@ struct in_ifaddr {
u_long ia_subnet; /* subnet number, including net */
u_long ia_subnetmask; /* mask of subnet part */
struct in_addr ia_netbroadcast; /* to recognize net broadcasts */
TAILQ_ENTRY(in_ifaddr) ia_link; /* tailq macro glue */
LIST_ENTRY(in_ifaddr) ia_hash; /* entry in bucket of inet addresses */
TAILQ_ENTRY(in_ifaddr) ia_link; /* list of internet addresses */
struct sockaddr_in ia_addr; /* reserve space for interface name */
struct sockaddr_in ia_dstaddr; /* reserve space for broadcast addr */
#define ia_broadaddr ia_dstaddr
@ -81,11 +83,25 @@ struct in_aliasreq {
#ifdef _KERNEL
extern TAILQ_HEAD(in_ifaddrhead, in_ifaddr) in_ifaddrhead;
extern struct ifqueue ipintrq; /* ip packet input queue */
extern struct in_addr zeroin_addr;
extern u_char inetctlerrmap[];
/*
* Hash table for IP addresses.
*/
extern LIST_HEAD(in_ifaddrhashhead, in_ifaddr) *in_ifaddrhashtbl;
extern TAILQ_HEAD(in_ifaddrhead, in_ifaddr) in_ifaddrhead;
extern u_long in_ifaddrhmask; /* mask for hash table */
#define INADDR_NHASH_LOG2 9
#define INADDR_NHASH (1 << INADDR_NHASH_LOG2)
#define INADDR_HMASK (INREASS_NHASH - 1)
#define INADDR_HASHVAL(x) fnv_32_buf((&(x)), sizeof(x), FNV1_32_INIT)
#define INADDR_HASH(x) \
(&in_ifaddrhashtbl[INADDR_HASHVAL(x) & in_ifaddrhmask])
/*
* Macro for finding the interface (ifnet structure) corresponding to one
* of our IP addresses.

View File

@ -461,7 +461,6 @@ icmp_input(m, off)
goto reflect;
case ICMP_MASKREQ:
#define satosin(sa) ((struct sockaddr_in *)(sa))
if (icmpmaskrepl == 0)
break;
/*
@ -584,8 +583,9 @@ static void
icmp_reflect(m)
struct mbuf *m;
{
register struct ip *ip = mtod(m, struct ip *);
register struct in_ifaddr *ia;
struct ip *ip = mtod(m, struct ip *);
struct ifaddr *ifa;
struct in_ifaddr *ia;
struct in_addr t;
struct mbuf *opts = 0;
int optlen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof(struct ip);
@ -604,23 +604,30 @@ icmp_reflect(m)
* or anonymous), use the address which corresponds
* to the incoming interface.
*/
TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
LIST_FOREACH(ia, INADDR_HASH(t.s_addr), ia_hash)
if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr)
break;
if (ia->ia_ifp && (ia->ia_ifp->if_flags & IFF_BROADCAST) &&
t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr)
break;
}
goto match;
if (m->m_pkthdr.rcvif->if_flags & IFF_BROADCAST) {
TAILQ_FOREACH(ifa, &m->m_pkthdr.rcvif->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != AF_INET)
continue;
ia = ifatoia(ifa);
if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
t.s_addr)
goto match;
}
}
KASSERT(m->m_pkthdr.rcvif != NULL, ("icmp_reflect: NULL rcvif"));
icmpdst.sin_addr = t;
if ((ia == (struct in_ifaddr *)0) && m->m_pkthdr.rcvif)
ia = (struct in_ifaddr *)ifaof_ifpforaddr(
(struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif);
ia = (struct in_ifaddr *)ifaof_ifpforaddr(
(struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif);
/*
* The following happens if the packet was not addressed to us,
* and was received on an interface with no IP address.
*/
if (ia == (struct in_ifaddr *)0)
if (ia == NULL)
ia = TAILQ_FIRST(&in_ifaddrhead);
match:
t = IA_SIN(ia)->sin_addr;
ip->ip_src = t;
ip->ip_ttl = ip_defttl;

View File

@ -146,11 +146,15 @@ SYSCTL_INT(_net_inet_ip, OID_AUTO, check_interface, CTLFLAG_RW,
static int ipprintfs = 0;
#endif
static int ipqmaxlen = IFQ_MAXLEN;
extern struct domain inetdomain;
extern struct protosw inetsw[];
u_char ip_protox[IPPROTO_MAX];
static int ipqmaxlen = IFQ_MAXLEN;
struct in_ifaddrhead in_ifaddrhead; /* first inet address */
struct in_ifaddrhead in_ifaddrhead; /* first inet address */
struct in_ifaddrhashhead *in_ifaddrhashtbl; /* inet addr hash table */
u_long in_ifaddrhmask; /* mask for hash table */
SYSCTL_INT(_net_inet_ip, IPCTL_INTRQMAXLEN, intr_queue_maxlen, CTLFLAG_RW,
&ipintrq.ifq_maxlen, 0, "Maximum size of the IP input queue");
SYSCTL_INT(_net_inet_ip, IPCTL_INTRQDROPS, intr_queue_drops, CTLFLAG_RD,
@ -234,6 +238,7 @@ ip_init()
register int i;
TAILQ_INIT(&in_ifaddrhead);
in_ifaddrhashtbl = hashinit(INADDR_NHASH, M_IFADDR, &in_ifaddrhmask);
pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW);
if (pr == 0)
panic("ip_init");
@ -273,6 +278,7 @@ ip_input(struct mbuf *m)
struct ip *ip;
struct ipq *fp;
struct in_ifaddr *ia = NULL;
struct ifaddr *ifa;
int i, hlen, checkif;
u_short sum;
u_int16_t divert_cookie; /* firewall cookie */
@ -557,12 +563,10 @@ ip_input(struct mbuf *m)
((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) &&
(ip_fw_fwd_addr == NULL);
TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
#ifdef BOOTP_COMPAT
if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY)
goto ours;
#endif
/*
* Check for exact addresses in the hash bucket.
*/
LIST_FOREACH(ia, INADDR_HASH(pkt_dst.s_addr), ia_hash) {
/*
* If the address matches, verify that the packet
* arrived via the correct interface if checking is
@ -571,20 +575,29 @@ ip_input(struct mbuf *m)
if (IA_SIN(ia)->sin_addr.s_addr == pkt_dst.s_addr &&
(!checkif || ia->ia_ifp == m->m_pkthdr.rcvif))
goto ours;
/*
* Only accept broadcast packets that arrive via the
* matching interface. Reception of forwarded directed
* broadcasts would be handled via ip_forward() and
* ether_output() with the loopback into the stack for
* SIMPLEX interfaces handled by ether_output().
*/
if (ia->ia_ifp == m->m_pkthdr.rcvif &&
ia->ia_ifp && ia->ia_ifp->if_flags & IFF_BROADCAST) {
}
/*
* Check for broadcast addresses.
*
* Only accept broadcast packets that arrive via the matching
* interface. Reception of forwarded directed broadcasts would
* be handled via ip_forward() and ether_output() with the loopback
* into the stack for SIMPLEX interfaces handled by ether_output().
*/
if (m->m_pkthdr.rcvif->if_flags & IFF_BROADCAST) {
TAILQ_FOREACH(ifa, &m->m_pkthdr.rcvif->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != AF_INET)
continue;
ia = ifatoia(ifa);
if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
pkt_dst.s_addr)
goto ours;
if (ia->ia_netbroadcast.s_addr == pkt_dst.s_addr)
goto ours;
#ifdef BOOTP_COMPAT
if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY)
goto ours;
#endif
}
}
if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {

View File

@ -713,7 +713,8 @@ ip_output(m0, opt, ro, flags, imo)
* as the packet runs through ip_input() as
* it is done through a ISR.
*/
TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) {
LIST_FOREACH(ia,
INADDR_HASH(dst->sin_addr.s_addr), ia_hash) {
/*
* If the addr to forward to is one
* of ours, we pretend to