Message ID | 20170225165900.10129-1-zaboj.campula@post.cz |
---|---|
State | Changes Requested, archived |
Delegated to: | stephen hemminger |
Headers | show |
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... > >Signed-off-by: Zaboj Campula <zaboj.campula@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 >
On Sat, 2017-02-25 at 18:39 +0100, Jiri Pirko wrote: > > 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. > > > > > > > > > Signed-off-by: Zaboj Campula <zaboj.campula@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 > >
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: >> > 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 ? > > >> >> >> >> > >> > > > Signed-off-by: Zaboj Campula <zaboj.campula@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 >> >
On Sun, 2017-02-26 at 08:56 +0100, Jiri Pirko wrote: > 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: > > > > 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 ? > 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.campula@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 > > > >
Sun, Feb 26, 2017 at 03:00:14PM CET, zaboj.campula@post.cz wrote: >On Sun, 2017-02-26 at 08:56 +0100, Jiri Pirko wrote: >> 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: >> > > > 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 ? >> > >Thanks for the link. I haven't seen plotnetcfg and I like it. >It is handy when the analyzed system has GUI. You can also run it remotelly. Also I believe that you can catch the state into some dump file and process it later on. Not 100% sure though. Ccing Jiri Benc who is the original author of plotnetcfg.
On Sun, 26 Feb 2017 15:46:10 +0100, Jiri Pirko wrote: > You can also run it remotelly. Also I believe that you can catch the > state into some dump file and process it later on. Not 100% sure though. > Ccing Jiri Benc who is the original author of plotnetcfg. 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. Jiri
On Sun, 26 Feb 2017 08:56:33 +0100
Jiri Pirko <jiri@resnulli.us> wrote:
> Did you see https://github.com/jbenc/plotnetcfg ?
Cool, thanks.
On Sat, 25 Feb 2017 16:59:00 +0000 Zaboj Campula <zaboj.campula@post.cz> wrote: > dd the argument '-tree' to ip-link to show network devices dependency tree. > > Example: > > $ ip -tree link > eth0 > bond0 > eth1 > bond0 > eth2 > bond1 > eth3 > bond1 Maybe use format similar to other utilities (lspci, lsusb, etc)?
On Sat, 25 Feb 2017 16:59:00 +0000 Zaboj Campula <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 Another alternative format would be to make -tree a output modifier and ident (like ps tree options). $ ip -t link 1: lo: <LOOPBACK,UP,LOWER_UP> 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 <BROADCAST,MULTICAST> 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: <BROADCAST,MULTICAST> 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
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.
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: <LOOPBACK,UP,LOWER_UP> 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 <BROADCAST,MULTICAST> 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: <BROADCAST,MULTICAST> 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.
Tue, Feb 28, 2017 at 09:19:23PM CET, zaboj.campula@post.cz wrote: >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: <LOOPBACK,UP,LOWER_UP> 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 <BROADCAST,MULTICAST> 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: <BROADCAST,MULTICAST> 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. I don't really think that the output you provide has any value. As JiriB wrote, it is really problematic to draw relationships between devices. Let's take OVS as a very non-trivial example. Your patch aims to handle only the very basic ones.
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. See the example below. > But neither directory structure is a tree (when consider links) > and there are a plenty of tools showing directory tree. Directory structure *is* a tree. Symlinks are a special case, for the purpose of displaying the tree they're just files. Hardlinks can be ignored when displaying a tree (because there are no hardlinks to directories). We don't have any of that. 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. Jiri
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
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);
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.campula@post.cz> --- include/utils.h | 1 + ip/ip.c | 5 ++- ip/ipaddress.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 87 insertions(+), 16 deletions(-)