Merge "Add retry and timeout for VPP interface discovery"

This commit is contained in:
Zuul 2017-10-18 22:08:51 +00:00 committed by Gerrit Code Review
commit 44f3957b9e
2 changed files with 49 additions and 35 deletions

View File

@ -14,6 +14,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import mock
import os
import os.path
import random
@ -354,6 +355,12 @@ class TestUtils(base.TestCase):
self.assertRaises(utils.VppException,
utils._get_vpp_interface_name, '0000:09.0')
@mock.patch('os_net_config.utils.processutils.execute',
return_value=('', None))
def test_get_vpp_interface_name_multiple_iterations(self, mock_execute):
self.assertIsNone(utils._get_vpp_interface_name('0000:00:09.0', 2, 1))
self.assertEqual(4, mock_execute.call_count)
def test_generate_vpp_config(self):
tmpdir = tempfile.mkdtemp()
config_path = os.path.join(tmpdir, 'startup.conf')
@ -406,7 +413,7 @@ dpdk {
return None, None
self.stubs.Set(processutils, 'execute', test_execute)
def test_get_vpp_interface_name(pci_dev):
def test_get_vpp_interface_name(pci_dev, tries, timeout):
return 'GigabitEthernet0/9/0'
self.stubs.Set(utils, '_get_vpp_interface_name',

View File

@ -18,6 +18,7 @@ import glob
import logging
import os
import re
import time
import yaml
from oslo_concurrency import processutils
@ -354,49 +355,51 @@ def restart_vpp(vpp_interfaces):
processutils.execute('systemctl', 'restart', 'vpp')
def _get_vpp_interface_name(pci_addr):
def _get_vpp_interface_name(pci_addr, tries=1, timeout=5):
"""Get VPP interface name from a given PCI address
From a running VPP instance, attempt to find the interface name from
a given PCI address of a NIC.
VppException will be raised if pci_addr is not formatted correctly.
ProcessExecutionError will be raised if VPP interface mapped to pci_addr
is not found.
:param pci_addr: PCI address to lookup, in the form of DDDD:BB:SS.F, where
- DDDD = Domain
- BB = Bus Number
- SS = Slot number
- F = Function
:param tries: Number of tries for getting vppctl output. Defaults to 1.
:param timeout: Timeout in seconds between tries. Defaults to 5.
:return: VPP interface name. None if an interface is not found.
"""
if not pci_addr:
return None
try:
processutils.execute('systemctl', 'is-active', 'vpp')
out, err = processutils.execute('vppctl', 'show', 'interfaces')
m = re.search(r':([0-9a-fA-F]{2}):([0-9a-fA-F]{2}).([0-9a-fA-F])',
pci_addr)
if m:
formatted_pci = "%x/%x/%x" % (int(m.group(1), 16),
int(m.group(2), 16),
int(m.group(3), 16))
else:
raise VppException('Invalid PCI address format: %s' % pci_addr)
for _ in range(tries):
try:
timestamp = time.time()
processutils.execute('systemctl', 'is-active', 'vpp')
out, err = processutils.execute('vppctl', 'show', 'interface')
logger.debug("vppctl show interface\n%s\n%s\n" % (out, err))
m = re.search(r':([0-9a-fA-F]{2}):([0-9a-fA-F]{2}).([0-9a-fA-F])',
pci_addr)
if m:
formatted_pci = "%x/%x/%x" % (int(m.group(1), 16),
int(m.group(2), 16),
int(m.group(3), 16))
else:
raise VppException('Invalid PCI address format: %s' % pci_addr)
m = re.search(r'^(\w+%s)\s+' % formatted_pci, out, re.MULTILINE)
if m:
logger.debug('VPP interface found: %s' % m.group(1))
return m.group(1)
else:
logger.debug('Interface with pci address %s not bound to VPP'
% pci_addr)
return None
except processutils.ProcessExecutionError:
logger.debug('Interface with pci address %s not bound to vpp' %
pci_addr)
m = re.search(r'^(\w+%s)\s+' % formatted_pci, out, re.MULTILINE)
if m:
logger.debug('VPP interface found: %s' % m.group(1))
return m.group(1)
except processutils.ProcessExecutionError:
pass
time.sleep(max(0, (timestamp + timeout) - time.time()))
else:
logger.info('Interface with pci address %s not bound to vpp' %
pci_addr)
return None
def generate_vpp_config(vpp_config_path, vpp_interfaces):
@ -442,11 +445,12 @@ def generate_vpp_config(vpp_config_path, vpp_interfaces):
# If such config line is found, we will replace the line with
# appropriate configuration, otherwise, add a new config line
# in 'dpdk' section of the config.
m = re.search(r'^\s*dev\s+%s\s*(\{[^}]*\})?\s*'
m = re.search(r'^\s*dev\s+%s\s*(\{[^}]*\})?\s*$'
% vpp_interface.pci_dev, data,
re.IGNORECASE | re.MULTILINE)
if m:
data = re.sub(m.group(0), ' dev %s\n' % int_cfg, data)
data = re.sub(m.group(0), ' dev %s\n' % int_cfg, data,
flags=re.MULTILINE)
else:
data = re.sub(r'(^\s*dpdk\s*\{)',
r'\1\n dev %s\n' % int_cfg,
@ -459,13 +463,15 @@ def generate_vpp_config(vpp_config_path, vpp_interfaces):
# configuration, otherwise, add a new line in 'dpdk' section.
m = re.search(r'^\s*uio-driver.*$', data, re.MULTILINE)
if m:
data = re.sub(m.group(0), r' uio-driver %s'
% vpp_interface.uio_driver, data)
data = re.sub(r'^\s*uio-driver.*$', ' uio-driver %s'
% vpp_interface.uio_driver, data,
flags=re.MULTILINE)
else:
data = re.sub(r'(dpdk\s*\{)',
data = re.sub(r'(^\s*dpdk\s*\{)',
r'\1\n uio-driver %s'
% vpp_interface.uio_driver,
data)
data,
flags=re.MULTILINE)
else:
logger.debug('pci address not found for interface %s, may have'
'already been bound to vpp' % vpp_interface.name)
@ -516,7 +522,8 @@ def update_vpp_mapping(vpp_interfaces):
# only trying one more time, can turn into a retry_counter if needed
# in the future.
for i in range(2):
vpp_name = _get_vpp_interface_name(vpp_int.pci_dev)
vpp_name = _get_vpp_interface_name(vpp_int.pci_dev,
tries=12, timeout=5)
if not vpp_name:
restart_vpp(vpp_interfaces)
else: