diff --git a/vmware_nsx/common/config.py b/vmware_nsx/common/config.py index 2389ddb84d..fae9f82e70 100644 --- a/vmware_nsx/common/config.py +++ b/vmware_nsx/common/config.py @@ -627,6 +627,10 @@ nsxv_opts = [ help=_("(Optional) If use_nsx_policies is True, this value " "will determine if a tenants can add rules to their " "security groups.")), + cfg.StrOpt('vdr_transit_network', default="169.254.2.0/28", + help=_("(Optional) Sets the network address for distributed " + "router TLR-PLR connectivity, with " + "/ syntax")), ] # Register the configuration options diff --git a/vmware_nsx/common/nsxv_constants.py b/vmware_nsx/common/nsxv_constants.py index 03e2c25076..2d00626e79 100644 --- a/vmware_nsx/common/nsxv_constants.py +++ b/vmware_nsx/common/nsxv_constants.py @@ -59,5 +59,4 @@ CSR_REQUEST = ("" # Reserved IPs that cannot overlap defined subnets RESERVED_IPS = ["169.254.128.0/17", "169.254.1.0/24", - "169.254.2.0/28", "169.254.64.192/26"] diff --git a/vmware_nsx/plugins/nsx_v/drivers/distributed_router_driver.py b/vmware_nsx/plugins/nsx_v/drivers/distributed_router_driver.py index 3023b5afe6..36a94767f9 100644 --- a/vmware_nsx/plugins/nsx_v/drivers/distributed_router_driver.py +++ b/vmware_nsx/plugins/nsx_v/drivers/distributed_router_driver.py @@ -26,8 +26,6 @@ from vmware_nsx.db import nsxv_db from vmware_nsx.plugins.nsx_v.drivers import ( abstract_router_driver as router_driver) from vmware_nsx.plugins.nsx_v import plugin as nsx_v -from vmware_nsx.plugins.nsx_v.vshield.common import ( - constants as vcns_const) from vmware_nsx.plugins.nsx_v.vshield import edge_utils LOG = logging.getLogger(__name__) @@ -52,8 +50,7 @@ class RouterDistributedDriver(router_driver.RouterBaseDriver): for subnet in subnets: routes.append({ 'destination': subnet, - 'nexthop': (vcns_const.INTEGRATION_LR_IPADDRESS. - split('/')[0]), + 'nexthop': (edge_utils.get_vdr_transit_network_tlr_address()), 'network_id': lswitch_id }) @@ -67,7 +64,7 @@ class RouterDistributedDriver(router_driver.RouterBaseDriver): def _update_routes_on_tlr( self, context, router_id, - newnexthop=vcns_const.INTEGRATION_EDGE_IPADDRESS, + newnexthop=edge_utils.get_vdr_transit_network_plr_address(), metadata_gateway=None): routes = [] diff --git a/vmware_nsx/plugins/nsx_v/plugin.py b/vmware_nsx/plugins/nsx_v/plugin.py index b762f21f4b..0e158dd6fb 100644 --- a/vmware_nsx/plugins/nsx_v/plugin.py +++ b/vmware_nsx/plugins/nsx_v/plugin.py @@ -1840,22 +1840,14 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin, For the V plugin we have a limitation that we should not use some reserved ranges like: 169.254.128.0/17 and 169.254.1.0/24 """ - reserved_subnets = nsxv_constants.RESERVED_IPS - # translate the given subnet to a range object data = subnet['subnet'] if data['cidr'] not in (constants.ATTR_NOT_SPECIFIED, None): - range = netaddr.IPNetwork(data['cidr']) - - # Check each reserved subnet for intersection - for reserved_subnet in reserved_subnets: - # translate the reserved subnet to a range object - reserved_range = netaddr.IPNetwork(reserved_subnet) - # check if new subnet overlaps this reserved subnet - if (range.first <= reserved_range.last - and reserved_range.first <= range.last): - return True + reserved_subnets = list(nsxv_constants.RESERVED_IPS) + reserved_subnets.append(cfg.CONF.nsxv.vdr_transit_network) + return edge_utils.is_overlapping_reserved_subnets(data['cidr'], + reserved_subnets) return False @@ -3551,6 +3543,9 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin, error = _("Configured %s not found") % field raise nsx_exc.NsxPluginException(err_msg=error) + if cfg.CONF.nsxv.vdr_transit_network: + edge_utils.validate_vdr_transit_network() + def _handle_qos_notification(self, qos_policys, event_type): qos_utils.handle_qos_notification(qos_policys, event_type, self._dvs) diff --git a/vmware_nsx/plugins/nsx_v/vshield/common/constants.py b/vmware_nsx/plugins/nsx_v/vshield/common/constants.py index 79be131603..faf2927c73 100644 --- a/vmware_nsx/plugins/nsx_v/vshield/common/constants.py +++ b/vmware_nsx/plugins/nsx_v/vshield/common/constants.py @@ -40,10 +40,6 @@ MAX_TUNNEL_NUM = (cfg.CONF.nsxv.maximum_tunnels_per_vnic if cfg.CONF.nsxv.maximum_tunnels_per_vnic > 0) else 10) -INTEGRATION_LR_IPADDRESS = "169.254.2.1/28" -INTEGRATION_EDGE_IPADDRESS = "169.254.2.3" -INTEGRATION_SUBNET_NETMASK = "255.255.255.240" - # SNAT rule location PREPEND = 0 APPEND = -1 diff --git a/vmware_nsx/plugins/nsx_v/vshield/edge_appliance_driver.py b/vmware_nsx/plugins/nsx_v/vshield/edge_appliance_driver.py index 6b0cc73d72..460939284d 100644 --- a/vmware_nsx/plugins/nsx_v/vshield/edge_appliance_driver.py +++ b/vmware_nsx/plugins/nsx_v/vshield/edge_appliance_driver.py @@ -383,8 +383,8 @@ class EdgeApplianceDriver(object): vnic_inside = self._assemble_edge_vnic( constants.INTERNAL_VNIC_NAME, constants.INTERNAL_VNIC_INDEX, internal_network, - constants.INTEGRATION_EDGE_IPADDRESS, - constants.INTEGRATION_SUBNET_NETMASK, + edge_utils.get_vdr_transit_network_plr_address(), + edge_utils.get_vdr_transit_network_netmask(), type="internal") edge['vnics']['vnics'].append(vnic_inside) @@ -457,8 +457,8 @@ class EdgeApplianceDriver(object): internal_vnic = self._assemble_edge_vnic( constants.INTERNAL_VNIC_NAME, constants.INTERNAL_VNIC_INDEX, internal_network, - constants.INTEGRATION_EDGE_IPADDRESS, - constants.INTEGRATION_SUBNET_NETMASK, + edge_utils.get_vdr_transit_network_plr_address(), + edge_utils.get_vdr_transit_network_netmask(), type="internal") edge['vnics']['vnics'].append(internal_vnic) if not dist and loadbalancer_enable: diff --git a/vmware_nsx/plugins/nsx_v/vshield/edge_utils.py b/vmware_nsx/plugins/nsx_v/vshield/edge_utils.py index 6dfc623450..57f645fe34 100644 --- a/vmware_nsx/plugins/nsx_v/vshield/edge_utils.py +++ b/vmware_nsx/plugins/nsx_v/vshield/edge_utils.py @@ -56,6 +56,59 @@ LOG = logging.getLogger(__name__) _uuid = uuidutils.generate_uuid +def _get_vdr_transit_network_ipobj(): + transit_net = cfg.CONF.nsxv.vdr_transit_network + return netaddr.IPNetwork(transit_net) + + +def get_vdr_transit_network_netmask(): + ip = _get_vdr_transit_network_ipobj() + return str(ip.netmask) + + +def get_vdr_transit_network_tlr_address(): + ip = _get_vdr_transit_network_ipobj() + return str(ip[1]) + + +def get_vdr_transit_network_plr_address(): + ip = _get_vdr_transit_network_ipobj() + return str(ip[2]) + + +def validate_vdr_transit_network(): + try: + ip = _get_vdr_transit_network_ipobj() + except Exception: + raise n_exc.Invalid(_("Invalid VDR transit network")) + if len(ip) < 4: + raise n_exc.Invalid(_("VDR transit address range too small")) + + if is_overlapping_reserved_subnets(cfg.CONF.nsxv.vdr_transit_network, + nsxv_constants.RESERVED_IPS): + raise n_exc.Invalid(_("VDR transit network overlaps reserved subnet")) + + +def is_overlapping_reserved_subnets(cidr, reserved_subnets): + """Return True if the subnet overlaps with reserved subnets. + + For the V plugin we have a limitation that we should not use + some reserved ranges like: 169.254.128.0/17 and 169.254.1.0/24 + """ + range = netaddr.IPNetwork(cidr) + + # Check each reserved subnet for intersection + for reserved_subnet in reserved_subnets: + # translate the reserved subnet to a range object + reserved_range = netaddr.IPNetwork(reserved_subnet) + # check if new subnet overlaps this reserved subnet + if (range.first <= reserved_range.last + and reserved_range.first <= range.last): + return True + + return False + + def parse_backup_edge_pool_opt(): """Parse edge pool opts and returns result.""" edge_pool_opts = cfg.CONF.nsxv.backup_edge_pool @@ -1523,8 +1576,8 @@ class EdgeManager(object): # add vdr's external interface to the lswitch tlr_vnic_index = self.nsxv_manager.add_vdr_internal_interface( tlr_edge_id, lswitch_id, - address=vcns_const.INTEGRATION_LR_IPADDRESS.split('/')[0], - netmask=vcns_const.INTEGRATION_SUBNET_NETMASK, + address=get_vdr_transit_network_tlr_address(), + netmask=get_vdr_transit_network_netmask(), type="uplink") nsxv_db.create_edge_vnic_binding( context.session, tlr_edge_id, tlr_vnic_index, lswitch_id) @@ -1548,8 +1601,8 @@ class EdgeManager(object): #TODO(berlin): the internal ip should change based on vnic_index self.nsxv_manager.update_interface( plr_router['id'], plr_edge_id, plr_vnic_index, lswitch_id, - address=vcns_const.INTEGRATION_EDGE_IPADDRESS, - netmask=vcns_const.INTEGRATION_SUBNET_NETMASK) + address=get_vdr_transit_network_plr_address(), + netmask=get_vdr_transit_network_netmask()) return plr_router['id'] def delete_plr_by_tlr_id(self, context, plr_id, router_id): diff --git a/vmware_nsx/tests/unit/nsx_v/vshield/test_edge_utils.py b/vmware_nsx/tests/unit/nsx_v/vshield/test_edge_utils.py index 29d0f68b26..27c9106817 100644 --- a/vmware_nsx/tests/unit/nsx_v/vshield/test_edge_utils.py +++ b/vmware_nsx/tests/unit/nsx_v/vshield/test_edge_utils.py @@ -773,3 +773,72 @@ class EdgeManagerTestCase(EdgeUtilsTestCaseMixin): availability_zone=self.az) self.edge_manager._free_edge_appliance( self.ctx, 'fake_id') + + +class VdrTransitNetUtilDefaultTestCase(EdgeUtilsTestCaseMixin): + EXPECTED_NETMASK = '255.255.255.240' + EXPECTED_TLR_IP = '169.254.2.1' + EXPECTED_PLR_IP = '169.254.2.2' + + def setUp(self): + super(VdrTransitNetUtilDefaultTestCase, self).setUp() + + def test_get_vdr_transit_network_netmask(self): + self.assertEqual(edge_utils.get_vdr_transit_network_netmask(), + self.EXPECTED_NETMASK) + + def test_get_vdr_transit_network_tlr_address(self): + self.assertEqual(edge_utils.get_vdr_transit_network_tlr_address(), + self.EXPECTED_TLR_IP) + + def test_get_vdr_transit_network_plr_address(self): + self.assertEqual(edge_utils.get_vdr_transit_network_plr_address(), + self.EXPECTED_PLR_IP) + + def test_is_overlapping_reserved_subnets(self): + self.assertTrue( + edge_utils.is_overlapping_reserved_subnets('169.254.1.0/24', + ['169.254.0.0/16'])) + self.assertTrue( + edge_utils.is_overlapping_reserved_subnets('169.254.1.0/24', + ['192.168.2.0/24', + '169.254.0.0/16'])) + self.assertFalse( + edge_utils.is_overlapping_reserved_subnets('169.254.1.0/24', + ['169.253.0.0/16'])) + self.assertFalse( + edge_utils.is_overlapping_reserved_subnets('169.254.1.0/24', + ['192.168.2.0/24', + '169.253.0.0/16'])) + + +class VdrTransitNetUtilTestCase(EdgeUtilsTestCaseMixin): + EXPECTED_NETMASK = '255.255.255.0' + EXPECTED_TLR_IP = '192.168.1.1' + EXPECTED_PLR_IP = '192.168.1.2' + + def setUp(self): + super(VdrTransitNetUtilTestCase, self).setUp() + + +class VdrTransitNetValidatorTestCase(EdgeUtilsTestCaseMixin): + def setUp(self): + super(VdrTransitNetValidatorTestCase, self).setUp() + + def _test_validator(self, cidr): + cfg.CONF.set_override('vdr_transit_network', cidr, 'nsxv') + return edge_utils.validate_vdr_transit_network() + + def test_vdr_transit_net_validator_success(self): + self.assertIsNone(self._test_validator('192.168.253.0/24')) + + def test_vdr_transit_net_validator_junk_cidr(self): + self.assertRaises(n_exc.Invalid, self._test_validator, 'not_a_subnet') + + def test_vdr_transit_net_validator_too_small_cidr(self): + self.assertRaises( + n_exc.Invalid, self._test_validator, '169.254.2.0/31') + + def test_vdr_transit_net_validator_overlap_cidr(self): + self.assertRaises( + n_exc.Invalid, self._test_validator, '169.254.0.0/16')