aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm/xfrm_policy.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-09-28 17:19:15 -0400
committerDavid S. Miller <davem@davemloft.net>2014-09-28 17:19:15 -0400
commitf5c7e1a47aeca2b31106aa94e7f4daa218e6c478 (patch)
treea5a0ed3429f83d7404dc4d8fe19ac060d6ddb307 /net/xfrm/xfrm_policy.c
parentfe2c5fb1ef24e97b7cf96e24200bbe503286cb95 (diff)
parent689f1c9de2abbd76fda224d12cea5f43568a4335 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next
Steffen Klassert says: ==================== pull request (net-next): ipsec-next 2014-09-25 1) Remove useless hash_resize_mutex in xfrm_hash_resize(). This mutex is used only there, but xfrm_hash_resize() can't be called concurrently at all. From Ying Xue. 2) Extend policy hashing to prefixed policies based on prefix lenght thresholds. From Christophe Gouault. 3) Make the policy hash table thresholds configurable via netlink. From Christophe Gouault. 4) Remove the maximum authentication length for AH. This was needed to limit stack usage. We switched already to allocate space, so no need to keep the limit. From Herbert Xu. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/xfrm/xfrm_policy.c')
-rw-r--r--net/xfrm/xfrm_policy.c140
1 files changed, 134 insertions, 6 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index fdde51f4271a..f623dca6ce30 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -349,12 +349,39 @@ static inline unsigned int idx_hash(struct net *net, u32 index)
349 return __idx_hash(index, net->xfrm.policy_idx_hmask); 349 return __idx_hash(index, net->xfrm.policy_idx_hmask);
350} 350}
351 351
352/* calculate policy hash thresholds */
353static void __get_hash_thresh(struct net *net,
354 unsigned short family, int dir,
355 u8 *dbits, u8 *sbits)
356{
357 switch (family) {
358 case AF_INET:
359 *dbits = net->xfrm.policy_bydst[dir].dbits4;
360 *sbits = net->xfrm.policy_bydst[dir].sbits4;
361 break;
362
363 case AF_INET6:
364 *dbits = net->xfrm.policy_bydst[dir].dbits6;
365 *sbits = net->xfrm.policy_bydst[dir].sbits6;
366 break;
367
368 default:
369 *dbits = 0;
370 *sbits = 0;
371 }
372}
373
352static struct hlist_head *policy_hash_bysel(struct net *net, 374static struct hlist_head *policy_hash_bysel(struct net *net,
353 const struct xfrm_selector *sel, 375 const struct xfrm_selector *sel,
354 unsigned short family, int dir) 376 unsigned short family, int dir)
355{ 377{
356 unsigned int hmask = net->xfrm.policy_bydst[dir].hmask; 378 unsigned int hmask = net->xfrm.policy_bydst[dir].hmask;
357 unsigned int hash = __sel_hash(sel, family, hmask); 379 unsigned int hash;
380 u8 dbits;
381 u8 sbits;
382
383 __get_hash_thresh(net, family, dir, &dbits, &sbits);
384 hash = __sel_hash(sel, family, hmask, dbits, sbits);
358 385
359 return (hash == hmask + 1 ? 386 return (hash == hmask + 1 ?
360 &net->xfrm.policy_inexact[dir] : 387 &net->xfrm.policy_inexact[dir] :
@@ -367,25 +394,35 @@ static struct hlist_head *policy_hash_direct(struct net *net,
367 unsigned short family, int dir) 394 unsigned short family, int dir)
368{ 395{
369 unsigned int hmask = net->xfrm.policy_bydst[dir].hmask; 396 unsigned int hmask = net->xfrm.policy_bydst[dir].hmask;
370 unsigned int hash = __addr_hash(daddr, saddr, family, hmask); 397 unsigned int hash;
398 u8 dbits;
399 u8 sbits;
400
401 __get_hash_thresh(net, family, dir, &dbits, &sbits);
402 hash = __addr_hash(daddr, saddr, family, hmask, dbits, sbits);
371 403
372 return net->xfrm.policy_bydst[dir].table + hash; 404 return net->xfrm.policy_bydst[dir].table + hash;
373} 405}
374 406
375static void xfrm_dst_hash_transfer(struct hlist_head *list, 407static void xfrm_dst_hash_transfer(struct net *net,
408 struct hlist_head *list,
376 struct hlist_head *ndsttable, 409 struct hlist_head *ndsttable,
377 unsigned int nhashmask) 410 unsigned int nhashmask,
411 int dir)
378{ 412{
379 struct hlist_node *tmp, *entry0 = NULL; 413 struct hlist_node *tmp, *entry0 = NULL;
380 struct xfrm_policy *pol; 414 struct xfrm_policy *pol;
381 unsigned int h0 = 0; 415 unsigned int h0 = 0;
416 u8 dbits;
417 u8 sbits;
382 418
383redo: 419redo:
384 hlist_for_each_entry_safe(pol, tmp, list, bydst) { 420 hlist_for_each_entry_safe(pol, tmp, list, bydst) {
385 unsigned int h; 421 unsigned int h;
386 422
423 __get_hash_thresh(net, pol->family, dir, &dbits, &sbits);
387 h = __addr_hash(&pol->selector.daddr, &pol->selector.saddr, 424 h = __addr_hash(&pol->selector.daddr, &pol->selector.saddr,
388 pol->family, nhashmask); 425 pol->family, nhashmask, dbits, sbits);
389 if (!entry0) { 426 if (!entry0) {
390 hlist_del(&pol->bydst); 427 hlist_del(&pol->bydst);
391 hlist_add_head(&pol->bydst, ndsttable+h); 428 hlist_add_head(&pol->bydst, ndsttable+h);
@@ -439,7 +476,7 @@ static void xfrm_bydst_resize(struct net *net, int dir)
439 write_lock_bh(&net->xfrm.xfrm_policy_lock); 476 write_lock_bh(&net->xfrm.xfrm_policy_lock);
440 477
441 for (i = hmask; i >= 0; i--) 478 for (i = hmask; i >= 0; i--)
442 xfrm_dst_hash_transfer(odst + i, ndst, nhashmask); 479 xfrm_dst_hash_transfer(net, odst + i, ndst, nhashmask, dir);
443 480
444 net->xfrm.policy_bydst[dir].table = ndst; 481 net->xfrm.policy_bydst[dir].table = ndst;
445 net->xfrm.policy_bydst[dir].hmask = nhashmask; 482 net->xfrm.policy_bydst[dir].hmask = nhashmask;
@@ -534,6 +571,86 @@ static void xfrm_hash_resize(struct work_struct *work)
534 mutex_unlock(&hash_resize_mutex); 571 mutex_unlock(&hash_resize_mutex);
535} 572}
536 573
574static void xfrm_hash_rebuild(struct work_struct *work)
575{
576 struct net *net = container_of(work, struct net,
577 xfrm.policy_hthresh.work);
578 unsigned int hmask;
579 struct xfrm_policy *pol;
580 struct xfrm_policy *policy;
581 struct hlist_head *chain;
582 struct hlist_head *odst;
583 struct hlist_node *newpos;
584 int i;
585 int dir;
586 unsigned seq;
587 u8 lbits4, rbits4, lbits6, rbits6;
588
589 mutex_lock(&hash_resize_mutex);
590
591 /* read selector prefixlen thresholds */
592 do {
593 seq = read_seqbegin(&net->xfrm.policy_hthresh.lock);
594
595 lbits4 = net->xfrm.policy_hthresh.lbits4;
596 rbits4 = net->xfrm.policy_hthresh.rbits4;
597 lbits6 = net->xfrm.policy_hthresh.lbits6;
598 rbits6 = net->xfrm.policy_hthresh.rbits6;
599 } while (read_seqretry(&net->xfrm.policy_hthresh.lock, seq));
600
601 write_lock_bh(&net->xfrm.xfrm_policy_lock);
602
603 /* reset the bydst and inexact table in all directions */
604 for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) {
605 INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]);
606 hmask = net->xfrm.policy_bydst[dir].hmask;
607 odst = net->xfrm.policy_bydst[dir].table;
608 for (i = hmask; i >= 0; i--)
609 INIT_HLIST_HEAD(odst + i);
610 if ((dir & XFRM_POLICY_MASK) == XFRM_POLICY_OUT) {
611 /* dir out => dst = remote, src = local */
612 net->xfrm.policy_bydst[dir].dbits4 = rbits4;
613 net->xfrm.policy_bydst[dir].sbits4 = lbits4;
614 net->xfrm.policy_bydst[dir].dbits6 = rbits6;
615 net->xfrm.policy_bydst[dir].sbits6 = lbits6;
616 } else {
617 /* dir in/fwd => dst = local, src = remote */
618 net->xfrm.policy_bydst[dir].dbits4 = lbits4;
619 net->xfrm.policy_bydst[dir].sbits4 = rbits4;
620 net->xfrm.policy_bydst[dir].dbits6 = lbits6;
621 net->xfrm.policy_bydst[dir].sbits6 = rbits6;
622 }
623 }
624
625 /* re-insert all policies by order of creation */
626 list_for_each_entry_reverse(policy, &net->xfrm.policy_all, walk.all) {
627 newpos = NULL;
628 chain = policy_hash_bysel(net, &policy->selector,
629 policy->family,
630 xfrm_policy_id2dir(policy->index));
631 hlist_for_each_entry(pol, chain, bydst) {
632 if (policy->priority >= pol->priority)
633 newpos = &pol->bydst;
634 else
635 break;
636 }
637 if (newpos)
638 hlist_add_behind(&policy->bydst, newpos);
639 else
640 hlist_add_head(&policy->bydst, chain);
641 }
642
643 write_unlock_bh(&net->xfrm.xfrm_policy_lock);
644
645 mutex_unlock(&hash_resize_mutex);
646}
647
648void xfrm_policy_hash_rebuild(struct net *net)
649{
650 schedule_work(&net->xfrm.policy_hthresh.work);
651}
652EXPORT_SYMBOL(xfrm_policy_hash_rebuild);
653
537/* Generate new index... KAME seems to generate them ordered by cost 654/* Generate new index... KAME seems to generate them ordered by cost
538 * of an absolute inpredictability of ordering of rules. This will not pass. */ 655 * of an absolute inpredictability of ordering of rules. This will not pass. */
539static u32 xfrm_gen_index(struct net *net, int dir, u32 index) 656static u32 xfrm_gen_index(struct net *net, int dir, u32 index)
@@ -2862,10 +2979,21 @@ static int __net_init xfrm_policy_init(struct net *net)
2862 if (!htab->table) 2979 if (!htab->table)
2863 goto out_bydst; 2980 goto out_bydst;
2864 htab->hmask = hmask; 2981 htab->hmask = hmask;
2982 htab->dbits4 = 32;
2983 htab->sbits4 = 32;
2984 htab->dbits6 = 128;
2985 htab->sbits6 = 128;
2865 } 2986 }
2987 net->xfrm.policy_hthresh.lbits4 = 32;
2988 net->xfrm.policy_hthresh.rbits4 = 32;
2989 net->xfrm.policy_hthresh.lbits6 = 128;
2990 net->xfrm.policy_hthresh.rbits6 = 128;
2991
2992 seqlock_init(&net->xfrm.policy_hthresh.lock);
2866 2993
2867 INIT_LIST_HEAD(&net->xfrm.policy_all); 2994 INIT_LIST_HEAD(&net->xfrm.policy_all);
2868 INIT_WORK(&net->xfrm.policy_hash_work, xfrm_hash_resize); 2995 INIT_WORK(&net->xfrm.policy_hash_work, xfrm_hash_resize);
2996 INIT_WORK(&net->xfrm.policy_hthresh.work, xfrm_hash_rebuild);
2869 if (net_eq(net, &init_net)) 2997 if (net_eq(net, &init_net))
2870 register_netdevice_notifier(&xfrm_dev_notifier); 2998 register_netdevice_notifier(&xfrm_dev_notifier);
2871 return 0; 2999 return 0;