diff --git a/etc/os-net-config/samples/ovs_dpdk.json b/etc/os-net-config/samples/ovs_dpdk.json index 5c84044..1dc523d 100644 --- a/etc/os-net-config/samples/ovs_dpdk.json +++ b/etc/os-net-config/samples/ovs_dpdk.json @@ -9,6 +9,7 @@ "driver": "igb_uio", "mtu": 8192, "rx_queue": 4, + "dpdk_lsc_interrupt": true, "members": [ { "type": "interface", diff --git a/etc/os-net-config/samples/ovs_dpdk.yaml b/etc/os-net-config/samples/ovs_dpdk.yaml index 81aa212..9f0b0d3 100644 --- a/etc/os-net-config/samples/ovs_dpdk.yaml +++ b/etc/os-net-config/samples/ovs_dpdk.yaml @@ -22,6 +22,7 @@ network_config: # should be less than the PMD cores as each queue will have one PMD # thread (CPU) associated with it. rx_queue: 4 + dpdk_lsc_interrupt: true members: - type: interface name: nic2 diff --git a/etc/os-net-config/samples/ovs_dpdk_bond.json b/etc/os-net-config/samples/ovs_dpdk_bond.json index 410d459..02948c1 100644 --- a/etc/os-net-config/samples/ovs_dpdk_bond.json +++ b/etc/os-net-config/samples/ovs_dpdk_bond.json @@ -8,6 +8,7 @@ "name" : "dpdkbond0", "mtu" : 9000, "rx_queue": 4, + "dpdk_lsc_interrupt": true, "members": [ { "type" : "ovs_dpdk_port", diff --git a/etc/os-net-config/samples/ovs_dpdk_bond.yaml b/etc/os-net-config/samples/ovs_dpdk_bond.yaml index 17a73a3..896ca79 100644 --- a/etc/os-net-config/samples/ovs_dpdk_bond.yaml +++ b/etc/os-net-config/samples/ovs_dpdk_bond.yaml @@ -23,6 +23,7 @@ network_config: # than the number of PMD cores, as each queue will have one PMD thread # (CPU) associated with it. rx_queue: 4 + dpdk_lsc_interrupt: true members: - type: ovs_dpdk_port diff --git a/os_net_config/__init__.py b/os_net_config/__init__.py index 7a00ee0..ce2ee86 100644 --- a/os_net_config/__init__.py +++ b/os_net_config/__init__.py @@ -316,7 +316,7 @@ class NetConfig(object): self.execute(msg, '/sbin/ip', 'link', 'set', 'dev', interface, 'down') - def ifup(self, interface, iftype='interface'): + def ifup(self, interface, iftype='interface', check_exit_code=True): """Run 'ifup' on the specified interface If a failure occurs when bringing up the interface it will be saved @@ -328,7 +328,7 @@ class NetConfig(object): """ msg = 'running ifup on %s: %s' % (iftype, interface) try: - self.execute(msg, '/sbin/ifup', interface) + self.execute(msg, '/sbin/ifup', interface, check_exit_code=check_exit_code) except processutils.ProcessExecutionError as e: self.errors.append(e) diff --git a/os_net_config/impl_ifcfg.py b/os_net_config/impl_ifcfg.py index 2fccbf3..c97ca0f 100644 --- a/os_net_config/impl_ifcfg.py +++ b/os_net_config/impl_ifcfg.py @@ -20,10 +20,13 @@ import logging import netaddr import os import re +import time +from netifaces import interfaces import os_net_config from os_net_config import objects from os_net_config import utils +from oslo_concurrency import processutils logger = logging.getLogger(__name__) @@ -364,6 +367,10 @@ class IfcfgNetConfig(os_net_config.NetConfig): data += "PHYSDEV=%s\n" % base_opt.device elif base_opt.linux_bond_name: data += "PHYSDEV=%s\n" % base_opt.linux_bond_name + elif base_opt.device: + # vlan on OVS bridge with device, create linux vlan + data += "VLAN=yes\n" + data += "PHYSDEV=%s\n" % base_opt.device else: if base_opt.ovs_options: data += "OVS_OPTIONS=\"%s\"\n" % base_opt.ovs_options @@ -391,9 +398,10 @@ class IfcfgNetConfig(os_net_config.NetConfig): data += "NFVSWITCH_BRIDGE=%s\n" % base_opt.nfvswitch_bridge_name if base_opt.ovs_port: if not isinstance(base_opt, objects.LinuxTeam): - data += "DEVICETYPE=ovs\n" + if not (isinstance(base_opt, objects.Vlan) and base_opt.device): + data += "DEVICETYPE=ovs\n" if base_opt.bridge_name: - if isinstance(base_opt, objects.Vlan): + if isinstance(base_opt, objects.Vlan) and not base_opt.device: data += "TYPE=OVSIntPort\n" data += "OVS_BRIDGE=%s\n" % base_opt.bridge_name data += "OVS_OPTIONS=\"tag=%s\"\n" % base_opt.vlan_id @@ -518,6 +526,10 @@ class IfcfgNetConfig(os_net_config.NetConfig): data += "RX_QUEUE=%i\n" % base_opt.rx_queue ovs_extra.append("set Interface $DEVICE " + "options:n_rxq=$RX_QUEUE") + if base_opt.dpdk_lsc_interrupt: + data += "DPDK_LSC_INTERRUPT=true\n" + ovs_extra.append("set Interface $DEVICE " + + "options:dpdk-lsc-interrupt=$DPDK_LSC_INTERRUPT") elif isinstance(base_opt, objects.OvsDpdkBond): ovs_extra.extend(base_opt.ovs_extra) # Referring to bug:1643026, the below commenting of the interfaces, @@ -554,6 +566,11 @@ class IfcfgNetConfig(os_net_config.NetConfig): for member in base_opt.members: ovs_extra.append("set Interface %s options:n_rxq=" "$RX_QUEUE" % member.name) + if base_opt.dpdk_lsc_interrupt: + data += "DPDK_LSC_INTERRUPT=true\n" + for member in base_opt.members: + ovs_extra.append("set Interface %s options:dpdk-lsc-interrupt=" + "$DPDK_LSC_INTERRUPT" % member.name) if base_opt.ovs_options: data += "OVS_OPTIONS=\"%s\"\n" % base_opt.ovs_options ovs_extra.extend(base_opt.ovs_extra) @@ -1500,6 +1517,11 @@ class IfcfgNetConfig(os_net_config.NetConfig): else: logger.info('No changes required for vlan interface: %s' % vlan_name) + # Vlan needs to be restarted if underneath bond is restarted + if vlan_name not in restart_vlans: + for linuxbond in restart_linux_bonds: + if 'PHYSDEV={}\n'.format(linuxbond) in vlan_data: + restart_vlans.append(vlan_name) if utils.diff(vlan_route_path, route_data): update_files[vlan_route_path] = route_data if vlan_name not in restart_vlans: @@ -1659,14 +1681,27 @@ class IfcfgNetConfig(os_net_config.NetConfig): stop_dhclient_process(interface) for interface in restart_interfaces: - self.ifup(interface) + check_exit_code = True + if interface not in interfaces(): + # Most DPDK drivers do not generate 'netdev' interfaces + logger.info('Device %s does not exist' % interface) + check_exit_code = False + self.ifup(interface, check_exit_code=check_exit_code) for linux_bond in restart_linux_bonds: self.ifup(linux_bond) for bond in self.bond_primary_ifaces: - self.ovs_appctl('bond/set-active-slave', bond, - self.bond_primary_ifaces[bond]) + for i in range(61): + try: + self.ovs_appctl('bond/set-active-slave', bond, + self.bond_primary_ifaces[bond]) + except processutils.ProcessExecutionError: + if i >= 60: + raise + time.sleep(5) + continue + break if ivs_uplinks or ivs_interfaces: logger.info("Attach to ivs with " diff --git a/os_net_config/objects.py b/os_net_config/objects.py index 538c367..806d082 100644 --- a/os_net_config/objects.py +++ b/os_net_config/objects.py @@ -1249,7 +1249,8 @@ class OvsDpdkPort(_BaseOpts): nic_mapping=None, persist_mapping=False, defroute=True, dhclient_args=None, dns_servers=None, nm_controlled=False, onboot=True, domain=None, members=None, driver='vfio-pci', - ovs_options=None, ovs_extra=None, rx_queue=None): + ovs_options=None, ovs_extra=None, rx_queue=None, + dpdk_lsc_interrupt=False): check_ovs_installed(self.__class__.__name__) @@ -1264,6 +1265,7 @@ class OvsDpdkPort(_BaseOpts): self.ovs_extra = format_ovs_extra(self, ovs_extra) self.driver = driver self.rx_queue = rx_queue + self.dpdk_lsc_interrupt = dpdk_lsc_interrupt @staticmethod def update_vf_config(iface): @@ -1331,6 +1333,11 @@ class OvsDpdkPort(_BaseOpts): raise InvalidConfigException(msg) rx_queue = json.get('rx_queue', None) + + dpdk_lsc_interrupt = strutils.bool_from_string(str(json.get('dpdk_lsc_interrupt', False))) + if not dpdk_lsc_interrupt and utils.is_mellanox(utils.get_pci_address(members[0].name, None), None): + dpdk_lsc_interrupt = True + ovs_options = json.get('ovs_options', []) ovs_options = ['options:%s' % opt for opt in ovs_options] ovs_extra = json.get('ovs_extra', []) @@ -1345,7 +1352,8 @@ class OvsDpdkPort(_BaseOpts): nm_controlled=nm_controlled, onboot=onboot, domain=domain, members=members, driver=driver, ovs_options=ovs_options, - ovs_extra=ovs_extra, rx_queue=rx_queue) + ovs_extra=ovs_extra, rx_queue=rx_queue, + dpdk_lsc_interrupt=dpdk_lsc_interrupt) class SriovVF(_BaseOpts): @@ -1493,7 +1501,8 @@ class OvsDpdkBond(_BaseOpts): members=None, ovs_options=None, ovs_extra=None, nic_mapping=None, persist_mapping=False, defroute=True, dhclient_args=None, dns_servers=None, nm_controlled=False, - onboot=True, domain=None, rx_queue=None): + onboot=True, domain=None, rx_queue=None, + dpdk_lsc_interrupt=False): check_ovs_installed(self.__class__.__name__) @@ -1507,6 +1516,7 @@ class OvsDpdkBond(_BaseOpts): self.ovs_options = ovs_options self.ovs_extra = format_ovs_extra(self, ovs_extra) self.rx_queue = rx_queue + self.dpdk_lsc_interrupt = dpdk_lsc_interrupt for member in self.members: if member.primary: @@ -1554,6 +1564,11 @@ class OvsDpdkBond(_BaseOpts): msg = 'Members must be a list.' raise InvalidConfigException(msg) + dpdk_lsc_interrupt = strutils.bool_from_string(str(json.get('dpdk_lsc_interrupt', False))) + if not dpdk_lsc_interrupt and \ + utils.is_mellanox(utils.get_pci_address(members[0].members[0].name, None), None): + dpdk_lsc_interrupt = True + return OvsDpdkBond(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6, addresses=addresses, routes=routes, rules=rules, mtu=mtu, members=members, ovs_options=ovs_options, @@ -1562,7 +1577,8 @@ class OvsDpdkBond(_BaseOpts): defroute=defroute, dhclient_args=dhclient_args, dns_servers=dns_servers, nm_controlled=nm_controlled, onboot=onboot, - domain=domain, rx_queue=rx_queue) + domain=domain, rx_queue=rx_queue, + dpdk_lsc_interrupt=dpdk_lsc_interrupt) class VppInterface(_BaseOpts): diff --git a/os_net_config/schema.yaml b/os_net_config/schema.yaml index 5643960..9d081f7 100644 --- a/os_net_config/schema.yaml +++ b/os_net_config/schema.yaml @@ -772,6 +772,8 @@ definitions: $ref: "#/definitions/ovs_extra_or_param" rx_queue: $ref: "#/definitions/int_or_param" + dpdk_lsc_interrupt: + $ref: "#/definitions/bool_or_param" # common options: use_dhcp: $ref: "#/definitions/bool_or_param" @@ -832,6 +834,8 @@ definitions: $ref: "#/definitions/ovs_extra_or_param" rx_queue: $ref: "#/definitions/int_or_param" + dpdk_lsc_interrupt: + $ref: "#/definitions/bool_or_param" # common options: use_dhcp: $ref: "#/definitions/bool_or_param" diff --git a/os_net_config/tests/test_cli.py b/os_net_config/tests/test_cli.py index b667a2a..4487d48 100644 --- a/os_net_config/tests/test_cli.py +++ b/os_net_config/tests/test_cli.py @@ -19,10 +19,12 @@ import random import sys import yaml +from mock import patch import os_net_config from os_net_config import cli from os_net_config import sriov_config from os_net_config.tests import base +from os_net_config.tests.test_utils import _PCI_OUTPUT from os_net_config import utils import six @@ -35,6 +37,18 @@ SAMPLE_BASE = os.path.join(REALPATH, '../../', 'etc', class TestCli(base.TestCase): def setUp(self): + patcher_get_pci_address = patch('os_net_config.utils.get_pci_address', + return_value=(_PCI_OUTPUT, None)) + self.mock_get_pci_address = patcher_get_pci_address.start() + self.addCleanup(patcher_get_pci_address.stop) + + interface_list = ['em1', 'em2', 'em3', 'vlan16', 'nic2', 'nic3', + 'bond0', 'bond1', 'dpdk0', 'dpdkbond0', + 'api201', 'storage202'] + patcher_interfaces = patch('os_net_config.impl_ifcfg.interfaces', + return_value=interface_list) + self.mock_interfaces = patcher_interfaces.start() + self.addCleanup(patcher_interfaces.stop) super(TestCli, self).setUp() rand = str(int(random.random() * 100000)) sriov_config._SRIOV_CONFIG_FILE = '/tmp/sriov_config_' + rand + '.yaml' diff --git a/os_net_config/tests/test_impl_ifcfg.py b/os_net_config/tests/test_impl_ifcfg.py index 5eba70b..11c3836 100644 --- a/os_net_config/tests/test_impl_ifcfg.py +++ b/os_net_config/tests/test_impl_ifcfg.py @@ -21,6 +21,7 @@ import tempfile from oslo_concurrency import processutils +from mock import patch import os_net_config from os_net_config import impl_ifcfg from os_net_config import objects @@ -354,6 +355,13 @@ OVS_OPTIONS="tag=5" BOOTPROTO=none """ +_LINUX_VLAN_OVS_BRIDGE = _BASE_VLAN_OVS + """VLAN=yes +PHYSDEV=em1 +TYPE=OVSPort +OVS_BRIDGE=br-ctlplane +BOOTPROTO=none +""" + _VLAN_LINUX_BRIDGE = _BASE_VLAN_OVS + """VLAN=yes PHYSDEV=em1 BRIDGE=br-ctlplane @@ -1082,13 +1090,13 @@ class TestIfcfgNetConfig(base.TestCase): self.assertEqual(_VLAN_NO_IP, self.get_vlan_config('vlan5')) def test_add_vlan_ovs(self): - vlan = objects.Vlan('em1', 5) + vlan = objects.Vlan(None, 5) vlan.ovs_port = True self.provider.add_vlan(vlan) self.assertEqual(_VLAN_OVS, self.get_vlan_config('vlan5')) def test_add_vlan_ovs_options(self): - vlan = objects.Vlan('em1', 5) + vlan = objects.Vlan(None, 5) vlan.ovs_port = True vlan.ovs_options = 'foo' vlan.ovs_extra = ['bar', 'baz'] @@ -1102,13 +1110,21 @@ class TestIfcfgNetConfig(base.TestCase): self.assertEqual(expected, self.get_vlan_config('vlan5')) def test_add_ovs_bridge_with_vlan(self): - vlan = objects.Vlan('em1', 5) + vlan = objects.Vlan(None, 5) bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True, members=[vlan]) self.provider.add_vlan(vlan) self.provider.add_bridge(bridge) self.assertEqual(_VLAN_OVS_BRIDGE, self.get_vlan_config('vlan5')) + def test_add_ovs_bridge_with_linux_vlan(self): + vlan = objects.Vlan('em1', 5) + bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True, + members=[vlan]) + self.provider.add_vlan(vlan) + self.provider.add_bridge(bridge) + self.assertEqual(_LINUX_VLAN_OVS_BRIDGE, self.get_vlan_config('vlan5')) + def test_add_linux_bridge_with_vlan(self): vlan = objects.Vlan('em1', 5) bridge = objects.LinuxBridge('br-ctlplane', use_dhcp=True, @@ -1634,13 +1650,14 @@ OVS_EXTRA="set Interface $DEVICE options:dpdk-devargs=0000:00:09.0" self.provider.bridge_data['br-link']) self.assertEqual(dpdk0_config, self.get_interface_config('dpdk0')) - def test_network_ovs_dpdk_bridge_and_port_with_mtu_rxqueue(self): + def test_network_ovs_dpdk_bridge_and_port_with_mtu_rxqueue_dpdklscinterrupt(self): nic_mapping = {'nic1': 'eth0', 'nic2': 'eth1', 'nic3': 'eth2'} self.stubbed_mapped_nics = nic_mapping interface = objects.Interface(name='nic3') dpdk_port = objects.OvsDpdkPort(name='dpdk0', members=[interface], - mtu=9000, rx_queue=4) + mtu=9000, rx_queue=4, + dpdk_lsc_interrupt='true') bridge = objects.OvsUserBridge('br-link', members=[dpdk_port]) def test_bind_dpdk_interfaces(ifname, driver, noop): @@ -1672,10 +1689,12 @@ DEVICETYPE=ovs TYPE=OVSDPDKPort OVS_BRIDGE=br-link RX_QUEUE=4 +DPDK_LSC_INTERRUPT=true MTU=9000 OVS_EXTRA="set Interface $DEVICE options:dpdk-devargs=0000:00:09.0 \ -- set Interface $DEVICE mtu_request=$MTU \ --- set Interface $DEVICE options:n_rxq=$RX_QUEUE" +-- set Interface $DEVICE options:n_rxq=$RX_QUEUE \ +-- set Interface $DEVICE options:dpdk-lsc-interrupt=$DPDK_LSC_INTERRUPT" """ self.assertEqual(br_link_config, self.provider.bridge_data['br-link']) @@ -1770,7 +1789,8 @@ OVS_EXTRA="set Interface dpdk0 options:dpdk-devargs=0000:00:08.0 \ iface1 = objects.Interface(name='nic3') dpdk1 = objects.OvsDpdkPort(name='dpdk1', members=[iface1]) bond = objects.OvsDpdkBond('dpdkbond0', rx_queue=4, - members=[dpdk0, dpdk1]) + members=[dpdk0, dpdk1], + dpdk_lsc_interrupt='true') bridge = objects.OvsUserBridge('br-link', members=[bond]) def test_bind_dpdk_interfaces(ifname, driver, noop): @@ -1795,10 +1815,13 @@ TYPE=OVSDPDKBond OVS_BRIDGE=br-link BOND_IFACES="dpdk0 dpdk1" RX_QUEUE=4 +DPDK_LSC_INTERRUPT=true OVS_EXTRA="set Interface dpdk0 options:dpdk-devargs=0000:00:08.0 \ -- set Interface dpdk1 options:dpdk-devargs=0000:00:09.0 \ -- set Interface dpdk0 options:n_rxq=$RX_QUEUE \ --- set Interface dpdk1 options:n_rxq=$RX_QUEUE" +-- set Interface dpdk1 options:n_rxq=$RX_QUEUE \ +-- set Interface dpdk0 options:dpdk-lsc-interrupt=$DPDK_LSC_INTERRUPT \ +-- set Interface dpdk1 options:dpdk-lsc-interrupt=$DPDK_LSC_INTERRUPT" """ self.assertEqual(dpdk_bond_config, self.get_interface_config('dpdkbond0')) @@ -1812,7 +1835,8 @@ OVS_EXTRA="set Interface dpdk0 options:dpdk-devargs=0000:00:08.0 \ iface1 = objects.Interface(name='nic3') dpdk1 = objects.OvsDpdkPort(name='dpdk1', members=[iface1]) bond = objects.OvsDpdkBond('dpdkbond0', rx_queue=4, mtu=9000, - members=[dpdk0, dpdk1]) + members=[dpdk0, dpdk1], + dpdk_lsc_interrupt='true') bridge = objects.OvsUserBridge('br-link', members=[bond]) def test_bind_dpdk_interfaces(ifname, driver, noop): @@ -1837,13 +1861,16 @@ TYPE=OVSDPDKBond OVS_BRIDGE=br-link BOND_IFACES="dpdk0 dpdk1" RX_QUEUE=4 +DPDK_LSC_INTERRUPT=true MTU=9000 OVS_EXTRA="set Interface dpdk0 options:dpdk-devargs=0000:00:08.0 \ -- set Interface dpdk1 options:dpdk-devargs=0000:00:09.0 \ -- set Interface dpdk0 mtu_request=$MTU \ -- set Interface dpdk1 mtu_request=$MTU \ -- set Interface dpdk0 options:n_rxq=$RX_QUEUE \ --- set Interface dpdk1 options:n_rxq=$RX_QUEUE" +-- set Interface dpdk1 options:n_rxq=$RX_QUEUE \ +-- set Interface dpdk0 options:dpdk-lsc-interrupt=$DPDK_LSC_INTERRUPT \ +-- set Interface dpdk1 options:dpdk-lsc-interrupt=$DPDK_LSC_INTERRUPT" """ self.assertEqual(dpdk_bond_config, self.get_interface_config('dpdkbond0')) @@ -1852,6 +1879,11 @@ OVS_EXTRA="set Interface dpdk0 options:dpdk-devargs=0000:00:08.0 \ class TestIfcfgNetConfigApply(base.TestCase): def setUp(self): + interface_list = ['em1', 'em2', 'bond0', 'bond1', 'ib0'] + patcher_interfaces = patch('os_net_config.impl_ifcfg.interfaces', + return_value=interface_list) + self.mock_interfaces = patcher_interfaces.start() + self.addCleanup(patcher_interfaces.stop) super(TestIfcfgNetConfigApply, self).setUp() self.temp_ifcfg_file = tempfile.NamedTemporaryFile() self.temp_bond_file = tempfile.NamedTemporaryFile() diff --git a/os_net_config/tests/test_objects.py b/os_net_config/tests/test_objects.py index 0d42721..b0e34dc 100644 --- a/os_net_config/tests/test_objects.py +++ b/os_net_config/tests/test_objects.py @@ -20,9 +20,11 @@ import random import six import yaml +from mock import patch from os_net_config import objects from os_net_config import sriov_config from os_net_config.tests import base +from os_net_config.tests.test_utils import _PCI_OUTPUT from os_net_config import utils @@ -1605,6 +1607,13 @@ class TestNicMapping(base.TestCase): def stub_is_ovs_installed(self): return True + def setUp(self): + patcher = patch('os_net_config.utils.get_pci_address', return_value=(_PCI_OUTPUT, None)) + self.mock_get_pci_address = patcher.start() + self.addCleanup(patcher.stop) + + super(TestNicMapping, self).setUp() + def tearDown(self): super(TestNicMapping, self).tearDown() objects._MAPPED_NICS = None @@ -2172,6 +2181,13 @@ class TestOvsDpdkBond(base.TestCase): # We want to test the function, not the dummy.. stub_mapped_nics = False + def setUp(self): + patcher = patch('os_net_config.utils.get_pci_address', return_value=(_PCI_OUTPUT, None)) + self.mock_get_pci_address = patcher.start() + self.addCleanup(patcher.stop) + + super(TestOvsDpdkBond, self).setUp() + def _stub_active_nics(self, nics): def dummy_ordered_active_nics(): return nics @@ -2189,6 +2205,7 @@ class TestOvsDpdkBond(base.TestCase): "type": "ovs_dpdk_bond", "name": "dpdkbond0", "use_dhcp": true, +"dpdk_lsc_interrupt": true, "members": [ { "type": "ovs_dpdk_port", @@ -2216,6 +2233,7 @@ class TestOvsDpdkBond(base.TestCase): bond = objects.object_from_json(json.loads(data)) self.assertEqual("dpdkbond0", bond.name) self.assertTrue(bond.use_dhcp) + self.assertTrue(bond.dpdk_lsc_interrupt) dpdk_port0 = bond.members[0] self.assertEqual("dpdk0", dpdk_port0.name) self.assertEqual("vfio-pci", dpdk_port0.driver) diff --git a/os_net_config/tests/test_utils.py b/os_net_config/tests/test_utils.py index 2c9a3b0..72dc107 100644 --- a/os_net_config/tests/test_utils.py +++ b/os_net_config/tests/test_utils.py @@ -328,6 +328,8 @@ class TestUtils(base.TestCase): if 'ethtool' in name: out = _PCI_OUTPUT return out, None + if 'lspci' in name: + return '', None self.stub_out('oslo_concurrency.processutils.execute', test_execute) pci = utils.get_pci_address('nic2', False) self.assertEqual('0000:00:19.0', pci) @@ -397,6 +399,8 @@ class TestUtils(base.TestCase): if 'ethtool' in name: out = _PCI_OUTPUT return out, None + if 'lspci' in name: + return '', None if 'driverctl' in name: return None, None @@ -415,6 +419,8 @@ class TestUtils(base.TestCase): if 'ethtool' in name: out = _PCI_OUTPUT return out, None + if 'lspci' in name: + return '', None if 'driverctl' in name: return None, 'Error' diff --git a/os_net_config/tests/test_validator.py b/os_net_config/tests/test_validator.py index 81131b2..01d38a7 100644 --- a/os_net_config/tests/test_validator.py +++ b/os_net_config/tests/test_validator.py @@ -335,6 +335,7 @@ class TestDeviceTypes(base.TestCase): "name": "dpdkbond0", "mtu": 9000, "rx_queue": 4, + "dpdk_lsc_interrupt": "true", "members": [{ "type": "ovs_dpdk_port", "name": "dpdk0", diff --git a/os_net_config/utils.py b/os_net_config/utils.py index 986bf46..a3daf6d 100644 --- a/os_net_config/utils.py +++ b/os_net_config/utils.py @@ -259,6 +259,17 @@ def bind_dpdk_interfaces(ifname, driver, noop): pci_address = get_pci_address(ifname, noop) if not noop: if pci_address: + if is_mellanox(pci_address, noop): + # Mellanox is binded only with dpdk-devargs and does not need + # vfio-pci like e.g. Intel Niantic. Just update DPDK map here. + try: + mac_address = interface_mac(ifname) + _update_dpdk_map(ifname, pci_address, mac_address, driver) + except Exception as exp: + logger.info('DPDK map update failed: {}'.format(exp)) + raise + return + # modbprobe of the driver has to be done before binding. # for reboots, puppet will add the modprobe to /etc/rc.modules if 'vfio-pci' in driver: @@ -307,6 +318,19 @@ def bind_dpdk_interfaces(ifname, driver, noop): {'name': ifname, 'driver': driver}) +def is_mellanox(pci_address, noop): + if not noop: + try: + file_path = '/sys/bus/pci/devices/{}/vendor'.format(pci_address) + with open(file_path, 'r') as vendor_file: + if '0x15b3' in vendor_file.read(): + return True + else: + return False + except Exception: + return False + + def get_pci_address(ifname, noop): # TODO(skramaja): Validate if the given interface supports dpdk if not noop: diff --git a/pylintrc b/pylintrc new file mode 100644 index 0000000..81b4f50 --- /dev/null +++ b/pylintrc @@ -0,0 +1,2 @@ +[MESSAGES CONTROL] +disable=E1101,F0401,E0211 diff --git a/tox.ini b/tox.ini index e7f0d84..6ad73ac 100644 --- a/tox.ini +++ b/tox.ini @@ -9,7 +9,7 @@ install_command = pip install -U {opts} {packages} setenv = VIRTUAL_ENV={envdir} deps = - -c{env:UPPER_CONSTRAINTS_FILE: https://releases.openstack.org/constraints/upper/stein} + -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/stein} -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt commands = stestr run --slowest {posargs} @@ -40,6 +40,6 @@ commands = python setup.py build_sphinx # E123, E125 skipped as they are invalid PEP-8. show-source = True -ignore = E123,E125 +ignore = E123,E125,E501 builtins = _ exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build