Thread (15 messages) 15 messages, 4 authors, 2017-03-02

Re: [PATCH] iproute2: show network device dependency tree

From: Jiri Pirko <jiri@resnulli.us>
Date: 2017-02-26 07:57:50

Sat, Feb 25, 2017 at 09:22:22PM CET, zaboj.campula@post.cz wrote:
On Sat, 2017-02-25 at 18:39 +0100, Jiri Pirko wrote:
quoted
quoted
Sat, Feb 25, 2017 at 05:59:00PM CET, zaboj.campula@post.cz wrote:
Add the argument '-tree' to ip-link to show network devices dependency tree.

Example:

$ ip -tree link
eth0
   bond0
eth1
   bond0
eth2
   bond1
eth3
   bond1

Hmm, what is this good for? I'm probably missing something...
I consider this kind of output useful when troubleshooting a complex
configuration with many interfaces. It may show relations among
interfaces.
Did you see https://github.com/jbenc/plotnetcfg ?

quoted

quoted
quoted
quoted
Signed-off-by: Zaboj Campula <redacted>
---
include/utils.h |  1 +
ip/ip.c         |  5 ++-
ip/ipaddress.c  | 97 ++++++++++++++++++++++++++++++++++++++++++++++++---------
3 files changed, 87 insertions(+), 16 deletions(-)
diff --git a/include/utils.h b/include/utils.h
index 22369e0..f1acf4d 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -20,6 +20,7 @@ extern int show_raw;
extern int resolve_hosts;
extern int oneline;
extern int brief;
+extern int tree;;
extern int timestamp;
extern int timestamp_short;
extern const char * _SL_;
diff --git a/ip/ip.c b/ip/ip.c
index 07050b0..29747a5 100644
--- a/ip/ip.c
+++ b/ip/ip.c
@@ -33,6 +33,7 @@ int show_details;
int resolve_hosts;
int oneline;
int brief;
+int tree;
int timestamp;
const char *_SL_;
int force;
@@ -57,7 +58,7 @@ static void usage(void)
"                    -h[uman-readable] | -iec |\n"
"                    -f[amily] { inet | inet6 | ipx | dnet | mpls | bridge | link } |\n"
"                    -4 | -6 | -I | -D | -B | -0 |\n"
-"                    -l[oops] { maximum-addr-flush-attempts } | -br[ief] |\n"
+"                    -l[oops] { maximum-addr-flush-attempts } | -br[ief] | -tr[ee] |\n"
"                    -o[neline] | -t[imestamp] | -ts[hort] | -b[atch] [filename] |\n"
"                    -rc[vbuf] [size] | -n[etns] name | -a[ll] | -c[olor]}\n");
	exit(-1);
@@ -257,6 +258,8 @@ int main(int argc, char **argv)
quoted
quoted
			batch_file = argv[1];
		} else if (matches(opt, "-brief") == 0) {
			++brief;
+		} else if (matches(opt, "-tree") == 0) {
+			++tree;
		} else if (matches(opt, "-rcvbuf") == 0) {
			unsigned int size;
diff --git a/ip/ipaddress.c b/ip/ipaddress.c
index 242c6ea..5ebcb1a 100644
--- a/ip/ipaddress.c
+++ b/ip/ipaddress.c
@@ -1534,6 +1534,69 @@ static int iplink_filter_req(struct nlmsghdr *nlh, int reqlen)
	return 0;
}

+static int has_master(struct nlmsg_chain *linfo, int index)
+{
quoted
quoted
+	struct nlmsg_list *l;
+	struct rtattr *tb[IFLA_MAX+1];
+	int len;
+	for (l = linfo->head; l; l = l->next) {
+		struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
+		len = l->h.nlmsg_len;
+		len -= NLMSG_LENGTH(sizeof(*ifi));
+		parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
+		if (tb[IFLA_MASTER] && *(int *)RTA_DATA(tb[IFLA_MASTER]) == index)
+			return 1;
+	}
+	return 0;
+}
+
+static struct nlmsg_list *get_master(struct nlmsg_chain *linfo, struct rtattr **tb)
+{
quoted
quoted
+	struct nlmsg_list *l;
+	if (tb[IFLA_MASTER]) {
+		int master = *(int *)RTA_DATA(tb[IFLA_MASTER]);
+		for (l = linfo->head; l; l = l->next) {
+			struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
+			if (ifi->ifi_index == master)
+				return l;
+		}
+	}
+	return NULL;
+}
+
+static void print_dev_tree_item(struct nlmsg_chain *linfo, struct nlmsg_list *l, int indent) {
quoted
quoted
+	char *name;
+	int len;
+	struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
+	struct rtattr *tb[IFLA_MAX+1];
+	len = l->h.nlmsg_len;
+	len -= NLMSG_LENGTH(sizeof(*ifi));
+	parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
+	name = (char *)(tb[IFLA_IFNAME] ? rta_getattr_str(tb[IFLA_IFNAME]) : "<nil>");
+
quoted
quoted
+	printf("%*s%s\n", indent * 4, "", name);
+
quoted
quoted
+	struct nlmsg_list *master = get_master(linfo, tb);
+	if (master) {
+		if (indent > 8) {
+			printf("%*s...\n", (indent + 1) * 4, "");
+		} else {
+			print_dev_tree_item(linfo, master, indent + 1);
+		}
+	}
+}
+
+static void print_devtree(struct nlmsg_chain *linfo)
+{
quoted
quoted
+	struct nlmsg_list *l;
+	for (l = linfo->head; l; l = l->next) {
+		struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
+		if (!has_master(linfo, ifi->ifi_index)) {
+			print_dev_tree_item(linfo, l, 0);
+		}
+	}
+}
+
static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
{
	struct nlmsg_chain linfo = { NULL, NULL};
@@ -1742,23 +1805,27 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
quoted
quoted
		ipaddr_filter(&linfo, &ainfo);
	}
quoted
quoted
-	for (l = linfo.head; l; l = l->next) {
-		int res = 0;
-		struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
-
quoted
quoted
-		if (brief) {
-			if (print_linkinfo_brief(NULL, &l->h, stdout) == 0)
+	if (tree) {
+		print_devtree(&linfo);
+	} else {
+		for (l = linfo.head; l; l = l->next) {
+			int res = 0;
+			struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
+
quoted
quoted
+			 if (brief) {
+				if (print_linkinfo_brief(NULL, &l->h, stdout) == 0)
+					if (filter.family != AF_PACKET)
+						print_selected_addrinfo(ifi,
+									ainfo.head,
+									stdout);
+			} else if (no_link ||
+				 (res = print_linkinfo(NULL, &l->h, stdout)) >= 0) {
				if (filter.family != AF_PACKET)
					print_selected_addrinfo(ifi,
-								ainfo.head,
-								stdout);
-		} else if (no_link ||
-			 (res = print_linkinfo(NULL, &l->h, stdout)) >= 0) {
-			if (filter.family != AF_PACKET)
-				print_selected_addrinfo(ifi,
-							ainfo.head, stdout);
-			if (res > 0 && !do_link && show_stats)
-				print_link_stats(stdout, &l->h);
+								ainfo.head, stdout);
+				if (res > 0 && !do_link && show_stats)
+					print_link_stats(stdout, &l->h);
+			}
		}
	}
	fflush(stdout);
-- 
2.9.3
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help