diff options
Diffstat (limited to 'net/xfrm/xfrm_policy.c')
-rw-r--r-- | net/xfrm/xfrm_policy.c | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index e6ff7b4046ea..55bcb8604bc6 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -566,6 +566,86 @@ static void xfrm_hash_resize(struct work_struct *work) | |||
566 | mutex_unlock(&hash_resize_mutex); | 566 | mutex_unlock(&hash_resize_mutex); |
567 | } | 567 | } |
568 | 568 | ||
569 | static void xfrm_hash_rebuild(struct work_struct *work) | ||
570 | { | ||
571 | struct net *net = container_of(work, struct net, | ||
572 | xfrm.policy_hthresh.work); | ||
573 | unsigned int hmask; | ||
574 | struct xfrm_policy *pol; | ||
575 | struct xfrm_policy *policy; | ||
576 | struct hlist_head *chain; | ||
577 | struct hlist_head *odst; | ||
578 | struct hlist_node *newpos; | ||
579 | int i; | ||
580 | int dir; | ||
581 | unsigned seq; | ||
582 | u8 lbits4, rbits4, lbits6, rbits6; | ||
583 | |||
584 | mutex_lock(&hash_resize_mutex); | ||
585 | |||
586 | /* read selector prefixlen thresholds */ | ||
587 | do { | ||
588 | seq = read_seqbegin(&net->xfrm.policy_hthresh.lock); | ||
589 | |||
590 | lbits4 = net->xfrm.policy_hthresh.lbits4; | ||
591 | rbits4 = net->xfrm.policy_hthresh.rbits4; | ||
592 | lbits6 = net->xfrm.policy_hthresh.lbits6; | ||
593 | rbits6 = net->xfrm.policy_hthresh.rbits6; | ||
594 | } while (read_seqretry(&net->xfrm.policy_hthresh.lock, seq)); | ||
595 | |||
596 | write_lock_bh(&net->xfrm.xfrm_policy_lock); | ||
597 | |||
598 | /* reset the bydst and inexact table in all directions */ | ||
599 | for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { | ||
600 | INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]); | ||
601 | hmask = net->xfrm.policy_bydst[dir].hmask; | ||
602 | odst = net->xfrm.policy_bydst[dir].table; | ||
603 | for (i = hmask; i >= 0; i--) | ||
604 | INIT_HLIST_HEAD(odst + i); | ||
605 | if ((dir & XFRM_POLICY_MASK) == XFRM_POLICY_OUT) { | ||
606 | /* dir out => dst = remote, src = local */ | ||
607 | net->xfrm.policy_bydst[dir].dbits4 = rbits4; | ||
608 | net->xfrm.policy_bydst[dir].sbits4 = lbits4; | ||
609 | net->xfrm.policy_bydst[dir].dbits6 = rbits6; | ||
610 | net->xfrm.policy_bydst[dir].sbits6 = lbits6; | ||
611 | } else { | ||
612 | /* dir in/fwd => dst = local, src = remote */ | ||
613 | net->xfrm.policy_bydst[dir].dbits4 = lbits4; | ||
614 | net->xfrm.policy_bydst[dir].sbits4 = rbits4; | ||
615 | net->xfrm.policy_bydst[dir].dbits6 = lbits6; | ||
616 | net->xfrm.policy_bydst[dir].sbits6 = rbits6; | ||
617 | } | ||
618 | } | ||
619 | |||
620 | /* re-insert all policies by order of creation */ | ||
621 | list_for_each_entry_reverse(policy, &net->xfrm.policy_all, walk.all) { | ||
622 | newpos = NULL; | ||
623 | chain = policy_hash_bysel(net, &policy->selector, | ||
624 | policy->family, | ||
625 | xfrm_policy_id2dir(policy->index)); | ||
626 | hlist_for_each_entry(pol, chain, bydst) { | ||
627 | if (policy->priority >= pol->priority) | ||
628 | newpos = &pol->bydst; | ||
629 | else | ||
630 | break; | ||
631 | } | ||
632 | if (newpos) | ||
633 | hlist_add_behind(&policy->bydst, newpos); | ||
634 | else | ||
635 | hlist_add_head(&policy->bydst, chain); | ||
636 | } | ||
637 | |||
638 | write_unlock_bh(&net->xfrm.xfrm_policy_lock); | ||
639 | |||
640 | mutex_unlock(&hash_resize_mutex); | ||
641 | } | ||
642 | |||
643 | void xfrm_policy_hash_rebuild(struct net *net) | ||
644 | { | ||
645 | schedule_work(&net->xfrm.policy_hthresh.work); | ||
646 | } | ||
647 | EXPORT_SYMBOL(xfrm_policy_hash_rebuild); | ||
648 | |||
569 | /* Generate new index... KAME seems to generate them ordered by cost | 649 | /* Generate new index... KAME seems to generate them ordered by cost |
570 | * of an absolute inpredictability of ordering of rules. This will not pass. */ | 650 | * of an absolute inpredictability of ordering of rules. This will not pass. */ |
571 | static u32 xfrm_gen_index(struct net *net, int dir, u32 index) | 651 | static u32 xfrm_gen_index(struct net *net, int dir, u32 index) |
@@ -2872,9 +2952,16 @@ static int __net_init xfrm_policy_init(struct net *net) | |||
2872 | htab->dbits6 = 128; | 2952 | htab->dbits6 = 128; |
2873 | htab->sbits6 = 128; | 2953 | htab->sbits6 = 128; |
2874 | } | 2954 | } |
2955 | net->xfrm.policy_hthresh.lbits4 = 32; | ||
2956 | net->xfrm.policy_hthresh.rbits4 = 32; | ||
2957 | net->xfrm.policy_hthresh.lbits6 = 128; | ||
2958 | net->xfrm.policy_hthresh.rbits6 = 128; | ||
2959 | |||
2960 | seqlock_init(&net->xfrm.policy_hthresh.lock); | ||
2875 | 2961 | ||
2876 | INIT_LIST_HEAD(&net->xfrm.policy_all); | 2962 | INIT_LIST_HEAD(&net->xfrm.policy_all); |
2877 | INIT_WORK(&net->xfrm.policy_hash_work, xfrm_hash_resize); | 2963 | INIT_WORK(&net->xfrm.policy_hash_work, xfrm_hash_resize); |
2964 | INIT_WORK(&net->xfrm.policy_hthresh.work, xfrm_hash_rebuild); | ||
2878 | if (net_eq(net, &init_net)) | 2965 | if (net_eq(net, &init_net)) |
2879 | register_netdevice_notifier(&xfrm_dev_notifier); | 2966 | register_netdevice_notifier(&xfrm_dev_notifier); |
2880 | return 0; | 2967 | return 0; |