mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
1280938465
[ Upstream commit 5a3da1fe95
]
This patch introduces a constant limit of the fragment queue hash
table bucket list lengths. Currently the limit 128 is choosen somewhat
arbitrary and just ensures that we can fill up the fragment cache with
empty packets up to the default ip_frag_high_thresh limits. It should
just protect from list iteration eating considerable amounts of cpu.
If we reach the maximum length in one hash bucket a warning is printed.
This is implemented on the caller side of inet_frag_find to distinguish
between the different users of inet_fragment.c.
I dropped the out of memory warning in the ipv4 fragment lookup path,
because we already get a warning by the slab allocator.
Cc: Eric Dumazet <eric.dumazet@gmail.com>
Cc: Jesper Dangaard Brouer <jbrouer@redhat.com>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Acked-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
83 lines
2.3 KiB
C
83 lines
2.3 KiB
C
#ifndef __NET_FRAG_H__
|
|
#define __NET_FRAG_H__
|
|
|
|
struct netns_frags {
|
|
int nqueues;
|
|
atomic_t mem;
|
|
struct list_head lru_list;
|
|
|
|
/* sysctls */
|
|
int timeout;
|
|
int high_thresh;
|
|
int low_thresh;
|
|
};
|
|
|
|
struct inet_frag_queue {
|
|
struct hlist_node list;
|
|
struct netns_frags *net;
|
|
struct list_head lru_list; /* lru list member */
|
|
spinlock_t lock;
|
|
atomic_t refcnt;
|
|
struct timer_list timer; /* when will this queue expire? */
|
|
struct sk_buff *fragments; /* list of received fragments */
|
|
struct sk_buff *fragments_tail;
|
|
ktime_t stamp;
|
|
int len; /* total length of orig datagram */
|
|
int meat;
|
|
__u8 last_in; /* first/last segment arrived? */
|
|
|
|
#define INET_FRAG_COMPLETE 4
|
|
#define INET_FRAG_FIRST_IN 2
|
|
#define INET_FRAG_LAST_IN 1
|
|
};
|
|
|
|
#define INETFRAGS_HASHSZ 64
|
|
|
|
/* averaged:
|
|
* max_depth = default ipfrag_high_thresh / INETFRAGS_HASHSZ /
|
|
* rounded up (SKB_TRUELEN(0) + sizeof(struct ipq or
|
|
* struct frag_queue))
|
|
*/
|
|
#define INETFRAGS_MAXDEPTH 128
|
|
|
|
struct inet_frags {
|
|
struct hlist_head hash[INETFRAGS_HASHSZ];
|
|
rwlock_t lock;
|
|
u32 rnd;
|
|
int qsize;
|
|
int secret_interval;
|
|
struct timer_list secret_timer;
|
|
|
|
unsigned int (*hashfn)(struct inet_frag_queue *);
|
|
void (*constructor)(struct inet_frag_queue *q,
|
|
void *arg);
|
|
void (*destructor)(struct inet_frag_queue *);
|
|
void (*skb_free)(struct sk_buff *);
|
|
int (*match)(struct inet_frag_queue *q,
|
|
void *arg);
|
|
void (*frag_expire)(unsigned long data);
|
|
};
|
|
|
|
void inet_frags_init(struct inet_frags *);
|
|
void inet_frags_fini(struct inet_frags *);
|
|
|
|
void inet_frags_init_net(struct netns_frags *nf);
|
|
void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f);
|
|
|
|
void inet_frag_kill(struct inet_frag_queue *q, struct inet_frags *f);
|
|
void inet_frag_destroy(struct inet_frag_queue *q,
|
|
struct inet_frags *f, int *work);
|
|
int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f);
|
|
struct inet_frag_queue *inet_frag_find(struct netns_frags *nf,
|
|
struct inet_frags *f, void *key, unsigned int hash)
|
|
__releases(&f->lock);
|
|
void inet_frag_maybe_warn_overflow(struct inet_frag_queue *q,
|
|
const char *prefix);
|
|
|
|
static inline void inet_frag_put(struct inet_frag_queue *q, struct inet_frags *f)
|
|
{
|
|
if (atomic_dec_and_test(&q->refcnt))
|
|
inet_frag_destroy(q, f, NULL);
|
|
}
|
|
|
|
#endif
|