Allow to use ip address and routes elements inside network ethernet. Also allow to configure point-to-point address for host side device.
Signed-off-by: Vasiliy Tolstov <v.tols...@selfip.ru> --- docs/formatdomain.html.in | 12 ++++++++- docs/schemas/network.rng | 3 +++ 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 + src/lxc/lxc_container.c | 2 +- src/network/bridge_driver.c | 2 +- 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 + are described in the documentation for the <code>ip</code> element in + <a href="formatnetwork.html#elementsAddress">network definitions</a>. + This is only used by the LXC and QEMU driver. </p> <h5><a name="elementVhostuser">vhost-user interface</a></h5> diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng index 4edb6eb31ad0..47b4b80fc0c3 100644 --- a/docs/schemas/network.rng +++ b/docs/schemas/network.rng @@ -315,6 +315,9 @@ </choice> </optional> <optional> + <attribute name="peer"><ref name="ipAddr"/></attribute> + </optional> + <optional> <attribute name="family"><ref name="addr-family"/></attribute> </optional> <optional> 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 */ }; 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 */ }; diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index 4fb2e2a75b9d..1a0cf7fdcdd2 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -1456,7 +1456,7 @@ virNetworkIPDefParseXML(const char *networkName, */ xmlNodePtr cur, save; - char *address = NULL, *netmask = NULL; + char *address = NULL, *netmask = NULL, *peer = NULL; unsigned long prefix = 0; int prefixRc; int result = -1; @@ -1502,6 +1502,14 @@ virNetworkIPDefParseXML(const char *networkName, else def->prefix = prefix; + peer = virXPathString("string(./@peer)", ctxt); + if (peer && (virSocketAddrParse(&def->peer, peer, AF_UNSPEC) < 0)) { + virReportError(VIR_ERR_XML_ERROR, + _("Invalid peer '%s' in network '%s'"), + peer, networkName); + goto cleanup; + } + /* validate address, etc. for each family */ if ((def->family == NULL) || (STREQ(def->family, "ipv4"))) { if (!(VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET) || @@ -1531,6 +1539,14 @@ virNetworkIPDefParseXML(const char *networkName, prefix, networkName); goto cleanup; } + if (peer) { + if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->peer, AF_INET)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Family 'ipv4' specified for non-IPv4 address '%s' in network '%s'"), + peer, networkName); + goto cleanup; + } + } } else if (STREQ(def->family, "ipv6")) { if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET6)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, @@ -1550,6 +1566,14 @@ virNetworkIPDefParseXML(const char *networkName, prefix, networkName); goto cleanup; } + if (peer) { + if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->peer, AF_INET6)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Family 'ipv6' specified for non-IPv6 address '%s' in network '%s'"), + peer, networkName); + goto cleanup; + } + } } else { virReportError(VIR_ERR_XML_ERROR, _("Unrecognized family '%s' in network '%s'"), diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h index b72257b970a8..9b8e807fda3c 100644 --- a/src/conf/network_conf.h +++ b/src/conf/network_conf.h @@ -152,6 +152,7 @@ struct _virNetworkIpDef { */ unsigned int prefix; /* ipv6 - only prefix allowed */ virSocketAddr netmask; /* ipv4 - either netmask or prefix specified */ + virSocketAddr peer; /* ipv4 or ipv6 peer address */ size_t nranges; /* Zero or more dhcp ranges */ virSocketAddrRangePtr ranges; 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; + } + } + } + + 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, -- 2.7.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list