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

Reply via email to