def test_create_update_subnet_hostroute(self): host_routes = [{'destination': '135.207.0.0/16', 'nexthop': '1.2.3.4'}] network, lswitch = self._test_create_network_revision() self.nb_api.update.reset_mock() self.nb_api.get.side_effect = nb_api_get_func(lswitch) with self.subnet(network={'network': network}, host_routes=host_routes, set_context=True) as subnet: self.nb_api.update.assert_called_once() lswitch = self.nb_api.update.call_args_list[0][0][0] self.assertIsInstance(lswitch, l2.LogicalSwitch) self.nb_api.get.side_effect = nb_api_get_func(lswitch) self.nb_api.update.reset_mock() df_subnet = lswitch.find_subnet(subnet['subnet']['id']) self.assertEqual( [host_route.HostRoute(**hr) for hr in host_routes], df_subnet.host_routes) data = {'subnet': {'host_routes': None}} req = self.new_update_request('subnets', data, subnet['subnet']['id']) req.get_response(self.api) self.nb_api.update.assert_called_once() lswitch = self.nb_api.update.call_args_list[0][0][0] df_subnet = lswitch.find_subnet(subnet['subnet']['id']) self.assertEqual([], df_subnet.host_routes)
def test_create_update_subnet_hostroute(self): host_routes = [{'destination': '135.207.0.0/16', 'nexthop': '1.2.3.4'}] network, lswitch = self._test_create_network_revision() self.nb_api.create.reset_mock() self.nb_api.update.reset_mock() self.nb_api.get.side_effect = nb_api_get_func(lswitch) with self.subnet(network={'network': network}, host_routes=host_routes, set_context=True) as n_subnet: # Create Subnet, create DHCP port self.assertEqual(2, self.nb_api.create.call_count) self.nb_api.update.assert_called_once() lswitch = self.nb_api.update.call_args_list[0][0][0] self.assertIsInstance(lswitch, l2.LogicalSwitch) dhcp_lport = self.nb_api.create.call_args_list[0][0][0] self.assertIsInstance(dhcp_lport, l2.LogicalPort) subnet = self.nb_api.create.call_args_list[1][0][0] self.assertIsInstance(subnet, l2.Subnet) self.nb_api.get.side_effect = nb_api_get_func(subnet) self.nb_api.update.reset_mock() self.assertEqual( [host_route.HostRoute(**hr) for hr in host_routes], subnet.host_routes) data = {'subnet': {'host_routes': None}} req = self.new_update_request('subnets', data, n_subnet['subnet']['id']) req.get_response(self.api) # Update subnet, update lswitch's version self.assertEqual(2, self.nb_api.update.call_count) subnet = self.nb_api.update.call_args_list[0][0][0] self.assertIsInstance(subnet, l2.Subnet) self.assertEqual([], subnet.host_routes)
def _get_host_routes_list_bin(self, subnet, lport): host_routes = copy.copy(subnet.host_routes) if self.conf.df_add_link_local_route: # Add route for metadata request. host_routes.append(host_route.HostRoute( destination='%s/32' % const.METADATA_SERVICE_IP, nexthop=lport.ip)) routes_bin = b'' opt = lport.dhcp_params.opts.get(dhcp.DHCP_CLASSLESS_ROUTE_OPT) if opt: dest_cidr, _c, via = opt.partition(',') host_routes.append( host_route.HostRoute(destination=dest_cidr, nexthop=via)) # We must add the default route here. if a host supports classless # route options, it must ignore the router option gateway = self._get_port_gateway_address(subnet, lport) if gateway is not None: host_routes.append( host_route.HostRoute( destination='0.0.0.0/0', nexthop=gateway, ), ) for route in host_routes: dest = route.destination.network mask = route.destination.prefixlen routes_bin += struct.pack('B', mask) """ for compact encoding Width of subnet mask Number of significant octets 0 0 1- 8 1 9-16 2 17-24 3 25-32 4 """ addr_bin = addrconv.ipv4.text_to_bin(dest) dest_len = int(math.ceil(mask / 8.0)) routes_bin += addr_bin[:dest_len] routes_bin += addrconv.ipv4.text_to_bin(route.nexthop) return routes_bin
def test_add_del_lport_after_router_route(self): # add route routes = [host_route.HostRoute(destination="10.100.0.0/16", nexthop="10.0.0.6"), host_route.HostRoute(destination="10.101.0.0/16", nexthop="10.0.0.6")] # Use another object here to differentiate the one in cache router_with_route = copy.deepcopy(self.router) router_with_route.routes = routes router_with_route.version += 1 self.controller.update(router_with_route) # No lport no flow for route self.assertFalse(self.app.mod_flow.called) self.controller.update(test_app_base.fake_local_port1) # 2 routes, 2 mod_flow and 1 mod_flow for add lport proactive route self.assertEqual(3, self.app.mod_flow.call_count) self.app.mod_flow.reset_mock() self.controller.delete(test_app_base.fake_local_port1) # 2 routes, 2 mod_flow and 1 mod_flow for del lport proactive route self.assertEqual(3, self.app.mod_flow.call_count)
def _get_host_routes_list_bin(self, subnet, lport): host_routes = copy.copy(subnet.host_routes) if self.conf.df_add_link_local_route: # Add route for metadata request. host_routes.append( host_route.HostRoute(destination='%s/32' % const.METADATA_SERVICE_IP, nexthop=lport.ip)) routes_bin = b'' dhcp_opts = lport.extra_dhcp_options for opt in dhcp_opts: if opt.tag == DHCP_CLASSLESS_ROUTE_OPT: dest_cidr, _c, via = opt.value.partition(',') host_routes.append( host_route.HostRoute(destination=dest_cidr, nexthop=via)) for route in host_routes: dest = route.destination.network mask = route.destination.prefixlen routes_bin += struct.pack('B', mask) """ for compact encoding Width of subnet mask Number of significant octets 0 0 1- 8 1 9-16 2 17-24 3 25-32 4 """ addr_bin = addrconv.ipv4.text_to_bin(dest) dest_len = int(math.ceil(mask / 8.0)) routes_bin += addr_bin[:dest_len] routes_bin += addrconv.ipv4.text_to_bin(route.nexthop) return routes_bin
def _reprocess_to_add_route(self, lport): """Add extra routes for lport. @param lport: The lport related to extra routes. """ LOG.debug("Reprocess to add extra routes that use lport %s " "as nexthop", lport) lswitch_id = lport.lswitch.id port_ip = lport.ip router, router_if = self._get_router_by_lswitch_and_port_ip( lswitch_id, port_ip) if not router: LOG.debug("No router for lport %s, skip adding extra route", lport) return router_id = router.id cached_routes = self.route_cache.get(router_id) if not cached_routes or not cached_routes.get(ROUTE_TO_ADD): LOG.debug("No extra routes need to be processed for logical " "router %s", router) return # Make a copy here, or else _change_route_cache_status will delete # elements in routes inside the iteration. routes = copy.deepcopy(cached_routes.get(ROUTE_TO_ADD)) for route in routes: if str(port_ip) != route[1]: continue route = host_route.HostRoute(destination=route[0], nexthop=route[1]) self._add_extra_route_to_router(router.unique_key, router_if.mac, lport.unique_key, lport.mac, route) self._change_route_cache_status(router_id, from_part=ROUTE_TO_ADD, to_part=ROUTE_ADDED, route=route)
def test_add_remove_bgp_network(self): bgp_speaker = objects.BGPSpeakerTestObj(self.neutron, self.nb_api) self.addCleanup(bgp_speaker.close) bgp_speaker.create() address_scope = objects.AddressScopeTestObj(self.neutron, self.nb_api) self.addCleanup(address_scope.close) as_id = address_scope.create() private_subnetpool = objects.SubnetPoolTestObj(self.neutron, self.nb_api) self.addCleanup(private_subnetpool.close) private_sp_id = private_subnetpool.create( subnetpool={ 'name': "private_sp", 'default_prefixlen': 24, 'prefixes': ["20.0.0.0/8"], 'address_scope_id': as_id }) public_subnetpool = objects.SubnetPoolTestObj(self.neutron, self.nb_api) self.addCleanup(public_subnetpool.close) public_sp_id = public_subnetpool.create( subnetpool={ 'name': "public_sp", 'default_prefixlen': 24, 'prefixes': ["172.24.4.0/24"], 'address_scope_id': as_id }) public_network = objects.NetworkTestObj(self.neutron, self.nb_api) self.addCleanup(public_network.close) public_network_id = public_network.create(network={ 'name': 'public', 'router:external': True }) public_subnet = objects.SubnetTestObj(self.neutron, self.nb_api, public_network_id) self.addCleanup(public_subnet.close) public_subnet.create( subnet={ 'ip_version': 4, 'network_id': public_network_id, 'subnetpool_id': public_sp_id }) private_network = objects.NetworkTestObj(self.neutron, self.nb_api) self.addCleanup(private_network.close) private_network_id = private_network.create(network={'name': "public"}) private_subnet = objects.SubnetTestObj(self.neutron, self.nb_api, private_network_id) self.addCleanup(private_subnet.close) private_sn_id = private_subnet.create( subnet={ 'ip_version': 4, 'network_id': private_network_id, 'subnetpool_id': private_sp_id }) bgp_speaker.add_network(public_network_id) router = objects.RouterTestObj(self.neutron, self.nb_api) self.addCleanup(router.close) router_id = router.create() self.neutron.add_interface_router(router_id, body={'subnet_id': private_sn_id}) self.neutron.add_gateway_router(router_id, body={'network_id': public_network_id}) # Finnally, verify the route has been set in nb db. nb_bgp_speaker = bgp_speaker.get_nb_bgp_speaker() self.assertEqual(1, len(nb_bgp_speaker.prefix_routes)) vm = objects.VMTestObj(self, self.neutron) self.addCleanup(vm.close) vm_id = vm.create(network=private_network) vm_port = self.neutron.list_ports(device_id=vm_id).get('ports')[0] vm_port_id = vm_port.get('id') fip = objects.FloatingipTestObj(self.neutron, self.nb_api) self.addCleanup(fip.close) fip.create({ 'floating_network_id': public_network_id, 'port_id': vm_port_id }) fip_addr = fip.get_floatingip().floating_ip_address nb_bgp_speaker = bgp_speaker.get_nb_bgp_speaker() self.assertEqual(1, len(nb_bgp_speaker.host_routes)) self.assertIn( host_route.HostRoute(destination=netaddr.IPNetwork(fip_addr), nexthop='172.24.4.100'), nb_bgp_speaker.host_routes) fip.update({'port_id': None}) nb_bgp_speaker = bgp_speaker.get_nb_bgp_speaker() self.assertFalse(nb_bgp_speaker.host_routes) bgp_speaker.remove_network(public_network_id) nb_bgp_speaker = bgp_speaker.get_nb_bgp_speaker() self.assertFalse(nb_bgp_speaker.prefix_routes)