diff options
| author | Jason Wang <jasowang@redhat.com> | 2013-01-22 22:59:13 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2013-01-23 13:47:06 -0500 |
| commit | b8732fb7f8920e2f6216d2b67faf8b0b0d67ca81 (patch) | |
| tree | 9e4f5052cea423ec1302e2175211d58adee0e300 | |
| parent | edfb6a148ce62e5e19354a1dcd9a34e00815c2a1 (diff) | |
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>
| -rw-r--r-- | drivers/net/tun.c | 7 |
1 files changed, 6 insertions, 1 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 8939d2117de2..cc09b67c23bc 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
| @@ -113,6 +113,7 @@ struct tap_filter { | |||
| 113 | * the netdevice to be fit in one page. So we can make sure the success of | 113 | * the netdevice to be fit in one page. So we can make sure the success of |
| 114 | * memory allocation. TODO: increase the limit. */ | 114 | * memory allocation. TODO: increase the limit. */ |
| 115 | #define MAX_TAP_QUEUES DEFAULT_MAX_NUM_RSS_QUEUES | 115 | #define MAX_TAP_QUEUES DEFAULT_MAX_NUM_RSS_QUEUES |
| 116 | #define MAX_TAP_FLOWS 4096 | ||
| 116 | 117 | ||
| 117 | #define TUN_FLOW_EXPIRE (3 * HZ) | 118 | #define TUN_FLOW_EXPIRE (3 * HZ) |
| 118 | 119 | ||
| @@ -185,6 +186,7 @@ struct tun_struct { | |||
| 185 | unsigned int numdisabled; | 186 | unsigned int numdisabled; |
| 186 | struct list_head disabled; | 187 | struct list_head disabled; |
| 187 | void *security; | 188 | void *security; |
| 189 | u32 flow_count; | ||
| 188 | }; | 190 | }; |
| 189 | 191 | ||
| 190 | static inline u32 tun_hashfn(u32 rxhash) | 192 | static inline u32 tun_hashfn(u32 rxhash) |
| @@ -218,6 +220,7 @@ static struct tun_flow_entry *tun_flow_create(struct tun_struct *tun, | |||
| 218 | e->queue_index = queue_index; | 220 | e->queue_index = queue_index; |
| 219 | e->tun = tun; | 221 | e->tun = tun; |
| 220 | hlist_add_head_rcu(&e->hash_link, head); | 222 | hlist_add_head_rcu(&e->hash_link, head); |
| 223 | ++tun->flow_count; | ||
| 221 | } | 224 | } |
| 222 | return e; | 225 | return e; |
| 223 | } | 226 | } |
| @@ -228,6 +231,7 @@ static void tun_flow_delete(struct tun_struct *tun, struct tun_flow_entry *e) | |||
| 228 | e->rxhash, e->queue_index); | 231 | e->rxhash, e->queue_index); |
| 229 | hlist_del_rcu(&e->hash_link); | 232 | hlist_del_rcu(&e->hash_link); |
| 230 | kfree_rcu(e, rcu); | 233 | kfree_rcu(e, rcu); |
| 234 | --tun->flow_count; | ||
| 231 | } | 235 | } |
| 232 | 236 | ||
| 233 | static void tun_flow_flush(struct tun_struct *tun) | 237 | static void tun_flow_flush(struct tun_struct *tun) |
| @@ -317,7 +321,8 @@ static void tun_flow_update(struct tun_struct *tun, u32 rxhash, | |||
| 317 | e->updated = jiffies; | 321 | e->updated = jiffies; |
| 318 | } else { | 322 | } else { |
| 319 | spin_lock_bh(&tun->lock); | 323 | spin_lock_bh(&tun->lock); |
| 320 | if (!tun_flow_find(head, rxhash)) | 324 | if (!tun_flow_find(head, rxhash) && |
| 325 | tun->flow_count < MAX_TAP_FLOWS) | ||
| 321 | tun_flow_create(tun, head, rxhash, queue_index); | 326 | tun_flow_create(tun, head, rxhash, queue_index); |
| 322 | 327 | ||
| 323 | if (!timer_pending(&tun->flow_gc_timer)) | 328 | if (!timer_pending(&tun->flow_gc_timer)) |
