o Since we always update either fragdrop or fragtimeout stat counter when we

free a fragment, provide two inline functions that do that for us:
  ipq_drop() and ipq_timeout().
o Rename ip_free_f() to ipq_free() to match the name scheme of IP reassembly.
o Remove assertion from ipq_free(), since it requires extra argument to be
  passed, but locking scheme is simple enough and function is static.

Sponsored by:	Nginx, Inc.
This commit is contained in:
glebius 2015-04-09 08:52:02 +00:00
parent 89392dc82f
commit ddd581998f

View File

@ -177,11 +177,27 @@ static struct mtx_padalign ipqlock[IPREASS_NHASH];
#define IPQ_LOCK(i) mtx_lock(&ipqlock[(i)])
#define IPQ_UNLOCK(i) mtx_unlock(&ipqlock[(i)])
#define IPQ_LOCK_INIT(i) mtx_init(&ipqlock[(i)], "ipqlock", NULL, MTX_DEF)
#define IPQ_LOCK_ASSERT(i) mtx_assert(&ipqlock[(i)], MA_OWNED)
static void maxnipq_update(void);
static void ipq_zone_change(void *);
static void ip_drain_vnet(void);
static void ipq_free(struct ipqhead *, struct ipq *);
static inline void
ipq_timeout(struct ipqhead *head, struct ipq *fp)
{
IPSTAT_ADD(ips_fragtimeout, fp->ipq_nfrags);
ipq_free(head, fp);
}
static inline void
ipq_drop(struct ipqhead *head, struct ipq *fp)
{
IPSTAT_ADD(ips_fragdropped, fp->ipq_nfrags);
ipq_free(head, fp);
}
static VNET_DEFINE(int, maxnipq); /* Administrative limit on # reass queues. */
static VNET_DEFINE(int, nipq); /* Total # of reass queues */
@ -209,8 +225,6 @@ SYSCTL_INT(_net_inet_ip, OID_AUTO, stealth, CTLFLAG_VNET | CTLFLAG_RW,
"IP stealth mode, no TTL decrementation on forwarding");
#endif
static void ip_freef(struct ipqhead *, int, struct ipq *);
/*
* IP statistics are stored in the "array" of counter(9)s.
*/
@ -881,9 +895,7 @@ ip_reass_purge_element(int skip_bucket)
IPQ_LOCK(i);
r = TAILQ_LAST(&V_ipq[i], ipqhead);
if (r) {
IPSTAT_ADD(ips_fragtimeout,
r->ipq_nfrags);
ip_freef(&V_ipq[i], i, r);
ipq_timeout(&V_ipq[i], r);
IPQ_UNLOCK(i);
return (i);
}
@ -964,10 +976,8 @@ ip_reass(struct mbuf *m)
* lock is no longer held.
*/
do_purge = 1;
} else {
IPSTAT_ADD(ips_fragtimeout, q->ipq_nfrags);
ip_freef(head, hash, q);
}
} else
ipq_timeout(head, q);
}
found:
@ -1125,20 +1135,16 @@ ip_reass(struct mbuf *m)
next = 0;
for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) {
if (ntohs(GETIP(q)->ip_off) != next) {
if (fp->ipq_nfrags > V_maxfragsperpacket) {
IPSTAT_ADD(ips_fragdropped, fp->ipq_nfrags);
ip_freef(head, hash, fp);
}
if (fp->ipq_nfrags > V_maxfragsperpacket)
ipq_drop(head, fp);
goto done;
}
next += ntohs(GETIP(q)->ip_len);
}
/* Make sure the last packet didn't have the IP_MF flag */
if (p->m_flags & M_IP_FRAG) {
if (fp->ipq_nfrags > V_maxfragsperpacket) {
IPSTAT_ADD(ips_fragdropped, fp->ipq_nfrags);
ip_freef(head, hash, fp);
}
if (fp->ipq_nfrags > V_maxfragsperpacket)
ipq_drop(head, fp);
goto done;
}
@ -1149,8 +1155,7 @@ ip_reass(struct mbuf *m)
ip = GETIP(q);
if (next + (ip->ip_hl << 2) > IP_MAXPACKET) {
IPSTAT_INC(ips_toolong);
IPSTAT_ADD(ips_fragdropped, fp->ipq_nfrags);
ip_freef(head, hash, fp);
ipq_drop(head, fp);
goto done;
}
@ -1266,12 +1271,10 @@ ip_reass(struct mbuf *m)
* associated datagrams.
*/
static void
ip_freef(struct ipqhead *fhp, int i, struct ipq *fp)
ipq_free(struct ipqhead *fhp, struct ipq *fp)
{
struct mbuf *q;
IPQ_LOCK_ASSERT(i);
while (fp->ipq_frags) {
q = fp->ipq_frags;
fp->ipq_frags = q->m_nextpkt;
@ -1304,11 +1307,8 @@ ip_slowtimo(void)
fpp = fp;
fp = TAILQ_NEXT(fp, ipq_list);
if(--fpp->ipq_ttl == 0) {
IPSTAT_ADD(ips_fragtimeout,
fpp->ipq_nfrags);
ip_freef(&V_ipq[i], i, fpp);
}
if(--fpp->ipq_ttl == 0)
ipq_timeout(&V_ipq[i], fpp);
}
IPQ_UNLOCK(i);
}
@ -1321,13 +1321,9 @@ ip_slowtimo(void)
for (i = 0; i < IPREASS_NHASH; i++) {
IPQ_LOCK(i);
while (V_nipq > V_maxnipq &&
!TAILQ_EMPTY(&V_ipq[i])) {
IPSTAT_ADD(ips_fragdropped,
TAILQ_FIRST(&V_ipq[i])->ipq_nfrags);
ip_freef(&V_ipq[i],
i,
!TAILQ_EMPTY(&V_ipq[i]))
ipq_drop(&V_ipq[i],
TAILQ_FIRST(&V_ipq[i]));
}
IPQ_UNLOCK(i);
}
}
@ -1346,11 +1342,8 @@ ip_drain_vnet(void)
for (i = 0; i < IPREASS_NHASH; i++) {
IPQ_LOCK(i);
while(!TAILQ_EMPTY(&V_ipq[i])) {
IPSTAT_ADD(ips_fragdropped,
TAILQ_FIRST(&V_ipq[i])->ipq_nfrags);
ip_freef(&V_ipq[i], i, TAILQ_FIRST(&V_ipq[i]));
}
while(!TAILQ_EMPTY(&V_ipq[i]))
ipq_drop(&V_ipq[i], TAILQ_FIRST(&V_ipq[i]));
IPQ_UNLOCK(i);
}
}