Пример #1
0
def main(argv=sys.argv, main_logger=None):
    opts = parse_opts(argv)
    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:
            main_logger.error(f"Invalid arguments for --numvfs {opts.numvfs}")
            return 1
    else:
        # Configure the PF's
        configure_sriov_pf()
        # Configure the VFs
        configure_sriov_vf()
Пример #2
0
def main(argv=sys.argv, main_logger=None):
    opts = parse_opts(argv)
    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 = []
    provider = None
    if opts.provider:
        if opts.provider == 'ifcfg':
            provider = impl_ifcfg.IfcfgNetConfig(noop=opts.noop,
                                                 root_dir=opts.root_dir)
        elif opts.provider == 'eni':
            provider = impl_eni.ENINetConfig(noop=opts.noop,
                                             root_dir=opts.root_dir)
        elif opts.provider == 'iproute':
            provider = impl_iproute.IPRouteNetConfig(noop=opts.noop,
                                                     root_dir=opts.root_dir)
        else:
            main_logger.error("Invalid provider specified.")
            return 1
    else:
        if os.path.exists('%s/etc/sysconfig/network-scripts/' % opts.root_dir):
            provider = impl_ifcfg.IfcfgNetConfig(noop=opts.noop,
                                                 root_dir=opts.root_dir)
        elif os.path.exists('%s/etc/network/' % opts.root_dir):
            provider = impl_eni.ENINetConfig(noop=opts.noop,
                                             root_dir=opts.root_dir)
        else:
            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):
        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")
            main_logger.debug(f"interface_mapping: {iface_mapping}")
            persist_mapping = opts.persist_mapping
            main_logger.debug(f"persist_mapping: {persist_mapping}")
    else:
        main_logger.info("Not using any mapping file.")
        iface_mapping = None
        persist_mapping = False

    # If --interfaces is specified, either return the real name of the
    # interfaces specified, or return the map of all nic abstractions/names.
    if opts.interfaces is not None:
        reported_nics = {}
        mapped_nics = objects.mapped_nics(iface_mapping)
        retval = 0
        if len(opts.interfaces) > 0:
            for requested_nic in opts.interfaces:
                found = False
                # Check to see if requested iface is a mapped NIC name.
                if requested_nic in mapped_nics:
                    reported_nics[requested_nic] = mapped_nics[requested_nic]
                    found = True
                # Check to see if the requested iface is a real NIC name
                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).
                        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:
                main_logger.debug("Interface mapping requested for interface: "
                                  "%s" % reported_nics.keys())
        else:
            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.
        main_logger.debug("Interface report requested, exiting after report.")
        print(json.dumps(reported_nics))
        return retval

    # Read config file containing network configs to apply
    if os.path.exists(opts.config_file):
        try:
            with open(opts.config_file) as cf:
                iface_array = yaml.safe_load(cf.read()).get("network_config")
                main_logger.debug(f"network_config: {iface_array}")
        except IOError:
            main_logger.error(f"Error reading file: {opts.config_file}")
            return 1
    else:
        main_logger.error(f"No config file exists at: {opts.config_file}")
        return 1

    if not isinstance(iface_array, list):
        main_logger.error("No interfaces defined in config: "
                          f"{opts.config_file}")
        return 1

    for iface_json in iface_array:
        if iface_json.get('type') != 'route_table':
            iface_json.update({'nic_mapping': iface_mapping})
            iface_json.update({'persist_mapping': persist_mapping})

    validation_errors = validator.validate_config(iface_array)
    if validation_errors:
        if opts.exit_on_validation_errors:
            main_logger.error('\n'.join(validation_errors))
            return 1
        else:
            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
    # devices are created.
    # The VFs will not be available now and an exception
    # SriovVfNotFoundException will be raised while fetching the device name.
    # After the first parse the SR-IOV PF devices would be configured and the
    # VF devices would be created.
    # In the second parse, all other objects shall be added
    for iface_json in iface_array:
        try:
            obj = objects.object_from_json(iface_json)
        except utils.SriovVfNotFoundException:
            continue
        if isinstance(obj, objects.SriovPF):
            configure_sriov = True
            provider.add_object(obj)
        elif hasattr(obj, 'members') and obj.members is not None:
            if check_configure_sriov(obj):
                configure_sriov = True
                provider.add_object(obj)

                sriovpf_member_of_bond_ovs_port_list.extend(
                    get_sriovpf_member_of_bond_ovs_port(obj))

    # After reboot, shared_block for pf interface in switchdev mode will be
    # missing in case IPv6 is enabled on the slaves of the bond and that bond
    # is an ovs port. This is due to the fact that OVS assumes another entity
    # manages the slaves.
    # So as a workaround for that case we are disabling IPv6 over pfs so that
    # OVS creates the shared_blocks ingress
    if sriovpf_member_of_bond_ovs_port_list:
        disable_ipv6_for_netdevs(sriovpf_member_of_bond_ovs_port_list)

    if configure_sriov:
        # Apply the ifcfgs for PFs now, so that NM_CONTROLLED=no is applied
        # for each of the PFs before configuring the numvfs for the PF device.
        # This step allows the network manager to unmanage the created VFs.
        # In the second parse, when these ifcfgs for PFs are encountered,
        # os-net-config skips the ifup <ifcfg-pfs>, since the ifcfgs for PFs
        # wouldn't have changed.
        pf_files_changed = provider.apply(cleanup=opts.cleanup,
                                          activate=not opts.no_activate)
        if not opts.noop:
            restart_ovs = bool(sriovpf_member_of_bond_ovs_port_list)
            # Avoid ovs restart for os-net-config re-runs, which will
            # dirupt the offload configuration
            if os.path.exists(utils._SRIOV_CONFIG_SERVICE_FILE):
                restart_ovs = False

            utils.configure_sriov_pfs(
                execution_from_cli=True,
                restart_openvswitch=restart_ovs)

    for iface_json in iface_array:
        # All objects other than the sriov_pf will be added here.
        # The VFs are expected to be available now and an exception
        # SriovVfNotFoundException shall be raised if not available.
        try:
            obj = objects.object_from_json(iface_json)
        except utils.SriovVfNotFoundException:
            if not opts.noop:
                raise
        if not isinstance(obj, objects.SriovPF):
            provider.add_object(obj)

    if configure_sriov and not opts.noop:
        utils.configure_sriov_vfs()

    files_changed = provider.apply(cleanup=opts.cleanup,
                                   activate=not opts.no_activate)
    if opts.noop:
        if configure_sriov:
            files_changed.update(pf_files_changed)
        for location, data in files_changed.items():
            print("File: %s\n" % location)
            print(data)
            print("----")

    if opts.detailed_exit_codes and len(files_changed) > 0:
        return 2

    return 0
Пример #3
0
import argparse
import json
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
from os_net_config import objects
from os_net_config import utils
from os_net_config import validator
from os_net_config import version

logger = common.configure_logger()

_SYSTEM_CTL_CONFIG_FILE = '/etc/sysctl.d/os-net-sysctl.conf'


def parse_opts(argv):
    parser = argparse.ArgumentParser(
        description='Configure host network interfaces using a JSON'
        ' config file format.')
    parser.add_argument('-c', '--config-file', metavar='CONFIG_FILE',
                        help="""path to the configuration file.""",
                        default='/etc/os-net-config/config.yaml')
    parser.add_argument('-m', '--mapping-file', metavar='MAPPING_FILE',
                        help="""path to the interface mapping file.""",
                        default='/etc/os-net-config/mapping.yaml')
    parser.add_argument('-i', '--interfaces', metavar='INTERFACES',