diff options
| author | Christophe Gouault <christophe.gouault@6wind.com> | 2014-08-29 10:16:05 -0400 |
|---|---|---|
| committer | Steffen Klassert <steffen.klassert@secunet.com> | 2014-09-02 07:37:56 -0400 |
| commit | 880a6fab8f6ba5b5abe59ea68533202ddea1012c (patch) | |
| tree | d5e83238ad632d0473aa3b75a5233359154df049 | |
| parent | b58555f1767c9f4e330fcf168e4e753d2d9196e0 (diff) | |
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.
Signed-off-by: Christophe Gouault <christophe.gouault@6wind.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
| -rw-r--r-- | include/net/netns/xfrm.h | 10 | ||||
| -rw-r--r-- | include/net/xfrm.h | 1 | ||||
| -rw-r--r-- | include/uapi/linux/xfrm.h | 7 | ||||
| -rw-r--r-- | net/xfrm/xfrm_policy.c | 87 | ||||
| -rw-r--r-- | net/xfrm/xfrm_user.c | 80 |
5 files changed, 182 insertions, 3 deletions
diff --git a/include/net/netns/xfrm.h b/include/net/netns/xfrm.h index 41902a8103bd..9da798256f0e 100644 --- a/include/net/netns/xfrm.h +++ b/include/net/netns/xfrm.h | |||
| @@ -19,6 +19,15 @@ struct xfrm_policy_hash { | |||
| 19 | u8 sbits6; | 19 | u8 sbits6; |
| 20 | }; | 20 | }; |
| 21 | 21 | ||
| 22 | struct 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 | |||
| 22 | struct netns_xfrm { | 31 | struct netns_xfrm { |
| 23 | struct list_head state_all; | 32 | struct list_head state_all; |
| 24 | /* | 33 | /* |
| @@ -45,6 +54,7 @@ struct netns_xfrm { | |||
| 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; |
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, | |||
| 1591 | struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8, int dir, | 1591 | struct 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); |
| 1593 | int xfrm_policy_flush(struct net *net, u8 type, bool task_valid); | 1593 | int xfrm_policy_flush(struct net *net, u8 type, bool task_valid); |
| 1594 | void xfrm_policy_hash_rebuild(struct net *net); | ||
| 1594 | u32 xfrm_get_acqseq(void); | 1595 | u32 xfrm_get_acqseq(void); |
| 1595 | int verify_spi_info(u8 proto, u32 min, u32 max); | 1596 | int verify_spi_info(u8 proto, u32 min, u32 max); |
| 1596 | int xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi); | 1597 | int 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 | ||
| 352 | struct xfrmu_spdhthresh { | ||
| 353 | __u8 lbits; | ||
| 354 | __u8 rbits; | ||
| 355 | }; | ||
| 356 | |||
| 350 | struct xfrm_usersa_info { | 357 | struct 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/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; |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index d4db6ebb089d..eaf8a8f1cbe8 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
| @@ -964,7 +964,9 @@ static inline size_t xfrm_spdinfo_msgsize(void) | |||
| 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 | ||
| 970 | static int build_spdinfo(struct sk_buff *skb, struct net *net, | 972 | static 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, | |||
| 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, | |||
| 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, | |||
| 1004 | return nlmsg_end(skb, nlh); | 1021 | return nlmsg_end(skb, nlh); |
| 1005 | } | 1022 | } |
| 1006 | 1023 | ||
| 1024 | static 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 | |||
| 1007 | static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh, | 1069 | static 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] = { | |||
| 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] = { | |||
| 2308 | [XFRMA_ADDRESS_FILTER] = { .len = sizeof(struct xfrm_address_filter) }, | 2371 | [XFRMA_ADDRESS_FILTER] = { .len = sizeof(struct xfrm_address_filter) }, |
| 2309 | }; | 2372 | }; |
| 2310 | 2373 | ||
| 2374 | static 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 | |||
| 2311 | static const struct xfrm_link { | 2379 | static 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 { | |||
| 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) | |||
| 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 | ||
