From: Jiri Pirko <j...@mellanox.com> Signed-off-by: Jiri Pirko <j...@mellanox.com> --- include/uapi/linux/if_link.h | 3 ++ include/uapi/linux/rtnetlink.h | 7 +++ include/utils.h | 1 + ip/ipaddress.c | 14 ++++++ ip/iplink.c | 81 ++++++++++++++++++++++++++++++++++ lib/utils.c | 19 +++++--- 6 files changed, 120 insertions(+), 5 deletions(-)
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index d36919fb4024..2386a3e94082 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -167,6 +167,9 @@ enum { IFLA_NEW_IFINDEX, IFLA_MIN_MTU, IFLA_MAX_MTU, + IFLA_ALT_IFNAME_MOD, /* Alternative ifname to add/delete */ + IFLA_ALT_IFNAME_LIST, /* nest */ + IFLA_ALT_IFNAME, /* Alternative ifname */ __IFLA_MAX }; diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h index 358e83ee134d..38a4f5b55e17 100644 --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h @@ -164,6 +164,13 @@ enum { RTM_GETNEXTHOP, #define RTM_GETNEXTHOP RTM_GETNEXTHOP + RTM_NEWALTIFNAME = 108, +#define RTM_NEWALTIFNAME RTM_NEWALTIFNAME + RTM_DELALTIFNAME, +#define RTM_DELALTIFNAME RTM_DELALTIFNAME + RTM_GETALTIFNAME, +#define RTM_GETALTIFNAME RTM_GETALTIFNAME + __RTM_MAX, #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) }; diff --git a/include/utils.h b/include/utils.h index 794d36053634..2dd6443fc6ff 100644 --- a/include/utils.h +++ b/include/utils.h @@ -196,6 +196,7 @@ void duparg(const char *, const char *) __attribute__((noreturn)); void duparg2(const char *, const char *) __attribute__((noreturn)); int nodev(const char *dev); int check_ifname(const char *); +int check_altifname(const char *); int get_ifname(char *, const char *); const char *get_ifname_rta(int ifindex, const struct rtattr *rta); bool matches(const char *prefix, const char *string); diff --git a/ip/ipaddress.c b/ip/ipaddress.c index bc8f5ba13c33..8060161dcf1a 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -1139,6 +1139,20 @@ int print_linkinfo(struct nlmsghdr *n, void *arg) close_json_array(PRINT_JSON, NULL); } + if (tb[IFLA_ALT_IFNAME_LIST]) { + struct rtattr *i, *alt_ifname_list = tb[IFLA_ALT_IFNAME_LIST]; + int rem = RTA_PAYLOAD(alt_ifname_list); + + open_json_array(PRINT_JSON, "altifnames"); + for (i = RTA_DATA(alt_ifname_list); RTA_OK(i, rem); + i = RTA_NEXT(i, rem)) { + print_nl(); + print_string(PRINT_ANY, NULL, + " altname %s", rta_getattr_str(i)); + } + close_json_array(PRINT_JSON, NULL); + } + print_string(PRINT_FP, NULL, "%s", "\n"); fflush(fp); return 1; diff --git a/ip/iplink.c b/ip/iplink.c index 212a088535da..45f975f1dce9 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -1617,6 +1617,84 @@ static int iplink_afstats(int argc, char **argv) return 0; } +static int iplink_altname_mod(int argc, char **argv, struct iplink_req *req) +{ + char *name = NULL; + char *dev = NULL; + + while (argc > 0) { + if (matches(*argv, "name") == 0) { + NEXT_ARG(); + if (check_altifname(*argv)) + invarg("not a valid altifname", *argv); + name = *argv; + } else if (matches(*argv, "help") == 0) { + usage(); + } else { + if (strcmp(*argv, "dev") == 0) + NEXT_ARG(); + if (dev) + duparg2("dev", *argv); + if (check_altifname(*argv)) + invarg("\"dev\" not a valid altifname", *argv); + dev = *argv; + } + argv++; argc--; + } + + if (!dev) { + fprintf(stderr, "Not enough of information: \"dev\" argument is required.\n"); + exit(-1); + } + + if (!name) { + if (req->n.nlmsg_type != RTM_NEWALTIFNAME) { + name = dev; + } else { + fprintf(stderr, "Not enough of information: \"name\" argument is required.\n"); + exit(-1); + } + } + + addattr_l(&req->n, sizeof(*req), IFLA_ALT_IFNAME, + dev, strlen(dev) + 1); + addattr_l(&req->n, sizeof(*req), IFLA_ALT_IFNAME_MOD, + name, strlen(name) + 1); + + if (rtnl_talk(&rth, &req->n, NULL) < 0) + return -2; + + return 0; +} + +static int iplink_altname(int argc, char **argv) +{ + struct iplink_req req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), + .n.nlmsg_flags = NLM_F_REQUEST, + .i.ifi_family = preferred_family, + }; + + if (argc <= 0) { + usage(); + exit(-1); + } + + if (matches(*argv, "add") == 0) { + req.n.nlmsg_flags |= NLM_F_EXCL | NLM_F_CREATE | NLM_F_APPEND; + req.n.nlmsg_type = RTM_NEWALTIFNAME; + } else if (matches(*argv, "del") == 0) { + req.n.nlmsg_flags |= RTM_DELLINK; + req.n.nlmsg_type = RTM_DELALTIFNAME; + } else if (matches(*argv, "help") == 0) { + usage(); + } else { + fprintf(stderr, "Operator required\n"); + exit(-1); + } + return iplink_altname_mod(argc - 1, argv + 1, &req); +} + static void do_help(int argc, char **argv) { struct link_util *lu = NULL; @@ -1674,6 +1752,9 @@ int do_iplink(int argc, char **argv) return 0; } + if (matches(*argv, "altname") == 0) + return iplink_altname(argc-1, argv+1); + if (matches(*argv, "help") == 0) { do_help(argc-1, argv+1); return 0; diff --git a/lib/utils.c b/lib/utils.c index 9ea21fa16503..80e025e96a5a 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -824,14 +824,10 @@ int nodev(const char *dev) return -1; } -int check_ifname(const char *name) +static int __check_ifname(const char *name) { - /* These checks mimic kernel checks in dev_valid_name */ if (*name == '\0') return -1; - if (strlen(name) >= IFNAMSIZ) - return -1; - while (*name) { if (*name == '/' || isspace(*name)) return -1; @@ -840,6 +836,19 @@ int check_ifname(const char *name) return 0; } +int check_ifname(const char *name) +{ + /* These checks mimic kernel checks in dev_valid_name */ + if (strlen(name) >= IFNAMSIZ) + return -1; + return __check_ifname(name); +} + +int check_altifname(const char *name) +{ + return __check_ifname(name); +} + /* buf is assumed to be IFNAMSIZ */ int get_ifname(char *buf, const char *name) { -- 2.21.0