aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm/xfrm_user.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_user.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_user.c')
-rw-r--r--net/xfrm/xfrm_user.c71
1 files changed, 43 insertions, 28 deletions
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index f971ca5645f8..f5fd5b3147cc 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -532,8 +532,6 @@ struct xfrm_dump_info {
532 struct sk_buff *out_skb; 532 struct sk_buff *out_skb;
533 u32 nlmsg_seq; 533 u32 nlmsg_seq;
534 u16 nlmsg_flags; 534 u16 nlmsg_flags;
535 int start_idx;
536 int this_idx;
537}; 535};
538 536
539static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb) 537static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb)
@@ -600,9 +598,6 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr)
600 struct nlmsghdr *nlh; 598 struct nlmsghdr *nlh;
601 int err; 599 int err;
602 600
603 if (sp->this_idx < sp->start_idx)
604 goto out;
605
606 nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq, 601 nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq,
607 XFRM_MSG_NEWSA, sizeof(*p), sp->nlmsg_flags); 602 XFRM_MSG_NEWSA, sizeof(*p), sp->nlmsg_flags);
608 if (nlh == NULL) 603 if (nlh == NULL)
@@ -615,8 +610,6 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr)
615 goto nla_put_failure; 610 goto nla_put_failure;
616 611
617 nlmsg_end(skb, nlh); 612 nlmsg_end(skb, nlh);
618out:
619 sp->this_idx++;
620 return 0; 613 return 0;
621 614
622nla_put_failure: 615nla_put_failure:
@@ -624,18 +617,32 @@ nla_put_failure:
624 return err; 617 return err;
625} 618}
626 619
620static int xfrm_dump_sa_done(struct netlink_callback *cb)
621{
622 struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1];
623 xfrm_state_walk_done(walk);
624 return 0;
625}
626
627static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb) 627static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb)
628{ 628{
629 struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1];
629 struct xfrm_dump_info info; 630 struct xfrm_dump_info info;
630 631
632 BUILD_BUG_ON(sizeof(struct xfrm_state_walk) >
633 sizeof(cb->args) - sizeof(cb->args[0]));
634
631 info.in_skb = cb->skb; 635 info.in_skb = cb->skb;
632 info.out_skb = skb; 636 info.out_skb = skb;
633 info.nlmsg_seq = cb->nlh->nlmsg_seq; 637 info.nlmsg_seq = cb->nlh->nlmsg_seq;
634 info.nlmsg_flags = NLM_F_MULTI; 638 info.nlmsg_flags = NLM_F_MULTI;
635 info.this_idx = 0; 639
636 info.start_idx = cb->args[0]; 640 if (!cb->args[0]) {
637 (void) xfrm_state_walk(0, dump_one_state, &info); 641 cb->args[0] = 1;
638 cb->args[0] = info.this_idx; 642 xfrm_state_walk_init(walk, 0);
643 }
644
645 (void) xfrm_state_walk(walk, dump_one_state, &info);
639 646
640 return skb->len; 647 return skb->len;
641} 648}
@@ -654,7 +661,6 @@ static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb,
654 info.out_skb = skb; 661 info.out_skb = skb;
655 info.nlmsg_seq = seq; 662 info.nlmsg_seq = seq;
656 info.nlmsg_flags = 0; 663 info.nlmsg_flags = 0;
657 info.this_idx = info.start_idx = 0;
658 664
659 if (dump_one_state(x, 0, &info)) { 665 if (dump_one_state(x, 0, &info)) {
660 kfree_skb(skb); 666 kfree_skb(skb);
@@ -1232,9 +1238,6 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr
1232 struct sk_buff *skb = sp->out_skb; 1238 struct sk_buff *skb = sp->out_skb;
1233 struct nlmsghdr *nlh; 1239 struct nlmsghdr *nlh;
1234 1240
1235 if (sp->this_idx < sp->start_idx)
1236 goto out;
1237
1238 nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq, 1241 nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq,
1239 XFRM_MSG_NEWPOLICY, sizeof(*p), sp->nlmsg_flags); 1242 XFRM_MSG_NEWPOLICY, sizeof(*p), sp->nlmsg_flags);
1240 if (nlh == NULL) 1243 if (nlh == NULL)
@@ -1250,8 +1253,6 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr
1250 goto nlmsg_failure; 1253 goto nlmsg_failure;
1251 1254
1252 nlmsg_end(skb, nlh); 1255 nlmsg_end(skb, nlh);
1253out:
1254 sp->this_idx++;
1255 return 0; 1256 return 0;
1256 1257
1257nlmsg_failure: 1258nlmsg_failure:
@@ -1259,21 +1260,33 @@ nlmsg_failure:
1259 return -EMSGSIZE; 1260 return -EMSGSIZE;
1260} 1261}
1261 1262
1263static int xfrm_dump_policy_done(struct netlink_callback *cb)
1264{
1265 struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1];
1266
1267 xfrm_policy_walk_done(walk);
1268 return 0;
1269}
1270
1262static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb) 1271static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb)
1263{ 1272{
1273 struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1];
1264 struct xfrm_dump_info info; 1274 struct xfrm_dump_info info;
1265 1275
1276 BUILD_BUG_ON(sizeof(struct xfrm_policy_walk) >
1277 sizeof(cb->args) - sizeof(cb->args[0]));
1278
1266 info.in_skb = cb->skb; 1279 info.in_skb = cb->skb;
1267 info.out_skb = skb; 1280 info.out_skb = skb;
1268 info.nlmsg_seq = cb->nlh->nlmsg_seq; 1281 info.nlmsg_seq = cb->nlh->nlmsg_seq;
1269 info.nlmsg_flags = NLM_F_MULTI; 1282 info.nlmsg_flags = NLM_F_MULTI;
1270 info.this_idx = 0; 1283
1271 info.start_idx = cb->args[0]; 1284 if (!cb->args[0]) {
1272 (void) xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_one_policy, &info); 1285 cb->args[0] = 1;
1273#ifdef CONFIG_XFRM_SUB_POLICY 1286 xfrm_policy_walk_init(walk, XFRM_POLICY_TYPE_ANY);
1274 (void) xfrm_policy_walk(XFRM_POLICY_TYPE_SUB, dump_one_policy, &info); 1287 }
1275#endif 1288
1276 cb->args[0] = info.this_idx; 1289 (void) xfrm_policy_walk(walk, dump_one_policy, &info);
1277 1290
1278 return skb->len; 1291 return skb->len;
1279} 1292}
@@ -1293,7 +1306,6 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb,
1293 info.out_skb = skb; 1306 info.out_skb = skb;
1294 info.nlmsg_seq = seq; 1307 info.nlmsg_seq = seq;
1295 info.nlmsg_flags = 0; 1308 info.nlmsg_flags = 0;
1296 info.this_idx = info.start_idx = 0;
1297 1309
1298 if (dump_one_policy(xp, dir, 0, &info) < 0) { 1310 if (dump_one_policy(xp, dir, 0, &info) < 0) {
1299 kfree_skb(skb); 1311 kfree_skb(skb);
@@ -1891,15 +1903,18 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
1891static struct xfrm_link { 1903static struct xfrm_link {
1892 int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **); 1904 int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **);
1893 int (*dump)(struct sk_buff *, struct netlink_callback *); 1905 int (*dump)(struct sk_buff *, struct netlink_callback *);
1906 int (*done)(struct netlink_callback *);
1894} xfrm_dispatch[XFRM_NR_MSGTYPES] = { 1907} xfrm_dispatch[XFRM_NR_MSGTYPES] = {
1895 [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa }, 1908 [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa },
1896 [XFRM_MSG_DELSA - XFRM_MSG_BASE] = { .doit = xfrm_del_sa }, 1909 [XFRM_MSG_DELSA - XFRM_MSG_BASE] = { .doit = xfrm_del_sa },
1897 [XFRM_MSG_GETSA - XFRM_MSG_BASE] = { .doit = xfrm_get_sa, 1910 [XFRM_MSG_GETSA - XFRM_MSG_BASE] = { .doit = xfrm_get_sa,
1898 .dump = xfrm_dump_sa }, 1911 .dump = xfrm_dump_sa,
1912 .done = xfrm_dump_sa_done },
1899 [XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, 1913 [XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy },
1900 [XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy }, 1914 [XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy },
1901 [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy, 1915 [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy,
1902 .dump = xfrm_dump_policy }, 1916 .dump = xfrm_dump_policy,
1917 .done = xfrm_dump_policy_done },
1903 [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi }, 1918 [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi },
1904 [XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire }, 1919 [XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire },
1905 [XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire }, 1920 [XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire },
@@ -1938,7 +1953,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
1938 if (link->dump == NULL) 1953 if (link->dump == NULL)
1939 return -EINVAL; 1954 return -EINVAL;
1940 1955
1941 return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, NULL); 1956 return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, link->done);
1942 } 1957 }
1943 1958
1944 err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs, XFRMA_MAX, 1959 err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs, XFRMA_MAX,