[libvirt] [PATCH v8 4/4] domifaddr: Add virsh support
John Ferlan
jferlan at redhat.com
Fri Feb 13 18:50:32 UTC 2015
On 01/25/2015 01:38 PM, Nehal J Wani wrote:
> tools/virsh-domain-monitor.c
> * Introduce new command : domifaddr
> Usage: domifaddr <domain> [interface] [--full] [--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
>
> virsh # domifaddr f20 eth1 --agent
> 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 --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
>
I for one like the format of the output and appreciate seeing it in the
commit message!
> Signed-off-by: Nehal J Wani <nehaljw.kkd1 at gmail.com>
> ---
> tools/virsh-domain-monitor.c | 141 +++++++++++++++++++++++++++++++++++++++++++
> tools/virsh.pod | 16 +++++
> 2 files changed, 157 insertions(+)
>
> diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c
> index 925eb1b..960b831 100644
> --- a/tools/virsh-domain-monitor.c
> +++ b/tools/virsh-domain-monitor.c
> @@ -2177,6 +2177,141 @@ 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 = "lease",
> + .type = VSH_OT_BOOL,
> + .flags = VSH_OFLAG_NONE,
> + .help = N_("parse dhcp lease file")},
> + {.name = "agent",
> + .type = VSH_OT_BOOL,
> + .flags = VSH_OFLAG_NONE,
> + .help = N_("query qemu guest 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;
> + unsigned int flags = 0;
> + bool ret = false;
> + bool full = vshCommandOptBool(cmd, "full");
> +
> + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
> + return false;
> +
> + if (vshCommandOptString(cmd, "interface", &interface) < 0)
> + goto cleanup;
> +
> + if (vshCommandOptBool(cmd, "lease"))
> + flags |= VIR_DOMAIN_INTERFACE_ADDRESSES_LEASE;
> +
> + if (vshCommandOptBool(cmd, "agent"))
> + flags |= VIR_DOMAIN_INTERFACE_ADDRESSES_AGENT;
> +
Since only one style would be displayed (lease in preference over agent)
- providing both flags could be an error... Unless of course you change
3/4 to allow tryAgent after tryLease returns.
> + if ((ifaces_count = virDomainInterfaceAddresses(dom, &ifaces, flags)) < 0) {
[1] Same Coverity issue as 2/4
> + 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",
Should this be " %-12s..." instead of "%-12s" (since everything else
adds that extra space).
> + 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)
again here Coverity complains because it doesn't understand the
relationship between ifaces_count and ifaces, so going with :
if (ifaces_count > 0) {
for (i = 0; i < ifaces_count; i++)
virDomainInterfaceFree(ifaces[i]);
}
pacifies Coverity.
> + for (i = 0; i < ifaces_count; i++)
> + virDomainInterfaceFree(ifaces[i]);
> + VIR_FREE(ifaces);
> +
> + virDomainFree(dom);
> + return ret;
> +}
> +
> const vshCmdDef domMonitoringCmds[] = {
> {.name = "domblkerror",
> .handler = cmdDomBlkError,
> @@ -2214,6 +2349,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 abe80c2..f5457bb 100644
> --- a/tools/virsh.pod
> +++ b/tools/virsh.pod
> @@ -729,6 +729,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<--snoop>]] [I<--lease>] [I<--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 interfac has multiple addresses or alias, otherwise
s/interfac/interface
> +it only displays the interface name for the first address, and "-" for the
> +others. If I<--lease> is specified, dhcp file is parsed and if I<--agent> is
> +specified, qemu guest agent is queried. It is not recommended to mix I<--agent>
> +with I<--lease> as it may return ambiguous results.
> +
Well technically as the code is written - if --lease and --agent are
provided, only --lease is returned
John
> =item B<domifstat> I<domain> I<interface-device>
>
> Get network interface stats for a running domain.
>
More information about the libvir-list
mailing list