In addition to the IP flow hash table, put the flows on a list. The table

is used for fast lookup, the list for traversal of all flows.  Also, use
PRT timers.
This commit is contained in:
thorpej 1998-06-02 15:48:03 +00:00
parent 9a4b24a02a
commit edc01ec330
2 changed files with 71 additions and 62 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip_flow.c,v 1.4 1998/05/18 17:08:56 matt Exp $ */
/* $NetBSD: ip_flow.c,v 1.5 1998/06/02 15:48:03 thorpej Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -64,10 +64,27 @@
#include <netinet/in_var.h>
#include <netinet/ip_var.h>
LIST_HEAD(ipflowhead, ipflow);
#define IPFLOW_TIMER (5 * PR_SLOWHZ)
#define IPFLOW_HASHSIZE (1 << IPFLOW_HASHBITS)
static LIST_HEAD(ipflowhead, ipflow) ipflows[IPFLOW_HASHSIZE];
static struct ipflowhead ipflowtable[IPFLOW_HASHSIZE];
static struct ipflowhead ipflowlist;
static int ipflow_inuse;
#define IPFLOW_INSERT(bucket, ipf) \
do { \
LIST_INSERT_HEAD((bucket), (ipf), ipf_hash); \
LIST_INSERT_HEAD(&ipflowlist, (ipf), ipf_list); \
} while (0)
#define IPFLOW_REMOVE(ipf) \
do { \
LIST_REMOVE((ipf), ipf_hash); \
LIST_REMOVE((ipf), ipf_list); \
} while (0)
#ifndef IPFLOW_MAX
#define IPFLOW_MAX 256
#endif
@ -95,13 +112,13 @@ ipflow_lookup(
hash = ipflow_hash(ip->ip_dst, ip->ip_src, ip->ip_tos);
ipf = LIST_FIRST(&ipflows[hash]);
ipf = LIST_FIRST(&ipflowtable[hash]);
while (ipf != NULL) {
if (ip->ip_dst.s_addr == ipf->ipf_dst.s_addr
&& ip->ip_src.s_addr == ipf->ipf_src.s_addr
&& ip->ip_tos == ipf->ipf_tos)
break;
ipf = LIST_NEXT(ipf, ipf_next);
ipf = LIST_NEXT(ipf, ipf_hash);
}
return ipf;
}
@ -124,8 +141,8 @@ ipflow_fastforward(
* IP header with no option and valid version and length
*/
ip = mtod(m, struct ip *);
if (ip->ip_v != IPVERSION || ip->ip_hl != (sizeof(struct ip) >> 2)
|| ntohs(ip->ip_len) > m->m_pkthdr.len)
if (ip->ip_v != IPVERSION || ip->ip_hl != (sizeof(struct ip) >> 2) ||
ntohs(ip->ip_len) > m->m_pkthdr.len)
return 0;
/*
* Find a flow.
@ -143,7 +160,8 @@ ipflow_fastforward(
* Route and interface still up?
*/
rt = ipf->ipf_ro.ro_rt;
if ((rt->rt_flags & RTF_UP) == 0 || (rt->rt_ifp->if_flags & IFF_UP) == 0)
if ((rt->rt_flags & RTF_UP) == 0 ||
(rt->rt_ifp->if_flags & IFF_UP) == 0)
return 0;
/*
@ -172,8 +190,9 @@ ipflow_fastforward(
* Send the packet on it's way. All we can get back is ENOBUFS
*/
ipf->ipf_uses++;
ipf->ipf_timer = IPFLOW_TIMER;
if ((error = (*rt->rt_ifp->if_output)(rt->rt_ifp, m, &ipf->ipf_ro.ro_dst, rt)) != 0) {
PRT_SLOW_ARM(ipf->ipf_timer, IPFLOW_TIMER);
if ((error = (*rt->rt_ifp->if_output)(rt->rt_ifp, m,
&ipf->ipf_ro.ro_dst, rt)) != 0) {
if (error == ENOBUFS)
ipf->ipf_dropped++;
else
@ -203,7 +222,7 @@ ipflow_free(
* network IPL.
*/
s = splimp();
LIST_REMOVE(ipf, ipf_next);
IPFLOW_REMOVE(ipf);
splx(s);
ipflow_addstats(ipf);
RTFREE(ipf->ipf_ro.ro_rt);
@ -217,32 +236,29 @@ ipflow_reap(
{
while (just_one || ipflow_inuse > ip_maxflows) {
struct ipflow *ipf, *maybe_ipf = NULL;
int idx;
int s;
for (idx = 0; idx < IPFLOW_HASHSIZE; idx++) {
ipf = LIST_FIRST(&ipflows[idx]);
while (ipf != NULL) {
/*
* If this no longer points to a valid route
* reclaim it.
*/
if ((ipf->ipf_ro.ro_rt->rt_flags & RTF_UP) == 0)
goto done;
/*
* choose the one that's been least recently
* used or has had the least uses in the
* last 1.5 intervals.
*/
if (maybe_ipf == NULL
|| ipf->ipf_timer < maybe_ipf->ipf_timer
|| (ipf->ipf_timer == maybe_ipf->ipf_timer
&& ipf->ipf_last_uses + ipf->ipf_uses <
maybe_ipf->ipf_last_uses +
maybe_ipf->ipf_uses))
maybe_ipf = ipf;
ipf = LIST_NEXT(ipf, ipf_next);
}
ipf = LIST_FIRST(&ipflowlist);
while (ipf != NULL) {
/*
* If this no longer points to a valid route
* reclaim it.
*/
if ((ipf->ipf_ro.ro_rt->rt_flags & RTF_UP) == 0)
goto done;
/*
* choose the one that's been least recently
* used or has had the least uses in the
* last 1.5 intervals.
*/
if (maybe_ipf == NULL ||
ipf->ipf_timer < maybe_ipf->ipf_timer ||
(ipf->ipf_timer == maybe_ipf->ipf_timer &&
ipf->ipf_last_uses + ipf->ipf_uses <
maybe_ipf->ipf_last_uses +
maybe_ipf->ipf_uses))
maybe_ipf = ipf;
ipf = LIST_NEXT(ipf, ipf_list);
}
ipf = maybe_ipf;
done:
@ -250,7 +266,7 @@ ipflow_reap(
* Remove the entry from the flow table.
*/
s = splimp();
LIST_REMOVE(ipf, ipf_next);
IPFLOW_REMOVE(ipf);
splx(s);
ipflow_addstats(ipf);
RTFREE(ipf->ipf_ro.ro_rt);
@ -266,29 +282,21 @@ void
ipflow_slowtimo(
void)
{
struct ipflow *ipf;
int idx;
int inuse = ipflow_inuse;
struct ipflow *ipf, *next_ipf;
/*
* Save ourselves some work if we know there aren't any flows.
*/
for (idx = 0; inuse > 0 && idx < IPFLOW_HASHSIZE; idx++) {
ipf = LIST_FIRST(&ipflows[idx]);
while (ipf != NULL) {
struct ipflow *next_ipf = LIST_NEXT(ipf, ipf_next);
inuse--;
if (--ipf->ipf_timer == 0) {
ipflow_free(ipf);
} else {
ipf->ipf_last_uses = ipf->ipf_uses;
ipf->ipf_ro.ro_rt->rt_use += ipf->ipf_uses;
ipstat.ips_forward += ipf->ipf_uses;
ipstat.ips_fastforward += ipf->ipf_uses;
ipf->ipf_uses = 0;
}
ipf = next_ipf;
ipf = LIST_FIRST(&ipflowlist);
while (ipf != NULL) {
next_ipf = LIST_NEXT(ipf, ipf_list);
if (PRT_SLOW_ISEXPIRED(ipf->ipf_timer)) {
ipflow_free(ipf);
} else {
ipf->ipf_last_uses = ipf->ipf_uses;
ipf->ipf_ro.ro_rt->rt_use += ipf->ipf_uses;
ipstat.ips_forward += ipf->ipf_uses;
ipstat.ips_fastforward += ipf->ipf_uses;
ipf->ipf_uses = 0;
}
ipf = next_ipf;
}
}
@ -326,7 +334,7 @@ ipflow_create(
bzero((caddr_t) ipf, sizeof(*ipf));
} else {
s = splimp();
LIST_REMOVE(ipf, ipf_next);
IPFLOW_REMOVE(ipf);
splx(s);
ipflow_addstats(ipf);
RTFREE(ipf->ipf_ro.ro_rt);
@ -342,13 +350,13 @@ ipflow_create(
ipf->ipf_dst = ip->ip_dst;
ipf->ipf_src = ip->ip_src;
ipf->ipf_tos = ip->ip_tos;
ipf->ipf_timer = IPFLOW_TIMER;
PRT_SLOW_ARM(ipf->ipf_timer, IPFLOW_TIMER);
ipf->ipf_start = time.tv_sec;
/*
* Insert into the approriate bucket of the flow table.
*/
hash = ipflow_hash(ip->ip_dst, ip->ip_src, ip->ip_tos);
s = splimp();
LIST_INSERT_HEAD(&ipflows[hash], ipf, ipf_next);
IPFLOW_INSERT(&ipflowtable[hash], ipf);
splx(s);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip_var.h,v 1.33 1998/05/11 23:13:40 thorpej Exp $ */
/* $NetBSD: ip_var.h,v 1.34 1998/06/02 15:48:03 thorpej Exp $ */
/*
* Copyright (c) 1982, 1986, 1993
@ -156,7 +156,8 @@ struct ipstat {
#define IPFLOW_HASHBITS 6 /* should not be a multiple of 8 */
struct ipflow {
LIST_ENTRY(ipflow) ipf_next; /* next ipflow in bucket */
LIST_ENTRY(ipflow) ipf_list; /* next in active list */
LIST_ENTRY(ipflow) ipf_hash; /* next ipflow in bucket */
struct in_addr ipf_dst; /* destination address */
struct in_addr ipf_src; /* source address */
u_int8_t ipf_tos; /* type-of-service */
@ -165,7 +166,7 @@ struct ipflow {
u_long ipf_last_uses; /* number of uses in last period */
u_long ipf_dropped; /* ENOBUFS returned by if_output */
u_long ipf_errors; /* other errors returned by if_output */
int ipf_timer; /* remaining lifetime of this entry */
u_int ipf_timer; /* lifetime timer */
time_t ipf_start; /* creation time */
};