diff options
Diffstat (limited to 'net/xfrm/xfrm_policy.c')
| -rw-r--r-- | net/xfrm/xfrm_policy.c | 67 |
1 files changed, 36 insertions, 31 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 934492bad8e0..8d1a898d0ba5 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
| @@ -680,16 +680,6 @@ static void xfrm_hash_resize(struct work_struct *work) | |||
| 680 | mutex_unlock(&hash_resize_mutex); | 680 | mutex_unlock(&hash_resize_mutex); |
| 681 | } | 681 | } |
| 682 | 682 | ||
| 683 | static void xfrm_hash_reset_inexact_table(struct net *net) | ||
| 684 | { | ||
| 685 | struct xfrm_pol_inexact_bin *b; | ||
| 686 | |||
| 687 | lockdep_assert_held(&net->xfrm.xfrm_policy_lock); | ||
| 688 | |||
| 689 | list_for_each_entry(b, &net->xfrm.inexact_bins, inexact_bins) | ||
| 690 | INIT_HLIST_HEAD(&b->hhead); | ||
| 691 | } | ||
| 692 | |||
| 693 | /* Make sure *pol can be inserted into fastbin. | 683 | /* Make sure *pol can be inserted into fastbin. |
| 694 | * Useful to check that later insert requests will be sucessful | 684 | * Useful to check that later insert requests will be sucessful |
| 695 | * (provided xfrm_policy_lock is held throughout). | 685 | * (provided xfrm_policy_lock is held throughout). |
| @@ -833,13 +823,13 @@ static void xfrm_policy_inexact_list_reinsert(struct net *net, | |||
| 833 | u16 family) | 823 | u16 family) |
| 834 | { | 824 | { |
| 835 | unsigned int matched_s, matched_d; | 825 | unsigned int matched_s, matched_d; |
| 836 | struct hlist_node *newpos = NULL; | ||
| 837 | struct xfrm_policy *policy, *p; | 826 | struct xfrm_policy *policy, *p; |
| 838 | 827 | ||
| 839 | matched_s = 0; | 828 | matched_s = 0; |
| 840 | matched_d = 0; | 829 | matched_d = 0; |
| 841 | 830 | ||
| 842 | list_for_each_entry_reverse(policy, &net->xfrm.policy_all, walk.all) { | 831 | list_for_each_entry_reverse(policy, &net->xfrm.policy_all, walk.all) { |
| 832 | struct hlist_node *newpos = NULL; | ||
| 843 | bool matches_s, matches_d; | 833 | bool matches_s, matches_d; |
| 844 | 834 | ||
| 845 | if (!policy->bydst_reinsert) | 835 | if (!policy->bydst_reinsert) |
| @@ -849,16 +839,19 @@ static void xfrm_policy_inexact_list_reinsert(struct net *net, | |||
| 849 | 839 | ||
| 850 | policy->bydst_reinsert = false; | 840 | policy->bydst_reinsert = false; |
| 851 | hlist_for_each_entry(p, &n->hhead, bydst) { | 841 | hlist_for_each_entry(p, &n->hhead, bydst) { |
| 852 | if (policy->priority >= p->priority) | 842 | if (policy->priority > p->priority) |
| 843 | newpos = &p->bydst; | ||
| 844 | else if (policy->priority == p->priority && | ||
| 845 | policy->pos > p->pos) | ||
| 853 | newpos = &p->bydst; | 846 | newpos = &p->bydst; |
| 854 | else | 847 | else |
| 855 | break; | 848 | break; |
| 856 | } | 849 | } |
| 857 | 850 | ||
| 858 | if (newpos) | 851 | if (newpos) |
| 859 | hlist_add_behind(&policy->bydst, newpos); | 852 | hlist_add_behind_rcu(&policy->bydst, newpos); |
| 860 | else | 853 | else |
| 861 | hlist_add_head(&policy->bydst, &n->hhead); | 854 | hlist_add_head_rcu(&policy->bydst, &n->hhead); |
| 862 | 855 | ||
| 863 | /* paranoia checks follow. | 856 | /* paranoia checks follow. |
| 864 | * Check that the reinserted policy matches at least | 857 | * Check that the reinserted policy matches at least |
| @@ -893,12 +886,13 @@ static void xfrm_policy_inexact_node_reinsert(struct net *net, | |||
| 893 | struct rb_root *new, | 886 | struct rb_root *new, |
| 894 | u16 family) | 887 | u16 family) |
| 895 | { | 888 | { |
| 896 | struct rb_node **p, *parent = NULL; | ||
| 897 | struct xfrm_pol_inexact_node *node; | 889 | struct xfrm_pol_inexact_node *node; |
| 890 | struct rb_node **p, *parent; | ||
| 898 | 891 | ||
| 899 | /* we should not have another subtree here */ | 892 | /* we should not have another subtree here */ |
| 900 | WARN_ON_ONCE(!RB_EMPTY_ROOT(&n->root)); | 893 | WARN_ON_ONCE(!RB_EMPTY_ROOT(&n->root)); |
| 901 | 894 | restart: | |
| 895 | parent = NULL; | ||
| 902 | p = &new->rb_node; | 896 | p = &new->rb_node; |
| 903 | while (*p) { | 897 | while (*p) { |
| 904 | u8 prefixlen; | 898 | u8 prefixlen; |
| @@ -918,12 +912,11 @@ static void xfrm_policy_inexact_node_reinsert(struct net *net, | |||
| 918 | } else { | 912 | } else { |
| 919 | struct xfrm_policy *tmp; | 913 | struct xfrm_policy *tmp; |
| 920 | 914 | ||
| 921 | hlist_for_each_entry(tmp, &node->hhead, bydst) | 915 | hlist_for_each_entry(tmp, &n->hhead, bydst) { |
| 922 | tmp->bydst_reinsert = true; | ||
| 923 | hlist_for_each_entry(tmp, &n->hhead, bydst) | ||
| 924 | tmp->bydst_reinsert = true; | 916 | tmp->bydst_reinsert = true; |
| 917 | hlist_del_rcu(&tmp->bydst); | ||
| 918 | } | ||
| 925 | 919 | ||
| 926 | INIT_HLIST_HEAD(&node->hhead); | ||
| 927 | xfrm_policy_inexact_list_reinsert(net, node, family); | 920 | xfrm_policy_inexact_list_reinsert(net, node, family); |
| 928 | 921 | ||
| 929 | if (node->prefixlen == n->prefixlen) { | 922 | if (node->prefixlen == n->prefixlen) { |
| @@ -935,8 +928,7 @@ static void xfrm_policy_inexact_node_reinsert(struct net *net, | |||
| 935 | kfree_rcu(n, rcu); | 928 | kfree_rcu(n, rcu); |
| 936 | n = node; | 929 | n = node; |
| 937 | n->prefixlen = prefixlen; | 930 | n->prefixlen = prefixlen; |
| 938 | *p = new->rb_node; | 931 | goto restart; |
| 939 | parent = NULL; | ||
| 940 | } | 932 | } |
| 941 | } | 933 | } |
| 942 | 934 | ||
| @@ -965,12 +957,11 @@ static void xfrm_policy_inexact_node_merge(struct net *net, | |||
| 965 | family); | 957 | family); |
| 966 | } | 958 | } |
| 967 | 959 | ||
| 968 | hlist_for_each_entry(tmp, &v->hhead, bydst) | 960 | hlist_for_each_entry(tmp, &v->hhead, bydst) { |
| 969 | tmp->bydst_reinsert = true; | ||
| 970 | hlist_for_each_entry(tmp, &n->hhead, bydst) | ||
| 971 | tmp->bydst_reinsert = true; | 961 | tmp->bydst_reinsert = true; |
| 962 | hlist_del_rcu(&tmp->bydst); | ||
| 963 | } | ||
| 972 | 964 | ||
| 973 | INIT_HLIST_HEAD(&n->hhead); | ||
| 974 | xfrm_policy_inexact_list_reinsert(net, n, family); | 965 | xfrm_policy_inexact_list_reinsert(net, n, family); |
| 975 | } | 966 | } |
| 976 | 967 | ||
| @@ -1235,6 +1226,7 @@ static void xfrm_hash_rebuild(struct work_struct *work) | |||
| 1235 | } while (read_seqretry(&net->xfrm.policy_hthresh.lock, seq)); | 1226 | } while (read_seqretry(&net->xfrm.policy_hthresh.lock, seq)); |
| 1236 | 1227 | ||
| 1237 | spin_lock_bh(&net->xfrm.xfrm_policy_lock); | 1228 | spin_lock_bh(&net->xfrm.xfrm_policy_lock); |
| 1229 | write_seqcount_begin(&xfrm_policy_hash_generation); | ||
| 1238 | 1230 | ||
| 1239 | /* make sure that we can insert the indirect policies again before | 1231 | /* make sure that we can insert the indirect policies again before |
| 1240 | * we start with destructive action. | 1232 | * we start with destructive action. |
| @@ -1278,10 +1270,14 @@ static void xfrm_hash_rebuild(struct work_struct *work) | |||
| 1278 | } | 1270 | } |
| 1279 | 1271 | ||
| 1280 | /* reset the bydst and inexact table in all directions */ | 1272 | /* reset the bydst and inexact table in all directions */ |
| 1281 | xfrm_hash_reset_inexact_table(net); | ||
| 1282 | |||
| 1283 | for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { | 1273 | for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { |
| 1284 | INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]); | 1274 | struct hlist_node *n; |
| 1275 | |||
| 1276 | hlist_for_each_entry_safe(policy, n, | ||
| 1277 | &net->xfrm.policy_inexact[dir], | ||
| 1278 | bydst_inexact_list) | ||
| 1279 | hlist_del_init(&policy->bydst_inexact_list); | ||
| 1280 | |||
| 1285 | hmask = net->xfrm.policy_bydst[dir].hmask; | 1281 | hmask = net->xfrm.policy_bydst[dir].hmask; |
| 1286 | odst = net->xfrm.policy_bydst[dir].table; | 1282 | odst = net->xfrm.policy_bydst[dir].table; |
| 1287 | for (i = hmask; i >= 0; i--) | 1283 | for (i = hmask; i >= 0; i--) |
| @@ -1313,6 +1309,9 @@ static void xfrm_hash_rebuild(struct work_struct *work) | |||
| 1313 | newpos = NULL; | 1309 | newpos = NULL; |
| 1314 | chain = policy_hash_bysel(net, &policy->selector, | 1310 | chain = policy_hash_bysel(net, &policy->selector, |
| 1315 | policy->family, dir); | 1311 | policy->family, dir); |
| 1312 | |||
| 1313 | hlist_del_rcu(&policy->bydst); | ||
| 1314 | |||
| 1316 | if (!chain) { | 1315 | if (!chain) { |
| 1317 | void *p = xfrm_policy_inexact_insert(policy, dir, 0); | 1316 | void *p = xfrm_policy_inexact_insert(policy, dir, 0); |
| 1318 | 1317 | ||
| @@ -1334,6 +1333,7 @@ static void xfrm_hash_rebuild(struct work_struct *work) | |||
| 1334 | 1333 | ||
| 1335 | out_unlock: | 1334 | out_unlock: |
| 1336 | __xfrm_policy_inexact_flush(net); | 1335 | __xfrm_policy_inexact_flush(net); |
| 1336 | write_seqcount_end(&xfrm_policy_hash_generation); | ||
| 1337 | spin_unlock_bh(&net->xfrm.xfrm_policy_lock); | 1337 | spin_unlock_bh(&net->xfrm.xfrm_policy_lock); |
| 1338 | 1338 | ||
| 1339 | mutex_unlock(&hash_resize_mutex); | 1339 | mutex_unlock(&hash_resize_mutex); |
| @@ -2600,7 +2600,10 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, | |||
| 2600 | dst_copy_metrics(dst1, dst); | 2600 | dst_copy_metrics(dst1, dst); |
| 2601 | 2601 | ||
| 2602 | if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { | 2602 | if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { |
| 2603 | __u32 mark = xfrm_smark_get(fl->flowi_mark, xfrm[i]); | 2603 | __u32 mark = 0; |
| 2604 | |||
| 2605 | if (xfrm[i]->props.smark.v || xfrm[i]->props.smark.m) | ||
| 2606 | mark = xfrm_smark_get(fl->flowi_mark, xfrm[i]); | ||
| 2604 | 2607 | ||
| 2605 | family = xfrm[i]->props.family; | 2608 | family = xfrm[i]->props.family; |
| 2606 | dst = xfrm_dst_lookup(xfrm[i], tos, fl->flowi_oif, | 2609 | dst = xfrm_dst_lookup(xfrm[i], tos, fl->flowi_oif, |
| @@ -3311,8 +3314,10 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
| 3311 | 3314 | ||
| 3312 | if (ifcb) { | 3315 | if (ifcb) { |
| 3313 | xi = ifcb->decode_session(skb); | 3316 | xi = ifcb->decode_session(skb); |
| 3314 | if (xi) | 3317 | if (xi) { |
| 3315 | if_id = xi->p.if_id; | 3318 | if_id = xi->p.if_id; |
| 3319 | net = xi->net; | ||
| 3320 | } | ||
| 3316 | } | 3321 | } |
| 3317 | rcu_read_unlock(); | 3322 | rcu_read_unlock(); |
| 3318 | 3323 | ||
