Re: [PATCH] iproute2: show network device dependency tree
On Wed, 2017-03-01 at 11:22 +0100, Jiri Benc wrote: > On Tue, 28 Feb 2017 20:07:37 +0000, Zaboj Campula wrote: > > Well it is impossible to draw a simple tree showing the configuration > > exactly with all details. May be it is too ambitious to draw a tree > > at all. > > I tried that and failed. I didn't want to have something that would > work only "somehow" as that would create confusion instead of helping. OK, I give up. My patch was naive and I deleted it. Nevertheless I still think it would be useful to show network interfaces dependencies in a pure text format. > Consider the very simple case of an interface with two vlan interfaces > and both of them in a bridge. > > vlan0 > /\ > eth0 br0 > \/ > vlan1 > > You can't represent this in a tree view. And this is just a very simple > example, in reality it tends to be much more complex. Perhaps something like that: eth0 vlan0 br0 vlan1 br0
Re: [PATCH] iproute2: show network device dependency tree
On Mon, 2017-02-27 at 10:55 -0800, Stephen Hemminger wrote: > > Another alternative format would be to make -tree a output modifier and ident > (like ps tree options). > > $ ip -t link > 1: lo:mtu 65536 qdisc noqueue state UNKNOWN mode > DEFAULT group default qlen 1 > link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 > 8: bond0 mtu 1500 qdisc pfifo_fast state DOWN mode > DEFAULT group default qlen 1000 > link/ether 52:54:00:66:24:cd brd ff:ff:ff:ff:ff:ff > 2: eth1: mtu 1500 qdisc pfifo_fast master bond0 > state DOWN mode DEFAULT group default qlen 1000 > link/ether 52:54:00:66:24:cd brd ff:ff:ff:ff:ff:ff OK, it looks better because the information is complete. I looked at several tree printing utilities and I like the lsblk format. But tabular format does not fit the ip-show well. I will try to indent the current ip-show output may be with fancy lines.
Re: [PATCH] iproute2: show network device dependency tree
On Mon, 2017-02-27 at 17:38 +0100, Jiri Benc wrote: > > It produces dot (graphviz) output or json and has no dependencies on > anything GUI related. Just run it on the remote machine and display the > output locally. > > ssh root@remote plotnetcfg | dot -Tpdf | whatever_pdf_viewer > > Note that some pdf viewers can't read stdin or require dash as the > parameter to use stdin. > > I don't think it's possible to enhance iproute2 to display the network > interface dependencies in an useful way. It's just too complex. It's > not even a (undirected) tree. I know there is an option to execute something remotely but I think a pure text output may be useful to get a quick overview. Well it is impossible to draw a simple tree showing the configuration exactly with all details. May be it is too ambitious to draw a tree at all. But neither directory structure is a tree (when consider links) and there are a plenty of tools showing directory tree.
Re: [PATCH] iproute2: show network device dependency tree
On Sun, 2017-02-26 at 08:56 +0100, Jiri Pirko wrote: > Sat, Feb 25, 2017 at 09:22:22PM CET, zaboj.camp...@post.cz wrote: > > On Sat, 2017-02-25 at 18:39 +0100, Jiri Pirko wrote: > > > > Sat, Feb 25, 2017 at 05:59:00PM CET, zaboj.camp...@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 ? > Thanks for the link. I haven't seen plotnetcfg and I like it. It is handy when the analyzed system has GUI. > > > > > > > > > > > > > > > > > > > > > > > > > > Signed-off-by: Zaboj Campula <zaboj.camp...@post.cz> > > > > > > > > --- > > > > 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) > > > > > > > > > > > > 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) &g
Re: [PATCH] iproute2: show network device dependency tree
On Sat, 2017-02-25 at 18:39 +0100, Jiri Pirko wrote: > > Sat, Feb 25, 2017 at 05:59:00PM CET, zaboj.camp...@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. > > > > > > > > > Signed-off-by: Zaboj Campula <zaboj.camp...@post.cz> > > --- > > 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) > > > > 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) > > +{ > > > > + 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(>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) > > +{ > > > > + 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(>h); > > > > + if (ifi->ifi_index == master) > > > > + return l; > > > > +
[PATCH] iproute2: show network device dependency tree
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 Signed-off-by: Zaboj Campula <zaboj.camp...@post.cz> --- 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) 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) +{ + 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(>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) +{ + 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(>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) { + char *name; + int len; + struct ifinfomsg *ifi = NLMSG_DATA(>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]) : ""); + + printf("%*s%s\n", indent * 4, "", name); + + 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) +{ + struct nlmsg_list *l; + for (l = linfo->head; l; l = l->next) { + struct ifinfomsg *ifi = NLMSG_DATA(>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) ipaddr_filter(, ); } - for (l = linfo.head; l; l = l->next) { - int res = 0; - struct ifinfomsg *ifi = NLMSG_DATA(>h); - -