tuntap: limit the number of flow caches

We create new flow caches when a new flow is identified by tuntap, This may lead
some issues:

- userspace may produce a huge amount of short live flows to exhaust host memory
- the unlimited number of flow caches may produce a long list which increase the
  time in the linear searching

Solve this by introducing a limit of total number of flow caches.

Cc: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Jason Wang 2013-01-23 03:59:13 +00:00 committed by David S. Miller
parent edfb6a148c
commit b8732fb7f8

View File

@ -113,6 +113,7 @@ struct tap_filter {
* the netdevice to be fit in one page. So we can make sure the success of * the netdevice to be fit in one page. So we can make sure the success of
* memory allocation. TODO: increase the limit. */ * memory allocation. TODO: increase the limit. */
#define MAX_TAP_QUEUES DEFAULT_MAX_NUM_RSS_QUEUES #define MAX_TAP_QUEUES DEFAULT_MAX_NUM_RSS_QUEUES
#define MAX_TAP_FLOWS 4096
#define TUN_FLOW_EXPIRE (3 * HZ) #define TUN_FLOW_EXPIRE (3 * HZ)
@ -185,6 +186,7 @@ struct tun_struct {
unsigned int numdisabled; unsigned int numdisabled;
struct list_head disabled; struct list_head disabled;
void *security; void *security;
u32 flow_count;
}; };
static inline u32 tun_hashfn(u32 rxhash) static inline u32 tun_hashfn(u32 rxhash)
@ -218,6 +220,7 @@ static struct tun_flow_entry *tun_flow_create(struct tun_struct *tun,
e->queue_index = queue_index; e->queue_index = queue_index;
e->tun = tun; e->tun = tun;
hlist_add_head_rcu(&e->hash_link, head); hlist_add_head_rcu(&e->hash_link, head);
++tun->flow_count;
} }
return e; return e;
} }
@ -228,6 +231,7 @@ static void tun_flow_delete(struct tun_struct *tun, struct tun_flow_entry *e)
e->rxhash, e->queue_index); e->rxhash, e->queue_index);
hlist_del_rcu(&e->hash_link); hlist_del_rcu(&e->hash_link);
kfree_rcu(e, rcu); kfree_rcu(e, rcu);
--tun->flow_count;
} }
static void tun_flow_flush(struct tun_struct *tun) static void tun_flow_flush(struct tun_struct *tun)
@ -317,7 +321,8 @@ static void tun_flow_update(struct tun_struct *tun, u32 rxhash,
e->updated = jiffies; e->updated = jiffies;
} else { } else {
spin_lock_bh(&tun->lock); spin_lock_bh(&tun->lock);
if (!tun_flow_find(head, rxhash)) if (!tun_flow_find(head, rxhash) &&
tun->flow_count < MAX_TAP_FLOWS)
tun_flow_create(tun, head, rxhash, queue_index); tun_flow_create(tun, head, rxhash, queue_index);
if (!timer_pending(&tun->flow_gc_timer)) if (!timer_pending(&tun->flow_gc_timer))