The new listenNetwork atribute needs to learn an IP address based on a named network. This patch provides a function networkGetNetworkAddress which provides that. Some networks have an IP address explicitly in their configuration (ie, those with a forward type of "none", "route", or "nat"). For those, we can just return the IP address from the config. The rest will have a physical device associated with them (either via <bridge name='...'/>, <forward ... dev='...'/>, or possibly via a pool of interfaces inside the network's <forward> element) and we will need to ask the kernel for the current IP address of that device (via the newly added ifaceGetIPAddress If networkGetNetworkAddress encounters an error while trying to learn the address for a network, it will return -1. In the case that libvirt has been compiled without the network driver, a static inline version of the function, which returns -2, will be used. This allows differentiating between a failure of the network driver, and its complete absence. --- src/libvirt_network.syms | 1 + src/network/bridge_driver.c | 100 +++++++++++++++++++++++++++++++++++++++++++ src/network/bridge_driver.h | 7 +++ 3 files changed, 108 insertions(+), 0 deletions(-) diff --git a/src/libvirt_network.syms b/src/libvirt_network.syms index e402b5f..1fe8902 100644 --- a/src/libvirt_network.syms +++ b/src/libvirt_network.syms @@ -5,5 +5,6 @@ # bridge_driver.h networkAllocateActualDevice; networkBuildDhcpDaemonCommandLine; +networkGetNetworkAddress; networkNotifyActualDevice; networkReleaseActualDevice; diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 15e0710..64ca9a8 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -55,6 +55,7 @@ #include "uuid.h" #include "iptables.h" #include "bridge.h" +#include "interface.h" #include "logging.h" #include "dnsmasq.h" #include "util/network.h" @@ -3087,3 +3088,102 @@ cleanup: iface->data.network.actual = NULL; return ret; } + +/* + * networkGetNetworkAddress: + * @netname: the name of a network + * @netaddr: string representation of IP address for that network. + * + * Attempt to return the IP (v4) address associated with the named + * network. If a libvirt virtual network, that will be provided in the + * configuration. For host bridge and direct (macvtap) networks, we + * must do an ioctl to learn the address. + * + * Note: This function returns the 1st IPv4 address it finds. It might + * be useful if it was more flexible, but the current use (getting a + * listen address for qemu's vnc/spice graphics server) can only use a + * single address anyway. + * + * Returns 0 on success, and puts a string (which must be free'd by + * the caller) into *netaddr. Returns -1 on failure + */ +int +networkGetNetworkAddress(const char *netname, char **netaddr) +{ + int ret = -1; + struct network_driver *driver = driverState; + virNetworkObjPtr network = NULL; + virNetworkDefPtr netdef; + virNetworkIpDefPtr ipdef; + virSocketAddr addr; + virSocketAddrPtr addrptr = NULL; + char *devname = NULL; + + *netaddr = NULL; + networkDriverLock(driver); + network = virNetworkFindByName(&driver->networks, netname); + networkDriverUnlock(driver); + if (!network) { + networkReportError(VIR_ERR_NO_NETWORK, + _("no network with matching name '%s'"), + netname); + goto cleanup; + } + netdef = network->def; + + switch (netdef->forwardType) { + case VIR_NETWORK_FORWARD_NONE: + case VIR_NETWORK_FORWARD_NAT: + case VIR_NETWORK_FORWARD_ROUTE: + /* if there's an ipv4def, get it's address */ + ipdef = virNetworkDefGetIpByIndex(netdef, AF_INET, 0); + if (!ipdef) { + networkReportError(VIR_ERR_INTERNAL_ERROR, + _("network '%s' doesn't have an IP address"), + netdef->name); + break; + } + addrptr = &ipdef->address; + break; + + case VIR_NETWORK_FORWARD_BRIDGE: + if ((devname = netdef->bridge)) + break; + /* + * If netdef->bridge wasn't set, this is a direct-mode + * interface, so purposefully fall through to the next case + */ + case VIR_NETWORK_FORWARD_PRIVATE: + case VIR_NETWORK_FORWARD_VEPA: + case VIR_NETWORK_FORWARD_PASSTHROUGH: + if ((netdef->nForwardIfs > 0) && netdef->forwardIfs) + devname = netdef->forwardIfs[0].dev; + + if (!devname) { + networkReportError(VIR_ERR_INTERNAL_ERROR, + _("network '%s' has no associated interface or bridge"), + netdef->name); + } + break; + } + + if (devname) { + if (ifaceGetIPAddress(devname, &addr)) { + virReportSystemError(errno, + _("Failed to get IP address for '%s' (network '%s')"), + devname, netdef->name); + } else { + addrptr = &addr; + } + } + + if (addrptr) { + *netaddr = virSocketFormatAddr(addrptr); + ret = 0; + } + +cleanup: + if (network) + virNetworkObjUnlock(network); + return ret; +} diff --git a/src/network/bridge_driver.h b/src/network/bridge_driver.h index 710d862..930c526 100644 --- a/src/network/bridge_driver.h +++ b/src/network/bridge_driver.h @@ -40,6 +40,8 @@ int networkAllocateActualDevice(virDomainNetDefPtr iface); int networkNotifyActualDevice(virDomainNetDefPtr iface); int networkReleaseActualDevice(virDomainNetDefPtr iface); +int networkGetNetworkAddress(const char *netname, char **netaddr); + int networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network, virCommandPtr *cmdout, char *pidfile, dnsmasqContext *dctx); @@ -57,6 +59,11 @@ networkReleaseActualDevice(virDomainNetDefPtr iface ATTRIBUTE_UNUSED) { return 0; } static inline int +networkGetNetworkAddress(const char *netname ATTRIBUTE_UNUSED, + char **netaddr ATTRIBUTE_UNUSED) + { return -2; } + +static inline int networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network ATTRIBUTE_UNUSED, virCommandPtr *cmdout ATTRIBUTE_UNUSED, char *pidfile ATTRIBUTE_UNUSED, -- 1.7.3.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list