def test_set_vnic_back_devs_max_capacity_invoked(self, mock_vioget): mock_sys = sys_wrapper(self.fake_sriovs) mock_vioget.return_value = [mock.Mock(uuid='vios_uuid1')] self.adpt.build_href.side_effect = lambda *a, **k: '%s' % a[1] vnic = card.VNIC.bld(self.adpt, pvid=5) self.assertEqual(0, len(vnic.back_devs)) tsriov.set_vnic_back_devs(vnic, ['pport_loc%d' % x for x in range(60)], sys_w=mock_sys, capacity=0.02, redundancy=1, max_capacity=0.75) # Ensure that the max and min capacities attached to back_devices as # expected self.assertEqual(0.02, vnic.back_devs[0].capacity) self.assertEqual(0.75, vnic.back_devs[0].max_capacity)
def plug(self, vif, slot_num, new_vif=True): if not new_vif: return None physnet = vif.get_physical_network() if not physnet: # Get physnet from neutron network if not present in vif # TODO(svenkat): This section of code will be eliminated in # pike release. Design will be in place to fix any vif # that has physical_network missing. The fix will be in # compute startup code. net_id = vif['network']['id'] admin_context = ctx.get_admin_context() napi = net_api.API() network = napi.get(admin_context, net_id) physnet = network.physical_network LOG.debug("Plugging vNIC SR-IOV vif for physical network %(physnet)s.", {'physnet': physnet}, instance=self.instance) # Get the msys msys = pvm_ms.System.get(self.adapter)[0] # Physical ports for the given port label pports_w = sriovtask.find_pports_for_portlabel(physnet, self.adapter, msys) pports = [pport.loc_code for pport in pports_w] if not pports: raise exception.VirtualInterfacePlugException( _("Unable to find acceptable Ethernet ports on physical " "network '%(physnet)s' for instance %(inst)s for SRIOV " "based VIF with MAC address %(vif_mac)s.") % { 'physnet': physnet, 'inst': self.instance.name, 'vif_mac': vif['address'] }) # MAC mac_address = pvm_util.sanitize_mac_for_api(vif['address']) # vlan id vlan_id = int(vif['details']['vlan']) # Redundancy: plugin sets from binding:profile, then conf, then default redundancy = int(vif['details']['redundancy']) # Capacity: plugin sets from binding:profile, then conf, then default capacity = vif['details']['capacity'] vnic = pvm_card.VNIC.bld(self.adapter, vlan_id, slot_num=slot_num, mac_addr=mac_address, allowed_vlans=pvm_util.VLANList.NONE, allowed_macs=pvm_util.MACList.NONE) sriovtask.set_vnic_back_devs(vnic, pports, sys_w=msys, redundancy=redundancy, capacity=capacity, check_port_status=True) return vnic.create(parent_type=pvm_lpar.LPAR, parent_uuid=vm.get_pvm_uuid(self.instance))
def test_set_vnic_back_devs(self, mock_shuffle, mock_vioget): """Test set_vnic_back_devs.""" mock_sys = sys_wrapper(self.fake_sriovs) mock_vioget.return_value = [ mock.Mock(uuid='vios_uuid1'), mock.Mock(uuid='vios_uuid2'), mock.Mock(uuid='vios_uuid3') ] self.adpt.build_href.side_effect = lambda *a, **k: '%s' % a[1] vnic = card.VNIC.bld(self.adpt, pvid=5) self.assertEqual(0, len(vnic.back_devs)) # Silly case: redundancy of zero tsriov.set_vnic_back_devs(vnic, [], sys_w=mock_sys, redundancy=0) self.assertEqual(0, len(vnic.back_devs)) mock_vioget.assert_called_once_with(self.adpt, None, 0) cap = 0.019 # Things to note about the following: # - VIOSes rotate. 1, 2, 3, repeat. If we hadn't mocked shuffle, the # base order would be random, but they would still rotate in whatever # that shuffled order was. # - The least-used (emptiest) physical ports come first... # - ...except (e.g. 21) we force distribution across cards, so... # - ...cards alternate until exhausted; hence 5 repeated at the end. # - Capacity set across the board according to the parameter. all_back_devs = [ ('vios_uuid1', 1, 12, cap), ('vios_uuid2', 5, 52, cap), ('vios_uuid3', 4, 42, cap), ('vios_uuid1', 2, 21, cap), ('vios_uuid2', 5, 54, cap), ('vios_uuid3', 4, 41, cap), ('vios_uuid1', 1, 13, cap), ('vios_uuid2', 5, 56, cap), ('vios_uuid3', 1, 11, cap), ('vios_uuid1', 5, 57, cap), ('vios_uuid2', 5, 55, cap), ('vios_uuid3', 5, 51, cap) ] # 5/55 is link-down. When it drops off, the last one moves to VIOS 2. live_back_devs = all_back_devs[:10] + [('vios_uuid2', 5, 51, cap)] # Use 'em all tsriov.set_vnic_back_devs(vnic, ['pport_loc%d' % x for x in range(60)], sys_w=mock_sys, capacity=cap, redundancy=12) self.assertEqual( all_back_devs, [(bd.vios_href, bd.sriov_adap_id, bd.pport_id, bd.capacity) for bd in vnic.back_devs]) # Check port status - 55 drops off tsriov.set_vnic_back_devs(vnic, ['pport_loc%d' % x for x in range(60)], sys_w=mock_sys, capacity=cap, redundancy=11, check_port_status=True) self.assertEqual( live_back_devs, [(bd.vios_href, bd.sriov_adap_id, bd.pport_id, bd.capacity) for bd in vnic.back_devs]) # Fail if we can't satisfy redundancy self.assertRaises(ex.InsufficientSRIOVCapacity, tsriov.set_vnic_back_devs, vnic, ['pport_loc%d' % x for x in range(60)], sys_w=mock_sys, capacity=cap, redundancy=13) # The passed-in wrapper isn't modified if the method raises. self.assertEqual( live_back_devs, [(bd.vios_href, bd.sriov_adap_id, bd.pport_id, bd.capacity) for bd in vnic.back_devs]) # Make sure redundancy caps it. # By reusing vnic without resetting its back_devs, we're proving the # documented behavior that the method clears first. tsriov.set_vnic_back_devs(vnic, ['pport_loc%d' % x for x in range(60)], sys_w=mock_sys, capacity=cap, redundancy=5) self.assertEqual( all_back_devs[:5], [(bd.vios_href, bd.sriov_adap_id, bd.pport_id, bd.capacity) for bd in vnic.back_devs]) self.assertEqual(5, mock_shuffle.call_count)