If no gateway is specified in RA the a guest will install
a default route to link-local address of the source of RA
(in this case, virbr*), which may disturb guest's networking
e.g. if the 'expected' default route is through another interface.
This patch adds an attribute 'ipv6noDefRoute=yes|no' to network
definition. If this attribute is set, we add
ra-param=*,0,0
// <interface>,<RA interval>,<default gateway lifetime>
// here we have "any interface","default interval","0
seconds"
to dnsmasq config. This makes the 'default gateway lifetime'
to be 0 seconds, which means that receiver of RA must not
install a default route from this RA.
---
src/conf/network_conf.c | 17 +++++++++++++++++
src/conf/network_conf.h | 3 +++
src/network/bridge_driver.c | 22 ++++++++++++++++++++++
src/util/virdnsmasq.h | 6 ++++++
4 files changed, 48 insertions(+)
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index 2d904df..364f3fe 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -2056,6 +2056,7 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
xmlNodePtr forwardNode = NULL;
char *ipv6nogwStr = NULL;
char *trustGuestRxFilters = NULL;
+ char *ipv6noDefRouteStr = NULL;
xmlNodePtr save = ctxt->node;
xmlNodePtr bandwidthNode = NULL;
xmlNodePtr vlanNode;
@@ -2124,6 +2125,19 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
VIR_FREE(trustGuestRxFilters);
}
+ ipv6noDefRouteStr = virXPathString("string(./@ipv6noDefRoute)", ctxt);
+ if (ipv6noDefRouteStr) {
+ if (STREQ(ipv6noDefRouteStr, "yes")) {
+ def->ipv6noDefRoute = true;
+ } else if (STRNEQ(ipv6noDefRouteStr, "no")) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid ipv6noDefRoute setting '%s' in network
'%s'"),
+ ipv6noDefRouteStr, def->name);
+ goto error;
+ }
+ VIR_FREE(ipv6noDefRouteStr);
+ }
+
/* Parse network domain information */
def->domain = virXPathString("string(./domain[1]/@name)", ctxt);
tmp = virXPathString("string(./domain[1]/@localOnly)", ctxt);
@@ -2401,6 +2415,7 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
VIR_FREE(ipNodes);
VIR_FREE(portGroupNodes);
VIR_FREE(ipv6nogwStr);
+ VIR_FREE(ipv6noDefRouteStr);
VIR_FREE(trustGuestRxFilters);
ctxt->node = save;
return NULL;
@@ -2728,6 +2743,8 @@ virNetworkDefFormatBuf(virBufferPtr buf,
if (def->trustGuestRxFilters)
virBufferAsprintf(buf, " trustGuestRxFilters='%s'",
virTristateBoolTypeToString(def->trustGuestRxFilters));
+ if (def->ipv6noDefRoute)
+ virBufferAddLit(buf, " ipv6noDefRoute='yes'");
virBufferAddLit(buf, ">\n");
virBufferAdjustIndent(buf, 2);
virBufferEscapeString(buf, "<name>%s</name>\n", def->name);
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
index e7ce674..e2d926f 100644
--- a/src/conf/network_conf.h
+++ b/src/conf/network_conf.h
@@ -253,6 +253,9 @@ struct _virNetworkDef {
virNetDevBandwidthPtr bandwidth;
virNetDevVlan vlan;
int trustGuestRxFilters; /* enum virTristateBool */
+
+ /* forbid dnsmasq to announce our link-local address as default gateway */
+ bool ipv6noDefRoute;
};
typedef struct _virNetworkObj virNetworkObj;
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 0221a38..a5998bb 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -1051,6 +1051,28 @@ networkDnsmasqConfContents(virNetworkObjPtr network,
if (network->def->forward.type == VIR_NETWORK_FORWARD_NONE) {
virBufferAddLit(&configbuf, "dhcp-option=3\n"
"no-resolv\n");
+ if (network->def->ipv6noDefRoute) {
+ /* Set RA interval to 0
+ * (= default, we cannot set 3rd parameter without setting 2nd)
+ * and default route lifetime to 0 seconds i.e.
+ * do not announce our link-local address as default gateway
+ */
+ if (!DNSMASQ_RA_PARAM_SUPPORT(caps)) {
+ unsigned long version = dnsmasqCapsGetVersion(caps);
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("The version of dnsmasq on this host "
+ "(%d.%d) doesn't support 'ra-param'
option "
+ "which is needed to disable "
+ "IPv6 default route. "
+ "Version %d.%d or later is required."),
+ (int)version / 1000000,
+ (int)(version % 1000000) / 1000,
+ DNSMASQ_RA_PARAM_MAJOR_REQD,
+ DNSMASQ_RA_PARAM_MINOR_REQD);
+ goto cleanup;
+ }
+ virBufferAddLit(&configbuf, "ra-param=*,0,0\n");
+ }
}
for (i = 0; i < dns->ntxts; i++) {
diff --git a/src/util/virdnsmasq.h b/src/util/virdnsmasq.h
index ed560da..95f4488 100644
--- a/src/util/virdnsmasq.h
+++ b/src/util/virdnsmasq.h
@@ -109,6 +109,8 @@ unsigned long dnsmasqCapsGetVersion(dnsmasqCapsPtr caps);
# define DNSMASQ_DHCPv6_MINOR_REQD 64
# define DNSMASQ_RA_MAJOR_REQD 2
# define DNSMASQ_RA_MINOR_REQD 64
+# define DNSMASQ_RA_PARAM_MAJOR_REQD 2
+# define DNSMASQ_RA_PARAM_MINOR_REQD 67
# define DNSMASQ_DHCPv6_SUPPORT(CAPS) \
(dnsmasqCapsGetVersion(CAPS) >= \
@@ -118,4 +120,8 @@ unsigned long dnsmasqCapsGetVersion(dnsmasqCapsPtr caps);
(dnsmasqCapsGetVersion(CAPS) >= \
(DNSMASQ_RA_MAJOR_REQD * 1000000) + \
(DNSMASQ_RA_MINOR_REQD * 1000))
+# define DNSMASQ_RA_PARAM_SUPPORT(CAPS) \
+ (dnsmasqCapsGetVersion(CAPS) >= \
+ (DNSMASQ_RA_PARAM_MAJOR_REQD * 1000000) + \
+ (DNSMASQ_RA_PARAM_MINOR_REQD * 1000))
#endif /* __DNSMASQ_H__ */
--
1.8.3.1