naccyde / rpms / iproute

Forked from rpms/iproute 7 months ago
Clone
Blob Blame History Raw
From 3873ff54417f7e514197d069bcad187ca2ec3b86 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Mon, 10 Aug 2015 17:26:16 +0200
Subject: [PATCH] {ip,xfrm}monitor: allows to monitor in several netns

This is a combination of six commits:

commit c1f4d1640efa2ba2219861852b351d5c369c3715
Author: Phil Sutter <psutter@redhat.com>
Date:   Mon Aug 10 17:26:16 2015 +0200

    include/linux/netlink.h: add NETLINK_LISTEN_ALL_NSID

    This is a selective backport for the following patches and will be replaced by
    full linux header update backports soon.

commit 2503247d58c36f9197144790455626bae105342a
Author: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Date:   Wed May 20 16:19:57 2015 +0200

    man: update ip monitor page

    Add label option.

    Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>

commit 0628cddd9d5c0cb9ed0e0aba136e50de93487150
Author: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Date:   Wed May 20 16:19:58 2015 +0200

    libnetlink: introduce rtnl_listen_filter_t

    There is no functional change with this commit. It only prepares the next one.

    Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>

commit 3b0006f8183e09eda5f2f11667f2b9d36fcd8c16
Author: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Date:   Wed May 20 16:19:59 2015 +0200

    ipmonitor: introduce print_headers

    The goal of this patch is to avoid code duplication.

    Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>

commit 449b824ad19679f66164e1e97513f36eee0d004e
Author: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Date:   Wed May 20 16:20:00 2015 +0200

    ipmonitor: allows to monitor in several netns

    With this patch, it's now possible to listen in all netns that have an nsid
    assigned into the netns where the socket is opened.

    Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>

commit b6ec53e3008aaf2acc3db146e24bc9a365e4b6c2
Author: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Date:   Wed May 20 16:20:01 2015 +0200

    xfrmmonitor: allows to monitor in several netns

    With this patch, it's now possible to listen in all netns that have an nsid
    assigned into the netns where is socket is opened.

    Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>

There were multiple conflicts to resolve due to the following missing commits:
- c16298b ip xfrm mon: Add objects list to the usage output
- 2271779 ip monitor: Dont print timestamp or banner-label for cloned routes
- 0018565 add ability to filter neighbour discovery by protocol
- 488c41d ip: Add label option to ip monitor
- e557212 netlink: extend buffers to 16K
- 093b764 ip monitor: Allow to filter events by dev
---
 bridge/monitor.c        |  1 +
 genl/ctrl.c             | 17 ++++++++++-----
 include/libnetlink.h    | 15 +++++++++++--
 include/linux/netlink.h |  1 +
 ip/ip_common.h          |  1 +
 ip/ipaddress.c          |  8 +++++--
 ip/iplink.c             |  1 +
 ip/ipmonitor.c          | 58 ++++++++++++++++++++++++++++++-------------------
 ip/ipnetconf.c          | 11 ++++++++--
 ip/ipnetns.c            |  1 +
 ip/iproute.c            |  9 +++++---
 ip/rtmon.c              | 12 +++++++---
 ip/xfrm_monitor.c       | 15 ++++++++++++-
 lib/libnetlink.c        | 49 +++++++++++++++++++++++++++++++++++++----
 man/man3/libnetlink.3   |  7 +++---
 man/man8/ip-monitor.8   | 36 ++++++++++++++++++++++++++++++
 man/man8/ip-xfrm.8      | 21 +++++++++++++++++-
 tc/tc_monitor.c         |  1 +
 18 files changed, 216 insertions(+), 48 deletions(-)

diff --git a/bridge/monitor.c b/bridge/monitor.c
index 76e7d47..82cdff0 100644
--- a/bridge/monitor.c
+++ b/bridge/monitor.c
@@ -47,6 +47,7 @@ static int show_mark(FILE *fp, const struct nlmsghdr *n)
 }
 
 static int accept_msg(const struct sockaddr_nl *who,
+		      struct rtnl_ctrl_data *ctrl,
 		      struct nlmsghdr *n, void *arg)
 {
 	FILE *fp = arg;
diff --git a/genl/ctrl.c b/genl/ctrl.c
index 7c42578..48cbc35 100644
--- a/genl/ctrl.c
+++ b/genl/ctrl.c
@@ -177,8 +177,9 @@ static int print_ctrl_grp(FILE *fp, struct rtattr *arg, __u32 ctrl_ver)
 /*
  * The controller sends one nlmsg per family
 */
-static int print_ctrl(const struct sockaddr_nl *who, struct nlmsghdr *n,
-		      void *arg)
+static int print_ctrl(const struct sockaddr_nl *who,
+		      struct rtnl_ctrl_data *ctrl,
+		      struct nlmsghdr *n, void *arg)
 {
 	struct rtattr *tb[CTRL_ATTR_MAX + 1];
 	struct genlmsghdr *ghdr = NLMSG_DATA(n);
@@ -281,6 +282,12 @@ static int print_ctrl(const struct sockaddr_nl *who, struct nlmsghdr *n,
 	return 0;
 }
 
+static int print_ctrl2(const struct sockaddr_nl *who,
+		      struct nlmsghdr *n, void *arg)
+{
+	return print_ctrl(who, NULL, n, arg);
+}
+
 static int ctrl_list(int cmd, int argc, char **argv)
 {
 	struct rtnl_handle rth;
@@ -339,7 +346,7 @@ static int ctrl_list(int cmd, int argc, char **argv)
 			goto ctrl_done;
 		}
 
-		if (print_ctrl(NULL, nlh, (void *) stdout) < 0) {
+		if (print_ctrl2(NULL, nlh, (void *) stdout) < 0) {
 			fprintf(stderr, "Dump terminated\n");
 			goto ctrl_done;
 		}
@@ -355,7 +362,7 @@ static int ctrl_list(int cmd, int argc, char **argv)
 			goto ctrl_done;
 		}
 
-		rtnl_dump_filter(&rth, print_ctrl, stdout);
+		rtnl_dump_filter(&rth, print_ctrl2, stdout);
 
         }
 
@@ -408,5 +415,5 @@ static int parse_ctrl(struct genl_util *a, int argc, char **argv)
 struct genl_util ctrl_genl_util = {
 	.name = "ctrl",
 	.parse_genlopt = parse_ctrl,
-	.print_genlopt = print_ctrl,
+	.print_genlopt = print_ctrl2,
 };
diff --git a/include/libnetlink.h b/include/libnetlink.h
index 5dcc0c3..ae93336 100644
--- a/include/libnetlink.h
+++ b/include/libnetlink.h
@@ -19,6 +19,8 @@ struct rtnl_handle
 	__u32			seq;
 	__u32			dump;
 	FILE		       *dump_fp;
+#define RTNL_HANDLE_F_LISTEN_ALL_NSID		0x01
+	int			flags;
 };
 
 extern int rcvbuf;
@@ -31,9 +33,17 @@ extern int rtnl_wilddump_req_filter(struct rtnl_handle *rth, int fam, int type,
 				    __u32 filt_mask);
 extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len);
 
+struct rtnl_ctrl_data {
+	int	nsid;
+};
+
 typedef int (*rtnl_filter_t)(const struct sockaddr_nl *,
 			     struct nlmsghdr *n, void *);
 
+typedef int (*rtnl_listen_filter_t)(const struct sockaddr_nl *,
+				    struct rtnl_ctrl_data *,
+				    struct nlmsghdr *n, void *);
+
 struct rtnl_dump_filter_arg
 {
 	rtnl_filter_t filter;
@@ -105,9 +115,10 @@ static inline const char *rta_getattr_str(const struct rtattr *rta)
 	return (const char *)RTA_DATA(rta);
 }
 
-extern int rtnl_listen(struct rtnl_handle *, rtnl_filter_t handler,
+extern int rtnl_listen_all_nsid(struct rtnl_handle *);
+extern int rtnl_listen(struct rtnl_handle *, rtnl_listen_filter_t handler,
 		       void *jarg);
-extern int rtnl_from_file(FILE *, rtnl_filter_t handler,
+extern int rtnl_from_file(FILE *, rtnl_listen_filter_t handler,
 		       void *jarg);
 
 #define NLMSG_TAIL(nmsg) \
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index e0a09df..0c89ddd 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -108,6 +108,7 @@ struct nlmsgerr {
 #define NETLINK_NO_ENOBUFS	5
 #define NETLINK_RX_RING		6
 #define NETLINK_TX_RING		7
+#define NETLINK_LISTEN_ALL_NSID	8
 
 struct nl_pktinfo {
 	__u32	group;
diff --git a/ip/ip_common.h b/ip/ip_common.h
index 85529f0..bd36924 100644
--- a/ip/ip_common.h
+++ b/ip/ip_common.h
@@ -29,6 +29,7 @@ extern int print_prefix(const struct sockaddr_nl *who,
 extern int print_rule(const struct sockaddr_nl *who,
 		      struct nlmsghdr *n, void *arg);
 extern int print_netconf(const struct sockaddr_nl *who,
+			 struct rtnl_ctrl_data *ctrl,
 			 struct nlmsghdr *n, void *arg);
 extern void netns_map_init(void);
 extern int print_nsid(const struct sockaddr_nl *who,
diff --git a/ip/ipaddress.c b/ip/ipaddress.c
index 4650a2e..30fda4f 100644
--- a/ip/ipaddress.c
+++ b/ip/ipaddress.c
@@ -1007,7 +1007,9 @@ static int save_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n,
 	return ret == n->nlmsg_len ? 0 : ret;
 }
 
-static int show_handler(const struct sockaddr_nl *nl, struct nlmsghdr *n, void *arg)
+static int show_handler(const struct sockaddr_nl *nl,
+			struct rtnl_ctrl_data *ctrl,
+			struct nlmsghdr *n, void *arg)
 {
 	struct ifaddrmsg *ifa = NLMSG_DATA(n);
 
@@ -1024,7 +1026,9 @@ static int ipaddr_showdump(void)
 	exit(rtnl_from_file(stdin, &show_handler, NULL));
 }
 
-static int restore_handler(const struct sockaddr_nl *nl, struct nlmsghdr *n, void *arg)
+static int restore_handler(const struct sockaddr_nl *nl,
+			   struct rtnl_ctrl_data *ctrl,
+			   struct nlmsghdr *n, void *arg)
 {
 	int ret;
 
diff --git a/ip/iplink.c b/ip/iplink.c
index e47cbdd..86ea23e 100644
--- a/ip/iplink.c
+++ b/ip/iplink.c
@@ -163,6 +163,7 @@ static int get_addr_gen_mode(const char *mode)
 static int have_rtnl_newlink = -1;
 
 static int accept_msg(const struct sockaddr_nl *who,
+		      struct rtnl_ctrl_data *ctrl,
 		      struct nlmsghdr *n, void *arg)
 {
 	struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
diff --git a/ip/ipmonitor.c b/ip/ipmonitor.c
index 148cf1e..131b6ac 100644
--- a/ip/ipmonitor.c
+++ b/ip/ipmonitor.c
@@ -26,18 +26,36 @@
 
 static void usage(void) __attribute__((noreturn));
 int prefix_banner;
+int listen_all_nsid;
 
 static void usage(void)
 {
-	fprintf(stderr, "Usage: ip monitor [ all | LISTofOBJECTS ] [ FILE ]\n");
+	fprintf(stderr, "Usage: ip monitor [ all | LISTofOBJECTS ] [ FILE ] "
+			"[all-nsid] [dev DEVICE]\n");
 	fprintf(stderr, "LISTofOBJECTS := link | address | route | mroute | prefix |\n");
 	fprintf(stderr, "                 neigh | netconf | nsid\n");
 	fprintf(stderr, "FILE := file FILENAME\n");
 	exit(-1);
 }
 
+static void print_headers(FILE *fp, char *label, struct rtnl_ctrl_data *ctrl)
+{
+	if (timestamp)
+		print_timestamp(fp);
+
+	if (listen_all_nsid) {
+		if (ctrl == NULL || ctrl->nsid < 0)
+			fprintf(fp, "[nsid current]");
+		else
+			fprintf(fp, "[nsid %d]", ctrl->nsid);
+	}
+
+	if (prefix_banner)
+		fprintf(fp, "%s", label);
+}
 
 static int accept_msg(const struct sockaddr_nl *who,
+		      struct rtnl_ctrl_data *ctrl,
 		      struct nlmsghdr *n, void *arg)
 {
 	FILE *fp = (FILE*)arg;
@@ -56,59 +74,51 @@ static int accept_msg(const struct sockaddr_nl *who,
 
 		if (r->rtm_family == RTNL_FAMILY_IPMR ||
 		    r->rtm_family == RTNL_FAMILY_IP6MR) {
-			if (prefix_banner)
-				fprintf(fp, "[MROUTE]");
+			print_headers(fp, "[MROUTE]", ctrl);
 			print_mroute(who, n, arg);
 			return 0;
 		} else {
-			if (prefix_banner)
-				fprintf(fp, "[ROUTE]");
+			print_headers(fp, "[ROUTE]", ctrl);
 			print_route(who, n, arg);
 			return 0;
 		}
 	}
+
 	if (n->nlmsg_type == RTM_NEWLINK || n->nlmsg_type == RTM_DELLINK) {
 		ll_remember_index(who, n, NULL);
-		if (prefix_banner)
-			fprintf(fp, "[LINK]");
+		print_headers(fp, "[LINK]", ctrl);
 		print_linkinfo(who, n, arg);
 		return 0;
 	}
 	if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) {
-		if (prefix_banner)
-			fprintf(fp, "[ADDR]");
+		print_headers(fp, "[ADDR]", ctrl);
 		print_addrinfo(who, n, arg);
 		return 0;
 	}
 	if (n->nlmsg_type == RTM_NEWADDRLABEL || n->nlmsg_type == RTM_DELADDRLABEL) {
-		if (prefix_banner)
-			fprintf(fp, "[ADDRLABEL]");
+		print_headers(fp, "[ADDRLABEL]", ctrl);
 		print_addrlabel(who, n, arg);
 		return 0;
 	}
 	if (n->nlmsg_type == RTM_NEWNEIGH || n->nlmsg_type == RTM_DELNEIGH ||
 	    n->nlmsg_type == RTM_GETNEIGH) {
-		if (prefix_banner)
-			fprintf(fp, "[NEIGH]");
+		print_headers(fp, "[NEIGH]", ctrl);
 		print_neigh(who, n, arg);
 		return 0;
 	}
 	if (n->nlmsg_type == RTM_NEWPREFIX) {
-		if (prefix_banner)
-			fprintf(fp, "[PREFIX]");
+		print_headers(fp, "[PREFIX]", ctrl);
 		print_prefix(who, n, arg);
 		return 0;
 	}
 	if (n->nlmsg_type == RTM_NEWRULE || n->nlmsg_type == RTM_DELRULE) {
-		if (prefix_banner)
-			fprintf(fp, "[RULE]");
+		print_headers(fp, "[RULE]", ctrl);
 		print_rule(who, n, arg);
 		return 0;
 	}
 	if (n->nlmsg_type == RTM_NEWNETCONF) {
-		if (prefix_banner)
-			fprintf(fp, "[NETCONF]");
-		print_netconf(who, n, arg);
+		print_headers(fp, "[NETCONF]", ctrl);
+		print_netconf(who, ctrl, n, arg);
 		return 0;
 	}
 	if (n->nlmsg_type == 15) {
@@ -128,8 +138,7 @@ static int accept_msg(const struct sockaddr_nl *who,
 	    n->nlmsg_type == RTM_DELTFILTER)
 		return 0;
 	if (n->nlmsg_type == RTM_NEWNSID || n->nlmsg_type == RTM_DELNSID) {
-		if (prefix_banner)
-			fprintf(fp, "[NSID]");
+		print_headers(fp, "[NSID]", ctrl);
 		print_nsid(who, n, arg);
 		return 0;
 	}
@@ -166,6 +175,8 @@ int do_ipmonitor(int argc, char **argv)
 		if (matches(*argv, "file") == 0) {
 			NEXT_ARG();
 			file = *argv;
+		} else if (matches(*argv, "all-nsid") == 0) {
+			listen_all_nsid = 1;
 		} else if (matches(*argv, "link") == 0) {
 			llink=1;
 			groups = 0;
@@ -250,6 +261,9 @@ int do_ipmonitor(int argc, char **argv)
 
 	if (rtnl_open(&rth, groups) < 0)
 		exit(1);
+	if (listen_all_nsid && rtnl_listen_all_nsid(&rth) < 0)
+		exit(1);
+
 	ll_init_map(&rth);
 	netns_map_init();
 
diff --git a/ip/ipnetconf.c b/ip/ipnetconf.c
index 9a77ecb..8e42132 100644
--- a/ip/ipnetconf.c
+++ b/ip/ipnetconf.c
@@ -40,7 +40,8 @@ static void usage(void)
 
 #define NETCONF_RTA(r)	((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct netconfmsg))))
 
-int print_netconf(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl,
+		  struct nlmsghdr *n, void *arg)
 {
 	FILE *fp = (FILE*)arg;
 	struct netconfmsg *ncm = NLMSG_DATA(n);
@@ -119,6 +120,12 @@ int print_netconf(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 	return 0;
 }
 
+static int print_netconf2(const struct sockaddr_nl *who,
+			  struct nlmsghdr *n, void *arg)
+{
+	return print_netconf(who, NULL, n, arg);
+}
+
 static void ipnetconf_reset_filter(void)
 {
 	memset(&filter, 0, sizeof(filter));
@@ -169,7 +176,7 @@ dump:
 			perror("Cannot send dump request");
 			exit(1);
 		}
-		if (rtnl_dump_filter(&rth, print_netconf, stdout) < 0) {
+		if (rtnl_dump_filter(&rth, print_netconf2, stdout) < 0) {
 			fprintf(stderr, "Dump terminated\n");
 			exit(1);
 		}
diff --git a/ip/ipnetns.c b/ip/ipnetns.c
index 438d59b..019f954 100644
--- a/ip/ipnetns.c
+++ b/ip/ipnetns.c
@@ -43,6 +43,7 @@ static struct rtnl_handle rtnsh = { .fd = -1 };
 static int have_rtnl_getnsid = -1;
 
 static int ipnetns_accept_msg(const struct sockaddr_nl *who,
+			      struct rtnl_ctrl_data *ctrl,
 			      struct nlmsghdr *n, void *arg)
 {
 	struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
diff --git a/ip/iproute.c b/ip/iproute.c
index 207301c..20980ab 100644
--- a/ip/iproute.c
+++ b/ip/iproute.c
@@ -1539,8 +1539,9 @@ static int iproute_get(int argc, char **argv)
 	exit(0);
 }
 
-static int restore_handler(const struct sockaddr_nl *nl, struct nlmsghdr *n,
-			   void *arg)
+static int restore_handler(const struct sockaddr_nl *nl,
+			   struct rtnl_ctrl_data *ctrl,
+			   struct nlmsghdr *n, void *arg)
 {
 	int ret;
 
@@ -1582,7 +1583,9 @@ static int iproute_restore(void)
 	exit(rtnl_from_file(stdin, &restore_handler, NULL));
 }
 
-static int show_handler(const struct sockaddr_nl *nl, struct nlmsghdr *n, void *arg)
+static int show_handler(const struct sockaddr_nl *nl,
+			struct rtnl_ctrl_data *ctrl,
+			struct nlmsghdr *n, void *arg)
 {
 	print_route(nl, n, stdout);
 	return 0;
diff --git a/ip/rtmon.c b/ip/rtmon.c
index 9227eac..5094d22 100644
--- a/ip/rtmon.c
+++ b/ip/rtmon.c
@@ -45,8 +45,8 @@ static void write_stamp(FILE *fp)
 	fwrite((void*)n1, 1, NLMSG_ALIGN(n1->nlmsg_len), fp);
 }
 
-static int dump_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
-		    void *arg)
+static int dump_msg(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl,
+		    struct nlmsghdr *n, void *arg)
 {
 	FILE *fp = (FILE*)arg;
 	if (!init_phase)
@@ -56,6 +56,12 @@ static int dump_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
 	return 0;
 }
 
+static int dump_msg2(const struct sockaddr_nl *who,
+		     struct nlmsghdr *n, void *arg)
+{
+	return dump_msg(who, NULL, n, arg);
+}
+
 static void usage(void)
 {
 	fprintf(stderr, "Usage: rtmon file FILE [ all | LISTofOBJECTS]\n");
@@ -163,7 +169,7 @@ main(int argc, char **argv)
 
 	write_stamp(fp);
 
-	if (rtnl_dump_filter(&rth, dump_msg, fp) < 0) {
+	if (rtnl_dump_filter(&rth, dump_msg2, fp) < 0) {
 		fprintf(stderr, "Dump terminated\n");
 		return 1;
 	}
diff --git a/ip/xfrm_monitor.c b/ip/xfrm_monitor.c
index 292193e..228aaf2 100644
--- a/ip/xfrm_monitor.c
+++ b/ip/xfrm_monitor.c
@@ -36,10 +36,11 @@
 #include "ip_common.h"
 
 static void usage(void) __attribute__((noreturn));
+int listen_all_nsid;
 
 static void usage(void)
 {
-	fprintf(stderr, "Usage: ip xfrm monitor [ all | LISTofXFRM-OBJECTS ]\n");
+	fprintf(stderr, "Usage: ip xfrm monitor [all-nsid] [ all | LISTofXFRM-OBJECTS ]\n");
 	exit(-1);
 }
 
@@ -291,6 +292,7 @@ static int xfrm_mapping_print(const struct sockaddr_nl *who,
 }
 
 static int xfrm_accept_msg(const struct sockaddr_nl *who,
+			   struct rtnl_ctrl_data *ctrl,
 			   struct nlmsghdr *n, void *arg)
 {
 	FILE *fp = (FILE*)arg;
@@ -298,6 +300,13 @@ static int xfrm_accept_msg(const struct sockaddr_nl *who,
 	if (timestamp)
 		print_timestamp(fp);
 
+	if (listen_all_nsid) {
+		if (ctrl == NULL || ctrl->nsid < 0)
+			fprintf(fp, "[nsid current]");
+		else
+			fprintf(fp, "[nsid %d]", ctrl->nsid);
+	}
+
 	switch (n->nlmsg_type) {
 	case XFRM_MSG_NEWSA:
 	case XFRM_MSG_DELSA:
@@ -360,6 +369,8 @@ int do_xfrm_monitor(int argc, char **argv)
 		if (matches(*argv, "file") == 0) {
 			NEXT_ARG();
 			file = *argv;
+		} else if (matches(*argv, "all-nsid") == 0) {
+			listen_all_nsid = 1;
 		} else if (matches(*argv, "acquire") == 0) {
 			lacquire=1;
 			groups = 0;
@@ -412,6 +423,8 @@ int do_xfrm_monitor(int argc, char **argv)
 
 	if (rtnl_open_byproto(&rth, groups, NETLINK_XFRM) < 0)
 		exit(1);
+	if (listen_all_nsid && rtnl_listen_all_nsid(&rth) < 0)
+		exit(1);
 
 	if (rtnl_listen(&rth, xfrm_accept_msg, (void*)stdout) < 0)
 		exit(2);
diff --git a/lib/libnetlink.c b/lib/libnetlink.c
index baac6ae..0a989f4 100644
--- a/lib/libnetlink.c
+++ b/lib/libnetlink.c
@@ -25,6 +25,10 @@
 
 #include "libnetlink.h"
 
+#ifndef SOL_NETLINK
+#define SOL_NETLINK 270
+#endif
+
 int rcvbuf = 1024 * 1024;
 
 void rtnl_close(struct rtnl_handle *rth)
@@ -406,8 +410,21 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
 	}
 }
 
+int rtnl_listen_all_nsid(struct rtnl_handle *rth)
+{
+	unsigned int on = 1;
+
+	if (setsockopt(rth->fd, SOL_NETLINK, NETLINK_LISTEN_ALL_NSID, &on,
+		       sizeof(on)) < 0) {
+		perror("NETLINK_LISTEN_ALL_NSID");
+		return -1;
+	}
+	rth->flags |= RTNL_HANDLE_F_LISTEN_ALL_NSID;
+	return 0;
+}
+
 int rtnl_listen(struct rtnl_handle *rtnl,
-		rtnl_filter_t handler,
+		rtnl_listen_filter_t handler,
 		void *jarg)
 {
 	int status;
@@ -421,6 +438,12 @@ int rtnl_listen(struct rtnl_handle *rtnl,
 		.msg_iovlen = 1,
 	};
 	char   buf[8192];
+	char   cmsgbuf[BUFSIZ];
+
+	if (rtnl->flags & RTNL_HANDLE_F_LISTEN_ALL_NSID) {
+		msg.msg_control = &cmsgbuf;
+		msg.msg_controllen = sizeof(cmsgbuf);
+	}
 
 	memset(&nladdr, 0, sizeof(nladdr));
 	nladdr.nl_family = AF_NETLINK;
@@ -429,6 +452,9 @@ int rtnl_listen(struct rtnl_handle *rtnl,
 
 	iov.iov_base = buf;
 	while (1) {
+		struct rtnl_ctrl_data ctrl;
+		struct cmsghdr *cmsg;
+
 		iov.iov_len = sizeof(buf);
 		status = recvmsg(rtnl->fd, &msg, 0);
 
@@ -449,6 +475,21 @@ int rtnl_listen(struct rtnl_handle *rtnl,
 			fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen);
 			exit(1);
 		}
+
+		if (rtnl->flags & RTNL_HANDLE_F_LISTEN_ALL_NSID) {
+			memset(&ctrl, 0, sizeof(ctrl));
+			ctrl.nsid = -1;
+			for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
+			     cmsg = CMSG_NXTHDR(&msg, cmsg))
+				if (cmsg->cmsg_level == SOL_NETLINK &&
+				    cmsg->cmsg_type == NETLINK_LISTEN_ALL_NSID &&
+				    cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
+					int *data = (int *)CMSG_DATA(cmsg);
+
+					ctrl.nsid = *data;
+				}
+		}
+
 		for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
 			int err;
 			int len = h->nlmsg_len;
@@ -463,7 +504,7 @@ int rtnl_listen(struct rtnl_handle *rtnl,
 				exit(1);
 			}
 
-			err = handler(&nladdr, h, jarg);
+			err = handler(&nladdr, &ctrl, h, jarg);
 			if (err < 0)
 				return err;
 
@@ -481,7 +522,7 @@ int rtnl_listen(struct rtnl_handle *rtnl,
 	}
 }
 
-int rtnl_from_file(FILE *rtnl, rtnl_filter_t handler,
+int rtnl_from_file(FILE *rtnl, rtnl_listen_filter_t handler,
 		   void *jarg)
 {
 	int status;
@@ -529,7 +570,7 @@ int rtnl_from_file(FILE *rtnl, rtnl_filter_t handler,
 			return -1;
 		}
 
-		err = handler(&nladdr, h, jarg);
+		err = handler(&nladdr, NULL, h, jarg);
 		if (err < 0)
 			return err;
 	}
diff --git a/man/man3/libnetlink.3 b/man/man3/libnetlink.3
index e999bd6..99be9cc 100644
--- a/man/man3/libnetlink.3
+++ b/man/man3/libnetlink.3
@@ -33,7 +33,8 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
 	      void *jarg)
 .sp
 int rtnl_listen(struct rtnl_handle *rtnl, 
-	      int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
+	      int (*handler)(struct sockaddr_nl *, struct rtnl_ctrl_data *,
+			     struct nlmsghdr *n, void *),
 	      void *jarg)
 .sp
 int rtnl_from_file(FILE *rtnl, 
@@ -108,8 +109,8 @@ rtnl_listen
 Receive netlink data after a request and pass it to 
 .I handler.
 .B handler
-is a callback that gets the message source address, the message itself,
-and the
+is a callback that gets the message source address, anscillary data, the message
+itself, and the
 .B jarg
 cookie as arguments. It will get called for all received messages.
 Only one message bundle is received. If there is a message
diff --git a/man/man8/ip-monitor.8 b/man/man8/ip-monitor.8
index a710b34..91099f8 100644
--- a/man/man8/ip-monitor.8
+++ b/man/man8/ip-monitor.8
@@ -11,6 +11,10 @@ ip-monitor, rtmon \- state monitoring
 .BR  "monitor" " [ " all " |"
 .IR OBJECT-LIST " ] ["
 .BI file " FILENAME "
+] [
+.BI label
+] [
+.BI all-nsid
 ]
 .sp
 
@@ -26,6 +30,10 @@ command is the first in the command line and then the object list follows:
 .BR "ip monitor" " [ " all " |"
 .IR OBJECT-LIST " ] ["
 .BI file " FILENAME "
+] [
+.BI label
+] [
+.BI all-nsid
 ]
 
 .I OBJECT-LIST
@@ -42,6 +50,32 @@ described in previous sections.
 
 .P
 If the
+.BI label
+option is set, a prefix is displayed before each message to
+show the family of the message. For example:
+.sp
+.in +2
+[NEIGH]10.16.0.112 dev eth0 lladdr 00:04:23:df:2f:d0 REACHABLE
+[LINK]3: eth1: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN group default
+    link/ether 52:54:00:12:34:57 brd ff:ff:ff:ff:ff:ff
+.in -2
+.sp
+
+.P
+If the
+.BI all-nsid
+option is set, the program listens to all network namespaces that have a
+nsid assigned into the network namespace were the program is running.
+A prefix is displayed to show the network namespace where the message
+originates. Example:
+.sp
+.in +2
+[nsid 0]10.16.0.112 dev eth0 lladdr 00:04:23:df:2f:d0 REACHABLE
+.in -2
+.sp
+
+.P
+If the
 .BI file
 option is given, the program does not listen on RTNETLINK,
 but opens the given file, and dumps its contents. The file
@@ -75,3 +109,5 @@ of starting.
 
 .SH AUTHOR
 Original Manpage by Michail Litvak <mci@owl.openwall.com>
+.br
+Manpage revised by Nicolas Dichtel <nicolas.dichtel@6wind.com>
diff --git a/man/man8/ip-xfrm.8 b/man/man8/ip-xfrm.8
index e305c0b..aea4fda 100644
--- a/man/man8/ip-xfrm.8
+++ b/man/man8/ip-xfrm.8
@@ -359,7 +359,11 @@ ip-xfrm \- transform configuration
 .BR required " | " use
 
 .ti -8
-.BR "ip xfrm monitor" " [ " all " |"
+.BR "ip xfrm monitor" " ["
+.BI all-nsid
+] [
+.BI all
+ |
 .IR LISTofXFRM-OBJECTS " ]"
 
 .ti -8
@@ -664,7 +668,22 @@ ip xfrm monitor 	state monitoring for xfrm objects
 .PP
 The xfrm objects to monitor can be optionally specified.
 
+.P
+If the
+.BI all-nsid
+option is set, the program listens to all network namespaces that have a
+nsid assigned into the network namespace were the program is running.
+A prefix is displayed to show the network namespace where the message
+originates. Example:
+.sp
+.in +2
+[nsid 1]Flushed state proto 0
+.in -2
+.sp
+
 .SH AUTHOR
 Manpage revised by David Ward <david.ward@ll.mit.edu>
 .br
 Manpage revised by Christophe Gouault <christophe.gouault@6wind.com>
+.br
+Manpage revised by Nicolas Dichtel <nicolas.dichtel@6wind.com>
diff --git a/tc/tc_monitor.c b/tc/tc_monitor.c
index 0efe034..cae3616 100644
--- a/tc/tc_monitor.c
+++ b/tc/tc_monitor.c
@@ -36,6 +36,7 @@ static void usage(void)
 
 
 static int accept_tcmsg(const struct sockaddr_nl *who,
+			struct rtnl_ctrl_data *ctrl,
 			struct nlmsghdr *n, void *arg)
 {
 	FILE *fp = (FILE*)arg;
-- 
1.8.3.1