Merge "Add IPv6 default route to DHCP namespace"
This commit is contained in:
commit
e4557a7793
|
@ -1114,31 +1114,39 @@ class DeviceManager(object):
|
||||||
return common_utils.get_dhcp_agent_device_id(network.id,
|
return common_utils.get_dhcp_agent_device_id(network.id,
|
||||||
self.conf.host)
|
self.conf.host)
|
||||||
|
|
||||||
def _set_default_route(self, network, device_name):
|
def _set_default_route_ip_version(self, network, device_name, ip_version):
|
||||||
"""Sets the default gateway for this dhcp namespace.
|
|
||||||
|
|
||||||
This method is idempotent and will only adjust the route if adjusting
|
|
||||||
it would change it from what it already is. This makes it safe to call
|
|
||||||
and avoids unnecessary perturbation of the system.
|
|
||||||
"""
|
|
||||||
device = ip_lib.IPDevice(device_name, namespace=network.namespace)
|
device = ip_lib.IPDevice(device_name, namespace=network.namespace)
|
||||||
gateway = device.route.get_gateway()
|
gateway = device.route.get_gateway(ip_version=ip_version)
|
||||||
if gateway:
|
if gateway:
|
||||||
gateway = gateway.get('gateway')
|
gateway = gateway.get('gateway')
|
||||||
|
|
||||||
for subnet in network.subnets:
|
for subnet in network.subnets:
|
||||||
skip_subnet = (
|
skip_subnet = (
|
||||||
subnet.ip_version != 4
|
subnet.ip_version != ip_version
|
||||||
or not subnet.enable_dhcp
|
or not subnet.enable_dhcp
|
||||||
or subnet.gateway_ip is None)
|
or subnet.gateway_ip is None)
|
||||||
|
|
||||||
if skip_subnet:
|
if skip_subnet:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if subnet.ip_version == constants.IP_VERSION_6:
|
||||||
|
# This is duplicating some of the API checks already done,
|
||||||
|
# but some of the functional tests call directly
|
||||||
|
prefixlen = netaddr.IPNetwork(subnet.cidr).prefixlen
|
||||||
|
if prefixlen == 0 or prefixlen > 126:
|
||||||
|
continue
|
||||||
|
modes = [constants.IPV6_SLAAC, constants.DHCPV6_STATELESS]
|
||||||
|
addr_mode = getattr(subnet, 'ipv6_address_mode', None)
|
||||||
|
ra_mode = getattr(subnet, 'ipv6_ra_mode', None)
|
||||||
|
if (prefixlen != 64 and
|
||||||
|
(addr_mode in modes or ra_mode in modes)):
|
||||||
|
continue
|
||||||
|
|
||||||
if gateway != subnet.gateway_ip:
|
if gateway != subnet.gateway_ip:
|
||||||
LOG.debug('Setting gateway for dhcp netns on net %(n)s to '
|
LOG.debug('Setting IPv%(version)s gateway for dhcp netns '
|
||||||
'%(ip)s',
|
'on net %(n)s to %(ip)s',
|
||||||
{'n': network.id, 'ip': subnet.gateway_ip})
|
{'n': network.id, 'ip': subnet.gateway_ip,
|
||||||
|
'version': ip_version})
|
||||||
|
|
||||||
# Check for and remove the on-link route for the old
|
# Check for and remove the on-link route for the old
|
||||||
# gateway being replaced, if it is outside the subnet
|
# gateway being replaced, if it is outside the subnet
|
||||||
|
@ -1146,12 +1154,8 @@ class DeviceManager(object):
|
||||||
not ipam_utils.check_subnet_ip(
|
not ipam_utils.check_subnet_ip(
|
||||||
subnet.cidr, gateway))
|
subnet.cidr, gateway))
|
||||||
if is_old_gateway_not_in_subnet:
|
if is_old_gateway_not_in_subnet:
|
||||||
v4_onlink = device.route.list_onlink_routes(
|
onlink = device.route.list_onlink_routes(ip_version)
|
||||||
constants.IP_VERSION_4)
|
existing_onlink_routes = set(r['cidr'] for r in onlink)
|
||||||
v6_onlink = device.route.list_onlink_routes(
|
|
||||||
constants.IP_VERSION_6)
|
|
||||||
existing_onlink_routes = set(
|
|
||||||
r['cidr'] for r in v4_onlink + v6_onlink)
|
|
||||||
if gateway in existing_onlink_routes:
|
if gateway in existing_onlink_routes:
|
||||||
device.route.delete_route(gateway, scope='link')
|
device.route.delete_route(gateway, scope='link')
|
||||||
|
|
||||||
|
@ -1168,10 +1172,23 @@ class DeviceManager(object):
|
||||||
# No subnets on the network have a valid gateway. Clean it up to avoid
|
# No subnets on the network have a valid gateway. Clean it up to avoid
|
||||||
# confusion from seeing an invalid gateway here.
|
# confusion from seeing an invalid gateway here.
|
||||||
if gateway is not None:
|
if gateway is not None:
|
||||||
LOG.debug('Removing gateway for dhcp netns on net %s', network.id)
|
LOG.debug('Removing IPv%(version)s gateway for dhcp netns on '
|
||||||
|
'net %(n)s',
|
||||||
|
{'n': network.id, 'version': ip_version})
|
||||||
|
|
||||||
device.route.delete_gateway(gateway)
|
device.route.delete_gateway(gateway)
|
||||||
|
|
||||||
|
def _set_default_route(self, network, device_name):
|
||||||
|
"""Sets the default gateway for this dhcp namespace.
|
||||||
|
|
||||||
|
This method is idempotent and will only adjust the route if adjusting
|
||||||
|
it would change it from what it already is. This makes it safe to call
|
||||||
|
and avoids unnecessary perturbation of the system.
|
||||||
|
"""
|
||||||
|
for ip_version in (constants.IP_VERSION_4, constants.IP_VERSION_6):
|
||||||
|
self._set_default_route_ip_version(network, device_name,
|
||||||
|
ip_version)
|
||||||
|
|
||||||
def _setup_existing_dhcp_port(self, network, device_id, dhcp_subnets):
|
def _setup_existing_dhcp_port(self, network, device_id, dhcp_subnets):
|
||||||
"""Set up the existing DHCP port, if there is one."""
|
"""Set up the existing DHCP port, if there is one."""
|
||||||
|
|
||||||
|
|
|
@ -50,9 +50,9 @@ class DHCPAgentOVSTestFramework(base.BaseSudoTestCase):
|
||||||
4: {'addr': '192.168.10.11',
|
4: {'addr': '192.168.10.11',
|
||||||
'cidr': '192.168.10.0/24',
|
'cidr': '192.168.10.0/24',
|
||||||
'gateway': '192.168.10.1'},
|
'gateway': '192.168.10.1'},
|
||||||
6: {'addr': '0:0:0:0:0:ffff:c0a8:a0b',
|
6: {'addr': '2001:db8:0:1::c0a8:a0b',
|
||||||
'cidr': '0:0:0:0:0:ffff:c0a8:a00/120',
|
'cidr': '2001:db8:0:1::c0a8:a00/120',
|
||||||
'gateway': '0:0:0:0:0:ffff:c0a8:a01'}, }
|
'gateway': '2001:db8:0:1::c0a8:a01'}, }
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(DHCPAgentOVSTestFramework, self).setUp()
|
super(DHCPAgentOVSTestFramework, self).setUp()
|
||||||
|
|
|
@ -1329,6 +1329,11 @@ class FakePort1(object):
|
||||||
self.id = 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee'
|
self.id = 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee'
|
||||||
|
|
||||||
|
|
||||||
|
class FakePort2(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.id = 'ffffffff-ffff-ffff-ffff-ffffffffffff'
|
||||||
|
|
||||||
|
|
||||||
class FakeV4Subnet(object):
|
class FakeV4Subnet(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.id = 'dddddddd-dddd-dddd-dddd-dddddddddddd'
|
self.id = 'dddddddd-dddd-dddd-dddd-dddddddddddd'
|
||||||
|
@ -1338,12 +1343,27 @@ class FakeV4Subnet(object):
|
||||||
self.enable_dhcp = True
|
self.enable_dhcp = True
|
||||||
|
|
||||||
|
|
||||||
|
class FakeV6Subnet(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.id = 'ffffffff-ffff-ffff-ffff-ffffffffffff'
|
||||||
|
self.ip_version = 6
|
||||||
|
self.cidr = '2001:db8:0:1::/64'
|
||||||
|
self.gateway_ip = '2001:db8:0:1::1'
|
||||||
|
self.enable_dhcp = True
|
||||||
|
|
||||||
|
|
||||||
class FakeV4SubnetOutsideGateway(FakeV4Subnet):
|
class FakeV4SubnetOutsideGateway(FakeV4Subnet):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(FakeV4SubnetOutsideGateway, self).__init__()
|
super(FakeV4SubnetOutsideGateway, self).__init__()
|
||||||
self.gateway_ip = '192.168.1.1'
|
self.gateway_ip = '192.168.1.1'
|
||||||
|
|
||||||
|
|
||||||
|
class FakeV6SubnetOutsideGateway(FakeV6Subnet):
|
||||||
|
def __init__(self):
|
||||||
|
super(FakeV6SubnetOutsideGateway, self).__init__()
|
||||||
|
self.gateway_ip = '2001:db8:1:1::1'
|
||||||
|
|
||||||
|
|
||||||
class FakeV4SubnetNoGateway(object):
|
class FakeV4SubnetNoGateway(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.id = 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee'
|
self.id = 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee'
|
||||||
|
@ -1353,6 +1373,15 @@ class FakeV4SubnetNoGateway(object):
|
||||||
self.enable_dhcp = True
|
self.enable_dhcp = True
|
||||||
|
|
||||||
|
|
||||||
|
class FakeV6SubnetNoGateway(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.id = 'ffffffff-ffff-ffff-ffff-ffffffffffff'
|
||||||
|
self.ip_version = 6
|
||||||
|
self.cidr = '2001:db8:1:0::/64'
|
||||||
|
self.gateway_ip = None
|
||||||
|
self.enable_dhcp = True
|
||||||
|
|
||||||
|
|
||||||
class FakeV4Network(object):
|
class FakeV4Network(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.id = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'
|
self.id = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'
|
||||||
|
@ -1361,24 +1390,39 @@ class FakeV4Network(object):
|
||||||
self.namespace = 'qdhcp-aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'
|
self.namespace = 'qdhcp-aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'
|
||||||
|
|
||||||
|
|
||||||
|
class FakeDualNetwork(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.id = 'dddddddd-dddd-dddd-dddd-dddddddddddd'
|
||||||
|
self.subnets = [FakeV4Subnet(), FakeV6Subnet()]
|
||||||
|
self.ports = [FakePort1(), FakePort2()]
|
||||||
|
self.namespace = 'qdhcp-dddddddd-dddd-dddd-dddd-dddddddddddd'
|
||||||
|
|
||||||
|
|
||||||
class FakeV4NetworkOutsideGateway(FakeV4Network):
|
class FakeV4NetworkOutsideGateway(FakeV4Network):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(FakeV4NetworkOutsideGateway, self).__init__()
|
super(FakeV4NetworkOutsideGateway, self).__init__()
|
||||||
self.subnets = [FakeV4SubnetOutsideGateway()]
|
self.subnets = [FakeV4SubnetOutsideGateway()]
|
||||||
|
|
||||||
|
|
||||||
class FakeV4NetworkNoSubnet(object):
|
class FakeDualNetworkOutsideGateway(FakeDualNetwork):
|
||||||
|
def __init__(self):
|
||||||
|
super(FakeDualNetworkOutsideGateway, self).__init__()
|
||||||
|
self.subnets = [FakeV4SubnetOutsideGateway(),
|
||||||
|
FakeV6SubnetOutsideGateway()]
|
||||||
|
|
||||||
|
|
||||||
|
class FakeDualNetworkNoSubnet(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.id = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'
|
self.id = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'
|
||||||
self.subnets = []
|
self.subnets = []
|
||||||
self.ports = []
|
self.ports = []
|
||||||
|
|
||||||
|
|
||||||
class FakeV4NetworkNoGateway(object):
|
class FakeDualNetworkNoGateway(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.id = 'cccccccc-cccc-cccc-cccc-cccccccccccc'
|
self.id = 'cccccccc-cccc-cccc-cccc-cccccccccccc'
|
||||||
self.subnets = [FakeV4SubnetNoGateway()]
|
self.subnets = [FakeV4SubnetNoGateway(), FakeV6SubnetNoGateway()]
|
||||||
self.ports = [FakePort1()]
|
self.ports = [FakePort1(), FakePort2()]
|
||||||
|
|
||||||
|
|
||||||
class TestDeviceManager(base.BaseTestCase):
|
class TestDeviceManager(base.BaseTestCase):
|
||||||
|
@ -1733,7 +1777,7 @@ class TestDeviceManager(base.BaseTestCase):
|
||||||
network = FakeV4Network()
|
network = FakeV4Network()
|
||||||
dh._set_default_route(network, 'tap-name')
|
dh._set_default_route(network, 'tap-name')
|
||||||
|
|
||||||
self.assertEqual(1, device.route.get_gateway.call_count)
|
self.assertEqual(2, device.route.get_gateway.call_count)
|
||||||
self.assertFalse(device.route.delete_gateway.called)
|
self.assertFalse(device.route.delete_gateway.called)
|
||||||
device.route.add_gateway.assert_called_once_with('192.168.0.1')
|
device.route.add_gateway.assert_called_once_with('192.168.0.1')
|
||||||
|
|
||||||
|
@ -1747,7 +1791,7 @@ class TestDeviceManager(base.BaseTestCase):
|
||||||
network = FakeV4NetworkOutsideGateway()
|
network = FakeV4NetworkOutsideGateway()
|
||||||
dh._set_default_route(network, 'tap-name')
|
dh._set_default_route(network, 'tap-name')
|
||||||
|
|
||||||
self.assertEqual(1, device.route.get_gateway.call_count)
|
self.assertEqual(2, device.route.get_gateway.call_count)
|
||||||
self.assertFalse(device.route.delete_gateway.called)
|
self.assertFalse(device.route.delete_gateway.called)
|
||||||
device.route.add_route.assert_called_once_with('192.168.1.1',
|
device.route.add_route.assert_called_once_with('192.168.1.1',
|
||||||
scope='link')
|
scope='link')
|
||||||
|
@ -1759,104 +1803,141 @@ class TestDeviceManager(base.BaseTestCase):
|
||||||
device = mock.Mock()
|
device = mock.Mock()
|
||||||
mock_IPDevice.return_value = device
|
mock_IPDevice.return_value = device
|
||||||
device.route.get_gateway.return_value = None
|
device.route.get_gateway.return_value = None
|
||||||
network = FakeV4NetworkNoSubnet()
|
network = FakeDualNetworkNoSubnet()
|
||||||
network.namespace = 'qdhcp-1234'
|
network.namespace = 'qdhcp-1234'
|
||||||
dh._set_default_route(network, 'tap-name')
|
dh._set_default_route(network, 'tap-name')
|
||||||
|
|
||||||
self.assertEqual(1, device.route.get_gateway.call_count)
|
self.assertEqual(2, device.route.get_gateway.call_count)
|
||||||
self.assertFalse(device.route.delete_gateway.called)
|
self.assertFalse(device.route.delete_gateway.called)
|
||||||
self.assertFalse(device.route.add_gateway.called)
|
self.assertFalse(device.route.add_gateway.called)
|
||||||
|
|
||||||
def test_set_default_route_no_subnet_delete_gateway(self):
|
def test_set_default_route_no_subnet_delete_gateway(self):
|
||||||
dh = dhcp.DeviceManager(cfg.CONF, None)
|
dh = dhcp.DeviceManager(cfg.CONF, None)
|
||||||
|
v4_gateway = '192.168.0.1'
|
||||||
|
v6_gateway = '2001:db8:0:1::1'
|
||||||
|
expected = [mock.call(v4_gateway),
|
||||||
|
mock.call(v6_gateway)]
|
||||||
with mock.patch.object(dhcp.ip_lib, 'IPDevice') as mock_IPDevice:
|
with mock.patch.object(dhcp.ip_lib, 'IPDevice') as mock_IPDevice:
|
||||||
device = mock.Mock()
|
device = mock.Mock()
|
||||||
mock_IPDevice.return_value = device
|
mock_IPDevice.return_value = device
|
||||||
device.route.get_gateway.return_value = dict(gateway='192.168.0.1')
|
device.route.get_gateway.side_effect = [
|
||||||
network = FakeV4NetworkNoSubnet()
|
dict(gateway=v4_gateway), dict(gateway=v6_gateway)]
|
||||||
|
network = FakeDualNetworkNoSubnet()
|
||||||
network.namespace = 'qdhcp-1234'
|
network.namespace = 'qdhcp-1234'
|
||||||
dh._set_default_route(network, 'tap-name')
|
dh._set_default_route(network, 'tap-name')
|
||||||
|
|
||||||
self.assertEqual(1, device.route.get_gateway.call_count)
|
self.assertEqual(2, device.route.get_gateway.call_count)
|
||||||
device.route.delete_gateway.assert_called_once_with('192.168.0.1')
|
self.assertEqual(2, device.route.delete_gateway.call_count)
|
||||||
|
device.route.delete_gateway.assert_has_calls(expected)
|
||||||
self.assertFalse(device.route.add_gateway.called)
|
self.assertFalse(device.route.add_gateway.called)
|
||||||
|
|
||||||
def test_set_default_route_no_gateway(self):
|
def test_set_default_route_no_gateway(self):
|
||||||
dh = dhcp.DeviceManager(cfg.CONF, None)
|
dh = dhcp.DeviceManager(cfg.CONF, None)
|
||||||
|
v4_gateway = '192.168.0.1'
|
||||||
|
v6_gateway = '2001:db8:0:1::1'
|
||||||
|
expected = [mock.call(v4_gateway),
|
||||||
|
mock.call(v6_gateway)]
|
||||||
with mock.patch.object(dhcp.ip_lib, 'IPDevice') as mock_IPDevice:
|
with mock.patch.object(dhcp.ip_lib, 'IPDevice') as mock_IPDevice:
|
||||||
device = mock.Mock()
|
device = mock.Mock()
|
||||||
mock_IPDevice.return_value = device
|
mock_IPDevice.return_value = device
|
||||||
device.route.get_gateway.return_value = dict(gateway='192.168.0.1')
|
device.route.get_gateway.side_effect = [
|
||||||
network = FakeV4NetworkNoGateway()
|
dict(gateway=v4_gateway), dict(gateway=v6_gateway)]
|
||||||
|
network = FakeDualNetworkNoGateway()
|
||||||
network.namespace = 'qdhcp-1234'
|
network.namespace = 'qdhcp-1234'
|
||||||
dh._set_default_route(network, 'tap-name')
|
dh._set_default_route(network, 'tap-name')
|
||||||
|
|
||||||
self.assertEqual(1, device.route.get_gateway.call_count)
|
self.assertEqual(2, device.route.get_gateway.call_count)
|
||||||
device.route.delete_gateway.assert_called_once_with('192.168.0.1')
|
self.assertEqual(2, device.route.delete_gateway.call_count)
|
||||||
|
device.route.delete_gateway.assert_has_calls(expected)
|
||||||
self.assertFalse(device.route.add_gateway.called)
|
self.assertFalse(device.route.add_gateway.called)
|
||||||
|
|
||||||
def test_set_default_route_do_nothing(self):
|
def test_set_default_route_do_nothing(self):
|
||||||
dh = dhcp.DeviceManager(cfg.CONF, None)
|
dh = dhcp.DeviceManager(cfg.CONF, None)
|
||||||
|
v4_gateway = '192.168.0.1'
|
||||||
|
v6_gateway = '2001:db8:0:1::1'
|
||||||
with mock.patch.object(dhcp.ip_lib, 'IPDevice') as mock_IPDevice:
|
with mock.patch.object(dhcp.ip_lib, 'IPDevice') as mock_IPDevice:
|
||||||
device = mock.Mock()
|
device = mock.Mock()
|
||||||
mock_IPDevice.return_value = device
|
mock_IPDevice.return_value = device
|
||||||
device.route.get_gateway.return_value = dict(gateway='192.168.0.1')
|
device.route.get_gateway.side_effect = [
|
||||||
network = FakeV4Network()
|
dict(gateway=v4_gateway), dict(gateway=v6_gateway)]
|
||||||
|
network = FakeDualNetwork()
|
||||||
dh._set_default_route(network, 'tap-name')
|
dh._set_default_route(network, 'tap-name')
|
||||||
|
|
||||||
self.assertEqual(1, device.route.get_gateway.call_count)
|
self.assertEqual(2, device.route.get_gateway.call_count)
|
||||||
self.assertFalse(device.route.delete_gateway.called)
|
self.assertFalse(device.route.delete_gateway.called)
|
||||||
self.assertFalse(device.route.add_gateway.called)
|
self.assertFalse(device.route.add_gateway.called)
|
||||||
|
|
||||||
def test_set_default_route_change_gateway(self):
|
def test_set_default_route_change_gateway(self):
|
||||||
dh = dhcp.DeviceManager(cfg.CONF, None)
|
dh = dhcp.DeviceManager(cfg.CONF, None)
|
||||||
|
v4_gateway = '192.168.0.1'
|
||||||
|
old_v4_gateway = '192.168.0.2'
|
||||||
|
v6_gateway = '2001:db8:0:1::1'
|
||||||
|
old_v6_gateway = '2001:db8:0:1::2'
|
||||||
|
expected = [mock.call(v4_gateway),
|
||||||
|
mock.call(v6_gateway)]
|
||||||
with mock.patch.object(dhcp.ip_lib, 'IPDevice') as mock_IPDevice:
|
with mock.patch.object(dhcp.ip_lib, 'IPDevice') as mock_IPDevice:
|
||||||
device = mock.Mock()
|
device = mock.Mock()
|
||||||
mock_IPDevice.return_value = device
|
mock_IPDevice.return_value = device
|
||||||
device.route.get_gateway.return_value = dict(gateway='192.168.0.2')
|
device.route.get_gateway.side_effect = [
|
||||||
network = FakeV4Network()
|
dict(gateway=old_v4_gateway), dict(gateway=old_v6_gateway)]
|
||||||
|
network = FakeDualNetwork()
|
||||||
dh._set_default_route(network, 'tap-name')
|
dh._set_default_route(network, 'tap-name')
|
||||||
|
|
||||||
self.assertEqual(1, device.route.get_gateway.call_count)
|
self.assertEqual(2, device.route.get_gateway.call_count)
|
||||||
self.assertFalse(device.route.delete_gateway.called)
|
self.assertFalse(device.route.delete_gateway.called)
|
||||||
device.route.add_gateway.assert_called_once_with('192.168.0.1')
|
device.route.add_gateway.assert_has_calls(expected)
|
||||||
|
|
||||||
def test_set_default_route_change_gateway_outside_subnet(self):
|
def test_set_default_route_change_gateway_outside_subnet(self):
|
||||||
dh = dhcp.DeviceManager(cfg.CONF, None)
|
dh = dhcp.DeviceManager(cfg.CONF, None)
|
||||||
|
v4_gateway = '192.168.1.1'
|
||||||
|
old_v4_gateway = '192.168.2.1'
|
||||||
|
v6_gateway = '2001:db8:1:1::1'
|
||||||
|
old_v6_gateway = '2001:db8:2:0::1'
|
||||||
|
add_route_expected = [mock.call(v4_gateway, scope='link'),
|
||||||
|
mock.call(v6_gateway, scope='link')]
|
||||||
|
add_gw_expected = [mock.call(v4_gateway),
|
||||||
|
mock.call(v6_gateway)]
|
||||||
with mock.patch.object(dhcp.ip_lib, 'IPDevice') as mock_IPDevice:
|
with mock.patch.object(dhcp.ip_lib, 'IPDevice') as mock_IPDevice:
|
||||||
device = mock.Mock()
|
device = mock.Mock()
|
||||||
mock_IPDevice.return_value = device
|
mock_IPDevice.return_value = device
|
||||||
device.route.list_onlink_routes.return_value = (
|
device.route.list_onlink_routes.side_effect = [
|
||||||
[{'cidr': '192.168.2.1'}])
|
[{'cidr': old_v4_gateway}], []]
|
||||||
device.route.get_gateway.return_value = dict(gateway='192.168.2.1')
|
device.route.get_gateway.side_effect = [
|
||||||
network = FakeV4NetworkOutsideGateway()
|
dict(gateway=old_v4_gateway), dict(gateway=old_v6_gateway)]
|
||||||
|
network = FakeDualNetworkOutsideGateway()
|
||||||
dh._set_default_route(network, 'tap-name')
|
dh._set_default_route(network, 'tap-name')
|
||||||
|
|
||||||
self.assertEqual(1, device.route.get_gateway.call_count)
|
self.assertEqual(2, device.route.get_gateway.call_count)
|
||||||
self.assertEqual(2, device.route.list_onlink_routes.call_count)
|
self.assertEqual(2, device.route.list_onlink_routes.call_count)
|
||||||
self.assertFalse(device.route.delete_gateway.called)
|
self.assertFalse(device.route.delete_gateway.called)
|
||||||
device.route.delete_route.assert_called_once_with('192.168.2.1',
|
device.route.delete_route.assert_called_once_with(old_v4_gateway,
|
||||||
scope='link')
|
scope='link')
|
||||||
device.route.add_route.assert_called_once_with('192.168.1.1',
|
device.route.add_route.assert_has_calls(add_route_expected)
|
||||||
scope='link')
|
device.route.add_gateway.assert_has_calls(add_gw_expected)
|
||||||
device.route.add_gateway.assert_called_once_with('192.168.1.1')
|
|
||||||
|
|
||||||
def test_set_default_route_two_subnets(self):
|
def test_set_default_route_two_subnets(self):
|
||||||
# Try two subnets. Should set gateway from the first.
|
# Try two subnets. Should set gateway from the first.
|
||||||
dh = dhcp.DeviceManager(cfg.CONF, None)
|
dh = dhcp.DeviceManager(cfg.CONF, None)
|
||||||
|
v4_gateway = '192.168.1.1'
|
||||||
|
v6_gateway = '2001:db8:1:1::1'
|
||||||
|
expected = [mock.call(v4_gateway),
|
||||||
|
mock.call(v6_gateway)]
|
||||||
with mock.patch.object(dhcp.ip_lib, 'IPDevice') as mock_IPDevice:
|
with mock.patch.object(dhcp.ip_lib, 'IPDevice') as mock_IPDevice:
|
||||||
device = mock.Mock()
|
device = mock.Mock()
|
||||||
mock_IPDevice.return_value = device
|
mock_IPDevice.return_value = device
|
||||||
device.route.get_gateway.return_value = None
|
device.route.get_gateway.return_value = None
|
||||||
network = FakeV4Network()
|
network = FakeDualNetwork()
|
||||||
subnet2 = FakeV4Subnet()
|
subnet2 = FakeV4Subnet()
|
||||||
subnet2.gateway_ip = '192.168.1.1'
|
subnet2.gateway_ip = v4_gateway
|
||||||
network.subnets = [subnet2, FakeV4Subnet()]
|
subnet3 = FakeV6Subnet()
|
||||||
|
subnet3.gateway_ip = v6_gateway
|
||||||
|
network.subnets = [subnet2, FakeV4Subnet(),
|
||||||
|
subnet3, FakeV6Subnet()]
|
||||||
dh._set_default_route(network, 'tap-name')
|
dh._set_default_route(network, 'tap-name')
|
||||||
|
|
||||||
self.assertEqual(1, device.route.get_gateway.call_count)
|
self.assertEqual(2, device.route.get_gateway.call_count)
|
||||||
self.assertFalse(device.route.delete_gateway.called)
|
self.assertFalse(device.route.delete_gateway.called)
|
||||||
device.route.add_gateway.assert_called_once_with('192.168.1.1')
|
device.route.add_gateway.assert_has_calls(expected)
|
||||||
|
|
||||||
|
|
||||||
class TestDictModel(base.BaseTestCase):
|
class TestDictModel(base.BaseTestCase):
|
||||||
|
|
Loading…
Reference in New Issue