mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-23 14:15:28 +00:00
Support multiple IP addresses on one network in bridge_driver.c
This patch reorganizes the code in bridge_driver.c to account for the concept of a single network with multiple IP addresses, without adding in the extra variable of IPv6. A small bit of code has been temporarily added that checks all given addresses to verify they are IPv4 - this will be removed when full IPv6 support is turned on.
This commit is contained in:
parent
a950dd2a31
commit
ad48dfa15c
@ -521,20 +521,25 @@ cleanup:
|
||||
}
|
||||
|
||||
static int
|
||||
dhcpStartDhcpDaemon(virNetworkObjPtr network,
|
||||
virNetworkIpDefPtr ipdef)
|
||||
networkStartDhcpDaemon(virNetworkObjPtr network)
|
||||
{
|
||||
virCommandPtr cmd = NULL;
|
||||
char *pidfile = NULL;
|
||||
int ret = -1, err;
|
||||
int ret = -1, err, ii;
|
||||
virNetworkIpDefPtr ipdef;
|
||||
|
||||
network->dnsmasqPid = -1;
|
||||
|
||||
if (!VIR_SOCKET_IS_FAMILY(&ipdef->address, AF_INET)) {
|
||||
networkReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
"%s", _("cannot start dhcp daemon without IPv4 address for server"));
|
||||
goto cleanup;
|
||||
/* Look for first IPv4 address that has dhcp defined. */
|
||||
/* We support dhcp config on 1 IPv4 interface only. */
|
||||
for (ii = 0;
|
||||
(ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, ii));
|
||||
ii++) {
|
||||
if (ipdef->nranges || ipdef->nhosts)
|
||||
break;
|
||||
}
|
||||
if (!ipdef)
|
||||
return 0;
|
||||
|
||||
if ((err = virFileMakePath(NETWORK_PID_DIR)) != 0) {
|
||||
virReportSystemError(err,
|
||||
@ -583,8 +588,8 @@ cleanup:
|
||||
|
||||
static int
|
||||
networkAddMasqueradingIptablesRules(struct network_driver *driver,
|
||||
virNetworkObjPtr network,
|
||||
virNetworkIpDefPtr ipdef)
|
||||
virNetworkObjPtr network,
|
||||
virNetworkIpDefPtr ipdef)
|
||||
{
|
||||
int prefix = virNetworkIpDefPrefix(ipdef);
|
||||
|
||||
@ -607,7 +612,9 @@ networkAddMasqueradingIptablesRules(struct network_driver *driver,
|
||||
goto masqerr1;
|
||||
}
|
||||
|
||||
/* allow forwarding packets to the bridge interface if they are part of an existing connection */
|
||||
/* allow forwarding packets to the bridge interface if they are
|
||||
* part of an existing connection
|
||||
*/
|
||||
if (iptablesAddForwardAllowRelatedIn(driver->iptables,
|
||||
&ipdef->address,
|
||||
prefix,
|
||||
@ -708,10 +715,48 @@ networkAddMasqueradingIptablesRules(struct network_driver *driver,
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
networkRemoveMasqueradingIptablesRules(struct network_driver *driver,
|
||||
virNetworkObjPtr network,
|
||||
virNetworkIpDefPtr ipdef)
|
||||
{
|
||||
int prefix = virNetworkIpDefPrefix(ipdef);
|
||||
|
||||
if (prefix >= 0) {
|
||||
iptablesRemoveForwardMasquerade(driver->iptables,
|
||||
&ipdef->address,
|
||||
prefix,
|
||||
network->def->forwardDev,
|
||||
"tcp");
|
||||
iptablesRemoveForwardMasquerade(driver->iptables,
|
||||
&ipdef->address,
|
||||
prefix,
|
||||
network->def->forwardDev,
|
||||
"udp");
|
||||
iptablesRemoveForwardMasquerade(driver->iptables,
|
||||
&ipdef->address,
|
||||
prefix,
|
||||
network->def->forwardDev,
|
||||
NULL);
|
||||
|
||||
iptablesRemoveForwardAllowRelatedIn(driver->iptables,
|
||||
&ipdef->address,
|
||||
prefix,
|
||||
network->def->bridge,
|
||||
network->def->forwardDev);
|
||||
iptablesRemoveForwardAllowOut(driver->iptables,
|
||||
&ipdef->address,
|
||||
prefix,
|
||||
network->def->bridge,
|
||||
network->def->forwardDev);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
networkAddRoutingIptablesRules(struct network_driver *driver,
|
||||
virNetworkObjPtr network,
|
||||
virNetworkIpDefPtr ipdef) {
|
||||
virNetworkIpDefPtr ipdef)
|
||||
{
|
||||
int prefix = virNetworkIpDefPrefix(ipdef);
|
||||
|
||||
if (prefix < 0) {
|
||||
@ -747,23 +792,56 @@ networkAddRoutingIptablesRules(struct network_driver *driver,
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
routeerr2:
|
||||
routeerr2:
|
||||
iptablesRemoveForwardAllowOut(driver->iptables,
|
||||
&ipdef->address,
|
||||
prefix,
|
||||
network->def->bridge,
|
||||
network->def->forwardDev);
|
||||
routeerr1:
|
||||
routeerr1:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
networkRemoveRoutingIptablesRules(struct network_driver *driver,
|
||||
virNetworkObjPtr network,
|
||||
virNetworkIpDefPtr ipdef)
|
||||
{
|
||||
int prefix = virNetworkIpDefPrefix(ipdef);
|
||||
|
||||
if (prefix >= 0) {
|
||||
iptablesRemoveForwardAllowIn(driver->iptables,
|
||||
&ipdef->address,
|
||||
prefix,
|
||||
network->def->bridge,
|
||||
network->def->forwardDev);
|
||||
|
||||
iptablesRemoveForwardAllowOut(driver->iptables,
|
||||
&ipdef->address,
|
||||
prefix,
|
||||
network->def->bridge,
|
||||
network->def->forwardDev);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
networkAddIptablesRules(struct network_driver *driver,
|
||||
virNetworkObjPtr network,
|
||||
virNetworkIpDefPtr ipdef) {
|
||||
networkAddGeneralIptablesRules(struct network_driver *driver,
|
||||
virNetworkObjPtr network)
|
||||
{
|
||||
int ii;
|
||||
virNetworkIpDefPtr ipv4def;
|
||||
|
||||
/* First look for first IPv4 address that has dhcp or tftpboot defined. */
|
||||
/* We support dhcp config on 1 IPv4 interface only. */
|
||||
for (ii = 0;
|
||||
(ipv4def = virNetworkDefGetIpByIndex(network->def, AF_INET, ii));
|
||||
ii++) {
|
||||
if (ipv4def->nranges || ipv4def->nhosts || ipv4def->tftproot)
|
||||
break;
|
||||
}
|
||||
|
||||
/* allow DHCP requests through to dnsmasq */
|
||||
|
||||
if (iptablesAddTcpInput(driver->iptables, network->def->bridge, 67) < 0) {
|
||||
networkReportError(VIR_ERR_SYSTEM_ERROR,
|
||||
_("failed to add iptables rule to allow DHCP requests from '%s'"),
|
||||
@ -778,6 +856,20 @@ networkAddIptablesRules(struct network_driver *driver,
|
||||
goto err2;
|
||||
}
|
||||
|
||||
/* If we are doing local DHCP service on this network, attempt to
|
||||
* add a rule that will fixup the checksum of DHCP response
|
||||
* packets back to the guests (but report failure without
|
||||
* aborting, since not all iptables implementations support it).
|
||||
*/
|
||||
|
||||
if (ipv4def && (ipv4def->nranges || ipv4def->nhosts) &&
|
||||
(iptablesAddOutputFixUdpChecksum(driver->iptables,
|
||||
network->def->bridge, 68) < 0)) {
|
||||
VIR_WARN("Could not add rule to fixup DHCP response checksums "
|
||||
"on network '%s'.", network->def->name);
|
||||
VIR_WARN0("May need to update iptables package & kernel to support CHECKSUM rule.");
|
||||
}
|
||||
|
||||
/* allow DNS requests through to dnsmasq */
|
||||
if (iptablesAddTcpInput(driver->iptables, network->def->bridge, 53) < 0) {
|
||||
networkReportError(VIR_ERR_SYSTEM_ERROR,
|
||||
@ -793,30 +885,29 @@ networkAddIptablesRules(struct network_driver *driver,
|
||||
goto err4;
|
||||
}
|
||||
|
||||
/* allow TFTP requests through to dnsmasq */
|
||||
if (ipdef && ipdef->tftproot &&
|
||||
/* allow TFTP requests through to dnsmasq if necessary */
|
||||
if (ipv4def && ipv4def->tftproot &&
|
||||
iptablesAddUdpInput(driver->iptables, network->def->bridge, 69) < 0) {
|
||||
networkReportError(VIR_ERR_SYSTEM_ERROR,
|
||||
_("failed to add iptables rule to allow TFTP requests from '%s'"),
|
||||
network->def->bridge);
|
||||
goto err4tftp;
|
||||
goto err5;
|
||||
}
|
||||
|
||||
|
||||
/* Catch all rules to block forwarding to/from bridges */
|
||||
|
||||
if (iptablesAddForwardRejectOut(driver->iptables, network->def->bridge) < 0) {
|
||||
networkReportError(VIR_ERR_SYSTEM_ERROR,
|
||||
_("failed to add iptables rule to block outbound traffic from '%s'"),
|
||||
network->def->bridge);
|
||||
goto err5;
|
||||
goto err6;
|
||||
}
|
||||
|
||||
if (iptablesAddForwardRejectIn(driver->iptables, network->def->bridge) < 0) {
|
||||
networkReportError(VIR_ERR_SYSTEM_ERROR,
|
||||
_("failed to add iptables rule to block inbound traffic to '%s'"),
|
||||
network->def->bridge);
|
||||
goto err6;
|
||||
goto err7;
|
||||
}
|
||||
|
||||
/* Allow traffic between guests on the same bridge */
|
||||
@ -824,129 +915,139 @@ networkAddIptablesRules(struct network_driver *driver,
|
||||
networkReportError(VIR_ERR_SYSTEM_ERROR,
|
||||
_("failed to add iptables rule to allow cross bridge traffic on '%s'"),
|
||||
network->def->bridge);
|
||||
goto err7;
|
||||
}
|
||||
|
||||
if (ipdef) {
|
||||
/* If masquerading is enabled, set up the rules*/
|
||||
if (network->def->forwardType == VIR_NETWORK_FORWARD_NAT &&
|
||||
networkAddMasqueradingIptablesRules(driver, network, ipdef) < 0)
|
||||
goto err8;
|
||||
/* else if routing is enabled, set up the rules*/
|
||||
else if (network->def->forwardType == VIR_NETWORK_FORWARD_ROUTE &&
|
||||
networkAddRoutingIptablesRules(driver, network, ipdef) < 0)
|
||||
goto err8;
|
||||
|
||||
/* If we are doing local DHCP service on this network, attempt to
|
||||
* add a rule that will fixup the checksum of DHCP response
|
||||
* packets back to the guests (but report failure without
|
||||
* aborting, since not all iptables implementations support it).
|
||||
*/
|
||||
|
||||
if (ipdef && (VIR_SOCKET_IS_FAMILY(&ipdef->address, AF_INET) ||
|
||||
ipdef->nranges) &&
|
||||
(iptablesAddOutputFixUdpChecksum(driver->iptables,
|
||||
network->def->bridge, 68) < 0)) {
|
||||
VIR_WARN("Could not add rule to fixup DHCP response checksums "
|
||||
"on network '%s'.", network->def->name);
|
||||
VIR_WARN0("May need to update iptables package & kernel to support CHECKSUM rule.");
|
||||
}
|
||||
goto err8;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err8:
|
||||
iptablesRemoveForwardAllowCross(driver->iptables,
|
||||
network->def->bridge);
|
||||
err7:
|
||||
iptablesRemoveForwardRejectIn(driver->iptables,
|
||||
network->def->bridge);
|
||||
err6:
|
||||
iptablesRemoveForwardRejectOut(driver->iptables,
|
||||
network->def->bridge);
|
||||
err5:
|
||||
if (ipdef && ipdef->tftproot) {
|
||||
/* unwind in reverse order from the point of failure */
|
||||
err8:
|
||||
iptablesRemoveForwardRejectIn(driver->iptables, network->def->bridge);
|
||||
err7:
|
||||
iptablesRemoveForwardRejectOut(driver->iptables, network->def->bridge);
|
||||
err6:
|
||||
if (ipv4def && ipv4def->tftproot) {
|
||||
iptablesRemoveUdpInput(driver->iptables, network->def->bridge, 69);
|
||||
}
|
||||
err4tftp:
|
||||
err5:
|
||||
iptablesRemoveUdpInput(driver->iptables, network->def->bridge, 53);
|
||||
err4:
|
||||
err4:
|
||||
iptablesRemoveTcpInput(driver->iptables, network->def->bridge, 53);
|
||||
err3:
|
||||
err3:
|
||||
iptablesRemoveUdpInput(driver->iptables, network->def->bridge, 67);
|
||||
err2:
|
||||
err2:
|
||||
iptablesRemoveTcpInput(driver->iptables, network->def->bridge, 67);
|
||||
err1:
|
||||
err1:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
networkRemoveIptablesRules(struct network_driver *driver,
|
||||
virNetworkObjPtr network,
|
||||
virNetworkIpDefPtr ipdef) {
|
||||
networkRemoveGeneralIptablesRules(struct network_driver *driver,
|
||||
virNetworkObjPtr network)
|
||||
{
|
||||
int ii;
|
||||
virNetworkIpDefPtr ipv4def;
|
||||
|
||||
if (ipdef && (VIR_SOCKET_HAS_ADDR(&ipdef->address) ||
|
||||
ipdef->nranges)) {
|
||||
iptablesRemoveOutputFixUdpChecksum(driver->iptables,
|
||||
network->def->bridge, 68);
|
||||
for (ii = 0;
|
||||
(ipv4def = virNetworkDefGetIpByIndex(network->def, AF_INET, ii));
|
||||
ii++) {
|
||||
if (ipv4def->nranges || ipv4def->nhosts || ipv4def->tftproot)
|
||||
break;
|
||||
}
|
||||
if (ipdef && network->def->forwardType != VIR_NETWORK_FORWARD_NONE) {
|
||||
int prefix = virNetworkIpDefPrefix(ipdef);
|
||||
|
||||
if (prefix < 0) {
|
||||
networkReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Invalid prefix or netmask for '%s'"),
|
||||
network->def->bridge);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (network->def->forwardType == VIR_NETWORK_FORWARD_NAT) {
|
||||
iptablesRemoveForwardMasquerade(driver->iptables,
|
||||
&ipdef->address,
|
||||
prefix,
|
||||
network->def->forwardDev,
|
||||
"tcp");
|
||||
iptablesRemoveForwardMasquerade(driver->iptables,
|
||||
&ipdef->address,
|
||||
prefix,
|
||||
network->def->forwardDev,
|
||||
"udp");
|
||||
iptablesRemoveForwardMasquerade(driver->iptables,
|
||||
&ipdef->address,
|
||||
prefix,
|
||||
network->def->forwardDev,
|
||||
NULL);
|
||||
iptablesRemoveForwardAllowRelatedIn(driver->iptables,
|
||||
&ipdef->address,
|
||||
prefix,
|
||||
network->def->bridge,
|
||||
network->def->forwardDev);
|
||||
} else if (network->def->forwardType == VIR_NETWORK_FORWARD_ROUTE) {
|
||||
iptablesRemoveForwardAllowIn(driver->iptables,
|
||||
&ipdef->address,
|
||||
prefix,
|
||||
network->def->bridge,
|
||||
network->def->forwardDev);
|
||||
}
|
||||
|
||||
iptablesRemoveForwardAllowOut(driver->iptables,
|
||||
&ipdef->address,
|
||||
prefix,
|
||||
network->def->bridge,
|
||||
network->def->forwardDev);
|
||||
}
|
||||
error:
|
||||
iptablesRemoveForwardAllowCross(driver->iptables, network->def->bridge);
|
||||
iptablesRemoveForwardRejectIn(driver->iptables, network->def->bridge);
|
||||
iptablesRemoveForwardRejectOut(driver->iptables, network->def->bridge);
|
||||
if (ipdef && ipdef->tftproot)
|
||||
if (ipv4def && ipv4def->tftproot) {
|
||||
iptablesRemoveUdpInput(driver->iptables, network->def->bridge, 69);
|
||||
}
|
||||
iptablesRemoveUdpInput(driver->iptables, network->def->bridge, 53);
|
||||
iptablesRemoveTcpInput(driver->iptables, network->def->bridge, 53);
|
||||
if (ipv4def && (ipv4def->nranges || ipv4def->nhosts)) {
|
||||
iptablesRemoveOutputFixUdpChecksum(driver->iptables,
|
||||
network->def->bridge, 68);
|
||||
}
|
||||
iptablesRemoveUdpInput(driver->iptables, network->def->bridge, 67);
|
||||
iptablesRemoveTcpInput(driver->iptables, network->def->bridge, 67);
|
||||
}
|
||||
|
||||
static int
|
||||
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;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
networkRemoveIpSpecificIptablesRules(struct network_driver *driver,
|
||||
virNetworkObjPtr network,
|
||||
virNetworkIpDefPtr ipdef)
|
||||
{
|
||||
if (network->def->forwardType == VIR_NETWORK_FORWARD_NAT)
|
||||
networkRemoveMasqueradingIptablesRules(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 */
|
||||
static int
|
||||
networkAddIptablesRules(struct network_driver *driver,
|
||||
virNetworkObjPtr network)
|
||||
{
|
||||
int ii;
|
||||
virNetworkIpDefPtr ipdef;
|
||||
|
||||
/* Add "once per network" rules */
|
||||
if (networkAddGeneralIptablesRules(driver, network) < 0)
|
||||
return -1;
|
||||
|
||||
for (ii = 0;
|
||||
(ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii));
|
||||
ii++) {
|
||||
/* Add address-specific iptables rules */
|
||||
if (networkAddIpSpecificIptablesRules(driver, network, ipdef) < 0) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
err:
|
||||
/* The final failed call to networkAddIpSpecificIptablesRules will
|
||||
* have removed any rules it created, but we need to remove those
|
||||
* added for previous IP addresses.
|
||||
*/
|
||||
while ((--ii >= 0) &&
|
||||
(ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii))) {
|
||||
networkRemoveIpSpecificIptablesRules(driver, network, ipdef);
|
||||
}
|
||||
networkRemoveGeneralIptablesRules(driver, network);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Remove all rules for all ip addresses (and general rules) on a network */
|
||||
static void
|
||||
networkRemoveIptablesRules(struct network_driver *driver,
|
||||
virNetworkObjPtr network)
|
||||
{
|
||||
int ii;
|
||||
virNetworkIpDefPtr ipdef;
|
||||
|
||||
for (ii = 0;
|
||||
(ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii));
|
||||
ii++) {
|
||||
networkRemoveIpSpecificIptablesRules(driver, network, ipdef);
|
||||
}
|
||||
networkRemoveGeneralIptablesRules(driver, network);
|
||||
}
|
||||
|
||||
static void
|
||||
networkReloadIptablesRules(struct network_driver *driver)
|
||||
{
|
||||
@ -956,22 +1057,12 @@ networkReloadIptablesRules(struct network_driver *driver)
|
||||
|
||||
for (i = 0 ; i < driver->networks.count ; i++) {
|
||||
virNetworkObjLock(driver->networks.objs[i]);
|
||||
|
||||
if (virNetworkObjIsActive(driver->networks.objs[i])) {
|
||||
virNetworkIpDefPtr ipv4def;
|
||||
|
||||
/* Find the one allowed IPv4 ip address in the definition */
|
||||
/* Even if none is found, we still call the functions below */
|
||||
ipv4def = virNetworkDefGetIpByIndex(driver->networks.objs[i]->def,
|
||||
AF_INET, 0);
|
||||
networkRemoveIptablesRules(driver, driver->networks.objs[i],
|
||||
ipv4def);
|
||||
if (networkAddIptablesRules(driver, driver->networks.objs[i],
|
||||
ipv4def) < 0) {
|
||||
/* failed to add but already logged */
|
||||
}
|
||||
networkRemoveIptablesRules(driver, driver->networks.objs[i]);
|
||||
if (networkAddIptablesRules(driver, driver->networks.objs[i]) < 0) {
|
||||
/* failed to add but already logged */
|
||||
}
|
||||
}
|
||||
|
||||
virNetworkObjUnlock(driver->networks.objs[i]);
|
||||
}
|
||||
}
|
||||
@ -1043,32 +1134,16 @@ cleanup:
|
||||
* other scenarios where we can ruin host network connectivity.
|
||||
* XXX: Using a proper library is preferred over parsing /proc
|
||||
*/
|
||||
static int networkCheckRouteCollision(virNetworkObjPtr network,
|
||||
virNetworkIpDefPtr ipdef)
|
||||
static int
|
||||
networkCheckRouteCollision(virNetworkObjPtr network)
|
||||
{
|
||||
int ret = -1, len;
|
||||
unsigned int net_dest;
|
||||
virSocketAddr netmask;
|
||||
int ret = 0, len;
|
||||
char *cur, *buf = NULL;
|
||||
enum {MAX_ROUTE_SIZE = 1024*64};
|
||||
|
||||
if (!VIR_SOCKET_IS_FAMILY(&ipdef->address, AF_INET)) {
|
||||
/* Only support collision check for IPv4 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (virNetworkIpDefNetmask(ipdef, &netmask) < 0) {
|
||||
networkReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Failed to get netmask of '%s'"),
|
||||
network->def->bridge);
|
||||
}
|
||||
|
||||
net_dest = (ipdef->address.data.inet4.sin_addr.s_addr &
|
||||
netmask.data.inet4.sin_addr.s_addr);
|
||||
|
||||
/* Read whole routing table into memory */
|
||||
if ((len = virFileReadAll(PROC_NET_ROUTE, MAX_ROUTE_SIZE, &buf)) < 0)
|
||||
goto error;
|
||||
goto out;
|
||||
|
||||
/* Dropping the last character shouldn't hurt */
|
||||
if (len > 0)
|
||||
@ -1087,7 +1162,8 @@ static int networkCheckRouteCollision(virNetworkObjPtr network,
|
||||
while (cur) {
|
||||
char iface[17], dest[128], mask[128];
|
||||
unsigned int addr_val, mask_val;
|
||||
int num;
|
||||
virNetworkIpDefPtr ipdef;
|
||||
int num, ii;
|
||||
|
||||
/* NUL-terminate the line, so sscanf doesn't go beyond a newline. */
|
||||
char *nl = strchr(cur, '\n');
|
||||
@ -1116,28 +1192,71 @@ static int networkCheckRouteCollision(virNetworkObjPtr network,
|
||||
|
||||
addr_val &= mask_val;
|
||||
|
||||
if ((net_dest == addr_val) &&
|
||||
(netmask.data.inet4.sin_addr.s_addr == mask_val)) {
|
||||
networkReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Network is already in use by interface %s"),
|
||||
iface);
|
||||
goto error;
|
||||
for (ii = 0;
|
||||
(ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, ii));
|
||||
ii++) {
|
||||
|
||||
unsigned int net_dest;
|
||||
virSocketAddr netmask;
|
||||
|
||||
if (virNetworkIpDefNetmask(ipdef, &netmask) < 0) {
|
||||
VIR_WARN("Failed to get netmask of '%s'",
|
||||
network->def->bridge);
|
||||
continue;
|
||||
}
|
||||
|
||||
net_dest = (ipdef->address.data.inet4.sin_addr.s_addr &
|
||||
netmask.data.inet4.sin_addr.s_addr);
|
||||
|
||||
if ((net_dest == addr_val) &&
|
||||
(netmask.data.inet4.sin_addr.s_addr == mask_val)) {
|
||||
networkReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Network is already in use by interface %s"),
|
||||
iface);
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
ret = 0;
|
||||
error:
|
||||
VIR_FREE(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int networkStartNetworkDaemon(struct network_driver *driver,
|
||||
virNetworkObjPtr network)
|
||||
static int
|
||||
networkAddAddrToBridge(struct network_driver *driver,
|
||||
virNetworkObjPtr network,
|
||||
virNetworkIpDefPtr ipdef)
|
||||
{
|
||||
int err;
|
||||
virErrorPtr save_err;
|
||||
virNetworkIpDefPtr ipv4def;
|
||||
int prefix = virNetworkIpDefPrefix(ipdef);
|
||||
|
||||
if (prefix < 0) {
|
||||
networkReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("bridge '%s' has an invalid netmask or IP address"),
|
||||
network->def->bridge);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (brAddInetAddress(driver->brctl, network->def->bridge,
|
||||
&ipdef->address, prefix) < 0) {
|
||||
networkReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("cannot set IP address on bridge '%s'"),
|
||||
network->def->bridge);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
networkStartNetworkDaemon(struct network_driver *driver,
|
||||
virNetworkObjPtr network)
|
||||
{
|
||||
int ii, err;
|
||||
bool v4present = false;
|
||||
virErrorPtr save_err = NULL;
|
||||
virNetworkIpDefPtr ipdef;
|
||||
|
||||
if (virNetworkObjIsActive(network)) {
|
||||
networkReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
@ -1145,13 +1264,11 @@ static int networkStartNetworkDaemon(struct network_driver *driver,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* find the one allowed IPv4 ip address in the definition */
|
||||
ipv4def = virNetworkDefGetIpByIndex(network->def, AF_INET, 0);
|
||||
|
||||
/* Check to see if network collides with an existing route */
|
||||
if (ipv4def && networkCheckRouteCollision(network, ipv4def) < 0)
|
||||
/* Check to see if any network IP collides with an existing route */
|
||||
if (networkCheckRouteCollision(network) < 0)
|
||||
return -1;
|
||||
|
||||
/* Create and configure the bridge device */
|
||||
if ((err = brAddBridge(driver->brctl, network->def->bridge))) {
|
||||
virReportSystemError(err,
|
||||
_("cannot create bridge '%s'"),
|
||||
@ -1159,15 +1276,13 @@ static int networkStartNetworkDaemon(struct network_driver *driver,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (networkDisableIPV6(network) < 0)
|
||||
goto err_delbr;
|
||||
|
||||
/* Set bridge options */
|
||||
if ((err = brSetForwardDelay(driver->brctl, network->def->bridge,
|
||||
network->def->delay))) {
|
||||
networkReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("cannot set forward delay on bridge '%s'"),
|
||||
network->def->bridge);
|
||||
goto err_delbr;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
if ((err = brSetEnableSTP(driver->brctl, network->def->bridge,
|
||||
@ -1175,90 +1290,95 @@ static int networkStartNetworkDaemon(struct network_driver *driver,
|
||||
networkReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("cannot set STP '%s' on bridge '%s'"),
|
||||
network->def->stp ? "on" : "off", network->def->bridge);
|
||||
goto err_delbr;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
if (ipv4def) {
|
||||
int prefix = virNetworkIpDefPrefix(ipv4def);
|
||||
/* Disable IPv6 on the bridge */
|
||||
if (networkDisableIPV6(network) < 0)
|
||||
goto err1;
|
||||
|
||||
if (prefix < 0) {
|
||||
networkReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("bridge '%s' has an invalid netmask or IP address"),
|
||||
network->def->bridge);
|
||||
goto err_delbr;
|
||||
}
|
||||
/* Add "once per network" rules */
|
||||
if (networkAddIptablesRules(driver, network) < 0)
|
||||
goto err1;
|
||||
|
||||
if ((err = brAddInetAddress(driver->brctl, network->def->bridge,
|
||||
&ipv4def->address, prefix))) {
|
||||
networkReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("cannot set IP address on bridge '%s'"),
|
||||
network->def->bridge);
|
||||
goto err_delbr;
|
||||
for (ii = 0;
|
||||
(ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii));
|
||||
ii++) {
|
||||
if (VIR_SOCKET_IS_FAMILY(&ipdef->address, AF_INET))
|
||||
v4present = true;
|
||||
|
||||
/* Add the IP address/netmask to the bridge */
|
||||
if (networkAddAddrToBridge(driver, network, ipdef) < 0) {
|
||||
goto err2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Bring up the bridge interface */
|
||||
if ((err = brSetInterfaceUp(driver->brctl, network->def->bridge, 1))) {
|
||||
virReportSystemError(err,
|
||||
_("failed to bring the bridge '%s' up"),
|
||||
network->def->bridge);
|
||||
goto err_delbr;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
if (ipv4def && networkAddIptablesRules(driver, network, ipv4def) < 0)
|
||||
goto err_delbr1;
|
||||
|
||||
/* If forwardType != NONE, turn on global IP forwarding */
|
||||
if (network->def->forwardType != VIR_NETWORK_FORWARD_NONE &&
|
||||
networkEnableIpForwarding() < 0) {
|
||||
virReportSystemError(errno, "%s",
|
||||
_("failed to enable IP forwarding"));
|
||||
goto err_delbr2;
|
||||
goto err3;
|
||||
}
|
||||
|
||||
/*
|
||||
* Start the dhcp daemon for the 1st (and only supported) ipv4
|
||||
* address.
|
||||
*/
|
||||
if (ipv4def && dhcpStartDhcpDaemon(network, ipv4def) < 0)
|
||||
goto err_delbr2;
|
||||
|
||||
/* start dnsmasq if there are any IPv4 addresses */
|
||||
if (v4present && networkStartDhcpDaemon(network) < 0)
|
||||
goto err3;
|
||||
|
||||
/* Persist the live configuration now we have bridge info */
|
||||
if (virNetworkSaveConfig(NETWORK_STATE_DIR, network->def) < 0) {
|
||||
goto err_kill;
|
||||
goto err4;
|
||||
}
|
||||
|
||||
network->active = 1;
|
||||
|
||||
return 0;
|
||||
|
||||
err_kill:
|
||||
err4:
|
||||
if (!save_err)
|
||||
save_err = virSaveLastError();
|
||||
|
||||
if (network->dnsmasqPid > 0) {
|
||||
kill(network->dnsmasqPid, SIGTERM);
|
||||
network->dnsmasqPid = -1;
|
||||
}
|
||||
|
||||
err_delbr2:
|
||||
save_err = virSaveLastError();
|
||||
if (ipv4def)
|
||||
networkRemoveIptablesRules(driver, network, ipv4def);
|
||||
if (save_err) {
|
||||
virSetError(save_err);
|
||||
virFreeError(save_err);
|
||||
}
|
||||
|
||||
err_delbr1:
|
||||
err3:
|
||||
if (!save_err)
|
||||
save_err = virSaveLastError();
|
||||
if ((err = brSetInterfaceUp(driver->brctl, network->def->bridge, 0))) {
|
||||
char ebuf[1024];
|
||||
VIR_WARN("Failed to bring down bridge '%s' : %s",
|
||||
network->def->bridge, virStrerror(err, ebuf, sizeof ebuf));
|
||||
}
|
||||
|
||||
err_delbr:
|
||||
err2:
|
||||
if (!save_err)
|
||||
save_err = virSaveLastError();
|
||||
networkRemoveIptablesRules(driver, network);
|
||||
|
||||
err1:
|
||||
if (!save_err)
|
||||
save_err = virSaveLastError();
|
||||
if ((err = brDeleteBridge(driver->brctl, network->def->bridge))) {
|
||||
char ebuf[1024];
|
||||
VIR_WARN("Failed to delete bridge '%s' : %s",
|
||||
network->def->bridge, virStrerror(err, ebuf, sizeof ebuf));
|
||||
}
|
||||
|
||||
if (save_err) {
|
||||
virSetError(save_err);
|
||||
virFreeError(save_err);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1268,7 +1388,6 @@ static int networkShutdownNetworkDaemon(struct network_driver *driver,
|
||||
{
|
||||
int err;
|
||||
char *stateFile;
|
||||
virNetworkIpDefPtr ipv4def;
|
||||
|
||||
VIR_INFO(_("Shutting down network '%s'"), network->def->name);
|
||||
|
||||
@ -1285,17 +1404,14 @@ static int networkShutdownNetworkDaemon(struct network_driver *driver,
|
||||
if (network->dnsmasqPid > 0)
|
||||
kill(network->dnsmasqPid, SIGTERM);
|
||||
|
||||
/* find the one allowed IPv4 ip address in the definition */
|
||||
ipv4def = virNetworkDefGetIpByIndex(network->def, AF_INET, 0);
|
||||
if (ipv4def)
|
||||
networkRemoveIptablesRules(driver, network, ipv4def);
|
||||
|
||||
char ebuf[1024];
|
||||
if ((err = brSetInterfaceUp(driver->brctl, network->def->bridge, 0))) {
|
||||
VIR_WARN("Failed to bring down bridge '%s' : %s",
|
||||
network->def->bridge, virStrerror(err, ebuf, sizeof ebuf));
|
||||
}
|
||||
|
||||
networkRemoveIptablesRules(driver, network);
|
||||
|
||||
if ((err = brDeleteBridge(driver->brctl, network->def->bridge))) {
|
||||
VIR_WARN("Failed to delete bridge '%s' : %s",
|
||||
network->def->bridge, virStrerror(err, ebuf, sizeof ebuf));
|
||||
@ -1552,10 +1668,11 @@ cleanup:
|
||||
|
||||
static virNetworkPtr networkDefine(virConnectPtr conn, const char *xml) {
|
||||
struct network_driver *driver = conn->networkPrivateData;
|
||||
virNetworkIpDefPtr ipv4def;
|
||||
virNetworkIpDefPtr ipdef, ipv4def = NULL;
|
||||
virNetworkDefPtr def;
|
||||
virNetworkObjPtr network = NULL;
|
||||
virNetworkPtr ret = NULL;
|
||||
int ii;
|
||||
|
||||
networkDriverLock(driver);
|
||||
|
||||
@ -1583,10 +1700,33 @@ static virNetworkPtr networkDefine(virConnectPtr conn, const char *xml) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* we only support dhcp on one IPv4 address per defined network */
|
||||
ipv4def = virNetworkDefGetIpByIndex(network->def, AF_INET, 0);
|
||||
/* we only support dhcp on one IPv4 address per defined network, and currently
|
||||
* don't support IPv6.
|
||||
*/
|
||||
for (ii = 0;
|
||||
(ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii));
|
||||
ii++) {
|
||||
if (VIR_SOCKET_IS_FAMILY(&ipdef->address, AF_INET)) {
|
||||
if (ipdef->nranges || ipdef->nhosts) {
|
||||
if (ipv4def) {
|
||||
networkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||
"%s", _("Multiple dhcp sections found. dhcp is supported only for a single IPv4 address on each network"));
|
||||
goto cleanup;
|
||||
} else {
|
||||
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 && ipv4def->nhosts > 0) {
|
||||
}
|
||||
}
|
||||
if (ipv4def) {
|
||||
dnsmasqContext *dctx = dnsmasqContextNew(network->def->name, DNSMASQ_STATE_DIR);
|
||||
if (dctx == NULL)
|
||||
goto cleanup;
|
||||
@ -1609,7 +1749,7 @@ static int networkUndefine(virNetworkPtr net) {
|
||||
struct network_driver *driver = net->conn->networkPrivateData;
|
||||
virNetworkObjPtr network;
|
||||
virNetworkIpDefPtr ipv4def;
|
||||
int ret = -1;
|
||||
int ret = -1, ii;
|
||||
|
||||
networkDriverLock(driver);
|
||||
|
||||
@ -1631,10 +1771,14 @@ static int networkUndefine(virNetworkPtr net) {
|
||||
network) < 0)
|
||||
goto cleanup;
|
||||
|
||||
/* find the one allowed IPv4 ip address in the definition */
|
||||
ipv4def = virNetworkDefGetIpByIndex(network->def, AF_INET, 0);
|
||||
|
||||
if (ipv4def && ipv4def->nhosts > 0) {
|
||||
/* we only support dhcp on one IPv4 address per defined network */
|
||||
for (ii = 0;
|
||||
(ipv4def = virNetworkDefGetIpByIndex(network->def, AF_INET, ii));
|
||||
ii++) {
|
||||
if (ipv4def->nranges || ipv4def->nhosts)
|
||||
break;
|
||||
}
|
||||
if (ipv4def) {
|
||||
dnsmasqContext *dctx = dnsmasqContextNew(network->def->name, DNSMASQ_STATE_DIR);
|
||||
if (dctx == NULL)
|
||||
goto cleanup;
|
||||
|
Loading…
Reference in New Issue
Block a user