diff options
-rw-r--r-- | include/net/netns/xfrm.h | 6 | ||||
-rw-r--r-- | net/xfrm/xfrm_policy.c | 57 |
2 files changed, 39 insertions, 24 deletions
diff --git a/include/net/netns/xfrm.h b/include/net/netns/xfrm.h index c7568315f16c..39cfa799fa90 100644 --- a/include/net/netns/xfrm.h +++ b/include/net/netns/xfrm.h | |||
@@ -6,6 +6,11 @@ | |||
6 | #include <linux/workqueue.h> | 6 | #include <linux/workqueue.h> |
7 | #include <linux/xfrm.h> | 7 | #include <linux/xfrm.h> |
8 | 8 | ||
9 | struct xfrm_policy_hash { | ||
10 | struct hlist_head *table; | ||
11 | unsigned int hmask; | ||
12 | }; | ||
13 | |||
9 | struct netns_xfrm { | 14 | struct netns_xfrm { |
10 | struct list_head state_all; | 15 | struct list_head state_all; |
11 | /* | 16 | /* |
@@ -31,6 +36,7 @@ struct netns_xfrm { | |||
31 | struct hlist_head *policy_byidx; | 36 | struct hlist_head *policy_byidx; |
32 | unsigned int policy_idx_hmask; | 37 | unsigned int policy_idx_hmask; |
33 | struct hlist_head policy_inexact[XFRM_POLICY_MAX * 2]; | 38 | struct hlist_head policy_inexact[XFRM_POLICY_MAX * 2]; |
39 | struct xfrm_policy_hash policy_bydst[XFRM_POLICY_MAX * 2]; | ||
34 | }; | 40 | }; |
35 | 41 | ||
36 | #endif | 42 | #endif |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index ba4e95b8e24e..929b2fdaa2ef 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -322,12 +322,6 @@ static void xfrm_policy_kill(struct xfrm_policy *policy) | |||
322 | schedule_work(&xfrm_policy_gc_work); | 322 | schedule_work(&xfrm_policy_gc_work); |
323 | } | 323 | } |
324 | 324 | ||
325 | struct xfrm_policy_hash { | ||
326 | struct hlist_head *table; | ||
327 | unsigned int hmask; | ||
328 | }; | ||
329 | |||
330 | static struct xfrm_policy_hash xfrm_policy_bydst[XFRM_POLICY_MAX*2] __read_mostly; | ||
331 | static unsigned int xfrm_policy_hashmax __read_mostly = 1 * 1024 * 1024; | 325 | static unsigned int xfrm_policy_hashmax __read_mostly = 1 * 1024 * 1024; |
332 | 326 | ||
333 | static inline unsigned int idx_hash(u32 index) | 327 | static inline unsigned int idx_hash(u32 index) |
@@ -337,20 +331,20 @@ static inline unsigned int idx_hash(u32 index) | |||
337 | 331 | ||
338 | static struct hlist_head *policy_hash_bysel(struct xfrm_selector *sel, unsigned short family, int dir) | 332 | static struct hlist_head *policy_hash_bysel(struct xfrm_selector *sel, unsigned short family, int dir) |
339 | { | 333 | { |
340 | unsigned int hmask = xfrm_policy_bydst[dir].hmask; | 334 | unsigned int hmask = init_net.xfrm.policy_bydst[dir].hmask; |
341 | unsigned int hash = __sel_hash(sel, family, hmask); | 335 | unsigned int hash = __sel_hash(sel, family, hmask); |
342 | 336 | ||
343 | return (hash == hmask + 1 ? | 337 | return (hash == hmask + 1 ? |
344 | &init_net.xfrm.policy_inexact[dir] : | 338 | &init_net.xfrm.policy_inexact[dir] : |
345 | xfrm_policy_bydst[dir].table + hash); | 339 | init_net.xfrm.policy_bydst[dir].table + hash); |
346 | } | 340 | } |
347 | 341 | ||
348 | static struct hlist_head *policy_hash_direct(xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family, int dir) | 342 | static struct hlist_head *policy_hash_direct(xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family, int dir) |
349 | { | 343 | { |
350 | unsigned int hmask = xfrm_policy_bydst[dir].hmask; | 344 | unsigned int hmask = init_net.xfrm.policy_bydst[dir].hmask; |
351 | unsigned int hash = __addr_hash(daddr, saddr, family, hmask); | 345 | unsigned int hash = __addr_hash(daddr, saddr, family, hmask); |
352 | 346 | ||
353 | return xfrm_policy_bydst[dir].table + hash; | 347 | return init_net.xfrm.policy_bydst[dir].table + hash; |
354 | } | 348 | } |
355 | 349 | ||
356 | static void xfrm_dst_hash_transfer(struct hlist_head *list, | 350 | static void xfrm_dst_hash_transfer(struct hlist_head *list, |
@@ -407,10 +401,10 @@ static unsigned long xfrm_new_hash_mask(unsigned int old_hmask) | |||
407 | 401 | ||
408 | static void xfrm_bydst_resize(int dir) | 402 | static void xfrm_bydst_resize(int dir) |
409 | { | 403 | { |
410 | unsigned int hmask = xfrm_policy_bydst[dir].hmask; | 404 | unsigned int hmask = init_net.xfrm.policy_bydst[dir].hmask; |
411 | unsigned int nhashmask = xfrm_new_hash_mask(hmask); | 405 | unsigned int nhashmask = xfrm_new_hash_mask(hmask); |
412 | unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head); | 406 | unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head); |
413 | struct hlist_head *odst = xfrm_policy_bydst[dir].table; | 407 | struct hlist_head *odst = init_net.xfrm.policy_bydst[dir].table; |
414 | struct hlist_head *ndst = xfrm_hash_alloc(nsize); | 408 | struct hlist_head *ndst = xfrm_hash_alloc(nsize); |
415 | int i; | 409 | int i; |
416 | 410 | ||
@@ -422,8 +416,8 @@ static void xfrm_bydst_resize(int dir) | |||
422 | for (i = hmask; i >= 0; i--) | 416 | for (i = hmask; i >= 0; i--) |
423 | xfrm_dst_hash_transfer(odst + i, ndst, nhashmask); | 417 | xfrm_dst_hash_transfer(odst + i, ndst, nhashmask); |
424 | 418 | ||
425 | xfrm_policy_bydst[dir].table = ndst; | 419 | init_net.xfrm.policy_bydst[dir].table = ndst; |
426 | xfrm_policy_bydst[dir].hmask = nhashmask; | 420 | init_net.xfrm.policy_bydst[dir].hmask = nhashmask; |
427 | 421 | ||
428 | write_unlock_bh(&xfrm_policy_lock); | 422 | write_unlock_bh(&xfrm_policy_lock); |
429 | 423 | ||
@@ -458,7 +452,7 @@ static void xfrm_byidx_resize(int total) | |||
458 | static inline int xfrm_bydst_should_resize(int dir, int *total) | 452 | static inline int xfrm_bydst_should_resize(int dir, int *total) |
459 | { | 453 | { |
460 | unsigned int cnt = xfrm_policy_count[dir]; | 454 | unsigned int cnt = xfrm_policy_count[dir]; |
461 | unsigned int hmask = xfrm_policy_bydst[dir].hmask; | 455 | unsigned int hmask = init_net.xfrm.policy_bydst[dir].hmask; |
462 | 456 | ||
463 | if (total) | 457 | if (total) |
464 | *total += cnt; | 458 | *total += cnt; |
@@ -763,9 +757,9 @@ xfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info) | |||
763 | return err; | 757 | return err; |
764 | } | 758 | } |
765 | } | 759 | } |
766 | for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) { | 760 | for (i = init_net.xfrm.policy_bydst[dir].hmask; i >= 0; i--) { |
767 | hlist_for_each_entry(pol, entry, | 761 | hlist_for_each_entry(pol, entry, |
768 | xfrm_policy_bydst[dir].table + i, | 762 | init_net.xfrm.policy_bydst[dir].table + i, |
769 | bydst) { | 763 | bydst) { |
770 | if (pol->type != type) | 764 | if (pol->type != type) |
771 | continue; | 765 | continue; |
@@ -827,10 +821,10 @@ int xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info) | |||
827 | goto again1; | 821 | goto again1; |
828 | } | 822 | } |
829 | 823 | ||
830 | for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) { | 824 | for (i = init_net.xfrm.policy_bydst[dir].hmask; i >= 0; i--) { |
831 | again2: | 825 | again2: |
832 | hlist_for_each_entry(pol, entry, | 826 | hlist_for_each_entry(pol, entry, |
833 | xfrm_policy_bydst[dir].table + i, | 827 | init_net.xfrm.policy_bydst[dir].table + i, |
834 | bydst) { | 828 | bydst) { |
835 | if (pol->type != type) | 829 | if (pol->type != type) |
836 | continue; | 830 | continue; |
@@ -2154,8 +2148,8 @@ static void xfrm_prune_bundles(int (*func)(struct dst_entry *)) | |||
2154 | &init_net.xfrm.policy_inexact[dir], bydst) | 2148 | &init_net.xfrm.policy_inexact[dir], bydst) |
2155 | prune_one_bundle(pol, func, &gc_list); | 2149 | prune_one_bundle(pol, func, &gc_list); |
2156 | 2150 | ||
2157 | table = xfrm_policy_bydst[dir].table; | 2151 | table = init_net.xfrm.policy_bydst[dir].table; |
2158 | for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) { | 2152 | for (i = init_net.xfrm.policy_bydst[dir].hmask; i >= 0; i--) { |
2159 | hlist_for_each_entry(pol, entry, table + i, bydst) | 2153 | hlist_for_each_entry(pol, entry, table + i, bydst) |
2160 | prune_one_bundle(pol, func, &gc_list); | 2154 | prune_one_bundle(pol, func, &gc_list); |
2161 | } | 2155 | } |
@@ -2415,11 +2409,11 @@ static int __net_init xfrm_policy_init(struct net *net) | |||
2415 | 2409 | ||
2416 | INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]); | 2410 | INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]); |
2417 | 2411 | ||
2418 | htab = &xfrm_policy_bydst[dir]; | 2412 | htab = &net->xfrm.policy_bydst[dir]; |
2419 | htab->table = xfrm_hash_alloc(sz); | 2413 | htab->table = xfrm_hash_alloc(sz); |
2420 | htab->hmask = hmask; | ||
2421 | if (!htab->table) | 2414 | if (!htab->table) |
2422 | panic("XFRM: failed to allocate bydst hash\n"); | 2415 | goto out_bydst; |
2416 | htab->hmask = hmask; | ||
2423 | } | 2417 | } |
2424 | 2418 | ||
2425 | INIT_LIST_HEAD(&net->xfrm.policy_all); | 2419 | INIT_LIST_HEAD(&net->xfrm.policy_all); |
@@ -2427,6 +2421,14 @@ static int __net_init xfrm_policy_init(struct net *net) | |||
2427 | register_netdevice_notifier(&xfrm_dev_notifier); | 2421 | register_netdevice_notifier(&xfrm_dev_notifier); |
2428 | return 0; | 2422 | return 0; |
2429 | 2423 | ||
2424 | out_bydst: | ||
2425 | for (dir--; dir >= 0; dir--) { | ||
2426 | struct xfrm_policy_hash *htab; | ||
2427 | |||
2428 | htab = &net->xfrm.policy_bydst[dir]; | ||
2429 | xfrm_hash_free(htab->table, sz); | ||
2430 | } | ||
2431 | xfrm_hash_free(net->xfrm.policy_byidx, sz); | ||
2430 | out_byidx: | 2432 | out_byidx: |
2431 | return -ENOMEM; | 2433 | return -ENOMEM; |
2432 | } | 2434 | } |
@@ -2439,7 +2441,14 @@ static void xfrm_policy_fini(struct net *net) | |||
2439 | WARN_ON(!list_empty(&net->xfrm.policy_all)); | 2441 | WARN_ON(!list_empty(&net->xfrm.policy_all)); |
2440 | 2442 | ||
2441 | for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { | 2443 | for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { |
2444 | struct xfrm_policy_hash *htab; | ||
2445 | |||
2442 | WARN_ON(!hlist_empty(&net->xfrm.policy_inexact[dir])); | 2446 | WARN_ON(!hlist_empty(&net->xfrm.policy_inexact[dir])); |
2447 | |||
2448 | htab = &net->xfrm.policy_bydst[dir]; | ||
2449 | sz = (htab->hmask + 1); | ||
2450 | WARN_ON(!hlist_empty(htab->table)); | ||
2451 | xfrm_hash_free(htab->table, sz); | ||
2443 | } | 2452 | } |
2444 | 2453 | ||
2445 | sz = (net->xfrm.policy_idx_hmask + 1) * sizeof(struct hlist_head); | 2454 | sz = (net->xfrm.policy_idx_hmask + 1) * sizeof(struct hlist_head); |