Upgrade os-net-config to version 10.4.1
[ta/os-net-config.git] / 0001-initial.patch
1 diff --git a/etc/os-net-config/samples/ovs_dpdk.json b/etc/os-net-config/samples/ovs_dpdk.json
2 index 5c84044..1dc523d 100644
3 --- a/etc/os-net-config/samples/ovs_dpdk.json
4 +++ b/etc/os-net-config/samples/ovs_dpdk.json
5 @@ -9,6 +9,7 @@
6                      "driver": "igb_uio",
7                      "mtu": 8192,
8                      "rx_queue": 4,
9 +                    "dpdk_lsc_interrupt": true,
10                      "members": [
11                          {
12                              "type": "interface",
13 diff --git a/etc/os-net-config/samples/ovs_dpdk.yaml b/etc/os-net-config/samples/ovs_dpdk.yaml
14 index 81aa212..9f0b0d3 100644
15 --- a/etc/os-net-config/samples/ovs_dpdk.yaml
16 +++ b/etc/os-net-config/samples/ovs_dpdk.yaml
17 @@ -22,6 +22,7 @@ network_config:
18          # should be less than the PMD cores as each queue will have one PMD
19          # thread (CPU) associated with it.
20          rx_queue: 4
21 +        dpdk_lsc_interrupt: true
22          members:
23              - type: interface
24                name: nic2
25 diff --git a/etc/os-net-config/samples/ovs_dpdk_bond.json b/etc/os-net-config/samples/ovs_dpdk_bond.json
26 index 410d459..02948c1 100644
27 --- a/etc/os-net-config/samples/ovs_dpdk_bond.json
28 +++ b/etc/os-net-config/samples/ovs_dpdk_bond.json
29 @@ -8,6 +8,7 @@
30                      "name" : "dpdkbond0",
31                      "mtu"  : 9000,
32                      "rx_queue": 4,
33 +                    "dpdk_lsc_interrupt": true,
34                      "members": [
35                          {
36                              "type" : "ovs_dpdk_port",
37 diff --git a/etc/os-net-config/samples/ovs_dpdk_bond.yaml b/etc/os-net-config/samples/ovs_dpdk_bond.yaml
38 index 17a73a3..896ca79 100644
39 --- a/etc/os-net-config/samples/ovs_dpdk_bond.yaml
40 +++ b/etc/os-net-config/samples/ovs_dpdk_bond.yaml
41 @@ -23,6 +23,7 @@ network_config:
42          # than the number of PMD cores, as each queue will have one PMD thread
43          # (CPU) associated with it.
44          rx_queue: 4
45 +        dpdk_lsc_interrupt: true
46          members:
47              -
48                type: ovs_dpdk_port
49 diff --git a/os_net_config/__init__.py b/os_net_config/__init__.py
50 index 7a00ee0..ce2ee86 100644
51 --- a/os_net_config/__init__.py
52 +++ b/os_net_config/__init__.py
53 @@ -316,7 +316,7 @@ class NetConfig(object):
54              self.execute(msg, '/sbin/ip',
55                           'link', 'set', 'dev', interface, 'down')
56  
57 -    def ifup(self, interface, iftype='interface'):
58 +    def ifup(self, interface, iftype='interface', check_exit_code=True):
59          """Run 'ifup' on the specified interface
60  
61          If a failure occurs when bringing up the interface it will be saved
62 @@ -328,7 +328,7 @@ class NetConfig(object):
63          """
64          msg = 'running ifup on %s: %s' % (iftype, interface)
65          try:
66 -            self.execute(msg, '/sbin/ifup', interface)
67 +            self.execute(msg, '/sbin/ifup', interface, check_exit_code=check_exit_code)
68          except processutils.ProcessExecutionError as e:
69              self.errors.append(e)
70  
71 diff --git a/os_net_config/impl_ifcfg.py b/os_net_config/impl_ifcfg.py
72 index 2fccbf3..c97ca0f 100644
73 --- a/os_net_config/impl_ifcfg.py
74 +++ b/os_net_config/impl_ifcfg.py
75 @@ -20,10 +20,13 @@ import logging
76  import netaddr
77  import os
78  import re
79 +import time
80  
81 +from netifaces import interfaces
82  import os_net_config
83  from os_net_config import objects
84  from os_net_config import utils
85 +from oslo_concurrency import processutils
86  
87  
88  logger = logging.getLogger(__name__)
89 @@ -364,6 +367,10 @@ class IfcfgNetConfig(os_net_config.NetConfig):
90                      data += "PHYSDEV=%s\n" % base_opt.device
91                  elif base_opt.linux_bond_name:
92                      data += "PHYSDEV=%s\n" % base_opt.linux_bond_name
93 +            elif base_opt.device:
94 +                # vlan on OVS bridge with device, create linux vlan
95 +                data += "VLAN=yes\n"
96 +                data += "PHYSDEV=%s\n" % base_opt.device
97              else:
98                  if base_opt.ovs_options:
99                      data += "OVS_OPTIONS=\"%s\"\n" % base_opt.ovs_options
100 @@ -391,9 +398,10 @@ class IfcfgNetConfig(os_net_config.NetConfig):
101              data += "NFVSWITCH_BRIDGE=%s\n" % base_opt.nfvswitch_bridge_name
102          if base_opt.ovs_port:
103              if not isinstance(base_opt, objects.LinuxTeam):
104 -                data += "DEVICETYPE=ovs\n"
105 +                if not (isinstance(base_opt, objects.Vlan) and base_opt.device):
106 +                    data += "DEVICETYPE=ovs\n"
107              if base_opt.bridge_name:
108 -                if isinstance(base_opt, objects.Vlan):
109 +                if isinstance(base_opt, objects.Vlan) and not base_opt.device:
110                      data += "TYPE=OVSIntPort\n"
111                      data += "OVS_BRIDGE=%s\n" % base_opt.bridge_name
112                      data += "OVS_OPTIONS=\"tag=%s\"\n" % base_opt.vlan_id
113 @@ -518,6 +526,10 @@ class IfcfgNetConfig(os_net_config.NetConfig):
114                  data += "RX_QUEUE=%i\n" % base_opt.rx_queue
115                  ovs_extra.append("set Interface $DEVICE " +
116                                   "options:n_rxq=$RX_QUEUE")
117 +            if base_opt.dpdk_lsc_interrupt:
118 +                data += "DPDK_LSC_INTERRUPT=true\n"
119 +                ovs_extra.append("set Interface $DEVICE " +
120 +                                 "options:dpdk-lsc-interrupt=$DPDK_LSC_INTERRUPT")
121          elif isinstance(base_opt, objects.OvsDpdkBond):
122              ovs_extra.extend(base_opt.ovs_extra)
123              # Referring to bug:1643026, the below commenting of the interfaces,
124 @@ -554,6 +566,11 @@ class IfcfgNetConfig(os_net_config.NetConfig):
125                      for member in base_opt.members:
126                          ovs_extra.append("set Interface %s options:n_rxq="
127                                           "$RX_QUEUE" % member.name)
128 +                if base_opt.dpdk_lsc_interrupt:
129 +                    data += "DPDK_LSC_INTERRUPT=true\n"
130 +                    for member in base_opt.members:
131 +                        ovs_extra.append("set Interface %s options:dpdk-lsc-interrupt="
132 +                                         "$DPDK_LSC_INTERRUPT" % member.name)
133              if base_opt.ovs_options:
134                  data += "OVS_OPTIONS=\"%s\"\n" % base_opt.ovs_options
135              ovs_extra.extend(base_opt.ovs_extra)
136 @@ -1500,6 +1517,11 @@ class IfcfgNetConfig(os_net_config.NetConfig):
137              else:
138                  logger.info('No changes required for vlan interface: %s' %
139                              vlan_name)
140 +                # Vlan needs to be restarted if underneath bond is restarted\r
141 +                if vlan_name not in restart_vlans:\r
142 +                    for linuxbond in restart_linux_bonds:\r
143 +                        if 'PHYSDEV={}\n'.format(linuxbond) in vlan_data:\r
144 +                            restart_vlans.append(vlan_name)
145              if utils.diff(vlan_route_path, route_data):
146                  update_files[vlan_route_path] = route_data
147                  if vlan_name not in restart_vlans:
148 @@ -1659,14 +1681,27 @@ class IfcfgNetConfig(os_net_config.NetConfig):
149                      stop_dhclient_process(interface)
150  
151              for interface in restart_interfaces:
152 -                self.ifup(interface)
153 +                check_exit_code = True
154 +                if interface not in interfaces():
155 +                    # Most DPDK drivers do not generate 'netdev' interfaces
156 +                    logger.info('Device %s does not exist' % interface)
157 +                    check_exit_code = False
158 +                self.ifup(interface, check_exit_code=check_exit_code)
159  
160              for linux_bond in restart_linux_bonds:
161                  self.ifup(linux_bond)
162  
163              for bond in self.bond_primary_ifaces:
164 -                self.ovs_appctl('bond/set-active-slave', bond,
165 -                                self.bond_primary_ifaces[bond])
166 +                for i in range(61):
167 +                    try:
168 +                        self.ovs_appctl('bond/set-active-slave', bond,
169 +                                        self.bond_primary_ifaces[bond])
170 +                    except processutils.ProcessExecutionError:
171 +                        if i >= 60:
172 +                            raise
173 +                        time.sleep(5)
174 +                        continue
175 +                    break
176  
177              if ivs_uplinks or ivs_interfaces:
178                  logger.info("Attach to ivs with "
179 diff --git a/os_net_config/objects.py b/os_net_config/objects.py
180 index 538c367..806d082 100644
181 --- a/os_net_config/objects.py
182 +++ b/os_net_config/objects.py
183 @@ -1249,7 +1249,8 @@ class OvsDpdkPort(_BaseOpts):
184                   nic_mapping=None, persist_mapping=False, defroute=True,
185                   dhclient_args=None, dns_servers=None, nm_controlled=False,
186                   onboot=True, domain=None, members=None, driver='vfio-pci',
187 -                 ovs_options=None, ovs_extra=None, rx_queue=None):
188 +                 ovs_options=None, ovs_extra=None, rx_queue=None,
189 +                 dpdk_lsc_interrupt=False):
190  
191          check_ovs_installed(self.__class__.__name__)
192  
193 @@ -1264,6 +1265,7 @@ class OvsDpdkPort(_BaseOpts):
194          self.ovs_extra = format_ovs_extra(self, ovs_extra)
195          self.driver = driver
196          self.rx_queue = rx_queue
197 +        self.dpdk_lsc_interrupt = dpdk_lsc_interrupt
198  
199      @staticmethod
200      def update_vf_config(iface):
201 @@ -1331,6 +1333,11 @@ class OvsDpdkPort(_BaseOpts):
202              raise InvalidConfigException(msg)
203  
204          rx_queue = json.get('rx_queue', None)
205 +
206 +        dpdk_lsc_interrupt = strutils.bool_from_string(str(json.get('dpdk_lsc_interrupt', False)))
207 +        if not dpdk_lsc_interrupt and utils.is_mellanox(utils.get_pci_address(members[0].name, None), None):
208 +            dpdk_lsc_interrupt = True
209 +
210          ovs_options = json.get('ovs_options', [])
211          ovs_options = ['options:%s' % opt for opt in ovs_options]
212          ovs_extra = json.get('ovs_extra', [])
213 @@ -1345,7 +1352,8 @@ class OvsDpdkPort(_BaseOpts):
214                             nm_controlled=nm_controlled, onboot=onboot,
215                             domain=domain, members=members, driver=driver,
216                             ovs_options=ovs_options,
217 -                           ovs_extra=ovs_extra, rx_queue=rx_queue)
218 +                           ovs_extra=ovs_extra, rx_queue=rx_queue,
219 +                           dpdk_lsc_interrupt=dpdk_lsc_interrupt)
220  
221  
222  class SriovVF(_BaseOpts):
223 @@ -1493,7 +1501,8 @@ class OvsDpdkBond(_BaseOpts):
224                   members=None, ovs_options=None, ovs_extra=None,
225                   nic_mapping=None, persist_mapping=False, defroute=True,
226                   dhclient_args=None, dns_servers=None, nm_controlled=False,
227 -                 onboot=True, domain=None, rx_queue=None):
228 +                 onboot=True, domain=None, rx_queue=None,
229 +                 dpdk_lsc_interrupt=False):
230  
231          check_ovs_installed(self.__class__.__name__)
232  
233 @@ -1507,6 +1516,7 @@ class OvsDpdkBond(_BaseOpts):
234          self.ovs_options = ovs_options
235          self.ovs_extra = format_ovs_extra(self, ovs_extra)
236          self.rx_queue = rx_queue
237 +        self.dpdk_lsc_interrupt = dpdk_lsc_interrupt
238  
239          for member in self.members:
240              if member.primary:
241 @@ -1554,6 +1564,11 @@ class OvsDpdkBond(_BaseOpts):
242                  msg = 'Members must be a list.'
243                  raise InvalidConfigException(msg)
244  
245 +        dpdk_lsc_interrupt = strutils.bool_from_string(str(json.get('dpdk_lsc_interrupt', False)))
246 +        if not dpdk_lsc_interrupt and \
247 +           utils.is_mellanox(utils.get_pci_address(members[0].members[0].name, None), None):
248 +            dpdk_lsc_interrupt = True
249 +
250          return OvsDpdkBond(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
251                             addresses=addresses, routes=routes, rules=rules,
252                             mtu=mtu, members=members, ovs_options=ovs_options,
253 @@ -1562,7 +1577,8 @@ class OvsDpdkBond(_BaseOpts):
254                             defroute=defroute, dhclient_args=dhclient_args,
255                             dns_servers=dns_servers,
256                             nm_controlled=nm_controlled, onboot=onboot,
257 -                           domain=domain, rx_queue=rx_queue)
258 +                           domain=domain, rx_queue=rx_queue,
259 +                           dpdk_lsc_interrupt=dpdk_lsc_interrupt)
260  
261  
262  class VppInterface(_BaseOpts):
263 diff --git a/os_net_config/schema.yaml b/os_net_config/schema.yaml
264 index 5643960..9d081f7 100644
265 --- a/os_net_config/schema.yaml
266 +++ b/os_net_config/schema.yaml
267 @@ -772,6 +772,8 @@ definitions:
268                  $ref: "#/definitions/ovs_extra_or_param"
269              rx_queue:
270                  $ref: "#/definitions/int_or_param"
271 +            dpdk_lsc_interrupt:
272 +                $ref: "#/definitions/bool_or_param"
273              # common options:
274              use_dhcp:
275                  $ref: "#/definitions/bool_or_param"
276 @@ -832,6 +834,8 @@ definitions:
277                  $ref: "#/definitions/ovs_extra_or_param"
278              rx_queue:
279                  $ref: "#/definitions/int_or_param"
280 +            dpdk_lsc_interrupt:
281 +                $ref: "#/definitions/bool_or_param"
282              # common options:
283              use_dhcp:
284                  $ref: "#/definitions/bool_or_param"
285 diff --git a/os_net_config/tests/test_cli.py b/os_net_config/tests/test_cli.py
286 index b667a2a..4487d48 100644
287 --- a/os_net_config/tests/test_cli.py
288 +++ b/os_net_config/tests/test_cli.py
289 @@ -19,10 +19,12 @@ import random
290  import sys
291  import yaml
292  
293 +from mock import patch
294  import os_net_config
295  from os_net_config import cli
296  from os_net_config import sriov_config
297  from os_net_config.tests import base
298 +from os_net_config.tests.test_utils import _PCI_OUTPUT
299  from os_net_config import utils
300  import six
301  
302 @@ -35,6 +37,18 @@ SAMPLE_BASE = os.path.join(REALPATH, '../../', 'etc',
303  class TestCli(base.TestCase):
304  
305      def setUp(self):
306 +        patcher_get_pci_address = patch('os_net_config.utils.get_pci_address',
307 +                                        return_value=(_PCI_OUTPUT, None))
308 +        self.mock_get_pci_address = patcher_get_pci_address.start()
309 +        self.addCleanup(patcher_get_pci_address.stop)
310 +
311 +        interface_list = ['em1', 'em2', 'em3', 'vlan16', 'nic2', 'nic3',
312 +                          'bond0', 'bond1', 'dpdk0', 'dpdkbond0',
313 +                          'api201', 'storage202']
314 +        patcher_interfaces = patch('os_net_config.impl_ifcfg.interfaces',
315 +                                   return_value=interface_list)
316 +        self.mock_interfaces = patcher_interfaces.start()
317 +        self.addCleanup(patcher_interfaces.stop)
318          super(TestCli, self).setUp()
319          rand = str(int(random.random() * 100000))
320          sriov_config._SRIOV_CONFIG_FILE = '/tmp/sriov_config_' + rand + '.yaml'
321 diff --git a/os_net_config/tests/test_impl_ifcfg.py b/os_net_config/tests/test_impl_ifcfg.py
322 index 5eba70b..11c3836 100644
323 --- a/os_net_config/tests/test_impl_ifcfg.py
324 +++ b/os_net_config/tests/test_impl_ifcfg.py
325 @@ -21,6 +21,7 @@ import tempfile
326  
327  from oslo_concurrency import processutils
328  
329 +from mock import patch
330  import os_net_config
331  from os_net_config import impl_ifcfg
332  from os_net_config import objects
333 @@ -354,6 +355,13 @@ OVS_OPTIONS="tag=5"
334  BOOTPROTO=none
335  """
336  
337 +_LINUX_VLAN_OVS_BRIDGE = _BASE_VLAN_OVS + """VLAN=yes
338 +PHYSDEV=em1
339 +TYPE=OVSPort
340 +OVS_BRIDGE=br-ctlplane
341 +BOOTPROTO=none
342 +"""
343 +
344  _VLAN_LINUX_BRIDGE = _BASE_VLAN_OVS + """VLAN=yes
345  PHYSDEV=em1
346  BRIDGE=br-ctlplane
347 @@ -1082,13 +1090,13 @@ class TestIfcfgNetConfig(base.TestCase):
348          self.assertEqual(_VLAN_NO_IP, self.get_vlan_config('vlan5'))
349  
350      def test_add_vlan_ovs(self):
351 -        vlan = objects.Vlan('em1', 5)
352 +        vlan = objects.Vlan(None, 5)
353          vlan.ovs_port = True
354          self.provider.add_vlan(vlan)
355          self.assertEqual(_VLAN_OVS, self.get_vlan_config('vlan5'))
356  
357      def test_add_vlan_ovs_options(self):
358 -        vlan = objects.Vlan('em1', 5)
359 +        vlan = objects.Vlan(None, 5)
360          vlan.ovs_port = True
361          vlan.ovs_options = 'foo'
362          vlan.ovs_extra = ['bar', 'baz']
363 @@ -1102,13 +1110,21 @@ class TestIfcfgNetConfig(base.TestCase):
364          self.assertEqual(expected, self.get_vlan_config('vlan5'))
365  
366      def test_add_ovs_bridge_with_vlan(self):
367 -        vlan = objects.Vlan('em1', 5)
368 +        vlan = objects.Vlan(None, 5)
369          bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True,
370                                     members=[vlan])
371          self.provider.add_vlan(vlan)
372          self.provider.add_bridge(bridge)
373          self.assertEqual(_VLAN_OVS_BRIDGE, self.get_vlan_config('vlan5'))
374  
375 +    def test_add_ovs_bridge_with_linux_vlan(self):
376 +        vlan = objects.Vlan('em1', 5)
377 +        bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True,
378 +                                   members=[vlan])
379 +        self.provider.add_vlan(vlan)
380 +        self.provider.add_bridge(bridge)
381 +        self.assertEqual(_LINUX_VLAN_OVS_BRIDGE, self.get_vlan_config('vlan5'))
382 +
383      def test_add_linux_bridge_with_vlan(self):
384          vlan = objects.Vlan('em1', 5)
385          bridge = objects.LinuxBridge('br-ctlplane', use_dhcp=True,
386 @@ -1634,13 +1650,14 @@ OVS_EXTRA="set Interface $DEVICE options:dpdk-devargs=0000:00:09.0"
387                           self.provider.bridge_data['br-link'])
388          self.assertEqual(dpdk0_config, self.get_interface_config('dpdk0'))
389  
390 -    def test_network_ovs_dpdk_bridge_and_port_with_mtu_rxqueue(self):
391 +    def test_network_ovs_dpdk_bridge_and_port_with_mtu_rxqueue_dpdklscinterrupt(self):
392          nic_mapping = {'nic1': 'eth0', 'nic2': 'eth1', 'nic3': 'eth2'}
393          self.stubbed_mapped_nics = nic_mapping
394  
395          interface = objects.Interface(name='nic3')
396          dpdk_port = objects.OvsDpdkPort(name='dpdk0', members=[interface],
397 -                                        mtu=9000, rx_queue=4)
398 +                                        mtu=9000, rx_queue=4,
399 +                                        dpdk_lsc_interrupt='true')
400          bridge = objects.OvsUserBridge('br-link', members=[dpdk_port])
401  
402          def test_bind_dpdk_interfaces(ifname, driver, noop):
403 @@ -1672,10 +1689,12 @@ DEVICETYPE=ovs
404  TYPE=OVSDPDKPort
405  OVS_BRIDGE=br-link
406  RX_QUEUE=4
407 +DPDK_LSC_INTERRUPT=true
408  MTU=9000
409  OVS_EXTRA="set Interface $DEVICE options:dpdk-devargs=0000:00:09.0 \
410  -- set Interface $DEVICE mtu_request=$MTU \
411 --- set Interface $DEVICE options:n_rxq=$RX_QUEUE"
412 +-- set Interface $DEVICE options:n_rxq=$RX_QUEUE \
413 +-- set Interface $DEVICE options:dpdk-lsc-interrupt=$DPDK_LSC_INTERRUPT"
414  """
415          self.assertEqual(br_link_config,
416                           self.provider.bridge_data['br-link'])
417 @@ -1770,7 +1789,8 @@ OVS_EXTRA="set Interface dpdk0 options:dpdk-devargs=0000:00:08.0 \
418          iface1 = objects.Interface(name='nic3')
419          dpdk1 = objects.OvsDpdkPort(name='dpdk1', members=[iface1])
420          bond = objects.OvsDpdkBond('dpdkbond0', rx_queue=4,
421 -                                   members=[dpdk0, dpdk1])
422 +                                   members=[dpdk0, dpdk1],
423 +                                   dpdk_lsc_interrupt='true')
424          bridge = objects.OvsUserBridge('br-link', members=[bond])
425  
426          def test_bind_dpdk_interfaces(ifname, driver, noop):
427 @@ -1795,10 +1815,13 @@ TYPE=OVSDPDKBond
428  OVS_BRIDGE=br-link
429  BOND_IFACES="dpdk0 dpdk1"
430  RX_QUEUE=4
431 +DPDK_LSC_INTERRUPT=true
432  OVS_EXTRA="set Interface dpdk0 options:dpdk-devargs=0000:00:08.0 \
433  -- set Interface dpdk1 options:dpdk-devargs=0000:00:09.0 \
434  -- set Interface dpdk0 options:n_rxq=$RX_QUEUE \
435 --- set Interface dpdk1 options:n_rxq=$RX_QUEUE"
436 +-- set Interface dpdk1 options:n_rxq=$RX_QUEUE \
437 +-- set Interface dpdk0 options:dpdk-lsc-interrupt=$DPDK_LSC_INTERRUPT \
438 +-- set Interface dpdk1 options:dpdk-lsc-interrupt=$DPDK_LSC_INTERRUPT"
439  """
440          self.assertEqual(dpdk_bond_config,
441                           self.get_interface_config('dpdkbond0'))
442 @@ -1812,7 +1835,8 @@ OVS_EXTRA="set Interface dpdk0 options:dpdk-devargs=0000:00:08.0 \
443          iface1 = objects.Interface(name='nic3')
444          dpdk1 = objects.OvsDpdkPort(name='dpdk1', members=[iface1])
445          bond = objects.OvsDpdkBond('dpdkbond0', rx_queue=4, mtu=9000,
446 -                                   members=[dpdk0, dpdk1])
447 +                                   members=[dpdk0, dpdk1],
448 +                                   dpdk_lsc_interrupt='true')
449          bridge = objects.OvsUserBridge('br-link', members=[bond])
450  
451          def test_bind_dpdk_interfaces(ifname, driver, noop):
452 @@ -1837,13 +1861,16 @@ TYPE=OVSDPDKBond
453  OVS_BRIDGE=br-link
454  BOND_IFACES="dpdk0 dpdk1"
455  RX_QUEUE=4
456 +DPDK_LSC_INTERRUPT=true
457  MTU=9000
458  OVS_EXTRA="set Interface dpdk0 options:dpdk-devargs=0000:00:08.0 \
459  -- set Interface dpdk1 options:dpdk-devargs=0000:00:09.0 \
460  -- set Interface dpdk0 mtu_request=$MTU \
461  -- set Interface dpdk1 mtu_request=$MTU \
462  -- set Interface dpdk0 options:n_rxq=$RX_QUEUE \
463 --- set Interface dpdk1 options:n_rxq=$RX_QUEUE"
464 +-- set Interface dpdk1 options:n_rxq=$RX_QUEUE \
465 +-- set Interface dpdk0 options:dpdk-lsc-interrupt=$DPDK_LSC_INTERRUPT \
466 +-- set Interface dpdk1 options:dpdk-lsc-interrupt=$DPDK_LSC_INTERRUPT"
467  """
468          self.assertEqual(dpdk_bond_config,
469                           self.get_interface_config('dpdkbond0'))
470 @@ -1852,6 +1879,11 @@ OVS_EXTRA="set Interface dpdk0 options:dpdk-devargs=0000:00:08.0 \
471  class TestIfcfgNetConfigApply(base.TestCase):
472  
473      def setUp(self):
474 +        interface_list = ['em1', 'em2', 'bond0', 'bond1', 'ib0']
475 +        patcher_interfaces = patch('os_net_config.impl_ifcfg.interfaces',
476 +                                   return_value=interface_list)
477 +        self.mock_interfaces = patcher_interfaces.start()
478 +        self.addCleanup(patcher_interfaces.stop)
479          super(TestIfcfgNetConfigApply, self).setUp()
480          self.temp_ifcfg_file = tempfile.NamedTemporaryFile()
481          self.temp_bond_file = tempfile.NamedTemporaryFile()
482 diff --git a/os_net_config/tests/test_objects.py b/os_net_config/tests/test_objects.py
483 index 0d42721..b0e34dc 100644
484 --- a/os_net_config/tests/test_objects.py
485 +++ b/os_net_config/tests/test_objects.py
486 @@ -20,9 +20,11 @@ import random
487  import six
488  import yaml
489  
490 +from mock import patch
491  from os_net_config import objects
492  from os_net_config import sriov_config
493  from os_net_config.tests import base
494 +from os_net_config.tests.test_utils import _PCI_OUTPUT
495  from os_net_config import utils
496  
497  
498 @@ -1605,6 +1607,13 @@ class TestNicMapping(base.TestCase):
499      def stub_is_ovs_installed(self):
500          return True
501  
502 +    def setUp(self):
503 +        patcher = patch('os_net_config.utils.get_pci_address', return_value=(_PCI_OUTPUT, None))
504 +        self.mock_get_pci_address = patcher.start()
505 +        self.addCleanup(patcher.stop)
506 +
507 +        super(TestNicMapping, self).setUp()
508 +
509      def tearDown(self):
510          super(TestNicMapping, self).tearDown()
511          objects._MAPPED_NICS = None
512 @@ -2172,6 +2181,13 @@ class TestOvsDpdkBond(base.TestCase):
513      # We want to test the function, not the dummy..
514      stub_mapped_nics = False
515  
516 +    def setUp(self):
517 +        patcher = patch('os_net_config.utils.get_pci_address', return_value=(_PCI_OUTPUT, None))
518 +        self.mock_get_pci_address = patcher.start()
519 +        self.addCleanup(patcher.stop)
520 +
521 +        super(TestOvsDpdkBond, self).setUp()
522 +
523      def _stub_active_nics(self, nics):
524          def dummy_ordered_active_nics():
525              return nics
526 @@ -2189,6 +2205,7 @@ class TestOvsDpdkBond(base.TestCase):
527  "type": "ovs_dpdk_bond",
528  "name": "dpdkbond0",
529  "use_dhcp": true,
530 +"dpdk_lsc_interrupt": true,
531  "members": [
532      {
533          "type": "ovs_dpdk_port",
534 @@ -2216,6 +2233,7 @@ class TestOvsDpdkBond(base.TestCase):
535          bond = objects.object_from_json(json.loads(data))
536          self.assertEqual("dpdkbond0", bond.name)
537          self.assertTrue(bond.use_dhcp)
538 +        self.assertTrue(bond.dpdk_lsc_interrupt)
539          dpdk_port0 = bond.members[0]
540          self.assertEqual("dpdk0", dpdk_port0.name)
541          self.assertEqual("vfio-pci", dpdk_port0.driver)
542 diff --git a/os_net_config/tests/test_utils.py b/os_net_config/tests/test_utils.py
543 index 2c9a3b0..72dc107 100644
544 --- a/os_net_config/tests/test_utils.py
545 +++ b/os_net_config/tests/test_utils.py
546 @@ -328,6 +328,8 @@ class TestUtils(base.TestCase):
547              if 'ethtool' in name:
548                  out = _PCI_OUTPUT
549                  return out, None
550 +            if 'lspci' in name:
551 +                return '', None
552          self.stub_out('oslo_concurrency.processutils.execute', test_execute)
553          pci = utils.get_pci_address('nic2', False)
554          self.assertEqual('0000:00:19.0', pci)
555 @@ -397,6 +399,8 @@ class TestUtils(base.TestCase):
556              if 'ethtool' in name:
557                  out = _PCI_OUTPUT
558                  return out, None
559 +            if 'lspci' in name:
560 +                return '', None
561              if 'driverctl' in name:
562                  return None, None
563  
564 @@ -415,6 +419,8 @@ class TestUtils(base.TestCase):
565              if 'ethtool' in name:
566                  out = _PCI_OUTPUT
567                  return out, None
568 +            if 'lspci' in name:
569 +                return '', None
570              if 'driverctl' in name:
571                  return None, 'Error'
572  
573 diff --git a/os_net_config/tests/test_validator.py b/os_net_config/tests/test_validator.py
574 index 81131b2..01d38a7 100644
575 --- a/os_net_config/tests/test_validator.py
576 +++ b/os_net_config/tests/test_validator.py
577 @@ -335,6 +335,7 @@ class TestDeviceTypes(base.TestCase):
578                  "name": "dpdkbond0",
579                  "mtu": 9000,
580                  "rx_queue": 4,
581 +                "dpdk_lsc_interrupt": "true",
582                  "members": [{
583                      "type": "ovs_dpdk_port",
584                      "name": "dpdk0",
585 diff --git a/os_net_config/utils.py b/os_net_config/utils.py
586 index 986bf46..a3daf6d 100644
587 --- a/os_net_config/utils.py
588 +++ b/os_net_config/utils.py
589 @@ -259,6 +259,17 @@ def bind_dpdk_interfaces(ifname, driver, noop):
590      pci_address = get_pci_address(ifname, noop)
591      if not noop:
592          if pci_address:
593 +            if is_mellanox(pci_address, noop):
594 +                # Mellanox is binded only with dpdk-devargs and does not need
595 +                # vfio-pci like e.g. Intel Niantic. Just update DPDK map here.
596 +                try:
597 +                    mac_address = interface_mac(ifname)
598 +                    _update_dpdk_map(ifname, pci_address, mac_address, driver)
599 +                except Exception as exp:
600 +                    logger.info('DPDK map update failed: {}'.format(exp))
601 +                    raise
602 +                return
603 +
604              # modbprobe of the driver has to be done before binding.
605              # for reboots, puppet will add the modprobe to /etc/rc.modules
606              if 'vfio-pci' in driver:
607 @@ -307,6 +318,19 @@ def bind_dpdk_interfaces(ifname, driver, noop):
608                      {'name': ifname, 'driver': driver})
609  
610  
611 +def is_mellanox(pci_address, noop):
612 +    if not noop:
613 +        try:
614 +            file_path = '/sys/bus/pci/devices/{}/vendor'.format(pci_address)
615 +            with open(file_path, 'r') as vendor_file:
616 +                if '0x15b3' in vendor_file.read():
617 +                    return True
618 +                else:
619 +                    return False
620 +        except Exception:
621 +            return False
622 +
623 +
624  def get_pci_address(ifname, noop):
625      # TODO(skramaja): Validate if the given interface supports dpdk
626      if not noop:
627 diff --git a/pylintrc b/pylintrc
628 new file mode 100644
629 index 0000000..81b4f50
630 --- /dev/null
631 +++ b/pylintrc
632 @@ -0,0 +1,2 @@
633 +[MESSAGES CONTROL]
634 +disable=E1101,F0401,E0211
635 diff --git a/tox.ini b/tox.ini
636 index e7f0d84..6ad73ac 100644
637 --- a/tox.ini
638 +++ b/tox.ini
639 @@ -9,7 +9,7 @@ install_command = pip install -U {opts} {packages}
640  setenv =
641     VIRTUAL_ENV={envdir}
642  deps =
643 -       -c{env:UPPER_CONSTRAINTS_FILE: https://releases.openstack.org/constraints/upper/stein}
644 +       -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/stein}
645         -r{toxinidir}/requirements.txt
646         -r{toxinidir}/test-requirements.txt
647  commands = stestr run --slowest {posargs}
648 @@ -40,6 +40,6 @@ commands = python setup.py build_sphinx
649  # E123, E125 skipped as they are invalid PEP-8.
650  
651  show-source = True
652 -ignore = E123,E125
653 +ignore = E123,E125,E501
654  builtins = _
655  exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build