Support ip address add xxx.yyy.zzz.lll/kk dev eth0 afnetns <afnetns-name>

Signed-off-by: Hannes Frederic Sowa <han...@stressinduktion.org>
---
 include/libnetlink.h    |  7 +++++++
 include/linux/if_addr.h |  2 ++
 include/namespace.h     |  2 ++
 ip/ipaddress.c          | 32 ++++++++++++++++++++++++++++++++
 ip/ipafnetns.c          | 26 +++++++-------------------
 lib/namespace.c         | 21 +++++++++++++++++++++
 6 files changed, 71 insertions(+), 19 deletions(-)

diff --git a/include/libnetlink.h b/include/libnetlink.h
index bd0267dfcc02ad..81ba0d3a032360 100644
--- a/include/libnetlink.h
+++ b/include/libnetlink.h
@@ -152,10 +152,17 @@ static inline __u32 rta_getattr_u32(const struct rtattr 
*rta)
 {
        return *(__u32 *)RTA_DATA(rta);
 }
+
+static inline __s32 rta_getattr_s32(const struct rtattr *rta)
+{
+       return *(__s32 *)RTA_DATA(rta);
+}
+
 static inline __be32 rta_getattr_be32(const struct rtattr *rta)
 {
        return ntohl(rta_getattr_u32(rta));
 }
+
 static inline __u64 rta_getattr_u64(const struct rtattr *rta)
 {
        __u64 tmp;
diff --git a/include/linux/if_addr.h b/include/linux/if_addr.h
index 26f0ecff9f13dd..dea1abe593ab29 100644
--- a/include/linux/if_addr.h
+++ b/include/linux/if_addr.h
@@ -32,6 +32,8 @@ enum {
        IFA_CACHEINFO,
        IFA_MULTICAST,
        IFA_FLAGS,
+       IFA_AFNETNS_FD,
+       IFA_AFNETNS_INODE,
        __IFA_MAX,
 };
 
diff --git a/include/namespace.h b/include/namespace.h
index acecc8c1f0d2b8..e0745ab0b50972 100644
--- a/include/namespace.h
+++ b/include/namespace.h
@@ -52,6 +52,8 @@ int netns_switch(char *netns);
 int netns_get_fd(const char *netns);
 int netns_foreach(int (*func)(char *nsname, void *arg), void *arg);
 
+int afnetns_open(const char *name);
+
 struct netns_func {
        int (*func)(char *nsname, void *arg);
        void *arg;
diff --git a/ip/ipaddress.c b/ip/ipaddress.c
index b8d9c7d917fe8d..2994b6a3e0a154 100644
--- a/ip/ipaddress.c
+++ b/ip/ipaddress.c
@@ -37,6 +37,7 @@
 #include "ip_common.h"
 #include "xdp.h"
 #include "color.h"
+#include "namespace.h"
 
 enum {
        IPADD_LIST,
@@ -999,6 +1000,18 @@ static int set_lifetime(unsigned int *lifetime, char 
*argv)
        return 0;
 }
 
+static int afnetns_get_fd(const char *name)
+{
+       int ns = -1;
+
+       if (name[0] == '/')
+               ns = open(name, O_RDONLY | O_CLOEXEC);
+       else
+               ns = afnetns_open(name);
+
+       return ns;
+}
+
 static unsigned int get_ifa_flags(struct ifaddrmsg *ifa,
                                  struct rtattr *ifa_flags_attr)
 {
@@ -1205,6 +1218,10 @@ int print_addrinfo(const struct sockaddr_nl *who, struct 
nlmsghdr *n,
                                fprintf(fp, "%usec", ci->ifa_prefered);
                }
        }
+       if (rta_tb[IFA_AFNETNS_INODE]) {
+               fprintf(fp, " afnet:[%u]",
+                       rta_getattr_u32(rta_tb[IFA_AFNETNS_INODE]));
+       }
        fprintf(fp, "\n");
 brief_exit:
        fflush(fp);
@@ -1883,6 +1900,7 @@ static int ipaddr_modify(int cmd, int flags, int argc, 
char **argv)
        int brd_len = 0;
        int any_len = 0;
        int scoped = 0;
+       int afnetns_fd = -1;
        __u32 preferred_lft = INFINITY_LIFE_TIME;
        __u32 valid_lft = INFINITY_LIFE_TIME;
        unsigned int ifa_flags = 0;
@@ -1958,6 +1976,14 @@ static int ipaddr_modify(int cmd, int flags, int argc, 
char **argv)
                        preferred_lftp = *argv;
                        if (set_lifetime(&preferred_lft, *argv))
                                invarg("preferred_lft value", *argv);
+               } else if (strcmp(*argv, "afnetns") == 0) {
+                       if (afnetns_fd != -1)
+                               duparg("afnetns", *argv);
+
+                       NEXT_ARG();
+                       afnetns_fd = afnetns_get_fd(*argv);
+                       if (afnetns_fd < 0)
+                               invarg("afnetns", *argv);
                } else if (strcmp(*argv, "home") == 0) {
                        ifa_flags |= IFA_F_HOMEADDRESS;
                } else if (strcmp(*argv, "nodad") == 0) {
@@ -2064,9 +2090,15 @@ static int ipaddr_modify(int cmd, int flags, int argc, 
char **argv)
                return -1;
        }
 
+       if (afnetns_fd != -1)
+               addattr32(&req.n, sizeof(req), IFA_AFNETNS_FD, afnetns_fd);
+
        if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
                return -2;
 
+       if (afnetns_fd > 0)
+               close(afnetns_fd);
+
        return 0;
 }
 
diff --git a/ip/ipafnetns.c b/ip/ipafnetns.c
index 5b7a7e59bc947a..5a197ad3866d18 100644
--- a/ip/ipafnetns.c
+++ b/ip/ipafnetns.c
@@ -148,37 +148,25 @@ out_delete:
 static int afnetns_switch(const char *name)
 {
        int err, ns;
-       char *path;
 
-       err = asprintf(&path, "%s/%s", AFNETNS_RUN_DIR, name);
-       if (err < 0) {
-               perror("asprintf");
-               return err;
-       };
-
-       ns = open(path, O_RDONLY | O_CLOEXEC);
-       if (ns < 0) {
-               fprintf(stderr, "Cannot open afnet namespace \"%s\": %s\n",
-                       name, strerror(errno));
-               err = ns;
-               goto out;
-       }
+       ns = afnetns_open(name);
+       if (ns < 0)
+               return ns;
 
        err = setns(ns, CLONE_NEWAFNET);
        if (err) {
                fprintf(stderr, "setting the afnet namespace \"%s\" failed: 
%s\n",
                        name, strerror(errno));
-               goto out;
+               return err;
        }
+
        err = close(ns);
        if (err) {
                perror("close");
-               goto out;
+               return err;
        }
 
-out:
-       free(path);
-       return err;
+       return 0;
 }
 
 static int afnetns_exec(int argc, char **argv)
diff --git a/lib/namespace.c b/lib/namespace.c
index 30b513889e6e24..f20e5b6ef5a3ef 100644
--- a/lib/namespace.c
+++ b/lib/namespace.c
@@ -124,3 +124,24 @@ int netns_foreach(int (*func)(char *nsname, void *arg), 
void *arg)
        closedir(dir);
        return 0;
 }
+
+int afnetns_open(const char *name)
+{
+       int ns;
+       char *path;
+
+       ns = asprintf(&path, "%s/%s", AFNETNS_RUN_DIR, name);
+       if (ns < 0) {
+               perror("asprintf");
+               return ns;
+       };
+
+       ns = open(path, O_RDONLY | O_CLOEXEC);
+       if (ns < 0) {
+               fprintf(stderr, "Cannot open afnet namespace \"%s\": %s\n",
+                       name, strerror(errno));
+       }
+
+       free(path);
+       return ns;
+}
-- 
2.9.3

Reply via email to