This command dumps the ARP and NDP tables maintained within slirp.
One use-case for it is showing the guest's IPv6 address(es).
Signed-off-by: Doug Evans <dje@google.com>
---
hmp-commands-info.hx | 15 +++++++
include/net/slirp.h | 1 +
net/slirp.c | 15 +++++++
tests/acceptance/info_neighbors.py | 69 ++++++++++++++++++++++++++++++
4 files changed, 100 insertions(+)
create mode 100644 tests/acceptance/info_neighbors.py
diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
index 27206ac049..386f09f163 100644
--- a/hmp-commands-info.hx
+++ b/hmp-commands-info.hx
@@ -512,6 +512,21 @@ SRST
Show user network stack connection states.
ERST
+#if defined(CONFIG_SLIRP)
+ {
+ .name = "neighbors",
+ .args_type = "",
+ .params = "",
+ .help = "show the ARP and NDP tables",
+ .cmd = hmp_info_neighbors,
+ },
+#endif
+
+SRST
+ ``info neighbors``
+ Show the ARP and NDP tables.
+ERST
+
{
.name = "migrate",
.args_type = "",
diff --git a/include/net/slirp.h b/include/net/slirp.h
index bad3e1e241..b9ccfda1e7 100644
--- a/include/net/slirp.h
+++ b/include/net/slirp.h
@@ -31,6 +31,7 @@ void hmp_hostfwd_add(Monitor *mon, const QDict *qdict);
void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict);
void hmp_info_usernet(Monitor *mon, const QDict *qdict);
+void hmp_info_neighbors(Monitor *mon, const QDict *qdict);
#endif
diff --git a/net/slirp.c b/net/slirp.c
index ad3a838e0b..29a4cd3fe1 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -1028,6 +1028,21 @@ void hmp_info_usernet(Monitor *mon, const QDict *qdict)
}
}
+void hmp_info_neighbors(Monitor *mon, const QDict *qdict)
+{
+ SlirpState *s;
+
+ QTAILQ_FOREACH(s, &slirp_stacks, entry) {
+ int id;
+ bool got_hub_id = net_hub_id_for_client(&s->nc, &id) == 0;
+ char *info = slirp_neighbor_info(s->slirp);
+ monitor_printf(mon, "Hub %d (%s):\n%s",
+ got_hub_id ? id : -1,
+ s->nc.name, info);
+ g_free(info);
+ }
+}
+
static void
net_init_slirp_configs(const StringList *fwd, int flags)
{
diff --git a/tests/acceptance/info_neighbors.py b/tests/acceptance/info_neighbors.py
new file mode 100644
index 0000000000..ff79ec3ff3
--- /dev/null
+++ b/tests/acceptance/info_neighbors.py
@@ -0,0 +1,69 @@
+# Test for the hmp command "info neighbors"
+#
+# Copyright 2021 Google LLC
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+import re
+
+from avocado_qemu import LinuxTest
+from avocado_qemu import Test
+
+VNET_HUB_HEADER = 'Hub -1 (vnet):'
+NEIGHBOR_HEADER_REGEX = '^ *Table *MacAddr *IP Address$'
+
+def trim(text):
+ return " ".join(text.split())
+
+def hmc(test, cmd):
+ return test.vm.command('human-monitor-command', command_line=cmd)
+
+def get_neighbors(test):
+ output = hmc(test, 'info neighbors').splitlines()
+ if len(output) < 2:
+ test.fail("Insufficient output from 'info neighbors'")
+ test.assertEquals(output[0], VNET_HUB_HEADER)
+ test.assertTrue(re.fullmatch(NEIGHBOR_HEADER_REGEX, output[1]))
+ return output[2:]
+
+class InfoNeighborsNone(Test):
+
+ def test_no_neighbors(self):
+ self.vm.add_args('-nodefaults',
+ '-netdev', 'user,id=vnet',
+ '-device', 'virtio-net,netdev=vnet')
+ self.vm.launch()
+ neighbors = get_neighbors(self)
+ self.assertEquals(len(neighbors), 0)
+
+class InfoNeighbors(LinuxTest):
+
+ def test_neighbors(self):
+ """
+ :avocado: tags=arch:x86_64
+ :avocado: tags=machine:pc
+ :avocado: tags=accel:kvm
+ """
+ self.require_accelerator('kvm')
+ self.vm.add_args("-accel", "kvm")
+ self.vm.add_args('-nographic',
+ '-m', '1024')
+ self.launch_and_wait()
+
+ # Ensure there's some packets to the guest and back.
+ self.ssh_command('pwd')
+
+ # We should now be aware of the guest as a neighbor.
+ expected_ipv4_neighbor = 'ARP 52:54:00:12:34:56 10.0.2.15'
+ # The default ipv6 net is fec0. Both fe80 and fec0 can appear.
+ expected_ipv6_neighbors = [
+ 'NDP 52:54:00:12:34:56 fe80::5054:ff:fe12:3456',
+ 'NDP 52:54:00:12:34:56 fec0::5054:ff:fe12:3456'
+ ]
+ neighbors = get_neighbors(self)
+ self.assertTrue(len(neighbors) >= 2 and len(neighbors) <= 3)
+ # IPv4 is output first.
+ self.assertEquals(trim(neighbors[0]), expected_ipv4_neighbor)
+ for neighbor in neighbors[1:]:
+ self.assertTrue(trim(neighbor) in expected_ipv6_neighbors)
--
2.33.0.153.gba50c8fa24-goog