On 03/11/2015 07:09 AM, Daniel P. Berrange wrote: > From: Nehal J Wani <nehaljw.kkd1@xxxxxxxxx> > > tools/virsh-domain-monitor.c > * Introduce new command : domifaddr > Usage: domifaddr <domain> [interface] [--full] [--source lease|agent] > > Example outputs: > virsh # domifaddr f20 > Name MAC address Protocol Address > ------------------------------------------------------------------------------- > lo 00:00:00:00:00:00 ipv4 127.0.0.1/8 > - - ipv6 ::1/128 > eth0 52:54:00:2e:45:ce ipv4 10.1.33.188/24 > - - ipv6 2001:db8:0:f101::2/64 > - - ipv6 fe80::5054:ff:fe2e:45ce/64 > eth1 52:54:00:b1:70:19 ipv4 192.168.105.201/16 > - - ipv4 192.168.201.195/16 > - - ipv6 fe80::5054:ff:feb1:7019/64 > eth2 52:54:00:36:2a:e5 N/A N/A > eth3 52:54:00:20:70:3d ipv4 192.168.105.240/16 > - - ipv6 fe80::5054:ff:fe20:703d/64 > Does the above list now change with the default --source of lease? Since the subsequent example lists --source agent, I suspect the above may not be "correct" for eth0. > virsh # domifaddr f20 eth1 --source lease > Name MAC address Protocol Address > ------------------------------------------------------------------------------- > eth1 52:54:00:b1:70:19 ipv4 192.168.105.201/16 > - - ipv4 192.168.201.195/16 > - - ipv6 fe80::5054:ff:feb1:7019/64 > > virsh # domifaddr f20 eth0 --source agent --full > Name MAC address Protocol Address > ------------------------------------------------------------------------------- > eth0 52:54:00:2e:45:ce ipv4 10.1.33.188/24 > eth0 52:54:00:2e:45:ce ipv6 2001:db8:0:f101::2/64 > eth0 52:54:00:2e:45:ce ipv6 fe80::5054:ff:fe2e:45ce/64 > > tools/virsh.pod > * Document new command > > Signed-off-by: Nehal J Wani <nehaljw.kkd1@xxxxxxxxx> > --- > tools/virsh-domain-monitor.c | 146 +++++++++++++++++++++++++++++++++++++++++++ > tools/virsh.pod | 16 +++++ > 2 files changed, 162 insertions(+) > > diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c > index 464ac11..92ce152 100644 > --- a/tools/virsh-domain-monitor.c > +++ b/tools/virsh-domain-monitor.c > @@ -2197,6 +2197,146 @@ cmdDomstats(vshControl *ctl, const vshCmd *cmd) > return ret; > } > > +/* "domifaddr" command > + */ > +static const vshCmdInfo info_domifaddr[] = { > + {"help", N_("Get network interfaces' addresses for a running domain")}, > + {"desc", N_("Get network interfaces' addresses for a running domain")}, > + {NULL, NULL} > +}; > + > +static const vshCmdOptDef opts_domifaddr[] = { > + {.name = "domain", > + .type = VSH_OT_DATA, > + .flags = VSH_OFLAG_REQ, > + .help = N_("domain name, id or uuid")}, > + {.name = "interface", > + .type = VSH_OT_STRING, > + .flags = VSH_OFLAG_NONE, > + .help = N_("network interface name")}, > + {.name = "full", > + .type = VSH_OT_BOOL, > + .flags = VSH_OFLAG_NONE, > + .help = N_("display full fields")}, > + {.name = "source", > + .type = VSH_OT_STRING, > + .flags = VSH_OFLAG_NONE, > + .help = N_("address source: 'lease' or 'agent'")}, > + {.name = NULL} > +}; > + > +static bool > +cmdDomIfAddr(vshControl *ctl, const vshCmd *cmd) > +{ > + virDomainPtr dom = NULL; > + const char *interface = NULL; > + virDomainInterfacePtr *ifaces = NULL; > + size_t i, j; > + int ifaces_count = 0; > + bool ret = false; > + bool full = vshCommandOptBool(cmd, "full"); > + const char *sourcestr = NULL; > + int source = VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE; > + > + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) > + return false; > + > + if (vshCommandOptString(cmd, "interface", &interface) < 0) > + goto cleanup; > + if (vshCommandOptString(cmd, "source", &sourcestr) < 0) > + goto cleanup; > + > + if (sourcestr) { > + if (STREQ(sourcestr, "lease")) { > + source = VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE; > + } else if (STREQ(sourcestr, "agent")) { > + source = VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT; > + } else { > + vshError(ctl, _("Unknown data source '%s'"), sourcestr); > + goto cleanup; > + } > + } > + > + if ((ifaces_count = virDomainInterfaceAddresses(dom, &ifaces, source, 0)) < 0) { > + vshError(ctl, _("Failed to query for interfaces addresses")); > + goto cleanup; > + } > + > + vshPrintExtra(ctl, " %-10s %-20s %-8s %s\n%s%s\n", _("Name"), > + _("MAC address"), _("Protocol"), _("Address"), > + _("-------------------------------------------------"), > + _("------------------------------")); > + > + for (i = 0; i < ifaces_count; i++) { > + virDomainInterfacePtr iface = ifaces[i]; > + const char *hwaddr = ""; > + const char *ip_addr_str = NULL; > + const char *type = NULL; > + > + if (interface && STRNEQ(interface, iface->name)) > + continue; > + > + hwaddr = iface->hwaddr; > + > + /* When the interface has no IP address */ > + if (!iface->naddrs) { > + vshPrintExtra(ctl, " %-10s %-17s %-12s %s\n", > + iface->name, hwaddr, "N/A", "N/A"); > + continue; > + } > + > + for (j = 0; j < iface->naddrs; j++) { > + virBuffer buf = VIR_BUFFER_INITIALIZER; > + > + switch (iface->addrs[j].type) { > + case VIR_IP_ADDR_TYPE_IPV4: > + type = "ipv4"; > + break; > + case VIR_IP_ADDR_TYPE_IPV6: > + type = "ipv6"; > + break; > + } > + > + virBufferAsprintf(&buf, "%-12s %s/%d", > + type, iface->addrs[j].addr, > + iface->addrs[j].prefix); > + > + if (virBufferError(&buf)) { > + virBufferFreeAndReset(&buf); > + virReportOOMError(); > + goto cleanup; > + } > + > + ip_addr_str = virBufferContentAndReset(&buf); > + > + if (!ip_addr_str) > + ip_addr_str = ""; > + > + /* Don't repeat interface name */ > + if (full || !j) > + vshPrintExtra(ctl, " %-10s %-17s %s\n", > + iface->name, hwaddr, ip_addr_str); > + else > + vshPrintExtra(ctl, " %-10s %-17s %s\n", > + "-", "-", ip_addr_str); > + > + virBufferFreeAndReset(&buf); > + } > + } > + > + ret = true; > + > + cleanup: > + if (ifaces && ifaces_count > 0) { > + for (i = 0; i < ifaces_count; i++) > + virDomainInterfaceFree(ifaces[i]); > + } > + VIR_FREE(ifaces); > + > + virDomainFree(dom); > + return ret; > +} > + > const vshCmdDef domMonitoringCmds[] = { > {.name = "domblkerror", > .handler = cmdDomBlkError, > @@ -2234,6 +2374,12 @@ const vshCmdDef domMonitoringCmds[] = { > .info = info_domif_getlink, > .flags = 0 > }, > + {.name = "domifaddr", > + .handler = cmdDomIfAddr, > + .opts = opts_domifaddr, > + .info = info_domifaddr, > + .flags = 0 > + }, > {.name = "domiflist", > .handler = cmdDomiflist, > .opts = opts_domiflist, > diff --git a/tools/virsh.pod b/tools/virsh.pod > index e65378e..4190485 100644 > --- a/tools/virsh.pod > +++ b/tools/virsh.pod > @@ -730,6 +730,22 @@ B<Explanation of fields> (fields appear in the following order): > flush_total_times - total time flush operations took (ns) > <-- other fields provided by hypervisor --> > > + > +=item B<domifaddr> I<domain> [I<interface>] [I<--full>] > + [I<--source lease|agent>] > + > +Get a list of interfaces of a running domain along with their IP and MAC > +addresses, or limited output just for one interface if I<interface> is > +specified. Note that I<interface> can be driver dependent, it can be the name > +within guest OS or the name you would see in domain XML. Moreover, the whole > +command may require a guest agent to be configured for the queried domain under > +some drivers, notably qemu. If I<--full> is specified, the interface name is > +always displayed when the interface has multiple addresses or alias, otherwise > +it only displays the interface name for the first address, and "-" for the > +others. The I<--source> argument specifies what data source to use for the > +addresses, currently one of 'lease' to read DHCP leases, or 'agent' to query > +the guest OS via an agent. > + If unspecified the default is 'lease'. > =item B<domifstat> I<domain> I<interface-device> > > Get network interface stats for a running domain. > ACK with the cleanups John -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list