netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH RFC iproute v1 0/4] afnetns: add support for afnetns
@ 2017-03-12 23:01 Hannes Frederic Sowa
  2017-03-12 23:01 ` [PATCH RFC iproute v1 1/4] afnetns: add iproute bits " Hannes Frederic Sowa
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Hannes Frederic Sowa @ 2017-03-12 23:01 UTC (permalink / raw)
  To: netdev

This patchset adds support for afnetns to iproute.

For more information on afnetns please look at the kernel patchset.

Patches for util-linux commands, namely nsenter and unshare, is
available here: <https://github.com/hannes/util-linux/tree/afnetns>

Hannes Frederic Sowa (4):
  afnetns: add iproute bits for afnetns
  afnetns: support for ipv4/v6 address management
  afnetns: introduce lib/afnetns.c and a name cache
  afnetns: only show afnetns when show_details

 include/afnetns.h       |   6 ++
 include/libnetlink.h    |   7 ++
 include/linux/if_addr.h |   2 +
 include/namespace.h     |   4 +
 include/utils.h         |   1 +
 ip/Makefile             |   2 +-
 ip/ip.c                 |   5 +-
 ip/ip_common.h          |   1 +
 ip/ipaddress.c          |  38 ++++++++
 ip/ipafnetns.c          | 216 +++++++++++++++++++++++++++++++++++++++++++++
 lib/Makefile            |   2 +-
 lib/afnetns.c           | 226 ++++++++++++++++++++++++++++++++++++++++++++++++
 lib/utils.c             |  36 ++++++++
 13 files changed, 542 insertions(+), 4 deletions(-)
 create mode 100644 include/afnetns.h
 create mode 100644 ip/ipafnetns.c
 create mode 100644 lib/afnetns.c

-- 
2.9.3

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH RFC iproute v1 1/4] afnetns: add iproute bits for afnetns
  2017-03-12 23:01 [PATCH RFC iproute v1 0/4] afnetns: add support for afnetns Hannes Frederic Sowa
@ 2017-03-12 23:01 ` Hannes Frederic Sowa
  2017-03-13 15:10   ` Stephen Hemminger
  2017-03-12 23:01 ` [PATCH RFC iproute v1 2/4] afnetns: support for ipv4/v6 address management Hannes Frederic Sowa
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 6+ messages in thread
From: Hannes Frederic Sowa @ 2017-03-12 23:01 UTC (permalink / raw)
  To: netdev

Like ip netns, ip afnetns ... provides the basic utility features to
create, delete afnet namespaces and execute commands inside afnetns.

Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
---
 include/namespace.h |   5 ++
 include/utils.h     |   1 +
 ip/Makefile         |   2 +-
 ip/ip.c             |   5 +-
 ip/ip_common.h      |   1 +
 ip/ipafnetns.c      | 227 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/utils.c         |  36 +++++++++
 7 files changed, 274 insertions(+), 3 deletions(-)
 create mode 100644 ip/ipafnetns.c

diff --git a/include/namespace.h b/include/namespace.h
index 51324b21ba0cd5..acecc8c1f0d2b8 100644
--- a/include/namespace.h
+++ b/include/namespace.h
@@ -7,6 +7,7 @@
 #include <sys/syscall.h>
 #include <errno.h>
 
+#define AFNETNS_RUN_DIR "/var/run/afnetns"
 #define NETNS_RUN_DIR "/var/run/netns"
 #define NETNS_ETC_DIR "/etc/netns"
 
@@ -14,6 +15,10 @@
 #define CLONE_NEWNET 0x40000000	/* New network namespace (lo, device, names sockets, etc) */
 #endif
 
+#ifndef CLONE_NEWAFNET
+#define CLONE_NEWAFNET	0x00001000	/* Clone new afnet context */
+#endif
+
 #ifndef MNT_DETACH
 #define MNT_DETACH	0x00000002	/* Just detach from the tree */
 #endif /* MNT_DETACH */
diff --git a/include/utils.h b/include/utils.h
index 22369e0b4e0374..59fdd76b502b3c 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -256,6 +256,7 @@ int do_each_netns(int (*func)(char *nsname, void *arg), void *arg,
 char *int_to_str(int val, char *buf);
 int get_guid(__u64 *guid, const char *arg);
 int get_real_family(int rtm_type, int rtm_family);
+int cmd_exec(const char *cmd, char **argv, bool do_fork);
 
 int cmd_exec(const char *cmd, char **argv, bool do_fork);
 int make_path(const char *path, mode_t mode);
diff --git a/ip/Makefile b/ip/Makefile
index 4276a34b529e3f..4da6f33968ffe1 100644
--- a/ip/Makefile
+++ b/ip/Makefile
@@ -8,7 +8,7 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.o \
     link_iptnl.o link_gre6.o iplink_bond.o iplink_bond_slave.o iplink_hsr.o \
     iplink_bridge.o iplink_bridge_slave.o ipfou.o iplink_ipvlan.o \
     iplink_geneve.o iplink_vrf.o iproute_lwtunnel.o ipmacsec.o ipila.o \
-    ipvrf.o iplink_xstats.o
+    ipvrf.o iplink_xstats.o ipafnetns.o
 
 RTMONOBJ=rtmon.o
 
diff --git a/ip/ip.c b/ip/ip.c
index 07050b07592ac1..6aa8aaab4c03f9 100644
--- a/ip/ip.c
+++ b/ip/ip.c
@@ -51,8 +51,8 @@ static void usage(void)
 "       ip [ -force ] -batch filename\n"
 "where  OBJECT := { link | address | addrlabel | route | rule | neigh | ntable |\n"
 "                   tunnel | tuntap | maddress | mroute | mrule | monitor | xfrm |\n"
-"                   netns | l2tp | fou | macsec | tcp_metrics | token | netconf | ila |\n"
-"                   vrf }\n"
+"                   netns | afnetns | l2tp | fou | macsec | tcp_metrics | token |\n"
+"                   netconf | ila | vrf }\n"
 "       OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n"
 "                    -h[uman-readable] | -iec |\n"
 "                    -f[amily] { inet | inet6 | ipx | dnet | mpls | bridge | link } |\n"
@@ -99,6 +99,7 @@ static const struct cmd {
 	{ "mroute",	do_multiroute },
 	{ "mrule",	do_multirule },
 	{ "netns",	do_netns },
+	{ "afnetns",	do_afnetns },
 	{ "netconf",	do_ipnetconf },
 	{ "vrf",	do_ipvrf},
 	{ "help",	do_help },
diff --git a/ip/ip_common.h b/ip/ip_common.h
index 5a39623aa21d9f..1f59db40038ef2 100644
--- a/ip/ip_common.h
+++ b/ip/ip_common.h
@@ -50,6 +50,7 @@ int do_multiaddr(int argc, char **argv);
 int do_multiroute(int argc, char **argv);
 int do_multirule(int argc, char **argv);
 int do_netns(int argc, char **argv);
+int do_afnetns(int argc, char **argv);
 int do_xfrm(int argc, char **argv);
 int do_ipl2tp(int argc, char **argv);
 int do_ipfou(int argc, char **argv);
diff --git a/ip/ipafnetns.c b/ip/ipafnetns.c
new file mode 100644
index 00000000000000..5b7a7e59bc947a
--- /dev/null
+++ b/ip/ipafnetns.c
@@ -0,0 +1,227 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <fcntl.h>
+
+#include "utils.h"
+#include "ip_common.h"
+#include "namespace.h"
+
+static void usage(void)
+{
+	static const char *help =
+		"Usage: ip afnetns list\n"
+		"       ip afnetns add NAME\n"
+		"       ip afnetns del NAME\n"
+		"       ip afnetns exec NAME cmd ...\n";
+	fputs(help, stderr);
+}
+
+static int afnetns_list(void)
+{
+	struct dirent *entry;
+	DIR *dir;
+
+	dir = opendir(AFNETNS_RUN_DIR);
+	if (!dir)
+		return 0;
+
+	while ((entry = readdir(dir))) {
+		if (!strcmp(entry->d_name, ".") ||
+		    !strcmp(entry->d_name, ".."))
+			continue;
+		printf("%s\n", entry->d_name);
+	}
+	closedir(dir);
+
+	return 0;
+}
+
+static int create_afnetns_dir(void)
+{
+	int err;
+	const mode_t mode = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
+
+	err = mkdir(AFNETNS_RUN_DIR, mode);
+	if (!err || errno == EEXIST)
+		return 0;
+
+	fprintf(stderr, "Could not create afnet run dir \"%s\": %s\n",
+		AFNETNS_RUN_DIR, strerror(errno));
+	return err;
+}
+
+static int afnetns_delete(int argc, char **argv)
+{
+	const char *name;
+	char *path;
+	int err;
+
+	if (argc < 1) {
+		fputs("No afnetns name specified\n", stderr);
+		return -1;
+	}
+
+	name = argv[0];
+	err = asprintf(&path, "%s/%s", AFNETNS_RUN_DIR, name);
+	if (err < 0) {
+		perror("asprintf");
+		return err;
+	}
+
+	err = umount2(path, MNT_DETACH);
+	if (err)
+		fprintf(stderr, "Cannot umount afnet namespace file \"%s\": %s\n",
+			path, strerror(errno));
+
+	err = unlink(path);
+	if (err) {
+		fprintf(stderr, "Cannot remove afnet namespace file \"%s\": %s\n",
+			path, strerror(errno));
+		goto out;
+	}
+
+out:
+	free(path);
+	return err;
+}
+
+static int afnetns_add(int argc, char **argv)
+{
+	const char *name;
+	int err, fd;
+	char *path;
+
+	if (argc < 1) {
+		fputs("No afnetns name specified\n", stderr);
+		return -1;
+	}
+
+	err = create_afnetns_dir();
+	if (err)
+		return err;
+
+	name = argv[0];
+	err = asprintf(&path, "%s/%s", AFNETNS_RUN_DIR, name);
+	if (err < 0) {
+		perror("asprintf");
+		return err;
+	}
+
+	fd = open(path, O_RDONLY|O_CREAT|O_EXCL, 0);
+	if (fd < 0) {
+		err = fd;
+		fprintf(stderr, "Cannot create afnetns file \"%s\": %s\n",
+			path, strerror(errno));
+		goto out;
+	}
+	err = close(fd);
+	if (err) {
+		perror("close");
+		goto out;
+	}
+
+	err = unshare(CLONE_NEWAFNET);
+	if (err < 0) {
+		fprintf(stderr, "Failed to create a new afnet namesapce \"%s\": %s\n",
+			name, strerror(errno));
+		goto out;
+	}
+
+	err = mount("/proc/self/ns/afnet", path, "none", MS_BIND, NULL);
+	if (err < 0) {
+		fprintf(stderr, "Bind /proc/self/ns/afnet -> %s failed: %s\n",
+			path, strerror(errno));
+		goto out_delete;
+	}
+
+	err = 0;
+out:
+	free(path);
+	return err;
+out_delete:
+	afnetns_delete(argc, argv);
+	goto out;
+}
+
+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;
+	}
+
+	err = setns(ns, CLONE_NEWAFNET);
+	if (err) {
+		fprintf(stderr, "setting the afnet namespace \"%s\" failed: %s\n",
+			name, strerror(errno));
+		goto out;
+	}
+	err = close(ns);
+	if (err) {
+		perror("close");
+		goto out;
+	}
+
+out:
+	free(path);
+	return err;
+}
+
+static int afnetns_exec(int argc, char **argv)
+{
+	const char *cmd;
+	int err;
+
+	if (argc < 2) {
+		fputs("No netns name and or commands specified\n", stderr);
+		return -1;
+	}
+
+	err = afnetns_switch(argv[0]);
+	if (err)
+		return err;
+
+	cmd = argv[1];
+	return -cmd_exec(cmd, argv + 1, !!batch_mode);
+}
+
+int do_afnetns(int argc, char **argv)
+{
+	if (argc < 1)
+		return afnetns_list();
+
+	if (!matches(*argv, "help")) {
+		usage();
+		return 0;
+	}
+
+	if (!matches(*argv, "list") || !matches(*argv, "show") ||
+	    !matches(*argv, "lst"))
+		return afnetns_list();
+
+	if (!matches(*argv, "add"))
+		return afnetns_add(argc-1, argv+1);
+
+	if (!matches(*argv, "delete"))
+		return afnetns_delete(argc-1, argv+1);
+
+	if (!matches(*argv, "exec"))
+		return afnetns_exec(argc-1, argv+1);
+
+	fprintf(stderr, "Command \"%s\" is unkown, try \"ip afnetns help\".\n", *argv);
+	return -1;
+}
diff --git a/lib/utils.c b/lib/utils.c
index 6d5642f4f1f3fa..d80618f7c485a4 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -17,7 +17,9 @@
 #include <syslog.h>
 #include <fcntl.h>
 #include <limits.h>
+#include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/wait.h>
 #include <netinet/in.h>
 #include <string.h>
 #include <netdb.h>
@@ -1214,3 +1216,37 @@ int get_real_family(int rtm_type, int rtm_family)
 
 	return rtm_family == RTNL_FAMILY_IPMR ? AF_INET : AF_INET6;
 }
+
+int cmd_exec(const char *cmd, char **argv, bool do_fork)
+{
+	fflush(stdout);
+	if (do_fork) {
+		int status;
+		pid_t pid;
+
+		pid = fork();
+		if (pid < 0) {
+			perror("fork");
+			exit(1);
+		}
+
+		if (pid != 0) {
+			/* Parent  */
+			if (waitpid(pid, &status, 0) < 0) {
+				perror("waitpid");
+				exit(1);
+			}
+
+			if (WIFEXITED(status)) {
+				return WEXITSTATUS(status);
+			}
+
+			exit(1);
+		}
+	}
+
+	if (execvp(cmd, argv)  < 0)
+		fprintf(stderr, "exec of \"%s\" failed: %s\n",
+				cmd, strerror(errno));
+	_exit(1);
+}
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH RFC iproute v1 2/4] afnetns: support for ipv4/v6 address management
  2017-03-12 23:01 [PATCH RFC iproute v1 0/4] afnetns: add support for afnetns Hannes Frederic Sowa
  2017-03-12 23:01 ` [PATCH RFC iproute v1 1/4] afnetns: add iproute bits " Hannes Frederic Sowa
@ 2017-03-12 23:01 ` Hannes Frederic Sowa
  2017-03-12 23:01 ` [PATCH RFC iproute v1 3/4] afnetns: introduce lib/afnetns.c and a name cache Hannes Frederic Sowa
  2017-03-12 23:01 ` [PATCH RFC iproute v1 4/4] afnetns: only show afnetns when show_details Hannes Frederic Sowa
  3 siblings, 0 replies; 6+ messages in thread
From: Hannes Frederic Sowa @ 2017-03-12 23:01 UTC (permalink / raw)
  To: netdev

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

Signed-off-by: Hannes Frederic Sowa <hannes@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

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH RFC iproute v1 3/4] afnetns: introduce lib/afnetns.c and a name cache
  2017-03-12 23:01 [PATCH RFC iproute v1 0/4] afnetns: add support for afnetns Hannes Frederic Sowa
  2017-03-12 23:01 ` [PATCH RFC iproute v1 1/4] afnetns: add iproute bits " Hannes Frederic Sowa
  2017-03-12 23:01 ` [PATCH RFC iproute v1 2/4] afnetns: support for ipv4/v6 address management Hannes Frederic Sowa
@ 2017-03-12 23:01 ` Hannes Frederic Sowa
  2017-03-12 23:01 ` [PATCH RFC iproute v1 4/4] afnetns: only show afnetns when show_details Hannes Frederic Sowa
  3 siblings, 0 replies; 6+ messages in thread
From: Hannes Frederic Sowa @ 2017-03-12 23:01 UTC (permalink / raw)
  To: netdev

This patch adds a name cache for afnetns, so we don't need to scan the
inodes all the same again. This speeds up address list in case of many
configured afnetns and ip addresses.

Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
---
 include/afnetns.h   |   6 ++
 include/namespace.h |   3 -
 ip/ipaddress.c      |  12 ++-
 ip/ipafnetns.c      |   1 +
 lib/Makefile        |   2 +-
 lib/afnetns.c       | 226 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/namespace.c     |  21 -----
 7 files changed, 243 insertions(+), 28 deletions(-)
 create mode 100644 include/afnetns.h
 create mode 100644 lib/afnetns.c

diff --git a/include/afnetns.h b/include/afnetns.h
new file mode 100644
index 00000000000000..287bcb6153611b
--- /dev/null
+++ b/include/afnetns.h
@@ -0,0 +1,6 @@
+#pragma once
+
+#define AFNETNS_RUN_DIR "/var/run/afnetns"
+
+int afnetns_open(const char *name);
+char *afnetns_lookup_name(ino_t inode);
diff --git a/include/namespace.h b/include/namespace.h
index e0745ab0b50972..8193e474a75f98 100644
--- a/include/namespace.h
+++ b/include/namespace.h
@@ -7,7 +7,6 @@
 #include <sys/syscall.h>
 #include <errno.h>
 
-#define AFNETNS_RUN_DIR "/var/run/afnetns"
 #define NETNS_RUN_DIR "/var/run/netns"
 #define NETNS_ETC_DIR "/etc/netns"
 
@@ -52,8 +51,6 @@ 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 2994b6a3e0a154..d954f3ea5bff40 100644
--- a/ip/ipaddress.c
+++ b/ip/ipaddress.c
@@ -38,6 +38,7 @@
 #include "xdp.h"
 #include "color.h"
 #include "namespace.h"
+#include "afnetns.h"
 
 enum {
 	IPADD_LIST,
@@ -1004,7 +1005,7 @@ static int afnetns_get_fd(const char *name)
 {
 	int ns = -1;
 
-	if (name[0] == '/')
+	if (strnlen(name, 1) && name[0] == '/')
 		ns = open(name, O_RDONLY | O_CLOEXEC);
 	else
 		ns = afnetns_open(name);
@@ -1219,8 +1220,13 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
 		}
 	}
 	if (rta_tb[IFA_AFNETNS_INODE]) {
-		fprintf(fp, " afnet:[%u]",
-			rta_getattr_u32(rta_tb[IFA_AFNETNS_INODE]));
+		ino_t inode;
+		char *name;
+
+		inode = rta_getattr_u32(rta_tb[IFA_AFNETNS_INODE]);
+		name = afnetns_lookup_name(inode);
+		if (name)
+			fprintf(fp, " afnet %s", name);
 	}
 	fprintf(fp, "\n");
 brief_exit:
diff --git a/ip/ipafnetns.c b/ip/ipafnetns.c
index 5a197ad3866d18..2fd749a3f20628 100644
--- a/ip/ipafnetns.c
+++ b/ip/ipafnetns.c
@@ -7,6 +7,7 @@
 #include "utils.h"
 #include "ip_common.h"
 #include "namespace.h"
+#include "afnetns.h"
 
 static void usage(void)
 {
diff --git a/lib/Makefile b/lib/Makefile
index 1d24ca24b9a39f..7825021ea3cfa8 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -8,7 +8,7 @@ CFLAGS += -fPIC
 
 UTILOBJ = utils.o rt_names.o ll_types.o ll_proto.o ll_addr.o \
 	inet_proto.o namespace.o json_writer.o \
-	names.o color.o bpf.o exec.o fs.o
+	names.o color.o bpf.o exec.o fs.o afnetns.o
 
 NLOBJ=libgenl.o ll_map.o libnetlink.o
 
diff --git a/lib/afnetns.c b/lib/afnetns.c
new file mode 100644
index 00000000000000..d58a55df46daa7
--- /dev/null
+++ b/lib/afnetns.c
@@ -0,0 +1,226 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <dirent.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <math.h>
+
+#include "list.h"
+#include "afnetns.h"
+
+#define ULONG_CHARS ((int)ceill(log10l(ULONG_MAX)))
+
+static struct inode_cache {
+	struct inode_cache *next;
+	ino_t inode;
+	char name[];
+} *cache[64];
+
+static int self_inode(ino_t *me)
+{
+	static bool initialized;
+	static ino_t inode;
+	long path_size;
+	char *path;
+	int err;
+
+	if (initialized) {
+		*me = inode;
+		return 0;
+	}
+
+	errno = 0;
+	path_size = pathconf("/proc/self/ns/afnet", _PC_PATH_MAX);
+	if (path_size < 0) {
+		if (errno)
+			perror("pathconf");
+		else
+			fprintf(stderr,
+				"couldn't determine _PC_PATH_MAX for procfs: %zd\n",
+				path_size);
+		return -1;
+	}
+
+	path = malloc(path_size);
+	if (!path) {
+		perror("malloc");
+		return -1;
+	}
+
+	err = readlink("/proc/self/ns/afnet", path, path_size);
+	if (err < 0) {
+		perror("readlink");
+		goto out;
+	} else if (err >= path_size) {
+		fprintf(stderr, "readlink(\"/proc/self/ns/afnet\") exceeded maximum path length: %d >= %ld",
+			err, path_size);
+		err = -1;
+		goto out;
+	}
+	path[err] = '\0';
+
+	if (sscanf(path, "afnet:[%lu]", &inode) != 1) {
+		perror("sscanf");
+		err = -1;
+		goto out;
+	}
+
+	initialized = true;
+	*me = inode;
+	err = 0;
+out:
+	free(path);
+	return err;
+}
+
+static struct inode_cache **lookup_node(ino_t inode)
+{
+	struct inode_cache **node;
+
+	node = cache + (inode & 63);
+	while (*node && node[0]->inode != inode)
+		node = &node[0]->next;
+
+	return node;
+}
+
+static void fill_cache(void)
+{
+	struct dirent *ent;
+	ino_t me;
+	DIR *dir;
+
+	if (self_inode(&me))
+		return;
+
+	dir = opendir(AFNETNS_RUN_DIR);
+	if (!dir)
+		return;
+
+	errno = 0;
+	while ((ent = readdir(dir))) {
+		struct inode_cache **node;
+		struct stat buf;
+		ino_t inode;
+		bool self;
+		char *end;
+		int fd;
+
+		if (!strcmp(ent->d_name, ".") ||
+		    !strcmp(ent->d_name, ".."))
+			continue;
+
+		fd = dirfd(dir);
+		if (fd < 0) {
+			perror("dirfd");
+			continue;
+		}
+
+		if (fstatat(fd, ent->d_name, &buf, 0)) {
+			perror("fstatat");
+			continue;
+		}
+
+		inode = buf.st_ino;
+		self = me == inode;
+
+		node = lookup_node(inode);
+		if (*node)
+			continue;
+
+		*node = malloc(sizeof(**node)
+			       + strlen(ent->d_name)
+			       + (self ? strlen(",self") : 0)
+			       + 1);
+		if (!*node)
+			continue;
+
+		node[0]->next = NULL;
+		node[0]->inode = inode;
+		end  = stpcpy(node[0]->name, ent->d_name);
+		if (self)
+			strcpy(end, ",self");
+
+		errno = 0;
+	}
+
+	if (errno)
+		perror("readdir");
+
+	if (closedir(dir))
+		perror("closedir");
+}
+
+static char *lookup_cache(ino_t inode)
+{
+	struct inode_cache **node;
+	bool self;
+	ino_t me;
+
+	node = lookup_node(inode);
+	if (*node)
+		return node[0]->name;
+
+	if (self_inode(&me))
+		return NULL;
+
+	self = me == inode;
+
+	*node = malloc(sizeof(**node) + ULONG_CHARS + strlen("afnet:[]") + 1 +
+		       (self ? strlen(",self") : 0));
+	if (!*node)
+		return NULL;
+
+	if (sprintf(node[0]->name, "afnet:[%lu]%s", inode, self ? ",self" : "") < 0) {
+		free(*node);
+		*node = NULL;
+		return NULL;
+	}
+
+	node[0]->next = NULL;
+	node[0]->inode = inode;
+	return node[0]->name;
+}
+
+char *afnetns_lookup_name(ino_t inode)
+{
+	static bool initialized = false;
+
+	if (!initialized) {
+		fill_cache();
+		initialized = true;
+	}
+
+	return lookup_cache(inode);
+}
+
+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;
+}
+
diff --git a/lib/namespace.c b/lib/namespace.c
index f20e5b6ef5a3ef..30b513889e6e24 100644
--- a/lib/namespace.c
+++ b/lib/namespace.c
@@ -124,24 +124,3 @@ 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

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH RFC iproute v1 4/4] afnetns: only show afnetns when show_details
  2017-03-12 23:01 [PATCH RFC iproute v1 0/4] afnetns: add support for afnetns Hannes Frederic Sowa
                   ` (2 preceding siblings ...)
  2017-03-12 23:01 ` [PATCH RFC iproute v1 3/4] afnetns: introduce lib/afnetns.c and a name cache Hannes Frederic Sowa
@ 2017-03-12 23:01 ` Hannes Frederic Sowa
  3 siblings, 0 replies; 6+ messages in thread
From: Hannes Frederic Sowa @ 2017-03-12 23:01 UTC (permalink / raw)
  To: netdev

Only show afnetns details when details are requested.

Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
---
 ip/ipaddress.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ip/ipaddress.c b/ip/ipaddress.c
index d954f3ea5bff40..cfb58e70e4f29f 100644
--- a/ip/ipaddress.c
+++ b/ip/ipaddress.c
@@ -1219,7 +1219,7 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
 				fprintf(fp, "%usec", ci->ifa_prefered);
 		}
 	}
-	if (rta_tb[IFA_AFNETNS_INODE]) {
+	if (show_details && rta_tb[IFA_AFNETNS_INODE]) {
 		ino_t inode;
 		char *name;
 
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH RFC iproute v1 1/4] afnetns: add iproute bits for afnetns
  2017-03-12 23:01 ` [PATCH RFC iproute v1 1/4] afnetns: add iproute bits " Hannes Frederic Sowa
@ 2017-03-13 15:10   ` Stephen Hemminger
  0 siblings, 0 replies; 6+ messages in thread
From: Stephen Hemminger @ 2017-03-13 15:10 UTC (permalink / raw)
  To: Hannes Frederic Sowa; +Cc: netdev

On Mon, 13 Mar 2017 00:01:35 +0100
Hannes Frederic Sowa <hannes@stressinduktion.org> wrote:

> diff --git a/include/namespace.h b/include/namespace.h
> index 51324b21ba0cd5..acecc8c1f0d2b8 100644
> --- a/include/namespace.h
> +++ b/include/namespace.h
> @@ -7,6 +7,7 @@
>  #include <sys/syscall.h>
>  #include <errno.h>
>  
> +#define AFNETNS_RUN_DIR "/var/run/afnetns"
>  #define NETNS_RUN_DIR "/var/run/netns"
>  #define NETNS_ETC_DIR "/etc/netns"
>  
> @@ -14,6 +15,10 @@
>  #define CLONE_NEWNET 0x40000000	/* New network namespace (lo, device, names sockets, etc) */
>  #endif
>  
> +#ifndef CLONE_NEWAFNET
> +#define CLONE_NEWAFNET	0x00001000	/* Clone new afnet context */
> +#endif
> +

These bits really need to come from a kernel exported header.

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2017-03-13 15:10 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-03-12 23:01 [PATCH RFC iproute v1 0/4] afnetns: add support for afnetns Hannes Frederic Sowa
2017-03-12 23:01 ` [PATCH RFC iproute v1 1/4] afnetns: add iproute bits " Hannes Frederic Sowa
2017-03-13 15:10   ` Stephen Hemminger
2017-03-12 23:01 ` [PATCH RFC iproute v1 2/4] afnetns: support for ipv4/v6 address management Hannes Frederic Sowa
2017-03-12 23:01 ` [PATCH RFC iproute v1 3/4] afnetns: introduce lib/afnetns.c and a name cache Hannes Frederic Sowa
2017-03-12 23:01 ` [PATCH RFC iproute v1 4/4] afnetns: only show afnetns when show_details Hannes Frederic Sowa

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).