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
<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 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.
This commit is contained in:
Laine Stump 2011-07-07 00:24:08 -04:00 committed by Daniel Veillard
parent c5d1592e20
commit 239322cbd4
3 changed files with 106 additions and 0 deletions

View File

@ -5,5 +5,6 @@
# bridge_driver.h # bridge_driver.h
networkAllocateActualDevice; networkAllocateActualDevice;
networkBuildDhcpDaemonCommandLine; networkBuildDhcpDaemonCommandLine;
networkGetNetworkAddress;
networkNotifyActualDevice; networkNotifyActualDevice;
networkReleaseActualDevice; networkReleaseActualDevice;

View File

@ -55,6 +55,7 @@
#include "uuid.h" #include "uuid.h"
#include "iptables.h" #include "iptables.h"
#include "bridge.h" #include "bridge.h"
#include "interface.h"
#include "logging.h" #include "logging.h"
#include "dnsmasq.h" #include "dnsmasq.h"
#include "util/network.h" #include "util/network.h"
@ -3090,3 +3091,103 @@ cleanup:
iface->data.network.actual = NULL; iface->data.network.actual = NULL;
return ret; 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;
}

View File

@ -43,6 +43,9 @@ int networkNotifyActualDevice(virDomainNetDefPtr iface)
int networkReleaseActualDevice(virDomainNetDefPtr iface) int networkReleaseActualDevice(virDomainNetDefPtr iface)
ATTRIBUTE_NONNULL(1); ATTRIBUTE_NONNULL(1);
int networkGetNetworkAddress(const char *netname, char **netaddr)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
int networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network, int networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network,
virCommandPtr *cmdout, char *pidfile, virCommandPtr *cmdout, char *pidfile,
dnsmasqContext *dctx) dnsmasqContext *dctx)
@ -52,6 +55,7 @@ int networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network,
# define networkAllocateActualDevice(iface) 0 # define networkAllocateActualDevice(iface) 0
# define networkNotifyActualDevice(iface) 0 # define networkNotifyActualDevice(iface) 0
# define networkReleaseActualDevice(iface) 0 # define networkReleaseActualDevice(iface) 0
# defing networkGetNetworkAddress(netname, netaddr) (-2)
# define networkBuildDhcpDaemonCommandLine(network, cmdout, pidfile, dctx) 0 # define networkBuildDhcpDaemonCommandLine(network, cmdout, pidfile, dctx) 0
# endif # endif