aboutsummaryrefslogtreecommitdiffstats
path: root/net/key/af_key.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/key/af_key.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/key/af_key.c')
-rw-r--r--net/key/af_key.c24
1 files changed, 20 insertions, 4 deletions
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 8b5f486ac80f..7cb6f1213360 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -1742,12 +1742,18 @@ static int pfkey_dump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr
1742{ 1742{
1743 u8 proto; 1743 u8 proto;
1744 struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk }; 1744 struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk };
1745 struct xfrm_state_walk walk;
1746 int rc;
1745 1747
1746 proto = pfkey_satype2proto(hdr->sadb_msg_satype); 1748 proto = pfkey_satype2proto(hdr->sadb_msg_satype);
1747 if (proto == 0) 1749 if (proto == 0)
1748 return -EINVAL; 1750 return -EINVAL;
1749 1751
1750 return xfrm_state_walk(proto, dump_sa, &data); 1752 xfrm_state_walk_init(&walk, proto);
1753 rc = xfrm_state_walk(&walk, dump_sa, &data);
1754 xfrm_state_walk_done(&walk);
1755
1756 return rc;
1751} 1757}
1752 1758
1753static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 1759static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
@@ -1780,7 +1786,9 @@ static int check_reqid(struct xfrm_policy *xp, int dir, int count, void *ptr)
1780 1786
1781static u32 gen_reqid(void) 1787static u32 gen_reqid(void)
1782{ 1788{
1789 struct xfrm_policy_walk walk;
1783 u32 start; 1790 u32 start;
1791 int rc;
1784 static u32 reqid = IPSEC_MANUAL_REQID_MAX; 1792 static u32 reqid = IPSEC_MANUAL_REQID_MAX;
1785 1793
1786 start = reqid; 1794 start = reqid;
@@ -1788,8 +1796,10 @@ static u32 gen_reqid(void)
1788 ++reqid; 1796 ++reqid;
1789 if (reqid == 0) 1797 if (reqid == 0)
1790 reqid = IPSEC_MANUAL_REQID_MAX+1; 1798 reqid = IPSEC_MANUAL_REQID_MAX+1;
1791 if (xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, check_reqid, 1799 xfrm_policy_walk_init(&walk, XFRM_POLICY_TYPE_MAIN);
1792 (void*)&reqid) != -EEXIST) 1800 rc = xfrm_policy_walk(&walk, check_reqid, (void*)&reqid);
1801 xfrm_policy_walk_done(&walk);
1802 if (rc != -EEXIST)
1793 return reqid; 1803 return reqid;
1794 } while (reqid != start); 1804 } while (reqid != start);
1795 return 0; 1805 return 0;
@@ -2665,8 +2675,14 @@ static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr)
2665static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 2675static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
2666{ 2676{
2667 struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk }; 2677 struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk };
2678 struct xfrm_policy_walk walk;
2679 int rc;
2680
2681 xfrm_policy_walk_init(&walk, XFRM_POLICY_TYPE_MAIN);
2682 rc = xfrm_policy_walk(&walk, dump_sp, &data);
2683 xfrm_policy_walk_done(&walk);
2668 2684
2669 return xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_sp, &data); 2685 return rc;
2670} 2686}
2671 2687
2672static int key_notify_policy_flush(struct km_event *c) 2688static int key_notify_policy_flush(struct km_event *c)