class TestDscpMarkingQoSOvs(_TestDscpMarkingQoS, base.BaseFullStackTestCase): scenarios = fullstack_utils.get_ovs_interface_scenarios() l2_agent_type = constants.AGENT_TYPE_OVS def _wait_for_dscp_marking_rule_applied(self, vm, dscp_mark): l2_extensions.wait_until_dscp_marking_rule_applied_ovs( vm.bridge, vm.port.name, dscp_mark)
class TestMinBwQoSOvs(_TestMinBwQoS, base.BaseFullStackTestCase): l2_agent_type = constants.AGENT_TYPE_OVS direction_scenarios = [('egress', { 'direction': constants.EGRESS_DIRECTION })] scenarios = testscenarios.multiply_scenarios( direction_scenarios, fullstack_utils.get_ovs_interface_scenarios()) def _wait_for_min_bw_rule_applied(self, vm, min_bw, direction): if direction == constants.EGRESS_DIRECTION: utils.wait_until_true(lambda: vm.bridge.get_egress_min_bw_for_port( vm.neutron_port['id']) == min_bw) elif direction == constants.INGRESS_DIRECTION: self.fail('"%s" direction not implemented' % constants.INGRESS_DIRECTION) def test_bw_limit_qos_port_removed(self): """Test if rate limit config is properly removed when whole port is removed. """ # Create port with qos policy attached vm, qos_policy = self._prepare_vm_with_qos_policy([ functools.partial(self._add_min_bw_rule, MIN_BANDWIDTH, self.direction) ]) self._wait_for_min_bw_rule_applied(vm, MIN_BANDWIDTH, self.direction) # Delete port with qos policy attached vm.destroy() self._wait_for_min_bw_rule_removed(vm, self.direction) self.assertIsNone(vm.bridge.find_qos(vm.port.name)) self.assertIsNone( vm.bridge.find_queue(vm.port.name, ovs_lib.QOS_DEFAULT_QUEUE))
class TestBwLimitQoSOvs(_TestBwLimitQoS, base.BaseFullStackTestCase): l2_agent_type = constants.AGENT_TYPE_OVS scenarios = fullstack_utils.get_ovs_interface_scenarios() def _wait_for_bw_rule_applied(self, vm, limit, burst): utils.wait_until_true(lambda: vm.bridge.get_egress_bw_limit_for_port( vm.port.name) == (limit, burst))
class TestUninterruptedConnectivityOnL2AgentRestart( BaseConnectivitySameNetworkTest): num_hosts = 2 ovs_agent_scenario = [('OVS', {'l2_agent_type': constants.AGENT_TYPE_OVS})] lb_agent_scenario = [('LB', { 'l2_agent_type': constants.AGENT_TYPE_LINUXBRIDGE })] network_scenarios = [ ('Flat network', { 'network_type': 'flat', 'l2_pop': False }), ('VLANs', { 'network_type': 'vlan', 'l2_pop': False }), ('VXLAN', { 'network_type': 'vxlan', 'l2_pop': False }), ] scenarios = ( testscenarios.multiply_scenarios(ovs_agent_scenario, network_scenarios, utils.get_ovs_interface_scenarios()) + testscenarios.multiply_scenarios(lb_agent_scenario, network_scenarios)) def test_l2_agent_restart(self, agent_restart_timeout=20): # Environment preparation is effectively the same as connectivity test vms = self._prepare_vms_in_single_network() vms.ping_all() ns0 = vms[0].namespace ip1 = vms[1].ip agents = [host.l2_agent for host in self.environment.hosts] # Restart agents on all nodes simultaneously while pinging across # the hosts. The ping has to cross int and phys bridges and travels # via central bridge as the vms are on separate hosts. with net_helpers.async_ping(ns0, [ip1], timeout=2, count=agent_restart_timeout) as done: LOG.debug("Restarting agents") executor = futures.ThreadPoolExecutor(max_workers=len(agents)) restarts = [agent.restart(executor=executor) for agent in agents] futures.wait(restarts, timeout=agent_restart_timeout) self.assertTrue(all([r.done() for r in restarts])) LOG.debug("Restarting agents - done") # It is necessary to give agents time to initialize # because some crucial steps (e.g. setting up bridge flows) # happen only after RPC is established common_utils.wait_until_true( done, exception=RuntimeError("Could not ping the other VM, L2 agent " "restart leads to network disruption"))
class TestBwLimitQoSOvs(_TestBwLimitQoS, base.BaseFullStackTestCase): l2_agent_type = constants.AGENT_TYPE_OVS direction_scenarios = [('ingress', { 'direction': constants.INGRESS_DIRECTION }), ('egress', { 'direction': constants.EGRESS_DIRECTION })] scenarios = testscenarios.multiply_scenarios( direction_scenarios, fullstack_utils.get_ovs_interface_scenarios()) @staticmethod def _get_expected_burst_value(limit, direction): # For egress bandwidth limit this value should be calculated as # bandwidth_limit * qos_consts.DEFAULT_BURST_RATE if direction == constants.EGRESS_DIRECTION: return TestBwLimitQoSOvs._get_expected_egress_burst_value(limit) else: return 0 def _wait_for_bw_rule_applied(self, vm, limit, burst, direction): if direction == constants.EGRESS_DIRECTION: utils.wait_until_true( lambda: vm.bridge.get_egress_bw_limit_for_port(vm.port.name) == (limit, burst)) elif direction == constants.INGRESS_DIRECTION: utils.wait_until_true( lambda: vm.bridge.get_ingress_bw_limit_for_port( vm.port.name) == (limit, burst))
class TestOvsConnectivitySameNetworkOnOvsBridgeControllerStop( BaseConnectivitySameNetworkTest): num_hosts = 2 l2_agent_type = constants.AGENT_TYPE_OVS network_scenarios = [('VXLAN', { 'network_type': 'vxlan', 'l2_pop': False }), ('GRE and l2pop', { 'network_type': 'gre', 'l2_pop': True }), ('VLANs', { 'network_type': 'vlan', 'l2_pop': False })] # Do not test for CLI ofctl interface as controller is irrelevant for CLI scenarios = testscenarios.multiply_scenarios( network_scenarios, [(m, v) for (m, v) in utils.get_ovs_interface_scenarios() if v['of_interface'] != 'ovs-ofctl']) def _test_controller_timeout_does_not_break_connectivity( self, kill_signal=None): # Environment preparation is effectively the same as connectivity test vms = self._prepare_vms_in_single_network() vms.ping_all() ns0 = vms[0].namespace ip1 = vms[1].ip LOG.debug("Stopping agents (hence also OVS bridge controllers)") for host in self.environment.hosts: if kill_signal is not None: host.l2_agent.stop(kill_signal=kill_signal) else: host.l2_agent.stop() # Ping to make sure that 3 x 5 seconds is overcame even under a high # load. The time was chosen to match three times inactivity_probe time, # which is the time after which the OVS vswitchd # treats the controller as dead and starts managing the bridge # by itself when the fail type settings is not set to secure (see # ovs-vsctl man page for further details) with net_helpers.async_ping(ns0, [ip1], timeout=2, count=25) as done: common_utils.wait_until_true(done, exception=RuntimeError( "Networking interrupted after " "controllers have vanished")) def test_controller_timeout_does_not_break_connectivity_sigterm(self): self._test_controller_timeout_does_not_break_connectivity() def test_controller_timeout_does_not_break_connectivity_sigkill(self): self._test_controller_timeout_does_not_break_connectivity( signal.SIGKILL)
class TestDscpMarkingQoSOvs(BaseQoSRuleTestCase, base.BaseFullStackTestCase): scenarios = fullstack_utils.get_ovs_interface_scenarios() l2_agent_type = constants.AGENT_TYPE_OVS def _wait_for_dscp_marking_rule_applied(self, vm, dscp_mark): l2_extensions.wait_until_dscp_marking_rule_applied( vm.bridge, vm.port.name, dscp_mark) def _wait_for_dscp_marking_rule_removed(self, vm): self._wait_for_dscp_marking_rule_applied(vm, None) def _add_dscp_rule(self, dscp_mark, qos_policy): qos_policy_id = qos_policy['id'] rule = self.safe_client.create_dscp_marking_rule( self.tenant_id, qos_policy_id, dscp_mark) # Make it consistent with GET reply rule['type'] = qos_consts.RULE_TYPE_DSCP_MARKING rule['qos_policy_id'] = qos_policy_id qos_policy['rules'].append(rule) def test_dscp_qos_policy_rule_lifecycle(self): new_dscp_mark = DSCP_MARK + 8 # Create port with qos policy attached vm, qos_policy = self._prepare_vm_with_qos_policy( [functools.partial(self._add_dscp_rule, DSCP_MARK)]) dscp_rule = qos_policy['rules'][0] self._wait_for_dscp_marking_rule_applied(vm, DSCP_MARK) qos_policy_id = qos_policy['id'] self.client.delete_dscp_marking_rule(dscp_rule['id'], qos_policy_id) self._wait_for_dscp_marking_rule_removed(vm) # Create new rule new_rule = self.safe_client.create_dscp_marking_rule( self.tenant_id, qos_policy_id, new_dscp_mark) self._wait_for_dscp_marking_rule_applied(vm, new_dscp_mark) # Update qos policy rule id self.client.update_dscp_marking_rule( new_rule['id'], qos_policy_id, body={'dscp_marking_rule': { 'dscp_mark': DSCP_MARK }}) self._wait_for_dscp_marking_rule_applied(vm, DSCP_MARK) # Remove qos policy from port self.client.update_port(vm.neutron_port['id'], body={'port': { 'qos_policy_id': None }}) self._wait_for_dscp_marking_rule_removed(vm)
class TestMinBwQoSOvs(_TestMinBwQoS, base.BaseFullStackTestCase): l2_agent_type = constants.AGENT_TYPE_OVS direction_scenarios = [('egress', { 'direction': constants.EGRESS_DIRECTION })] scenarios = testscenarios.multiply_scenarios( direction_scenarios, fullstack_utils.get_ovs_interface_scenarios()) def _wait_for_min_bw_rule_applied(self, vm, min_bw, direction): if direction == constants.EGRESS_DIRECTION: utils.wait_until_true(lambda: vm.bridge.get_egress_min_bw_for_port( vm.neutron_port['id']) == min_bw) elif direction == constants.INGRESS_DIRECTION: self.fail('"%s" direction not implemented' % constants.INGRESS_DIRECTION) def _find_agent_qos_and_queue(self, vm): # NOTE(ralonsoh): the "_min_bw_qos_id" in vm.bridge is not the same as # the ID in the agent br_int instance. We need first to find the QoS # register and the Queue assigned to vm.neutron_port['id'] queue = vm.bridge._find_queue(vm.neutron_port['id']) queue_num = int(queue['external_ids']['queue-num']) qoses = vm.bridge._list_qos() for qos in qoses: qos_queue = qos['queues'].get(queue_num) if qos_queue and qos_queue.uuid == queue['_uuid']: return qos, qos_queue self.fail('QoS register not found with queue-num %s' % queue_num) def test_min_bw_qos_port_removed(self): """Test if min BW limit config is properly removed when port removed""" # Create port with qos policy attached vm, qos_policy = self._prepare_vm_with_qos_policy([ functools.partial(self._add_min_bw_rule, MIN_BANDWIDTH, self.direction) ]) self._wait_for_min_bw_rule_applied(vm, MIN_BANDWIDTH, self.direction) qos, queue = self._find_agent_qos_and_queue(vm) self.assertEqual({'min-rate': str(MIN_BANDWIDTH * 1000)}, queue.other_config) queues = vm.bridge._list_queues(port=vm.neutron_port['id']) self.assertEqual(1, len(queues)) self.assertEqual(queue.uuid, queues[0]['_uuid']) # Delete port with qos policy attached vm.destroy() self._wait_for_min_bw_rule_removed(vm, self.direction) self.assertEqual([], vm.bridge._list_queues(port=vm.neutron_port['id']))
class TestBwLimitQoSOvs(_TestBwLimitQoS, base.BaseFullStackTestCase): l2_agent_type = constants.AGENT_TYPE_OVS direction_scenarios = [('ingress', { 'direction': constants.INGRESS_DIRECTION }), ('egress', { 'direction': constants.EGRESS_DIRECTION })] scenarios = testscenarios.multiply_scenarios( direction_scenarios, fullstack_utils.get_ovs_interface_scenarios()) @staticmethod def _get_expected_burst_value(limit, direction): # For egress bandwidth limit this value should be calculated as # bandwidth_limit * qos_consts.DEFAULT_BURST_RATE if direction == constants.EGRESS_DIRECTION: return TestBwLimitQoSOvs._get_expected_egress_burst_value(limit) else: return 0 def _wait_for_bw_rule_applied(self, vm, limit, burst, direction): if direction == constants.EGRESS_DIRECTION: utils.wait_until_true( lambda: vm.bridge.get_egress_bw_limit_for_port(vm.port.name) == (limit, burst)) elif direction == constants.INGRESS_DIRECTION: utils.wait_until_true( lambda: vm.bridge.get_ingress_bw_limit_for_port( vm.port.name) == (limit, burst)) @tests_base.unstable_test("bug 1737892") def test_bw_limit_qos_port_removed(self): """Test if rate limit config is properly removed when whole port is removed. """ # Create port with qos policy attached vm, qos_policy = self._prepare_vm_with_qos_policy([ functools.partial(self._add_bw_limit_rule, BANDWIDTH_LIMIT, BANDWIDTH_BURST, self.direction) ]) self._wait_for_bw_rule_applied(vm, BANDWIDTH_LIMIT, BANDWIDTH_BURST, self.direction) # Delete port with qos policy attached vm.destroy() self._wait_for_bw_rule_removed(vm, self.direction) self.assertIsNone(vm.bridge.find_qos(vm.port.name)) self.assertIsNone( vm.bridge.find_queue(vm.port.name, ovs_lib.QOS_DEFAULT_QUEUE))
class TestOvsConnectivitySameNetwork(BaseConnectivitySameNetworkTest): l2_agent_type = constants.AGENT_TYPE_OVS network_scenarios = [ ('VXLAN', {'network_type': 'vxlan', 'l2_pop': False}), ('GRE-l2pop-arp_responder', {'network_type': 'gre', 'l2_pop': True, 'arp_responder': True}), ('VLANs', {'network_type': 'vlan', 'l2_pop': False})] scenarios = testscenarios.multiply_scenarios( network_scenarios, utils.get_ovs_interface_scenarios()) def test_connectivity(self): self._test_connectivity()
class TestUninterruptedConnectivityOnL2AgentRestart( BaseConnectivitySameNetworkTest): num_hosts = 2 ovs_agent_scenario = [('OVS', {'l2_agent_type': constants.AGENT_TYPE_OVS})] lb_agent_scenario = [('LB', { 'l2_agent_type': constants.AGENT_TYPE_LINUXBRIDGE })] network_scenarios = [ ('Flat network', { 'network_type': 'flat', 'l2_pop': False }), ('VLANs', { 'network_type': 'vlan', 'l2_pop': False }), ('VXLAN', { 'network_type': 'vxlan', 'l2_pop': False }), ] scenarios = ( testscenarios.multiply_scenarios(ovs_agent_scenario, network_scenarios, utils.get_ovs_interface_scenarios()) + testscenarios.multiply_scenarios(lb_agent_scenario, network_scenarios)) def test_l2_agent_restart(self, agent_restart_timeout=20): # Environment preparation is effectively the same as connectivity test vms = self._prepare_vms_in_single_network() vms.ping_all() ns0 = vms[0].namespace ip1 = vms[1].ip agents = [host.l2_agent for host in self.environment.hosts] # Restart agents on all nodes simultaneously while pinging across # the hosts. The ping has to cross int and phys bridges and travels # via central bridge as the vms are on separate hosts. self._assert_ping_during_agents_restart( agents, ns0, [ip1], restart_timeout=agent_restart_timeout, ping_timeout=2, count=agent_restart_timeout)
class TestBwLimitQoSOvs(_TestBwLimitQoS, base.BaseFullStackTestCase): l2_agent_type = constants.AGENT_TYPE_OVS direction_scenarios = [('ingress', { 'direction': common_constants.INGRESS_DIRECTION }), ('egress', { 'direction': common_constants.EGRESS_DIRECTION })] scenarios = testscenarios.multiply_scenarios( direction_scenarios, fullstack_utils.get_ovs_interface_scenarios()) def _wait_for_bw_rule_applied(self, vm, limit, burst, direction): if direction == common_constants.EGRESS_DIRECTION: utils.wait_until_true( lambda: vm.bridge.get_egress_bw_limit_for_port(vm.port.name) == (limit, burst)) elif direction == common_constants.INGRESS_DIRECTION: utils.wait_until_true( lambda: vm.bridge.get_ingress_bw_limit_for_port( vm.port.name) == (limit, burst)) def test_bw_limit_direction_change(self): # Create port with qos policy attached, with rule self.direction vm, qos_policy = self._prepare_vm_with_qos_policy([ functools.partial(self._add_bw_limit_rule, BANDWIDTH_LIMIT, BANDWIDTH_BURST, self.direction) ]) bw_rule = qos_policy['rules'][0] self._wait_for_bw_rule_applied(vm, BANDWIDTH_LIMIT, BANDWIDTH_BURST, self.direction) # Update rule by changing direction to opposite then it was before self.client.update_bandwidth_limit_rule(bw_rule['id'], qos_policy['id'], body={ 'bandwidth_limit_rule': { 'direction': self.reverse_direction } }) self._wait_for_bw_rule_removed(vm, self.direction) self._wait_for_bw_rule_applied(vm, BANDWIDTH_LIMIT, BANDWIDTH_BURST, self.reverse_direction)
class TestDscpMarkingQoSOvs(BaseQoSRuleTestCase, base.BaseFullStackTestCase): scenarios = fullstack_utils.get_ovs_interface_scenarios() l2_agent_type = constants.AGENT_TYPE_OVS def setUp(self): host_desc = [ environment.HostDescription(l3_agent=False, of_interface=self.of_interface, ovsdb_interface=self.ovsdb_interface, l2_agent_type=self.l2_agent_type) for _ in range(2) ] env_desc = environment.EnvironmentDescription(qos=True) env = environment.Environment(env_desc, host_desc) super(BaseQoSRuleTestCase, self).setUp(env) self.tenant_id = uuidutils.generate_uuid() self.network = self.safe_client.create_network(self.tenant_id, 'network-test') self.subnet = self.safe_client.create_subnet(self.tenant_id, self.network['id'], cidr='10.0.0.0/24', gateway_ip='10.0.0.1', name='subnet-test', enable_dhcp=False) def _wait_for_dscp_marking_rule_applied(self, vm, dscp_mark): l2_extensions.wait_until_dscp_marking_rule_applied( vm.bridge, vm.port.name, dscp_mark) def _wait_for_dscp_marking_rule_removed(self, vm): self._wait_for_dscp_marking_rule_applied(vm, None) def _add_dscp_rule(self, dscp_mark, qos_policy): qos_policy_id = qos_policy['id'] rule = self.safe_client.create_dscp_marking_rule( self.tenant_id, qos_policy_id, dscp_mark) # Make it consistent with GET reply rule['type'] = qos_consts.RULE_TYPE_DSCP_MARKING rule['qos_policy_id'] = qos_policy_id qos_policy['rules'].append(rule) def test_dscp_qos_policy_rule_lifecycle(self): new_dscp_mark = DSCP_MARK + 8 # Create port with qos policy attached vm, qos_policy = self._prepare_vm_with_qos_policy( [functools.partial(self._add_dscp_rule, DSCP_MARK)]) dscp_rule = qos_policy['rules'][0] self._wait_for_dscp_marking_rule_applied(vm, DSCP_MARK) qos_policy_id = qos_policy['id'] self.client.delete_dscp_marking_rule(dscp_rule['id'], qos_policy_id) self._wait_for_dscp_marking_rule_removed(vm) # Create new rule new_rule = self.safe_client.create_dscp_marking_rule( self.tenant_id, qos_policy_id, new_dscp_mark) self._wait_for_dscp_marking_rule_applied(vm, new_dscp_mark) # Update qos policy rule id self.client.update_dscp_marking_rule( new_rule['id'], qos_policy_id, body={'dscp_marking_rule': { 'dscp_mark': DSCP_MARK }}) self._wait_for_dscp_marking_rule_applied(vm, DSCP_MARK) # Remove qos policy from port self.client.update_port(vm.neutron_port['id'], body={'port': { 'qos_policy_id': None }}) self._wait_for_dscp_marking_rule_removed(vm) def test_dscp_marking_packets(self): # Create port (vm) which will be used to received and test packets receiver_port = self.safe_client.create_port( self.tenant_id, self.network['id'], self.environment.hosts[1].hostname) receiver = self.useFixture( machine.FakeFullstackMachine(self.environment.hosts[1], self.network['id'], self.tenant_id, self.safe_client, neutron_port=receiver_port)) # Create port with qos policy attached sender, qos_policy = self._prepare_vm_with_qos_policy( [functools.partial(self._add_dscp_rule, DSCP_MARK)]) sender.block_until_boot() receiver.block_until_boot() self._wait_for_dscp_marking_rule_applied(sender, DSCP_MARK) l2_extensions.wait_for_dscp_marked_packet(sender, receiver, DSCP_MARK)