aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm/xfrm_policy.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/xfrm/xfrm_policy.c')
-rw-r--r--net/xfrm/xfrm_policy.c144
1 files changed, 135 insertions, 9 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index fdde51f4271a..4c4e457e7888 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)
@@ -1844,10 +1961,8 @@ static int xdst_queue_output(struct sock *sk, struct sk_buff *skb)
1844 struct xfrm_dst *xdst = (struct xfrm_dst *) dst; 1961 struct xfrm_dst *xdst = (struct xfrm_dst *) dst;
1845 struct xfrm_policy *pol = xdst->pols[0]; 1962 struct xfrm_policy *pol = xdst->pols[0];
1846 struct xfrm_policy_queue *pq = &pol->polq; 1963 struct xfrm_policy_queue *pq = &pol->polq;
1847 const struct sk_buff *fclone = skb + 1;
1848 1964
1849 if (unlikely(skb->fclone == SKB_FCLONE_ORIG && 1965 if (unlikely(skb_fclone_busy(skb))) {
1850 fclone->fclone == SKB_FCLONE_CLONE)) {
1851 kfree_skb(skb); 1966 kfree_skb(skb);
1852 return 0; 1967 return 0;
1853 } 1968 }
@@ -2862,10 +2977,21 @@ static int __net_init xfrm_policy_init(struct net *net)
2862 if (!htab->table) 2977 if (!htab->table)
2863 goto out_bydst; 2978 goto out_bydst;
2864 htab->hmask = hmask; 2979 htab->hmask = hmask;
2980 htab->dbits4 = 32;
2981 htab->sbits4 = 32;
2982 htab->dbits6 = 128;
2983 htab->sbits6 = 128;
2865 } 2984 }
2985 net->xfrm.policy_hthresh.lbits4 = 32;
2986 net->xfrm.policy_hthresh.rbits4 = 32;
2987 net->xfrm.policy_hthresh.lbits6 = 128;
2988 net->xfrm.policy_hthresh.rbits6 = 128;
2989
2990 seqlock_init(&net->xfrm.policy_hthresh.lock);
2866 2991
2867 INIT_LIST_HEAD(&net->xfrm.policy_all); 2992 INIT_LIST_HEAD(&net->xfrm.policy_all);
2868 INIT_WORK(&net->xfrm.policy_hash_work, xfrm_hash_resize); 2993 INIT_WORK(&net->xfrm.policy_hash_work, xfrm_hash_resize);
2994 INIT_WORK(&net->xfrm.policy_hthresh.work, xfrm_hash_rebuild);
2869 if (net_eq(net, &init_net)) 2995 if (net_eq(net, &init_net))
2870 register_netdevice_notifier(&xfrm_dev_notifier); 2996 register_netdevice_notifier(&xfrm_dev_notifier);
2871 return 0; 2997 return 0;