From: David Ahern <dsah...@gmail.com> Using iproute2 to create a bridge and add 4094 vlans to it can take from 2 to 3 *minutes*. The reason is the extraneous call to ll_name_to_index. ll_name_to_index results in an ioctl(SIOCGIFINDEX) call which in turn invokes dev_load. If the index does not exist, which it won't when creating a new link, dev_load calls modprobe twice -- once for netdev-NAME and again for NAME. This is unnecessary overhead for each link create.
When ip link is invoked for a new device, there is no reason to call ll_name_to_index for the new device. With this patch, creating a bridge and adding 4094 vlans takes less than 3 *seconds*. Signed-off-by: David Ahern <dsah...@gmail.com> --- ip/ip_common.h | 3 ++- ip/iplink.c | 22 +++++++++++++--------- ip/iplink_vxcan.c | 3 ++- ip/link_veth.c | 3 ++- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/ip/ip_common.h b/ip/ip_common.h index 1b89795caa58..67f413474631 100644 --- a/ip/ip_common.h +++ b/ip/ip_common.h @@ -132,7 +132,8 @@ struct link_util { struct link_util *get_link_kind(const char *kind); -int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type); +int iplink_parse(int argc, char **argv, struct iplink_req *req, + char **type, bool is_add_cmd); /* iplink_bridge.c */ void br_dump_bridge_id(const struct ifla_bridge_id *id, char *buf, size_t len); diff --git a/ip/iplink.c b/ip/iplink.c index e6bb4493120e..c8bf49ed3d24 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -571,7 +571,8 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp, return 0; } -int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type) +int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type, + bool is_add_cmd) { char *name = NULL; char *dev = NULL; @@ -610,7 +611,8 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type) name = *argv; if (!dev) { dev = name; - dev_index = ll_name_to_index(dev); + if (!is_add_cmd) + dev_index = ll_name_to_index(dev); } } else if (strcmp(*argv, "index") == 0) { NEXT_ARG(); @@ -919,7 +921,8 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type) if (check_ifname(*argv)) invarg("\"dev\" not a valid ifname", *argv); dev = *argv; - dev_index = ll_name_to_index(dev); + if (!is_add_cmd) + dev_index = ll_name_to_index(dev); } argc--; argv++; } @@ -1011,7 +1014,8 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type) return ret; } -static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv) +static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv, + bool is_add_cmd) { char *type = NULL; struct iplink_req req = { @@ -1022,7 +1026,7 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv) }; int ret; - ret = iplink_parse(argc, argv, &req, &type); + ret = iplink_parse(argc, argv, &req, &type, is_add_cmd); if (ret < 0) return ret; @@ -1630,18 +1634,18 @@ int do_iplink(int argc, char **argv) if (matches(*argv, "add") == 0) return iplink_modify(RTM_NEWLINK, NLM_F_CREATE|NLM_F_EXCL, - argc-1, argv+1); + argc-1, argv+1, true); if (matches(*argv, "set") == 0 || matches(*argv, "change") == 0) return iplink_modify(RTM_NEWLINK, 0, - argc-1, argv+1); + argc-1, argv+1, false); if (matches(*argv, "replace") == 0) return iplink_modify(RTM_NEWLINK, NLM_F_CREATE|NLM_F_REPLACE, - argc-1, argv+1); + argc-1, argv+1, false); if (matches(*argv, "delete") == 0) return iplink_modify(RTM_DELLINK, 0, - argc-1, argv+1); + argc-1, argv+1, false); } else { #if IPLINK_IOCTL_COMPAT if (matches(*argv, "set") == 0) diff --git a/ip/iplink_vxcan.c b/ip/iplink_vxcan.c index 8b08c9a70c65..e30a784d9851 100644 --- a/ip/iplink_vxcan.c +++ b/ip/iplink_vxcan.c @@ -56,7 +56,8 @@ static int vxcan_parse_opt(struct link_util *lu, int argc, char **argv, n->nlmsg_len += sizeof(struct ifinfomsg); - err = iplink_parse(argc - 1, argv + 1, (struct iplink_req *)n, &type); + err = iplink_parse(argc - 1, argv + 1, (struct iplink_req *)n, &type, + false); if (err < 0) return err; diff --git a/ip/link_veth.c b/ip/link_veth.c index 33e8f2b102e7..68823931c0ec 100644 --- a/ip/link_veth.c +++ b/ip/link_veth.c @@ -54,7 +54,8 @@ static int veth_parse_opt(struct link_util *lu, int argc, char **argv, n->nlmsg_len += sizeof(struct ifinfomsg); - err = iplink_parse(argc - 1, argv + 1, (struct iplink_req *)n, &type); + err = iplink_parse(argc - 1, argv + 1, (struct iplink_req *)n, &type, + false); if (err < 0) return err; -- 2.11.0