From ca481a6f8f230f41a93a296dc8ee50398bb50ed4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=A9dric=20Bosdonnat?= <cbosdonnat@suse.com>
Date: Wed, 14 Jan 2015 14:21:10 +0100
Subject: [PATCH 3/7] Move code related to network routes to
 networkcommon_conf.[ch]

Moving code for parsing and formatting network routes to
networkcommon_conf helps reusing those routes for domains. The route
definition has been hidden to help reducing the number of unnecessary
checks in the format function.

Squashed in bug fix commit '6f32ebc7'
---
 po/POTFILES.in                |   1 +
 src/Makefile.am               |   3 +-
 src/conf/network_conf.c       | 299 ++----------------------------
 src/conf/network_conf.h       |  22 +--
 src/conf/networkcommon_conf.c | 413 ++++++++++++++++++++++++++++++++++++++++++
 src/conf/networkcommon_conf.h |  72 ++++++++
 src/libvirt_private.syms      |  11 ++
 src/network/bridge_driver.c   |  44 ++---
 8 files changed, 526 insertions(+), 339 deletions(-)
 create mode 100644 src/conf/networkcommon_conf.c
 create mode 100644 src/conf/networkcommon_conf.h

Index: libvirt-1.2.5/po/POTFILES.in
===================================================================
--- libvirt-1.2.5.orig/po/POTFILES.in
+++ libvirt-1.2.5/po/POTFILES.in
@@ -22,6 +22,7 @@ src/conf/netdev_bandwidth_conf.c
 src/conf/netdev_vlan_conf.c
 src/conf/netdev_vport_profile_conf.c
 src/conf/network_conf.c
+src/conf/networkcommon_conf.c
 src/conf/node_device_conf.c
 src/conf/nwfilter_conf.c
 src/conf/nwfilter_params.c
Index: libvirt-1.2.5/src/Makefile.am
===================================================================
--- libvirt-1.2.5.orig/src/Makefile.am
+++ libvirt-1.2.5/src/Makefile.am
@@ -265,7 +265,8 @@ NETWORK_EVENT_SOURCES =						\
 
 # Network driver generic impl APIs
 NETWORK_CONF_SOURCES =						\
-		conf/network_conf.c conf/network_conf.h
+		conf/network_conf.c conf/network_conf.h \
+		conf/networkcommon_conf.c conf/networkcommon_conf.h
 
 # Network filter driver generic impl APIs
 NWFILTER_PARAM_CONF_SOURCES =					\
Index: libvirt-1.2.5/src/conf/network_conf.c
===================================================================
--- libvirt-1.2.5.orig/src/conf/network_conf.c
+++ libvirt-1.2.5/src/conf/network_conf.c
@@ -165,12 +165,6 @@ virNetworkIpDefClear(virNetworkIpDefPtr
 }
 
 static void
-virNetworkRouteDefClear(virNetworkRouteDefPtr def)
-{
-    VIR_FREE(def->family);
-}
-
-static void
 virNetworkDNSTxtDefClear(virNetworkDNSTxtDefPtr def)
 {
     VIR_FREE(def->name);
@@ -255,9 +249,8 @@ virNetworkDefFree(virNetworkDefPtr def)
     }
     VIR_FREE(def->ips);
 
-    for (i = 0; i < def->nroutes && def->routes; i++) {
-        virNetworkRouteDefClear(&def->routes[i]);
-    }
+    for (i = 0; i < def->nroutes && def->routes; i++)
+        virNetworkRouteDefFree(def->routes[i]);
     VIR_FREE(def->routes);
 
     for (i = 0; i < def->nPortGroups && def->portGroups; i++) {
@@ -1381,233 +1374,6 @@ virNetworkIPDefParseXML(const char *netw
 }
 
 static int
-virNetworkRouteDefParseXML(const char *networkName,
-                           xmlNodePtr node,
-                           xmlXPathContextPtr ctxt,
-                           virNetworkRouteDefPtr def)
-{
-    /*
-     * virNetworkRouteDef object is already allocated as part
-     * of an array.  On failure clear: it out, but don't free it.
-     */
-
-    xmlNodePtr save;
-    char *address = NULL, *netmask = NULL;
-    char *gateway = NULL;
-    unsigned long prefix = 0, metric = 0;
-    int result = -1;
-    int prefixRc, metricRc;
-    virSocketAddr testAddr;
-
-    save = ctxt->node;
-    ctxt->node = node;
-
-    /* grab raw data from XML */
-    def->family = virXPathString("string(./@family)", ctxt);
-    address = virXPathString("string(./@address)", ctxt);
-    netmask = virXPathString("string(./@netmask)", ctxt);
-    gateway = virXPathString("string(./@gateway)", ctxt);
-    prefixRc = virXPathULong("string(./@prefix)", ctxt, &prefix);
-    if (prefixRc == -2) {
-        virReportError(VIR_ERR_XML_ERROR,
-                       _("Invalid prefix specified "
-                         "in route definition of network '%s'"),
-                       networkName);
-        goto cleanup;
-    }
-    def->has_prefix = (prefixRc == 0);
-    def->prefix = prefix;
-    metricRc = virXPathULong("string(./@metric)", ctxt, &metric);
-    if (metricRc == -2) {
-        virReportError(VIR_ERR_XML_ERROR,
-                       _("Invalid metric specified "
-                         "in route definition of network '%s'"),
-                       networkName);
-        goto cleanup;
-    }
-    if (metricRc == 0) {
-        def->has_metric = true;
-        if (metric == 0) {
-            virReportError(VIR_ERR_XML_ERROR,
-                           _("Invalid metric value, must be > 0 "
-                             "in route definition of network '%s'"),
-                           networkName);
-            goto cleanup;
-        }
-    }
-    def->metric = metric;
-
-    /* Note: both network and gateway addresses must be specified */
-
-    if (!address) {
-        virReportError(VIR_ERR_XML_ERROR,
-                       _("Missing required address attribute "
-                         "in route definition of network '%s'"),
-                       networkName);
-        goto cleanup;
-    }
-
-    if (!gateway) {
-        virReportError(VIR_ERR_XML_ERROR,
-                       _("Missing required gateway attribute "
-                         "in route definition of network '%s'"),
-                       networkName);
-        goto cleanup;
-    }
-
-    if (virSocketAddrParse(&def->address, address, AF_UNSPEC) < 0) {
-        virReportError(VIR_ERR_XML_ERROR,
-                       _("Bad network address '%s' "
-                         "in route definition of network '%s'"),
-                       address, networkName);
-        goto cleanup;
-    }
-
-    if (virSocketAddrParse(&def->gateway, gateway, AF_UNSPEC) < 0) {
-        virReportError(VIR_ERR_XML_ERROR,
-                       _("Bad gateway address '%s' "
-                         "in route definition of network '%s'"),
-                       gateway, networkName);
-        goto cleanup;
-    }
-
-    /* validate network address, etc. for each family */
-    if ((def->family == NULL) || (STREQ(def->family, "ipv4"))) {
-        if (!(VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET) ||
-              VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_UNSPEC))) {
-            virReportError(VIR_ERR_XML_ERROR,
-                           def->family == NULL ?
-                           _("No family specified for non-IPv4 address '%s' "
-                             "in route definition of network '%s'") :
-                           _("IPv4 family specified for non-IPv4 address '%s' "
-                             "in route definition of network '%s'"),
-                           address, networkName);
-            goto cleanup;
-        }
-        if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->gateway, AF_INET)) {
-            virReportError(VIR_ERR_XML_ERROR,
-                           def->family == NULL ?
-                           _("No family specified for non-IPv4 gateway '%s' "
-                             "in route definition of network '%s'") :
-                           _("IPv4 family specified for non-IPv4 gateway '%s' "
-                             "in route definition of network '%s'"),
-                           address, networkName);
-            goto cleanup;
-        }
-        if (netmask) {
-            if (virSocketAddrParse(&def->netmask, netmask, AF_UNSPEC) < 0) {
-                virReportError(VIR_ERR_XML_ERROR,
-                               _("Bad netmask address '%s' "
-                                 "in route definition of network '%s'"),
-                               netmask, networkName);
-                goto cleanup;
-            }
-            if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->netmask, AF_INET)) {
-                virReportError(VIR_ERR_XML_ERROR,
-                               _("Network '%s' has invalid netmask '%s' "
-                                 "for address '%s' (both must be IPv4)"),
-                               networkName, netmask, address);
-                goto cleanup;
-            }
-            if (def->has_prefix) {
-                /* can't have both netmask and prefix at the same time */
-                virReportError(VIR_ERR_XML_ERROR,
-                               _("Route definition '%s' cannot have both "
-                                 "a prefix and a netmask"),
-                               networkName);
-                goto cleanup;
-            }
-        }
-        if (def->prefix > 32) {
-            virReportError(VIR_ERR_XML_ERROR,
-                           _("Invalid prefix %u specified "
-                             "in route definition of network '%s', "
-                             "must be 0 - 32"),
-                           def->prefix, networkName);
-            goto cleanup;
-        }
-    } else if (STREQ(def->family, "ipv6")) {
-        if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET6)) {
-            virReportError(VIR_ERR_XML_ERROR,
-                           _("ipv6 family specified for non-IPv6 address '%s' "
-                             "in route definition of network '%s'"),
-                           address, networkName);
-            goto cleanup;
-        }
-        if (netmask) {
-            virReportError(VIR_ERR_XML_ERROR,
-                           _("Specifying netmask invalid for IPv6 address '%s' "
-                             "in route definition of network '%s'"),
-                           address, networkName);
-            goto cleanup;
-        }
-        if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->gateway, AF_INET6)) {
-            virReportError(VIR_ERR_XML_ERROR,
-                           _("ipv6 specified for non-IPv6 gateway address '%s' "
-                             "in route definition of network '%s'"),
-                           gateway, networkName);
-            goto cleanup;
-        }
-        if (def->prefix > 128) {
-            virReportError(VIR_ERR_XML_ERROR,
-                           _("Invalid prefix %u specified "
-                             "in route definition of network '%s', "
-                             "must be 0 - 128"),
-                           def->prefix, networkName);
-            goto cleanup;
-        }
-    } else {
-        virReportError(VIR_ERR_XML_ERROR,
-                       _("Unrecognized family '%s' "
-                         "in route definition of network'%s'"),
-                       def->family, networkName);
-        goto cleanup;
-    }
-
-    /* make sure the address is a network address */
-    if (netmask) {
-        if (virSocketAddrMask(&def->address, &def->netmask, &testAddr) < 0) {
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("error converting address '%s' with netmask '%s' "
-                             "to network-address "
-                             "in route definition of network '%s'"),
-                           address, netmask, networkName);
-            goto cleanup;
-        }
-    } else {
-        if (virSocketAddrMaskByPrefix(&def->address,
-                                      def->prefix, &testAddr) < 0) {
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("error converting address '%s' with prefix %u "
-                             "to network-address "
-                             "in route definition of network '%s'"),
-                           address, def->prefix, networkName);
-            goto cleanup;
-        }
-    }
-    if (!virSocketAddrEqual(&def->address, &testAddr)) {
-        virReportError(VIR_ERR_XML_ERROR,
-                       _("address '%s' in route definition of network '%s' "
-                         "is not a network address"),
-                       address, networkName);
-        goto cleanup;
-    }
-
-    result = 0;
-
- cleanup:
-    if (result < 0) {
-        virNetworkRouteDefClear(def);
-    }
-    VIR_FREE(address);
-    VIR_FREE(netmask);
-    VIR_FREE(gateway);
-
-    ctxt->node = save;
-    return result;
-}
-
-static int
 virNetworkPortGroupParseXML(virPortGroupDefPtr def,
                             xmlNodePtr node,
                             xmlXPathContextPtr ctxt)
@@ -2175,10 +1941,13 @@ virNetworkDefParseXML(xmlXPathContextPtr
             goto error;
         /* parse each definition */
         for (i = 0; i < nRoutes; i++) {
-            int ret = virNetworkRouteDefParseXML(def->name, routeNodes[i],
-                                              ctxt, &def->routes[i]);
-            if (ret < 0)
+            virNetworkRouteDefPtr route = NULL;
+
+            if (!(route = virNetworkRouteDefParseXML(def->name,
+                                                     routeNodes[i],
+                                                     ctxt)))
                 goto error;
+            def->routes[i] = route;
             def->nroutes++;
         }
 
@@ -2194,17 +1963,18 @@ virNetworkDefParseXML(xmlXPathContextPtr
             size_t j;
             virSocketAddr testAddr, testGw;
             bool addrMatch;
-            virNetworkRouteDefPtr gwdef = &def->routes[i];
+            virNetworkRouteDefPtr gwdef = def->routes[i];
+            virSocketAddrPtr gateway = virNetworkRouteDefGetGateway(gwdef);
             addrMatch = false;
             for (j = 0; j < nIps; j++) {
                 virNetworkIpDefPtr def2 = &def->ips[j];
-                if (VIR_SOCKET_ADDR_FAMILY(&gwdef->gateway)
+                if (VIR_SOCKET_ADDR_FAMILY(gateway)
                     != VIR_SOCKET_ADDR_FAMILY(&def2->address)) {
                     continue;
                 }
                 int prefix = virNetworkIpDefPrefix(def2);
                 virSocketAddrMaskByPrefix(&def2->address, prefix, &testAddr);
-                virSocketAddrMaskByPrefix(&gwdef->gateway, prefix, &testGw);
+                virSocketAddrMaskByPrefix(gateway, prefix, &testGw);
                 if (VIR_SOCKET_ADDR_VALID(&testAddr) &&
                     VIR_SOCKET_ADDR_VALID(&testGw) &&
                     virSocketAddrEqual(&testAddr, &testGw)) {
@@ -2213,7 +1983,7 @@ virNetworkDefParseXML(xmlXPathContextPtr
                 }
             }
             if (!addrMatch) {
-                char *gw = virSocketAddrFormat(&gwdef->gateway);
+                char *gw = virSocketAddrFormat(gateway);
                 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                _("unreachable static route gateway '%s' specified for network '%s'"),
                                gw, def->name);
@@ -2541,53 +2311,6 @@ virNetworkIpDefFormat(virBufferPtr buf,
 }
 
 static int
-virNetworkRouteDefFormat(virBufferPtr buf,
-                         const virNetworkRouteDef *def)
-{
-    int result = -1;
-
-    virBufferAddLit(buf, "<route");
-
-    if (def->family) {
-        virBufferAsprintf(buf, " family='%s'", def->family);
-    }
-    if (VIR_SOCKET_ADDR_VALID(&def->address)) {
-        char *addr = virSocketAddrFormat(&def->address);
-
-        if (!addr)
-            goto error;
-        virBufferAsprintf(buf, " address='%s'", addr);
-        VIR_FREE(addr);
-    }
-    if (VIR_SOCKET_ADDR_VALID(&def->netmask)) {
-        char *addr = virSocketAddrFormat(&def->netmask);
-
-        if (!addr)
-            goto error;
-        virBufferAsprintf(buf, " netmask='%s'", addr);
-        VIR_FREE(addr);
-    }
-    if (def->has_prefix) {
-        virBufferAsprintf(buf, " prefix='%u'", def->prefix);
-    }
-    if (VIR_SOCKET_ADDR_VALID(&def->gateway)) {
-        char *addr = virSocketAddrFormat(&def->gateway);
-        if (!addr)
-            goto error;
-        virBufferAsprintf(buf, " gateway='%s'", addr);
-        VIR_FREE(addr);
-    }
-    if (def->has_metric && def->metric > 0) {
-        virBufferAsprintf(buf, " metric='%u'", def->metric);
-    }
-    virBufferAddLit(buf, "/>\n");
-
-    result = 0;
- error:
-    return result;
-}
-
-static int
 virPortGroupDefFormat(virBufferPtr buf,
                       const virPortGroupDef *def)
 {
@@ -2801,7 +2524,7 @@ virNetworkDefFormatBuf(virBufferPtr buf,
     }
 
     for (i = 0; i < def->nroutes; i++) {
-        if (virNetworkRouteDefFormat(buf, &def->routes[i]) < 0)
+        if (virNetworkRouteDefFormat(buf, def->routes[i]) < 0)
             goto error;
     }
 
Index: libvirt-1.2.5/src/conf/network_conf.h
===================================================================
--- libvirt-1.2.5.orig/src/conf/network_conf.h
+++ libvirt-1.2.5/src/conf/network_conf.h
@@ -39,6 +39,7 @@
 # include "virmacaddr.h"
 # include "device_conf.h"
 # include "virbitmap.h"
+# include "networkcommon_conf.h"
 
 typedef enum {
     VIR_NETWORK_FORWARD_NONE   = 0,
@@ -165,25 +166,6 @@ struct _virNetworkIpDef {
     virSocketAddr bootserver;
    };
 
-typedef struct _virNetworkRouteDef virNetworkRouteDef;
-typedef virNetworkRouteDef *virNetworkRouteDefPtr;
-struct _virNetworkRouteDef {
-    char *family;               /* ipv4 or ipv6 - default is ipv4 */
-    virSocketAddr address;      /* Routed Network IP address */
-
-    /* One or the other of the following two will be used for a given
-     * Network address, but never both. The parser guarantees this.
-     * The virSocketAddrGetIpPrefix() can be used to get a
-     * valid prefix.
-     */
-    virSocketAddr netmask;      /* ipv4 - either netmask or prefix specified */
-    unsigned int prefix;        /* ipv6 - only prefix allowed */
-    bool has_prefix;            /* prefix= was specified */
-    unsigned int metric;        /* value for metric (defaults to 1) */
-    bool has_metric;            /* metric= was specified */
-    virSocketAddr gateway;      /* gateway IP address for ip-route */
-   };
-
 typedef struct _virNetworkForwardIfDef virNetworkForwardIfDef;
 typedef virNetworkForwardIfDef *virNetworkForwardIfDefPtr;
 struct _virNetworkForwardIfDef {
@@ -260,7 +242,7 @@ struct _virNetworkDef {
     virNetworkIpDefPtr ips; /* ptr to array of IP addresses on this network */
 
     size_t nroutes;
-    virNetworkRouteDefPtr routes; /* ptr to array of static routes on this interface */
+    virNetworkRouteDefPtr *routes; /* ptr to array of static routes on this interface */
 
     virNetworkDNSDef dns;   /* dns related configuration */
     virNetDevVPortProfilePtr virtPortProfile;
Index: libvirt-1.2.5/src/conf/networkcommon_conf.c
===================================================================
--- /dev/null
+++ libvirt-1.2.5/src/conf/networkcommon_conf.c
@@ -0,0 +1,415 @@
+/*
+ * networkcommon_conf.c: network XML handling
+ *
+ * Copyright (C) 2006-2014 Red Hat, Inc.
+ * Copyright (C) 2006-2008 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Daniel P. Berrange <berrange@redhat.com>
+ */
+
+#include <config.h>
+
+#include "virerror.h"
+#include "datatypes.h"
+#include "networkcommon_conf.h"
+#include "viralloc.h"
+#include "virstring.h"
+#include "virxml.h"
+
+#define VIR_FROM_THIS VIR_FROM_NETWORK
+
+struct _virNetworkRouteDef {
+    char *family;               /* ipv4 or ipv6 - default is ipv4 */
+    virSocketAddr address;      /* Routed Network IP address */
+
+    /* One or the other of the following two will be used for a given
+     * Network address, but never both. The parser guarantees this.
+     * The virSocketAddrGetIpPrefix() can be used to get a
+     * valid prefix.
+     */
+    virSocketAddr netmask;      /* ipv4 - either netmask or prefix specified */
+    unsigned int prefix;        /* ipv6 - only prefix allowed */
+    bool has_prefix;            /* prefix= was specified */
+    unsigned int metric;        /* value for metric (defaults to 1) */
+    bool has_metric;            /* metric= was specified */
+    virSocketAddr gateway;      /* gateway IP address for ip-route */
+};
+
+void
+virNetworkRouteDefFree(virNetworkRouteDefPtr def)
+{
+    if (!def)
+        return;
+    VIR_FREE(def->family);
+    VIR_FREE(def);
+}
+
+virNetworkRouteDefPtr
+virNetworkRouteDefCreate(const char *errorDetail,
+                         char *family,
+                         char *address,
+                         char *netmask,
+                         char *gateway,
+                         unsigned int prefix,
+                         bool hasPrefix,
+                         unsigned int metric,
+                         bool hasMetric)
+{
+    virNetworkRouteDefPtr def = NULL;
+    virSocketAddr testAddr;
+
+    if (VIR_ALLOC(def) < 0)
+        return NULL;
+
+    if (VIR_STRDUP(def->family, family) < 0)
+        goto error;
+
+    def->prefix = prefix;
+    def->has_prefix = hasPrefix;
+    def->metric = metric;
+    def->has_metric = hasMetric;
+
+    /* Note: both network and gateway addresses must be specified */
+
+    if (!address) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("%s: Missing required address attribute "
+                         "in route definition"),
+                       errorDetail);
+        goto error;
+    }
+
+    if (!gateway) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("%s: Missing required gateway attribute "
+                         "in route definition"),
+                       errorDetail);
+        goto error;
+    }
+
+    if (virSocketAddrParse(&def->address, address, AF_UNSPEC) < 0) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("%s: Bad network address '%s' "
+                         "in route definition"),
+                       errorDetail, address);
+        goto error;
+    }
+
+    if (virSocketAddrParse(&def->gateway, gateway, AF_UNSPEC) < 0) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("%s: Bad gateway address '%s' "
+                         "in route definition"),
+                       errorDetail, gateway);
+        goto error;
+    }
+
+    /* validate network address, etc. for each family */
+    if ((def->family == NULL) || (STREQ(def->family, "ipv4"))) {
+        if (!(VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET) ||
+              VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_UNSPEC))) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           def->family == NULL ?
+                           _("%s: No family specified for non-IPv4 address '%s' "
+                             "in route definition") :
+                           _("%s: IPv4 family specified for non-IPv4 address '%s' "
+                             "in route definition"),
+                           errorDetail, address);
+            goto error;
+        }
+        if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->gateway, AF_INET)) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           def->family == NULL ?
+                           _("%s: No family specified for non-IPv4 gateway '%s' "
+                             "in route definition") :
+                           _("%s: IPv4 family specified for non-IPv4 gateway '%s' "
+                             "in route definition"),
+                           errorDetail, address);
+            goto error;
+        }
+        if (netmask) {
+            if (virSocketAddrParse(&def->netmask, netmask, AF_UNSPEC) < 0) {
+                virReportError(VIR_ERR_XML_ERROR,
+                               _("%s: Bad netmask address '%s' "
+                                 "in route definition"),
+                               errorDetail, netmask);
+                goto error;
+            }
+            if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->netmask, AF_INET)) {
+                virReportError(VIR_ERR_XML_ERROR,
+                               _("%s: Invalid netmask '%s' "
+                                 "for address '%s' (both must be IPv4)"),
+                               errorDetail, netmask, address);
+                goto error;
+            }
+            if (def->has_prefix) {
+                /* can't have both netmask and prefix at the same time */
+                virReportError(VIR_ERR_XML_ERROR,
+                               _("%s: Route definition cannot have both "
+                                 "a prefix and a netmask"),
+                               errorDetail);
+                goto error;
+            }
+        }
+        if (def->prefix > 32) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("%s: Invalid prefix %u specified "
+                             "in route definition, "
+                             "must be 0 - 32"),
+                           errorDetail, def->prefix);
+            goto error;
+        }
+    } else if (STREQ(def->family, "ipv6")) {
+        if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET6)) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("%s: ipv6 family specified for non-IPv6 address '%s' "
+                             "in route definition"),
+                           errorDetail, address);
+            goto error;
+        }
+        if (netmask) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("%s: Specifying netmask invalid for IPv6 address '%s' "
+                             "in route definition"),
+                           errorDetail, address);
+            goto error;
+        }
+        if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->gateway, AF_INET6)) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("%s: ipv6 specified for non-IPv6 gateway address '%s' "
+                             "in route definition"),
+                           errorDetail, gateway);
+            goto error;
+        }
+        if (def->prefix > 128) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("%s: Invalid prefix %u specified "
+                             "in route definition, "
+                             "must be 0 - 128"),
+                           errorDetail, def->prefix);
+            goto error;
+        }
+    } else {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("%s: Unrecognized family '%s' "
+                         "in route definition"),
+                       errorDetail, def->family);
+        goto error;
+    }
+
+    /* make sure the address is a network address */
+    if (netmask) {
+        if (virSocketAddrMask(&def->address, &def->netmask, &testAddr) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("%s: Error converting address '%s' with netmask '%s' "
+                             "to network-address "
+                             "in route definition"),
+                           errorDetail, address, netmask);
+            goto error;
+        }
+    } else {
+        if (virSocketAddrMaskByPrefix(&def->address,
+                                      def->prefix, &testAddr) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("%s: Error converting address '%s' with prefix %u "
+                             "to network-address "
+                             "in route definition"),
+                           errorDetail, address, def->prefix);
+            goto error;
+        }
+    }
+    if (!virSocketAddrEqual(&def->address, &testAddr)) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("%s: Address '%s' in route definition "
+                         "is not a network address"),
+                       errorDetail, address);
+        goto error;
+    }
+
+    return def;
+
+ error:
+    virNetworkRouteDefFree(def);
+    return NULL;
+}
+
+virNetworkRouteDefPtr
+virNetworkRouteDefParseXML(const char *errorDetail,
+                           xmlNodePtr node,
+                           xmlXPathContextPtr ctxt)
+{
+    /*
+     * virNetworkRouteDef object is already allocated as part
+     * of an array.  On failure clear: it out, but don't free it.
+     */
+
+    virNetworkRouteDefPtr def = NULL;
+    xmlNodePtr save;
+    char *family = NULL;
+    char *address = NULL, *netmask = NULL;
+    char *gateway = NULL;
+    unsigned long prefix = 0, metric = 0;
+    int prefixRc, metricRc;
+    bool hasPrefix = false;
+    bool hasMetric = false;
+
+    save = ctxt->node;
+    ctxt->node = node;
+
+    /* grab raw data from XML */
+    family = virXPathString("string(./@family)", ctxt);
+    address = virXPathString("string(./@address)", ctxt);
+    netmask = virXPathString("string(./@netmask)", ctxt);
+    gateway = virXPathString("string(./@gateway)", ctxt);
+    prefixRc = virXPathULong("string(./@prefix)", ctxt, &prefix);
+    if (prefixRc == -2) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("%s: Invalid prefix specified "
+                         "in route definition"),
+                       errorDetail);
+        goto cleanup;
+    }
+    hasPrefix = (prefixRc == 0);
+    metricRc = virXPathULong("string(./@metric)", ctxt, &metric);
+    if (metricRc == -2) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("%s: Invalid metric specified "
+                         "in route definition"),
+                       errorDetail);
+        goto cleanup;
+    }
+    if (metricRc == 0) {
+        hasMetric = true;
+        if (metric == 0) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("%s: Invalid metric value, must be > 0 "
+                             "in route definition"),
+                           errorDetail);
+            goto cleanup;
+        }
+    }
+
+    def = virNetworkRouteDefCreate(errorDetail, family, address, netmask,
+                                   gateway, prefix, hasPrefix, metric,
+                                   hasMetric);
+
+ cleanup:
+    ctxt->node = save;
+    VIR_FREE(family);
+    VIR_FREE(address);
+    VIR_FREE(netmask);
+    VIR_FREE(gateway);
+    return def;
+}
+
+int
+virNetworkRouteDefFormat(virBufferPtr buf,
+                         const virNetworkRouteDef *def)
+{
+    int result = -1;
+    char *addr = NULL;
+
+    virBufferAddLit(buf, "<route");
+
+    if (def->family)
+        virBufferAsprintf(buf, " family='%s'", def->family);
+
+    if (!(addr = virSocketAddrFormat(&def->address)))
+        goto cleanup;
+    virBufferAsprintf(buf, " address='%s'", addr);
+    VIR_FREE(addr);
+
+    if (VIR_SOCKET_ADDR_VALID(&def->netmask)) {
+        if (!(addr = virSocketAddrFormat(&def->netmask)))
+            goto cleanup;
+        virBufferAsprintf(buf, " netmask='%s'", addr);
+        VIR_FREE(addr);
+    }
+    if (def->has_prefix)
+        virBufferAsprintf(buf, " prefix='%u'", def->prefix);
+
+    if (!(addr = virSocketAddrFormat(&def->gateway)))
+        goto cleanup;
+    virBufferAsprintf(buf, " gateway='%s'", addr);
+    VIR_FREE(addr);
+
+    if (def->has_metric && def->metric > 0)
+        virBufferAsprintf(buf, " metric='%u'", def->metric);
+    virBufferAddLit(buf, "/>\n");
+
+    result = 0;
+ cleanup:
+    return result;
+}
+
+virSocketAddrPtr
+virNetworkRouteDefGetAddress(virNetworkRouteDefPtr def)
+{
+    if (def)
+        return &def->address;
+
+    return NULL;
+}
+
+int
+virNetworkRouteDefGetPrefix(virNetworkRouteDefPtr def)
+{
+    int prefix = 0;
+    virSocketAddr zero;
+
+    if (!def)
+        return -1;
+
+    /* this creates an all-0 address of the appropriate family */
+    ignore_value(virSocketAddrParse(&zero,
+                                    (VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET)
+                                     ? VIR_SOCKET_ADDR_IPV4_ALL
+                                     : VIR_SOCKET_ADDR_IPV6_ALL),
+                                    VIR_SOCKET_ADDR_FAMILY(&def->address)));
+
+    if (virSocketAddrEqual(&def->address, &zero)) {
+        if (def->has_prefix && def->prefix == 0)
+            prefix = 0;
+        else if ((VIR_SOCKET_ADDR_IS_FAMILY(&def->netmask, AF_INET) &&
+                  virSocketAddrEqual(&def->netmask, &zero)))
+            prefix = 0;
+        else
+            prefix = virSocketAddrGetIpPrefix(&def->address, &def->netmask,
+                                              def->prefix);
+    } else {
+        prefix = virSocketAddrGetIpPrefix(&def->address, &def->netmask,
+                                          def->prefix);
+    }
+
+    return prefix;
+}
+
+unsigned int
+virNetworkRouteDefGetMetric(virNetworkRouteDefPtr def)
+{
+    if (def && def->has_metric && def->metric > 0)
+        return def->metric;
+
+    return 1;
+}
+
+virSocketAddrPtr
+virNetworkRouteDefGetGateway(virNetworkRouteDefPtr def)
+{
+    if (def)
+        return &def->gateway;
+    return NULL;
+}
Index: libvirt-1.2.5/src/conf/networkcommon_conf.h
===================================================================
--- /dev/null
+++ libvirt-1.2.5/src/conf/networkcommon_conf.h
@@ -0,0 +1,72 @@
+/*
+ * networkcommon_conf.h: network XML handling
+ *
+ * Copyright (C) 2006-2014 Red Hat, Inc.
+ * Copyright (C) 2006-2008 Daniel P. Berrange
+ * Copyright (c) 2015 SUSE LINUX Products GmbH, Nuernberg, Germany.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Daniel P. Berrange <berrange@redhat.com>
+ */
+
+#ifndef __NETWORKCOMMON_CONF_H__
+# define __NETWORKCOMMON_CONF_H__
+
+# include <libxml/tree.h>
+# include <libxml/xpath.h>
+
+# include "internal.h"
+# include "virbuffer.h"
+# include "virsocketaddr.h"
+
+typedef struct _virNetworkRouteDef virNetworkRouteDef;
+typedef virNetworkRouteDef *virNetworkRouteDefPtr;
+
+void
+virNetworkRouteDefFree(virNetworkRouteDefPtr def);
+
+virNetworkRouteDefPtr
+virNetworkRouteDefCreate(const char *networkName,
+                         char *family,
+                         char *address,
+                         char *netmask,
+                         char *gateway,
+                         unsigned int prefix,
+                         bool hasPrefix,
+                         unsigned int metric,
+                         bool hasMetric);
+
+virNetworkRouteDefPtr
+virNetworkRouteDefParseXML(const char *networkName,
+                           xmlNodePtr node,
+                           xmlXPathContextPtr ctxt);
+int
+virNetworkRouteDefFormat(virBufferPtr buf,
+                         const virNetworkRouteDef *def);
+
+virSocketAddrPtr
+virNetworkRouteDefGetAddress(virNetworkRouteDefPtr def);
+
+int
+virNetworkRouteDefGetPrefix(virNetworkRouteDefPtr def);
+
+unsigned int
+virNetworkRouteDefGetMetric(virNetworkRouteDefPtr def);
+
+virSocketAddrPtr
+virNetworkRouteDefGetGateway(virNetworkRouteDefPtr def);
+
+#endif /* __NETWORKCOMMON_CONF_H__ */
Index: libvirt-1.2.5/src/libvirt_private.syms
===================================================================
--- libvirt-1.2.5.orig/src/libvirt_private.syms
+++ libvirt-1.2.5/src/libvirt_private.syms
@@ -566,6 +566,17 @@ virNetworkEventLifecycleNew;
 virNetworkEventStateRegisterID;
 
 
+# conf/networkcommon_conf.h
+virNetworkRouteDefCreate;
+virNetworkRouteDefFormat;
+virNetworkRouteDefFree;
+virNetworkRouteDefGetAddress;
+virNetworkRouteDefGetGateway;
+virNetworkRouteDefGetMetric;
+virNetworkRouteDefGetPrefix;
+virNetworkRouteDefParseXML;
+
+
 # conf/node_device_conf.h
 virNodeDevCapsDefFree;
 virNodeDevCapTypeFromString;
Index: libvirt-1.2.5/src/network/bridge_driver.c
===================================================================
--- libvirt-1.2.5.orig/src/network/bridge_driver.c
+++ libvirt-1.2.5/src/network/bridge_driver.c
@@ -1886,29 +1886,10 @@ static int
 networkAddRouteToBridge(virNetworkObjPtr network,
                         virNetworkRouteDefPtr routedef)
 {
-    int prefix = 0;
-    unsigned int metric;
-    virSocketAddrPtr addr = &routedef->address;
-    virSocketAddrPtr mask = &routedef->netmask;
-    virSocketAddr zero;
-
-    /* this creates an all-0 address of the appropriate family */
-    ignore_value(virSocketAddrParse(&zero,
-                                    (VIR_SOCKET_ADDR_IS_FAMILY(addr, AF_INET)
-                                     ? "0.0.0.0" : "::"),
-                                    VIR_SOCKET_ADDR_FAMILY(addr)));
-
-    if (virSocketAddrEqual(addr, &zero)) {
-        if (routedef->has_prefix && routedef->prefix == 0)
-            prefix = 0;
-        else if ((VIR_SOCKET_ADDR_IS_FAMILY(mask, AF_INET) &&
-                virSocketAddrEqual(mask, &zero)))
-            prefix = 0;
-        else
-            prefix = virSocketAddrGetIpPrefix(addr, mask, routedef->prefix);
-    } else {
-        prefix = virSocketAddrGetIpPrefix(addr, mask, routedef->prefix);
-    }
+    int prefix = virNetworkRouteDefGetPrefix(routedef);
+    unsigned int metric = virNetworkRouteDefGetMetric(routedef);
+    virSocketAddrPtr addr = virNetworkRouteDefGetAddress(routedef);
+    virSocketAddrPtr gateway = virNetworkRouteDefGetGateway(routedef);
 
     if (prefix < 0) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -1918,13 +1899,8 @@ networkAddRouteToBridge(virNetworkObjPtr
         return -1;
     }
 
-    if (routedef->has_metric && routedef->metric > 0)
-        metric = routedef->metric;
-    else
-        metric = 1;
-
-    if (virNetDevAddRoute(network->def->bridge, &routedef->address,
-                          prefix, &routedef->gateway, metric) < 0) {
+    if (virNetDevAddRoute(network->def->bridge, addr,
+                          prefix, gateway, metric) < 0) {
         return -1;
     }
     return 0;
@@ -2014,11 +1990,15 @@ networkStartNetworkVirtual(virNetworkDri
         goto err2;
 
     for (i = 0; i < network->def->nroutes; i++) {
-        routedef = &network->def->routes[i];
+        virSocketAddrPtr gateway = NULL;
+
+        routedef = network->def->routes[i];
+        gateway = virNetworkRouteDefGetGateway(routedef);
+
         /* Add the IP route to the bridge */
         /* ignore errors, error msg will be generated */
         /* but libvirt will not know and net-destroy will work. */
-        if (VIR_SOCKET_ADDR_VALID(&routedef->gateway)) {
+        if (VIR_SOCKET_ADDR_VALID(gateway)) {
             if (networkAddRouteToBridge(network, routedef) < 0) {
                 /* an error occurred adding the static route */
                 continue; /* for now, do nothing */
