Use own IPv4 reassembly queue entry structure and leave struct ipqent only

for TCP.  Now both struct ipfr_qent, struct ipfr_queue and hashed fragment
queue are abstracted and no longer public.
This commit is contained in:
rmind 2010-08-25 00:05:14 +00:00
parent 3b6fdb92e5
commit 574e8cee41
2 changed files with 74 additions and 84 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip_reass.c,v 1.2 2010/07/19 14:09:45 rmind Exp $ */
/* $NetBSD: ip_reass.c,v 1.3 2010/08/25 00:05:14 rmind Exp $ */
/*
* Copyright (c) 1982, 1986, 1988, 1993
@ -46,7 +46,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ip_reass.c,v 1.2 2010/07/19 14:09:45 rmind Exp $");
__KERNEL_RCSID(0, "$NetBSD: ip_reass.c,v 1.3 2010/08/25 00:05:14 rmind Exp $");
#include <sys/param.h>
#include <sys/types.h>
@ -73,7 +73,32 @@ __KERNEL_RCSID(0, "$NetBSD: ip_reass.c,v 1.2 2010/07/19 14:09:45 rmind Exp $");
#include <netinet/in_var.h>
/*
* IP datagram reassembly hashed queues, pool, lock and counters.
* IP reassembly queue structures. Each fragment being reassembled is
* attached to one of these structures. They are timed out after TTL
* drops to 0, and may also be reclaimed if memory becomes tight.
*/
typedef struct ipfr_qent {
TAILQ_ENTRY(ipfr_qent) ipqe_q;
struct ip * ipqe_ip;
struct mbuf * ipqe_m;
bool ipqe_mff;
} ipfr_qent_t;
typedef struct ipfr_queue {
LIST_ENTRY(ipfr_queue) ipq_q; /* to other reass headers */
TAILQ_HEAD(, ipfr_qent) ipq_fragq; /* queue of fragment entries */
uint8_t ipq_ttl; /* time for reass q to live */
uint8_t ipq_p; /* protocol of this fragment */
uint16_t ipq_id; /* sequence id for reassembly */
struct in_addr ipq_src;
struct in_addr ipq_dst;
uint16_t ipq_nfrags; /* frags in this queue entry */
uint8_t ipq_tos; /* TOS of this fragment */
} ipfr_queue_t;
/*
* Hash table of IP reassembly queues.
*/
#define IPREASS_HASH_SHIFT 6
#define IPREASS_HASH_SIZE (1 << IPREASS_HASH_SHIFT)
@ -81,52 +106,36 @@ __KERNEL_RCSID(0, "$NetBSD: ip_reass.c,v 1.2 2010/07/19 14:09:45 rmind Exp $");
#define IPREASS_HASH(x, y) \
(((((x) & 0xf) | ((((x) >> 8) & 0xf) << 4)) ^ (y)) & IPREASS_HASH_MASK)
struct ipqhead ipq[IPREASS_HASH_SIZE];
struct pool ipqent_pool;
static int ipq_locked;
static LIST_HEAD(, ipfr_queue) ip_frags[IPREASS_HASH_SIZE];
static struct pool ipqent_pool;
static int ipq_locked;
static int ip_nfragpackets; /* packets in reass queue */
static int ip_nfrags; /* total fragments in reass queues */
/* Number of packets in reassembly queue and total number of fragments. */
static int ip_nfragpackets;
static int ip_nfrags;
static int ip_maxfragpackets; /* limit on packets. XXX sysctl */
static int ip_maxfrags; /* limit on fragments. XXX sysctl */
/* Limits on packet and fragments. */
static int ip_maxfragpackets;
static int ip_maxfrags;
/*
* IP reassembly queue structure. Each fragment being reassembled is
* attached to one of these structures. They are timed out after ipq_ttl
* drops to 0, and may also be reclaimed if memory becomes tight.
* Cached copy of nmbclusters. If nbclusters is different, recalculate
* IP parameters derived from nmbclusters.
*/
struct ipq {
LIST_ENTRY(ipq) ipq_q; /* to other reass headers */
uint8_t ipq_ttl; /* time for reass q to live */
uint8_t ipq_p; /* protocol of this fragment */
uint16_t ipq_id; /* sequence id for reassembly */
struct ipqehead ipq_fragq; /* to ip fragment queue */
struct in_addr ipq_src;
struct in_addr ipq_dst;
uint16_t ipq_nfrags; /* frags in this queue entry */
uint8_t ipq_tos; /* TOS of this fragment */
};
/*
* Cached copy of nmbclusters. If nbclusters is different,
* recalculate IP parameters derived from nmbclusters.
*/
static int ip_nmbclusters; /* copy of nmbclusters */
static int ip_nmbclusters;
/*
* IP reassembly TTL machinery for multiplicative drop.
*/
static u_int fragttl_histo[IPFRAGTTL + 1];
static u_int fragttl_histo[IPFRAGTTL + 1];
void sysctl_ip_reass_setup(void);
static void ip_nmbclusters_changed(void);
void sysctl_ip_reass_setup(void);
static void ip_nmbclusters_changed(void);
static struct ipq * ip_reass_lookup(struct ip *, u_int *);
static struct mbuf * ip_reass(struct ipqent *, struct ipq *, u_int);
static struct mbuf * ip_reass(ipfr_qent_t *, ipfr_queue_t *, u_int);
static u_int ip_reass_ttl_decr(u_int ticks);
static void ip_reass_drophalf(void);
static void ip_freef(struct ipq *);
static void ip_freef(ipfr_queue_t *);
/*
* ip_reass_init:
@ -138,11 +147,11 @@ ip_reass_init(void)
{
int i;
pool_init(&ipqent_pool, sizeof(struct ipqent), 0, 0, 0, "ipqepl",
pool_init(&ipqent_pool, sizeof(ipfr_qent_t), 0, 0, 0, "ipqepl",
NULL, IPL_VM);
for (i = 0; i < IPREASS_HASH_SIZE; i++) {
LIST_INIT(&ipq[i]);
LIST_INIT(&ip_frags[i]);
}
ip_maxfragpackets = 200;
ip_maxfrags = 0;
@ -254,34 +263,6 @@ do { \
#define IPQ_UNLOCK() ipq_unlock()
/*
* ip_reass_lookup:
*
* Look for queue of fragments of this datagram.
*/
static struct ipq *
ip_reass_lookup(struct ip *ip, u_int *hashp)
{
struct ipq *fp;
u_int hash;
IPQ_LOCK();
hash = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id);
LIST_FOREACH(fp, &ipq[hash], ipq_q) {
if (ip->ip_id != fp->ipq_id)
continue;
if (!in_hosteq(ip->ip_src, fp->ipq_src))
continue;
if (!in_hosteq(ip->ip_dst, fp->ipq_dst))
continue;
if (ip->ip_p != fp->ipq_p)
continue;
break;
}
*hashp = hash;
return fp;
}
/*
* ip_reass:
*
@ -290,12 +271,11 @@ ip_reass_lookup(struct ip *ip, u_int *hashp)
* then it is given as 'fp'; otherwise have to make a chain.
*/
struct mbuf *
ip_reass(struct ipqent *ipqe, struct ipq *fp, u_int hash)
ip_reass(ipfr_qent_t *ipqe, ipfr_queue_t *fp, const u_int hash)
{
struct ipqhead *ipqhead = &ipq[hash];
const int hlen = ipqe->ipqe_ip->ip_hl << 2;
struct mbuf *m = ipqe->ipqe_m, *t;
struct ipqent *nq, *p, *q;
ipfr_qent_t *nq, *p, *q;
struct ip *ip;
int i, next, s;
@ -338,11 +318,11 @@ ip_reass(struct ipqent *ipqe, struct ipq *fp, u_int hash)
goto dropfrag;
}
ip_nfragpackets++;
fp = malloc(sizeof(struct ipq), M_FTABLE, M_NOWAIT);
fp = malloc(sizeof(ipfr_queue_t), M_FTABLE, M_NOWAIT);
if (fp == NULL) {
goto dropfrag;
}
LIST_INSERT_HEAD(ipqhead, fp, ipq_q);
LIST_INSERT_HEAD(&ip_frags[hash], fp, ipq_q);
fp->ipq_nfrags = 1;
fp->ipq_ttl = IPFRAGTTL;
fp->ipq_p = ipqe->ipqe_ip->ip_p;
@ -510,9 +490,9 @@ dropfrag:
* Free a fragment reassembly header and all associated datagrams.
*/
static void
ip_freef(struct ipq *fp)
ip_freef(ipfr_queue_t *fp)
{
struct ipqent *q, *p;
ipfr_qent_t *q, *p;
u_int nfrags = 0;
int s;
@ -550,14 +530,14 @@ static u_int
ip_reass_ttl_decr(u_int ticks)
{
u_int nfrags, median, dropfraction, keepfraction;
struct ipq *fp, *nfp;
ipfr_queue_t *fp, *nfp;
int i;
nfrags = 0;
memset(fragttl_histo, 0, sizeof(fragttl_histo));
for (i = 0; i < IPREASS_HASH_SIZE; i++) {
for (fp = LIST_FIRST(&ipq[i]); fp != NULL; fp = nfp) {
for (fp = LIST_FIRST(&ip_frags[i]); fp != NULL; fp = nfp) {
fp->ipq_ttl = ((fp->ipq_ttl <= ticks) ?
0 : fp->ipq_ttl - ticks);
nfp = LIST_NEXT(fp, ipq_q);
@ -660,8 +640,8 @@ ip_reass_slowtimo(void)
i = dropscanidx;
while (ip_nfragpackets > ip_maxfragpackets && wrapped == 0) {
while (LIST_FIRST(&ipq[i]) != NULL) {
ip_freef(LIST_FIRST(&ipq[i]));
while (LIST_FIRST(&ip_frags[i]) != NULL) {
ip_freef(LIST_FIRST(&ip_frags[i]));
}
if (++i >= IPREASS_HASH_SIZE) {
i = 0;
@ -691,12 +671,24 @@ ip_reass_slowtimo(void)
int
ip_reass_packet(struct mbuf *m, struct ip *ip, bool mff, struct mbuf **m_final)
{
struct ipq *fp;
struct ipqent *ipqe;
ipfr_queue_t *fp;
ipfr_qent_t *ipqe;
u_int hash;
/* Look for queue of fragments of this datagram. */
fp = ip_reass_lookup(ip, &hash);
IPQ_LOCK();
hash = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id);
LIST_FOREACH(fp, &ip_frags[hash], ipq_q) {
if (ip->ip_id != fp->ipq_id)
continue;
if (!in_hosteq(ip->ip_src, fp->ipq_src))
continue;
if (!in_hosteq(ip->ip_dst, fp->ipq_dst))
continue;
if (ip->ip_p != fp->ipq_p)
continue;
break;
}
/* Make sure that TOS matches previous fragments. */
if (fp && fp->ipq_tos != ip->ip_tos) {

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip_var.h,v 1.94 2010/07/19 19:16:45 rmind Exp $ */
/* $NetBSD: ip_var.h,v 1.95 2010/08/25 00:05:14 rmind Exp $ */
/*
* Copyright (c) 1982, 1986, 1993
@ -49,7 +49,7 @@ struct ipovly {
} __packed;
/*
* Ip (reassembly or sequence) queue structures.
* IP sequence queue structure.
*
* XXX -- The following explains why the ipqe_m field is here, for TCP's use:
* We want to avoid doing m_pullup on incoming packets but that
@ -77,7 +77,6 @@ struct ipqent {
u_int32_t ipqe_len;
u_int32_t ipqe_flags;
};
#define ipqe_ip _ipqe_u1._ip
#define ipqe_tcp _ipqe_u1._tcp
/*
@ -161,7 +160,6 @@ struct ip_moptions {
extern struct domain inetdomain;
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 */