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.. :-)
Ah, I guess that you have no much time to do that. :-)
>
> 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)".
Indeed. In fact, an Ipv6 address is a long string, It is really hard to align with columns.
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:
Agree.
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.
Ok, I will extend it in V3 later.
>
> Related kernel commit:
> 502a2ffd7376 ("ipv6: convert idev_list to list macros")
>
> Reported-by: Buland Kumar Singh <bsingh@redhat.com>
> Signed-off-by: Lianbo Jiang <lijiang@redhat.com>
> ---
> 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).
Ok, Let's remove it this time. We can add it again if needed in the future.
> } 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 :-)
You are right. I did the test on several v2.6 vmcores, v5.19 and the latest kernel vmcores.
But still not cover all cases.
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.)
This can be removed, if an Ipv6 address is added after IPv4(without Ipv6 columns).
> +
> + 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)?
Rethink about it. It should be better to check it with VALID_MEMBER(inet6_ifaddr_if_list), so that we can put the code block of do_list() at the start of this function, and check for the latest kernel first.
...
+ if (!ip6_ptr)
+ return;
+
+ if (VALID_MEMBER(inet6_ifaddr_if_list)) {
+ 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++) {
...
+ }
+
+ FREEBUF(ld->list_ptr);
+ return;
+ }
+ /*
+ * 502a2ffd7376 ("ipv6: convert idev_list to list macros")
+ * v2.6.35-rc1~473^2~733
+ */
+ readmem(ip6_ptr + OFFSET(inet6_dev_addr_list), KVADDR,
+ &addr, sizeof(void *), "inet6_dev.addr_list", FAULT_ON_ERROR);
+
+ while (addr) {
...
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.
Good findings.
> +
> + 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.
Sounds good. I will make these changes in v3 and post it later.
Thanks.
Lianbo
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