On 03/31/2016 05:22 AM, Vasiliy Tolstov wrote:
Allow to use ip address and routes elements inside network ethernet.
Also allow to configure point-to-point address for host side device.
In order to allow for possible backporting of parts of this feature
without requiring backports of the rest, I think this should be in 4
patches:
1) changes to virnetdev.[ch] to support setting a peer address
2) changes to domain_conf.[ch], domaincommon.rng (that's the RNG file
that needs modification, not network.rng), and formatdomain.html.in to
add peer address to the config.
3) change to lxc_container.c to support setting the peer address.
4) change to qemu_interface.c to support setting ip/peer/route.
This way someone could backport the lxc support without needing to
backport qemu support, or they could backport some potential future fix
to one of the virNetDev*() functions without needing to backport the new
functionality at the hypervisor level. (I know this seems pedantic, but
multiple times I've ended up needing to manaually mangle bugfix patches
during a backport in order to account for lack of some feature on the
old branch).
Signed-off-by: Vasiliy Tolstov <v.tolstov(a)selfip.ru>
---
docs/formatdomain.html.in | 12 ++++++++-
docs/schemas/network.rng | 3 +++
As I noted above, the file that needs this addition is domaincommon.rng
(which has the RNG for domain XML) not network.rng (which has the RNG
for libvirt virtual network XML, a completely different thing from the
<interface> inside a <domain>).
include/libvirt/libvirt-domain.h | 1 +
src/conf/domain_conf.c | 14 ++++++++++-
src/conf/domain_conf.h | 1 +
src/conf/network_conf.c | 26 ++++++++++++++++++-
src/conf/network_conf.h | 1 +
Since it seems that my understanding is correct (this feature is to
support setting a POINTOPOINT peer address on the tap device used by a
domain's <interface type='ethernet'> device), you should get rid of the
changes to network_conf.[ch] - those are for configuring a libvirt
virtual network, not for configuring a domain's <interface> element.
src/lxc/lxc_container.c | 2 +-
src/network/bridge_driver.c | 2 +-
The change to bridge_driver should also be eliminated (except that
you'll need to put a NULL in place of the peer address). AFAIK it's
nonsensical to set a POINTOPOINT peer address for a linux host bridge
device (that's what this change does).
src/qemu/qemu_interface.c | 39
+++++++++++++++++++++++++++++
src/util/virnetdev.c | 54 ++++++++++++++++++++++++++++------------
src/util/virnetdev.h | 1 +
12 files changed, 135 insertions(+), 21 deletions(-)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 71ffe750452e..1203e96a8286 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -4717,6 +4717,7 @@ qemu-kvm -net nic,model=? /dev/null
<source network='default'/>
<target dev='vnet0'/>
<b><ip address='192.168.122.5'
prefix='24'/></b>
+ <b><ip address='192.168.122.5' prefix='24'
peer='10.0.0.10'/></b>
<b><route family='ipv4' address='192.168.122.0'
prefix='24' gateway='192.168.122.1'/></b>
<b><route family='ipv4' address='192.168.122.8'
gateway='192.168.122.1'/></b>
</interface>
@@ -4749,7 +4750,16 @@ qemu-kvm -net nic,model=? /dev/null
to define the network routes to use for the network device. The attributes
of this element are described in the documentation for the
<code>route</code>
element in <a href="formatnetwork.html#elementsStaticroute">network
definitions</a>.
- This is only used by the LXC driver.
+ This is used by the LXC driver and <span class="since">Since
1.3.3</span> by the QEMU
+ driver.
+ </p>
+
+ <p>
+ <span class="since">Since 1.3.3</span> ip elements can hold
peer attribute to assign
+ point-to-point address for the network device. The attributes of this element
"to assign *a* point-to-point address"
+ are described in the documentation for the
<code>ip</code> element in
+ <a href="formatnetwork.html#elementsAddress">network
definitions</a>.
The above is untrue. You haven't made (and *shouldn't* make) any changes
to formatnetwork.html.in, so it doesn't contain any info about the
"peer" attribute. Since there are differences between <ip> for a domain
and for a network, you should document them separately.
+ This is only used by the LXC and QEMU driver.
s/driver/drivers/
diff --git a/include/libvirt/libvirt-domain.h
b/include/libvirt/libvirt-domain.h
index 7e06796c3c73..437e87fac01c 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -3937,6 +3937,7 @@ typedef virDomainIPAddress *virDomainIPAddressPtr;
struct _virDomainInterfaceIPAddress {
int type; /* virIPAddrType */
char *addr; /* IP address */
+ char *peer; /* IP peer */
unsigned int prefix; /* IP address prefix */
};
You've added this into the struct that is used to report IP address info
returned by virDomainInterfaceAddresses, but haven't put anything into
the code supporting that API to report a peer address. You should either
add that support, or remove peer from this struct.
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index d5d9ff702f42..34855233ad15 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -5725,7 +5725,7 @@ virDomainNetIpParseXML(xmlNodePtr node)
unsigned int prefixValue = 0;
char *familyStr = NULL;
int family = AF_UNSPEC;
- char *address = NULL;
+ char *address = NULL, *peer = NULL;
if (!(prefixStr = virXMLPropString(node, "prefix")) ||
(virStrToLong_ui(prefixStr, NULL, 10, &prefixValue) < 0)) {
@@ -5739,6 +5739,9 @@ virDomainNetIpParseXML(xmlNodePtr node)
goto cleanup;
}
+ if ((peer = virXMLPropString(node, "peer")) == NULL)
+ VIR_DEBUG("Peer is empty");
+
familyStr = virXMLPropString(node, "family");
if (familyStr && STREQ(familyStr, "ipv4"))
family = AF_INET;
@@ -5756,6 +5759,14 @@ virDomainNetIpParseXML(xmlNodePtr node)
address);
goto cleanup;
}
+
+ if ((peer != NULL) && (virSocketAddrParse(&ip->peer, peer, family)
< 0)) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("Failed to parse IP address: '%s'"),
+ peer);
+ goto cleanup;
+ }
+
ip->prefix = prefixValue;
ret = ip;
@@ -5765,6 +5776,7 @@ virDomainNetIpParseXML(xmlNodePtr node)
VIR_FREE(prefixStr);
VIR_FREE(familyStr);
VIR_FREE(address);
+ VIR_FREE(peer);
VIR_FREE(ip);
return ret;
}
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 83bdd67dec45..040882ec8460 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -513,6 +513,7 @@ typedef struct _virDomainNetIpDef virDomainNetIpDef;
typedef virDomainNetIpDef *virDomainNetIpDefPtr;
struct _virDomainNetIpDef {
virSocketAddr address; /* ipv4 or ipv6 address */
+ virSocketAddr peer; /* ipv4 or ipv6 address of peer */
unsigned int prefix; /* number of 1 bits in the net mask */
};
[removed unneeded network_conf.[ch] diffs]
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
index 348bbfbc01fc..a1deb0c00d4c 100644
--- a/src/lxc/lxc_container.c
+++ b/src/lxc/lxc_container.c
@@ -520,7 +520,7 @@ static int lxcContainerRenameAndEnableInterfaces(virDomainDefPtr
vmDef,
VIR_DEBUG("Adding IP address '%s/%u' to '%s'",
ipStr, ip->prefix, newname);
- if (virNetDevSetIPAddress(newname, &ip->address, prefix) < 0) {
+ if (virNetDevSetIPAddress(newname, &ip->address, &ip->peer,
prefix) < 0) {
virReportError(VIR_ERR_SYSTEM_ERROR,
_("Failed to set IP address '%s' on
%s"),
ipStr, newname);
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index a09a7e474fc5..f3ff88ff55a6 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -1970,7 +1970,7 @@ networkAddAddrToBridge(virNetworkObjPtr network,
}
if (virNetDevSetIPAddress(network->def->bridge,
- &ipdef->address, prefix) < 0)
+ &ipdef->address, &ipdef->peer, prefix) <
0)
return -1;
return 0;
diff --git a/src/qemu/qemu_interface.c b/src/qemu/qemu_interface.c
index 13a513152876..5729325fadb9 100644
--- a/src/qemu/qemu_interface.c
+++ b/src/qemu/qemu_interface.c
@@ -474,6 +474,45 @@ qemuInterfaceEthernetConnect(virDomainDefPtr def,
if (virNetDevSetMAC(net->ifname, &tapmac) < 0)
goto cleanup;
+ for (j = 0; j < net->nips; j++) {
+ virDomainNetIpDefPtr ip = net->ips[j];
+ unsigned int prefix = (ip->prefix > 0) ? ip->prefix :
+ VIR_SOCKET_ADDR_DEFAULT_PREFIX;
+ char *ipStr = virSocketAddrFormat(&ip->address);
+
+ VIR_DEBUG("Adding IP address '%s/%u' to '%s'",
+ ipStr, ip->prefix, net->ifname);
+
+ if (virNetDevSetIPAddress(net->ifname, &ip->address, &ip->peer,
prefix) < 0) {
+ virReportError(VIR_ERR_SYSTEM_ERROR,
+ _("Failed to set IP address '%s' on %s"),
+ ipStr, net->ifname);
+ VIR_FREE(ipStr);
+ goto cleanup;
+ }
+ VIR_FREE(ipStr);
+ }
+
+ if (net->linkstate == VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP ||
+ net->linkstate == VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DEFAULT) {
+ if (virNetDevSetOnline(net->ifname, true) < 0)
+ goto cleanup;
+
+ /* Set the routes */
+ for (j = 0; j < net->nroutes; j++) {
+ virNetworkRouteDefPtr route = net->routes[j];
+
+ if (virNetDevAddRoute(net->ifname,
+ virNetworkRouteDefGetAddress(route),
+ virNetworkRouteDefGetPrefix(route),
+ virNetworkRouteDefGetGateway(route),
+ virNetworkRouteDefGetMetric(route)) < 0) {
+ goto cleanup;
+ }
+ }
+ }
+
+
Seeing this makes me think that there is nothing in the validation to
assure somebody doesn't try to set an ip address for an interface type
that doesn't support it. Of course that's not necessary for this feature
to work (it's an existing problem) but a separate patch to log an error
if there are any ip's set for types other than ethernet would be a nice
touch (currently this happens in two places for some reason -
qemuBuildInterfaceCommandLine() and qemuDomainAttachNetDevice() - there
seems to be a lot of duplicated code there...)
if (net->script &&
qemuExecuteEthernetScript(net->ifname, net->script) < 0)
goto cleanup;
diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c
index aed50f546263..6e32ebbf6cee 100644
--- a/src/util/virnetdev.c
+++ b/src/util/virnetdev.c
@@ -1039,21 +1039,28 @@ virNetDevCreateNetlinkAddressMessage(int messageType,
const char *ifname,
virSocketAddr *addr,
unsigned int prefix,
- virSocketAddr *broadcast)
+ virSocketAddr *broadcast,
+ virSocketAddr *peer)
{
struct nl_msg *nlmsg = NULL;
struct ifaddrmsg ifa;
unsigned int ifindex;
void *addrData = NULL;
+ void *peerData = NULL;
void *broadcastData = NULL;
size_t addrDataLen;
if (virNetDevGetIPAddressBinary(addr, &addrData, &addrDataLen) < 0)
return NULL;
- if (broadcast && virNetDevGetIPAddressBinary(broadcast, &broadcastData,
- &addrDataLen) < 0)
- return NULL;
+ if (peer && VIR_SOCKET_ADDR_VALID(peer)) {
+ if (virNetDevGetIPAddressBinary(peer, &peerData, &addrDataLen) < 0)
+ return NULL;
+ } else if (broadcast) {
+ if (virNetDevGetIPAddressBinary(broadcast, &broadcastData,
+ &addrDataLen) < 0)
+ return NULL;
+ }
/* Get the interface index */
if ((ifindex = if_nametoindex(ifname)) == 0)
@@ -1078,12 +1085,15 @@ virNetDevCreateNetlinkAddressMessage(int messageType,
if (nla_put(nlmsg, IFA_LOCAL, addrDataLen, addrData) < 0)
goto buffer_too_small;
- if (nla_put(nlmsg, IFA_ADDRESS, addrDataLen, addrData) < 0)
- goto buffer_too_small;
+ if (peerData) {
+ if (nla_put(nlmsg, IFA_ADDRESS, addrDataLen, peerData) < 0)
+ goto buffer_too_small;
+ }
- if (broadcastData &&
- nla_put(nlmsg, IFA_BROADCAST, addrDataLen, broadcastData) < 0)
- goto buffer_too_small;
+ if (broadcastData) {
+ if (nla_put(nlmsg, IFA_BROADCAST, addrDataLen, broadcastData) < 0)
+ goto buffer_too_small;
+ }
return nlmsg;
@@ -1098,6 +1108,7 @@ virNetDevCreateNetlinkAddressMessage(int messageType,
* virNetDevSetIPAddress:
* @ifname: the interface name
* @addr: the IP address (IPv4 or IPv6)
+ * @peer: The IP address of peer (IPv4 or IPv6)
* @prefix: number of 1 bits in the netmask
*
* Add an IP address to an interface. This function *does not* remove
@@ -1108,6 +1119,7 @@ virNetDevCreateNetlinkAddressMessage(int messageType,
*/
int virNetDevSetIPAddress(const char *ifname,
virSocketAddr *addr,
+ virSocketAddr *peer,
unsigned int prefix)
{
virSocketAddr *broadcast = NULL;
@@ -1116,9 +1128,8 @@ int virNetDevSetIPAddress(const char *ifname,
struct nlmsghdr *resp = NULL;
unsigned int recvbuflen;
-
/* The caller needs to provide a correct address */
- if (VIR_SOCKET_ADDR_FAMILY(addr) == AF_INET) {
+ if (VIR_SOCKET_ADDR_FAMILY(addr) == AF_INET && !VIR_SOCKET_ADDR_VALID(peer))
{
/* compute a broadcast address if this is IPv4 */
if (VIR_ALLOC(broadcast) < 0)
return -1;
@@ -1129,7 +1140,7 @@ int virNetDevSetIPAddress(const char *ifname,
if (!(nlmsg = virNetDevCreateNetlinkAddressMessage(RTM_NEWADDR, ifname,
addr, prefix,
- broadcast)))
+ broadcast, peer)))
goto cleanup;
if (virNetlinkCommand(nlmsg, &resp, &recvbuflen, 0, 0,
@@ -1288,7 +1299,7 @@ int virNetDevClearIPAddress(const char *ifname,
if (!(nlmsg = virNetDevCreateNetlinkAddressMessage(RTM_DELADDR, ifname,
addr, prefix,
- NULL)))
+ NULL, NULL)))
goto cleanup;
if (virNetlinkCommand(nlmsg, &resp, &recvbuflen, 0, 0,
@@ -1423,21 +1434,27 @@ virNetDevWaitDadFinish(virSocketAddrPtr *addrs, size_t count)
int virNetDevSetIPAddress(const char *ifname,
virSocketAddr *addr,
+ virSocketAddr *peer,
unsigned int prefix)
{
virCommandPtr cmd = NULL;
- char *addrstr = NULL, *bcaststr = NULL;
+ char *addrstr = NULL, *bcaststr = NULL, *peerstr = NULL;
virSocketAddr broadcast;
int ret = -1;
if (!(addrstr = virSocketAddrFormat(addr)))
goto cleanup;
+
+ if (VIR_SOCKET_ADDR_VALID(peer) && !(peerstr =
virSocketAddrFormat(&peer)))
+ goto cleanup;
+
/* format up a broadcast address if this is IPv4 */
- if ((VIR_SOCKET_ADDR_IS_FAMILY(addr, AF_INET)) &&
+ if (!peerstr && ((VIR_SOCKET_ADDR_IS_FAMILY(addr, AF_INET)) &&
((virSocketAddrBroadcastByPrefix(addr, prefix, &broadcast) < 0) ||
- !(bcaststr = virSocketAddrFormat(&broadcast)))) {
+ !(bcaststr = virSocketAddrFormat(&broadcast))))) {
goto cleanup;
}
+
# ifdef IFCONFIG_PATH
cmd = virCommandNew(IFCONFIG_PATH);
virCommandAddArg(cmd, ifname);
@@ -1446,6 +1463,8 @@ int virNetDevSetIPAddress(const char *ifname,
else
virCommandAddArg(cmd, "inet");
virCommandAddArgFormat(cmd, "%s/%u", addrstr, prefix);
+ if (peerstr)
+ virCommandAddArgList(cmd, "pointopoint", peerstr, NULL);
if (bcaststr)
virCommandAddArgList(cmd, "broadcast", bcaststr, NULL);
virCommandAddArg(cmd, "alias");
@@ -1453,6 +1472,8 @@ int virNetDevSetIPAddress(const char *ifname,
cmd = virCommandNew(IP_PATH);
virCommandAddArgList(cmd, "addr", "add", NULL);
virCommandAddArgFormat(cmd, "%s/%u", addrstr, prefix);
+ if (peerstr)
+ virCommandAddArgList(cmd, "peer", peerstr, NULL);
if (bcaststr)
virCommandAddArgList(cmd, "broadcast", bcaststr, NULL);
virCommandAddArgList(cmd, "dev", ifname, NULL);
@@ -1465,6 +1486,7 @@ int virNetDevSetIPAddress(const char *ifname,
cleanup:
VIR_FREE(addrstr);
VIR_FREE(bcaststr);
+ VIR_FREE(peerstr);
virCommandFree(cmd);
return ret;
}
diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h
index e7719d58a410..240fff774d30 100644
--- a/src/util/virnetdev.h
+++ b/src/util/virnetdev.h
@@ -90,6 +90,7 @@ int virNetDevGetOnline(const char *ifname,
int virNetDevSetIPAddress(const char *ifname,
virSocketAddr *addr,
+ virSocketAddr *peer,
unsigned int prefix)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
int virNetDevAddRoute(const char *ifname,