Replace the single global IP reassembly list/listhead, with a

hashtable of list-heads. Independently re-invented, then reworked to
match similar code in FreeBSD.
This commit is contained in:
jonathan 2003-12-06 23:56:10 +00:00
parent 464de24c0e
commit c56097abb8
2 changed files with 66 additions and 22 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip_input.c,v 1.189 2003/12/04 19:38:24 atatat Exp $ */
/* $NetBSD: ip_input.c,v 1.190 2003/12/06 23:56:10 jonathan Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -98,7 +98,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.189 2003/12/04 19:38:24 atatat Exp $");
__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.190 2003/12/06 23:56:10 jonathan Exp $");
#include "opt_inet.h"
#include "opt_gateway.h"
@ -236,7 +236,16 @@ uint16_t ip_id;
struct pfil_head inet_pfil_hook;
#endif
struct ipqhead ipq;
/* IP datagram reassembly queues (hashed) */
#define IPREASS_NHASH_LOG2 6
#define IPREASS_NHASH (1 << IPREASS_NHASH_LOG2)
#define IPREASS_HMASK (IPREASS_NHASH - 1)
#define IPREASS_HASH(x,y) \
(((((x) & 0xF) | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK)
struct ipqhead ipq[IPREASS_NHASH];
#ifdef notyet
static int nipq = 0; /* total # of reass queues */
#endif
int ipq_locked;
int ip_nfragpackets = 0;
int ip_maxfragpackets = 200;
@ -363,7 +372,9 @@ ip_init()
if (pr->pr_domain->dom_family == PF_INET &&
pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW)
ip_protox[pr->pr_protocol] = pr - inetsw;
LIST_INIT(&ipq);
for (i = 0; i < IPREASS_NHASH; i++)
LIST_INIT(&ipq[i]);
ip_id = time.tv_sec & 0xfffff;
ipintrq.ifq_maxlen = ipqmaxlen;
TAILQ_INIT(&in_ifaddrhead);
@ -437,6 +448,7 @@ ip_input(struct mbuf *m)
int downmatch;
int checkif;
int srcrt = 0;
u_int hash;
#ifdef FAST_IPSEC
struct m_tag *mtag;
struct tdb_ident *tdbi;
@ -823,12 +835,17 @@ ours:
* of this datagram.
*/
IPQ_LOCK();
LIST_FOREACH(fp, &ipq, ipq_q)
hash = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id);
/* XXX LIST_FOREACH(fp, &ipq[hash], ipq_q) */
for (fp = LIST_FIRST(&ipq[hash]); fp != NULL;
fp = LIST_NEXT(fp, ipq_q)) {
if (ip->ip_id == fp->ipq_id &&
in_hosteq(ip->ip_src, fp->ipq_src) &&
in_hosteq(ip->ip_dst, fp->ipq_dst) &&
ip->ip_p == fp->ipq_p)
goto found;
}
fp = 0;
found:
@ -869,7 +886,7 @@ found:
ipqe->ipqe_mff = mff;
ipqe->ipqe_m = m;
ipqe->ipqe_ip = ip;
m = ip_reass(ipqe, fp);
m = ip_reass(ipqe, fp, &ipq[hash]);
if (m == 0) {
IPQ_UNLOCK();
return;
@ -966,9 +983,10 @@ badcsum:
* is given as fp; otherwise have to make a chain.
*/
struct mbuf *
ip_reass(ipqe, fp)
ip_reass(ipqe, fp, ipqhead)
struct ipqent *ipqe;
struct ipq *fp;
struct ipqhead *ipqhead;
{
struct mbuf *m = ipqe->ipqe_m;
struct ipqent *nq, *p, *q;
@ -1005,7 +1023,7 @@ ip_reass(ipqe, fp)
M_FTABLE, M_NOWAIT);
if (fp == NULL)
goto dropfrag;
LIST_INSERT_HEAD(&ipq, fp, ipq_q);
LIST_INSERT_HEAD(ipqhead, fp, ipq_q);
fp->ipq_ttl = IPFRAGTTL;
fp->ipq_p = ipqe->ipqe_ip->ip_p;
fp->ipq_id = ipqe->ipqe_ip->ip_id;
@ -1171,27 +1189,47 @@ ip_freef(fp)
void
ip_slowtimo()
{
static unsigned dropscanidx = 0;
unsigned i;
struct ipq *fp, *nfp;
int s = splsoftnet();
IPQ_LOCK();
for (fp = LIST_FIRST(&ipq); fp != NULL; fp = nfp) {
nfp = LIST_NEXT(fp, ipq_q);
if (--fp->ipq_ttl == 0) {
ipstat.ips_fragtimeout++;
ip_freef(fp);
for (i = 0; i < IPREASS_NHASH; i++) {
for (fp = LIST_FIRST(&ipq[i]); fp != NULL; fp = nfp) {
nfp = LIST_NEXT(fp, ipq_q);
if (--fp->ipq_ttl == 0) {
ipstat.ips_fragtimeout++;
ip_freef(fp);
}
}
}
/*
* If we are over the maximum number of fragments
* (due to the limit being lowered), drain off
* enough to get down to the new limit.
* enough to get down to the new limit. Start draining
* from the reassembly hashqueue most recently drained.
*/
if (ip_maxfragpackets < 0)
;
else {
while (ip_nfragpackets > ip_maxfragpackets && LIST_FIRST(&ipq))
ip_freef(LIST_FIRST(&ipq));
int wrapped = 0;
i = dropscanidx;
while (ip_nfragpackets > ip_maxfragpackets && wrapped == 0) {
while (LIST_FIRST(&ipq[i]) != NULL)
ip_freef(LIST_FIRST(&ipq[i]));
if (++i >= IPREASS_NHASH) {
i = 0;
}
/*
* Dont scan forever even if fragment counters are
* wrong: stop after scanning entire reassembly queue.
*/
if (i == dropscanidx)
wrapped = 1;
}
dropscanidx = i;
}
IPQ_UNLOCK();
#ifdef GATEWAY
@ -1206,6 +1244,7 @@ ip_slowtimo()
void
ip_drain()
{
int i;
/*
* We may be called from a device's interrupt context. If
@ -1214,9 +1253,14 @@ ip_drain()
if (ipq_lock_try() == 0)
return;
while (LIST_FIRST(&ipq) != NULL) {
ipstat.ips_fragdropped++;
ip_freef(LIST_FIRST(&ipq));
for (i = 0; i < IPREASS_NHASH; i++) {
struct ipqhead *ipqh = &ipq[i];
struct ipq *fp, *nfp;
for (fp = LIST_FIRST(ipqh); fp != NULL; fp = nfp) {
nfp = LIST_NEXT(fp, ipq_q);
ip_freef(fp);
ipstat.ips_fragdropped++;
}
}
IPQ_UNLOCK();

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip_var.h,v 1.62 2003/11/26 21:15:47 itojun Exp $ */
/* $NetBSD: ip_var.h,v 1.63 2003/12/06 23:56:10 jonathan Exp $ */
/*
* Copyright (c) 1982, 1986, 1993
@ -192,7 +192,7 @@ struct ipflow {
#endif
extern struct ipstat ipstat; /* ip statistics */
extern LIST_HEAD(ipqhead, ipq) ipq; /* ip reass. queue */
extern LIST_HEAD(ipqhead, ipq) ipq[]; /* ip reass. queue */
extern int ip_defttl; /* default IP ttl */
extern int ipforwarding; /* ip forwarding */
extern int ip_mtudisc; /* mtu discovery */
@ -227,7 +227,7 @@ int ip_output __P((struct mbuf *, ...));
int ip_fragment(struct mbuf *, struct ifnet *, u_long);
int ip_pcbopts __P((struct mbuf **, struct mbuf *));
struct mbuf *
ip_reass __P((struct ipqent *, struct ipq *));
ip_reass __P((struct ipqent *, struct ipq *, struct ipqhead *));
struct in_ifaddr *
ip_rtaddr __P((struct in_addr));
void ip_savecontrol __P((struct inpcb *, struct mbuf **, struct ip *,