atomic_t ip6_frag_mem = ATOMIC_INIT(0);
/* Memory Tracking Functions. */
-static inline void frag_kfree_skb(struct sk_buff *skb)
+static inline void frag_kfree_skb(struct sk_buff *skb, int *work)
{
+ if (work)
+ *work -= skb->truesize;
atomic_sub(skb->truesize, &ip6_frag_mem);
kfree_skb(skb);
}
-static inline void frag_free_queue(struct frag_queue *fq)
+static inline void frag_free_queue(struct frag_queue *fq, int *work)
{
+ if (work)
+ *work -= sizeof(struct frag_queue);
atomic_sub(sizeof(struct frag_queue), &ip6_frag_mem);
kfree(fq);
}
/* Destruction primitives. */
/* Complete destruction of fq. */
-static void ip6_frag_destroy(struct frag_queue *fq)
+static void ip6_frag_destroy(struct frag_queue *fq, int *work)
{
struct sk_buff *fp;
while (fp) {
struct sk_buff *xp = fp->next;
- frag_kfree_skb(fp);
+ frag_kfree_skb(fp, work);
fp = xp;
}
- frag_free_queue(fq);
+ frag_free_queue(fq, work);
}
-static __inline__ void fq_put(struct frag_queue *fq)
+static __inline__ void fq_put(struct frag_queue *fq, int *work)
{
if (atomic_dec_and_test(&fq->refcnt))
- ip6_frag_destroy(fq);
+ ip6_frag_destroy(fq, work);
}
/* Kill fq entry. It is not destroyed immediately,
{
struct frag_queue *fq;
struct list_head *tmp;
+ int work;
- for(;;) {
- if (atomic_read(&ip6_frag_mem) <= sysctl_ip6frag_low_thresh)
- return;
+ work = atomic_read(&ip6_frag_mem) - sysctl_ip6frag_low_thresh;
+ if (work <= 0)
+ return;
+
+ while(work > 0) {
read_lock(&ip6_frag_lock);
if (list_empty(&ip6_frag_lru_list)) {
read_unlock(&ip6_frag_lock);
fq_kill(fq);
spin_unlock(&fq->lock);
- fq_put(fq);
- IP6_INC_STATS_BH(ReasmFails);
+ fq_put(fq, &work);
+ IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
}
}
fq_kill(fq);
- IP6_INC_STATS_BH(ReasmTimeout);
- IP6_INC_STATS_BH(ReasmFails);
+ IP6_INC_STATS_BH(IPSTATS_MIB_REASMTIMEOUT);
+ IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
/* Send error only if the first segment arrived. */
if (fq->last_in&FIRST_IN && fq->fragments) {
}
out:
spin_unlock(&fq->lock);
- fq_put(fq);
+ fq_put(fq, NULL);
}
/* Creation primitives. */
atomic_inc(&fq->refcnt);
write_unlock(&ip6_frag_lock);
fq_in->last_in |= COMPLETE;
- fq_put(fq_in);
+ fq_put(fq_in, NULL);
return fq;
}
}
return ip6_frag_intern(hash, fq);
oom:
- IP6_INC_STATS_BH(ReasmFails);
+ IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
return NULL;
}
((u8 *) (fhdr + 1) - (u8 *) (skb->nh.ipv6h + 1)));
if ((unsigned int)end > IPV6_MAXPLEN) {
- IP6_INC_STATS_BH(InHdrErrors);
+ IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
icmpv6_param_prob(skb,ICMPV6_HDR_FIELD, (u8*)&fhdr->frag_off - skb->nh.raw);
return;
}
/* RFC2460 says always send parameter problem in
* this case. -DaveM
*/
- IP6_INC_STATS_BH(InHdrErrors);
+ IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
offsetof(struct ipv6hdr, payload_len));
return;
fq->fragments = next;
fq->meat -= free_it->len;
- frag_kfree_skb(free_it);
+ frag_kfree_skb(free_it, NULL);
}
}
return;
err:
- IP6_INC_STATS(ReasmFails);
+ IP6_INC_STATS(IPSTATS_MIB_REASMFAILS);
kfree_skb(skb);
}
head->next = NULL;
head->dev = dev;
head->stamp = fq->stamp;
- head->nh.ipv6h->payload_len = ntohs(payload_len);
+ head->nh.ipv6h->payload_len = htons(payload_len);
*skb_in = head;
if (head->ip_summed == CHECKSUM_HW)
head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum);
- IP6_INC_STATS_BH(ReasmOKs);
+ IP6_INC_STATS_BH(IPSTATS_MIB_REASMOKS);
fq->fragments = NULL;
*nhoffp = nhoff;
return 1;
if (net_ratelimit())
printk(KERN_DEBUG "ip6_frag_reasm: no memory for reassembly\n");
out_fail:
- IP6_INC_STATS_BH(ReasmFails);
+ IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
return -1;
}
hdr = skb->nh.ipv6h;
- IP6_INC_STATS_BH(ReasmReqds);
+ IP6_INC_STATS_BH(IPSTATS_MIB_REASMREQDS);
/* Jumbo payload inhibits frag. header */
if (hdr->payload_len==0) {
- IP6_INC_STATS(InHdrErrors);
+ IP6_INC_STATS(IPSTATS_MIB_INHDRERRORS);
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw);
return -1;
}
if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+sizeof(struct frag_hdr))) {
- IP6_INC_STATS(InHdrErrors);
+ IP6_INC_STATS(IPSTATS_MIB_INHDRERRORS);
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw-skb->nh.raw);
return -1;
}
if (!(fhdr->frag_off & htons(0xFFF9))) {
/* It is not a fragmented frame */
skb->h.raw += sizeof(struct frag_hdr);
- IP6_INC_STATS_BH(ReasmOKs);
+ IP6_INC_STATS_BH(IPSTATS_MIB_REASMOKS);
*nhoffp = (u8*)fhdr - skb->nh.raw;
return 1;
ret = ip6_frag_reasm(fq, skbp, nhoffp, dev);
spin_unlock(&fq->lock);
- fq_put(fq);
+ fq_put(fq, NULL);
return ret;
}
- IP6_INC_STATS_BH(ReasmFails);
+ IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
kfree_skb(skb);
return -1;
}