diff options
Diffstat (limited to 'net/xfrm/xfrm_policy.c')
-rw-r--r-- | net/xfrm/xfrm_policy.c | 123 |
1 files changed, 65 insertions, 58 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 841b32a2e680..832b47c1de80 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -34,7 +34,7 @@ | |||
34 | 34 | ||
35 | #include "xfrm_hash.h" | 35 | #include "xfrm_hash.h" |
36 | 36 | ||
37 | int sysctl_xfrm_larval_drop __read_mostly; | 37 | int sysctl_xfrm_larval_drop __read_mostly = 1; |
38 | 38 | ||
39 | #ifdef CONFIG_XFRM_STATISTICS | 39 | #ifdef CONFIG_XFRM_STATISTICS |
40 | DEFINE_SNMP_STAT(struct linux_xfrm_mib, xfrm_statistics) __read_mostly; | 40 | DEFINE_SNMP_STAT(struct linux_xfrm_mib, xfrm_statistics) __read_mostly; |
@@ -46,7 +46,7 @@ EXPORT_SYMBOL(xfrm_cfg_mutex); | |||
46 | 46 | ||
47 | static DEFINE_RWLOCK(xfrm_policy_lock); | 47 | static DEFINE_RWLOCK(xfrm_policy_lock); |
48 | 48 | ||
49 | static struct list_head xfrm_policy_bytype[XFRM_POLICY_TYPE_MAX]; | 49 | static struct list_head xfrm_policy_all; |
50 | unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2]; | 50 | unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2]; |
51 | EXPORT_SYMBOL(xfrm_policy_count); | 51 | EXPORT_SYMBOL(xfrm_policy_count); |
52 | 52 | ||
@@ -164,7 +164,7 @@ static void xfrm_policy_timer(unsigned long data) | |||
164 | 164 | ||
165 | read_lock(&xp->lock); | 165 | read_lock(&xp->lock); |
166 | 166 | ||
167 | if (xp->dead) | 167 | if (xp->walk.dead) |
168 | goto out; | 168 | goto out; |
169 | 169 | ||
170 | dir = xfrm_policy_id2dir(xp->index); | 170 | dir = xfrm_policy_id2dir(xp->index); |
@@ -236,7 +236,7 @@ struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp) | |||
236 | policy = kzalloc(sizeof(struct xfrm_policy), gfp); | 236 | policy = kzalloc(sizeof(struct xfrm_policy), gfp); |
237 | 237 | ||
238 | if (policy) { | 238 | if (policy) { |
239 | INIT_LIST_HEAD(&policy->bytype); | 239 | INIT_LIST_HEAD(&policy->walk.all); |
240 | INIT_HLIST_NODE(&policy->bydst); | 240 | INIT_HLIST_NODE(&policy->bydst); |
241 | INIT_HLIST_NODE(&policy->byidx); | 241 | INIT_HLIST_NODE(&policy->byidx); |
242 | rwlock_init(&policy->lock); | 242 | rwlock_init(&policy->lock); |
@@ -252,17 +252,13 @@ EXPORT_SYMBOL(xfrm_policy_alloc); | |||
252 | 252 | ||
253 | void xfrm_policy_destroy(struct xfrm_policy *policy) | 253 | void xfrm_policy_destroy(struct xfrm_policy *policy) |
254 | { | 254 | { |
255 | BUG_ON(!policy->dead); | 255 | BUG_ON(!policy->walk.dead); |
256 | 256 | ||
257 | BUG_ON(policy->bundles); | 257 | BUG_ON(policy->bundles); |
258 | 258 | ||
259 | if (del_timer(&policy->timer)) | 259 | if (del_timer(&policy->timer)) |
260 | BUG(); | 260 | BUG(); |
261 | 261 | ||
262 | write_lock_bh(&xfrm_policy_lock); | ||
263 | list_del(&policy->bytype); | ||
264 | write_unlock_bh(&xfrm_policy_lock); | ||
265 | |||
266 | security_xfrm_policy_free(policy->security); | 262 | security_xfrm_policy_free(policy->security); |
267 | kfree(policy); | 263 | kfree(policy); |
268 | } | 264 | } |
@@ -310,8 +306,8 @@ static void xfrm_policy_kill(struct xfrm_policy *policy) | |||
310 | int dead; | 306 | int dead; |
311 | 307 | ||
312 | write_lock_bh(&policy->lock); | 308 | write_lock_bh(&policy->lock); |
313 | dead = policy->dead; | 309 | dead = policy->walk.dead; |
314 | policy->dead = 1; | 310 | policy->walk.dead = 1; |
315 | write_unlock_bh(&policy->lock); | 311 | write_unlock_bh(&policy->lock); |
316 | 312 | ||
317 | if (unlikely(dead)) { | 313 | if (unlikely(dead)) { |
@@ -609,6 +605,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
609 | if (delpol) { | 605 | if (delpol) { |
610 | hlist_del(&delpol->bydst); | 606 | hlist_del(&delpol->bydst); |
611 | hlist_del(&delpol->byidx); | 607 | hlist_del(&delpol->byidx); |
608 | list_del(&delpol->walk.all); | ||
612 | xfrm_policy_count[dir]--; | 609 | xfrm_policy_count[dir]--; |
613 | } | 610 | } |
614 | policy->index = delpol ? delpol->index : xfrm_gen_index(policy->type, dir); | 611 | policy->index = delpol ? delpol->index : xfrm_gen_index(policy->type, dir); |
@@ -617,7 +614,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
617 | policy->curlft.use_time = 0; | 614 | policy->curlft.use_time = 0; |
618 | if (!mod_timer(&policy->timer, jiffies + HZ)) | 615 | if (!mod_timer(&policy->timer, jiffies + HZ)) |
619 | xfrm_pol_hold(policy); | 616 | xfrm_pol_hold(policy); |
620 | list_add_tail(&policy->bytype, &xfrm_policy_bytype[policy->type]); | 617 | list_add(&policy->walk.all, &xfrm_policy_all); |
621 | write_unlock_bh(&xfrm_policy_lock); | 618 | write_unlock_bh(&xfrm_policy_lock); |
622 | 619 | ||
623 | if (delpol) | 620 | if (delpol) |
@@ -684,6 +681,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir, | |||
684 | } | 681 | } |
685 | hlist_del(&pol->bydst); | 682 | hlist_del(&pol->bydst); |
686 | hlist_del(&pol->byidx); | 683 | hlist_del(&pol->byidx); |
684 | list_del(&pol->walk.all); | ||
687 | xfrm_policy_count[dir]--; | 685 | xfrm_policy_count[dir]--; |
688 | } | 686 | } |
689 | ret = pol; | 687 | ret = pol; |
@@ -727,6 +725,7 @@ struct xfrm_policy *xfrm_policy_byid(u8 type, int dir, u32 id, int delete, | |||
727 | } | 725 | } |
728 | hlist_del(&pol->bydst); | 726 | hlist_del(&pol->bydst); |
729 | hlist_del(&pol->byidx); | 727 | hlist_del(&pol->byidx); |
728 | list_del(&pol->walk.all); | ||
730 | xfrm_policy_count[dir]--; | 729 | xfrm_policy_count[dir]--; |
731 | } | 730 | } |
732 | ret = pol; | 731 | ret = pol; |
@@ -840,6 +839,7 @@ int xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info) | |||
840 | continue; | 839 | continue; |
841 | hlist_del(&pol->bydst); | 840 | hlist_del(&pol->bydst); |
842 | hlist_del(&pol->byidx); | 841 | hlist_del(&pol->byidx); |
842 | list_del(&pol->walk.all); | ||
843 | write_unlock_bh(&xfrm_policy_lock); | 843 | write_unlock_bh(&xfrm_policy_lock); |
844 | 844 | ||
845 | xfrm_audit_policy_delete(pol, 1, | 845 | xfrm_audit_policy_delete(pol, 1, |
@@ -867,60 +867,68 @@ int xfrm_policy_walk(struct xfrm_policy_walk *walk, | |||
867 | int (*func)(struct xfrm_policy *, int, int, void*), | 867 | int (*func)(struct xfrm_policy *, int, int, void*), |
868 | void *data) | 868 | void *data) |
869 | { | 869 | { |
870 | struct xfrm_policy *old, *pol, *last = NULL; | 870 | struct xfrm_policy *pol; |
871 | struct xfrm_policy_walk_entry *x; | ||
871 | int error = 0; | 872 | int error = 0; |
872 | 873 | ||
873 | if (walk->type >= XFRM_POLICY_TYPE_MAX && | 874 | if (walk->type >= XFRM_POLICY_TYPE_MAX && |
874 | walk->type != XFRM_POLICY_TYPE_ANY) | 875 | walk->type != XFRM_POLICY_TYPE_ANY) |
875 | return -EINVAL; | 876 | return -EINVAL; |
876 | 877 | ||
877 | if (walk->policy == NULL && walk->count != 0) | 878 | if (list_empty(&walk->walk.all) && walk->seq != 0) |
878 | return 0; | 879 | return 0; |
879 | 880 | ||
880 | old = pol = walk->policy; | 881 | write_lock_bh(&xfrm_policy_lock); |
881 | walk->policy = NULL; | 882 | if (list_empty(&walk->walk.all)) |
882 | read_lock_bh(&xfrm_policy_lock); | 883 | x = list_first_entry(&xfrm_policy_all, struct xfrm_policy_walk_entry, all); |
883 | 884 | else | |
884 | for (; walk->cur_type < XFRM_POLICY_TYPE_MAX; walk->cur_type++) { | 885 | x = list_entry(&walk->walk.all, struct xfrm_policy_walk_entry, all); |
885 | if (walk->type != walk->cur_type && | 886 | list_for_each_entry_from(x, &xfrm_policy_all, all) { |
886 | walk->type != XFRM_POLICY_TYPE_ANY) | 887 | if (x->dead) |
887 | continue; | 888 | continue; |
888 | 889 | pol = container_of(x, struct xfrm_policy, walk); | |
889 | if (pol == NULL) { | 890 | if (walk->type != XFRM_POLICY_TYPE_ANY && |
890 | pol = list_first_entry(&xfrm_policy_bytype[walk->cur_type], | 891 | walk->type != pol->type) |
891 | struct xfrm_policy, bytype); | 892 | continue; |
892 | } | 893 | error = func(pol, xfrm_policy_id2dir(pol->index), |
893 | list_for_each_entry_from(pol, &xfrm_policy_bytype[walk->cur_type], bytype) { | 894 | walk->seq, data); |
894 | if (pol->dead) | 895 | if (error) { |
895 | continue; | 896 | list_move_tail(&walk->walk.all, &x->all); |
896 | if (last) { | 897 | goto out; |
897 | error = func(last, xfrm_policy_id2dir(last->index), | ||
898 | walk->count, data); | ||
899 | if (error) { | ||
900 | xfrm_pol_hold(last); | ||
901 | walk->policy = last; | ||
902 | goto out; | ||
903 | } | ||
904 | } | ||
905 | last = pol; | ||
906 | walk->count++; | ||
907 | } | 898 | } |
908 | pol = NULL; | 899 | walk->seq++; |
909 | } | 900 | } |
910 | if (walk->count == 0) { | 901 | if (walk->seq == 0) { |
911 | error = -ENOENT; | 902 | error = -ENOENT; |
912 | goto out; | 903 | goto out; |
913 | } | 904 | } |
914 | if (last) | 905 | list_del_init(&walk->walk.all); |
915 | error = func(last, xfrm_policy_id2dir(last->index), 0, data); | ||
916 | out: | 906 | out: |
917 | read_unlock_bh(&xfrm_policy_lock); | 907 | write_unlock_bh(&xfrm_policy_lock); |
918 | if (old != NULL) | ||
919 | xfrm_pol_put(old); | ||
920 | return error; | 908 | return error; |
921 | } | 909 | } |
922 | EXPORT_SYMBOL(xfrm_policy_walk); | 910 | EXPORT_SYMBOL(xfrm_policy_walk); |
923 | 911 | ||
912 | void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type) | ||
913 | { | ||
914 | INIT_LIST_HEAD(&walk->walk.all); | ||
915 | walk->walk.dead = 1; | ||
916 | walk->type = type; | ||
917 | walk->seq = 0; | ||
918 | } | ||
919 | EXPORT_SYMBOL(xfrm_policy_walk_init); | ||
920 | |||
921 | void xfrm_policy_walk_done(struct xfrm_policy_walk *walk) | ||
922 | { | ||
923 | if (list_empty(&walk->walk.all)) | ||
924 | return; | ||
925 | |||
926 | write_lock_bh(&xfrm_policy_lock); | ||
927 | list_del(&walk->walk.all); | ||
928 | write_unlock_bh(&xfrm_policy_lock); | ||
929 | } | ||
930 | EXPORT_SYMBOL(xfrm_policy_walk_done); | ||
931 | |||
924 | /* | 932 | /* |
925 | * Find policy to apply to this flow. | 933 | * Find policy to apply to this flow. |
926 | * | 934 | * |
@@ -1077,6 +1085,7 @@ static void __xfrm_policy_link(struct xfrm_policy *pol, int dir) | |||
1077 | struct hlist_head *chain = policy_hash_bysel(&pol->selector, | 1085 | struct hlist_head *chain = policy_hash_bysel(&pol->selector, |
1078 | pol->family, dir); | 1086 | pol->family, dir); |
1079 | 1087 | ||
1088 | list_add(&pol->walk.all, &xfrm_policy_all); | ||
1080 | hlist_add_head(&pol->bydst, chain); | 1089 | hlist_add_head(&pol->bydst, chain); |
1081 | hlist_add_head(&pol->byidx, xfrm_policy_byidx+idx_hash(pol->index)); | 1090 | hlist_add_head(&pol->byidx, xfrm_policy_byidx+idx_hash(pol->index)); |
1082 | xfrm_policy_count[dir]++; | 1091 | xfrm_policy_count[dir]++; |
@@ -1094,6 +1103,7 @@ static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, | |||
1094 | 1103 | ||
1095 | hlist_del(&pol->bydst); | 1104 | hlist_del(&pol->bydst); |
1096 | hlist_del(&pol->byidx); | 1105 | hlist_del(&pol->byidx); |
1106 | list_del(&pol->walk.all); | ||
1097 | xfrm_policy_count[dir]--; | 1107 | xfrm_policy_count[dir]--; |
1098 | 1108 | ||
1099 | return pol; | 1109 | return pol; |
@@ -1719,7 +1729,7 @@ restart: | |||
1719 | 1729 | ||
1720 | for (pi = 0; pi < npols; pi++) { | 1730 | for (pi = 0; pi < npols; pi++) { |
1721 | read_lock_bh(&pols[pi]->lock); | 1731 | read_lock_bh(&pols[pi]->lock); |
1722 | pol_dead |= pols[pi]->dead; | 1732 | pol_dead |= pols[pi]->walk.dead; |
1723 | read_unlock_bh(&pols[pi]->lock); | 1733 | read_unlock_bh(&pols[pi]->lock); |
1724 | } | 1734 | } |
1725 | 1735 | ||
@@ -1731,8 +1741,7 @@ restart: | |||
1731 | * We can't enlist stable bundles either. | 1741 | * We can't enlist stable bundles either. |
1732 | */ | 1742 | */ |
1733 | write_unlock_bh(&policy->lock); | 1743 | write_unlock_bh(&policy->lock); |
1734 | if (dst) | 1744 | dst_free(dst); |
1735 | dst_free(dst); | ||
1736 | 1745 | ||
1737 | if (pol_dead) | 1746 | if (pol_dead) |
1738 | XFRM_INC_STATS(LINUX_MIB_XFRMOUTPOLDEAD); | 1747 | XFRM_INC_STATS(LINUX_MIB_XFRMOUTPOLDEAD); |
@@ -1748,8 +1757,7 @@ restart: | |||
1748 | err = xfrm_dst_update_origin(dst, fl); | 1757 | err = xfrm_dst_update_origin(dst, fl); |
1749 | if (unlikely(err)) { | 1758 | if (unlikely(err)) { |
1750 | write_unlock_bh(&policy->lock); | 1759 | write_unlock_bh(&policy->lock); |
1751 | if (dst) | 1760 | dst_free(dst); |
1752 | dst_free(dst); | ||
1753 | XFRM_INC_STATS(LINUX_MIB_XFRMOUTBUNDLECHECKERROR); | 1761 | XFRM_INC_STATS(LINUX_MIB_XFRMOUTBUNDLECHECKERROR); |
1754 | goto error; | 1762 | goto error; |
1755 | } | 1763 | } |
@@ -2416,9 +2424,7 @@ static void __init xfrm_policy_init(void) | |||
2416 | panic("XFRM: failed to allocate bydst hash\n"); | 2424 | panic("XFRM: failed to allocate bydst hash\n"); |
2417 | } | 2425 | } |
2418 | 2426 | ||
2419 | for (dir = 0; dir < XFRM_POLICY_TYPE_MAX; dir++) | 2427 | INIT_LIST_HEAD(&xfrm_policy_all); |
2420 | INIT_LIST_HEAD(&xfrm_policy_bytype[dir]); | ||
2421 | |||
2422 | INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task); | 2428 | INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task); |
2423 | register_netdevice_notifier(&xfrm_dev_notifier); | 2429 | register_netdevice_notifier(&xfrm_dev_notifier); |
2424 | } | 2430 | } |
@@ -2602,7 +2608,7 @@ static int xfrm_policy_migrate(struct xfrm_policy *pol, | |||
2602 | int i, j, n = 0; | 2608 | int i, j, n = 0; |
2603 | 2609 | ||
2604 | write_lock_bh(&pol->lock); | 2610 | write_lock_bh(&pol->lock); |
2605 | if (unlikely(pol->dead)) { | 2611 | if (unlikely(pol->walk.dead)) { |
2606 | /* target policy has been deleted */ | 2612 | /* target policy has been deleted */ |
2607 | write_unlock_bh(&pol->lock); | 2613 | write_unlock_bh(&pol->lock); |
2608 | return -ENOENT; | 2614 | return -ENOENT; |
@@ -2673,7 +2679,8 @@ static int xfrm_migrate_check(struct xfrm_migrate *m, int num_migrate) | |||
2673 | } | 2679 | } |
2674 | 2680 | ||
2675 | int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | 2681 | int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type, |
2676 | struct xfrm_migrate *m, int num_migrate) | 2682 | struct xfrm_migrate *m, int num_migrate, |
2683 | struct xfrm_kmaddress *k) | ||
2677 | { | 2684 | { |
2678 | int i, err, nx_cur = 0, nx_new = 0; | 2685 | int i, err, nx_cur = 0, nx_new = 0; |
2679 | struct xfrm_policy *pol = NULL; | 2686 | struct xfrm_policy *pol = NULL; |
@@ -2717,7 +2724,7 @@ int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | |||
2717 | } | 2724 | } |
2718 | 2725 | ||
2719 | /* Stage 5 - announce */ | 2726 | /* Stage 5 - announce */ |
2720 | km_migrate(sel, dir, type, m, num_migrate); | 2727 | km_migrate(sel, dir, type, m, num_migrate, k); |
2721 | 2728 | ||
2722 | xfrm_pol_put(pol); | 2729 | xfrm_pol_put(pol); |
2723 | 2730 | ||