aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm/xfrm_policy.c
diff options
context:
space:
mode:
authorTimo Teras <timo.teras@iki.fi>2008-02-29 00:31:08 -0500
committerDavid S. Miller <davem@davemloft.net>2008-02-29 00:31:08 -0500
commit4c563f7669c10a12354b72b518c2287ffc6ebfb3 (patch)
tree056ec93f192f31640f32983c9e11bc7ce1c0692f /net/xfrm/xfrm_policy.c
parent1e04d530705280770e003ac8db516722cca54758 (diff)
[XFRM]: Speed up xfrm_policy and xfrm_state walking
Change xfrm_policy and xfrm_state walking algorithm from O(n^2) to O(n). This is achieved adding the entries to one more list which is used solely for walking the entries. This also fixes some races where the dump can have duplicate or missing entries when the SPD/SADB is modified during an ongoing dump. Dumping SADB with 20000 entries using "time ip xfrm state" the sys time dropped from 1.012s to 0.080s. Signed-off-by: Timo Teras <timo.teras@iki.fi> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/xfrm/xfrm_policy.c')
-rw-r--r--net/xfrm/xfrm_policy.c79
1 files changed, 46 insertions, 33 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 9fc4c315f6cd..bae94a8031a2 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -46,6 +46,7 @@ EXPORT_SYMBOL(xfrm_cfg_mutex);
46 46
47static DEFINE_RWLOCK(xfrm_policy_lock); 47static DEFINE_RWLOCK(xfrm_policy_lock);
48 48
49static struct list_head xfrm_policy_bytype[XFRM_POLICY_TYPE_MAX];
49unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2]; 50unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2];
50EXPORT_SYMBOL(xfrm_policy_count); 51EXPORT_SYMBOL(xfrm_policy_count);
51 52
@@ -208,6 +209,7 @@ struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp)
208 policy = kzalloc(sizeof(struct xfrm_policy), gfp); 209 policy = kzalloc(sizeof(struct xfrm_policy), gfp);
209 210
210 if (policy) { 211 if (policy) {
212 INIT_LIST_HEAD(&policy->bytype);
211 INIT_HLIST_NODE(&policy->bydst); 213 INIT_HLIST_NODE(&policy->bydst);
212 INIT_HLIST_NODE(&policy->byidx); 214 INIT_HLIST_NODE(&policy->byidx);
213 rwlock_init(&policy->lock); 215 rwlock_init(&policy->lock);
@@ -230,6 +232,10 @@ void xfrm_policy_destroy(struct xfrm_policy *policy)
230 if (del_timer(&policy->timer)) 232 if (del_timer(&policy->timer))
231 BUG(); 233 BUG();
232 234
235 write_lock_bh(&xfrm_policy_lock);
236 list_del(&policy->bytype);
237 write_unlock_bh(&xfrm_policy_lock);
238
233 security_xfrm_policy_free(policy); 239 security_xfrm_policy_free(policy);
234 kfree(policy); 240 kfree(policy);
235} 241}
@@ -584,6 +590,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
584 policy->curlft.use_time = 0; 590 policy->curlft.use_time = 0;
585 if (!mod_timer(&policy->timer, jiffies + HZ)) 591 if (!mod_timer(&policy->timer, jiffies + HZ))
586 xfrm_pol_hold(policy); 592 xfrm_pol_hold(policy);
593 list_add_tail(&policy->bytype, &xfrm_policy_bytype[policy->type]);
587 write_unlock_bh(&xfrm_policy_lock); 594 write_unlock_bh(&xfrm_policy_lock);
588 595
589 if (delpol) 596 if (delpol)
@@ -822,57 +829,60 @@ out:
822} 829}
823EXPORT_SYMBOL(xfrm_policy_flush); 830EXPORT_SYMBOL(xfrm_policy_flush);
824 831
825int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), 832int xfrm_policy_walk(struct xfrm_policy_walk *walk,
833 int (*func)(struct xfrm_policy *, int, int, void*),
826 void *data) 834 void *data)
827{ 835{
828 struct xfrm_policy *pol, *last = NULL; 836 struct xfrm_policy *old, *pol, *last = NULL;
829 struct hlist_node *entry; 837 int error = 0;
830 int dir, last_dir = 0, count, error; 838
839 if (walk->type >= XFRM_POLICY_TYPE_MAX &&
840 walk->type != XFRM_POLICY_TYPE_ANY)
841 return -EINVAL;
831 842
843 if (walk->policy == NULL && walk->count != 0)
844 return 0;
845
846 old = pol = walk->policy;
847 walk->policy = NULL;
832 read_lock_bh(&xfrm_policy_lock); 848 read_lock_bh(&xfrm_policy_lock);
833 count = 0;
834 849
835 for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { 850 for (; walk->cur_type < XFRM_POLICY_TYPE_MAX; walk->cur_type++) {
836 struct hlist_head *table = xfrm_policy_bydst[dir].table; 851 if (walk->type != walk->cur_type &&
837 int i; 852 walk->type != XFRM_POLICY_TYPE_ANY)
853 continue;
838 854
839 hlist_for_each_entry(pol, entry, 855 if (pol == NULL) {
840 &xfrm_policy_inexact[dir], bydst) { 856 pol = list_first_entry(&xfrm_policy_bytype[walk->cur_type],
841 if (pol->type != type) 857 struct xfrm_policy, bytype);
858 }
859 list_for_each_entry_from(pol, &xfrm_policy_bytype[walk->cur_type], bytype) {
860 if (pol->dead)
842 continue; 861 continue;
843 if (last) { 862 if (last) {
844 error = func(last, last_dir % XFRM_POLICY_MAX, 863 error = func(last, xfrm_policy_id2dir(last->index),
845 count, data); 864 walk->count, data);
846 if (error) 865 if (error) {
866 xfrm_pol_hold(last);
867 walk->policy = last;
847 goto out; 868 goto out;
848 }
849 last = pol;
850 last_dir = dir;
851 count++;
852 }
853 for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {
854 hlist_for_each_entry(pol, entry, table + i, bydst) {
855 if (pol->type != type)
856 continue;
857 if (last) {
858 error = func(last, last_dir % XFRM_POLICY_MAX,
859 count, data);
860 if (error)
861 goto out;
862 } 869 }
863 last = pol;
864 last_dir = dir;
865 count++;
866 } 870 }
871 last = pol;
872 walk->count++;
867 } 873 }
874 pol = NULL;
868 } 875 }
869 if (count == 0) { 876 if (walk->count == 0) {
870 error = -ENOENT; 877 error = -ENOENT;
871 goto out; 878 goto out;
872 } 879 }
873 error = func(last, last_dir % XFRM_POLICY_MAX, 0, data); 880 if (last)
881 error = func(last, xfrm_policy_id2dir(last->index), 0, data);
874out: 882out:
875 read_unlock_bh(&xfrm_policy_lock); 883 read_unlock_bh(&xfrm_policy_lock);
884 if (old != NULL)
885 xfrm_pol_put(old);
876 return error; 886 return error;
877} 887}
878EXPORT_SYMBOL(xfrm_policy_walk); 888EXPORT_SYMBOL(xfrm_policy_walk);
@@ -2365,6 +2375,9 @@ static void __init xfrm_policy_init(void)
2365 panic("XFRM: failed to allocate bydst hash\n"); 2375 panic("XFRM: failed to allocate bydst hash\n");
2366 } 2376 }
2367 2377
2378 for (dir = 0; dir < XFRM_POLICY_TYPE_MAX; dir++)
2379 INIT_LIST_HEAD(&xfrm_policy_bytype[dir]);
2380
2368 INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task); 2381 INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task);
2369 register_netdevice_notifier(&xfrm_dev_notifier); 2382 register_netdevice_notifier(&xfrm_dev_notifier);
2370} 2383}