aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/netns/xfrm.h6
-rw-r--r--net/xfrm/xfrm_policy.c57
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
9struct xfrm_policy_hash {
10 struct hlist_head *table;
11 unsigned int hmask;
12};
13
9struct netns_xfrm { 14struct 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
325struct xfrm_policy_hash {
326 struct hlist_head *table;
327 unsigned int hmask;
328};
329
330static struct xfrm_policy_hash xfrm_policy_bydst[XFRM_POLICY_MAX*2] __read_mostly;
331static unsigned int xfrm_policy_hashmax __read_mostly = 1 * 1024 * 1024; 325static unsigned int xfrm_policy_hashmax __read_mostly = 1 * 1024 * 1024;
332 326
333static inline unsigned int idx_hash(u32 index) 327static inline unsigned int idx_hash(u32 index)
@@ -337,20 +331,20 @@ static inline unsigned int idx_hash(u32 index)
337 331
338static struct hlist_head *policy_hash_bysel(struct xfrm_selector *sel, unsigned short family, int dir) 332static 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
348static struct hlist_head *policy_hash_direct(xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family, int dir) 342static 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
356static void xfrm_dst_hash_transfer(struct hlist_head *list, 350static 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
408static void xfrm_bydst_resize(int dir) 402static 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)
458static inline int xfrm_bydst_should_resize(int dir, int *total) 452static 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
2424out_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);
2430out_byidx: 2432out_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);