aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--include/net/ah.h3
-rw-r--r--include/net/netns/xfrm.h14
-rw-r--r--include/net/xfrm.h1
-rw-r--r--include/uapi/linux/xfrm.h7
-rw-r--r--net/ipv4/ah4.c2
-rw-r--r--net/ipv6/ah6.c2
-rw-r--r--net/xfrm/xfrm_hash.h76
-rw-r--r--net/xfrm/xfrm_policy.c140
-rw-r--r--net/xfrm/xfrm_state.c13
-rw-r--r--net/xfrm/xfrm_user.c83
10 files changed, 303 insertions, 38 deletions
diff --git a/include/net/ah.h b/include/net/ah.h
index ca95b98969dd..4e2dfa474a7e 100644
--- a/include/net/ah.h
+++ b/include/net/ah.h
@@ -3,9 +3,6 @@
3 3
4#include <linux/skbuff.h> 4#include <linux/skbuff.h>
5 5
6/* This is the maximum truncated ICV length that we know of. */
7#define MAX_AH_AUTH_LEN 64
8
9struct crypto_ahash; 6struct crypto_ahash;
10 7
11struct ah_data { 8struct ah_data {
diff --git a/include/net/netns/xfrm.h b/include/net/netns/xfrm.h
index 3492434baf88..9da798256f0e 100644
--- a/include/net/netns/xfrm.h
+++ b/include/net/netns/xfrm.h
@@ -13,6 +13,19 @@ struct ctl_table_header;
13struct xfrm_policy_hash { 13struct xfrm_policy_hash {
14 struct hlist_head *table; 14 struct hlist_head *table;
15 unsigned int hmask; 15 unsigned int hmask;
16 u8 dbits4;
17 u8 sbits4;
18 u8 dbits6;
19 u8 sbits6;
20};
21
22struct xfrm_policy_hthresh {
23 struct work_struct work;
24 seqlock_t lock;
25 u8 lbits4;
26 u8 rbits4;
27 u8 lbits6;
28 u8 rbits6;
16}; 29};
17 30
18struct netns_xfrm { 31struct netns_xfrm {
@@ -41,6 +54,7 @@ struct netns_xfrm {
41 struct xfrm_policy_hash policy_bydst[XFRM_POLICY_MAX * 2]; 54 struct xfrm_policy_hash policy_bydst[XFRM_POLICY_MAX * 2];
42 unsigned int policy_count[XFRM_POLICY_MAX * 2]; 55 unsigned int policy_count[XFRM_POLICY_MAX * 2];
43 struct work_struct policy_hash_work; 56 struct work_struct policy_hash_work;
57 struct xfrm_policy_hthresh policy_hthresh;
44 58
45 59
46 struct sock *nlsk; 60 struct sock *nlsk;
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 721e9c3b11bd..dc4865e90fe4 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -1591,6 +1591,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark,
1591struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8, int dir, 1591struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8, int dir,
1592 u32 id, int delete, int *err); 1592 u32 id, int delete, int *err);
1593int xfrm_policy_flush(struct net *net, u8 type, bool task_valid); 1593int xfrm_policy_flush(struct net *net, u8 type, bool task_valid);
1594void xfrm_policy_hash_rebuild(struct net *net);
1594u32 xfrm_get_acqseq(void); 1595u32 xfrm_get_acqseq(void);
1595int verify_spi_info(u8 proto, u32 min, u32 max); 1596int verify_spi_info(u8 proto, u32 min, u32 max);
1596int xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi); 1597int xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi);
diff --git a/include/uapi/linux/xfrm.h b/include/uapi/linux/xfrm.h
index 25e5dd916ba4..02d5125a5ee8 100644
--- a/include/uapi/linux/xfrm.h
+++ b/include/uapi/linux/xfrm.h
@@ -328,6 +328,8 @@ enum xfrm_spdattr_type_t {
328 XFRMA_SPD_UNSPEC, 328 XFRMA_SPD_UNSPEC,
329 XFRMA_SPD_INFO, 329 XFRMA_SPD_INFO,
330 XFRMA_SPD_HINFO, 330 XFRMA_SPD_HINFO,
331 XFRMA_SPD_IPV4_HTHRESH,
332 XFRMA_SPD_IPV6_HTHRESH,
331 __XFRMA_SPD_MAX 333 __XFRMA_SPD_MAX
332 334
333#define XFRMA_SPD_MAX (__XFRMA_SPD_MAX - 1) 335#define XFRMA_SPD_MAX (__XFRMA_SPD_MAX - 1)
@@ -347,6 +349,11 @@ struct xfrmu_spdhinfo {
347 __u32 spdhmcnt; 349 __u32 spdhmcnt;
348}; 350};
349 351
352struct xfrmu_spdhthresh {
353 __u8 lbits;
354 __u8 rbits;
355};
356
350struct xfrm_usersa_info { 357struct xfrm_usersa_info {
351 struct xfrm_selector sel; 358 struct xfrm_selector sel;
352 struct xfrm_id id; 359 struct xfrm_id id;
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index a2afa89513a0..ac9a32ec3ee4 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -505,8 +505,6 @@ static int ah_init_state(struct xfrm_state *x)
505 ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; 505 ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8;
506 ahp->icv_trunc_len = x->aalg->alg_trunc_len/8; 506 ahp->icv_trunc_len = x->aalg->alg_trunc_len/8;
507 507
508 BUG_ON(ahp->icv_trunc_len > MAX_AH_AUTH_LEN);
509
510 if (x->props.flags & XFRM_STATE_ALIGN4) 508 if (x->props.flags & XFRM_STATE_ALIGN4)
511 x->props.header_len = XFRM_ALIGN4(sizeof(struct ip_auth_hdr) + 509 x->props.header_len = XFRM_ALIGN4(sizeof(struct ip_auth_hdr) +
512 ahp->icv_trunc_len); 510 ahp->icv_trunc_len);
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index fcffd4e522c8..6d16eb0e0c7f 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -713,8 +713,6 @@ static int ah6_init_state(struct xfrm_state *x)
713 ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; 713 ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8;
714 ahp->icv_trunc_len = x->aalg->alg_trunc_len/8; 714 ahp->icv_trunc_len = x->aalg->alg_trunc_len/8;
715 715
716 BUG_ON(ahp->icv_trunc_len > MAX_AH_AUTH_LEN);
717
718 x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + 716 x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) +
719 ahp->icv_trunc_len); 717 ahp->icv_trunc_len);
720 switch (x->props.mode) { 718 switch (x->props.mode) {
diff --git a/net/xfrm/xfrm_hash.h b/net/xfrm/xfrm_hash.h
index 0622d319e1f2..666c5ffe929d 100644
--- a/net/xfrm/xfrm_hash.h
+++ b/net/xfrm/xfrm_hash.h
@@ -3,6 +3,7 @@
3 3
4#include <linux/xfrm.h> 4#include <linux/xfrm.h>
5#include <linux/socket.h> 5#include <linux/socket.h>
6#include <linux/jhash.h>
6 7
7static inline unsigned int __xfrm4_addr_hash(const xfrm_address_t *addr) 8static inline unsigned int __xfrm4_addr_hash(const xfrm_address_t *addr)
8{ 9{
@@ -28,6 +29,58 @@ static inline unsigned int __xfrm6_daddr_saddr_hash(const xfrm_address_t *daddr,
28 saddr->a6[2] ^ saddr->a6[3]); 29 saddr->a6[2] ^ saddr->a6[3]);
29} 30}
30 31
32static inline u32 __bits2mask32(__u8 bits)
33{
34 u32 mask32 = 0xffffffff;
35
36 if (bits == 0)
37 mask32 = 0;
38 else if (bits < 32)
39 mask32 <<= (32 - bits);
40
41 return mask32;
42}
43
44static inline unsigned int __xfrm4_dpref_spref_hash(const xfrm_address_t *daddr,
45 const xfrm_address_t *saddr,
46 __u8 dbits,
47 __u8 sbits)
48{
49 return jhash_2words(ntohl(daddr->a4) & __bits2mask32(dbits),
50 ntohl(saddr->a4) & __bits2mask32(sbits),
51 0);
52}
53
54static inline unsigned int __xfrm6_pref_hash(const xfrm_address_t *addr,
55 __u8 prefixlen)
56{
57 int pdw;
58 int pbi;
59 u32 initval = 0;
60
61 pdw = prefixlen >> 5; /* num of whole u32 in prefix */
62 pbi = prefixlen & 0x1f; /* num of bits in incomplete u32 in prefix */
63
64 if (pbi) {
65 __be32 mask;
66
67 mask = htonl((0xffffffff) << (32 - pbi));
68
69 initval = (__force u32)(addr->a6[pdw] & mask);
70 }
71
72 return jhash2((__force u32 *)addr->a6, pdw, initval);
73}
74
75static inline unsigned int __xfrm6_dpref_spref_hash(const xfrm_address_t *daddr,
76 const xfrm_address_t *saddr,
77 __u8 dbits,
78 __u8 sbits)
79{
80 return __xfrm6_pref_hash(daddr, dbits) ^
81 __xfrm6_pref_hash(saddr, sbits);
82}
83
31static inline unsigned int __xfrm_dst_hash(const xfrm_address_t *daddr, 84static inline unsigned int __xfrm_dst_hash(const xfrm_address_t *daddr,
32 const xfrm_address_t *saddr, 85 const xfrm_address_t *saddr,
33 u32 reqid, unsigned short family, 86 u32 reqid, unsigned short family,
@@ -84,7 +137,8 @@ static inline unsigned int __idx_hash(u32 index, unsigned int hmask)
84} 137}
85 138
86static inline unsigned int __sel_hash(const struct xfrm_selector *sel, 139static inline unsigned int __sel_hash(const struct xfrm_selector *sel,
87 unsigned short family, unsigned int hmask) 140 unsigned short family, unsigned int hmask,
141 u8 dbits, u8 sbits)
88{ 142{
89 const xfrm_address_t *daddr = &sel->daddr; 143 const xfrm_address_t *daddr = &sel->daddr;
90 const xfrm_address_t *saddr = &sel->saddr; 144 const xfrm_address_t *saddr = &sel->saddr;
@@ -92,19 +146,19 @@ static inline unsigned int __sel_hash(const struct xfrm_selector *sel,
92 146
93 switch (family) { 147 switch (family) {
94 case AF_INET: 148 case AF_INET:
95 if (sel->prefixlen_d != 32 || 149 if (sel->prefixlen_d < dbits ||
96 sel->prefixlen_s != 32) 150 sel->prefixlen_s < sbits)
97 return hmask + 1; 151 return hmask + 1;
98 152
99 h = __xfrm4_daddr_saddr_hash(daddr, saddr); 153 h = __xfrm4_dpref_spref_hash(daddr, saddr, dbits, sbits);
100 break; 154 break;
101 155
102 case AF_INET6: 156 case AF_INET6:
103 if (sel->prefixlen_d != 128 || 157 if (sel->prefixlen_d < dbits ||
104 sel->prefixlen_s != 128) 158 sel->prefixlen_s < sbits)
105 return hmask + 1; 159 return hmask + 1;
106 160
107 h = __xfrm6_daddr_saddr_hash(daddr, saddr); 161 h = __xfrm6_dpref_spref_hash(daddr, saddr, dbits, sbits);
108 break; 162 break;
109 } 163 }
110 h ^= (h >> 16); 164 h ^= (h >> 16);
@@ -113,17 +167,19 @@ static inline unsigned int __sel_hash(const struct xfrm_selector *sel,
113 167
114static inline unsigned int __addr_hash(const xfrm_address_t *daddr, 168static inline unsigned int __addr_hash(const xfrm_address_t *daddr,
115 const xfrm_address_t *saddr, 169 const xfrm_address_t *saddr,
116 unsigned short family, unsigned int hmask) 170 unsigned short family,
171 unsigned int hmask,
172 u8 dbits, u8 sbits)
117{ 173{
118 unsigned int h = 0; 174 unsigned int h = 0;
119 175
120 switch (family) { 176 switch (family) {
121 case AF_INET: 177 case AF_INET:
122 h = __xfrm4_daddr_saddr_hash(daddr, saddr); 178 h = __xfrm4_dpref_spref_hash(daddr, saddr, dbits, sbits);
123 break; 179 break;
124 180
125 case AF_INET6: 181 case AF_INET6:
126 h = __xfrm6_daddr_saddr_hash(daddr, saddr); 182 h = __xfrm6_dpref_spref_hash(daddr, saddr, dbits, sbits);
127 break; 183 break;
128 } 184 }
129 h ^= (h >> 16); 185 h ^= (h >> 16);
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;
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 0ab54134bb40..de971b6d38c5 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -97,8 +97,6 @@ static unsigned long xfrm_hash_new_size(unsigned int state_hmask)
97 return ((state_hmask + 1) << 1) * sizeof(struct hlist_head); 97 return ((state_hmask + 1) << 1) * sizeof(struct hlist_head);
98} 98}
99 99
100static DEFINE_MUTEX(hash_resize_mutex);
101
102static void xfrm_hash_resize(struct work_struct *work) 100static void xfrm_hash_resize(struct work_struct *work)
103{ 101{
104 struct net *net = container_of(work, struct net, xfrm.state_hash_work); 102 struct net *net = container_of(work, struct net, xfrm.state_hash_work);
@@ -107,22 +105,20 @@ static void xfrm_hash_resize(struct work_struct *work)
107 unsigned int nhashmask, ohashmask; 105 unsigned int nhashmask, ohashmask;
108 int i; 106 int i;
109 107
110 mutex_lock(&hash_resize_mutex);
111
112 nsize = xfrm_hash_new_size(net->xfrm.state_hmask); 108 nsize = xfrm_hash_new_size(net->xfrm.state_hmask);
113 ndst = xfrm_hash_alloc(nsize); 109 ndst = xfrm_hash_alloc(nsize);
114 if (!ndst) 110 if (!ndst)
115 goto out_unlock; 111 return;
116 nsrc = xfrm_hash_alloc(nsize); 112 nsrc = xfrm_hash_alloc(nsize);
117 if (!nsrc) { 113 if (!nsrc) {
118 xfrm_hash_free(ndst, nsize); 114 xfrm_hash_free(ndst, nsize);
119 goto out_unlock; 115 return;
120 } 116 }
121 nspi = xfrm_hash_alloc(nsize); 117 nspi = xfrm_hash_alloc(nsize);
122 if (!nspi) { 118 if (!nspi) {
123 xfrm_hash_free(ndst, nsize); 119 xfrm_hash_free(ndst, nsize);
124 xfrm_hash_free(nsrc, nsize); 120 xfrm_hash_free(nsrc, nsize);
125 goto out_unlock; 121 return;
126 } 122 }
127 123
128 spin_lock_bh(&net->xfrm.xfrm_state_lock); 124 spin_lock_bh(&net->xfrm.xfrm_state_lock);
@@ -148,9 +144,6 @@ static void xfrm_hash_resize(struct work_struct *work)
148 xfrm_hash_free(odst, osize); 144 xfrm_hash_free(odst, osize);
149 xfrm_hash_free(osrc, osize); 145 xfrm_hash_free(osrc, osize);
150 xfrm_hash_free(ospi, osize); 146 xfrm_hash_free(ospi, osize);
151
152out_unlock:
153 mutex_unlock(&hash_resize_mutex);
154} 147}
155 148
156static DEFINE_SPINLOCK(xfrm_state_afinfo_lock); 149static DEFINE_SPINLOCK(xfrm_state_afinfo_lock);
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index d4db6ebb089d..e812e988c111 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -333,8 +333,7 @@ static int attach_auth_trunc(struct xfrm_algo_auth **algpp, u8 *props,
333 algo = xfrm_aalg_get_byname(ualg->alg_name, 1); 333 algo = xfrm_aalg_get_byname(ualg->alg_name, 1);
334 if (!algo) 334 if (!algo)
335 return -ENOSYS; 335 return -ENOSYS;
336 if ((ualg->alg_trunc_len / 8) > MAX_AH_AUTH_LEN || 336 if (ualg->alg_trunc_len > algo->uinfo.auth.icv_fullbits)
337 ualg->alg_trunc_len > algo->uinfo.auth.icv_fullbits)
338 return -EINVAL; 337 return -EINVAL;
339 *props = algo->desc.sadb_alg_id; 338 *props = algo->desc.sadb_alg_id;
340 339
@@ -964,7 +963,9 @@ static inline size_t xfrm_spdinfo_msgsize(void)
964{ 963{
965 return NLMSG_ALIGN(4) 964 return NLMSG_ALIGN(4)
966 + nla_total_size(sizeof(struct xfrmu_spdinfo)) 965 + nla_total_size(sizeof(struct xfrmu_spdinfo))
967 + nla_total_size(sizeof(struct xfrmu_spdhinfo)); 966 + nla_total_size(sizeof(struct xfrmu_spdhinfo))
967 + nla_total_size(sizeof(struct xfrmu_spdhthresh))
968 + nla_total_size(sizeof(struct xfrmu_spdhthresh));
968} 969}
969 970
970static int build_spdinfo(struct sk_buff *skb, struct net *net, 971static int build_spdinfo(struct sk_buff *skb, struct net *net,
@@ -973,9 +974,11 @@ static int build_spdinfo(struct sk_buff *skb, struct net *net,
973 struct xfrmk_spdinfo si; 974 struct xfrmk_spdinfo si;
974 struct xfrmu_spdinfo spc; 975 struct xfrmu_spdinfo spc;
975 struct xfrmu_spdhinfo sph; 976 struct xfrmu_spdhinfo sph;
977 struct xfrmu_spdhthresh spt4, spt6;
976 struct nlmsghdr *nlh; 978 struct nlmsghdr *nlh;
977 int err; 979 int err;
978 u32 *f; 980 u32 *f;
981 unsigned lseq;
979 982
980 nlh = nlmsg_put(skb, portid, seq, XFRM_MSG_NEWSPDINFO, sizeof(u32), 0); 983 nlh = nlmsg_put(skb, portid, seq, XFRM_MSG_NEWSPDINFO, sizeof(u32), 0);
981 if (nlh == NULL) /* shouldn't really happen ... */ 984 if (nlh == NULL) /* shouldn't really happen ... */
@@ -993,9 +996,22 @@ static int build_spdinfo(struct sk_buff *skb, struct net *net,
993 sph.spdhcnt = si.spdhcnt; 996 sph.spdhcnt = si.spdhcnt;
994 sph.spdhmcnt = si.spdhmcnt; 997 sph.spdhmcnt = si.spdhmcnt;
995 998
999 do {
1000 lseq = read_seqbegin(&net->xfrm.policy_hthresh.lock);
1001
1002 spt4.lbits = net->xfrm.policy_hthresh.lbits4;
1003 spt4.rbits = net->xfrm.policy_hthresh.rbits4;
1004 spt6.lbits = net->xfrm.policy_hthresh.lbits6;
1005 spt6.rbits = net->xfrm.policy_hthresh.rbits6;
1006 } while (read_seqretry(&net->xfrm.policy_hthresh.lock, lseq));
1007
996 err = nla_put(skb, XFRMA_SPD_INFO, sizeof(spc), &spc); 1008 err = nla_put(skb, XFRMA_SPD_INFO, sizeof(spc), &spc);
997 if (!err) 1009 if (!err)
998 err = nla_put(skb, XFRMA_SPD_HINFO, sizeof(sph), &sph); 1010 err = nla_put(skb, XFRMA_SPD_HINFO, sizeof(sph), &sph);
1011 if (!err)
1012 err = nla_put(skb, XFRMA_SPD_IPV4_HTHRESH, sizeof(spt4), &spt4);
1013 if (!err)
1014 err = nla_put(skb, XFRMA_SPD_IPV6_HTHRESH, sizeof(spt6), &spt6);
999 if (err) { 1015 if (err) {
1000 nlmsg_cancel(skb, nlh); 1016 nlmsg_cancel(skb, nlh);
1001 return err; 1017 return err;
@@ -1004,6 +1020,51 @@ static int build_spdinfo(struct sk_buff *skb, struct net *net,
1004 return nlmsg_end(skb, nlh); 1020 return nlmsg_end(skb, nlh);
1005} 1021}
1006 1022
1023static int xfrm_set_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
1024 struct nlattr **attrs)
1025{
1026 struct net *net = sock_net(skb->sk);
1027 struct xfrmu_spdhthresh *thresh4 = NULL;
1028 struct xfrmu_spdhthresh *thresh6 = NULL;
1029
1030 /* selector prefixlen thresholds to hash policies */
1031 if (attrs[XFRMA_SPD_IPV4_HTHRESH]) {
1032 struct nlattr *rta = attrs[XFRMA_SPD_IPV4_HTHRESH];
1033
1034 if (nla_len(rta) < sizeof(*thresh4))
1035 return -EINVAL;
1036 thresh4 = nla_data(rta);
1037 if (thresh4->lbits > 32 || thresh4->rbits > 32)
1038 return -EINVAL;
1039 }
1040 if (attrs[XFRMA_SPD_IPV6_HTHRESH]) {
1041 struct nlattr *rta = attrs[XFRMA_SPD_IPV6_HTHRESH];
1042
1043 if (nla_len(rta) < sizeof(*thresh6))
1044 return -EINVAL;
1045 thresh6 = nla_data(rta);
1046 if (thresh6->lbits > 128 || thresh6->rbits > 128)
1047 return -EINVAL;
1048 }
1049
1050 if (thresh4 || thresh6) {
1051 write_seqlock(&net->xfrm.policy_hthresh.lock);
1052 if (thresh4) {
1053 net->xfrm.policy_hthresh.lbits4 = thresh4->lbits;
1054 net->xfrm.policy_hthresh.rbits4 = thresh4->rbits;
1055 }
1056 if (thresh6) {
1057 net->xfrm.policy_hthresh.lbits6 = thresh6->lbits;
1058 net->xfrm.policy_hthresh.rbits6 = thresh6->rbits;
1059 }
1060 write_sequnlock(&net->xfrm.policy_hthresh.lock);
1061
1062 xfrm_policy_hash_rebuild(net);
1063 }
1064
1065 return 0;
1066}
1067
1007static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh, 1068static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
1008 struct nlattr **attrs) 1069 struct nlattr **attrs)
1009{ 1070{
@@ -2274,6 +2335,7 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = {
2274 [XFRM_MSG_REPORT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report), 2335 [XFRM_MSG_REPORT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report),
2275 [XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id), 2336 [XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
2276 [XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = sizeof(u32), 2337 [XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = sizeof(u32),
2338 [XFRM_MSG_NEWSPDINFO - XFRM_MSG_BASE] = sizeof(u32),
2277 [XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = sizeof(u32), 2339 [XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = sizeof(u32),
2278}; 2340};
2279 2341
@@ -2308,10 +2370,17 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
2308 [XFRMA_ADDRESS_FILTER] = { .len = sizeof(struct xfrm_address_filter) }, 2370 [XFRMA_ADDRESS_FILTER] = { .len = sizeof(struct xfrm_address_filter) },
2309}; 2371};
2310 2372
2373static const struct nla_policy xfrma_spd_policy[XFRMA_SPD_MAX+1] = {
2374 [XFRMA_SPD_IPV4_HTHRESH] = { .len = sizeof(struct xfrmu_spdhthresh) },
2375 [XFRMA_SPD_IPV6_HTHRESH] = { .len = sizeof(struct xfrmu_spdhthresh) },
2376};
2377
2311static const struct xfrm_link { 2378static const struct xfrm_link {
2312 int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **); 2379 int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **);
2313 int (*dump)(struct sk_buff *, struct netlink_callback *); 2380 int (*dump)(struct sk_buff *, struct netlink_callback *);
2314 int (*done)(struct netlink_callback *); 2381 int (*done)(struct netlink_callback *);
2382 const struct nla_policy *nla_pol;
2383 int nla_max;
2315} xfrm_dispatch[XFRM_NR_MSGTYPES] = { 2384} xfrm_dispatch[XFRM_NR_MSGTYPES] = {
2316 [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa }, 2385 [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa },
2317 [XFRM_MSG_DELSA - XFRM_MSG_BASE] = { .doit = xfrm_del_sa }, 2386 [XFRM_MSG_DELSA - XFRM_MSG_BASE] = { .doit = xfrm_del_sa },
@@ -2335,6 +2404,9 @@ static const struct xfrm_link {
2335 [XFRM_MSG_GETAE - XFRM_MSG_BASE] = { .doit = xfrm_get_ae }, 2404 [XFRM_MSG_GETAE - XFRM_MSG_BASE] = { .doit = xfrm_get_ae },
2336 [XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = { .doit = xfrm_do_migrate }, 2405 [XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = { .doit = xfrm_do_migrate },
2337 [XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = { .doit = xfrm_get_sadinfo }, 2406 [XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = { .doit = xfrm_get_sadinfo },
2407 [XFRM_MSG_NEWSPDINFO - XFRM_MSG_BASE] = { .doit = xfrm_set_spdinfo,
2408 .nla_pol = xfrma_spd_policy,
2409 .nla_max = XFRMA_SPD_MAX },
2338 [XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = { .doit = xfrm_get_spdinfo }, 2410 [XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = { .doit = xfrm_get_spdinfo },
2339}; 2411};
2340 2412
@@ -2371,8 +2443,9 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
2371 } 2443 }
2372 } 2444 }
2373 2445
2374 err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs, XFRMA_MAX, 2446 err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs,
2375 xfrma_policy); 2447 link->nla_max ? : XFRMA_MAX,
2448 link->nla_pol ? : xfrma_policy);
2376 if (err < 0) 2449 if (err < 0)
2377 return err; 2450 return err;
2378 2451