From 239322cbd4d559231b1e6cfb6a71c6c884752026 Mon Sep 17 00:00:00 2001 From: Laine Stump Date: Thu, 7 Jul 2011 00:24:08 -0400 Subject: [PATCH] network: provide internal API to return IP of a network The new listenNetwork attribute 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 , , or possibly via a pool of interfaces inside the network's element) and we will need to ask the kernel for a 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, the call is a macro which reduces to -2. This allows differentiating between a failure of the network driver, and its complete absence. --- src/libvirt_network.syms | 1 + src/network/bridge_driver.c | 101 ++++++++++++++++++++++++++++++++++++ src/network/bridge_driver.h | 4 ++ 3 files changed, 106 insertions(+) diff --git a/src/libvirt_network.syms b/src/libvirt_network.syms index e402b5f283..1fe89027b4 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 99033a2e04..4a274086e4 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" @@ -3090,3 +3091,103 @@ 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 an 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 or -2 if + * completely unsupported. + */ +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 IPv4 address"), + netdef->name); + break; + } + addrptr = &ipdef->address; + break; + + case VIR_NETWORK_FORWARD_BRIDGE: + if ((devname = netdef->bridge)) + break; + /* + * fall through if netdef->bridge wasn't set, since this is + * also a direct-mode interface. + */ + 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 d409f76136..518a5ba3bb 100644 --- a/src/network/bridge_driver.h +++ b/src/network/bridge_driver.h @@ -43,6 +43,9 @@ int networkNotifyActualDevice(virDomainNetDefPtr iface) int networkReleaseActualDevice(virDomainNetDefPtr iface) ATTRIBUTE_NONNULL(1); +int networkGetNetworkAddress(const char *netname, char **netaddr) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + int networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network, virCommandPtr *cmdout, char *pidfile, dnsmasqContext *dctx) @@ -52,6 +55,7 @@ int networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network, # define networkAllocateActualDevice(iface) 0 # define networkNotifyActualDevice(iface) 0 # define networkReleaseActualDevice(iface) 0 +# defing networkGetNetworkAddress(netname, netaddr) (-2) # define networkBuildDhcpDaemonCommandLine(network, cmdout, pidfile, dctx) 0 # endif