Blob Blame History Raw
commit f389090cd1dc2f9945c19f837ade98bd733015cb
Author: Pavel Šimerda <psimerda@redhat.com>
Date:   Thu May 28 23:39:22 2015 +0200

    backport selected library functions

diff --git a/include/libnetlink.h b/include/libnetlink.h
index ec3d657..5dcc0c3 100644
--- a/include/libnetlink.h
+++ b/include/libnetlink.h
@@ -18,6 +18,7 @@ struct rtnl_handle
 	struct sockaddr_nl	peer;
 	__u32			seq;
 	__u32			dump;
+	FILE		       *dump_fp;
 };
 
 extern int rcvbuf;
@@ -68,11 +69,15 @@ extern int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int le
 extern int parse_rtattr_flags(struct rtattr *tb[], int max, struct rtattr *rta,
 			      int len, unsigned short flags);
 extern int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len);
+extern struct rtattr *parse_rtattr_one(int type, struct rtattr *rta, int len);
 extern int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta, int len);
 
 #define parse_rtattr_nested(tb, max, rta) \
 	(parse_rtattr((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta)))
 
+#define parse_rtattr_one_nested(type, rta) \
+	(parse_rtattr_one(type, RTA_DATA(rta), RTA_PAYLOAD(rta)))
+
 #define parse_rtattr_nested_compat(tb, max, rta, data, len) \
 	({ data = RTA_PAYLOAD(rta) >= len ? RTA_DATA(rta) : NULL;	\
 		__parse_rtattr_nested_compat(tb, max, rta, len); })
@@ -140,5 +145,17 @@ extern int rtnl_from_file(FILE *, rtnl_filter_t handler,
 #define NDTA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndtmsg))
 #endif
 
+#ifndef NETNS_RTA
+#define NETNS_RTA(r) \
+	((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))))
+#endif
+#ifndef NETNS_PAYLOAD
+#define NETNS_PAYLOAD(n)	NLMSG_PAYLOAD(n,sizeof(struct rtgenmsg))
+#endif
+
+/* User defined nlmsg_type which is used mostly for logging netlink
+ * messages from dump file */
+#define NLMSG_TSTAMP	15
+
 #endif /* __LIBNETLINK_H__ */
 
diff --git a/include/namespace.h b/include/namespace.h
new file mode 100644
index 0000000..a2ac7dc
--- /dev/null
+++ b/include/namespace.h
@@ -0,0 +1,54 @@
+#ifndef __NAMESPACE_H__
+#define __NAMESPACE_H__ 1
+
+#include <sched.h>
+#include <sys/mount.h>
+#include <sys/syscall.h>
+#include <errno.h>
+
+#define NETNS_RUN_DIR "/var/run/netns"
+#define NETNS_ETC_DIR "/etc/netns"
+
+#ifndef CLONE_NEWNET
+#define CLONE_NEWNET 0x40000000	/* New network namespace (lo, device, names sockets, etc) */
+#endif
+
+#ifndef MNT_DETACH
+#define MNT_DETACH	0x00000002	/* Just detach from the tree */
+#endif /* MNT_DETACH */
+
+/* sys/mount.h may be out too old to have these */
+#ifndef MS_REC
+#define MS_REC		16384
+#endif
+
+#ifndef MS_SLAVE
+#define MS_SLAVE	(1 << 19)
+#endif
+
+#ifndef MS_SHARED
+#define MS_SHARED	(1 << 20)
+#endif
+
+#ifndef HAVE_SETNS
+static inline int setns(int fd, int nstype)
+{
+#ifdef __NR_setns
+	return syscall(__NR_setns, fd, nstype);
+#else
+	errno = ENOSYS;
+	return -1;
+#endif
+}
+#endif /* HAVE_SETNS */
+
+extern int netns_switch(char *netns);
+extern int netns_get_fd(const char *netns);
+extern int netns_foreach(int (*func)(char *nsname, void *arg), void *arg);
+
+struct netns_func {
+	int (*func)(char *nsname, void *arg);
+	void *arg;
+};
+
+#endif /* __NAMESPACE_H__ */
diff --git a/include/rt_names.h b/include/rt_names.h
index 37adbd3..c0ea4f9 100644
--- a/include/rt_names.h
+++ b/include/rt_names.h
@@ -8,6 +8,7 @@ const char *rtnl_rtscope_n2a(int id, char *buf, int len);
 const char *rtnl_rttable_n2a(__u32 id, char *buf, int len);
 const char *rtnl_rtrealm_n2a(int id, char *buf, int len);
 const char *rtnl_dsfield_n2a(int id, char *buf, int len);
+const char *rtnl_group_n2a(int id, char *buf, int len);
 
 int rtnl_rtprot_a2n(__u32 *id, const char *arg);
 int rtnl_rtscope_a2n(__u32 *id, const char *arg);
@@ -28,5 +29,7 @@ int ll_addr_a2n(char *lladdr, int len, const char *arg);
 const char * ll_proto_n2a(unsigned short id, char *buf, int len);
 int ll_proto_a2n(unsigned short *id, const char *buf);
 
+const char *nl_proto_n2a(int id, char *buf, int len);
+int nl_proto_a2n(__u32 *id, const char *arg);
 
 #endif
diff --git a/include/utils.h b/include/utils.h
index 24ff19f..ca05b02 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -5,12 +5,15 @@
 #include <asm/types.h>
 #include <resolv.h>
 #include <stdlib.h>
+#include <stdbool.h>
 
 #include "libnetlink.h"
 #include "ll_map.h"
 #include "rtm_map.h"
 
 extern int preferred_family;
+extern int human_readable;
+extern int use_iec;
 extern int show_stats;
 extern int show_details;
 extern int show_raw;
@@ -20,6 +23,7 @@ extern int timestamp;
 extern char * _SL_;
 extern int max_flush_loops;
 extern int batch_mode;
+extern bool do_all;
 
 #ifndef IPPROTO_ESP
 #define IPPROTO_ESP	50
@@ -151,9 +155,16 @@ int print_timestamp(FILE *fp);
 extern int cmdlineno;
 extern ssize_t getcmdline(char **line, size_t *len, FILE *in);
 extern int makeargs(char *line, char *argv[], int maxargs);
+extern int inet_get_addr(const char *src, __u32 *dst, struct in6_addr *dst6);
 
 struct iplink_req;
 int iplink_parse(int argc, char **argv, struct iplink_req *req,
 		char **name, char **type, char **link, char **dev,
 		int *group);
+
+extern int do_each_netns(int (*func)(char *nsname, void *arg), void *arg,
+		bool show_label);
+
+char *int_to_str(int val, char *buf);
+
 #endif /* __UTILS_H__ */
diff --git a/lib/Makefile b/lib/Makefile
index a42b885..66f89f1 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,8 +1,12 @@
 include ../Config
 
+ifeq ($(IP_CONFIG_SETNS),y)
+	CFLAGS += -DHAVE_SETNS
+endif
+
 CFLAGS += -fPIC
 
-UTILOBJ=utils.o rt_names.o ll_types.o ll_proto.o ll_addr.o inet_proto.o
+UTILOBJ=utils.o rt_names.o ll_types.o ll_proto.o ll_addr.o inet_proto.o namespace.o
 
 NLOBJ=libgenl.o ll_map.o libnetlink.o
 
diff --git a/lib/namespace.c b/lib/namespace.c
new file mode 100644
index 0000000..c03a103
--- /dev/null
+++ b/lib/namespace.c
@@ -0,0 +1,123 @@
+/*
+ * namespace.c
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ */
+
+#include <fcntl.h>
+#include <dirent.h>
+
+#include "utils.h"
+#include "namespace.h"
+
+static void bind_etc(const char *name)
+{
+	char etc_netns_path[MAXPATHLEN];
+	char netns_name[MAXPATHLEN];
+	char etc_name[MAXPATHLEN];
+	struct dirent *entry;
+	DIR *dir;
+
+	snprintf(etc_netns_path, sizeof(etc_netns_path), "%s/%s", NETNS_ETC_DIR, name);
+	dir = opendir(etc_netns_path);
+	if (!dir)
+		return;
+
+	while ((entry = readdir(dir)) != NULL) {
+		if (strcmp(entry->d_name, ".") == 0)
+			continue;
+		if (strcmp(entry->d_name, "..") == 0)
+			continue;
+		snprintf(netns_name, sizeof(netns_name), "%s/%s", etc_netns_path, entry->d_name);
+		snprintf(etc_name, sizeof(etc_name), "/etc/%s", entry->d_name);
+		if (mount(netns_name, etc_name, "none", MS_BIND, NULL) < 0) {
+			fprintf(stderr, "Bind %s -> %s failed: %s\n",
+				netns_name, etc_name, strerror(errno));
+		}
+	}
+	closedir(dir);
+}
+
+int netns_switch(char *name)
+{
+	char net_path[MAXPATHLEN];
+	int netns;
+
+	snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name);
+	netns = open(net_path, O_RDONLY | O_CLOEXEC);
+	if (netns < 0) {
+		fprintf(stderr, "Cannot open network namespace \"%s\": %s\n",
+			name, strerror(errno));
+		return -1;
+	}
+
+	if (setns(netns, CLONE_NEWNET) < 0) {
+		fprintf(stderr, "setting the network namespace \"%s\" failed: %s\n",
+			name, strerror(errno));
+		return -1;
+	}
+
+	if (unshare(CLONE_NEWNS) < 0) {
+		fprintf(stderr, "unshare failed: %s\n", strerror(errno));
+		return -1;
+	}
+	/* Don't let any mounts propagate back to the parent */
+	if (mount("", "/", "none", MS_SLAVE | MS_REC, NULL)) {
+		fprintf(stderr, "\"mount --make-rslave /\" failed: %s\n",
+			strerror(errno));
+		return -1;
+	}
+	/* Mount a version of /sys that describes the network namespace */
+	if (umount2("/sys", MNT_DETACH) < 0) {
+		fprintf(stderr, "umount of /sys failed: %s\n", strerror(errno));
+		return -1;
+	}
+	if (mount(name, "/sys", "sysfs", 0, NULL) < 0) {
+		fprintf(stderr, "mount of /sys failed: %s\n",strerror(errno));
+		return -1;
+	}
+
+	/* Setup bind mounts for config files in /etc */
+	bind_etc(name);
+	return 0;
+}
+
+int netns_get_fd(const char *name)
+{
+	char pathbuf[MAXPATHLEN];
+	const char *path, *ptr;
+
+	path = name;
+	ptr = strchr(name, '/');
+	if (!ptr) {
+		snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
+			NETNS_RUN_DIR, name );
+		path = pathbuf;
+	}
+	return open(path, O_RDONLY);
+}
+
+int netns_foreach(int (*func)(char *nsname, void *arg), void *arg)
+{
+	DIR *dir;
+	struct dirent *entry;
+
+	dir = opendir(NETNS_RUN_DIR);
+	if (!dir)
+		return -1;
+
+	while ((entry = readdir(dir)) != NULL) {
+		if (strcmp(entry->d_name, ".") == 0)
+			continue;
+		if (strcmp(entry->d_name, "..") == 0)
+			continue;
+		if (func(entry->d_name, arg))
+			break;
+	}
+
+	closedir(dir);
+	return 0;
+}
diff --git a/lib/rt_names.c b/lib/rt_names.c
index 02f1417..c2e60de 100644
--- a/lib/rt_names.c
+++ b/lib/rt_names.c
@@ -500,3 +500,104 @@ int rtnl_group_a2n(int *id, const char *arg)
 	*id = i;
 	return 0;
 }
+
+const char *rtnl_group_n2a(int id, char *buf, int len)
+{
+	struct rtnl_hash_entry *entry;
+	int i;
+
+	if (!rtnl_group_init)
+		rtnl_group_initialize();
+
+	for (i=0; i<256; i++) {
+		entry = rtnl_group_hash[i];
+		if (entry && entry->id == id) {
+			return entry->name;
+		}
+	}
+
+	snprintf(buf, len, "%d", id);
+	return buf;
+}
+
+static char *nl_proto_tab[256] = {
+	[NETLINK_ROUTE]          = "rtnl",
+	[NETLINK_UNUSED]         = "unused",
+	[NETLINK_USERSOCK]       = "usersock",
+	[NETLINK_FIREWALL]       = "fw",
+	[NETLINK_SOCK_DIAG]      = "tcpdiag",
+	[NETLINK_NFLOG]          = "nflog",
+	[NETLINK_XFRM]           = "xfrm",
+	[NETLINK_SELINUX]        = "selinux",
+	[NETLINK_ISCSI]          = "iscsi",
+	[NETLINK_AUDIT]          = "audit",
+	[NETLINK_FIB_LOOKUP]     = "fiblookup",
+	[NETLINK_CONNECTOR]      = "connector",
+	[NETLINK_NETFILTER]      = "nft",
+	[NETLINK_IP6_FW]         = "ip6fw",
+	[NETLINK_DNRTMSG]        = "dec-rt",
+	[NETLINK_KOBJECT_UEVENT] = "uevent",
+	[NETLINK_GENERIC]        = "genl",
+	[NETLINK_SCSITRANSPORT]  = "scsi-trans",
+	[NETLINK_ECRYPTFS]       = "ecryptfs",
+	[NETLINK_RDMA]           = "rdma",
+	[NETLINK_CRYPTO]         = "crypto",
+};
+
+static int nl_proto_init;
+
+static void nl_proto_initialize(void)
+{
+	nl_proto_init = 1;
+	rtnl_tab_initialize(CONFDIR "/nl_protos",
+			    nl_proto_tab, 256);
+}
+
+const char *nl_proto_n2a(int id, char *buf, int len)
+{
+	if (id < 0 || id >= 256) {
+		snprintf(buf, len, "%u", id);
+		return buf;
+	}
+
+	if (!nl_proto_init)
+		nl_proto_initialize();
+
+	if (nl_proto_tab[id])
+		return nl_proto_tab[id];
+
+	snprintf(buf, len, "%u", id);
+	return buf;
+}
+
+int nl_proto_a2n(__u32 *id, const char *arg)
+{
+	static char *cache = NULL;
+	static unsigned long res;
+	char *end;
+	int i;
+
+	if (cache && strcmp(cache, arg) == 0) {
+		*id = res;
+		return 0;
+	}
+
+	if (!nl_proto_init)
+		nl_proto_initialize();
+
+	for (i = 0; i < 256; i++) {
+		if (nl_proto_tab[i] &&
+		    strcmp(nl_proto_tab[i], arg) == 0) {
+			cache = nl_proto_tab[i];
+			res = i;
+			*id = res;
+			return 0;
+		}
+	}
+
+	res = strtoul(arg, &end, 0);
+	if (!end || end == arg || *end || res > 255)
+		return -1;
+	*id = res;
+	return 0;
+}
diff --git a/lib/utils.c b/lib/utils.c
index 0f9de02..299b485 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -31,6 +31,7 @@
 
 
 #include "utils.h"
+#include "namespace.h"
 
 int get_integer(int *val, const char *arg, int base)
 {
@@ -864,3 +865,44 @@ int makeargs(char *line, char *argv[], int maxargs)
 
 	return argc;
 }
+
+int inet_get_addr(const char *src, __u32 *dst, struct in6_addr *dst6)
+{
+	if (strchr(src, ':'))
+		return inet_pton(AF_INET6, src, dst6);
+	else
+		return inet_pton(AF_INET, src, dst);
+}
+
+static int on_netns(char *nsname, void *arg)
+{
+	struct netns_func *f = arg;
+
+	if (netns_switch(nsname))
+		return -1;
+
+	return f->func(nsname, f->arg);
+}
+
+static int on_netns_label(char *nsname, void *arg)
+{
+	printf("\nnetns: %s\n", nsname);
+	return on_netns(nsname, arg);
+}
+
+int do_each_netns(int (*func)(char *nsname, void *arg), void *arg,
+		bool show_label)
+{
+	struct netns_func nsf = { .func = func, .arg = arg };
+
+	if (show_label)
+		return netns_foreach(on_netns_label, &nsf);
+
+	return netns_foreach(on_netns, &nsf);
+}
+
+char *int_to_str(int val, char *buf)
+{
+	sprintf(buf, "%d", val);
+	return buf;
+}
diff --git a/misc/Makefile b/misc/Makefile
index a59ff87..a516bd8 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -5,6 +5,10 @@ TARGETS=ss nstat ifstat rtacct arpd lnstat
 
 include ../Config
 
+ifeq ($(IP_CONFIG_SETNS),y)
+	CFLAGS += -DHAVE_SETNS
+endif
+
 all: $(TARGETS)
 
 ss: $(SSOBJ)