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) > > > > 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(&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) > > > > +{ > > > > > > > > > > > > + 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) { > > > > > > > > > > > > + 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>"); > > > > > > > > + > > > > > > + 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(&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) > > > > > > ipaddr_filter(&linfo, &ainfo); > > > > > > > > } > > > > > > > > > > > > > > > > - for (l = linfo.head; l; l = l->next) { > > > > > > > > > > > > - int res = 0; > > > > > > - struct ifinfomsg *ifi = NLMSG_DATA(&l->h); > > > > > > > > - > > > > > > > > > > > > - 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); > > > > > > > > + > > > > > > > > > > > > + 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 > > > >