History

xfrm: configure policy hash table thresholds by netlink

Enable to specify local and remote prefix length thresholds for the policy hash table via a netlink XFRM_MSG_NEWSPDINFO message. prefix length thresholds are specified by XFRMA_SPD_IPV4_HTHRESH and XFRMA_SPD_IPV6_HTHRESH optional attributes (struct xfrmu_spdhthresh). example: struct xfrmu_spdhthresh thresh4 = { .lbits = 0; .rbits = 24; }; struct xfrmu_spdhthresh thresh6 = { .lbits = 0; .rbits = 56; }; struct nlmsghdr *hdr; struct nl_msg *msg; msg = nlmsg_alloc(); hdr = nlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, XFRMA_SPD_IPV4_HTHRESH, sizeof(__u32), NLM_F_REQUEST); nla_put(msg, XFRMA_SPD_IPV4_HTHRESH, sizeof(thresh4), &thresh4); nla_put(msg, XFRMA_SPD_IPV6_HTHRESH, sizeof(thresh6), &thresh6); nla_send_auto(sk, msg); The numbers are the policy selector minimum prefix lengths to put a policy in the hash table. - lbits is the local threshold (source address for out policies, destination address for in and fwd policies). - rbits is the remote threshold (destination address for out policies, source address for in and fwd policies). The default values are: XFRMA_SPD_IPV4_HTHRESH: 32 32 XFRMA_SPD_IPV6_HTHRESH: 128 128 Dynamic re-building of the SPD is performed when the thresholds values are changed. The current thresholds can be read via a XFRM_MSG_GETSPDINFO request: the kernel replies to XFRM_MSG_GETSPDINFO requests by an XFRM_MSG_NEWSPDINFO message, with both attributes XFRMA_SPD_IPV4_HTHRESH and XFRMA_SPD_IPV6_HTHRESH.

Christophe Gouault committed 12 years ago

Commit 880a6fa1 parent b58555f5 files · +182 −3Browse files

Unified · Split

5 files
  1. include/net/netns/xfrm.h +10 −0
  2. include/net/xfrm.h +1 −0
  3. include/uapi/linux/xfrm.h +7 −0
  4. net/xfrm/xfrm_policy.c +87 −0
  5. net/xfrm/xfrm_user.c +77 −3
include/net/netns/xfrm.h+10−0
@@ -19,6 +19,15 @@ struct xfrm_policy_hash { · 18 unmodified lines
19 u8 sbits6;19 u8 sbits6;
20};20};
21 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;
29};
30
22struct netns_xfrm {31struct netns_xfrm {
23 struct list_head state_all;32 struct list_head state_all;
24 /*33 /*
@@ -45,6 +54,7 @@ struct netns_xfrm { · 20 unmodified lines
45 struct xfrm_policy_hash policy_bydst[XFRM_POLICY_MAX * 2];54 struct xfrm_policy_hash policy_bydst[XFRM_POLICY_MAX * 2];
46 unsigned int policy_count[XFRM_POLICY_MAX * 2];55 unsigned int policy_count[XFRM_POLICY_MAX * 2];
47 struct work_struct policy_hash_work;56 struct work_struct policy_hash_work;
57 struct xfrm_policy_hthresh policy_hthresh;
48 58
49 59
50 struct sock *nlsk;60 struct sock *nlsk;
include/net/xfrm.h+1−0
@@ -1591,6 +1591,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, · 1590 unmodified lines
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);
include/uapi/linux/xfrm.h+7−0
@@ -328,6 +328,8 @@ enum xfrm_spdattr_type_t { · 327 unmodified lines
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_MAX333 __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 { · 13 unmodified lines
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;
net/xfrm/xfrm_policy.c+87−0
@@ -566,6 +566,86 @@ static void xfrm_hash_resize(struct work_struct *work) · 565 unmodified lines
566 mutex_unlock(&hash_resize_mutex);566 mutex_unlock(&hash_resize_mutex);
567}567}
568 568
569static 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
643void xfrm_policy_hash_rebuild(struct net *net)
644{
645 schedule_work(&net->xfrm.policy_hthresh.work);
646}
647EXPORT_SYMBOL(xfrm_policy_hash_rebuild);
648
569/* Generate new index... KAME seems to generate them ordered by cost649/* 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. */
571static u32 xfrm_gen_index(struct net *net, int dir, u32 index)651static 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) · 2300 unmodified lines
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;
net/xfrm/xfrm_user.c+77−3
@@ -964,7 +964,9 @@ static inline size_t xfrm_spdinfo_msgsize(void) · 963 unmodified lines
964{964{
965 return NLMSG_ALIGN(4)965 return NLMSG_ALIGN(4)
966 + nla_total_size(sizeof(struct xfrmu_spdinfo))966 + nla_total_size(sizeof(struct xfrmu_spdinfo))
967 + nla_total_size(sizeof(struct xfrmu_spdhinfo));967 + nla_total_size(sizeof(struct xfrmu_spdhinfo))
968 + nla_total_size(sizeof(struct xfrmu_spdhthresh))
969 + nla_total_size(sizeof(struct xfrmu_spdhthresh));
968}970}
969 971
970static int build_spdinfo(struct sk_buff *skb, struct net *net,972static int build_spdinfo(struct sk_buff *skb, struct net *net,
@@ -973,9 +975,11 @@ static int build_spdinfo(struct sk_buff *skb, struct net *net, · 2 unmodified lines
973 struct xfrmk_spdinfo si;975 struct xfrmk_spdinfo si;
974 struct xfrmu_spdinfo spc;976 struct xfrmu_spdinfo spc;
975 struct xfrmu_spdhinfo sph;977 struct xfrmu_spdhinfo sph;
978 struct xfrmu_spdhthresh spt4, spt6;
976 struct nlmsghdr *nlh;979 struct nlmsghdr *nlh;
977 int err;980 int err;
978 u32 *f;981 u32 *f;
982 unsigned lseq;
979 983
980 nlh = nlmsg_put(skb, portid, seq, XFRM_MSG_NEWSPDINFO, sizeof(u32), 0);984 nlh = nlmsg_put(skb, portid, seq, XFRM_MSG_NEWSPDINFO, sizeof(u32), 0);
981 if (nlh == NULL) /* shouldn't really happen ... */985 if (nlh == NULL) /* shouldn't really happen ... */
@@ -993,9 +997,22 @@ static int build_spdinfo(struct sk_buff *skb, struct net *net, · 11 unmodified lines
993 sph.spdhcnt = si.spdhcnt;997 sph.spdhcnt = si.spdhcnt;
994 sph.spdhmcnt = si.spdhmcnt;998 sph.spdhmcnt = si.spdhmcnt;
995 999
1000 do {
1001 lseq = read_seqbegin(&net->xfrm.policy_hthresh.lock);
1002
1003 spt4.lbits = net->xfrm.policy_hthresh.lbits4;
1004 spt4.rbits = net->xfrm.policy_hthresh.rbits4;
1005 spt6.lbits = net->xfrm.policy_hthresh.lbits6;
1006 spt6.rbits = net->xfrm.policy_hthresh.rbits6;
1007 } while (read_seqretry(&net->xfrm.policy_hthresh.lock, lseq));
1008
996 err = nla_put(skb, XFRMA_SPD_INFO, sizeof(spc), &spc);1009 err = nla_put(skb, XFRMA_SPD_INFO, sizeof(spc), &spc);
997 if (!err)1010 if (!err)
998 err = nla_put(skb, XFRMA_SPD_HINFO, sizeof(sph), &sph);1011 err = nla_put(skb, XFRMA_SPD_HINFO, sizeof(sph), &sph);
1012 if (!err)
1013 err = nla_put(skb, XFRMA_SPD_IPV4_HTHRESH, sizeof(spt4), &spt4);
1014 if (!err)
1015 err = nla_put(skb, XFRMA_SPD_IPV6_HTHRESH, sizeof(spt6), &spt6);
999 if (err) {1016 if (err) {
1000 nlmsg_cancel(skb, nlh);1017 nlmsg_cancel(skb, nlh);
1001 return err;1018 return err;
@@ -1004,6 +1021,51 @@ static int build_spdinfo(struct sk_buff *skb, struct net *net, · 2 unmodified lines
1004 return nlmsg_end(skb, nlh);1021 return nlmsg_end(skb, nlh);
1005}1022}
1006 1023
1024static int xfrm_set_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
1025 struct nlattr **attrs)
1026{
1027 struct net *net = sock_net(skb->sk);
1028 struct xfrmu_spdhthresh *thresh4 = NULL;
1029 struct xfrmu_spdhthresh *thresh6 = NULL;
1030
1031 /* selector prefixlen thresholds to hash policies */
1032 if (attrs[XFRMA_SPD_IPV4_HTHRESH]) {
1033 struct nlattr *rta = attrs[XFRMA_SPD_IPV4_HTHRESH];
1034
1035 if (nla_len(rta) < sizeof(*thresh4))
1036 return -EINVAL;
1037 thresh4 = nla_data(rta);
1038 if (thresh4->lbits > 32 || thresh4->rbits > 32)
1039 return -EINVAL;
1040 }
1041 if (attrs[XFRMA_SPD_IPV6_HTHRESH]) {
1042 struct nlattr *rta = attrs[XFRMA_SPD_IPV6_HTHRESH];
1043
1044 if (nla_len(rta) < sizeof(*thresh6))
1045 return -EINVAL;
1046 thresh6 = nla_data(rta);
1047 if (thresh6->lbits > 128 || thresh6->rbits > 128)
1048 return -EINVAL;
1049 }
1050
1051 if (thresh4 || thresh6) {
1052 write_seqlock(&net->xfrm.policy_hthresh.lock);
1053 if (thresh4) {
1054 net->xfrm.policy_hthresh.lbits4 = thresh4->lbits;
1055 net->xfrm.policy_hthresh.rbits4 = thresh4->rbits;
1056 }
1057 if (thresh6) {
1058 net->xfrm.policy_hthresh.lbits6 = thresh6->lbits;
1059 net->xfrm.policy_hthresh.rbits6 = thresh6->rbits;
1060 }
1061 write_sequnlock(&net->xfrm.policy_hthresh.lock);
1062
1063 xfrm_policy_hash_rebuild(net);
1064 }
1065
1066 return 0;
1067}
1068
1007static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh,1069static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
1008 struct nlattr **attrs)1070 struct nlattr **attrs)
1009{1071{
@@ -2274,6 +2336,7 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { · 1264 unmodified lines
2274 [XFRM_MSG_REPORT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report),2336 [XFRM_MSG_REPORT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report),
2275 [XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),2337 [XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
2276 [XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = sizeof(u32),2338 [XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = sizeof(u32),
2339 [XFRM_MSG_NEWSPDINFO - XFRM_MSG_BASE] = sizeof(u32),
2277 [XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = sizeof(u32),2340 [XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = sizeof(u32),
2278};2341};
2279 2342
@@ -2308,10 +2371,17 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { · 28 unmodified lines
2308 [XFRMA_ADDRESS_FILTER] = { .len = sizeof(struct xfrm_address_filter) },2371 [XFRMA_ADDRESS_FILTER] = { .len = sizeof(struct xfrm_address_filter) },
2309};2372};
2310 2373
2374static const struct nla_policy xfrma_spd_policy[XFRMA_SPD_MAX+1] = {
2375 [XFRMA_SPD_IPV4_HTHRESH] = { .len = sizeof(struct xfrmu_spdhthresh) },
2376 [XFRMA_SPD_IPV6_HTHRESH] = { .len = sizeof(struct xfrmu_spdhthresh) },
2377};
2378
2311static const struct xfrm_link {2379static const struct xfrm_link {
2312 int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **);2380 int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **);
2313 int (*dump)(struct sk_buff *, struct netlink_callback *);2381 int (*dump)(struct sk_buff *, struct netlink_callback *);
2314 int (*done)(struct netlink_callback *);2382 int (*done)(struct netlink_callback *);
2383 const struct nla_policy *nla_pol;
2384 int nla_max;
2315} xfrm_dispatch[XFRM_NR_MSGTYPES] = {2385} xfrm_dispatch[XFRM_NR_MSGTYPES] = {
2316 [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa },2386 [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa },
2317 [XFRM_MSG_DELSA - XFRM_MSG_BASE] = { .doit = xfrm_del_sa },2387 [XFRM_MSG_DELSA - XFRM_MSG_BASE] = { .doit = xfrm_del_sa },
@@ -2335,6 +2405,9 @@ static const struct xfrm_link { · 17 unmodified lines
2335 [XFRM_MSG_GETAE - XFRM_MSG_BASE] = { .doit = xfrm_get_ae },2405 [XFRM_MSG_GETAE - XFRM_MSG_BASE] = { .doit = xfrm_get_ae },
2336 [XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = { .doit = xfrm_do_migrate },2406 [XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = { .doit = xfrm_do_migrate },
2337 [XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = { .doit = xfrm_get_sadinfo },2407 [XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = { .doit = xfrm_get_sadinfo },
2408 [XFRM_MSG_NEWSPDINFO - XFRM_MSG_BASE] = { .doit = xfrm_set_spdinfo,
2409 .nla_pol = xfrma_spd_policy,
2410 .nla_max = XFRMA_SPD_MAX },
2338 [XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = { .doit = xfrm_get_spdinfo },2411 [XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = { .doit = xfrm_get_spdinfo },
2339};2412};
2340 2413
@@ -2371,8 +2444,9 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) · 30 unmodified lines
2371 }2444 }
2372 }2445 }
2373 2446
2374 err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs, XFRMA_MAX,2447 err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs,
2375 xfrma_policy);2448 link->nla_max ? : XFRMA_MAX,
2449 link->nla_pol ? : xfrma_policy);
2376 if (err < 0)2450 if (err < 0)
2377 return err;2451 return err;
2378 2452