mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 21:55:25 +00:00
Turn on IPv6 support in the bridge_driver.c virtual network driver
At this point everything is already in place to make IPv6 happen, we just need to add a few rules, remove some checks for IPv4-only, and document the changes to the XML on the website.
This commit is contained in:
parent
537e65e7b7
commit
6ccce75240
@ -85,8 +85,13 @@
|
||||
</dd>
|
||||
<dt><code>forward</code></dt>
|
||||
<dd>Inclusion of the <code>forward</code> element indicates that
|
||||
the virtual network is to be connected to the physical LAN. If
|
||||
no attributes are set, NAT forwarding will be used for connectivity.
|
||||
the virtual network is to be connected to the physical
|
||||
LAN. the <code>mode</code> attribute determines the method of
|
||||
forwarding; possible selections are 'nat' and 'route'. If mode
|
||||
is not specified, NAT forwarding will be used for
|
||||
connectivity. If a network has any IPv6 addresses defined,
|
||||
even if <code>mode</code> is given as 'nat', the IPv6 traffic
|
||||
will be forwarded using routing, since IPv6 has no concept of NAT.
|
||||
Firewall rules will allow forwarding to any other network device whether
|
||||
ethernet, wireless, dialup, or VPN. If the <code>dev</code> attribute
|
||||
is set, the firewall rules will restrict forwarding to the named
|
||||
@ -118,21 +123,37 @@
|
||||
<dl>
|
||||
<dt><code>ip</code></dt>
|
||||
<dd>The <code>address</code> attribute defines an IPv4 address in
|
||||
dotted-decimal format, that will be configured on the bridge
|
||||
dotted-decimal format, or an IPv6 address in standard
|
||||
colon-separated hexadecimal format, that will be configured on
|
||||
the bridge
|
||||
device associated with the virtual network. To the guests this
|
||||
address will be their default route. The <code>netmask</code>
|
||||
address will be their default route. For IPv4 addresses, the <code>netmask</code>
|
||||
attribute defines the significant bits of the network address,
|
||||
again specified in dotted-decimal format. <span class="since">Since 0.3.0</span>
|
||||
again specified in dotted-decimal format. For IPv6 addresses,
|
||||
and as an alternate method for IPv4 addresses, you can specify
|
||||
the significant bits of the network address with the <code>prefix</code>
|
||||
attribute, which is an integer (for example, <code>netmask='255.255.255.0'</code>
|
||||
could also be given as <code>prefix='24'</code>. The <code>family</code>
|
||||
attribute is used to specify the type of address - 'ipv4' or 'ipv6'; if no
|
||||
<code>family</code> is given, 'ipv4' is assumed. A network can have more than
|
||||
one of each family of address defined, but only a single address can have a
|
||||
<code>dhcp</code> or <code>tftp</code> element. <span class="since">Since 0.3.0;
|
||||
IPv6, multiple addresses on a single network, <code>family</code>, and
|
||||
<code>prefix</code> since 0.8.7</span>
|
||||
</dd><dt><code>tftp</code></dt><dd>Immediately within
|
||||
the <code>ip</code> element there is an optional <code>tftp</code>
|
||||
element. The presence of this element and of its attribute
|
||||
<code>root</code> enables TFTP services. The attribute specifies
|
||||
the path to the root directory served via TFTP.
|
||||
the path to the root directory served via TFTP. <code>tftp</code> is not
|
||||
supported for IPv6 addresses, can only be specified on a single IPv4 address
|
||||
per network.
|
||||
<span class="since">Since 0.7.1</span>
|
||||
</dd><dt><code>dhcp</code></dt><dd>Also within the <code>ip</code> element there is an
|
||||
optional <code>dhcp</code> element. The presence of this element
|
||||
enables DHCP services on the virtual network. It will further
|
||||
contain one or more <code>range</code> elements.
|
||||
contain one or more <code>range</code> elements. The
|
||||
<code>dhcp</code> element is not supported for IPv6, and
|
||||
is only supported on a single IP address per network for IPv4.
|
||||
<span class="since">Since 0.3.0</span>
|
||||
</dd>
|
||||
<dt><code>range</code></dt>
|
||||
|
@ -824,6 +824,65 @@ networkRemoveRoutingIptablesRules(struct network_driver *driver,
|
||||
}
|
||||
}
|
||||
|
||||
/* Add all once/network rules required for IPv6 (if any IPv6 addresses are defined) */
|
||||
static int
|
||||
networkAddGeneralIp6tablesRules(struct network_driver *driver,
|
||||
virNetworkObjPtr network)
|
||||
{
|
||||
|
||||
if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0))
|
||||
return 0;
|
||||
|
||||
/* Catch all rules to block forwarding to/from bridges */
|
||||
|
||||
if (iptablesAddForwardRejectOut(driver->iptables, AF_INET6,
|
||||
network->def->bridge) < 0) {
|
||||
networkReportError(VIR_ERR_SYSTEM_ERROR,
|
||||
_("failed to add ip6tables rule to block outbound traffic from '%s'"),
|
||||
network->def->bridge);
|
||||
goto err1;
|
||||
}
|
||||
|
||||
if (iptablesAddForwardRejectIn(driver->iptables, AF_INET6,
|
||||
network->def->bridge) < 0) {
|
||||
networkReportError(VIR_ERR_SYSTEM_ERROR,
|
||||
_("failed to add ip6tables rule to block inbound traffic to '%s'"),
|
||||
network->def->bridge);
|
||||
goto err2;
|
||||
}
|
||||
|
||||
/* Allow traffic between guests on the same bridge */
|
||||
if (iptablesAddForwardAllowCross(driver->iptables, AF_INET6,
|
||||
network->def->bridge) < 0) {
|
||||
networkReportError(VIR_ERR_SYSTEM_ERROR,
|
||||
_("failed to add ip6tables rule to allow cross bridge traffic on '%s'"),
|
||||
network->def->bridge);
|
||||
goto err3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
/* unwind in reverse order from the point of failure */
|
||||
err3:
|
||||
iptablesRemoveForwardRejectIn(driver->iptables, AF_INET6, network->def->bridge);
|
||||
err2:
|
||||
iptablesRemoveForwardRejectOut(driver->iptables, AF_INET6, network->def->bridge);
|
||||
err1:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
networkRemoveGeneralIp6tablesRules(struct network_driver *driver,
|
||||
virNetworkObjPtr network)
|
||||
{
|
||||
if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0))
|
||||
return;
|
||||
|
||||
iptablesRemoveForwardAllowCross(driver->iptables, AF_INET6, network->def->bridge);
|
||||
iptablesRemoveForwardRejectIn(driver->iptables, AF_INET6, network->def->bridge);
|
||||
iptablesRemoveForwardRejectOut(driver->iptables, AF_INET6, network->def->bridge);
|
||||
}
|
||||
|
||||
static int
|
||||
networkAddGeneralIptablesRules(struct network_driver *driver,
|
||||
virNetworkObjPtr network)
|
||||
@ -926,9 +985,16 @@ networkAddGeneralIptablesRules(struct network_driver *driver,
|
||||
goto err8;
|
||||
}
|
||||
|
||||
/* add IPv6 general rules, if needed */
|
||||
if (networkAddGeneralIp6tablesRules(driver, network) < 0) {
|
||||
goto err9;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
/* unwind in reverse order from the point of failure */
|
||||
err9:
|
||||
iptablesRemoveForwardAllowCross(driver->iptables, AF_INET, network->def->bridge);
|
||||
err8:
|
||||
iptablesRemoveForwardRejectIn(driver->iptables, AF_INET, network->def->bridge);
|
||||
err7:
|
||||
@ -956,6 +1022,8 @@ networkRemoveGeneralIptablesRules(struct network_driver *driver,
|
||||
int ii;
|
||||
virNetworkIpDefPtr ipv4def;
|
||||
|
||||
networkRemoveGeneralIp6tablesRules(driver, network);
|
||||
|
||||
for (ii = 0;
|
||||
(ipv4def = virNetworkDefGetIpByIndex(network->def, AF_INET, ii));
|
||||
ii++) {
|
||||
@ -984,13 +1052,18 @@ networkAddIpSpecificIptablesRules(struct network_driver *driver,
|
||||
virNetworkObjPtr network,
|
||||
virNetworkIpDefPtr ipdef)
|
||||
{
|
||||
if (network->def->forwardType == VIR_NETWORK_FORWARD_NAT &&
|
||||
networkAddMasqueradingIptablesRules(driver, network, ipdef) < 0)
|
||||
return -1;
|
||||
if (network->def->forwardType == VIR_NETWORK_FORWARD_ROUTE &&
|
||||
networkAddRoutingIptablesRules(driver, network, ipdef) < 0)
|
||||
return -1;
|
||||
/* NB: in the case of IPv6, routing rules are added when the
|
||||
* forward mode is NAT. This is because IPv6 has no NAT.
|
||||
*/
|
||||
|
||||
if (network->def->forwardType == VIR_NETWORK_FORWARD_NAT) {
|
||||
if (VIR_SOCKET_IS_FAMILY(&ipdef->address, AF_INET))
|
||||
return networkAddMasqueradingIptablesRules(driver, network, ipdef);
|
||||
else if (VIR_SOCKET_IS_FAMILY(&ipdef->address, AF_INET6))
|
||||
return networkAddRoutingIptablesRules(driver, network, ipdef);
|
||||
} else if (network->def->forwardType == VIR_NETWORK_FORWARD_ROUTE) {
|
||||
return networkAddRoutingIptablesRules(driver, network, ipdef);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -999,10 +1072,14 @@ networkRemoveIpSpecificIptablesRules(struct network_driver *driver,
|
||||
virNetworkObjPtr network,
|
||||
virNetworkIpDefPtr ipdef)
|
||||
{
|
||||
if (network->def->forwardType == VIR_NETWORK_FORWARD_NAT)
|
||||
if (network->def->forwardType == VIR_NETWORK_FORWARD_NAT) {
|
||||
if (VIR_SOCKET_IS_FAMILY(&ipdef->address, AF_INET))
|
||||
networkRemoveMasqueradingIptablesRules(driver, network, ipdef);
|
||||
else if (network->def->forwardType == VIR_NETWORK_FORWARD_ROUTE)
|
||||
else if (VIR_SOCKET_IS_FAMILY(&ipdef->address, AF_INET6))
|
||||
networkRemoveRoutingIptablesRules(driver, network, ipdef);
|
||||
} else if (network->def->forwardType == VIR_NETWORK_FORWARD_ROUTE) {
|
||||
networkRemoveRoutingIptablesRules(driver, network, ipdef);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add all rules for all ip addresses (and general rules) on a network */
|
||||
@ -1084,30 +1161,47 @@ networkEnableIpForwarding(void)
|
||||
|
||||
#define SYSCTL_PATH "/proc/sys"
|
||||
|
||||
static int networkDisableIPV6(virNetworkObjPtr network)
|
||||
static int
|
||||
networkSetIPv6Sysctls(virNetworkObjPtr network)
|
||||
{
|
||||
char *field = NULL;
|
||||
int ret = -1;
|
||||
|
||||
if (virAsprintf(&field, SYSCTL_PATH "/net/ipv6/conf/%s/disable_ipv6", network->def->bridge) < 0) {
|
||||
if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0)) {
|
||||
/* Only set disable_ipv6 if there are no ipv6 addresses defined for
|
||||
* the network.
|
||||
*/
|
||||
if (virAsprintf(&field, SYSCTL_PATH "/net/ipv6/conf/%s/disable_ipv6",
|
||||
network->def->bridge) < 0) {
|
||||
virReportOOMError();
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (access(field, W_OK) < 0 && errno == ENOENT) {
|
||||
VIR_DEBUG("ipv6 appears to already be disabled on %s", network->def->bridge);
|
||||
VIR_DEBUG("ipv6 appears to already be disabled on %s",
|
||||
network->def->bridge);
|
||||
ret = 0;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (virFileWriteStr(field, "1", 0) < 0) {
|
||||
virReportSystemError(errno,
|
||||
_("cannot enable %s"), field);
|
||||
_("cannot write to %s to disable IPv6 on bridge %s"),
|
||||
field, network->def->bridge);
|
||||
goto cleanup;
|
||||
}
|
||||
VIR_FREE(field);
|
||||
}
|
||||
|
||||
if (virAsprintf(&field, SYSCTL_PATH "/net/ipv6/conf/%s/accept_ra", network->def->bridge) < 0) {
|
||||
/* The rest of the ipv6 sysctl tunables should always be set,
|
||||
* whether or not we're using ipv6 on this bridge.
|
||||
*/
|
||||
|
||||
/* Prevent guests from hijacking the host network by sending out
|
||||
* their own router advertisements.
|
||||
*/
|
||||
if (virAsprintf(&field, SYSCTL_PATH "/net/ipv6/conf/%s/accept_ra",
|
||||
network->def->bridge) < 0) {
|
||||
virReportOOMError();
|
||||
goto cleanup;
|
||||
}
|
||||
@ -1119,7 +1213,11 @@ static int networkDisableIPV6(virNetworkObjPtr network)
|
||||
}
|
||||
VIR_FREE(field);
|
||||
|
||||
if (virAsprintf(&field, SYSCTL_PATH "/net/ipv6/conf/%s/autoconf", network->def->bridge) < 0) {
|
||||
/* All interfaces used as a gateway (which is what this is, by
|
||||
* definition), must always have autoconf=0.
|
||||
*/
|
||||
if (virAsprintf(&field, SYSCTL_PATH "/net/ipv6/conf/%s/autoconf",
|
||||
network->def->bridge) < 0) {
|
||||
virReportOOMError();
|
||||
goto cleanup;
|
||||
}
|
||||
@ -1262,7 +1360,7 @@ networkStartNetworkDaemon(struct network_driver *driver,
|
||||
virNetworkObjPtr network)
|
||||
{
|
||||
int ii, err;
|
||||
bool v4present = false;
|
||||
bool v4present = false, v6present = false;
|
||||
virErrorPtr save_err = NULL;
|
||||
virNetworkIpDefPtr ipdef;
|
||||
|
||||
@ -1301,8 +1399,10 @@ networkStartNetworkDaemon(struct network_driver *driver,
|
||||
goto err1;
|
||||
}
|
||||
|
||||
/* Disable IPv6 on the bridge */
|
||||
if (networkDisableIPV6(network) < 0)
|
||||
/* Disable IPv6 on the bridge if there are no IPv6 addresses
|
||||
* defined, and set other IPv6 sysctl tunables appropriately.
|
||||
*/
|
||||
if (networkSetIPv6Sysctls(network) < 0)
|
||||
goto err1;
|
||||
|
||||
/* Add "once per network" rules */
|
||||
@ -1314,6 +1414,8 @@ networkStartNetworkDaemon(struct network_driver *driver,
|
||||
ii++) {
|
||||
if (VIR_SOCKET_IS_FAMILY(&ipdef->address, AF_INET))
|
||||
v4present = true;
|
||||
if (VIR_SOCKET_IS_FAMILY(&ipdef->address, AF_INET6))
|
||||
v6present = true;
|
||||
|
||||
/* Add the IP address/netmask to the bridge */
|
||||
if (networkAddAddrToBridge(driver, network, ipdef) < 0) {
|
||||
@ -1708,9 +1810,7 @@ static virNetworkPtr networkDefine(virConnectPtr conn, const char *xml) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* we only support dhcp on one IPv4 address per defined network, and currently
|
||||
* don't support IPv6.
|
||||
*/
|
||||
/* We only support dhcp on one IPv4 address per defined network */
|
||||
for (ii = 0;
|
||||
(ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii));
|
||||
ii++) {
|
||||
@ -1724,14 +1824,6 @@ static virNetworkPtr networkDefine(virConnectPtr conn, const char *xml) {
|
||||
ipv4def = ipdef;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* we currently only support IPv4 */
|
||||
networkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||
_("unsupported address family '%s' (%d) in network definition"),
|
||||
ipdef->family ? ipdef->family : "unspecified",
|
||||
VIR_SOCKET_FAMILY(&ipdef->address));
|
||||
goto cleanup;
|
||||
|
||||
}
|
||||
}
|
||||
if (ipv4def) {
|
||||
@ -1756,7 +1848,8 @@ cleanup:
|
||||
static int networkUndefine(virNetworkPtr net) {
|
||||
struct network_driver *driver = net->conn->networkPrivateData;
|
||||
virNetworkObjPtr network;
|
||||
virNetworkIpDefPtr ipv4def;
|
||||
virNetworkIpDefPtr ipdef;
|
||||
bool dhcp_present = false, v6present = false;
|
||||
int ret = -1, ii;
|
||||
|
||||
networkDriverLock(driver);
|
||||
@ -1781,12 +1874,17 @@ static int networkUndefine(virNetworkPtr net) {
|
||||
|
||||
/* we only support dhcp on one IPv4 address per defined network */
|
||||
for (ii = 0;
|
||||
(ipv4def = virNetworkDefGetIpByIndex(network->def, AF_INET, ii));
|
||||
(ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii));
|
||||
ii++) {
|
||||
if (ipv4def->nranges || ipv4def->nhosts)
|
||||
break;
|
||||
if (VIR_SOCKET_IS_FAMILY(&ipdef->address, AF_INET)) {
|
||||
if (ipdef->nranges || ipdef->nhosts)
|
||||
dhcp_present = true;
|
||||
} else if (VIR_SOCKET_IS_FAMILY(&ipdef->address, AF_INET6)) {
|
||||
v6present = true;
|
||||
}
|
||||
if (ipv4def) {
|
||||
}
|
||||
|
||||
if (dhcp_present) {
|
||||
dnsmasqContext *dctx = dnsmasqContextNew(network->def->name, DNSMASQ_STATE_DIR);
|
||||
if (dctx == NULL)
|
||||
goto cleanup;
|
||||
|
Loading…
Reference in New Issue
Block a user