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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list