[libvirt] [PATCH] allow ip and route elements for netdev ethernet

Vasiliy Tolstov v.tolstov at selfip.ru
Thu Mar 31 09:22:00 UTC 2016


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.tolstov at 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




More information about the libvir-list mailing list