Adding logging to file

It's important to support logging to a file for troubleshooting purpose.
It's also important to rotate this file as it might grow quite large
over time.

Also, creating a common module where we can move gradually functions
that are common to any other modules. We currently can't import utils
from sriov_config for example because utils is already importing
sriov_config. This leads to duplicate code which is harder to maintain.

Change-Id: Ieafc2adc0247efc47130cd5ea29c59a140feaf0c
This commit is contained in:
David Vallee Delisle 2021-10-29 17:37:14 -04:00
parent 5ed22d9da4
commit aa4ba26cf1
7 changed files with 199 additions and 156 deletions

View File

@ -16,11 +16,11 @@
import argparse
import logging
import os
import sys
import yaml
from os_net_config import common
from os_net_config import impl_eni
from os_net_config import impl_ifcfg
from os_net_config import impl_iproute
@ -29,7 +29,8 @@ from os_net_config import utils
from os_net_config import validator
from os_net_config import version
logger = logging.getLogger(__name__)
logger = common.configure_logger()
_SYSTEM_CTL_CONFIG_FILE = '/etc/sysctl.d/os-net-sysctl.conf'
@ -120,20 +121,6 @@ def parse_opts(argv):
return opts
def configure_logger(verbose=False, debug=False):
LOG_FORMAT = '[%(asctime)s] [%(levelname)s] %(message)s'
DATE_FORMAT = '%Y/%m/%d %I:%M:%S %p'
log_level = logging.WARN
if debug:
log_level = logging.DEBUG
elif verbose:
log_level = logging.INFO
logging.basicConfig(format=LOG_FORMAT, datefmt=DATE_FORMAT,
level=log_level)
def check_configure_sriov(obj):
configure_sriov = False
for member in obj.members:
@ -163,10 +150,12 @@ def get_sriovpf_member_of_bond_ovs_port(obj):
return net_devs_list
def main(argv=sys.argv):
def main(argv=sys.argv, main_logger=None):
opts = parse_opts(argv)
configure_logger(opts.verbose, opts.debug)
logger.info('Using config file at: %s' % opts.config_file)
if not main_logger:
main_logger = common.configure_logger(log_file=not opts.noop)
common.logger_level(main_logger, opts.verbose, opts.debug)
main_logger.info(f"Using config file at: {opts.config_file}")
iface_array = []
configure_sriov = False
sriovpf_member_of_bond_ovs_port_list = []
@ -182,7 +171,7 @@ def main(argv=sys.argv):
provider = impl_iproute.IPRouteNetConfig(noop=opts.noop,
root_dir=opts.root_dir)
else:
logger.error('Invalid provider specified.')
main_logger.error("Invalid provider specified.")
return 1
else:
if os.path.exists('%s/etc/sysconfig/network-scripts/' % opts.root_dir):
@ -192,22 +181,23 @@ def main(argv=sys.argv):
provider = impl_eni.ENINetConfig(noop=opts.noop,
root_dir=opts.root_dir)
else:
logger.error('Unable to set provider for this operating system.')
main_logger.error("Unable to set provider for this operating "
"system.")
return 1
# Read the interface mapping file, if it exists
# This allows you to override the default network naming abstraction
# mappings by specifying a specific nicN->name or nicN->MAC mapping
if os.path.exists(opts.mapping_file):
logger.info('Using mapping file at: %s' % opts.mapping_file)
main_logger.info(f"Using mapping file at: {opts.mapping_file}")
with open(opts.mapping_file) as cf:
iface_map = yaml.safe_load(cf.read())
iface_mapping = iface_map.get("interface_mapping")
logger.debug('interface_mapping JSON: %s' % str(iface_mapping))
main_logger.debug(f"interface_mapping JSON: {str(iface_mapping)}")
persist_mapping = opts.persist_mapping
logger.debug('persist_mapping: %s' % persist_mapping)
main_logger.debug(f"persist_mapping: {persist_mapping}")
else:
logger.info('Not using any mapping file.')
main_logger.info("Not using any mapping file.")
iface_mapping = None
persist_mapping = False
@ -228,22 +218,22 @@ def main(argv=sys.argv):
if requested_nic in mapped_nics.values():
if found is True: # Name matches alias and real NIC
# (return the mapped NIC, but warn of overlap).
logger.warning('"%s" overlaps with real NIC name.'
% (requested_nic))
main_logger.warning(f"{requested_nic} overlaps with "
"real NIC name.")
else:
reported_nics[requested_nic] = requested_nic
found = True
if not found:
retval = 1
if reported_nics:
logger.debug("Interface mapping requested for interface: "
"%s" % reported_nics.keys())
main_logger.debug("Interface mapping requested for interface: "
"%s" % reported_nics.keys())
else:
logger.debug("Interface mapping requested for all interfaces")
main_logger.debug("Interface mapping requested for all interfaces")
reported_nics = mapped_nics
# Return the report on the mapped NICs. If all NICs were found, exit
# cleanly, otherwise exit with status 1.
logger.debug("Interface report requested, exiting after report.")
main_logger.debug("Interface report requested, exiting after report.")
print(reported_nics)
return retval
@ -252,16 +242,17 @@ def main(argv=sys.argv):
try:
with open(opts.config_file) as cf:
iface_array = yaml.safe_load(cf.read()).get("network_config")
logger.debug('network_config JSON: %s' % str(iface_array))
main_logger.debug(f"network_config JSON: {str(iface_array)}")
except IOError:
logger.error("Error reading file: %s" % opts.config_file)
main_logger.error(f"Error reading file: {opts.config_file}")
return 1
else:
logger.error('No config file exists at: %s' % opts.config_file)
main_logger.error(f"No config file exists at: {opts.config_file}")
return 1
if not isinstance(iface_array, list):
logger.error('No interfaces defined in config: %s' % opts.config_file)
main_logger.error("No interfaces defined in config: "
f"{opts.config_file}")
return 1
for iface_json in iface_array:
@ -272,10 +263,10 @@ def main(argv=sys.argv):
validation_errors = validator.validate_config(iface_array)
if validation_errors:
if opts.exit_on_validation_errors:
logger.error('\n'.join(validation_errors))
main_logger.error('\n'.join(validation_errors))
return 1
else:
logger.warning('\n'.join(validation_errors))
main_logger.warning('\n'.join(validation_errors))
# Look for the presence of SriovPF types in the first parse of the json
# if SriovPFs exists then PF devices needs to be configured so that the VF
@ -362,4 +353,4 @@ def main(argv=sys.argv):
if __name__ == '__main__':
sys.exit(main(sys.argv))
sys.exit(main(sys.argv, main_logger=logger))

86
os_net_config/common.py Normal file
View File

@ -0,0 +1,86 @@
# -*- coding: utf-8 -*-
# Copyright 2014 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# Common functions and variables meant to be shared across various modules
# As opposed to utils, this is meant to be imported from anywhere. We can't
# import anything from os_net_config here.
import logging
import logging.handlers
import os
import sys
SYS_CLASS_NET = '/sys/class/net'
_LOG_FILE = '/var/log/os-net-config.log'
def configure_logger(log_file=False, verbose=False, debug=False):
LOG_FORMAT = ('%(asctime)s.%(msecs)03d %(levelname)s '
'%(name)s.%(funcName)s %(message)s')
DATE_FORMAT = '%Y-%m-%d %H:%M:%S'
logger = logging.getLogger("os_net_config")
logger.handlers.clear()
logger_level(logger, verbose, debug)
logger.propagate = True
formatter = logging.Formatter(fmt=LOG_FORMAT, datefmt=DATE_FORMAT)
if log_file:
file_handler = logging.handlers.RotatingFileHandler(
_LOG_FILE, maxBytes=10485760, backupCount=7
)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
stream_handler = logging.StreamHandler(sys.stdout)
stream_handler.setFormatter(formatter)
logger.addHandler(stream_handler)
return logger
def logger_level(logger, verbose=False, debug=False):
log_level = logging.WARN
if debug:
log_level = logging.DEBUG
elif verbose:
log_level = logging.INFO
logger.setLevel(log_level)
def get_dev_path(ifname, path=None):
if not path:
path = ""
elif path.startswith("_"):
path = path[1:]
else:
path = f"device/{path}"
return os.path.join(SYS_CLASS_NET, ifname, path)
def get_vendor_id(ifname):
try:
with open(get_dev_path(ifname, "vendor"), 'r') as f:
out = f.read().strip()
return out
except IOError:
return
def get_device_id(ifname):
try:
with open(get_dev_path(ifname, 'device'), 'r') as f:
out = f.read().strip()
return out
except IOError:
return

View File

@ -22,7 +22,6 @@
# An entry point os-net-config-sriov is added for invocation of this module.
import argparse
import logging
import os
import pyudev
import queue
@ -31,11 +30,12 @@ import sys
import time
import yaml
from os_net_config import common
from os_net_config import sriov_bind_config
from oslo_concurrency import processutils
logger = logging.getLogger(__name__)
_SYS_CLASS_NET = '/sys/class/net'
logger = common.configure_logger()
_UDEV_RULE_FILE = '/etc/udev/rules.d/80-persistent-os-net-config.rules'
_UDEV_LEGACY_RULE_FILE = '/etc/udev/rules.d/70-os-net-config-sriov.rules'
_IFUP_LOCAL_FILE = '/sbin/ifup-local'
@ -112,11 +112,6 @@ def _get_sriov_map():
return sriov_map
def _get_dev_path(ifname, path=None):
path = f"device/{path}" if path else "device"
return os.path.join(_SYS_CLASS_NET, ifname, path)
def _wait_for_vf_creation(pf_name, numvfs):
vf_count = 0
vf_list = []
@ -155,7 +150,7 @@ def get_numvfs(ifname):
:returns: int -- the number of current VFs on ifname
:raises: SRIOVNumvfsException
"""
sriov_numvfs_path = _get_dev_path(ifname, "sriov_numvfs")
sriov_numvfs_path = common.get_dev_path(ifname, "sriov_numvfs")
logger.debug(f"Getting numvfs for interface {ifname}")
try:
with open(sriov_numvfs_path, 'r') as f:
@ -198,7 +193,7 @@ def set_numvfs(ifname, numvfs):
f"{ifname}")
return curr_numvfs
sriov_numvfs_path = _get_dev_path(ifname, "sriov_numvfs")
sriov_numvfs_path = common.get_dev_path(ifname, "sriov_numvfs")
try:
logger.debug(f"Setting {sriov_numvfs_path} to {numvfs}")
with open(sriov_numvfs_path, "w") as f:
@ -305,7 +300,7 @@ def configure_sriov_pf(execution_from_cli=False, restart_openvswitch=False):
item['numvfs'])
# When configuring vdpa, we need to configure switchdev before
# we create the VFs
vendor_id = get_vendor_id(item['name'])
vendor_id = common.get_vendor_id(item['name'])
is_mlnx = vendor_id == MLNX_VENDOR_ID
# Configure switchdev mode when vdpa
if item.get('vdpa') and is_mlnx:
@ -407,7 +402,7 @@ def add_udev_rule_for_legacy_sriov_pf(pf_name, numvfs):
def add_udev_rule_for_vf_representors(pf_name):
logger.info(f"adding udev rules for vf representators {pf_name}")
phys_switch_id_path = os.path.join(_SYS_CLASS_NET, pf_name,
phys_switch_id_path = os.path.join(common.SYS_CLASS_NET, pf_name,
"phys_switch_id")
phys_switch_id = get_file_data(phys_switch_id_path).strip()
pf_pci = get_pf_pci(pf_name)
@ -553,35 +548,26 @@ def _pf_interface_up(pf_device):
run_ip_config_cmd('ip', 'link', 'set', 'dev', pf_device['name'], 'up')
def get_vendor_id(ifname):
try:
with open(_get_dev_path(ifname, "vendor"), 'r') as f:
out = f.read().strip()
return out
except IOError:
return
def get_pf_pci(pf_name):
pf_pci_path = _get_dev_path(pf_name, "uevent")
pf_pci_path = common.get_dev_path(pf_name, "uevent")
pf_info = get_file_data(pf_pci_path)
pf_pci = re.search(r'PCI_SLOT_NAME=(.*)', pf_info, re.MULTILINE).group(1)
return pf_pci
def get_pf_device_id(pf_name):
pf_device_path = _get_dev_path(pf_name, "device")
pf_device_path = common.get_dev_path(pf_name, "device")
pf_device_id = get_file_data(pf_device_path).strip()
return pf_device_id
def get_vf_pcis_list(pf_name):
vf_pcis_list = []
listOfPfFiles = os.listdir(os.path.join(_SYS_CLASS_NET, pf_name,
listOfPfFiles = os.listdir(os.path.join(common.SYS_CLASS_NET, pf_name,
"device"))
for pf_file in listOfPfFiles:
if pf_file.startswith("virtfn"):
vf_info = get_file_data(_get_dev_path(pf_name,
vf_info = get_file_data(common.get_dev_path(pf_name,
f"{pf_file}/uevent"))
vf_pcis_list.append(re.search(r'PCI_SLOT_NAME=(.*)',
vf_info, re.MULTILINE).group(1))
@ -675,30 +661,18 @@ def parse_opts(argv):
return opts
def configure_logger(verbose=False, debug=False):
LOG_FORMAT = '[%(asctime)s] [%(levelname)s] %(message)s'
DATE_FORMAT = '%Y/%m/%d %I:%M:%S %p'
log_level = logging.WARN
if debug:
log_level = logging.DEBUG
elif verbose:
log_level = logging.INFO
logging.basicConfig(format=LOG_FORMAT, datefmt=DATE_FORMAT,
level=log_level)
def main(argv=sys.argv):
def main(argv=sys.argv, main_logger=None):
opts = parse_opts(argv)
configure_logger(opts.verbose, opts.debug)
if not main_logger:
main_logger = common.configure_logger(log_file=True)
common.logger_level(main_logger, opts.verbose, opts.debug)
if opts.numvfs:
if re.match(r"^\w+:\d+$", opts.numvfs):
device_name, numvfs = opts.numvfs.split(':')
set_numvfs(device_name, int(numvfs))
else:
logging.error(f"Invalid arguments for --numvfs {opts.numvfs}")
main_logger.error(f"Invalid arguments for --numvfs {opts.numvfs}")
return 1
else:
# Configure the PF's

View File

@ -17,11 +17,13 @@
from io import StringIO
import os.path
import random
import re
import sys
import yaml
import os_net_config
from os_net_config import cli
from os_net_config import common
from os_net_config import sriov_config
from os_net_config.tests import base
from os_net_config import utils
@ -38,6 +40,9 @@ class TestCli(base.TestCase):
super(TestCli, self).setUp()
rand = str(int(random.random() * 100000))
sriov_config._SRIOV_CONFIG_FILE = '/tmp/sriov_config_' + rand + '.yaml'
common._LOG_FILE = '/tmp/' + rand + 'os_net_config.log'
sys.stdout = StringIO()
sys.stderr = StringIO()
def stub_is_ovs_installed():
return True
@ -46,24 +51,22 @@ class TestCli(base.TestCase):
def tearDown(self):
super(TestCli, self).tearDown()
if os.path.isfile(common._LOG_FILE):
os.remove(common._LOG_FILE)
if os.path.isfile(sriov_config._SRIOV_CONFIG_FILE):
os.remove(sriov_config._SRIOV_CONFIG_FILE)
def run_cli(self, argstr, exitcodes=(0,)):
orig = sys.stdout
orig_stderr = sys.stderr
sys.stdout = StringIO()
sys.stderr = StringIO()
for s in [sys.stdout, sys.stderr]:
s.flush()
s.truncate(0)
s.seek(0)
ret = cli.main(argstr.split())
self.assertIn(ret, exitcodes)
sys.stdout.flush()
sys.stderr.flush()
stdout = sys.stdout.getvalue()
sys.stdout.close()
sys.stdout = orig
stderr = sys.stderr.getvalue()
sys.stderr.close()
sys.stderr = orig_stderr
return (stdout, stderr)
def stub_get_stored_pci_address(self, ifname, noop):
@ -420,6 +423,11 @@ class TestCli(base.TestCase):
self.assertEqual(stdout_yaml, stdout_json)
def test_contrail_vrouter_dpdk_noop_output(self):
timestamp_rex = re.compile(
(r'contrail_vrouter_dpdk\.(yaml|json)|^[\d]{4}-[\d]{2}-[\d]{2} '
r'[\d]{2}:[\d]{2}:[\d]{2}\.[\d]{3} '),
flags=re.M
)
cvi_yaml = os.path.join(SAMPLE_BASE, 'contrail_vrouter_dpdk.yaml')
cvi_json = os.path.join(SAMPLE_BASE, 'contrail_vrouter_dpdk.json')
self.stub_out('os_net_config.utils.get_stored_pci_address',
@ -440,4 +448,6 @@ class TestCli(base.TestCase):
'TYPE=dpdk']
for dev in sanity_devices:
self.assertIn(dev, stdout_yaml)
stdout_yaml = timestamp_rex.sub('', stdout_yaml)
stdout_json = timestamp_rex.sub('', stdout_json)
self.assertEqual(stdout_yaml, stdout_json)

View File

@ -21,6 +21,7 @@ import shutil
import tempfile
from os_net_config import common
from os_net_config import sriov_config
from os_net_config.tests import base
from os_net_config import utils
@ -34,8 +35,9 @@ class TestSriovConfig(base.TestCase):
rand = str(int(random.random() * 100000))
tmpdir = tempfile.mkdtemp()
self.stub_out('os_net_config.sriov_config._SYS_CLASS_NET', tmpdir)
self.stub_out('os_net_config.common.SYS_CLASS_NET', tmpdir)
common._LOG_FILE = '/tmp/' + rand + 'os_net_config.log'
sriov_config._UDEV_RULE_FILE = '/tmp/' + rand + 'etc_udev_rules.d'\
'80-persistent-os-net-config.rules'
sriov_config._UDEV_LEGACY_RULE_FILE = '/tmp/' + rand + 'etc_udev_'\
@ -50,11 +52,13 @@ class TestSriovConfig(base.TestCase):
def tearDown(self):
super(TestSriovConfig, self).tearDown()
if os.path.isfile(common._LOG_FILE):
os.remove(common._LOG_FILE)
if os.path.isfile(sriov_config._SRIOV_CONFIG_FILE):
os.remove(sriov_config._SRIOV_CONFIG_FILE)
if os.path.isfile(sriov_config._IFUP_LOCAL_FILE):
os.remove(sriov_config._IFUP_LOCAL_FILE)
shutil.rmtree(sriov_config._SYS_CLASS_NET)
shutil.rmtree(common.SYS_CLASS_NET)
if os.path.isfile(sriov_config._RESET_SRIOV_RULES_FILE):
os.remove(sriov_config._RESET_SRIOV_RULES_FILE)
if os.path.isfile(sriov_config._ALLOCATE_VFS_FILE):
@ -63,8 +67,8 @@ class TestSriovConfig(base.TestCase):
os.remove(sriov_config._UDEV_LEGACY_RULE_FILE)
def _write_numvfs(self, ifname, numvfs=0):
os.makedirs(sriov_config._get_dev_path(ifname))
numvfs_file = sriov_config._get_dev_path(ifname, 'sriov_numvfs')
os.makedirs(common.get_dev_path(ifname, '_device'))
numvfs_file = common.get_dev_path(ifname, 'sriov_numvfs')
with open(numvfs_file, 'w') as f:
f.write(str(numvfs))
@ -250,7 +254,7 @@ class TestSriovConfig(base.TestCase):
def get_vendor_id_stub(ifname):
return vendor_id
self.stub_out('os_net_config.sriov_config.get_vendor_id',
self.stub_out('os_net_config.common.get_vendor_id',
get_vendor_id_stub)
def configure_switchdev_stub(pf_name):
@ -311,7 +315,6 @@ class TestSriovConfig(base.TestCase):
self._action_order = []
utils.write_yaml_config(sriov_config._SRIOV_CONFIG_FILE, pf_config)
sriov_config.configure_logger(debug=True)
sriov_config.configure_sriov_pf()
self.assertEqual(exp_actions, self._action_order)
f = open(sriov_config._UDEV_LEGACY_RULE_FILE, 'r')
@ -358,7 +361,6 @@ class TestSriovConfig(base.TestCase):
self._action_order = []
utils.write_yaml_config(sriov_config._SRIOV_CONFIG_FILE, pf_config)
sriov_config.configure_logger(debug=True)
sriov_config.configure_sriov_pf()
self.assertEqual(exp_actions, self._action_order)
f = open(sriov_config._UDEV_LEGACY_RULE_FILE, 'r')
@ -406,7 +408,6 @@ class TestSriovConfig(base.TestCase):
self._action_order = []
utils.write_yaml_config(sriov_config._SRIOV_CONFIG_FILE, pf_config)
sriov_config.configure_logger(debug=True)
sriov_config.configure_sriov_pf()
self.assertEqual(exp_actions, self._action_order)
f = open(sriov_config._UDEV_LEGACY_RULE_FILE, 'r')
@ -446,7 +447,6 @@ class TestSriovConfig(base.TestCase):
self._action_order = []
utils.write_yaml_config(sriov_config._SRIOV_CONFIG_FILE, pf_config)
sriov_config.configure_logger(debug=True)
sriov_config.configure_sriov_pf()
self.assertEqual(exp_actions, self._action_order)
self.assertEqual(10, sriov_config.get_numvfs('p2p1'))

View File

@ -22,6 +22,7 @@ import tempfile
from unittest import mock
import yaml
from os_net_config import common
from os_net_config import objects
from os_net_config import sriov_config
from os_net_config.tests import base
@ -29,6 +30,7 @@ from os_net_config import utils
from oslo_concurrency import processutils
_PCI_OUTPUT = '''driver: e1000e
version: 3.2.6-k
firmware-version: 0.13-3
@ -102,7 +104,7 @@ class TestUtils(base.TestCase):
def test_ordered_active_nics(self):
tmpdir = tempfile.mkdtemp()
self.stub_out('os_net_config.utils._SYS_CLASS_NET', tmpdir)
self.stub_out('os_net_config.common.SYS_CLASS_NET', tmpdir)
def test_is_available_nic(interface_name, check_active):
return True
@ -355,7 +357,7 @@ class TestUtils(base.TestCase):
def test_get_vf_devname_net_dir_not_found(self):
tmpdir = tempfile.mkdtemp()
self.stub_out('os_net_config.utils._SYS_CLASS_NET', tmpdir)
self.stub_out('os_net_config.common.SYS_CLASS_NET', tmpdir)
self.assertRaises(utils.SriovVfNotFoundException,
utils.get_vf_devname, "eth1", 1)
@ -363,14 +365,14 @@ class TestUtils(base.TestCase):
def test_get_vf_devname_vf_dir_found_in_map(self):
tmpdir = tempfile.mkdtemp()
self.stub_out('os_net_config.utils._SYS_CLASS_NET', tmpdir)
self.stub_out('os_net_config.common.SYS_CLASS_NET', tmpdir)
def test_get_vf_name_from_map(pf_name, vfid):
return pf_name + '_' + str(vfid)
self.stub_out('os_net_config.utils._get_vf_name_from_map',
test_get_vf_name_from_map)
vf_path = os.path.join(utils._SYS_CLASS_NET, 'eth1/device/virtfn1')
vf_path = os.path.join(common.SYS_CLASS_NET, 'eth1/device/virtfn1')
os.makedirs(vf_path)
self.assertEqual(utils.get_vf_devname("eth1", 1), "eth1_1")
@ -378,14 +380,14 @@ class TestUtils(base.TestCase):
def test_get_vf_devname_vf_dir_not_found(self):
tmpdir = tempfile.mkdtemp()
self.stub_out('os_net_config.utils._SYS_CLASS_NET', tmpdir)
self.stub_out('os_net_config.common.SYS_CLASS_NET', tmpdir)
def test_get_vf_name_from_map(pf_name, vfid):
return None
self.stub_out('os_net_config.utils._get_vf_name_from_map',
test_get_vf_name_from_map)
vf_path = os.path.join(utils._SYS_CLASS_NET, 'eth1/device/virtfn1')
vf_path = os.path.join(common.SYS_CLASS_NET, 'eth1/device/virtfn1')
os.makedirs(vf_path)
self.assertRaises(utils.SriovVfNotFoundException,
@ -394,9 +396,9 @@ class TestUtils(base.TestCase):
def test_get_vf_devname_vf_dir_found(self):
tmpdir = tempfile.mkdtemp()
self.stub_out('os_net_config.utils._SYS_CLASS_NET', tmpdir)
self.stub_out('os_net_config.common.SYS_CLASS_NET', tmpdir)
vf_path = os.path.join(utils._SYS_CLASS_NET,
vf_path = os.path.join(common.SYS_CLASS_NET,
'eth1/device/virtfn1/net/eth1_1')
os.makedirs(vf_path)
@ -448,28 +450,28 @@ class TestUtils(base.TestCase):
def test_get_vendor_id_success(self):
mocked_open = mock.mock_open(read_data='0x15b3\n')
with mock.patch('os_net_config.utils.open', mocked_open, create=True):
vendor = utils.get_vendor_id('nic2')
with mock.patch('os_net_config.common.open', mocked_open, create=True):
vendor = common.get_vendor_id('nic2')
self.assertEqual('0x15b3', vendor)
def test_get_vendor_id_exception(self):
mocked_open = mock.mock_open()
mocked_open.side_effect = IOError
with mock.patch('os_net_config.utils.open', mocked_open, create=True):
vendor = utils.get_vendor_id('nic2')
with mock.patch('os_net_config.common.open', mocked_open, create=True):
vendor = common.get_vendor_id('nic2')
self.assertEqual(None, vendor)
def test_get_device_id_success(self):
mocked_open = mock.mock_open(read_data='0x1003\n')
with mock.patch('os_net_config.utils.open', mocked_open, create=True):
device = utils.get_device_id('nic2')
with mock.patch('os_net_config.common.open', mocked_open, create=True):
device = common.get_device_id('nic2')
self.assertEqual('0x1003', device)
def test_get_device_id_exception(self):
mocked_open = mock.mock_open()
mocked_open.side_effect = IOError
with mock.patch('os_net_config.utils.open', mocked_open, create=True):
device = utils.get_device_id('nic2')
device = common.get_device_id('nic2')
self.assertEqual(None, device)
def test_bind_dpdk_interfaces(self):
@ -636,7 +638,7 @@ class TestUtils(base.TestCase):
def test_ordered_active_nics_with_dpdk_mapping(self):
tmpdir = tempfile.mkdtemp()
self.stub_out('os_net_config.utils._SYS_CLASS_NET', tmpdir)
self.stub_out('os_net_config.common.SYS_CLASS_NET', tmpdir)
tmp_pci_dir = tempfile.mkdtemp()
self.stub_out('os_net_config.utils._SYS_BUS_PCI_DEV', tmp_pci_dir)
physfn_path = utils._SYS_BUS_PCI_DEV + '/0000:05:01.1/physfn'
@ -677,7 +679,7 @@ class TestUtils(base.TestCase):
def test_ordered_active_nics_with_dpdk_mapping_of_vf(self):
tmpdir = tempfile.mkdtemp()
self.stub_out('os_net_config.utils._SYS_CLASS_NET', tmpdir)
self.stub_out('os_net_config.common.SYS_CLASS_NET', tmpdir)
tmp_pci_dir = tempfile.mkdtemp()
self.stub_out('os_net_config.utils._SYS_BUS_PCI_DEV', tmp_pci_dir)
physfn_path = utils._SYS_BUS_PCI_DEV + '/0000:05:01.1/physfn'
@ -721,7 +723,7 @@ class TestUtils(base.TestCase):
self.stub_out('os_net_config.utils.get_stored_pci_address',
test_get_stored_pci_address)
tmpdir = tempfile.mkdtemp()
self.stub_out('os_net_config.utils._SYS_CLASS_NET', tmpdir)
self.stub_out('os_net_config.common.SYS_CLASS_NET', tmpdir)
nic = 'p4p1'
nic_path = os.path.join(tmpdir, nic)
os.makedirs(nic_path)
@ -764,7 +766,7 @@ class TestUtils(base.TestCase):
def test_is_active_nic_for_sriov_vf(self):
tmpdir = tempfile.mkdtemp()
self.stub_out('os_net_config.utils._SYS_CLASS_NET', tmpdir)
self.stub_out('os_net_config.common.SYS_CLASS_NET', tmpdir)
# SR-IOV PF = ens802f0
# SR-IOV VF = enp129s2

View File

@ -21,11 +21,11 @@ import re
import time
import yaml
from os_net_config import common
from os_net_config import sriov_config
from oslo_concurrency import processutils
logger = logging.getLogger(__name__)
_SYS_CLASS_NET = '/sys/class/net'
_SYS_BUS_PCI_DEV = '/sys/bus/pci/devices'
# File to contain the DPDK mapped nics, as nic name will not be available after
# binding driver, which is required for correct nic numbering.
@ -109,14 +109,14 @@ def get_file_data(filename):
def interface_mac(name):
try: # If the iface is part of a Linux bond, the real MAC is only here.
with open(_SYS_CLASS_NET + '/%s/bonding_slave/perm_hwaddr' % name,
with open(common.get_dev_path(name, 'bonding_slave/perm_hwaddr'),
'r') as f:
return f.read().rstrip()
except IOError:
pass # Iface is not part of a bond, continue
try:
with open(_SYS_CLASS_NET + '/%s/address' % name, 'r') as f:
with open(common.get_dev_path(name, '_address'), 'r') as f:
return f.read().rstrip()
except IOError:
# If the interface is bound to a DPDK driver, get the mac address from
@ -137,12 +137,12 @@ def is_real_nic(interface_name):
if interface_name == 'lo':
return True
device_dir = _SYS_CLASS_NET + '/%s/device' % interface_name
device_dir = common.get_dev_path(interface_name, '_device')
has_device_dir = os.path.isdir(device_dir)
address = None
try:
with open(_SYS_CLASS_NET + '/%s/address' % interface_name, 'r') as f:
with open(common.get_dev_path(interface_name, "_address"), 'r') as f:
address = f.read().rstrip()
except IOError:
return False
@ -155,7 +155,7 @@ def is_real_nic(interface_name):
def _is_vf(pci_address):
# If DPDK drivers are bound on a VF, then the path _SYS_CLASS_NET
# If DPDK drivers are bound on a VF, then the path common.SYS_CLASS_NET
# wouldn't exist. Instead we look for the path
# /sys/bus/pci/devices/<PCI addr>/physfn to understand if the device
# is actually a VF. This path could be used by VFs not bound with
@ -167,7 +167,7 @@ def _is_vf(pci_address):
def _is_vf_by_name(interface_name, check_mapping_file=False):
vf_path_check = _SYS_CLASS_NET + '/%s/device/physfn' % interface_name
vf_path_check = common.get_dev_path(interface_name, 'physfn')
is_sriov_vf = os.path.isdir(vf_path_check)
if not is_sriov_vf and check_mapping_file:
sriov_map = _get_sriov_map()
@ -187,7 +187,8 @@ def _is_available_nic(interface_name, check_active=True):
return False
operstate = None
with open(_SYS_CLASS_NET + '/%s/operstate' % interface_name, 'r') as f:
with open(common.get_dev_path(interface_name, '_operstate'),
'r') as f:
operstate = f.read().rstrip().lower()
if check_active and operstate != 'up':
return False
@ -231,8 +232,8 @@ def _ordered_nics(check_active):
embedded_nics = []
nics = []
logger.info("Finding active nics")
for name in glob.iglob(_SYS_CLASS_NET + '/*'):
nic = name[(len(_SYS_CLASS_NET) + 1):]
for name in glob.iglob(common.SYS_CLASS_NET + '/*'):
nic = name[(len(common.SYS_CLASS_NET) + 1):]
if _is_available_nic(nic, check_active):
if _is_embedded_nic(nic):
logger.info("%s is an embedded active nic" % nic)
@ -304,7 +305,7 @@ def bind_dpdk_interfaces(ifname, driver, noop):
raise OvsDpdkBindException(msg)
mac_address = interface_mac(ifname)
vendor_id = get_vendor_id(ifname)
vendor_id = common.get_vendor_id(ifname)
try:
out, err = processutils.execute('driverctl', 'set-override',
pci_address, driver)
@ -382,29 +383,9 @@ def translate_ifname_to_pci_address(ifname, noop):
return pci_address
def get_vendor_id(ifname):
try:
with open('%s/%s/device/vendor' % (_SYS_CLASS_NET, ifname),
'r') as f:
out = f.read().strip()
return out
except IOError:
return
def get_device_id(ifname):
try:
with open('%s/%s/device/device' % (_SYS_CLASS_NET, ifname),
'r') as f:
out = f.read().strip()
return out
except IOError:
return
def is_mellanox_interface(ifname):
MLNX_VENDOR_ID = "0x15b3"
vendor_id = get_vendor_id(ifname)
vendor_id = common.get_vendor_id(ifname)
if vendor_id == MLNX_VENDOR_ID:
return True
return False
@ -412,7 +393,7 @@ def is_mellanox_interface(ifname):
def get_interface_driver(ifname):
try:
uevent = '%s/%s/device/uevent' % (_SYS_CLASS_NET, ifname)
uevent = common.get_dev_path(ifname, 'device/uevent')
with open(uevent, 'r') as f:
out = f.read().strip()
for line in out.split('\n'):
@ -426,8 +407,8 @@ def get_interface_driver(ifname):
def get_dpdk_devargs(ifname, noop):
if not noop:
vendor_id = get_vendor_id(ifname)
device_id = get_device_id(ifname)
vendor_id = common.get_vendor_id(ifname)
device_id = common.get_device_id(ifname)
if vendor_id == "0x15b3":
logger.info("Getting devargs for Mellanox cards")
if device_id == "0x1007":
@ -446,7 +427,6 @@ def get_dpdk_devargs(ifname, noop):
# be treated the same as VFs of other devices
dpdk_devargs = get_pci_address(ifname, noop)
else:
logger.error("Unable to get devargs for interface %s" % ifname)
msg = ("Unable to get devargs for interface %s" % ifname)
raise InvalidInterfaceException(msg)
else:
@ -646,8 +626,8 @@ def configure_sriov_vfs():
def get_vf_devname(pf_name, vfid):
vf_path = os.path.join(_SYS_CLASS_NET, pf_name, "device/virtfn%d/net"
% vfid)
vf_path = os.path.join(common.SYS_CLASS_NET, pf_name,
f"device/virtfn{vfid}/net")
if os.path.isdir(vf_path):
vf_nic = os.listdir(vf_path)
else: