On 2023/02/27 23:49, Lianbo Jiang wrote: > Currently, the "net" command displays only the IPv4 address of a network > interface, it doesn't support outputting IPv6 address yet. For example: Thanks! This has been on my to-do list for a long time.. :-) > > Without the patch: > crash> net > NET_DEVICE NAME IP ADDRESS(ES) > ffff8d01b1205000 lo 127.0.0.1 > ffff8d0087e40000 eno1 192.168.122.2 > > With the patch: > crash> net > NET_DEVICE NAME IP ADDRESS(ES) INET6 ADDRESS > ffff8d01b1205000 lo 127.0.0.1 ::1 > ffff8d0087e40000 eno1 192.168.122.2 xxxx:xx:x:xxxx:xxxx:xxx:xxxx:xxxx, yyyy::yyyy:yyy:yyyy:yyyy The indent looks odd, and I think that adding the new column "INET6 ADDRESS" may not be so useful because secondary addresses are often seen in the field as the header says "IP ADDRESS(ES)". For example, on one of my machines: crash> net NET_DEVICE NAME IP ADDRESS(ES) INET6 ADDRESS ffff9752fc7b1000 lo 127.0.0.1 ::1 ffff9752e4b94000 enp1s0f0 ffff9752e739c000 enp1s0f1 ffff975242ba6000 virbr0 192.168.122.1 ffff9752c7ff4000 virbr0-nic ffff975261be4000 vnet0 fe80::fc54:ff:fe1d:5abe ffff9751031c0000 vnet1 fe80::fc54:ff:fe06:735d ffff9752d87d5000 bond0 192.168.0.171, 192.168.0.172, 192.168.0.173 fe80::xxxx:xxxx:xxxx:xxxx ffff973bac3ab000 bond0.100 192.168.100.171, 192.168.100.172, 192.168.100.173 IPv6 addresses can be distinguished from IPv4 ones with itself, so how about just adding them to IPv4 ones? without the new column: crash> net NET_DEVICE NAME IP ADDRESS(ES) ffff9752fc7b1000 lo 127.0.0.1, ::1 ffff9752e4b94000 enp1s0f0 ffff9752e739c000 enp1s0f1 ffff975242ba6000 virbr0 192.168.122.1 ffff9752c7ff4000 virbr0-nic ffff975261be4000 vnet0 fe80::fc54:ff:fe1d:5abe ffff9751031c0000 vnet1 fe80::fc54:ff:fe06:735d ffff9752d87d5000 bond0 192.168.0.171, 192.168.0.172, 192.168.0.173, fe80::xxxx:xxxx:xxxx:xxxx ffff973bac3ab000 bond0.100 192.168.100.171, 192.168.100.172, 192.168.100.173 And these days, device names tend to be longer than before, so I would like to extend it to "%-10s " or so at this opportunity like the above. > > Related kernel commit: > 502a2ffd7376 ("ipv6: convert idev_list to list macros") > > Reported-by: Buland Kumar Singh <bsingh@xxxxxxxxxx> > Signed-off-by: Lianbo Jiang <lijiang@xxxxxxxxxx> > --- > defs.h | 6 +++ > net.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++--- > symbols.c | 12 ++++++ > 3 files changed, 135 insertions(+), 6 deletions(-) > > diff --git a/defs.h b/defs.h > index e76af3c78b69..1f2cf6e0ce01 100644 > --- a/defs.h > +++ b/defs.h > @@ -2208,6 +2208,12 @@ struct offset_table { /* stash of commonly-used offsets */ > long sock_common_skc_v6_daddr; > long sock_common_skc_v6_rcv_saddr; > long inactive_task_frame_bp; > + long net_device_ip6_ptr; > + long inet6_dev_addr_list; > + long inet6_ifaddr_addr; > + long inet6_ifaddr_if_list; > + long inet6_ifaddr_if_next; > + long in6_addr_in6_u; > }; > > struct size_table { /* stash of commonly-used sizes */ > diff --git a/net.c b/net.c > index aa445ab7ee13..52336762c85c 100644 > --- a/net.c > +++ b/net.c > @@ -41,6 +41,7 @@ struct net_table { > long in_ifaddr_ifa_next; > long in_ifaddr_ifa_address; > int net_device_name_index; > + long dev_ip6_ptr; This looks unnecessary, because this is set only to OFFSET(net_device_ip6_ptr). > } net_table = { 0 }; > > struct net_table *net = &net_table; > @@ -71,6 +72,7 @@ static void print_neighbour_q(ulong, int); > static void get_netdev_info(ulong, struct devinfo *); > static void get_device_name(ulong, char *); > static long get_device_address(ulong, char **, long); > +static void get_device_ip6_address(ulong, char **, long); > static void get_sock_info(ulong, char *); > static void dump_arp(void); > static void arp_state_to_flags(unsigned char); > @@ -114,6 +116,13 @@ net_init(void) > net->dev_ip_ptr = MEMBER_OFFSET_INIT(net_device_ip_ptr, > "net_device", "ip_ptr"); > MEMBER_OFFSET_INIT(net_device_dev_list, "net_device", "dev_list"); > + net->dev_ip6_ptr = MEMBER_OFFSET_INIT(net_device_ip6_ptr, "net_device", "ip6_ptr"); > + MEMBER_OFFSET_INIT(inet6_dev_addr_list, "inet6_dev", "addr_list"); > + MEMBER_OFFSET_INIT(inet6_ifaddr_addr, "inet6_ifaddr", "addr"); > + MEMBER_OFFSET_INIT(inet6_ifaddr_if_list, "inet6_ifaddr", "if_list"); > + MEMBER_OFFSET_INIT(inet6_ifaddr_if_next, "inet6_ifaddr", "if_next"); > + MEMBER_OFFSET_INIT(in6_addr_in6_u, "in6_addr", "in6_u"); > + > MEMBER_OFFSET_INIT(net_dev_base_head, "net", "dev_base_head"); > ARRAY_LENGTH_INIT(net->net_device_name_index, > net_device_name, "net_device.name", NULL, sizeof(char)); > @@ -466,7 +475,7 @@ show_net_devices(ulong task) > buf = GETBUF(buflen); > flen = MAX(VADDR_PRLEN, strlen(net->netdevice)); > > - fprintf(fp, "%s NAME IP ADDRESS(ES)\n", > + fprintf(fp, "%s NAME IP ADDRESS(ES) INET6 ADDRESS\n", > mkstring(upper_case(net->netdevice, buf), > flen, CENTER|LJUST, NULL)); > Just memo: v2.6.24 introduced init_net --> show_net_devices_v3() v2.6.22 introduced dev_base_head --> show_net_devices_v2() earlier used dev_base --> show_net_devices() The patch works even on v2.6.16 vmcore :-) crash> net NET_DEVICE NAME IP ADDRESS(ES) INET6 ADDRESS ffffffff803c1480 lo 127.0.0.1 ::1 ffff81003eb73000 eth0 xx.xx.xxx.xx fe80::xxx:xxxx:xxxx:xxxx > @@ -477,7 +486,14 @@ show_net_devices(ulong task) > get_device_name(next, buf); > fprintf(fp, "%-6s ", buf); > > - buflen = get_device_address(next, &buf, buflen); > + get_device_address(next, &buf, buflen); > + > + if (strlen(buf) > 0) > + fprintf(fp, "%-6s ", buf); > + else > + fprintf(fp, "\t\t"); (It would be better to avoid using '\t' in output usually for indent because it can vary with the terminal or something, I think.) > + > + get_device_ip6_address(next, &buf, buflen); > fprintf(fp, "%s\n", buf); > > readmem(next+net->dev_next, KVADDR, &next, > @@ -503,7 +519,7 @@ show_net_devices_v2(ulong task) > buf = GETBUF(buflen); > flen = MAX(VADDR_PRLEN, strlen(net->netdevice)); > > - fprintf(fp, "%s NAME IP ADDRESS(ES)\n", > + fprintf(fp, "%s NAME IP ADDRESS(ES) INET6 ADDRESS\n", > mkstring(upper_case(net->netdevice, buf), > flen, CENTER|LJUST, NULL)); > > @@ -530,7 +546,14 @@ show_net_devices_v2(ulong task) > get_device_name(ld->list_ptr[i], buf); > fprintf(fp, "%-6s ", buf); > > - buflen = get_device_address(ld->list_ptr[i], &buf, buflen); > + get_device_address(ld->list_ptr[i], &buf, buflen); > + > + if (strlen(buf) > 0) > + fprintf(fp, "%-6s ", buf); > + else > + fprintf(fp, "\t\t"); > + > + get_device_ip6_address(ld->list_ptr[i], &buf, buflen); > fprintf(fp, "%s\n", buf); > } > > @@ -556,7 +579,7 @@ show_net_devices_v3(ulong task) > buf = GETBUF(buflen); > flen = MAX(VADDR_PRLEN, strlen(net->netdevice)); > > - fprintf(fp, "%s NAME IP ADDRESS(ES)\n", > + fprintf(fp, "%s NAME IP ADDRESS(ES) INET6 ADDRESS\n", > mkstring(upper_case(net->netdevice, buf), > flen, CENTER|LJUST, NULL)); > > @@ -593,7 +616,14 @@ show_net_devices_v3(ulong task) > get_device_name(ld->list_ptr[i], buf); > fprintf(fp, "%-6s ", buf); > > - buflen = get_device_address(ld->list_ptr[i], &buf, buflen); > + get_device_address(ld->list_ptr[i], &buf, buflen); > + > + if (strlen(buf) > 0) > + fprintf(fp, "%-6s ", buf); > + else > + fprintf(fp, "\t\t"); > + > + get_device_ip6_address(ld->list_ptr[i], &buf, buflen); > fprintf(fp, "%s\n", buf); > } > > @@ -925,6 +955,87 @@ get_device_address(ulong devaddr, char **bufp, long buflen) > return buflen; > } > > +static void > +get_device_ip6_address(ulong devaddr, char **bufp, long buflen) > +{ > + ulong ip6_ptr = 0, i, cnt = 0, pos = 0, bufsize = buflen; > + struct list_data list_data, *ld; > + struct in6_addr ip6_addr; > + char *buf; > + char str[INET6_ADDRSTRLEN + 1] = {0}; > + char buffer[INET6_ADDRSTRLEN + 4] = {0}; > + uint len = 0; > + > + buf = *bufp; > + BZERO(buf, buflen); > + > + readmem(devaddr + net->dev_ip6_ptr, KVADDR, > + &ip6_ptr, sizeof(ulong), "ip6_ptr", FAULT_ON_ERROR); > + > + if (!ip6_ptr) > + return; > + > + if (MEMBER_TYPE("inet6_dev", "addr_list") == TYPE_CODE_PTR) { This can be replaced with VALID_MEMBER(inet6_ifaddr_if_next)? It will be faster than MEMBER_TYPE(). > + ulong addrp = 0; > + /* > + * 502a2ffd7376 ("ipv6: convert idev_list to list macros") > + * v2.6.35-rc1~473^2~733 > + */ > + readmem(ip6_ptr + OFFSET(inet6_dev_addr_list), KVADDR, > + &addrp, sizeof(void *), "addr_list", FAULT_ON_ERROR); "inet6_dev.addr_list" is better. > + > + while (addrp) { > + readmem(addrp + OFFSET(in6_addr_in6_u), KVADDR, &ip6_addr, > + sizeof(struct in6_addr), "in6_addr.in6_u", FAULT_ON_ERROR); > + inet_ntop(AF_INET6, (void*)&ip6_addr, str, INET6_ADDRSTRLEN); > + sprintf(buffer, "%s%s", pos ? ", " : "", str); > + len = strlen(buffer); > + > + if (pos + len >= bufsize) { > + RESIZEBUF(*bufp, bufsize, bufsize + buflen); > + buf = *bufp; > + BZERO(buf + bufsize, buflen); > + bufsize += buflen; > + } > + BCOPY(buffer, &buf[pos], len); > + pos += len; > + readmem(addrp + OFFSET(inet6_ifaddr_if_next), KVADDR, &addrp, > + sizeof(void *), "inet6_ifaddr.if_next", FAULT_ON_ERROR); > + } > + > + return; > + } > + > + ld = &list_data; > + BZERO(ld, sizeof(struct list_data)); > + ld->flags |= LIST_ALLOCATE; > + ld->start = ip6_ptr + OFFSET(inet6_dev_addr_list); > + cnt = do_list(ld); > + > + for (i = 1; i < cnt; i++) { > + ulong addr; > + > + addr = ld->list_ptr[i] + OFFSET(inet6_ifaddr_addr); > + addr -= OFFSET(inet6_ifaddr_if_list); > + readmem(addr + OFFSET(in6_addr_in6_u), KVADDR, &ip6_addr, > + sizeof(struct in6_addr), "in6_addr.in6_u", FAULT_ON_ERROR); > + > + inet_ntop(AF_INET6, (void*)&ip6_addr, str, INET6_ADDRSTRLEN); > + sprintf(buffer, "%s%s", pos ? ", " : "", str); > + len = strlen(buffer); > + > + if (pos + len >= bufsize) { > + RESIZEBUF(*bufp, bufsize, bufsize + buflen); > + buf = *bufp; > + BZERO(buf + bufsize, buflen); > + bufsize += buflen; > + } > + BCOPY(buffer, &buf[pos], len); > + pos += len; > + } > + > + FREEBUF(ld->list_ptr); > +} > /* > * Get the family, type, local and destination address/port pairs. > */ > diff --git a/symbols.c b/symbols.c > index a974fc9141a0..c8bdeb841cdc 100644 > --- a/symbols.c > +++ b/symbols.c > @@ -9787,6 +9787,18 @@ dump_offset_table(char *spec, ulong makestruct) > OFFSET(net_device_addr_len)); > fprintf(fp, " net_device_ip_ptr: %ld\n", > OFFSET(net_device_ip_ptr)); > + fprintf(fp, " net_device_ip6_ptr: %ld\n", > + OFFSET(net_device_ip6_ptr)); > + fprintf(fp, " inet6_dev_addr_list: %ld\n", > + OFFSET(inet6_dev_addr_list)); > + fprintf(fp, " inet6_ifaddr_addr: %ld\n", > + OFFSET(inet6_ifaddr_addr)); > + fprintf(fp, " inet6_ifaddr_if_list: %ld\n", > + OFFSET(inet6_ifaddr_if_list)); > + fprintf(fp, " inet6_ifaddr_if_next: %ld\n", > + OFFSET(inet6_ifaddr_if_next)); > + fprintf(fp, " in6_addr_in6_u: %ld\n", > + OFFSET(in6_addr_in6_u)); > fprintf(fp, " net_device_dev_list: %ld\n", > OFFSET(net_device_dev_list)); > fprintf(fp, " net_dev_base_head: %ld\n", Please change each of these to one line for readability, and.. crash> help -o ... net_device_addr_len: 493 net_device_ip_ptr: 616 net_device_ip6_ptr: 632 inet6_dev_addr_list: 8 inet6_ifaddr_addr: 0 inet6_ifaddr_if_list: 232 inet6_ifaddr_if_next: -1 in6_addr_in6_u: 0 net_device_dev_list: 80 please don't separate the same "net_device" struct members.. How about this? putting ipv6 related ones together. net_device_addr_len: 493 net_device_ip_ptr: 616 + net_device_ip6_ptr: 632 net_device_dev_list: 80 ... inet_opt_sport: 784 inet_opt_num: 14 + inet6_dev_addr_list: 8 + inet6_ifaddr_addr: 0 + inet6_ifaddr_if_list: 232 + inet6_ifaddr_if_next: -1 + in6_addr_in6_u: 0 ipv6_pinfo_rcv_saddr: -1 ipv6_pinfo_daddr: -1 Thanks, Kazu -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://listman.redhat.com/mailman/listinfo/crash-utility Contribution Guidelines: https://github.com/crash-utility/crash/wiki