Add seed code for os-net-config
[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 609d5dc..0523bfc 100644
51 --- a/os_net_config/__init__.py
52 +++ b/os_net_config/__init__.py
53 @@ -253,7 +253,7 @@ class NetConfig(object):
54          msg = 'running ifdown on %s: %s' % (iftype, interface)
55          self.execute(msg, '/sbin/ifdown', interface, check_exit_code=False)
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 @@ -265,7 +265,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 3a82597..3fd7eb5 100644
73 --- a/os_net_config/impl_ifcfg.py
74 +++ b/os_net_config/impl_ifcfg.py
75 @@ -18,10 +18,13 @@ import glob
76  import logging
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 @@ -162,6 +165,10 @@ class IfcfgNetConfig(os_net_config.NetConfig):
90                  else:
91                      if 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          elif isinstance(base_opt, objects.IvsInterface):
98              data += "TYPE=IVSIntPort\n"
99          elif isinstance(base_opt, objects.NfvswitchInternal):
100 @@ -187,9 +194,11 @@ 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)
106 +                        and base_opt.device):
107 +                    data += "DEVICETYPE=ovs\n"
108              if base_opt.bridge_name:
109 -                if isinstance(base_opt, objects.Vlan):
110 +                if isinstance(base_opt, objects.Vlan) and not base_opt.device:
111                      data += "TYPE=OVSIntPort\n"
112                      data += "OVS_BRIDGE=%s\n" % base_opt.bridge_name
113                      data += "OVS_OPTIONS=\"tag=%s\"\n" % base_opt.vlan_id
114 @@ -313,6 +322,10 @@ class IfcfgNetConfig(os_net_config.NetConfig):
115                  data += "RX_QUEUE=%i\n" % base_opt.rx_queue
116                  ovs_extra.append("set Interface $DEVICE " +
117                                   "options:n_rxq=$RX_QUEUE")
118 +            if base_opt.dpdk_lsc_interrupt:
119 +                data += "DPDK_LSC_INTERRUPT=true\n"
120 +                ovs_extra.append("set Interface $DEVICE " +
121 +                                 "options:dpdk-lsc-interrupt=$DPDK_LSC_INTERRUPT")
122          elif isinstance(base_opt, objects.OvsDpdkBond):
123              ovs_extra.extend(base_opt.ovs_extra)
124              # Referring to bug:1643026, the below commenting of the interfaces,
125 @@ -349,6 +362,11 @@ class IfcfgNetConfig(os_net_config.NetConfig):
126                      for member in base_opt.members:
127                          ovs_extra.append("set Interface %s options:n_rxq="
128                                           "$RX_QUEUE" % member.name)
129 +                if base_opt.dpdk_lsc_interrupt:
130 +                    data += "DPDK_LSC_INTERRUPT=true\n"
131 +                    for member in base_opt.members:
132 +                        ovs_extra.append("set Interface %s options:dpdk-lsc-interrupt="
133 +                                         "$DPDK_LSC_INTERRUPT" % member.name)
134              if base_opt.ovs_options:
135                  data += "OVS_OPTIONS=\"%s\"\n" % base_opt.ovs_options
136              ovs_extra.extend(base_opt.ovs_extra)
137 @@ -1043,14 +1061,27 @@ class IfcfgNetConfig(os_net_config.NetConfig):
138                      stop_dhclient_process(interface)
139  
140              for interface in restart_interfaces:
141 -                self.ifup(interface)
142 +                check_exit_code = True
143 +                if interface not in interfaces():
144 +                    # Most DPDK drivers do not generate 'netdev' interfaces
145 +                    logger.info('Device %s does not exist' % interface)
146 +                    check_exit_code = False
147 +                self.ifup(interface, check_exit_code=check_exit_code)
148  
149              for linux_bond in restart_linux_bonds:
150                  self.ifup(linux_bond)
151  
152              for bond in self.bond_primary_ifaces:
153 -                self.ovs_appctl('bond/set-active-slave', bond,
154 -                                self.bond_primary_ifaces[bond])
155 +                for i in range(61):
156 +                    try:
157 +                        self.ovs_appctl('bond/set-active-slave', bond,
158 +                                        self.bond_primary_ifaces[bond])
159 +                    except processutils.ProcessExecutionError:
160 +                        if i >= 60:
161 +                            raise
162 +                        time.sleep(5)
163 +                        continue
164 +                    break
165  
166              if ivs_uplinks or ivs_interfaces:
167                  logger.info("Attach to ivs with "
168 diff --git a/os_net_config/objects.py b/os_net_config/objects.py
169 index 417f34a..1b321f3 100644
170 --- a/os_net_config/objects.py
171 +++ b/os_net_config/objects.py
172 @@ -993,7 +993,7 @@ class OvsDpdkPort(_BaseOpts):
173                   persist_mapping=False, defroute=True, dhclient_args=None,
174                   dns_servers=None, nm_controlled=False, members=None,
175                   driver='vfio-pci', ovs_options=None, ovs_extra=None,
176 -                 rx_queue=None):
177 +                 rx_queue=None, dpdk_lsc_interrupt=False):
178  
179          super(OvsDpdkPort, self).__init__(name, use_dhcp, use_dhcpv6,
180                                            addresses, routes, mtu, primary,
181 @@ -1005,6 +1005,7 @@ class OvsDpdkPort(_BaseOpts):
182          self.ovs_extra = format_ovs_extra(self, ovs_extra)
183          self.driver = driver
184          self.rx_queue = rx_queue
185 +        self.dpdk_lsc_interrupt = dpdk_lsc_interrupt
186  
187      @staticmethod
188      def from_json(json):
189 @@ -1047,6 +1048,11 @@ class OvsDpdkPort(_BaseOpts):
190              raise InvalidConfigException(msg)
191  
192          rx_queue = json.get('rx_queue', None)
193 +
194 +        dpdk_lsc_interrupt = strutils.bool_from_string(str(json.get('dpdk_lsc_interrupt', False)))
195 +        if not dpdk_lsc_interrupt and utils.is_mellanox(utils.get_pci_address(members[0].name, None), None):
196 +            dpdk_lsc_interrupt = True
197 +
198          ovs_options = json.get('ovs_options', [])
199          ovs_options = ['options:%s' % opt for opt in ovs_options]
200          ovs_extra = json.get('ovs_extra', [])
201 @@ -1060,7 +1066,8 @@ class OvsDpdkPort(_BaseOpts):
202                             dns_servers=dns_servers,
203                             nm_controlled=nm_controlled, members=members,
204                             driver=driver, ovs_options=ovs_options,
205 -                           ovs_extra=ovs_extra, rx_queue=rx_queue)
206 +                           ovs_extra=ovs_extra, rx_queue=rx_queue,
207 +                           dpdk_lsc_interrupt=dpdk_lsc_interrupt)
208  
209  
210  class OvsDpdkBond(_BaseOpts):
211 @@ -1070,7 +1077,8 @@ class OvsDpdkBond(_BaseOpts):
212                   routes=None, mtu=None, primary=False, members=None,
213                   ovs_options=None, ovs_extra=None, nic_mapping=None,
214                   persist_mapping=False, defroute=True, dhclient_args=None,
215 -                 dns_servers=None, nm_controlled=False, rx_queue=None):
216 +                 dns_servers=None, nm_controlled=False, rx_queue=None,
217 +                 dpdk_lsc_interrupt=False):
218          super(OvsDpdkBond, self).__init__(name, use_dhcp, use_dhcpv6,
219                                            addresses, routes, mtu, primary,
220                                            nic_mapping, persist_mapping,
221 @@ -1080,6 +1088,7 @@ class OvsDpdkBond(_BaseOpts):
222          self.ovs_options = ovs_options
223          self.ovs_extra = format_ovs_extra(self, ovs_extra)
224          self.rx_queue = rx_queue
225 +        self.dpdk_lsc_interrupt = dpdk_lsc_interrupt
226  
227          for member in self.members:
228              if member.primary:
229 @@ -1127,6 +1136,11 @@ class OvsDpdkBond(_BaseOpts):
230                  msg = 'Members must be a list.'
231                  raise InvalidConfigException(msg)
232  
233 +        dpdk_lsc_interrupt = strutils.bool_from_string(str(json.get('dpdk_lsc_interrupt', False)))
234 +        if not dpdk_lsc_interrupt and \
235 +           utils.is_mellanox(utils.get_pci_address(members[0].members[0].name, None), None):
236 +            dpdk_lsc_interrupt = True
237 +
238          return OvsDpdkBond(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
239                             addresses=addresses, routes=routes, mtu=mtu,
240                             members=members, ovs_options=ovs_options,
241 @@ -1134,7 +1148,8 @@ class OvsDpdkBond(_BaseOpts):
242                             persist_mapping=persist_mapping,
243                             defroute=defroute, dhclient_args=dhclient_args,
244                             dns_servers=dns_servers,
245 -                           nm_controlled=nm_controlled, rx_queue=rx_queue)
246 +                           nm_controlled=nm_controlled, rx_queue=rx_queue,
247 +                           dpdk_lsc_interrupt=dpdk_lsc_interrupt)
248  
249  
250  class VppInterface(_BaseOpts):
251 diff --git a/os_net_config/schema.yaml b/os_net_config/schema.yaml
252 index 5060a34..62aeb41 100644
253 --- a/os_net_config/schema.yaml
254 +++ b/os_net_config/schema.yaml
255 @@ -529,6 +529,8 @@ definitions:
256                  $ref: "#/definitions/ovs_extra_or_param"
257              rx_queue:
258                  $ref: "#/definitions/int_or_param"
259 +            dpdk_lsc_interrupt:
260 +                $ref: "#/definitions/bool_or_param"
261              # common options:
262              use_dhcp:
263                  $ref: "#/definitions/bool_or_param"
264 @@ -581,6 +583,8 @@ definitions:
265                  $ref: "#/definitions/ovs_extra_or_param"
266              rx_queue:
267                  $ref: "#/definitions/int_or_param"
268 +            dpdk_lsc_interrupt:
269 +                $ref: "#/definitions/bool_or_param"
270              # common options:
271              use_dhcp:
272                  $ref: "#/definitions/bool_or_param"
273 diff --git a/os_net_config/tests/test_cli.py b/os_net_config/tests/test_cli.py
274 index 32f9395..338f946 100644
275 --- a/os_net_config/tests/test_cli.py
276 +++ b/os_net_config/tests/test_cli.py
277 @@ -17,10 +17,12 @@
278  import os.path
279  import sys
280  
281 +from mock import patch
282  import os_net_config
283  from os_net_config import cli
284  from os_net_config import impl_ifcfg
285  from os_net_config.tests import base
286 +from os_net_config.tests.test_utils import _PCI_OUTPUT
287  import six
288  
289  
290 @@ -31,6 +33,22 @@ SAMPLE_BASE = os.path.join(REALPATH, '../../', 'etc',
291  
292  class TestCli(base.TestCase):
293  
294 +    def setUp(self):
295 +        patcher_get_pci_address = patch('os_net_config.utils.get_pci_address',
296 +                                        return_value=(_PCI_OUTPUT, None))
297 +        self.mock_get_pci_address = patcher_get_pci_address.start()
298 +        self.addCleanup(patcher_get_pci_address.stop)
299 +
300 +        interface_list = ['em1', 'em2', 'em3', 'vlan16', 'nic2', 'nic3',
301 +                          'bond0', 'bond1', 'dpdk0', 'dpdkbond0',
302 +                          'api201', 'storage202']
303 +        patcher_interfaces = patch('os_net_config.impl_ifcfg.interfaces',
304 +                                   return_value=interface_list)
305 +        self.mock_interfaces = patcher_interfaces.start()
306 +        self.addCleanup(patcher_interfaces.stop)
307 +
308 +        super(TestCli, self).setUp()
309 +
310      def run_cli(self, argstr, exitcodes=(0,)):
311          orig = sys.stdout
312          orig_stderr = sys.stderr
313 diff --git a/os_net_config/tests/test_impl_ifcfg.py b/os_net_config/tests/test_impl_ifcfg.py
314 index 337eeb3..a0abf93 100644
315 --- a/os_net_config/tests/test_impl_ifcfg.py
316 +++ b/os_net_config/tests/test_impl_ifcfg.py
317 @@ -19,6 +19,7 @@ import tempfile
318  
319  from oslo_concurrency import processutils
320  
321 +from mock import patch
322  import os_net_config
323  from os_net_config import impl_ifcfg
324  from os_net_config import NetConfig
325 @@ -260,6 +261,13 @@ OVS_OPTIONS="tag=5"
326  BOOTPROTO=none
327  """
328  
329 +_LINUX_VLAN_OVS_BRIDGE = _BASE_VLAN_OVS + """VLAN=yes
330 +PHYSDEV=em1
331 +TYPE=OVSPort
332 +OVS_BRIDGE=br-ctlplane
333 +BOOTPROTO=none
334 +"""
335 +
336  _VLAN_LINUX_BRIDGE = _BASE_VLAN_OVS + """VLAN=yes
337  PHYSDEV=em1
338  BRIDGE=br-ctlplane
339 @@ -719,7 +727,7 @@ class TestIfcfgNetConfig(base.TestCase):
340          self.assertEqual(_VLAN_NO_IP, self.get_vlan_config('vlan5'))
341  
342      def test_add_vlan_ovs(self):
343 -        vlan = objects.Vlan('em1', 5)
344 +        vlan = objects.Vlan(None, 5)
345          vlan.ovs_port = True
346          self.provider.add_vlan(vlan)
347          self.assertEqual(_VLAN_OVS, self.get_vlan_config('vlan5'))
348 @@ -731,13 +739,21 @@ class TestIfcfgNetConfig(base.TestCase):
349          self.assertEqual(expected, self.get_vlan_config('vlan5'))
350  
351      def test_add_ovs_bridge_with_vlan(self):
352 -        vlan = objects.Vlan('em1', 5)
353 +        vlan = objects.Vlan(None, 5)
354          bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True,
355                                     members=[vlan])
356          self.provider.add_vlan(vlan)
357          self.provider.add_bridge(bridge)
358          self.assertEqual(_VLAN_OVS_BRIDGE, self.get_vlan_config('vlan5'))
359  
360 +    def test_add_ovs_bridge_with_linux_vlan(self):
361 +        vlan = objects.Vlan('em1', 5)
362 +        bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True,
363 +                                   members=[vlan])
364 +        self.provider.add_vlan(vlan)
365 +        self.provider.add_bridge(bridge)
366 +        self.assertEqual(_LINUX_VLAN_OVS_BRIDGE, self.get_vlan_config('vlan5'))
367 +
368      def test_add_linux_bridge_with_vlan(self):
369          vlan = objects.Vlan('em1', 5)
370          bridge = objects.LinuxBridge('br-ctlplane', use_dhcp=True,
371 @@ -932,13 +948,14 @@ OVS_EXTRA="set Interface $DEVICE options:dpdk-devargs=0000:00:09.0"
372                           self.provider.bridge_data['br-link'])
373          self.assertEqual(dpdk0_config, self.get_interface_config('dpdk0'))
374  
375 -    def test_network_ovs_dpdk_bridge_and_port_with_mtu_rxqueue(self):
376 +    def test_network_ovs_dpdk_bridge_and_port_with_mtu_rxqueue_dpdklscinterrupt(self):
377          nic_mapping = {'nic1': 'eth0', 'nic2': 'eth1', 'nic3': 'eth2'}
378          self.stubbed_mapped_nics = nic_mapping
379  
380          interface = objects.Interface(name='nic3')
381          dpdk_port = objects.OvsDpdkPort(name='dpdk0', members=[interface],
382 -                                        mtu=9000, rx_queue=4)
383 +                                        mtu=9000, rx_queue=4,
384 +                                        dpdk_lsc_interrupt='true')
385          bridge = objects.OvsUserBridge('br-link', members=[dpdk_port])
386  
387          def test_bind_dpdk_interfaces(ifname, driver, noop):
388 @@ -970,10 +987,12 @@ DEVICETYPE=ovs
389  TYPE=OVSDPDKPort
390  OVS_BRIDGE=br-link
391  RX_QUEUE=4
392 +DPDK_LSC_INTERRUPT=true
393  MTU=9000
394  OVS_EXTRA="set Interface $DEVICE options:dpdk-devargs=0000:00:09.0 \
395  -- set Interface $DEVICE mtu_request=$MTU \
396 --- set Interface $DEVICE options:n_rxq=$RX_QUEUE"
397 +-- set Interface $DEVICE options:n_rxq=$RX_QUEUE \
398 +-- set Interface $DEVICE options:dpdk-lsc-interrupt=$DPDK_LSC_INTERRUPT"
399  """
400          self.assertEqual(br_link_config,
401                           self.provider.bridge_data['br-link'])
402 @@ -1068,7 +1087,8 @@ OVS_EXTRA="set Interface dpdk0 options:dpdk-devargs=0000:00:08.0 \
403          iface1 = objects.Interface(name='nic3')
404          dpdk1 = objects.OvsDpdkPort(name='dpdk1', members=[iface1])
405          bond = objects.OvsDpdkBond('dpdkbond0', rx_queue=4,
406 -                                   members=[dpdk0, dpdk1])
407 +                                   members=[dpdk0, dpdk1],
408 +                                   dpdk_lsc_interrupt='true')
409          bridge = objects.OvsUserBridge('br-link', members=[bond])
410  
411          def test_bind_dpdk_interfaces(ifname, driver, noop):
412 @@ -1093,10 +1113,13 @@ TYPE=OVSDPDKBond
413  OVS_BRIDGE=br-link
414  BOND_IFACES="dpdk0 dpdk1"
415  RX_QUEUE=4
416 +DPDK_LSC_INTERRUPT=true
417  OVS_EXTRA="set Interface dpdk0 options:dpdk-devargs=0000:00:08.0 \
418  -- set Interface dpdk1 options:dpdk-devargs=0000:00:09.0 \
419  -- set Interface dpdk0 options:n_rxq=$RX_QUEUE \
420 --- set Interface dpdk1 options:n_rxq=$RX_QUEUE"
421 +-- set Interface dpdk1 options:n_rxq=$RX_QUEUE \
422 +-- set Interface dpdk0 options:dpdk-lsc-interrupt=$DPDK_LSC_INTERRUPT \
423 +-- set Interface dpdk1 options:dpdk-lsc-interrupt=$DPDK_LSC_INTERRUPT"
424  """
425          self.assertEqual(dpdk_bond_config,
426                           self.get_interface_config('dpdkbond0'))
427 @@ -1110,7 +1133,8 @@ OVS_EXTRA="set Interface dpdk0 options:dpdk-devargs=0000:00:08.0 \
428          iface1 = objects.Interface(name='nic3')
429          dpdk1 = objects.OvsDpdkPort(name='dpdk1', members=[iface1])
430          bond = objects.OvsDpdkBond('dpdkbond0', rx_queue=4, mtu=9000,
431 -                                   members=[dpdk0, dpdk1])
432 +                                   members=[dpdk0, dpdk1],
433 +                                   dpdk_lsc_interrupt='true')
434          bridge = objects.OvsUserBridge('br-link', members=[bond])
435  
436          def test_bind_dpdk_interfaces(ifname, driver, noop):
437 @@ -1135,13 +1159,16 @@ TYPE=OVSDPDKBond
438  OVS_BRIDGE=br-link
439  BOND_IFACES="dpdk0 dpdk1"
440  RX_QUEUE=4
441 +DPDK_LSC_INTERRUPT=true
442  MTU=9000
443  OVS_EXTRA="set Interface dpdk0 options:dpdk-devargs=0000:00:08.0 \
444  -- set Interface dpdk1 options:dpdk-devargs=0000:00:09.0 \
445  -- set Interface dpdk0 mtu_request=$MTU \
446  -- set Interface dpdk1 mtu_request=$MTU \
447  -- set Interface dpdk0 options:n_rxq=$RX_QUEUE \
448 --- set Interface dpdk1 options:n_rxq=$RX_QUEUE"
449 +-- set Interface dpdk1 options:n_rxq=$RX_QUEUE \
450 +-- set Interface dpdk0 options:dpdk-lsc-interrupt=$DPDK_LSC_INTERRUPT \
451 +-- set Interface dpdk1 options:dpdk-lsc-interrupt=$DPDK_LSC_INTERRUPT"
452  """
453          self.assertEqual(dpdk_bond_config,
454                           self.get_interface_config('dpdkbond0'))
455 @@ -1150,6 +1177,11 @@ OVS_EXTRA="set Interface dpdk0 options:dpdk-devargs=0000:00:08.0 \
456  class TestIfcfgNetConfigApply(base.TestCase):
457  
458      def setUp(self):
459 +        interface_list = ['em1', 'em2', 'bond0', 'bond1', 'ib0']
460 +        patcher_interfaces = patch('os_net_config.impl_ifcfg.interfaces',
461 +                                   return_value=interface_list)
462 +        self.mock_interfaces = patcher_interfaces.start()
463 +        self.addCleanup(patcher_interfaces.stop)
464          super(TestIfcfgNetConfigApply, self).setUp()
465          self.temp_ifcfg_file = tempfile.NamedTemporaryFile()
466          self.temp_bond_file = tempfile.NamedTemporaryFile()
467 diff --git a/os_net_config/tests/test_objects.py b/os_net_config/tests/test_objects.py
468 index 1c07eee..39a7884 100644
469 --- a/os_net_config/tests/test_objects.py
470 +++ b/os_net_config/tests/test_objects.py
471 @@ -17,8 +17,10 @@
472  import json
473  import six
474  
475 +from mock import patch
476  from os_net_config import objects
477  from os_net_config.tests import base
478 +from os_net_config.tests.test_utils import _PCI_OUTPUT
479  from os_net_config import utils
480  
481  
482 @@ -917,6 +919,13 @@ class TestNicMapping(base.TestCase):
483      # We want to test the function, not the dummy..
484      stub_mapped_nics = False
485  
486 +    def setUp(self):
487 +        patcher = patch('os_net_config.utils.get_pci_address', return_value=(_PCI_OUTPUT, None))
488 +        self.mock_get_pci_address = patcher.start()
489 +        self.addCleanup(patcher.stop)
490 +
491 +        super(TestNicMapping, self).setUp()
492 +
493      def tearDown(self):
494          super(TestNicMapping, self).tearDown()
495          objects._MAPPED_NICS = None
496 @@ -1122,6 +1131,13 @@ class TestOvsDpdkBond(base.TestCase):
497      # We want to test the function, not the dummy..
498      stub_mapped_nics = False
499  
500 +    def setUp(self):
501 +        patcher = patch('os_net_config.utils.get_pci_address', return_value=(_PCI_OUTPUT, None))
502 +        self.mock_get_pci_address = patcher.start()
503 +        self.addCleanup(patcher.stop)
504 +
505 +        super(TestOvsDpdkBond, self).setUp()
506 +
507      def _stub_active_nics(self, nics):
508          def dummy_ordered_active_nics():
509              return nics
510 @@ -1133,6 +1149,7 @@ class TestOvsDpdkBond(base.TestCase):
511  "type": "ovs_dpdk_bond",
512  "name": "dpdkbond0",
513  "use_dhcp": true,
514 +"dpdk_lsc_interrupt": true,
515  "members": [
516      {
517          "type": "ovs_dpdk_port",
518 @@ -1160,6 +1177,7 @@ class TestOvsDpdkBond(base.TestCase):
519          bond = objects.object_from_json(json.loads(data))
520          self.assertEqual("dpdkbond0", bond.name)
521          self.assertTrue(bond.use_dhcp)
522 +        self.assertTrue(bond.dpdk_lsc_interrupt)
523          dpdk_port0 = bond.members[0]
524          self.assertEqual("dpdk0", dpdk_port0.name)
525          self.assertEqual("vfio-pci", dpdk_port0.driver)
526 diff --git a/os_net_config/tests/test_utils.py b/os_net_config/tests/test_utils.py
527 index e09b6f7..66a0e59 100644
528 --- a/os_net_config/tests/test_utils.py
529 +++ b/os_net_config/tests/test_utils.py
530 @@ -110,6 +110,8 @@ class TestUtils(base.TestCase):
531              if 'ethtool' in name:
532                  out = _PCI_OUTPUT
533                  return out, None
534 +            if 'lspci' in name:
535 +                return '', None
536          self.stubs.Set(processutils, 'execute', test_execute)
537          pci = utils.get_pci_address('nic2', False)
538          self.assertEqual('0000:00:19.0', pci)
539 @@ -153,6 +155,8 @@ class TestUtils(base.TestCase):
540              if 'ethtool' in name:
541                  out = _PCI_OUTPUT
542                  return out, None
543 +            if 'lspci' in name:
544 +                return '', None
545              if 'driverctl' in name:
546                  return None, None
547  
548 @@ -171,6 +175,8 @@ class TestUtils(base.TestCase):
549              if 'ethtool' in name:
550                  out = _PCI_OUTPUT
551                  return out, None
552 +            if 'lspci' in name:
553 +                return '', None
554              if 'driverctl' in name:
555                  return None, 'Error'
556  
557 diff --git a/os_net_config/tests/test_validator.py b/os_net_config/tests/test_validator.py
558 index 7991d9f..fd33ca2 100644
559 --- a/os_net_config/tests/test_validator.py
560 +++ b/os_net_config/tests/test_validator.py
561 @@ -264,6 +264,7 @@ class TestDeviceTypes(base.TestCase):
562                  "name": "dpdkbond0",
563                  "mtu": 9000,
564                  "rx_queue": 4,
565 +                "dpdk_lsc_interrupt": "true",
566                  "members": [{
567                      "type": "ovs_dpdk_port",
568                      "name": "dpdk0",
569 diff --git a/os_net_config/utils.py b/os_net_config/utils.py
570 index 27e888d..98e2741 100644
571 --- a/os_net_config/utils.py
572 +++ b/os_net_config/utils.py
573 @@ -216,6 +216,17 @@ def bind_dpdk_interfaces(ifname, driver, noop):
574      pci_address = get_pci_address(ifname, noop)
575      if not noop:
576          if pci_address:
577 +            if is_mellanox(pci_address, noop):
578 +                # Mellanox is binded only with dpdk-devargs and does not need
579 +                # vfio-pci like e.g. Intel Niantic. Just update DPDK map here.
580 +                try:
581 +                    mac_address = interface_mac(ifname)
582 +                    _update_dpdk_map(ifname, pci_address, mac_address, driver)
583 +                except Exception as exp:
584 +                    logger.info('DPDK map update failed: {}'.format(exp))
585 +                    raise
586 +                return
587 +
588              # modbprobe of the driver has to be done before binding.
589              # for reboots, puppet will add the modprobe to /etc/rc.modules
590              if 'vfio-pci' in driver:
591 @@ -252,6 +263,19 @@ def bind_dpdk_interfaces(ifname, driver, noop):
592                      {'name': ifname, 'driver': driver})
593  
594  
595 +def is_mellanox(pci_address, noop):
596 +    if not noop:
597 +        try:
598 +            file_path = '/sys/bus/pci/devices/{}/vendor'.format(pci_address)
599 +            with open(file_path, 'r') as vendor_file:
600 +                if '0x15b3' in vendor_file.read():
601 +                    return True
602 +                else:
603 +                    return False
604 +        except Exception:
605 +            return False
606 +
607 +
608  def get_pci_address(ifname, noop):
609      # TODO(skramaja): Validate if the given interface supports dpdk
610      if not noop:
611 diff --git a/pylintrc b/pylintrc
612 new file mode 100644
613 index 0000000..81b4f50
614 --- /dev/null
615 +++ b/pylintrc
616 @@ -0,0 +1,2 @@
617 +[MESSAGES CONTROL]
618 +disable=E1101,F0401,E0211
619 diff --git a/tox.ini b/tox.ini
620 index 1dd9da1..962540a 100644
621 --- a/tox.ini
622 +++ b/tox.ini
623 @@ -28,6 +28,6 @@ commands = python setup.py build_sphinx
624  # E123, E125 skipped as they are invalid PEP-8.
625  
626  show-source = True
627 -ignore = E123,E125
628 +ignore = E123,E125,E501
629  builtins = _
630  exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build