Assign peer address if it provided Signed-off-by: Vasiliy Tolstov <v.tolstov@xxxxxxxxx> --- 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/util/virnetdev.c | 43 +++++++++++++++++++++++++++------------- src/util/virnetdev.h | 1 + 9 files changed, 73 insertions(+), 18 deletions(-) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 4ac29cd78816..d2cd45eba253 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -3926,6 +3926,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 7d68096f0e55..fa62cda7a290 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 85c4f554a2e2..0feff47ac99e 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..a909b660b3ae 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, NULL, 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..b3dbea13b58f 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, NULL, prefix) < 0) return -1; return 0; diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index aed50f546263..d171f34e6058 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,10 +1434,11 @@ 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; @@ -1453,6 +1465,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 +1479,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@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list