diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index e018cc09..00000000 --- a/.coveragerc +++ /dev/null @@ -1,7 +0,0 @@ -[run] -branch = True -source = os_net_config -omit = os_net_config/tests/* - -[report] -ignore_errors = True diff --git a/.gitignore b/.gitignore deleted file mode 100644 index e7c7ed90..00000000 --- a/.gitignore +++ /dev/null @@ -1,53 +0,0 @@ -*.py[cod] - -# C extensions -*.so - -# Packages -*.egg* -dist -build -eggs -parts -bin -var -sdist -develop-eggs -.installed.cfg -lib -lib64 - -# Installer logs -pip-log.txt - -# Unit test / coverage reports -.coverage -.tox -.stestr/ -cover - -# Translations -*.mo - -# Mr Developer -.mr.developer.cfg -.project -.pydevproject - -# Complexity -output/*.html -output/*/index.html - -# Sphinx -doc/build - -# pbr generates these -AUTHORS -ChangeLog - -# Editors -*~ -.*.swp - -# Visual Studio Code -.vscode diff --git a/.mailmap b/.mailmap deleted file mode 100644 index cc92f17b..00000000 --- a/.mailmap +++ /dev/null @@ -1,3 +0,0 @@ -# Format is: -# -# \ No newline at end of file diff --git a/.stestr.conf b/.stestr.conf deleted file mode 100644 index 49d5a09d..00000000 --- a/.stestr.conf +++ /dev/null @@ -1,4 +0,0 @@ -[DEFAULT] -test_path=./os_net_config/tests -top_dir=./ - diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index 0e3f19be..00000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,16 +0,0 @@ -If you would like to contribute to the development of OpenStack, -you must follow the steps in this page: - -https://docs.openstack.org/infra/manual/developers.html - -Once those steps have been completed, changes to OpenStack -should be submitted for review via the Gerrit tool, following -the workflow documented at: - -https://docs.openstack.org/infra/manual/developers.html#development-workflow - -Pull requests submitted through GitHub will be ignored. - -Bugs should be filed on Launchpad, not GitHub: - -https://bugs.launchpad.net/os-net-config diff --git a/HACKING.rst b/HACKING.rst deleted file mode 100644 index 31be2839..00000000 --- a/HACKING.rst +++ /dev/null @@ -1,4 +0,0 @@ -os-net-config Style Commandments -================================ - -Read the OpenStack Style Commandments https://docs.openstack.org/hacking/latest/ diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 67db8588..00000000 --- a/LICENSE +++ /dev/null @@ -1,175 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. diff --git a/README.rst b/README.rst index 382de0f7..4ee2c5f1 100644 --- a/README.rst +++ b/README.rst @@ -1,36 +1,10 @@ -============= -os-net-config -============= +This project is no longer maintained. -Team and repository tags ------------------------- +The contents of this repository are still available in the Git +source code management system. To see the contents of this +repository before it reached its end of life, please check out the +previous commit with "git checkout HEAD^1". -.. image:: https://governance.openstack.org/tc/badges/os-net-config.svg - :target: https://governance.openstack.org/tc/reference/tags/index.html - -Overview --------- - -``os-net-config`` is a host network configuration tool which supports multiple -backend configuration providers. - -* Documentation: https://docs.openstack.org/os-net-config/latest -* Source: https://opendev.org/openstack/os-net-config -* Bugs: https://bugs.launchpad.net/os-net-config -* Release Notes: https://docs.openstack.org/releasenotes/os-net-config -* Free software: Apache License (2.0) - - -Features --------- - -The core aim of this project is to allow fine grained (but extendable) -configuration of the networking parameters for a network host. The -project consists of: - -* A CLI (os-net-config) which provides configuration via a YAML or JSON - file formats. By default os-net-config uses a YAML config file located - at /etc/os-net-config/config.yaml. This can be customized via the - --config-file CLI option. - -* A python library which provides configuration via an object model. \ No newline at end of file +For any further questions, please email +openstack-discuss@lists.openstack.org or join #openstack-dev on +OFTC. diff --git a/babel.cfg b/babel.cfg deleted file mode 100644 index efceab81..00000000 --- a/babel.cfg +++ /dev/null @@ -1 +0,0 @@ -[python: **.py] diff --git a/bindep.txt b/bindep.txt deleted file mode 100644 index d74079fa..00000000 --- a/bindep.txt +++ /dev/null @@ -1,9 +0,0 @@ -# This is a cross-platform list tracking distribution packages needed for -# install and tests; -# see https://docs.openstack.org/infra/bindep/ for additional information. - -ethtool -nmstate [platform:rpm] -NetworkManager-ovs [platform:rpm] -python3-libnmstate [platform:rpm] -nmstate-libs [platform:rpm] diff --git a/doc/requirements.txt b/doc/requirements.txt deleted file mode 100644 index eccc937c..00000000 --- a/doc/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -sphinx>=2.0.0,!=2.1.0 # BSD -openstackdocstheme>=2.2.1 # Apache-2.0 diff --git a/doc/source/conf.py b/doc/source/conf.py deleted file mode 100755 index 4dba6bef..00000000 --- a/doc/source/conf.py +++ /dev/null @@ -1,81 +0,0 @@ -# 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. - -import os -import sys - -sys.path.insert(0, os.path.abspath('../..')) -# -- General configuration ---------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = [ - 'sphinx.ext.autodoc', - #'sphinx.ext.intersphinx', - 'openstackdocstheme' -] - -# openstackdocstheme options -openstackdocs_repo_name = 'openstack/os-net-config' -openstackdocs_auto_name = False -openstackdocs_bug_project = 'os-net-config' -openstackdocs_bug_tag = '' -html_theme = 'openstackdocs' - -# autodoc generation is a bit aggressive and a nuisance when doing heavy -# text edit cycles. -# execute "export SPHINX_DEBUG=1" in your terminal to disable - -# The suffix of source filenames. -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = 'os-net-config' -copyright = '2013, OpenStack Foundation' - -# If true, '()' will be appended to :func: etc. cross-reference text. -add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -add_module_names = True - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'native' - -# -- Options for HTML output -------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. Major themes that come with -# Sphinx are currently 'default' and 'sphinxdoc'. -# html_theme_path = ["."] -# html_theme = '_theme' -# html_static_path = ['static'] - -# Output file base name for HTML help builder. -htmlhelp_basename = '%sdoc' % project - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass -# [howto/manual]). -latex_documents = [ - ('index', - '%s.tex' % project, - '%s Documentation' % project, - 'OpenStack Foundation', 'manual'), -] - -# Example configuration for intersphinx: refer to the Python standard library. -#intersphinx_mapping = {'http://docs.python.org/': None} diff --git a/doc/source/config.rst b/doc/source/config.rst deleted file mode 100644 index 6b09f454..00000000 --- a/doc/source/config.rst +++ /dev/null @@ -1,487 +0,0 @@ -=============================== -Network configuration reference -=============================== - -This section describes the supported ``/etc/os-net-config/config.yaml`` YAML -format and how they map to networking backend providers. The root element is -a ``network_config`` attribute, and the value is an array of dicts entries -describing the physical and virtual interfaces to configure. Each interface -entry has a mandatory ``type`` attribute, and the value determines what other -attributes are supported for that type. - -.. _common-attributes: - -Common attributes ------------------ - -The following attributes are used in many types. See :ref:`multiple-nics` for -examples. - -addresses -========= - -A list of ``ip_netmask`` entries to specify the network addresses for this -interface. For example: - - .. code-block:: yaml - - addresses: - - ip_netmask: 192.0.2.2/24 - - ip_netmask: 192.0.3.2/32 - -ifcfg implementation -^^^^^^^^^^^^^^^^^^^^ - -Sets ``BOOTPROTO=static`` and populates ``IPADDR`` and ``NETMASK, followed by -``IPADDR``, ``NETMASK`` for subsequent addresses with ```` incrementing -from ``1``. - -defroute -======== - -A boolean which defaults to ``true``. When ``false`` the default route given by an -IPV4 DHCP server will be ignored. - -ifcfg implementation -^^^^^^^^^^^^^^^^^^^^ - -Sets ``DEFROUTE=no`` when set to ``false``. - -dhclient_args -============= - -Arguments to append to the call to the dhclient command, as a single string. - -ifcfg implementation -^^^^^^^^^^^^^^^^^^^^ - -Sets ``DHCLIENTARGS`` to the supplied value - -dns_servers -=========== - -A list of DNS servers (maximum of 2) to use for name resolution. - -ifcfg implementation -^^^^^^^^^^^^^^^^^^^^ - -Sets ``DNS1``, ``DNS2`` to support up to 2 DNS resolvers. - -domain -====== - -A string or a list of strings containing DNS search domains - -ifcfg implementation -^^^^^^^^^^^^^^^^^^^^ - -Sets ``DOMAIN`` containing all values as a space-separated list. - -mtu -=== - -Maximum transmission unit for this interface. - -ifcfg implementation -^^^^^^^^^^^^^^^^^^^^ - -Sets ``MTU`` to the specified value. If unspecified the default is ``1500``. - -name -==== - -This is the name for the interface which is one of: - -- the name of existing physical interface (NIC) -- the identifier from the mapping file which maps to a NIC -- the desired name of a bridge or bond -- a numbered identifier ``nic`` starting with ``1`` for each active NIC: - ``nic1``, ``nic2`` etc - - -ifcfg implementation -^^^^^^^^^^^^^^^^^^^^ - -When the name is an identifier in the mapping file or a ``nic`` -identifier, the actual name used will be the mapping value, not the -identifier. - -The name format of a physical interfaces depends on ``biosdevname`` or -``net.ifnames`` sysctl settings or udev rules for persistent names. Names -will begin with ``eth`` if both sysctl settings are disabled and there are no -udev rules. The sort order used to allocate ``nic`` identifiers are: - -- Embedded interfaces first (``em``, ``eth``, ``eno``) ordered - alphanumerically -- Then, other active NICs ordered alphanumerically - -Each interface definition is written to -``/etc/sysconfig/network-scripts/ifcfg-`` and the first value in the -file is ``DEVICE=``. - -nm_controlled -============= - -Boolean whether this interface is managed by `NetworkManager`_, defaults to -``false``. - -ifcfg implementation -^^^^^^^^^^^^^^^^^^^^ - -Sets ``NM_CONTROLLED=yes`` or ``NM_CONTROLLED=no`` - -onboot -====== - -Boolean which determines whether to enable the interface on machine boot, -defaults to ``true``. - -ifcfg implementation -^^^^^^^^^^^^^^^^^^^^ - -Sets ``ONBOOT=yes`` or ``ONBOOT=no``. - -primary -======= - -In the ``members`` entries for a bond or bridge this may be set to ``true`` -for the primary interface. This results in the bond or bridge inheriting the MAC -address of the primary interface. - -routes -====== - -A list of route entries for this interface containing attributes: - -- ``default`` Boolean whether this is the default route for this interface -- ``ip_netmask`` or ``destination`` Destination network address when ``default`` - is ``false`` -- ``next_hop`` or ``nexthop`` Gateway address for route destination - -Other supported attributes include: - -- ``route_table`` The table ID or name to add this route to -- ``route_options`` String of extra options to append to the end of the route - -For example: - - .. code-block:: yaml - - routes: - - default: true - next_hop: 198.51.100.1 - - ip_netmask: 192.0.2.2/24 - next_hop: 203.0.113.254 - route_table: 2 - route_options: metric 100 - -ifcfg implementation -^^^^^^^^^^^^^^^^^^^^ - -A routes file for each interface definition is written to -``/etc/sysconfig/network-scripts/route-``. - -rules -===== - -A list of commented route rules, for example: - - .. code-block:: yaml - - rules: - - rule: "iif em1 table 200" - comment: "Route incoming traffic to em1 with table 200" - - rule: "from 192.0.2.0/24 table 200" - comment: "Route all traffic from 192.0.2.0/24 with table 200" - - rule: "add blackhole from 172.19.40.0/24 table 200" - - rule: "add unreachable iif em1 from 192.168.1.0/24" - -ifcfg implementation -^^^^^^^^^^^^^^^^^^^^ - -Each interface is iterated in order and its rules are compared to existing -rules then converged by running ``ip rule del `` and ``ip rule add -``. - -use_dhcp -======== - -Boolean for whether to use DHCP for the IPv4 boot protocol. - -ifcfg implementation -^^^^^^^^^^^^^^^^^^^^ - -Sets ``PEERDNS=no`` when ``false``. - -use_dhcpv6 -========== - -Boolean for whether to use DHCP for the IPv6 boot protocol. - -ifcfg implementation -^^^^^^^^^^^^^^^^^^^^ - -Sets ``DHCPV6C=yes`` when ``true``. - -.. - Undocumented: - rules - nic_mapping - persist_mapping - - -.. _ovs-attributes: - -Open vSwitch attributes ------------------------ - -The `Open vSwitch`_ types support some or all of these attributes: - -.. _ovs-options: - -ovs_options -=========== - -String of other options to pass to Open vSwitch for this bond or bridge. - -ifcfg implementation -^^^^^^^^^^^^^^^^^^^^ - -Sets the ``OVS_OPTIONS`` value. - -.. _ovs-extra: - -ovs_extra -========= - -A list of extra options to pass to Open vSwitch. - -ifcfg implementation -^^^^^^^^^^^^^^^^^^^^ - -Will set the ``OVS_EXTRA`` value with all the provided values. - -ovs_fail_mode -============= - -Failure mode for a bridge, defaults to ``standard``, can also be set to ``secure`` - -ifcfg implementation -^^^^^^^^^^^^^^^^^^^^ - -Will be appended to the ``OVS_OPTIONS`` value and the concatenated list of -``OVS_EXTRA`` values. - -type: interface ---------------- - -Configures a physical NIC. See :ref:`multiple-nics` for examples. All of the -:ref:`common-attributes` can be used with this type along with the following -attributes: - -ethtool_opts -============ - -Device-specific options supported by `ethtool`_. - -ifcfg implementation -^^^^^^^^^^^^^^^^^^^^ - -Sets ``ETHTOOL_OPTS`` to the value. - -hotplug -======= - -A boolean for whether to activate the device when it is plugged in. - -ifcfg implementation -^^^^^^^^^^^^^^^^^^^^ - -Sets ``HOTPLUG=yes`` or ``HOTPLUG=no`` - -linkdelay -========= - -Integer number of seconds to wait for link negotiation before configuring -the device. - -ifcfg implementation -^^^^^^^^^^^^^^^^^^^^ - -Sets ``LINKDELAY`` to the delay value. - -type: ovs_bridge ----------------- - -Configures an `Open vSwitch`_ bridge. See :ref:`control-plane-bridge` for an -example. All of the :ref:`common-attributes` and :ref:`ovs-attributes` can be -used with this type. The ``members`` attribute contains a list of entries for -interfaces to bridge typically of ``type``: - -- ``interface`` -- ``linux_bond`` -- ``ovs_bond`` -- ``vlan`` -- other Open vSwitch internal interfaces - - -ifcfg implementation -==================== - -Values ``DEVICETYPE=ovs`` and ``TYPE=OVSBridge`` are set. When ``use_dhcp`` -or ``use_dhcpv6`` is ``true``, ``OVSBOOTPROTO=dhcp`` is set and -``OVSDHCPINTERFACES`` is populated. - -type: ovs_bond --------------- - -Configures an `Open vSwitch`_ bond. See :ref:`ovs-bond` for an example. All -of the :ref:`common-attributes` and :ref:`ovs-attributes` can be used with -this type. The ``members`` attribute contains a list of entries for -interfaces to be bonded. - -ifcfg implementation -==================== - -Values ``DEVICETYPE=ovs`` and ``TYPE=OVSBridge`` are set. When ``use_dhcp`` -or ``use_dhcpv6`` is ``true``, ``OVSBOOTPROTO=dhcp`` is set and -``OVSDHCPINTERFACES`` is populated. - -type: vlan ----------- - -Configures VLAN tagging for one VLAN. See :ref:`bonds-with-vlans` for an -example. :ref:`common-attributes` are supported but generally only ``mtu``, -``addresses`` or ``routes`` are used. - -Other attributes for ``vlan`` are: - -device -====== - -The ``name`` of an existing interface entry, which will typically be of -``type: interface``, ``type: ovs_bond``, or ``type: linux_bond``. Usually -``device`` is only used when the VLAN is not part of an ``ovs_bridge``. A -VLAN on an ``ovs_bridge`` is part of the ``members`` list for the bridge, -where a Linux VLAN is associated with an ``interface`` or ``linux_bond`` -using the ``device`` parameter. - -vlan_id -======= - -The VLAN ID to tag when passing through the ``device`` interface. - -ifcfg implementation -==================== - -Sets ``VLAN=yes`` and ``PHYSDEV`` to the ``device`` value. - -type: linux_bridge ------------------- - -Configures a `Linux bridge`_. See :ref:`linux-bridge` for an example. All of -the :ref:`common-attributes` can be used with this type. The ``members`` -attribute contains a list of entries for interfaces to bridge. - -ifcfg implementation -==================== - -Sets ``TYPE=Bridge`` and ``DELAY=0``. The MAC address of the ``members`` -interface which has ``primary: true`` will be used for the ``MACADDR`` value. - -type: linux_bond ----------------- - -Configures a `Linux bond`_. See :ref:`bonds-vlans-dpdk` for an example. All -of the :ref:`common-attributes` can be used with this type. The ``members`` -attribute contains a list of entries for interfaces to be bonded. - -Extra bonding options are specified in the ``bonding_options`` string. - -ifcfg implementation -==================== - -The MAC address of the ``members`` interface which has ``primary: true`` will -be used for the ``MACADDR`` value. ``BONDING_OPTS`` will contain the value of the -``bonding_options`` attribute. - -type: ovs_user_bridge ---------------------- - -Configures an `Open vSwitch`_ bridge where the members are user ports. This -is generally used to set up `DPDK vHost User Ports`_. See -:ref:`bonds-vlans-dpdk` for an example. All of the :ref:`common-attributes` -and :ref:`ovs-attributes` can be used with this type. The ``members`` -attribute usually contains a single ``type: ovs_dpdk_bond`` entry. - -ifcfg implementation -==================== - -Values ``DEVICETYPE=ovs`` and ``TYPE=OVSUserBridge`` are set. When ``use_dhcp`` -or ``use_dhcpv6`` is ``true``, ``OVSBOOTPROTO=dhcp`` is set and -``OVSDHCPINTERFACES`` is populated. - -Each ``members`` interface also has ``OVS_BRIDGE`` set, as well as other -values depending on the type of the member. - -type: ovs_dpdk_bond -------------------- - -Configures an `Open vSwitch`_ bond for binding DPDK ports. See -:ref:`bonds-vlans-dpdk` for an example. All of the :ref:`common-attributes` -and :ref:`ovs-attributes` can be used with this type. The ``members`` -attribute contains a list of ``type: ovs_dpdk_port`` ports to be bonded. The -value for attribute ``rx_queue`` will determine the RX queue length. - -ifcfg implementation -==================== - -Values ``DEVICETYPE=ovs``, ``TYPE=OVSDPDKBond``, and ``RX_QUEUE`` are set. -``BOND_IFACES`` is populated with the ``name`` of all members. ``OVS_EXTRA`` -is extended with a ``set Interface...`` directive for each member. - -type: ovs_dpdk_port -------------------- - -Creates an Open vSwitch DPDK port, usually in the ``members`` of a ``type: -ovs_dpdk_bond`` bond interface. See :ref:`bonds-vlans-dpdk` for an example. -All of the :ref:`common-attributes` and :ref:`ovs-attributes` can be used -with this type. Each port must have a ``members`` list with a single -interface entry. A port can have its own ``rx_queue`` specifed. The -``driver`` attribute can override the default kernel driver module of -``vfio-pci``. - -ifcfg implementation -==================== - -Values ``DEVICETYPE=ovs`` and ``TYPE=OVSDPDKPort``, and ``RX_QUEUE`` are set. -``OVS_EXTRA`` is extended with a ``set Interface...`` directive for the one -``members`` interface. - -.. - Undocumented types: - route_table - route_rule - team - ivs_bridge - ivs_interface - nfvswitch_bridge - nfvswitch_internal - ovs_tunnel - ovs_patch_port - ib_interface - ib_child_interface - vpp_interface - vpp_bond - contrail_vrouter - contrail_vrouter_dpdk - sriov_pf - sriov_vf - linux_tap - -.. _NetworkManager: https://en.wikipedia.org/wiki/NetworkManager -.. _ethtool: https://en.wikipedia.org/wiki/Ethtool -.. _Open vSwitch: https://www.openvswitch.org/ -.. _Linux bridge: https://wiki.linuxfoundation.org/networking/bridge -.. _Linux bond: https://wiki.linuxfoundation.org/networking/bonding -.. _DPDK vHost User Ports: https://docs.openvswitch.org/en/latest/topics/dpdk/vhost-user/ diff --git a/doc/source/contributing.rst b/doc/source/contributing.rst deleted file mode 100644 index ed77c126..00000000 --- a/doc/source/contributing.rst +++ /dev/null @@ -1,4 +0,0 @@ -============ -Contributing -============ -.. include:: ../../CONTRIBUTING.rst \ No newline at end of file diff --git a/doc/source/examples.rst b/doc/source/examples.rst deleted file mode 100644 index e193f69c..00000000 --- a/doc/source/examples.rst +++ /dev/null @@ -1,206 +0,0 @@ -====================== -Example configurations -====================== - -.. _multiple-nics: - -Multiple NICs -------------- - - .. code-block:: yaml - - network_config: - - type: interface - name: nic1 - mtu: 1500 - dns_servers: 8.8.8.8 - domain: example.com - routes: - - default: true - next_hop: 198.51.100.1 - - ip_netmask: 192.0.2.2/24 - next_hop: 203.0.113.254 - use_dhcp: false - addresses: - - ip_netmask: 198.18.100.0/15 - - type: interface - name: nic2 - use_dhcp: true - - type: interface - name: nic3 - use_dhcp: false # do not configure this interface - -.. _control-plane-bridge: - -Control plane bridge --------------------- - - .. code-block:: yaml - - network_config: - - type: ovs_bridge - name: br-ctlplane - use_dhcp: false - ovs_extra: - - br-set-external-id br-ctlplane bridge-id br-ctlplane - addresses: - - ip_netmask: 192.0.2.2/24 - - ip_netmask: 198.51.100.2/24 - - ip_netmask: 203.0.113.2/24 - dns_servers: 8.8.8.8 - domain: example.com - members: - - type: interface - name: nic1 - primary: true - mtu: 1450 - -.. _ovs-bond: - -OVS bond --------- - - .. code-block:: yaml - - network_config: - - type: ovs_bridge - name: br-ex - use_dhcp: true - dns_servers: 8.8.8.8 - domain: example.com - members: - - type: ovs_bond - name: bond1 - use_dhcp: true - ovs_options: bond_mode=balance-slb - members: - - type: interface - name: nic1 - - type: interface - name: nic2 - -.. _bonds-with-vlans: - -Bonds with VLANs and jumbo frames ---------------------------------- - - .. code-block:: yaml - - network_config: - - type: interface - name: nic1 - - type: ovs_bridge - name: br-bond - dns_servers: 8.8.8.8 - domain: example.com - members: - - type: ovs_bond - name: bond1 - mtu: 9000 - ovs_options: bond_mode=balance-tcp lacp=active other-config:lacp-fallback-ab=true - members: - - type: interface - name: nic2 - mtu: 9000 - primary: true - - type: interface - name: nic3 - mtu: 9000 - - type: vlan - device: bond1 - mtu: 9000 - vlan_id: 10 - addresses: - - ip_netmask: 198.51.200.2/24 - - type: vlan - device: bond1 - mtu: 9000 - vlan_id: 20 - addresses: - - ip_netmask: 198.51.100.2/24 - -.. _linux-bridge: - -Linux bridge ------------- - - .. code-block:: yaml - - network_config: - - type: linux_bridge - name: br-ex - addresses: - - ip_netmask: 192.0.2.2/24 - dns_servers: 8.8.8.8 - domain: example.com - members: - - type: interface - name: nic1 - # force the MAC address of the bridge to this interface - primary: true - routes: - - ip_netmask: 0.0.0.0/0 - next_hop: 10.0.0.1 - default: true - -.. _bonds-vlans-dpdk: - -Linux bonds, VLANs, and DPDK ----------------------------- - - .. code-block:: yaml - - network_config: - - type: interface - name: nic1 - mtu: 1500 - use_dhcp: false - addresses: - - ip_netmask: 192.0.2.2/24 - routes: - - ip_netmask: 0.0.0.0/0 - next_hop: 10.0.0.1 - default: true - - type: linux_bond - name: bond_api - mtu: 1500 - use_dhcp: false - dns_servers: 8.8.8.8 - members: - - type: interface - name: nic2 - mtu: 1500 - primary: true - - type: interface - name: nic3 - mtu: 1500 - - type: vlan - device: bond_api - mtu: 1500 - vlan_id: 10 - addresses: - - ip_netmask: 198.51.200.2/24 - - type: vlan - device: bond_api - mtu: 1500 - vlan_id: 20 - addresses: - - ip_netmask: 198.51.100.2/24 - # Used as a provider network with external DHCP # - - type: ovs_user_bridge - name: br-dpdk0 - members: - - type: ovs_dpdk_bond - name: dpdkbond0 - rx_queue: 1 - members: - - type: ovs_dpdk_port - name: dpdk0 - members: - - type: interface - name: nic4 - - type: ovs_dpdk_port - name: dpdk1 - members: - - type: interface - name: nic5 \ No newline at end of file diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index 1121b0f3..00000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,26 +0,0 @@ -.. os-net-config documentation master file, created by - sphinx-quickstart on Tue Jul 9 22:26:36 2013. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to os-net-config's documentation! -======================================================== - -Contents: - -.. toctree:: - :maxdepth: 2 - - readme - installation - usage - config - examples - contributing - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/doc/source/installation.rst b/doc/source/installation.rst deleted file mode 100644 index f2213c3f..00000000 --- a/doc/source/installation.rst +++ /dev/null @@ -1,12 +0,0 @@ -============ -Installation -============ - -At the command line:: - - $ pip install os-net-config - -Or, if you have virtualenvwrapper installed:: - - $ mkvirtualenv os-net-config - $ pip install os-net-config \ No newline at end of file diff --git a/doc/source/readme.rst b/doc/source/readme.rst deleted file mode 100644 index 38ba8043..00000000 --- a/doc/source/readme.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../../README.rst \ No newline at end of file diff --git a/doc/source/usage.rst b/doc/source/usage.rst deleted file mode 100644 index 852e7b88..00000000 --- a/doc/source/usage.rst +++ /dev/null @@ -1,80 +0,0 @@ -===== -Usage -===== - -Backend Provider Detection --------------------------- - -The ``--provider`` argument to ``os-net-config`` selects one of the available -backend providers: - -- ``ifcfg`` Configure network interfaces using the ifcfg format - ``/etc/sysconfig/network-scripts/`` files. -- ``eni`` Configure network interfaces using the Debian/Ubuntu - ``/etc/network/interfaces`` format -- ``iproute`` (Not implemented) - -When the ``--provider`` argument is not specified when calling -``os-net-config`` the provider will be chosen using the following rules: - -1) If path ``/etc/sysconfig/network-scripts/`` exists, use the ``ifcfg`` - provider. - -2) Otherwise if path ``/etc/network/`` exists, use the ``eni`` provider. - -In these rules, if a path is specified for ``--root-dir`` this will be -prepended to the checked paths before doing the above tests. - -Interface Mapping ------------------ - -The file ``/etc/os-net-config/mapping.yaml`` can contain mappings from -interface identifiers to the actual interface names. A different mapping file can -be used by using the ``--mapping-file`` argument to ``os-net-config``. - -This mapping allows consistent interface identifiers to be used in the config -without needing the full interface name which can vary across servers and -hardware changes. This also allows config to be performed for interfaces -which are in a ``DOWN`` state before configuration. - -The format of the mapping.yaml is as follows: - - .. code-block:: yaml - - interface_mapping: - nic1: enp0s20f0u2u1u2 - nic2: enp0s31f6 - -To assist in writing this file, the following command will generate a JSON -snippet with discovered interfaces:: - - $ os-net-config --interfaces - {'nic1': 'enp0s20f0u2u1u2', 'nic2': 'enp0s31f6'} - -When the ``--persist-mapping`` argument is specified when calling -``os-net-config`` then the existing interfaces names will be permanently -renamed to their identifier name. - -Network Configuration ---------------------- - -By default the file ``/etc/os-net-config/config.yaml`` will be sourced for -the network configuration, but an alternate file can be used with the -``--config-file`` argument. The following arguments change the behaviour -during configuration: - -- ``--detailed-exit-codes`` If enabled an exit code of ``2`` means that - files were modified. -- ``--exit-on-validation-errors`` Exit with an error if configuration - file validation fails. -- ``--noop`` Return the configuration commands, without applying them. -- ``--no-activate`` Install the configuration but don't start/stop - interfaces. -- ``--cleanup`` Cleanup unconfigured interfaces. - -Python Library --------------- - -To use os-net-config in a project:: - - import os_net_config \ No newline at end of file diff --git a/etc/os-net-config/samples/bond.json b/etc/os-net-config/samples/bond.json deleted file mode 100644 index b21b2d9b..00000000 --- a/etc/os-net-config/samples/bond.json +++ /dev/null @@ -1,19 +0,0 @@ -{ "network_config": [ - { - "type": "ovs_bridge", - "name": "br-ctlplane", - "use_dhcp": "true", - "members": [ - { - "type": "ovs_bond", - "name": "bond1", - "use_dhcp": "true", - "members": [ - { "type": "interface", "name": "em1" }, - { "type": "interface", "name": "em2" } - ] - } - ] - } - ] -} diff --git a/etc/os-net-config/samples/bond.yaml b/etc/os-net-config/samples/bond.yaml deleted file mode 100644 index 7b8b4ece..00000000 --- a/etc/os-net-config/samples/bond.yaml +++ /dev/null @@ -1,17 +0,0 @@ -network_config: - - - type: ovs_bridge - name: br-ctlplane - use_dhcp: true - members: - - - type: ovs_bond - name: bond1 - use_dhcp: true - members: - - - type: interface - name: em1 - - - type: interface - name: em2 diff --git a/etc/os-net-config/samples/bond_mapped.yaml b/etc/os-net-config/samples/bond_mapped.yaml deleted file mode 100644 index 1b5ad6d4..00000000 --- a/etc/os-net-config/samples/bond_mapped.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# Example showing use of the optional nicN abstraction -# for device naming, which defaults to an ordered -# translation to biodev names based on which interfaces -# are active on the system. -# Optionally the default mapping may be overridden by -# a mapping file via the -m option. -network_config: - - - type: ovs_bridge - name: br-ctlplane - use_dhcp: true - members: - - - type: ovs_bond - name: bond1 - use_dhcp: true - members: - - - type: interface - name: nic1 - - - type: interface - name: nic2 diff --git a/etc/os-net-config/samples/bridge_dhcp.json b/etc/os-net-config/samples/bridge_dhcp.json deleted file mode 100644 index 76d54086..00000000 --- a/etc/os-net-config/samples/bridge_dhcp.json +++ /dev/null @@ -1,17 +0,0 @@ -{ "network_config": [ - { - "type": "ovs_bridge", - "name": "br-ctlplane", - "ovs_extra": [ - "br-set-external-id br-ctlplane bridge-id br-ctlplane" - ], - "use_dhcp": "true", - "members": [ - { - "type": "interface", - "name": "em1" - } - ] - } - ] -} diff --git a/etc/os-net-config/samples/bridge_dhcp.yaml b/etc/os-net-config/samples/bridge_dhcp.yaml deleted file mode 100644 index a6ac5933..00000000 --- a/etc/os-net-config/samples/bridge_dhcp.yaml +++ /dev/null @@ -1,11 +0,0 @@ -network_config: - - - type: ovs_bridge - name: br-ctlplane - use_dhcp: true - ovs_extra: - - br-set-external-id br-ctlplane bridge-id br-ctlplane - members: - - - type: interface - name: em1 diff --git a/etc/os-net-config/samples/bridge_fail_mode.json b/etc/os-net-config/samples/bridge_fail_mode.json deleted file mode 100644 index 6492da6f..00000000 --- a/etc/os-net-config/samples/bridge_fail_mode.json +++ /dev/null @@ -1,15 +0,0 @@ -{ "network_config": [ - { - "type": "ovs_bridge", - "name": "br-ctlplane", - "ovs_fail_mode": "secure", - "use_dhcp": "true", - "members": [ - { - "type": "interface", - "name": "em1" - } - ] - } - ] -} diff --git a/etc/os-net-config/samples/bridge_fail_mode.yaml b/etc/os-net-config/samples/bridge_fail_mode.yaml deleted file mode 100644 index 7589c256..00000000 --- a/etc/os-net-config/samples/bridge_fail_mode.yaml +++ /dev/null @@ -1,10 +0,0 @@ -network_config: - - - type: ovs_bridge - name: br-ctlplane - use_dhcp: true - ovs_fail_mode: secure - members: - - - type: interface - name: em1 diff --git a/etc/os-net-config/samples/bridge_ovs_extra.json b/etc/os-net-config/samples/bridge_ovs_extra.json deleted file mode 100644 index d71ead59..00000000 --- a/etc/os-net-config/samples/bridge_ovs_extra.json +++ /dev/null @@ -1,18 +0,0 @@ -{ "network_config": [ - { - "type": "ovs_bridge", - "name": "br-ctlplane", - "ovs_extra": [ - "br-set-external-id br-ctlplane bridge-id br-ctlplane", - "set bridge {name} stp_enable=true" - ], - "use_dhcp": "true", - "members": [ - { - "type": "interface", - "name": "em1" - } - ] - } - ] -} diff --git a/etc/os-net-config/samples/bridge_ovs_extra.yaml b/etc/os-net-config/samples/bridge_ovs_extra.yaml deleted file mode 100644 index e369d62b..00000000 --- a/etc/os-net-config/samples/bridge_ovs_extra.yaml +++ /dev/null @@ -1,12 +0,0 @@ -network_config: - - - type: ovs_bridge - name: br-ctlplane - use_dhcp: true - ovs_extra: - - br-set-external-id br-ctlplane bridge-id br-ctlplane - - set bridge {name} stp_enable=true - members: - - - type: interface - name: em1 diff --git a/etc/os-net-config/samples/bridge_vlan.json b/etc/os-net-config/samples/bridge_vlan.json deleted file mode 100644 index 5d84f822..00000000 --- a/etc/os-net-config/samples/bridge_vlan.json +++ /dev/null @@ -1,29 +0,0 @@ -{ "network_config": [ - { - "type": "ovs_bridge", - "name": "br-ctlplane", - "use_dhcp": "true", - "members": [ - { - "type": "interface", - "name": "em1" - }, - { - "type": "vlan", - "vlan_id": 16, - "ovs_options": "mac=00:11:22:33:44:55", - "ovs_extra": [ - "foo=bar" - ], - "addresses": [{ - "ip_netmask": "192.0.2.1/24" - }] - } - ], - "routes": [{ - "next_hop": "192.0.2.1", - "ip_netmask": "192.0.2.1/24" - }] - } - ] -} diff --git a/etc/os-net-config/samples/bridge_vlan.yaml b/etc/os-net-config/samples/bridge_vlan.yaml deleted file mode 100644 index 46d2069a..00000000 --- a/etc/os-net-config/samples/bridge_vlan.yaml +++ /dev/null @@ -1,22 +0,0 @@ -network_config: - - - type: ovs_bridge - name: br-ctlplane - use_dhcp: true - members: - - - type: interface - name: em1 - - - type: vlan - vlan_id: 16 - ovs_options: "mac=00:11:22:33:44:55" - ovs_extra: - - "foo=bar" - addresses: - - - ip_netmask: 192.0.2.1/24 - routes: - - - next_hop: 192.0.2.1 - ip_netmask: 192.0.2.1/24 diff --git a/etc/os-net-config/samples/contrail_vrouter.json b/etc/os-net-config/samples/contrail_vrouter.json deleted file mode 100644 index c1ff9c9f..00000000 --- a/etc/os-net-config/samples/contrail_vrouter.json +++ /dev/null @@ -1,14 +0,0 @@ -{ "network_config": [ - { - "type": "contrail_vrouter", - "name": "vhost0", - "members": [ - { - "type": "interface", - "name": "em3" - } - ], - "mtu": 1500 - } - ] -} diff --git a/etc/os-net-config/samples/contrail_vrouter.yaml b/etc/os-net-config/samples/contrail_vrouter.yaml deleted file mode 100644 index 79a85c0d..00000000 --- a/etc/os-net-config/samples/contrail_vrouter.yaml +++ /dev/null @@ -1,9 +0,0 @@ -network_config: - - - type: contrail_vrouter - name: vhost0 - members: - - - type: interface - name: em3 - mtu: 1500 diff --git a/etc/os-net-config/samples/contrail_vrouter_dpdk.json b/etc/os-net-config/samples/contrail_vrouter_dpdk.json deleted file mode 100644 index a4427de6..00000000 --- a/etc/os-net-config/samples/contrail_vrouter_dpdk.json +++ /dev/null @@ -1,15 +0,0 @@ -{ "network_config": [ - { - "type": "contrail_vrouter_dpdk", - "name": "vhost0", - "members": [ - { - "type": "interface", - "name": "em3" - } - ], - "mtu": 1500, - "driver": "vfio" - } - ] -} diff --git a/etc/os-net-config/samples/contrail_vrouter_dpdk.yaml b/etc/os-net-config/samples/contrail_vrouter_dpdk.yaml deleted file mode 100644 index b795a3db..00000000 --- a/etc/os-net-config/samples/contrail_vrouter_dpdk.yaml +++ /dev/null @@ -1,10 +0,0 @@ -network_config: - - - type: contrail_vrouter_dpdk - name: vhost0 - members: - - - type: interface - name: em3 - mtu: 1500 - driver: vfio #default driver is uio_pci_generic diff --git a/etc/os-net-config/samples/contrail_vrouter_dpdk_bond.json b/etc/os-net-config/samples/contrail_vrouter_dpdk_bond.json deleted file mode 100644 index c88dc339..00000000 --- a/etc/os-net-config/samples/contrail_vrouter_dpdk_bond.json +++ /dev/null @@ -1,20 +0,0 @@ -{ "network_config": [ - { - "type": "contrail_vrouter_dpdk", - "name": "vhost0", - "members": [ - { - "type": "interface", - "name": "em3" - }, - { - "type": "interface", - "name": "em1" - } - ], - "bond_mode": "2", - "bond_policy": "802.3ad", - "mtu": 1500 - } - ] -} diff --git a/etc/os-net-config/samples/contrail_vrouter_dpdk_bond.yaml b/etc/os-net-config/samples/contrail_vrouter_dpdk_bond.yaml deleted file mode 100644 index b2b8c2fd..00000000 --- a/etc/os-net-config/samples/contrail_vrouter_dpdk_bond.yaml +++ /dev/null @@ -1,14 +0,0 @@ -network_config: - - - type: contrail_vrouter_dpdk - name: vhost0 - members: - - - type: interface - name: em3 - - - type: interface - name: em1 - mtu: 1500 - bond_mode: 2 - bond_policy: 802.3ad diff --git a/etc/os-net-config/samples/contrail_vrouter_vlan.json b/etc/os-net-config/samples/contrail_vrouter_vlan.json deleted file mode 100644 index d48e1a78..00000000 --- a/etc/os-net-config/samples/contrail_vrouter_vlan.json +++ /dev/null @@ -1,15 +0,0 @@ -{ "network_config": [ - { - "type": "contrail_vrouter", - "name": "vhost0", - "members": [ - { - "type": "vlan", - "vlan_id": 100, - "device": "em3" - } - ], - "mtu": 1500 - } - ] -} diff --git a/etc/os-net-config/samples/contrail_vrouter_vlan.yaml b/etc/os-net-config/samples/contrail_vrouter_vlan.yaml deleted file mode 100644 index 9192c8aa..00000000 --- a/etc/os-net-config/samples/contrail_vrouter_vlan.yaml +++ /dev/null @@ -1,10 +0,0 @@ -network_config: - - - type: contrail_vrouter - name: vhost0 - members: - - - type: vlan - vlan_id: 100 - device: em3 - mtu: 1500 diff --git a/etc/os-net-config/samples/ib_child_interface.json b/etc/os-net-config/samples/ib_child_interface.json deleted file mode 100644 index 40e538a3..00000000 --- a/etc/os-net-config/samples/ib_child_interface.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "network_config": [ - { - "type": "ib_interface", - "name": "ib0", - "use_dhcp": false - }, - { - "type": "ib_child_interface", - "parent": "ib0", - "pkey_id": 100, - "use_dhcp": false, - "addresses": [ - { - "ip_netmask": "10.20.30.40/24" - } - ] - } - ] -} diff --git a/etc/os-net-config/samples/ib_child_interface.yaml b/etc/os-net-config/samples/ib_child_interface.yaml deleted file mode 100644 index 84315479..00000000 --- a/etc/os-net-config/samples/ib_child_interface.yaml +++ /dev/null @@ -1,18 +0,0 @@ -network_config: - # Note(abdallahyas): a parent InfiniBand interface is needed to be up for - # the IPoIB pkey interface to work. The ib0 interface here is just there - # to make sure that it is up, it can be configured separately. - - - - type: ib_interface - name: ib0 - use_dhcp: false - - - - type: ib_child_interface - parent: ib0 - pkey_id: 100 - use_dhcp: false - addresses: - - - ip_netmask: 10.20.30.40/24 diff --git a/etc/os-net-config/samples/ib_interface.json b/etc/os-net-config/samples/ib_interface.json deleted file mode 100644 index f552af31..00000000 --- a/etc/os-net-config/samples/ib_interface.json +++ /dev/null @@ -1,26 +0,0 @@ -{"network_config": [ - { - "type": "ib_interface", - "name": "ib0", - "use_dhcp": false, - "addresses": [ - { - "ip_netmask": "192.0.2.1/24" - } - ], - "routes": [ - { - "ip_netmask": "0.0.0.0/0", - "next_hop": "192.0.2.254", - "default": "true" - } - ] - }, - { - "type": "ib_interface", - "name": "ib1", - "use_dhcp": true, - "defroute": false - } - ] -} diff --git a/etc/os-net-config/samples/ib_interface.yaml b/etc/os-net-config/samples/ib_interface.yaml deleted file mode 100644 index 6210f0a2..00000000 --- a/etc/os-net-config/samples/ib_interface.yaml +++ /dev/null @@ -1,18 +0,0 @@ -network_config: - - - type: ib_interface - name: ib0 - use_dhcp: false - addresses: - - - ip_netmask: 192.0.2.1/24 - routes: - - - ip_netmask: 0.0.0.0/0 - next_hop: 192.0.2.254 - default: true - - - type: interface - name: ib1 - use_dhcp: true - defroute: false diff --git a/etc/os-net-config/samples/interface.json b/etc/os-net-config/samples/interface.json deleted file mode 100644 index 028143b5..00000000 --- a/etc/os-net-config/samples/interface.json +++ /dev/null @@ -1,40 +0,0 @@ -{"network_config": [ - { - "type": "interface", - "name": "em1", - "use_dhcp": false, - "use_dhcpv6": false, - "addresses": [ - { - "ip_netmask": "192.0.2.1/24" - } - ], - "routes": [ - { - "ip_netmask": "0.0.0.0/0", - "next_hop": "192.0.2.254", - "default": "true" - }, - { - "ip_netmask": "10.1.2.0/24", - "next_hop": "192.0.2.5", - "route_options": "metric 10" - } - ] - }, - { - "type": "interface", - "name": "em2", - "use_dhcp": true, - "defroute": false, - "ethtool_opts": "speed 1000 duplex full" - }, - { - "type": "interface", - "name": "em3", - "use_dhcp": true, - "hotplug": true, - "onboot": false - } - ] -} diff --git a/etc/os-net-config/samples/interface.yaml b/etc/os-net-config/samples/interface.yaml deleted file mode 100644 index 4f20d4e5..00000000 --- a/etc/os-net-config/samples/interface.yaml +++ /dev/null @@ -1,30 +0,0 @@ -network_config: - - - type: interface - name: em1 - use_dhcp: false - use_dhcpv6: false - addresses: - - - ip_netmask: 192.0.2.1/24 - routes: - - - ip_netmask: 0.0.0.0/0 - next_hop: 192.0.2.254 - default: true - - - ip_netmask: 10.1.2.0/24 - next_hop: 192.0.2.5 - route_options: "metric 10" - - - type: interface - name: em2 - use_dhcp: true - defroute: false - ethtool_opts: "speed 1000 duplex full" - - - type: interface - name: em3 - use_dhcp: true - hotplug: true - onboot: false # if not set default is true diff --git a/etc/os-net-config/samples/ivs.json b/etc/os-net-config/samples/ivs.json deleted file mode 100644 index 746e1c0c..00000000 --- a/etc/os-net-config/samples/ivs.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "network_config": [ - { - "type": "ivs_bridge", - "members": [ - { - "type": "interface", - "name": "nic2", - }, - { - "type": "interface", - "name": "nic3" - }, - { - "type": "ivs_interface", - "name": "api", - "addresses": [ - { - "ip_netmask": "172.16.2.7/24" - } - ], - "vlan_id": 201 - }, - { - "type": "ivs_interface", - "name": "storage", - "addresses": [ - { - "ip_netmask": "172.16.1.6/24" - } - ], - "vlan_id": 202 - } - ] - } - ] -} diff --git a/etc/os-net-config/samples/ivs.yaml b/etc/os-net-config/samples/ivs.yaml deleted file mode 100644 index 9813316f..00000000 --- a/etc/os-net-config/samples/ivs.yaml +++ /dev/null @@ -1,24 +0,0 @@ -network_config: - - - type: ivs_bridge - members: - - - type: interface - name: nic2 - - - type: interface - name: nic3 - - - type: ivs_interface - name: api - vlan_id: 201 - addresses: - - - ip_netmask: 172.16.2.7/24 - - - type: ivs_interface - name: storage - vlan_id: 202 - addresses: - - - ip_netmask: 172.16.1.6/24 diff --git a/etc/os-net-config/samples/linux_bond.yaml b/etc/os-net-config/samples/linux_bond.yaml deleted file mode 100644 index 566c747a..00000000 --- a/etc/os-net-config/samples/linux_bond.yaml +++ /dev/null @@ -1,13 +0,0 @@ -network_config: - - - type: linux_bond - name: bond1 - use_dhcp: true - bonding_options: "mode=active-backup" - members: - - - type: interface - name: em1 - - - type: interface - name: em2 diff --git a/etc/os-net-config/samples/linux_bond_networkmanager.yaml b/etc/os-net-config/samples/linux_bond_networkmanager.yaml deleted file mode 100644 index c7036c01..00000000 --- a/etc/os-net-config/samples/linux_bond_networkmanager.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# To use NetworkManager to manage an interface, set nm_controlled=true. -# Note that some interface types may not be supported by NetworkManager. -network_config: - - - type: linux_bond - name: bond1 - nm_controlled: true - use_dhcp: true - bonding_options: "mode=active-backup" - members: - - - type: interface - name: em1 - nm_controlled: true - - - type: interface - name: em2 - nm_controlled: true diff --git a/etc/os-net-config/samples/linux_bridge.yaml b/etc/os-net-config/samples/linux_bridge.yaml deleted file mode 100644 index 051f6f32..00000000 --- a/etc/os-net-config/samples/linux_bridge.yaml +++ /dev/null @@ -1,9 +0,0 @@ -network_config: - - - type: linux_bridge - name: br-ctlplane - use_dhcp: true - members: - - - type: interface - name: em1 diff --git a/etc/os-net-config/samples/linux_tap.json b/etc/os-net-config/samples/linux_tap.json deleted file mode 100644 index 22bf3b3e..00000000 --- a/etc/os-net-config/samples/linux_tap.json +++ /dev/null @@ -1,8 +0,0 @@ -{ "network_config": [ - { - "type": "linux_tap", - "name": "tap0", - "use_dhcp": true - } - ] -} diff --git a/etc/os-net-config/samples/linux_tap.yaml b/etc/os-net-config/samples/linux_tap.yaml deleted file mode 100644 index 26c9e71e..00000000 --- a/etc/os-net-config/samples/linux_tap.yaml +++ /dev/null @@ -1,6 +0,0 @@ -network_config: - - - type: linux_tap - name: tap0 - use_dhcp: true - diff --git a/etc/os-net-config/samples/mapping.yaml b/etc/os-net-config/samples/mapping.yaml deleted file mode 100644 index a832dc9e..00000000 --- a/etc/os-net-config/samples/mapping.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# This can be used with the -m option to override the -# default mapping of the nicN aliases in configs -# The mapping can specify either a device name or a mac address -# If --persist-mapping is specified, we write the device aliases -# config instead of the system names, e.g we actually configure -# nic1 intead of em3. This is probably best used with --cleanup -# to remove the stale configs e.g for em3 -interface_mapping: - nic1: em3 - nic2: em1 - nic3: 12:34:56:de:f0:12 - nic4: 12:34:56:78:9a:bc diff --git a/etc/os-net-config/samples/mapping_mnemonic.yaml b/etc/os-net-config/samples/mapping_mnemonic.yaml deleted file mode 100644 index 10f31ded..00000000 --- a/etc/os-net-config/samples/mapping_mnemonic.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# See the mapping.yaml sample for an overview of the mapping functionality. -# This shows the use of mnemonic aliases instead of the default nicN aliases -# in configs. It can be used with the -m option to override the default -# mapping of the nicN aliases. -interface_mapping: - provision: em1 - bond0p1: em2 - bond0p2: 12:34:56:de:f0:12 diff --git a/etc/os-net-config/samples/mapping_report.yaml b/etc/os-net-config/samples/mapping_report.yaml deleted file mode 100644 index 2cb49b59..00000000 --- a/etc/os-net-config/samples/mapping_report.yaml +++ /dev/null @@ -1,5 +0,0 @@ -interface_mapping: - nic1: em1 - nic2: em2 - nic3: em4 - nic4: em3 diff --git a/etc/os-net-config/samples/nfvswitch.json b/etc/os-net-config/samples/nfvswitch.json deleted file mode 100644 index b081de98..00000000 --- a/etc/os-net-config/samples/nfvswitch.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "network_config": [ - { - "type": "nfvswitch_bridge", - "options": "-c 2,3,4,5", - "members": [ - { - "type": "interface", - "name": "nic2", - }, - { - "type": "interface", - "name": "nic3" - }, - { - "type": "nfvswitch_internal", - "name": "api", - "addresses": [ - { - "ip_netmask": "172.16.2.7/24" - } - ], - "vlan_id": 201 - }, - { - "type": "nfvswitch_internal", - "name": "storage", - "addresses": [ - { - "ip_netmask": "172.16.1.6/24" - } - ], - "vlan_id": 202 - } - ] - } - ] -} diff --git a/etc/os-net-config/samples/nfvswitch.yaml b/etc/os-net-config/samples/nfvswitch.yaml deleted file mode 100644 index d7571aed..00000000 --- a/etc/os-net-config/samples/nfvswitch.yaml +++ /dev/null @@ -1,25 +0,0 @@ -network_config: - - - type: nfvswitch_bridge - options: "-c 2,3,4,5" - members: - - - type: interface - name: nic2 - - - type: interface - name: nic3 - - - type: nfvswitch_internal - name: api - vlan_id: 201 - addresses: - - - ip_netmask: 172.16.2.7/24 - - - type: nfvswitch_internal - name: storage - vlan_id: 202 - addresses: - - - ip_netmask: 172.16.1.6/24 diff --git a/etc/os-net-config/samples/ovs_dpdk.json b/etc/os-net-config/samples/ovs_dpdk.json deleted file mode 100644 index ddfdb0a6..00000000 --- a/etc/os-net-config/samples/ovs_dpdk.json +++ /dev/null @@ -1,24 +0,0 @@ -{ "network_config": [ - { - "type": "ovs_user_bridge", - "name": "br-link", - "members": [ - { - "type": "ovs_dpdk_port", - "name": "dpdk0", - "driver": "igb_uio", - "mtu": 8192, - "rx_queue": 4, - "rx_queue_size": 1024, - "tx_queue_size": 2048, - "members": [ - { - "type": "interface", - "name": "nic2", - } - ] - } - ] - } - ] -} diff --git a/etc/os-net-config/samples/ovs_dpdk.yaml b/etc/os-net-config/samples/ovs_dpdk.yaml deleted file mode 100644 index f970f888..00000000 --- a/etc/os-net-config/samples/ovs_dpdk.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# ovs_user_bridge type refers to the OVSUserBridge OVS ifup type, which will -# have the datapath type set as 'netdev' for DPDK processing. -# ovs_dpdk_port type refers to the OVSDPDKPort OVS ifup type, which will -# add the port to the bridge with the interface type as 'dpdk'. - -network_config: - - - type: ovs_user_bridge - name: br-link - members: - - - type: ovs_dpdk_port - # dpdk0 name is generated by dpdk drivers after dpdk_nic_bind - name: dpdk0 - # driver is optional argument, default driver is 'vfio-pci' - driver: igb_uio - # MTU is optional, used for jumbo frames - mtu: 8192 - # rx_queue is optional, used for multi-queue option. It configures the - # maximum number of queues for a physical interface. If not defined, - # the physical interface will have single queue. The number of queues - # should be less than the PMD cores as each queue will have one PMD - # thread (CPU) associated with it. - rx_queue: 4 - # rx_queue_size and tx_queue_size are optional. It configures the - # number of rx/tx descriptors that the associated NIC will be - # initialized with. - rx_queue_size: 1024 - tx_queue_size: 2048 - members: - - type: interface - name: nic2 diff --git a/etc/os-net-config/samples/ovs_dpdk_bond.json b/etc/os-net-config/samples/ovs_dpdk_bond.json deleted file mode 100644 index 410d4594..00000000 --- a/etc/os-net-config/samples/ovs_dpdk_bond.json +++ /dev/null @@ -1,37 +0,0 @@ -{ "network_config": [ - { - "type": "ovs_user_bridge", - "name": "br-link", - "members": [ - { - "type" : "ovs_dpdk_bond", - "name" : "dpdkbond0", - "mtu" : 9000, - "rx_queue": 4, - "members": [ - { - "type" : "ovs_dpdk_port", - "name" : "dpdk0", - "members": [ - { - "type": "interface", - "name": "nic2" - } - ] - }, - { - "type" : "ovs_dpdk_port", - "name" : "dpdk1", - "members": [ - { - "type": "interface", - "name": "nic3" - } - ] - }, - ] - } - ] - } - ] -} diff --git a/etc/os-net-config/samples/ovs_dpdk_bond.yaml b/etc/os-net-config/samples/ovs_dpdk_bond.yaml deleted file mode 100644 index 17a73a3f..00000000 --- a/etc/os-net-config/samples/ovs_dpdk_bond.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# ovs_user_bridge type refers to the OVSUserBridge OVS ifup type, which will -# have the datapath type set as 'netdev' for DPDK processing. -# ovs_dpdk_port type refers to the OVSDPDKPort OVS ifup type, which will -# add the port to the bridge with the interface type as 'dpdk'. -# ovs_dpdk_bond type refers to the OVSDPDKBond OVS ifup type, which will -# create the bond with dpdk interface type for dpdk ports - -network_config: - - - type: ovs_user_bridge - name: br-link - members: - - - type: ovs_dpdk_bond - name: dpdkbond0 - # MTU is optional, e.g. for jumbo frames - mtu: 9000 - # rx_queue is optional, used for multi-queue option. It configures the - # maximum number of queues for each interface associated with the - # ovs_dpdk_bond. If not defined, the physical interfaces will have - # single queue. - # (rx_queue) x (Number of members in the ovs_dpdk_bond) should be less - # than the number of PMD cores, as each queue will have one PMD thread - # (CPU) associated with it. - rx_queue: 4 - members: - - - type: ovs_dpdk_port - name: dpdk0 - members: - - - type: interface - name: nic2 - - - type: ovs_dpdk_port - name: dpdk1 - members: - - - type: interface - name: nic3 diff --git a/etc/os-net-config/samples/ovs_patch_port.json b/etc/os-net-config/samples/ovs_patch_port.json deleted file mode 100644 index d4573717..00000000 --- a/etc/os-net-config/samples/ovs_patch_port.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "network_config": [ - { - "name": "br-ctlplane", - "type": "ovs_bridge", - "members": [ - { - "mtu": 1500, - "primary": "true", - "name": "eth1", - "type": "interface" - } - ], - "ovs_extra": [ - "br-set-external-id br-ctlplane bridge-id br-ctlplane" - ], - "mtu": 1500, - "addresses": [ - { - "ip_netmask": "192.0.2.1/24" - } - ] - }, - { - "name": "br_pub-patch", - "type": "ovs_patch_port", - "bridge_name": "br-ctlplane", - "peer": "br-ctlplane-patch" - }, - { - "name": "br-ctlplane-patch", - "type": "ovs_patch_port", - "bridge_name": "br_pub", - "peer": "br_pub-patch" - } - ] -} diff --git a/etc/os-net-config/samples/ovs_patch_port.yaml b/etc/os-net-config/samples/ovs_patch_port.yaml deleted file mode 100644 index bae88800..00000000 --- a/etc/os-net-config/samples/ovs_patch_port.yaml +++ /dev/null @@ -1,23 +0,0 @@ -network_config: - - - type: ovs_bridge - name: br-ctlplane - mtu: 1500 - members: - - - type: interface - name: eth1 - # force the MAC address of the bridge to this interface - primary: true - mtu: 1500 - ovs_extra: ["br-set-external-id br-ctlplane bridge-id br-ctlplane"] - - - type: ovs_patch_port - name: br_pub-patch - bridge_name: br-ctlplane - peer: br-ctlplane-patch - - - type: ovs_patch_port - name: br-ctlplane-patch - bridge_name: br_pub - peer: br_pub-patch diff --git a/etc/os-net-config/samples/routes.yaml b/etc/os-net-config/samples/routes.yaml deleted file mode 100644 index fbbce0ac..00000000 --- a/etc/os-net-config/samples/routes.yaml +++ /dev/null @@ -1,52 +0,0 @@ -network_config: - - - type: route_table - name: custom - table_id: 200 - - - type: route_table - name: alternate - table_id: 201 - - - type: interface - name: em1 - use_dhcp: false - addresses: - - - ip_netmask: 192.0.2.1/24 - routes: - - - ip_netmask: 10.1.3.0/24 - next_hop: 192.0.2.5 - route_options: "metric 10" - table: 200 # Use table ID or table name - - - ip_netmask: 0.0.0.0/0 - next_hop: 192.0.2.254 - default: true - table: 200 - rules: - - rule: "iif em1 table 200" - comment: "Route incoming traffic to em1 with table 200" - - rule: "from 192.0.2.0/24 table 200" - comment: "Route all traffic from 192.0.2.0/24 with table 200" - - rule: "add blackhole from 172.19.40.0/24 table 200" - - rule: "add unreachable iif em1 from 192.168.1.0/24" - - - type: interface - name: em2 - use_dhcp: false - addresses: - - ip_netmask: 10.0.2.1/24 - routes: - - - ip_netmask: 10.1.3.0/24 - next_hop: 10.0.2.253 - table: alternate # Use table ID or table name - - - default: true - next_hop: 10.0.3.254 - route_options: "table alternate" - rules: - - rule: "iif em2 table alternate" - - rule: "from 10.0.2.0/24 table alternate" diff --git a/etc/os-net-config/samples/sriov_pf.json b/etc/os-net-config/samples/sriov_pf.json deleted file mode 100644 index 383b5582..00000000 --- a/etc/os-net-config/samples/sriov_pf.json +++ /dev/null @@ -1,130 +0,0 @@ -{ - "network_config": [ - { - "type": "sriov_pf", - "name": "p2p1", - "numvfs": 10, - "use_dhcp": false, - "promisc": true, - "ethtool_opts": "speed 1000 duplex full" - }, - { - "type": "sriov_pf", - "name": "p2p2", - "numvfs": 10, - "use_dhcp": false, - "promisc": true - }, - { - "type": "sriov_vf", - "device": "p2p1", - "vfid": 5, - "addresses": [ - { - "ip_netmask": "192.0.2.1/24" - } - ], - "vlan_id": 100, - "qos": 2, - "min_tx_rate": 10, - "max_tx_rate": 100, - "spoofcheck": true, - "macaddr": "00:78:90:80:cc:30", - "trust": true, - "state": "auto", - "promisc": false, - "ethtool_opts": "speed 1000 duplex full" - }, - { - "type": "ovs_bridge", - "name": "br-vfs", - "members": [ - { - "type": "sriov_vf", - "vfid": 1, - "trust": true, - "device": "p2p1", - "promisc": true, - "vlan_id": 116, - "qos": 3, - "min_tx_rate": 0, - "max_tx_rate": 0, - "spoofcheck": false - } - ], - "use_dhcp": true - }, - { - "type": "ovs_bridge", - "name": "br-bond", - "use_dhcp": true, - "members": [ - { - "type": "ovs_bond", - "name": "bond_vf", - "ovs_options": "bond_mode=active-backup", - "members": [ - { - "type": "sriov_vf", - "device": "p2p1", - "vfid": 2, - "vlan_id": 112, - "qos": 4, - "min_tx_rate": 0, - "max_tx_rate": 0, - "primary": true, - "trust": true, - "promisc": true, - "spoofcheck": false - }, - { - "type": "sriov_vf", - "device": "p2p2", - "vfid": 2, - "vlan_id": 112, - "qos": 4, - "min_tx_rate": 0, - "max_tx_rate": 0, - "trust": true, - "promisc": true, - "spoofcheck": false - } - ] - } - ] - }, - { - "type": "linux_bond", - "name": "bond_lnx", - "use_dhcp": true, - "bonding_options": "mode=active-backup", - "members": [ - { - "type": "sriov_vf", - "device": "p2p1", - "vfid": 3, - "vlan_id": 113, - "qos": 5, - "min_tx_rate": 0, - "max_tx_rate": 0, - "spoofcheck": false, - "trust": true, - "promisc": false, - "primary": true, - }, - { - "type": "sriov_vf", - "device": "p2p2", - "vfid": 3, - "vlan_id": 113, - "qos": 5, - "min_tx_rate": 0, - "max_tx_rate": 0, - "spoofcheck": false, - "trust": true, - "promisc": false - } - ] - } - ] -} diff --git a/etc/os-net-config/samples/sriov_pf.yaml b/etc/os-net-config/samples/sriov_pf.yaml deleted file mode 100644 index 1fd440af..00000000 --- a/etc/os-net-config/samples/sriov_pf.yaml +++ /dev/null @@ -1,158 +0,0 @@ -network_config: - # sriov_pf type shall be used to configure the PF's of NICs. - # The numvfs configured for the PF's shall be set on the sriov_numvfs of the - # sysfs for the corresponding NIC and the persistence of the same across reboots - # shall be handled - - - type: sriov_pf - # nic name or nic number of the NIC that needs to be configured for SRIOV - name: p2p1 - # number of VFs required on the particular NIC - numvfs: 10 - # Dont set the IP address on the PF - use_dhcp: false - # Allow all the traffic received. It might be needed when one of its VF - # is attached to a ovs bridge. Default: true - promisc: true - # Set ethtool options (optional) - ethtool_opts: "speed 1000 duplex full" - - - - type: sriov_pf - name: p2p2 - numvfs: 10 - use_dhcp: false - promisc: true - # sriov_vf type shall be used to configure the VF's of NICs. - # It requires the PF devices to be configured via sriov_pf types - # "name" parameter is not required for VF's. It'll be derived from the VF id - # and the PF device name. - - type: sriov_vf - # The PF device needs to be configured via the sriov_pf type - # the PF device could be a nic number (ex: nic5) or nic name (ex: ens20f0) - device: p2p1 - # The VF id shall be the VF number between 0 to (numvfs-1), where numvfs - # is the member of the sriov_pf type - vfid: 5 - addresses: - - ip_netmask: 192.0.2.1/24 - # When specified, all traffic sent from the VF will be tagged with the - # specified VLAN ID. Incoming traffic will be filtered for the specified - # VLAN ID, and will have all VLAN tags stripped before being passed to the - # VF. Setting this parameter to 0 disables VLAN tagging and filtering. - vlan_id: 100 - # VLAN-Quality Of Service (priority) bits for the VLAN tag. - # When specified, all VLAN tags transmitted by the VF will include the - # specified priority bits in the VLAN tag. Requires vlan_id - # Default value is 0. - qos: 2 - # change the allowed minimum transmit bandwidth, in Mbps, for the specified VF. - # Minimum TXRATE should be always <= Maximum TXRATE. - # Setting this parameter to 0 disables rate limiting. - min_tx_rate: 10 - # change the allowed maximum transmit bandwidth, in Mbps, for the specified VF. - # Setting this parameter to 0 disables rate limiting. - max_tx_rate: 100 - # MAC spoofing is a method of altering the MAC address - # The MAC address anti-spoofing when enabled protects from malicious MAC - # address spoofing. It should be disabled for 802.3ad bonds. - spoofcheck: true - # Change the MAC address of the VF. - macaddr: 00:78:90:80:cc:30 - # Enabling trust (true) for VF allows enabling multicast/promiscuous mode - # on the VF. The default value is false. - trust: true - # Link state seen by the VF - # - auto: a reflection of the PF link state (default) - # - enable: lets the VF to communicate with other VFs on this host even - # if the PF link state is down - # - disable: causes the HW to drop any packets sent by the VF. - state: auto - # Enabling promisc mode allows the traffic originally targeted to go to the - # VF and it will also receive the unmatched traffic and all the multicast - # traffic received in the physical port. Note that all traffic that has - # destination mac that does not match any of the VFs/PF MAC addresses is - # referred to as unmatched traffic. - # The default value is false. Requires the enabling of trust mode - promisc: false - # Set ethtool options (optional) - ethtool_opts: "speed 1000 duplex full" - # Attach a SR-IOV VF to a ovs bridge - - type: ovs_bridge - name: br-vfs - use_dhcp: true - members: - # Specify the type - - type: sriov_vf - # Required field - device: p2p1 - # Required field - vfid: 1 - # Optional field - vlan_id: 116 - # Optional field, but requires vlan_id - qos: 3 - # For OVS Bridge, the default value is true (recommended) - trust: true - # For OVS Bridge, the default value is true (recommended) - promisc: true - # For OVS Bridge, the default value is false (recommended) - spoofcheck: false - - type: ovs_bridge - name: br-bond - use_dhcp: true - members: - - - type: ovs_bond - name: bond_vf - ovs_options: "bond_mode=active-backup" - members: - - - type: sriov_vf - device: p2p1 - vfid: 2 - vlan_id: 112 - qos: 4 - primary: true - # For OVS Bond, the default value is true (recommended) - trust: true - # For OVS Bond, the default value is true (recommended) - promisc: true - # For OVS Bond, the default value is false (recommended) - spoofcheck: false - - - type: sriov_vf - device: p2p2 - vfid: 2 - vlan_id: 112 - qos: 4 - trust: true - promisc: true - spoofcheck: false - - type: linux_bond - name: bond_lnx - use_dhcp: true - bonding_options: "mode=active-backup" - members: - - - type: sriov_vf - device: p2p1 - vfid: 3 - vlan_id: 113 - qos: 5 - # For linux_bond, the default value is false - spoofcheck: false - # For linux_bond, the default value is true - trust: true - # For linux_bond, the default value is false - promisc: false - primary: true - - - type: sriov_vf - device: p2p2 - vfid: 3 - vlan_id: 113 - qos: 5 - spoofcheck: false - trust: true - promisc: false diff --git a/etc/os-net-config/samples/sriov_pf_ovs_dpdk.json b/etc/os-net-config/samples/sriov_pf_ovs_dpdk.json deleted file mode 100644 index 5d15bf13..00000000 --- a/etc/os-net-config/samples/sriov_pf_ovs_dpdk.json +++ /dev/null @@ -1,102 +0,0 @@ -{ - "network_config": [ - { - "type": "sriov_pf", - "name": "p2p1", - "numvfs": 10, - "use_dhcp": false, - "promisc": true - }, - { - "type": "sriov_pf", - "name": "p2p2", - "numvfs": 10, - "use_dhcp": false, - "promisc": true - }, - { - "type": "sriov_vf", - "device": "p2p1", - "vfid": 5, - "addresses": [ - { - "ip_netmask": "192.0.2.1/24" - } - ], - "vlan_id": 100, - "qos": 2, - "spoofcheck": true, - "macaddr": "00:78:90:80:cc:30", - "trust": true, - "state": "auto", - "promisc": false - }, - { - "name": "br-vfs", - "type": "ovs_user_bridge", - "use_dhcp": false, - "members": [ - { - "name": "dpdk0", - "type": "ovs_dpdk_port", - "members": [ - { - "device": "p5p2", - "qos": 3, - "spoofcheck": false, - "trust": true, - "type": "sriov_vf", - "vfid": 1, - "vlan_id": 116 - } - ] - } - ] - - }, - { - "type": "ovs_user_bridge", - "name": "br-bond", - "members": [ - { - "type" : "ovs_dpdk_bond", - "name" : "dpdkbond1", - "ovs_options": "bond_mode=active-backup", - "members": [ - { - "type" : "ovs_dpdk_port", - "name" : "dpdk2", - "members": [ - { - "type": "sriov_vf", - "device": "p2p1", - "vfid": 4, - "vlan_id": 114, - "spoofcheck": false, - "trust": true, - "qos": 6 - } - ], - "primary": true - }, - { - "type" : "ovs_dpdk_port", - "name" : "dpdk3", - "members": [ - { - "type": "sriov_vf", - "device": "p2p2", - "vfid": 4, - "vlan_id": 114, - "spoofcheck": false, - "trust": true, - "qos": 6 - } - ] - } - ] - } - ] - } - ] -} diff --git a/etc/os-net-config/samples/sriov_pf_ovs_dpdk.yaml b/etc/os-net-config/samples/sriov_pf_ovs_dpdk.yaml deleted file mode 100644 index aac2f7c3..00000000 --- a/etc/os-net-config/samples/sriov_pf_ovs_dpdk.yaml +++ /dev/null @@ -1,129 +0,0 @@ - - -network_config: - # sriov_pf type shall be used to configure the PF's of NICs. - # The numvfs configured for the PF's shall be set on the sriov_numvfs of the - # sysfs for the corresponding NIC and the persistence of the same across reboots - # shall be handled - - - type: sriov_pf - # nic name or nic number of the NIC that needs to be configured for SRIOV - name: p2p1 - # number of VFs required on the particular NIC - numvfs: 10 - # Dont set the IP address on the PF - use_dhcp: false - # Allow all the traffic received. It might be needed when one of its VF - # is attached to a ovs bridge. Default: true - promisc: true - - - type: sriov_pf - name: p2p2 - numvfs: 10 - use_dhcp: false - promisc: true - # sriov_vf type shall be used to configure the VF's of NICs. - # It requires the PF devices to be configured via sriov_pf types - # "name" parameter is not required for VF's. It'll be derived from the VF id - # and the PF device name. - - type: sriov_vf - # The PF device needs to be configured via the sriov_pf type - # the PF device could be a nic number (ex: nic5) or nic name (ex: ens20f0) - device: p2p1 - # The VF id shall be the VF number between 0 to (numvfs-1), where numvfs - # is the member of the sriov_pf type - vfid: 5 - addresses: - - ip_netmask: 192.0.2.1/24 - # When specified, all traffic sent from the VF will be tagged with the - # specified VLAN ID. Incoming traffic will be filtered for the specified - # VLAN ID, and will have all VLAN tags stripped before being passed to the - # VF. Setting this parameter to 0 disables VLAN tagging and filtering. - vlan_id: 100 - # VLAN-Quality Of Service (priority) bits for the VLAN tag. - # When specified, all VLAN tags transmitted by the VF will include the - # specified priority bits in the VLAN tag. Requires vlan_id - # Default value is 0. - qos: 2 - # MAC spoofing is a method of altering the MAC address - # The MAC address anti-spoofing when enabled protects from malicious MAC - # address spoofing. It should be disabled for 802.3ad bonds. - spoofcheck: true - # Change the MAC address of the VF. - macaddr: 00:78:90:80:cc:30 - # Enabling trust (true) for VF allows enabling multicast/promiscuous mode - # on the VF. The default value is false. - trust: true - # Link state seen by the VF - # - auto: a reflection of the PF link state (default) - # - enable: lets the VF to communicate with other VFs on this host even - # if the PF link state is down - # - disable: causes the HW to drop any packets sent by the VF. - state: auto - # Enabling promisc mode allows the traffic originally targeted to go to the - # VF and it will also receive the unmatched traffic and all the multicast - # traffic received in the physical port. Note that all traffic that has - # destination mac that does not match any of the VFs/PF MAC addresses is - # referred to as unmatched traffic. - # The default value is false. Requires the enabling of trust mode - promisc: false - # Attach a SR-IOV VF to a ovs user bridge - - type: ovs_user_bridge - name: br-vfs - use_dhcp: false - members: - - type: ovs_dpdk_port - name: dpdk0 - members: - # Specify the type - - type: sriov_vf - # Required field - device: p5p2 - # Required field - vfid: 1 - # Optional field - vlan_id: 116 - # Optional field, but requires vlan_id - qos: 3 - # Set trust to true when attaching to ovs_user_bridge - trust: true - # Set spoofcheck to false when attaching to ovs_user_bridge - spoofcheck: false - # Note: Do not set promisc mode. - - - type: ovs_user_bridge - name: br-bond - members: - - - type: ovs_dpdk_bond - name: dpdkbond1 - ovs_options: "bond_mode=active-backup" - members: - - - type: ovs_dpdk_port - name: dpdk2 - members: - - - type: sriov_vf - device: p2p1 - vfid: 4 - vlan_id: 114 - qos: 6 - # Default/Recommended : false - spoofcheck: false - # Default/Recommended : true - trust: true - primary: true - # Note: DO NOT SET promisc mode - - - type: ovs_dpdk_port - name: dpdk3 - members: - - - type: sriov_vf - device: p2p2 - vfid: 4 - vlan_id: 114 - qos: 6 - spoofcheck: false - trust: true diff --git a/etc/os-net-config/samples/sriov_pf_switchdev.json b/etc/os-net-config/samples/sriov_pf_switchdev.json deleted file mode 100644 index 391d8ace..00000000 --- a/etc/os-net-config/samples/sriov_pf_switchdev.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "network_config": [ - { - "type": "sriov_pf", - "name": "p2p1", - "numvfs": 10, - "use_dhcp": false, - "promisc": true, - "link_mode": "switchdev", - "steering_mode": "dmfs" - }, - { - "type": "ovs_bridge", - "name": "br-pfs", - "members": [ - { - "type": "sriov_pf", - "name": "p2p2", - "numvfs": 10, - "promisc": true, - "use_dhcp": false, - "link_mode": "switchdev" - } - ], - "use_dhcp": true - }, - { - "type": "ovs_bridge", - "name": "br-bond", - "use_dhcp": true, - "members": [ - { - "type": "ovs_bond", - "name": "bond_pf", - "ovs_options": "bond_mode=active-backup", - "members": [ - { - "type": "sriov_pf", - "name": "p5p1", - "numvfs": 10, - "primary": true, - "promisc": true, - "use_dhcp": false, - "link_mode": "switchdev" - }, - { - "type": "sriov_pf", - "name": "p5p2", - "numvfs": 10, - "promisc": true, - "use_dhcp": false, - "link_mode": "switchdev" - } - ] - } - ] - }, - { - "type": "linux_bond", - "name": "bond_lnx", - "use_dhcp": true, - "bonding_options": "mode=active-backup", - "members": [ - { - "type": "sriov_pf", - "name": "p6p1", - "numvfs": 10, - "primary": true, - "promisc": true, - "use_dhcp": false, - "link_mode": "switchdev" - }, - { - "type": "sriov_pf", - "name": "p6p2", - "numvfs": 10, - "promisc": true, - "use_dhcp": false, - "link_mode": "switchdev" - - } - ] - } - ] -} diff --git a/etc/os-net-config/samples/sriov_pf_switchdev.yaml b/etc/os-net-config/samples/sriov_pf_switchdev.yaml deleted file mode 100644 index 21b11856..00000000 --- a/etc/os-net-config/samples/sriov_pf_switchdev.yaml +++ /dev/null @@ -1,90 +0,0 @@ -network_config: - # sriov_pf type shall be used to configure the PF's of NICs. - # The numvfs configured for the PF's shall be set on the sriov_numvfs of the - # sysfs for the corresponding NIC and the persistence of the same across reboots - # shall be handled. - # The link_mode configured the mode of the sriov_pf which can be "switchdev" - # or legacy. - # In case fo switchdev, you will enable the hardware offloading and VF-LAG - # capabilities - # For now, if you configured link_mode with "switchdev" you will not be able - # to use any of its sriov_vfs, the vfs will be only used for vms. - - - type: sriov_pf - # nic name or nic number of the NIC that needs to be configured for SRIOV - name: p2p1 - # number of VFs required on the particular NIC - numvfs: 10 - addresses: - - ip_netmask: 192.0.2.1/24 - # Allow all the traffic received. Default: true - promisc: true - # The mode of sriov_pf which: - # - switchdev - # - legacy (default) - link_mode: switchdev - # (Optional) The flow steering mode, which could be smfs or dmfs - # If it's not set (None), the default will be smfs - steering_mode: dmfs - - - - type: ovs_bridge - name: br-pfs - use_dhcp: true - members: - - - type: sriov_pf - name: p2p2 - numvfs: 10 - promisc: true - use_dhcp: false - link_mode: switchdev - - - - type: ovs_bridge - name: br-bond - use_dhcp: true - members: - - - type: ovs_bond - name: bond_pf - ovs_options: "bond_mode=active-backup" - members: - - - type: sriov_pf - name: p5p1 - numvfs: 10 - primary: true - promisc: true - use_dhcp: false - link_mode: switchdev - - - type: sriov_pf - name: p5p2 - numvfs: 10 - promisc: true - use_dhcp: false - link_mode: switchdev - - - - # VF-LAG capability, which means that the vfs will be bonded in hardware - type: linux_bond - name: bond_lnx - use_dhcp: true - bonding_options: "mode=active-backup" - members: - - - type: sriov_pf - name: p6p1 - numvfs: 10 - primary: true - promisc: true - use_dhcp: false - link_mode: switchdev - - - type: sriov_pf - name: p6p2 - numvfs: 10 - promisc: true - use_dhcp: false - link_mode: switchdev diff --git a/etc/os-net-config/samples/team.json b/etc/os-net-config/samples/team.json deleted file mode 100644 index 4524b3cb..00000000 --- a/etc/os-net-config/samples/team.json +++ /dev/null @@ -1,13 +0,0 @@ -{ "network_config": [ - { - "type": "team", - "name": "team1", - "use_dhcp": true, - "bonding_options": "{\"runner\": {\"name\": \"activebackup\"}}", - "members": [ - { "type": "interface", "name": "em1", "primary": true }, - { "type": "interface", "name": "em2" } - ] - } - ] -} diff --git a/etc/os-net-config/samples/team.yaml b/etc/os-net-config/samples/team.yaml deleted file mode 100644 index 3770de0e..00000000 --- a/etc/os-net-config/samples/team.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# Config for bonding with teamd. Bonding options are provided as a JSON -# string. The following runners are available in teamd: broadcast, -# roundrobin, activebackup, loadbalance, and lacp. -# Please see the teamd.conf(5) man page for more information. -network_config: - - - type: team - name: team1 - use_dhcp: true - bonding_options: '{"runner": {"name": "activebackup"}}' - members: - - - type: interface - name: em1 - primary: true - - - type: interface - name: em2 diff --git a/etc/os-net-config/samples/vdpa.json b/etc/os-net-config/samples/vdpa.json deleted file mode 100644 index 6a50c04c..00000000 --- a/etc/os-net-config/samples/vdpa.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "network_config": [ - { - "type": "ovs_bridge", - "name": "br-vdpa", - "members": [ - { - "type": "sriov_pf", - "name": "p2p1", - "numvfs": 10, - "vdpa": true, - "use_dhcp": false, - "link_mode": "switchdev" - }, - { - "type": "sriov_pf", - "name": "p2p2", - "numvfs": 10, - "vdpa": true, - "use_dhcp": false, - "link_mode": "switchdev" - } - - ], - "use_dhcp": true - } - ] -} diff --git a/etc/os-net-config/samples/vdpa.yaml b/etc/os-net-config/samples/vdpa.yaml deleted file mode 100644 index 2a4cf9ae..00000000 --- a/etc/os-net-config/samples/vdpa.yaml +++ /dev/null @@ -1,31 +0,0 @@ -network_config: - # Since vDPA can't function without OVS Hardware Offload, the PFs have to - # be a member of an ovs_bridge. - - type: ovs_bridge - name: br-vdpa - use_dhcp: true - members: - # sriov_pf type shall be used to configure the PF's of vDPA devices. - # The numvfs configured for the PF's shall be set on the sriov_numvfs of the - # sysfs for the corresponding NIC and the persistence of the same across reboots - # shall be handled - - - type: sriov_pf - # nic name or nic number of the NIC that needs to be configured for vDPA - name: p2p1 - # Flag this PF as a vDPA device - vdpa: true - # number of VFs required on the particular NIC - # Should be at least one when vdpa is true - numvfs: 10 - # Dont set the IP address on the PF - use_dhcp: false - # Link mode for the PF has to be switchdev when vdpa is true - link_mode: switchdev - - - type: sriov_pf - name: p2p2 - vdpa: true - numvfs: 10 - use_dhcp: false - link_mode: switchdev diff --git a/etc/os-net-config/samples/vpp_bond.json b/etc/os-net-config/samples/vpp_bond.json deleted file mode 100644 index 8f67a358..00000000 --- a/etc/os-net-config/samples/vpp_bond.json +++ /dev/null @@ -1,23 +0,0 @@ -{ "network_config": [ - { - "type": "vpp_bond", - "name": "net_bonding0", - "addresses": [ - { - "ip_netmask": "192.0.2.1/24" - } - ], - "bonding_options": "mode=2,xmit_policy=l34", - "members": [ - { - "type": "vpp_interface", - "name": "eth1" - }, - { - "type": "vpp_interface", - "name": "eth2" - } - ] - } - ] -} diff --git a/etc/os-net-config/samples/vpp_bond.yaml b/etc/os-net-config/samples/vpp_bond.yaml deleted file mode 100644 index ce312ecb..00000000 --- a/etc/os-net-config/samples/vpp_bond.yaml +++ /dev/null @@ -1,17 +0,0 @@ -network_config: - - - type: vpp_bond - # name must be in the format of eth_bondX or net_bondingX, where X is a - # unique number for each bond. - name: net_bonding0 - addresses: - - - ip_netmask: 192.0.2.1/24 - bonding_options: "mode=2,xmit_policy=l34" - members: - - - type: vpp_interface - name: eth1 - - - type: vpp_interface - name: eth2 diff --git a/etc/os-net-config/samples/vpp_interface.json b/etc/os-net-config/samples/vpp_interface.json deleted file mode 100644 index 5d2f82aa..00000000 --- a/etc/os-net-config/samples/vpp_interface.json +++ /dev/null @@ -1,14 +0,0 @@ -{ "network_config": [ - { - "type": "vpp_interface", - "name": "nic2", - "addresses": [ - { - "ip_netmask": "192.0.2.1/24" - } - ], - "uio_driver": "uio_pci_generic", - "options": "vlan-strip-offload off" - } - ] -} diff --git a/etc/os-net-config/samples/vpp_interface.yaml b/etc/os-net-config/samples/vpp_interface.yaml deleted file mode 100644 index de790d59..00000000 --- a/etc/os-net-config/samples/vpp_interface.yaml +++ /dev/null @@ -1,18 +0,0 @@ -network_config: - - - type: vpp_interface - name: nic2 - addresses: - - - ip_netmask: 192.0.2.1/24 - # DPDK poll-mode driver name. Defaults to 'vfio-pci', other possible value - # is 'uio_pci_generic'. It is also possible to specify other driver names - # such as 'igb_uio', however, it is assumed that any required kernel - # modules for those drivers are already loaded when os-net-config is - # invoked. - uio_driver: uio_pci_generic - # Interface options such as vlan stripping and tx/rx transmit queues - # specification. Reference for those configurations can - # be found at https://wiki.fd.io/view/VPP/Command-line_Arguments - # Example: 'vlan-strip-offload on num-rx-queues 3' - #options: "vlan-strip-offload off" diff --git a/os_net_config/__init__.py b/os_net_config/__init__.py deleted file mode 100644 index 0fbffee8..00000000 --- a/os_net_config/__init__.py +++ /dev/null @@ -1,387 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2014-2015 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. - -import logging -import os - -from oslo_concurrency import processutils - -from os_net_config import objects -from os_net_config import utils - - -logger = logging.getLogger(__name__) - - -class NotImplemented(Exception): - pass - - -class ConfigurationError(Exception): - pass - - -class NetConfig(object): - """Common network config methods class.""" - - def __init__(self, noop=False, root_dir=''): - self.noop = noop - self.log_prefix = "NOOP: " if noop else "" - self.root_dir = root_dir - self.errors = [] - - def add_object(self, obj): - """Convenience method to add any type of object to the network config. - - See objects.py. - - :param obj: The object to add. - """ - if isinstance(obj, objects.RouteTable): - self.add_route_table(obj) - if isinstance(obj, objects.Interface): - self.add_interface(obj) - elif isinstance(obj, objects.Vlan): - self.add_vlan(obj) - elif isinstance(obj, objects.IvsInterface): - self.add_ivs_interface(obj) - elif isinstance(obj, objects.NfvswitchInternal): - self.add_nfvswitch_internal(obj) - elif isinstance(obj, objects.OvsBridge): - self.add_bridge(obj) - for member in obj.members: - self.add_object(member) - elif isinstance(obj, objects.OvsUserBridge): - self.add_ovs_user_bridge(obj) - for member in obj.members: - self.add_object(member) - elif isinstance(obj, objects.LinuxBridge): - self.add_linux_bridge(obj) - for member in obj.members: - self.add_object(member) - elif isinstance(obj, objects.IvsBridge): - self.add_ivs_bridge(obj) - for member in obj.members: - self.add_object(member) - elif isinstance(obj, objects.NfvswitchBridge): - self.add_nfvswitch_bridge(obj) - for member in obj.members: - self.add_object(member) - elif isinstance(obj, objects.OvsBond): - self.add_bond(obj) - for member in obj.members: - self.add_object(member) - elif isinstance(obj, objects.LinuxBond): - self.add_linux_bond(obj) - for member in obj.members: - self.add_object(member) - elif isinstance(obj, objects.LinuxTeam): - self.add_linux_team(obj) - for member in obj.members: - self.add_object(member) - elif isinstance(obj, objects.OvsTunnel): - self.add_ovs_tunnel(obj) - elif isinstance(obj, objects.OvsPatchPort): - self.add_ovs_patch_port(obj) - elif isinstance(obj, objects.IbInterface): - self.add_ib_interface(obj) - elif isinstance(obj, objects.IbChildInterface): - self.add_ib_child_interface(obj) - elif isinstance(obj, objects.OvsDpdkPort): - self.add_ovs_dpdk_port(obj) - elif isinstance(obj, objects.OvsDpdkBond): - self.add_ovs_dpdk_bond(obj) - elif isinstance(obj, objects.SriovPF): - self.add_sriov_pf(obj) - elif isinstance(obj, objects.SriovVF): - self.add_sriov_vf(obj) - elif isinstance(obj, objects.VppInterface): - self.add_vpp_interface(obj) - elif isinstance(obj, objects.VppBond): - self.add_vpp_bond(obj) - for member in obj.members: - self.add_object(member) - elif isinstance(obj, objects.ContrailVrouter): - self.add_contrail_vrouter(obj) - elif isinstance(obj, objects.ContrailVrouterDpdk): - self.add_contrail_vrouter_dpdk(obj) - elif isinstance(obj, objects.LinuxTap): - self.add_linux_tap(obj) - - def add_route_table(self, route_table): - """Add a route table object to the net config object. - - :param route_table: The RouteTable object to add. - """ - raise NotImplementedError("add_route_table is not implemented.") - - def add_interface(self, interface): - """Add an Interface object to the net config object. - - :param interface: The Interface object to add. - """ - raise NotImplementedError("add_interface is not implemented.") - - def add_vlan(self, vlan): - """Add a Vlan object to the net config object. - - :param vlan: The vlan object to add. - """ - raise NotImplementedError("add_vlan is not implemented.") - - def add_bridge(self, bridge): - """Add an OvsBridge object to the net config object. - - :param bridge: The OvsBridge object to add. - """ - raise NotImplementedError("add_bridge is not implemented.") - - def add_ovs_user_bridge(self, bridge): - """Add an OvsUserBridge object to the net config object. - - :param bridge: The OvsUserBridge object to add. - """ - raise NotImplementedError("add_ovs_user_bridge is not implemented.") - - def add_linux_bridge(self, bridge): - """Add a LinuxBridge object to the net config object. - - :param bridge: The LinuxBridge object to add. - """ - raise NotImplementedError("add_linux_bridge is not implemented.") - - def add_ivs_bridge(self, bridge): - """Add a IvsBridge object to the net config object. - - :param bridge: The IvsBridge object to add. - """ - raise NotImplementedError("add_ivs_bridge is not implemented.") - - def add_nfvswitch_bridge(self, bridge): - """Add a NfvswitchBridge object to the net config object. - - :param bridge: The NfvswitchBridge object to add. - """ - raise NotImplementedError("add_nfvswitch_bridge is not implemented.") - - def add_bond(self, bond): - """Add an OvsBond object to the net config object. - - :param bond: The OvsBond object to add. - """ - raise NotImplementedError("add_bond is not implemented.") - - def add_linux_bond(self, bond): - """Add a LinuxBond object to the net config object. - - :param bond: The LinuxBond object to add. - """ - raise NotImplementedError("add_linux_bond is not implemented.") - - def add_linux_team(self, team): - """Add a LinuxTeam object to the net config object. - - :param team: The LinuxTeam object to add. - """ - raise NotImplementedError("add_linux_team is not implemented.") - - def add_ovs_tunnel(self, tunnel): - """Add a OvsTunnel object to the net config object. - - :param tunnel: The OvsTunnel object to add. - """ - raise NotImplementedError("add_ovs_tunnel is not implemented.") - - def add_ovs_patch_port(self, ovs_patch_port): - """Add a OvsPatchPort object to the net config object. - - :param ovs_patch_port: The OvsPatchPort object to add. - """ - raise NotImplementedError("add_ovs_patch_port is not implemented.") - - def add_ib_interface(self, ib_interface): - """Add an InfiniBand Interface object to the net config object. - - :param interface: The InfiniBand Interface object to add. - """ - raise NotImplementedError("add_ib_interface is not implemented.") - - def add_ib_child_interface(self, ib_child_interface): - """Add an InfiniBand child interface object to the net config object. - - :param ib_child_interface: The InfiniBand child - interface object to add. - """ - raise NotImplementedError("add_ib_child_interface is not implemented.") - - def add_ovs_dpdk_port(self, ovs_dpdk_port): - """Add a OvsDpdkPort object to the net config object. - - :param ovs_dpdk_port: The OvsDpdkPort object to add. - """ - raise NotImplementedError("add_ovs_dpdk_port is not implemented.") - - def add_ovs_dpdk_bond(self, ovs_dpdk_bond): - """Add a OvsDpdkBond object to the net config object. - - :param ovs_dpdk_bond: The OvsDpdkBond object to add. - """ - raise NotImplementedError("add_ovs_dpdk_bond is not implemented.") - - def add_sriov_pf(self, sriov_pf): - """Add a SriovPF object to the net config object. - - :param sriov_pf: The SriovPF object to add. - """ - raise NotImplementedError("add_sriov_pf is not implemented.") - - def add_sriov_vf(self, sriov_vf): - """Add a SriovVF object to the net config object. - - :param sriov_vf: The SriovVF object to add. - """ - raise NotImplementedError("add_sriov_vf is not implemented.") - - def add_vpp_interface(self, vpp_interface): - """Add a VppInterface object to the net config object. - - :param vpp_interface: The VppInterface object to add. - """ - raise NotImplementedError("add_vpp_interface is not implemented.") - - def add_vpp_bond(self, vpp_bond): - """Add a VppBond object to the net config object. - - :param vpp_bond: The VppBond object to add. - """ - raise NotImplementedError("add_vpp_bond is not implemented.") - - def add_contrail_vrouter(self, contrail_vrouter): - """Add a ContrailVrouter object to the net config object. - - :param contrail_vrouter: - The ContrailVrouter object to add. - """ - raise NotImplementedError("add_contrail_vrouter is not implemented.") - - def add_contrail_vrouter_dpdk(self, contrail_vrouter_dpdk): - """Add a ContrailVrouterDpdk object to the net config object. - - :param contrail_vrouter_dpdk: - The ContrailVrouterDpdk object to add. - """ - raise NotImplementedError( - "add_contrail_vrouter_dpdk is not implemented.") - - def add_linux_tap(self, linux_tap): - """Add a LinuxTap object to the net config object. - - :param linux_tap: - The LinuxTap object to add. - """ - raise NotImplementedError( - "add_linux_tap is not implemented.") - - def apply(self, cleanup=False): - """Apply the network configuration. - - :param cleanup: A boolean which indicates whether any undefined - (existing but not present in the object model) interfaces - should be disabled and deleted. - :returns: a dict of the format: filename/data which contains info - for each file that was changed (or would be changed if in --noop - mode). - """ - raise NotImplementedError("apply is not implemented.") - - def execute(self, msg, cmd, *args, **kwargs): - """Print a message and run a command. - - Print a message and run a command with processutils - in noop mode, this just prints a message. - """ - logger.info('%s%s' % (self.log_prefix, msg)) - if not self.noop: - processutils.execute(cmd, *args, **kwargs) - - def write_config(self, filename, data, msg=None): - msg = msg or "Writing config %s" % filename - logger.info('%s%s' % (self.log_prefix, msg)) - if not self.noop: - utils.write_config(filename, data) - - def remove_config(self, filename, msg=None): - msg = msg or "Removing config %s" % filename - logger.info('%s%s' % (self.log_prefix, msg)) - if not self.noop: - os.remove(filename) - - def ifdown(self, interface, iftype='interface'): - msg = 'running ifdown on %s: %s' % (iftype, interface) - self.execute(msg, '/sbin/ifdown', interface, check_exit_code=False) - if utils.is_active_nic(interface): - msg = '%s %s is up, trying with ip command' % (iftype, interface) - self.execute(msg, '/sbin/ip', - 'link', 'set', 'dev', interface, 'down') - - def ifup(self, interface, iftype='interface'): - """Run 'ifup' on the specified interface - - If a failure occurs when bringing up the interface it will be saved - to self.errors for later handling. This allows callers to continue - trying to bring up interfaces even if one fails. - - :param interface: The name of the interface to be started. - :param iftype: The type of the interface. - """ - msg = 'running ifup on %s: %s' % (iftype, interface) - try: - self.execute(msg, '/sbin/ifup', interface) - except processutils.ProcessExecutionError as e: - self.errors.append(e) - - def ifrename(self, oldname, newname): - msg = 'renaming %s to %s: ' % (oldname, newname) - # ifdown isn't enough when renaming, we need the link down - for name in (oldname, newname): - if utils.is_active_nic(name): - self.execute(msg, '/sbin/ip', - 'link', 'set', 'dev', name, 'down') - self.execute(msg, '/sbin/ip', - 'link', 'set', 'dev', name, 'link', 'down') - self.execute(msg, '/sbin/ip', - 'link', 'set', 'dev', oldname, 'name', newname) - self.execute(msg, '/sbin/ip', - 'link', 'set', 'dev', newname, 'up') - - def ovs_appctl(self, action, *parameters, ignore_err=False): - """Run 'ovs-appctl' with the specified action - - Its possible the command may fail due to timing if, for example, - the command affects an interface and it the prior ifup command - has not completed. So retry the command and if a failures still - occurs save the error for later handling. - - :param action: The ovs-appctl action. - :param parameters: Parameters to pass to ovs-appctl. - """ - msg = 'Running ovs-appctl %s %s' % (action, parameters) - try: - self.execute(msg, '/bin/ovs-appctl', action, *parameters, - delay_on_retry=True, attempts=5) - except processutils.ProcessExecutionError as e: - if not ignore_err: - self.errors.append(e) diff --git a/os_net_config/cli.py b/os_net_config/cli.py deleted file mode 100644 index 85438227..00000000 --- a/os_net_config/cli.py +++ /dev/null @@ -1,365 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2014-2015 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. - - -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 impl_nmstate -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', - help="""Identify the real interface for a nic name. """ - """If a real name is given, it is returned if live. """ - """If no value is given, display full NIC mapping. """ - """Exit after printing, ignoring other parameters. """, - nargs='*', default=None) - parser.add_argument('-p', '--provider', metavar='PROVIDER', - help="""The provider to use. """ - """One of: ifcfg, eni, nmstate, iproute.""", - default=None) - parser.add_argument('-r', '--root-dir', metavar='ROOT_DIR', - help="""The root directory of the filesystem.""", - default='') - parser.add_argument('--detailed-exit-codes', - action='store_true', - help="""Enable detailed exit codes. """ - """If enabled an exit code of '2' means """ - """that files were modified. """ - """Disabled by default.""", - default=False) - - parser.add_argument( - '--exit-on-validation-errors', - action='store_true', - help="Exit with an error if configuration file validation fails. " - "Without this option, just log a warning and continue.", - default=False) - - parser.add_argument( - '-d', '--debug', - dest="debug", - action='store_true', - help="Print debugging output.", - required=False) - parser.add_argument( - '-v', '--verbose', - dest="verbose", - action='store_true', - help="Print verbose output.", - required=False) - - parser.add_argument('--version', action='version', - version=version.version_info.version_string()) - parser.add_argument( - '--noop', - dest="noop", - action='store_true', - help="Return the configuration commands, without applying them.", - required=False) - - parser.add_argument( - '--no-activate', - dest="no_activate", - action='store_true', - help="Install the configuration but don't start/stop interfaces.", - required=False) - - parser.add_argument( - '--cleanup', - dest="cleanup", - action='store_true', - help="Cleanup unconfigured interfaces.", - required=False) - - parser.add_argument( - '--persist-mapping', - dest="persist_mapping", - action='store_true', - help="Make aliases defined in the mapping file permanent " - "(WARNING, permanently renames nics).", - required=False) - - opts = parser.parse_args(argv[1:]) - - return opts - - -def _is_sriovpf_obj_found(obj): - configure_sriov = False - if isinstance(obj, objects.SriovPF): - configure_sriov = True - elif hasattr(obj, 'members') and obj.members is not None: - for member in obj.members: - if isinstance(member, objects.SriovPF): - configure_sriov = True - break - else: - configure_sriov = _is_sriovpf_obj_found(member) - return configure_sriov - - -def disable_ipv6_for_netdevs(net_devices): - sysctl_conf = "" - for net_device in net_devices: - sysctl_conf += "net.ipv6.conf.%s.disable_ipv6 = 1\n" % net_device - utils.write_config(_SYSTEM_CTL_CONFIG_FILE, sysctl_conf) - - -def get_sriovpf_member_of_bond_ovs_port(obj): - net_devs_list = [] - if isinstance(obj, objects.OvsBridge): - for member in obj.members: - if isinstance(member, objects.LinuxBond): - for child_member in member.members: - if isinstance(child_member, objects.SriovPF): - if child_member.link_mode == 'switchdev': - net_devs_list.append(child_member.name) - return net_devs_list - - -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_bond_ovs_ports = [] - 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) - elif opts.provider == 'nmstate': - provider = impl_nmstate.NmstateNetConfig(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) - opts.provider = "ifcfg" - elif os.path.exists('%s/etc/network/' % opts.root_dir): - provider = impl_eni.ENINetConfig(noop=opts.noop, - root_dir=opts.root_dir) - opts.provider = "eni" - 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 _is_sriovpf_obj_found(obj): - configure_sriov = True - provider.add_object(obj) - # Look for the presence of SriovPF as members of LinuxBond and that - # LinuxBond is member of OvsBridge - sriovpf_bond_ovs_ports.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_bond_ovs_ports: - disable_ipv6_for_netdevs(sriovpf_bond_ovs_ports) - - 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 , since the ifcfgs for PFs - # wouldn't have changed. - pf_files_changed = provider.apply(cleanup=opts.cleanup, - activate=not opts.no_activate) - if opts.provider == 'ifcfg' and not opts.noop: - restart_ovs = bool(sriovpf_bond_ovs_ports) - # 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 sriov_pfs at top level or at any member level will be - # ignored and all other objects are parsed 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 _is_sriovpf_obj_found(obj): - provider.add_object(obj) - - if opts.provider == 'ifcfg' and 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 - - -if __name__ == '__main__': - sys.exit(main(sys.argv, main_logger=logger)) diff --git a/os_net_config/common.py b/os_net_config/common.py deleted file mode 100644 index d41fbb54..00000000 --- a/os_net_config/common.py +++ /dev/null @@ -1,302 +0,0 @@ -# -*- 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 -from oslo_concurrency import processutils -import sys -import yaml - -# File to contain the DPDK mapped nics, as nic name will not be available after -# binding driver, which is required for correct nic numbering. -# Format of the file (list mapped nic's details): -# - -# name: eth1 -# pci_address: 0000:02:00.0 -# mac_address: 01:02:03:04:05:06 -# driver: vfio-pci -DPDK_MAPPING_FILE = '/var/lib/os-net-config/dpdk_mapping.yaml' - -# File to contain the list of SR-IOV PF, VF and their configurations -# Format of the file shall be -# - device_type: pf -# name: -# numvfs: -# promisc: "on"/"off" -# - device_type: vf -# device: -# name: -# vfid: -# name: -# vlan_id: -# qos: -# spoofcheck: "on"/"off" -# trust: "on"/"off" -# state: "auto"/"enable"/"disable" -# macaddr: -# promisc: "on"/"off" -SRIOV_CONFIG_FILE = '/var/lib/os-net-config/sriov_config.yaml' - - -_SYS_BUS_PCI_DEV = '/sys/bus/pci/devices' -SYS_CLASS_NET = '/sys/class/net' -_LOG_FILE = '/var/log/os-net-config.log' -MLNX_VENDOR_ID = "0x15b3" - -logger = logging.getLogger(__name__) - - -class OvsDpdkBindException(ValueError): - pass - - -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_pci_dev_path(pci_address, path=None): - if not path: - path = "" - elif path.startswith("_"): - path = path[1:] - return os.path.join(_SYS_BUS_PCI_DEV, pci_address, 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 - - -def get_file_data(filename): - if not os.path.exists(filename): - return '' - try: - with open(filename, 'r') as f: - return f.read() - except IOError: - logger.error(f"Error reading file: {filename}") - return '' - - -def get_sriov_map(pf_name=None): - contents = get_file_data(SRIOV_CONFIG_FILE) - sriov_map = yaml.safe_load(contents) if contents else [] - if len(sriov_map) and pf_name: - return [pf for pf in sriov_map if pf['name'] == pf_name] - return sriov_map - - -def get_dpdk_map(): - contents = get_file_data(DPDK_MAPPING_FILE) - dpdk_map = yaml.safe_load(contents) if contents else [] - return dpdk_map - - -def _get_dpdk_mac_address(name): - contents = get_file_data(DPDK_MAPPING_FILE) - dpdk_map = yaml.safe_load(contents) if contents else [] - for item in dpdk_map: - if item['name'] == name: - return item['mac_address'] - - -def interface_mac(name): - try: # If the iface is part of a Linux bond, the real MAC is only here. - with open(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(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 - # the DPDK mapping file as /sys files will be removed after binding. - dpdk_mac_address = _get_dpdk_mac_address(name) - if dpdk_mac_address: - return dpdk_mac_address - - logger.error("Unable to read mac address: %s" % name) - raise - - -def get_interface_driver_by_pci_address(pci_address): - try: - uevent = get_pci_dev_path(pci_address, 'uevent') - with open(uevent, 'r') as f: - out = f.read().strip() - for line in out.split('\n'): - if 'DRIVER' in line: - driver = line.split('=') - if len(driver) == 2: - return driver[1] - except IOError: - return - - -def is_mellanox_interface(ifname): - vendor_id = get_vendor_id(ifname) - return vendor_id == MLNX_VENDOR_ID - - -def is_vf(pci_address): - - # 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//physfn to understand if the device - # is actually a VF. This path could be used by VFs not bound with - # DPDK drivers as well - - vf_path_check = _SYS_BUS_PCI_DEV + '/%s/physfn' % pci_address - is_sriov_vf = os.path.isdir(vf_path_check) - return is_sriov_vf - - -def is_vf_by_name(interface_name, check_mapping_file=False): - vf_path_check = 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() - for item in sriov_map: - if (item['name'] == interface_name and - item['device_type'] == 'vf'): - is_sriov_vf = True - return is_sriov_vf - - -def set_driverctl_override(pci_address, driver): - if driver is None: - logger.info(f"Driver override is not required for device" - "{pci_address}") - return False - iface_driver = get_interface_driver_by_pci_address(pci_address) - if iface_driver == driver: - logger.info(f"Driver {driver} is already bound to the device" - "{pci_address}") - return False - try: - if is_vf(pci_address): - out, err = processutils.execute('driverctl', '--nosave', - 'set-override', pci_address, - driver) - else: - out, err = processutils.execute('driverctl', 'set-override', - pci_address, driver) - if err: - msg = f"Failed to bind dpdk interface {pci_address} err - {err}" - raise OvsDpdkBindException(msg) - except processutils.ProcessExecutionError: - msg = f"Failed to bind interface {pci_address} with dpdk" - raise OvsDpdkBindException(msg) - return err - - -def list_kmods(mods: list) -> list: - """Listing Kernel Modules - - Checks in currently loaded modules for a list - of modules and returns the ones that are not loaded - """ - try: - stdout, stderr = processutils.execute('lsmod') - except processutils.ProcessExecutionError as exc: - logger.error(f"Failed to get lsmod: {exc}") - raise - modules = set([line.split()[0] for line in stdout.strip().split('\n')]) - return list(set(mods) - set(modules)) - - -def load_kmods(mods: list): - """Loading Kernel Modules - - Loads modules from list that are not already loaded - """ - needed = list_kmods(mods) - for mod in needed: - try: - stdout, stderr = processutils.execute('modprobe', mod) - except processutils.ProcessExecutionError as exc: - logger.error(f"Failed to modprobe {mod}: {exc}") - raise - - -def restorecon(path: str): - """Executes restorecon on a path""" - logger.info(f"Restoring selinux context on {path}") - try: - stdout, stderr = processutils.execute('restorecon', '-R', '-F', '-v', - path) - except processutils.ProcessExecutionError as exc: - logger.error(f"Failed to restorecon on {path}: {exc}") - raise - logger.debug(f"Restorecon completed: {stdout}") diff --git a/os_net_config/impl_eni.py b/os_net_config/impl_eni.py deleted file mode 100644 index 2dae97b0..00000000 --- a/os_net_config/impl_eni.py +++ /dev/null @@ -1,256 +0,0 @@ -# -*- Coding: utf-8 -*- - -# Copyright 2014-2015 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. - -import logging - -import netaddr -import os_net_config -from os_net_config import common -from os_net_config import objects -from os_net_config import utils - -logger = logging.getLogger(__name__) - - -# TODO(?): should move to interfaces.d -def _network_config_path(prefix=''): - return prefix + "/etc/network/interfaces" - - -class ENINetConfig(os_net_config.NetConfig): - """Debian/Ubuntu implementation for network config - - Configure iface/bridge/routes using debian/ubuntu - /etc/network/interfaces format. - """ - - def __init__(self, noop=False, root_dir=''): - super(ENINetConfig, self).__init__(noop, root_dir) - self.interfaces = {} - self.routes = {} - self.bridges = {} - logger.info('ENI net config provider created.') - - def _add_common(self, interface, static_addr=None, ip_version=4): - - ovs_extra = [] - data = "" - address_data = "" - if static_addr: - address_data += " address %s\n" % static_addr.ip - if ip_version == 6: - address_data += " netmask %s\n" % static_addr.prefixlen - else: - address_data += " netmask %s\n" % static_addr.netmask - else: - v4_addresses = interface.v4_addresses() - if v4_addresses: - for v4_address in v4_addresses: - data += self._add_common(interface, v4_address) - - v6_addresses = interface.v6_addresses() - if v6_addresses: - for v6_address in v6_addresses: - data += self._add_common(interface, v6_address, 6) - - if data: - return data - - if isinstance(interface, objects.Vlan): - _iface = "iface vlan%i " % interface.vlan_id - else: - _iface = "iface %s " % interface.name - if static_addr and static_addr.version == 6: - _iface += "inet6 " - else: - _iface += "inet " - if interface.use_dhcp: - _iface += "dhcp\n" - elif interface.addresses: - _iface += "static\n" - else: - _iface += "manual\n" - if isinstance(interface, objects.OvsBridge): - data += "auto %s\n" % interface.name - data += "allow-ovs %s\n" % interface.name - data += _iface - data += address_data - data += " ovs_type OVSBridge\n" - if interface.members: - data += " ovs_ports" - for i in interface.members: - data += " %s" % i.name - data += "\n" - for mem in interface.members: - if isinstance(mem, objects.Interface): - data += " pre-up ip addr flush dev %s\n" % mem.name - if interface.primary_interface_name: - mac = common.interface_mac( - interface.primary_interface_name) - ovs_extra.append("set bridge %s other-config:hwaddr=%s" % - (interface.name, mac)) - ovs_extra.extend(interface.ovs_extra) - elif interface.ovs_port: - if isinstance(interface, objects.Vlan): - data += "auto vlan%i\n" % interface.vlan_id - data += "allow-%s vlan%i\n" % (interface.bridge_name, - interface.vlan_id) - data += _iface - data += address_data - data += " ovs_bridge %s\n" % interface.bridge_name - data += " ovs_type OVSIntPort\n" - data += " ovs_options tag=%s\n" % interface.vlan_id - - else: - data += "auto %s\n" % interface.name - data += "allow-%s %s\n" % (interface.bridge_name, - interface.name) - data += _iface - data += address_data - data += " ovs_bridge %s\n" % interface.bridge_name - data += " ovs_type OVSPort\n" - elif isinstance(interface, objects.Vlan): - data += "auto vlan%i\n" % interface.vlan_id - data += _iface - data += address_data - data += " vlan-raw-device %s\n" % interface.device - else: - if isinstance(interface, objects.Interface) and interface.hotplug: - data += "allow-hotplug %s\n" % interface.name - else: - data += "auto %s\n" % interface.name - data += _iface - data += address_data - if interface.mtu: - data += " mtu %i\n" % interface.mtu - - if interface.hwaddr: - raise NotImplementedError("hwaddr is not implemented.") - - if ovs_extra: - data += " ovs_extra %s\n" % " -- ".join(ovs_extra) - - return data - - def add_interface(self, interface): - """Add an Interface object to the net config object. - - :param interface: The Interface object to add. - """ - logger.info('adding interface: %s' % interface.name) - data = self._add_common(interface) - logger.debug('interface data: %s' % data) - self.interfaces[interface.name] = data - if interface.routes: - self._add_routes(interface.name, interface.routes) - - def add_bridge(self, bridge): - """Add an OvsBridge object to the net config object. - - :param bridge: The OvsBridge object to add. - """ - logger.info('adding bridge: %s' % bridge.name) - data = self._add_common(bridge) - logger.debug('bridge data: %s' % data) - self.bridges[bridge.name] = data - if bridge.routes: - self._add_routes(bridge.name, bridge.routes) - - def add_vlan(self, vlan): - """Add a Vlan object to the net config object. - - :param vlan: The vlan object to add. - """ - logger.info('adding vlan: %s' % vlan.name) - data = self._add_common(vlan) - logger.debug('vlan data: %s' % data) - self.interfaces[vlan.name] = data - if vlan.routes: - self._add_routes(vlan.name, vlan.routes) - - def _add_routes(self, interface_name, routes=[]): - logger.info('adding custom route for interface: %s' % interface_name) - data = "" - for route in routes: - options = "" - if route.route_options: - options = " %s" % (route.route_options) - if route.default and not route.ip_netmask: - rt = netaddr.IPNetwork("0.0.0.0/0") - else: - rt = netaddr.IPNetwork(route.ip_netmask) - data += "up route add -net %s netmask %s gw %s%s\n" % ( - str(rt.ip), str(rt.netmask), route.next_hop, options) - data += "down route del -net %s netmask %s gw %s%s\n" % ( - str(rt.ip), str(rt.netmask), route.next_hop, options) - self.routes[interface_name] = data - logger.debug('route data: %s' % self.routes[interface_name]) - - def apply(self, cleanup=False, activate=True): - """Apply the network configuration. - - :param cleanup: A boolean which indicates whether any undefined - (existing but not present in the object model) interface - should be disabled and deleted. - :param activate: A boolean which indicates if the config should - be activated by stopping/starting interfaces - :returns: a dict of the format: filename/data which contains info - for each file that was changed (or would be changed if in --noop - mode). - Note the noop mode is set via the constructor noop boolean - """ - new_config = "" - - # write out bridges first. This ensures that an ifup -a - # on reboot brings them up first - for bridge_name, bridge_data in self.bridges.items(): - route_data = self.routes.get(bridge_name) - bridge_data += (route_data or '') - new_config += bridge_data - - for interface_name, iface_data in self.interfaces.items(): - route_data = self.routes.get(interface_name) - iface_data += (route_data or '') - new_config += iface_data - - if utils.diff(_network_config_path(self.root_dir), new_config): - if activate: - for interface in self.interfaces.keys(): - self.ifdown(interface) - - for bridge in self.bridges.keys(): - self.ifdown(bridge, iftype='bridge') - - self.write_config(_network_config_path(self.root_dir), new_config) - - if activate: - for bridge in self.bridges.keys(): - self.ifup(bridge, iftype='bridge') - - for interface in self.interfaces.keys(): - self.ifup(interface) - - if self.errors: - message = 'Failure(s) occurred when applying configuration' - logger.error(message) - for e in self.errors: - logger.error('stdout: %s, stderr: %s', e.stdout, - e.stderr) - raise os_net_config.ConfigurationError(message) - else: - logger.info('No interface changes are required.') - - return {_network_config_path(self.root_dir): new_config} diff --git a/os_net_config/impl_ifcfg.py b/os_net_config/impl_ifcfg.py deleted file mode 100644 index 422cf947..00000000 --- a/os_net_config/impl_ifcfg.py +++ /dev/null @@ -1,2011 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2014-2015 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. - -import glob -import itertools -import logging -import netaddr -import os -import re - -import os_net_config -from os_net_config import common -from os_net_config import objects -from os_net_config import utils - -logger = logging.getLogger(__name__) - -# Import the raw NetConfig object so we can call its methods -netconfig = os_net_config.NetConfig() - -MAC_TABLE_SIZE = 50000 -_ROUTE_TABLE_DEFAULT = """# reserved values -# -255\tlocal -254\tmain -253\tdefault -0\tunspec -# -# local -# -#1\tinr.ruhep\n""" - - -def ifcfg_config_path(name): - return "/etc/sysconfig/network-scripts/ifcfg-%s" % name - - -def remove_ifcfg_config(ifname): - if re.match(r'[\w-]+$', ifname): - ifcfg_file = ifcfg_config_path(ifname) - if os.path.exists(ifcfg_file): - logger.info('removing existing ifcfg script for intf: %s' % ifname) - os.remove(ifcfg_file) - - -# NOTE(dprince): added here for testability -def bridge_config_path(name): - return ifcfg_config_path(name) - - -def ivs_config_path(): - return "/etc/sysconfig/ivs" - - -def nfvswitch_config_path(): - return "/etc/sysconfig/nfvswitch" - - -def vpp_config_path(): - return "/etc/vpp/startup.conf" - - -def route_config_path(name): - return "/etc/sysconfig/network-scripts/route-%s" % name - - -def route6_config_path(name): - return "/etc/sysconfig/network-scripts/route6-%s" % name - - -def route_rule_config_path(name): - return "/etc/sysconfig/network-scripts/rule-%s" % name - - -def route_table_config_path(): - return "/etc/iproute2/rt_tables" - - -def cleanup_pattern(): - return "/etc/sysconfig/network-scripts/ifcfg-*" - - -def dhclient_path(): - if os.path.exists("/usr/sbin/dhclient"): - return "/usr/sbin/dhclient" - elif os.path.exists("/sbin/dhclient"): - return "/sbin/dhclient" - else: - raise RuntimeError("Could not find dhclient") - - -def stop_dhclient_process(interface): - """Stop a DHCP process when no longer needed. - - This method exists so that it may be stubbed out for unit tests. - :param interface: The interface on which to stop dhclient. - """ - pid_file = '/var/run/dhclient-%s.pid' % (interface) - try: - dhclient = dhclient_path() - except RuntimeError as err: - logger.info('Exception when stopping dhclient: %s' % err) - return - - if os.path.exists(pid_file): - msg = 'Stopping %s on interface %s' % (dhclient, interface) - netconfig.execute(msg, dhclient, '-r', '-pf', - pid_file, interface) - try: - os.unlink(pid_file) - except OSError as err: - logger.error('Could not remove dhclient pid file \'%s\': %s' % - (pid_file, err)) - - -class IfcfgNetConfig(os_net_config.NetConfig): - """Configure network interfaces using the ifcfg format.""" - - def __init__(self, noop=False, root_dir=''): - super(IfcfgNetConfig, self).__init__(noop, root_dir) - self.interface_data = {} - self.ivsinterface_data = {} - self.nfvswitch_intiface_data = {} - self.nfvswitch_options = None - self.vlan_data = {} - self.ib_childs_data = {} - self.route_data = {} - self.route6_data = {} - self.route_table_data = {} - self.rule_data = {} - self.bridge_data = {} - self.linuxbridge_data = {} - self.linuxbond_data = {} - self.ib_interface_data = {} - self.linuxteam_data = {} - self.vpp_interface_data = {} - self.vpp_bond_data = {} - self.member_names = {} - self.renamed_interfaces = {} - self.bond_primary_ifaces = {} - logger.info('Ifcfg net config provider created.') - - def parse_ifcfg(self, ifcfg_data): - """Break out the key/value pairs from ifcfg_data - - Return the keys and values without quotes. - """ - ifcfg_values = {} - for line in ifcfg_data.split("\n"): - if not line.startswith("#") and line.find("=") > 0: - k, v = line.split("=", 1) - ifcfg_values[k] = v.strip("\"'") - return ifcfg_values - - def parse_ifcfg_routes(self, ifcfg_data): - """Break out the individual routes from an ifcfg route file.""" - routes = [] - for line in ifcfg_data.split("\n"): - if not line.startswith("#"): - routes.append(line) - return routes - - def parse_ifcfg_rules(self, ifcfg_data): - """Break out the individual rules from an ifcfg rule file.""" - rules = [] - for line in ifcfg_data.split("\n"): - if not line.startswith("#"): - rules.append(line) - return rules - - def enumerate_ifcfg_changes(self, ifcfg_data_old, ifcfg_data_new): - """Determine which values are added/modified/removed - - :param ifcfg_data_old: content of existing ifcfg file - :param ifcfg_data_new: content of replacement ifcfg file - :return: dict of changed values and states (added, removed, modified) - """ - - changed_values = {} - for key in ifcfg_data_old: - if key in ifcfg_data_new: - if ifcfg_data_old[key].upper() != ifcfg_data_new[key].upper(): - changed_values[key] = "modified" - else: - changed_values[key] = "removed" - for key in ifcfg_data_new: - if key not in ifcfg_data_old: - changed_values[key] = "added" - return changed_values - - def enumerate_ifcfg_route_changes(self, old_routes, new_routes): - """Determine which routes are added or removed. - - :param file_values: contents of existing interface route file - :param data_values: contents of replacement interface route file - :return: list of tuples representing changes (route, state), where - state is one of added or removed - """ - - route_changes = [] - for route in old_routes: - if route not in new_routes: - route_changes.append((route, 'removed')) - for route in new_routes: - if route not in old_routes: - route_changes.append((route, 'added')) - return route_changes - - def enumerate_ifcfg_rule_changes(self, old_rules, new_rules): - """Determine which routes are added or removed. - - :param file_values: contents of existing interface route rule file - :param data_values: contents of replacement interface route rule file - :return: list of tuples representing changes (rule, state), where - state is one of added or removed - """ - - rule_changes = [] - for rule in old_rules: - if rule not in new_rules: - rule_changes.append((rule, 'removed')) - for rule in new_rules: - if rule not in old_rules: - rule_changes.append((rule, 'added')) - return rule_changes - - def ifcfg_requires_restart(self, filename, new_data): - """Determine if changes to the ifcfg file require a restart to apply. - - Simple changes like IP, MTU, and routes can be directly applied - without restarting the interface. - - :param filename: The ifcfg- filename. - :type filename: string - :param new_data: The data for the new ifcfg- file. - :type new_data: string - :returns: boolean value for whether a restart is required - """ - - file_data = common.get_file_data(filename) - logger.debug("Original ifcfg file:\n%s" % file_data) - logger.debug("New ifcfg file:\n%s" % new_data) - file_values = self.parse_ifcfg(file_data) - new_values = self.parse_ifcfg(new_data) - restart_required = False - # Certain changes can be applied without restarting the interface - permitted_changes = [ - "IPADDR", - "NETMASK", - "MTU", - "ONBOOT", - "ETHTOOL_OPTS" - ] - # Check whether any of the changes require restart - for change in self.enumerate_ifcfg_changes(file_values, new_values): - if change not in permitted_changes: - # Moving to DHCP requires restarting interface - if change in ["BOOTPROTO", "OVSBOOTPROTO"]: - if change in new_values: - if (new_values[change].upper() == "DHCP"): - restart_required = True - logger.debug( - "DHCP on %s requires restart" % change) - else: - restart_required = True - if not restart_required: - logger.debug("Changes do not require restart") - return restart_required - - def iproute2_apply_commands(self, device_name, filename, data): - """Return list of commands needed to implement changes. - - Given ifcfg data for an interface, return commands required to - apply the configuration using 'ip' commands. - - :param device_name: The name of the int, bridge, or bond - :type device_name: string - :param filename: The ifcfg- filename. - :type filename: string - :param data: The data for the new ifcfg- file. - :type data: string - :returns: commands (commands to be run) - """ - - previous_cfg = common.get_file_data(filename) - file_values = self.parse_ifcfg(previous_cfg) - data_values = self.parse_ifcfg(data) - logger.debug("File values:\n%s" % file_values) - logger.debug("Data values:\n%s" % data_values) - changes = self.enumerate_ifcfg_changes(file_values, data_values) - commands = [] - new_cidr = 0 - old_cidr = 0 - # Convert dot notation netmask to CIDR length notation - if "NETMASK" in file_values: - netmask = file_values["NETMASK"] - old_cidr = netaddr.IPAddress(netmask).netmask_bits() - if "NETMASK" in data_values: - netmask = data_values["NETMASK"] - new_cidr = netaddr.IPAddress(netmask).netmask_bits() - if "IPADDR" in changes: - if changes["IPADDR"] == "removed" or changes[ - "IPADDR"] == "modified": - if old_cidr: - commands.append("addr del %s/%s dev %s" % - (file_values["IPADDR"], old_cidr, - device_name)) - else: - # Cannot remove old IP specifically if netmask not known - commands.append("addr flush dev %s" % device_name) - if changes["IPADDR"] == "added" or changes["IPADDR"] == "modified": - commands.insert(0, "addr add %s/%s dev %s" % - (data_values["IPADDR"], new_cidr, device_name)) - if "MTU" in changes: - if changes["MTU"] == "added" or changes["MTU"] == "modified": - commands.append("link set dev %s mtu %s" % - (device_name, data_values["MTU"])) - elif changes["MTU"] == "removed": - commands.append("link set dev %s mtu 1500" % device_name) - return commands - - def ethtool_apply_command(self, device_name, filename, data): - """Return list of commands needed to implement changes. - - Given ifcfg data for an interface, return commands required to - apply the configuration using 'ethtool' commands. - - :param device_name: The name of the int, bridge, or bond - :type device_name: string - :param filename: The ifcfg- filename. - :type filename: string - :param data: The data for the new ifcfg- file. - :type data: string - :returns: commands (commands to be run) - """ - - previous_cfg = common.get_file_data(filename) - file_values = self.parse_ifcfg(previous_cfg) - data_values = self.parse_ifcfg(data) - logger.debug("File values:\n%s" % file_values) - logger.debug("Data values:\n%s" % data_values) - changes = self.enumerate_ifcfg_changes(file_values, data_values) - commands = [] - - if "ETHTOOL_OPTS" in changes: - if changes["ETHTOOL_OPTS"] == "added" or \ - changes["ETHTOOL_OPTS"] == "modified": - for command_opts in data_values["ETHTOOL_OPTS"].split(';'): - if re.match(r'\s*-+\w+-*\w* ', command_opts): - if device_name or "${DEVICE}" or "$DEVICE" \ - in command_opts: - commands.append("%s" % command_opts) - else: - msg = ("Assigned interface name to \ - ETHTOOL_OPTS is invalid %s" % device_name) - raise utils.InvalidInterfaceException(msg) - else: - commands.append("-s %s %s" % - (device_name, command_opts)) - return commands - - def iproute2_route_commands(self, filename, data): - """Return a list of commands for 'ip route' to modify routing table. - - The list of commands is generated by comparing the old and new - configs, and calculating which routes need to be added and which - need to be removed. - - :param filename: path to the original interface route file - :param data: data that is to be written to new route file - :return: list of commands to feed to 'ip' to reconfigure routes - """ - - file_values = self.parse_ifcfg_routes(common.get_file_data(filename)) - data_values = self.parse_ifcfg_routes(data) - route_changes = self.enumerate_ifcfg_route_changes(file_values, - data_values) - commands = [] - - for route in route_changes: - if route[1] == 'removed': - commands.append('route del ' + route[0]) - elif route[1] == 'added': - commands.append('route add ' + route[0]) - return commands - - def iproute2_rule_commands(self, filename, data): - """Return a list of commands for 'ip route' to modify routing rules. - - The list of commands is generated by comparing the old and new - configs, and calculating which rules need to be added and which - need to be removed. - - :param filename: path to the original interface route rule file - :param data: data that is to be written to new route rule file - :return: list of commands to feed to 'ip' to reconfigure route rules - """ - - file_values = self.parse_ifcfg_rules(common.get_file_data(filename)) - data_values = self.parse_ifcfg_rules(data) - rule_changes = self.enumerate_ifcfg_rule_changes(file_values, - data_values) - commands = [] - - for rule in rule_changes: - if rule[1] == 'removed': - commands.append('rule del ' + rule[0]) - elif rule[1] == 'added': - commands.append('rule add ' + rule[0]) - return commands - - def child_members(self, name): - children = set() - try: - for member in self.member_names[name]: - children.add(member) - children.update(self.child_members(member)) - except KeyError: - pass - return children - - def _add_common(self, base_opt): - - ovs_extra = [] - data = "# This file is autogenerated by os-net-config\n" - data += "DEVICE=%s\n" % base_opt.name - if base_opt.onboot: - data += "ONBOOT=yes\n" - else: - data += "ONBOOT=no\n" - if isinstance(base_opt, objects.Interface) and base_opt.hotplug: - data += "HOTPLUG=yes\n" - else: - data += "HOTPLUG=no\n" - if base_opt.nm_controlled: - data += "NM_CONTROLLED=yes\n" - else: - data += "NM_CONTROLLED=no\n" - if not base_opt.dns_servers and not base_opt.use_dhcp: - data += "PEERDNS=no\n" - if isinstance(base_opt, objects.Vlan): - if not base_opt.ovs_port: - # vlans on OVS bridges are internal ports (no device, etc) - data += "VLAN=yes\n" - if base_opt.device: - data += "PHYSDEV=%s\n" % base_opt.device - elif base_opt.linux_bond_name: - data += "PHYSDEV=%s\n" % base_opt.linux_bond_name - else: - if base_opt.ovs_options: - data += "OVS_OPTIONS=\"%s\"\n" % base_opt.ovs_options - ovs_extra.extend(base_opt.ovs_extra) - elif isinstance(base_opt, objects.IvsInterface): - data += "TYPE=IVSIntPort\n" - elif isinstance(base_opt, objects.NfvswitchInternal): - data += "TYPE=NFVSWITCHIntPort\n" - elif isinstance(base_opt, objects.IbInterface): - data += "TYPE=Infiniband\n" - elif isinstance(base_opt, objects.IbChildInterface): - data += "TYPE=Infiniband\n" - data += "PKEY=yes\n" - data += "PHYSDEV=%s\n" % base_opt.parent - data += "PKEY_ID=%s\n" % base_opt.pkey_id - elif re.match(r'\w+\.\d+$', base_opt.name): - data += "VLAN=yes\n" - elif isinstance(base_opt, objects.Interface): - if base_opt.linkdelay: - data += "LINKDELAY=%s\n" % base_opt.linkdelay - if base_opt.linux_bond_name: - data += "MASTER=%s\n" % base_opt.linux_bond_name - data += "SLAVE=yes\n" - if base_opt.linux_team_name: - data += "TEAM_MASTER=%s\n" % base_opt.linux_team_name - if base_opt.primary: - data += "TEAM_PORT_CONFIG='{\"prio\": 100}'\n" - if base_opt.ivs_bridge_name: - data += "DEVICETYPE=ivs\n" - data += "IVS_BRIDGE=%s\n" % base_opt.ivs_bridge_name - if base_opt.nfvswitch_bridge_name: - data += "DEVICETYPE=nfvswitch\n" - data += "NFVSWITCH_BRIDGE=%s\n" % base_opt.nfvswitch_bridge_name - if base_opt.ovs_port: - if not isinstance(base_opt, objects.LinuxTeam): - data += "DEVICETYPE=ovs\n" - if base_opt.bridge_name: - if isinstance(base_opt, objects.Vlan): - data += "TYPE=OVSIntPort\n" - data += "OVS_BRIDGE=%s\n" % base_opt.bridge_name - data += "OVS_OPTIONS=\"tag=%s\"\n" % base_opt.vlan_id - else: - data += "TYPE=OVSPort\n" - data += "OVS_BRIDGE=%s\n" % base_opt.bridge_name - if base_opt.linux_bridge_name: - data += "BRIDGE=%s\n" % base_opt.linux_bridge_name - if isinstance(base_opt, objects.OvsBridge): - data += "DEVICETYPE=ovs\n" - data += "TYPE=OVSBridge\n" - if base_opt.use_dhcp or base_opt.use_dhcpv6: - data += "OVSBOOTPROTO=dhcp\n" - if base_opt.members: - members = [member.name for member in base_opt.members] - self.member_names[base_opt.name] = members - if base_opt.use_dhcp: - data += ("OVSDHCPINTERFACES=\"%s\"\n" % " ".join(members)) - ovs_extra.append("set bridge %s other-config:mac-table-size=%d" % - (base_opt.name, MAC_TABLE_SIZE)) - if base_opt.primary_interface_name: - mac = common.interface_mac(base_opt.primary_interface_name) - ovs_extra.append("set bridge %s other-config:hwaddr=%s" % - (base_opt.name, mac)) - if base_opt.ovs_options: - data += "OVS_OPTIONS=\"%s\"\n" % base_opt.ovs_options - ovs_extra.extend(base_opt.ovs_extra) - elif isinstance(base_opt, objects.OvsUserBridge): - data += "DEVICETYPE=ovs\n" - data += "TYPE=OVSUserBridge\n" - if base_opt.use_dhcp or base_opt.use_dhcpv6: - data += "OVSBOOTPROTO=dhcp\n" - if base_opt.members: - members = [member.name for member in base_opt.members] - self.member_names[base_opt.name] = members - if base_opt.use_dhcp: - data += ("OVSDHCPINTERFACES=\"%s\"\n" % " ".join(members)) - if base_opt.ovs_options: - data += "OVS_OPTIONS=\"%s\"\n" % base_opt.ovs_options - ovs_extra.extend(base_opt.ovs_extra) - elif isinstance(base_opt, objects.OvsBond): - if base_opt.primary_interface_name: - primary_name = base_opt.primary_interface_name - self.bond_primary_ifaces[base_opt.name] = primary_name - data += "DEVICETYPE=ovs\n" - data += "TYPE=OVSBond\n" - if base_opt.use_dhcp or base_opt.use_dhcpv6: - data += "OVSBOOTPROTO=dhcp\n" - if base_opt.members: - members = [member.name for member in base_opt.members] - self.member_names[base_opt.name] = members - data += ("BOND_IFACES=\"%s\"\n" % " ".join(members)) - if base_opt.ovs_options: - data += "OVS_OPTIONS=\"%s\"\n" % base_opt.ovs_options - ovs_extra.extend(base_opt.ovs_extra) - elif isinstance(base_opt, objects.LinuxBridge): - data += "TYPE=Bridge\n" - data += "DELAY=0\n" - if base_opt.use_dhcp: - data += "BOOTPROTO=dhcp\n" - if base_opt.members: - members = [member.name for member in base_opt.members] - self.member_names[base_opt.name] = members - if base_opt.primary_interface_name: - primary_name = base_opt.primary_interface_name - primary_mac = common.interface_mac(primary_name) - data += "MACADDR=\"%s\"\n" % primary_mac - elif isinstance(base_opt, objects.LinuxBond): - if base_opt.primary_interface_name: - primary_name = base_opt.primary_interface_name - primary_mac = common.interface_mac(primary_name) - data += "MACADDR=\"%s\"\n" % primary_mac - if base_opt.use_dhcp: - data += "BOOTPROTO=dhcp\n" - if base_opt.members: - members = [member.name for member in base_opt.members] - self.member_names[base_opt.name] = members - if base_opt.bonding_options: - data += "BONDING_OPTS=\"%s\"\n" % base_opt.bonding_options - elif isinstance(base_opt, objects.LinuxTeam): - if base_opt.primary_interface_name: - primary_name = base_opt.primary_interface_name - primary_mac = common.interface_mac(primary_name) - data += "MACADDR=\"%s\"\n" % primary_mac - if base_opt.use_dhcp: - data += "BOOTPROTO=dhcp\n" - if base_opt.members: - members = [member.name for member in base_opt.members] - self.member_names[base_opt.name] = members - data += "DEVICETYPE=Team\n" - if base_opt.bonding_options: - data += "TEAM_CONFIG='%s'\n" % base_opt.bonding_options - elif isinstance(base_opt, objects.OvsTunnel): - ovs_extra.extend(base_opt.ovs_extra) - data += "DEVICETYPE=ovs\n" - data += "TYPE=OVSTunnel\n" - data += "OVS_BRIDGE=%s\n" % base_opt.bridge_name - data += "OVS_TUNNEL_TYPE=%s\n" % base_opt.tunnel_type - data += "OVS_TUNNEL_OPTIONS=\"%s\"\n" % \ - ' '.join(base_opt.ovs_options) - elif isinstance(base_opt, objects.OvsPatchPort): - ovs_extra.extend(base_opt.ovs_extra) - data += "DEVICETYPE=ovs\n" - data += "TYPE=OVSPatchPort\n" - data += "OVS_BRIDGE=%s\n" % base_opt.bridge_name - data += "OVS_PATCH_PEER=%s\n" % base_opt.peer - elif isinstance(base_opt, objects.OvsDpdkPort): - ovs_extra.extend(base_opt.ovs_extra) - data += "DEVICETYPE=ovs\n" - data += "TYPE=OVSDPDKPort\n" - data += "OVS_BRIDGE=%s\n" % base_opt.bridge_name - # Validation of DPDK port having only one interface is done prior - # to this. So accesing the interface name statically. - # Also dpdk_devargs would be valid here, since - # bind_dpdk_interfaces() is invoked before this. - dpdk_devargs = utils.get_dpdk_devargs( - base_opt.members[0].name, self.noop) - - ovs_extra.append("set Interface $DEVICE options:dpdk-devargs=" - "%s" % dpdk_devargs) - if base_opt.mtu: - ovs_extra.append("set Interface $DEVICE mtu_request=$MTU") - if base_opt.rx_queue: - data += "RX_QUEUE=%i\n" % base_opt.rx_queue - ovs_extra.append("set Interface $DEVICE " + - "options:n_rxq=$RX_QUEUE") - if base_opt.rx_queue_size: - data += "RX_QUEUE_SIZE=%i\n" % base_opt.rx_queue_size - ovs_extra.append("set Interface $DEVICE " + - "options:n_rxq_desc=$RX_QUEUE_SIZE") - if base_opt.tx_queue_size: - data += "TX_QUEUE_SIZE=%i\n" % base_opt.tx_queue_size - ovs_extra.append("set Interface $DEVICE " + - "options:n_txq_desc=$TX_QUEUE_SIZE") - elif isinstance(base_opt, objects.OvsDpdkBond): - ovs_extra.extend(base_opt.ovs_extra) - # Referring to bug:1643026, the below commenting of the interfaces, - # is to workaround the error, but is not the long term solution. - # The long term solution is to run DPDK options before - # os-net-config, which is being tracked at BUG:1654975 - # if base_opt.primary_interface_name: - # primary_name = base_opt.primary_interface_name - # self.bond_primary_ifaces[base_opt.name] = primary_name - data += "DEVICETYPE=ovs\n" - data += "TYPE=OVSDPDKBond\n" - data += "OVS_BRIDGE=%s\n" % base_opt.bridge_name - if base_opt.members: - for bond_member in base_opt.members: - # Validation of DPDK port having only one interface is done - # prior to this. So accesing the interface name statically. - # Also dpdk_devargs would be valid here, since - # bind_dpdk_interfaces () is invoked before this. - dpdk_devargs = utils.get_dpdk_devargs( - bond_member.members[0].name, self.noop) - ovs_extra.append("set Interface %s options:" - "dpdk-devargs=%s" - % (bond_member.name, dpdk_devargs)) - members = [member.name for member in base_opt.members] - data += ("BOND_IFACES=\"%s\"\n" % " ".join(members)) - # MTU configuration given for the OvsDpdkbond shall be applied - # to each of the members of the OvsDpdkbond - if base_opt.mtu: - for member in base_opt.members: - ovs_extra.append("set Interface %s mtu_request=$MTU" % - member.name) - if base_opt.rx_queue: - data += "RX_QUEUE=%i\n" % base_opt.rx_queue - for member in base_opt.members: - ovs_extra.append("set Interface %s options:n_rxq=" - "$RX_QUEUE" % member.name) - if base_opt.rx_queue_size: - data += "RX_QUEUE_SIZE=%i\n" % base_opt.rx_queue_size - for member in base_opt.members: - ovs_extra.append("set Interface %s options:n_rxq_desc=" - "$RX_QUEUE_SIZE" % member.name) - if base_opt.tx_queue_size: - data += "TX_QUEUE_SIZE=%i\n" % base_opt.tx_queue_size - for member in base_opt.members: - ovs_extra.append("set Interface %s options:n_txq_desc=" - "$TX_QUEUE_SIZE" % member.name) - - if base_opt.ovs_options: - data += "OVS_OPTIONS=\"%s\"\n" % base_opt.ovs_options - ovs_extra.extend(base_opt.ovs_extra) - else: - if base_opt.use_dhcp: - data += "BOOTPROTO=dhcp\n" - elif not base_opt.addresses: - data += "BOOTPROTO=none\n" - if hasattr(base_opt, 'ethtool_opts') and base_opt.ethtool_opts: - data += "ETHTOOL_OPTS=\"%s\"\n" % base_opt.ethtool_opts - - if base_opt.mtu: - data += "MTU=%i\n" % base_opt.mtu - if base_opt.use_dhcpv6 or base_opt.v6_addresses(): - data += "IPV6INIT=yes\n" - if base_opt.mtu: - data += "IPV6_MTU=%i\n" % base_opt.mtu - if base_opt.use_dhcpv6: - data += "DHCPV6C=yes\n" - elif base_opt.addresses: - v4_addresses = base_opt.v4_addresses() - if v4_addresses: - data += "BOOTPROTO=static\n" - for i, address in enumerate(v4_addresses): - num = '%s' % i if i else '' - data += "IPADDR%s=%s\n" % (num, address.ip) - data += "NETMASK%s=%s\n" % (num, address.netmask) - - v6_addresses = base_opt.v6_addresses() - if v6_addresses: - first_v6 = v6_addresses[0] - data += "IPV6_AUTOCONF=no\n" - data += "IPV6ADDR=%s\n" % first_v6.ip_netmask - if len(v6_addresses) > 1: - secondaries_v6 = " ".join(map(lambda a: a.ip_netmask, - v6_addresses[1:])) - data += "IPV6ADDR_SECONDARIES=\"%s\"\n" % secondaries_v6 - - if base_opt.hwaddr: - data += "HWADDR=%s\n" % base_opt.hwaddr - if ovs_extra: - data += "OVS_EXTRA=\"%s\"\n" % " -- ".join(ovs_extra) - if not base_opt.defroute: - data += "DEFROUTE=no\n" - if base_opt.dhclient_args: - data += "DHCLIENTARGS=%s\n" % base_opt.dhclient_args - if base_opt.dns_servers: - data += "DNS1=%s\n" % base_opt.dns_servers[0] - if len(base_opt.dns_servers) >= 2: - data += "DNS2=%s\n" % base_opt.dns_servers[1] - if len(base_opt.dns_servers) > 2: - logger.warning('ifcfg format supports max 2 resolvers.') - if base_opt.domain: - if type(base_opt.domain) == list: - data += "DOMAIN=\"%s\"\n" % ' '.join(base_opt.domain) - else: - data += "DOMAIN=%s\n" % base_opt.domain - return data - - def _add_routes(self, interface_name, routes=[]): - logger.info('adding custom route for interface: %s' % interface_name) - data = "" - first_line = "" - data6 = "" - first_line6 = "" - for route in routes: - options = "" - table = "" - if route.route_options: - options = " %s" % route.route_options - if route.route_table: - if route.route_options.find('table ') == -1: - table = " table %s" % route.route_table - if ":" not in route.next_hop: - # Route is an IPv4 route - if route.default: - first_line = "default via %s dev %s%s%s\n" % ( - route.next_hop, interface_name, - table, options) - else: - data += "%s via %s dev %s%s%s\n" % ( - route.ip_netmask, route.next_hop, - interface_name, table, options) - else: - # Route is an IPv6 route - if route.default: - first_line6 = "default via %s dev %s%s%s\n" % ( - route.next_hop, interface_name, - table, options) - else: - data6 += "%s via %s dev %s%s%s\n" % ( - route.ip_netmask, route.next_hop, - interface_name, table, options) - self.route_data[interface_name] = first_line + data - self.route6_data[interface_name] = first_line6 + data6 - logger.debug('route data: %s' % self.route_data[interface_name]) - logger.debug('ipv6 route data: %s' % self.route6_data[interface_name]) - - def _add_rules(self, interface, rules): - """Add RouteRule objects to an interface. - - :param interface: the name of the interface to apply rules. - :param rules: the list of rules to apply to the interface. - """ - logger.info('adding route rules for interface: %s' % interface) - data = "" - first_line = "# This file is autogenerated by os-net-config\n" - for rule in rules: - if rule.comment: - data += "# %s\n" % rule.comment - data += "%s\n" % rule.rule - self.rule_data[interface] = first_line + data - logger.debug('rules for interface: %s' % self.rule_data[interface]) - - def add_route_table(self, route_table): - """Add a RouteTable object to the net config object. - - :param route_table: the RouteTable object to add. - """ - logger.info('adding route table: %s %s' % (route_table.table_id, - route_table.name)) - self.route_table_data[int(route_table.table_id)] = route_table.name - - def add_interface(self, interface): - """Add an Interface object to the net config object. - - :param interface: The Interface object to add. - """ - logger.info('adding interface: %s' % interface.name) - data = self._add_common(interface) - logger.debug('interface data: %s' % data) - self.interface_data[interface.name] = data - if interface.routes: - self._add_routes(interface.name, interface.routes) - if interface.rules: - self._add_rules(interface.name, interface.rules) - - if interface.renamed: - logger.info("Interface %s being renamed to %s" - % (interface.hwname, interface.name)) - self.renamed_interfaces[interface.hwname] = interface.name - - def add_vlan(self, vlan): - """Add a Vlan object to the net config object. - - :param vlan: The vlan object to add. - """ - logger.info('adding vlan: %s' % vlan.name) - data = self._add_common(vlan) - logger.debug('vlan data: %s' % data) - self.vlan_data[vlan.name] = data - if vlan.routes: - self._add_routes(vlan.name, vlan.routes) - if vlan.rules: - self._add_rules(vlan.name, vlan.rules) - - def add_ivs_interface(self, ivs_interface): - """Add a ivs_interface object to the net config object. - - :param ivs_interface: The ivs_interface object to add. - """ - logger.info('adding ivs_interface: %s' % ivs_interface.name) - data = self._add_common(ivs_interface) - logger.debug('ivs_interface data: %s' % data) - self.ivsinterface_data[ivs_interface.name] = data - if ivs_interface.routes: - self._add_routes(ivs_interface.name, ivs_interface.routes) - if ivs_interface.rules: - self._add_rules(ivs_interface.name, ivs_interface.rules) - - def add_nfvswitch_internal(self, nfvswitch_internal): - """Add a nfvswitch_internal interface object to the net config object. - - :param nfvswitch_internal: The nfvswitch_internal object to add. - """ - iface_name = nfvswitch_internal.name - logger.info('adding nfvswitch_internal interface: %s' % iface_name) - data = self._add_common(nfvswitch_internal) - logger.debug('nfvswitch_internal interface data: %s' % data) - self.nfvswitch_intiface_data[iface_name] = data - if nfvswitch_internal.routes: - self._add_routes(iface_name, nfvswitch_internal.routes) - if nfvswitch_internal.rules: - self._add_rules(iface_name, nfvswitch_internal.rules) - - def add_bridge(self, bridge): - """Add an OvsBridge object to the net config object. - - :param bridge: The OvsBridge object to add. - """ - logger.info('adding bridge: %s' % bridge.name) - data = self._add_common(bridge) - logger.debug('bridge data: %s' % data) - self.bridge_data[bridge.name] = data - if bridge.routes: - self._add_routes(bridge.name, bridge.routes) - if bridge.rules: - self._add_rules(bridge.name, bridge.rules) - - def add_ovs_user_bridge(self, bridge): - """Add an OvsUserBridge object to the net config object. - - :param bridge: The OvsUserBridge object to add. - """ - logger.info('adding ovs user bridge: %s' % bridge.name) - data = self._add_common(bridge) - logger.debug('ovs user bridge data: %s' % data) - self.bridge_data[bridge.name] = data - if bridge.routes: - self._add_routes(bridge.name, bridge.routes) - if bridge.rules: - self._add_rules(bridge.name, bridge.rules) - - def add_linux_bridge(self, bridge): - """Add a LinuxBridge object to the net config object. - - :param bridge: The LinuxBridge object to add. - """ - logger.info('adding linux bridge: %s' % bridge.name) - data = self._add_common(bridge) - logger.debug('bridge data: %s' % data) - self.linuxbridge_data[bridge.name] = data - if bridge.routes: - self._add_routes(bridge.name, bridge.routes) - if bridge.rules: - self._add_rules(bridge.name, bridge.rules) - - def add_ivs_bridge(self, bridge): - """Add a IvsBridge object to the net config object. - - IVS can only support one virtual switch per node, - using "ivs" as its name. As long as the ivs service - is running, the ivs virtual switch will be there. - It is impossible to add multiple ivs virtual switches - per node. - :param bridge: The IvsBridge object to add. - """ - pass - - def add_nfvswitch_bridge(self, bridge): - """Add a NFVSwitchBridge object to the net config object. - - NFVSwitch can only support one virtual switch per node, - using "nfvswitch" as its name. As long as the nfvswitch service - is running, the nfvswitch virtual switch will be available. - :param bridge: The NfvswitchBridge object to add. - """ - self.nfvswitch_options = bridge.options - - def add_bond(self, bond): - """Add an OvsBond object to the net config object. - - :param bond: The OvsBond object to add. - """ - logger.info('adding bond: %s' % bond.name) - data = self._add_common(bond) - logger.debug('bond data: %s' % data) - self.interface_data[bond.name] = data - if bond.routes: - self._add_routes(bond.name, bond.routes) - if bond.rules: - self._add_rules(bond.name, bond.rules) - - def add_linux_bond(self, bond): - """Add a LinuxBond object to the net config object. - - :param bond: The LinuxBond object to add. - """ - logger.info('adding linux bond: %s' % bond.name) - data = self._add_common(bond) - logger.debug('bond data: %s' % data) - self.linuxbond_data[bond.name] = data - if bond.routes: - self._add_routes(bond.name, bond.routes) - if bond.rules: - self._add_rules(bond.name, bond.rules) - - def add_linux_team(self, team): - """Add a LinuxTeam object to the net config object. - - :param team: The LinuxTeam object to add. - """ - logger.info('adding linux team: %s' % team.name) - data = self._add_common(team) - logger.debug('team data: %s' % data) - self.linuxteam_data[team.name] = data - if team.routes: - self._add_routes(team.name, team.routes) - if team.rules: - self._add_rules(team.name, team.rules) - - def add_ovs_tunnel(self, tunnel): - """Add a OvsTunnel object to the net config object. - - :param tunnel: The OvsTunnel object to add. - """ - logger.info('adding ovs tunnel: %s' % tunnel.name) - data = self._add_common(tunnel) - logger.debug('ovs tunnel data: %s' % data) - self.interface_data[tunnel.name] = data - - def add_ovs_patch_port(self, ovs_patch_port): - """Add a OvsPatchPort object to the net config object. - - :param ovs_patch_port: The OvsPatchPort object to add. - """ - logger.info('adding ovs patch port: %s' % ovs_patch_port.name) - data = self._add_common(ovs_patch_port) - logger.debug('ovs patch port data: %s' % data) - self.interface_data[ovs_patch_port.name] = data - - def add_ib_interface(self, ib_interface): - """Add an InfiniBand interface object to the net config object. - - :param ib_interface: The InfiniBand interface object to add. - """ - logger.info('adding ib_interface: %s' % ib_interface.name) - data = self._add_common(ib_interface) - logger.debug('ib_interface data: %s' % data) - self.ib_interface_data[ib_interface.name] = data - if ib_interface.routes: - self._add_routes(ib_interface.name, ib_interface.routes) - if ib_interface.rules: - self._add_rules(ib_interface.name, ib_interface.rules) - - if ib_interface.renamed: - logger.info("InfiniBand interface %s being renamed to %s" - % (ib_interface.hwname, ib_interface.name)) - self.renamed_interfaces[ib_interface.hwname] = ib_interface.name - - def add_ib_child_interface(self, ib_child_interface): - """Add an InfiniBand child interface object to the net config object. - - :param ib_child_interface: The InfiniBand child - interface object to add. - """ - logger.info('adding ib_child_interface: %s' % ib_child_interface.name) - data = self._add_common(ib_child_interface) - logger.debug('ib_child_interface data: %s' % data) - self.ib_childs_data[ib_child_interface.name] = data - if ib_child_interface.routes: - self._add_routes(ib_child_interface.name, - ib_child_interface.routes) - if ib_child_interface.rules: - self._add_rules(ib_child_interface.name, ib_child_interface.rules) - - def add_ovs_dpdk_port(self, ovs_dpdk_port): - """Add a OvsDpdkPort object to the net config object. - - :param ovs_dpdk_port: The OvsDpdkPort object to add. - """ - logger.info('adding ovs dpdk port: %s' % ovs_dpdk_port.name) - - # DPDK Port will have only one member of type Interface, validation - # checks are added at the object creation stage. - ifname = ovs_dpdk_port.members[0].name - - # Bind the dpdk interface - utils.bind_dpdk_interfaces(ifname, ovs_dpdk_port.driver, self.noop) - if not self.noop and (not common.is_mellanox_interface(ifname)): - remove_ifcfg_config(ifname) - - data = self._add_common(ovs_dpdk_port) - logger.debug('ovs dpdk port data: %s' % data) - self.interface_data[ovs_dpdk_port.name] = data - - """Add an extra ifcfg entry for mellanox NICs, - for the interface which is a member of ovs_dpdk_port - with NM and DHCP disabled - """ - if common.is_mellanox_interface(ifname): - self.nm_controlled = False - self.use_dhcp = False - dpdk_if_name = objects.Interface(ifname) - self.add_interface(dpdk_if_name) - - def add_ovs_dpdk_bond(self, ovs_dpdk_bond): - """Add an OvsDPDKBond object to the net config object. - - :param ovs_dpdk_bond: The OvsBond object to add. - """ - logger.info('adding ovs dpdk bond: %s' % ovs_dpdk_bond.name) - - # Bind the dpdk interface - for dpdk_port in ovs_dpdk_bond.members: - # DPDK Port will have only one member of type Interface, validation - # checks are added at the object creation stage. - ifname = dpdk_port.members[0].name - utils.bind_dpdk_interfaces(ifname, dpdk_port.driver, self.noop) - if not self.noop and (not common.is_mellanox_interface(ifname)): - remove_ifcfg_config(ifname) - - data = self._add_common(ovs_dpdk_bond) - logger.debug('ovs dpdk bond data: %s' % data) - self.interface_data[ovs_dpdk_bond.name] = data - if ovs_dpdk_bond.routes: - self._add_routes(ovs_dpdk_bond.name, ovs_dpdk_bond.routes) - if ovs_dpdk_bond.rules: - self._add_rules(ovs_dpdk_bond.name, ovs_dpdk_bond.rules) - - """Add an extra ifcfg entry for mellanox NICs, - for all interfaces which is a member of ovs_dpdk_bond - with NM and DHCP disabled - """ - for dpdk_port in ovs_dpdk_bond.members: - ifname = dpdk_port.members[0].name - if common.is_mellanox_interface(ifname): - self.nm_controlled = False - self.use_dhcp = False - dpdk_if_name = objects.Interface(ifname) - self.add_interface(dpdk_if_name) - - def add_sriov_pf(self, sriov_pf): - """Add a SriovPF object to the net config object - - :param sriov_pf: The SriovPF object to add - """ - logger.info('adding sriov pf: %s' % sriov_pf.name) - data = self._add_common(sriov_pf) - logger.debug('sriov pf data: %s' % data) - utils.update_sriov_pf_map(sriov_pf.name, sriov_pf.numvfs, - self.noop, promisc=sriov_pf.promisc, - link_mode=sriov_pf.link_mode, - vdpa=sriov_pf.vdpa, - steering_mode=sriov_pf.steering_mode) - self.interface_data[sriov_pf.name] = data - if sriov_pf.routes: - self._add_routes(sriov_pf.name, sriov_pf.routes) - if sriov_pf.rules: - self._add_rules(sriov_pf.name, sriov_pf.rules) - - def add_sriov_vf(self, sriov_vf): - """Add a SriovVF object to the net config object - - :param sriov_vf: The SriovVF object to add - """ - logger.info('adding sriov vf: %s for pf: %s, vfid: %d' - % (sriov_vf.name, sriov_vf.device, sriov_vf.vfid)) - data = self._add_common(sriov_vf) - logger.debug('sriov vf data: %s' % data) - self.interface_data[sriov_vf.name] = data - if sriov_vf.routes: - self._add_routes(sriov_vf.name, sriov_vf.routes) - if sriov_vf.rules: - self._add_rules(sriov_vf.name, sriov_vf.rules) - - def add_vpp_interface(self, vpp_interface): - """Add a VppInterface object to the net config object - - :param vpp_interface: The VppInterface object to add - """ - vpp_interface.pci_dev = utils.get_pci_address(vpp_interface.name, - False) - if not vpp_interface.pci_dev: - vpp_interface.pci_dev = utils.get_stored_pci_address( - vpp_interface.name, False) - vpp_interface.hwaddr = common.interface_mac(vpp_interface.name) - if not self.noop: - self.ifdown(vpp_interface.name) - remove_ifcfg_config(vpp_interface.name) - logger.info('adding vpp interface: %s %s' - % (vpp_interface.name, vpp_interface.pci_dev)) - self.vpp_interface_data[vpp_interface.name] = vpp_interface - - def add_vpp_bond(self, vpp_bond): - """Add a VppInterface object to the net config object - - :param vpp_bond: The VPPBond object to add - """ - logger.info('adding vpp bond: %s' % vpp_bond.name) - self.vpp_bond_data[vpp_bond.name] = vpp_bond - - def add_contrail_vrouter(self, contrail_vrouter): - """Add a ContraiVrouter object to the net config object - - :param contrail_vrouter: - The ContrailVrouter object to add - """ - logger.info('adding contrail_vrouter interface: %s' - % contrail_vrouter.name) - ifnames = ",".join([m.name for m in contrail_vrouter.members]) - data = self._add_common(contrail_vrouter) - data += "DEVICETYPE=vhost\n" - data += "TYPE=kernel_mode\n" - data += "BIND_INT=%s\n" % ifnames - logger.debug('contrail data: %s' % data) - self.interface_data[contrail_vrouter.name] = data - if contrail_vrouter.routes: - self._add_routes(contrail_vrouter.name, contrail_vrouter.routes) - if contrail_vrouter.rules: - self._add_rules(contrail_vrouter.name, contrail_vrouter.rules) - - def add_contrail_vrouter_dpdk(self, contrail_vrouter_dpdk): - """Add a ContraiVrouterDpdk object to the net config object - - :param contrail_vrouter_dpdk: - The ContrailVrouterDpdk object to add - """ - logger.info('adding contrail vrouter dpdk interface: %s' - % contrail_vrouter_dpdk.name) - pci_string = ",".join( - utils.translate_ifname_to_pci_address(bind_int.name, self.noop) - for bind_int in contrail_vrouter_dpdk.members) - data = self._add_common(contrail_vrouter_dpdk) - data += "DEVICETYPE=vhost\n" - data += "TYPE=dpdk\n" - data += "BIND_INT=%s\n" % pci_string - if len(contrail_vrouter_dpdk.members) > 1: - data += "BOND_MODE=%s\n" % contrail_vrouter_dpdk.bond_mode - data += "BOND_POLICY=%s\n" % contrail_vrouter_dpdk.bond_policy - data += "DRIVER=%s\n" % contrail_vrouter_dpdk.driver - data += "CPU_LIST=%s\n" % contrail_vrouter_dpdk.cpu_list - if contrail_vrouter_dpdk.vlan_id: - data += "VLAN_ID=%s\n" % contrail_vrouter_dpdk.vlan_id - logger.debug('contrail dpdk data: %s' % data) - self.interface_data[contrail_vrouter_dpdk.name] = data - if contrail_vrouter_dpdk.routes: - self._add_routes(contrail_vrouter_dpdk.name, - contrail_vrouter_dpdk.routes) - if contrail_vrouter_dpdk.rules: - self._add_rules(contrail_vrouter_dpdk.name, - contrail_vrouter_dpdk.rules) - - def add_linux_tap(self, linux_tap): - """Add a LinuxTap object to the net config object - - :param linux_tap: - The LinuxTap object to add - """ - logger.info('adding Linux TAP interface: %s' - % linux_tap.name) - data = self._add_common(linux_tap) - data += "TYPE=Tap\n" - self.interface_data[linux_tap.name] = data - if linux_tap.routes: - self._add_routes(linux_tap.name, - linux_tap.routes) - if linux_tap.rules: - self._add_rules(linux_tap.name, - linux_tap.rules) - - def generate_ivs_config(self, ivs_uplinks, ivs_interfaces): - """Generate configuration content for ivs.""" - - intfs = [] - for intf in ivs_uplinks: - intfs.append(' -u ') - intfs.append(intf) - uplink_str = ''.join(intfs) - - intfs = [] - for intf in ivs_interfaces: - intfs.append(' --internal-port=') - intfs.append(intf) - intf_str = ''.join(intfs) - - data = ("DAEMON_ARGS=\"--hitless --certificate /etc/ivs " - "--inband-vlan 4092%s%s\"" - % (uplink_str, intf_str)) - return data - - def generate_nfvswitch_config(self, nfvswitch_ifaces, - nfvswitch_internal_ifaces): - """Generate configuration content for nfvswitch.""" - - options_str = "" - if self.nfvswitch_options: - options_str = self.nfvswitch_options - - ifaces = [] - for iface in nfvswitch_ifaces: - ifaces.append(' -u ') - ifaces.append(iface) - iface_str = ''.join(ifaces) - - ifaces = [] - for iface in nfvswitch_internal_ifaces: - ifaces.append(' -m ') - ifaces.append(iface) - internal_str = ''.join(ifaces) - - data = "SETUP_ARGS=\"%s%s%s\"" % (options_str, iface_str, internal_str) - return data - - def generate_route_table_config(self, route_tables): - """Generate configuration content for routing tables. - - This method first extracts the existing route table definitions. If - any non-default tables exist, they will be kept unless they conflict - with new tables defined in the route_tables dict. - - :param route_tables: A dict of RouteTable objects - """ - - custom_tables = {} - res_ids = ['0', '253', '254', '255'] - res_names = ['unspec', 'default', 'main', 'local'] - rt_config = common.get_file_data(route_table_config_path()).split('\n') - rt_defaults = _ROUTE_TABLE_DEFAULT.split("\n") - data = _ROUTE_TABLE_DEFAULT - for line in (line for line in rt_config if line not in rt_defaults): - # Leave non-standard comments intact in file - if line.startswith('#') and not line.strip() in rt_defaults: - data += "%s\n" % line - # Ignore old managed entries, will be added back if in new config. - elif line.find("# os-net-config managed table") == -1: - id_name = line.split() - # Keep custom tables if there is no conflict with new tables. - if id_name[0].isdigit() and len(id_name) > 1: - if not id_name[0] in res_ids: - if not id_name[1] in res_names: - if not int(id_name[0]) in route_tables: - if not id_name[1] in route_tables.values(): - # Replicate line with any comments appended - custom_tables[id_name[0]] = id_name[1] - data += "%s\n" % line - if custom_tables: - logger.debug("Existing route tables: %s" % custom_tables) - for id in sorted(route_tables): - if str(id) in res_ids: - message = "Table %s(%s) conflicts with reserved table %s(%s)" \ - % (route_tables[id], id, - res_names[res_ids.index(str(id))], id) - raise os_net_config.ConfigurationError(message) - elif route_tables[id] in res_names: - message = "Table %s(%s) conflicts with reserved table %s(%s)" \ - % (route_tables[id], id, route_tables[id], - res_ids[res_names.index(route_tables[id])]) - raise os_net_config.ConfigurationError(message) - else: - data += "%s\t%s # os-net-config managed table\n" \ - % (id, route_tables[id]) - return data - - def apply(self, cleanup=False, activate=True): - """Apply the network configuration. - - :param cleanup: A boolean which indicates whether any undefined - (existing but not present in the object model) interface - should be disabled and deleted. - :param activate: A boolean which indicates if the config should - be activated by stopping/starting interfaces - NOTE: if cleanup is specified we will deactivate interfaces even - if activate is false - :returns: a dict of the format: filename/data which contains info - for each file that was changed (or would be changed if in --noop - mode). - Note the noop mode is set via the constructor noop boolean - """ - logger.info('applying network configs...') - restart_interfaces = [] - restart_vlans = [] - restart_ib_childs = [] - restart_bridges = [] - restart_linux_bonds = [] - start_linux_bonds = [] - restart_linux_teams = [] - restart_vpp = False - apply_interfaces = [] - apply_bridges = [] - apply_routes = [] - apply_rules = [] - update_files = {} - all_file_names = [] - linux_bond_children = {} - ivs_uplinks = [] # ivs physical uplinks - ivs_interfaces = [] # ivs internal ports - nfvswitch_interfaces = [] # nfvswitch physical interfaces - nfvswitch_internal_ifaces = [] # nfvswitch internal/management ports - stop_dhclient_interfaces = [] - ovs_needs_restart = False - vpp_interfaces = self.vpp_interface_data.values() - vpp_bonds = self.vpp_bond_data.values() - ipcmd = utils.iproute2_path() - ethtoolcmd = utils.ethtool_path() - - for interface_name, iface_data in self.interface_data.items(): - route_data = self.route_data.get(interface_name, '') - route6_data = self.route6_data.get(interface_name, '') - rule_data = self.rule_data.get(interface_name, '') - interface_path = self.root_dir + ifcfg_config_path(interface_name) - route_path = self.root_dir + route_config_path(interface_name) - route6_path = self.root_dir + route6_config_path(interface_name) - rule_path = self.root_dir + route_rule_config_path(interface_name) - all_file_names.append(interface_path) - all_file_names.append(route_path) - all_file_names.append(route6_path) - if "IVS_BRIDGE" in iface_data: - ivs_uplinks.append(interface_name) - if "NFVSWITCH_BRIDGE" in iface_data: - nfvswitch_interfaces.append(interface_name) - if utils.diff(interface_path, iface_data): - if self.ifcfg_requires_restart(interface_path, iface_data): - restart_interfaces.append(interface_name) - # Openvswitch needs to be restarted when OVSDPDKPort or - # OVSDPDKBond is added - if "OVSDPDK" in iface_data: - ovs_needs_restart = True - else: - apply_interfaces.append( - (interface_name, interface_path, iface_data)) - update_files[interface_path] = iface_data - if "BOOTPROTO=dhcp" not in iface_data: - stop_dhclient_interfaces.append(interface_name) - - else: - logger.info('No changes required for interface: %s' % - interface_name) - if utils.diff(route_path, route_data): - update_files[route_path] = route_data - if interface_name not in restart_interfaces: - apply_routes.append((interface_name, route_data)) - if utils.diff(route6_path, route6_data): - update_files[route6_path] = route6_data - if interface_name not in restart_interfaces: - apply_routes.append((interface_name, route6_data)) - if utils.diff(rule_path, rule_data): - update_files[rule_path] = rule_data - if interface_name not in restart_interfaces: - apply_rules.append((interface_name, rule_data)) - - for interface_name, iface_data in self.ivsinterface_data.items(): - route_data = self.route_data.get(interface_name, '') - route6_data = self.route6_data.get(interface_name, '') - rule_data = self.rule_data.get(interface_name, '') - interface_path = self.root_dir + ifcfg_config_path(interface_name) - route_path = self.root_dir + route_config_path(interface_name) - route6_path = self.root_dir + route6_config_path(interface_name) - rule_path = self.root_dir + route_rule_config_path(interface_name) - all_file_names.append(interface_path) - all_file_names.append(route_path) - all_file_names.append(route6_path) - all_file_names.append(rule_path) - ivs_interfaces.append(interface_name) - if utils.diff(interface_path, iface_data): - if self.ifcfg_requires_restart(interface_path, iface_data): - restart_interfaces.append(interface_name) - else: - apply_interfaces.append( - (interface_name, interface_path, iface_data)) - update_files[interface_path] = iface_data - else: - logger.info('No changes required for ivs interface: %s' % - interface_name) - if utils.diff(route_path, route_data): - update_files[route_path] = route_data - if interface_name not in restart_interfaces: - apply_routes.append((interface_name, route_data)) - if utils.diff(route6_path, route6_data): - update_files[route6_path] = route6_data - if interface_name not in restart_interfaces: - apply_routes.append((interface_name, route6_data)) - if utils.diff(rule_path, rule_data): - update_files[rule_path] = rule_data - if interface_name not in restart_interfaces: - apply_rules.append((interface_name, rule_data)) - - for iface_name, iface_data in self.nfvswitch_intiface_data.items(): - route_data = self.route_data.get(iface_name, '') - route6_data = self.route6_data.get(iface_name, '') - rule_data = self.rule_data.get(iface_name, '') - iface_path = self.root_dir + ifcfg_config_path(iface_name) - route_path = self.root_dir + route_config_path(iface_name) - route6_path = self.root_dir + route6_config_path(iface_name) - rule_path = self.root_dir + route_rule_config_path(iface_name) - all_file_names.append(iface_path) - all_file_names.append(route_path) - all_file_names.append(route6_path) - all_file_names.append(rule_path) - nfvswitch_internal_ifaces.append(iface_name) - if utils.diff(iface_path, iface_data): - if self.ifcfg_requires_restart(iface_path, iface_data): - restart_interfaces.append(iface_name) - else: - apply_interfaces.append( - (iface_name, iface_path, iface_data)) - update_files[iface_path] = iface_data - else: - logger.info('No changes required for nfvswitch interface: %s' % - iface_name) - if utils.diff(route_path, route_data): - update_files[route_path] = route_data - if iface_name not in restart_interfaces: - apply_routes.append((iface_name, route_data)) - if utils.diff(route6_path, route6_data): - update_files[route6_path] = route6_data - if iface_name not in restart_interfaces: - apply_routes.append((iface_name, route6_data)) - if utils.diff(rule_path, rule_data): - update_files[rule_path] = rule_data - if iface_name not in restart_interfaces: - apply_rules.append((iface_name, rule_data)) - - for bridge_name, bridge_data in self.bridge_data.items(): - route_data = self.route_data.get(bridge_name, '') - route6_data = self.route6_data.get(bridge_name, '') - rule_data = self.rule_data.get(bridge_name, '') - bridge_path = self.root_dir + bridge_config_path(bridge_name) - br_route_path = self.root_dir + route_config_path(bridge_name) - br_route6_path = self.root_dir + route6_config_path(bridge_name) - br_rule_path = self.root_dir + route_rule_config_path(bridge_name) - all_file_names.append(bridge_path) - all_file_names.append(br_route_path) - all_file_names.append(br_route6_path) - all_file_names.append(br_rule_path) - if utils.diff(bridge_path, bridge_data): - if self.ifcfg_requires_restart(bridge_path, bridge_data): - restart_bridges.append(bridge_name) - # Avoid duplicate interface being added to the restart list - children = self.child_members(bridge_name) - for child in children: - if child not in restart_interfaces: - restart_interfaces.append(child) - else: - apply_bridges.append((bridge_name, bridge_path, - bridge_data)) - update_files[bridge_path] = bridge_data - else: - logger.info('No changes required for bridge: %s' % bridge_name) - if utils.diff(br_route_path, route_data): - update_files[br_route_path] = route_data - if bridge_name not in restart_interfaces: - apply_routes.append((bridge_name, route_data)) - if utils.diff(br_route6_path, route6_data): - update_files[br_route6_path] = route6_data - if bridge_name not in restart_interfaces: - apply_routes.append((bridge_name, route6_data)) - if utils.diff(br_rule_path, rule_data): - update_files[br_rule_path] = rule_data - if bridge_name not in restart_interfaces: - apply_rules.append((bridge_name, rule_data)) - - for bridge_name, bridge_data in self.linuxbridge_data.items(): - route_data = self.route_data.get(bridge_name, '') - route6_data = self.route6_data.get(bridge_name, '') - rule_data = self.rule_data.get(bridge_name, '') - bridge_path = self.root_dir + bridge_config_path(bridge_name) - br_route_path = self.root_dir + route_config_path(bridge_name) - br_route6_path = self.root_dir + route6_config_path(bridge_name) - br_rule_path = self.root_dir + route_rule_config_path(bridge_name) - all_file_names.append(bridge_path) - all_file_names.append(br_route_path) - all_file_names.append(br_route6_path) - all_file_names.append(br_rule_path) - if utils.diff(bridge_path, bridge_data): - if self.ifcfg_requires_restart(bridge_path, bridge_data): - restart_bridges.append(bridge_name) - # Avoid duplicate interface being added to the restart list - children = self.child_members(bridge_name) - for child in children: - if child not in restart_interfaces: - restart_interfaces.append(child) - else: - apply_bridges.append((bridge_name, bridge_path, - bridge_data)) - update_files[bridge_path] = bridge_data - else: - logger.info('No changes required for bridge: %s' % bridge_name) - if utils.diff(br_route_path, route_data): - update_files[br_route_path] = route_data - if bridge_name not in restart_bridges: - apply_routes.append((bridge_name, route_data)) - if utils.diff(route6_path, route6_data): - update_files[route6_path] = route6_data - if bridge_name not in restart_bridges: - apply_routes.append((bridge_name, route6_data)) - if utils.diff(br_rule_path, rule_data): - update_files[br_rule_path] = rule_data - if bridge_name not in restart_bridges: - apply_rules.append((bridge_name, rule_data)) - - for team_name, team_data in self.linuxteam_data.items(): - route_data = self.route_data.get(team_name, '') - route6_data = self.route6_data.get(team_name, '') - rule_data = self.rule_data.get(team_name, '') - team_path = self.root_dir + bridge_config_path(team_name) - team_route_path = self.root_dir + route_config_path(team_name) - team_route6_path = self.root_dir + route6_config_path(team_name) - team_rule_path = self.root_dir + route_rule_config_path(team_name) - all_file_names.append(team_path) - all_file_names.append(team_route_path) - all_file_names.append(team_route6_path) - all_file_names.append(team_rule_path) - if utils.diff(team_path, team_data): - if self.ifcfg_requires_restart(team_path, team_data): - restart_linux_teams.append(team_name) - # Avoid duplicate interface being added to the restart list - children = self.child_members(team_name) - for child in children: - if child not in restart_interfaces: - restart_interfaces.append(child) - else: - apply_interfaces.append( - (team_name, team_path, team_data)) - update_files[team_path] = team_data - else: - logger.info('No changes required for linux team: %s' % - team_name) - if utils.diff(team_route_path, route_data): - update_files[team_route_path] = route_data - if team_name not in restart_linux_teams: - apply_routes.append((team_name, route_data)) - if utils.diff(team_route6_path, route6_data): - update_files[team_route6_path] = route6_data - if team_name not in restart_linux_teams: - apply_routes.append((team_name, route6_data)) - if utils.diff(team_rule_path, rule_data): - update_files[team_rule_path] = rule_data - - for bond_name, bond_data in self.linuxbond_data.items(): - route_data = self.route_data.get(bond_name, '') - route6_data = self.route6_data.get(bond_name, '') - rule_data = self.rule_data.get(bond_name, '') - bond_path = self.root_dir + bridge_config_path(bond_name) - bond_route_path = self.root_dir + route_config_path(bond_name) - bond_route6_path = self.root_dir + route6_config_path(bond_name) - bond_rule_path = self.root_dir + route_rule_config_path(bond_name) - all_file_names.append(bond_path) - all_file_names.append(bond_route_path) - all_file_names.append(bond_route6_path) - all_file_names.append(bond_rule_path) - children = self.child_members(bond_name) - linux_bond_children[bond_name] = children - if utils.diff(bond_path, bond_data): - if self.ifcfg_requires_restart(bond_path, bond_data): - restart_linux_bonds.append(bond_name) - # Avoid duplicate interface being added to the restart list - for child in children: - if child not in restart_interfaces: - restart_interfaces.append(child) - else: - apply_interfaces.append( - (bond_name, bond_path, bond_data)) - update_files[bond_path] = bond_data - else: - logger.info('No changes required for linux bond: %s' % - bond_name) - if utils.diff(bond_route_path, route_data): - update_files[bond_route_path] = route_data - if bond_name not in restart_linux_bonds: - apply_routes.append((bond_name, route_data)) - if utils.diff(bond_route6_path, route6_data): - update_files[bond_route6_path] = route6_data - if bond_name not in restart_linux_bonds: - apply_routes.append((bond_name, route6_data)) - if utils.diff(bond_rule_path, rule_data): - update_files[bond_rule_path] = rule_data - - # Infiniband interfaces are handled similarly to Ethernet interfaces - for interface_name, iface_data in self.ib_interface_data.items(): - route_data = self.route_data.get(interface_name, '') - route6_data = self.route6_data.get(interface_name, '') - rule_data = self.rule_data.get(interface_name, '') - interface_path = self.root_dir + ifcfg_config_path(interface_name) - route_path = self.root_dir + route_config_path(interface_name) - route6_path = self.root_dir + route6_config_path(interface_name) - rule_path = self.root_dir + route_rule_config_path(interface_name) - all_file_names.append(interface_path) - all_file_names.append(route_path) - all_file_names.append(route6_path) - all_file_names.append(rule_path) - # TODO(dsneddon) determine if InfiniBand can be used with IVS - if "IVS_BRIDGE" in iface_data: - ivs_uplinks.append(interface_name) - if utils.diff(interface_path, iface_data): - if self.ifcfg_requires_restart(interface_path, iface_data): - restart_interfaces.append(interface_name) - else: - apply_interfaces.append( - (interface_name, interface_path, iface_data)) - update_files[interface_path] = iface_data - else: - logger.info('No changes required for InfiniBand iface: %s' % - interface_name) - if utils.diff(route_path, route_data): - update_files[route_path] = route_data - if interface_name not in restart_interfaces: - apply_routes.append((interface_name, route_data)) - if utils.diff(route6_path, route6_data): - update_files[route6_path] = route6_data - if interface_name not in restart_interfaces: - apply_routes.append((interface_name, route6_data)) - if utils.diff(rule_path, rule_data): - update_files[rule_path] = rule_data - if interface_name not in restart_interfaces: - apply_rules.append((interface_name, rule_data)) - - # NOTE(hjensas): Process the VLAN's last so that we know if the vlan's - # parent interface is being restarted. - for vlan_name, vlan_data in self.vlan_data.items(): - route_data = self.route_data.get(vlan_name, '') - route6_data = self.route6_data.get(vlan_name, '') - rule_data = self.rule_data.get(vlan_name, '') - vlan_path = self.root_dir + ifcfg_config_path(vlan_name) - vlan_route_path = self.root_dir + route_config_path(vlan_name) - vlan_route6_path = self.root_dir + route6_config_path(vlan_name) - vlan_rule_path = self.root_dir + route_rule_config_path(vlan_name) - all_file_names.append(vlan_path) - all_file_names.append(vlan_route_path) - all_file_names.append(vlan_route6_path) - all_file_names.append(vlan_rule_path) - restarts_concatenated = itertools.chain(restart_interfaces, - restart_bridges, - restart_linux_bonds, - restart_linux_teams) - if (self.parse_ifcfg(vlan_data).get('PHYSDEV') in - restarts_concatenated): - if vlan_name not in restart_vlans: - restart_vlans.append(vlan_name) - update_files[vlan_path] = vlan_data - elif utils.diff(vlan_path, vlan_data): - if self.ifcfg_requires_restart(vlan_path, vlan_data): - restart_vlans.append(vlan_name) - else: - apply_interfaces.append( - (vlan_name, vlan_path, vlan_data)) - update_files[vlan_path] = vlan_data - else: - logger.info('No changes required for vlan interface: %s' % - vlan_name) - if utils.diff(vlan_route_path, route_data): - update_files[vlan_route_path] = route_data - if vlan_name not in restart_vlans: - apply_routes.append((vlan_name, route_data)) - if utils.diff(vlan_route6_path, route6_data): - update_files[vlan_route6_path] = route6_data - if vlan_name not in restart_vlans: - apply_routes.append((vlan_name, route6_data)) - if utils.diff(vlan_rule_path, rule_data): - update_files[vlan_rule_path] = rule_data - if vlan_name not in restart_vlans: - apply_rules.append((vlan_name, rule_data)) - - for ib_child_name, ib_child_data in self.ib_childs_data.items(): - route_data = self.route_data.get(ib_child_name, '') - route6_data = self.route6_data.get(ib_child_name, '') - rule_data = self.rule_data.get(ib_child_name, '') - ib_child_path = self.root_dir + ifcfg_config_path(ib_child_name) - ib_child_route_path = \ - self.root_dir + route_config_path(ib_child_name) - ib_child_route6_path = \ - self.root_dir + route6_config_path(ib_child_name) - ib_child_rule_path = \ - self.root_dir + route_rule_config_path(ib_child_name) - all_file_names.append(ib_child_path) - all_file_names.append(ib_child_route_path) - all_file_names.append(ib_child_route6_path) - all_file_names.append(ib_child_rule_path) - restarts_concatenated = itertools.chain(restart_interfaces, - restart_bridges, - restart_linux_bonds, - restart_linux_teams) - if (self.parse_ifcfg(ib_child_data).get('PHYSDEV') in - restarts_concatenated): - if ib_child_name not in restart_ib_childs: - restart_ib_childs.append(ib_child_name) - update_files[ib_child_path] = ib_child_data - elif utils.diff(ib_child_path, ib_child_data): - if self.ifcfg_requires_restart(ib_child_path, ib_child_data): - restart_ib_childs.append(ib_child_name) - else: - apply_interfaces.append( - (ib_child_name, ib_child_path, ib_child_data)) - update_files[ib_child_path] = ib_child_data - else: - logger.info('No changes required for the ib child interface: ' - '%s' % ib_child_name) - if utils.diff(ib_child_route_path, route_data): - update_files[ib_child_route_path] = route_data - if ib_child_name not in restart_ib_childs: - apply_routes.append((ib_child_name, route_data)) - if utils.diff(ib_child_route6_path, route6_data): - update_files[ib_child_route6_path] = route6_data - if ib_child_name not in restart_ib_childs: - apply_routes.append((ib_child_name, route6_data)) - if utils.diff(ib_child_rule_path, rule_data): - update_files[ib_child_rule_path] = rule_data - if ib_child_name not in restart_ib_childs: - apply_rules.append((ib_child_name, rule_data)) - - if self.vpp_interface_data or self.vpp_bond_data: - vpp_path = self.root_dir + vpp_config_path() - vpp_config = utils.generate_vpp_config(vpp_path, vpp_interfaces, - vpp_bonds) - if utils.diff(vpp_path, vpp_config): - restart_vpp = True - update_files[vpp_path] = vpp_config - else: - logger.info('No changes required for VPP') - - if cleanup: - for ifcfg_file in glob.iglob(cleanup_pattern()): - if ifcfg_file not in all_file_names: - interface_name = ifcfg_file[len(cleanup_pattern()) - 1:] - if interface_name != 'lo': - logger.info('cleaning up interface: %s' - % interface_name) - self.ifdown(interface_name) - self.remove_config(ifcfg_file) - - if activate: - for interface in apply_interfaces: - logger.debug('Running ip commands on interface: %s' % - interface[0]) - commands = self.iproute2_apply_commands(interface[0], - interface[1], - interface[2]) - for command in commands: - try: - args = command.split() - self.execute('Running ip %s' % command, ipcmd, *args) - except Exception as e: - logger.warning("Error in 'ip %s', restarting %s:\n%s" % - (command, interface[0], str(e))) - restart_interfaces.append(interface[0]) - restart_interfaces.extend( - self.child_members(interface[0])) - break - - commands = self.ethtool_apply_command(interface[0], - interface[1], - interface[2]) - if commands is not None: - for command in commands: - try: - args = command.split() - args = [interface[0] - if item in ["${DEVICE}", "$DEVICE"] - else item for item in args] - self.execute('Running ethtool %s' % command, - ethtoolcmd, *args) - except Exception as e: - logger.warning("Error in 'ethtool %s', restarting %s:\ - \n%s)" % - (command, interface[0], str(e))) - restart_interfaces.append(interface[0]) - restart_interfaces.extend( - self.child_members(interface[0])) - break - - for bridge in apply_bridges: - logger.debug('Running ip commands on bridge: %s' % - bridge[0]) - commands = self.iproute2_apply_commands(bridge[0], - bridge[1], - bridge[2]) - for command in commands: - try: - args = command.split() - self.execute('Running ip %s' % command, ipcmd, *args) - except Exception as e: - logger.warning("Error in 'ip %s', restarting %s:\n%s" % - (command, bridge[0], str(e))) - restart_bridges.append(bridge[0]) - restart_interfaces.extend( - self.child_members(bridge[0])) - break - - for interface in apply_routes: - logger.debug('Applying routes for interface %s' % interface[0]) - filename = self.root_dir + route_config_path(interface[0]) - commands = self.iproute2_route_commands(filename, interface[1]) - for command in commands: - args = command.split() - try: - if len(args) > 0: - self.execute('Running ip %s' % command, ipcmd, - *args) - except Exception as e: - logger.warning("Error in 'ip %s', restarting %s:\n%s" % - (command, interface[0], str(e))) - restart_interfaces.append(interface[0]) - restart_interfaces.extend( - self.child_members(interface[0])) - break - - for interface in apply_rules: - logger.debug('Applying rules for interface %s' % interface[0]) - filename = self.root_dir + route_rule_config_path(interface[0]) - commands = self.iproute2_rule_commands(filename, interface[1]) - for command in commands: - args = command.split() - try: - if len(args) > 0: - self.execute('Running ip %s' % command, ipcmd, - *args) - except Exception as e: - logger.warning("Error in 'ip %s', restarting %s:\n%s" % - (command, interface[0], str(e))) - restart_interfaces.append(interface[0]) - restart_interfaces.extend( - self.child_members(interface[0])) - break - - for vlan in restart_vlans: - self.ifdown(vlan) - - for ib_child in restart_ib_childs: - self.ifdown(ib_child) - - for interface in restart_interfaces: - self.ifdown(interface) - for bond in linux_bond_children: - if interface in linux_bond_children[bond]: - if bond not in restart_linux_bonds: - start_linux_bonds.append(bond) - - for linux_bond in restart_linux_bonds: - self.ifdown(linux_bond) - - for linux_team in restart_linux_teams: - self.ifdown(linux_team) - - for bridge in restart_bridges: - self.ifdown(bridge, iftype='bridge') - - for vpp_interface in vpp_interfaces: - self.ifdown(vpp_interface.name) - - for oldname, newname in self.renamed_interfaces.items(): - self.ifrename(oldname, newname) - - # DPDK initialization is done before running os-net-config, to make - # the DPDK ports available when enabled. DPDK Hotplug support is - # supported only in OvS 2.7 version. Until then, OvS needs to be - # restarted after adding a DPDK port. This change will be removed - # on migration to OvS 2.7 where DPDK Hotplug support is available. - if ovs_needs_restart: - msg = "Restart openvswitch" - self.execute(msg, '/usr/bin/systemctl', - 'restart', 'openvswitch') - - for location, data in update_files.items(): - self.write_config(location, data) - - if self.route_table_data: - location = route_table_config_path() - data = self.generate_route_table_config(self.route_table_data) - self.write_config(location, data) - - if ivs_uplinks or ivs_interfaces: - location = ivs_config_path() - data = self.generate_ivs_config(ivs_uplinks, ivs_interfaces) - if (utils.diff(location, data)): - self.write_config(location, data) - msg = "Restart ivs" - self.execute(msg, '/usr/bin/systemctl', - 'restart', 'ivs') - - if nfvswitch_interfaces or nfvswitch_internal_ifaces: - location = nfvswitch_config_path() - data = self.generate_nfvswitch_config(nfvswitch_interfaces, - nfvswitch_internal_ifaces) - if (utils.diff(location, data)): - self.write_config(location, data) - msg = "Restart nfvswitch" - self.execute(msg, '/usr/bin/systemctl', - 'restart', 'nfvswitch') - - if activate: - for linux_team in restart_linux_teams: - self.ifup(linux_team) - - for bridge in restart_bridges: - self.ifup(bridge, iftype='bridge') - - # If dhclient is running and dhcp not set, stop dhclient - for interface in stop_dhclient_interfaces: - logger.debug("Calling stop_dhclient_interfaces() for %s" % - interface) - if not self.noop: - stop_dhclient_process(interface) - - for interface in restart_interfaces: - self.ifup(interface) - - for linux_bond in start_linux_bonds: - if linux_bond not in restart_linux_bonds: - restart_linux_bonds.append(linux_bond) - - for linux_bond in restart_linux_bonds: - self.ifup(linux_bond) - - for bond in self.bond_primary_ifaces: - self.ovs_appctl('bond/set-active-slave', bond, - self.bond_primary_ifaces[bond], - ignore_err=True) - - if ivs_uplinks or ivs_interfaces: - logger.info("Attach to ivs with " - "uplinks: %s, " - "interfaces: %s" % - (ivs_uplinks, ivs_interfaces)) - for ivs_uplink in ivs_uplinks: - self.ifup(ivs_uplink) - for ivs_interface in ivs_interfaces: - self.ifup(ivs_interface) - - if nfvswitch_interfaces or nfvswitch_internal_ifaces: - logger.info("Attach to nfvswitch with " - "interfaces: %s, " - "internal interfaces: %s" % - (nfvswitch_interfaces, nfvswitch_internal_ifaces)) - for nfvswitch_interface in nfvswitch_interfaces: - self.ifup(nfvswitch_interface) - for nfvswitch_internal in nfvswitch_internal_ifaces: - self.ifup(nfvswitch_internal) - - for ib_child in restart_ib_childs: - self.ifup(ib_child) - - for vlan in restart_vlans: - self.ifup(vlan) - - if not self.noop: - if restart_vpp: - logger.info('Restarting VPP') - utils.restart_vpp(vpp_interfaces) - - if self.vpp_interface_data: - logger.info('Updating VPP mapping') - utils.update_vpp_mapping(vpp_interfaces, vpp_bonds) - - if self.errors: - message = 'Failure(s) occurred when applying configuration' - logger.error(message) - for e in self.errors: - logger.error('stdout: %s, stderr: %s', e.stdout, e.stderr) - raise os_net_config.ConfigurationError(message) - - return update_files diff --git a/os_net_config/impl_iproute.py b/os_net_config/impl_iproute.py deleted file mode 100644 index ddc6a7b0..00000000 --- a/os_net_config/impl_iproute.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- 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. - -import os_net_config - - -class IprouteNetConfig(os_net_config.NetConfig): - """Configure network interfaces using iproute2.""" diff --git a/os_net_config/impl_nmstate.py b/os_net_config/impl_nmstate.py deleted file mode 100644 index 088870f6..00000000 --- a/os_net_config/impl_nmstate.py +++ /dev/null @@ -1,1621 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2014-2015 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. - -import copy -from libnmstate import netapplier -from libnmstate import netinfo -from libnmstate.schema import Bond -from libnmstate.schema import BondMode -from libnmstate.schema import DNS -from libnmstate.schema import Ethernet -from libnmstate.schema import Ethtool -from libnmstate.schema import InfiniBand -from libnmstate.schema import Interface -from libnmstate.schema import InterfaceIPv4 -from libnmstate.schema import InterfaceIPv6 -from libnmstate.schema import InterfaceState -from libnmstate.schema import InterfaceType -from libnmstate.schema import OVSBridge -from libnmstate.schema import OvsDB -from libnmstate.schema import OVSInterface -from libnmstate.schema import Route as NMRoute -from libnmstate.schema import RouteRule as NMRouteRule -from libnmstate.schema import VLAN -import logging -import netaddr -import re -import yaml - -import os_net_config -from os_net_config import common -from os_net_config import objects -from os_net_config import utils - -logger = logging.getLogger(__name__) - -# Import the raw NetConfig object so we can call its methods -netconfig = os_net_config.NetConfig() - -_OS_NET_CONFIG_MANAGED = "# os-net-config managed table" - -_ROUTE_TABLE_DEFAULT = """# reserved values -# -255\tlocal -254\tmain -253\tdefault -0\tunspec -# -# local -# -#1\tinr.ruhep\n""" - - -IPV4_DEFAULT_GATEWAY_DESTINATION = "0.0.0.0/0" -IPV6_DEFAULT_GATEWAY_DESTINATION = "::/0" - - -def route_table_config_path(): - return "/etc/iproute2/rt_tables" - - -def _get_type_value(str_val): - if isinstance(str_val, str): - if str_val.isdigit(): - return int(str_val) - if str_val.lower() in ['true', 'yes', 'on']: - return True - if str_val.lower() in ['false', 'no', 'off']: - return False - return str_val - - -def get_route_options(route_options, key): - - items = route_options.split(' ') - iter_list = iter(items) - for item in iter_list: - if key in item: - return _get_type_value(next(iter_list)) - return - - -def is_dict_subset(superset, subset): - """Check to see if one dict is a subset of another dict.""" - - if superset == subset: - return True - if superset and subset: - for key, value in subset.items(): - if key not in superset: - return False - if isinstance(value, dict): - if not is_dict_subset(superset[key], value): - return False - elif isinstance(value, int): - if value != superset[key]: - return False - elif isinstance(value, str): - if value != superset[key]: - return False - elif isinstance(value, list): - try: - if not set(value) <= set(superset[key]): - return False - except TypeError: - for item in value: - if item not in superset[key]: - return False - elif isinstance(value, set): - if not value <= superset[key]: - return False - else: - if not value == superset[key]: - return False - return True - return False - - -def _add_sub_tree(data, subtree): - config = data - if subtree: - for cfg in subtree: - if cfg not in config: - config[cfg] = {} - config = config[cfg] - return config - - -def parse_bonding_options(bond_options_str): - bond_options_dict = {} - if bond_options_str: - options = re.findall(r'(.+?)=(.+?)($|\s)', bond_options_str) - for option in options: - bond_options_dict[option[0]] = _get_type_value(option[1]) - return bond_options_dict - - -def set_linux_bonding_options(bond_options, primary_iface=None): - linux_bond_options = ["updelay", "miimon", "lacp_rate"] - bond_data = {Bond.MODE: BondMode.ACTIVE_BACKUP, - Bond.OPTIONS_SUBTREE: {}, - Bond.PORT: []} - bond_options_data = {} - if 'mode' in bond_options: - bond_data[Bond.MODE] = bond_options['mode'] - - for options in linux_bond_options: - if options in bond_options: - bond_options_data[options] = bond_options[options] - bond_data[Bond.OPTIONS_SUBTREE] = bond_options_data - - if primary_iface and bond_data[Bond.MODE] == BondMode.ACTIVE_BACKUP: - bond_options_data['primary'] = primary_iface - - if len(bond_data[Bond.OPTIONS_SUBTREE]) == 0: - del bond_data[Bond.OPTIONS_SUBTREE] - return bond_data - - -def set_ovs_bonding_options(bond_options): - # Duplicate entries for other-config are added so as to avoid - # the confusion around other-config vs other_config in ovs - ovs_other_config = ["other_config:lacp-fallback-ab", - "other_config:lacp-time", - "other_config:bond-detect-mode", - "other_config:bond-miimon-interval", - "other_config:bond-rebalance-interval", - "other_config:bond-primary", - "other-config:lacp-fallback-ab", - "other-config:lacp-time", - "other-config:bond-detect-mode", - "other-config:bond-miimon-interval", - "other-config:bond-rebalance-interval", - "other-config:bond-primary"] - other_config = {} - bond_data = {OVSBridge.Port.LinkAggregation.MODE: 'active-backup', - OVSBridge.PORT_SUBTREE: - [{OVSBridge.Port.LinkAggregation.PORT_SUBTREE: []}], - OvsDB.KEY: {OvsDB.OTHER_CONFIG: other_config}} - - if 'bond_mode' in bond_options: - bond_data[OVSBridge.Port.LinkAggregation.MODE - ] = bond_options['bond_mode'] - elif 'lacp' in bond_options and bond_options['lacp'] == 'active': - bond_data[OVSBridge.Port.LinkAggregation.MODE - ] = OVSBridge.Port.LinkAggregation.Mode.LACP - - if 'bond_updelay' in bond_options: - bond_data[OVSBridge.Port.LinkAggregation.Options.UP_DELAY - ] = bond_options['bond_updelay'] - - for options in ovs_other_config: - if options in bond_options: - other_config[options[len("other_config:"):] - ] = bond_options[options] - - return bond_data - - -def _is_any_ip_addr(address): - if address.lower() == 'any' or address.lower() == 'all': - return True - return False - - -class NmstateNetConfig(os_net_config.NetConfig): - """Configure network interfaces using NetworkManager via nmstate API.""" - - def __init__(self, noop=False, root_dir=''): - super(NmstateNetConfig, self).__init__(noop, root_dir) - self.interface_data = {} - self.vlan_data = {} - self.route_data = {} - self.rules_data = [] - self.dns_data = {'server': [], 'domain': []} - self.bridge_data = {} - self.linuxbond_data = {} - self.ovs_port_data = {} - self.member_names = {} - self.renamed_interfaces = {} - self.bond_primary_ifaces = {} - self.route_table_data = {} - self.sriov_pf_data = {} - self.sriov_vf_data = {} - logger.info('nmstate net config provider created.') - - def __dump_config(self, config, msg="Applying config"): - cfg_dump = yaml.dump(config, default_flow_style=False, - allow_unicode=True, encoding=None) - logger.debug("----------------------------") - logger.debug(f"{msg}\n{cfg_dump}") - - def get_vf_config(self, sriov_vf): - """Identify the nmstate schema for the given VF - - :param sriov_vf: The SriovVF object to add - """ - vf_config = {} - vf_config[Ethernet.SRIOV.VFS.ID] = sriov_vf.vfid - if sriov_vf.macaddr: - vf_config[Ethernet.SRIOV.VFS.MAC_ADDRESS] = sriov_vf.macaddr - if sriov_vf.spoofcheck: - if sriov_vf.spoofcheck == 'on': - vf_config[Ethernet.SRIOV.VFS.SPOOF_CHECK] = True - else: - vf_config[Ethernet.SRIOV.VFS.SPOOF_CHECK] = False - if sriov_vf.trust: - if sriov_vf.trust == 'on': - vf_config[Ethernet.SRIOV.VFS.TRUST] = True - else: - vf_config[Ethernet.SRIOV.VFS.TRUST] = False - if sriov_vf.min_tx_rate: - vf_config[Ethernet.SRIOV.VFS.MIN_TX_RATE] = sriov_vf.min_tx_rate - if sriov_vf.max_tx_rate: - vf_config[Ethernet.SRIOV.VFS.MAX_TX_RATE] = sriov_vf.max_tx_rate - if sriov_vf.vlan_id: - vf_config[Ethernet.SRIOV.VFS.VLAN_ID] = sriov_vf.vlan_id - if sriov_vf.qos: - vf_config[Ethernet.SRIOV.VFS.QOS] = sriov_vf.qos - return vf_config - - def prepare_sriov_vf_config(self): - iface_schema = [] - - for pf in self.sriov_vf_data.keys(): - required_vfs = [] - if pf in self.sriov_pf_data: - pf_state = self.sriov_pf_data[pf] - - else: - msg = f"{pf} not found" - raise os_net_config.ConfigurationError(msg) - - for vf in self.sriov_vf_data[pf]: - if vf: - required_vfs.append(vf) - - pf_state[ - Ethernet.CONFIG_SUBTREE][ - Ethernet.SRIOV_SUBTREE][ - Ethernet.SRIOV.VFS_SUBTREE] = required_vfs - iface_schema.append(pf_state) - return iface_schema - - def get_route_tables(self): - """Generate configuration content for routing tables. - - This method first extracts the existing route table definitions. If - any non-default tables exist, they will be kept unless they conflict - with new tables defined in the route_tables dict. - - :param route_tables: A dict of RouteTable objects - """ - - rt_tables = {} - rt_config = common.get_file_data(route_table_config_path()).split('\n') - for line in rt_config: - # ignore comments and black lines - line = line.strip() - if not line or line.startswith('#'): - pass - else: - id_name = line.split() - if len(id_name) > 1 and id_name[0].isdigit(): - rt_tables[id_name[1]] = int(id_name[0]) - self.__dump_config(rt_tables, - msg='Contents of /etc/iproute2/rt_tables') - return rt_tables - - def generate_route_table_config(self, route_tables): - """Generate configuration content for routing tables. - - This method first extracts the existing route table definitions. If - any non-default tables exist, they will be kept unless they conflict - with new tables defined in the route_tables dict. - - :param route_tables: A dict of RouteTable objects - """ - - custom_tables = {} - res_ids = ['0', '253', '254', '255'] - res_names = ['unspec', 'default', 'main', 'local'] - rt_config = common.get_file_data(route_table_config_path()).split('\n') - rt_defaults = _ROUTE_TABLE_DEFAULT.split("\n") - data = _ROUTE_TABLE_DEFAULT - for line in rt_config: - line = line.strip() - if line in rt_defaults: - continue - # Leave non-standard comments intact in file - if line.startswith('#'): - data += f"{line}\n" - # Ignore old managed entries, will be added back if in new config. - elif line.find(_OS_NET_CONFIG_MANAGED) == -1: - id_name = line.split() - # Keep custom tables if there is no conflict with new tables. - if len(id_name) > 1 and id_name[0].isdigit(): - if not id_name[0] in res_ids: - if not id_name[1] in res_names: - if not int(id_name[0]) in route_tables: - if not id_name[1] in route_tables.values(): - # Replicate line with any comments appended - custom_tables[id_name[0]] = id_name[1] - data += f"{line}\n" - if custom_tables: - logger.debug(f"Existing route tables: {custom_tables}") - for id in sorted(route_tables): - if str(id) in res_ids: - message = f"Table {route_tables[id]}({id}) conflicts with " \ - f"reserved table "\ - f"{res_names[res_ids.index(str(id))]}({id})" - raise os_net_config.ConfigurationError(message) - elif route_tables[id] in res_names: - message = f"Table {route_tables[id]}({id}) conflicts with "\ - f"reserved table {route_tables[id]}" \ - f"({res_ids[res_names.index(route_tables[id])]})" - raise os_net_config.ConfigurationError(message) - else: - data += f"{id}\t{route_tables[id]} "\ - f"{_OS_NET_CONFIG_MANAGED}\n" - return data - - def iface_state(self, name=''): - """Return the current interface state according to nmstate. - - Return the current state of all interfaces, or the named interface. - :param name: name of the interface to return state, otherwise all. - :returns: list state of all interfaces when name is not specified, or - the state of the specific interface when name is specified - """ - ifaces = netinfo.show_running_config()[Interface.KEY] - if name != '': - for iface in ifaces: - if iface[Interface.NAME] != name: - continue - self.__dump_config(iface, msg=f"Running config for {name}") - return iface - else: - self.__dump_config(ifaces, - msg=f"Running config for all interfaces") - return ifaces - - def cleanup_all_ifaces(self, exclude_nics=[]): - - exclude_nics.extend(['lo']) - ifaces = netinfo.show_running_config()[Interface.KEY] - - for iface in ifaces: - if Interface.NAME in iface and \ - iface[Interface.NAME] not in exclude_nics: - iface[Interface.STATE] = InterfaceState.DOWN - state = {Interface.KEY: [iface]} - self.__dump_config(state, - msg=f"Cleaning up {iface[Interface.NAME]}") - if not self.noop: - netapplier.apply(state, verify_change=True) - - def route_state(self, name=''): - """Return the current routes set according to nmstate. - - Return the current routes for all interfaces, or the named interface. - :param name: name of the interface to return state, otherwise all. - :returns: list of all interfaces, or those matching name if specified - """ - - routes = netinfo.show_running_config()[ - NMRoute.KEY][NMRoute.CONFIG] - if name != "": - route = list(x for x in routes if x[ - NMRoute.NEXT_HOP_INTERFACE] == name) - self.__dump_config(route, - msg=f'Running route config for {name}') - return route - else: - self.__dump_config(routes, msg=f'Running routes config') - return routes - - def rule_state(self): - """Return the current rules set according to nmstate. - - Return the current ip rules for all interfaces, or the named interface. - :param name: name of the interface to return state, otherwise all. - :returns: list of all interfaces, or those matching name if specified - """ - - rules = netinfo.show_running_config()[ - NMRouteRule.KEY][NMRouteRule.CONFIG] - self.__dump_config(rules, msg=f'List of IP rules running config') - return rules - - def set_ifaces(self, iface_data): - """Apply the desired state using nmstate. - - :param iface_data: interface config json - :param verify: boolean that determines if config will be verified - """ - state = {Interface.KEY: iface_data} - self.__dump_config(state, msg=f"Overall interface config") - return state - - def set_dns(self): - """Apply the desired DNS using nmstate. - - :param dns_data: config json - :param verify: boolean that determines if config will be verified - """ - - state = {DNS.KEY: {DNS.CONFIG: {DNS.SERVER: self.dns_data['server'], - DNS.SEARCH: self.dns_data['domain']}}} - self.__dump_config(state, msg=f"Overall DNS") - return state - - def set_routes(self, route_data): - """Apply the desired routes using nmstate. - - :param route_data: list of routes - :param verify: boolean that determines if config will be verified - """ - - state = {NMRoute.KEY: {NMRoute.CONFIG: route_data}} - self.__dump_config(state, msg=f'Overall routes') - return state - - def set_rules(self, rule_data,): - """Apply the desired rules using nmstate. - - :param rule_data: list of rules - :param verify: boolean that determines if config will be verified - """ - - state = {NMRouteRule.KEY: {NMRouteRule.CONFIG: rule_data}} - self.__dump_config(state, msg=f'Overall rules') - return state - - def nmstate_apply(self, new_state, verify=True): - self.__dump_config(new_state, msg=f'Applying the config with nmstate') - if not self.noop: - netapplier.apply(new_state, verify_change=verify) - - def generate_routes(self, interface_name): - """Generate the route configurations required. Add/Remove routes - - : param interface_name: interface name for which routes are required - """ - - reqd_route = self.route_data.get(interface_name, []) - curr_routes = self.route_state(interface_name) - - routes = [] - self.__dump_config(curr_routes, - msg=f'Running route config for {interface_name}') - self.__dump_config(reqd_route, - msg=f'Required route changes for {interface_name}') - - for c_route in curr_routes: - no_metric = copy.deepcopy(c_route) - if NMRoute.METRIC in no_metric: - del no_metric[NMRoute.METRIC] - if c_route not in reqd_route and no_metric not in reqd_route: - c_route[NMRoute.STATE] = NMRoute.STATE_ABSENT - routes.append(c_route) - logger.info(f'Removing route {c_route}') - routes.extend(reqd_route) - return routes - - def generate_rules(self): - """Generate the rule configurations required. Add/Remove rules - - """ - - reqd_rule = self.rules_data - curr_rules = self.rule_state() - - rules = [] - self.__dump_config(curr_rules, - msg=f'Running set of ip rules') - - self.__dump_config(reqd_rule, - msg=f'Required ip rules') - for c_rule in curr_rules: - if c_rule not in reqd_rule: - c_rule[NMRouteRule.STATE] = NMRouteRule.STATE_ABSENT - rules.append(c_rule) - logger.info(f'Removing rule {c_rule}') - rules.extend(reqd_rule) - return rules - - def interface_mac(self, iface): - iface_data = self.iface_state(iface) - if iface_data and Interface.MAC in iface_data: - return iface_data[Interface.MAC] - - def get_ovs_ports(self, members): - bps = [] - for member in members: - if member.startswith('vlan'): - vlan_id = int(member.strip('vlan')) - port = { - OVSBridge.Port.NAME: member, - OVSBridge.Port.VLAN_SUBTREE: { - OVSBridge.Port.Vlan.MODE: 'access', - OVSBridge.Port.Vlan.TAG: vlan_id - } - } - bps.append(port) - # if the member is of type interface but a vlan - # like eth0.605 - elif re.match(r'\w+\.\d+$', member): - vlan_id = int(member.split('.')[1]) - port = { - OVSBridge.Port.NAME: member, - OVSBridge.Port.VLAN_SUBTREE: { - OVSBridge.Port.Vlan.MODE: 'access', - OVSBridge.Port.Vlan.TAG: vlan_id - } - } - bps.append(port) - else: - port = {'name': member} - bps.append(port) - - logger.debug(f"Adding ovs ports {bps}") - return bps - - def add_ethtool_subtree(self, data, sub_config, command): - config = _add_sub_tree(data, sub_config['sub-tree']) - ethtool_map = sub_config['map'] - - # skip first 2 entries as they are already validated - for index in range(2, len(command) - 1, 2): - value = _get_type_value(command[index + 1]) - if command[index] in ethtool_map.keys(): - config[ethtool_map[command[index]]] = value - elif (sub_config['sub-options'] == 'copy'): - config[command[index]] = value - else: - msg = f'Unhandled ethtool option {command[index]} for '\ - f'command {command}.' - raise os_net_config.ConfigurationError(msg) - - def add_ethtool_config(self, iface_name, data, ethtool_options): - - ethtool_generic_options = {'sub-tree': [Ethernet.CONFIG_SUBTREE], - 'sub-options': None, - 'map': { - 'speed': Ethernet.SPEED, - 'autoneg': Ethernet.AUTO_NEGOTIATION, - 'duplex': Ethernet.DUPLEX} - } - ethtool_set_ring = {'sub-tree': [Ethtool.CONFIG_SUBTREE, - Ethtool.Ring.CONFIG_SUBTREE], - 'sub-options': None, - 'map': { - 'rx': Ethtool.Ring.RX, - 'tx': Ethtool.Ring.TX, - 'rx-jumbo': Ethtool.Ring.RX_JUMBO, - 'rx-mini': Ethtool.Ring.RX_MINI} - } - ethtool_set_pause = {'sub-tree': [Ethtool.CONFIG_SUBTREE, - Ethtool.Pause.CONFIG_SUBTREE], - 'sub-options': None, - 'map': { - 'autoneg': Ethtool.Pause.AUTO_NEGOTIATION, - 'tx': Ethtool.Pause.TX, - 'rx': Ethtool.Pause.RX} - } - coalesce_map = {'adaptive-rx': Ethtool.Coalesce.ADAPTIVE_RX, - 'adaptive-tx': Ethtool.Coalesce.ADAPTIVE_TX, - 'rx-usecs': Ethtool.Coalesce.RX_USECS, - 'rx-frames': Ethtool.Coalesce.RX_FRAMES, - 'rx-usecs-irq': Ethtool.Coalesce.RX_USECS_IRQ, - 'rx-frames-irq': Ethtool.Coalesce.RX_FRAMES_IRQ, - 'tx-usecs': Ethtool.Coalesce.TX_USECS, - 'tx-frames': Ethtool.Coalesce.TX_FRAMES, - 'tx-usecs-irq': Ethtool.Coalesce.TX_USECS_IRQ, - 'tx-frames-irq': Ethtool.Coalesce.TX_FRAMES_IRQ, - 'stats-block-usecs': - Ethtool.Coalesce.STATS_BLOCK_USECS, - 'pkt-rate-low': Ethtool.Coalesce.PKT_RATE_LOW, - 'rx-usecs-low': Ethtool.Coalesce.RX_USECS_LOW, - 'rx-frames-low': Ethtool.Coalesce.RX_FRAMES_LOW, - 'tx-usecs-low': Ethtool.Coalesce.TX_USECS_LOW, - 'tx-frames-low': Ethtool.Coalesce.TX_FRAMES_LOW, - 'pkt-rate-high': Ethtool.Coalesce.PKT_RATE_HIGH, - 'rx-usecs-high': Ethtool.Coalesce.RX_USECS_HIGH, - 'rx-frames-high': Ethtool.Coalesce.RX_FRAMES_HIGH, - 'tx-usecs-high': Ethtool.Coalesce.TX_USECS_HIGH, - 'tx-frames-high': Ethtool.Coalesce.TX_FRAMES_HIGH, - 'sample-interval': Ethtool.Coalesce.SAMPLE_INTERVAL} - ethtool_set_coalesce = {'sub-tree': [Ethtool.CONFIG_SUBTREE, - Ethtool.Coalesce.CONFIG_SUBTREE], - 'sub-options': None, - 'map': coalesce_map - } - ethtool_set_features = {'sub-tree': [Ethtool.CONFIG_SUBTREE, - Ethtool.Feature.CONFIG_SUBTREE], - 'sub-options': 'copy', - 'map': {}} - ethtool_map = {'-G': ethtool_set_ring, - '--set-ring': ethtool_set_ring, - '-A': ethtool_set_pause, - '--pause': ethtool_set_pause, - '-C': ethtool_set_coalesce, - '--coalesce': ethtool_set_coalesce, - '-K': ethtool_set_features, - '--features': ethtool_set_features, - '--offload': ethtool_set_features, - '-s': ethtool_generic_options, - '--change': ethtool_generic_options} - if Ethernet.CONFIG_SUBTREE not in data: - data[Ethernet.CONFIG_SUBTREE] = {} - if Ethtool.CONFIG_SUBTREE not in data: - data[Ethtool.CONFIG_SUBTREE] = {} - - for ethtool_opts in ethtool_options.split(';'): - ethtool_opts = ethtool_opts.strip() - if re.match(r'^(-[\S-]+[ ]+[\S]+)([ ]+[\S-]+[ ]+[\S]+)+', - ethtool_opts): - # The regex pattern is strict and hence a minimum of 4 items - # are present in ethtool_opts. - command = ethtool_opts.split() - if len(command) < 4: - msg = f"Ethtool options {command} is incomplete" - raise os_net_config.ConfigurationError(msg) - - option = command[0] - accepted_dev_names = ['${DEVICE}', '$DEVICE', iface_name] - if command[1] not in accepted_dev_names: - msg = f'Skipping {ethtool_opts} due to incorrect device '\ - f'name present for interface {iface_name}' - raise os_net_config.ConfigurationError(msg) - if option in ethtool_map.keys(): - self.add_ethtool_subtree(data, ethtool_map[option], - command) - else: - msg = f'Unhandled ethtool_opts {ethtool_opts} for device'\ - f' {iface_name}. Option {option} is not supported.' - raise os_net_config.ConfigurationError(msg) - else: - command_str = '-s ${DEVICE} ' + ethtool_opts - command = command_str.split() - option = command[0] - self.add_ethtool_subtree(data, ethtool_map[option], command) - - def _add_common(self, base_opt): - - data = {Interface.IPV4: {InterfaceIPv4.ENABLED: False}, - Interface.IPV6: {InterfaceIPv6.ENABLED: False}, - Interface.NAME: base_opt.name} - if base_opt.use_dhcp: - data[Interface.IPV4][InterfaceIPv4.ENABLED] = True - data[Interface.IPV4][InterfaceIPv4.DHCP] = True - data[Interface.IPV4][InterfaceIPv4.AUTO_DNS] = True - data[Interface.IPV4][InterfaceIPv4.AUTO_ROUTES] = True - data[Interface.IPV4][InterfaceIPv4.AUTO_GATEWAY] = True - else: - data[Interface.IPV4][InterfaceIPv4.DHCP] = False - if base_opt.dns_servers: - data[Interface.IPV4][InterfaceIPv4.AUTO_DNS] = False - - if base_opt.use_dhcpv6: - data[Interface.IPV6][InterfaceIPv6.ENABLED] = True - data[Interface.IPV6][InterfaceIPv6.DHCP] = True - data[Interface.IPV6][InterfaceIPv6.AUTO_DNS] = True - data[Interface.IPV6][InterfaceIPv6.AUTOCONF] = True - data[Interface.IPV6][InterfaceIPv6.AUTO_DNS] = True - data[Interface.IPV6][InterfaceIPv6.AUTO_ROUTES] = True - data[Interface.IPV6][InterfaceIPv6.AUTO_GATEWAY] = True - else: - data[Interface.IPV6][InterfaceIPv6.DHCP] = False - data[Interface.IPV6][InterfaceIPv6.AUTOCONF] = False - if base_opt.dns_servers: - data[Interface.IPV6][InterfaceIPv6.AUTO_DNS] = False - - if not base_opt.defroute: - data[Interface.IPV4][InterfaceIPv4.AUTO_GATEWAY] = False - data[Interface.IPV6][InterfaceIPv6.AUTO_GATEWAY] = False - - # NetworkManager always starts on boot, so set enabled state instead - if base_opt.onboot: - data[Interface.STATE] = InterfaceState.UP - else: - data[Interface.STATE] = InterfaceState.DOWN - - if not base_opt.nm_controlled: - logger.info('Using NetworkManager, nm_controlled is always true.' - 'Deprecating it from next release') - if isinstance(base_opt, objects.Interface): - if not base_opt.hotplug: - logger.info('Using NetworkManager, hotplug is always set to' - 'true. Deprecating it from next release') - - if base_opt.mtu: - data[Interface.MTU] = base_opt.mtu - if base_opt.addresses: - v4_addresses = base_opt.v4_addresses() - if v4_addresses: - for address in v4_addresses: - netmask_ip = netaddr.IPAddress(address.netmask) - ip_netmask = {'ip': address.ip, - 'prefix-length': netmask_ip.netmask_bits()} - if InterfaceIPv4.ADDRESS not in data[Interface.IPV4]: - data[Interface.IPV4][InterfaceIPv4.ADDRESS] = [] - data[Interface.IPV4][InterfaceIPv4.ENABLED] = True - data[Interface.IPV4][InterfaceIPv4.ADDRESS].append( - ip_netmask) - - v6_addresses = base_opt.v6_addresses() - if v6_addresses: - for v6_address in v6_addresses: - netmask_ip = netaddr.IPAddress(v6_address.netmask) - v6ip_netmask = {'ip': v6_address.ip, - 'prefix-length': - netmask_ip.netmask_bits()} - if InterfaceIPv6.ADDRESS not in data[Interface.IPV6]: - data[Interface.IPV6][InterfaceIPv6.ADDRESS] = [] - data[Interface.IPV6][InterfaceIPv6.ENABLED] = True - data[Interface.IPV6][InterfaceIPv6.ADDRESS].append( - v6ip_netmask) - - if base_opt.dhclient_args: - msg = "DHCP Client args not supported in impl_nmstate, ignoring" - logger.error(msg) - if base_opt.dns_servers: - self._add_dns_servers(base_opt.dns_servers) - if base_opt.domain: - self._add_dns_domain(base_opt.domain) - if base_opt.routes: - self._add_routes(base_opt.name, base_opt.routes) - if base_opt.rules: - self._add_rules(base_opt.name, base_opt.rules) - return data - - def _add_routes(self, interface_name, routes=[]): - - routes_data = [] - logger.info(f'adding custom route for interface: {interface_name}') - - for route in routes: - route_data = {} - if route.route_options: - value = get_route_options(route.route_options, 'metric') - if value: - route.metric = value - value = get_route_options(route.route_options, 'table') - if value: - route.route_table = value - - if route.metric: - route_data[NMRoute.METRIC] = route.metric - if route.ip_netmask: - route_data[NMRoute.DESTINATION] = route.ip_netmask - if route.next_hop: - route_data[NMRoute.NEXT_HOP_ADDRESS] = route.next_hop - route_data[NMRoute.NEXT_HOP_INTERFACE] = interface_name - if route.default: - if ":" in route.next_hop: - route_data[NMRoute.DESTINATION] = \ - IPV6_DEFAULT_GATEWAY_DESTINATION - else: - route_data[NMRoute.DESTINATION] = \ - IPV4_DEFAULT_GATEWAY_DESTINATION - rt_tables = self.get_route_tables() - if route.route_table: - if str(route.route_table).isdigit(): - route_data[NMRoute.TABLE_ID] = route.route_table - elif route.route_table in rt_tables: - route_data[NMRoute.TABLE_ID] = \ - rt_tables[route.route_table] - else: - logger.error(f'Unidentified mapping for route_table ' - '{route.route_table}') - - routes_data.append(route_data) - - self.route_data[interface_name] = routes_data - logger.debug(f'route data: {self.route_data[interface_name]}') - - def add_route_table(self, route_table): - """Add a RouteTable object to the net config object. - - :param route_table: the RouteTable object to add. - """ - logger.info(f'adding route table: {route_table.table_id} ' - f'{route_table.name}') - self.route_table_data[int(route_table.table_id)] = route_table.name - location = route_table_config_path() - data = self.generate_route_table_config(self.route_table_data) - self.write_config(location, data) - - def _parse_ip_rules(self, rule): - nm_rule_map = { - 'blackhole': {'nm_key': NMRouteRule.ACTION, - 'nm_value': NMRouteRule.ACTION_BLACKHOLE}, - 'unreachable': {'nm_key': NMRouteRule.ACTION, - 'nm_value': NMRouteRule.ACTION_UNREACHABLE}, - 'prohibit': {'nm_key': NMRouteRule.ACTION, - 'nm_value': NMRouteRule.ACTION_PROHIBIT}, - 'fwmark': {'nm_key': NMRouteRule.FWMARK, 'nm_value': None}, - 'fwmask': {'nm_key': NMRouteRule.FWMASK, 'nm_value': None}, - 'iif': {'nm_key': NMRouteRule.IIF, 'nm_value': None}, - 'from': {'nm_key': NMRouteRule.IP_FROM, 'nm_value': None}, - 'to': {'nm_key': NMRouteRule.IP_TO, 'nm_value': None}, - 'priority': {'nm_key': NMRouteRule.PRIORITY, 'nm_value': None}, - 'table': {'nm_key': NMRouteRule.ROUTE_TABLE, 'nm_value': None}} - logger.debug(f"Parse Rule {rule}") - items = rule.split() - keyword = items[0] - parse_start_index = 1 - rule_config = {} - if keyword == 'del': - rule_config[NMRouteRule.STATE] = NMRouteRule.STATE_ABSENT - elif keyword in nm_rule_map.keys(): - parse_start_index = 0 - elif keyword != 'add': - msg = f"unhandled ip rule command {rule}" - raise os_net_config.ConfigurationError(msg) - - items_iter = iter(items[parse_start_index:]) - - parse_complete = True - while True: - try: - parse_complete = True - item = next(items_iter) - logger.debug(f"parse item {item}") - if item in nm_rule_map.keys(): - value = _get_type_value(nm_rule_map[item]['nm_value']) - if not value: - parse_complete = False - value = _get_type_value(next(items_iter)) - rule_config[nm_rule_map[item]['nm_key']] = value - else: - msg = f"unhandled ip rule command {rule}" - raise os_net_config.ConfigurationError(msg) - except StopIteration: - if not parse_complete: - msg = f"incomplete ip rule command {rule}" - raise os_net_config.ConfigurationError(msg) - break - - # Just remove the from/to address when its all/any - # the address defaults to all/any. - if NMRouteRule.IP_FROM in rule_config: - if _is_any_ip_addr(rule_config[NMRouteRule.IP_FROM]): - del rule_config[NMRouteRule.IP_FROM] - if NMRouteRule.IP_TO in rule_config: - if _is_any_ip_addr(rule_config[NMRouteRule.IP_TO]): - del rule_config[NMRouteRule.IP_TO] - - # TODO(Karthik) Add support for ipv6 rules as well - # When neither IP_FROM nor IP_TO is set, specify the IP family - if (NMRouteRule.IP_FROM not in rule_config.keys() and - NMRouteRule.IP_TO not in rule_config.keys()): - rule_config[NMRouteRule.FAMILY] = NMRouteRule.FAMILY_IPV4 - - if NMRouteRule.PRIORITY not in rule_config.keys(): - logger.warning(f"The ip rule {rule} doesn't have the priority set." - "Its advisable to configure the priorities in " - "order to have a deterministic behaviour") - - return rule_config - - def _add_rules(self, interface_name, rules=[]): - for rule in rules: - rule_nm = self._parse_ip_rules(rule.rule) - self.rules_data.append(rule_nm) - - logger.debug(f'rule data: {self.rules_data}') - - def _add_dns_servers(self, dns_servers): - for dns_server in dns_servers: - if dns_server not in self.dns_data['server']: - logger.debug(f"Adding DNS server {dns_server}") - self.dns_data['server'].append(dns_server) - - def _add_dns_domain(self, dns_domain): - if isinstance(dns_domain, str): - logger.debug(f"Adding DNS domain {dns_domain}") - self.dns_data['domain'].extend([dns_domain]) - return - - for domain in dns_domain: - if domain not in self.dns_data['domain']: - logger.debug(f"Adding DNS domain {domain}") - self.dns_data['domain'].append(domain) - - def add_interface(self, interface): - """Add an Interface object to the net config object. - - :param interface: The Interface object to add. - """ - if re.match(r'\w+\.\d+$', interface.name): - vlan_id = int(interface.name.split('.')[1]) - device = interface.name.split('.')[0] - vlan_port = objects.Vlan( - device, vlan_id, - use_dhcp=interface.use_dhcp, use_dhcpv6=interface.use_dhcpv6, - addresses=interface.addresses, routes=interface.routes, - rules=interface.rules, mtu=interface.mtu, - primary=interface.primary, nic_mapping=None, - persist_mapping=None, defroute=interface.defroute, - dhclient_args=interface.dhclient_args, - dns_servers=interface.dns_servers, nm_controlled=True, - onboot=interface.onboot, domain=interface.domain) - vlan_port.name = interface.name - self.add_vlan(vlan_port) - return - - logger.info(f'adding interface: {interface.name}') - data = self._add_common(interface) - if isinstance(interface, objects.Interface): - data[Interface.TYPE] = InterfaceType.ETHERNET - data[Ethernet.CONFIG_SUBTREE] = {} - - if interface.ethtool_opts: - self.add_ethtool_config(interface.name, data, - interface.ethtool_opts) - - if interface.renamed: - logger.info(f"Interface {interface.hwname} being renamed to" - f"{interface.name}") - self.renamed_interfaces[interface.hwname] = interface.name - if interface.hwaddr: - data[Interface.MAC] = interface.hwaddr - - logger.debug(f'interface data: {data}') - self.interface_data[interface.name] = data - - def add_vlan(self, vlan): - """Add a Vlan object to the net config object. - - :param vlan: The vlan object to add. - """ - logger.info(f'adding vlan: {vlan.name}') - - data = self._add_common(vlan) - if vlan.device: - base_iface = vlan.device - elif vlan.linux_bond_name: - base_iface = vlan.linux_bond_name - - if vlan.bridge_name: - # Handle the VLANs for ovs bridges - # vlans on OVS bridges are internal ports (no device, etc) - data[Interface.TYPE] = InterfaceType.OVS_INTERFACE - else: - data[Interface.TYPE] = InterfaceType.VLAN - data[VLAN.CONFIG_SUBTREE] = {} - data[VLAN.CONFIG_SUBTREE][VLAN.ID] = vlan.vlan_id - data[VLAN.CONFIG_SUBTREE][VLAN.BASE_IFACE] = base_iface - - logger.debug(f'vlan data: {data}') - self.vlan_data[vlan.name] = data - - def _ovs_extra_cfg_eq_val(self, ovs_extra, cmd_map, data): - index = 0 - logger.info(f'Current ovs_extra {ovs_extra}') - for a, b in zip(ovs_extra, cmd_map['command']): - if not re.match(b, a, re.IGNORECASE): - return False - index = index + 1 - for idx in range(index, len(ovs_extra)): - value = None - for cfg in cmd_map['action']: - if re.match(cfg['config'], ovs_extra[idx], re.IGNORECASE): - value = None - if 'value' in cfg: - value = cfg['value'] - elif 'value_pattern' in cfg: - m = re.search(cfg['value_pattern'], ovs_extra[idx]) - if m: - value = _get_type_value(m.group(1)) - if value is None: - msg = "Invalid ovs_extra format detected. "\ - f"{' '.join(ovs_extra)}" - raise os_net_config.ConfigurationError(msg) - config = _add_sub_tree(data, cfg['sub_tree']) - if cfg['nm_config']: - config[cfg['nm_config']] = value - elif cfg['nm_config_regex']: - logger.info(f'Regex pattern seen for {ovs_extra}') - m = re.search(cfg['nm_config_regex'], ovs_extra[idx]) - if m: - config[m.group(1)] = value - else: - msg = "Invalid ovs_extra format detected. "\ - f"{' '.join(ovs_extra)}" - raise os_net_config.ConfigurationError(msg) - else: - msg = 'NM config not found' - raise os_net_config.ConfigurationError(msg) - logger.info(f"Adding ovs_extra {config} in " - f"{cfg['sub_tree']}") - - def _ovs_extra_cfg_val(self, ovs_extra, cmd_map, data): - index = 0 - for a, b in zip(ovs_extra, cmd_map['command']): - if not re.match(b, a, re.IGNORECASE): - return False - index = index + 1 - if len(ovs_extra) > (index + 1): - value = None - for cfg in cmd_map['action']: - if re.match(cfg['config'], ovs_extra[index], re.IGNORECASE): - value = None - if 'value' in cfg: - value = cfg['value'] - elif 'value_pattern' in cfg: - m = re.search(cfg['value_pattern'], - ovs_extra[index + 1]) - if m: - value = _get_type_value(m.group(1)) - if value is None: - msg = f"Invalid ovs_extra format detected."\ - f"{' '.join(ovs_extra)}" - raise os_net_config.ConfigurationError(msg) - config = _add_sub_tree(data, cfg['sub_tree']) - if cfg['nm_config']: - config[cfg['nm_config']] = value - elif cfg['nm_config_regex']: - m = re.search(cfg['nm_config_regex'], ovs_extra[index]) - if m: - config[m.group(1)] = value - else: - msg = f"Invalid ovs_extra format detected."\ - f"{' '.join(ovs_extra)}" - raise os_net_config.ConfigurationError(msg) - else: - msg = 'NM config not found' - raise os_net_config.ConfigurationError(msg) - logger.info(f"Adding ovs_extra {config} in " - f"{cfg['sub_tree']}") - - def parse_ovs_extra(self, ovs_extras, name, data): - - bridge_cfg = [{'config': r'^fail_mode=[\w+]', - 'sub_tree': [OVSBridge.CONFIG_SUBTREE, - OVSBridge.OPTIONS_SUBTREE], - 'nm_config': OVSBridge.Options.FAIL_MODE, - 'value_pattern': r'^fail_mode=(.+?)$'}, - {'config': r'^mcast_snooping_enable=[\w+]', - 'sub_tree': [OVSBridge.CONFIG_SUBTREE, - OVSBridge.OPTIONS_SUBTREE], - 'nm_config': OVSBridge.Options.MCAST_SNOOPING_ENABLED, - 'value_pattern': r'^mcast_snooping_enable=(.+?)$'}, - {'config': r'^rstp_enable=[\w+]', - 'sub_tree': [OVSBridge.CONFIG_SUBTREE, - OVSBridge.OPTIONS_SUBTREE], - 'nm_config': OVSBridge.Options.RSTP, - 'value_pattern': r'^rstp_enable=(.+?)$'}, - {'config': r'^stp_enable=[\w+]', - 'sub_tree': [OVSBridge.CONFIG_SUBTREE, - OVSBridge.OPTIONS_SUBTREE], - 'nm_config': OVSBridge.Options.STP, - 'value_pattern': r'^stp_enable=(.+?)$'}, - {'config': r'^other_config:[\w+]', - 'sub_tree': [OvsDB.KEY, OvsDB.OTHER_CONFIG], - 'nm_config': None, - 'nm_config_regex': r'^other_config:(.+?)=', - 'value_pattern': r'^other_config:.*=(.+?)$'}, - {'config': r'^other-config:[\w+]', - 'sub_tree': [OvsDB.KEY, OvsDB.OTHER_CONFIG], - 'nm_config': None, - 'nm_config_regex': r'^other-config:(.+?)=', - 'value_pattern': r'^other-config:.*=(.+?)$'}] - - iface_cfg = [{'config': r'^other_config:[\w+]', - 'sub_tree': [OvsDB.KEY, OvsDB.OTHER_CONFIG], - 'nm_config': None, - 'nm_config_regex': r'^other_config:(.+?)=', - 'value_pattern': r'^other_config:.*=(.+?)$'}, - {'config': r'^other-config:[\w+]', - 'sub_tree': [OvsDB.KEY, OvsDB.OTHER_CONFIG], - 'nm_config': None, - 'nm_config_regex': r'^other-config:(.+?)=', - 'value_pattern': r'^other-config:.*=(.+?)$'}] - - external_id_cfg = [{'sub_tree': [OvsDB.KEY, OvsDB.EXTERNAL_IDS], - 'config': r'.*', - 'nm_config': None, - 'nm_config_regex': r'^(.+?)$', - 'value_pattern': r'^(.+?)$'}] - cfg_eq_val_pair = [{'command': ['set', 'bridge', '({name}|%s)' % name], - 'action': bridge_cfg}, - {'command': ['set', 'interface', - '({name}|%s)' % name], - 'action': iface_cfg}] - - cfg_val_pair = [{'command': ['br-set-external-id', - '({name}|%s)' % name], - 'action': external_id_cfg}] - # ovs-vsctl set Bridge $name = - # ovs-vsctl set Interface $name = - # ovs-vsctl br-set-external-id $name key [value] - for ovs_extra in ovs_extras: - ovs_extra_cmd = ovs_extra.split(' ') - for cmd_map in cfg_eq_val_pair: - self._ovs_extra_cfg_eq_val(ovs_extra_cmd, cmd_map, data) - for cmd_map in cfg_val_pair: - self._ovs_extra_cfg_val(ovs_extra_cmd, cmd_map, data) - - def parse_ovs_extra_for_ports(self, ovs_extras, bridge_name, data): - port_vlan_cfg = [{'config': r'^tag=[\w+]', - 'sub_tree': [OVSBridge.Port.VLAN_SUBTREE], - 'nm_config': OVSBridge.Port.Vlan.TAG, - 'value_pattern': r'^tag=(.+?)$'}, - {'config': r'^tag=[\w+]', - 'sub_tree': [OVSBridge.Port.VLAN_SUBTREE], - 'nm_config': OVSBridge.Port.Vlan.MODE, - 'value': 'access'}] - cfg_eq_val_pair = [{'command': ['set', 'port', - '({name}|%s)' % bridge_name], - 'action': port_vlan_cfg}] - for ovs_extra in ovs_extras: - ovs_extra_cmd = ovs_extra.split(' ') - for cmd_map in cfg_eq_val_pair: - self._ovs_extra_cfg_eq_val(ovs_extra_cmd, cmd_map, data) - - def add_bridge(self, bridge, dpdk=False): - """Add an OvsBridge object to the net config object. - - :param bridge: The OvsBridge object to add. - """ - - # Create the internal ovs interface. Some of the settings of the - # bridge like MTU, ip address are to be applied on this interface - ovs_port_name = f"{bridge.name}-p" - ovs_interface_port = objects.OvsInterface( - ovs_port_name, use_dhcp=bridge.use_dhcp, - use_dhcpv6=bridge.use_dhcpv6, - addresses=bridge.addresses, routes=bridge.routes, - rules=bridge.rules, mtu=bridge.mtu, primary=False, - nic_mapping=None, persist_mapping=None, - defroute=bridge.defroute, dhclient_args=bridge.dhclient_args, - dns_servers=bridge.dns_servers, - nm_controlled=None, onboot=bridge.onboot, - domain=bridge.domain) - self.add_ovs_interface(ovs_interface_port) - - ovs_int_port = {'name': ovs_interface_port.name} - if bridge.ovs_extra: - logger.info(f"Parsing ovs_extra for ports: {bridge.ovs_extra}") - self.parse_ovs_extra_for_ports(bridge.ovs_extra, - bridge.name, ovs_int_port) - - logger.info(f'adding bridge: {bridge.name}') - - # Clear the settings from the bridge, since these will be applied - # on the interface - if bridge.routes: - bridge.routes.clear() - bridge.defroute = False - if bridge.dns_servers: - bridge.dns_servers.clear() - if bridge.domain: - bridge.domain.clear() - if bridge.mtu: - bridge.mtu = None - data = self._add_common(bridge) - - data[Interface.TYPE] = OVSBridge.TYPE - # address bits can't be on the ovs-bridge - del data[Interface.IPV4] - del data[Interface.IPV6] - ovs_bridge_options = {OVSBridge.Options.FAIL_MODE: - objects.DEFAULT_OVS_BRIDGE_FAIL_MODE, - OVSBridge.Options.MCAST_SNOOPING_ENABLED: False, - OVSBridge.Options.RSTP: False, - OVSBridge.Options.STP: False} - data[OVSBridge.CONFIG_SUBTREE] = { - OVSBridge.OPTIONS_SUBTREE: ovs_bridge_options, - OVSBridge.PORT_SUBTREE: [], - } - data[OvsDB.KEY] = {OvsDB.EXTERNAL_IDS: {}, - OvsDB.OTHER_CONFIG: {}} - if bridge.primary_interface_name: - mac = self.interface_mac(bridge.primary_interface_name) - bridge.ovs_extra.append("set bridge %s other_config:hwaddr=%s" % - (bridge.name, mac)) - if bridge.ovs_extra: - logger.info(f"Parsing ovs_extra : {bridge.ovs_extra}") - self.parse_ovs_extra(bridge.ovs_extra, bridge.name, data) - - if dpdk: - ovs_bridge_options[OVSBridge.Options.DATAPATH] = 'netdev' - if bridge.members: - members = [] - ovs_bond = False - ovs_port = False - for member in bridge.members: - if (isinstance(member, objects.OvsBond) or - isinstance(member, objects.OvsDpdkBond)): - if ovs_port: - msg = "Ovs Bond and ovs port can't be members to "\ - "the ovs bridge" - raise os_net_config.ConfigurationError(msg) - if member.primary_interface_name: - add_bond_setting = "other_config:bond-primary="\ - f"{member.primary_interface_name}" - if member.ovs_options: - member.ovs_options = member.ovs_options + " " +\ - add_bond_setting - else: - member.ovs_options = add_bond_setting - - logger.info(f"OVS Options are {member.ovs_options}") - bond_options = parse_bonding_options(member.ovs_options) - bond_data = set_ovs_bonding_options(bond_options) - bond_port = [{ - OVSBridge.Port.LINK_AGGREGATION_SUBTREE: bond_data, - OVSBridge.Port.NAME: member.name}, - ovs_int_port] - data[OVSBridge.CONFIG_SUBTREE - ][OVSBridge.PORT_SUBTREE] = bond_port - - ovs_bond = True - logger.debug("OVS Bond members %s added" % members) - if member.members: - members = [m.name for m in member.members] - elif ovs_bond: - msg = "Ovs Bond and ovs port can't be members to "\ - "the ovs bridge" - raise os_net_config.ConfigurationError(msg) - else: - ovs_port = True - logger.debug("Adding member ovs port %s" % member.name) - members.append(member.name) - if members: - logger.debug("Add ovs ports and vlans to ovs bridge") - bps = self.get_ovs_ports(members) - else: - msg = "No members added for ovs bridge" - raise os_net_config.ConfigurationError(msg) - - self.member_names[bridge.name] = members - - if ovs_port: - # Add the internal ovs interface - bps.append(ovs_int_port) - data[OVSBridge.CONFIG_SUBTREE][OVSBridge.PORT_SUBTREE] = bps - elif ovs_bond: - bond_data[OVSBridge.Port.LinkAggregation.PORT_SUBTREE] = bps - - if bridge.primary_interface_name: - mac = self.interface_mac(bridge.primary_interface_name) - data[Interface.MAC] = mac - - self.bridge_data[bridge.name] = data - logger.debug('bridge data: %s' % data) - - def add_ovs_user_bridge(self, bridge): - """Add an OvsUserBridge object to the net config object. - - :param bridge: The OvsUserBridge object to add. - """ - logger.info('adding ovs user bridge: %s' % bridge.name) - self.add_bridge(bridge, dpdk=True) - - def add_ovs_interface(self, ovs_interface): - """Add a OvsDpdkPort object to the net config object. - - :param ovs_dpdk_port: The OvsDpdkPort object to add. - """ - logger.info('adding ovs dpdk port: %s' % ovs_interface.name) - data = self._add_common(ovs_interface) - data[Interface.TYPE] = OVSInterface.TYPE - data[Interface.STATE] = InterfaceState.UP - logger.debug(f'add ovs_interface data: {data}') - self.interface_data[ovs_interface.name] = data - - def add_ovs_dpdk_port(self, ovs_dpdk_port): - """Add a OvsDpdkPort object to the net config object. - - :param ovs_dpdk_port: The OvsDpdkPort object to add. - """ - logger.info('adding ovs dpdk port: %s' % ovs_dpdk_port.name) - - # DPDK Port will have only one member of type Interface, validation - # checks are added at the object creation stage. - ifname = ovs_dpdk_port.members[0].name - - # Bind the dpdk interface - utils.bind_dpdk_interfaces(ifname, ovs_dpdk_port.driver, self.noop) - data = self._add_common(ovs_dpdk_port) - data[Interface.TYPE] = OVSInterface.TYPE - data[Interface.STATE] = InterfaceState.UP - - pci_address = utils.get_dpdk_devargs(ifname, noop=False) - - data[OVSInterface.DPDK_CONFIG_SUBTREE - ] = {OVSInterface.Dpdk.DEVARGS: pci_address} - if ovs_dpdk_port.rx_queue: - data[OVSInterface.DPDK_CONFIG_SUBTREE - ][OVSInterface.Dpdk.RX_QUEUE] = ovs_dpdk_port.rx_queue - if ovs_dpdk_port.rx_queue_size: - data[OVSInterface.DPDK_CONFIG_SUBTREE - ][OVSInterface.Dpdk.N_RXQ_DESC] = ovs_dpdk_port.rx_queue_size - if ovs_dpdk_port.tx_queue_size: - data[OVSInterface.DPDK_CONFIG_SUBTREE - ][OVSInterface.Dpdk.N_TXQ_DESC] = ovs_dpdk_port.tx_queue_size - data[OvsDB.KEY] = {OvsDB.EXTERNAL_IDS: {}, - OvsDB.OTHER_CONFIG: {}} - if ovs_dpdk_port.ovs_extra: - logger.info(f"Parsing ovs_extra : {ovs_dpdk_port.ovs_extra}") - self.parse_ovs_extra(ovs_dpdk_port.ovs_extra, - ovs_dpdk_port.name, data) - - logger.debug(f'ovs dpdk port data: {data}') - self.interface_data[ovs_dpdk_port.name] = data - - def add_linux_bridge(self, bridge): - """Add a LinuxBridge object to the net config object. - - :param bridge: The LinuxBridge object to add. - """ - logger.info(f'adding linux bridge: {bridge.name}') - data = self._add_common(bridge) - logger.debug('bridge data: %s' % data) - self.linuxbridge_data[bridge.name] = data - - def add_bond(self, bond): - """Add an OvsBond object to the net config object. - - :param bond: The OvsBond object to add. - """ - # The ovs bond is already added in add_bridge()x - logger.info('adding bond: %s' % bond.name) - return - - def add_ovs_dpdk_bond(self, bond): - """Add an OvsDpdkBond object to the net config object. - - :param bond: The OvsBond object to add. - """ - logger.info('adding Ovs DPDK Bond: %s' % bond.name) - for member in bond.members: - if bond.mtu: - member.mtu = bond.mtu - if bond.rx_queue: - member.rx_queue = bond.rx_queue - self.add_ovs_dpdk_port(member) - return - - def add_linux_bond(self, bond): - """Add a LinuxBond object to the net config object. - - :param bond: The LinuxBond object to add. - """ - logger.info('adding linux bond: %s' % bond.name) - data = self._add_common(bond) - - data[Interface.TYPE] = InterfaceType.BOND - data[Interface.STATE] = InterfaceState.UP - - bond_options = {} - if bond.bonding_options: - bond_options = parse_bonding_options(bond.bonding_options) - - bond_data = set_linux_bonding_options( - bond_options, primary_iface=bond.primary_interface_name) - if bond_data: - data[Bond.CONFIG_SUBTREE] = bond_data - - if bond.members: - members = [member.name for member in bond.members] - self.member_names[bond.name] = members - data[Bond.CONFIG_SUBTREE][Bond.PORT] = members - - logger.debug('bond data: %s' % data) - self.linuxbond_data[bond.name] = data - - def add_sriov_pf(self, sriov_pf): - """Add a SriovPF object to the net config object - - :param sriov_pf: The SriovPF object to add - """ - logger.info(f'adding sriov pf: {sriov_pf.name}') - data = self._add_common(sriov_pf) - data[Interface.TYPE] = InterfaceType.ETHERNET - data[Ethernet.CONFIG_SUBTREE] = {} - data[Ethernet.CONFIG_SUBTREE][Ethernet.SRIOV_SUBTREE] = { - Ethernet.SRIOV.TOTAL_VFS: sriov_pf.numvfs} - - if sriov_pf.promisc: - data[Interface.ACCEPT_ALL_MAC_ADDRESSES] = True - if sriov_pf.link_mode == 'switchdev': - data[Ethtool.CONFIG_SUBTREE] = {} - data[Ethtool.CONFIG_SUBTREE][Ethtool.Feature.CONFIG_SUBTREE] = { - 'hw-tc-offload': True} - if sriov_pf.promisc: - data[Interface.ACCEPT_ALL_MAC_ADDRESSES] = True - - if sriov_pf.ethtool_opts: - self.add_ethtool_config(sriov_pf.name, data, - sriov_pf.ethtool_opts) - - logger.debug('sriov pf data: %s' % data) - self.sriov_vf_data[sriov_pf.name] = [None] * sriov_pf.numvfs - self.interface_data[sriov_pf.name] = data - self.sriov_pf_data[sriov_pf.name] = data - - def add_sriov_vf(self, sriov_vf): - """Add a SriovVF object to the net config object - - :param sriov_vf: The SriovVF object to add - """ - logger.info('adding sriov vf: %s for pf: %s, vfid: %d' - % (sriov_vf.name, sriov_vf.device, sriov_vf.vfid)) - data = self._add_common(sriov_vf) - data[Interface.TYPE] = InterfaceType.ETHERNET - data[Ethernet.CONFIG_SUBTREE] = {} - if sriov_vf.promisc: - data[Interface.ACCEPT_ALL_MAC_ADDRESSES] = True - logger.debug('sriov vf data: %s' % data) - self.interface_data[sriov_vf.name] = data - vf_config = self.get_vf_config(sriov_vf) - logger.debug("Adding vf config %s" % vf_config) - - # sriov_vf_data is a list of vf configuration data of size numvfs. - # The vfid is used as index. - if sriov_vf.device not in self.sriov_vf_data: - msg = f"VF configuration is seen while the parent device"\ - f" {sriov_vf.device} is not availavle" - raise os_net_config.ConfigurationError(msg) - - self.sriov_vf_data[sriov_vf.device][sriov_vf.vfid] = vf_config - if sriov_vf.ethtool_opts: - self.add_ethtool_config(sriov_vf.name, data, - sriov_vf.ethtool_opts) - - def add_ib_interface(self, ib_interface): - """Add an InfiniBand interface object to the net config object. - - :param ib_interface: The InfiniBand interface object to add. - """ - logger.info('adding ib_interface: %s' % ib_interface.name) - data = self._add_common(ib_interface) - logger.debug('ib_interface data: %s' % data) - data[Interface.TYPE] = InterfaceType.INFINIBAND - if ib_interface.ethtool_opts: - self.add_ethtool_config(ib_interface.name, data, - ib_interface.ethtool_opts) - # Default mode is set to 'datagram' since 'connected' is not - # supported in some devices - config = {} - config[InfiniBand.MODE] = InfiniBand.Mode.DATAGRAM - data[InfiniBand.CONFIG_SUBTREE] = config - self.interface_data[ib_interface.name] = data - - def add_ib_child_interface(self, ib_child_interface): - """Add an InfiniBand child interface object to the net config object. - - :param ib_child_interface: The InfiniBand child - interface object to add. - """ - logger.info('adding ib_child_interface: %s' % ib_child_interface.name) - data = self._add_common(ib_child_interface) - logger.debug('ib_child_interface data: %s' % data) - data[Interface.TYPE] = InterfaceType.INFINIBAND - config = {} - config[InfiniBand.PKEY] = ib_child_interface.pkey_id - config[InfiniBand.BASE_IFACE] = ib_child_interface.parent - # Default mode is set to 'datagram' since 'connected' is not - # supported in some devices - config[InfiniBand.MODE] = InfiniBand.Mode.DATAGRAM - data[InfiniBand.CONFIG_SUBTREE] = config - self.interface_data[ib_child_interface.name] = data - - def apply(self, cleanup=False, activate=True): - """Apply the network configuration. - - :param cleanup: A boolean which indicates whether any undefined - (existing but not present in the object model) interface - should be disabled and deleted. - :param activate: A boolean which indicates if the config should - be activated by stopping/starting interfaces - NOTE: if cleanup is specified we will deactivate interfaces even - if activate is false - :returns: a dict of the format: filename/data which contains info - for each file that was changed (or would be changed if in --noop - mode). - Note the noop mode is set via the constructor noop boolean - """ - logger.info('applying network configs...') - if cleanup: - logger.info('Cleaning up all network configs...') - self.cleanup_all_ifaces() - - apply_routes = [] - updated_interfaces = {} - logger.debug("----------------------------") - vf_config = self.prepare_sriov_vf_config() - apply_data = {} - apply_data.update(self.set_ifaces(vf_config)) - - for interface_name, iface_data in self.interface_data.items(): - iface_state = self.iface_state(interface_name) - if not is_dict_subset(iface_state, iface_data): - updated_interfaces[interface_name] = iface_data - else: - logger.info('No changes required for interface: ' - f'{interface_name}') - routes_data = self.generate_routes(interface_name) - logger.info(f'Routes_data {routes_data}') - apply_routes.extend(routes_data) - - for bridge_name, bridge_data in self.bridge_data.items(): - - bridge_state = self.iface_state(bridge_name) - if not is_dict_subset(bridge_state, bridge_data): - updated_interfaces[bridge_name] = bridge_data - else: - logger.info('No changes required for bridge: %s' % - bridge_name) - - routes_data = self.generate_routes(bridge_name) - logger.info(f'Routes_data {routes_data}') - apply_routes.extend(routes_data) - - for bond_name, bond_data in self.linuxbond_data.items(): - bond_state = self.iface_state(bond_name) - if not is_dict_subset(bond_state, bond_data): - updated_interfaces[bond_name] = bond_data - else: - logger.info('No changes required for bond: %s' % - bond_name) - routes_data = self.generate_routes(bond_name) - logger.info('Routes_data %s' % routes_data) - apply_routes.extend(routes_data) - - for vlan_name, vlan_data in self.vlan_data.items(): - vlan_state = self.iface_state(vlan_name) - if not is_dict_subset(vlan_state, vlan_data): - updated_interfaces[vlan_name] = vlan_data - else: - logger.info('No changes required for vlan interface: %s' % - vlan_name) - routes_data = self.generate_routes(vlan_name) - logger.info('Routes_data %s' % routes_data) - apply_routes.extend(routes_data) - - apply_data.update(self.set_ifaces(list(updated_interfaces.values()))) - apply_data.update(self.set_routes(apply_routes)) - - rules_data = self.generate_rules() - logger.info(f'Rules_data {rules_data}') - - apply_data.update(self.set_rules(rules_data)) - - apply_data.update(self.set_dns()) - - if activate: - if not self.noop: - self.nmstate_apply(apply_data, verify=True) - - if self.errors: - message = 'Failure(s) occurred when applying configuration' - logger.error(message) - for e in self.errors: - logger.error(str(e)) - raise os_net_config.ConfigurationError(message) - - self.interface_data = {} - self.bridge_data = {} - self.linuxbond_data = {} - self.vlan_data = {} - - return updated_interfaces diff --git a/os_net_config/objects.py b/os_net_config/objects.py deleted file mode 100644 index 7c1f8e41..00000000 --- a/os_net_config/objects.py +++ /dev/null @@ -1,1966 +0,0 @@ -# -*- 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. - -# -# NOTE: When making changes to the object model, remember to also update -# schema.yaml to reflect changes to the schema of config files! -# - -import logging -import netaddr -from oslo_utils import strutils - -from os_net_config import common -from os_net_config import utils - - -logger = logging.getLogger(__name__) - -_MAPPED_NICS = None -STANDALONE_FAIL_MODE = 'standalone' -DEFAULT_OVS_BRIDGE_FAIL_MODE = STANDALONE_FAIL_MODE - - -class InvalidConfigException(ValueError): - pass - - -def object_from_json(json): - obj_type = json.get("type") - if obj_type == "route_table": - return RouteTable.from_json(json) - if obj_type == "route_rule": - return RouteRule.from_json(json) - if obj_type == "interface": - return Interface.from_json(json) - elif obj_type == "vlan": - return Vlan.from_json(json) - elif obj_type == "ovs_bridge": - return OvsBridge.from_json(json) - elif obj_type == "ovs_user_bridge": - return OvsUserBridge.from_json(json) - elif obj_type == "ovs_bond": - return OvsBond.from_json(json) - elif obj_type == "ovs_interface": - return OvsInterface.from_json(json) - elif obj_type == "linux_bond": - return LinuxBond.from_json(json) - elif obj_type == "team": - return LinuxTeam.from_json(json) - elif obj_type == "linux_bridge": - return LinuxBridge.from_json(json) - elif obj_type == "ivs_bridge": - return IvsBridge.from_json(json) - elif obj_type == "ivs_interface": - return IvsInterface.from_json(json) - elif obj_type == "nfvswitch_bridge": - return NfvswitchBridge.from_json(json) - elif obj_type == "nfvswitch_internal": - return NfvswitchInternal.from_json(json) - elif obj_type == "ovs_tunnel": - return OvsTunnel.from_json(json) - elif obj_type == "ovs_patch_port": - return OvsPatchPort.from_json(json) - elif obj_type == "ib_interface": - return IbInterface.from_json(json) - elif obj_type == "ib_child_interface": - return IbChildInterface.from_json(json) - elif obj_type == "ovs_dpdk_port": - return OvsDpdkPort.from_json(json) - elif obj_type == "ovs_dpdk_bond": - return OvsDpdkBond.from_json(json) - elif obj_type == "vpp_interface": - return VppInterface.from_json(json) - elif obj_type == "vpp_bond": - return VppBond.from_json(json) - elif obj_type == "contrail_vrouter": - return ContrailVrouter.from_json(json) - elif obj_type == "contrail_vrouter_dpdk": - return ContrailVrouterDpdk.from_json(json) - elif obj_type == "sriov_pf": - return SriovPF.from_json(json) - elif obj_type == "sriov_vf": - return SriovVF.from_json(json) - elif obj_type == "linux_tap": - return LinuxTap.from_json(json) - - -def _get_required_field(json, name, object_name, datatype=None): - field = json.get(name) - if not datatype: - if field is None: - msg = '%s JSON objects require \'%s\' to be configured.' \ - % (object_name, name) - raise InvalidConfigException(msg) - elif not isinstance(field, datatype): - msg = '%s JSON objects require \'%s\' to be configured as %s'\ - % (object_name, name, str(datatype)) - raise InvalidConfigException(msg) - return field - - -def _update_members(json, nic_mapping, persist_mapping): - """Update object's members fields and pass mapping info to each member. - - :param json: dictionary containing object values - :param nic_mapping: mapping of abstractions to actual nic names - :param persist_mapping: bool indicating mapping file should be permanent - :returns members: updated members - """ - members = [] - - members_json = json.get('members') - if members_json: - if isinstance(members_json, list): - for member in members_json: - # If this member already has a nic mapping, don't overwrite it - if not member.get('nic_mapping'): - member.update({'nic_mapping': nic_mapping}) - member.update({'persist_mapping': persist_mapping}) - members.append(object_from_json(member)) - else: - msg = 'Members must be a list.' - raise InvalidConfigException(msg) - - return members - - -def mapped_nics(nic_mapping=None): - mapping = nic_mapping or {} - global _MAPPED_NICS - if _MAPPED_NICS: - return _MAPPED_NICS - _MAPPED_NICS = {} - - if mapping: - # If mapping file provided, nics need not be active - available_nics = utils.ordered_available_nics() - for nic_alias, nic_mapped in mapping.items(): - - if netaddr.valid_mac(nic_mapped): - # If 'nic' is actually a mac address, retrieve actual nic name - for nic in available_nics: - try: - mac = common.interface_mac(nic) - except IOError: - continue - if nic_mapped == mac: - logger.debug("%s matches device %s" % - (nic_mapped, nic)) - nic_mapped = nic - break - else: - # The mac could not be found on this system - logger.error('mac %s not found in available nics (%s)' - % (nic_mapped, ', '.join(available_nics))) - continue - - elif nic_mapped not in available_nics: - # nic doesn't exist on this system - logger.error('nic %s not found in available nics (%s)' - % (nic_mapped, ', '.join(available_nics))) - continue - - # Duplicate mappings are not allowed - if nic_mapped in _MAPPED_NICS.values(): - msg = ('interface %s already mapped, ' - 'check mapping file for duplicates' - % nic_mapped) - raise InvalidConfigException(msg) - - # Using a mapping name that overlaps with a real NIC is not allowed - # (However using the name of an inactive NIC as an alias is - # permitted). - if utils.is_active_nic(nic_alias): - msg = ('cannot map %s to alias %s, alias overlaps with active ' - 'NIC.' % (nic_mapped, nic_alias)) - raise InvalidConfigException(msg) - elif utils.is_real_nic(nic_alias): - logger.warning("Mapped nic %s overlaps with name of inactive " - "NIC." % (nic_alias)) - - _MAPPED_NICS[nic_alias] = nic_mapped - logger.info("%s in mapping file mapped to: %s" - % (nic_alias, nic_mapped)) - - # nics not in mapping file must be active in order to be mapped - active_nics = utils.ordered_active_nics() - - # Add default numbered mappings, but do not overwrite existing entries - for nic_mapped in set(active_nics).difference(set(_MAPPED_NICS.values())): - nic_alias = "nic%i" % (active_nics.index(nic_mapped) + 1) - if nic_alias in _MAPPED_NICS: - logger.warning("no mapping for interface %s because " - "%s is mapped to %s" - % (nic_mapped, nic_alias, _MAPPED_NICS[nic_alias])) - else: - _MAPPED_NICS[nic_alias] = nic_mapped - logger.info("%s mapped to: %s" % (nic_alias, nic_mapped)) - - if not _MAPPED_NICS: - logger.warning('No active nics found.') - return _MAPPED_NICS - - -def format_ovs_extra(obj, templates): - """Map OVS object properties into a string to be used for ovs_extra.""" - - return [t.format(name=obj.name) for t in templates or []] - - -def _add_fail_mode(fail_mode): - ovs_extra = ['set bridge {name} fail_mode=%s' % fail_mode] - if fail_mode == STANDALONE_FAIL_MODE: - ovs_extra.append('del-controller {name}') - return ovs_extra - - -def check_ovs_installed(name): - if not utils.is_ovs_installed(): - msg = '%s cannot be created as OpenvSwitch is not installed.' % name - raise InvalidConfigException(msg) - - -class Route(object): - """Base class for network routes.""" - - def __init__(self, next_hop, ip_netmask="", default=False, - route_options="", route_table=None, metric=None): - self.next_hop = next_hop - self.ip_netmask = ip_netmask - self.default = default - self.route_options = route_options - self.route_table = route_table - self.metric = metric - - @staticmethod - def from_json(json): - if json.get('next_hop') and json.get('nexthop'): - msg = ('Invalid Route JSON object with both next_hop and nexthop ' - 'configured. Use either next_hop or nexthop.') - raise InvalidConfigException(msg) - - if json.get('ip_netmask') and json.get('destination'): - msg = ('Invalid Route JSON object with both ip_netmask and ' - 'destination configured. Use either ip_netmask or ' - 'destination.') - raise InvalidConfigException(msg) - - next_hop = json.get('next_hop', json.get('nexthop')) - if next_hop is None: - msg = ('Route JSON objects require next_hop or nexthop to be ' - 'configured.') - raise InvalidConfigException(msg) - ip_netmask = json.get('ip_netmask', json.get('destination', "")) - route_options = json.get('route_options', "") - default = strutils.bool_from_string(str(json.get('default', False))) - route_options = json.get('route_options', "") - route_table = json.get('table', "") - metric = json.get('metric', "") - return Route(next_hop, ip_netmask, default, - route_options, route_table, metric) - - -class Address(object): - """Base class for network addresses.""" - - def __init__(self, ip_netmask): - self.ip_netmask = ip_netmask - ip_nw = netaddr.IPNetwork(self.ip_netmask) - self.ip = str(ip_nw.ip) - self.netmask = str(ip_nw.netmask) - self.prefixlen = ip_nw.prefixlen - self.version = ip_nw.version - - @staticmethod - def from_json(json): - ip_netmask = _get_required_field(json, 'ip_netmask', 'Address') - return Address(ip_netmask) - - -class RouteRule(object): - """Base class for route rules.""" - - def __init__(self, rule, comment=""): - self.rule = rule - self.comment = comment - - @staticmethod - def from_json(json): - rule = _get_required_field(json, 'rule', 'RouteRule') - comment = json.get('comment', "") - return RouteRule(rule, comment) - - -class RouteTable(object): - """Base class for route tables for policy-based routing.""" - - def __init__(self, name, table_id): - self.name = name - self.table_id = table_id - - @staticmethod - def from_json(json): - name = _get_required_field(json, 'name', 'RouteTable') - table_id = _get_required_field(json, 'table_id', 'RouteTable') - reserved_ids = [0, 253, 254, 255] - reserved_names = ['unspec', 'default', 'main', 'local'] - if table_id in reserved_ids: - msg = 'Route table "%s" conflicts with reserved table "%s %s"'\ - % (table_id, table_id, - reserved_names[reserved_ids.index(table_id)]) - raise InvalidConfigException(msg) - elif name in reserved_names: - msg = 'Route table "%s" conflicts with reserved table "%s %s"'\ - % (name, reserved_ids[reserved_names.index(name)], name) - raise InvalidConfigException(msg) - return RouteTable(name, table_id) - - -class _BaseOpts(object): - """Base abstraction for logical port options.""" - - def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None, - routes=None, rules=None, mtu=None, primary=False, - nic_mapping=None, persist_mapping=False, defroute=True, - dhclient_args=None, dns_servers=None, nm_controlled=False, - onboot=True, domain=None): - addresses = addresses or [] - routes = routes or [] - rules = rules or [] - dns_servers = dns_servers or [] - mapped_nic_names = mapped_nics(nic_mapping) - self.hwaddr = None - self.hwname = None - self.renamed = False - # Split name to support . format, e.g. em1.10 or nic1.10 - if len(name.split('.')) > 1 and name.split('.')[1].isdigit(): - base_name = name.split('.')[0] - vlan_suffix = '.%s' % name.split('.')[1] - else: - base_name = name - vlan_suffix = '' - if base_name in mapped_nic_names: - if persist_mapping: - self.name = name - self.hwname = '%s%s' % (mapped_nic_names[base_name], - vlan_suffix) - self.hwaddr = common.interface_mac(self.hwname) - self.renamed = True - else: - self.name = '%s%s' % (mapped_nic_names[base_name], vlan_suffix) - else: - self.name = name - - self.mtu = mtu - self.use_dhcp = use_dhcp - self.use_dhcpv6 = use_dhcpv6 - self.addresses = addresses - self.routes = routes - self.rules = rules - self.primary = primary - self.defroute = defroute - self.dhclient_args = dhclient_args - self.dns_servers = dns_servers - self.domain = domain - self.nm_controlled = nm_controlled - self.onboot = onboot - self.bridge_name = None # internal - self.linux_bridge_name = None # internal - self.ivs_bridge_name = None # internal - self.nfvswitch_bridge_name = None # internal - self.linux_bond_name = None # internal - self.linux_team_name = None # internal - self.ovs_port = False # internal - self.primary_interface_name = None # internal - - def v4_addresses(self): - v4_addresses = [] - for addr in self.addresses: - if addr.version == 4: - v4_addresses.append(addr) - - return v4_addresses - - def v6_addresses(self): - v6_addresses = [] - for addr in self.addresses: - if addr.version == 6: - v6_addresses.append(addr) - - return v6_addresses - - @staticmethod - def base_opts_from_json(json, include_primary=True): - use_dhcp = strutils.bool_from_string(str(json.get('use_dhcp', False))) - use_dhcpv6 = strutils.bool_from_string(str(json.get('use_dhcpv6', - False))) - defroute = strutils.bool_from_string(str(json.get('defroute', - True))) - mtu = json.get('mtu', None) - dhclient_args = json.get('dhclient_args') - dns_servers = json.get('dns_servers') - domain = json.get('domain') - nm_controlled = strutils.bool_from_string(str(json.get('nm_controlled', - False))) - onboot = strutils.bool_from_string(str(json.get('onboot', - True))) - primary = strutils.bool_from_string(str(json.get('primary', False))) - addresses = [] - routes = [] - rules = [] - - # addresses - addresses_json = json.get('addresses') - if addresses_json: - if isinstance(addresses_json, list): - for address in addresses_json: - addresses.append(Address.from_json(address)) - else: - msg = 'Addresses must be a list.' - raise InvalidConfigException(msg) - - # routes - routes_json = json.get('routes') - if routes_json: - if isinstance(routes_json, list): - for route in routes_json: - routes.append(Route.from_json(route)) - else: - msg = 'Routes must be a list.' - raise InvalidConfigException(msg) - - # rules - rules_json = json.get('rules') - if rules_json: - if isinstance(rules_json, list): - for rule in rules_json: - rules.append(RouteRule.from_json(rule)) - else: - msg = 'Routes must be a list.' - raise InvalidConfigException(msg) - - nic_mapping = json.get('nic_mapping') - persist_mapping = json.get('persist_mapping') - - if include_primary: - return (use_dhcp, use_dhcpv6, addresses, routes, rules, mtu, - primary, nic_mapping, persist_mapping, defroute, - dhclient_args, dns_servers, nm_controlled, onboot, domain) - else: - return (use_dhcp, use_dhcpv6, addresses, routes, rules, mtu, - nic_mapping, persist_mapping, defroute, dhclient_args, - dns_servers, nm_controlled, onboot, domain) - - -class Interface(_BaseOpts): - """Base class for network interfaces.""" - - def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None, - routes=None, rules=None, mtu=None, primary=False, - nic_mapping=None, persist_mapping=False, defroute=True, - dhclient_args=None, dns_servers=None, nm_controlled=False, - onboot=True, domain=None, ethtool_opts=None, hotplug=False, - linkdelay=None): - addresses = addresses or [] - routes = routes or [] - rules = rules or [] - dns_servers = dns_servers or [] - super(Interface, self).__init__(name, use_dhcp, use_dhcpv6, addresses, - routes, rules, mtu, primary, - nic_mapping, persist_mapping, defroute, - dhclient_args, dns_servers, - nm_controlled, onboot, domain) - self.ethtool_opts = ethtool_opts - self.hotplug = hotplug - self.linkdelay = linkdelay - - @staticmethod - def from_json(json): - name = _get_required_field(json, 'name', 'Interface') - hotplug = strutils.bool_from_string(str(json.get('hotplug', False))) - opts = _BaseOpts.base_opts_from_json(json) - ethtool_opts = json.get('ethtool_opts', None) - linkdelay = json.get('linkdelay', None) - return Interface(name, *opts, ethtool_opts=ethtool_opts, - hotplug=hotplug, linkdelay=linkdelay) - - -class Vlan(_BaseOpts): - """Base class for VLANs. - - NOTE: the name parameter must be formated w/ vlan where - matches the vlan ID being used. Example: vlan5 - """ - - def __init__(self, device, vlan_id, use_dhcp=False, use_dhcpv6=False, - addresses=None, routes=None, rules=None, mtu=None, - primary=False, nic_mapping=None, persist_mapping=False, - defroute=True, dhclient_args=None, dns_servers=None, - nm_controlled=False, onboot=True, domain=None, - ovs_options=None, ovs_extra=None): - addresses = addresses or [] - routes = routes or [] - rules = rules or [] - dns_servers = dns_servers or [] - name = 'vlan%i' % vlan_id - super(Vlan, self).__init__(name, use_dhcp, use_dhcpv6, addresses, - routes, rules, mtu, primary, nic_mapping, - persist_mapping, defroute, dhclient_args, - dns_servers, nm_controlled, onboot, domain) - self.vlan_id = int(vlan_id) - self.ovs_options = ovs_options - ovs_extra = ovs_extra or [] - self.ovs_extra = format_ovs_extra(self, ovs_extra) - mapped_nic_names = mapped_nics(nic_mapping) - if device in mapped_nic_names: - self.device = mapped_nic_names[device] - else: - self.device = device - - @staticmethod - def from_json(json): - # A vlan on an OVS bridge won't require a device (OVS Int Port) - device = json.get('device') - vlan_id = _get_required_field(json, 'vlan_id', 'Vlan') - opts = _BaseOpts.base_opts_from_json(json) - ovs_options = json.get('ovs_options') - ovs_extra = json.get('ovs_extra', []) - if not isinstance(ovs_extra, list): - ovs_extra = [ovs_extra] - return Vlan(device, vlan_id, *opts, ovs_options=ovs_options, - ovs_extra=ovs_extra) - - -class IvsInterface(_BaseOpts): - """Base class for ivs interfaces.""" - - def __init__(self, vlan_id, name='ivs', use_dhcp=False, use_dhcpv6=False, - addresses=None, routes=None, rules=None, mtu=1500, - primary=False, nic_mapping=None, persist_mapping=False, - defroute=True, dhclient_args=None, dns_servers=None, - nm_controlled=False, onboot=True, domain=None): - addresses = addresses or [] - routes = routes or [] - rules = rules or [] - dns_servers = dns_servers or [] - name_vlan = '%s%i' % (name, vlan_id) - super(IvsInterface, self).__init__(name_vlan, use_dhcp, use_dhcpv6, - addresses, routes, rules, mtu, - primary, nic_mapping, - persist_mapping, defroute, - dhclient_args, dns_servers, - nm_controlled, onboot, domain) - self.vlan_id = int(vlan_id) - - @staticmethod - def from_json(json): - name = json.get('name') - vlan_id = _get_required_field(json, 'vlan_id', 'IvsInterface') - opts = _BaseOpts.base_opts_from_json(json) - return IvsInterface(vlan_id, name, *opts) - - -class OvsInterface(_BaseOpts): - """Base class for ovs interfaces. - - Nmstate requires an OvS interafce to be attached to the bridge where - the settings like MTU, IP address could be applied. This interface is - created internaly to accomodate the same. Also ovs_extra / ovs_options - support is also added along with - """ - - def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None, - routes=None, rules=None, mtu=None, primary=False, - nic_mapping=None, persist_mapping=False, defroute=True, - dhclient_args=None, dns_servers=None, nm_controlled=False, - onboot=True, domain=None): - addresses = addresses or [] - routes = routes or [] - rules = rules or [] - dns_servers = dns_servers or [] - super(OvsInterface, self).__init__( - name, use_dhcp, use_dhcpv6, addresses, - routes, rules, mtu, primary, - nic_mapping, persist_mapping, defroute, - dhclient_args, dns_servers, - nm_controlled, onboot, domain) - - @staticmethod - def from_json(json): - name = _get_required_field(json, 'name', 'OvsInterface') - opts = _BaseOpts.base_opts_from_json(json) - return OvsInterface(name, *opts) - - -class NfvswitchInternal(_BaseOpts): - """Base class for nfvswitch internal interfaces.""" - - def __init__(self, vlan_id, name='nfvswitch', use_dhcp=False, - use_dhcpv6=False, addresses=None, routes=None, rules=None, - mtu=1500, primary=False, nic_mapping=None, - persist_mapping=False, defroute=True, dhclient_args=None, - dns_servers=None, nm_controlled=False, onboot=True, - domain=None): - addresses = addresses or [] - routes = routes or [] - rules = rules or [] - dns_servers = dns_servers or [] - name_vlan = '%s%i' % (name, vlan_id) - super(NfvswitchInternal, self).__init__(name_vlan, use_dhcp, - use_dhcpv6, addresses, routes, - rules, mtu, primary, - nic_mapping, persist_mapping, - defroute, dhclient_args, - dns_servers, nm_controlled, - onboot, domain) - self.vlan_id = int(vlan_id) - - @staticmethod - def from_json(json): - name = json.get('name') - vlan_id = _get_required_field(json, 'vlan_id', 'NfvswitchInternal') - opts = _BaseOpts.base_opts_from_json(json) - return NfvswitchInternal(vlan_id, name, *opts) - - -class OvsBridge(_BaseOpts): - """Base class for OVS bridges.""" - - def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None, - routes=None, rules=None, mtu=None, members=None, - ovs_options=None, ovs_extra=None, nic_mapping=None, - persist_mapping=False, defroute=True, dhclient_args=None, - dns_servers=None, nm_controlled=False, onboot=True, - domain=None, fail_mode=None): - - check_ovs_installed(self.__class__.__name__) - - addresses = addresses or [] - routes = routes or [] - rules = rules or [] - members = members or [] - dns_servers = dns_servers or [] - super(OvsBridge, self).__init__(name, use_dhcp, use_dhcpv6, addresses, - routes, rules, mtu, False, nic_mapping, - persist_mapping, defroute, - dhclient_args, dns_servers, - nm_controlled, onboot, domain) - self.members = members - self.ovs_options = ovs_options - ovs_extra = ovs_extra or [] - if fail_mode: - ovs_extra.extend(_add_fail_mode(fail_mode)) - self.ovs_extra = format_ovs_extra(self, ovs_extra) - for member in self.members: - member.bridge_name = name - if isinstance(member, SriovVF): - OvsBridge.update_vf_config(member) - if not isinstance(member, OvsTunnel): - member.ovs_port = True - if member.primary: - if self.primary_interface_name: - msg = 'Only one primary interface allowed per bridge.' - raise InvalidConfigException(msg) - if member.primary_interface_name: - self.primary_interface_name = member.primary_interface_name - else: - self.primary_interface_name = member.name - - @staticmethod - def update_vf_config(iface): - if iface.trust is None: - logger.info("Trust is not set for VF %s:%d, defaulting to on" - % (iface.device, iface.vfid)) - iface.trust = "on" - if iface.spoofcheck is None: - logger.info("Spoofcheck is not set for VF %s:%d, defaulting to off" - % (iface.device, iface.vfid)) - iface.spoofcheck = "off" - if iface.promisc is None: - logger.info("Promisc is not set for VF %s:%d, defaulting to on" - % (iface.device, iface.vfid)) - iface.promisc = "on" - utils.update_sriov_vf_map(iface.device, iface.vfid, iface.name, - vlan_id=iface.vlan_id, qos=iface.qos, - spoofcheck=iface.spoofcheck, - trust=iface.trust, state=iface.state, - macaddr=iface.macaddr, promisc=iface.promisc, - pci_address=iface.pci_address, - min_tx_rate=iface.min_tx_rate, - max_tx_rate=iface.max_tx_rate) - - @staticmethod - def from_json(json): - name = _get_required_field(json, 'name', 'OvsBridge') - (use_dhcp, use_dhcpv6, addresses, routes, rules, mtu, nic_mapping, - persist_mapping, defroute, dhclient_args, dns_servers, - nm_controlled, onboot, domain) = _BaseOpts.base_opts_from_json( - json, include_primary=False) - ovs_options = json.get('ovs_options') - ovs_extra = json.get('ovs_extra', []) - if not isinstance(ovs_extra, list): - ovs_extra = [ovs_extra] - fail_mode = json.get('ovs_fail_mode', DEFAULT_OVS_BRIDGE_FAIL_MODE) - - members = _update_members(json, nic_mapping, persist_mapping) - - return OvsBridge(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6, - addresses=addresses, routes=routes, rules=rules, - mtu=mtu, members=members, ovs_options=ovs_options, - ovs_extra=ovs_extra, nic_mapping=nic_mapping, - persist_mapping=persist_mapping, defroute=defroute, - dhclient_args=dhclient_args, dns_servers=dns_servers, - nm_controlled=nm_controlled, onboot=onboot, - domain=domain, fail_mode=fail_mode) - - -class OvsUserBridge(_BaseOpts): - """Base class for OVS User bridges.""" - - def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None, - routes=None, rules=None, mtu=None, members=None, - ovs_options=None, ovs_extra=None, nic_mapping=None, - persist_mapping=False, defroute=True, dhclient_args=None, - dns_servers=None, nm_controlled=False, onboot=True, - domain=None, fail_mode=None): - - check_ovs_installed(self.__class__.__name__) - - super(OvsUserBridge, self).__init__(name, use_dhcp, use_dhcpv6, - addresses, routes, rules, mtu, - False, nic_mapping, - persist_mapping, defroute, - dhclient_args, dns_servers, - nm_controlled, onboot, domain) - self.members = members or [] - self.ovs_options = ovs_options - ovs_extra = ovs_extra or [] - if fail_mode: - ovs_extra.extend(_add_fail_mode(fail_mode)) - self.ovs_extra = format_ovs_extra(self, ovs_extra) - for member in self.members: - member.bridge_name = name - if not isinstance(member, OvsTunnel) and \ - not isinstance(member, OvsDpdkPort) and \ - not isinstance(member, OvsDpdkBond): - member.ovs_port = True - if member.primary: - if self.primary_interface_name: - msg = 'Only one primary interface allowed per bridge.' - raise InvalidConfigException(msg) - if member.primary_interface_name: - self.primary_interface_name = member.primary_interface_name - else: - self.primary_interface_name = member.name - - @staticmethod - def from_json(json): - name = _get_required_field(json, 'name', 'OvsUserBridge') - (use_dhcp, use_dhcpv6, addresses, routes, rules, mtu, nic_mapping, - persist_mapping, defroute, dhclient_args, dns_servers, - nm_controlled, onboot, domain) = _BaseOpts.base_opts_from_json( - json, include_primary=False) - ovs_options = json.get('ovs_options') - ovs_extra = json.get('ovs_extra', []) - if not isinstance(ovs_extra, list): - ovs_extra = [ovs_extra] - fail_mode = json.get('ovs_fail_mode', DEFAULT_OVS_BRIDGE_FAIL_MODE) - - members = _update_members(json, nic_mapping, persist_mapping) - - return OvsUserBridge(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6, - addresses=addresses, routes=routes, rules=rules, - mtu=mtu, members=members, ovs_options=ovs_options, - ovs_extra=ovs_extra, nic_mapping=nic_mapping, - persist_mapping=persist_mapping, - defroute=defroute, dhclient_args=dhclient_args, - dns_servers=dns_servers, - nm_controlled=nm_controlled, onboot=onboot, - domain=domain, fail_mode=fail_mode) - - -class LinuxBridge(_BaseOpts): - """Base class for Linux bridges.""" - - def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None, - routes=None, rules=None, mtu=None, members=None, - nic_mapping=None, persist_mapping=False, defroute=True, - dhclient_args=None, dns_servers=None, nm_controlled=False, - onboot=True, domain=None): - addresses = addresses or [] - routes = routes or [] - rules = rules or [] - members = members or [] - dns_servers = dns_servers or [] - super(LinuxBridge, self).__init__(name, use_dhcp, use_dhcpv6, - addresses, routes, rules, mtu, False, - nic_mapping, persist_mapping, - defroute, dhclient_args, dns_servers, - nm_controlled, onboot, domain) - self.members = members - for member in self.members: - member.linux_bridge_name = name - member.ovs_port = False - if member.primary: - if self.primary_interface_name: - msg = 'Only one primary interface allowed per bridge.' - raise InvalidConfigException(msg) - if member.primary_interface_name: - self.primary_interface_name = member.primary_interface_name - else: - self.primary_interface_name = member.name - - @staticmethod - def from_json(json): - name = _get_required_field(json, 'name', 'LinuxBridge') - (use_dhcp, use_dhcpv6, addresses, routes, rules, mtu, nic_mapping, - persist_mapping, defroute, dhclient_args, dns_servers, nm_controlled, - onboot, domain) = _BaseOpts.base_opts_from_json(json, - include_primary=False) - - members = _update_members(json, nic_mapping, persist_mapping) - - return LinuxBridge(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6, - addresses=addresses, routes=routes, rules=rules, - mtu=mtu, members=members, nic_mapping=nic_mapping, - persist_mapping=persist_mapping, defroute=defroute, - dhclient_args=dhclient_args, - dns_servers=dns_servers, - nm_controlled=nm_controlled, onboot=onboot, - domain=domain) - - -class IvsBridge(_BaseOpts): - """Base class for IVS bridges. - - Indigo Virtual Switch (IVS) is a virtual switch for Linux. - It is compatible with the KVM hypervisor and leveraging the - Open vSwitch kernel module for packet forwarding. There are - three major differences between IVS and OVS: - 1. Each node can have at most one ivs, no name required. - 2. Bond is not allowed to attach to an ivs. It is the SDN - controller's job to dynamically form bonds on ivs. - 3. IP address can only be statically assigned. - """ - - def __init__(self, name='ivs', use_dhcp=False, use_dhcpv6=False, - addresses=None, rules=None, routes=None, - mtu=1500, members=None, nic_mapping=None, - persist_mapping=False, defroute=True, dhclient_args=None, - dns_servers=None, nm_controlled=False, onboot=True, - domain=None): - addresses = addresses or [] - routes = routes or [] - rules = rules or [] - members = members or [] - dns_servers = dns_servers or [] - super(IvsBridge, self).__init__(name, use_dhcp, use_dhcpv6, - addresses, routes, rules, mtu, False, - nic_mapping, persist_mapping, - defroute, dhclient_args, dns_servers, - nm_controlled, onboot, domain) - self.members = members - for member in self.members: - if isinstance(member, OvsBond) or isinstance(member, LinuxBond): - msg = 'IVS does not support bond interfaces.' - raise InvalidConfigException(msg) - member.ivs_bridge_name = name - member.ovs_port = False - self.primary_interface_name = None # ivs doesn't use primary intf - - @staticmethod - def from_json(json): - name = 'ivs' - (use_dhcp, use_dhcpv6, addresses, routes, rules, mtu, nic_mapping, - persist_mapping, defroute, dhclient_args, dns_servers, nm_controlled, - onboot, domain) = _BaseOpts.base_opts_from_json(json, - include_primary=False) - - members = _update_members(json, nic_mapping, persist_mapping) - - return IvsBridge(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6, - addresses=addresses, routes=routes, rules=rules, - mtu=mtu, members=members, nic_mapping=nic_mapping, - persist_mapping=persist_mapping, defroute=defroute, - dhclient_args=dhclient_args, - dns_servers=dns_servers, nm_controlled=nm_controlled, - onboot=onboot, domain=domain) - - -class NfvswitchBridge(_BaseOpts): - """Base class for NFVSwitch bridges. - - NFVSwitch is a virtual switch for Linux. - It is compatible with the KVM hypervisor and uses DPDK for packet - forwarding. - """ - - def __init__(self, name='nfvswitch', use_dhcp=False, use_dhcpv6=False, - addresses=None, routes=None, rules=None, mtu=1500, - members=None, nic_mapping=None, persist_mapping=False, - defroute=True, dhclient_args=None, dns_servers=None, - nm_controlled=False, onboot=True, domain=None, options=""): - addresses = addresses or [] - routes = routes or [] - rules = rules or [] - members = members or [] - dns_servers = dns_servers or [] - super(NfvswitchBridge, self).__init__(name, use_dhcp, use_dhcpv6, - addresses, routes, rules, mtu, - False, nic_mapping, - persist_mapping, defroute, - dhclient_args, dns_servers, - nm_controlled, onboot, domain) - self.options = options - self.members = members - for member in self.members: - if isinstance(member, OvsBond) or isinstance(member, LinuxBond): - msg = 'NFVSwitch does not support bond interfaces.' - raise InvalidConfigException(msg) - member.nfvswitch_bridge_name = name - member.ovs_port = False - self.primary_interface_name = None - - @staticmethod - def from_json(json): - name = 'nfvswitch' - (use_dhcp, use_dhcpv6, addresses, routes, rules, mtu, nic_mapping, - persist_mapping, defroute, dhclient_args, dns_servers, nm_controlled, - onboot, domain) = _BaseOpts.base_opts_from_json(json, - include_primary=False) - - members = _update_members(json, nic_mapping, persist_mapping) - - options = json.get('options') - if not options: - msg = 'Config "options" is mandatory.' - raise InvalidConfigException(msg) - - return NfvswitchBridge(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6, - addresses=addresses, routes=routes, rules=rules, - mtu=mtu, members=members, - nic_mapping=nic_mapping, - persist_mapping=persist_mapping, - defroute=defroute, dhclient_args=dhclient_args, - dns_servers=dns_servers, - nm_controlled=nm_controlled, onboot=onboot, - domain=domain, options=options) - - -class LinuxTeam(_BaseOpts): - """Base class for Linux bonds using teamd.""" - - def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None, - routes=None, rules=None, mtu=None, primary=False, - members=None, bonding_options=None, nic_mapping=None, - persist_mapping=False, defroute=True, dhclient_args=None, - dns_servers=None, nm_controlled=False, onboot=True, - domain=None): - addresses = addresses or [] - routes = routes or [] - rules = rules or [] - members = members or [] - dns_servers = dns_servers or [] - super(LinuxTeam, self).__init__(name, use_dhcp, use_dhcpv6, addresses, - routes, rules, mtu, primary, - nic_mapping, persist_mapping, defroute, - dhclient_args, dns_servers, - nm_controlled, onboot, domain) - self.members = members - self.bonding_options = bonding_options - for member in self.members: - member.linux_team_name = name - if member.primary: - if self.primary_interface_name: - msg = 'Only one primary interface allowed per team.' - raise InvalidConfigException(msg) - if member.primary_interface_name: - self.primary_interface_name = member.primary_interface_name - else: - self.primary_interface_name = member.name - - @staticmethod - def from_json(json): - name = _get_required_field(json, 'name', 'LinuxTeam') - (use_dhcp, use_dhcpv6, addresses, routes, rules, mtu, nic_mapping, - persist_mapping, defroute, dhclient_args, dns_servers, nm_controlled, - onboot, domain) = _BaseOpts.base_opts_from_json(json, - include_primary=False) - - bonding_options = json.get('bonding_options') - members = _update_members(json, nic_mapping, persist_mapping) - - return LinuxTeam(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6, - addresses=addresses, routes=routes, rules=rules, - mtu=mtu, members=members, - bonding_options=bonding_options, - nic_mapping=nic_mapping, - persist_mapping=persist_mapping, defroute=defroute, - dhclient_args=dhclient_args, dns_servers=dns_servers, - nm_controlled=nm_controlled, onboot=onboot, - domain=domain) - - -class LinuxBond(_BaseOpts): - """Base class for Linux bonds.""" - - def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None, - routes=None, rules=None, mtu=None, primary=False, - members=None, bonding_options=None, nic_mapping=None, - persist_mapping=False, defroute=True, dhclient_args=None, - dns_servers=None, nm_controlled=False, onboot=True, - domain=None, ethtool_opts=None): - addresses = addresses or [] - routes = routes or [] - rules = rules or [] - members = members or [] - dns_servers = dns_servers or [] - super(LinuxBond, self).__init__(name, use_dhcp, use_dhcpv6, addresses, - routes, rules, mtu, primary, - nic_mapping, persist_mapping, defroute, - dhclient_args, dns_servers, - nm_controlled, onboot, domain) - self.members = members - self.bonding_options = bonding_options - self.ethtool_opts = ethtool_opts - for member in self.members: - if isinstance(member, SriovPF): - utils.update_sriov_pf_map(member.name, member.numvfs, False, - lag_candidate=True) - if isinstance(member, SriovVF): - LinuxBond.update_vf_config(member) - member.linux_bond_name = name - if member.primary: - if self.primary_interface_name: - msg = 'Only one primary interface allowed per bond.' - raise InvalidConfigException(msg) - if member.primary_interface_name: - self.primary_interface_name = member.primary_interface_name - else: - self.primary_interface_name = member.name - - @staticmethod - def update_vf_config(iface): - if iface.trust is None: - logger.info("Trust is not set for VF %s:%d, defaulting to on" - % (iface.device, iface.vfid)) - iface.trust = 'on' - if iface.spoofcheck is None: - logger.info("Spoofcheck is not set for VF %s:%d, defaulting to off" - % (iface.device, iface.vfid)) - iface.spoofcheck = 'off' - if iface.promisc is None: - logger.info("Promisc is not set for VF %s:%d, defaulting to off" - % (iface.device, iface.vfid)) - iface.promisc = 'off' - utils.update_sriov_vf_map(iface.device, iface.vfid, iface.name, - vlan_id=iface.vlan_id, qos=iface.qos, - spoofcheck=iface.spoofcheck, - trust=iface.trust, state=iface.state, - macaddr=iface.macaddr, promisc=iface.promisc, - pci_address=iface.pci_address, - min_tx_rate=iface.min_tx_rate, - max_tx_rate=iface.max_tx_rate, - driver=None) - - @staticmethod - def from_json(json): - name = _get_required_field(json, 'name', 'LinuxBond') - (use_dhcp, use_dhcpv6, addresses, routes, rules, mtu, nic_mapping, - persist_mapping, defroute, dhclient_args, dns_servers, nm_controlled, - onboot, domain) = _BaseOpts.base_opts_from_json( - json, include_primary=False) - bonding_options = json.get('bonding_options') - ethtool_opts = json.get('ethtool_opts', None) - - members = _update_members(json, nic_mapping, persist_mapping) - - return LinuxBond(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6, - addresses=addresses, routes=routes, rules=rules, - mtu=mtu, members=members, - bonding_options=bonding_options, - nic_mapping=nic_mapping, - persist_mapping=persist_mapping, defroute=defroute, - dhclient_args=dhclient_args, dns_servers=dns_servers, - nm_controlled=nm_controlled, onboot=onboot, - domain=domain, ethtool_opts=ethtool_opts) - - -class OvsBond(_BaseOpts): - """Base class for OVS bonds.""" - - def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None, - routes=None, rules=None, mtu=None, primary=False, - members=None, ovs_options=None, ovs_extra=None, - nic_mapping=None, persist_mapping=False, defroute=True, - dhclient_args=None, dns_servers=None, nm_controlled=False, - onboot=True, domain=None): - - check_ovs_installed(self.__class__.__name__) - - addresses = addresses or [] - routes = routes or [] - rules = rules or [] - members = members or [] - dns_servers = dns_servers or [] - super(OvsBond, self).__init__(name, use_dhcp, use_dhcpv6, addresses, - routes, rules, mtu, primary, nic_mapping, - persist_mapping, defroute, dhclient_args, - dns_servers, nm_controlled, onboot, - domain) - self.members = members - self.ovs_options = ovs_options - self.ovs_extra = format_ovs_extra(self, ovs_extra) - for member in self.members: - if isinstance(member, SriovVF): - OvsBond.update_vf_config(member) - if member.primary: - if self.primary_interface_name: - msg = 'Only one primary interface allowed per bond.' - raise InvalidConfigException(msg) - if member.primary_interface_name: - self.primary_interface_name = member.primary_interface_name - else: - self.primary_interface_name = member.name - if not self.primary_interface_name: - bond_members = list(self.members) - bond_members.sort(key=lambda x: x.name) - self.primary_interface_name = bond_members[0].name - - @staticmethod - def update_vf_config(iface): - if iface.trust is None: - logger.info("Trust is not set for VF %s:%d, defaulting to on" - % (iface.device, iface.vfid)) - iface.trust = "on" - if iface.spoofcheck is None: - logger.info("Spoofcheck is not set for VF %s:%d, defaulting to off" - % (iface.device, iface.vfid)) - iface.spoofcheck = "off" - if iface.promisc is None: - logger.info("Promisc is not set for VF %s:%d, defaulting to on" - % (iface.device, iface.vfid)) - iface.promisc = "on" - utils.update_sriov_vf_map(iface.device, iface.vfid, iface.name, - vlan_id=iface.vlan_id, qos=iface.qos, - spoofcheck=iface.spoofcheck, - trust=iface.trust, state=iface.state, - macaddr=iface.macaddr, promisc=iface.promisc, - min_tx_rate=iface.min_tx_rate, - max_tx_rate=iface.max_tx_rate, - driver=None) - - @staticmethod - def from_json(json): - name = _get_required_field(json, 'name', 'OvsBond') - (use_dhcp, use_dhcpv6, addresses, routes, rules, mtu, nic_mapping, - persist_mapping, defroute, dhclient_args, dns_servers, nm_controlled, - onboot, domain) = _BaseOpts.base_opts_from_json( - json, include_primary=False) - ovs_options = json.get('ovs_options') - ovs_extra = json.get('ovs_extra', []) - if not isinstance(ovs_extra, list): - ovs_extra = [ovs_extra] - - members = _update_members(json, nic_mapping, persist_mapping) - - return OvsBond(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6, - addresses=addresses, routes=routes, rules=rules, - mtu=mtu, members=members, ovs_options=ovs_options, - ovs_extra=ovs_extra, nic_mapping=nic_mapping, - persist_mapping=persist_mapping, defroute=defroute, - dhclient_args=dhclient_args, dns_servers=dns_servers, - nm_controlled=nm_controlled, onboot=onboot, - domain=domain) - - -class OvsTunnel(_BaseOpts): - """Base class for OVS Tunnels.""" - - def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None, - routes=None, rules=None, mtu=None, primary=False, - nic_mapping=None, persist_mapping=False, defroute=True, - dhclient_args=None, dns_servers=None, nm_controlled=False, - onboot=True, domain=None, tunnel_type=None, ovs_options=None, - ovs_extra=None): - - check_ovs_installed(self.__class__.__name__) - - addresses = addresses or [] - routes = routes or [] - rules = rules or [] - dns_servers = dns_servers or [] - super(OvsTunnel, self).__init__(name, use_dhcp, use_dhcpv6, addresses, - routes, rules, mtu, primary, - nic_mapping, persist_mapping, defroute, - dhclient_args, dns_servers, - nm_controlled, onboot, domain) - self.tunnel_type = tunnel_type - self.ovs_options = ovs_options or [] - self.ovs_extra = format_ovs_extra(self, ovs_extra) - - @staticmethod - def from_json(json): - name = _get_required_field(json, 'name', 'OvsTunnel') - tunnel_type = _get_required_field(json, 'tunnel_type', 'OvsTunnel') - ovs_options = json.get('ovs_options', []) - ovs_options = ['options:%s' % opt for opt in ovs_options] - ovs_extra = json.get('ovs_extra', []) - if not isinstance(ovs_extra, list): - ovs_extra = [ovs_extra] - opts = _BaseOpts.base_opts_from_json(json) - return OvsTunnel(name, *opts, tunnel_type=tunnel_type, - ovs_options=ovs_options, ovs_extra=ovs_extra) - - -class OvsPatchPort(_BaseOpts): - """Base class for OVS Patch Ports.""" - - def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None, - routes=None, rules=None, mtu=None, primary=False, - nic_mapping=None, persist_mapping=False, defroute=True, - dhclient_args=None, dns_servers=None, nm_controlled=False, - onboot=True, domain=None, bridge_name=None, peer=None, - ovs_options=None, ovs_extra=None): - - check_ovs_installed(self.__class__.__name__) - - addresses = addresses or [] - routes = routes or [] - rules = rules or [] - dns_servers = dns_servers or [] - super(OvsPatchPort, self).__init__(name, use_dhcp, use_dhcpv6, - addresses, routes, rules, mtu, - primary, nic_mapping, - persist_mapping, defroute, - dhclient_args, dns_servers, - nm_controlled, onboot, domain) - self.bridge_name = bridge_name - self.peer = peer - self.ovs_options = ovs_options or [] - self.ovs_extra = format_ovs_extra(self, ovs_extra) - - @staticmethod - def from_json(json): - name = _get_required_field(json, 'name', 'OvsPatchPort') - bridge_name = _get_required_field(json, 'bridge_name', 'OvsPatchPort') - peer = _get_required_field(json, 'peer', 'OvsPatchPort') - ovs_options = json.get('ovs_options', []) - ovs_options = ['options:%s' % opt for opt in ovs_options] - ovs_extra = json.get('ovs_extra', []) - if not isinstance(ovs_extra, list): - ovs_extra = [ovs_extra] - opts = _BaseOpts.base_opts_from_json(json) - return OvsPatchPort(name, *opts, bridge_name=bridge_name, peer=peer, - ovs_options=ovs_options, ovs_extra=ovs_extra) - - -class IbInterface(_BaseOpts): - """Base class for InfiniBand network interfaces.""" - - def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None, - routes=None, rules=None, mtu=None, primary=False, - nic_mapping=None, persist_mapping=False, defroute=True, - dhclient_args=None, dns_servers=None, nm_controlled=False, - onboot=True, domain=None, ethtool_opts=None): - addresses = addresses or [] - routes = routes or [] - rules = rules or [] - dns_servers = dns_servers or [] - super(IbInterface, self).__init__(name, use_dhcp, use_dhcpv6, - addresses, routes, rules, mtu, - primary, nic_mapping, - persist_mapping, defroute, - dhclient_args, dns_servers, - nm_controlled, onboot, domain) - self.ethtool_opts = ethtool_opts - - @staticmethod - def from_json(json): - name = _get_required_field(json, 'name', 'IbInterface') - ethtool_opts = json.get('ethtool_opts', None) - opts = _BaseOpts.base_opts_from_json(json) - return IbInterface(name, *opts, ethtool_opts=ethtool_opts) - - -class IbChildInterface(_BaseOpts): - """Base class for InfiniBand child network interfaces.""" - - def __init__(self, parent, pkey_id, use_dhcp=False, use_dhcpv6=False, - addresses=None, routes=None, rules=None, mtu=None, - primary=False, nic_mapping=None, persist_mapping=False, - defroute=True, dhclient_args=None, dns_servers=None, - nm_controlled=True, onboot=True, domain=None): - addresses = addresses or [] - routes = routes or [] - rules = rules or [] - dns_servers = dns_servers or [] - full_pkey_id = 0x8000 | pkey_id - self.pkey_id = hex(full_pkey_id) - self.parent = parent - name = "%s.%04x" % (parent, full_pkey_id) - nm_controlled = True - super(IbChildInterface, self).__init__(name, use_dhcp, use_dhcpv6, - addresses, routes, rules, mtu, - primary, nic_mapping, - persist_mapping, defroute, - dhclient_args, dns_servers, - nm_controlled, onboot, domain) - - @staticmethod - def from_json(json): - parent = _get_required_field(json, 'parent', 'IbChildInterface') - pkey_id = _get_required_field(json, 'pkey_id', 'IbChildInterface') - try: - pkey_id = int(pkey_id) - except ValueError: - try: - pkey_id = int(pkey_id, base=16) - except Exception: - # Note (Abdallahyas): We do not care for other - # bases other than base 10 or base 16 - msg = "pkey only supports base 10 or base 16 int numbers" - raise InvalidConfigException(msg) - if (pkey_id < 0x0001 or pkey_id >= 0x7fff): - msg = "Invalid pkey value 0x%X" % pkey_id - raise InvalidConfigException(msg) - opts = _BaseOpts.base_opts_from_json(json) - return IbChildInterface(parent, pkey_id, *opts) - - -class OvsDpdkPort(_BaseOpts): - """Base class for OVS Dpdk Ports.""" - - def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None, - routes=None, rules=None, mtu=None, primary=False, - nic_mapping=None, persist_mapping=False, defroute=True, - dhclient_args=None, dns_servers=None, nm_controlled=False, - onboot=True, domain=None, members=None, driver='vfio-pci', - ovs_options=None, ovs_extra=None, rx_queue=None, - rx_queue_size=None, tx_queue_size=None): - - check_ovs_installed(self.__class__.__name__) - - super(OvsDpdkPort, self).__init__(name, use_dhcp, use_dhcpv6, - addresses, routes, rules, mtu, - primary, nic_mapping, - persist_mapping, defroute, - dhclient_args, dns_servers, - nm_controlled, onboot, domain) - self.members = members or [] - self.ovs_options = ovs_options or [] - self.ovs_extra = format_ovs_extra(self, ovs_extra) - self.driver = driver - self.rx_queue = rx_queue - self.rx_queue_size = rx_queue_size - self.tx_queue_size = tx_queue_size - - @staticmethod - def update_vf_config(iface, driver=None): - if iface.trust is None: - logger.info("Trust is not set for VF %s:%d, defaulting to on" - % (iface.device, iface.vfid)) - iface.trust = "on" - if iface.spoofcheck is None: - logger.info("Spoofcheck is not set for VF %s:%d, defaulting to off" - % (iface.device, iface.vfid)) - iface.spoofcheck = "off" - if iface.promisc is not None: - logger.warning("Promisc can't be changed for ovs_dpdk_port") - iface.promisc = None - logger.info("Overriding the default driver for DPDK") - utils.update_sriov_vf_map(iface.device, iface.vfid, iface.name, - vlan_id=iface.vlan_id, qos=iface.qos, - spoofcheck=iface.spoofcheck, - trust=iface.trust, state=iface.state, - macaddr=iface.macaddr, promisc=iface.promisc, - pci_address=iface.pci_address, - min_tx_rate=iface.min_tx_rate, - max_tx_rate=iface.max_tx_rate, - driver=driver) - - @staticmethod - def from_json(json): - name = _get_required_field(json, 'name', 'OvsDpdkPort') - # driver name by default will be 'vfio-pci' if not specified - (use_dhcp, use_dhcpv6, addresses, routes, rules, mtu, primary, - nic_mapping, persist_mapping, defroute, dhclient_args, - dns_servers, nm_controlled, - onboot, domain) = _BaseOpts.base_opts_from_json(json) - - driver = json.get('driver') - if not driver: - driver = 'vfio-pci' - - # members - members = [] - members_json = json.get('members') - if members_json: - if isinstance(members_json, list): - if len(members_json) == 1: - member = members_json[0] - if not member.get('nic_mapping'): - member.update({'nic_mapping': nic_mapping}) - member.update({'persist_mapping': persist_mapping}) - iface = object_from_json(member) - if isinstance(iface, Interface): - - # TODO(skramaja): Add checks for IP and route not to - # be set in the interface part of DPDK Port - members.append(iface) - elif isinstance(iface, SriovVF): - OvsDpdkPort.update_vf_config(iface, driver) - members.append(iface) - else: - msg = 'Unsupported OVS DPDK Port member type' - raise InvalidConfigException(msg) - else: - msg = 'OVS DPDK Port should have only one member' - raise InvalidConfigException(msg) - else: - msg = 'Members must be a list.' - raise InvalidConfigException(msg) - else: - msg = 'DPDK Port should have one member as Interface' - raise InvalidConfigException(msg) - - rx_queue = json.get('rx_queue', None) - rx_queue_size = json.get('rx_queue_size', None) - tx_queue_size = json.get('tx_queue_size', None) - ovs_options = json.get('ovs_options', []) - ovs_options = ['options:%s' % opt for opt in ovs_options] - ovs_extra = json.get('ovs_extra', []) - if not isinstance(ovs_extra, list): - ovs_extra = [ovs_extra] - return OvsDpdkPort(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6, - addresses=addresses, routes=routes, rules=rules, - mtu=mtu, primary=primary, nic_mapping=nic_mapping, - persist_mapping=persist_mapping, defroute=defroute, - dhclient_args=dhclient_args, - dns_servers=dns_servers, - nm_controlled=nm_controlled, onboot=onboot, - domain=domain, members=members, driver=driver, - ovs_options=ovs_options, - ovs_extra=ovs_extra, rx_queue=rx_queue, - rx_queue_size=rx_queue_size, - tx_queue_size=tx_queue_size) - - -class SriovVF(_BaseOpts): - """Base class for SR-IOV VF.""" - - def __init__(self, device, vfid, use_dhcp=False, use_dhcpv6=False, - addresses=None, routes=None, rules=None, mtu=None, - primary=False, nic_mapping=None, persist_mapping=False, - defroute=True, dhclient_args=None, dns_servers=None, - nm_controlled=False, onboot=True, domain=None, vlan_id=0, - qos=0, spoofcheck=None, trust=None, state=None, macaddr=None, - promisc=None, min_tx_rate=0, max_tx_rate=0, - ethtool_opts=None): - addresses = addresses or [] - routes = routes or [] - rules = rules or [] - dns_servers = dns_servers or [] - mapped_nic_names = mapped_nics(nic_mapping) - if device in mapped_nic_names: - device = mapped_nic_names[device] - # Empty strings are set for the name field. - # The provider shall identify the VF name from the PF device name - # (device) and the VF id. - name = utils.get_vf_devname(device, vfid) - super(SriovVF, self).__init__(name, use_dhcp, use_dhcpv6, addresses, - routes, rules, mtu, primary, nic_mapping, - persist_mapping, defroute, - dhclient_args, dns_servers, - nm_controlled, onboot, domain) - self.vfid = int(vfid) - self.device = device - self.vlan_id = int(vlan_id) - self.qos = int(qos) - self.min_tx_rate = int(min_tx_rate) - self.max_tx_rate = int(max_tx_rate) - self.spoofcheck = spoofcheck - self.trust = trust - self.state = state - pci_address = utils.get_pci_address(name, False) - if pci_address is None: - pci_address = utils.get_stored_pci_address(name, False) - self.macaddr = macaddr - self.promisc = promisc - self.pci_address = pci_address - self.driver = None - self.ethtool_opts = ethtool_opts - utils.update_sriov_vf_map(device, self.vfid, name, - vlan_id=self.vlan_id, - qos=self.qos, - spoofcheck=spoofcheck, - trust=trust, - state=state, - macaddr=macaddr, - promisc=promisc, - pci_address=pci_address, - min_tx_rate=min_tx_rate, - max_tx_rate=max_tx_rate, - driver=self.driver) - - @staticmethod - def get_on_off(config): - rval = None - if config is False or config == "off": - rval = "off" - elif config is True or config == "on": - rval = "on" - return rval - - @staticmethod - def from_json(json): - # Get the VF id - vfid = _get_required_field(json, 'vfid', 'SriovVF', datatype=int) - # Get the PF device name - device = _get_required_field(json, 'device', 'SriovVF') - opts = _BaseOpts.base_opts_from_json(json) - vlan_id = json.get('vlan_id', 0) - qos = json.get('qos', 0) - if qos != 0 and vlan_id == 0: - msg = "Vlan tag not set for QOS - VF: %s:%d" % (device, vfid) - raise InvalidConfigException(msg) - min_tx_rate = json.get('min_tx_rate', 0) - max_tx_rate = json.get('max_tx_rate', 0) - if max_tx_rate > 0 and min_tx_rate > max_tx_rate: - msg = ("vf %s:%d: min_tx_rate(%d) > max_tx_rate(%d)" % - (device, vfid, min_tx_rate, max_tx_rate)) - raise InvalidConfigException(msg) - - spoofcheck = SriovVF.get_on_off(json.get('spoofcheck')) - trust = SriovVF.get_on_off(json.get('trust')) - promisc = SriovVF.get_on_off(json.get('promisc')) - state = json.get('state') - if state not in [None, 'auto', 'enable', 'disable']: - msg = 'Expecting state to match auto/enable/disable' - raise InvalidConfigException(msg) - macaddr = json.get('macaddr') - ethtool_opts = json.get('ethtool_opts', None) - return SriovVF(device, vfid, *opts, vlan_id=vlan_id, qos=qos, - spoofcheck=spoofcheck, trust=trust, state=state, - macaddr=macaddr, promisc=promisc, - min_tx_rate=min_tx_rate, max_tx_rate=max_tx_rate, - ethtool_opts=ethtool_opts) - - -class SriovPF(_BaseOpts): - """Base class for SR-IOV PF.""" - - def __init__(self, name, numvfs, use_dhcp=False, use_dhcpv6=False, - addresses=None, routes=None, rules=None, mtu=None, - primary=False, nic_mapping=None, persist_mapping=False, - defroute=True, dhclient_args=None, dns_servers=None, - nm_controlled=False, onboot=True, domain=None, members=None, - promisc=None, link_mode='legacy', ethtool_opts=None, - vdpa=False, steering_mode=None): - addresses = addresses or [] - routes = routes or [] - rules = rules or [] - dns_servers = dns_servers or [] - super(SriovPF, self).__init__(name, use_dhcp, use_dhcpv6, addresses, - routes, rules, mtu, primary, nic_mapping, - persist_mapping, defroute, - dhclient_args, dns_servers, - nm_controlled, onboot, domain) - self.numvfs = int(numvfs) - mapped_nic_names = mapped_nics(nic_mapping) - if name in mapped_nic_names: - self.name = mapped_nic_names[name] - else: - self.name = name - self.promisc = promisc - self.link_mode = link_mode - self.ethtool_opts = ethtool_opts - self.vdpa = vdpa - self.steering_mode = steering_mode - - @staticmethod - def get_on_off(config): - rval = None - if config is False or config == "off": - rval = "off" - elif config is True or config == "on": - rval = "on" - return rval - - @staticmethod - def from_json(json): - name = _get_required_field(json, 'name', 'SriovPF') - numvfs = _get_required_field(json, 'numvfs', 'SriovPF') - # SR-IOV PF - promisc: on (default) - promisc = json.get('promisc', True) - promisc = SriovPF.get_on_off(promisc) - link_mode = json.get('link_mode', 'legacy') - ethtool_opts = json.get('ethtool_opts', None) - vdpa = json.get('vdpa', False) - steering_mode = json.get('steering_mode') - if steering_mode is not None and steering_mode not in ['smfs', 'dmfs']: - msg = 'Expecting steering_mode to match smfs/dmfs' - raise InvalidConfigException(msg) - if vdpa: - msg = "" - if link_mode != 'switchdev': - msg += "Expecting link_mode to be switchdev when vdpa is "\ - f"enabled, not {link_mode}\n" - if not int(numvfs): - msg += ("Expecting to have at least 1 numvfs when vdpa is " - "enabled\n") - if len(msg): - raise InvalidConfigException(msg) - if link_mode not in ['legacy', 'switchdev']: - msg = 'Expecting link_mode to match legacy/switchdev' - raise InvalidConfigException(msg) - opts = _BaseOpts.base_opts_from_json(json) - return SriovPF(name, numvfs, *opts, promisc=promisc, - link_mode=link_mode, ethtool_opts=ethtool_opts, - vdpa=vdpa, steering_mode=steering_mode) - - -class OvsDpdkBond(_BaseOpts): - """Base class for OVS DPDK bonds.""" - - def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None, - routes=None, rules=None, mtu=None, primary=False, - members=None, ovs_options=None, ovs_extra=None, - nic_mapping=None, persist_mapping=False, defroute=True, - dhclient_args=None, dns_servers=None, nm_controlled=False, - onboot=True, domain=None, rx_queue=None, - rx_queue_size=None, tx_queue_size=None): - - check_ovs_installed(self.__class__.__name__) - - super(OvsDpdkBond, self).__init__(name, use_dhcp, use_dhcpv6, - addresses, routes, rules, mtu, - primary, nic_mapping, - persist_mapping, defroute, - dhclient_args, dns_servers, - nm_controlled, onboot, domain) - self.members = members or [] - self.ovs_options = ovs_options - self.ovs_extra = format_ovs_extra(self, ovs_extra) - self.rx_queue = rx_queue - self.rx_queue_size = rx_queue_size - self.tx_queue_size = tx_queue_size - - for member in self.members: - if member.primary: - if self.primary_interface_name: - msg = 'Only one primary interface allowed per bond (dpdk).' - raise InvalidConfigException(msg) - if member.primary_interface_name: - self.primary_interface_name = member.primary_interface_name - else: - self.primary_interface_name = member.name - if not self.primary_interface_name: - bond_members = list(self.members) - bond_members.sort(key=lambda x: x.name) - self.primary_interface_name = bond_members[0].name - - @staticmethod - def from_json(json): - name = _get_required_field(json, 'name', 'OvsDpdkBond') - (use_dhcp, use_dhcpv6, addresses, routes, rules, mtu, nic_mapping, - persist_mapping, defroute, dhclient_args, dns_servers, nm_controlled, - onboot, domain) = _BaseOpts.base_opts_from_json( - json, include_primary=False) - rx_queue = json.get('rx_queue', None) - rx_queue_size = json.get('rx_queue_size', None) - tx_queue_size = json.get('tx_queue_size', None) - ovs_options = json.get('ovs_options') - ovs_extra = json.get('ovs_extra', []) - if not isinstance(ovs_extra, list): - ovs_extra = [ovs_extra] - members = [] - - # members - members_json = json.get('members') - if members_json: - if isinstance(members_json, list): - for member in members_json: - if not member.get('nic_mapping'): - member.update({'nic_mapping': nic_mapping}) - member.update({'persist_mapping': persist_mapping}) - obj = object_from_json(member) - if isinstance(obj, OvsDpdkPort): - members.append(obj) - else: - msg = 'Members must be of type ovs_dpdk_port' - raise InvalidConfigException(msg) - else: - msg = 'Members must be a list.' - raise InvalidConfigException(msg) - - return OvsDpdkBond(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6, - addresses=addresses, routes=routes, rules=rules, - mtu=mtu, members=members, ovs_options=ovs_options, - ovs_extra=ovs_extra, nic_mapping=nic_mapping, - persist_mapping=persist_mapping, - defroute=defroute, dhclient_args=dhclient_args, - dns_servers=dns_servers, - nm_controlled=nm_controlled, onboot=onboot, - domain=domain, rx_queue=rx_queue, - rx_queue_size=rx_queue_size, - tx_queue_size=tx_queue_size) - - -class VppInterface(_BaseOpts): - """Base class for VPP Interface. - - Vector Packet Processing (VPP) is a high performance packet processing - stack that runs in user space in Linux. VPP is used as an alternative to - kernel networking stack for accelerated network data path. VPP uses DPDK - poll-mode drivers to bind system interfaces rather than kernel drivers. - VPP bound interfaces are not visible to kernel networking stack, so we - must handle them separately. - - The following parameters can be specified in addition to base Interface: - - uio_driver: DPDK poll-mode driver name. Defaults to 'vfio-pci', valid - values are 'uio_pci_generic' and 'vfio-pci'. - - options: Interface options such as vlan stripping and tx/rx transmit - queues specification. Defaults to None. Reference for those - configurations can be found at - https://wiki.fd.io/view/VPP/Command-line_Arguments - Example: 'vlan-strip-offload on num-rx-queues 3' - - Note that 'name' attribute is used to indicate the kernel nic that should - be bound to VPP. Once VPP binds the interface, a mapping file will be - updated with the interface's information, and this file will be used in - subsequent runs of os-net-config. - """ - def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None, - routes=None, rules=None, mtu=None, primary=False, - nic_mapping=None, persist_mapping=False, defroute=True, - dhclient_args=None, dns_servers=None, nm_controlled=False, - onboot=True, domain=None, uio_driver='vfio-pci', - options=None): - addresses = addresses or [] - routes = routes or [] - rules = rules or [] - - super(VppInterface, self).__init__(name, use_dhcp, use_dhcpv6, - addresses, routes, rules, mtu, - primary, nic_mapping, - persist_mapping, defroute, - dhclient_args, dns_servers, - nm_controlled, onboot, domain) - self.uio_driver = uio_driver - self.options = options - # pci_dev contains pci address for the interface, it will be populated - # when interface is added to config object. It will be determined - # either through ethtool or by looking up the dpdk mapping file. - self.pci_dev = None - - @staticmethod - def from_json(json): - name = _get_required_field(json, 'name', 'VppInterface') - uio_driver = json.get('uio_driver', 'vfio-pci') - options = json.get('options', '') - - opts = _BaseOpts.base_opts_from_json(json) - return VppInterface(name, *opts, uio_driver=uio_driver, - options=options) - - -class VppBond(_BaseOpts): - """Base class for VPP Bond.""" - def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None, - routes=None, rules=None, mtu=None, primary=False, - nic_mapping=None, persist_mapping=False, defroute=True, - dhclient_args=None, dns_servers=None, nm_controlled=False, - onboot=True, domain=None, members=None, bonding_options=None): - addresses = addresses or [] - members = members or [] - routes = routes or [] - rules = rules or [] - - super(VppBond, self).__init__(name, use_dhcp, use_dhcpv6, - addresses, routes, rules, mtu, primary, - nic_mapping, persist_mapping, - defroute, dhclient_args, - dns_servers, nm_controlled, onboot, - domain) - self.members = members - self.bonding_options = bonding_options - - @staticmethod - def from_json(json): - name = _get_required_field(json, 'name', 'VppBond') - bonding_options = json.get('bonding_options', '') - - (use_dhcp, use_dhcpv6, addresses, routes, rules, mtu, nic_mapping, - persist_mapping, defroute, dhclient_args, dns_servers, nm_controlled, - onboot, domain) = _BaseOpts.base_opts_from_json(json, - include_primary=False) - - members = [] - members_json = json.get('members', None) - if members_json: - if isinstance(members_json, list): - for member in members_json: - if not member.get('nic_mapping'): - member.update({'nic_mapping': nic_mapping}) - member.update({'persist_mapping': persist_mapping}) - obj = object_from_json(member) - if isinstance(obj, VppInterface): - members.append(obj) - else: - msg = 'Members must be of type vpp_interface' - raise InvalidConfigException(msg) - else: - msg = 'Members must be a list.' - raise InvalidConfigException(msg) - - return VppBond(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6, - addresses=addresses, routes=routes, rules=rules, - mtu=mtu, members=members, nic_mapping=nic_mapping, - persist_mapping=persist_mapping, - defroute=defroute, dhclient_args=dhclient_args, - dns_servers=dns_servers, nm_controlled=nm_controlled, - onboot=onboot, domain=domain, - bonding_options=bonding_options) - - -class ContrailVrouter(_BaseOpts): - """Base class for Contrail Interface. - - Contrail Vrouter is the interface transporting traffic for the Contrail - SDN Controller. - - The following parameters can be specified in addition to base Interface: - - members: List of sole interface to use by vhost0 - """ - def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None, - routes=None, rules=None, mtu=None, primary=False, - nic_mapping=None, persist_mapping=False, defroute=True, - dhclient_args=None, dns_servers=None, nm_controlled=False, - onboot=True, domain=None, members=None): - addresses = addresses or [] - - super(ContrailVrouter, self).__init__(name, use_dhcp, use_dhcpv6, - addresses, routes, rules, mtu, - primary, nic_mapping, - persist_mapping, defroute, - dhclient_args, dns_servers, - nm_controlled, onboot, domain) - self.members = members or [] - - @staticmethod - def from_json(json): - name = _get_required_field(json, 'name', 'ContrailVrouter') - - (_use_dhcp, _use_dhcpv6, _addresses, _routes, _rules, _mtu, _primary, - nic_mapping, persist_mapping, _defroute, _dhclient_args, _dns_servers, - _nm_controlled, _onboot, - _domain) = opts = _BaseOpts.base_opts_from_json(json) - members = _update_members(json, nic_mapping, persist_mapping) - - return ContrailVrouter(name, *opts, members=members) - - -class ContrailVrouterDpdk(_BaseOpts): - """Base class for Contrail DPDK Interface. - - Contrail Vrouter is the interface transporting traffic for the Contrail - SDN Controller. - - The following parameters can be specified in addition to base Interface: - - members: List of interfaces to use by vhost0 - - bond_mode: Bonding mode - - bond_policy: Bonding transmit hash policy - - cpu_list: CPU set string eg "1-4,6,7-15:2" - - vlan_id: - """ - def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None, - routes=None, rules=None, mtu=None, primary=False, - nic_mapping=None, persist_mapping=False, defroute=True, - dhclient_args=None, dns_servers=None, nm_controlled=False, - onboot=True, domain=None, members=None, bond_mode=None, - bond_policy=None, driver=None, cpu_list='0-31', vlan_id=None): - addresses = addresses or [] - - super(ContrailVrouterDpdk, self).__init__(name, use_dhcp, use_dhcpv6, - addresses, routes, rules, - mtu, primary, nic_mapping, - persist_mapping, defroute, - dhclient_args, dns_servers, - nm_controlled, onboot, - domain) - - self.members = members or [] - self.bond_mode = bond_mode - self.bond_policy = bond_policy - self.driver = driver or 'uio_pci_generic' - self.cpu_list = cpu_list - self.vlan_id = vlan_id - - @staticmethod - def from_json(json): - name = _get_required_field(json, 'name', 'ContrailVrouterDpdk') - bond_mode = json.get('bond_mode', '') - bond_policy = json.get('bond_policy', '') - driver = json.get('driver', 'uio_pci_generic') - cpu_list = json.get('cpu_list', '0-31') - vlan_id = json.get('vlan_id', '') - - (_use_dhcp, _use_dhcpv6, _addresses, _routes, _rules, _mtu, _primary, - nic_mapping, persist_mapping, _defroute, _dhclient_args, _dns_servers, - _nm_controlled, _onboot, - _domain) = opts = _BaseOpts.base_opts_from_json(json) - members = _update_members(json, nic_mapping, persist_mapping) - - return ContrailVrouterDpdk(name, *opts, members=members, - bond_mode=bond_mode, - bond_policy=bond_policy, driver=driver, - cpu_list=cpu_list, vlan_id=vlan_id) - - -class LinuxTap(_BaseOpts): - """Base class for Linux tap Interface. - - TAP, namely network TAP, simulates a link layer device and operates in - layer 2 carrying Ethernet frames. - A user space program may also pass packets into a TAP device. In this - case the TAP device delivers (or "injects") these packets to the - operating-system network stack thus emulating their reception from an - external source. - """ - def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None, - routes=None, rules=None, mtu=None, primary=False, - nic_mapping=None, persist_mapping=False, defroute=True, - dhclient_args=None, dns_servers=None, nm_controlled=False, - onboot=True, domain=None, members=None): - super(LinuxTap, self).__init__(name, use_dhcp, use_dhcpv6, - addresses, routes, rules, mtu, - primary, nic_mapping, - persist_mapping, defroute, - dhclient_args, dns_servers, - nm_controlled, onboot, domain) - - @staticmethod - def from_json(json): - name = _get_required_field(json, 'name', 'LinuxTap') - - (_use_dhcp, _use_dhcpv6, _addresses, _routes, _rules, _mtu, _primary, - nic_mapping, persist_mapping, _defroute, _dhclient_args, _dns_servers, - _nm_controlled, _onboot, - _domain) = opts = _BaseOpts.base_opts_from_json(json) - - return LinuxTap(name, *opts) diff --git a/os_net_config/schema.yaml b/os_net_config/schema.yaml deleted file mode 100644 index 3a0bf119..00000000 --- a/os_net_config/schema.yaml +++ /dev/null @@ -1,1592 +0,0 @@ ---- -$schema: http://json-schema.org/draft-04/schema - -definitions: - # base types - param: - oneOf: - - type: object - properties: - get_param: - type: string - additionalProperties: False - - type: object - properties: - get_input: - type: string - additionalProperties: False - string_or_param: - oneOf: - - type: string - - $ref: "#/definitions/param" - int_or_param: - oneOf: - - type: integer - - $ref: "#/definitions/param" - bool_or_param: - oneOf: - - type: boolean - - # also accept strings of boolean values (like oslo_utils.strutils) - type: string - pattern: "(?i)^(t|true|on|y|yes|1|f|false|off|n|no|0)$" - - $ref: "#/definitions/param" - sriov_vf_state_string: - type: string - pattern: "^(auto|enable|disable)$" - sriov_link_mode_or_param: - oneOf: - - type: string - pattern: "^(legacy|switchdev)$" - - $ref: "#/definitions/param" - sriov_steering_mode_or_param: - oneOf: - - type: string - pattern: "^(smfs|dmfs)$" - - $ref: "#/definitions/param" - # MAC address type - mac_address_string: - type: string - pattern: "^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$" - # IP address and address+prefix types - ipv4_address_string: - type: string - pattern: "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}\ - (25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$" - ipv6_address_string: - type: string - pattern: "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}\ - |([0-9a-fA-F]{1,4}:){1,7}:\ - |([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}\ - |([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}\ - |([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}\ - |([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}\ - |([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}\ - |[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})\ - |:((:[0-9a-fA-F]{1,4}){1,7}|:))$" - ip_address_string: - oneOf: - - $ref: "#/definitions/ipv4_address_string" - - $ref: "#/definitions/ipv6_address_string" - ip_address_string_or_param: - oneOf: - - $ref: "#/definitions/ip_address_string" - - $ref: "#/definitions/param" - list_of_ip_address_string_or_param: - oneOf: - - type: array - items: - $ref: "#/definitions/ip_address_string_or_param" - minItems: 0 - - $ref: "#/definitions/param" - - ipv4_cidr_string: - type: string - pattern: "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}\ - (25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\ - /(3[0-2]|[1-2][0-9]|[0-9])$" - ipv6_cidr_string: - type: string - pattern: "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}\ - |([0-9a-fA-F]{1,4}:){1,7}:\ - |([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}\ - |([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}\ - |([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}\ - |([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}\ - |([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}\ - |[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})\ - |:((:[0-9a-fA-F]{1,4}){1,7}|:))\ - /(12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9])$" - ip_cidr_string: - oneOf: - - $ref: "#/definitions/ipv4_cidr_string" - - $ref: "#/definitions/ipv6_cidr_string" - ip_cidr_string_or_param: - oneOf: - - $ref: "#/definitions/ip_cidr_string" - - $ref: "#/definitions/param" - - type: object - properties: - list_join: - type: array - items: - - enum: ["/"] - - type: array - items: - - $ref: "#/definitions/ip_address_string_or_param" - - $ref: "#/definitions/int_or_param" - required: - - list_join - additionalProperties: False - domain_name_string: - type: string - pattern: >- - ^(?=^.{1,255}$)(?!.*\.\..*)(.{1,63}\.)+(.{0,63}\.?)|(?!\.)(?!.*\.\..*)(^.{1,63}$)|(^\.$)$ - - list_of_domain_name_string_or_domain_name_string: - oneOf: - - type: array - items: - $ref: "#/definitions/domain_name_string" - minItems: 0 - - $ref: "#/definitions/domain_name_string" - - # os-net-config derived types - address: - type: object - properties: - ip_netmask: - $ref: "#/definitions/ip_cidr_string_or_param" - required: - - ip_netmask - additionalProperties: False - list_of_address: - type: array - items: - $ref: "#/definitions/address" - minItems: 1 - - route: - type: object - oneOf: - - properties: - next_hop: - $ref: "#/definitions/ip_address_string_or_param" - ip_netmask: - $ref: "#/definitions/ip_cidr_string_or_param" - default: - $ref: "#/definitions/bool_or_param" - route_options: - $ref: "#/definitions/string_or_param" - table: - anyOf: - - $ref: "#/definitions/string_or_param" - - $ref: "#/definitions/int_or_param" - requires: - - next_hop - additionalProperties: False - - properties: - nexthop: - $ref: "#/definitions/ip_address_string_or_param" - destination: - $ref: "#/definitions/ip_cidr_string_or_param" - default: - $ref: "#/definitions/bool_or_param" - route_options: - $ref: "#/definitions/string_or_param" - table: - anyOf: - - $ref: "#/definitions/string_or_param" - - $ref: "#/definitions/int_or_param" - requires: - - nexthop - additionalProperties: False - list_of_route: - type: array - items: - $ref: "#/definitions/route" - minItems: 0 - - route_rule: - type: object - properties: - rule: - $ref: "#/definitions/string_or_param" - comment: - $ref: "#/definitions/string_or_param" - required: - - rule - additionalProperties: False - list_of_rule: - type: array - items: - $ref: "#/definitions/route_rule" - minItems: 1 - - nic_mapping: - type: ["object", "null"] - - bonding_options: - type: string - - ovs_options_string: - type: string - pattern: "^((?:[a-zA-Z][a-zA-Z0-9: _-]*)=(?:[a-zA-Z0-9:._-]+)[ ]*)+$" - ovs_options_string_or_param: - oneOf: - - $ref: "#/definitions/ovs_options_string" - - $ref: "#/definitions/param" - ovs_single_option_string: - type: string - pattern: "^([a-zA-Z][a-zA-Z0-9: _-]*)=([a-zA-Z0-9._-]+)$" - ovs_options_list: - type: array - items: - $ref: "#/definitions/ovs_single_option_string" - minItems: 1 - ovs_options_list_or_param: - oneOf: - - $ref: "#/definitions/ovs_options_list" - - $ref: "#/definitions/param" - ovs_fail_mode: - enum: ["standalone", "secure"] - ovs_fail_mode_or_param: - oneOf: - - $ref: "#/definitions/ovs_fail_mode" - - $ref: "#/definitions/param" - ovs_extra_string: - type: string - ovs_extra: - oneOf: - - $ref: "#/definitions/ovs_extra_string" - - type: array - items: - $ref: "#/definitions/ovs_extra_string" - minItems: 1 - ovs_extra_or_param: - oneOf: - - $ref: "#/definitions/ovs_extra" - - $ref: "#/definitions/param" - ovs_tunnel_type: - enum: ["vxlan", "gre"] - ovs_tunnel_type_or_param: - oneOf: - - $ref: "#/definitions/ovs_tunnel_type" - - $ref: "#/definitions/param" - - # os-net-config device types - interface: - type: object - properties: - type: - enum: ["interface"] - name: - $ref: "#/definitions/string_or_param" - primary: - $ref: "#/definitions/bool_or_param" - ethtool_opts: - $ref: "#/definitions/string_or_param" - hotplug: - $ref: "#/definitions/bool_or_param" - # common options: - use_dhcp: - $ref: "#/definitions/bool_or_param" - use_dhcpv6: - $ref: "#/definitions/bool_or_param" - addresses: - $ref: "#/definitions/list_of_address" - routes: - $ref: "#/definitions/list_of_route" - rules: - $ref: "#/definitions/list_of_rule" - mtu: - $ref: "#/definitions/int_or_param" - nic_mapping: - $ref: "#/definitions/nic_mapping" - persist_mapping: - $ref: "#/definitions/bool_or_param" - defroute: - $ref: "#/definitions/bool_or_param" - dhclient_args: - $ref: "#/definitions/string_or_param" - dns_servers: - $ref: "#/definitions/list_of_ip_address_string_or_param" - nm_controlled: - $ref: "#/definitions/bool_or_param" - onboot: - $ref: "#/definitions/bool_or_param" - domain: - $ref: "#/definitions/list_of_domain_name_string_or_domain_name_string" - linkdelay: - $ref: "#/definitions/int_or_param" - required: - - type - - name - additionalProperties: False - - route_table: - type: object - properties: - type: - enum: ["route_table"] - name: - $ref: "#/definitions/string_or_param" - table_id: - anyOf: - - $ref: "#/definitions/int_or_param" - - $ref: "#/definitions/string_or_param" - required: - - type - - name - - table_id - additionalProperties: False - - sriov_pf: - type: object - properties: - type: - enum: ["sriov_pf"] - name: - $ref: "#/definitions/string_or_param" - primary: - $ref: "#/definitions/bool_or_param" - numvfs: - $ref: "#/definitions/int_or_param" - promisc: - $ref: "#/definitions/bool_or_param" - hotplug: - $ref: "#/definitions/bool_or_param" - ethtool_opts: - $ref: "#/definitions/string_or_param" - # common options: - use_dhcp: - $ref: "#/definitions/bool_or_param" - use_dhcpv6: - $ref: "#/definitions/bool_or_param" - addresses: - $ref: "#/definitions/list_of_address" - routes: - $ref: "#/definitions/list_of_route" - rules: - $ref: "#/definitions/list_of_rule" - mtu: - $ref: "#/definitions/int_or_param" - nic_mapping: - $ref: "#/definitions/nic_mapping" - persist_mapping: - $ref: "#/definitions/bool_or_param" - defroute: - $ref: "#/definitions/bool_or_param" - dhclient_args: - $ref: "#/definitions/string_or_param" - dns_servers: - $ref: "#/definitions/list_of_ip_address_string_or_param" - nm_controlled: - $ref: "#/definitions/bool_or_param" - onboot: - $ref: "#/definitions/bool_or_param" - domain: - $ref: "#/definitions/list_of_domain_name_string_or_domain_name_string" - link_mode: - $ref: "#/definitions/sriov_link_mode_or_param" - vdpa: - $ref: "#/definitions/bool_or_param" - steering_mode: - $ref: "#/definitions/sriov_steering_mode_or_param" - required: - - type - - name - - numvfs - additionalProperties: False - - sriov_vf: - type: object - properties: - type: - enum: ["sriov_vf"] - primary: - $ref: "#/definitions/bool_or_param" - device: - $ref: "#/definitions/string_or_param" - vfid: - $ref: "#/definitions/int_or_param" - vlan_id: - $ref: "#/definitions/int_or_param" - qos: - $ref: "#/definitions/int_or_param" - min_tx_rate: - $ref: "#/definitions/int_or_param" - max_tx_rate: - $ref: "#/definitions/int_or_param" - hotplug: - $ref: "#/definitions/bool_or_param" - spoofcheck: - $ref: "#/definitions/bool_or_param" - trust: - $ref: "#/definitions/bool_or_param" - promisc: - $ref: "#/definitions/bool_or_param" - macaddr: - $ref: "#/definitions/mac_address_string" - state: - $ref: "#/definitions/sriov_vf_state_string" - # common options: - use_dhcp: - $ref: "#/definitions/bool_or_param" - use_dhcpv6: - $ref: "#/definitions/bool_or_param" - addresses: - $ref: "#/definitions/list_of_address" - routes: - $ref: "#/definitions/list_of_route" - rules: - $ref: "#/definitions/list_of_rule" - mtu: - $ref: "#/definitions/int_or_param" - nic_mapping: - $ref: "#/definitions/nic_mapping" - persist_mapping: - $ref: "#/definitions/bool_or_param" - defroute: - $ref: "#/definitions/bool_or_param" - dhclient_args: - $ref: "#/definitions/string_or_param" - dns_servers: - $ref: "#/definitions/list_of_ip_address_string_or_param" - nm_controlled: - $ref: "#/definitions/bool_or_param" - onboot: - $ref: "#/definitions/bool_or_param" - domain: - $ref: "#/definitions/list_of_domain_name_string_or_domain_name_string" - ethtool_opts: - $ref: "#/definitions/string_or_param" - required: - - type - - device - - vfid - additionalProperties: False - - vlan: - type: object - properties: - type: - enum: ["vlan"] - vlan_id: - $ref: "#/definitions/int_or_param" - device: - $ref: "#/definitions/string_or_param" - primary: - $ref: "#/definitions/bool_or_param" - # common options: - use_dhcp: - $ref: "#/definitions/bool_or_param" - use_dhcpv6: - $ref: "#/definitions/bool_or_param" - addresses: - $ref: "#/definitions/list_of_address" - routes: - $ref: "#/definitions/list_of_route" - rules: - $ref: "#/definitions/list_of_rule" - mtu: - $ref: "#/definitions/int_or_param" - nic_mapping: - $ref: "#/definitions/nic_mapping" - persist_mapping: - $ref: "#/definitions/bool_or_param" - defroute: - $ref: "#/definitions/bool_or_param" - dhclient_args: - $ref: "#/definitions/string_or_param" - dns_servers: - $ref: "#/definitions/list_of_ip_address_string_or_param" - nm_controlled: - $ref: "#/definitions/bool_or_param" - onboot: - $ref: "#/definitions/bool_or_param" - domain: - $ref: "#/definitions/list_of_domain_name_string_or_domain_name_string" - ovs_options: - $ref: "#/definitions/ovs_options_string_or_param" - ovs_extra: - $ref: "#/definitions/ovs_extra_or_param" - required: - - type - - vlan_id - additionalProperties: False - - ovs_bridge: - type: object - properties: - type: - enum: ["ovs_bridge"] - name: - $ref: "#/definitions/string_or_param" - members: - type: array - items: - oneOf: - - $ref: "#/definitions/interface" - - $ref: "#/definitions/vlan" - - $ref: "#/definitions/linux_bond" - - $ref: "#/definitions/linux_team" - - $ref: "#/definitions/ovs_bond" - - $ref: "#/definitions/ovs_tunnel" - - $ref: "#/definitions/ovs_patch_port" - - $ref: "#/definitions/sriov_vf" - - $ref: "#/definitions/sriov_pf" - ovs_options: - $ref: "#/definitions/ovs_options_string_or_param" - ovs_extra: - $ref: "#/definitions/ovs_extra_or_param" - ovs_fail_mode: - $ref: "#/definitions/ovs_fail_mode_or_param" - # common options: - use_dhcp: - $ref: "#/definitions/bool_or_param" - use_dhcpv6: - $ref: "#/definitions/bool_or_param" - addresses: - $ref: "#/definitions/list_of_address" - routes: - $ref: "#/definitions/list_of_route" - rules: - $ref: "#/definitions/list_of_rule" - mtu: - $ref: "#/definitions/int_or_param" - nic_mapping: - $ref: "#/definitions/nic_mapping" - persist_mapping: - $ref: "#/definitions/bool_or_param" - defroute: - $ref: "#/definitions/bool_or_param" - dhclient_args: - $ref: "#/definitions/string_or_param" - dns_servers: - $ref: "#/definitions/list_of_ip_address_string_or_param" - nm_controlled: - $ref: "#/definitions/bool_or_param" - onboot: - $ref: "#/definitions/bool_or_param" - domain: - $ref: "#/definitions/list_of_domain_name_string_or_domain_name_string" - required: - - type - - name - - members - additionalProperties: False - - ovs_user_bridge: - type: object - properties: - type: - enum: ["ovs_user_bridge"] - name: - $ref: "#/definitions/string_or_param" - members: - type: array - items: - oneOf: - - $ref: "#/definitions/interface" - - $ref: "#/definitions/vlan" - - $ref: "#/definitions/ovs_bond" - - $ref: "#/definitions/ovs_patch_port" - - $ref: "#/definitions/ovs_tunnel" - - $ref: "#/definitions/ovs_dpdk_bond" - - $ref: "#/definitions/ovs_dpdk_port" - ovs_options: - $ref: "#/definitions/ovs_options_string_or_param" - ovs_extra: - $ref: "#/definitions/ovs_extra_or_param" - ovs_fail_mode: - $ref: "#/definitions/ovs_fail_mode_or_param" - # common options: - use_dhcp: - $ref: "#/definitions/bool_or_param" - use_dhcpv6: - $ref: "#/definitions/bool_or_param" - addresses: - $ref: "#/definitions/list_of_address" - routes: - $ref: "#/definitions/list_of_route" - rules: - $ref: "#/definitions/list_of_rule" - mtu: - $ref: "#/definitions/int_or_param" - nic_mapping: - $ref: "#/definitions/nic_mapping" - persist_mapping: - $ref: "#/definitions/bool_or_param" - defroute: - $ref: "#/definitions/bool_or_param" - dhclient_args: - $ref: "#/definitions/string_or_param" - dns_servers: - $ref: "#/definitions/list_of_ip_address_string_or_param" - nm_controlled: - $ref: "#/definitions/bool_or_param" - onboot: - $ref: "#/definitions/bool_or_param" - domain: - $ref: "#/definitions/list_of_domain_name_string_or_domain_name_string" - required: - - type - - name - - members - additionalProperties: False - - ovs_bond: - type: object - properties: - type: - enum: ["ovs_bond"] - name: - $ref: "#/definitions/string_or_param" - members: - type: array - items: - oneOf: - - $ref: "#/definitions/interface" - - $ref: "#/definitions/sriov_vf" - - $ref: "#/definitions/vlan" - - $ref: "#/definitions/sriov_pf" - minItems: 1 - ovs_options: - $ref: "#/definitions/ovs_options_string_or_param" - ovs_extra: - $ref: "#/definitions/ovs_extra_or_param" - # common options: - use_dhcp: - $ref: "#/definitions/bool_or_param" - use_dhcpv6: - $ref: "#/definitions/bool_or_param" - addresses: - $ref: "#/definitions/list_of_address" - routes: - $ref: "#/definitions/list_of_route" - rules: - $ref: "#/definitions/list_of_rule" - mtu: - $ref: "#/definitions/int_or_param" - nic_mapping: - $ref: "#/definitions/nic_mapping" - persist_mapping: - $ref: "#/definitions/bool_or_param" - defroute: - $ref: "#/definitions/bool_or_param" - dhclient_args: - $ref: "#/definitions/string_or_param" - dns_servers: - $ref: "#/definitions/list_of_ip_address_string_or_param" - nm_controlled: - $ref: "#/definitions/bool_or_param" - onboot: - $ref: "#/definitions/bool_or_param" - domain: - $ref: "#/definitions/list_of_domain_name_string_or_domain_name_string" - required: - - type - - name - - members - additionalProperties: False - - ovs_patch_port: - type: object - properties: - type: - enum: ["ovs_patch_port"] - name: - $ref: "#/definitions/string_or_param" - bridge_name: - $ref: "#/definitions/string_or_param" - peer: - $ref: "#/definitions/string_or_param" - primary: - $ref: "#/definitions/bool_or_param" - ovs_options: - $ref: "#/definitions/ovs_options_list_or_param" - ovs_extra: - $ref: "#/definitions/ovs_extra_or_param" - # common options: - use_dhcp: - $ref: "#/definitions/bool_or_param" - use_dhcpv6: - $ref: "#/definitions/bool_or_param" - addresses: - $ref: "#/definitions/list_of_address" - routes: - $ref: "#/definitions/list_of_route" - rules: - $ref: "#/definitions/list_of_rule" - mtu: - $ref: "#/definitions/int_or_param" - nic_mapping: - $ref: "#/definitions/nic_mapping" - persist_mapping: - $ref: "#/definitions/bool_or_param" - defroute: - $ref: "#/definitions/bool_or_param" - dhclient_args: - $ref: "#/definitions/string_or_param" - dns_servers: - $ref: "#/definitions/list_of_ip_address_string_or_param" - nm_controlled: - $ref: "#/definitions/bool_or_param" - onboot: - $ref: "#/definitions/bool_or_param" - domain: - $ref: "#/definitions/list_of_domain_name_string_or_domain_name_string" - required: - - type - - name - - bridge_name - - peer - additionalProperties: False - - ovs_tunnel: - type: object - properties: - type: - enum: ["ovs_tunnel"] - name: - $ref: "#/definitions/string_or_param" - tunnel_type: - $ref: "#/definitions/ovs_tunnel_type_or_param" - primary: - $ref: "#/definitions/bool_or_param" - ovs_options: - $ref: "#/definitions/ovs_options_list_or_param" - ovs_extra: - $ref: "#/definitions/ovs_extra_or_param" - # common options: - use_dhcp: - $ref: "#/definitions/bool_or_param" - use_dhcpv6: - $ref: "#/definitions/bool_or_param" - addresses: - $ref: "#/definitions/list_of_address" - routes: - $ref: "#/definitions/list_of_route" - rules: - $ref: "#/definitions/list_of_rule" - mtu: - $ref: "#/definitions/int_or_param" - nic_mapping: - $ref: "#/definitions/nic_mapping" - persist_mapping: - $ref: "#/definitions/bool_or_param" - defroute: - $ref: "#/definitions/bool_or_param" - dhclient_args: - $ref: "#/definitions/string_or_param" - dns_servers: - $ref: "#/definitions/list_of_ip_address_string_or_param" - nm_controlled: - $ref: "#/definitions/bool_or_param" - onboot: - $ref: "#/definitions/bool_or_param" - domain: - $ref: "#/definitions/list_of_domain_name_string_or_domain_name_string" - required: - - type - - name - - tunnel_type - additionalProperties: False - - ovs_dpdk_bond: - type: object - properties: - type: - enum: ["ovs_dpdk_bond"] - name: - $ref: "#/definitions/string_or_param" - members: - type: array - items: - - $ref: "#/definitions/ovs_dpdk_port" - ovs_options: - $ref: "#/definitions/ovs_options_string_or_param" - ovs_extra: - $ref: "#/definitions/ovs_extra_or_param" - rx_queue: - $ref: "#/definitions/int_or_param" - rx_queue_size: - $ref: "#/definitions/int_or_param" - tx_queue_size: - $ref: "#/definitions/int_or_param" - # common options: - use_dhcp: - $ref: "#/definitions/bool_or_param" - use_dhcpv6: - $ref: "#/definitions/bool_or_param" - addresses: - $ref: "#/definitions/list_of_address" - routes: - $ref: "#/definitions/list_of_route" - rules: - $ref: "#/definitions/list_of_rule" - mtu: - $ref: "#/definitions/int_or_param" - nic_mapping: - $ref: "#/definitions/nic_mapping" - persist_mapping: - $ref: "#/definitions/bool_or_param" - defroute: - $ref: "#/definitions/bool_or_param" - dhclient_args: - $ref: "#/definitions/string_or_param" - dns_servers: - $ref: "#/definitions/list_of_ip_address_string_or_param" - nm_controlled: - $ref: "#/definitions/bool_or_param" - onboot: - $ref: "#/definitions/bool_or_param" - domain: - $ref: "#/definitions/list_of_domain_name_string_or_domain_name_string" - required: - - type - - name - - members - additionalProperties: False - - ovs_dpdk_port: - type: object - properties: - type: - enum: ["ovs_dpdk_port"] - name: - $ref: "#/definitions/string_or_param" - driver: - $ref: "#/definitions/string_or_param" - members: - type: array - items: - oneOf: - - $ref: "#/definitions/interface" - - $ref: "#/definitions/sriov_vf" - minItems: 1 - maxItems: 1 - primary: - $ref: "#/definitions/bool_or_param" - ovs_options: - $ref: "#/definitions/ovs_options_string_or_param" - ovs_extra: - $ref: "#/definitions/ovs_extra_or_param" - rx_queue: - $ref: "#/definitions/int_or_param" - rx_queue_size: - $ref: "#/definitions/int_or_param" - tx_queue_size: - $ref: "#/definitions/int_or_param" - # common options: - use_dhcp: - $ref: "#/definitions/bool_or_param" - use_dhcpv6: - $ref: "#/definitions/bool_or_param" - addresses: - $ref: "#/definitions/list_of_address" - routes: - $ref: "#/definitions/list_of_route" - rules: - $ref: "#/definitions/list_of_rule" - mtu: - $ref: "#/definitions/int_or_param" - nic_mapping: - $ref: "#/definitions/nic_mapping" - persist_mapping: - $ref: "#/definitions/bool_or_param" - defroute: - $ref: "#/definitions/bool_or_param" - dhclient_args: - $ref: "#/definitions/string_or_param" - dns_servers: - $ref: "#/definitions/list_of_ip_address_string_or_param" - nm_controlled: - $ref: "#/definitions/bool_or_param" - onboot: - $ref: "#/definitions/bool_or_param" - domain: - $ref: "#/definitions/list_of_domain_name_string_or_domain_name_string" - required: - - type - - name - - members - additionalProperties: False - - vpp_interface: - type: object - properties: - type: - enum: ["vpp_interface"] - name: - $ref: "#/definitions/string_or_param" - uio_driver: - $ref: "#/definitions/string_or_param" - options: - $ref: "#/definitions/string_or_param" - # common options: - use_dhcp: - $ref: "#/definitions/bool_or_param" - use_dhcpv6: - $ref: "#/definitions/bool_or_param" - addresses: - $ref: "#/definitions/list_of_address" - routes: - $ref: "#/definitions/list_of_route" - rules: - $ref: "#/definitions/list_of_rule" - mtu: - $ref: "#/definitions/int_or_param" - nic_mapping: - $ref: "#/definitions/nic_mapping" - persist_mapping: - $ref: "#/definitions/bool_or_param" - defroute: - $ref: "#/definitions/bool_or_param" - dhclient_args: - $ref: "#/definitions/string_or_param" - dns_servers: - $ref: "#/definitions/list_of_ip_address_string_or_param" - nm_controlled: - $ref: "#/definitions/bool_or_param" - onboot: - $ref: "#/definitions/bool_or_param" - domain: - $ref: "#/definitions/list_of_domain_name_string_or_domain_name_string" - required: - - type - - name - additionalProperties: False - - vpp_bond: - type: object - properties: - type: - enum: ["vpp_bond"] - name: - $ref: "#/definitions/string_or_param" - uio_driver: - $ref: "#/definitions/string_or_param" - options: - $ref: "#/definitions/string_or_param" - # common options: - use_dhcp: - $ref: "#/definitions/bool_or_param" - use_dhcpv6: - $ref: "#/definitions/bool_or_param" - addresses: - $ref: "#/definitions/list_of_address" - routes: - $ref: "#/definitions/list_of_route" - rules: - $ref: "#/definitions/list_of_rule" - mtu: - $ref: "#/definitions/int_or_param" - nic_mapping: - $ref: "#/definitions/nic_mapping" - persist_mapping: - $ref: "#/definitions/bool_or_param" - defroute: - $ref: "#/definitions/bool_or_param" - dhclient_args: - $ref: "#/definitions/string_or_param" - dns_servers: - $ref: "#/definitions/list_of_ip_address_string_or_param" - nm_controlled: - $ref: "#/definitions/bool_or_param" - onboot: - $ref: "#/definitions/bool_or_param" - domain: - $ref: "#/definitions/list_of_domain_name_string_or_domain_name_string" - members: - type: array - items: - oneOf: - - $ref: "#/definitions/vpp_interface" - bonding_options: - $ref: "#/definitions/string_or_param" - required: - - type - - name - additionalProperties: False - - contrail_vrouter: - type: object - properties: - type: - enum: ["contrail_vrouter"] - name: - $ref: "#/definitions/string_or_param" - members: - type: array - items: - oneOf: - - $ref: "#/definitions/interface" - - $ref: "#/definitions/vlan" - - $ref: "#/definitions/linux_bond" - minItems: 1 - # common options: - use_dhcp: - $ref: "#/definitions/bool_or_param" - use_dhcpv6: - $ref: "#/definitions/bool_or_param" - addresses: - $ref: "#/definitions/list_of_address" - routes: - $ref: "#/definitions/list_of_route" - rules: - $ref: "#/definitions/list_of_rule" - mtu: - $ref: "#/definitions/int_or_param" - nic_mapping: - $ref: "#/definitions/nic_mapping" - persist_mapping: - $ref: "#/definitions/bool_or_param" - defroute: - $ref: "#/definitions/bool_or_param" - dhclient_args: - $ref: "#/definitions/string_or_param" - dns_servers: - $ref: "#/definitions/list_of_ip_address_string_or_param" - nm_controlled: - $ref: "#/definitions/bool_or_param" - required: - - type - - name - - members - additionalProperties: False - - contrail_vrouter_dpdk: - type: object - properties: - type: - enum: ["contrail_vrouter_dpdk"] - name: - $ref: "#/definitions/string_or_param" - members: - type: array - items: - - $ref: "#/definitions/interface" - minItems: 1 - bond_mode: - anyOf: - - $ref: "#/definitions/string_or_param" - - $ref: "#/definitions/int_or_param" - bond_policy: - anyOf: - - $ref: "#/definitions/string_or_param" - - $ref: "#/definitions/int_or_param" - driver: - $ref: "#/definitions/string_or_param" - cpu_list: - $ref: "#/definitions/string_or_param" - vlan_id: - anyOf: - - $ref: "#/definitions/string_or_param" - - $ref: "#/definitions/int_or_param" - # common options: - use_dhcp: - $ref: "#/definitions/bool_or_param" - use_dhcpv6: - $ref: "#/definitions/bool_or_param" - addresses: - $ref: "#/definitions/list_of_address" - routes: - $ref: "#/definitions/list_of_route" - rules: - $ref: "#/definitions/list_of_rule" - mtu: - $ref: "#/definitions/int_or_param" - nic_mapping: - $ref: "#/definitions/nic_mapping" - persist_mapping: - $ref: "#/definitions/bool_or_param" - defroute: - $ref: "#/definitions/bool_or_param" - dhclient_args: - $ref: "#/definitions/string_or_param" - dns_servers: - $ref: "#/definitions/list_of_ip_address_string_or_param" - nm_controlled: - $ref: "#/definitions/bool_or_param" - required: - - type - - name - - members - additionalProperties: False - - linux_tap: - type: object - properties: - type: - enum: ["linux_tap"] - name: - $ref: "#/definitions/string_or_param" - # common options: - use_dhcp: - $ref: "#/definitions/bool_or_param" - use_dhcpv6: - $ref: "#/definitions/bool_or_param" - addresses: - $ref: "#/definitions/list_of_address" - routes: - $ref: "#/definitions/list_of_route" - rules: - $ref: "#/definitions/list_of_rule" - mtu: - $ref: "#/definitions/int_or_param" - nic_mapping: - $ref: "#/definitions/nic_mapping" - persist_mapping: - $ref: "#/definitions/bool_or_param" - defroute: - $ref: "#/definitions/bool_or_param" - dhclient_args: - $ref: "#/definitions/string_or_param" - dns_servers: - $ref: "#/definitions/list_of_ip_address_string_or_param" - nm_controlled: - $ref: "#/definitions/bool_or_param" - required: - - type - - name - additionalProperties: False - - linux_bridge: - type: object - properties: - type: - enum: ["linux_bridge"] - name: - $ref: "#/definitions/string_or_param" - members: - type: array - items: - oneOf: - - $ref: "#/definitions/interface" - - $ref: "#/definitions/vlan" - - $ref: "#/definitions/linux_bond" - # common options: - use_dhcp: - $ref: "#/definitions/bool_or_param" - use_dhcpv6: - $ref: "#/definitions/bool_or_param" - addresses: - $ref: "#/definitions/list_of_address" - routes: - $ref: "#/definitions/list_of_route" - rules: - $ref: "#/definitions/list_of_rule" - mtu: - $ref: "#/definitions/int_or_param" - nic_mapping: - $ref: "#/definitions/nic_mapping" - persist_mapping: - $ref: "#/definitions/bool_or_param" - defroute: - $ref: "#/definitions/bool_or_param" - dhclient_args: - $ref: "#/definitions/string_or_param" - dns_servers: - $ref: "#/definitions/list_of_ip_address_string_or_param" - nm_controlled: - $ref: "#/definitions/bool_or_param" - onboot: - $ref: "#/definitions/bool_or_param" - domain: - $ref: "#/definitions/list_of_domain_name_string_or_domain_name_string" - required: - - type - - name - - members - additionalProperties: False - - linux_bond: - type: object - properties: - type: - enum: ["linux_bond"] - name: - $ref: "#/definitions/string_or_param" - members: - type: array - items: - oneOf: - - $ref: "#/definitions/interface" - - $ref: "#/definitions/vlan" - - $ref: "#/definitions/sriov_vf" - - $ref: "#/definitions/sriov_pf" - bonding_options: - $ref: "#/definitions/bonding_options" - # common options: - use_dhcp: - $ref: "#/definitions/bool_or_param" - use_dhcpv6: - $ref: "#/definitions/bool_or_param" - addresses: - $ref: "#/definitions/list_of_address" - routes: - $ref: "#/definitions/list_of_route" - rules: - $ref: "#/definitions/list_of_rule" - mtu: - $ref: "#/definitions/int_or_param" - nic_mapping: - $ref: "#/definitions/nic_mapping" - persist_mapping: - $ref: "#/definitions/bool_or_param" - defroute: - $ref: "#/definitions/bool_or_param" - dhclient_args: - $ref: "#/definitions/string_or_param" - dns_servers: - $ref: "#/definitions/list_of_ip_address_string_or_param" - nm_controlled: - $ref: "#/definitions/bool_or_param" - onboot: - $ref: "#/definitions/bool_or_param" - domain: - $ref: "#/definitions/list_of_domain_name_string_or_domain_name_string" - ethtool_opts: - $ref: "#/definitions/string_or_param" - required: - - type - - name - - members - additionalProperties: False - - linux_team: - type: object - properties: - type: - enum: ["team"] - name: - $ref: "#/definitions/string_or_param" - members: - type: array - items: - oneOf: - - $ref: "#/definitions/interface" - - $ref: "#/definitions/vlan" - bonding_options: - $ref: "#/definitions/bonding_options" - # common options: - use_dhcp: - $ref: "#/definitions/bool_or_param" - use_dhcpv6: - $ref: "#/definitions/bool_or_param" - addresses: - $ref: "#/definitions/list_of_address" - routes: - $ref: "#/definitions/list_of_route" - rules: - $ref: "#/definitions/list_of_rule" - mtu: - $ref: "#/definitions/int_or_param" - nic_mapping: - $ref: "#/definitions/nic_mapping" - persist_mapping: - $ref: "#/definitions/bool_or_param" - defroute: - $ref: "#/definitions/bool_or_param" - dhclient_args: - $ref: "#/definitions/string_or_param" - dns_servers: - $ref: "#/definitions/list_of_ip_address_string_or_param" - nm_controlled: - $ref: "#/definitions/bool_or_param" - onboot: - $ref: "#/definitions/bool_or_param" - domain: - $ref: "#/definitions/list_of_domain_name_string_or_domain_name_string" - required: - - type - - name - - members - additionalProperties: False - - ivs_bridge: - type: object - properties: - type: - enum: ["ivs_bridge"] - members: - type: array - items: - oneOf: - - $ref: "#/definitions/interface" - - $ref: "#/definitions/ivs_interface" - # common options: - use_dhcp: - $ref: "#/definitions/bool_or_param" - use_dhcpv6: - $ref: "#/definitions/bool_or_param" - addresses: - $ref: "#/definitions/list_of_address" - routes: - $ref: "#/definitions/list_of_route" - rules: - $ref: "#/definitions/list_of_rule" - mtu: - $ref: "#/definitions/int_or_param" - nic_mapping: - $ref: "#/definitions/nic_mapping" - persist_mapping: - $ref: "#/definitions/bool_or_param" - defroute: - $ref: "#/definitions/bool_or_param" - dhclient_args: - $ref: "#/definitions/string_or_param" - dns_servers: - $ref: "#/definitions/list_of_ip_address_string_or_param" - nm_controlled: - $ref: "#/definitions/bool_or_param" - onboot: - $ref: "#/definitions/bool_or_param" - domain: - $ref: "#/definitions/list_of_domain_name_string_or_domain_name_string" - required: - - type - - members - additionalProperties: False - - ivs_interface: - type: object - properties: - type: - enum: ["ivs_interface"] - name: - $ref: "#/definitions/string_or_param" - vlan_id: - $ref: "#/definitions/int_or_param" - primary: - $ref: "#/definitions/bool_or_param" - # common options: - use_dhcp: - $ref: "#/definitions/bool_or_param" - use_dhcpv6: - $ref: "#/definitions/bool_or_param" - addresses: - $ref: "#/definitions/list_of_address" - routes: - $ref: "#/definitions/list_of_route" - rules: - $ref: "#/definitions/list_of_rule" - mtu: - $ref: "#/definitions/int_or_param" - nic_mapping: - $ref: "#/definitions/nic_mapping" - persist_mapping: - $ref: "#/definitions/bool_or_param" - defroute: - $ref: "#/definitions/bool_or_param" - dhclient_args: - $ref: "#/definitions/string_or_param" - dns_servers: - $ref: "#/definitions/list_of_ip_address_string_or_param" - nm_controlled: - $ref: "#/definitions/bool_or_param" - onboot: - $ref: "#/definitions/bool_or_param" - domain: - $ref: "#/definitions/list_of_domain_name_string_or_domain_name_string" - required: - - type - - vlan_id - additionalProperties: False - - nfvswitch_bridge: - type: object - properties: - type: - enum: ["nfvswitch_bridge"] - members: - type: array - items: - oneOf: - - $ref: "#/definitions/interface" - - $ref: "#/definitions/vlan" - - $ref: "#/definitions/nfvswitch_internal" - options: - $ref: "#/definitions/string_or_param" - # common options: - use_dhcp: - $ref: "#/definitions/bool_or_param" - use_dhcpv6: - $ref: "#/definitions/bool_or_param" - addresses: - $ref: "#/definitions/list_of_address" - routes: - $ref: "#/definitions/list_of_route" - rules: - $ref: "#/definitions/list_of_rule" - mtu: - $ref: "#/definitions/int_or_param" - nic_mapping: - $ref: "#/definitions/nic_mapping" - persist_mapping: - $ref: "#/definitions/bool_or_param" - defroute: - $ref: "#/definitions/bool_or_param" - dhclient_args: - $ref: "#/definitions/string_or_param" - dns_servers: - $ref: "#/definitions/list_of_ip_address_string_or_param" - nm_controlled: - $ref: "#/definitions/bool_or_param" - onboot: - $ref: "#/definitions/bool_or_param" - domain: - $ref: "#/definitions/list_of_domain_name_string_or_domain_name_string" - required: - - type - - options - - members - additionalProperties: False - - nfvswitch_internal: - type: object - properties: - type: - enum: ["nfvswitch_internal"] - name: - $ref: "#/definitions/string_or_param" - vlan_id: - $ref: "#/definitions/int_or_param" - primary: - $ref: "#/definitions/bool_or_param" - # common options: - use_dhcp: - $ref: "#/definitions/bool_or_param" - use_dhcpv6: - $ref: "#/definitions/bool_or_param" - addresses: - $ref: "#/definitions/list_of_address" - routes: - $ref: "#/definitions/list_of_route" - rules: - $ref: "#/definitions/list_of_rule" - mtu: - $ref: "#/definitions/int_or_param" - nic_mapping: - $ref: "#/definitions/nic_mapping" - persist_mapping: - $ref: "#/definitions/bool_or_param" - defroute: - $ref: "#/definitions/bool_or_param" - dhclient_args: - $ref: "#/definitions/string_or_param" - dns_servers: - $ref: "#/definitions/list_of_ip_address_string_or_param" - nm_controlled: - $ref: "#/definitions/bool_or_param" - onboot: - $ref: "#/definitions/bool_or_param" - domain: - $ref: "#/definitions/list_of_domain_name_string_or_domain_name_string" - required: - - type - - vlan_id - additionalProperties: False - - ib_interface: - type: object - properties: - type: - enum: ["ib_interface"] - name: - $ref: "#/definitions/string_or_param" - primary: - $ref: "#/definitions/bool_or_param" - ethtool_opts: - $ref: "#/definitions/string_or_param" - # common options: - use_dhcp: - $ref: "#/definitions/bool_or_param" - use_dhcpv6: - $ref: "#/definitions/bool_or_param" - addresses: - $ref: "#/definitions/list_of_address" - routes: - $ref: "#/definitions/list_of_route" - rules: - $ref: "#/definitions/list_of_rule" - mtu: - $ref: "#/definitions/int_or_param" - nic_mapping: - $ref: "#/definitions/nic_mapping" - persist_mapping: - $ref: "#/definitions/bool_or_param" - defroute: - $ref: "#/definitions/bool_or_param" - dhclient_args: - $ref: "#/definitions/string_or_param" - dns_servers: - $ref: "#/definitions/list_of_ip_address_string_or_param" - nm_controlled: - $ref: "#/definitions/bool_or_param" - onboot: - $ref: "#/definitions/bool_or_param" - domain: - $ref: "#/definitions/list_of_domain_name_string_or_domain_name_string" - required: - - type - - name - additionalProperties: False - - ib_child_interface: - type: object - properties: - type: - enum: ["ib_child_interface"] - parent: - $ref: "#/definitions/string_or_param" - pkey_id: - $ref: "#/definitions/int_or_param" - primary: - $ref: "#/definitions/bool_or_param" - # common options: - use_dhcp: - $ref: "#/definitions/bool_or_param" - use_dhcpv6: - $ref: "#/definitions/bool_or_param" - addresses: - $ref: "#/definitions/list_of_address" - routes: - $ref: "#/definitions/list_of_route" - rules: - $ref: "#/definitions/list_of_rule" - mtu: - $ref: "#/definitions/int_or_param" - nic_mapping: - $ref: "#/definitions/nic_mapping" - persist_mapping: - $ref: "#/definitions/bool_or_param" - defroute: - $ref: "#/definitions/bool_or_param" - dhclient_args: - $ref: "#/definitions/string_or_param" - dns_servers: - $ref: "#/definitions/list_of_ip_address_string_or_param" - nm_controlled: - $ref: "#/definitions/bool_or_param" - onboot: - $ref: "#/definitions/bool_or_param" - domain: - $ref: "#/definitions/list_of_domain_name_string_or_domain_name_string" - required: - - type - - parent - - pkey_id - additionalProperties: False - -type: array -items: - oneOf: - - $ref: "#/definitions/interface" - - $ref: "#/definitions/route_table" - - $ref: "#/definitions/sriov_pf" - - $ref: "#/definitions/sriov_vf" - - $ref: "#/definitions/vlan" - - $ref: "#/definitions/ovs_bridge" - - $ref: "#/definitions/ovs_user_bridge" - - $ref: "#/definitions/ovs_bond" - - $ref: "#/definitions/ovs_patch_port" - - $ref: "#/definitions/ovs_tunnel" - - $ref: "#/definitions/ovs_dpdk_bond" - - $ref: "#/definitions/ovs_dpdk_port" - - $ref: "#/definitions/linux_bridge" - - $ref: "#/definitions/linux_bond" - - $ref: "#/definitions/linux_team" - - $ref: "#/definitions/ivs_bridge" - - $ref: "#/definitions/ivs_interface" - - $ref: "#/definitions/nfvswitch_bridge" - - $ref: "#/definitions/nfvswitch_internal" - - $ref: "#/definitions/ib_interface" - - $ref: "#/definitions/ib_child_interface" - - $ref: "#/definitions/vpp_interface" - - $ref: "#/definitions/vpp_bond" - - $ref: "#/definitions/contrail_vrouter" - - $ref: "#/definitions/contrail_vrouter_dpdk" - - $ref: "#/definitions/linux_tap" -minItems: 1 diff --git a/os_net_config/sriov_bind_config.py b/os_net_config/sriov_bind_config.py deleted file mode 100644 index 90bc6cc8..00000000 --- a/os_net_config/sriov_bind_config.py +++ /dev/null @@ -1,137 +0,0 @@ -# Copyright 2020 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. - -# - - -import logging -import os -import yaml - - -from oslo_concurrency import processutils - - -logger = logging.getLogger(__name__) -_PCI_DRIVER_BIND_FILE_PATH = "/sys/bus/pci/drivers/%(driver)s/bind" -_PCI_DRIVER_FILE_PATH = "/sys/bus/pci/devices/%(pci)s/driver" -_SRIOV_BIND_CONFIG_FILE = "/var/lib/os-net-config/sriov_bind_config.yaml" -_SRIOV_BIND_SERVICE_FILE = "/etc/systemd/system/sriov_bind.service" -_SRIOV_BIND_SERVICE_CONTENT = """[Unit] -Description=SR-IOV vfs binding -After=network.service sriov_config.service - -[Service] -Type=oneshot -ExecStart=/usr/bin/os-net-config-sriov-bind - -[Install] -WantedBy=multi-user.target -""" - -# File to contain the map of drivers and it's VFs list that should be bound -# Format of the file shall be -# : -# - '' -# - '' -# - '' -# - '' -# : -# - '' -# - '' -# - '' -# - '' - - -def get_file_data(filename): - if not os.path.exists(filename): - logger.error("Error file is not exist: %s" % filename) - raise FileNotFoundError(filename) - try: - with open(filename, 'r') as f: - return f.read() - except IOError: - logger.error("Error reading file: %s" % filename) - raise - - -def ensure_directory_presence(filepath): - dir_path = os.path.dirname(filepath) - if not os.path.exists(dir_path): - os.makedirs(dir_path) - - -def write_yaml_config(filepath, data): - ensure_directory_presence(filepath) - with open(filepath, 'w') as f: - yaml.safe_dump(data, f, default_flow_style=False) - - -def update_sriov_bind_pcis_map(sriov_bind_pcis_map): - sriov_bind_config_data = {} - try: - sriov_bind_config_data = _get_sriov_bind_pcis_map() - except Exception: - pass - # Compare two levels of the dictionary to conditionally write - # sriov_bind_pcis_map if it differs from existning sriov_bind_config_data - if (sriov_bind_config_data == {} or - set(sriov_bind_config_data.keys()) != - set(sriov_bind_pcis_map.keys()) or not - all([set(sriov_bind_config_data[key]) == - set(sriov_bind_pcis_map[key]) for key in - sriov_bind_config_data])): - write_yaml_config(_SRIOV_BIND_CONFIG_FILE, sriov_bind_pcis_map) - - -def _get_sriov_bind_pcis_map(): - contents = get_file_data(_SRIOV_BIND_CONFIG_FILE) - sriov_bind_pcis_map = yaml.safe_load(contents) if contents else {} - return sriov_bind_pcis_map - - -def configure_sriov_bind_service(): - """Generate the sriov_bind.service - - sriov_bind service shall bind all the vfs of switchdev-mode mlnx SriovPF - nics during reboot of the nodes. - """ - with open(_SRIOV_BIND_SERVICE_FILE, 'w') as f: - f.write(_SRIOV_BIND_SERVICE_CONTENT) - processutils.execute('systemctl', 'enable', 'sriov_bind') - - -def bind_vfs(sriov_bind_pcis_map=None): - if not sriov_bind_pcis_map: - sriov_bind_pcis_map = _get_sriov_bind_pcis_map() - for driver, pcis_list in sriov_bind_pcis_map.items(): - for vf_pci in pcis_list: - vf_pci_driver_path = _PCI_DRIVER_FILE_PATH % {"pci": vf_pci} - if not os.path.exists(vf_pci_driver_path): - pci_driver_bind_file_path = _PCI_DRIVER_BIND_FILE_PATH %\ - {"driver": driver} - try: - with open(pci_driver_bind_file_path, 'w') as f: - f.write("%s" % vf_pci) - logger.info("Vf %s has been bound" % vf_pci) - except IOError: - logger.error("Failed to bind vf %s" % vf_pci) - - -def main(): - bind_vfs() - - -if __name__ == "__main__": - main() diff --git a/os_net_config/sriov_config.py b/os_net_config/sriov_config.py deleted file mode 100644 index 29695300..00000000 --- a/os_net_config/sriov_config.py +++ /dev/null @@ -1,816 +0,0 @@ -# -*- 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. - -# -# The sriov_config.py module does the SR-IOV PF configuration. -# It'll be invoked by the sriov_config systemd service for the persistence of -# the SR-IOV configuration across reboots. And os-net-config:utils also invokes -# it for the first time configuration. -# An entry point os-net-config-sriov is added for invocation of this module. - -import argparse -import os -import pyudev -import queue -import re -import sys -import time - -from json import loads -from os_net_config import common -from os_net_config import sriov_bind_config -from oslo_concurrency import processutils - -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' -_RESET_SRIOV_RULES_FILE = '/etc/udev/rules.d/70-tripleo-reset-sriov.rules' -_ALLOCATE_VFS_FILE = '/etc/sysconfig/allocate_vfs' -_MLNX_DRIVER = "mlx5_core" -MLNX_UNBIND_FILE_PATH = "/sys/bus/pci/drivers/mlx5_core/unbind" -MLNX5_VDPA_KMODS = [ - "vdpa", - "vhost_vdpa", - "mlx5_vdpa", -] - -MAX_RETRIES = 10 -MLNX_LAG_PATH = "/sys/kernel/debug/mlx5/{pf_pci}/lag/state" -PF_FUNC_RE = re.compile(r"\.(\d+)$", 0) - -VF_PCI_RE = re.compile(r'/[\d]{4}\:(\d+):(\d+)\.(\d+)/net/[^\/]+$') -# In order to keep VF representor name consistent specially after the upgrade -# proccess, we should have a udev rule to handle that. -# The udev rule will rename the VF representor as "_" -_REP_LINK_NAME_FILE = "/etc/udev/rep-link-name.sh" -_REP_LINK_NAME_DATA = '''#!/bin/bash -# This file is autogenerated by os-net-config -set -x -PORT="$1" -echo "NUMBER=${PORT##pf*vf}" -''' - -# Create a queue for passing the udev network events -vf_queue = queue.Queue() - - -# Global variable to store link between pci/pf -# for udev rule creationg when dealing with mlnx vdpa -vf_to_pf = {} - - -class SRIOVNumvfsException(ValueError): - pass - - -def udev_event_handler(action, device): - event = {"action": action, "device": device.sys_path} - logger.info( - f"Received udev event {event['action']} for {event['device']}" - ) - vf_queue.put(event) - - -def _norm_path(dev, suffix): - return os.path.normpath(os.path.join(dev, suffix)) - - -def _get_pf_path(device): - pf_path = _norm_path(device, "../../physfn/net") - if not os.path.isdir(pf_path): - pf_path = _norm_path(device, "physfn/net") - if not os.path.isdir(pf_path): - pf_path = None - return pf_path - - -def _driver_unbind(dev): - vf_pci_path = f"/sys/bus/pci/devices/{dev}/driver" - if os.path.exists(vf_pci_path): - logger.info(f"{dev}: Unbinding driver") - with open(MLNX_UNBIND_FILE_PATH, 'w') as f: - f.write(dev) - else: - logger.info(f"{dev}: No driver to unbind") - - -def _wait_for_vf_creation(pf_name, numvfs): - vf_count = 0 - pf_config = common.get_sriov_map(pf_name) - vdpa = False - if len(pf_config): - vdpa = pf_config[0].get('vdpa', False) - while vf_count < numvfs: - try: - # wait for 5 seconds after every udev event - event = vf_queue.get(True, 5) - vf_name = os.path.basename(event["device"]) - pf_path = _get_pf_path(event["device"]) - logger.debug(f"{event['device']}: Got udev event: {event}") - if pf_path: - pf_nic = os.listdir(pf_path) - # NOTE(dvd): For vDPA devices, the VF event we're interrested - # in contains all the VFs. We can also use this to build a dict - # to correlate the VF pci address to the PF when creating the - # vdpa representator udev rule - # - # Data structure sample for vDPA: - # pf_path: - # /sys/devices/pci0000:00/0000:00:02.2/0000:06:01.2/physfn/net - # pf_nic: ['enp6s0f1np1_0', 'enp6s0f1np1_1', 'enp6s0f1np1'] - # pf_name: enp6s0f1np1 - if vf_name not in vf_to_pf and pf_name in pf_nic: - vf_to_pf[vf_name] = { - 'device': event['device'], - 'pf': pf_name - } - logger.info( - f"{pf_name}: VF {vf_name} created" - ) - vf_count += 1 - elif vf_name in vf_to_pf: - logger.debug( - f"{pf_name}: VF {vf_name} was already created" - ) - elif vdpa: - logger.warning(f"{pf_name}: This PF is not in {pf_path}") - else: - logger.warning( - f"{pf_name}: Unable to parse event {event['device']}" - ) - elif not vdpa: - logger.warning(f"{event['device']}: Unable to find PF") - except queue.Empty: - logger.info(f"{pf_name}: Timeout in the creation of VFs") - return - logger.info(f"{pf_name}: Required VFs are created") - - -def get_numvfs(ifname): - """Getting sriov_numvfs for PF - - Wrapper that will get the sriov_numvfs file for a PF. - - :param ifname: interface name (ie: p1p1) - :returns: int -- the number of current VFs on ifname - :raises: SRIOVNumvfsException - """ - sriov_numvfs_path = common.get_dev_path(ifname, "sriov_numvfs") - logger.debug(f"{ifname}: Getting numvfs for interface") - try: - with open(sriov_numvfs_path, 'r') as f: - curr_numvfs = int(f.read()) - except IOError as exc: - msg = f"{ifname}: Unable to read numvfs: {exc}" - raise SRIOVNumvfsException(msg) - logger.debug(f"{ifname}: Interface has {curr_numvfs} configured") - return curr_numvfs - - -def set_numvfs(ifname, numvfs): - """Setting sriov_numvfs for PF - - Wrapper that will set the sriov_numvfs file for a PF. - - After numvfs has been set for an interface, _wait_for_vf_creation will be - called to monitor the creation. - - Some restrictions: - - if current number of VF is already defined, we can't change numvfs - - if sriov_numvfs doesn't exist for an interface, we can't create it - - :param ifname: interface name (ie: p1p1) - :param numvfs: an int that represents the number of VFs to be created. - :returns: int -- the number of current VFs on ifname - :raises: SRIOVNumvfsException - """ - curr_numvfs = get_numvfs(ifname) - logger.debug(f"{ifname}: Interface has {curr_numvfs} configured, setting " - f"to {numvfs}") - if not isinstance(numvfs, int): - msg = (f"{ifname}: Unable to configure pf with numvfs: {numvfs}\n" - f"numvfs must be an integer") - raise SRIOVNumvfsException(msg) - - if numvfs != curr_numvfs: - if curr_numvfs != 0: - logger.warning(f"{ifname}: Numvfs already configured to " - f"{curr_numvfs}") - return curr_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: - f.write("%d" % numvfs) - except IOError as exc: - msg = (f"{ifname} Unable to configure pf with numvfs: {numvfs}\n" - f"{exc}") - raise SRIOVNumvfsException(msg) - - _wait_for_vf_creation(ifname, numvfs) - curr_numvfs = get_numvfs(ifname) - if curr_numvfs != numvfs: - msg = (f"{ifname}: Unable to configure pf with numvfs: {numvfs}\n" - "sriov_numvfs file is not set to the targeted number of " - "vfs") - raise SRIOVNumvfsException(msg) - return curr_numvfs - - -def restart_ovs_and_pfs_netdevs(): - sriov_map = common.get_sriov_map() - processutils.execute('/usr/bin/systemctl', 'restart', 'openvswitch') - for item in sriov_map: - if item['device_type'] == 'pf': - if_down_interface(item['name']) - if_up_interface(item['name']) - - -def cleanup_puppet_config(): - file_contents = "" - if os.path.exists(_RESET_SRIOV_RULES_FILE): - os.remove(_RESET_SRIOV_RULES_FILE) - if os.path.exists(_ALLOCATE_VFS_FILE): - os.remove(_ALLOCATE_VFS_FILE) - if os.path.exists(_IFUP_LOCAL_FILE): - # Remove the invocation of allocate_vfs script generated by puppet - # After the removal of allocate_vfs, if the ifup-local file has just - # "#!/bin/bash" left, then remove the file as well. - with open(_IFUP_LOCAL_FILE) as oldfile: - for line in oldfile: - if "/etc/sysconfig/allocate_vfs" not in line: - file_contents = file_contents + line - if file_contents.strip() == "#!/bin/bash": - os.remove(_IFUP_LOCAL_FILE) - else: - with open(_IFUP_LOCAL_FILE, 'w') as newfile: - newfile.write(file_contents) - - -def udev_monitor_setup(): - # Create a context for pyudev and observe udev events for network - context = pyudev.Context() - monitor = pyudev.Monitor.from_netlink(context) - monitor.filter_by('net') - observer = pyudev.MonitorObserver(monitor, udev_event_handler) - return observer - - -def udev_monitor_start(observer): - observer.start() - - -def udev_monitor_stop(observer): - observer.stop() - - -def is_partitioned_pf(dev_name: str) -> bool: - """Check if any nic-partition(VF) is already used - - Given a PF device, returns True if any VFs of this - device are in-use. - """ - sriov_map = common.get_sriov_map() - for config in sriov_map: - devtype = config.get('device_type', None) - if devtype == 'vf': - name = config.get('device', {}).get('name') - vf_name = config.get('name') - if dev_name == name: - logger.warning(f"{name} has VF({vf_name}) used by host") - return True - return False - - -def configure_sriov_pf(execution_from_cli=False, restart_openvswitch=False): - observer = udev_monitor_setup() - udev_monitor_start(observer) - - sriov_map = common.get_sriov_map() - dpdk_vfs_pcis_list = [] - vf_lag_sriov_pfs_list = [] - trigger_udev_rule = False - - # Cleanup the previous config by puppet-tripleo - cleanup_puppet_config() - if any(item.get('vdpa') for item in sriov_map): - common.load_kmods(MLNX5_VDPA_KMODS) - vdpa_devices = get_vdpa_vhost_devices() - - for item in sriov_map: - if item['device_type'] == 'pf': - if pf_configure_status(item): - logger.debug(f"PF {item['name']} is already configured") - continue - _pf_interface_up(item) - if item.get('link_mode') == "legacy": - # Add a udev rule to configure the VF's when PF's are - # released by a guest - if not is_partitioned_pf(item['name']): - add_udev_rule_for_legacy_sriov_pf(item['name'], - item['numvfs']) - # When configuring vdpa, we need to configure switchdev before - # we create the VFs - is_mlnx = common.is_mellanox_interface(item['name']) - vdpa = item.get('vdpa') - # Configure switchdev mode when vdpa - # It has to happen before we set_numvfs - if vdpa and is_mlnx: - configure_switchdev(item['name']) - set_numvfs(item['name'], item['numvfs']) - # Configure switchdev, unbind driver and configure vdpa - if item.get('link_mode') == "switchdev" and is_mlnx: - logger.info(f"{item['name']}: Mellanox card") - vf_pcis_list = get_vf_pcis_list(item['name']) - for vf_pci in vf_pcis_list: - if not vdpa: - # For DPDK, we need to unbind the driver - _driver_unbind(vf_pci) - else: - if vf_pci not in vdpa_devices: - configure_vdpa_vhost_device(vf_pci) - else: - logger.info( - f"{item['name']}: vDPA device already created " - f"for {vf_pci}" - ) - if vdpa: - common.restorecon('/dev/vhost-*') - logger.info(f"{item['name']}: Adding udev rules") - # Adding a udev rule to make vf-representors unmanaged by - # NetworkManager - add_udev_rule_to_unmanage_vf_representors_by_nm() - - # Adding a udev rule to save the sriov_pf name - trigger_udev_rule = add_udev_rule_for_sriov_pf(item['name'])\ - or trigger_udev_rule - - trigger_udev_rule = add_udev_rule_for_vf_representors( - item['name']) or trigger_udev_rule - - if not vdpa: - # This is used for the sriov_bind_config - dpdk_vfs_pcis_list += vf_pcis_list - - # Configure flow steering mode, default to smfs - configure_flow_steering(item['name'], - item.get('steering_mode', 'smfs')) - - # Configure switchdev mode - configure_switchdev(item['name']) - # Add sriovpf to vf_lag_sriov_pfs_list if it's - # a linux bond member (lag_candidate) - if item.get('lag_candidate', False): - vf_lag_sriov_pfs_list.append(item['name']) - # Adding a udev rule to rename vf-representors - else: - trigger_udev_rule = add_udev_rule_for_vdpa_representors( - item['name']) or trigger_udev_rule - - # Moving the sriov-PFs to switchdev mode will put the netdev - # interfaces in down state. - # In case we are running during initial deployment, - # bring the interfaces up. - # In case we are running as part of the sriov_config service - # after reboot, net config scripts, which run after - # sriov_config service will bring the interfaces up. - if execution_from_cli: - if_up_interface(item['name']) - - if restart_openvswitch: - restart_ovs_and_pfs_netdevs() - - if vf_lag_sriov_pfs_list and execution_from_cli: - _wait_for_lag_creation(vf_lag_sriov_pfs_list) - - if dpdk_vfs_pcis_list and not vdpa: - sriov_bind_pcis_map = {_MLNX_DRIVER: dpdk_vfs_pcis_list} - if not execution_from_cli: - sriov_bind_config.update_sriov_bind_pcis_map(sriov_bind_pcis_map) - else: - sriov_bind_config.configure_sriov_bind_service() - sriov_bind_config.bind_vfs(sriov_bind_pcis_map) - - # Trigger udev rules if there is new rules written - if trigger_udev_rule: - trigger_udev_rules() - - udev_monitor_stop(observer) - - -def _wait_for_uplink_rep_creation(pf_name): - uplink_rep_phys_switch_id_path = f"/sys/class/net/{pf_name}/phys_switch_id" - - for i in range(MAX_RETRIES): - if common.get_file_data(uplink_rep_phys_switch_id_path): - logger.info(f"{pf_name} Uplink representor ready") - break - time.sleep(1) - else: - raise RuntimeError(f"{pf_name}: Timeout waiting uplink representor") - - -def _wait_for_lag_creation(lag_sriov_pf_list): - for sriov_pf in lag_sriov_pf_list: - pf_pci = get_pf_pci(sriov_pf) - lag_path = MLNX_LAG_PATH.format(pf_pci=pf_pci) - if os.path.exists(lag_path): - for i in range(MAX_RETRIES): - lag_state = common.get_file_data(lag_path).strip() - if lag_state == "active": - logger.info(f"VF-LAG is enabled for interface {sriov_pf}" - f" after {i} retries") - break - time.sleep(1) - else: - raise RuntimeError("VF-LAG is not created for interface" - f" {sriov_pf} after {i} retries") - else: - logger.warning(f"Lag path {lag_path} does not exist for this " - "kernel, skipping..") - - -def create_rep_link_name_script(): - with open(_REP_LINK_NAME_FILE, "w") as f: - f.write(_REP_LINK_NAME_DATA) - # Make the _REP_LINK_NAME_FILE executable - os.chmod(_REP_LINK_NAME_FILE, 0o755) - - -def add_udev_rule_for_sriov_pf(pf_name): - logger.info(f"{pf_name}: adding udev rules for sriov") - pf_pci = get_pf_pci(pf_name) - udev_data_line = 'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", '\ - f'KERNELS=="{pf_pci}", NAME="{pf_name}"' - return add_udev_rule(udev_data_line, _UDEV_RULE_FILE) - - -def add_udev_rule_for_legacy_sriov_pf(pf_name, numvfs): - logger.info(f"{pf_name}: adding udev rules for legacy sriov: {numvfs}") - udev_line = f'KERNEL=="{pf_name}", '\ - f'RUN+="/bin/os-net-config-sriov -n %k:{numvfs}"' - pattern = f'KERNEL=="{pf_name}", RUN+="/bin/os-net-config-sriov -n' - return add_udev_rule(udev_line, _UDEV_LEGACY_RULE_FILE, pattern) - - -def add_udev_rule_for_vf_representors(pf_name): - logger.info(f"{pf_name}: adding udev rules for vf representators") - phys_switch_id_path = common.get_dev_path(pf_name, - "_phys_switch_id") - phys_switch_id = common.get_file_data(phys_switch_id_path).strip() - pf_pci = get_pf_pci(pf_name) - pf_fun_num_match = PF_FUNC_RE.search(pf_pci) - if not pf_fun_num_match: - logger.error(f"{pf_name}: Failed to get function number " - "and so failed to create a udev rule for renaming " - "its vf-represent") - return - - pf_fun_num = pf_fun_num_match.group(1) - udev_data_line = 'SUBSYSTEM=="net", ACTION=="add", ATTR{phys_switch_id}'\ - '=="%s", ATTR{phys_port_name}=="pf%svf*", '\ - 'IMPORT{program}="%s $attr{phys_port_name}", '\ - 'NAME="%s_$env{NUMBER}"' % (phys_switch_id, - pf_fun_num, - _REP_LINK_NAME_FILE, - pf_name) - create_rep_link_name_script() - return add_udev_rule(udev_data_line, _UDEV_RULE_FILE) - - -def add_udev_rule_for_vdpa_representors(pf_name): - logger.info(f"{pf_name}: adding udev rules for vdpa representators") - udev_lines = "" - for vf, att in vf_to_pf.items(): - mac = common.interface_mac(vf) - vadd = VF_PCI_RE.search(att.get('device')) - if not vadd: - logger.error( - f"{att.get('device')}/{vf}: Failed to get pf/vf numbers " - "and so failed to create a udev rule for renaming vdpa dev" - ) - continue - vdpa_rep = f"vdpa{vadd.group(1)}p{vadd.group(2)}vf{vadd.group(3)}" - logger.info(f"{vdpa_rep}: Adding udev representor rule.") - udev_lines += ( - 'SUBSYSTEM=="net", ACTION=="add", ' - f'ATTR{{address}}=="{mac}", NAME="{vdpa_rep}"\n' - ) - return add_udev_rule(udev_lines, _UDEV_RULE_FILE) - - -def add_udev_rule_to_unmanage_vf_representors_by_nm(): - logger.info("adding udev rules to unmanage vf representators") - udev_data_line = 'SUBSYSTEM=="net", ACTION=="add", ATTR{phys_switch_id}'\ - '!="", ATTR{phys_port_name}=="pf*vf*", '\ - 'ENV{NM_UNMANAGED}="1"' - return add_udev_rule(udev_data_line, _UDEV_RULE_FILE) - - -def add_udev_rule(udev_data, udev_file, pattern=None): - logger.debug(f"adding udev rule to {udev_file}: {udev_data}") - trigger_udev_rule = False - udev_data = udev_data.strip() - if not pattern: - pattern = udev_data - if not os.path.exists(udev_file): - with open(udev_file, "w") as f: - data = "# This file is autogenerated by os-net-config\n"\ - f"{udev_data}\n" - f.write(data) - else: - file_data = common.get_file_data(udev_file) - udev_lines = file_data.splitlines() - if pattern in file_data: - if udev_data in udev_lines: - return trigger_udev_rule - with open(udev_file, "w") as f: - for line in udev_lines: - if pattern in line: - f.write(udev_data + "\n") - else: - f.write(line + "\n") - else: - with open(udev_file, "a") as f: - f.write(udev_data + "\n") - - reload_udev_rules() - trigger_udev_rule = True - return trigger_udev_rule - - -def reload_udev_rules(): - try: - processutils.execute('/usr/sbin/udevadm', 'control', '--reload-rules') - logger.info("udev rules reloaded successfully") - except processutils.ProcessExecutionError as exc: - logger.error(f"Failed to reload udev rules: {exc}") - raise - - -def trigger_udev_rules(): - try: - processutils.execute('/usr/sbin/udevadm', 'trigger', '--action=add', - '--attr-match=subsystem=net') - logger.info("udev rules triggered successfully") - except processutils.ProcessExecutionError as exc: - logger.error(f"Failed to trigger udev rules: {exc}") - raise - - -def configure_switchdev(pf_name): - pf_pci = get_pf_pci(pf_name) - pf_device_id = get_pf_device_id(pf_name) - if pf_device_id == "0x1013" or pf_device_id == "0x1015": - try: - processutils.execute('/usr/sbin/devlink', 'dev', 'eswitch', 'set', - f'pci/{pf_pci}', 'inline-mode', 'transport') - except processutils.ProcessExecutionError as exc: - logger.error(f"{pf_name}: Failed to set inline-mode to transport " - f"for {pf_pci}: {exc}") - raise - try: - processutils.execute('/usr/sbin/devlink', 'dev', 'eswitch', 'set', - f'pci/{pf_pci}', 'mode', 'switchdev') - except processutils.ProcessExecutionError as exc: - logger.error(f"{pf_name}: Failed to set mode to switchdev for " - f"{pf_pci}: {exc}") - raise - logger.info(f"{pf_name}: Device pci/{pf_pci} set to switchdev mode.") - - # WA to make sure that the uplink_rep is ready after moving to switchdev, - # as moving to switchdev will remove the sriov_pf and create uplink - # representor, so we need to make sure that uplink representor is ready - # before proceed - _wait_for_uplink_rep_creation(pf_name) - - try: - processutils.execute('/usr/sbin/ethtool', '-K', pf_name, - 'hw-tc-offload', 'on') - logger.info(f"{pf_name}: Enabled \"hw-tc-offload\" for PF.") - except processutils.ProcessExecutionError as exc: - logger.error(f"{pf_name}: Failed to enable hw-tc-offload: {exc}") - raise - - -def get_vdpa_vhost_devices(): - logger.info(f"Getting list of vdpa devices") - try: - stdout, stderr = processutils.execute('vdpa', '-j', 'dev') - except processutils.ProcessExecutionError as exc: - logger.error(f"Failed to get vdpa vhost devices: {exc}") - raise - return loads(stdout)['dev'] - - -def configure_vdpa_vhost_device(pci): - logger.info(f"{pci}: Creating vdpa device") - try: - processutils.execute('vdpa', 'dev', 'add', 'name', pci, - 'mgmtdev', f'pci/{pci}') - except processutils.ProcessExecutionError as exc: - logger.error(f"{pci}: Failed to create vdpa vhost device: {exc}") - raise - - -def configure_flow_steering(pf_name, steering_mode): - pf_pci = get_pf_pci(pf_name) - try: - processutils.execute('/usr/sbin/devlink', 'dev', 'param', 'set', - f'pci/{pf_pci}', 'name', 'flow_steering_mode', - 'value', steering_mode, 'cmode', 'runtime') - logger.info(f"{pf_name}: Device pci/{pf_pci} is set to" - " {steering_mode} steering mode.") - except processutils.ProcessExecutionError as exc: - logger.warning(f"{pf_name}: Could not set pci/{pf_pci} to" - f" {steering_mode} steering mode: {exc}") - - -def run_ip_config_cmd(*cmd, **kwargs): - logger.info("Running %s" % ' '.join(cmd)) - try: - processutils.execute(*cmd, delay_on_retry=True, attempts=10, **kwargs) - except processutils.ProcessExecutionError as exc: - logger.error("Failed to execute %s: %s" % (' '.join(cmd), exc)) - raise - - -def _pf_interface_up(pf_device): - if 'promisc' in pf_device: - run_ip_config_cmd('ip', 'link', 'set', 'dev', pf_device['name'], - 'promisc', pf_device['promisc']) - logger.info(f"{pf_device['name']}: Bringing up PF") - run_ip_config_cmd('ip', 'link', 'set', 'dev', pf_device['name'], 'up') - - -def pf_configure_status(pf_device): - return pf_device['numvfs'] == get_numvfs(pf_device['name']) - - -def run_ip_config_cmd_safe(raise_error, *cmd, **kwargs): - try: - run_ip_config_cmd(*cmd) - except processutils.ProcessExecutionError: - if raise_error: - raise - - -def get_pf_pci(pf_name): - pf_pci_path = common.get_dev_path(pf_name, "uevent") - pf_info = common.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 = common.get_dev_path(pf_name, "device") - pf_device_id = common.get_file_data(pf_device_path).strip() - return pf_device_id - - -def get_vf_pcis_list(pf_name): - vf_pcis_list = [] - pf_files = os.listdir(common.get_dev_path(pf_name, "_device")) - for pf_file in pf_files: - if pf_file.startswith("virtfn"): - vf_info = common.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)) - return vf_pcis_list - - -def if_down_interface(device): - logger.info(f"{device}: Running /sbin/ifdown") - try: - processutils.execute('/sbin/ifdown', device) - except processutils.ProcessExecutionError: - logger.error(f"{device}: Failed to ifdown") - raise - - -def if_up_interface(device): - logger.info(f"{device}: Running /sbin/ifup") - try: - processutils.execute('/sbin/ifup', device) - except processutils.ProcessExecutionError: - logger.error(f"{device}: Failed to ifup") - raise - - -def configure_sriov_vf(): - sriov_map = common.get_sriov_map() - for item in sriov_map: - raise_error = True - if item['device_type'] == 'vf': - pf_name = item['device']['name'] - vfid = item['device']['vfid'] - base_cmd = ('ip', 'link', 'set', 'dev', pf_name, 'vf', str(vfid)) - logger.info(f"{pf_name}: Configuring settings for VF: {vfid} " - f"VF name: {item['name']}") - raise_error = True - if 'macaddr' in item: - cmd = base_cmd + ('mac', item['macaddr']) - run_ip_config_cmd(*cmd) - if 'vlan_id' in item: - vlan_cmd = base_cmd + ('vlan', str(item['vlan_id'])) - if 'qos' in item: - vlan_cmd = vlan_cmd + ('qos', str(item['qos'])) - run_ip_config_cmd(*vlan_cmd) - if 'max_tx_rate' in item: - cmd = base_cmd + ('max_tx_rate', str(item['max_tx_rate'])) - if item['max_tx_rate'] == 0: - raise_error = False - run_ip_config_cmd_safe(raise_error, *cmd) - if 'min_tx_rate' in item: - cmd = base_cmd + ('min_tx_rate', str(item['min_tx_rate'])) - if item['min_tx_rate'] == 0: - raise_error = False - run_ip_config_cmd_safe(raise_error, *cmd) - if 'spoofcheck' in item: - cmd = base_cmd + ('spoofchk', item['spoofcheck']) - run_ip_config_cmd(*cmd) - if 'state' in item: - cmd = base_cmd + ('state', item['state']) - run_ip_config_cmd(*cmd) - if 'trust' in item: - cmd = base_cmd + ('trust', item['trust']) - run_ip_config_cmd(*cmd) - if 'promisc' in item: - run_ip_config_cmd('ip', 'link', 'set', 'dev', item['name'], - 'promisc', item['promisc']) - if 'driver' in item: - common.set_driverctl_override(item['pci_address'], - item['driver']) - - -def parse_opts(argv): - - parser = argparse.ArgumentParser( - description='Configure SR-IOV PF and VF interfaces using a YAML' - ' config file format.') - - parser.add_argument( - '-d', '--debug', - dest="debug", - action='store_true', - help="Print debugging output.", - required=False) - - parser.add_argument( - '-v', '--verbose', - dest="verbose", - action='store_true', - help="Print verbose output.", - required=False) - - parser.add_argument( - '-n', '--numvfs', - dest="numvfs", - action='store', - help="Provide the numvfs for device in the format :", - required=False) - - opts = parser.parse_args(argv[1:]) - - return opts - - -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() - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/os_net_config/tests/__init__.py b/os_net_config/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/os_net_config/tests/base.py b/os_net_config/tests/base.py deleted file mode 100644 index 3a643b01..00000000 --- a/os_net_config/tests/base.py +++ /dev/null @@ -1,77 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2010-2011 OpenStack Foundation -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# 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. - -import os - -import fixtures -import testtools - -_TRUE_VALUES = ('True', 'true', '1', 'yes') - - -class TestCase(testtools.TestCase): - - """Test case base class for all unit tests.""" - stub_mapped_nics = True - - def setUp(self): - """Run before each test method to initialize test environment.""" - - super(TestCase, self).setUp() - self.stubbed_mapped_nics = {} - - def dummy_mapped_nics(nic_mapping=None): - return self.stubbed_mapped_nics - if self.stub_mapped_nics: - self.stub_out('os_net_config.objects.mapped_nics', - dummy_mapped_nics) - - test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0) - try: - test_timeout = int(test_timeout) - except ValueError: - # If timeout value is invalid do not set a timeout. - test_timeout = 0 - if test_timeout > 0: - self.useFixture(fixtures.Timeout(test_timeout, gentle=True)) - - self.useFixture(fixtures.NestedTempfile()) - self.useFixture(fixtures.TempHomeDir()) - - if os.environ.get('OS_STDOUT_CAPTURE') in _TRUE_VALUES: - stdout = self.useFixture(fixtures.StringStream('stdout')).stream - self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout)) - if os.environ.get('OS_STDERR_CAPTURE') in _TRUE_VALUES: - stderr = self.useFixture(fixtures.StringStream('stderr')).stream - self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr)) - - self.log_fixture = self.useFixture(fixtures.FakeLogger()) - - def stub_out(self, old, new): - """Replace a function for the duration of the test. - - Use the monkey patch fixture to replace a function for the - duration of a test. Useful when you want to provide fake - methods instead of mocks during testing. - - This should be used instead of set.stubs.Set (which is based - on mox) going forward. - """ - self.useFixture(fixtures.MonkeyPatch(old, new)) - - def tearDown(self): - super(TestCase, self).tearDown() diff --git a/os_net_config/tests/environment/netinfo_running_info_1.yaml b/os_net_config/tests/environment/netinfo_running_info_1.yaml deleted file mode 100644 index 64c330fa..00000000 --- a/os_net_config/tests/environment/netinfo_running_info_1.yaml +++ /dev/null @@ -1,438 +0,0 @@ -dns-resolver: - config: {} -hostname: - config: dell-r640-oss-14.lab.eng.brq.redhat.com - running: dell-r640-oss-14.lab.eng.brq.redhat.com -interfaces: -- accept-all-mac-addresses: false - ethernet: - auto-negotiation: true - duplex: full - speed: 1000 - sr-iov: - total-vfs: 0 - vfs: [] - ethtool: - coalesce: - adaptive-rx: true - adaptive-tx: true - rx-usecs: 50 - rx-usecs-high: 0 - tx-frames-irq: 256 - tx-usecs: 50 - tx-usecs-high: 0 - feature: - highdma: true - hw-tc-offload: false - l2-fwd-offload: false - rx-checksum: true - rx-gro: true - rx-gro-list: false - rx-hashing: true - rx-ntuple-filter: true - rx-udp-gro-forwarding: false - rx-udp_tunnel-port-offload: true - rx-vlan-hw-parse: true - tx-checksum-ip-generic: true - tx-checksum-sctp: true - tx-generic-segmentation: true - tx-gre-csum-segmentation: true - tx-gre-segmentation: true - tx-gso-partial: true - tx-ipxip4-segmentation: true - tx-ipxip6-segmentation: true - tx-nocache-copy: false - tx-tcp-ecn-segmentation: true - tx-tcp-mangleid-segmentation: false - tx-tcp-segmentation: true - tx-tcp6-segmentation: true - tx-udp-segmentation: true - tx-udp_tnl-csum-segmentation: true - tx-udp_tnl-segmentation: true - tx-vlan-hw-insert: true - pause: - autoneg: true - rx: false - tx: false - ring: - rx: 512 - rx-max: 4096 - tx: 512 - tx-max: 4096 - ipv4: - address: [] - auto-dns: true - auto-gateway: true - auto-route-table-id: 0 - auto-routes: true - dhcp: true - enabled: true - ipv6: - addr-gen-mode: eui64 - address: - - ip: fe80::e643:4bff:fe5c:9680 - prefix-length: 64 - auto-dns: true - auto-gateway: true - auto-route-table-id: 0 - auto-routes: true - autoconf: true - dhcp: true - enabled: true - lldp: - enabled: false - mac-address: E4:43:4B:5C:96:80 - mtu: 1500 - name: eno1 - state: up - type: ethernet - wait-ip: any -- accept-all-mac-addresses: false - ethernet: - auto-negotiation: false - duplex: full - speed: 10000 - sr-iov: - total-vfs: 0 - vfs: [] - ethtool: - coalesce: - adaptive-rx: true - adaptive-tx: true - rx-usecs: 50 - rx-usecs-high: 0 - tx-frames-irq: 256 - tx-usecs: 50 - tx-usecs-high: 0 - feature: - highdma: true - hw-tc-offload: false - l2-fwd-offload: false - rx-checksum: true - rx-gro: true - rx-gro-list: false - rx-hashing: true - rx-ntuple-filter: true - rx-udp-gro-forwarding: false - rx-udp_tunnel-port-offload: true - rx-vlan-hw-parse: true - tx-checksum-ip-generic: true - tx-checksum-sctp: true - tx-generic-segmentation: true - tx-gre-csum-segmentation: true - tx-gre-segmentation: true - tx-gso-partial: true - tx-ipxip4-segmentation: true - tx-ipxip6-segmentation: true - tx-nocache-copy: false - tx-tcp-ecn-segmentation: true - tx-tcp-mangleid-segmentation: false - tx-tcp-segmentation: true - tx-tcp6-segmentation: true - tx-udp-segmentation: true - tx-udp_tnl-csum-segmentation: true - tx-udp_tnl-segmentation: true - tx-vlan-hw-insert: true - pause: - autoneg: false - rx: false - tx: false - ring: - rx: 512 - rx-max: 4096 - tx: 512 - tx-max: 4096 - ipv4: - enabled: false - ipv6: - enabled: false - mac-address: E4:43:4B:5C:96:81 - mtu: 1500 - name: eno2 - state: down - type: ethernet -- accept-all-mac-addresses: false - ethernet: - auto-negotiation: false - duplex: full - speed: 10000 - sr-iov: - total-vfs: 0 - vfs: [] - ethtool: - coalesce: - adaptive-rx: true - adaptive-tx: true - rx-usecs: 50 - rx-usecs-high: 0 - tx-frames-irq: 256 - tx-usecs: 50 - tx-usecs-high: 0 - feature: - highdma: true - hw-tc-offload: false - l2-fwd-offload: false - rx-checksum: true - rx-gro: true - rx-gro-list: false - rx-hashing: true - rx-ntuple-filter: true - rx-udp-gro-forwarding: false - rx-udp_tunnel-port-offload: true - rx-vlan-hw-parse: true - tx-checksum-ip-generic: true - tx-checksum-sctp: true - tx-generic-segmentation: true - tx-gre-csum-segmentation: true - tx-gre-segmentation: true - tx-gso-partial: true - tx-ipxip4-segmentation: true - tx-ipxip6-segmentation: true - tx-nocache-copy: false - tx-tcp-ecn-segmentation: true - tx-tcp-mangleid-segmentation: false - tx-tcp-segmentation: true - tx-tcp6-segmentation: true - tx-udp-segmentation: true - tx-udp_tnl-csum-segmentation: true - tx-udp_tnl-segmentation: true - tx-vlan-hw-insert: true - pause: - autoneg: false - rx: false - tx: false - ring: - rx: 512 - rx-max: 4096 - tx: 512 - tx-max: 4096 - ipv4: - enabled: false - ipv6: - enabled: false - mac-address: E4:43:4B:5C:96:82 - mtu: 1500 - name: em1 - state: down - type: ethernet -- accept-all-mac-addresses: false - ethernet: - auto-negotiation: false - duplex: full - speed: 10000 - sr-iov: - total-vfs: 0 - vfs: [] - ethtool: - coalesce: - adaptive-rx: true - adaptive-tx: true - rx-usecs: 50 - rx-usecs-high: 0 - tx-frames-irq: 256 - tx-usecs: 50 - tx-usecs-high: 0 - feature: - highdma: true - hw-tc-offload: false - l2-fwd-offload: false - rx-checksum: true - rx-gro: true - rx-gro-list: false - rx-hashing: true - rx-ntuple-filter: true - rx-udp-gro-forwarding: false - rx-udp_tunnel-port-offload: true - rx-vlan-hw-parse: true - tx-checksum-ip-generic: true - tx-checksum-sctp: true - tx-generic-segmentation: true - tx-gre-csum-segmentation: true - tx-gre-segmentation: true - tx-gso-partial: true - tx-ipxip4-segmentation: true - tx-ipxip6-segmentation: true - tx-nocache-copy: false - tx-tcp-ecn-segmentation: true - tx-tcp-mangleid-segmentation: false - tx-tcp-segmentation: true - tx-tcp6-segmentation: true - tx-udp-segmentation: true - tx-udp_tnl-csum-segmentation: true - tx-udp_tnl-segmentation: true - tx-vlan-hw-insert: true - pause: - autoneg: false - rx: false - tx: false - ring: - rx: 512 - rx-max: 4096 - tx: 512 - tx-max: 4096 - ipv4: - enabled: false - ipv6: - enabled: false - mac-address: E4:43:4B:5C:96:83 - mtu: 1500 - name: em2 - state: down - type: ethernet -- accept-all-mac-addresses: false - ethernet: - auto-negotiation: true - duplex: full - speed: 40000 - sr-iov: - total-vfs: 0 - vfs: [] - ethtool: - coalesce: - adaptive-rx: true - adaptive-tx: true - rx-frames: 128 - rx-usecs: 8 - tx-frames: 128 - tx-usecs: 8 - feature: - hw-tc-offload: true - rx-all: false - rx-checksum: true - rx-fcs: false - rx-gro: true - rx-gro-list: false - rx-hashing: true - rx-lro: false - rx-ntuple-filter: false - rx-udp-gro-forwarding: false - rx-udp_tunnel-port-offload: true - rx-vlan-filter: true - rx-vlan-hw-parse: true - tx-checksum-ip-generic: true - tx-generic-segmentation: true - tx-gre-segmentation: true - tx-gso-partial: true - tx-ipxip4-segmentation: true - tx-ipxip6-segmentation: true - tx-nocache-copy: false - tx-tcp-mangleid-segmentation: false - tx-tcp-segmentation: true - tx-tcp6-segmentation: true - tx-udp-segmentation: true - tx-udp_tnl-segmentation: true - tx-vlan-hw-insert: true - tx-vlan-stag-hw-insert: true - pause: - autoneg: false - rx: true - tx: true - ring: - rx: 1024 - rx-max: 8192 - tx: 1024 - tx-max: 8192 - ipv4: - enabled: false - ipv6: - enabled: false - mac-address: 98:03:9B:7F:9E:48 - mtu: 1500 - name: enp59s0f0np0 - state: down - type: ethernet -- accept-all-mac-addresses: false - ethernet: - auto-negotiation: true - duplex: full - speed: 40000 - sr-iov: - total-vfs: 0 - vfs: [] - ethtool: - coalesce: - adaptive-rx: true - adaptive-tx: true - rx-frames: 128 - rx-usecs: 8 - tx-frames: 128 - tx-usecs: 8 - feature: - hw-tc-offload: true - rx-all: false - rx-checksum: true - rx-fcs: false - rx-gro: true - rx-gro-list: false - rx-hashing: true - rx-lro: false - rx-ntuple-filter: false - rx-udp-gro-forwarding: false - rx-udp_tunnel-port-offload: true - rx-vlan-filter: true - rx-vlan-hw-parse: true - tx-checksum-ip-generic: true - tx-generic-segmentation: true - tx-gre-segmentation: true - tx-gso-partial: true - tx-ipxip4-segmentation: true - tx-ipxip6-segmentation: true - tx-nocache-copy: false - tx-tcp-mangleid-segmentation: false - tx-tcp-segmentation: true - tx-tcp6-segmentation: true - tx-udp-segmentation: true - tx-udp_tnl-segmentation: true - tx-vlan-hw-insert: true - tx-vlan-stag-hw-insert: true - pause: - autoneg: false - rx: true - tx: true - ring: - rx: 1024 - rx-max: 8192 - tx: 1024 - tx-max: 8192 - ipv4: - enabled: false - ipv6: - enabled: false - mac-address: 98:03:9B:7F:9E:49 - mtu: 1500 - name: enp59s0f1np1 - state: down - type: ethernet -- accept-all-mac-addresses: false - ethtool: - feature: - rx-gro: true - rx-gro-list: false - rx-udp-gro-forwarding: false - tx-generic-segmentation: true - tx-gso-list: true - tx-sctp-segmentation: true - tx-tcp-ecn-segmentation: true - tx-tcp-mangleid-segmentation: true - tx-tcp-segmentation: true - tx-tcp6-segmentation: true - tx-udp-segmentation: true - ipv4: - address: - - ip: 127.0.0.1 - prefix-length: 8 - enabled: true - ipv6: - address: - - ip: ::1 - prefix-length: 128 - enabled: true - mac-address: 00:00:00:00:00:00 - mtu: 65536 - name: lo - state: up - type: loopback -route-rules: - config: [] -routes: - config: [] diff --git a/os_net_config/tests/test_cli.py b/os_net_config/tests/test_cli.py deleted file mode 100644 index c85b2ecc..00000000 --- a/os_net_config/tests/test_cli.py +++ /dev/null @@ -1,451 +0,0 @@ -# -*- 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. - -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.tests import base - - -REALPATH = os.path.dirname(os.path.realpath(__file__)) -SAMPLE_BASE = os.path.join(REALPATH, '../../', 'etc', - 'os-net-config', 'samples') - - -class TestCli(base.TestCase): - - def setUp(self): - super(TestCli, self).setUp() - rand = str(int(random.random() * 100000)) - common.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 - self.stub_out('os_net_config.utils.is_ovs_installed', - stub_is_ovs_installed) - - def tearDown(self): - super(TestCli, self).tearDown() - if os.path.isfile(common._LOG_FILE): - os.remove(common._LOG_FILE) - if os.path.isfile(common.SRIOV_CONFIG_FILE): - os.remove(common.SRIOV_CONFIG_FILE) - - def run_cli(self, argstr, exitcodes=(0,)): - 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() - stderr = sys.stderr.getvalue() - return (stdout, stderr) - - def stub_get_stored_pci_address(self, ifname, noop): - if 'eth0' in ifname: - return "0000:00:07.0" - if 'eth1' in ifname: - return "0000:00:08.0" - if 'eth2' in ifname: - return "0000:00:09.0" - if 'em3' in ifname: - return "0000:00:03.0" - if 'em1' in ifname: - return "0000:00:01.0" - - def test_bond_noop_output(self): - bond_yaml = os.path.join(SAMPLE_BASE, 'bond.yaml') - bond_json = os.path.join(SAMPLE_BASE, 'bond.json') - stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop ' - '--exit-on-validation-errors ' - '-c %s' % bond_yaml) - self.assertEqual('', stderr) - stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop ' - '--exit-on-validation-errors ' - '-c %s' % bond_json) - self.assertEqual('', stderr) - sanity_devices = ['DEVICE=br-ctlplane', - 'DEVICE=em2', - 'DEVICE=em1', - 'DEVICE=bond1', - 'DEVICETYPE=ovs'] - for dev in sanity_devices: - self.assertIn(dev, stdout_yaml) - self.assertEqual(stdout_yaml, stdout_json) - - def test_ivs_noop_output(self): - ivs_yaml = os.path.join(SAMPLE_BASE, 'ivs.yaml') - ivs_json = os.path.join(SAMPLE_BASE, 'ivs.json') - stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop ' - '--exit-on-validation-errors ' - '-c %s' % ivs_yaml) - self.assertEqual('', stderr) - stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop ' - '--exit-on-validation-errors ' - '-c %s' % ivs_json) - self.assertEqual('', stderr) - sanity_devices = ['DEVICE=nic2', - 'DEVICE=nic3', - 'DEVICE=api201', - 'DEVICE=storage202', - 'DEVICETYPE=ivs'] - for dev in sanity_devices: - self.assertIn(dev, stdout_yaml) - self.assertEqual(stdout_yaml, stdout_json) - - def test_bridge_noop_output(self): - bridge_yaml = os.path.join(SAMPLE_BASE, 'bridge_dhcp.yaml') - bridge_json = os.path.join(SAMPLE_BASE, 'bridge_dhcp.json') - stdout_yaml, stderr = self.run_cli('ARG0 --provider=eni --noop ' - '--exit-on-validation-errors ' - '-c %s' % bridge_yaml) - self.assertEqual('', stderr) - stdout_json, stderr = self.run_cli('ARG0 --provider=eni --noop ' - '--exit-on-validation-errors ' - '-c %s' % bridge_json) - self.assertEqual('', stderr) - sanity_devices = ['iface br-ctlplane inet dhcp', - 'iface em1', - 'ovs_type OVSBridge'] - for dev in sanity_devices: - self.assertIn(dev, stdout_yaml) - self.assertEqual(stdout_yaml, stdout_json) - - def test_vlan_noop_output(self): - vlan_yaml = os.path.join(SAMPLE_BASE, 'bridge_vlan.yaml') - vlan_json = os.path.join(SAMPLE_BASE, 'bridge_vlan.json') - stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop ' - '--exit-on-validation-errors ' - '-c %s' % vlan_yaml) - self.assertEqual('', stderr) - stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop ' - '--exit-on-validation-errors ' - '-c %s' % vlan_json) - self.assertEqual('', stderr) - sanity_devices = ['DEVICE=br-ctlplane', - 'DEVICE=em1', - 'DEVICE=vlan16', - 'DEVICETYPE=ovs'] - for dev in sanity_devices: - self.assertIn(dev, stdout_yaml) - self.assertEqual(stdout_yaml, stdout_json) - - def test_interface_noop_output(self): - interface_yaml = os.path.join(SAMPLE_BASE, 'interface.yaml') - interface_json = os.path.join(SAMPLE_BASE, 'interface.json') - stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop ' - '--exit-on-validation-errors ' - '-c %s' % interface_yaml) - self.assertEqual('', stderr) - stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop ' - '--exit-on-validation-errors ' - '-c %s' % interface_json) - self.assertEqual('', stderr) - sanity_devices = ['DEVICE=em1', - 'BOOTPROTO=static', - 'IPADDR=192.0.2.1'] - for dev in sanity_devices: - self.assertIn(dev, stdout_yaml) - self.assertEqual(stdout_yaml, stdout_json) - - def test_bridge_noop_rootfs(self): - for provider in ('ifcfg', 'eni'): - bond_yaml = os.path.join(SAMPLE_BASE, 'bridge_dhcp.yaml') - stdout_yaml, stderr = self.run_cli('ARG0 --provider=%s --noop ' - '--exit-on-validation-errors ' - '--root-dir=/rootfs ' - '-c %s' % (provider, bond_yaml)) - self.assertEqual('', stderr) - self.assertIn('File: /rootfs/', stdout_yaml) - - def test_interface_noop_detailed_exit_codes(self): - interface_yaml = os.path.join(SAMPLE_BASE, 'interface.yaml') - stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop ' - '--exit-on-validation-errors ' - '-c %s --detailed-exit-codes' - % interface_yaml, exitcodes=(2,)) - - def test_interface_noop_detailed_exit_codes_no_changes(self): - interface_yaml = os.path.join(SAMPLE_BASE, 'interface.yaml') - - class TestImpl(os_net_config.NetConfig): - - def add_interface(self, interface): - pass - - def apply(self, cleanup=False, activate=True): - # this fake implementation returns no changes - return {} - - self.stub_out('os_net_config.impl_ifcfg.IfcfgNetConfig', TestImpl) - stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop ' - '--exit-on-validation-errors ' - '-c %s --detailed-exit-codes' - % interface_yaml, exitcodes=(0,)) - - def test_sriov_noop_output(self): - def test_get_vf_devname(device, vfid): - return device + '_' + str(vfid) - - def test_get_pci_address(ifname, noop): - return '0000:79:10.2' - - def test_interface_mac(name): - return 'AA:BB:CC:DD:EE:FF' - - self.stub_out('os_net_config.utils.get_vf_devname', - test_get_vf_devname) - self.stub_out('os_net_config.utils.get_pci_address', - test_get_pci_address) - self.stub_out('os_net_config.common.interface_mac', - test_interface_mac) - ivs_yaml = os.path.join(SAMPLE_BASE, 'sriov_pf.yaml') - ivs_json = os.path.join(SAMPLE_BASE, 'sriov_pf.json') - stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop ' - '--exit-on-validation-errors ' - '-c %s' % ivs_yaml) - self.assertEqual('', stderr) - contents = common.get_file_data(common.SRIOV_CONFIG_FILE) - sriov_config_yaml = yaml.safe_load(contents) - os.remove(common.SRIOV_CONFIG_FILE) - stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop ' - '--exit-on-validation-errors ' - '-c %s' % ivs_json) - self.assertEqual('', stderr) - contents = common.get_file_data(common.SRIOV_CONFIG_FILE) - sriov_config_json = yaml.safe_load(contents) - sanity_devices = ['DEVICE=p2p1', - 'DEVICE=p2p1_5', - 'DEVICE=p2p1_1', - 'DEVICE=br-vfs', - 'DEVICE=br-bond', - 'TYPE=OVSBridge'] - for dev in sanity_devices: - self.assertIn(dev, stdout_yaml) - self.assertEqual(stdout_yaml, stdout_json) - self.assertCountEqual(sriov_config_yaml, sriov_config_json) - - def test_sriov_vf_with_dpdk_noop_output(self): - def test_get_vf_devname(device, vfid): - return device + '_' + str(vfid) - - def test_get_pci_address(ifname, noop): - return '0000:79:10.2' - - self.stub_out('os_net_config.utils.get_vf_devname', - test_get_vf_devname) - self.stub_out('os_net_config.utils.get_pci_address', - test_get_pci_address) - ivs_yaml = os.path.join(SAMPLE_BASE, 'sriov_pf_ovs_dpdk.yaml') - ivs_json = os.path.join(SAMPLE_BASE, 'sriov_pf_ovs_dpdk.json') - stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop ' - '--exit-on-validation-errors ' - '-c %s' % ivs_yaml) - self.assertEqual('', stderr) - contents = common.get_file_data(common.SRIOV_CONFIG_FILE) - sriov_config_yaml = yaml.safe_load(contents) - os.remove(common.SRIOV_CONFIG_FILE) - stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop ' - '--exit-on-validation-errors ' - '-c %s' % ivs_json) - self.assertEqual('', stderr) - contents = common.get_file_data(common.SRIOV_CONFIG_FILE) - sriov_config_json = yaml.safe_load(contents) - sanity_devices = ['DEVICE=p2p1', - 'DEVICE=p2p1_5', - 'DEVICE=br-vfs', - 'TYPE=OVSUserBridge', - 'DEVICE=dpdk0', - 'TYPE=OVSDPDKPort'] - for dev in sanity_devices: - self.assertIn(dev, stdout_yaml) - self.assertEqual(stdout_yaml, stdout_json) - self.assertCountEqual(sriov_config_yaml, sriov_config_json) - - def test_ovs_dpdk_bond_noop_output(self): - ivs_yaml = os.path.join(SAMPLE_BASE, 'ovs_dpdk_bond.yaml') - ivs_json = os.path.join(SAMPLE_BASE, 'ovs_dpdk_bond.json') - stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop ' - '--exit-on-validation-errors ' - '-c %s' % ivs_yaml) - self.assertEqual('', stderr) - stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop ' - '--exit-on-validation-errors ' - '-c %s' % ivs_json) - self.assertEqual('', stderr) - sanity_devices = ['DEVICE=br-link', - 'TYPE=OVSUserBridge', - 'DEVICE=dpdkbond0', - 'TYPE=OVSDPDKBond'] - for dev in sanity_devices: - self.assertIn(dev, stdout_yaml) - self.assertEqual(stdout_yaml, stdout_json) - - def test_nfvswitch_noop_output(self): - nfvswitch_yaml = os.path.join(SAMPLE_BASE, 'nfvswitch.yaml') - nfvswitch_json = os.path.join(SAMPLE_BASE, 'nfvswitch.json') - stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop ' - '--exit-on-validation-errors ' - '-c %s' % nfvswitch_yaml) - self.assertEqual('', stderr) - stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop ' - '--exit-on-validation-errors ' - '-c %s' % nfvswitch_json) - self.assertEqual('', stderr) - sanity_devices = ['DEVICE=nic2', - 'DEVICE=nic3', - 'DEVICE=api201', - 'DEVICE=storage202', - 'DEVICETYPE=nfvswitch'] - for dev in sanity_devices: - self.assertIn(dev, stdout_yaml) - self.assertEqual(stdout_yaml, stdout_json) - - def test_ovs_dpdk_noop_output(self): - ivs_yaml = os.path.join(SAMPLE_BASE, 'ovs_dpdk.yaml') - ivs_json = os.path.join(SAMPLE_BASE, 'ovs_dpdk.json') - stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop ' - '--exit-on-validation-errors ' - '-c %s' % ivs_yaml) - self.assertEqual('', stderr) - stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop ' - '--exit-on-validation-errors ' - '-c %s' % ivs_json) - self.assertEqual('', stderr) - sanity_devices = ['DEVICE=br-link', - 'TYPE=OVSUserBridge', - 'DEVICE=dpdk0', - 'TYPE=OVSDPDKPort'] - for dev in sanity_devices: - self.assertIn(dev, stdout_yaml) - self.assertEqual(stdout_yaml, stdout_json) - - def test_nic_mapping_report_output(self): - mapping_report = os.path.join(SAMPLE_BASE, 'mapping_report.yaml') - - def dummy_mapped_nics(nic_mapping=None): - return nic_mapping - self.stub_out('os_net_config.objects.mapped_nics', dummy_mapped_nics) - - stdout, stderr = self.run_cli('ARG0 --interfaces ' - '--exit-on-validation-errors ' - '-m %s' % mapping_report) - self.assertEqual('', stderr) - stdout_list = yaml.safe_load(stdout) - self.assertEqual(stdout_list['nic1'], 'em1') - self.assertEqual(stdout_list['nic2'], 'em2') - self.assertEqual(stdout_list['nic3'], 'em4') - self.assertEqual(stdout_list['nic4'], 'em3') - - def test_nic_mapping_report_with_explicit_interface_name(self): - mapping_report = os.path.join(SAMPLE_BASE, 'mapping_report.yaml') - - def dummy_mapped_nics(nic_mapping=None): - return nic_mapping - self.stub_out('os_net_config.objects.mapped_nics', dummy_mapped_nics) - - stdout, stderr = self.run_cli('ARG0 --interfaces em2 em3 ' - '--exit-on-validation-errors ' - '-m %s' % mapping_report) - self.assertEqual('', stderr) - stdout_list = yaml.safe_load(stdout) - self.assertNotIn('em1', stdout_list.keys()) - self.assertNotIn('em1', stdout_list.values()) - self.assertEqual(stdout_list['em2'], 'em2') - self.assertEqual(stdout_list['em3'], 'em3') - self.assertNotIn('em4', stdout_list.keys()) - self.assertNotIn('em4', stdout_list.values()) - - def test_contrail_vrouter_noop_output(self): - cvi_yaml = os.path.join(SAMPLE_BASE, 'contrail_vrouter.yaml') - cvi_json = os.path.join(SAMPLE_BASE, 'contrail_vrouter.json') - stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop ' - '--exit-on-validation-errors ' - '-c %s' % cvi_yaml) - self.assertEqual('', stderr) - stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop ' - '--exit-on-validation-errors ' - '-c %s' % cvi_json) - self.assertEqual('', stderr) - sanity_devices = ['DEVICE=vhost0', - 'BIND_INT=em3', - 'DEVICETYPE=vhost', - 'TYPE=kernel_mode'] - for dev in sanity_devices: - self.assertIn(dev, stdout_yaml) - self.assertEqual(stdout_yaml, stdout_json) - - def test_contrail_vrouter_vlan_noop_output(self): - cvi_yaml = os.path.join(SAMPLE_BASE, 'contrail_vrouter_vlan.yaml') - cvi_json = os.path.join(SAMPLE_BASE, 'contrail_vrouter_vlan.json') - stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop ' - '--exit-on-validation-errors ' - '-c %s' % cvi_yaml) - self.assertEqual('', stderr) - stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop ' - '--exit-on-validation-errors ' - '-c %s' % cvi_json) - self.assertEqual('', stderr) - sanity_devices = ['DEVICE=vhost0', - 'BIND_INT=vlan100', - 'DEVICETYPE=vhost', - 'TYPE=kernel_mode'] - for dev in sanity_devices: - self.assertIn(dev, stdout_yaml) - 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', - self.stub_get_stored_pci_address) - stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop ' - '--exit-on-validation-errors ' - '--debug ' - '-c %s' % cvi_yaml) - self.assertEqual('', stderr) - stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop ' - '--exit-on-validation-errors ' - '--debug ' - '-c %s' % cvi_json) - self.assertEqual('', stderr) - sanity_devices = ['DEVICE=vhost0', - 'BIND_INT=0000:00:03.0', - 'DEVICETYPE=vhost', - '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) diff --git a/os_net_config/tests/test_impl_eni.py b/os_net_config/tests/test_impl_eni.py deleted file mode 100644 index df88d8bd..00000000 --- a/os_net_config/tests/test_impl_eni.py +++ /dev/null @@ -1,407 +0,0 @@ -# -*- 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. - -import tempfile - -from oslo_concurrency import processutils - -import os_net_config -from os_net_config import common -from os_net_config import impl_eni -from os_net_config import objects -from os_net_config.tests import base - -_AUTO = "auto eth0\n" - -_v4_IFACE_NO_IP = _AUTO + "iface eth0 inet manual\n" - -_V4_IFACE_STATIC_IP = _AUTO + """iface eth0 inet static - address 192.168.1.2 - netmask 255.255.255.0 -""" - -_IFACE_HOTPLUG = """allow-hotplug eth0 -iface eth0 inet static - address 192.168.1.2 - netmask 255.255.255.0 -""" - -_V4_IFACE_STATIC_IP_MULTIPLE = (_V4_IFACE_STATIC_IP + _AUTO + - """iface eth0 inet static - address 10.0.0.2 - netmask 255.0.0.0 -""") - -_V6_IFACE_STATIC_IP = _AUTO + """iface eth0 inet6 static - address fe80::2677:3ff:fe7d:4c - netmask 128 -""" - -_V6_IFACE_STATIC_IP_MULTIPLE = (_V6_IFACE_STATIC_IP + _AUTO + - """iface eth0 inet6 static - address 2001:abcd::2 - netmask 64 -""") - -_IFACE_DHCP = _AUTO + "iface eth0 inet dhcp\n" - -_OVS_PORT_BASE = _AUTO + "allow-br0 eth0\n" - -_OVS_PORT_IFACE = _OVS_PORT_BASE + """iface eth0 inet manual - ovs_bridge br0 - ovs_type OVSPort -""" - -_OVS_BRIDGE_DHCP = """auto br0 -allow-ovs br0 -iface br0 inet dhcp - ovs_type OVSBridge - ovs_ports eth0 - pre-up ip addr flush dev eth0 -""" - -_OVS_BRIDGE_DHCP_STANDALONE = _OVS_BRIDGE_DHCP + ( - " ovs_extra set bridge br0 fail_mode=standalone " - "-- del-controller br0\n") - -_OVS_BRIDGE_DHCP_SECURE = _OVS_BRIDGE_DHCP + \ - " ovs_extra set bridge br0 fail_mode=secure\n" - -_OVS_BRIDGE_DHCP_PRIMARY_INTERFACE = _OVS_BRIDGE_DHCP + \ - " ovs_extra set bridge br0 other-config:hwaddr=a1:b2:c3:d4:e5\n" - -_OVS_BRIDGE_DHCP_OVS_EXTRA = _OVS_BRIDGE_DHCP + \ - " ovs_extra set bridge br0 other-config:hwaddr=a1:b2:c3:d4:e5" + \ - " -- br-set-external-id br0 bridge-id br0\n" - - -_VLAN_NO_IP = """auto vlan5 -iface vlan5 inet manual - vlan-raw-device eth0 -""" - -_VLAN_OVS_PORT = """auto vlan5 -allow-br0 vlan5 -iface vlan5 inet manual - ovs_bridge br0 - ovs_type OVSIntPort - ovs_options tag=5 -""" - -_RTS = """up route add -net 172.19.0.0 netmask 255.255.255.0 gw 192.168.1.1 -down route del -net 172.19.0.0 netmask 255.255.255.0 gw 192.168.1.1 -up route add -net 172.20.0.0 netmask 255.255.255.0 gw 192.168.1.5 metric 100 -down route del -net 172.20.0.0 netmask 255.255.255.0 gw 192.168.1.5 metric 100 -""" - - -class TestENINetConfig(base.TestCase): - - def setUp(self): - super(TestENINetConfig, self).setUp() - - def stub_is_ovs_installed(): - return True - self.stub_out('os_net_config.utils.is_ovs_installed', - stub_is_ovs_installed) - - self.provider = impl_eni.ENINetConfig() - self.if_name = 'eth0' - - def tearDown(self): - super(TestENINetConfig, self).tearDown() - - def get_interface_config(self, name="eth0"): - return self.provider.interfaces[name] - - def get_route_config(self): - return self.provider.routes[self.if_name] - - def _default_interface(self, addr=[], rts=[], hotplug=False): - return objects.Interface(self.if_name, addresses=addr, routes=rts, - hotplug=hotplug) - - def test_interface_no_ip(self): - interface = self._default_interface() - self.provider.add_interface(interface) - self.assertEqual(_v4_IFACE_NO_IP, self.get_interface_config()) - - def test_add_interface_with_v4(self): - v4_addr = objects.Address('192.168.1.2/24') - interface = self._default_interface([v4_addr]) - self.provider.add_interface(interface) - self.assertEqual(_V4_IFACE_STATIC_IP, self.get_interface_config()) - - def test_add_interface_with_hotplug(self): - v4_addr = objects.Address('192.168.1.2/24') - interface = self._default_interface(addr=[v4_addr], hotplug=True) - self.provider.add_interface(interface) - self.assertEqual(_IFACE_HOTPLUG, self.get_interface_config()) - - def test_add_interface_with_v4_multiple(self): - v4_addresses = [objects.Address('192.168.1.2/24'), - objects.Address('10.0.0.2/8')] - interface = self._default_interface(v4_addresses) - self.provider.add_interface(interface) - self.assertEqual(_V4_IFACE_STATIC_IP_MULTIPLE, - self.get_interface_config()) - - def test_add_interface_with_v6(self): - v6_addr = objects.Address('fe80::2677:3ff:fe7d:4c') - interface = self._default_interface([v6_addr]) - self.provider.add_interface(interface) - self.assertEqual(_V6_IFACE_STATIC_IP, self.get_interface_config()) - - def test_add_interface_with_v6_multiple(self): - v6_addresses = [objects.Address('fe80::2677:3ff:fe7d:4c'), - objects.Address('2001:abcd::2/64')] - interface = self._default_interface(v6_addresses) - self.provider.add_interface(interface) - self.assertEqual(_V6_IFACE_STATIC_IP_MULTIPLE, - self.get_interface_config()) - - def test_add_interface_dhcp(self): - interface = self._default_interface() - interface.use_dhcp = True - self.provider.add_interface(interface) - self.assertEqual(_IFACE_DHCP, self.get_interface_config()) - - def test_add_interface_with_both_v4_and_v6(self): - v4_addr = objects.Address('192.168.1.2/24') - v6_addr = objects.Address('fe80::2677:3ff:fe7d:4c') - interface = self._default_interface([v4_addr, v6_addr]) - self.provider.add_interface(interface) - self.assertEqual(_V4_IFACE_STATIC_IP + _V6_IFACE_STATIC_IP, - self.get_interface_config()) - - def test_add_ovs_port_interface(self): - interface = self._default_interface() - interface.ovs_port = True - interface.bridge_name = 'br0' - self.provider.add_interface(interface) - self.assertEqual(_OVS_PORT_IFACE, self.get_interface_config()) - - def test_network_with_routes(self): - route1 = objects.Route('192.168.1.1', '172.19.0.0/24') - route2 = objects.Route('192.168.1.5', '172.20.0.0/24', - route_options="metric 100") - v4_addr = objects.Address('192.168.1.2/24') - interface = self._default_interface([v4_addr], [route1, route2]) - self.provider.add_interface(interface) - self.assertEqual(_V4_IFACE_STATIC_IP, self.get_interface_config()) - self.assertEqual(_RTS, self.get_route_config()) - - def test_network_ovs_bridge_with_dhcp(self): - interface = self._default_interface() - bridge = objects.OvsBridge('br0', use_dhcp=True, - members=[interface]) - self.provider.add_bridge(bridge) - self.provider.add_interface(interface) - self.assertEqual(_OVS_PORT_IFACE, self.get_interface_config()) - self.assertEqual(_OVS_BRIDGE_DHCP, self.provider.bridges['br0']) - - def test_network_ovs_bridge_with_standalone_fail_mode(self): - interface = self._default_interface() - bridge = objects.OvsBridge('br0', use_dhcp=True, - members=[interface], - fail_mode='standalone') - self.provider.add_bridge(bridge) - self.provider.add_interface(interface) - self.assertEqual(_OVS_PORT_IFACE, self.get_interface_config()) - self.assertEqual(_OVS_BRIDGE_DHCP_STANDALONE, - self.provider.bridges['br0']) - - def test_network_ovs_bridge_with_secure_fail_mode(self): - interface = self._default_interface() - bridge = objects.OvsBridge('br0', use_dhcp=True, - members=[interface], - fail_mode='secure') - self.provider.add_bridge(bridge) - self.provider.add_interface(interface) - self.assertEqual(_OVS_PORT_IFACE, self.get_interface_config()) - self.assertEqual(_OVS_BRIDGE_DHCP_SECURE, - self.provider.bridges['br0']) - - def test_network_ovs_bridge_with_dhcp_and_primary_interface(self): - - def test_interface_mac(name): - return "a1:b2:c3:d4:e5" - self.stub_out('os_net_config.common.interface_mac', test_interface_mac) - - interface = objects.Interface(self.if_name, primary=True) - bridge = objects.OvsBridge('br0', use_dhcp=True, - members=[interface]) - self.provider.add_bridge(bridge) - self.provider.add_interface(interface) - self.assertEqual(_OVS_PORT_IFACE, self.get_interface_config()) - self.assertEqual(_OVS_BRIDGE_DHCP_PRIMARY_INTERFACE, - self.provider.bridges['br0']) - - def test_network_ovs_bridge_with_dhcp_and_primary_with_ovs_extra(self): - - def test_interface_mac(name): - return "a1:b2:c3:d4:e5" - self.stub_out('os_net_config.common.interface_mac', test_interface_mac) - - interface = objects.Interface(self.if_name, primary=True) - ovs_extra = "br-set-external-id br0 bridge-id br0" - bridge = objects.OvsBridge('br0', use_dhcp=True, - members=[interface], - ovs_extra=[ovs_extra]) - self.provider.add_bridge(bridge) - self.provider.add_interface(interface) - self.assertEqual(_OVS_PORT_IFACE, self.get_interface_config()) - self.assertEqual(_OVS_BRIDGE_DHCP_OVS_EXTRA, - self.provider.bridges['br0']) - - def test_network_ovs_bridge_with_dhcp_and_primary_with_ovs_format(self): - - def test_interface_mac(name): - return "a1:b2:c3:d4:e5" - self.stub_out('os_net_config.common.interface_mac', test_interface_mac) - - interface = objects.Interface(self.if_name, primary=True) - ovs_extra = "br-set-external-id {name} bridge-id {name}" - bridge = objects.OvsBridge('br0', use_dhcp=True, - members=[interface], - ovs_extra=[ovs_extra]) - self.provider.add_bridge(bridge) - self.provider.add_interface(interface) - self.assertEqual(_OVS_PORT_IFACE, self.get_interface_config()) - self.assertEqual(_OVS_BRIDGE_DHCP_OVS_EXTRA, - self.provider.bridges['br0']) - - def test_vlan(self): - vlan = objects.Vlan('eth0', 5) - self.provider.add_vlan(vlan) - self.assertEqual(_VLAN_NO_IP, self.get_interface_config('vlan5')) - - def test_vlan_mtu_1500(self): - vlan = objects.Vlan('eth0', 5, mtu=1500) - self.provider.add_vlan(vlan) - expected = _VLAN_NO_IP + ' mtu 1500\n' - self.assertEqual(expected, self.get_interface_config('vlan5')) - - def test_vlan_ovs_bridge_int_port(self): - vlan = objects.Vlan('eth0', 5) - bridge = objects.OvsBridge('br0', use_dhcp=True, - members=[vlan]) - self.provider.add_bridge(bridge) - self.provider.add_vlan(vlan) - self.assertEqual(_VLAN_OVS_PORT, self.get_interface_config('vlan5')) - - -class TestENINetConfigApply(base.TestCase): - - def setUp(self): - super(TestENINetConfigApply, self).setUp() - self.temp_config_file = tempfile.NamedTemporaryFile() - self.ifup_interface_names = [] - - def test_config_path(prefix): - return self.temp_config_file.name - self.stub_out( - 'os_net_config.impl_eni._network_config_path', test_config_path) - - def stub_is_ovs_installed(): - return True - self.stub_out('os_net_config.utils.is_ovs_installed', - stub_is_ovs_installed) - - def test_execute(*args, **kwargs): - if args[0] == '/sbin/ifup': - self.ifup_interface_names.append(args[1]) - pass - - self.stub_out('oslo_concurrency.processutils.execute', test_execute) - - self.provider = impl_eni.ENINetConfig() - - def tearDown(self): - self.temp_config_file.close() - super(TestENINetConfigApply, self).tearDown() - - def test_network_apply(self): - route1 = objects.Route('192.168.1.1', '172.19.0.0/24') - route2 = objects.Route('192.168.1.5', '172.20.0.0/24', - route_options="metric 100") - v4_addr = objects.Address('192.168.1.2/24') - interface = objects.Interface('eth0', addresses=[v4_addr], - routes=[route1, route2]) - self.provider.add_interface(interface) - - self.provider.apply() - iface_data = common.get_file_data(self.temp_config_file.name) - self.assertEqual((_V4_IFACE_STATIC_IP + _RTS), iface_data) - self.assertIn('eth0', self.ifup_interface_names) - - def test_apply_noactivate(self): - route1 = objects.Route('192.168.1.1', '172.19.0.0/24') - route2 = objects.Route('192.168.1.5', '172.20.0.0/24', - route_options="metric 100") - v4_addr = objects.Address('192.168.1.2/24') - interface = objects.Interface('eth0', addresses=[v4_addr], - routes=[route1, route2]) - self.provider.add_interface(interface) - - self.provider.apply(activate=False) - iface_data = common.get_file_data(self.temp_config_file.name) - self.assertEqual((_V4_IFACE_STATIC_IP + _RTS), iface_data) - self.assertEqual([], self.ifup_interface_names) - - def test_dhcp_ovs_bridge_network_apply(self): - interface = objects.Interface('eth0') - bridge = objects.OvsBridge('br0', use_dhcp=True, - members=[interface]) - self.provider.add_interface(interface) - self.provider.add_bridge(bridge) - self.provider.apply() - iface_data = common.get_file_data(self.temp_config_file.name) - self.assertEqual((_OVS_BRIDGE_DHCP + _OVS_PORT_IFACE), iface_data) - self.assertIn('eth0', self.ifup_interface_names) - self.assertIn('br0', self.ifup_interface_names) - - def _failed_execute(*args, **kwargs): - if kwargs.get('check_exit_code', True): - raise processutils.ProcessExecutionError('Test stderr', - 'Test stdout', - str(kwargs)) - - def test_interface_failure(self): - self.stub_out('oslo_concurrency.processutils.execute', - self._failed_execute) - v4_addr = objects.Address('192.168.1.2/24') - interface = objects.Interface('em1', addresses=[v4_addr]) - self.provider.add_interface(interface) - - self.assertRaises(os_net_config.ConfigurationError, - self.provider.apply) - self.assertEqual(1, len(self.provider.errors)) - - def test_interface_failure_multiple(self): - self.stub_out('oslo_concurrency.processutils.execute', - self._failed_execute) - v4_addr = objects.Address('192.168.1.2/24') - interface = objects.Interface('em1', addresses=[v4_addr]) - v4_addr2 = objects.Address('192.168.2.2/24') - interface2 = objects.Interface('em2', addresses=[v4_addr2]) - self.provider.add_interface(interface) - self.provider.add_interface(interface2) - - self.assertRaises(os_net_config.ConfigurationError, - self.provider.apply) - # Even though the first one failed, we should have attempted both - self.assertEqual(2, len(self.provider.errors)) diff --git a/os_net_config/tests/test_impl_ifcfg.py b/os_net_config/tests/test_impl_ifcfg.py deleted file mode 100644 index c37bd723..00000000 --- a/os_net_config/tests/test_impl_ifcfg.py +++ /dev/null @@ -1,2897 +0,0 @@ -# -*- 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. - -import os.path -import random -import shutil -import tempfile - -from oslo_concurrency import processutils - -import os_net_config -from os_net_config import common -from os_net_config import impl_ifcfg -from os_net_config import objects -from os_net_config.tests import base -from os_net_config import utils - - -_BASE_IFCFG = """# This file is autogenerated by os-net-config -DEVICE=em1 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -""" - -_BASE_IFCFG_NETWORKMANAGER = """# This file is autogenerated by os-net-config -DEVICE=em1 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=yes -PEERDNS=no -""" - -_HOTPLUG = """# This file is autogenerated by os-net-config -DEVICE=em1 -ONBOOT=yes -HOTPLUG=yes -NM_CONTROLLED=no -PEERDNS=no -BOOTPROTO=none -""" - -_ONBOOT = """# This file is autogenerated by os-net-config -DEVICE=em1 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -BOOTPROTO=none -""" - -_LINKDELAY = """# This file is autogenerated by os-net-config -DEVICE=em1 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -LINKDELAY=10 -BOOTPROTO=none -""" - -_NO_IP = _BASE_IFCFG + "BOOTPROTO=none\n" - -_V4_IFCFG = _BASE_IFCFG + """BOOTPROTO=static -IPADDR=192.168.1.2 -NETMASK=255.255.255.0 -""" - -_V4_V6_IFCFG = _BASE_IFCFG + """IPV6INIT=yes -BOOTPROTO=static -IPADDR=192.168.1.2 -NETMASK=255.255.255.0 -IPV6_AUTOCONF=no -IPV6ADDR=2001:abc:a::/64 -""" - -_IFCFG_VLAN = """# This file is autogenerated by os-net-config -DEVICE=em1.120 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -VLAN=yes -BOOTPROTO=none -""" - -_IFCFG_DHCP = """# This file is autogenerated by os-net-config -DEVICE="eth0" -BOOTPROTO="dhcp" -ONBOOT="yes" -TYPE="Ethernet" -""" - -_IFCFG_STATIC1 = """# This file is autogenerated by os-net-config -DEVICE=eth0 -BOOTPROTO=static -IPADDR=10.0.0.1 -NETMASK=255.255.255.0 -TYPE=Ethernet -ONBOOT=yes -""" - -_IFCFG_STATIC1_MTU = _IFCFG_STATIC1 + "\nMTU=9000" - -_IFCFG_STATIC1_ETHTOOL1 = _IFCFG_STATIC1 +\ - "\nETHTOOL_OPTS=\"speed 100 duplex full autoneg off\"" - -_IFCFG_STATIC1_ETHTOOL2 = _IFCFG_STATIC1 +\ - "\nETHTOOL_OPTS=\"-G ${DEVICE} rx 1024 tx 1024\"" - -_IFCFG_STATIC1_ETHTOOL3 = _IFCFG_STATIC1 +\ - "\nETHTOOL_OPTS=\"--set-ring ${DEVICE} rx 1024 tx 1024\"" - -_IFCFG_STATIC1_ETHTOOL4 = _IFCFG_STATIC1 +\ - "\nETHTOOL_OPTS=\"--pause ${DEVICE} autoneg on\"" - -_IFCFG_STATIC1_ETHTOOL5 = _IFCFG_STATIC1 +\ - "\nETHTOOL_OPTS=\"-G ${DEVICE} rx 1024 tx 1024;\ --A ${DEVICE} autoneg on;\ ---pause ${DEVICE} autoneg off;\ ---set-ring ${DEVICE} rx 512\"" - -_IFCFG_STATIC1_ETHTOOL6 = _IFCFG_STATIC1 +\ - "\nETHTOOL_OPTS=\"-G $DEVICE rx 1024 tx 1024\"" - -_IFCFG_STATIC1_ETHTOOL7 = _IFCFG_STATIC1 +\ - "\nETHTOOL_OPTS=\"-G eth0 rx 1024 tx 1024\"" - - -_IFCFG_STATIC2 = """DEVICE=eth0 -BOOTPROTO=static -IPADDR=10.0.1.2 -NETMASK=255.255.254.0 -TYPE=Ethernet -ONBOOT=yes -""" - -_IFCFG_STATIC2_MTU = _IFCFG_STATIC2 + "\nMTU=9000" - -_IFCFG_OVS = """DEVICE=eth0 -ONBOOT=yes -DEVICETYPE=ovs -TYPE=OVSPort -OVS_BRIDGE=brctlplane -BOOTPROTO=none -HOTPLUG=no -""" - -_IFCFG_ROUTES1 = """default via 192.0.2.1 dev eth0 -192.0.2.1/24 via 192.0.2.1 dev eth0 -""" - -_IFCFG_ROUTES2 = """default via 192.0.1.1 dev eth0 -192.0.1.1/24 via 192.0.3.1 dev eth1 -""" - -_IFCFG_RULES1 = """to 192.168.2.0/24 table main priority 500 -from 192.168.2.0/24 table 200 priority 501 -""" - -_IFCFG_RULES2 = """to 192.168.1.0/24 table main priority 500 -from 192.168.1.0/24 table 200 priority 501 -""" - -_V4_IFCFG_MAPPED = _V4_IFCFG.replace('em1', 'nic1') + "HWADDR=a1:b2:c3:d4:e5\n" - - -_BASE_IB_IFCFG = """# This file is autogenerated by os-net-config -DEVICE=ib0 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -TYPE=Infiniband -""" - -_IB_IFCFG = _BASE_IB_IFCFG + """BOOTPROTO=none -""" - -_V4_IB_IFCFG = _BASE_IB_IFCFG + """BOOTPROTO=static -IPADDR=192.168.1.2 -NETMASK=255.255.255.0 -""" - -_V4_IFCFG_MULTIPLE = _V4_IFCFG + """IPADDR1=192.168.1.3 -NETMASK1=255.255.255.255 -IPADDR2=10.0.0.2 -NETMASK2=255.0.0.0 -""" - -_IB_V4_IFCFG_MULTIPLE = _V4_IB_IFCFG + """IPADDR1=192.168.1.3 -NETMASK1=255.255.255.255 -IPADDR2=10.0.0.2 -NETMASK2=255.0.0.0 -""" - -_BASE_IB_CHILD_IFCFG = """# This file is autogenerated by os-net-config -DEVICE=ib0.8001 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=yes -PEERDNS=no -TYPE=Infiniband -PKEY=yes -PHYSDEV=ib0 -PKEY_ID=0x8001 -BOOTPROTO=none -""" - -_V6_IFCFG = _BASE_IFCFG + """IPV6INIT=yes -IPV6_AUTOCONF=no -IPV6ADDR=2001:abc:a::/64 -""" - -_V6_IFCFG_MULTIPLE = (_V6_IFCFG + "IPV6ADDR_SECONDARIES=\"2001:abc:b::1/64 " + - "2001:abc:c::2/96\"\n") - -_OVS_IFCFG = _BASE_IFCFG + "DEVICETYPE=ovs\nBOOTPROTO=none\n" - -_OVS_IFCFG_TUNNEL = """# This file is autogenerated by os-net-config -DEVICE=tun0 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -DEVICETYPE=ovs -TYPE=OVSTunnel -OVS_BRIDGE=br-ctlplane -OVS_TUNNEL_TYPE=gre -OVS_TUNNEL_OPTIONS="options:remote_ip=192.168.1.1" -""" - - -_OVS_BRIDGE_IFCFG = _BASE_IFCFG + "DEVICETYPE=ovs\n" - -_LINUX_BRIDGE_IFCFG = _BASE_IFCFG + "BRIDGE=br-ctlplane\nBOOTPROTO=none\n" - -_ROUTES = """default via 192.168.1.1 dev em1 metric 10 -172.19.0.0/24 via 192.168.1.1 dev em1 -172.20.0.0/24 via 192.168.1.5 dev em1 metric 100 -""" - -_ROUTES_PF = """default via 192.168.1.1 dev enp3s0f0 metric 10 -172.19.0.0/24 via 192.168.1.1 dev enp3s0f0 -172.20.0.0/24 via 192.168.1.5 dev enp3s0f0 metric 100 -""" - -_ROUTES_WITH_TABLES = """172.19.0.0/24 via 192.168.1.1 dev em1 table table1 -172.20.0.0/24 via 192.168.1.1 dev em1 table 201 -172.21.0.0/24 via 192.168.1.1 dev em1 table 200 -""" - -_ROUTE_RULES = """# This file is autogenerated by os-net-config -# test comment -from 192.0.2.0/24 table 200 -""" - -_RT_DEFAULT = """# reserved values -# -255\tlocal -254\tmain -253\tdefault -0\tunspec -# -# local -# -#1\tinr.ruhep\n""" - -_RT_CUSTOM = _RT_DEFAULT + "# Custom\n10\tcustom # Custom table\n20\ttable1\n" - -_RT_FULL = _RT_DEFAULT + """# Custom -10\tcustom # os-net-config managed table -200\ttable1 # os-net-config managed table\n""" - -_ROUTES_V6 = """default via 2001:db8::1 dev em1 -2001:db8:dead:beef:cafe::/56 via fd00:fd00:2000::1 dev em1 -2001:db8:dead:beff::/64 via fd00:fd00:2000::1 dev em1 metric 100 -""" - - -_OVS_INTERFACE = _BASE_IFCFG + """DEVICETYPE=ovs -TYPE=OVSPort -OVS_BRIDGE=br-ctlplane -BOOTPROTO=none -""" - -_OVS_BRIDGE_DHCP = """# This file is autogenerated by os-net-config -DEVICE=br-ctlplane -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -DEVICETYPE=ovs -TYPE=OVSBridge -OVSBOOTPROTO=dhcp -OVSDHCPINTERFACES="em1" -OVS_EXTRA="set bridge br-ctlplane other-config:mac-table-size=50000" -""" - -_OVS_BRIDGE_DHCPV6 = """# This file is autogenerated by os-net-config -DEVICE=br-ctlplane -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -DEVICETYPE=ovs -TYPE=OVSBridge -OVSBOOTPROTO=dhcp -IPV6INIT=yes -DHCPV6C=yes -OVS_EXTRA="set bridge br-ctlplane other-config:mac-table-size=50000" -""" - -_NM_CONTROLLED_INTERFACE = _BASE_IFCFG_NETWORKMANAGER + """MASTER=bond1 -SLAVE=yes -BOOTPROTO=none -""" - -_NM_CONTROLLED_BOND = """# This file is autogenerated by os-net-config -DEVICE=bond1 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=yes -PEERDNS=no -""" - -_OVS_BRIDGE_DHCP_STANDALONE = _OVS_BRIDGE_DHCP[:-2] + ( - " -- set bridge br-ctlplane fail_mode=standalone " - "-- del-controller br-ctlplane\"\n") - -_OVS_BRIDGE_DHCP_SECURE = _OVS_BRIDGE_DHCP[:-2] + \ - " -- set bridge br-ctlplane fail_mode=secure\"\n" - - -_LINUX_BRIDGE_DHCP = """# This file is autogenerated by os-net-config -DEVICE=br-ctlplane -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -TYPE=Bridge -DELAY=0 -BOOTPROTO=dhcp -""" - -_OVS_BRIDGE_STATIC = """# This file is autogenerated by os-net-config -DEVICE=br-ctlplane -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -DEVICETYPE=ovs -TYPE=OVSBridge -BOOTPROTO=static -IPADDR=192.168.1.2 -NETMASK=255.255.255.0 -OVS_EXTRA="set bridge br-ctlplane other-config:mac-table-size=50000" -""" - -_LINUX_BRIDGE_STATIC = """# This file is autogenerated by os-net-config -DEVICE=br-ctlplane -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -TYPE=Bridge -DELAY=0 -BOOTPROTO=static -IPADDR=192.168.1.2 -NETMASK=255.255.255.0 -""" - -_OVS_BRIDGE_DHCP_PRIMARY_INTERFACE = _OVS_BRIDGE_DHCP[:-2] + \ - " -- set bridge br-ctlplane other-config:hwaddr=a1:b2:c3:d4:e5\"\n" - - -_OVS_BRIDGE_DHCP_OVS_EXTRA = _OVS_BRIDGE_DHCP[:-2] + \ - " -- set bridge br-ctlplane other-config:hwaddr=a1:b2:c3:d4:e5" + \ - " -- br-set-external-id br-ctlplane bridge-id br-ctlplane\"\n" - - -_BASE_VLAN = """# This file is autogenerated by os-net-config -DEVICE=vlan5 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -VLAN=yes -PHYSDEV=em1 -""" - -# vlans on an OVS bridge do not set VLAN=yes or PHYSDEV -_BASE_VLAN_OVS = """# This file is autogenerated by os-net-config -DEVICE=vlan5 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -""" - -_VLAN_NO_IP = _BASE_VLAN + "BOOTPROTO=none\n" - - -_VLAN_OVS = _BASE_VLAN_OVS + "DEVICETYPE=ovs\nBOOTPROTO=none\n" - - -_VLAN_OVS_EXTRA = _BASE_VLAN_OVS + "OVS_OPTIONS=\"foo\"\nDEVICETYPE=ovs\n" + \ - "BOOTPROTO=none\nOVS_EXTRA=\"bar -- baz\"\n" - - -_VLAN_OVS_BRIDGE = _BASE_VLAN_OVS + """DEVICETYPE=ovs -TYPE=OVSIntPort -OVS_BRIDGE=br-ctlplane -OVS_OPTIONS="tag=5" -BOOTPROTO=none -""" - -_VLAN_LINUX_BRIDGE = _BASE_VLAN_OVS + """VLAN=yes -PHYSDEV=em1 -BRIDGE=br-ctlplane -BOOTPROTO=none -""" - -_OVS_BOND_DHCP = """# This file is autogenerated by os-net-config -DEVICE=bond0 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -DEVICETYPE=ovs -TYPE=OVSBond -OVSBOOTPROTO=dhcp -BOND_IFACES="em1 em2" -""" - -_LINUX_BOND_DHCP = """# This file is autogenerated by os-net-config -DEVICE=bond0 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -BOOTPROTO=dhcp -""" - - -_LINUX_TEAM_DHCP = """# This file is autogenerated by os-net-config -DEVICE=team0 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -BOOTPROTO=dhcp -DEVICETYPE=Team -""" - - -_LINUX_BOND_INTERFACE = _BASE_IFCFG + """MASTER=bond0 -SLAVE=yes -BOOTPROTO=none -""" - -_LINUX_TEAM_INTERFACE = _BASE_IFCFG + """TEAM_MASTER=team0 -BOOTPROTO=none -""" - -_IVS_UPLINK = """# This file is autogenerated by os-net-config -DEVICE=em1 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -DEVICETYPE=ivs -IVS_BRIDGE=ivs -BOOTPROTO=none -""" - -_IVS_INTERFACE = """# This file is autogenerated by os-net-config -DEVICE=storage5 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -TYPE=IVSIntPort -DEVICETYPE=ivs -IVS_BRIDGE=ivs -MTU=1500 -BOOTPROTO=static -IPADDR=172.16.2.7 -NETMASK=255.255.255.0 -""" - -_IVS_CONFIG = ('DAEMON_ARGS=\"--hitless --certificate /etc/ivs ' - '--inband-vlan 4092 -u em1 --internal-port=storage5\"') - -_NFVSWITCH_INTERFACE = """# This file is autogenerated by os-net-config -DEVICE=em1 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -DEVICETYPE=nfvswitch -NFVSWITCH_BRIDGE=nfvswitch -BOOTPROTO=none -""" - -_NFVSWITCH_INTERNAL = """# This file is autogenerated by os-net-config -DEVICE=storage5 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -TYPE=NFVSWITCHIntPort -DEVICETYPE=nfvswitch -NFVSWITCH_BRIDGE=nfvswitch -MTU=1500 -BOOTPROTO=static -IPADDR=172.16.2.7 -NETMASK=255.255.255.0 -""" - -_NFVSWITCH_CONFIG = ('SETUP_ARGS=\"-c 2,3,4,5 -u em1 -m storage5\"') - -_OVS_IFCFG_PATCH_PORT = """# This file is autogenerated by os-net-config -DEVICE=br-pub-patch -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -DEVICETYPE=ovs -TYPE=OVSPatchPort -OVS_BRIDGE=br-ex -OVS_PATCH_PEER=br-ex-patch -""" - -_LINUX_TEAM_PRIMARY_IFACE = """# This file is autogenerated by os-net-config -DEVICE=em1 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -TEAM_MASTER=team1 -TEAM_PORT_CONFIG='{"prio": 100}' -BOOTPROTO=none -""" - -_CONTRAIL_VROUTER_IFACE = """# This file is autogenerated by os-net-config -DEVICE=vhost0 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -BOOTPROTO=static -IPADDR=10.0.0.30 -NETMASK=255.255.255.0 -DEVICETYPE=vhost -TYPE=kernel_mode -BIND_INT=em3 -""" - -_CONTRAIL_VROUTER_IFACE_L3MH = """# This file is autogenerated by os-net-config -DEVICE=vhost0 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -BOOTPROTO=none -DEVICETYPE=vhost -TYPE=kernel_mode -BIND_INT=em3,em4 -""" - -_CONTRAIL_VROUTER_VLAN_IFACE = """# This file is autogenerated by os-net-config -DEVICE=vhost0 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -BOOTPROTO=static -IPADDR=10.0.0.30 -NETMASK=255.255.255.0 -DEVICETYPE=vhost -TYPE=kernel_mode -BIND_INT=vlan100 -""" - -_CONTRAIL_VROUTER_DPDK_IFACE = """# This file is autogenerated by os-net-config -DEVICE=vhost0 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -BOOTPROTO=static -IPADDR=10.0.0.30 -NETMASK=255.255.255.0 -DEVICETYPE=vhost -TYPE=dpdk -BIND_INT=0000:00:03.0 -DRIVER=uio_pci_generic -CPU_LIST=0-31 -""" - -_CONTRAIL_VROUTER_DPDK_IFACE_CUST_DRIVER = """# This file is autogenerated by \ -os-net-config -DEVICE=vhost0 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -BOOTPROTO=static -IPADDR=10.0.0.30 -NETMASK=255.255.255.0 -DEVICETYPE=vhost -TYPE=dpdk -BIND_INT=0000:00:03.0 -DRIVER=vfio -CPU_LIST=0-31 -""" - -_CONTRAIL_VROUTER_DPDK_BOND_IFACE = """# This file is autogenerated by \ -os-net-config -DEVICE=vhost0 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -BOOTPROTO=static -IPADDR=10.0.0.30 -NETMASK=255.255.255.0 -DEVICETYPE=vhost -TYPE=dpdk -BIND_INT=0000:00:03.0,0000:00:01.0 -BOND_MODE=2 -BOND_POLICY=802.3ad -DRIVER=uio_pci_generic -CPU_LIST=2,3 -""" - -_LINUX_TAP_ROUTES = """default via 192.168.1.1 dev tap0 metric 10 -172.19.0.0/24 via 192.168.1.1 dev tap0 -172.20.0.0/24 via 192.168.1.5 dev tap0 metric 100 -""" - -_LINUX_TAP_IFACE = """# This file is autogenerated by os-net-config -DEVICE=tap0 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -BOOTPROTO=static -IPADDR=192.168.1.2 -NETMASK=255.255.255.0 -TYPE=Tap -""" - -_SRIOV_PF_IFCFG = """# This file is autogenerated by os-net-config -DEVICE=enp3s0f0 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -BOOTPROTO=none -""" - -_V4_SRIOV_PF_IFCFG = """# This file is autogenerated by os-net-config -DEVICE=enp3s0f0 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -BOOTPROTO=static -IPADDR=192.168.1.2 -NETMASK=255.255.255.0 -""" - - -class TestIfcfgNetConfig(base.TestCase): - def setUp(self): - super(TestIfcfgNetConfig, self).setUp() - rand = str(int(random.random() * 100000)) - common.SRIOV_CONFIG_FILE = '/tmp/sriov_config_' + rand + '.yaml' - - self.provider = impl_ifcfg.IfcfgNetConfig() - - def stub_is_ovs_installed(): - return True - self.stub_out('os_net_config.utils.is_ovs_installed', - stub_is_ovs_installed) - - def tearDown(self): - super(TestIfcfgNetConfig, self).tearDown() - if os.path.isfile(common.SRIOV_CONFIG_FILE): - os.remove(common.SRIOV_CONFIG_FILE) - - def get_interface_config(self, name='em1'): - return self.provider.interface_data[name] - - def get_vlan_config(self, name='vlan1'): - return self.provider.vlan_data[name] - - def get_linux_bond_config(self, name='bond0'): - return self.provider.linuxbond_data[name] - - def get_linux_team_config(self, name='team0'): - return self.provider.linuxteam_data[name] - - def get_route_config(self, name='em1'): - return self.provider.route_data.get(name, '') - - def get_route_table_config(self, name='custom', table_id=200): - return self.provider.route_table_data.get(name, table_id) - - def get_rule_config(self, name='em1'): - return self.provider.rule_data.get(name) - - def get_route6_config(self, name='em1'): - return self.provider.route6_data.get(name, '') - - def stub_get_stored_pci_address(self, ifname, noop): - if 'eth0' in ifname: - return "0000:00:07.0" - if 'eth1' in ifname: - return "0000:00:08.0" - if 'eth2' in ifname: - return "0000:00:09.0" - if 'em3' in ifname: - return "0000:00:03.0" - if 'em2' in ifname: - return "0000:00:02.0" - if 'em1' in ifname: - return "0000:00:01.0" - - def test_add_route_table(self): - route_table1 = objects.RouteTable('table1', 200) - route_table2 = objects.RouteTable('table2', '201') - self.provider.add_route_table(route_table1) - self.provider.add_route_table(route_table2) - self.assertEqual("table1", self.get_route_table_config(200)) - self.assertEqual("table2", self.get_route_table_config(201)) - - def test_add_route_with_table(self): - route_rule1 = objects.RouteRule('from 192.0.2.0/24 table 200', - 'test comment') - # Test route table by name - route1 = objects.Route('192.168.1.1', '172.19.0.0/24', False, - route_table="table1") - # Test that table specified in route_options takes precedence - route2 = objects.Route('192.168.1.1', '172.20.0.0/24', False, - 'table 201', route_table=200) - # Test route table specified by integer ID - route3 = objects.Route('192.168.1.1', '172.21.0.0/24', False, - route_table=200) - v4_addr = objects.Address('192.168.1.2/24') - interface = objects.Interface('em1', addresses=[v4_addr], - routes=[route1, route2, route3], - rules=[route_rule1]) - self.provider.add_interface(interface) - self.assertEqual(_V4_IFCFG, self.get_interface_config()) - self.assertEqual(_ROUTES_WITH_TABLES, self.get_route_config()) - self.assertEqual(_ROUTE_RULES, self.get_rule_config()) - - def test_add_base_interface(self): - interface = objects.Interface('em1') - self.provider.add_interface(interface) - self.assertEqual(_NO_IP, self.get_interface_config()) - - def test_add_interface_with_hotplug(self): - interface = objects.Interface('em1', hotplug=True) - self.provider.add_interface(interface) - self.assertEqual(_HOTPLUG, self.get_interface_config()) - - def test_add_interface_with_onboot(self): - interface = objects.Interface('em1', onboot=True) - self.provider.add_interface(interface) - self.assertEqual(_ONBOOT, self.get_interface_config()) - - def test_add_interface_with_linkdelay(self): - interface = objects.Interface('em1', linkdelay=10) - self.provider.add_interface(interface) - self.assertEqual(_LINKDELAY, self.get_interface_config()) - - def test_add_base_interface_vlan(self): - interface = objects.Interface('em1.120') - self.provider.add_interface(interface) - self.assertEqual(_IFCFG_VLAN, self.get_interface_config('em1.120')) - - def test_add_ovs_interface(self): - interface = objects.Interface('em1') - interface.ovs_port = True - self.provider.add_interface(interface) - self.assertEqual(_OVS_IFCFG, self.get_interface_config()) - - def test_add_ovs_tunnel(self): - interface = objects.OvsTunnel('tun0') - interface.type = 'ovs_tunnel' - interface.tunnel_type = 'gre' - interface.ovs_options = ['options:remote_ip=192.168.1.1'] - interface.bridge_name = 'br-ctlplane' - self.provider.add_interface(interface) - self.assertEqual(_OVS_IFCFG_TUNNEL, self.get_interface_config('tun0')) - - def test_add_ovs_patch_port(self): - patch_port = objects.OvsPatchPort("br-pub-patch") - patch_port.type = 'ovs_patch_port' - patch_port.bridge_name = 'br-ex' - patch_port.peer = 'br-ex-patch' - self.provider.add_interface(patch_port) - self.assertEqual(_OVS_IFCFG_PATCH_PORT, - self.get_interface_config('br-pub-patch')) - - def test_add_interface_with_v4(self): - v4_addr = objects.Address('192.168.1.2/24') - interface = objects.Interface('em1', addresses=[v4_addr]) - self.provider.add_interface(interface) - self.assertEqual(_V4_IFCFG, self.get_interface_config()) - self.assertEqual('', self.get_route_config()) - - def test_add_interface_with_v4_multiple(self): - addresses = [objects.Address('192.168.1.2/24'), - objects.Address('192.168.1.3/32'), - objects.Address('10.0.0.2/8')] - interface = objects.Interface('em1', addresses=addresses) - self.provider.add_interface(interface) - self.assertEqual(_V4_IFCFG_MULTIPLE, self.get_interface_config()) - self.assertEqual('', self.get_route_config()) - - def test_add_interface_map_persisted(self): - def test_interface_mac(name): - macs = {'em1': 'a1:b2:c3:d4:e5'} - return macs[name] - self.stub_out('os_net_config.common.interface_mac', test_interface_mac) - - nic_mapping = {'nic1': 'em1'} - self.stubbed_mapped_nics = nic_mapping - v4_addr = objects.Address('192.168.1.2/24') - interface = objects.Interface('nic1', addresses=[v4_addr], - nic_mapping=nic_mapping, - persist_mapping=True) - self.assertEqual('a1:b2:c3:d4:e5', interface.hwaddr) - self.provider.add_interface(interface) - self.assertEqual(_V4_IFCFG_MAPPED, self.get_interface_config('nic1')) - self.assertEqual('', self.get_route_config('nic1')) - - def test_add_interface_with_v6(self): - v6_addr = objects.Address('2001:abc:a::/64') - interface = objects.Interface('em1', addresses=[v6_addr]) - self.provider.add_interface(interface) - self.assertEqual(_V6_IFCFG, self.get_interface_config()) - - def test_add_interface_with_v6_multiple(self): - addresses = [objects.Address('2001:abc:a::/64'), - objects.Address('2001:abc:b::1/64'), - objects.Address('2001:abc:c::2/96')] - interface = objects.Interface('em1', addresses=addresses) - self.provider.add_interface(interface) - self.assertEqual(_V6_IFCFG_MULTIPLE, self.get_interface_config()) - - def test_network_with_routes(self): - route1 = objects.Route('192.168.1.1', default=True, - route_options="metric 10") - route2 = objects.Route('192.168.1.1', '172.19.0.0/24') - route3 = objects.Route('192.168.1.5', '172.20.0.0/24', - route_options="metric 100") - v4_addr = objects.Address('192.168.1.2/24') - interface = objects.Interface('em1', addresses=[v4_addr], - routes=[route1, route2, route3]) - self.provider.add_interface(interface) - self.assertEqual(_V4_IFCFG, self.get_interface_config()) - self.assertEqual(_ROUTES, self.get_route_config()) - - def test_network_with_ipv6_routes(self): - route1 = objects.Route('192.168.1.1', default=True, - route_options="metric 10") - route2 = objects.Route('192.168.1.1', '172.19.0.0/24') - route3 = objects.Route('192.168.1.5', '172.20.0.0/24', - route_options="metric 100") - route4 = objects.Route('2001:db8::1', default=True) - route5 = objects.Route('fd00:fd00:2000::1', - '2001:db8:dead:beef:cafe::/56') - route6 = objects.Route('fd00:fd00:2000::1', - '2001:db8:dead:beff::/64', - route_options="metric 100") - v4_addr = objects.Address('192.168.1.2/24') - v6_addr = objects.Address('2001:abc:a::/64') - interface = objects.Interface('em1', addresses=[v4_addr, v6_addr], - routes=[route1, route2, route3, - route4, route5, route6]) - self.provider.add_interface(interface) - self.assertEqual(_V4_V6_IFCFG, self.get_interface_config()) - self.assertEqual(_ROUTES_V6, self.get_route6_config()) - - def test_network_ovs_bridge_with_dhcp(self): - interface = objects.Interface('em1') - bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True, - members=[interface]) - self.provider.add_interface(interface) - self.provider.add_bridge(bridge) - self.assertEqual(_OVS_INTERFACE, self.get_interface_config()) - self.assertEqual(_OVS_BRIDGE_DHCP, - self.provider.bridge_data['br-ctlplane']) - - def test_network_ovs_bridge_with_dhcpv6(self): - interface = objects.Interface('em1') - bridge = objects.OvsBridge('br-ctlplane', use_dhcpv6=True, - members=[interface]) - self.provider.add_interface(interface) - self.provider.add_bridge(bridge) - self.assertEqual(_OVS_INTERFACE, self.get_interface_config()) - self.assertEqual(_OVS_BRIDGE_DHCPV6, - self.provider.bridge_data['br-ctlplane']) - - def test_network_ovs_bridge_with_standalone_fail_mode(self): - interface = objects.Interface('em1') - bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True, - members=[interface], - fail_mode='standalone') - self.provider.add_interface(interface) - self.provider.add_bridge(bridge) - self.assertEqual(_OVS_INTERFACE, self.get_interface_config()) - self.assertEqual(_OVS_BRIDGE_DHCP_STANDALONE, - self.provider.bridge_data['br-ctlplane']) - - def test_network_ovs_bridge_with_secure_fail_mode(self): - interface = objects.Interface('em1') - bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True, - members=[interface], - fail_mode='secure') - self.provider.add_interface(interface) - self.provider.add_bridge(bridge) - self.assertEqual(_OVS_INTERFACE, self.get_interface_config()) - self.assertEqual(_OVS_BRIDGE_DHCP_SECURE, - self.provider.bridge_data['br-ctlplane']) - - def test_network_linux_bridge_with_dhcp(self): - interface = objects.Interface('em1') - bridge = objects.LinuxBridge('br-ctlplane', use_dhcp=True, - members=[interface]) - self.provider.add_linux_bridge(bridge) - self.provider.add_interface(interface) - self.assertEqual(_LINUX_BRIDGE_IFCFG, self.get_interface_config()) - self.assertEqual(_LINUX_BRIDGE_DHCP, - self.provider.linuxbridge_data['br-ctlplane']) - - def test_network_ovs_bridge_static(self): - v4_addr = objects.Address('192.168.1.2/24') - interface = objects.Interface('em1') - bridge = objects.OvsBridge('br-ctlplane', members=[interface], - addresses=[v4_addr]) - self.provider.add_interface(interface) - self.provider.add_bridge(bridge) - self.assertEqual(_OVS_INTERFACE, self.get_interface_config()) - self.assertEqual(_OVS_BRIDGE_STATIC, - self.provider.bridge_data['br-ctlplane']) - - def test_network_ovs_bridge_with_tunnel(self): - interface = objects.OvsTunnel('tun0') - interface.type = 'ovs_tunnel' - interface.tunnel_type = 'gre' - interface.ovs_options = ['options:remote_ip=192.168.1.1'] - interface.bridge_name = 'br-ctlplane' - self.provider.add_interface(interface) - v4_addr = objects.Address('192.168.1.2/24') - bridge = objects.OvsBridge('br-ctlplane', members=[interface], - addresses=[v4_addr]) - self.provider.add_bridge(bridge) - self.provider.add_interface(interface) - self.assertEqual(_OVS_IFCFG_TUNNEL, self.get_interface_config('tun0')) - self.assertEqual(_OVS_BRIDGE_STATIC, - self.provider.bridge_data['br-ctlplane']) - - def test_network_linux_bridge_static(self): - v4_addr = objects.Address('192.168.1.2/24') - interface = objects.Interface('em1') - bridge = objects.LinuxBridge('br-ctlplane', members=[interface], - addresses=[v4_addr]) - self.provider.add_interface(interface) - self.provider.add_bridge(bridge) - self.assertEqual(_LINUX_BRIDGE_IFCFG, self.get_interface_config()) - self.assertEqual(_LINUX_BRIDGE_STATIC, - self.provider.bridge_data['br-ctlplane']) - - def test_network_ovs_bridge_has_mac_table_size(self): - bridge = objects.OvsBridge('br-test') - self.provider.add_bridge(bridge) - self.assertIn("set bridge br-test other-config:mac-table-size=50000", - self.provider.bridge_data['br-test']) - - def test_network_ovs_bridge_with_dhcp_primary_interface(self): - def test_interface_mac(name): - return "a1:b2:c3:d4:e5" - self.stub_out('os_net_config.common.interface_mac', test_interface_mac) - - interface = objects.Interface('em1', primary=True) - bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True, - members=[interface]) - self.provider.add_interface(interface) - self.provider.add_bridge(bridge) - self.assertEqual(_OVS_INTERFACE, self.get_interface_config()) - self.assertEqual(_OVS_BRIDGE_DHCP_PRIMARY_INTERFACE, - self.provider.bridge_data['br-ctlplane']) - - def test_network_ovs_bridge_with_dhcp_primary_interface_with_extra(self): - def test_interface_mac(name): - return "a1:b2:c3:d4:e5" - self.stub_out('os_net_config.common.interface_mac', test_interface_mac) - - interface = objects.Interface('em1', primary=True) - ovs_extra = "br-set-external-id br-ctlplane bridge-id br-ctlplane" - bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True, - members=[interface], - ovs_extra=[ovs_extra]) - self.provider.add_interface(interface) - self.provider.add_bridge(bridge) - self.assertEqual(_OVS_INTERFACE, self.get_interface_config()) - self.assertEqual(_OVS_BRIDGE_DHCP_OVS_EXTRA, - self.provider.bridge_data['br-ctlplane']) - - def test_network_ovs_bridge_with_dhcp_primary_interface_with_format(self): - def test_interface_mac(name): - return "a1:b2:c3:d4:e5" - self.stub_out('os_net_config.common.interface_mac', test_interface_mac) - - interface = objects.Interface('em1', primary=True) - ovs_extra = "br-set-external-id {name} bridge-id {name}" - bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True, - members=[interface], - ovs_extra=[ovs_extra]) - self.provider.add_interface(interface) - self.provider.add_bridge(bridge) - self.assertEqual(_OVS_INTERFACE, self.get_interface_config()) - self.assertEqual(_OVS_BRIDGE_DHCP_OVS_EXTRA, - self.provider.bridge_data['br-ctlplane']) - - def test_network_ivs_with_uplink_and_interface(self): - interface = objects.Interface('em1') - v4_addr = objects.Address('172.16.2.7/24') - ivs_interface = objects.IvsInterface(vlan_id=5, - name='storage', - addresses=[v4_addr]) - bridge = objects.IvsBridge(members=[interface, ivs_interface]) - self.provider.add_interface(interface) - self.provider.add_ivs_interface(ivs_interface) - self.provider.add_bridge(bridge) - self.assertEqual(_IVS_UPLINK, self.get_interface_config()) - self.assertEqual(_IVS_INTERFACE, - self.provider.ivsinterface_data[ivs_interface.name]) - data = self.provider.generate_ivs_config(['em1'], ['storage5']) - self.assertEqual(_IVS_CONFIG, data) - - def test_network_nfvswitch_with_interfaces_and_internal_interfaces(self): - interface = objects.Interface('em1') - v4_addr = objects.Address('172.16.2.7/24') - nfvswitch_internal = objects.NfvswitchInternal(vlan_id=5, - name='storage', - addresses=[v4_addr]) - iface_name = nfvswitch_internal.name - bridge = objects.NfvswitchBridge(members=[interface, - nfvswitch_internal], - options="-c 2,3,4,5") - self.provider.add_interface(interface) - self.provider.add_nfvswitch_internal(nfvswitch_internal) - self.provider.add_nfvswitch_bridge(bridge) - self.assertEqual(_NFVSWITCH_INTERFACE, self.get_interface_config()) - self.assertEqual(_NFVSWITCH_INTERNAL, - self.provider.nfvswitch_intiface_data[iface_name]) - data = self.provider.generate_nfvswitch_config(['em1'], ['storage5']) - self.assertEqual(_NFVSWITCH_CONFIG, data) - - def test_add_ib_interface_with_v4_multiple(self): - addresses = [objects.Address('192.168.1.2/24'), - objects.Address('192.168.1.3/32'), - objects.Address('10.0.0.2/8')] - ib_interface = objects.IbInterface('ib0', addresses=addresses) - self.provider.add_interface(ib_interface) - self.assertEqual(_IB_V4_IFCFG_MULTIPLE, - self.get_interface_config('ib0')) - self.assertEqual('', self.get_route_config()) - - def test_add_ib_child_interface(self): - ib_child_interface = objects.IbChildInterface('ib0', 1) - self.provider.add_interface(ib_child_interface) - self.assertEqual(_BASE_IB_CHILD_IFCFG, - self.get_interface_config('ib0.8001')) - self.assertEqual('', self.get_route_config()) - - def test_add_contrail_vrouter(self): - addresses = [objects.Address('10.0.0.30/24')] - interface1 = objects.Interface('em3') - cvi = objects.ContrailVrouter('vhost0', addresses=addresses, - members=[interface1],) - self.provider.add_contrail_vrouter(cvi) - self.assertEqual( - _CONTRAIL_VROUTER_IFACE, - self.provider.interface_data['vhost0']) - self.assertEqual('', self.get_route_config('vhost0')) - - def test_add_contrail_vrouter_l3mh(self): - interface1 = objects.Interface('em3') - interface2 = objects.Interface('em4') - cvi = objects.ContrailVrouter('vhost0', - members=[interface1, interface2],) - self.provider.add_contrail_vrouter(cvi) - self.assertEqual( - _CONTRAIL_VROUTER_IFACE_L3MH, - self.provider.interface_data['vhost0']) - self.assertEqual('', self.get_route_config('vhost0')) - - def test_add_contrail_vrouter_vlan(self): - addresses = [objects.Address('10.0.0.30/24')] - interface1 = objects.Interface('vlan100') - cvi = objects.ContrailVrouter('vhost0', addresses=addresses, - members=[interface1],) - self.provider.add_contrail_vrouter(cvi) - self.assertEqual( - _CONTRAIL_VROUTER_VLAN_IFACE, - self.provider.interface_data['vhost0']) - self.assertEqual('', self.get_route_config('vhost0')) - - def test_add_contrail_vrouter_with_nic_mapping(self): - nic_mapping = {'nic1': 'em3'} - self.stubbed_mapped_nics = nic_mapping - addresses = [objects.Address('10.0.0.30/24')] - interface1 = objects.Interface('nic1') - cvi = objects.ContrailVrouter('vhost0', addresses=addresses, - members=[interface1]) - self.provider.add_contrail_vrouter(cvi) - self.assertEqual( - _CONTRAIL_VROUTER_IFACE, - self.provider.interface_data['vhost0']) - self.assertEqual('', self.get_route_config('vhost0')) - - def test_add_contrail_vrouter_dpdk_interface(self): - addresses = [objects.Address('10.0.0.30/24')] - interface1 = objects.Interface('em3') - self.stub_out('os_net_config.utils.get_stored_pci_address', - self.stub_get_stored_pci_address) - cvi = objects.ContrailVrouterDpdk('vhost0', addresses=addresses, - members=[interface1]) - self.provider.noop = True - self.provider.add_contrail_vrouter_dpdk(cvi) - self.assertEqual( - _CONTRAIL_VROUTER_DPDK_IFACE, - self.provider.interface_data['vhost0']) - self.assertEqual('', self.get_route_config('vhost0')) - - def test_add_contrail_vrouter_dpdk_interface_cust_driver(self): - addresses = [objects.Address('10.0.0.30/24')] - interface1 = objects.Interface('em3') - self.stub_out('os_net_config.utils.get_stored_pci_address', - self.stub_get_stored_pci_address) - cvi = objects.ContrailVrouterDpdk('vhost0', addresses=addresses, - members=[interface1], driver='vfio') - self.provider.noop = True - self.provider.add_contrail_vrouter_dpdk(cvi) - self.assertEqual( - _CONTRAIL_VROUTER_DPDK_IFACE_CUST_DRIVER, - self.provider.interface_data['vhost0']) - self.assertEqual('', self.get_route_config('vhost0')) - - def test_add_contrail_vrouter_dpdk_interface_nic_mapping(self): - nic_mapping = {'nic1': 'em3'} - self.stubbed_mapped_nics = nic_mapping - addresses = [objects.Address('10.0.0.30/24')] - interface1 = objects.Interface('nic1') - self.stub_out('os_net_config.utils.get_stored_pci_address', - self.stub_get_stored_pci_address) - cvi = objects.ContrailVrouterDpdk('vhost0', addresses=addresses, - members=[interface1]) - self.provider.noop = True - self.provider.add_contrail_vrouter_dpdk(cvi) - self.assertEqual( - _CONTRAIL_VROUTER_DPDK_IFACE, - self.provider.interface_data['vhost0']) - self.assertEqual('', self.get_route_config('vhost0')) - - def test_add_contrail_vrouter_dpdk_bond_interface(self): - addresses = [objects.Address('10.0.0.30/24')] - interface1 = objects.Interface('em3') - interface2 = objects.Interface('em1') - self.stub_out('os_net_config.utils.get_stored_pci_address', - self.stub_get_stored_pci_address) - cvi = objects.ContrailVrouterDpdk('vhost0', addresses=addresses, - members=[interface1, interface2], - bond_mode="2", - bond_policy="802.3ad", - cpu_list="2,3") - self.provider.noop = True - self.provider.add_contrail_vrouter_dpdk(cvi) - self.assertEqual( - _CONTRAIL_VROUTER_DPDK_BOND_IFACE, - self.provider.interface_data['vhost0']) - self.assertEqual('', self.get_route_config('vhost0')) - - def test_add_contrail_vrouter_dpdk_bond_interface_nic_mapping(self): - nic_mapping = {'nic1': 'em3', 'nic2': 'em1'} - self.stubbed_mapped_nics = nic_mapping - addresses = [objects.Address('10.0.0.30/24')] - interface1 = objects.Interface('nic1') - interface2 = objects.Interface('nic2') - self.stub_out('os_net_config.utils.get_stored_pci_address', - self.stub_get_stored_pci_address) - cvi = objects.ContrailVrouterDpdk('vhost0', addresses=addresses, - members=[interface1, interface2], - bond_mode="2", - bond_policy="802.3ad", - cpu_list="2,3") - self.provider.noop = True - self.provider.add_contrail_vrouter_dpdk(cvi) - self.assertEqual( - _CONTRAIL_VROUTER_DPDK_BOND_IFACE, - self.provider.interface_data['vhost0']) - self.assertEqual('', self.get_route_config('vhost0')) - - def test_add_linux_tap(self): - v4_addr = objects.Address('192.168.1.2/24') - route1 = objects.Route('192.168.1.1', default=True, - route_options="metric 10") - route2 = objects.Route('192.168.1.1', '172.19.0.0/24') - route3 = objects.Route('192.168.1.5', '172.20.0.0/24', - route_options="metric 100") - tap = objects.LinuxTap('tap0', addresses=[v4_addr], - nm_controlled=False, - routes=[route1, route2, route3]) - self.provider.add_linux_tap(tap) - self.assertEqual( - _LINUX_TAP_IFACE, - self.get_interface_config('tap0')) - self.assertEqual( - _LINUX_TAP_ROUTES, - self.get_route_config('tap0')) - - def test_add_vlan(self): - vlan = objects.Vlan('em1', 5) - self.provider.add_vlan(vlan) - self.assertEqual(_VLAN_NO_IP, self.get_vlan_config('vlan5')) - - def test_add_vlan_ovs(self): - vlan = objects.Vlan('em1', 5) - vlan.ovs_port = True - self.provider.add_vlan(vlan) - self.assertEqual(_VLAN_OVS, self.get_vlan_config('vlan5')) - - def test_add_vlan_ovs_options(self): - vlan = objects.Vlan('em1', 5) - vlan.ovs_port = True - vlan.ovs_options = 'foo' - vlan.ovs_extra = ['bar', 'baz'] - self.provider.add_vlan(vlan) - self.assertEqual(_VLAN_OVS_EXTRA, self.get_vlan_config('vlan5')) - - def test_add_vlan_mtu_1500(self): - vlan = objects.Vlan('em1', 5, mtu=1500) - self.provider.add_vlan(vlan) - expected = _VLAN_NO_IP + 'MTU=1500\n' - self.assertEqual(expected, self.get_vlan_config('vlan5')) - - def test_add_ovs_bridge_with_vlan(self): - vlan = objects.Vlan('em1', 5) - bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True, - members=[vlan]) - self.provider.add_vlan(vlan) - self.provider.add_bridge(bridge) - self.assertEqual(_VLAN_OVS_BRIDGE, self.get_vlan_config('vlan5')) - - def test_add_linux_bridge_with_vlan(self): - vlan = objects.Vlan('em1', 5) - bridge = objects.LinuxBridge('br-ctlplane', use_dhcp=True, - members=[vlan]) - self.provider.add_vlan(vlan) - self.provider.add_bridge(bridge) - self.assertEqual(_VLAN_LINUX_BRIDGE, self.get_vlan_config('vlan5')) - - def test_ovs_bond(self): - interface1 = objects.Interface('em1') - interface2 = objects.Interface('em2') - bond = objects.OvsBond('bond0', use_dhcp=True, - members=[interface1, interface2]) - self.provider.add_interface(interface1) - self.provider.add_interface(interface2) - self.provider.add_bond(bond) - self.assertEqual(_NO_IP, self.get_interface_config('em1')) - - em2_config = """# This file is autogenerated by os-net-config -DEVICE=em2 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -BOOTPROTO=none -""" - self.assertEqual(em2_config, self.get_interface_config('em2')) - self.assertEqual(_OVS_BOND_DHCP, - self.get_interface_config('bond0')) - - def test_linux_bond(self): - interface1 = objects.Interface('em1') - interface2 = objects.Interface('em2') - bond = objects.LinuxBond('bond0', use_dhcp=True, - members=[interface1, interface2]) - self.provider.add_linux_bond(bond) - self.provider.add_interface(interface1) - self.provider.add_interface(interface2) - self.assertEqual(_LINUX_BOND_DHCP, - self.get_linux_bond_config('bond0')) - self.assertEqual(_LINUX_BOND_INTERFACE, - self.get_interface_config('em1')) - - def test_linux_team(self): - interface1 = objects.Interface('em1') - interface2 = objects.Interface('em2') - team = objects.LinuxTeam('team0', use_dhcp=True, - members=[interface1, interface2]) - self.provider.add_linux_team(team) - self.provider.add_interface(interface1) - self.provider.add_interface(interface2) - self.assertEqual(_LINUX_TEAM_DHCP, - self.get_linux_team_config('team0')) - self.assertEqual(_LINUX_TEAM_INTERFACE, - self.get_interface_config('em1')) - - def test_interface_defroute(self): - interface1 = objects.Interface('em1') - interface2 = objects.Interface('em2', defroute=False) - self.provider.add_interface(interface1) - self.provider.add_interface(interface2) - em1_config = """# This file is autogenerated by os-net-config -DEVICE=em1 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -BOOTPROTO=none -""" - em2_config = """# This file is autogenerated by os-net-config -DEVICE=em2 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -BOOTPROTO=none -DEFROUTE=no -""" - self.assertEqual(em1_config, self.get_interface_config('em1')) - self.assertEqual(em2_config, self.get_interface_config('em2')) - - def test_interface_dhclient_opts(self): - interface1 = objects.Interface('em1', dhclient_args='--foobar') - self.provider.add_interface(interface1) - em1_config = """# This file is autogenerated by os-net-config -DEVICE=em1 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -BOOTPROTO=none -DHCLIENTARGS=--foobar -""" - self.assertEqual(em1_config, self.get_interface_config('em1')) - - def test_sriov_pf_ethtool_opts(self): - ifc = objects.SriovPF('enp3s0f0', 16, - ethtool_opts='speed 1000 duplex full') - self.provider.add_interface(ifc) - pf_config = "".join((_SRIOV_PF_IFCFG, - "ETHTOOL_OPTS=\"speed 1000 duplex full\"\n")) - self.assertEqual(pf_config, self.get_interface_config('enp3s0f0')) - - def test_interface_ethtool_opts(self): - interface1 = objects.Interface('em1', - ethtool_opts='speed 1000 duplex full') - self.provider.add_interface(interface1) - em1_config = """# This file is autogenerated by os-net-config -DEVICE=em1 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -BOOTPROTO=none -ETHTOOL_OPTS=\"speed 1000 duplex full\" -""" - self.assertEqual(em1_config, self.get_interface_config('em1')) - - def test_ib_interface_ethtool_opts(self): - ifc = objects.IbInterface('ib0', ethtool_opts='speed 1000 duplex full') - self.provider.add_interface(ifc) - ib_config = "".join((_IB_IFCFG, - "ETHTOOL_OPTS=\"speed 1000 duplex full\"\n")) - self.assertEqual(ib_config, self.get_interface_config('ib0')) - - def test_linux_bond_with_ethtool_opts(self): - interface1 = objects.Interface( - 'em1', - ethtool_opts='-K ${DEVICE} tx-gre-csum-segmentation off') - interface2 = objects.Interface( - 'em2', - ethtool_opts='-K ${DEVICE} tx-gre-csum-segmentation off') - bond = objects.LinuxBond( - 'bond0', use_dhcp=True, - members=[interface1, interface2], - ethtool_opts='-K ${DEVICE} tx-gre-csum-segmentation off') - self.provider.add_linux_bond(bond) - self.provider.add_interface(interface1) - self.provider.add_interface(interface2) - bond_config = "".join( - (_LINUX_BOND_DHCP, - "ETHTOOL_OPTS=\"-K ${DEVICE} tx-gre-csum-segmentation off\"\n")) - interface_config = "".join( - (_LINUX_BOND_INTERFACE, - "ETHTOOL_OPTS=\"-K ${DEVICE} tx-gre-csum-segmentation off\"\n")) - self.assertEqual(bond_config, - self.get_linux_bond_config('bond0')) - self.assertEqual(interface_config, - self.get_interface_config('em1')) - - def test_interface_single_dns_server(self): - interface1 = objects.Interface('em1', dns_servers=['1.2.3.4']) - self.provider.add_interface(interface1) - em1_config = """# This file is autogenerated by os-net-config -DEVICE=em1 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -BOOTPROTO=none -DNS1=1.2.3.4 -""" - self.assertEqual(em1_config, self.get_interface_config('em1')) - - def test_interface_dns_servers(self): - interface1 = objects.Interface('em1', dns_servers=['1.2.3.4', - '5.6.7.8']) - self.provider.add_interface(interface1) - em1_config = """# This file is autogenerated by os-net-config -DEVICE=em1 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -BOOTPROTO=none -DNS1=1.2.3.4 -DNS2=5.6.7.8 -""" - self.assertEqual(em1_config, self.get_interface_config('em1')) - - def test_interface_more_dns_servers(self): - interface1 = objects.Interface('em1', dns_servers=['1.2.3.4', - '5.6.7.8', - '9.10.11.12']) - self.provider.add_interface(interface1) - em1_config = """# This file is autogenerated by os-net-config -DEVICE=em1 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -BOOTPROTO=none -DNS1=1.2.3.4 -DNS2=5.6.7.8 -""" - self.assertEqual(em1_config, self.get_interface_config('em1')) - - def test_interface_single_domain(self): - interface1 = objects.Interface('em1', dns_servers=['1.2.3.4'], - domain='openstack.local') - self.provider.add_interface(interface1) - em1_config = """# This file is autogenerated by os-net-config -DEVICE=em1 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -BOOTPROTO=none -DNS1=1.2.3.4 -DOMAIN=openstack.local -""" - self.assertEqual(em1_config, self.get_interface_config('em1')) - - def test_interface_single_domain_in_list(self): - interface1 = objects.Interface('em1', dns_servers=['1.2.3.4'], - domain=['openstack.local']) - self.provider.add_interface(interface1) - em1_config = """# This file is autogenerated by os-net-config -DEVICE=em1 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -BOOTPROTO=none -DNS1=1.2.3.4 -DOMAIN="openstack.local" -""" - self.assertEqual(em1_config, self.get_interface_config('em1')) - - def test_interface_multiple_domains(self): - interface1 = objects.Interface( - 'em1', - dns_servers=['1.2.3.4'], - domain=['openstack.local', 'subdomain.openstack.local']) - self.provider.add_interface(interface1) - em1_config = """# This file is autogenerated by os-net-config -DEVICE=em1 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -BOOTPROTO=none -DNS1=1.2.3.4 -DOMAIN="openstack.local subdomain.openstack.local" -""" - self.assertEqual(em1_config, self.get_interface_config('em1')) - - def test_nm_controlled(self): - interface1 = objects.Interface('em1', nm_controlled=True) - interface2 = objects.Interface('em2', nm_controlled=True) - bond = objects.LinuxBond('bond1', nm_controlled=True, - members=[interface1, interface2]) - self.provider.add_linux_bond(bond) - self.provider.add_interface(interface1) - self.provider.add_interface(interface2) - - ifcfg_data = self.get_interface_config('em1') - self.assertEqual(_NM_CONTROLLED_INTERFACE, ifcfg_data) - bond_data = self.get_linux_bond_config('bond1') - self.assertEqual(_NM_CONTROLLED_BOND, bond_data) - - def test_network_sriov_vf_without_config(self): - nic_mapping = {'nic1': 'eth0', 'nic2': 'eth1', 'nic3': 'eth2'} - self.stubbed_mapped_nics = nic_mapping - addresses = [objects.Address('10.0.0.30/24')] - - def test_update_sriov_vf_map(pf_name, vfid, vf_name, vlan_id=None, - qos=None, spoofcheck=None, trust=None, - state=None, macaddr=None, promisc=None, - pci_address=None, min_tx_rate=0, - max_tx_rate=0, driver=None): - self.assertEqual(pf_name, 'eth2') - self.assertEqual(vfid, 7) - self.assertEqual(vlan_id, 0) - self.assertEqual(qos, 0) - self.assertEqual(min_tx_rate, 0) - self.assertEqual(max_tx_rate, 0) - self.assertEqual(spoofcheck, None) - self.assertEqual(trust, None) - self.assertEqual(state, None) - self.assertEqual(macaddr, None) - self.assertEqual(pci_address, '0000:79:10.2') - self.assertEqual(driver, None) - self.stub_out('os_net_config.utils.update_sriov_vf_map', - test_update_sriov_vf_map) - - def test_get_vf_devname(device, vfid): - return device + '_' + str(vfid) - - def test_get_pci_address(ifname, noop): - return '0000:79:10.2' - - self.stub_out('os_net_config.utils.get_vf_devname', - test_get_vf_devname) - - self.stub_out('os_net_config.utils.get_pci_address', - test_get_pci_address) - - vf = objects.SriovVF(device='nic3', vfid=7, addresses=addresses) - self.provider.add_sriov_vf(vf) - vf_config = """# This file is autogenerated by os-net-config -DEVICE=eth2_7 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -BOOTPROTO=static -IPADDR=10.0.0.30 -NETMASK=255.255.255.0 -""" - self.assertEqual(vf_config, self.get_interface_config('eth2_7')) - - def test_network_sriov_vf_true(self): - nic_mapping = {'nic1': 'eth0', 'nic2': 'eth1', 'nic3': 'eth2'} - self.stubbed_mapped_nics = nic_mapping - addresses = [objects.Address('10.0.0.30/24')] - - def test_update_sriov_vf_map(pf_name, vfid, vf_name, vlan_id=None, - qos=None, spoofcheck=None, trust=None, - state=None, macaddr=None, promisc=None, - pci_address=None, min_tx_rate=0, - max_tx_rate=0, driver=None): - self.assertEqual(pf_name, 'eth2') - self.assertEqual(vf_name, 'eth2_7') - self.assertEqual(vfid, 7) - self.assertEqual(vlan_id, 100) - self.assertEqual(qos, 10) - self.assertEqual(min_tx_rate, 0) - self.assertEqual(max_tx_rate, 0) - self.assertTrue(spoofcheck) - self.assertTrue(trust) - self.assertEqual(state, "auto") - self.assertEqual(macaddr, "AA:BB:CC:DD:EE:FF") - self.assertTrue(promisc) - self.assertEqual(pci_address, '0000:80:10.1') - self.assertEqual(driver, None) - self.stub_out('os_net_config.utils.update_sriov_vf_map', - test_update_sriov_vf_map) - - def test_get_vf_devname(device, vfid): - return device + '_' + str(vfid) - - def test_get_pci_address(ifname, noop): - return '0000:80:10.1' - - self.stub_out('os_net_config.utils.get_vf_devname', - test_get_vf_devname) - - self.stub_out('os_net_config.utils.get_pci_address', - test_get_pci_address) - - vf = objects.SriovVF(device='nic3', vfid=7, addresses=addresses, - vlan_id='100', qos='10', spoofcheck=True, - trust=True, state="auto", - macaddr="AA:BB:CC:DD:EE:FF", promisc=True) - - self.provider.add_sriov_vf(vf) - vf_config = """# This file is autogenerated by os-net-config -DEVICE=eth2_7 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -BOOTPROTO=static -IPADDR=10.0.0.30 -NETMASK=255.255.255.0 -""" - self.assertEqual(vf_config, self.get_interface_config('eth2_7')) - - def test_network_sriov_vf_config_false(self): - nic_mapping = {'nic1': 'eth0', 'nic2': 'eth1', 'nic3': 'eth2'} - self.stubbed_mapped_nics = nic_mapping - addresses = [objects.Address('10.0.0.30/24')] - - def test_update_sriov_vf_map(pf_name, vfid, vf_name, vlan_id=None, - qos=None, spoofcheck=None, trust=None, - state=None, macaddr=None, promisc=None, - pci_address=None, min_tx_rate=0, - max_tx_rate=0, driver=None): - self.assertEqual(pf_name, 'eth2') - self.assertEqual(vf_name, 'eth2_7') - self.assertEqual(vfid, 7) - self.assertEqual(vlan_id, 100) - self.assertEqual(qos, 10) - self.assertEqual(min_tx_rate, 0) - self.assertEqual(max_tx_rate, 0) - self.assertFalse(spoofcheck) - self.assertFalse(trust) - self.assertEqual(state, "enable") - self.assertEqual(macaddr, "AA:BB:CC:DD:EE:FF") - self.assertFalse(promisc) - self.assertEqual(pci_address, '0000:82:00.2') - self.assertEqual(driver, None) - self.stub_out('os_net_config.utils.update_sriov_vf_map', - test_update_sriov_vf_map) - - def test_get_vf_devname(device, vfid): - return device + '_' + str(vfid) - - def test_get_pci_address(ifname, noop): - return '0000:82:00.2' - - self.stub_out('os_net_config.utils.get_vf_devname', - test_get_vf_devname) - - self.stub_out('os_net_config.utils.get_pci_address', - test_get_pci_address) - - vf = objects.SriovVF(device='nic3', vfid=7, addresses=addresses, - vlan_id='100', qos='10', spoofcheck=False, - trust=False, state="enable", - macaddr="AA:BB:CC:DD:EE:FF", promisc=False) - - self.provider.add_sriov_vf(vf) - vf_config = """# This file is autogenerated by os-net-config -DEVICE=eth2_7 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -BOOTPROTO=static -IPADDR=10.0.0.30 -NETMASK=255.255.255.0 -""" - self.assertEqual(vf_config, self.get_interface_config('eth2_7')) - - def test_network_sriov_pf_without_promisc(self): - nic_mapping = {'nic1': 'eth0', 'nic2': 'eth1', 'nic3': 'eth2'} - self.stubbed_mapped_nics = nic_mapping - - pf = objects.SriovPF(name='nic3', numvfs=10) - - def test_update_sriov_pf_map(name, numvfs, noop, promisc=None, - link_mode='legacy', vdpa=False, - steering_mode="smfs"): - self.assertEqual(name, 'eth2') - self.assertEqual(numvfs, 10) - self.assertEqual(promisc, None) - self.assertEqual(link_mode, 'legacy') - self.stub_out('os_net_config.utils.update_sriov_pf_map', - test_update_sriov_pf_map) - self.provider.add_sriov_pf(pf) - pf_config = """# This file is autogenerated by os-net-config -DEVICE=eth2 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -BOOTPROTO=none -""" - self.assertEqual(pf_config, self.get_interface_config('eth2')) - - def test_network_sriov_pf_with_promisc_on(self): - nic_mapping = {'nic1': 'eth0', 'nic2': 'eth1', 'nic3': 'eth2'} - self.stubbed_mapped_nics = nic_mapping - - pf = objects.SriovPF(name='nic3', numvfs=10, promisc=True) - - def test_update_sriov_pf_map(name, numvfs, noop, promisc=None, - link_mode='legacy', vdpa=False, - steering_mode="smfs"): - self.assertEqual(name, 'eth2') - self.assertEqual(numvfs, 10) - self.assertTrue(promisc) - self.assertEqual(link_mode, 'legacy') - self.stub_out('os_net_config.utils.update_sriov_pf_map', - test_update_sriov_pf_map) - self.provider.add_sriov_pf(pf) - pf_config = """# This file is autogenerated by os-net-config -DEVICE=eth2 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -BOOTPROTO=none -""" - self.assertEqual(pf_config, self.get_interface_config('eth2')) - - def test_network_sriov_pf_with_promisc_off(self): - nic_mapping = {'nic1': 'eth0', 'nic2': 'eth1', 'nic3': 'eth2'} - self.stubbed_mapped_nics = nic_mapping - - pf = objects.SriovPF(name='nic3', numvfs=10, promisc=False) - - def test_update_sriov_pf_map(name, numvfs, noop, promisc=None, - link_mode='legacy', vdpa=False, - steering_mode="smfs"): - self.assertEqual(name, 'eth2') - self.assertEqual(numvfs, 10) - self.assertFalse(promisc) - self.assertEqual(link_mode, 'legacy') - self.stub_out('os_net_config.utils.update_sriov_pf_map', - test_update_sriov_pf_map) - self.provider.add_sriov_pf(pf) - pf_config = """# This file is autogenerated by os-net-config -DEVICE=eth2 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -BOOTPROTO=none -""" - self.assertEqual(pf_config, self.get_interface_config('eth2')) - - def test_network_ovs_dpdk_bridge_and_port(self): - nic_mapping = {'nic1': 'eth0', 'nic2': 'eth1', 'nic3': 'eth2'} - self.stubbed_mapped_nics = nic_mapping - - interface = objects.Interface(name='nic3') - dpdk_port = objects.OvsDpdkPort(name='dpdk0', members=[interface]) - bridge = objects.OvsUserBridge('br-link', members=[dpdk_port]) - - def test_bind_dpdk_interfaces(ifname, driver, noop): - self.assertEqual(ifname, 'eth2') - self.assertEqual(driver, 'vfio-pci') - self.stub_out('os_net_config.utils.bind_dpdk_interfaces', - test_bind_dpdk_interfaces) - self.stub_out('os_net_config.utils.get_stored_pci_address', - self.stub_get_stored_pci_address) - - self.provider.add_ovs_dpdk_port(dpdk_port) - self.provider.add_ovs_user_bridge(bridge) - br_link_config = """# This file is autogenerated by os-net-config -DEVICE=br-link -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -DEVICETYPE=ovs -TYPE=OVSUserBridge -""" - dpdk0_config = """# This file is autogenerated by os-net-config -DEVICE=dpdk0 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -DEVICETYPE=ovs -TYPE=OVSDPDKPort -OVS_BRIDGE=br-link -OVS_EXTRA="set Interface $DEVICE options:dpdk-devargs=0000:00:09.0" -""" - self.assertEqual(br_link_config, - self.provider.bridge_data['br-link']) - self.assertEqual(dpdk0_config, self.get_interface_config('dpdk0')) - - def test_network_ovs_mellanox_dpdk_bridge_and_port(self): - nic_mapping = {'nic1': 'em1', 'nic2': 'em2', 'nic3': 'em3'} - self.stubbed_mapped_nics = nic_mapping - - def stub_vendor_id_mellanox(ifname): - return True - self.stub_out('os_net_config.common.is_mellanox_interface', - stub_vendor_id_mellanox) - - interface = objects.Interface(name='nic1') - dpdk_port = objects.OvsDpdkPort(name='dpdk-link1-port', - members=[interface], - driver='mlx5_core') - bridge = objects.OvsUserBridge('br-link1', members=[dpdk_port]) - - def test_bind_dpdk_interfaces(ifname, driver, noop): - self.assertEqual(ifname, 'em1') - self.assertEqual(driver, 'mlx5_core') - self.stub_out('os_net_config.utils.bind_dpdk_interfaces', - test_bind_dpdk_interfaces) - self.stub_out('os_net_config.utils.get_stored_pci_address', - self.stub_get_stored_pci_address) - - self.provider.add_ovs_dpdk_port(dpdk_port) - self.provider.add_ovs_user_bridge(bridge) - br_link_config = """# This file is autogenerated by os-net-config -DEVICE=br-link1 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -DEVICETYPE=ovs -TYPE=OVSUserBridge -""" - dpdk0_config = """# This file is autogenerated by os-net-config -DEVICE=dpdk-link1-port -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -DEVICETYPE=ovs -TYPE=OVSDPDKPort -OVS_BRIDGE=br-link1 -OVS_EXTRA="set Interface $DEVICE options:dpdk-devargs=0000:00:01.0" -""" - self.assertEqual(br_link_config, - self.provider.bridge_data['br-link1']) - self.assertEqual(dpdk0_config, - self.get_interface_config('dpdk-link1-port')) - - if_config = """# This file is autogenerated by os-net-config -DEVICE=em1 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -BOOTPROTO=none -""" - self.assertEqual(if_config, - self.get_interface_config('em1')) - - def test_network_ovs_dpdk_bridge_and_port_with_queue_size(self): - nic_mapping = {'nic1': 'eth0', 'nic2': 'eth1', 'nic3': 'eth2'} - self.stubbed_mapped_nics = nic_mapping - - interface = objects.Interface(name='nic3') - dpdk_port = objects.OvsDpdkPort(name='dpdk0', members=[interface], - rx_queue_size=1024, - tx_queue_size=2048) - bridge = objects.OvsUserBridge('br-link', members=[dpdk_port]) - - def test_bind_dpdk_interfaces(ifname, driver, noop): - self.assertEqual(ifname, 'eth2') - self.assertEqual(driver, 'vfio-pci') - self.stub_out('os_net_config.utils.bind_dpdk_interfaces', - test_bind_dpdk_interfaces) - self.stub_out('os_net_config.utils.get_stored_pci_address', - self.stub_get_stored_pci_address) - - self.provider.add_ovs_dpdk_port(dpdk_port) - self.provider.add_ovs_user_bridge(bridge) - br_link_config = """# This file is autogenerated by os-net-config -DEVICE=br-link -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -DEVICETYPE=ovs -TYPE=OVSUserBridge -""" - dpdk0_config = """# This file is autogenerated by os-net-config -DEVICE=dpdk0 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -DEVICETYPE=ovs -TYPE=OVSDPDKPort -OVS_BRIDGE=br-link -RX_QUEUE_SIZE=1024 -TX_QUEUE_SIZE=2048 -OVS_EXTRA="set Interface $DEVICE options:dpdk-devargs=0000:00:09.0 \ --- set Interface $DEVICE options:n_rxq_desc=$RX_QUEUE_SIZE \ --- set Interface $DEVICE options:n_txq_desc=$TX_QUEUE_SIZE" -""" - self.assertEqual(br_link_config, - self.provider.bridge_data['br-link']) - self.assertEqual(dpdk0_config, self.get_interface_config('dpdk0')) - - def test_network_ovs_dpdk_bridge_and_port_with_mtu_rxqueue(self): - nic_mapping = {'nic1': 'eth0', 'nic2': 'eth1', 'nic3': 'eth2'} - self.stubbed_mapped_nics = nic_mapping - - interface = objects.Interface(name='nic3') - dpdk_port = objects.OvsDpdkPort(name='dpdk0', members=[interface], - mtu=9000, rx_queue=4) - bridge = objects.OvsUserBridge('br-link', members=[dpdk_port]) - - def test_bind_dpdk_interfaces(ifname, driver, noop): - self.assertEqual(ifname, 'eth2') - self.assertEqual(driver, 'vfio-pci') - self.stub_out('os_net_config.utils.bind_dpdk_interfaces', - test_bind_dpdk_interfaces) - self.stub_out('os_net_config.utils.get_stored_pci_address', - self.stub_get_stored_pci_address) - - self.provider.add_ovs_dpdk_port(dpdk_port) - self.provider.add_ovs_user_bridge(bridge) - br_link_config = """# This file is autogenerated by os-net-config -DEVICE=br-link -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -DEVICETYPE=ovs -TYPE=OVSUserBridge -""" - dpdk0_config = """# This file is autogenerated by os-net-config -DEVICE=dpdk0 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -DEVICETYPE=ovs -TYPE=OVSDPDKPort -OVS_BRIDGE=br-link -RX_QUEUE=4 -MTU=9000 -OVS_EXTRA="set Interface $DEVICE options:dpdk-devargs=0000:00:09.0 \ --- set Interface $DEVICE mtu_request=$MTU \ --- set Interface $DEVICE options:n_rxq=$RX_QUEUE" -""" - self.assertEqual(br_link_config, - self.provider.bridge_data['br-link']) - self.assertEqual(dpdk0_config, self.get_interface_config('dpdk0')) - - def test_network_ovs_dpdk_bond(self): - nic_mapping = {'nic1': 'eth0', 'nic2': 'eth1', 'nic3': 'eth2'} - self.stubbed_mapped_nics = nic_mapping - - iface0 = objects.Interface(name='nic2') - dpdk0 = objects.OvsDpdkPort(name='dpdk0', members=[iface0]) - iface1 = objects.Interface(name='nic3') - dpdk1 = objects.OvsDpdkPort(name='dpdk1', members=[iface1]) - bond = objects.OvsDpdkBond('dpdkbond0', members=[dpdk0, dpdk1]) - bridge = objects.OvsUserBridge('br-link', members=[bond]) - - def test_bind_dpdk_interfaces(ifname, driver, noop): - self.assertIn(ifname, ['eth1', 'eth2']) - self.assertEqual(driver, 'vfio-pci') - self.stub_out('os_net_config.utils.bind_dpdk_interfaces', - test_bind_dpdk_interfaces) - self.stub_out('os_net_config.utils.get_stored_pci_address', - self.stub_get_stored_pci_address) - - self.provider.add_ovs_dpdk_bond(bond) - self.provider.add_ovs_user_bridge(bridge) - - dpdk_bond_config = """# This file is autogenerated by os-net-config -DEVICE=dpdkbond0 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -DEVICETYPE=ovs -TYPE=OVSDPDKBond -OVS_BRIDGE=br-link -BOND_IFACES="dpdk0 dpdk1" -OVS_EXTRA="set Interface dpdk0 options:dpdk-devargs=0000:00:08.0 \ --- set Interface dpdk1 options:dpdk-devargs=0000:00:09.0" -""" - self.assertEqual(dpdk_bond_config, - self.get_interface_config('dpdkbond0')) - - def test_network_ovs_mellanox_dpdk_bond(self): - nic_mapping = {'nic1': 'em1', 'nic2': 'em2', 'nic3': 'em3'} - self.stubbed_mapped_nics = nic_mapping - - def stub_vendor_id_mellanox(ifname): - return True - self.stub_out('os_net_config.common.is_mellanox_interface', - stub_vendor_id_mellanox) - - iface0 = objects.Interface(name='nic1') - dpdk0 = objects.OvsDpdkPort(name='dpdk0', - members=[iface0], driver='mlx5_core') - iface1 = objects.Interface(name='nic2') - dpdk1 = objects.OvsDpdkPort(name='dpdk1', - members=[iface1], driver='mlx5_core') - bond = objects.OvsDpdkBond('dpdkbond0', members=[dpdk0, dpdk1]) - bridge = objects.OvsUserBridge('br-link', members=[bond]) - - def test_bind_dpdk_interfaces(ifname, driver, noop): - self.assertIn(ifname, ['em1', 'em2']) - self.assertEqual(driver, 'mlx5_core') - self.stub_out('os_net_config.utils.bind_dpdk_interfaces', - test_bind_dpdk_interfaces) - self.stub_out('os_net_config.utils.get_stored_pci_address', - self.stub_get_stored_pci_address) - - self.provider.add_ovs_dpdk_bond(bond) - self.provider.add_ovs_user_bridge(bridge) - - dpdk_bond_config = """# This file is autogenerated by os-net-config -DEVICE=dpdkbond0 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -DEVICETYPE=ovs -TYPE=OVSDPDKBond -OVS_BRIDGE=br-link -BOND_IFACES="dpdk0 dpdk1" -OVS_EXTRA="set Interface dpdk0 options:dpdk-devargs=0000:00:01.0 \ --- set Interface dpdk1 options:dpdk-devargs=0000:00:02.0" -""" - self.assertEqual(dpdk_bond_config, - self.get_interface_config('dpdkbond0')) - - if_cfg1 = """# This file is autogenerated by os-net-config -DEVICE=em1 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -BOOTPROTO=none -""" - if_cfg2 = """# This file is autogenerated by os-net-config -DEVICE=em2 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -BOOTPROTO=none -""" - self.assertEqual(if_cfg1, - self.get_interface_config('em1')) - self.assertEqual(if_cfg2, - self.get_interface_config('em2')) - - def test_network_ovs_dpdk_bond_with_mtu(self): - nic_mapping = {'nic1': 'eth0', 'nic2': 'eth1', 'nic3': 'eth2'} - self.stubbed_mapped_nics = nic_mapping - - iface0 = objects.Interface(name='nic2') - dpdk0 = objects.OvsDpdkPort(name='dpdk0', members=[iface0]) - iface1 = objects.Interface(name='nic3') - dpdk1 = objects.OvsDpdkPort(name='dpdk1', members=[iface1]) - bond = objects.OvsDpdkBond('dpdkbond0', mtu=9000, - members=[dpdk0, dpdk1]) - bridge = objects.OvsUserBridge('br-link', members=[bond]) - - def test_bind_dpdk_interfaces(ifname, driver, noop): - self.assertIn(ifname, ['eth1', 'eth2']) - self.assertEqual(driver, 'vfio-pci') - self.stub_out('os_net_config.utils.bind_dpdk_interfaces', - test_bind_dpdk_interfaces) - self.stub_out('os_net_config.utils.get_stored_pci_address', - self.stub_get_stored_pci_address) - - self.provider.add_ovs_dpdk_bond(bond) - self.provider.add_ovs_user_bridge(bridge) - - dpdk_bond_config = """# This file is autogenerated by os-net-config -DEVICE=dpdkbond0 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -DEVICETYPE=ovs -TYPE=OVSDPDKBond -OVS_BRIDGE=br-link -BOND_IFACES="dpdk0 dpdk1" -MTU=9000 -OVS_EXTRA="set Interface dpdk0 options:dpdk-devargs=0000:00:08.0 \ --- set Interface dpdk1 options:dpdk-devargs=0000:00:09.0 \ --- set Interface dpdk0 mtu_request=$MTU \ --- set Interface dpdk1 mtu_request=$MTU" -""" - self.assertEqual(dpdk_bond_config, - self.get_interface_config('dpdkbond0')) - - def test_network_ovs_dpdk_bond_with_rx_queue(self): - nic_mapping = {'nic1': 'eth0', 'nic2': 'eth1', 'nic3': 'eth2'} - self.stubbed_mapped_nics = nic_mapping - - iface0 = objects.Interface(name='nic2') - dpdk0 = objects.OvsDpdkPort(name='dpdk0', members=[iface0]) - iface1 = objects.Interface(name='nic3') - dpdk1 = objects.OvsDpdkPort(name='dpdk1', members=[iface1]) - bond = objects.OvsDpdkBond('dpdkbond0', rx_queue=4, - members=[dpdk0, dpdk1]) - bridge = objects.OvsUserBridge('br-link', members=[bond]) - - def test_bind_dpdk_interfaces(ifname, driver, noop): - self.assertIn(ifname, ['eth1', 'eth2']) - self.assertEqual(driver, 'vfio-pci') - self.stub_out('os_net_config.utils.bind_dpdk_interfaces', - test_bind_dpdk_interfaces) - self.stub_out('os_net_config.utils.get_stored_pci_address', - self.stub_get_stored_pci_address) - - self.provider.add_ovs_dpdk_bond(bond) - self.provider.add_ovs_user_bridge(bridge) - - dpdk_bond_config = """# This file is autogenerated by os-net-config -DEVICE=dpdkbond0 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -DEVICETYPE=ovs -TYPE=OVSDPDKBond -OVS_BRIDGE=br-link -BOND_IFACES="dpdk0 dpdk1" -RX_QUEUE=4 -OVS_EXTRA="set Interface dpdk0 options:dpdk-devargs=0000:00:08.0 \ --- set Interface dpdk1 options:dpdk-devargs=0000:00:09.0 \ --- set Interface dpdk0 options:n_rxq=$RX_QUEUE \ --- set Interface dpdk1 options:n_rxq=$RX_QUEUE" -""" - self.assertEqual(dpdk_bond_config, - self.get_interface_config('dpdkbond0')) - - def test_network_ovs_dpdk_bond_with_queue_size(self): - nic_mapping = {'nic1': 'eth0', 'nic2': 'eth1', 'nic3': 'eth2'} - self.stubbed_mapped_nics = nic_mapping - - iface0 = objects.Interface(name='nic2') - dpdk0 = objects.OvsDpdkPort(name='dpdk0', members=[iface0]) - iface1 = objects.Interface(name='nic3') - dpdk1 = objects.OvsDpdkPort(name='dpdk1', members=[iface1]) - bond = objects.OvsDpdkBond('dpdkbond0', rx_queue_size=1024, - tx_queue_size=2048, - members=[dpdk0, dpdk1]) - bridge = objects.OvsUserBridge('br-link', members=[bond]) - - def test_bind_dpdk_interfaces(ifname, driver, noop): - self.assertIn(ifname, ['eth1', 'eth2']) - self.assertEqual(driver, 'vfio-pci') - self.stub_out('os_net_config.utils.bind_dpdk_interfaces', - test_bind_dpdk_interfaces) - self.stub_out('os_net_config.utils.get_stored_pci_address', - self.stub_get_stored_pci_address) - - self.provider.add_ovs_dpdk_bond(bond) - self.provider.add_ovs_user_bridge(bridge) - - dpdk_bond_config = """# This file is autogenerated by os-net-config -DEVICE=dpdkbond0 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -DEVICETYPE=ovs -TYPE=OVSDPDKBond -OVS_BRIDGE=br-link -BOND_IFACES="dpdk0 dpdk1" -RX_QUEUE_SIZE=1024 -TX_QUEUE_SIZE=2048 -OVS_EXTRA="set Interface dpdk0 options:dpdk-devargs=0000:00:08.0 \ --- set Interface dpdk1 options:dpdk-devargs=0000:00:09.0 \ --- set Interface dpdk0 options:n_rxq_desc=$RX_QUEUE_SIZE \ --- set Interface dpdk1 options:n_rxq_desc=$RX_QUEUE_SIZE \ --- set Interface dpdk0 options:n_txq_desc=$TX_QUEUE_SIZE \ --- set Interface dpdk1 options:n_txq_desc=$TX_QUEUE_SIZE" -""" - self.assertEqual(dpdk_bond_config, - self.get_interface_config('dpdkbond0')) - - def test_network_ovs_dpdk_bond_with_mtu_and_rx_queue(self): - nic_mapping = {'nic1': 'eth0', 'nic2': 'eth1', 'nic3': 'eth2'} - self.stubbed_mapped_nics = nic_mapping - - iface0 = objects.Interface(name='nic2') - dpdk0 = objects.OvsDpdkPort(name='dpdk0', members=[iface0]) - iface1 = objects.Interface(name='nic3') - dpdk1 = objects.OvsDpdkPort(name='dpdk1', members=[iface1]) - bond = objects.OvsDpdkBond('dpdkbond0', rx_queue=4, mtu=9000, - members=[dpdk0, dpdk1]) - bridge = objects.OvsUserBridge('br-link', members=[bond]) - - def test_bind_dpdk_interfaces(ifname, driver, noop): - self.assertIn(ifname, ['eth1', 'eth2']) - self.assertEqual(driver, 'vfio-pci') - self.stub_out('os_net_config.utils.bind_dpdk_interfaces', - test_bind_dpdk_interfaces) - self.stub_out('os_net_config.utils.get_stored_pci_address', - self.stub_get_stored_pci_address) - - self.provider.add_ovs_dpdk_bond(bond) - self.provider.add_ovs_user_bridge(bridge) - - dpdk_bond_config = """# This file is autogenerated by os-net-config -DEVICE=dpdkbond0 -ONBOOT=yes -HOTPLUG=no -NM_CONTROLLED=no -PEERDNS=no -DEVICETYPE=ovs -TYPE=OVSDPDKBond -OVS_BRIDGE=br-link -BOND_IFACES="dpdk0 dpdk1" -RX_QUEUE=4 -MTU=9000 -OVS_EXTRA="set Interface dpdk0 options:dpdk-devargs=0000:00:08.0 \ --- set Interface dpdk1 options:dpdk-devargs=0000:00:09.0 \ --- set Interface dpdk0 mtu_request=$MTU \ --- set Interface dpdk1 mtu_request=$MTU \ --- set Interface dpdk0 options:n_rxq=$RX_QUEUE \ --- set Interface dpdk1 options:n_rxq=$RX_QUEUE" -""" - self.assertEqual(dpdk_bond_config, - self.get_interface_config('dpdkbond0')) - - -class TestIfcfgNetConfigApply(base.TestCase): - - def setUp(self): - super(TestIfcfgNetConfigApply, self).setUp() - self.temp_ifcfg_file = tempfile.NamedTemporaryFile() - self.temp_bond_file = tempfile.NamedTemporaryFile() - self.temp_route_file = tempfile.NamedTemporaryFile() - self.temp_route6_file = tempfile.NamedTemporaryFile() - self.temp_route_table_file = tempfile.NamedTemporaryFile() - self.temp_rule_file = tempfile.NamedTemporaryFile() - self.temp_bridge_file = tempfile.NamedTemporaryFile() - self.temp_cleanup_file = tempfile.NamedTemporaryFile(delete=False) - self.ifup_interface_names = [] - self.ovs_appctl_cmds = [] - self.stop_dhclient_interfaces = [] - self.ip_reconfigure_commands = [] - - def test_ifcfg_path(name): - return self.temp_ifcfg_file.name - self.stub_out( - 'os_net_config.impl_ifcfg.ifcfg_config_path', test_ifcfg_path) - - def test_remove_ifcfg_config(name): - ifcfg_file = self.temp_ifcfg_file.name - if os.path.exists(ifcfg_file): - os.remove(ifcfg_file) - self.stub_out('os_net_config.impl_ifcfg.remove_ifcfg_config', - test_remove_ifcfg_config) - - def test_routes_path(name): - return self.temp_route_file.name - self.stub_out( - 'os_net_config.impl_ifcfg.route_config_path', test_routes_path) - - def test_routes6_path(name): - return self.temp_route6_file.name - self.stub_out( - 'os_net_config.impl_ifcfg.route6_config_path', test_routes6_path) - - def test_rules_path(name): - return self.temp_rule_file.name - self.stub_out( - 'os_net_config.impl_ifcfg.route_rule_config_path', test_rules_path) - - def test_route_table_path(): - return self.temp_route_table_file.name - self.stub_out( - 'os_net_config.impl_ifcfg.route_table_config_path', - test_route_table_path) - utils.write_config(self.temp_route_table_file.name, _RT_CUSTOM) - - def test_bridge_path(name): - return self.temp_bridge_file.name - self.stub_out( - 'os_net_config.impl_ifcfg.bridge_config_path', test_bridge_path) - - def test_cleanup_pattern(): - return self.temp_cleanup_file.name - self.stub_out('os_net_config.impl_ifcfg.cleanup_pattern', - test_cleanup_pattern) - - def test_stop_dhclient_process(interface): - self.stop_dhclient_interfaces.append(interface) - self.stub_out('os_net_config.impl_ifcfg.stop_dhclient_process', - test_stop_dhclient_process) - - def test_execute(*args, **kwargs): - if args[0] == '/sbin/ifup': - self.ifup_interface_names.append(args[1]) - elif args[0] == '/bin/ovs-appctl': - self.ovs_appctl_cmds.append(' '.join(args)) - elif args[0] == '/sbin/ip' or args[0] == '/usr/sbin/ip': - self.ip_reconfigure_commands.append(' '.join(args[1:])) - pass - self.stub_out('oslo_concurrency.processutils.execute', test_execute) - - def stub_is_ovs_installed(): - return True - self.stub_out('os_net_config.utils.is_ovs_installed', - stub_is_ovs_installed) - - self.provider = impl_ifcfg.IfcfgNetConfig() - - def tearDown(self): - self.temp_ifcfg_file.close() - self.temp_route_file.close() - self.temp_route6_file.close() - self.temp_bridge_file.close() - if os.path.exists(self.temp_cleanup_file.name): - self.temp_cleanup_file.close() - super(TestIfcfgNetConfigApply, self).tearDown() - - def test_route_table_apply(self): - # Test overriding an existing route table - route_table1 = objects.RouteTable('custom', 10) - self.provider.add_route_table(route_table1) - route_table2 = objects.RouteTable('table1', 200) - self.provider.add_route_table(route_table2) - - def test_route_table_path(): - return self.temp_route_table_file.name - self.stub_out( - 'os_net_config.impl_ifcfg.route_table_config_path', - test_route_table_path) - utils.write_config(self.temp_route_table_file.name, _RT_CUSTOM) - - self.provider.apply() - - route_table_data = common.get_file_data( - self.temp_route_table_file.name) - self.assertEqual(_RT_FULL, route_table_data) - - def test_reserved_route_table_id(self): - route_table1 = objects.RouteTable('table1', 253) - self.provider.add_route_table(route_table1) - - self.assertRaises(os_net_config.ConfigurationError, - self.provider.apply) - - def test_reserved_route_table_name(self): - route_table2 = objects.RouteTable('default', 200) - self.provider.add_route_table(route_table2) - - self.assertRaises(os_net_config.ConfigurationError, - self.provider.apply) - - def test_network_apply(self): - route1 = objects.Route('192.168.1.1', default=True, - route_options="metric 10") - route2 = objects.Route('192.168.1.1', '172.19.0.0/24') - route3 = objects.Route('192.168.1.5', '172.20.0.0/24', - route_options="metric 100") - v4_addr = objects.Address('192.168.1.2/24') - interface = objects.Interface('em1', addresses=[v4_addr], - routes=[route1, route2, route3]) - self.provider.add_interface(interface) - - self.provider.apply() - - ifcfg_data = common.get_file_data(self.temp_ifcfg_file.name) - self.assertEqual(_V4_IFCFG, ifcfg_data) - route_data = common.get_file_data(self.temp_route_file.name) - self.assertEqual(_ROUTES, route_data) - - def test_sriov_pf_network_apply(self): - def get_numvfs_stub(pf_name): - return 0 - self.stub_out('os_net_config.sriov_config.get_numvfs', - get_numvfs_stub) - route1 = objects.Route('192.168.1.1', default=True, - route_options="metric 10") - route2 = objects.Route('192.168.1.1', '172.19.0.0/24') - route3 = objects.Route('192.168.1.5', '172.20.0.0/24', - route_options="metric 100") - v4_addr = objects.Address('192.168.1.2/24') - pf = objects.SriovPF('enp3s0f0', numvfs=10, addresses=[v4_addr], - promisc=False, routes=[route1, route2, route3]) - self.provider.add_sriov_pf(pf) - - self.provider.apply() - - ifcfg_data = common.get_file_data(self.temp_ifcfg_file.name) - self.assertEqual(_V4_SRIOV_PF_IFCFG, ifcfg_data) - route_data = common.get_file_data(self.temp_route_file.name) - self.assertEqual(_ROUTES_PF, route_data) - - def test_dhcp_ovs_bridge_network_apply(self): - interface = objects.Interface('em1') - bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True, - members=[interface]) - self.provider.add_interface(interface) - self.provider.add_bridge(bridge) - self.provider.apply() - - ifcfg_data = common.get_file_data(self.temp_ifcfg_file.name) - self.assertEqual(_OVS_INTERFACE, ifcfg_data) - bridge_data = common.get_file_data(self.temp_bridge_file.name) - self.assertEqual(_OVS_BRIDGE_DHCP, bridge_data) - route_data = common.get_file_data(self.temp_route_file.name) - self.assertEqual("", route_data) - - def test_dhclient_stop_on_iface_activate(self): - self.stop_dhclient_interfaces = [] - v4_addr = objects.Address('192.168.1.2/24') - interface = objects.Interface('em1', addresses=[v4_addr]) - interface2 = objects.Interface('em2', use_dhcp=True) - interface3 = objects.Interface('em3', use_dhcp=False) - self.provider.add_interface(interface) - self.provider.add_interface(interface2) - self.provider.add_interface(interface3) - self.provider.apply() - # stop dhclient on em1 due to static IP and em3 due to no IP - self.assertIn('em1', self.stop_dhclient_interfaces) - self.assertIn('em3', self.stop_dhclient_interfaces) - self.assertNotIn('em2', self.stop_dhclient_interfaces) - - def test_apply_noactivate(self): - interface = objects.Interface('em1') - bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True, - members=[interface]) - self.provider.add_interface(interface) - self.provider.add_bridge(bridge) - self.provider.apply(activate=False) - self.assertEqual([], self.ifup_interface_names) - - def test_bond_active_slave(self): - # setup and apply a bond - interface1 = objects.Interface('em1') - interface2 = objects.Interface('em2', primary=True) - bond = objects.OvsBond('bond1', use_dhcp=True, - members=[interface1, interface2]) - self.provider.add_interface(interface1) - self.provider.add_interface(interface2) - self.provider.add_bond(bond) - self.provider.apply() - ovs_appctl_cmds = '/bin/ovs-appctl bond/set-active-slave bond1 em2' - self.assertIn(ovs_appctl_cmds, self.ovs_appctl_cmds) - - def test_bond_active_ordering(self): - # setup and apply a bond - interface1 = objects.Interface('em1') - interface2 = objects.Interface('em2') - bond = objects.OvsBond('bond1', use_dhcp=True, - members=[interface1, interface2]) - self.provider.add_interface(interface1) - self.provider.add_interface(interface2) - self.provider.add_bond(bond) - self.provider.apply() - ovs_appctl_cmds = '/bin/ovs-appctl bond/set-active-slave bond1 em1' - self.assertIn(ovs_appctl_cmds, self.ovs_appctl_cmds) - - def test_reconfigure_and_apply(self): - route1 = objects.Route('192.168.1.1', default=True) - route2 = objects.Route('192.168.1.1', '172.19.0.0/24') - v4_addr1 = objects.Address('192.168.1.2/24') - interface1 = objects.Interface('em1', addresses=[v4_addr1], - routes=[route1, route2]) - self.provider.add_interface(interface1) - self.provider.apply() - self.assertIn('em1', self.ifup_interface_names) - - expected_commands = ['addr add 192.168.0.2/23 dev em1', - 'addr del 192.168.1.2/24 dev em1', - 'link set dev em1 mtu 9000'] - - v4_addr2 = objects.Address('192.168.0.2/23') - interface2 = objects.Interface('em1', addresses=[v4_addr2], - routes=[route1, route2], mtu=9000) - self.provider.add_interface(interface2) - self.provider.apply() - self.assertEqual(expected_commands, self.ip_reconfigure_commands) - - self.ip_reconfigure_commands = [] - expected_commands = ['addr add 192.168.1.2/24 dev em1', - 'addr del 192.168.0.2/23 dev em1', - 'link set dev em1 mtu 1500', - 'route del default via 192.168.1.1 dev em1', - 'route del 172.19.0.0/24 via 192.168.1.1 dev em1', - 'route add default via 192.168.0.1 dev em1', - 'route add 172.19.0.0/24 via 192.168.0.1 dev em1'] - - route3 = objects.Route('192.168.0.1', default=True) - route4 = objects.Route('192.168.0.1', '172.19.0.0/24') - interface3 = objects.Interface('em1', addresses=[v4_addr1], - routes=[route3, route4]) - self.provider.add_interface(interface3) - self.provider.apply() - self.assertEqual(expected_commands, self.ip_reconfigure_commands) - - def test_change_restart_required(self): - - tmpdir = tempfile.mkdtemp() - interface = "eth0" - interface_filename = tmpdir + '/ifcfg-' + interface - file = open(interface_filename, 'w') - file.write(_IFCFG_DHCP) - file.close() - - # Changing a dhcp interface to static should not require restart - self.assertFalse( - self.provider.ifcfg_requires_restart(interface_filename, - _IFCFG_STATIC1)) - - # Changing a standard interface to ovs should require restart - self.assertTrue( - self.provider.ifcfg_requires_restart(interface_filename, - _IFCFG_OVS)) - - # Changing a static interface to dhcp should require restart - file = open(interface_filename, 'w') - file.write(_IFCFG_STATIC1) - file.close() - self.assertTrue(self.provider.ifcfg_requires_restart( - interface_filename, _IFCFG_DHCP)) - - # Configuring a previously unconfigured interface requires restart - self.assertTrue(self.provider.ifcfg_requires_restart('/doesnotexist', - _IFCFG_DHCP)) - - shutil.rmtree(tmpdir) - - def test_ifcfg_route_commands(self): - - tmpdir = tempfile.mkdtemp() - interface = "eth0" - interface_filename = tmpdir + '/route-' + interface - file = open(interface_filename, 'w') - file.write(_IFCFG_ROUTES1) - file.close() - - # Changing only the routes should delete and add routes - command_list1 = ['route del default via 192.0.2.1 dev eth0', - 'route del 192.0.2.1/24 via 192.0.2.1 dev eth0', - 'route add default via 192.0.1.1 dev eth0', - 'route add 192.0.1.1/24 via 192.0.3.1 dev eth1'] - commands = self.provider.iproute2_route_commands(interface_filename, - _IFCFG_ROUTES2) - self.assertTrue(commands == command_list1) - - shutil.rmtree(tmpdir) - - def test_ifcfg_rule_commands(self): - - tmpdir = tempfile.mkdtemp() - interface = "eth0" - rule_filename = tmpdir + '/rule-' + interface - file = open(rule_filename, 'w') - file.write(_IFCFG_RULES1) - file.close() - - # Changing only the rules should delete and add rules - command_list1 = ['rule del to 192.168.2.0/24 table main priority 500', - 'rule del from 192.168.2.0/24 table 200 priority 501', - 'rule add to 192.168.1.0/24 table main priority 500', - 'rule add from 192.168.1.0/24 table 200 priority 501'] - commands = self.provider.iproute2_rule_commands(rule_filename, - _IFCFG_RULES2) - self.assertTrue(commands == command_list1) - - shutil.rmtree(tmpdir) - - def test_ifcfg_ipmtu_commands(self): - - tmpdir = tempfile.mkdtemp() - interface = "eth0" - interface_filename = tmpdir + '/ifcfg-' + interface - file = open(interface_filename, 'w') - file.write(_IFCFG_STATIC1) - file.close() - - # Changing only the IP should delete and add the IP - command_list1 = ['addr add 10.0.1.2/23 dev eth0', - 'addr del 10.0.0.1/24 dev eth0'] - commands = self.provider.iproute2_apply_commands(interface, - interface_filename, - _IFCFG_STATIC2) - self.assertTrue(commands == command_list1) - - # Changing only the MTU should just set the interface MTU - command_list2 = ['link set dev eth0 mtu 9000'] - commands = self.provider.iproute2_apply_commands(interface, - interface_filename, - _IFCFG_STATIC1_MTU) - self.assertTrue(commands == command_list2) - - # Changing both the IP and MTU should delete IP, add IP, and set MTU - command_list3 = ['addr add 10.0.1.2/23 dev eth0', - 'addr del 10.0.0.1/24 dev eth0', - 'link set dev eth0 mtu 9000'] - commands = self.provider.iproute2_apply_commands(interface, - interface_filename, - _IFCFG_STATIC2_MTU) - self.assertTrue(commands == command_list3) - - shutil.rmtree(tmpdir) - - def test_ifcfg_ethtool_commands(self): - - tmpdir = tempfile.mkdtemp() - interface = "eth0" - interface_filename = tmpdir + '/ifcfg-' + interface - file = open(interface_filename, 'w') - file.write(_IFCFG_STATIC1) - file.close() - - command_list1 = ['-s eth0 speed 100 duplex full autoneg off'] - command = self.provider.ethtool_apply_command(interface, - interface_filename, - _IFCFG_STATIC1_ETHTOOL1) - self.assertTrue(command == command_list1) - - command_list2 = ['-G ${DEVICE} rx 1024 tx 1024'] - command = self.provider.ethtool_apply_command(interface, - interface_filename, - _IFCFG_STATIC1_ETHTOOL2) - self.assertTrue(command == command_list2) - - command_list3 = ['--set-ring ${DEVICE} rx 1024 tx 1024'] - command = self.provider.ethtool_apply_command(interface, - interface_filename, - _IFCFG_STATIC1_ETHTOOL3) - self.assertTrue(command == command_list3) - - command_list4 = ['--pause ${DEVICE} autoneg on'] - command = self.provider.ethtool_apply_command(interface, - interface_filename, - _IFCFG_STATIC1_ETHTOOL4) - self.assertTrue(command == command_list4) - - command_list5 = ['-G ${DEVICE} rx 1024 tx 1024', - '-A ${DEVICE} autoneg on', - '--pause ${DEVICE} autoneg off', - '--set-ring ${DEVICE} rx 512'] - command = self.provider.ethtool_apply_command(interface, - interface_filename, - _IFCFG_STATIC1_ETHTOOL5) - self.assertTrue(command == command_list5) - - command_list6 = ['-G $DEVICE rx 1024 tx 1024'] - command = self.provider.ethtool_apply_command(interface, - interface_filename, - _IFCFG_STATIC1_ETHTOOL6) - self.assertTrue(command == command_list6) - - command_list7 = ['-G eth0 rx 1024 tx 1024'] - command = self.provider.ethtool_apply_command(interface, - interface_filename, - _IFCFG_STATIC1_ETHTOOL7) - self.assertTrue(command == command_list7) - - shutil.rmtree(tmpdir) - - def test_restart_children_on_change(self): - # setup and apply a bridge - interface = objects.Interface('em1') - bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True, - members=[interface]) - self.provider.add_interface(interface) - self.provider.add_bridge(bridge) - self.provider.apply() - self.assertIn('em1', self.ifup_interface_names) - self.assertIn('br-ctlplane', self.ifup_interface_names) - - # changing the bridge should restart the interface too - self.ifup_interface_names = [] - bridge = objects.OvsBridge('br-ctlplane', use_dhcp=False, - members=[interface]) - self.provider.add_interface(interface) - self.provider.add_bridge(bridge) - self.provider.apply() - self.assertIn('em1', self.ifup_interface_names) - - # test infiniband interfaces act as proper bridge members - ib_interface = objects.IbInterface('ib0') - bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True, - members=[ib_interface]) - self.provider.add_interface(ib_interface) - self.provider.add_bridge(bridge) - self.provider.apply() - self.assertIn('ib0', self.ifup_interface_names) - self.assertIn('br-ctlplane', self.ifup_interface_names) - - # changing the bridge should restart the interface too - self.ifup_interface_names = [] - bridge = objects.OvsBridge('br-ctlplane', use_dhcp=False, - members=[ib_interface]) - self.provider.add_interface(interface) - self.provider.add_bridge(bridge) - self.provider.apply() - self.assertIn('ib0', self.ifup_interface_names) - - # setup and apply a bond on a bridge - self.ifup_interface_names = [] - interface1 = objects.Interface('em1') - interface2 = objects.Interface('em2') - bond = objects.OvsBond('bond0', - members=[interface1, interface2]) - bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True, - members=[bond]) - self.provider.add_interface(interface1) - self.provider.add_interface(interface2) - self.provider.add_bond(bond) - self.provider.add_bridge(bridge) - self.provider.apply() - - # changing the bridge should restart everything - self.ifup_interface_names = [] - bridge = objects.OvsBridge('br-ctlplane', use_dhcp=False, - members=[bond]) - self.provider.add_interface(interface1) - self.provider.add_interface(interface2) - self.provider.add_bond(bond) - self.provider.add_bridge(bridge) - self.provider.apply() - self.assertIn('br-ctlplane', self.ifup_interface_names) - self.assertIn('bond0', self.ifup_interface_names) - self.assertIn('em1', self.ifup_interface_names) - self.assertIn('em2', self.ifup_interface_names) - - def test_restart_vlans_on_bond_change(self): - self.ifup_interface_names = [] - interface1 = objects.Interface('em1') - interface2 = objects.Interface('em2') - bond = objects.LinuxBond('bond0', members=[interface1, interface2]) - vlan = objects.Vlan('bond0', 10) - self.provider.add_interface(interface1) - self.provider.add_interface(interface2) - self.provider.add_linux_bond(bond) - self.provider.add_vlan(vlan) - self.provider.apply() - self.assertIn('bond0', self.ifup_interface_names) - self.assertIn('em1', self.ifup_interface_names) - self.assertIn('em2', self.ifup_interface_names) - self.assertIn('vlan10', self.ifup_interface_names) - - # Change the bond configuration - self.ifup_interface_names = [] - bond.bonding_options = 'mode=1 miimon=100' - self.provider.add_linux_bond(bond) - self.provider.apply() - self.assertIn('bond0', self.ifup_interface_names) - self.assertIn('em1', self.ifup_interface_names) - self.assertIn('em2', self.ifup_interface_names) - self.assertIn('vlan10', self.ifup_interface_names) - - def test_linux_bond_ifup_on_child_restart(self): - # if a bond slave is restarted then ifup should be called on the bond - self.ifup_interface_names = [] - interface1 = objects.Interface('em1') - bond = objects.LinuxBond('bond0', members=[interface1]) - self.provider.add_linux_bond(bond) - self.provider.add_interface(interface1) - self.provider.apply() - self.assertIn('em1', self.ifup_interface_names) - self.assertIn('bond0', self.ifup_interface_names) - - self.ifup_interface_names = [] - # changing mtu should not require a restart of em1 (or the bond) - interface1.mtu = 9000 - self.provider.linuxbond_data = {} - self.provider.interface_data = {} - self.provider.add_linux_bond(bond) - self.provider.add_interface(interface1) - self.provider.apply() - self.assertNotIn('em1', self.ifup_interface_names) - self.assertNotIn('bond0', self.ifup_interface_names) - - # changing nm_controlled should require a restart of em1 (and the bond) - interface1.nm_controlled = True - self.provider.add_interface(interface1) - self.provider.apply() - self.assertIn('em1', self.ifup_interface_names) - self.assertIn('bond0', self.ifup_interface_names) - - def test_restart_interface_counts(self): - interface = objects.Interface('em1') - interface2 = objects.Interface('em2') - bond = objects.LinuxBond('bond0', members=[interface, interface2]) - self.provider.add_bond(bond) - self.provider.add_interface(interface) - self.provider.add_interface(interface2) - self.provider.apply() - self.assertEqual(1, self.ifup_interface_names.count("em1")) - self.assertEqual(1, self.ifup_interface_names.count("em2")) - self.assertEqual(1, self.ifup_interface_names.count("bond0")) - - def test_vlan_apply(self): - vlan = objects.Vlan('em1', 5) - self.provider.add_vlan(vlan) - self.provider.apply() - - ifcfg_data = common.get_file_data(self.temp_ifcfg_file.name) - self.assertEqual(_VLAN_NO_IP, ifcfg_data) - - def test_cleanup(self): - self.provider.apply(cleanup=True) - self.assertTrue(not os.path.exists(self.temp_cleanup_file.name)) - - def test_cleanup_not_loopback(self): - tmp_lo_file = '%s-lo' % self.temp_cleanup_file.name - utils.write_config(tmp_lo_file, 'foo') - - def test_cleanup_pattern(): - return '%s-*' % self.temp_cleanup_file.name - self.stub_out('os_net_config.impl_ifcfg.cleanup_pattern', - test_cleanup_pattern) - - self.provider.apply(cleanup=True) - self.assertTrue(os.path.exists(tmp_lo_file)) - os.remove(tmp_lo_file) - - def test_ovs_restart_called(self): - interface = objects.Interface('em1') - dpdk_port = objects.OvsDpdkPort('dpdk0', members=[interface]) - execute_strings = [] - - def test_execute(*args, **kwargs): - execute_strings.append(args[1]) - self.stub_out('os_net_config.NetConfig.execute', test_execute) - - self.provider.noop = True - self.provider.add_ovs_dpdk_port(dpdk_port) - self.provider.apply() - self.assertIn('Restart openvswitch', execute_strings) - - def test_ovs_restart_not_called(self): - interface = objects.Interface('em1') - execute_strings = [] - - def test_execute(*args, **kwargs): - execute_strings.append(args[1]) - self.stub_out('os_net_config.NetConfig.execute', test_execute) - - self.provider.noop = True - self.provider.add_interface(interface) - self.provider.apply() - self.assertNotIn('Restart openvswitch', execute_strings) - - def _failed_execute(*args, **kwargs): - if kwargs.get('check_exit_code', True): - raise processutils.ProcessExecutionError('Test stderr', - 'Test stdout', - str(kwargs)) - - def test_interface_failure(self): - self.stub_out('oslo_concurrency.processutils.execute', - self._failed_execute) - v4_addr = objects.Address('192.168.1.2/24') - interface = objects.Interface('em1', addresses=[v4_addr]) - self.provider.add_interface(interface) - - self.assertRaises(os_net_config.ConfigurationError, - self.provider.apply) - self.assertEqual(1, len(self.provider.errors)) - - def test_interface_failure_multiple(self): - self.stub_out('oslo_concurrency.processutils.execute', - self._failed_execute) - v4_addr = objects.Address('192.168.1.2/24') - interface = objects.Interface('em1', addresses=[v4_addr]) - v4_addr2 = objects.Address('192.168.2.2/24') - interface2 = objects.Interface('em2', addresses=[v4_addr2]) - self.provider.add_interface(interface) - self.provider.add_interface(interface2) - - self.assertRaises(os_net_config.ConfigurationError, - self.provider.apply) - # Even though the first one failed, we should have attempted both - self.assertEqual(2, len(self.provider.errors)) diff --git a/os_net_config/tests/test_impl_nmstate.py b/os_net_config/tests/test_impl_nmstate.py deleted file mode 100644 index d147ce72..00000000 --- a/os_net_config/tests/test_impl_nmstate.py +++ /dev/null @@ -1,1589 +0,0 @@ -# -*- 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. - -from libnmstate.schema import Ethernet -from libnmstate.schema import Ethtool -import os.path -import tempfile -import yaml - -import os_net_config -from os_net_config import impl_nmstate -from os_net_config import objects -from os_net_config.tests import base -from os_net_config import utils - - -TEST_ENV_DIR = os.path.realpath(os.path.join(os.path.dirname(__file__), - 'environment')) - -_RT_DEFAULT = """# reserved values -# -255\tlocal -254\tmain -253\tdefault -0\tunspec -# -# local -# -#1\tinr.ruhep\n""" - -_RT_CUSTOM = _RT_DEFAULT + "# Custom\n10\tcustom # Custom table\n20\ttable1\n" - -_BASE_IFACE_CFG = """ - - - type: interface - name: em1 - - - type: interface - name: eno2 - addresses: - - ip_netmask: 2001:abc:a::2/64 - - ip_netmask: 192.168.1.2/24 -""" - -_BASE_IFACE_CFG_APPLIED = """ - em1: - name: em1 - type: ethernet - state: up - ethernet: {} - ipv4: - enabled: false - dhcp: False - ipv6: - enabled: false - dhcp: False - autoconf: False - eno2: - name: eno2 - type: ethernet - state: up - ethernet: {} - ipv4: - address: - - ip: 192.168.1.2 - prefix-length: 24 - dhcp: false - enabled: true - ipv6: - address: - - ip: 2001:abc:a::2 - prefix-length: 64 - autoconf: false - dhcp: false - enabled: true -""" - - -_BASE_NMSTATE_IFACE_CFG = """- name: em1 - type: ethernet - state: up -""" - -_NO_IP = _BASE_NMSTATE_IFACE_CFG + """ ethernet: {} - ipv4: - enabled: false - dhcp: False - ipv6: - enabled: false - dhcp: False - autoconf: False -""" - -_V4_NMCFG = _BASE_NMSTATE_IFACE_CFG + """ ethernet: {} - ipv6: - enabled: False - autoconf: False - dhcp: False - ipv4: - enabled: True - dhcp: False - address: - - ip: 192.168.1.2 - prefix-length: 24 -""" - -_V4_NMCFG_MULTIPLE = _V4_NMCFG + """ - ip: 192.168.2.2 - prefix-length: 32 - - ip: 10.0.0.2 - prefix-length: 8 -""" - -_V4_NMCFG_MAPPED = _V4_NMCFG + """ - 802-3-Ethernet.cloned-mac-address: a1:b2:c3:d4:e5 -""" - -_V4_V6_NMCFG = _BASE_NMSTATE_IFACE_CFG + """ ipv6: - enabled: True - autoconf: False - dhcp: False - address: - - ip: 2001:abc:a::2 - prefix-length: 64 - ipv4: - enabled: True - dhcp: False - address: - - ip: 192.168.1.2 - prefix-length: 24 - ethernet: {} -""" - -_V6_NMCFG = _BASE_NMSTATE_IFACE_CFG + """ ethernet: {} - ipv4: - enabled: False - dhcp: False - ipv6: - enabled: True - autoconf: False - dhcp: False - address: - - ip: "2001:abc:a::" - prefix-length: 64 -""" - -_V6_NMCFG_MULTIPLE = _V6_NMCFG + """ - ip: 2001:abc:b::1 - prefix-length: 64 - - ip: 2001:abc:c::2 - prefix-length: 96 -""" - - -class TestNmstateNetConfig(base.TestCase): - def setUp(self): - super(TestNmstateNetConfig, self).setUp() - self.temp_route_table_file = tempfile.NamedTemporaryFile() - self.provider = impl_nmstate.NmstateNetConfig() - - def stub_is_ovs_installed(): - return True - self.stub_out('os_net_config.utils.is_ovs_installed', - stub_is_ovs_installed) - - def test_route_table_path(): - return self.temp_route_table_file.name - self.stub_out( - 'os_net_config.impl_nmstate.route_table_config_path', - test_route_table_path) - utils.write_config(self.temp_route_table_file.name, _RT_CUSTOM) - - def get_interface_config(self, name='em1'): - return self.provider.interface_data[name] - - def get_vlan_config(self, name): - return self.provider.vlan_data[name] - - def get_bridge_config(self, name): - return self.provider.bridge_data[name] - - def get_linuxbond_config(self, name='bond0'): - return self.provider.linuxbond_data[name] - - def get_nmstate_ethtool_opts(self, name): - data = {} - data[Ethernet.CONFIG_SUBTREE] = \ - self.provider.interface_data[name][Ethernet.CONFIG_SUBTREE] - data[Ethtool.CONFIG_SUBTREE] = \ - self.provider.interface_data[name][Ethtool.CONFIG_SUBTREE] - return data - - def get_dns_data(self): - return self.provider.dns_data - - def get_route_table_config(self, name='custom', table_id=200): - return self.provider.route_table_data.get(name, table_id) - - def get_rule_config(self): - return self.provider.rules_data - - def get_route_config(self, name): - return self.provider.route_data.get(name, '') - - def test_add_base_interface(self): - interface = objects.Interface('em1') - self.provider.add_interface(interface) - self.assertEqual(yaml.safe_load(_NO_IP)[0], - self.get_interface_config()) - self.assertEqual('', self.get_route_config('em1')) - - def test_add_interface_with_v6(self): - v6_addr = objects.Address('2001:abc:a::/64') - interface = objects.Interface('em1', addresses=[v6_addr]) - self.provider.add_interface(interface) - self.assertEqual(yaml.safe_load(_V6_NMCFG)[0], - self.get_interface_config()) - self.assertEqual('', self.get_route_config('em1')) - - def test_add_interface_with_v4_v6(self): - addresses = [objects.Address('2001:abc:a::2/64'), - objects.Address('192.168.1.2/24')] - interface = objects.Interface('em1', addresses=addresses) - self.provider.add_interface(interface) - self.assertEqual(yaml.safe_load(_V4_V6_NMCFG)[0], - self.get_interface_config()) - self.assertEqual('', self.get_route_config('em1')) - - def test_add_interface_with_v6_multiple(self): - addresses = [objects.Address('2001:abc:a::/64'), - objects.Address('2001:abc:b::1/64'), - objects.Address('2001:abc:c::2/96')] - interface = objects.Interface('em1', addresses=addresses) - self.provider.add_interface(interface) - self.assertEqual(yaml.safe_load(_V6_NMCFG_MULTIPLE)[0], - self.get_interface_config()) - self.assertEqual('', self.get_route_config('em1')) - - def test_interface_defroute(self): - interface1 = objects.Interface('em1') - interface2 = objects.Interface('em2', defroute=False) - self.provider.add_interface(interface1) - self.provider.add_interface(interface2) - em1_config = """- name: em1 - type: ethernet - state: up - ethernet: {} - ipv4: - enabled: False - dhcp: False - ipv6: - enabled: False - autoconf: False - dhcp: False -""" - em2_config = """- name: em2 - type: ethernet - state: up - ethernet: {} - ipv4: - enabled: False - auto-gateway: False - dhcp: False - ipv6: - auto-gateway: False - enabled: False - autoconf: False - dhcp: False -""" - self.assertEqual(yaml.safe_load(em1_config)[0], - self.get_interface_config('em1')) - self.assertEqual('', self.get_route_config('em1')) - self.assertEqual(yaml.safe_load(em2_config)[0], - self.get_interface_config('em2')) - self.assertEqual('', self.get_route_config('em2')) - - def test_interface_dns_server(self): - interface1 = objects.Interface('em1', dns_servers=['1.2.3.4']) - self.provider.add_interface(interface1) - em1_config = """- name: em1 - type: ethernet - state: up - ethernet: {} - ipv4: - auto-dns: False - enabled: False - dhcp: False - ipv6: - auto-dns: False - enabled: False - autoconf: False - dhcp: False -""" - test_dns_config1 = """ - server: - - 1.2.3.4 - domain: [] -""" - self.assertEqual(yaml.safe_load(em1_config)[0], - self.get_interface_config('em1')) - - self.assertEqual(yaml.safe_load(test_dns_config1), - self.get_dns_data()) - interface2 = objects.Interface('em2', - dns_servers=['1.2.3.4', - '2001:4860:4860::8888'], - domain=['example.com', 'server.org']) - self.provider.add_interface(interface2) - test_dns_config2 = """ - server: - - 1.2.3.4 - - 2001:4860:4860::8888 - domain: - - example.com - - server.org -""" - self.assertEqual(yaml.safe_load(test_dns_config2), - self.get_dns_data()) - interface3 = objects.Interface('em3', - dns_servers=['1.2.3.4', - '2001:4860:4860::8888'], - domain='testdomain.com') - self.provider.add_interface(interface3) - test_dns_config3 = """ - server: - - 1.2.3.4 - - 2001:4860:4860::8888 - domain: - - example.com - - server.org - - testdomain.com -""" - self.assertEqual(yaml.safe_load(test_dns_config3), - self.get_dns_data()) - - def test_ethtool_opts(self): - interface1 = objects.Interface('em1', - ethtool_opts='speed 1000 duplex full ' - 'autoneg on') - interface2 = objects.Interface('em2', - ethtool_opts='--set-ring \ - ${DEVICE} rx 1024 tx 1024') - interface3 = objects.Interface('em3', - ethtool_opts='-G $DEVICE ' - 'rx 1024 tx 1024;' - '-A ${DEVICE} autoneg on;' - '--offload ${DEVICE} ' - 'hw-tc-offload on') - interface4 = objects.Interface('em4', - ethtool_opts='-K ${DEVICE} ' - 'hw-tc-offload on;' - '-C ${DEVICE} adaptive-rx off ' - 'adaptive-tx off') - interface5 = objects.Interface('em5', - ethtool_opts='-s ${DEVICE} speed ' - '100 duplex half autoneg off') - # Mismatch in device name - interface6 = objects.Interface('em6', - ethtool_opts='-s em3 speed 100 ' - 'duplex half autoneg off') - # Unhandled option -U - interface7 = objects.Interface('em7', - ethtool_opts='-U ${DEVICE} ' - 'flow-type tcp4 tos 1 action 10') - # Unsupported option `advertise` - interface8 = objects.Interface('em8', - ethtool_opts='advertise 0x100000') - # Unsupported format - interface9 = objects.Interface('em9', - ethtool_opts='s $DEVICE rx 78') - - self.provider.add_interface(interface1) - self.provider.add_interface(interface2) - self.provider.add_interface(interface3) - self.provider.add_interface(interface4) - self.provider.add_interface(interface5) - - em1_config = """ - - ethernet: - speed: 1000 - duplex: full - auto-negotiation: true - ethtool: {} -""" - em2_config = """ - - ethernet: {} - ethtool: - ring: - rx: 1024 - tx: 1024 -""" - em3_config = """ - - ethernet: {} - ethtool: - ring: - rx: 1024 - tx: 1024 - pause: - autoneg: true - feature: - hw-tc-offload: true -""" - em4_config = """ - - ethernet: {} - ethtool: - feature: - hw-tc-offload: true - coalesce: - adaptive-rx: false - adaptive-tx: false -""" - em5_config = """ - - ethernet: - speed: 100 - duplex: half - auto-negotiation: false - ethtool: {} -""" - self.assertEqual(yaml.safe_load(em1_config)[0], - self.get_nmstate_ethtool_opts('em1')) - self.assertEqual(yaml.safe_load(em2_config)[0], - self.get_nmstate_ethtool_opts('em2')) - self.assertEqual(yaml.safe_load(em3_config)[0], - self.get_nmstate_ethtool_opts('em3')) - self.assertEqual(yaml.safe_load(em4_config)[0], - self.get_nmstate_ethtool_opts('em4')) - self.assertEqual(yaml.safe_load(em5_config)[0], - self.get_nmstate_ethtool_opts('em5')) - self.assertRaises(os_net_config.ConfigurationError, - self.provider.add_interface, - interface6) - self.assertRaises(os_net_config.ConfigurationError, - self.provider.add_interface, - interface7) - self.assertRaises(os_net_config.ConfigurationError, - self.provider.add_interface, - interface8) - self.assertRaises(os_net_config.ConfigurationError, - self.provider.add_interface, - interface9) - - def test_add_route_table(self): - route_table1 = objects.RouteTable('table1', 200) - route_table2 = objects.RouteTable('table2', '201') - self.provider.add_route_table(route_table1) - self.provider.add_route_table(route_table2) - self.assertEqual("table1", self.get_route_table_config(200)) - self.assertEqual("table2", self.get_route_table_config(201)) - - def test_add_route_with_table(self): - expected_route_table = """ - - destination: 172.19.0.0/24 - next-hop-address: 192.168.1.1 - next-hop-interface: em1 - table-id: 200 - - destination: 172.20.0.0/24 - next-hop-address: 192.168.1.1 - next-hop-interface: em1 - table-id: 201 - - destination: 172.21.0.0/24 - next-hop-address: 192.168.1.1 - next-hop-interface: em1 - table-id: 200 - """ - expected_rule = """ - - ip-from: 192.0.2.0/24 - route-table: 200 - """ - route_table1 = objects.RouteTable('table1', 200) - self.provider.add_route_table(route_table1) - - route_rule1 = objects.RouteRule('from 192.0.2.0/24 table 200', - 'test comment') - # Test route table by name - route1 = objects.Route('192.168.1.1', '172.19.0.0/24', False, - route_table="table1") - # Test that table specified in route_options takes precedence - route2 = objects.Route('192.168.1.1', '172.20.0.0/24', False, - 'table 201', route_table=200) - # Test route table specified by integer ID - route3 = objects.Route('192.168.1.1', '172.21.0.0/24', False, - route_table=200) - v4_addr = objects.Address('192.168.1.2/24') - interface = objects.Interface('em1', addresses=[v4_addr], - routes=[route1, route2, route3], - rules=[route_rule1]) - self.provider.add_interface(interface) - - self.assertEqual(yaml.safe_load(expected_route_table), - self.get_route_config('em1')) - self.assertEqual(yaml.safe_load(expected_rule), - self.get_rule_config()) - - def test_ip_rules(self): - expected_rule = """ - - action: blackhole - ip-from: 172.19.40.0/24 - route-table: 200 - - action: unreachable - iif: em1 - ip-from: 192.168.1.0/24 - - family: ipv4 - iif: em1 - route-table: 200 - """ - rule1 = objects.RouteRule( - 'add blackhole from 172.19.40.0/24 table 200', 'rule1') - rule2 = objects.RouteRule( - 'add unreachable iif em1 from 192.168.1.0/24', 'rule2') - rule3 = objects.RouteRule('iif em1 table 200', 'rule3') - v4_addr = objects.Address('192.168.1.2/24') - interface = objects.Interface('em1', addresses=[v4_addr], - rules=[rule1, rule2, rule3]) - self.provider.add_interface(interface) - - self.assertEqual(yaml.safe_load(expected_rule), - self.get_rule_config()) - - def test_network_with_routes(self): - expected_route_table = """ - - destination: 0.0.0.0/0 - metric: 10 - next-hop-address: 192.168.1.1 - next-hop-interface: em1 - - destination: 172.19.0.0/24 - next-hop-address: 192.168.1.1 - next-hop-interface: em1 - - destination: 172.20.0.0/24 - metric: 100 - next-hop-address: 192.168.1.5 - next-hop-interface: em1 - """ - route1 = objects.Route('192.168.1.1', default=True, - route_options="metric 10") - route2 = objects.Route('192.168.1.1', '172.19.0.0/24') - route3 = objects.Route('192.168.1.5', '172.20.0.0/24', - route_options="metric 100") - v4_addr = objects.Address('192.168.1.2/24') - interface = objects.Interface('em1', addresses=[v4_addr], - routes=[route1, route2, route3]) - self.provider.add_interface(interface) - self.assertEqual(yaml.safe_load(expected_route_table), - self.get_route_config('em1')) - - def test_network_with_ipv6_routes(self): - expected_route_table = """ - - destination: ::/0 - next-hop-address: 2001:db8::1 - next-hop-interface: em1 - - destination: 2001:db8:dead:beef:cafe::/56 - next-hop-address: fd00:fd00:2000::1 - next-hop-interface: em1 - - destination: 2001:db8:dead:beff::/64 - metric: 100 - next-hop-address: fd00:fd00:2000::1 - next-hop-interface: em1 - """ - route4 = objects.Route('2001:db8::1', default=True) - route5 = objects.Route('fd00:fd00:2000::1', - '2001:db8:dead:beef:cafe::/56') - route6 = objects.Route('fd00:fd00:2000::1', - '2001:db8:dead:beff::/64', - route_options="metric 100") - v4_addr = objects.Address('192.168.1.2/24') - v6_addr = objects.Address('2001:abc:a::/64') - interface = objects.Interface('em1', addresses=[v4_addr, v6_addr], - routes=[route4, route5, route6]) - self.provider.add_interface(interface) - self.assertEqual(yaml.safe_load(expected_route_table), - self.get_route_config('em1')) - - def test_linux_bond(self): - expected_config1 = """ - name: bond0 - type: bond - state: up - link-aggregation: - mode: active-backup - port: - - em1 - - em2 - options: - primary: em1 - ipv4: - auto-dns: True - enabled: True - dhcp: True - auto-routes: True - auto-gateway: True - ipv6: - enabled: False - autoconf: False - dhcp: False - """ - expected_em1_cfg = """ - name: em1 - state: up - ethernet: {} - ipv4: - dhcp: False - enabled: False - ipv6: - autoconf: False - dhcp: False - enabled: False - type: ethernet - """ - expected_em2_cfg = """ - name: em2 - state: up - ethernet: {} - ipv4: - dhcp: False - enabled: False - ipv6: - autoconf: False - dhcp: False - enabled: False - type: ethernet - """ - - expected_config2 = """ - name: bond1 - type: bond - state: up - link-aggregation: - mode: 802.3ad - options: - miimon: 100 - updelay: 1000 - lacp_rate: slow - port: - - em3 - - em4 - ipv4: - auto-dns: True - enabled: True - dhcp: True - auto-routes: True - auto-gateway: True - ipv6: - enabled: False - autoconf: False - dhcp: False - """ - interface1 = objects.Interface('em1', primary=True) - interface2 = objects.Interface('em2') - bond = objects.LinuxBond('bond0', use_dhcp=True, - members=[interface1, interface2]) - self.provider.add_linux_bond(bond) - self.provider.add_interface(interface1) - self.provider.add_interface(interface2) - self.assertEqual(yaml.safe_load(expected_config1), - self.get_linuxbond_config('bond0')) - self.assertEqual(yaml.safe_load(expected_em1_cfg), - self.get_interface_config('em1')) - self.assertEqual(yaml.safe_load(expected_em2_cfg), - self.get_interface_config('em2')) - - # primary interface is used only for active-slave bonds - interface1 = objects.Interface('em3') - interface2 = objects.Interface('em4', primary=True) - bond = objects.LinuxBond('bond1', use_dhcp=True, - members=[interface1, interface2], - bonding_options="mode=802.3ad " - "lacp_rate=slow updelay=1000 miimon=100") - self.provider.add_linux_bond(bond) - self.assertEqual(yaml.safe_load(expected_config2), - self.get_linuxbond_config('bond1')) - - def test_network_ovs_bridge_with_dhcp(self): - expected_brctl_p_cfg = """ - name: br-ctlplane-p - state: up - type: ovs-interface - ipv4: - auto-dns: True - auto-gateway: True - auto-routes: True - dhcp: True - enabled: True - ipv6: - autoconf: False - dhcp: False - enabled: False - """ - expected_brctl_cfg = """ - name: br-ctlplane - type: ovs-bridge - bridge: - options: - fail-mode: standalone - mcast-snooping-enable: False - rstp: False - stp: False - port: - - name: em1 - - name: br-ctlplane-p - ovs-db: - external_ids: {} - other_config: {} - state: up - """ - - interface = objects.Interface('em1') - bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True, - members=[interface]) - self.provider.add_bridge(bridge) - self.assertEqual(yaml.safe_load(expected_brctl_p_cfg), - self.get_interface_config('br-ctlplane-p')) - self.assertEqual(yaml.safe_load(expected_brctl_cfg), - self.get_bridge_config('br-ctlplane')) - - def test_network_ovs_bridge_with_bond(self): - expected_brctl2_p_cfg = """ - name: br-ctlplane2-p - state: up - type: ovs-interface - ipv4: - auto-dns: True - auto-gateway: True - auto-routes: True - dhcp: True - enabled: True - ipv6: - autoconf: False - dhcp: False - enabled: False - """ - expected_brctl2_cfg = """ - name: br-ctlplane2 - type: ovs-bridge - bridge: - options: - fail-mode: standalone - mcast-snooping-enable: False - rstp: False - stp: False - port: - - name: bond0 - link-aggregation: - mode: active-backup - port: - - name: em2 - - name: em3 - ovs-db: - other_config: - bond-primary: em2 - - name: br-ctlplane2-p - ovs-db: - external_ids: {} - other_config: {} - state: up - """ - - interface1 = objects.Interface('em2') - interface2 = objects.Interface('em3') - bond = objects.OvsBond('bond0', members=[interface1, interface2]) - bridge = objects.OvsBridge('br-ctlplane2', use_dhcp=True, - members=[bond]) - self.provider.add_bridge(bridge) - self.assertEqual(yaml.safe_load(expected_brctl2_p_cfg), - self.get_interface_config('br-ctlplane2-p')) - self.assertEqual(yaml.safe_load(expected_brctl2_cfg), - self.get_bridge_config('br-ctlplane2')) - - def test_network_ovs_bridge_with_bond_options(self): - expected_brctl2_cfg = """ - name: br-ctlplane2 - type: ovs-bridge - bridge: - options: - fail-mode: standalone - mcast-snooping-enable: False - rstp: False - stp: False - port: - - name: bond0 - link-aggregation: - bond-updelay: 1000 - mode: balance-slb - ovs-db: - other_config: - bond-detect-mode: miimon - bond-miimon-interval: 100 - bond-rebalance-interval: 10000 - bond-primary: em2 - lacp-fallback-ab: true - lacp-time: fast - port: - - name: em2 - - name: em3 - - name: br-ctlplane2-p - state: up - ovs-db: - external_ids: {} - other_config: {} - """ - interface1 = objects.Interface('em2') - interface2 = objects.Interface('em3') - - ovs_options = 'bond_mode=balance-slb ' \ - 'other-config:lacp-fallback-ab=true ' \ - 'other-config:lacp-time=fast ' \ - 'other_config:bond-detect-mode=miimon ' \ - 'other_config:bond-miimon-interval=100 ' \ - 'bond_updelay=1000 ' \ - 'other_config:bond-rebalance-interval=10000' - bond = objects.OvsBond('bond0', members=[interface1, interface2], - ovs_options=ovs_options) - bridge = objects.OvsBridge('br-ctlplane2', use_dhcp=True, - members=[bond]) - self.provider.add_bridge(bridge) - self.assertEqual(yaml.safe_load(expected_brctl2_cfg), - self.get_bridge_config('br-ctlplane2')) - - def test_network_ovs_bridge_with_ovs_extra(self): - expected_brctl2_cfg = """ - name: br-ctlplane2 - type: ovs-bridge - bridge: - options: - fail-mode: standalone - mcast-snooping-enable: True - rstp: True - stp: True - port: - - name: bond0 - link-aggregation: - mode: balance-slb - port: - - name: em2 - - name: em3 - ovs-db: - other_config: - bond-primary: em2 - - name: br-ctlplane2-p - vlan: - tag: 70 - mode: access - ovs-db: - external_ids: - bridge-id: br-ctlplane - other_config: - stp-priority: '0x7800' - state: up - """ - interface1 = objects.Interface('em2') - interface2 = objects.Interface('em3') - ovs_extra = [ - "br-set-external-id br-ctlplane2 bridge-id br-ctlplane", - "set bridge {name} stp_enable=true rstp_enable=true", - "set bridge {name} fail_mode=standalone", - "set bridge br-ctlplane2 mcast_snooping_enable=true", - "set Bridge {name} other_config:stp-priority=0x7800", - "set port {name} tag=70"] - - ovs_options = 'bond_mode=balance-slb' - bond = objects.OvsBond('bond0', members=[interface1, interface2], - ovs_options=ovs_options) - bridge = objects.OvsBridge('br-ctlplane2', use_dhcp=True, - members=[bond], ovs_extra=ovs_extra) - self.provider.add_bridge(bridge) - self.assertEqual(yaml.safe_load(expected_brctl2_cfg), - self.get_bridge_config('br-ctlplane2')) - - def test_network_ovs_bridge_without_bond_with_ovs_extra(self): - expected_brctl2_cfg = """ - name: br-ctlplane2 - type: ovs-bridge - bridge: - options: - fail-mode: standalone - mcast-snooping-enable: True - rstp: True - stp: True - port: - - name: em2 - - name: em3 - - name: br-ctlplane2-p - vlan: - tag: 70 - mode: access - ovs-db: - external_ids: - bridge-id: br-ctlplane - other_config: - stp-priority: '0x7800' - state: up - """ - interface1 = objects.Interface('em2') - interface2 = objects.Interface('em3') - ovs_extra = [ - "br-set-external-id br-ctlplane2 bridge-id br-ctlplane", - "set bridge {name} stp_enable=true rstp_enable=true", - "set bridge {name} fail_mode=standalone", - "set bridge br-ctlplane2 mcast_snooping_enable=true", - "set Bridge {name} other_config:stp-priority=0x7800", - "set port {name} tag=70"] - - bridge = objects.OvsBridge('br-ctlplane2', use_dhcp=True, - members=[interface1, interface2], - ovs_extra=ovs_extra) - self.provider.add_bridge(bridge) - self.assertEqual(yaml.safe_load(expected_brctl2_cfg), - self.get_bridge_config('br-ctlplane2')) - - def test_network_ovs_bridge_with_linux_bond(self): - expected_brctl2_cfg = """ - name: br-ctlplane2 - type: ovs-bridge - bridge: - options: - fail-mode: standalone - mcast-snooping-enable: False - rstp: False - stp: False - port: - - name: bond0 - - name: br-ctlplane2-p - ovs-db: - external_ids: {} - other_config: {} - state: up - ovs-db: - external_ids: {} - other_config: {} - """ - expected_bond0_config = """ - name: bond0 - type: bond - state: up - link-aggregation: - mode: active-backup - port: - - em3 - - em2 - options: - primary: em3 - ipv4: - enabled: False - dhcp: False - ipv6: - enabled: False - autoconf: False - dhcp: False - """ - interface1 = objects.Interface('em2') - interface2 = objects.Interface('em3', primary=True) - - bond = objects.LinuxBond('bond0', members=[interface1, interface2]) - bridge = objects.OvsBridge('br-ctlplane2', use_dhcp=True, - members=[bond]) - self.provider.add_bridge(bridge) - self.provider.add_linux_bond(bond) - self.assertEqual(yaml.safe_load(expected_brctl2_cfg), - self.get_bridge_config('br-ctlplane2')) - self.assertCountEqual(yaml.safe_load(expected_bond0_config), - self.get_linuxbond_config('bond0')) - - def test_vlan_interface(self): - expected_vlan1_cfg = """ - name: vlan502 - type: vlan - vlan: - base-iface: em2 - id: 502 - state: up - ipv4: - dhcp: false - enabled: false - ipv6: - address: - - ip: "2001:abc:a::" - prefix-length: 64 - autoconf: false - dhcp: false - enabled: true - """ - v6_addr = objects.Address('2001:abc:a::/64') - vlan1 = objects.Vlan('em2', 502, addresses=[v6_addr]) - self.provider.add_vlan(vlan1) - self.assertEqual(yaml.safe_load(expected_vlan1_cfg), - self.get_vlan_config('vlan502')) - - def test_vlan_as_interface(self): - expected_vlan1_cfg = """ - name: em2.502 - type: vlan - vlan: - base-iface: em2 - id: 502 - state: up - ipv4: - dhcp: false - enabled: false - ipv6: - address: - - ip: "2001:abc:a::" - prefix-length: 64 - autoconf: false - dhcp: false - enabled: true - """ - v6_addr = objects.Address('2001:abc:a::/64') - em2 = objects.Interface('em2.502', addresses=[v6_addr]) - self.provider.add_interface(em2) - self.assertEqual(yaml.safe_load(expected_vlan1_cfg), - self.get_vlan_config('em2.502')) - - def test_add_vlan_ovs(self): - expected_vlan1_cfg = """ - name: vlan5 - ipv4: - dhcp: false - enabled: false - ipv6: - autoconf: false - dhcp: false - enabled: false - state: up - type: ovs-interface - """ - expected_bridge_cfg = """ - name: br-ctlplane - bridge: - options: - fail-mode: standalone - mcast-snooping-enable: false - rstp: false - stp: false - port: - - name: em2 - - name: vlan5 - vlan: - mode: access - tag: 5 - - name: br-ctlplane-p - ovs-db: - external_ids: {} - other_config: {} - state: up - type: ovs-bridge - """ - interface1 = objects.Interface('em2') - vlan = objects.Vlan(None, 5) - bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True, - members=[interface1, vlan]) - self.provider.add_bridge(bridge) - self.provider.add_vlan(vlan) - self.assertEqual(yaml.safe_load(expected_vlan1_cfg), - self.get_vlan_config('vlan5')) - self.assertEqual(yaml.safe_load(expected_bridge_cfg), - self.get_bridge_config('br-ctlplane')) - - def test_add_vlan_mtu_1500(self): - expected_vlan1_cfg = """ - name: vlan5 - type: vlan - vlan: - base-iface: em1 - id: 5 - state: up - mtu: 1500 - ipv4: - dhcp: false - enabled: false - ipv6: - autoconf: false - dhcp: false - enabled: false - """ - vlan = objects.Vlan('em1', 5, mtu=1500) - self.provider.add_vlan(vlan) - self.assertEqual(yaml.safe_load(expected_vlan1_cfg), - self.get_vlan_config('vlan5')) - - def test_add_ovs_bridge_with_vlan(self): - expected_vlan1_cfg = """ - name: vlan5 - ipv4: - dhcp: false - enabled: false - ipv6: - autoconf: false - dhcp: false - enabled: false - state: up - type: ovs-interface - """ - expected_bridge_cfg = """ - name: br-ctlplane - bridge: - options: - fail-mode: standalone - mcast-snooping-enable: false - rstp: false - stp: false - port: - - name: vlan5 - vlan: - mode: access - tag: 5 - - name: br-ctlplane-p - ovs-db: - external_ids: {} - other_config: {} - state: up - type: ovs-bridge - """ - vlan = objects.Vlan('em2', 5) - bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True, - members=[vlan]) - self.provider.add_vlan(vlan) - self.provider.add_bridge(bridge) - self.assertEqual(yaml.safe_load(expected_bridge_cfg), - self.get_bridge_config('br-ctlplane')) - self.assertEqual(yaml.safe_load(expected_vlan1_cfg), - self.get_vlan_config('vlan5')) - - def test_vlan_over_linux_bond(self): - expected_vlan1_cfg = """ - name: vlan5 - type: vlan - vlan: - base-iface: bond0 - id: 5 - state: up - ipv4: - dhcp: false - enabled: false - ipv6: - autoconf: false - dhcp: false - enabled: false - """ - interface1 = objects.Interface('em1', primary=True) - interface2 = objects.Interface('em2') - bond = objects.LinuxBond('bond0', use_dhcp=True, - members=[interface1, interface2]) - vlan = objects.Vlan('bond0', 5) - self.provider.add_linux_bond(bond) - self.provider.add_interface(interface1) - self.provider.add_interface(interface2) - self.provider.add_vlan(vlan) - self.assertEqual(yaml.safe_load(expected_vlan1_cfg), - self.get_vlan_config('vlan5')) - - def test_add_vlan_route_rules(self): - expected_vlan1_cfg = """ - name: vlan5 - type: vlan - vlan: - base-iface: em1 - id: 5 - state: up - ipv4: - dhcp: false - enabled: true - address: - - ip: 192.168.1.2 - prefix-length: 24 - ipv6: - autoconf: false - dhcp: false - enabled: false - """ - - expected_route_table = """ - - destination: 172.19.0.0/24 - next-hop-address: 192.168.1.1 - next-hop-interface: vlan5 - table-id: 200 - - destination: 172.20.0.0/24 - next-hop-address: 192.168.1.1 - next-hop-interface: vlan5 - table-id: 201 - - destination: 172.21.0.0/24 - next-hop-address: 192.168.1.1 - next-hop-interface: vlan5 - table-id: 200 - """ - expected_rule = """ - - ip-from: 192.0.2.0/24 - route-table: 200 - """ - - route_table1 = objects.RouteTable('table1', 200) - self.provider.add_route_table(route_table1) - - route_rule1 = objects.RouteRule('from 192.0.2.0/24 table 200', - 'test comment') - # Test route table by name - route1 = objects.Route('192.168.1.1', '172.19.0.0/24', False, - route_table="table1") - - # Test that table specified in route_options takes precedence - route2 = objects.Route('192.168.1.1', '172.20.0.0/24', False, - 'table 201', route_table=200) - # Test route table specified by integer ID - route3 = objects.Route('192.168.1.1', '172.21.0.0/24', False, - route_table=200) - v4_addr = objects.Address('192.168.1.2/24') - vlan = objects.Vlan('em1', 5, addresses=[v4_addr], - routes=[route1, route2, route3], - rules=[route_rule1]) - self.provider.add_vlan(vlan) - self.assertEqual(yaml.safe_load(expected_vlan1_cfg), - self.get_vlan_config('vlan5')) - self.assertEqual(yaml.safe_load(expected_route_table), - self.get_route_config('vlan5')) - self.assertEqual(yaml.safe_load(expected_rule), - self.get_rule_config()) - - def test_sriov_pf_without_nicpart(self): - nic_mapping = {'nic1': 'eth0', 'nic2': 'eth1', 'nic3': 'eth2'} - self.stubbed_mapped_nics = nic_mapping - - def update_sriov_pf_map_stub(ifname, numvfs, noop, promisc=None, - link_mode='legacy', vdpa=False, - steering_mode=None, lag_candidate=None): - return - self.stub_out('os_net_config.utils.update_sriov_pf_map', - update_sriov_pf_map_stub) - - pf = objects.SriovPF(name='nic3', numvfs=10) - self.provider.add_sriov_pf(pf) - exp_pf_config = """ - name: eth2 - state: up - type: ethernet - ethernet: - sr-iov: - total-vfs: 10 - ipv4: - dhcp: False - enabled: False - ipv6: - autoconf: False - dhcp: False - enabled: False - """ - self.assertEqual(yaml.safe_load(exp_pf_config), - self.get_interface_config('eth2')) - - def test_sriov_pf_with_nicpart_ovs(self): - nic_mapping = {'nic1': 'eth0', 'nic2': 'eth1', 'nic3': 'eth2'} - self.stubbed_mapped_nics = nic_mapping - - def update_sriov_pf_map_stub(ifname, numvfs, noop, promisc=None, - link_mode='legacy', vdpa=False, - steering_mode=None, lag_candidate=None): - return - self.stub_out('os_net_config.utils.update_sriov_pf_map', - update_sriov_pf_map_stub) - - def test_get_vf_devname(device, vfid): - return device + '_' + str(vfid) - self.stub_out('os_net_config.utils.get_vf_devname', - test_get_vf_devname) - - pf1 = objects.SriovPF(name='nic3', numvfs=10) - self.provider.add_sriov_pf(pf1) - pf2 = objects.SriovPF(name='nic2', numvfs=10) - self.provider.add_sriov_pf(pf2) - - ovs_config = """ - type: ovs_bridge - name: br-bond - use_dhcp: true - members: - - - type: ovs_bond - name: bond_vf - ovs_options: "bond_mode=active-backup" - members: - - - type: sriov_vf - device: nic3 - vfid: 2 - vlan_id: 112 - qos: 4 - primary: true - - - type: sriov_vf - device: nic2 - vfid: 2 - vlan_id: 112 - qos: 4 - """ - - ovs_obj = objects.object_from_json(yaml.safe_load(ovs_config)) - self.provider.add_bridge(ovs_obj) - self.provider.add_sriov_vf(ovs_obj.members[0].members[0]) - self.provider.add_sriov_vf(ovs_obj.members[0].members[1]) - - exp_pf_config = """ - - name: eth2 - state: up - type: ethernet - ethernet: - sr-iov: - total-vfs: 10 - vfs: - - id: 2 - spoof-check: false - trust: true - vlan-id: 112 - qos: 4 - ipv4: - dhcp: False - enabled: False - ipv6: - autoconf: False - dhcp: False - enabled: False - - name: eth1 - state: up - type: ethernet - ethernet: - sr-iov: - total-vfs: 10 - vfs: - - id: 2 - spoof-check: false - trust: true - vlan-id: 112 - qos: 4 - ipv4: - dhcp: False - enabled: False - ipv6: - autoconf: False - dhcp: False - enabled: False - """ - - exp_bridge_config = """ - name: br-bond - state: up - type: ovs-bridge - bridge: - options: - fail-mode: standalone - mcast-snooping-enable: False - rstp: False - stp: False - port: - - name: bond_vf - link-aggregation: - mode: active-backup - ovs-db: - other_config: - bond-primary: eth2_2 - port: - - name: eth2_2 - - name: eth1_2 - - name: br-bond-p - ovs-db: - external_ids: {} - other_config: {} - """ - - vf_config = self.provider.prepare_sriov_vf_config() - self.assertEqual(yaml.safe_load(exp_pf_config), - vf_config) - self.assertEqual(yaml.safe_load(exp_bridge_config), - self.get_bridge_config('br-bond')) - - def test_sriov_pf_with_nicpart_linux_bond(self): - nic_mapping = {'nic1': 'eth0', 'nic2': 'eth1', 'nic3': 'eth2'} - self.stubbed_mapped_nics = nic_mapping - - def update_sriov_pf_map_stub(ifname, numvfs, noop, promisc=None, - link_mode='legacy', vdpa=False, - steering_mode=None, lag_candidate=None): - return - self.stub_out('os_net_config.utils.update_sriov_pf_map', - update_sriov_pf_map_stub) - - def test_get_vf_devname(device, vfid): - return device + '_' + str(vfid) - self.stub_out('os_net_config.utils.get_vf_devname', - test_get_vf_devname) - - pf1 = objects.SriovPF(name='nic3', numvfs=10) - self.provider.add_sriov_pf(pf1) - pf2 = objects.SriovPF(name='nic2', numvfs=10) - self.provider.add_sriov_pf(pf2) - - lnxbond_config = """ - type: linux_bond - name: bond_lnx - use_dhcp: true - bonding_options: "mode=active-backup" - members: - - - type: sriov_vf - device: eth1 - vfid: 3 - vlan_id: 113 - qos: 5 - primary: true - - - type: sriov_vf - device: eth2 - vfid: 3 - vlan_id: 113 - qos: 5 - """ - - lb_obj = objects.object_from_json(yaml.safe_load(lnxbond_config)) - self.provider.add_linux_bond(lb_obj) - self.provider.add_sriov_vf(lb_obj.members[0]) - self.provider.add_sriov_vf(lb_obj.members[1]) - - exp_pf_config = """ - - name: eth2 - state: up - type: ethernet - ethernet: - sr-iov: - total-vfs: 10 - vfs: - - id: 3 - spoof-check: false - trust: true - vlan-id: 113 - qos: 5 - ipv4: - dhcp: False - enabled: False - ipv6: - autoconf: False - dhcp: False - enabled: False - - name: eth1 - state: up - type: ethernet - ethernet: - sr-iov: - total-vfs: 10 - vfs: - - id: 3 - spoof-check: false - trust: true - vlan-id: 113 - qos: 5 - ipv4: - dhcp: False - enabled: False - ipv6: - autoconf: False - dhcp: False - enabled: False - """ - - exp_bond_config = """ - name: bond_lnx - state: up - type: bond - ipv4: - auto-dns: true - auto-gateway: true - auto-routes: true - dhcp: true - enabled: true - ipv6: - autoconf: false - dhcp: false - enabled: false - link-aggregation: - mode: active-backup - options: - primary: eth1_3 - port: - - eth1_3 - - eth2_3 - """ - - vf_config = self.provider.prepare_sriov_vf_config() - self.assertEqual(yaml.safe_load(exp_pf_config), - vf_config) - self.assertEqual(yaml.safe_load(exp_bond_config), - self.get_linuxbond_config('bond_lnx')) - - def test_infiniband_parent(self): - expected_ib_config = """ - ipv4: - dhcp: False - enabled: False - ipv6: - autoconf: False - dhcp: False - enabled: False - mtu: 1400 - name: ib0 - state: up - type: infiniband - infiniband: - mode: datagram - """ - - interface1 = objects.Interface('ib0', mtu=1400) - self.provider.add_ib_interface(interface1) - self.assertEqual(yaml.safe_load(expected_ib_config), - self.get_interface_config('ib0')) - - expected_ib2_config = """ - name: ib0.8064 - ipv4: - dhcp: False - enabled: True - address: - - ip: 192.168.1.2 - prefix-length: 24 - ipv6: - autoconf: False - dhcp: False - enabled: False - state: up - type: infiniband - infiniband: - pkey: "0x8064" - base-iface: ib0 - mode: datagram - """ - v4_addr = objects.Address('192.168.1.2/24') - interface2 = objects.IbChildInterface(parent='ib0', - pkey_id=100, - addresses=[v4_addr]) - self.provider.add_ib_child_interface(interface2) - self.assertEqual(yaml.safe_load(expected_ib2_config), - self.get_interface_config('ib0.8064')) - - -class TestNmstateNetConfigApply(base.TestCase): - - def setUp(self): - super(TestNmstateNetConfigApply, self).setUp() - - def test_iface_state(iface_data='', verify_change=True): - # This function returns None - return None - self.stub_out( - 'libnmstate.netapplier.apply', test_iface_state) - self.provider = impl_nmstate.NmstateNetConfig() - - def add_object(self, nic_config): - iface_array = yaml.safe_load(nic_config) - for iface_json in iface_array: - obj = objects.object_from_json(iface_json) - self.provider.add_object(obj) - - def get_running_info(self, yaml_file): - with open(yaml_file) as f: - data = yaml.load(f, Loader=yaml.SafeLoader) - return data - - def tearDown(self): - super(TestNmstateNetConfigApply, self).tearDown() - - def test_base_interface(self): - - def show_running_info_stub(): - running_info_path = os.path.join( - os.path.dirname(__file__), - 'environment/netinfo_running_info_1.yaml') - running_info = self.get_running_info(running_info_path) - return running_info - self.stub_out('libnmstate.netinfo.show_running_config', - show_running_info_stub) - - self.add_object(_BASE_IFACE_CFG) - updated_files = self.provider.apply() - self.assertEqual(yaml.load(_BASE_IFACE_CFG_APPLIED, - Loader=yaml.SafeLoader), - updated_files) diff --git a/os_net_config/tests/test_objects.py b/os_net_config/tests/test_objects.py deleted file mode 100644 index 00d54ff8..00000000 --- a/os_net_config/tests/test_objects.py +++ /dev/null @@ -1,2521 +0,0 @@ -# -*- 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. - -import json -import os -import random -import yaml - -from os_net_config import common -from os_net_config import objects -from os_net_config.tests import base - - -class TestRoute(base.TestCase): - - def test_from_json(self): - data = '{"next_hop": "172.19.0.1", "ip_netmask": "172.19.0.0/24", ' \ - '"route_options": "metric 10", "table": "200"}' - route = objects.Route.from_json(json.loads(data)) - self.assertEqual("172.19.0.1", route.next_hop) - self.assertEqual("172.19.0.0/24", route.ip_netmask) - self.assertFalse(route.default) - self.assertEqual("metric 10", route.route_options) - self.assertEqual("200", route.route_table) - - def test_from_json_default_route(self): - data = '{"next_hop": "172.19.0.1", "ip_netmask": "172.19.0.0/24", ' \ - '"default": true, "route_options": "metric 10"}' - route = objects.Route.from_json(json.loads(data)) - self.assertEqual("172.19.0.1", route.next_hop) - self.assertEqual("172.19.0.0/24", route.ip_netmask) - self.assertTrue(route.default) - self.assertEqual("metric 10", route.route_options) - - data = '{"next_hop": "172.19.0.1", "ip_netmask": "172.19.0.0/24", ' \ - '"default": "true", "route_options": "metric 10"}' - route = objects.Route.from_json(json.loads(data)) - self.assertEqual("172.19.0.1", route.next_hop) - self.assertEqual("172.19.0.0/24", route.ip_netmask) - self.assertTrue(route.default) - self.assertEqual("metric 10", route.route_options) - - def test_from_json_neutron_schema(self): - data = '{"nexthop": "172.19.0.254", "destination": "192.168.1.0/26"}' - route = objects.Route.from_json(json.loads(data)) - self.assertEqual("172.19.0.254", route.next_hop) - self.assertEqual("192.168.1.0/26", route.ip_netmask) - - data = {'nexthop': '172.19.0.254', - 'next_hop': '172.19.0.1', - 'destination': '192.168.1.0/26'} - self.assertRaises(objects.InvalidConfigException, - objects.Route.from_json, data) - - data = {'nexthop': '172.19.0.254', - 'destination': '192.168.1.0/26', - 'ip_netmask': '172.19.0.0/24'} - self.assertRaises(objects.InvalidConfigException, - objects.Route.from_json, data) - - -class TestRouteTable(base.TestCase): - - def test_from_json(self): - data = '{"type": "route_table", "name": "custom", "table_id": 200}' - route_table = objects.RouteTable.from_json(json.loads(data)) - self.assertEqual("custom", route_table.name) - self.assertEqual(200, route_table.table_id) - - def test_from_json_invalid(self): - self.assertRaises(objects.InvalidConfigException, - objects.RouteTable.from_json, - {}) - - data = '{"type": "route_table", "table_id": 200}' - json_data = json.loads(data) - self.assertRaises(objects.InvalidConfigException, - objects.RouteTable.from_json, - json_data) - - data = '{"type": "route_table", "name": "custom"}' - json_data = json.loads(data) - self.assertRaises(objects.InvalidConfigException, - objects.RouteTable.from_json, - json_data) - - -class TestRouteRule(base.TestCase): - - def test_rule(self): - rule1 = objects.RouteRule('from 192.0.2.0/24 table 200 prio 1000') - self.assertEqual('from 192.0.2.0/24 table 200 prio 1000', rule1.rule) - - def test_rule_from_json(self): - data = '{"rule":"from 172.19.0.0/24 table 200", "comment":"test"}' - route_rule = objects.RouteRule.from_json(json.loads(data)) - self.assertEqual("from 172.19.0.0/24 table 200", route_rule.rule) - self.assertEqual("test", route_rule.comment) - - -class TestAddress(base.TestCase): - - def test_ipv4_address(self): - address = objects.Address('192.168.1.1/24') - self.assertEqual("192.168.1.1", address.ip) - self.assertEqual("255.255.255.0", address.netmask) - self.assertEqual(4, address.version) - - def test_ipv6_address(self): - address = objects.Address('2001:abc:a::/64') - self.assertEqual("2001:abc:a::", address.ip) - self.assertEqual("ffff:ffff:ffff:ffff::", address.netmask) - self.assertEqual(6, address.version) - - def test_from_json(self): - data = '{"ip_netmask": "192.0.2.5/24"}' - address = objects.Address.from_json(json.loads(data)) - self.assertEqual("192.0.2.5", address.ip) - self.assertEqual("255.255.255.0", address.netmask) - self.assertEqual(4, address.version) - - def test_from_json_invalid(self): - self.assertRaises(objects.InvalidConfigException, - objects.Address.from_json, - {}) - data = '{"ip_netmask": false}' - json_data = json.loads(data) - self.assertRaises(TypeError, - objects.Address.from_json, - json_data) - - -class TestInterface(base.TestCase): - - def test_interface_addresses(self): - v4_addr = objects.Address('192.168.1.1/24') - v6_addr = objects.Address('2001:abc:a::/64') - interface = objects.Interface('foo', addresses=[v4_addr, v6_addr]) - self.assertEqual("192.168.1.1", interface.v4_addresses()[0].ip) - self.assertEqual("2001:abc:a::", interface.v6_addresses()[0].ip) - - def test_from_json_dhcp(self): - data = '{"type": "interface", "name": "em1", "use_dhcp": true}' - interface = objects.object_from_json(json.loads(data)) - self.assertEqual("em1", interface.name) - self.assertTrue(interface.use_dhcp) - - def test_from_json_dhcpv6(self): - data = '{"type": "interface", "name": "em1", "use_dhcpv6": true}' - interface = objects.object_from_json(json.loads(data)) - self.assertEqual("em1", interface.name) - self.assertTrue(interface.use_dhcpv6) - - def test_from_json_dotted_vlan(self): - def dummy_mapped_nics(nic_mapping=None): - return {"nic1": "em3"} - self.stub_out('os_net_config.objects.mapped_nics', dummy_mapped_nics) - - data = '{"type": "interface", "name": "nic1.10", "use_dhcp": true}' - interface = objects.object_from_json(json.loads(data)) - self.assertEqual("em3.10", interface.name) - - def test_from_json_hotplug(self): - data = """{ -"type": "interface", -"name": "em1", -"hotplug": true -} -""" - interface = objects.object_from_json(json.loads(data)) - self.assertEqual("em1", interface.name) - self.assertTrue(interface.hotplug) - - def test_from_json_hotplug_off_by_default(self): - data = """{ -"type": "interface", -"name": "em1" -} -""" - interface = objects.object_from_json(json.loads(data)) - self.assertEqual("em1", interface.name) - self.assertFalse(interface.hotplug) - - def test_from_json_defroute(self): - data = '{"type": "interface", "name": "em1", "use_dhcp": true}' - interface1 = objects.object_from_json(json.loads(data)) - data = """{ -"type": "interface", -"name": "em1", -"use_dhcp": true, -"defroute": false -} -""" - interface2 = objects.object_from_json(json.loads(data)) - self.assertTrue(interface1.defroute) - self.assertFalse(interface2.defroute) - - def test_from_json_dhclient_args(self): - data = """{ -"type": "interface", -"name": "em1", -"use_dhcp": true, -"dhclient_args": "--foobar" -} -""" - interface1 = objects.object_from_json(json.loads(data)) - self.assertEqual("--foobar", interface1.dhclient_args) - - def test_from_json_nm_controlled_false(self): - data = """{ -"type": "interface", -"name": "em1", -"nm_controlled": false -} -""" - interface1 = objects.object_from_json(json.loads(data)) - self.assertFalse(interface1.nm_controlled) - - def test_from_json_nm_controlled_true(self): - data = """{ -"type": "interface", -"name": "em1", -"nm_controlled": true -} -""" - interface1 = objects.object_from_json(json.loads(data)) - self.assertTrue(interface1.nm_controlled) - - def test_from_json_nm_controlled_false_boolstr(self): - data = """{ -"type": "interface", -"name": "em1", -"nm_controlled": "no" -} -""" - interface1 = objects.object_from_json(json.loads(data)) - self.assertFalse(interface1.nm_controlled) - - def test_from_json_nm_controlled_true_boolstr(self): - data = """{ -"type": "interface", -"name": "em1", -"nm_controlled": "yes" -} -""" - interface1 = objects.object_from_json(json.loads(data)) - self.assertTrue(interface1.nm_controlled) - - def test_from_json_onboot_false(self): - data = """{ -"type": "interface", -"name": "em1", -"onboot": false -} -""" - interface1 = objects.object_from_json(json.loads(data)) - self.assertFalse(interface1.onboot) - - def test_from_json_onboot_true(self): - data = """{ -"type": "interface", -"name": "em1", -"onboot": true -} -""" - interface1 = objects.object_from_json(json.loads(data)) - self.assertTrue(interface1.onboot) - - def test_from_json_onboot_false_boolstr(self): - data = """{ -"type": "interface", -"name": "em1", -"onboot": "no" -} -""" - interface1 = objects.object_from_json(json.loads(data)) - self.assertFalse(interface1.onboot) - - def test_from_json_onboot_true_boolstr(self): - data = """{ -"type": "interface", -"name": "em1", -"onboot": "yes" -} -""" - interface1 = objects.object_from_json(json.loads(data)) - self.assertTrue(interface1.onboot) - - def test_from_json_dns_servers(self): - data = """{ -"type": "interface", -"name": "em1", -"use_dhcp": true, -"dns_servers": ["1.2.3.4"] -} -""" - interface1 = objects.object_from_json(json.loads(data)) - self.assertEqual(["1.2.3.4"], interface1.dns_servers) - - def test_from_json_domain(self): - data = """{ -"type": "interface", -"name": "em1", -"use_dhcp": true, -"domain": "openstack.local" -} -""" - interface1 = objects.object_from_json(json.loads(data)) - self.assertEqual("openstack.local", interface1.domain) - - def test_from_json_domain_list(self): - data = """{ -"type": "interface", -"name": "em1", -"use_dhcp": true, -"domain": ["openstack.local", "subdomain.openstack.local"] -} -""" - interface1 = objects.object_from_json(json.loads(data)) - self.assertEqual( - ["openstack.local", "subdomain.openstack.local"], - interface1.domain) - - def test_from_json_dhcp_nic1(self): - def dummy_mapped_nics(nic_mapping=None): - return {"nic1": "em3"} - self.stub_out('os_net_config.objects.mapped_nics', dummy_mapped_nics) - - data = '{"type": "interface", "name": "nic1", "use_dhcp": true}' - interface = objects.object_from_json(json.loads(data)) - self.assertEqual("em3", interface.name) - self.assertTrue(interface.use_dhcp) - - def test_from_json_with_addresses(self): - data = """{ -"type": "interface", -"name": "em1", -"use_dhcp": false, -"mtu": 1501, -"ethtool_opts": "speed 1000 duplex full", -"addresses": [{ - "ip_netmask": "192.0.2.1/24" -}], -"routes": [{ - "next_hop": "192.0.2.1", - "ip_netmask": "192.0.2.1/24", - "route_options": "metric 10" -}] -} -""" - interface = objects.object_from_json(json.loads(data)) - self.assertEqual("em1", interface.name) - self.assertFalse(interface.use_dhcp) - self.assertFalse(interface.use_dhcpv6) - self.assertEqual(1501, interface.mtu) - self.assertEqual("speed 1000 duplex full", interface.ethtool_opts) - address1 = interface.v4_addresses()[0] - self.assertEqual("192.0.2.1", address1.ip) - self.assertEqual("255.255.255.0", address1.netmask) - route1 = interface.routes[0] - self.assertEqual("192.0.2.1", route1.next_hop) - self.assertEqual("192.0.2.1/24", route1.ip_netmask) - self.assertEqual("metric 10", route1.route_options) - - -class TestVlan(base.TestCase): - - def test_from_json_dhcp(self): - data = '{"type": "vlan", "device": "em1", "vlan_id": 16,' \ - '"use_dhcp": true}' - vlan = objects.object_from_json(json.loads(data)) - self.assertEqual("em1", vlan.device) - self.assertEqual(16, vlan.vlan_id) - self.assertTrue(vlan.use_dhcp) - - def test_from_json_dhcp_nic1(self): - def dummy_mapped_nics(nic_mapping=None): - return {"nic1": "em4"} - self.stub_out('os_net_config.objects.mapped_nics', dummy_mapped_nics) - - data = '{"type": "vlan", "device": "nic1", "vlan_id": 16,' \ - '"use_dhcp": true}' - vlan = objects.object_from_json(json.loads(data)) - self.assertEqual("em4", vlan.device) - self.assertEqual(16, vlan.vlan_id) - self.assertTrue(vlan.use_dhcp) - - def test_from_json_ovs_options_extra(self): - data = '{"type": "vlan", "device": "em1", "vlan_id": 16,' \ - '"use_dhcp": true, "ovs_options": "foo",' \ - '"ovs_extra": ["bar","baz"]}' - vlan = objects.object_from_json(json.loads(data)) - self.assertEqual("foo", vlan.ovs_options) - self.assertEqual(["bar", "baz"], vlan.ovs_extra) - - -class TestBridge(base.TestCase): - - def setUp(self): - super(TestBridge, self).setUp() - rand = str(int(random.random() * 100000)) - common.SRIOV_CONFIG_FILE = '/tmp/sriov_config_' + rand + '.yaml' - - def stub_is_ovs_installed(): - return True - self.stub_out('os_net_config.utils.is_ovs_installed', - stub_is_ovs_installed) - - def tearDown(self): - super(TestBridge, self).tearDown() - if os.path.isfile(common.SRIOV_CONFIG_FILE): - os.remove(common.SRIOV_CONFIG_FILE) - - def test_from_json_dhcp(self): - data = """{ -"type": "ovs_bridge", -"name": "br-foo", -"use_dhcp": true, -"members": [{ - "type": "interface", - "name": "em1" -}] -} -""" - bridge = objects.object_from_json(json.loads(data)) - self.assertEqual("br-foo", bridge.name) - self.assertTrue(bridge.use_dhcp) - interface1 = bridge.members[0] - self.assertEqual("em1", interface1.name) - self.assertTrue(interface1.ovs_port) - self.assertEqual("br-foo", interface1.bridge_name) - - def test_ovs_bridge_with_vf_default(self): - data = """{ -"type": "ovs_bridge", -"name": "br-foo", -"use_dhcp": true, -"members": [{ - "type": "sriov_vf", - "device": "em1", - "vfid": 1, - "vlan_id": 111, - "qos": 1 -}] -} -""" - vf_final = [{'device_type': 'vf', 'name': 'em1_1', - 'device': {'name': 'em1', 'vfid': 1}, - 'vlan_id': 111, 'qos': 1, - 'min_tx_rate': 0, 'max_tx_rate': 0, - 'spoofcheck': 'off', 'trust': 'on', - 'promisc': 'on', 'pci_address': '0000:79:10.2'}] - - def test_get_vf_devname(device, vfid): - return device + '_' + str(vfid) - - def test_get_pci_address(ifname, noop): - return '0000:79:10.2' - - self.stub_out('os_net_config.utils.get_vf_devname', - test_get_vf_devname) - self.stub_out('os_net_config.utils.get_pci_address', - test_get_pci_address) - - bridge = objects.object_from_json(json.loads(data)) - self.assertEqual("br-foo", bridge.name) - self.assertTrue(bridge.use_dhcp) - interface1 = bridge.members[0] - self.assertEqual("em1", interface1.device) - self.assertTrue(interface1.ovs_port) - self.assertEqual("br-foo", interface1.bridge_name) - - contents = common.get_file_data(common.SRIOV_CONFIG_FILE) - vf_map = yaml.safe_load(contents) if contents else [] - self.assertListEqual(vf_final, vf_map) - - def test_ovs_bond_with_vf_default(self): - data = """{ -"type": "ovs_bridge", -"name": "br-foo", -"use_dhcp": true, -"members": [{ - "type": "ovs_bond", - "name": "bond1", - "members": [{ - "type": "sriov_vf", - "device": "em1", - "vfid": 1, - "vlan_id": 111, - "qos": 1, - "primary": true - }, - { - "type": "sriov_vf", - "device": "em2", - "vfid": 1, - "vlan_id": 111, - "qos": 1 - } - ] -}] -} -""" - vf_final = [{'device_type': 'vf', 'name': 'em1_1', - 'device': {'name': 'em1', 'vfid': 1}, - 'vlan_id': 111, 'qos': 1, - 'min_tx_rate': 0, 'max_tx_rate': 0, - 'spoofcheck': 'off', 'trust': 'on', - 'promisc': 'on'}, - {'device_type': 'vf', 'name': 'em2_1', - 'device': {'name': 'em2', 'vfid': 1}, - 'vlan_id': 111, 'qos': 1, - 'min_tx_rate': 0, 'max_tx_rate': 0, - 'spoofcheck': 'off', 'trust': 'on', - 'promisc': 'on'}] - - def test_get_vf_devname(device, vfid): - return device + '_' + str(vfid) - - def test_get_pci_address(ifname, noop): - return '0000:79:10.2' - - self.stub_out('os_net_config.utils.get_vf_devname', - test_get_vf_devname) - self.stub_out('os_net_config.utils.get_pci_address', - test_get_pci_address) - - bridge = objects.object_from_json(json.loads(data)) - self.assertEqual("br-foo", bridge.name) - self.assertTrue(bridge.use_dhcp) - bond = bridge.members[0] - interface1 = bond.members[0] - interface2 = bond.members[1] - self.assertEqual("em1", interface1.device) - self.assertEqual("em2", interface2.device) - self.assertEqual("br-foo", bond.bridge_name) - - contents = common.get_file_data(common.SRIOV_CONFIG_FILE) - vf_map = yaml.safe_load(contents) if contents else [] - self.assertListEqual(vf_final, vf_map) - - def test_ovs_bond_with_vf_custom(self): - data = """{ -"type": "ovs_bridge", -"name": "br-foo", -"use_dhcp": true, -"members": [{ - "type": "ovs_bond", - "name": "bond1", - "members": [{ - "type": "sriov_vf", - "device": "em1", - "vfid": 1, - "vlan_id": 111, - "qos": 1, - "primary": true, - "trust": false, - "spoofcheck": true, - "promisc": false - }, - { - "type": "sriov_vf", - "device": "em2", - "vfid": 1, - "vlan_id": 111, - "qos": 1, - "trust": false, - "spoofcheck": true, - "promisc": false - } - ] -}] -} -""" - vf_final = [{'device_type': 'vf', 'name': 'em1_1', - 'device': {'name': 'em1', 'vfid': 1}, - 'vlan_id': 111, 'qos': 1, - 'min_tx_rate': 0, 'max_tx_rate': 0, - 'spoofcheck': 'on', 'trust': 'off', - 'promisc': 'off'}, - {'device_type': 'vf', 'name': 'em2_1', - 'device': {'name': 'em2', 'vfid': 1}, - 'vlan_id': 111, 'qos': 1, - 'min_tx_rate': 0, 'max_tx_rate': 0, - 'spoofcheck': 'on', 'trust': 'off', - 'promisc': 'off'}] - - def test_get_vf_devname(device, vfid): - return device + '_' + str(vfid) - - def test_get_pci_address(ifname, noop): - return '0000:79:10.2' - - self.stub_out('os_net_config.utils.get_vf_devname', - test_get_vf_devname) - self.stub_out('os_net_config.utils.get_pci_address', - test_get_pci_address) - - objects.object_from_json(json.loads(data)) - - contents = common.get_file_data(common.SRIOV_CONFIG_FILE) - vf_map = yaml.safe_load(contents) if contents else [] - self.assertListEqual(vf_final, vf_map) - - def test_ovs_bridge_with_vf_param_provided(self): - data = """{ -"type": "ovs_bridge", -"name": "br-foo", -"use_dhcp": true, -"members": [{ - "type": "sriov_vf", - "device": "em1", - "vfid": 1, - "vlan_id": 111, - "qos": 1, - "spoofcheck": false, - "trust": false, - "promisc": false -}] -} -""" - vf_final = [{'device_type': 'vf', 'name': 'em1_1', - 'device': {'name': 'em1', 'vfid': 1}, - 'vlan_id': 111, 'qos': 1, - 'min_tx_rate': 0, 'max_tx_rate': 0, - 'pci_address': '0000:79:10.2', - 'spoofcheck': 'off', 'trust': 'off', - 'promisc': 'off'}] - - def test_get_vf_devname(device, vfid): - return device + '_' + str(vfid) - - def test_get_pci_address(ifname, noop): - return '0000:79:10.2' - - self.stub_out('os_net_config.utils.get_vf_devname', - test_get_vf_devname) - self.stub_out('os_net_config.utils.get_pci_address', - test_get_pci_address) - bridge = objects.object_from_json(json.loads(data)) - self.assertEqual("br-foo", bridge.name) - self.assertTrue(bridge.use_dhcp) - interface1 = bridge.members[0] - self.assertEqual("em1", interface1.device) - self.assertTrue(interface1.ovs_port) - self.assertEqual("br-foo", interface1.bridge_name) - - contents = common.get_file_data(common.SRIOV_CONFIG_FILE) - vf_map = yaml.safe_load(contents) if contents else [] - self.assertListEqual(vf_final, vf_map) - - def test_ovs_user_bridge_with_vf_default(self): - data = """{ -"type": "ovs_user_bridge", -"name": "br-foo", -"use_dhcp": true, -"members": [{ - "type": "ovs_dpdk_port", - "name": "dpdk0", - "members": [ - { - "type": "sriov_vf", - "device": "em1", - "vfid": 1, - "vlan_id": 111, - "qos": 1 - } - ] -}] -} -""" - vf_final = [{'device_type': 'vf', 'name': 'em1_1', - 'device': {'name': 'em1', 'vfid': 1}, - 'vlan_id': 111, 'qos': 1, - 'min_tx_rate': 0, 'max_tx_rate': 0, - 'spoofcheck': 'off', 'trust': 'on', - 'pci_address': '0000:79:10.2', - 'driver': 'vfio-pci' - }] - - def test_get_vf_devname(device, vfid): - return device + '_' + str(vfid) - - def test_get_pci_address(ifname, noop): - return '0000:79:10.2' - - self.stub_out('os_net_config.utils.get_vf_devname', - test_get_vf_devname) - self.stub_out('os_net_config.utils.get_pci_address', - test_get_pci_address) - - bridge = objects.object_from_json(json.loads(data)) - self.assertEqual("br-foo", bridge.name) - self.assertTrue(bridge.use_dhcp) - dpdk_interface = bridge.members[0] - self.assertEqual("dpdk0", dpdk_interface.name) - self.assertFalse(dpdk_interface.ovs_port) - self.assertEqual("br-foo", dpdk_interface.bridge_name) - - contents = common.get_file_data(common.SRIOV_CONFIG_FILE) - vf_map = yaml.safe_load(contents) if contents else [] - self.assertListEqual(vf_final, vf_map) - - def test_ovs_user_bridge_with_param_set(self): - data = """{ -"type": "ovs_user_bridge", -"name": "br-foo", -"use_dhcp": true, -"members": [{ - "type": "ovs_dpdk_port", - "name": "dpdk0", - "members": [ - { - "type": "sriov_vf", - "device": "em1", - "vfid": 1, - "vlan_id": 111, - "qos": 1, - "min_tx_rate": 100, - "max_tx_rate": 500, - "spoofcheck": false, - "trust": false, - "promisc": false - } - ] -}] -} -""" - vf_final = [{'device_type': 'vf', 'name': 'em1_1', - 'device': {'name': 'em1', 'vfid': 1}, - 'vlan_id': 111, 'qos': 1, - 'min_tx_rate': 100, 'max_tx_rate': 500, - 'spoofcheck': 'off', 'trust': 'off', - 'pci_address': '0000:79:10.2', - 'driver': 'vfio-pci' - }] - - def test_get_vf_devname(device, vfid): - return device + '_' + str(vfid) - - def test_get_pci_address(ifname, noop): - return '0000:79:10.2' - - self.stub_out('os_net_config.utils.get_vf_devname', - test_get_vf_devname) - self.stub_out('os_net_config.utils.get_pci_address', - test_get_pci_address) - - bridge = objects.object_from_json(json.loads(data)) - self.assertEqual("br-foo", bridge.name) - self.assertTrue(bridge.use_dhcp) - dpdk_interface = bridge.members[0] - self.assertEqual("dpdk0", dpdk_interface.name) - self.assertFalse(dpdk_interface.ovs_port) - self.assertEqual("br-foo", dpdk_interface.bridge_name) - - contents = common.get_file_data(common.SRIOV_CONFIG_FILE) - vf_map = yaml.safe_load(contents) if contents else [] - self.assertListEqual(vf_final, vf_map) - - def test_from_json_dhcp_with_nic1(self): - def dummy_mapped_nics(nic_mapping=None): - return {"nic1": "em5"} - self.stub_out('os_net_config.objects.mapped_nics', dummy_mapped_nics) - - data = """{ -"type": "ovs_bridge", -"name": "br-foo", -"use_dhcp": true, -"members": [{ - "type": "interface", - "name": "nic1" -}] -} -""" - bridge = objects.object_from_json(json.loads(data)) - self.assertEqual("br-foo", bridge.name) - self.assertTrue(bridge.use_dhcp) - interface1 = bridge.members[0] - self.assertEqual("em5", interface1.name) - self.assertTrue(interface1.ovs_port) - self.assertEqual("br-foo", interface1.bridge_name) - - def test_from_json_primary_interface(self): - data = """{ -"type": "ovs_bridge", -"name": "br-foo", -"use_dhcp": true, -"members": [ - { - "type": "interface", - "name": "em1", - "primary": "true" - }, - { - "type": "interface", - "name": "em2" - }] -} -""" - bridge = objects.object_from_json(json.loads(data)) - self.assertEqual("br-foo", bridge.name) - self.assertTrue(bridge.use_dhcp) - self.assertEqual("em1", bridge.primary_interface_name) - interface1 = bridge.members[0] - self.assertEqual("em1", interface1.name) - self.assertTrue(interface1.ovs_port) - self.assertTrue(interface1.primary) - self.assertEqual("br-foo", interface1.bridge_name) - interface2 = bridge.members[1] - self.assertEqual("em2", interface2.name) - self.assertTrue(interface2.ovs_port) - self.assertEqual("br-foo", interface2.bridge_name) - - def test_from_json_ovs_extra(self): - data = """{ -"type": "ovs_bridge", -"name": "br-foo", -"ovs_extra": ["bar"], -"ovs_fail_mode": "standalone" -} -""" - bridge = objects.object_from_json(json.loads(data)) - self.assertTrue(3 == len(bridge.ovs_extra)) - self.assertCountEqual(["bar", - "set bridge br-foo fail_mode=standalone", - "del-controller br-foo"], - bridge.ovs_extra) - - def test_from_json_ovs_extra_string(self): - data = """{ -"type": "ovs_bridge", -"name": "br-foo", -"ovs_extra": "bar", -"ovs_fail_mode": "standalone" -} -""" - bridge = objects.object_from_json(json.loads(data)) - self.assertCountEqual(["bar", - "set bridge br-foo fail_mode=standalone", - "del-controller br-foo"], - bridge.ovs_extra) - - -class TestLinuxBridge(base.TestCase): - - def test_from_json_dhcp(self): - data = """{ -"type": "linux_bridge", -"name": "br-foo", -"use_dhcp": true, -"members": [{ - "type": "interface", - "name": "em1" -}] -} -""" - bridge = objects.object_from_json(json.loads(data)) - self.assertEqual("br-foo", bridge.name) - self.assertTrue(bridge.use_dhcp) - interface1 = bridge.members[0] - self.assertEqual("em1", interface1.name) - self.assertFalse(interface1.ovs_port) - self.assertEqual("br-foo", interface1.linux_bridge_name) - - def test_from_json_dhcp_with_nic1(self): - def dummy_mapped_nics(nic_mapping=None): - return {"nic1": "em5"} - self.stub_out('os_net_config.objects.mapped_nics', dummy_mapped_nics) - - data = """{ -"type": "linux_bridge", -"name": "br-foo", -"use_dhcp": true, -"members": [{ - "type": "interface", - "name": "nic1" -}] -} -""" - bridge = objects.object_from_json(json.loads(data)) - self.assertEqual("br-foo", bridge.name) - self.assertTrue(bridge.use_dhcp) - interface1 = bridge.members[0] - self.assertEqual("em5", interface1.name) - self.assertFalse(interface1.ovs_port) - self.assertEqual("br-foo", interface1.linux_bridge_name) - - def test_from_json_primary_interface(self): - data = """{ -"type": "linux_bridge", -"name": "br-foo", -"use_dhcp": true, -"members": [ - { - "type": "interface", - "name": "em1", - "primary": "true" - }, - { - "type": "interface", - "name": "em2" - }] -} -""" - bridge = objects.object_from_json(json.loads(data)) - self.assertEqual("br-foo", bridge.name) - self.assertTrue(bridge.use_dhcp) - self.assertEqual("em1", bridge.primary_interface_name) - interface1 = bridge.members[0] - self.assertEqual("em1", interface1.name) - self.assertFalse(interface1.ovs_port) - self.assertTrue(interface1.primary) - self.assertEqual("br-foo", interface1.linux_bridge_name) - interface2 = bridge.members[1] - self.assertEqual("em2", interface2.name) - self.assertFalse(interface2.ovs_port) - self.assertEqual("br-foo", interface2.linux_bridge_name) - - -class TestIvsBridge(base.TestCase): - - def test_from_json(self): - data = """{ -"type": "ivs_bridge", -"members": [ - {"type": "interface", "name": "nic2"}, - {"type": "interface", "name": "nic3"} - ] -} -""" - bridge = objects.object_from_json(json.loads(data)) - self.assertEqual("ivs", bridge.name) - interface1 = bridge.members[0] - self.assertEqual("nic2", interface1.name) - self.assertEqual(False, interface1.ovs_port) - interface2 = bridge.members[1] - self.assertEqual("nic3", interface2.name) - self.assertEqual(False, interface2.ovs_port) - self.assertEqual("ivs", interface1.ivs_bridge_name) - - -class TestIvsInterface(base.TestCase): - - def test_ivs_interface_from_json(self): - data = """{ -"type": "ivs_bridge", -"members": [ - {"type": "ivs_interface", "name": "storage", "vlan_id": 202} - ] -} -""" - bridge = objects.object_from_json(json.loads(data)) - self.assertEqual("ivs", bridge.name) - interface1 = bridge.members[0] - self.assertEqual("storage202", interface1.name) - self.assertEqual(False, interface1.ovs_port) - self.assertEqual("ivs", interface1.ivs_bridge_name) - - def test_bond_interface_from_json(self): - data = """{ -"type": "ivs_bridge", -"members": [{ - "type": "linux_bond", - "name": "bond1", - "members": [ - {"type": "interface", "name": "nic2"}, - {"type": "interface", "name": "nic3"} - ] -}] -} -""" - err = self.assertRaises(objects.InvalidConfigException, - objects.IvsBridge.from_json, - json.loads(data)) - expected = 'IVS does not support bond interfaces.' - self.assertIn(expected, str(err)) - - -class TestNfvswitchBridge(base.TestCase): - - def test_from_json(self): - data = """{ -"type": "nfvswitch_bridge", -"options": "-c 2,3,4,5", -"members": [ - {"type": "interface","name": "nic1"}, - {"type": "interface","name": "nic2"} - ] -} -""" - bridge = objects.object_from_json(json.loads(data)) - self.assertEqual("nfvswitch", bridge.name) - self.assertEqual("-c 2,3,4,5", bridge.options) - interface1 = bridge.members[0] - self.assertEqual("nic1", interface1.name) - self.assertEqual(False, interface1.ovs_port) - interface2 = bridge.members[1] - self.assertEqual("nic2", interface2.name) - self.assertEqual(False, interface2.ovs_port) - self.assertEqual("nfvswitch", interface1.nfvswitch_bridge_name) - - -class TestNfvswitchInterface(base.TestCase): - - def test_nfvswitch_internal_from_json(self): - data = """{ -"type": "nfvswitch_bridge", -"options": "-c 2,3,4,5", -"members": [ - {"type": "nfvswitch_internal", "name": "storage", "vlan_id": 202}, - {"type": "nfvswitch_internal", "name": "api", "vlan_id": 201} - ] -} -""" - bridge = objects.object_from_json(json.loads(data)) - self.assertEqual("nfvswitch", bridge.name) - self.assertEqual("-c 2,3,4,5", bridge.options) - interface1 = bridge.members[0] - self.assertEqual("storage202", interface1.name) - interface2 = bridge.members[1] - self.assertEqual("api201", interface2.name) - self.assertEqual(False, interface1.ovs_port) - self.assertEqual("nfvswitch", interface1.nfvswitch_bridge_name) - - def test_bond_interface_from_json(self): - data = """{ -"type": "nfvswitch_bridge", -"options": "-c 2,3,4,5", -"members": [{ - "type": "linux_bond", "name": "bond1", "members": - [{"type": "interface", "name": "nic2"}, - {"type": "interface", "name": "nic3"}] - } - ] -} -""" - err = self.assertRaises(objects.InvalidConfigException, - objects.NfvswitchBridge.from_json, - json.loads(data)) - expected = 'NFVSwitch does not support bond interfaces.' - self.assertIn(expected, str(err)) - - -class TestBond(base.TestCase): - - def setUp(self): - super(TestBond, self).setUp() - - def stub_is_ovs_installed(): - return True - self.stub_out('os_net_config.utils.is_ovs_installed', - stub_is_ovs_installed) - - def test_from_json_dhcp(self): - data = """{ -"type": "ovs_bond", -"name": "bond1", -"use_dhcp": true, -"members": [ - { - "type": "interface", - "name": "em1" - }, - { - "type": "interface", - "name": "em2" - } -] -} -""" - bridge = objects.object_from_json(json.loads(data)) - self.assertEqual("bond1", bridge.name) - self.assertTrue(bridge.use_dhcp) - interface1 = bridge.members[0] - self.assertEqual("em1", interface1.name) - interface2 = bridge.members[1] - self.assertEqual("em2", interface2.name) - - def test_from_json_dhcp_with_nic1_nic2(self): - - def dummy_mapped_nics(nic_mapping=None): - return {"nic1": "em1", "nic2": "em2"} - self.stub_out('os_net_config.objects.mapped_nics', dummy_mapped_nics) - - data = """{ -"type": "ovs_bond", -"name": "bond1", -"use_dhcp": true, -"members": [ - { - "type": "interface", - "name": "nic1" - }, - { - "type": "interface", - "name": "nic2" - } -] -} -""" - bridge = objects.object_from_json(json.loads(data)) - self.assertEqual("bond1", bridge.name) - self.assertTrue(bridge.use_dhcp) - interface1 = bridge.members[0] - self.assertEqual("em1", interface1.name) - interface2 = bridge.members[1] - self.assertEqual("em2", interface2.name) - - def _stub_active_nics(self, nics): - def dummy_ordered_active_nics(): - return nics - self.stub_out('os_net_config.utils.ordered_active_nics', - dummy_ordered_active_nics) - - def _stub_available_nics(self, nics): - def dummy_ordered_available_nics(): - return nics - self.stub_out('os_net_config.utils.ordered_available_nics', - dummy_ordered_available_nics) - - -class TestLinuxTeam(base.TestCase): - - def test_from_json_dhcp(self): - data = """{ -"type": "team", -"name": "team1", -"use_dhcp": true, -"members": [ - { "type": "interface", "name": "em1", "primary": true }, - { "type": "interface", "name": "em2" } -] -} -""" - team = objects.object_from_json(json.loads(data)) - self.assertEqual("team1", team.name) - self.assertTrue(team.use_dhcp) - interface1 = team.members[0] - self.assertEqual("em1", interface1.name) - interface2 = team.members[1] - self.assertEqual("em2", interface2.name) - - -class TestLinuxBond(base.TestCase): - - def setUp(self): - super(TestLinuxBond, self).setUp() - rand = str(int(random.random() * 100000)) - common.SRIOV_CONFIG_FILE = '/tmp/sriov_config_' + rand + '.yaml' - - def stub_is_ovs_installed(): - return True - self.stub_out('os_net_config.utils.is_ovs_installed', - stub_is_ovs_installed) - - def tearDown(self): - super(TestLinuxBond, self).tearDown() - if os.path.isfile(common.SRIOV_CONFIG_FILE): - os.remove(common.SRIOV_CONFIG_FILE) - - def test_from_json_dhcp(self): - data = """{ -"type": "linux_bond", -"name": "bond1", -"use_dhcp": true, -"members": [ - { - "type": "interface", - "name": "em1" - }, - { - "type": "interface", - "name": "em2" - } -] -} -""" - bond = objects.object_from_json(json.loads(data)) - self.assertEqual("bond1", bond.name) - self.assertTrue(bond.use_dhcp) - self.assertIsNone(bond.ethtool_opts) - interface1 = bond.members[0] - self.assertEqual("em1", interface1.name) - interface2 = bond.members[1] - self.assertEqual("em2", interface2.name) - - def test_from_json_dhcp_with_nic1_nic2(self): - - def dummy_mapped_nics(nic_mapping=None): - return {"nic1": "em1", "nic2": "em2"} - self.stub_out('os_net_config.objects.mapped_nics', dummy_mapped_nics) - - data = """{ -"type": "linux_bond", -"name": "bond1", -"use_dhcp": true, -"members": [ - { - "type": "interface", - "name": "nic1" - }, - { - "type": "interface", - "name": "nic2" - } -] -} -""" - bond = objects.object_from_json(json.loads(data)) - self.assertEqual("bond1", bond.name) - self.assertTrue(bond.use_dhcp) - interface1 = bond.members[0] - self.assertEqual("em1", interface1.name) - interface2 = bond.members[1] - self.assertEqual("em2", interface2.name) - - def test_linux_bond_with_vf_default(self): - data = """{ -"type": "linux_bond", -"name": "bond1", -"use_dhcp": true, -"members": [{ - "type": "sriov_vf", - "device": "em1", - "vfid": 1, - "vlan_id": 111, - "qos": 1, - "max_tx_rate": 10, - "primary": true - }, - { - "type": "sriov_vf", - "device": "em2", - "vfid": 1, - "vlan_id": 111, - "qos": 1, - "max_tx_rate": 10 -}] -} -""" - vf_final = [{'device_type': 'vf', 'name': 'em1_1', - 'device': {'name': 'em1', 'vfid': 1}, - 'vlan_id': 111, 'qos': 1, - 'min_tx_rate': 0, 'max_tx_rate': 10, - 'pci_address': '0000:79:10.1', - 'spoofcheck': 'off', 'trust': 'on', - 'promisc': 'off'}, - {'device_type': 'vf', 'name': 'em2_1', - 'device': {'name': 'em2', 'vfid': 1}, - 'vlan_id': 111, 'qos': 1, - 'min_tx_rate': 0, 'max_tx_rate': 10, - 'pci_address': '0000:79:10.2', - 'spoofcheck': 'off', 'trust': 'on', - 'promisc': 'off'}] - - def test_get_vf_devname(device, vfid): - return device + '_' + str(vfid) - - def test_get_pci_address(ifname, noop): - if ifname == 'em1_1': - return '0000:79:10.1' - elif ifname == 'em2_1': - return '0000:79:10.2' - - self.stub_out('os_net_config.utils.get_vf_devname', - test_get_vf_devname) - self.stub_out('os_net_config.utils.get_pci_address', - test_get_pci_address) - - bond = objects.object_from_json(json.loads(data)) - self.assertEqual("bond1", bond.name) - self.assertTrue(bond.use_dhcp) - interface1 = bond.members[0] - interface2 = bond.members[1] - self.assertEqual("em1", interface1.device) - self.assertEqual("em2", interface2.device) - - contents = common.get_file_data(common.SRIOV_CONFIG_FILE) - vf_map = yaml.safe_load(contents) if contents else [] - self.assertListEqual(vf_final, vf_map) - - def test_linux_bond_with_vf_param_provided(self): - data = """{ -"type": "linux_bond", -"name": "bond1", -"use_dhcp": true, -"members": [{ - "type": "sriov_vf", - "device": "em1", - "vfid": 1, - "vlan_id": 111, - "qos": 1, - "trust": false, - "spoofcheck": false, - "promisc": false - }, - { - "type": "sriov_vf", - "device": "em2", - "vfid": 1, - "vlan_id": 111, - "qos": 1, - "trust": false, - "spoofcheck": false, - "promisc": false - } -] -} -""" - vf_final = [{'device_type': 'vf', 'name': 'em1_1', - 'device': {'name': 'em1', 'vfid': 1}, - 'vlan_id': 111, 'qos': 1, - 'min_tx_rate': 0, 'max_tx_rate': 0, - 'pci_address': '0000:79:10.1', - 'spoofcheck': 'off', 'trust': 'off', - 'promisc': 'off'}, - {'device_type': 'vf', 'name': 'em2_1', - 'device': {'name': 'em2', 'vfid': 1}, - 'vlan_id': 111, 'qos': 1, - 'min_tx_rate': 0, 'max_tx_rate': 0, - 'pci_address': '0000:79:10.2', - 'spoofcheck': 'off', 'trust': 'off', - 'promisc': 'off'}] - - def test_get_vf_devname(device, vfid): - return device + '_' + str(vfid) - - def test_get_pci_address(ifname, noop): - if ifname == 'em1_1': - return '0000:79:10.1' - elif ifname == 'em2_1': - return '0000:79:10.2' - - self.stub_out('os_net_config.utils.get_vf_devname', - test_get_vf_devname) - self.stub_out('os_net_config.utils.get_pci_address', - test_get_pci_address) - - objects.object_from_json(json.loads(data)) - contents = common.get_file_data(common.SRIOV_CONFIG_FILE) - vf_map = yaml.safe_load(contents) if contents else [] - self.assertListEqual(vf_final, vf_map) - - def test_linux_bond_with_ethtool_opts(self): - data = """{ -"type": "linux_bond", -"name": "bond1", -"use_dhcp": true, -"ethtool_opts": "-K ${DEVICE} tx-gre-csum-segmentation off", -"members": [ - { - "type": "interface", - "name": "em1", - "ethtool_opts": "-K ${DEVICE} tx-gre-csum-segmentation off" - }, - { - "type": "interface", - "name": "em2", - "ethtool_opts": "-K ${DEVICE} tx-gre-csum-segmentation off" - } -] -} -""" - bond = objects.object_from_json(json.loads(data)) - self.assertEqual("bond1", bond.name) - self.assertEqual("-K ${DEVICE} tx-gre-csum-segmentation off", - bond.ethtool_opts) - interface1 = bond.members[0] - interface2 = bond.members[1] - self.assertEqual("em1", interface1.name) - self.assertEqual("em2", interface2.name) - self.assertEqual("-K ${DEVICE} tx-gre-csum-segmentation off", - interface1.ethtool_opts) - self.assertEqual("-K ${DEVICE} tx-gre-csum-segmentation off", - interface2.ethtool_opts) - - -class TestOvsTunnel(base.TestCase): - - def setUp(self): - super(TestOvsTunnel, self).setUp() - - def stub_is_ovs_installed(): - return True - self.stub_out('os_net_config.utils.is_ovs_installed', - stub_is_ovs_installed) - - def test_from_json(self): - data = """{ -"type": "ovs_bridge", -"name": "br-foo", -"members": [{ - "type": "ovs_tunnel", - "name": "tun0", - "tunnel_type": "gre", - "ovs_options": [ - "remote_ip=192.168.1.1" - ], - "ovs_extra": [ - "ovs extra" - ] -}] -} -""" - bridge = objects.object_from_json(json.loads(data)) - self.assertEqual("br-foo", bridge.name) - tun0 = bridge.members[0] - self.assertEqual("tun0", tun0.name) - self.assertFalse(tun0.ovs_port) - self.assertEqual("br-foo", tun0.bridge_name) - self.assertEqual("gre", tun0.tunnel_type) - self.assertEqual( - ["options:remote_ip=192.168.1.1"], - tun0.ovs_options) - self.assertEqual( - ["ovs extra"], - tun0.ovs_extra) - - def test_ovs_extra_formatting(self): - data = """{ -"type": "ovs_bridge", -"name": "br-foo", -"ovs_extra": [ - "set bridge {name} something" -], -"members": [{ - "type": "ovs_tunnel", - "name": "tun0", - "tunnel_type": "gre", - "ovs_options": [ - "remote_ip=192.168.1.1" - ], - "ovs_extra": [ - "ovs extra", - "ovs {name} extra" - ] -}] -} -""" - bridge = objects.object_from_json(json.loads(data)) - self.assertEqual("br-foo", bridge.name) - self.assertEqual(["set bridge br-foo something", - "set bridge br-foo fail_mode=standalone", - "del-controller br-foo"], - bridge.ovs_extra) - tun0 = bridge.members[0] - self.assertEqual("tun0", tun0.name) - self.assertFalse(tun0.ovs_port) - self.assertEqual("br-foo", tun0.bridge_name) - self.assertEqual("gre", tun0.tunnel_type) - self.assertEqual( - ["options:remote_ip=192.168.1.1"], - tun0.ovs_options) - self.assertEqual( - ["ovs extra", "ovs tun0 extra"], - tun0.ovs_extra) - - -class TestOvsPatchPort(base.TestCase): - - def setUp(self): - super(TestOvsPatchPort, self).setUp() - - def stub_is_ovs_installed(): - return True - self.stub_out('os_net_config.utils.is_ovs_installed', - stub_is_ovs_installed) - - def test_from_json(self): - data = """{ -"type": "ovs_patch_port", -"name": "br-pub-patch", -"bridge_name": "br-ex", -"peer": "br-ex-patch" -} -""" - patch_port = objects.object_from_json(json.loads(data)) - self.assertEqual("br-pub-patch", patch_port.name) - self.assertEqual("br-ex", patch_port.bridge_name) - self.assertEqual("br-ex-patch", patch_port.peer) - - def test_from_json_with_extra(self): - data = """{ -"type": "ovs_patch_port", -"name": "br-pub-patch", -"bridge_name": "br-ex", -"peer": "br-ex-patch", -"ovs_extra": [ - "ovs {name} extra" -] -} -""" - patch_port = objects.object_from_json(json.loads(data)) - self.assertEqual(["ovs br-pub-patch extra"], - patch_port.ovs_extra) - self.assertEqual("br-pub-patch", patch_port.name) - self.assertEqual("br-ex", patch_port.bridge_name) - self.assertEqual("br-ex-patch", patch_port.peer) - - -class TestIbInterface(base.TestCase): - - def test_ib_interface_addresses(self): - v4_addr = objects.Address('192.168.1.1/24') - v6_addr = objects.Address('2001:abc:a::/64') - ib_interface = objects.IbInterface('foo', addresses=[v4_addr, v6_addr]) - self.assertEqual("192.168.1.1", ib_interface.v4_addresses()[0].ip) - self.assertEqual("2001:abc:a::", ib_interface.v6_addresses()[0].ip) - - def test_from_json_dhcp(self): - data = '{"type": "ib_interface", "name": "ib0", "use_dhcp": true}' - ib_interface = objects.object_from_json(json.loads(data)) - self.assertEqual("ib0", ib_interface.name) - self.assertIsNone(ib_interface.ethtool_opts) - self.assertTrue(ib_interface.use_dhcp) - - def test_from_json_defroute(self): - data = '{"type": "ib_interface", "name": "ib0", "use_dhcp": true}' - ib_interface1 = objects.object_from_json(json.loads(data)) - data = """{ -"type": "ib_interface", -"name": "ib0", -"use_dhcp": true, -"defroute": false -} -""" - ib_interface2 = objects.object_from_json(json.loads(data)) - self.assertTrue(ib_interface1.defroute) - self.assertFalse(ib_interface2.defroute) - - def test_from_json_ethtool_opts(self): - data = """{ - "type": "ib_interface", - "name": "ib0", - "ethtool_opts": "speed 1000 duplex full" - }""" - ib_ifc = objects.object_from_json(json.loads(data)) - self.assertEqual("speed 1000 duplex full", ib_ifc.ethtool_opts) - - def test_from_json_dhclient_args(self): - data = """{ -"type": "ib_interface", -"name": "ib0", -"use_dhcp": true, -"dhclient_args": "--foobar" -} -""" - ib_interface1 = objects.object_from_json(json.loads(data)) - self.assertEqual("--foobar", ib_interface1.dhclient_args) - - def test_from_json_dns_servers(self): - data = """{ -"type": "ib_interface", -"name": "ib0", -"use_dhcp": true, -"dns_servers": ["1.2.3.4"] -} -""" - ib_interface1 = objects.object_from_json(json.loads(data)) - self.assertEqual(["1.2.3.4"], ib_interface1.dns_servers) - - def test_from_json_dhcp_nic1(self): - def dummy_mapped_nics(nic_mapping=None): - return {"nic1": "ib0"} - self.stub_out('os_net_config.objects.mapped_nics', dummy_mapped_nics) - - data = '{"type": "ib_interface", "name": "nic1", "use_dhcp": true}' - ib_interface = objects.object_from_json(json.loads(data)) - self.assertEqual("ib0", ib_interface.name) - self.assertTrue(ib_interface.use_dhcp) - - def test_from_json_with_addresses(self): - data = """{ -"type": "ib_interface", -"name": "ib0", -"use_dhcp": false, -"mtu": 1501, -"addresses": [{ - "ip_netmask": "192.0.2.1/24" -}], -"routes": [{ - "next_hop": "192.0.2.1", - "ip_netmask": "192.0.2.1/24", - "route_options": "metric 10" -}] -} -""" - ib_interface = objects.object_from_json(json.loads(data)) - self.assertEqual("ib0", ib_interface.name) - self.assertFalse(ib_interface.use_dhcp) - self.assertFalse(ib_interface.use_dhcpv6) - self.assertEqual(1501, ib_interface.mtu) - address1 = ib_interface.v4_addresses()[0] - self.assertEqual("192.0.2.1", address1.ip) - self.assertEqual("255.255.255.0", address1.netmask) - route1 = ib_interface.routes[0] - self.assertEqual("192.0.2.1", route1.next_hop) - self.assertEqual("192.0.2.1/24", route1.ip_netmask) - self.assertEqual("metric 10", route1.route_options) - - -class TestIbChildInterface(base.TestCase): - - def test_ib_child_interface_name(self): - ib_child_interface = objects.IbChildInterface('foo', pkey_id=100) - self.assertEqual("foo.8064", ib_child_interface.name) - self.assertEqual("foo", ib_child_interface.parent) - - def test_ib_child_interface_pkey_id_valid(self): - ib_child_interface = objects.IbChildInterface('foo', pkey_id=100) - self.assertEqual("0x8064", ib_child_interface.pkey_id) - - def test_ib_child_interface_pkey_id_hexa(self): - data = '{"type": "ib_child_interface", ' \ - '"parent": "foo", "pkey_id": "0x64"}' - ib_child_interface = \ - objects.IbChildInterface.from_json(json.loads(data)) - self.assertEqual("0x8064", ib_child_interface.pkey_id) - - def test_ib_child_interface_pkey_id_invalid_base(self): - data = '{"type": "ib_child_interface", ' \ - '"parent": "foo", "pkey_id": "0b01100100"}' - self.assertRaises(objects.InvalidConfigException, - objects.object_from_json, - json.loads(data)) - - def test_ib_child_interface_nm_controlled_true(self): - data = '{"type": "ib_child_interface", ' \ - '"parent": "foo", "pkey_id": 100}' - ib_child_interface = \ - objects.IbChildInterface.from_json(json.loads(data)) - self.assertEqual(True, ib_child_interface.nm_controlled) - - def test_ib_child_interface_pkey_id_zero(self): - data = '{"type": "ib_child_interface", ' \ - '"parent": "foo", "pkey_id": 0}' - self.assertRaises(objects.InvalidConfigException, - objects.object_from_json, - json.loads(data)) - - def test_ib_child_interface_pkey_id_managment(self): - data = '{"type": "ib_child_interface", ' \ - '"parent": "foo", "pkey_id": "0x7fff"}' - self.assertRaises(objects.InvalidConfigException, - objects.object_from_json, - json.loads(data)) - - def test_ib_child_interface_pkey_id_max(self): - data = '{"type": "ib_child_interface", ' \ - '"parent": "foo", "pkey_id": "0x8001"}' - self.assertRaises(objects.InvalidConfigException, - objects.object_from_json, - json.loads(data)) - - -class TestNicMapping(base.TestCase): - - # We want to test the function, not the dummy.. - stub_mapped_nics = False - - def stub_is_ovs_installed(self): - return True - - def tearDown(self): - super(TestNicMapping, self).tearDown() - objects._MAPPED_NICS = None - - def _stub_active_nics(self, nics): - def dummy_ordered_active_nics(): - return nics - self.stub_out('os_net_config.utils.ordered_active_nics', - dummy_ordered_active_nics) - - def _stub_available_nics(self, nics): - def dummy_ordered_available_nics(): - return nics - self.stub_out('os_net_config.utils.ordered_available_nics', - dummy_ordered_available_nics) - - def test_mapped_nics_default(self): - self._stub_active_nics(['em1', 'em2']) - expected = {'nic1': 'em1', 'nic2': 'em2'} - self.assertEqual(expected, objects.mapped_nics()) - - def test_mapped_nics_mapped(self): - self._stub_active_nics(['em1', 'em2']) - self._stub_available_nics(['em1', 'em2']) - mapping = {'nic1': 'em2', 'nic2': 'em1'} - expected = {'nic1': 'em2', 'nic2': 'em1'} - self.assertEqual(expected, objects.mapped_nics(nic_mapping=mapping)) - - def test_mapped_nics_mapped_partial(self): - self._stub_active_nics(['em1', 'em2', 'em3', 'em4']) - self._stub_available_nics(['em1', 'em2', 'em3', 'em4']) - mapping = {'nic1': 'em2', 'nic2': 'em1'} - expected = {'nic1': 'em2', 'nic2': 'em1', 'nic3': 'em3', 'nic4': 'em4'} - self.assertEqual(expected, objects.mapped_nics(nic_mapping=mapping)) - - def test_mapped_nics_mapped_partial_reordered(self): - self._stub_active_nics(['em1', 'em2', 'em3', 'em4']) - self._stub_available_nics(['em1', 'em2', 'em3', 'em4']) - mapping = {'nic1': 'em1', 'nic2': 'em3'} - expected = {'nic1': 'em1', 'nic2': 'em3', 'nic4': 'em4'} - self.assertEqual(expected, objects.mapped_nics(nic_mapping=mapping)) - - def test_mapped_nics_mapped_unnumbered(self): - self._stub_active_nics(['em1', 'em2', 'em3', 'em4']) - self._stub_available_nics(['em1', 'em2', 'em3', 'em4']) - mapping = {'John': 'em1', 'Paul': 'em2', 'George': 'em3'} - expected = {'John': 'em1', 'Paul': 'em2', 'George': 'em3', - 'nic4': 'em4'} - self.assertEqual(expected, objects.mapped_nics(nic_mapping=mapping)) - - def test_mapped_nics_map_error_notactive(self): - self._stub_active_nics(['em2']) - self._stub_available_nics(['em1', 'em2', 'em3']) - mapping = {'nic2': 'em1'} - expected = {'nic1': 'em2', 'nic2': 'em1'} - self.assertEqual(expected, objects.mapped_nics(nic_mapping=mapping)) - - def test_mapped_nics_map_error_duplicate(self): - self._stub_active_nics(['em1', 'em2']) - self._stub_available_nics(['em1', 'em2']) - mapping = {'nic1': 'em1', 'nic2': 'em1'} - err = self.assertRaises(objects.InvalidConfigException, - objects.mapped_nics, nic_mapping=mapping) - expected = 'em1 already mapped, check mapping file for duplicates' - self.assertIn(expected, str(err)) - - def test_mapped_nics_map_invalid_nic(self): - self._stub_active_nics(['em1']) - self._stub_available_nics(['em1', 'em2']) - mapping = {'nic1': 'em1', 'nic2': 'foo'} - expected = {'nic1': 'em1'} - self.assertEqual(expected, objects.mapped_nics(nic_mapping=mapping)) - - def test_mapped_nics_map_mac(self): - def dummy_interface_mac(name): - mac_map = {'em1': '12:34:56:78:9a:bc', - 'em2': '12:34:56:de:f0:12'} - return mac_map[name] - self.stub_out('os_net_config.common.interface_mac', - dummy_interface_mac) - self._stub_active_nics(['em1', 'em2']) - self._stub_available_nics(['em1', 'em2']) - mapping = {'nic1': '12:34:56:de:f0:12', 'nic2': '12:34:56:78:9a:bc'} - expected = {'nic1': 'em2', 'nic2': 'em1'} - self.assertEqual(expected, objects.mapped_nics(nic_mapping=mapping)) - - def test_mapped_nics_map_invalid_mac(self): - def dummy_interface_mac(name): - mac_map = {'em1': '12:34:56:78:9a:bc', - 'em2': '12:34:56:de:f0:12'} - return mac_map[name] - - self.stub_out('os_net_config.common.interface_mac', - dummy_interface_mac) - self._stub_active_nics(['em1', 'em2']) - self._stub_available_nics(['em1', 'em2']) - mapping = {'nic1': '12:34:56:de:f0:12', 'nic2': 'aa:bb:cc:dd:ee:ff'} - expected = {'nic1': 'em2'} - self.assertEqual(expected, objects.mapped_nics(nic_mapping=mapping)) - - def test_mapped_nics_no_active(self): - self._stub_active_nics([]) - expected = {} - # This only emits a warning, so it should still work - self.assertEqual(expected, objects.mapped_nics()) - - def test_mapped_nics_mapping_overlap_real_nic_name(self): - def dummy_is_active_nic(nic): - if nic == 'em1': - return True - elif nic == 'nic1': - return False - - self.stub_out('os_net_config.utils.is_active_nic', dummy_is_active_nic) - self._stub_available_nics(['em1', 'em2']) - mapping = {'nic1': 'em1', 'em1': 'em2'} - err = self.assertRaises(objects.InvalidConfigException, - objects.mapped_nics, nic_mapping=mapping) - expected = 'cannot map em2 to alias em1, alias overlaps' - self.assertIn(expected, str(err)) - - def test_mapped_nics_mapping_inactive_name_as_alias(self): - def dummy_is_active_nic(nic): - return False - - def dummy_is_real_nic(nic): - return True - - self.stub_out('os_net_config.utils.is_active_nic', dummy_is_active_nic) - self.stub_out('os_net_config.utils.is_real_nic', dummy_is_real_nic) - self._stub_active_nics([]) - self._stub_available_nics(['em1', 'em2']) - mapping = {'em2': 'em1', 'nic1': 'em2'} - expected = {'em2': 'em1', 'nic1': 'em2'} - self.assertEqual(expected, objects.mapped_nics(nic_mapping=mapping)) - - # Test that mapping file is passed to interface members from parent object - def _test_mapped_nics_with_parent(self, type, name): - self._stub_available_nics(['foo', 'bar']) - mapping = {"nic1": "foo", "nic2": "bar"} - - data = """{ - "members": [{"type": "interface", "name": "nic1"}, - {"type": "interface", "name": "nic2"}] - } - """ - json_output = json.loads(data) - json_output.update({'type': type}) - json_output.update({'name': name}) - json_output.update({'nic_mapping': mapping}) - obj = objects.object_from_json(json_output) - - self.assertEqual("foo", obj.members[0].name) - self.assertEqual("bar", obj.members[1].name) - - def test_mapped_nics_ovs_bond(self): - self.stub_out('os_net_config.utils.is_ovs_installed', - self.stub_is_ovs_installed) - self._test_mapped_nics_with_parent("ovs_bond", "bond1") - - def test_mapped_nics_linux_bond(self): - self._test_mapped_nics_with_parent("linux_bond", "bond1") - - def test_mapped_nics_ovs_bridge(self): - self.stub_out('os_net_config.utils.is_ovs_installed', - self.stub_is_ovs_installed) - self._test_mapped_nics_with_parent("ovs_bridge", "br-foo") - - def test_mapped_nics_ovs_user_bridge(self): - self.stub_out('os_net_config.utils.is_ovs_installed', - self.stub_is_ovs_installed) - self._test_mapped_nics_with_parent("ovs_user_bridge", "br-foo") - - def test_mapped_nics_linux_bridge(self): - self._test_mapped_nics_with_parent("linux_bridge", "br-foo") - - def test_mapped_nics_ivs_bridge(self): - self._test_mapped_nics_with_parent("ivs_bridge", "br-foo") - - def test_mapped_nics_linux_team(self): - self._test_mapped_nics_with_parent("team", "team-foo") - - def test_mapped_nics_bridge_and_bond(self): - self.stub_out('os_net_config.utils.is_ovs_installed', - self.stub_is_ovs_installed) - - self._stub_available_nics(['foo', 'bar']) - mapping = {"nic1": "foo", "nic2": "bar"} - - data = """{ -"type": "ovs_bridge", -"name": "br-foo", -"members": [ - { - "type": "ovs_bond", - "name": "bond0", - "members": [{"type": "interface", "name": "nic1"}, - {"type": "interface", "name": "nic2"}] - } -] -} -""" - json_output = json.loads(data) - json_output.update({'nic_mapping': mapping}) - obj = objects.object_from_json(json_output) - - interface1 = obj.members[0].members[0] - interface2 = obj.members[0].members[1] - self.assertEqual("foo", interface1.name) - self.assertEqual("bar", interface2.name) - - def test_mapped_nics_ovs_dpdk_bond(self): - self.stub_out('os_net_config.utils.is_ovs_installed', - self.stub_is_ovs_installed) - self._stub_available_nics(['foo', 'bar']) - mapping = {"nic2": "foo", "nic3": "bar"} - - data = """{ -"type": "ovs_dpdk_bond", -"name": "dpdkbond0", -"members": [ - { - "type": "ovs_dpdk_port", - "name": "dpdk0", - "members": [{"type": "interface", "name": "nic2"}] - }, - { - "type": "ovs_dpdk_port", - "name": "dpdk1", - "members": [{"type": "interface", "name": "nic3"}] - } -] -} -""" - json_output = json.loads(data) - json_output.update({'nic_mapping': mapping}) - dpdk_port = objects.object_from_json(json_output) - interface1 = dpdk_port.members[0].members[0] - interface2 = dpdk_port.members[1].members[0] - - self.assertEqual("foo", interface1.name) - self.assertEqual("bar", interface2.name) - - -class TestSriovPF(base.TestCase): - - def test_from_json_numvfs(self): - data = '{"type": "sriov_pf", "name": "em1", "numvfs": 16,' \ - '"use_dhcp": false, "promisc": false}' - pf = objects.object_from_json(json.loads(data)) - self.assertEqual("em1", pf.name) - self.assertEqual(16, pf.numvfs) - self.assertEqual("off", pf.promisc) - self.assertFalse(pf.use_dhcp) - self.assertEqual("legacy", pf.link_mode) - self.assertIsNone(pf.ethtool_opts) - - def test_from_json_numvfs_nic1(self): - def dummy_mapped_nics(nic_mapping=None): - return {"nic1": "em4"} - self.stub_out('os_net_config.objects.mapped_nics', dummy_mapped_nics) - - data = '{"type": "sriov_pf", "name": "nic1", "numvfs": 16,' \ - '"use_dhcp": false, "promisc": true}' - pf = objects.object_from_json(json.loads(data)) - self.assertEqual("em4", pf.name) - self.assertEqual(16, pf.numvfs) - self.assertFalse(pf.use_dhcp) - self.assertEqual('on', pf.promisc) - - def test_from_json_without_promisc(self): - def dummy_mapped_nics(nic_mapping=None): - return {"nic1": "em4"} - self.stub_out('os_net_config.objects.mapped_nics', dummy_mapped_nics) - - data = '{"type": "sriov_pf", "name": "nic1", "numvfs": 16,' \ - '"use_dhcp": false}' - pf = objects.object_from_json(json.loads(data)) - self.assertEqual("em4", pf.name) - self.assertEqual(16, pf.numvfs) - self.assertFalse(pf.use_dhcp) - self.assertEqual('on', pf.promisc) - - def test_from_json_link_mode(self): - data = '{"type": "sriov_pf", "name": "p6p1", "numvfs": 8,' \ - '"use_dhcp": false, "promisc": false, "link_mode":' \ - '"switchdev"}' - pf = objects.object_from_json(json.loads(data)) - self.assertEqual("p6p1", pf.name) - self.assertEqual(8, pf.numvfs) - self.assertEqual("off", pf.promisc) - self.assertFalse(pf.use_dhcp) - self.assertEqual("switchdev", pf.link_mode) - - def test_from_json_link_mode_invalid(self): - data = '{"type": "sriov_pf", "name": "p6p1", "numvfs": 8,' \ - '"use_dhcp": false, "promisc": false, "link_mode":' \ - '"none_switchdev"}' - err = self.assertRaises(objects.InvalidConfigException, - objects.object_from_json, - json.loads(data)) - expected = 'Expecting link_mode to match legacy/switchdev' - self.assertIn(expected, str(err)) - - def test_from_json_vdpa_link_mode_invalid(self): - data = '{"type": "sriov_pf", "name": "p6p1", "numvfs": 8,' \ - '"use_dhcp": false, "promisc": false, "link_mode":' \ - '"none_switchdev", "vdpa": true}' - err = self.assertRaises(objects.InvalidConfigException, - objects.object_from_json, - json.loads(data)) - expected = 'Expecting link_mode to be switchdev when vdpa is enabled' - self.assertIn(expected, str(err)) - - def test_from_json_vdpa_no_numvfs(self): - data = '{"type": "sriov_pf", "name": "p6p1", "numvfs": 0,' \ - '"use_dhcp": false, "promisc": false, "link_mode":' \ - '"switchdev", "vdpa": true}' - err = self.assertRaises(objects.InvalidConfigException, - objects.object_from_json, - json.loads(data)) - expected = 'Expecting to have at least 1 numvfs when vdpa is enabled' - self.assertIn(expected, str(err)) - - def test_from_json_steering_mode_dmfs(self): - data = '{"type": "sriov_pf", "name": "p6p1", "numvfs": 8,' \ - '"use_dhcp": false, "promisc": false, "link_mode":' \ - '"switchdev", "steering_mode": "dmfs"}' - pf = objects.object_from_json(json.loads(data)) - self.assertEqual("p6p1", pf.name) - self.assertEqual(8, pf.numvfs) - self.assertEqual("off", pf.promisc) - self.assertFalse(pf.use_dhcp) - self.assertEqual("switchdev", pf.link_mode) - self.assertEqual("dmfs", pf.steering_mode) - - def test_from_json_steering_mode_smfs(self): - data = '{"type": "sriov_pf", "name": "p6p1", "numvfs": 8,' \ - '"use_dhcp": false, "promisc": false, "link_mode":' \ - '"switchdev", "steering_mode": "smfs"}' - pf = objects.object_from_json(json.loads(data)) - self.assertEqual("p6p1", pf.name) - self.assertEqual(8, pf.numvfs) - self.assertEqual("off", pf.promisc) - self.assertFalse(pf.use_dhcp) - self.assertEqual("switchdev", pf.link_mode) - self.assertEqual("smfs", pf.steering_mode) - - def test_from_json_steering_mode_none(self): - data = '{"type": "sriov_pf", "name": "p6p1", "numvfs": 8,' \ - '"use_dhcp": false, "promisc": false, "link_mode":' \ - '"switchdev"}' - pf = objects.object_from_json(json.loads(data)) - self.assertEqual("p6p1", pf.name) - self.assertEqual(8, pf.numvfs) - self.assertEqual("off", pf.promisc) - self.assertFalse(pf.use_dhcp) - self.assertEqual("switchdev", pf.link_mode) - self.assertIsNone(pf.steering_mode) - - def test_from_json_steering_mode_invalid(self): - data = '{"type": "sriov_pf", "name": "p6p1", "numvfs": 8,' \ - '"use_dhcp": false, "promisc": false, "link_mode":' \ - '"switchdev", "steering_mode": "dmfss"}' - err = self.assertRaises(objects.InvalidConfigException, - objects.object_from_json, - json.loads(data)) - expected = 'Expecting steering_mode to match smfs/dmfs' - self.assertIn(expected, str(err)) - - def test_from_json_ethtool_opts(self): - data = '{"type": "sriov_pf", "name": "em1", "numvfs": 16, ' \ - '"use_dhcp": false, "promisc": false, ' \ - '"ethtool_opts": "speed 1000 duplex full"}' - pf_ifc = objects.object_from_json(json.loads(data)) - self.assertEqual("speed 1000 duplex full", pf_ifc.ethtool_opts) - - -class TestSriovVF(base.TestCase): - - def setUp(self): - super(TestSriovVF, self).setUp() - - def tearDown(self): - super(TestSriovVF, self).tearDown() - - def test_from_json_zero_vfid(self): - def test_get_vf_devname(device, vfid): - return device + '_' + str(vfid) - - def test_get_pci_address(ifname, noop): - return '0000:79:10.2' - - self.stub_out('os_net_config.utils.get_vf_devname', - test_get_vf_devname) - self.stub_out('os_net_config.utils.get_pci_address', - test_get_pci_address) - data = '{"type": "sriov_vf", "device": "em1", "vfid": 0}' - vf = objects.object_from_json(json.loads(data)) - self.assertEqual("em1", vf.device) - self.assertEqual(0, vf.vfid) - self.assertEqual("em1_0", vf.name) - - def test_from_json_invalid_vfid(self): - def test_get_vf_devname(device, vfid): - return device + '_' + str(vfid) - - def test_get_pci_address(ifname, noop): - return '0000:79:10.2' - - self.stub_out('os_net_config.utils.get_vf_devname', - test_get_vf_devname) - self.stub_out('os_net_config.utils.get_pci_address', - test_get_pci_address) - data = '{"type": "sriov_vf", "device": "em1", "vfid": "0"}' - err = self.assertRaises(objects.InvalidConfigException, - objects.object_from_json, - json.loads(data)) - expected = 'SriovVF JSON objects require \'vfid\' to be configured ' \ - 'as %s' % (str(int)) - self.assertIn(expected, str(err)) - - def test_from_json_no_vfid(self): - def test_get_vf_devname(device, vfid): - return device + '_' + str(vfid) - - def test_get_pci_address(ifname, noop): - return '0000:79:10.2' - - self.stub_out('os_net_config.utils.get_vf_devname', - test_get_vf_devname) - self.stub_out('os_net_config.utils.get_pci_address', - test_get_pci_address) - data = '{"type": "sriov_vf", "device": "em1"}' - err = self.assertRaises(objects.InvalidConfigException, - objects.object_from_json, - json.loads(data)) - expected = 'SriovVF JSON objects require \'vfid\' to be configured ' \ - 'as %s' % (str(int)) - self.assertIn(expected, str(err)) - - def test_from_json_vfid(self): - def test_get_vf_devname(device, vfid): - return device + '_' + str(vfid) - - def test_get_pci_address(ifname, noop): - return '0000:79:10.2' - - self.stub_out('os_net_config.utils.get_vf_devname', - test_get_vf_devname) - self.stub_out('os_net_config.utils.get_pci_address', - test_get_pci_address) - data = '{"type": "sriov_vf", "device": "em1", "vfid": 16,' \ - '"use_dhcp": false}' - vf = objects.object_from_json(json.loads(data)) - self.assertEqual("em1", vf.device) - self.assertEqual(16, vf.vfid) - self.assertFalse(vf.use_dhcp) - self.assertEqual("em1_16", vf.name) - - def test_from_json_name_ignored(self): - def test_get_vf_devname(device, vfid): - return device + '_' + str(vfid) - - def test_get_pci_address(ifname, noop): - return '0000:79:10.2' - - self.stub_out('os_net_config.utils.get_vf_devname', - test_get_vf_devname) - self.stub_out('os_net_config.utils.get_pci_address', - test_get_pci_address) - data = '{"type": "sriov_vf", "device": "em1", "vfid": 16,' \ - '"use_dhcp": false, "name": "em1_7"}' - vf = objects.object_from_json(json.loads(data)) - self.assertEqual("em1", vf.device) - self.assertEqual(16, vf.vfid) - self.assertFalse(vf.use_dhcp) - self.assertEqual("em1_16", vf.name) - - def test_from_json_vfid_configs_enabled(self): - def test_get_vf_devname(device, vfid): - return device + '_' + str(vfid) - - def test_get_pci_address(ifname, noop): - return '0000:79:10.2' - - self.stub_out('os_net_config.utils.get_vf_devname', - test_get_vf_devname) - self.stub_out('os_net_config.utils.get_pci_address', - test_get_pci_address) - - data = '{"type": "sriov_vf", "device": "em4", "vfid": 16,' \ - '"use_dhcp": false, "vlan_id": 100, "qos": 2, "trust": true,' \ - '"state": "auto", "spoofcheck": true,' \ - '"macaddr":"AA:BB:CC:DD:EE:FF", "promisc": true}' - vf = objects.object_from_json(json.loads(data)) - self.assertEqual("em4", vf.device) - self.assertEqual(16, vf.vfid) - self.assertFalse(vf.use_dhcp) - self.assertEqual("em4_16", vf.name) - self.assertEqual(100, vf.vlan_id) - self.assertEqual(2, vf.qos) - self.assertEqual("on", vf.spoofcheck) - self.assertEqual("on", vf.trust) - self.assertEqual("auto", vf.state) - self.assertEqual("AA:BB:CC:DD:EE:FF", vf.macaddr) - self.assertEqual("on", vf.promisc) - - def test_from_json_vfid_configs_disabled(self): - def test_get_vf_devname(device, vfid): - return device + '_' + str(vfid) - - def test_get_pci_address(ifname, noop): - return '0000:79:10.2' - - self.stub_out('os_net_config.utils.get_vf_devname', - test_get_vf_devname) - self.stub_out('os_net_config.utils.get_pci_address', - test_get_pci_address) - - data = '{"type": "sriov_vf", "device": "em4", "vfid": 16,' \ - '"use_dhcp": false, "vlan_id": 0, "qos": 0, "trust": false,' \ - '"state": "disable", "spoofcheck": false,' \ - '"promisc": false}' - vf = objects.object_from_json(json.loads(data)) - self.assertEqual("em4", vf.device) - self.assertEqual(16, vf.vfid) - self.assertFalse(vf.use_dhcp) - self.assertEqual("em4_16", vf.name) - self.assertEqual(0, vf.vlan_id) - self.assertEqual(0, vf.qos) - self.assertEqual("off", vf.spoofcheck) - self.assertEqual("off", vf.trust) - self.assertEqual("disable", vf.state) - self.assertEqual(None, vf.macaddr) - self.assertEqual("off", vf.promisc) - - def test_from_json_vfid_invalid_state(self): - def test_get_vf_devname(device, vfid): - return device + '_' + str(vfid) - - def test_get_pci_address(ifname, noop): - return '0000:79:10.2' - - self.stub_out('os_net_config.utils.get_vf_devname', - test_get_vf_devname) - self.stub_out('os_net_config.utils.get_pci_address', - test_get_pci_address) - - data = '{"type": "sriov_vf", "device": "em4", "vfid": 16,' \ - '"use_dhcp": false, "vlan_id": 0, "qos": 0, "trust": false,' \ - '"state": "disabled", ' \ - '"promisc": false}' - err = self.assertRaises(objects.InvalidConfigException, - objects.object_from_json, - json.loads(data)) - expected = 'Expecting state to match auto/enable/disable' - self.assertIn(expected, str(err)) - - def test_from_json_vfid_invalid_qos(self): - def test_get_vf_devname(device, vfid): - return device + '_' + str(vfid) - - def test_get_pci_address(ifname, noop): - return '0000:79:10.2' - - self.stub_out('os_net_config.utils.get_vf_devname', - test_get_vf_devname) - self.stub_out('os_net_config.utils.get_pci_address', - test_get_pci_address) - - data = '{"type": "sriov_vf", "device": "em4", "vfid": 16,' \ - '"use_dhcp": false, "vlan_id": 0, "qos": 10, "trust": false,' \ - '"promisc": false}' - err = self.assertRaises(objects.InvalidConfigException, - objects.object_from_json, - json.loads(data)) - expected = 'Vlan tag not set for QOS - VF: em4:16' - self.assertIn(expected, str(err)) - - def test_from_json_vfid_nic1(self): - def test_get_vf_devname(device, vfid): - return device + '_' + str(vfid) - - def test_get_pci_address(ifname, noop): - return '0000:79:10.2' - - self.stub_out('os_net_config.utils.get_vf_devname', - test_get_vf_devname) - self.stub_out('os_net_config.utils.get_pci_address', - test_get_pci_address) - - def dummy_mapped_nics(nic_mapping=None): - return {"nic1": "em4"} - - self.stub_out('os_net_config.objects.mapped_nics', dummy_mapped_nics) - - data = '{"type": "sriov_vf", "device": "nic1", "vfid": 16,' \ - '"use_dhcp": false}' - vf = objects.object_from_json(json.loads(data)) - self.assertEqual("em4", vf.device) - self.assertEqual(16, vf.vfid) - self.assertFalse(vf.use_dhcp) - self.assertEqual("em4_16", vf.name) - - def test_from_json_pci_address_none(self): - def test_get_vf_devname(device, vfid): - return device + '_' + str(vfid) - - def test_get_pci_address(ifname, noop): - return None - - def test_get_stored_pci_address(ifname, noop): - return '0000:79:10.2' - - self.stub_out('os_net_config.utils.get_vf_devname', - test_get_vf_devname) - self.stub_out('os_net_config.utils.get_pci_address', - test_get_pci_address) - self.stub_out('os_net_config.utils.get_stored_pci_address', - test_get_stored_pci_address) - data = '{"type": "sriov_vf", "device": "em1", "vfid": 16,' \ - '"use_dhcp": false}' - vf = objects.object_from_json(json.loads(data)) - self.assertEqual("em1", vf.device) - self.assertEqual(16, vf.vfid) - self.assertFalse(vf.use_dhcp) - self.assertEqual("em1_16", vf.name) - - -class TestOvsDpdkBond(base.TestCase): - - # We want to test the function, not the dummy.. - stub_mapped_nics = False - - def _stub_active_nics(self, nics): - def dummy_ordered_active_nics(): - return nics - self.stub_out('os_net_config.utils.ordered_active_nics', - dummy_ordered_active_nics) - - def stub_is_ovs_installed(self): - return True - - def test_from_json_dhcp(self): - self.stub_out('os_net_config.utils.is_ovs_installed', - self.stub_is_ovs_installed) - self._stub_active_nics(['eth0', 'eth1', 'eth2']) - data = """{ -"type": "ovs_dpdk_bond", -"name": "dpdkbond0", -"use_dhcp": true, -"members": [ - { - "type": "ovs_dpdk_port", - "name": "dpdk0", - "members": [ - { - "type": "interface", - "name": "nic2" - } - ] - }, - { - "type": "ovs_dpdk_port", - "name": "dpdk1", - "members": [ - { - "type": "interface", - "name": "nic3" - } - ] - } -] -} -""" - bond = objects.object_from_json(json.loads(data)) - self.assertEqual("dpdkbond0", bond.name) - self.assertTrue(bond.use_dhcp) - dpdk_port0 = bond.members[0] - self.assertEqual("dpdk0", dpdk_port0.name) - self.assertEqual("vfio-pci", dpdk_port0.driver) - iface1 = dpdk_port0.members[0] - self.assertEqual("eth1", iface1.name) - dpdk_port1 = bond.members[1] - self.assertEqual("dpdk1", dpdk_port1.name) - self.assertEqual("vfio-pci", dpdk_port1.driver) - iface2 = dpdk_port1.members[0] - self.assertEqual("eth2", iface2.name) - - -class TestVppInterface(base.TestCase): - - def test_vpp_interface_from_json(self): - data = """{ -"type": "vpp_interface", -"name": "em1", -"uio_driver": "uio_pci_generic", -"options": "vlan-strip-offload off" -} -""" - - vpp_interface = objects.object_from_json(json.loads(data)) - self.assertEqual("em1", vpp_interface.name) - self.assertEqual("uio_pci_generic", vpp_interface.uio_driver) - self.assertEqual("vlan-strip-offload off", vpp_interface.options) - - -class TestVppBond(base.TestCase): - - def test_vpp_interface_from_json(self): - data = """{ -"type": "vpp_bond", -"name": "net_bonding0", -"members": [ - { - "type": "vpp_interface", - "name": "eth1" - }, - { - "type": "vpp_interface", - "name": "eth2" - } -], -"bonding_options": "mode=2,xmit_policy=l34" -} -""" - - vpp_bond = objects.object_from_json(json.loads(data)) - self.assertEqual("net_bonding0", vpp_bond.name) - self.assertEqual("mode=2,xmit_policy=l34", vpp_bond.bonding_options) - vpp_int1 = vpp_bond.members[0] - self.assertEqual("eth1", vpp_int1.name) - vpp_int2 = vpp_bond.members[1] - self.assertEqual("eth2", vpp_int2.name) - - def test_invalid_vpp_interface_from_json(self): - data = """{ -"type": "vpp_bond", -"name": "net_bonding0", -"members": [ - { - "type": "vpp_interface", - "name": "eth1" - }, - { - "type": "interface", - "name": "eth2" - } -], -"bonding_options": "mode=2,xmit_policy=l34" -} -""" - - err = self.assertRaises(objects.InvalidConfigException, - objects.object_from_json, - json.loads(data)) - expected = 'Members must be of type vpp_interface' - self.assertIn(expected, str(err)) - - -class TestOvsRequiredObjects(base.TestCase): - - def stub_is_ovs_installed(self): - return False - - def test_ovs_bond(self): - data = """{ - "type": "ovs_bond", - "name": "bond1", - "use_dhcp": true, - "members": [ - { - "type": "interface", - "name": "nic1" - }, - { - "type": "interface", - "name": "nic2" - } - ] - } - """ - - self.stub_out('os_net_config.utils.is_ovs_installed', - self.stub_is_ovs_installed) - err = self.assertRaises(objects.InvalidConfigException, - objects.OvsBond.from_json, - json.loads(data)) - expected = 'OvsBond cannot be created as OpenvSwitch is not installed.' - self.assertIn(expected, str(err)) - - def test_ovs_bridge(self): - data = """{ - "type": "ovs_bridge", - "name": "br-foo", - "use_dhcp": true, - "members": [{ - "type": "interface", - "name": "em1" - }] - } - """ - - self.stub_out('os_net_config.utils.is_ovs_installed', - self.stub_is_ovs_installed) - err = self.assertRaises(objects.InvalidConfigException, - objects.OvsBridge.from_json, - json.loads(data)) - expected = 'OvsBridge cannot be created as OpenvSwitch is not ' \ - 'installed.' - self.assertIn(expected, str(err)) - - def test_dpdk_port(self): - data = """{ - "type": "ovs_dpdk_port", - "name": "dpdk0", - "members": [{"type": "interface", "name": "nic"}] - } - """ - - self.stub_out('os_net_config.utils.is_ovs_installed', - self.stub_is_ovs_installed) - err = self.assertRaises(objects.InvalidConfigException, - objects.OvsDpdkPort.from_json, - json.loads(data)) - expected = 'OvsDpdkPort cannot be created as OpenvSwitch is not ' \ - 'installed.' - self.assertIn(expected, str(err)) - - -class TestLinuxTap(base.TestCase): - - def test_linux_tap_from_json(self): - data = """{ -"type": "linux_tap", -"name": "tap0", -"nm_controlled": false -} -""" - - linux_tap = objects.object_from_json(json.loads(data)) - self.assertEqual("tap0", linux_tap.name) - self.assertEqual(False, linux_tap.nm_controlled) diff --git a/os_net_config/tests/test_os_net_config.py b/os_net_config/tests/test_os_net_config.py deleted file mode 100644 index ad45baac..00000000 --- a/os_net_config/tests/test_os_net_config.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- 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. - -""" -test_os_net_config ----------------------------------- - -Tests for `os_net_config` module. -""" - -from os_net_config.tests import base - - -class TestOs_net_config(base.TestCase): - - def test_something(self): - pass diff --git a/os_net_config/tests/test_sriov_bind_config.py b/os_net_config/tests/test_sriov_bind_config.py deleted file mode 100644 index aad9e605..00000000 --- a/os_net_config/tests/test_sriov_bind_config.py +++ /dev/null @@ -1,53 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2019 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. - -import os -import os.path -import random - - -from os_net_config import sriov_bind_config -from os_net_config.tests import base -from os_net_config import utils - - -class TestSriovBindConfig(base.TestCase): - """Unit tests for methods defined in sriov_bind_config.py""" - - def setUp(self): - super(TestSriovBindConfig, self).setUp() - rand = str(int(random.random() * 100000)) - - sriov_bind_config._SRIOV_BIND_CONFIG_FILE = '/tmp/' + rand +\ - 'sriov_bind_config.yaml' - sriov_bind_config._PCI_DRIVER_BIND_FILE_PATH = '/tmp/' + rand +\ - '%(driver)s/bind' - - def tearDown(self): - super(TestSriovBindConfig, self).tearDown() - if os.path.isfile(sriov_bind_config._SRIOV_BIND_CONFIG_FILE): - os.remove(sriov_bind_config._SRIOV_BIND_CONFIG_FILE) - - def test_bind_vfs(self): - """Test SR-IOV VFs binding""" - vfs_driver = "mlx5_core" - sriov_bind_pcis_map = {vfs_driver: ['0000:03:00.2', '0000:03:00.3']} - os.makedirs(sriov_bind_config._PCI_DRIVER_BIND_FILE_PATH % - {"driver": vfs_driver}) - - utils.write_yaml_config(sriov_bind_config._SRIOV_BIND_CONFIG_FILE, - sriov_bind_pcis_map) - sriov_bind_config.bind_vfs() diff --git a/os_net_config/tests/test_sriov_config.py b/os_net_config/tests/test_sriov_config.py deleted file mode 100644 index 988fc4a4..00000000 --- a/os_net_config/tests/test_sriov_config.py +++ /dev/null @@ -1,628 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2019 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. - -import os -import os.path -import random -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 - - -class TestSriovConfig(base.TestCase): - """Unit tests for methods defined in sriov_config.py""" - - def setUp(self): - super(TestSriovConfig, self).setUp() - rand = str(int(random.random() * 100000)) - - tmpdir = tempfile.mkdtemp() - 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_'\ - 'rules.d_70-os-net-config-sriov.rules' - sriov_config._IFUP_LOCAL_FILE = '/tmp/' + rand + 'sbin_ifup-local' - sriov_config._RESET_SRIOV_RULES_FILE = '/tmp/' + rand + 'etc_udev_'\ - 'rules.d_70-tripleo-reset-sriov.rules' - sriov_config._ALLOCATE_VFS_FILE = '/tmp/' + rand + 'etc_sysconfig_'\ - 'allocate_vfs' - common.SRIOV_CONFIG_FILE = '/tmp/' + rand + 'sriov_config.yaml' - sriov_config._REP_LINK_NAME_FILE = '/tmp/' + rand + 'rep_link.sh' - - def tearDown(self): - super(TestSriovConfig, self).tearDown() - if os.path.isfile(common._LOG_FILE): - os.remove(common._LOG_FILE) - if os.path.isfile(common.SRIOV_CONFIG_FILE): - os.remove(common.SRIOV_CONFIG_FILE) - if os.path.isfile(sriov_config._IFUP_LOCAL_FILE): - os.remove(sriov_config._IFUP_LOCAL_FILE) - 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): - os.remove(sriov_config._ALLOCATE_VFS_FILE) - if os.path.isfile(sriov_config._UDEV_LEGACY_RULE_FILE): - os.remove(sriov_config._UDEV_LEGACY_RULE_FILE) - - def _write_numvfs(self, ifname, numvfs=0): - 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)) - - def _save_action(self, action): - try: - self._action_order.append(action) - except AttributeError: - self._action_order = [action] - - def setUp_udev_stubs(self): - def udev_monitor_setup_stub(): - self._save_action('udev_monitor_setup') - return - self.stub_out('os_net_config.sriov_config.udev_monitor_setup', - udev_monitor_setup_stub) - - def udev_monitor_start_stub(observer): - self._save_action('udev_monitor_start') - return - self.stub_out('os_net_config.sriov_config.udev_monitor_start', - udev_monitor_start_stub) - - def udev_monitor_stop_stub(observer): - self._save_action('udev_monitor_stop') - return - self.stub_out('os_net_config.sriov_config.udev_monitor_stop', - udev_monitor_stop_stub) - - def trigger_udev_rules_stub(): - self._save_action('trigger_udev_rules') - return - self.stub_out('os_net_config.sriov_config.trigger_udev_rules', - trigger_udev_rules_stub) - - def reload_udev_rules_stub(): - self._save_action('reload_udev_rules') - return - self.stub_out('os_net_config.sriov_config.reload_udev_rules', - reload_udev_rules_stub) - - def test_add_udev_rules(self): - """Test Add udev rules - - """ - def get_pf_pci_stub(name): - pci_address = {"p2p1": "0000:01:01.0", - "p2p2": "0000:01:02.0", - "p2p3": "0000:01:03.0"} - return pci_address[name] - self.stub_out('os_net_config.sriov_config.get_pf_pci', - get_pf_pci_stub) - - self.setUp_udev_stubs() - - exp_udev_content = '# This file is autogenerated by os-net-config\n'\ - 'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", '\ - 'KERNELS=="0000:01:01.0", NAME="p2p1"\n' - - sriov_config.add_udev_rule_for_sriov_pf("p2p1") - f = open(sriov_config._UDEV_RULE_FILE, 'r') - self.assertEqual(exp_udev_content, f.read()) - - def test_append_udev_rules(self): - """Test adding udev rules - - """ - def get_pf_pci_stub(name): - pci_address = {"p2p1": "0000:01:01.0", - "p2p2": "0000:01:02.0", - "p2p3": "0000:01:03.0"} - return pci_address[name] - self.stub_out('os_net_config.sriov_config.get_pf_pci', - get_pf_pci_stub) - - self.setUp_udev_stubs() - - exp_udev_content = '# This file is autogenerated by os-net-config\n'\ - 'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", '\ - 'KERNELS=="0000:01:01.0", NAME="p2p1"\n' \ - 'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", '\ - 'KERNELS=="0000:01:02.0", NAME="p2p2"\n' - udev_content = '# This file is autogenerated by os-net-config\n'\ - 'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", '\ - 'KERNELS=="0000:01:01.0", NAME="p2p1"\n' - udev_file = open(sriov_config._UDEV_RULE_FILE, "w") - udev_file.write(udev_content) - udev_file.close() - sriov_config.add_udev_rule_for_sriov_pf("p2p2") - f = open(sriov_config._UDEV_RULE_FILE, 'r') - self.assertEqual(exp_udev_content, f.read()) - - def test_add_legacy_udev_rules(self): - """Test Add udev rules for legacy sriov - - """ - self.setUp_udev_stubs() - - exp_udev_content = '# This file is autogenerated by os-net-config\n'\ - 'KERNEL=="p2p1", RUN+="/bin/os-net-config-sriov -n %k:8"\n' - sriov_config.add_udev_rule_for_legacy_sriov_pf("p2p1", 8) - f = open(sriov_config._UDEV_LEGACY_RULE_FILE, 'r') - self.assertEqual(exp_udev_content, f.read()) - - def test_modify_legacy_udev_rules(self): - """Test modifying udev rules for legacy sriov - - """ - self.setUp_udev_stubs() - - udev_content = '# This file is autogenerated by os-net-config\n'\ - 'KERNEL=="p2p1", RUN+="/bin/os-net-config-sriov -n %k:10"\n'\ - 'KERNEL=="p2p2", RUN+="/bin/os-net-config-sriov -n %k:12"\n' - exp_udev_content = '# This file is autogenerated by os-net-config\n'\ - 'KERNEL=="p2p1", RUN+="/bin/os-net-config-sriov -n %k:8"\n'\ - 'KERNEL=="p2p2", RUN+="/bin/os-net-config-sriov -n %k:12"\n' - udev_file = open(sriov_config._UDEV_LEGACY_RULE_FILE, "w") - udev_file.write(udev_content) - udev_file.close() - sriov_config.add_udev_rule_for_legacy_sriov_pf("p2p1", 8) - f = open(udev_file.name, 'r') - self.assertEqual(exp_udev_content, f.read()) - - def test_same_legacy_udev_rules(self): - """Test without changing udev rules for legacy sriov - - """ - self.setUp_udev_stubs() - - udev_content = '# This file is autogenerated by os-net-config\n'\ - 'KERNEL=="p2p1", RUN+="/bin/os-net-config-sriov -n %k:8"\n'\ - 'KERNEL=="p2p2", RUN+="/bin/os-net-config-sriov -n %k:10"\n' - exp_udev_content = '# This file is autogenerated by os-net-config\n'\ - 'KERNEL=="p2p1", RUN+="/bin/os-net-config-sriov -n %k:8"\n'\ - 'KERNEL=="p2p2", RUN+="/bin/os-net-config-sriov -n %k:10"\n' - udev_file = open(sriov_config._UDEV_LEGACY_RULE_FILE, "w") - udev_file.write(udev_content) - udev_file.close() - sriov_config.add_udev_rule_for_legacy_sriov_pf("p2p2", 10) - f = open(udev_file.name, 'r') - self.assertEqual(exp_udev_content, f.read()) - - def test_append_legacy_udev_rules(self): - """Test appending udev rules for legacy sriov - - """ - self.setUp_udev_stubs() - - udev_content = '# This file is autogenerated by os-net-config\n'\ - 'KERNEL=="p2p1", RUN+="/bin/os-net-config-sriov -n %k:8"\n'\ - 'KERNEL=="p2p2", RUN+="/bin/os-net-config-sriov -n %k:10"\n' - exp_udev_content = '# This file is autogenerated by os-net-config\n'\ - 'KERNEL=="p2p1", RUN+="/bin/os-net-config-sriov -n %k:8"\n'\ - 'KERNEL=="p2p2", RUN+="/bin/os-net-config-sriov -n %k:10"\n' \ - 'KERNEL=="p2p3", RUN+="/bin/os-net-config-sriov -n %k:12"\n' - udev_file = open(sriov_config._UDEV_LEGACY_RULE_FILE, "w") - udev_file.write(udev_content) - udev_file.close() - sriov_config.add_udev_rule_for_legacy_sriov_pf("p2p3", 12) - f = open(udev_file.name, 'r') - self.assertEqual(exp_udev_content, f.read()) - - def setUp_pf_stubs(self, vendor_id="0x8086"): - - run_cmd = [] - - self.setUp_udev_stubs() - - def run_ip_config_cmd_stub(*args, **kwargs): - run_cmd.append(' '.join(args)) - self.stub_out('os_net_config.sriov_config.run_ip_config_cmd', - run_ip_config_cmd_stub) - - def cleanup_puppet_config_stub(): - return - self.stub_out('os_net_config.sriov_config.cleanup_puppet_config', - cleanup_puppet_config_stub) - - def _wait_for_vf_creation_stub(pf_name, numvfs): - self._save_action('_wait_for_vf_creation') - return - self.stub_out('os_net_config.sriov_config._wait_for_vf_creation', - _wait_for_vf_creation_stub) - - def get_vendor_id_stub(ifname): - return vendor_id - self.stub_out('os_net_config.common.get_vendor_id', - get_vendor_id_stub) - - def configure_switchdev_stub(pf_name): - self._save_action('configure_switchdev') - return - self.stub_out('os_net_config.sriov_config.configure_switchdev', - configure_switchdev_stub) - - self.set_numvfs = sriov_config.set_numvfs - self.get_numvfs = sriov_config.get_numvfs - - def get_numvfs_stub(*args): - self._save_action('get_numvfs') - return self.get_numvfs(*args) - self.stub_out('os_net_config.sriov_config.get_numvfs', - get_numvfs_stub) - - def set_numvfs_stub(*args): - self._save_action('set_numvfs') - return self.set_numvfs(*args) - self.stub_out('os_net_config.sriov_config.set_numvfs', - set_numvfs_stub) - - def get_pf_pci_stub(name): - pci_address = {"p2p1": "0000:01:01.0", - "p2p2": "0000:01:02.0", - "p2p3": "0000:01:03.0"} - return pci_address[name] - self.stub_out('os_net_config.sriov_config.get_pf_pci', - get_pf_pci_stub) - - def get_vdpa_vhost_devices_stub(): - self._save_action('get_vdpa_vhost_devices') - return - self.stub_out('os_net_config.sriov_config.get_vdpa_vhost_devices', - get_vdpa_vhost_devices_stub) - - def load_kmods_stub(mods): - return - self.stub_out('os_net_config.sriov_config.load_kmods', - load_kmods_stub) - - def modprobe_stub(*args): - out = """vdpa x - vhost_vdpa x - """ - return out, "hello" - self.stub_out('oslo_concurrency.processutils.execute', - modprobe_stub) - - def reload_udev_rules_stub(): - self._save_action('reload_udev_rules') - return - self.stub_out('os_net_config.sriov_config.reload_udev_rules', - reload_udev_rules_stub) - - def test_list_kmods(self): - self.setUp_pf_stubs() - self.assertEqual([], common.list_kmods(["vhost_vdpa", "vdpa"])) - self.assertEqual(["test"], common.list_kmods(["test", "vdpa"])) - - def test_configure_sriov_pf(self): - """Test the numvfs setting for SR-IOV PF - - Test the udev rules created for legacy mode of SR-IOV PF - """ - - self.setUp_pf_stubs() - - exp_udev_content = '# This file is autogenerated by os-net-config\n'\ - 'KERNEL=="p2p1", RUN+="/bin/os-net-config-sriov -n %k:10"\n'\ - 'KERNEL=="p2p2", RUN+="/bin/os-net-config-sriov -n %k:12"\n' - exp_actions = [ - 'udev_monitor_setup', - 'udev_monitor_start', - 'get_numvfs', - 'reload_udev_rules', - 'set_numvfs', - 'get_numvfs', - '_wait_for_vf_creation', - 'get_numvfs', - 'get_numvfs', - 'reload_udev_rules', - 'set_numvfs', - 'get_numvfs', - '_wait_for_vf_creation', - 'get_numvfs', - 'udev_monitor_stop', - ] - - pf_config = [{"device_type": "pf", "name": "p2p1", "numvfs": 10, - "promisc": "on", "link_mode": "legacy"}, - {"device_type": "pf", "name": "p2p2", "numvfs": 12, - "promisc": "off", "link_mode": "legacy"}] - - for ifname in ['p2p1', 'p2p2']: - self._write_numvfs(ifname) - - self._action_order = [] - utils.write_yaml_config(common.SRIOV_CONFIG_FILE, pf_config) - sriov_config.configure_sriov_pf() - self.assertEqual(exp_actions, self._action_order) - f = open(sriov_config._UDEV_LEGACY_RULE_FILE, 'r') - self.assertEqual(exp_udev_content, f.read()) - self.assertEqual(10, sriov_config.get_numvfs('p2p1')) - self.assertEqual(12, sriov_config.get_numvfs('p2p2')) - - def test_configure_sriov_pf_nicpart(self): - """Test the udev rules created for legacy mode of SR-IOV PF - - In this case, the VF(s) are already bound/attached - """ - - self.setUp_pf_stubs() - - exp_udev_content = '# This file is autogenerated by os-net-config\n'\ - 'KERNEL=="p2p2", RUN+="/bin/os-net-config-sriov -n %k:12"\n' - exp_actions = [ - 'udev_monitor_setup', - 'udev_monitor_start', - 'get_numvfs', - 'set_numvfs', - 'get_numvfs', - '_wait_for_vf_creation', - 'get_numvfs', - 'get_numvfs', - 'reload_udev_rules', - 'set_numvfs', - 'get_numvfs', - '_wait_for_vf_creation', - 'get_numvfs', - 'udev_monitor_stop', - ] - - pf_config = [{"device_type": "pf", "name": "p2p1", "numvfs": 10, - "promisc": "on", "link_mode": "legacy"}, - {"device_type": "pf", "name": "p2p2", "numvfs": 12, - "promisc": "off", "link_mode": "legacy"}, - {"device": {"name": "p2p1", "vfid": 0}, - "device_type": "vf", "name": "p2p1v0", "max_tx_rate": 0, - "min_tx_rate": 0, "pci_address": "0000:18:0a.0", - "trust": "on", "spoofcheck": "off"}] - - for ifname in ['p2p1', 'p2p2']: - self._write_numvfs(ifname) - - self._action_order = [] - utils.write_yaml_config(common.SRIOV_CONFIG_FILE, pf_config) - sriov_config.configure_sriov_pf() - self.assertEqual(exp_actions, self._action_order) - f = open(sriov_config._UDEV_LEGACY_RULE_FILE, 'r') - self.assertEqual(exp_udev_content, f.read()) - self.assertEqual(12, sriov_config.get_numvfs('p2p2')) - - def test_configure_sriov_pf_non_nicpart(self): - """Test the udev rules created for legacy mode of SR-IOV PF - - In this case, the nic partitioned VF(s) are not attached - """ - - self.setUp_pf_stubs() - - exp_udev_content = '# This file is autogenerated by os-net-config\n'\ - 'KERNEL=="p2p1", RUN+="/bin/os-net-config-sriov -n %k:10"\n'\ - 'KERNEL=="p2p2", RUN+="/bin/os-net-config-sriov -n %k:12"\n' - exp_actions = [ - 'udev_monitor_setup', - 'udev_monitor_start', - 'get_numvfs', - 'reload_udev_rules', - 'set_numvfs', - 'get_numvfs', - '_wait_for_vf_creation', - 'get_numvfs', - 'get_numvfs', - 'reload_udev_rules', - 'set_numvfs', - 'get_numvfs', - '_wait_for_vf_creation', - 'get_numvfs', - 'udev_monitor_stop', - ] - - pf_config = [{"device_type": "pf", "name": "p2p1", "numvfs": 10, - "promisc": "on", "link_mode": "legacy"}, - {"device_type": "pf", "name": "p2p2", "numvfs": 12, - "promisc": "off", "link_mode": "legacy"}, - {"device": {"name": "eno3", "vfid": 1}, - "device_type": "vf", "name": "eno3v0", "max_tx_rate": 0, - "min_tx_rate": 0, "pci_address": "0000:18:0e.1", - "trust": "on", "spoofcheck": "off"}] - - for ifname in ['p2p1', 'p2p2']: - self._write_numvfs(ifname) - - self._action_order = [] - utils.write_yaml_config(common.SRIOV_CONFIG_FILE, pf_config) - sriov_config.configure_sriov_pf() - self.assertEqual(exp_actions, self._action_order) - f = open(sriov_config._UDEV_LEGACY_RULE_FILE, 'r') - self.assertEqual(exp_udev_content, f.read()) - self.assertEqual(10, sriov_config.get_numvfs('p2p1')) - self.assertEqual(12, sriov_config.get_numvfs('p2p2')) - - def test_configure_vdpa_pf(self): - """Test the vdpa PF - - """ - - self.setUp_pf_stubs(common.MLNX_VENDOR_ID) - - exp_actions = [ - 'udev_monitor_setup', - 'udev_monitor_start', - 'get_vdpa_vhost_devices', - 'get_numvfs', - 'configure_switchdev', - 'set_numvfs', - 'get_numvfs', - '_wait_for_vf_creation', - 'get_numvfs', - 'reload_udev_rules', - 'reload_udev_rules', - 'reload_udev_rules', - 'reload_udev_rules', - 'get_numvfs', - 'configure_switchdev', - 'set_numvfs', - 'get_numvfs', - '_wait_for_vf_creation', - 'get_numvfs', - 'reload_udev_rules', - 'reload_udev_rules', - 'reload_udev_rules', - 'trigger_udev_rules', - 'udev_monitor_stop', - ] - - pf_config = [{"device_type": "pf", "name": "p2p1", "numvfs": 10, - "vdpa": True, "link_mode": "switchdev"}, - {"device_type": "pf", "name": "p2p2", "numvfs": 12, - "vdpa": True, "link_mode": "switchdev"}] - - for ifname in ['p2p1', 'p2p2']: - self._write_numvfs(ifname) - - self._action_order = [] - utils.write_yaml_config(common.SRIOV_CONFIG_FILE, pf_config) - sriov_config.configure_sriov_pf() - self.assertEqual(exp_actions, self._action_order) - self.assertEqual(10, sriov_config.get_numvfs('p2p1')) - self.assertEqual(12, sriov_config.get_numvfs('p2p2')) - - def test_cleanup_puppet_config_deprecation(self): - """Test the cleanup of puppet-tripleo generated config file. - - Usecase: The ifup-local has the default content generated by - puppet-tripleo - """ - - content = '#!/bin/bash\n'\ - '/etc/sysconfig/allocate_vfs $1' - f = open(sriov_config._RESET_SRIOV_RULES_FILE, "w+") - f.close() - f = open(sriov_config._ALLOCATE_VFS_FILE, "w+") - f.close() - f = open(sriov_config._IFUP_LOCAL_FILE, "w+") - f.write(content) - f.close() - - sriov_config.cleanup_puppet_config() - self.assertEqual(False, - os.path.exists(sriov_config._RESET_SRIOV_RULES_FILE)) - self.assertEqual(False, - os.path.exists(sriov_config._ALLOCATE_VFS_FILE)) - self.assertEqual(False, - os.path.exists(sriov_config._IFUP_LOCAL_FILE)) - - def test_cleanup_puppet_config_new(self): - """Test the cleanup of puppet-tripleo generated config file. - - Usecase: When os-net-config is run on fresh deployments, all these - files will not exist. - """ - - sriov_config.cleanup_puppet_config() - self.assertEqual(False, - os.path.exists(sriov_config._RESET_SRIOV_RULES_FILE)) - self.assertEqual(False, - os.path.exists(sriov_config._ALLOCATE_VFS_FILE)) - self.assertEqual(False, - os.path.exists(sriov_config._IFUP_LOCAL_FILE)) - - def test_cleanup_puppet_config_modified(self): - """Test the cleanup of puppet-tripleo generated config file - - Usecase: When os-net-config is run first time after the deprecation - of NeutronSriovNumVFs and ifup-local has contents other than invoking - allocate_vfs. - """ - - content = '#!/bin/bash\n'\ - '/etc/sysconfig/allocate_vfs $1\n'\ - '/usr/sbin/ifup eth0' - mod_content = '#!/bin/bash\n'\ - '/usr/sbin/ifup eth0' - f = open(sriov_config._IFUP_LOCAL_FILE, "w+") - f.write(content) - f.close() - - sriov_config.cleanup_puppet_config() - self.assertEqual(False, - os.path.exists(sriov_config._RESET_SRIOV_RULES_FILE)) - self.assertEqual(False, - os.path.exists(sriov_config._ALLOCATE_VFS_FILE)) - self.assertEqual(True, - os.path.exists(sriov_config._IFUP_LOCAL_FILE)) - - f = open(sriov_config._IFUP_LOCAL_FILE, "r") - self.assertEqual(mod_content, f.read()) - - def test_numvfs_config(self): - """Test the numvfs config with valid arguments""" - - self._write_numvfs('p2p1') - self.assertEqual(None, sriov_config.main(['ARG0', '-n', 'p2p1:15'])) - self.assertEqual(15, sriov_config.get_numvfs('p2p1')) - - def test_numvfs_invalid_params(self): - """Test the numvfs config with invalid arguments""" - - self._write_numvfs('p2p1') - self.assertEqual(1, sriov_config.main(['ARG0', '-n', 'p2p1:15a'])) - self.assertEqual(0, sriov_config.get_numvfs('p2p1')) - - def test_numvfs_preconfigured(self): - """Test the numvfs config while its already configured""" - - self._write_numvfs('p2p1', 10) - self.assertEqual(None, sriov_config.main(['ARG0', '-n', 'p2p1:15'])) - self.assertEqual(10, sriov_config.get_numvfs('p2p1')) - - def test_configure_sriov_vf(self): - """Test configuration of SR-IOV VF settings""" - - vf_config = [{"device_type": "vf", "device": {"name": "p2p1", - "vfid": 1}, "promisc": "on", "vlan_id": 101, - "qos": 5, "macaddr": "AA:BB:CC:DD:EE:FF", - "spoofcheck": "on", "state": "auto", "trust": "on", - "min_tx_rate": 0, "max_tx_rate": 100, - "name": "p2p1_1"}] - exp_cmds = ["ip link set dev p2p1 vf 1 mac AA:BB:CC:DD:EE:FF", - "ip link set dev p2p1 vf 1 vlan 101 qos 5", - "ip link set dev p2p1 vf 1 min_tx_rate 0", - "ip link set dev p2p1 vf 1 max_tx_rate 100", - "ip link set dev p2p1_1 promisc on", - "ip link set dev p2p1 vf 1 spoofchk on", - "ip link set dev p2p1 vf 1 state auto", - "ip link set dev p2p1 vf 1 trust on"] - run_cmd = [] - - def run_ip_config_cmd_stub(*args, **kwargs): - run_cmd.append(' '.join(args)) - self.stub_out('os_net_config.sriov_config.run_ip_config_cmd', - run_ip_config_cmd_stub) - - utils.write_yaml_config(common.SRIOV_CONFIG_FILE, vf_config) - sriov_config.configure_sriov_vf() - - for cmd in exp_cmds: - self.assertIn(cmd, run_cmd) diff --git a/os_net_config/tests/test_utils.py b/os_net_config/tests/test_utils.py deleted file mode 100644 index b089e35f..00000000 --- a/os_net_config/tests/test_utils.py +++ /dev/null @@ -1,1015 +0,0 @@ -# -*- 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. - -import os -import os.path -import random -import shutil -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 -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 -expansion-rom-version: -bus-info: 0000:00:19.0 -supports-statistics: yes -supports-test: yes -supports-eeprom-access: yes -supports-register-dump: yes -supports-priv-flags: no -''' - -_VPPCTL_OUTPUT = ''' - Name Idx State Counter Count -GigabitEthernet0/9/0 1 down -local0 0 down - -''' - -_VPPBOND_OUTPUT = """ - Name Idx Link Hardware -BondEthernet0 3 up Slave-Idx: 1 2 -TenGigabitEthernet2/0/0 1 slave TenGigabitEthernet2/0/0 -TenGigabitEthernet2/0/1 2 slave TenGigabitEthernet2/0/1 -""" - -_INITIAL_VPP_CONFIG = ''' -unix { - nodaemon - log /tmp/vpp.log - full-coredump -} - - -api-trace { - on -} - -api-segment { - gid vpp -} - -dpdk { -} -''' - -udev_content = '# This file is autogenerated by os-net-config\n'\ - 'KERNEL=="eth1", RUN+="/bin/os-net-config-sriov -n %k:10"\n' \ - 'KERNEL=="eth2", RUN+="/bin/os-net-config-sriov -n %k:10"\n' -UDEV_FILE = '/tmp/70-os-net-config-sriov.' - - -class TestUtils(base.TestCase): - - def setUp(self): - super(TestUtils, self).setUp() - rand = str(int(random.random() * 100000)) - common.DPDK_MAPPING_FILE = '/tmp/dpdk_mapping_' + rand + '.yaml' - common.SRIOV_CONFIG_FILE = '/tmp/sriov_config_' + rand + '.yaml' - common._LOG_FILE = '/tmp/' + rand + 'os_net_config.log' - sriov_config._UDEV_LEGACY_RULE_FILE = UDEV_FILE + rand - - def tearDown(self): - super(TestUtils, self).tearDown() - if os.path.isfile(common.DPDK_MAPPING_FILE): - os.remove(common.DPDK_MAPPING_FILE) - if os.path.isfile(common._LOG_FILE): - os.remove(common._LOG_FILE) - if os.path.isfile(common.SRIOV_CONFIG_FILE): - os.remove(common.SRIOV_CONFIG_FILE) - if os.path.isfile(sriov_config._UDEV_LEGACY_RULE_FILE): - os.remove(sriov_config._UDEV_LEGACY_RULE_FILE) - - def test_ordered_active_nics(self): - - tmpdir = tempfile.mkdtemp() - self.stub_out('os_net_config.common.SYS_CLASS_NET', tmpdir) - - def test_is_available_nic(interface_name, check_active): - return True - self.stub_out('os_net_config.utils._is_available_nic', - test_is_available_nic) - - for nic in ['a1', 'em1', 'em2', 'eth2', 'z1', - 'enp8s0', 'enp10s0', 'enp1s0f0']: - with open(os.path.join(tmpdir, nic), 'w') as f: - f.write(nic) - - nics = utils.ordered_active_nics() - self.assertEqual('em1', nics[0]) - self.assertEqual('em2', nics[1]) - self.assertEqual('eth2', nics[2]) - self.assertEqual('a1', nics[3]) - self.assertEqual('enp1s0f0', nics[4]) - self.assertEqual('enp8s0', nics[5]) - self.assertEqual('enp10s0', nics[6]) - self.assertEqual('z1', nics[7]) - - shutil.rmtree(tmpdir) - - def test_update_sriov_pf_map_new(self): - def get_numvfs_stub(pf_name): - return 0 - self.stub_out('os_net_config.sriov_config.get_numvfs', - get_numvfs_stub) - utils.update_sriov_pf_map('eth1', 10, False) - contents = common.get_file_data(common.SRIOV_CONFIG_FILE) - sriov_pf_map = yaml.safe_load(contents) if contents else [] - self.assertEqual(1, len(sriov_pf_map)) - test_sriov_pf_map = [{'device_type': 'pf', 'link_mode': 'legacy', - 'name': 'eth1', 'numvfs': 10, 'vdpa': False}] - self.assertListEqual(test_sriov_pf_map, sriov_pf_map) - - def test_update_sriov_pf_map_with_same_numvfs(self): - def get_numvfs_stub(pf_name): - return 10 - self.stub_out('os_net_config.sriov_config.get_numvfs', - get_numvfs_stub) - utils.update_sriov_pf_map('eth1', 10, False) - contents = common.get_file_data(common.SRIOV_CONFIG_FILE) - sriov_pf_map = yaml.safe_load(contents) if contents else [] - self.assertEqual(1, len(sriov_pf_map)) - test_sriov_pf_map = [{'device_type': 'pf', 'link_mode': 'legacy', - 'name': 'eth1', 'numvfs': 10, 'vdpa': False}] - self.assertListEqual(test_sriov_pf_map, sriov_pf_map) - - def test_update_sriov_pf_map_with_diff_numvfs(self): - def get_numvfs_stub(pf_name): - return 12 - self.stub_out('os_net_config.sriov_config.get_numvfs', - get_numvfs_stub) - self.assertRaises(sriov_config.SRIOVNumvfsException, - utils.update_sriov_pf_map, 'eth1', 10, False) - - def test_update_sriov_pf_map_new_with_promisc(self): - def get_numvfs_stub(pf_name): - return 0 - self.stub_out('os_net_config.sriov_config.get_numvfs', - get_numvfs_stub) - utils.update_sriov_pf_map('eth1', 10, False, promisc='off') - contents = common.get_file_data(common.SRIOV_CONFIG_FILE) - sriov_pf_map = yaml.safe_load(contents) if contents else [] - self.assertEqual(1, len(sriov_pf_map)) - test_sriov_pf_map = [{'device_type': 'pf', 'link_mode': 'legacy', - 'name': 'eth1', 'numvfs': 10, 'promisc': 'off', - 'vdpa': False}] - self.assertListEqual(test_sriov_pf_map, sriov_pf_map) - - def test_update_sriov_pf_map_new_with_vdpa(self): - def get_numvfs_stub(pf_name): - return 0 - self.stub_out('os_net_config.sriov_config.get_numvfs', - get_numvfs_stub) - utils.update_sriov_pf_map('eth1', 10, False, vdpa=True) - contents = common.get_file_data(common.SRIOV_CONFIG_FILE) - sriov_pf_map = yaml.safe_load(contents) if contents else [] - self.assertEqual(1, len(sriov_pf_map)) - test_sriov_pf_map = [{'device_type': 'pf', 'link_mode': 'legacy', - 'name': 'eth1', 'numvfs': 10, 'vdpa': True}] - self.assertListEqual(test_sriov_pf_map, sriov_pf_map) - - def test_update_sriov_pf_map_exist(self): - def get_numvfs_stub(pf_name): - return 10 - self.stub_out('os_net_config.sriov_config.get_numvfs', - get_numvfs_stub) - pf_initial = [{'device_type': 'pf', 'link_mode': 'legacy', - 'name': 'eth1', 'numvfs': 10}] - utils.write_yaml_config(common.SRIOV_CONFIG_FILE, pf_initial) - self.assertRaises(sriov_config.SRIOVNumvfsException, - utils.update_sriov_pf_map, 'eth1', 20, False) - - def test_update_sriov_pf_map_exist_with_promisc(self): - def get_numvfs_stub(pf_name): - return 10 - self.stub_out('os_net_config.sriov_config.get_numvfs', - get_numvfs_stub) - pf_initial = [{'device_type': 'pf', 'link_mode': 'legacy', - 'name': 'eth1', 'numvfs': 10, 'promisc': 'on', - 'vdpa': False}] - utils.write_yaml_config(common.SRIOV_CONFIG_FILE, pf_initial) - - utils.update_sriov_pf_map('eth1', 10, False, promisc='off') - pf_final = [{'device_type': 'pf', 'link_mode': 'legacy', - 'name': 'eth1', 'numvfs': 10, 'promisc': 'off', - 'vdpa': False}] - contents = common.get_file_data(common.SRIOV_CONFIG_FILE) - - pf_map = yaml.safe_load(contents) if contents else [] - self.assertEqual(1, len(pf_map)) - self.assertListEqual(pf_final, pf_map) - - def test_update_sriov_pf_map_exist_with_vdpa(self): - def get_numvfs_stub(pf_name): - return 10 - self.stub_out('os_net_config.sriov_config.get_numvfs', - get_numvfs_stub) - pf_initial = [{'device_type': 'pf', 'link_mode': 'legacy', - 'name': 'eth1', 'numvfs': 10, 'promisc': 'on', - 'vdpa': False}] - utils.write_yaml_config(common.SRIOV_CONFIG_FILE, pf_initial) - - utils.update_sriov_pf_map('eth1', 10, False, vdpa=True) - pf_final = [{'device_type': 'pf', 'link_mode': 'legacy', - 'name': 'eth1', 'numvfs': 10, 'promisc': 'on', - 'vdpa': True}] - contents = common.get_file_data(common.SRIOV_CONFIG_FILE) - - pf_map = yaml.safe_load(contents) if contents else [] - self.assertEqual(1, len(pf_map)) - self.assertListEqual(pf_final, pf_map) - - def test_update_sriov_pf_map_new_with_lag_candidate(self): - def get_numvfs_stub(pf_name): - return 0 - self.stub_out('os_net_config.sriov_config.get_numvfs', - get_numvfs_stub) - utils.update_sriov_pf_map('eth1', 10, False, lag_candidate=True) - contents = common.get_file_data(common.SRIOV_CONFIG_FILE) - sriov_pf_map = yaml.safe_load(contents) if contents else [] - self.assertEqual(1, len(sriov_pf_map)) - test_sriov_pf_map = [{'device_type': 'pf', 'link_mode': 'legacy', - 'name': 'eth1', 'numvfs': 10, 'vdpa': False, - 'lag_candidate': True}] - self.assertListEqual(test_sriov_pf_map, sriov_pf_map) - - def test_update_sriov_pf_map_exist_with_lag_candidate(self): - def get_numvfs_stub(pf_name): - return 10 - self.stub_out('os_net_config.sriov_config.get_numvfs', - get_numvfs_stub) - pf_initial = [{'device_type': 'pf', 'link_mode': 'legacy', - 'name': 'eth1', 'numvfs': 10, 'promisc': 'on', - 'vdpa': False, 'lag_candidate': False}] - utils.write_yaml_config(common.SRIOV_CONFIG_FILE, pf_initial) - - utils.update_sriov_pf_map('eth1', 10, False, lag_candidate=True) - pf_final = [{'device_type': 'pf', 'link_mode': 'legacy', - 'name': 'eth1', 'numvfs': 10, 'promisc': 'on', - 'vdpa': False, 'lag_candidate': True}] - contents = common.get_file_data(common.SRIOV_CONFIG_FILE) - - pf_map = yaml.safe_load(contents) if contents else [] - self.assertEqual(1, len(pf_map)) - self.assertListEqual(pf_final, pf_map) - - def test_update_sriov_pf_map_exist_with_lag_candidate_not_exist_true( - self): - def get_numvfs_stub(pf_name): - return 10 - self.stub_out('os_net_config.sriov_config.get_numvfs', - get_numvfs_stub) - pf_initial = [{'device_type': 'pf', 'link_mode': 'legacy', - 'name': 'eth1', 'numvfs': 10, 'promisc': 'on', - 'vdpa': False}] - utils.write_yaml_config(common.SRIOV_CONFIG_FILE, pf_initial) - - utils.update_sriov_pf_map('eth1', 10, False, lag_candidate=True) - pf_final = [{'device_type': 'pf', 'link_mode': 'legacy', - 'name': 'eth1', 'numvfs': 10, 'promisc': 'on', - 'vdpa': False, 'lag_candidate': True}] - contents = common.get_file_data(common.SRIOV_CONFIG_FILE) - - pf_map = yaml.safe_load(contents) if contents else [] - self.assertEqual(1, len(pf_map)) - self.assertListEqual(pf_final, pf_map) - - def test_update_sriov_pf_map_exist_with_lag_candidate_not_exist_false( - self): - def get_numvfs_stub(pf_name): - return 10 - self.stub_out('os_net_config.sriov_config.get_numvfs', - get_numvfs_stub) - pf_initial = [{'device_type': 'pf', 'link_mode': 'legacy', - 'name': 'eth1', 'numvfs': 10, 'promisc': 'on', - 'vdpa': False}] - utils.write_yaml_config(common.SRIOV_CONFIG_FILE, pf_initial) - - utils.update_sriov_pf_map('eth1', 10, False, lag_candidate=False) - pf_final = [{'device_type': 'pf', 'link_mode': 'legacy', - 'name': 'eth1', 'numvfs': 10, 'promisc': 'on', - 'vdpa': False, 'lag_candidate': False}] - contents = common.get_file_data(common.SRIOV_CONFIG_FILE) - - pf_map = yaml.safe_load(contents) if contents else [] - self.assertEqual(1, len(pf_map)) - self.assertListEqual(pf_final, pf_map) - - def test_update_sriov_vf_map_minimal_new(self): - utils.update_sriov_vf_map('eth1', 2, 'eth1_2') - contents = common.get_file_data(common.SRIOV_CONFIG_FILE) - sriov_vf_map = yaml.safe_load(contents) if contents else [] - self.assertEqual(1, len(sriov_vf_map)) - test_sriov_vf_map = [{'device_type': 'vf', 'name': 'eth1_2', - 'min_tx_rate': 0, 'max_tx_rate': 0, - 'device': {"name": "eth1", "vfid": 2}}] - self.assertListEqual(test_sriov_vf_map, sriov_vf_map) - - def test_udev_rule_for_sriov_vf(self): - def get_numvfs_stub(pf_name): - return 10 - self.stub_out('os_net_config.sriov_config.get_numvfs', - get_numvfs_stub) - utils.update_sriov_pf_map('eth1', 10, False) - utils.update_sriov_pf_map('eth2', 10, False) - utils.update_sriov_vf_map('eth1', 2, 'eth1_2') - contents = common.get_file_data(common.SRIOV_CONFIG_FILE) - sriov_vf_map = yaml.safe_load(contents) if contents else [] - self.assertEqual(3, len(sriov_vf_map)) - - test_sriov_vf_map = {'device': {'name': 'eth1', 'vfid': 2}, - 'device_type': 'vf', 'max_tx_rate': 0, - 'min_tx_rate': 0, 'name': 'eth1_2'} - udev_file = open(sriov_config._UDEV_LEGACY_RULE_FILE, "w") - udev_file.write(udev_content) - udev_file.close() - - # sriov_config.add_udev_rule_for_legacy_sriov_pf("eth1", 10) - for dev in sriov_vf_map: - if(dev.keys() == test_sriov_vf_map.keys()): - self.assertEqual(test_sriov_vf_map, dev) - - expect = '# This file is autogenerated by os-net-config\n'\ - 'KERNEL=="eth2", RUN+="/bin/os-net-config-sriov -n %k:10"\n' - utils.nicpart_udev_rules_check() - f = open(sriov_config._UDEV_LEGACY_RULE_FILE, 'r') - self.assertEqual(expect, f.read()) - f.close() - - def test_update_sriov_vf_map_complete_new(self): - utils.update_sriov_vf_map('eth1', 2, 'eth1_2', vlan_id=10, qos=5, - spoofcheck="on", trust="on", state="enable", - macaddr="AA:BB:CC:DD:EE:FF", promisc="off", - pci_address="0000:80:00.1", max_tx_rate=10) - contents = common.get_file_data(common.SRIOV_CONFIG_FILE) - sriov_vf_map = yaml.safe_load(contents) if contents else [] - self.assertEqual(1, len(sriov_vf_map)) - test_sriov_vf_map = [{'device_type': 'vf', 'name': 'eth1_2', - 'device': {'name': 'eth1', 'vfid': 2}, - 'vlan_id': 10, 'qos': 5, - 'min_tx_rate': 0, 'max_tx_rate': 10, - 'spoofcheck': 'on', 'trust': 'on', - 'state': 'enable', - 'macaddr': 'AA:BB:CC:DD:EE:FF', - 'promisc': 'off', - 'pci_address': "0000:80:00.1"}] - self.assertListEqual(test_sriov_vf_map, sriov_vf_map) - - def test_update_sriov_vf_map_exist(self): - vf_initial = [{'device_type': 'vf', 'name': 'eth1_2', - 'device': {"name": "eth1", "vfid": 2}}] - utils.write_yaml_config(common.SRIOV_CONFIG_FILE, vf_initial) - - utils.update_sriov_vf_map('eth1', 2, 'eth1_2', vlan_id=10, qos=5, - spoofcheck="on", trust="on", state="enable", - macaddr="AA:BB:CC:DD:EE:FF", promisc="off", - pci_address="0000:80:00.1", max_tx_rate=10) - vf_final = [{'device_type': 'vf', 'name': 'eth1_2', - 'device': {'name': 'eth1', 'vfid': 2}, - 'vlan_id': 10, 'qos': 5, - 'min_tx_rate': 0, 'max_tx_rate': 10, - 'spoofcheck': 'on', 'trust': 'on', - 'state': 'enable', - 'macaddr': 'AA:BB:CC:DD:EE:FF', - 'promisc': 'off', - 'pci_address': '0000:80:00.1'}] - contents = common.get_file_data(common.SRIOV_CONFIG_FILE) - - vf_map = yaml.safe_load(contents) if contents else [] - self.assertEqual(1, len(vf_map)) - self.assertListEqual(vf_final, vf_map) - - def test_update_sriov_vf_map_exist_complete(self): - vf_initial = [{'device_type': 'vf', 'name': 'eth1_2', - 'device': {'name': 'eth1', 'vfid': 2}, - 'vlan_id': 10, 'qos': 5, - 'min_tx_rate': 0, 'max_tx_rate': 00, - 'spoofcheck': 'on', 'trust': 'on', - 'state': 'enable', - 'macaddr': 'AA:BB:CC:DD:EE:FF', - 'promisc': 'off', - 'pci_address': "0000:80:00.1"}] - utils.write_yaml_config(common.SRIOV_CONFIG_FILE, vf_initial) - - utils.update_sriov_vf_map('eth1', 2, 'eth1_2', vlan_id=100, qos=15, - spoofcheck="off", trust="off", state="auto", - macaddr="BB:BB:CC:DD:EE:FF", promisc="on", - pci_address="0000:80:00.1", max_tx_rate=40) - vf_final = [{'device_type': 'vf', 'name': 'eth1_2', - 'device': {'name': 'eth1', 'vfid': 2}, - 'vlan_id': 100, 'qos': 15, - 'min_tx_rate': 0, 'max_tx_rate': 40, - 'spoofcheck': 'off', 'trust': 'off', - 'state': 'auto', - 'macaddr': 'BB:BB:CC:DD:EE:FF', - 'promisc': 'on', - 'pci_address': '0000:80:00.1'}] - contents = common.get_file_data(common.SRIOV_CONFIG_FILE) - - vf_map = yaml.safe_load(contents) if contents else [] - self.assertEqual(1, len(vf_map)) - self.assertListEqual(vf_final, vf_map) - - def test_get_vf_devname_net_dir_not_found(self): - tmpdir = tempfile.mkdtemp() - self.stub_out('os_net_config.common.SYS_CLASS_NET', tmpdir) - - self.assertRaises(utils.SriovVfNotFoundException, - utils.get_vf_devname, "eth1", 1) - shutil.rmtree(tmpdir) - - def test_get_vf_devname_vf_dir_found_in_map(self): - tmpdir = tempfile.mkdtemp() - 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(common.SYS_CLASS_NET, 'eth1/device/virtfn1') - os.makedirs(vf_path) - - self.assertEqual(utils.get_vf_devname("eth1", 1), "eth1_1") - shutil.rmtree(tmpdir) - - def test_get_vf_devname_vf_dir_not_found(self): - tmpdir = tempfile.mkdtemp() - 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(common.SYS_CLASS_NET, 'eth1/device/virtfn1') - os.makedirs(vf_path) - - self.assertRaises(utils.SriovVfNotFoundException, - utils.get_vf_devname, "eth1", 1) - shutil.rmtree(tmpdir) - - def test_get_vf_devname_vf_dir_found(self): - tmpdir = tempfile.mkdtemp() - self.stub_out('os_net_config.common.SYS_CLASS_NET', tmpdir) - - vf_path = os.path.join(common.SYS_CLASS_NET, - 'eth1/device/virtfn1/net/eth1_1') - os.makedirs(vf_path) - - self.assertEqual(utils.get_vf_devname("eth1", 1), "eth1_1") - shutil.rmtree(tmpdir) - - def test_get_pci_address_success(self): - def test_execute(name, dummy1, dummy2=None, dummy3=None): - if 'ethtool' in name: - out = _PCI_OUTPUT - return out, None - self.stub_out('oslo_concurrency.processutils.execute', test_execute) - pci = utils.get_pci_address('nic2', False) - self.assertEqual('0000:00:19.0', pci) - - def test_get_pci_address_exception(self): - def test_execute(name, dummy1, dummy2=None, dummy3=None): - if 'ethtool' in name: - raise processutils.ProcessExecutionError - self.stub_out('oslo_concurrency.processutils.execute', test_execute) - pci = utils.get_pci_address('nic2', False) - self.assertEqual(None, pci) - - def test_get_pci_address_error(self): - def test_execute(name, dummy1, dummy2=None, dummy3=None): - if 'ethtool' in name: - return None, 'Error' - self.stub_out('oslo_concurrency.processutils.execute', test_execute) - pci = utils.get_pci_address('nic2', False) - self.assertEqual(None, pci) - - def test_get_stored_pci_address_success(self): - def test_get_dpdk_map(): - return [{'name': 'eth1', 'pci_address': '0000:00:09.0', - 'mac_address': '01:02:03:04:05:06', - 'driver': 'vfio-pci'}] - - self.stub_out('os_net_config.common.get_dpdk_map', test_get_dpdk_map) - pci = utils.get_stored_pci_address('eth1', False) - self.assertEqual('0000:00:09.0', pci) - - def test_get_stored_pci_address_empty(self): - def test_get_dpdk_map(): - return [] - - self.stub_out('os_net_config.common.get_dpdk_map', test_get_dpdk_map) - pci = utils.get_stored_pci_address('eth1', False) - self.assertEqual(None, pci) - - def test_get_vendor_id_success(self): - mocked_open = mock.mock_open(read_data='0x15b3\n') - 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.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.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 = common.get_device_id('nic2') - self.assertEqual(None, device) - - def test_bind_dpdk_interfaces(self): - def test_execute(name, dummy1, dummy2=None, dummy3=None): - if 'ethtool' in name: - out = _PCI_OUTPUT - return out, None - if 'driverctl' in name: - return None, None - - def test_get_dpdk_mac_address(name): - return '01:02:03:04:05:06' - self.stub_out('oslo_concurrency.processutils.execute', test_execute) - self.stub_out('os_net_config.common._get_dpdk_mac_address', - test_get_dpdk_mac_address) - try: - utils.bind_dpdk_interfaces('nic2', 'vfio-pci', False) - except common.OvsDpdkBindException: - self.fail("Received OvsDpdkBindException unexpectedly") - - def test_bind_dpdk_interfaces_fail(self): - def test_execute(name, dummy1, dummy2=None, dummy3=None): - if 'ethtool' in name: - out = _PCI_OUTPUT - return out, None - if 'driverctl' in name: - return None, 'Error' - - def test_get_dpdk_mac_address(name): - return '01:02:03:04:05:06' - self.stub_out('oslo_concurrency.processutils.execute', test_execute) - self.stub_out('os_net_config.common._get_dpdk_mac_address', - test_get_dpdk_mac_address) - - self.assertRaises(common.OvsDpdkBindException, - utils.bind_dpdk_interfaces, 'eth1', 'vfio-pci', - False) - - def test_bind_dpdk_interfaces_skip_valid_device(self): - def test_execute(name, dummy1, dummy2=None, dummy3=None): - if 'ethtool' in name: - return None, 'Error' - if 'driverctl' in name: - return None, None - - def test_get_dpdk_mac_address(name): - return '01:02:03:04:05:06' - - def test_get_dpdk_map(): - return [{'name': 'eth1', 'pci_address': '0000:00:09.0', - 'mac_address': '01:02:03:04:05:06', - 'driver': 'vfio-pci'}] - - self.stub_out('os_net_config.common.get_dpdk_map', test_get_dpdk_map) - self.stub_out('oslo_concurrency.processutils.execute', test_execute) - self.stub_out('os_net_config.utils_get_dpdk_mac_address', - test_get_dpdk_mac_address) - try: - utils.bind_dpdk_interfaces('eth1', 'vfio-pci', False) - except common.OvsDpdkBindException: - self.fail("Received OvsDpdkBindException unexpectedly") - - def test_bind_dpdk_interfaces_fail_invalid_device(self): - def test_execute(name, dummy1, dummy2=None, dummy3=None): - if 'ethtool' in name: - return None, 'Error' - if 'driverctl' in name: - return None, None - - def test_get_dpdk_mac_address(name): - return '01:02:03:04:05:06' - - def test_get_dpdk_map(): - return [{'name': 'eth1', 'pci_address': '0000:00:09.0', - 'mac_address': '01:02:03:04:05:06', - 'driver': 'vfio-pci'}] - - self.stub_out('os_net_config.common.get_dpdk_map', - test_get_dpdk_map) - self.stub_out('oslo_concurrency.processutils.execute', - test_execute) - self.stub_out('os_net_config.utils._get_dpdk_mac_address', - test_get_dpdk_mac_address) - - self.assertRaises(common.OvsDpdkBindException, - utils.bind_dpdk_interfaces, 'eth2', 'vfio-pci', - False) - - def test_bind_dpdk_interfaces_same_driver(self): - mocked_open = mock.mock_open(read_data='DRIVER=vfio-pci\n') - self.stub_out('os_net_config.utils.open', mocked_open) - mocked_logger = mock.Mock() - self.stub_out('os_net_config.utils.logger.info', mocked_logger) - try: - utils.bind_dpdk_interfaces('eth1', 'vfio-pci', False) - except common.OvsDpdkBindException: - self.fail("Received OvsDpdkBindException unexpectedly") - msg = "Driver (vfio-pci) is already bound to the device (eth1)" - mocked_logger.assert_called_with(msg) - - def test_get_interface_driver(self): - mocked_open = mock.mock_open(read_data='DRIVER=vfio-pci\n') - self.stub_out('os_net_config.utils.open', mocked_open) - driver = utils.get_interface_driver('eth1') - self.assertEqual(driver, 'vfio-pci') - - def test_get_interface_driver_fail_none(self): - mocked_open = mock.mock_open(read_data='') - self.stub_out('os_net_config.utils.open', mocked_open) - driver = utils.get_interface_driver('eth1') - self.assertFalse(driver) - - def test_get_interface_driver_fail_empty(self): - mocked_open = mock.mock_open(read_data='DRIVER\n') - self.stub_out('os_net_config.utils.open', mocked_open) - driver = utils.get_interface_driver('eth1') - self.assertFalse(driver) - - def test__update_dpdk_map_new(self): - utils._update_dpdk_map('eth1', '0000:03:00.0', '01:02:03:04:05:06', - 'vfio-pci') - contents = common.get_file_data(common.DPDK_MAPPING_FILE) - - dpdk_map = yaml.safe_load(contents) if contents else [] - self.assertEqual(1, len(dpdk_map)) - dpdk_test = [{'name': 'eth1', 'pci_address': '0000:03:00.0', - 'mac_address': '01:02:03:04:05:06', - 'driver': 'vfio-pci'}] - self.assertListEqual(dpdk_test, dpdk_map) - - def test_update_dpdk_map_exist(self): - dpdk_test = [{'name': 'eth1', 'pci_address': '0000:03:00.0', - 'mac_address': '01:02:03:04:05:06', - 'driver': 'vfio-pci'}] - utils.write_yaml_config(common.DPDK_MAPPING_FILE, dpdk_test) - - utils._update_dpdk_map('eth1', '0000:03:00.0', '01:02:03:04:05:06', - 'vfio-pci') - contents = common.get_file_data(common.DPDK_MAPPING_FILE) - - dpdk_map = yaml.safe_load(contents) if contents else [] - self.assertEqual(1, len(dpdk_map)) - self.assertListEqual(dpdk_test, dpdk_map) - - def test_update_dpdk_map_value_change(self): - dpdk_test = [{'name': 'eth1', 'pci_address': '0000:03:00.0', - 'driver': 'vfio-pci'}] - utils.write_yaml_config(common.DPDK_MAPPING_FILE, dpdk_test) - - dpdk_test = [{'name': 'eth1', 'pci_address': '0000:03:00.0', - 'mac_address': '01:02:03:04:05:06', - 'driver': 'vfio-pci'}] - utils._update_dpdk_map('eth1', '0000:03:00.0', '01:02:03:04:05:06', - 'vfio-pci') - try: - contents = common.get_file_data(common.DPDK_MAPPING_FILE) - except IOError: - pass - - dpdk_map = yaml.safe_load(contents) if contents else [] - self.assertEqual(1, len(dpdk_map)) - self.assertListEqual(dpdk_test, dpdk_map) - - def test_ordered_active_nics_with_dpdk_mapping(self): - - tmpdir = tempfile.mkdtemp() - self.stub_out('os_net_config.common.SYS_CLASS_NET', tmpdir) - tmp_pci_dir = tempfile.mkdtemp() - self.stub_out('os_net_config.common._SYS_BUS_PCI_DEV', tmp_pci_dir) - physfn_path = common._SYS_BUS_PCI_DEV + '/0000:05:01.1/physfn' - os.makedirs(physfn_path) - - def test_is_available_nic(interface_name, check_active): - return True - self.stub_out('os_net_config.utils._is_available_nic', - test_is_available_nic) - - for nic in ['a1', 'em1', 'em2', 'eth2', 'z1', - 'enp8s0', 'enp10s0', 'enp1s0f0']: - with open(os.path.join(tmpdir, nic), 'w') as f: - f.write(nic) - - utils._update_dpdk_map('eth1', '0000:03:00.0', '01:02:03:04:05:06', - 'vfio-pci') - utils._update_dpdk_map('p3p1', '0000:04:00.0', '01:02:03:04:05:07', - 'igb_uio') - utils._update_dpdk_map('p3p0_0', '0000:05:01.1', 'AA:02:03:04:05:FF', - 'vfio-pci') - - nics = utils.ordered_active_nics() - - self.assertEqual('em1', nics[0]) - self.assertEqual('em2', nics[1]) - self.assertEqual('eth1', nics[2]) # DPDK bound nic - self.assertEqual('eth2', nics[3]) - self.assertEqual('a1', nics[4]) - self.assertEqual('enp1s0f0', nics[5]) - self.assertEqual('enp8s0', nics[6]) - self.assertEqual('enp10s0', nics[7]) - self.assertEqual('p3p1', nics[8]) # DPDK bound nic - self.assertEqual('z1', nics[9]) - - shutil.rmtree(tmpdir) - shutil.rmtree(tmp_pci_dir) - - def test_ordered_active_nics_with_dpdk_mapping_of_vf(self): - tmpdir = tempfile.mkdtemp() - self.stub_out('os_net_config.common.SYS_CLASS_NET', tmpdir) - tmp_pci_dir = tempfile.mkdtemp() - self.stub_out('os_net_config.common._SYS_BUS_PCI_DEV', tmp_pci_dir) - physfn_path = common._SYS_BUS_PCI_DEV + '/0000:05:01.1/physfn' - os.makedirs(physfn_path) - - def test_is_available_nic(interface_name, check_active): - return True - self.stub_out('os_net_config.utils._is_available_nic', - test_is_available_nic) - - utils._update_dpdk_map('eth2_0', '0000:06:01.1', 'AA:02:03:04:05:FE', - 'vfio-pci') - utils.update_sriov_vf_map('eth2', 0, 'eth2_0') - - nics = utils.ordered_active_nics() - - self.assertEqual(len(nics), 0) - - shutil.rmtree(tmpdir) - shutil.rmtree(tmp_pci_dir) - - def test_interface_mac_raises(self): - self.assertRaises(IOError, common.interface_mac, 'ens20f2p3') - - def test_get_dpdk_devargs_mlnx(self): - def test_execute(name, dummy1, dummy2=None, dummy3=None): - if 'ethtool' in name: - out = _PCI_OUTPUT - return out, None - - def test_get_stored_pci_address(ifname, noop): - return "0000:00:07.0" - - self.stub_out('oslo_concurrency.processutils.execute', test_execute) - 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.common.SYS_CLASS_NET', tmpdir) - nic = 'p4p1' - nic_path = os.path.join(tmpdir, nic) - os.makedirs(nic_path) - os.makedirs(os.path.join(nic_path, 'device')) - # Testing standard Mellanox Connect-X cards - with open(os.path.join(nic_path, 'operstate'), 'w') as f: - f.write('up') - with open(os.path.join(nic_path, 'address'), 'w') as f: - f.write('00:0f:21:69:39:14') - with open(os.path.join(nic_path, 'device', 'vendor'), 'w') as f: - f.write('0x15b3') - self.assertEqual(utils.get_dpdk_devargs(nic, False), - '0000:00:19.0') - # Testing VFs of Mellanox Connect-X cards - os.makedirs(os.path.join(nic_path, 'device', 'physfn')) - self.assertEqual(utils.get_dpdk_devargs(nic, False), - '0000:00:19.0') - - # Check if devargs is derived, when the operstate is down - os.rmdir(os.path.join(nic_path, 'device', 'physfn')) - with open(os.path.join(nic_path, 'operstate'), 'w') as f: - f.write('down') - self.assertEqual(utils.get_dpdk_devargs(nic, False), - '0000:00:19.0') - - # now testing the Mellanox CX3 - with open(os.path.join(nic_path, 'device', 'device'), 'w') as f: - f.write('0x1007') - self.assertEqual(utils.get_dpdk_devargs(nic, False), - 'class=eth,mac=00:0f:21:69:39:14') - with open(os.path.join(nic_path, 'device', 'vendor'), 'w') as f: - f.write('0x15b4') - self.assertEqual(utils.get_dpdk_devargs(nic, False), - '0000:00:07.0') - shutil.rmtree(tmpdir) - - def test_is_active_nic_for_sriov_vf(self): - - tmpdir = tempfile.mkdtemp() - self.stub_out('os_net_config.common.SYS_CLASS_NET', tmpdir) - - # SR-IOV PF = ens802f0 - # SR-IOV VF = enp129s2 - for nic in ['ens802f0', 'enp129s2']: - nic_path = os.path.join(tmpdir, nic) - os.makedirs(nic_path) - os.makedirs(os.path.join(nic_path, 'device')) - with open(os.path.join(nic_path, 'operstate'), 'w') as f: - f.write('up') - with open(os.path.join(nic_path, 'address'), 'w') as f: - f.write('1.2.3.4') - - nic_path = os.path.join(tmpdir, 'enp129s2', 'device', 'physfn') - os.makedirs(nic_path) - - self.assertEqual(utils.is_active_nic('ens802f0'), True) - self.assertEqual(utils.is_active_nic('enp129s2'), False) - - shutil.rmtree(tmpdir) - - def test_get_vpp_interface(self): - def test_execute(name, *args, **kwargs): - if 'systemctl' in name: - return None, None - if 'vppctl' in name: - return _VPPCTL_OUTPUT, None - - self.stub_out('oslo_concurrency.processutils.execute', - test_execute) - - int_info = utils._get_vpp_interface('0000:00:09.0') - self.assertIsNotNone(int_info) - self.assertEqual('GigabitEthernet0/9/0', int_info['name']) - self.assertEqual('1', int_info['index']) - self.assertIsNone(utils._get_vpp_interface(None)) - self.assertIsNone(utils._get_vpp_interface('0000:01:09.0')) - self.assertRaises(utils.VppException, - utils._get_vpp_interface, '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('0000:00:09.0', 2, 1)) - self.assertEqual(4, mock_execute.call_count) - - def test_get_vpp_bond(self): - def test_execute(name, *args, **kwargs): - if 'systemctl' in name: - return None, None - if 'vppctl' in name: - return _VPPBOND_OUTPUT, None - - self.stub_out('oslo_concurrency.processutils.execute', test_execute) - bond_info = utils._get_vpp_bond(['1', '2']) - self.assertIsNotNone(bond_info) - self.assertEqual('BondEthernet0', bond_info['name']) - self.assertEqual('3', bond_info['index']) - self.assertIsNone(utils._get_vpp_bond(['1'])) - self.assertIsNone(utils._get_vpp_bond(['1', '2', '3'])) - self.assertIsNone(utils._get_vpp_bond([])) - - def test_generate_vpp_config(self): - tmpdir = tempfile.mkdtemp() - config_path = os.path.join(tmpdir, 'startup.conf') - with open(config_path, 'w') as f: - f.write(_INITIAL_VPP_CONFIG) - vpp_exec_path = os.path.join(tmpdir, 'vpp-exec') - utils._VPP_EXEC_FILE = vpp_exec_path - - int1 = objects.VppInterface('em1', options="vlan-strip-offload off") - int1.pci_dev = '0000:00:09.0' - int2 = objects.VppInterface('em2') - int2.pci_dev = '0000:00:09.1' - interfaces = [int1, int2] - bonds = [] - expected_config = ''' -unix { - exec %s - nodaemon - log /tmp/vpp.log - full-coredump -} - - -api-trace { - on -} - -api-segment { - gid vpp -} - -dpdk { - dev 0000:00:09.1 - uio-driver vfio-pci - dev 0000:00:09.0 {vlan-strip-offload off} - -} -''' % vpp_exec_path - self.assertEqual(expected_config, - utils.generate_vpp_config(config_path, interfaces, - bonds)) - - bonds = [objects.VppBond('net_bonding0', members=interfaces, - bonding_options='mode=2,xmit_policy=l3')] - expected_config = ''' -unix { - exec %s - nodaemon - log /tmp/vpp.log - full-coredump -} - - -api-trace { - on -} - -api-segment { - gid vpp -} - -dpdk { - vdev net_bonding0,slave=0000:00:09.0,slave=0000:00:09.1,mode=2,xmit_policy=l3 - dev 0000:00:09.1 - uio-driver vfio-pci - dev 0000:00:09.0 {vlan-strip-offload off} - -} -''' % vpp_exec_path - self.assertEqual(expected_config, - utils.generate_vpp_config(config_path, interfaces, - bonds)) - - def test_update_vpp_mapping(self): - tmpdir = tempfile.mkdtemp() - vpp_exec_path = os.path.join(tmpdir, 'vpp-exec') - utils._VPP_EXEC_FILE = vpp_exec_path - - def test_get_dpdk_map(): - return [{'name': 'eth1', 'pci_address': '0000:00:09.0', - 'mac_address': '01:02:03:04:05:06', - 'driver': 'vfio-pci'}] - - self.stub_out('os_net_config.common.get_dpdk_map', test_get_dpdk_map) - - def test_execute(name, *args, **kwargs): - return None, None - self.stub_out('oslo_concurrency.processutils.execute', test_execute) - - def test_get_vpp_interface(pci_dev, tries, timeout): - return {'name': 'GigabitEthernet0/9/0', 'index': '1'} - - self.stub_out('os_net_config.utils._get_vpp_interface', - test_get_vpp_interface) - - int1 = objects.VppInterface('eth1', options="vlan-strip-offload off") - int1.pci_dev = '0000:00:09.0' - int1.hwaddr = '01:02:03:04:05:06' - int2 = objects.VppInterface('eth2') - int2.pci_dev = '0000:00:09.1' - int2.hwaddr = '01:02:03:04:05:07' - interfaces = [int1, int2] - - utils.update_vpp_mapping(interfaces, []) - - contents = common.get_file_data(common.DPDK_MAPPING_FILE) - - dpdk_test = [{'name': 'eth1', 'pci_address': '0000:00:09.0', - 'mac_address': '01:02:03:04:05:06', - 'driver': 'vfio-pci'}, - {'name': 'eth2', 'pci_address': '0000:00:09.1', - 'mac_address': '01:02:03:04:05:07', - 'driver': 'vfio-pci'}] - dpdk_map = yaml.safe_load(contents) if contents else [] - self.assertEqual(2, len(dpdk_map)) - self.assertListEqual(dpdk_test, dpdk_map) diff --git a/os_net_config/tests/test_validator.py b/os_net_config/tests/test_validator.py deleted file mode 100644 index 81131b24..00000000 --- a/os_net_config/tests/test_validator.py +++ /dev/null @@ -1,463 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2017 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. - -import glob -import jsonschema -import os.path -import yaml - -from os_net_config.tests import base -from os_net_config import validator - - -REALPATH = os.path.dirname(os.path.realpath(__file__)) -SAMPLE_BASE = os.path.join(REALPATH, '../../', 'etc', - 'os-net-config', 'samples') - - -class TestSchemaValidation(base.TestCase): - - def test_schema_is_valid(self): - schema = validator.get_os_net_config_schema() - jsonschema.Draft4Validator.check_schema(schema) - - def test__validate_config(self): - schema = {"type": "string"} - errors = validator._validate_config(42, "foo", schema, False) - self.assertEqual(len(errors), 1) - errors = validator._validate_config("42", "foo", schema, False) - self.assertEqual(len(errors), 0) - - def test_consistent_error_messages_type(self): - error = jsonschema.ValidationError( - "%r is not of type %r" % (u'name', u'string'), validator=u'type', - validator_value=u'string', instance=u'name') - msg = validator._get_consistent_error_message(error) - self.assertEqual(msg, "'name' is not of type 'string'") - - def test_consistent_error_messages_oneOf(self): - error = jsonschema.ValidationError( - "%r is not one of %r" % (u'type', [u'vlan', u'interface']), - validator=u'enum', validator_value=[u'vlan', u'interface'], - instance=u'type') - msg = validator._get_consistent_error_message(error) - self.assertEqual(msg, "'type' is not one of ['vlan','interface']") - - def test_consistent_error_messages_required(self): - error = jsonschema.ValidationError( - "%r is a required property" % u'name', validator=u'required') - msg = validator._get_consistent_error_message(error) - self.assertEqual(msg, "'name' is a required property") - error = jsonschema.ValidationError( - "u'name' is a required property", validator=u'required') - msg = validator._get_consistent_error_message(error) - self.assertEqual(msg, "'name' is a required property") - - def test_pretty_print_schema_path(self): - schema = validator.get_os_net_config_schema() - path = ['items', 'oneOf', 0, 'properties', 'name'] - path_string = validator._pretty_print_schema_path(path, schema) - self.assertEqual(path_string, "items/oneOf/interface/name") - - def test_find_type_in_list_of_references(self): - schemas = [ - {'$ref': '#/definitions/vlan'}, - {'properties': {'type': 'interface'}}, - None - ] - result = validator._find_type_in_schema_list(schemas, 'vlan') - self.assertEqual(result, (True, 0)) - result = validator._find_type_in_schema_list(schemas, 'interface') - self.assertEqual(result, (True, 1)) - result = validator._find_type_in_schema_list(schemas, 'ovs_bridge') - self.assertEqual(result, (False, 0)) - - def test_missing_required_property(self): - ifaces = [{"type": "interface"}] - errors = validator.validate_config(ifaces) - self.assertEqual(len(errors), 1) - self.assertIn("'name' is a required property", errors[0]) - - -class TestBaseTypes(base.TestCase): - - def test_param(self): - schema = validator.get_schema_for_defined_type("bool_or_param") - v = jsonschema.Draft4Validator(schema) - self.assertTrue(v.is_valid({"get_param": "foo"})) - self.assertTrue(v.is_valid({"get_input": "bar"})) - self.assertFalse(v.is_valid([])) - self.assertFalse(v.is_valid({})) - self.assertFalse(v.is_valid(None)) - self.assertFalse(v.is_valid("foo")) - - def test_bool_or_param(self): - schema = validator.get_schema_for_defined_type("bool_or_param") - v = jsonschema.Draft4Validator(schema) - self.assertTrue(v.is_valid(True)) - self.assertTrue(v.is_valid(False)) - self.assertTrue(v.is_valid("TRUE")) - self.assertTrue(v.is_valid("true")) - self.assertTrue(v.is_valid("yes")) - self.assertTrue(v.is_valid("1")) - self.assertTrue(v.is_valid("on")) - self.assertTrue(v.is_valid("false")) - self.assertTrue(v.is_valid("FALSE")) - self.assertTrue(v.is_valid("off")) - self.assertTrue(v.is_valid("no")) - self.assertTrue(v.is_valid("0")) - self.assertFalse(v.is_valid([])) - self.assertFalse(v.is_valid({})) - self.assertFalse(v.is_valid(None)) - self.assertFalse(v.is_valid("falsch")) - - def test_ip_address_string(self): - schema = validator.get_schema_for_defined_type("ip_address_string") - v = jsonschema.Draft4Validator(schema) - self.assertTrue(v.is_valid("0.0.0.0")) - self.assertTrue(v.is_valid("192.168.0.1")) - self.assertTrue(v.is_valid("::")) - self.assertTrue(v.is_valid("fe80::")) - self.assertTrue(v.is_valid("1:1:1::")) - self.assertFalse(v.is_valid("192.168.0.1/24")) - - def test_ip_cidr_string(self): - schema = validator.get_schema_for_defined_type("ip_cidr_string") - v = jsonschema.Draft4Validator(schema) - self.assertTrue(v.is_valid("0.0.0.0/0")) - self.assertTrue(v.is_valid("192.168.0.1/24")) - self.assertTrue(v.is_valid("::/0")) - self.assertTrue(v.is_valid("::1/128")) - self.assertTrue(v.is_valid("fe80::1/64")) - self.assertFalse(v.is_valid("193.168.0.1")) - - def test_domain_name_string(self): - schema = validator.get_schema_for_defined_type("domain_name_string") - v = jsonschema.Draft4Validator(schema) - self.assertTrue(v.is_valid('localdomain')) - self.assertTrue(v.is_valid('openstack.local')) - self.assertTrue(v.is_valid('999.local')) - self.assertTrue(v.is_valid('_foo.bar')) - self.assertTrue(v.is_valid('_foo.bar.domain')) - self.assertTrue(v.is_valid('trailing.dot.domain.')) - self.assertTrue(v.is_valid('.')) - self.assertFalse(v.is_valid('.com')) - self.assertFalse(v.is_valid('..')) - self.assertFalse(v.is_valid('foo..bar')) - # Label too long - domain = ('123456789-123456789-123456789-123456789-123456789-' - '123456789-1234.com') - self.assertFalse(v.is_valid(domain)) - domain = ('123456789-123456789-123456789-123456789-123456789-' - '123456789-12345678') - self.assertFalse(v.is_valid(domain)) - domain = ('123456789.123456789.123456789.123456789.123456789.' - '123456789.123456789.123456789.123456789.123456789.' - '123456789.123456789.123456789.123456789.123456789.' - '123456789.123456789.123456789.123456789.123456789.' - '123456789.123456789.123456789.123456789.123456789.' - 'aa.com') - self.assertEqual(len(domain), 256) - self.assertFalse(v.is_valid(domain)) - - -class TestDerivedTypes(base.TestCase): - - def test_address(self): - schema = validator.get_schema_for_defined_type("address") - v = jsonschema.Draft4Validator(schema) - data = {"ip_netmask": "127.0.0.1/32"} - self.assertTrue(v.is_valid(data)) - data = {"ip_netmask": "127.0.0.1"} - self.assertFalse(v.is_valid(data)) - data = {"ip_netmask": None} - self.assertFalse(v.is_valid(data)) - data = {"ip_netmask": "127.0.0.1/32", "unkown_property": "value"} - self.assertFalse(v.is_valid(data)) - self.assertFalse(v.is_valid([])) - self.assertFalse(v.is_valid(None)) - - def test_list_of_address(self): - schema = validator.get_schema_for_defined_type("list_of_address") - v = jsonschema.Draft4Validator(schema) - data = {"ip_netmask": "127.0.0.1/32"} - self.assertTrue(v.is_valid([data])) - self.assertFalse(v.is_valid(data)) - self.assertFalse(v.is_valid([])) - self.assertFalse(v.is_valid(None)) - - def test_route(self): - schema = validator.get_schema_for_defined_type("route") - v = jsonschema.Draft4Validator(schema) - data = {"next_hop": "172.19.0.1", "ip_netmask": "172.19.0.0/24", - "default": True, "route_options": "metric 10"} - self.assertTrue(v.is_valid(data)) - data = {"nexthop": "172.19.0.1", "destination": "172.19.0.0/24", - "default": True, "route_options": "metric 10"} - self.assertTrue(v.is_valid(data)) - - # Validation fails unless only os-net-config or neutron schema. - # os-net-config :: ip_netmask + next_hop - # neutron :: destination + nexthop - data = {"next_hop": "172.19.0.1", "destination": "172.19.0.0/24"} - self.assertFalse(v.is_valid(data)) - data = {"nexthop": "172.19.0.1", "ip_netmask": "172.19.0.0/24"} - self.assertFalse(v.is_valid(data)) - data = {"nexthop": "172.19.0.1", "destination": "172.19.0.0/24", - "ip_netmask": "172.19.0.0/24"} - self.assertFalse(v.is_valid(data)) - data = {"next_hop": "172.19.0.1", "nexthop": "172.19.0.1", - "destination": "172.19.0.0/24"} - self.assertFalse(v.is_valid(data)) - - data["unkown_property"] = "value" - self.assertFalse(v.is_valid(data)) - self.assertFalse(v.is_valid({})) - self.assertFalse(v.is_valid([])) - self.assertFalse(v.is_valid(None)) - - def test_route_table(self): - schema = validator.get_schema_for_defined_type("route_table") - v = jsonschema.Draft4Validator(schema) - data = {"type": "route_table", "name": "custom", "table_id": "20"} - self.assertTrue(v.is_valid(data)) - data["unkown_property"] = "value" - self.assertFalse(v.is_valid(data)) - self.assertFalse(v.is_valid({})) - self.assertFalse(v.is_valid([])) - self.assertFalse(v.is_valid(None)) - - def test_route_rule(self): - schema = validator.get_schema_for_defined_type("route_rule") - v = jsonschema.Draft4Validator(schema) - data = {"rule": "iif em2 table 20"} - self.assertTrue(v.is_valid(data)) - data["unkown_property"] = "value" - self.assertFalse(v.is_valid(data)) - self.assertFalse(v.is_valid({})) - self.assertFalse(v.is_valid([])) - self.assertFalse(v.is_valid(None)) - - -class TestDeviceTypes(base.TestCase): - - def test_interface(self): - schema = validator.get_schema_for_defined_type("interface") - v = jsonschema.Draft4Validator(schema) - data = { - "type": "interface", - "name": "em1", - "use_dhcp": False, - "addresses": [{ - "ip_netmask": "192.0.2.1/24" - }], - "defroute": False, - "dhclient_args": "--foobar", - "dns_servers": ["1.2.3.4"], - "domain": "openstack.local", - "mtu": 1501, - "ethtool_opts": "speed 1000 duplex full", - "hotplug": True, - "onboot": True, - "routes": [{ - "next_hop": "192.0.2.1", - "ip_netmask": "192.0.2.1/24", - "route_options": "metric 10" - }] - } - self.assertTrue(v.is_valid(data)) - - def test_vlan(self): - schema = validator.get_schema_for_defined_type("vlan") - v = jsonschema.Draft4Validator(schema) - data = { - "type": "vlan", - "vlan_id": 101, - "addresses": [{ - "ip_netmask": "192.0.2.1/24" - }] - } - self.assertTrue(v.is_valid(data)) - - def test_ovs_bridge(self): - schema = validator.get_schema_for_defined_type("ovs_bridge") - v = jsonschema.Draft4Validator(schema) - data = { - "type": "ovs_bridge", - "name": "br-ctlplane", - "ovs_options": "lacp=active", - "ovs_extra": [ - "br-set-external-id br-ctlplane bridge-id br-ctlplane", - "set bridge {name} stp_enable=true" - ], - "ovs_fail_mode": "secure", - "members": [ - {"type": "interface", "name": "em1"} - ] - } - self.assertTrue(v.is_valid(data)) - - def test_ovs_bond(self): - schema = validator.get_schema_for_defined_type("ovs_bond") - v = jsonschema.Draft4Validator(schema) - data = { - "type": "ovs_bond", - "name": "bond1", - "use_dhcp": "true", - "members": [ - {"type": "interface", "name": "em1"}, - {"type": "interface", "name": "em2"} - ] - } - self.assertTrue(v.is_valid(data)) - - def test_ovs_user_bridge(self): - schema = validator.get_schema_for_defined_type("ovs_user_bridge") - v = jsonschema.Draft4Validator(schema) - data = { - "type": "ovs_user_bridge", - "name": "br-link", - "members": [{ - "type": "ovs_dpdk_bond", - "name": "dpdkbond0", - "mtu": 9000, - "rx_queue": 4, - "members": [{ - "type": "ovs_dpdk_port", - "name": "dpdk0", - "members": [{ - "type": "interface", - "name": "nic2" - }] - }, { - "type": "ovs_dpdk_port", - "name": "dpdk1", - "members": [{ - "type": "interface", - "name": "nic3" - }] - }] - }] - } - self.assertTrue(v.is_valid(data)) - - def test_ovs_patch_port(self): - schema = validator.get_schema_for_defined_type("ovs_patch_port") - v = jsonschema.Draft4Validator(schema) - data = { - "type": "ovs_patch_port", - "name": "br_pub-patch", - "bridge_name": "br-ctlplane", - "peer": "br-ctlplane-patch" - } - self.assertTrue(v.is_valid(data)) - - def test_ovs_tunnel(self): - schema = validator.get_schema_for_defined_type("ovs_tunnel") - v = jsonschema.Draft4Validator(schema) - data = { - "type": "ovs_tunnel", - "name": "tun0", - "tunnel_type": "vxlan", - "ovs_options": ["lacp=active"] - } - self.assertTrue(v.is_valid(data)) - - def test_vpp_interface(self): - schema = validator.get_schema_for_defined_type("vpp_interface") - v = jsonschema.Draft4Validator(schema) - data = { - "type": "vpp_interface", - "name": "nic2", - "addresses": [ - {"ip_netmask": "192.0.2.1/24"} - ], - "uio_driver": "uio_pci_generic", - "options": "vlan-strip-offload off" - } - self.assertTrue(v.is_valid(data)) - - def test_linux_bridge(self): - schema = validator.get_schema_for_defined_type("linux_bridge") - v = jsonschema.Draft4Validator(schema) - data = { - "type": "linux_bridge", - "name": "br-ctlplane", - "use_dhcp": True, - "members": [ - {"type": "interface", "name": "em1"} - ] - } - self.assertTrue(v.is_valid(data)) - - def test_linux_bond(self): - schema = validator.get_schema_for_defined_type("linux_bond") - v = jsonschema.Draft4Validator(schema) - data = { - "type": "linux_bond", - "name": "bond1", - "use_dhcp": True, - "bonding_options": "mode=active-backup", - "members": [ - {"type": "interface", "name": "em1"}, - {"type": "interface", "name": "em2"} - ] - } - self.assertTrue(v.is_valid(data)) - - def test_nfvswitch_bridge(self): - schema = validator.get_schema_for_defined_type("nfvswitch_bridge") - v = jsonschema.Draft4Validator(schema) - data = { - "type": "nfvswitch_bridge", - "options": "-c 2,3,4,5", - "members": [{ - "type": "nfvswitch_internal", - "name": "api", - "addresses": [ - {"ip_netmask": "172.16.2.7/24"} - ], - "vlan_id": 201 - }, { - "type": "nfvswitch_internal", - "name": "storage", - "addresses": [ - {"ip_netmask": "172.16.1.6/24"} - ], - "vlan_id": 202 - }] - } - self.assertTrue(v.is_valid(data)) - - -class TestSampleFiles(base.TestCase): - - def test_sample_files(self): - sample_files = (glob.glob(os.path.join(SAMPLE_BASE, '*.json')) + - glob.glob(os.path.join(SAMPLE_BASE, '*.yaml'))) - for sample_file in sample_files: - with open(sample_file, 'r') as f: - try: - config = yaml.safe_load(f.read()).get("network_config") - except Exception: - continue - if not config: - continue - errors = validator.validate_config(config, sample_file) - if os.path.basename(sample_file).startswith("invalid_"): - self.assertTrue(errors) - else: - self.assertFalse(errors) diff --git a/os_net_config/utils.py b/os_net_config/utils.py deleted file mode 100644 index 81bbe9bb..00000000 --- a/os_net_config/utils.py +++ /dev/null @@ -1,865 +0,0 @@ -# -*- 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. - -import glob -import logging -import os -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__) -# sriov_config service shall be created and enabled so that the various -# SR-IOV PF and VF configurations shall be done during reboot as well using -# sriov_config.py installed in path /usr/bin/os-net-config-sriov -_SRIOV_CONFIG_SERVICE_FILE = "/etc/systemd/system/sriov_config.service" -_SRIOV_CONFIG_DEVICE_CONTENT = """[Unit] -Description=SR-IOV numvfs configuration -After=systemd-udev-settle.service openibd.service -Before=network-pre.target openvswitch.service - -[Service] -Type=oneshot -ExecStart=/usr/bin/os-net-config-sriov - -[Install] -WantedBy=basic.target -""" - -# VPP startup operational configuration file. The content of this file will -# be executed when VPP starts as if typed from CLI. -_VPP_EXEC_FILE = '/etc/vpp/vpp-exec' - - -class InvalidInterfaceException(ValueError): - pass - - -class VppException(ValueError): - pass - - -class ContrailVrouterException(ValueError): - pass - - -class SriovVfNotFoundException(ValueError): - pass - - -def write_config(filename, data): - with open(filename, 'w') as f: - f.write(str(data)) - - -def write_yaml_config(filepath, data): - ensure_directory_presence(filepath) - with open(filepath, 'w') as f: - yaml.safe_dump(data, f, default_flow_style=False) - - -def ensure_directory_presence(filepath): - dir_path = os.path.dirname(filepath) - if not os.path.exists(dir_path): - os.makedirs(dir_path) - - -def is_active_nic(interface_name): - return _is_available_nic(interface_name, True) - - -def is_real_nic(interface_name): - if interface_name == 'lo': - return True - - device_dir = common.get_dev_path(interface_name, '_device') - has_device_dir = os.path.isdir(device_dir) - - address = None - try: - with open(common.get_dev_path(interface_name, "_address"), 'r') as f: - address = f.read().rstrip() - except IOError: - return False - - if has_device_dir and address: - return True - else: - return False - - -def _is_available_nic(interface_name, check_active=True): - try: - if interface_name == 'lo': - return False - - if not is_real_nic(interface_name): - return False - - operstate = None - 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 - - # If SR-IOV Virtual Functions (VF) are enabled in an interface, there - # will be additional nics created for each VF. It has to be ignored in - # the nic numbering. All the VFs will have a reference to the PF with - # directory name as 'physfn', if this directory is present it should be - # ignored. - if common.is_vf_by_name(interface_name): - return False - - # nic is available - return True - - except IOError: - return False - - -def _natural_sort_key(s): - nsre = re.compile('([0-9]+)') - return [int(text) if text.isdigit() else text - for text in re.split(nsre, s)] - - -def _is_embedded_nic(nic): - if nic.startswith('em') or nic.startswith('eth') or nic.startswith('eno'): - return True - return False - - -def ordered_available_nics(): - return _ordered_nics(False) - - -def ordered_active_nics(): - return _ordered_nics(True) - - -def _ordered_nics(check_active): - embedded_nics = [] - nics = [] - logger.info("Finding active nics") - 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) - embedded_nics.append(nic) - else: - logger.info("%s is an active nic" % nic) - nics.append(nic) - else: - logger.info("%s is not an active nic" % nic) - - # Adding nics which are bound to DPDK as it will not be found in '/sys' - # after it is bound to DPDK driver. - contents = common.get_file_data(common.DPDK_MAPPING_FILE) - if contents: - dpdk_map = yaml.safe_load(contents) - for item in dpdk_map: - # If the DPDK drivers are bound to a VF, the same needs - # to be skipped for the NIC ordering - nic = item['name'] - if common.is_vf(item['pci_address']): - logger.info("%s is a VF, skipping it for NIC ordering" % nic) - elif common.is_vf_by_name(nic, True): - logger.info("%s is a VF, skipping it for NIC ordering" % nic) - elif _is_embedded_nic(nic): - logger.info("%s is an embedded DPDK bound nic" % nic) - if nic not in embedded_nics: - embedded_nics.append(nic) - else: - logger.info("%s is an DPDK bound nic" % nic) - if nic not in nics: - nics.append(nic) - else: - logger.info("No DPDK mapping available in path (%s)" % - common.DPDK_MAPPING_FILE) - - # NOTE: we could just natural sort all active devices, - # but this ensures em, eno, and eth are ordered first - # (more backwards compatible) - active_nics = (sorted(embedded_nics, key=_natural_sort_key) + - sorted(nics, key=_natural_sort_key)) - logger.info("Active nics are %s" % active_nics) - return active_nics - - -def diff(filename, data): - file_data = common.get_file_data(filename) - logger.debug("Diff file data:\n%s" % file_data) - logger.debug("Diff data:\n%s" % data) - # convert to string as JSON may have unicode in it - return not file_data == data - - -def bind_dpdk_interfaces(ifname, driver, noop): - if common.is_mellanox_interface(ifname) and 'vfio-pci' in driver: - msg = ("For Mellanox NIC %s, the default driver vfio-pci " - "needs to be overridden" % ifname) - raise common.OvsDpdkBindException(msg) - - iface_driver = get_interface_driver(ifname) - if iface_driver == driver: - logger.info("Driver (%s) is already bound to the device (%s)" % - (driver, ifname)) - return - pci_address = get_pci_address(ifname, noop) - if not noop: - if pci_address: - # modbprobe of the driver has to be done before binding. - # for reboots, puppet will add the modprobe to /etc/rc.modules - if 'vfio-pci' in driver: - try: - processutils.execute('modprobe', 'vfio-pci') - except processutils.ProcessExecutionError: - msg = "Failed to modprobe vfio-pci module" - raise common.OvsDpdkBindException(msg) - - mac_address = common.interface_mac(ifname) - vendor_id = common.get_vendor_id(ifname) - err = common.set_driverctl_override(pci_address, driver) - if not err: - _update_dpdk_map(ifname, pci_address, mac_address, driver) - # Not like other nics, beacause mellanox nics keep the - # interface after binding it to dpdk, so we are adding - # ethtool command with 10 attempts after binding the driver - # just to make sure that the interface is initialized - # successfully in order not to fail in each of this cases: - # - get_dpdk_devargs() in case of OvsDpdkPort and - # OvsDpdkBond. - # - bind_dpdk_interface() in case of OvsDpdkBond. - if vendor_id == common.MLNX_VENDOR_ID: - processutils.execute('ethtool', '-i', ifname, attempts=10) - else: - # Check if the pci address is already fetched and stored. - # If the pci address could not be fetched from dpdk_mapping.yaml - # raise OvsDpdkBindException, since the interface is neither - # available nor bound with dpdk. - if not get_stored_pci_address(ifname, noop): - msg = "Interface %s cannot be found" % ifname - raise common.OvsDpdkBindException(msg) - else: - logger.info('Interface %(name)s bound to DPDK driver %(driver)s ' - 'using driverctl command' % - {'name': ifname, 'driver': driver}) - - -def get_pci_address(ifname, noop): - # TODO(skramaja): Validate if the given interface supports dpdk - if not noop: - try: - out, err = processutils.execute('ethtool', '-i', ifname) - if not err: - for item in out.split('\n'): - if 'bus-info' in item: - return item.split(' ')[1] - except processutils.ProcessExecutionError: - # If ifname is already bound, then ethtool will not be able to - # list the device, in which case, binding is already done, proceed - # with scripts generation. - return - - else: - logger.info('Fetch the PCI address of the interface %s using ' - 'ethtool' % ifname) - - -def get_stored_pci_address(ifname, noop): - if not noop: - dpdk_map = common.get_dpdk_map() - for dpdk_nic in dpdk_map: - if dpdk_nic['name'] == ifname: - return dpdk_nic['pci_address'] - else: - logger.info('Fetch the PCI address of the interface %s using ' - 'ethtool' % ifname) - - -def translate_ifname_to_pci_address(ifname, noop): - pci_address = get_stored_pci_address(ifname, noop) - if pci_address is None and not noop: - pci_address = get_pci_address(ifname, noop=False) - mac_address = common.interface_mac(ifname) - _update_dpdk_map(ifname, pci_address, mac_address, driver=None) - return pci_address - - -def get_interface_driver(ifname): - try: - uevent = common.get_dev_path(ifname, 'device/uevent') - with open(uevent, 'r') as f: - out = f.read().strip() - for line in out.split('\n'): - if 'DRIVER' in line: - driver = line.split('=') - if len(driver) == 2: - return driver[1] - except IOError: - return - - -def get_dpdk_devargs(ifname, noop): - if not noop: - vendor_id = common.get_vendor_id(ifname) - device_id = common.get_device_id(ifname) - if vendor_id == common.MLNX_VENDOR_ID: - logger.info("Getting devargs for Mellanox cards") - if device_id == "0x1007": - # Some NICs (i.e. Mellanox ConnectX-3) have only one PCI - # address associated with multiple ports. Using a PCI - # device won’t work. Instead, we should use - # "class=eth,mac=" - dpdk_devargs = f"class=eth,mac={common.interface_mac(ifname)}" - else: - # Get the PCI address of the devices other than CX-3. - # It includes the VFs as well. For all Other Mellanox devices - # the PCI address are not stored in dpdk_mapping.yaml file, - # so we need to get their pci address with ethtool. - dpdk_devargs = get_pci_address(ifname, noop) - else: - logger.info("Getting stored PCI address as devarg") - dpdk_devargs = get_stored_pci_address(ifname, noop) - logger.debug("Devargs found: %s" % (dpdk_devargs)) - return dpdk_devargs - - -# Once the interface is bound to a DPDK driver, all the references to the -# interface including '/sys' and '/proc', will be removed. And there is no -# way to identify the nic name after it is bound. So, the DPDK bound nic info -# is stored persistently in DPDK_MAPPING_FILE and is used to for nic numbering -# on subsequent runs of os-net-config. -def _update_dpdk_map(ifname, pci_address, mac_address, driver): - dpdk_map = common.get_dpdk_map() - for item in dpdk_map: - if item['pci_address'] == pci_address: - item['name'] = ifname - item['mac_address'] = mac_address - item['driver'] = driver - break - else: - new_item = {} - new_item['pci_address'] = pci_address - new_item['name'] = ifname - new_item['mac_address'] = mac_address - new_item['driver'] = driver - dpdk_map.append(new_item) - - write_yaml_config(common.DPDK_MAPPING_FILE, dpdk_map) - - -def update_sriov_pf_map(ifname, numvfs, noop, promisc=None, - link_mode='legacy', vdpa=False, steering_mode=None, - lag_candidate=None): - if not noop: - cur_numvfs = sriov_config.get_numvfs(ifname) - if cur_numvfs > 0 and cur_numvfs != numvfs: - msg = ("Can't change the numvfs for %s" % ifname) - raise sriov_config.SRIOVNumvfsException(msg) - sriov_map = common.get_sriov_map() - for item in sriov_map: - if item['device_type'] == 'pf' and item['name'] == ifname: - item['numvfs'] = numvfs - item['vdpa'] = vdpa - if promisc is not None: - item['promisc'] = promisc - item['link_mode'] = link_mode - if steering_mode is not None: - item['steering_mode'] = steering_mode - if lag_candidate is not None: - item['lag_candidate'] = lag_candidate - break - else: - new_item = {} - new_item['device_type'] = 'pf' - new_item['name'] = ifname - new_item['numvfs'] = numvfs - new_item['vdpa'] = vdpa - if promisc is not None: - new_item['promisc'] = promisc - new_item['link_mode'] = link_mode - if steering_mode is not None: - new_item['steering_mode'] = steering_mode - if lag_candidate is not None: - new_item['lag_candidate'] = lag_candidate - sriov_map.append(new_item) - - write_yaml_config(common.SRIOV_CONFIG_FILE, sriov_map) - - -def _set_vf_fields(vf_name, vlan_id, qos, spoofcheck, trust, state, macaddr, - promisc, pci_address, min_tx_rate, max_tx_rate, driver): - vf_configs = {} - vf_configs['name'] = vf_name - if vlan_id != 0: - vf_configs['vlan_id'] = vlan_id - else: - vf_configs['vlan_id'] = None - if qos != 0: - vf_configs['qos'] = qos - else: - vf_configs['qos'] = None - vf_configs['min_tx_rate'] = min_tx_rate - vf_configs['max_tx_rate'] = max_tx_rate - vf_configs['spoofcheck'] = spoofcheck - vf_configs['trust'] = trust - vf_configs['state'] = state - vf_configs['macaddr'] = macaddr - vf_configs['promisc'] = promisc - vf_configs['pci_address'] = pci_address - if driver: - vf_configs['driver'] = driver - return vf_configs - - -def _clear_empty_values(vf_config): - for (key, val) in list(vf_config.items()): - if val is None: - del vf_config[key] - - -def update_sriov_vf_map(pf_name, vfid, vf_name, vlan_id=0, qos=0, - spoofcheck=None, trust=None, state=None, macaddr=None, - promisc=None, pci_address=None, - min_tx_rate=0, max_tx_rate=0, driver=None): - sriov_map = common.get_sriov_map() - for item in sriov_map: - if (item['device_type'] == 'vf' and - item['device'].get('name') == pf_name and - item['device'].get('vfid') == vfid): - item.update(_set_vf_fields(vf_name, vlan_id, qos, spoofcheck, - trust, state, macaddr, promisc, - pci_address, min_tx_rate, max_tx_rate, - driver)) - _clear_empty_values(item) - break - else: - new_item = {} - new_item['device_type'] = 'vf' - new_item['device'] = {"name": pf_name, "vfid": vfid} - new_item.update(_set_vf_fields(vf_name, vlan_id, qos, spoofcheck, - trust, state, macaddr, promisc, - pci_address, min_tx_rate, max_tx_rate, - driver)) - _clear_empty_values(new_item) - sriov_map.append(new_item) - - write_yaml_config(common.SRIOV_CONFIG_FILE, sriov_map) - - -def _get_vf_name_from_map(pf_name, vfid): - sriov_map = common.get_sriov_map() - for item in sriov_map: - if (item['device_type'] == 'vf' and - item['device'].get('name') == pf_name and - item['device'].get('vfid') == vfid): - return item['name'] - - -def nicpart_udev_rules_check(): - """Clean-up UDEV rules on initial deployment - - After writing sriov_config.yaml file, clean-up - UDEV rule(s) of PF for which VFs are used by host - """ - if not os.path.exists(sriov_config._UDEV_LEGACY_RULE_FILE): - return - - udev = '^KERNEL=="(.*)", RUN.*' - udev_reg = re.compile(udev, 0) - - with open(sriov_config._UDEV_LEGACY_RULE_FILE, "r") as fp: - rules = fp.readlines() - - with open(sriov_config._UDEV_LEGACY_RULE_FILE, "w") as fp: - for line in rules: - match = udev_reg.match(line) - if match: - dev_name = match.group(1) - if not sriov_config.is_partitioned_pf(dev_name): - fp.write(line) - else: - fp.write(line) - - -def _configure_sriov_config_service(): - """Generate the sriov_config.service - - sriov_config service shall configure the numvfs for the SriovPF nics - during reboot of the nodes. - """ - with open(_SRIOV_CONFIG_SERVICE_FILE, 'w') as f: - f.write(_SRIOV_CONFIG_DEVICE_CONTENT) - processutils.execute('systemctl', 'enable', 'sriov_config') - - -def configure_sriov_pfs(execution_from_cli=False, restart_openvswitch=False): - logger.info("Configuring PFs now") - sriov_config.configure_sriov_pf( - execution_from_cli=execution_from_cli, - restart_openvswitch=restart_openvswitch) - _configure_sriov_config_service() - - -def configure_sriov_vfs(): - logger.info("Configuring VFs now") - sriov_config.configure_sriov_vf() - nicpart_udev_rules_check() - - -def get_vf_devname(pf_name, vfid): - vf_path = common.get_dev_path(pf_name, f"virtfn{vfid}/net") - if os.path.isdir(vf_path): - vf_nic = os.listdir(vf_path) - else: - # if VF devices are bound with other drivers (DPDK) then the path - # doesn't exist. In such cases let us retrieve the vf name stored in - # the map - vf_name = _get_vf_name_from_map(pf_name, vfid) - if vf_name is not None: - return vf_name - else: - msg = "NIC %s with VF id: %d could not be found" % (pf_name, vfid) - raise SriovVfNotFoundException(msg) - if len(vf_nic) != 1: - msg = "VF name could not be identified in %s" % vf_path - raise SriovVfNotFoundException(msg) - # The VF's actual device name shall be the only directory seen in the path - # /sys/class/net//device/virtfn/net - return vf_nic[0] - - -def restart_vpp(vpp_interfaces): - for vpp_int in vpp_interfaces: - if 'vfio-pci' in vpp_int.uio_driver: - processutils.execute('modprobe', 'vfio-pci') - logger.info('Restarting VPP') - processutils.execute('systemctl', 'restart', 'vpp') - - -def _get_vpp_interface(pci_addr, tries=1, timeout=5): - """Get VPP interface information from a given PCI address - - From a running VPP instance, attempt to find the interface name and index - from a given PCI address of a NIC. The index is used to identify VPP bond - interface associated with the VPP interface. - - :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 - - for _ in range(tries): - try: - timestamp = time.time() - processutils.execute('systemctl', 'is-active', 'vpp') - out, err = processutils.execute('vppctl', 'show', 'interface', - check_exit_code=False) - 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+(\d+)' % formatted_pci, out, - re.MULTILINE) - if m: - logger.info('VPP interface found: %s, index: %s' % - (m.group(1), m.group(2))) - return {'name': m.group(1), 'index': m.group(2)} - 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 _get_vpp_bond(member_ids): - """Get VPP bond information from a given list of VPP interface indices - - :param member_ids: list of VPP interfaces indices for the bond - :return: VPP bond name and index. None if an interface is not found. - """ - if not member_ids: - return None - - member_ids.sort() - member_ids_str = ' '.join(member_ids) - - out, err = processutils.execute('vppctl', 'show', - 'hardware-interfaces', 'bond', 'brief', - check_exit_code=False) - logger.debug('vppctl show hardware-interfaces bond brief\n%s' % out) - m = re.search(r'^\s*(BondEthernet\d+)\s+(\d+)\s+.+Slave-Idx:\s+%s\s*$' % - member_ids_str, - out, - re.MULTILINE) - if m: - logger.info('Bond found: %s, index: %s' % (m.group(1), m.group(2))) - return {'name': m.group(1), 'index': m.group(2)} - else: - logger.info('Bond with member indices "%s" not found in VPP' - % member_ids_str) - return None - - -def generate_vpp_config(vpp_config_path, vpp_interfaces, vpp_bonds): - """Generate configuration content for VPP - - Generate interface related configuration content for VPP. Current - configuration will be preserved, with interface related configurations - updated or inserted. The config only affects 'dpdk' section of VPP config - file, and only those lines affecting interfaces, specifically, lines - containing the following: - dpdk { - ... - dev {} - uio-driver - ... - } - - :param vpp_config_path: VPP Configuration file path - :param vpp_interfaces: List of VPP interface objects - :param vpp_bonds: List of VPP bond objects - :return: updated VPP config content. - """ - - data = common.get_file_data(vpp_config_path) - - # Add interface config to 'dpdk' section - for vpp_interface in vpp_interfaces: - if vpp_interface.pci_dev: - logger.info('vpp interface %s pci dev: %s' - % (vpp_interface.name, vpp_interface.pci_dev)) - - if vpp_interface.options: - int_cfg = '%s {%s}' % (vpp_interface.pci_dev, - vpp_interface.options) - else: - int_cfg = vpp_interface.pci_dev - - # Make sure 'dpdk' section exists in the config - if not re.search(r'^\s*dpdk\s*\{', data, re.MULTILINE): - data += "\ndpdk {\n}\n" - - # Find existing config line for the device we are trying to - # configure, the line should look like 'dev ...' - # 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*$' - % vpp_interface.pci_dev, data, - re.IGNORECASE | re.MULTILINE) - if m: - 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, - data, - flags=re.MULTILINE) - - if vpp_interface.uio_driver: - # Check if there is existing uio-driver configuration, if - # found, the line will be replaced with the appropriate - # configuration, otherwise, add a new line in 'dpdk' section. - m = re.search(r'^\s*uio-driver.*$', data, re.MULTILINE) - if m: - data = re.sub(r'^\s*uio-driver.*$', ' uio-driver %s' - % vpp_interface.uio_driver, data, - flags=re.MULTILINE) - else: - data = re.sub(r'(^\s*dpdk\s*\{)', - r'\1\n uio-driver %s' - % vpp_interface.uio_driver, - data, - flags=re.MULTILINE) - else: - raise VppException('Interface %s has no PCI address and is not' - ' found in mapping file' % vpp_interface.name) - - # Add bond config to 'dpdk' section - for vpp_bond in vpp_bonds: - slave_str = '' - for member in vpp_bond.members: - slave_str += ",slave=%s" % member.pci_dev - if vpp_bond.bonding_options: - options_str = ',' + vpp_bond.bonding_options.strip(' ,') - else: - options_str = '' - - if slave_str: - m = re.search(r'^\s*vdev\s+%s.*$' % vpp_bond.name, - data, re.MULTILINE) - if m: - data = re.sub(m.group(0), r' vdev %s%s%s' - % (vpp_bond.name, slave_str, options_str), - data) - else: - data = re.sub(r'(^\s*dpdk\s*\{)', - r'\1\n vdev %s%s%s' - % (vpp_bond.name, slave_str, options_str), - data, - flags=re.MULTILINE) - - # Add start up script for VPP to config. This script will be executed by - # VPP on service start. - if not re.search(r'^\s*unix\s*\{', data, re.MULTILINE): - data += "\nunix {\n}\n" - - m = re.search(r'^\s*(exec|startup-config).*$', - data, - re.IGNORECASE | re.MULTILINE) - if m: - data = re.sub(m.group(0), ' exec %s' % _VPP_EXEC_FILE, data) - else: - data = re.sub(r'(^\s*unix\s*\{)', - r'\1\n exec %s' % _VPP_EXEC_FILE, - data, - flags=re.MULTILINE) - # Make sure startup script exists to avoid VPP startup failure. - open(_VPP_EXEC_FILE, 'a').close() - - return data - - -def update_vpp_mapping(vpp_interfaces, vpp_bonds): - """Verify VPP interface binding and update mapping file - - VppException will be raised if interfaces are not properly bound. - - :param vpp_interfaces: List of VPP interface objects - :param vpp_bonds: List of VPP bond objects - """ - cli_list = [] - - for vpp_int in vpp_interfaces: - # Try to get VPP interface name. In case VPP service is down - # for some reason, we will restart VPP and try again. Currently - # only trying one more time, can turn into a retry_counter if needed - # in the future. - for i in range(2): - int_info = _get_vpp_interface(vpp_int.pci_dev, - tries=12, timeout=5) - if not int_info: - restart_vpp(vpp_interfaces) - else: - vpp_int.vpp_name = int_info['name'] - vpp_int.vpp_idx = int_info['index'] - break - else: - raise VppException('Interface %s with pci address %s not ' - 'bound to vpp' - % (vpp_int.name, vpp_int.pci_dev)) - - # Generate content of startup script for VPP - if not vpp_bonds: - cli_list.append('set interface state %s up' - % int_info['name']) - for address in vpp_int.addresses: - cli_list.append('set interface ip address %s %s/%s\n' - % (int_info['name'], address.ip, - address.prefixlen)) - - logger.info('Updating mapping for vpp interface %s:' - 'pci_dev: %s mac address: %s uio driver: %s' - % (vpp_int.name, vpp_int.pci_dev, vpp_int.hwaddr, - vpp_int.uio_driver)) - _update_dpdk_map(vpp_int.name, vpp_int.pci_dev, vpp_int.hwaddr, - vpp_int.uio_driver) - - for vpp_bond in vpp_bonds: - bond_ids = [member.vpp_idx for member in vpp_bond.members] - bond_info = _get_vpp_bond(bond_ids) - if bond_info: - cli_list.append('set interface state %s up' - % bond_info['name']) - for address in vpp_bond.addresses: - cli_list.append('set interface ip address %s %s/%s' - % (bond_info['name'], address.ip, - address.prefixlen)) - else: - raise VppException('Bond %s not found in VPP.' % vpp_bond.name) - - vpp_start_cli = common.get_file_data(_VPP_EXEC_FILE) - for cli_line in cli_list: - if not re.search(r'^\s*%s\s*$' % cli_line, - vpp_start_cli, re.MULTILINE): - vpp_start_cli += cli_line + '\n' - - if diff(_VPP_EXEC_FILE, vpp_start_cli): - write_config(_VPP_EXEC_FILE, vpp_start_cli) - restart_vpp(vpp_interfaces) - - # Enable VPP service to make the VPP interface configuration - # persistent. - processutils.execute('systemctl', 'enable', 'vpp') - - -def is_ovs_installed(): - """Check if OpenVswitch is installed - - Verify that OpenVswitch is installed by checking if - ovs-appctl is on the system. If OVS is not installed - it will limit os-net-config's ability to set up ovs-bonds, - ovs-bridges etc. - """ - return os.path.exists("/usr/bin/ovs-appctl") - - -def iproute2_path(): - """Find 'ip' executable.""" - if os.access('/sbin/ip', os.X_OK): - ipcmd = '/sbin/ip' - elif os.access('/usr/sbin/ip', os.X_OK): - ipcmd = '/usr/sbin/ip' - else: - logger.warning("Could not execute /sbin/ip or /usr/sbin/ip") - return False - return ipcmd - - -def ethtool_path(): - """Find 'ethtool' executable.""" - if os.access('/sbin/ethtool', os.X_OK): - ethtoolcmd = '/sbin/ethtool' - elif os.access('/usr/sbin/ethtool', os.X_OK): - ethtoolcmd = '/usr/sbin/ethtool' - else: - logger.warning("Could not execute /sbin/ethtool or /usr/sbin/ethtool") - return False - return ethtoolcmd diff --git a/os_net_config/validator.py b/os_net_config/validator.py deleted file mode 100644 index 16744aff..00000000 --- a/os_net_config/validator.py +++ /dev/null @@ -1,182 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright 2017 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. - -import collections -import collections.abc -import copy -import jsonschema -import pkg_resources -import yaml - - -def get_os_net_config_schema(): - """Returns the schema for os_net_config's config files.""" - schema_string = pkg_resources.resource_string(__name__, "schema.yaml") - return yaml.safe_load(schema_string) - - -def get_schema_for_defined_type(defined_type): - """Returns the schema for a given defined type of the full schema.""" - full_schema = get_os_net_config_schema() - type_schema = copy.deepcopy(full_schema["definitions"][defined_type]) - type_schema["$schema"] = full_schema["$schema"] - type_schema["definitions"] = full_schema["definitions"] - return type_schema - - -def validate_config(config, config_name="Config file"): - """Validates a list of interface/bridge configurations against the schema. - - If validation fails, returns a list of validation error message strings. - If validation succeeds, returns an empty list. - `config_name` can be used to prefix errors with a more specific name. - """ - return _validate_config(config, config_name, - get_os_net_config_schema(), True) - - -def _validate_config(config, config_name, schema, filter_errors): - error_messages = [] - validator = jsonschema.Draft4Validator(schema) - v_errors = validator.iter_errors(config) - v_errors = sorted(v_errors, key=lambda e: e.path) - for v_error in v_errors: - error_message = _get_consistent_error_message(v_error) - details = _get_detailed_errors(v_error, 1, v_error.schema_path, - schema, filter_errors=filter_errors) - - config_path = '/'.join([str(x) for x in v_error.path]) - if details: - error_messages.append( - "{} failed schema validation at network_config/{}:\n" - " {}\n" - " Sub-schemas tested and not matching:\n" - " {}" - .format(config_name, config_path, error_message, - '\n '.join(details))) - else: - error_messages.append( - "{} failed schema validation at network_config/{}:\n" - " {}" - .format(config_name, config_path, error_message)) - return error_messages - - -def _get_consistent_error_message(error): - """Returns error messages consistent across Python 2 and 3. - - jsonschema uses repr() to print its error messages, which means strings - will render as "u'...'" in Python 2 and "'...'" in Python 3, making - testing for error messages unnecessarily difficult. - """ - - if error.validator == 'type': - return "'{}' is not of type '{}'".format( - error.instance, error.validator_value) - elif error.validator == 'enum': - return "'{}' is not one of ['{}']".format( - error.instance, "','".join(error.validator_value)) - elif error.validator == 'required': - if error.message[0:2] == "u'": - return error.message[1:] - return error.message - - -def _get_detailed_errors(error, depth, absolute_schema_path, absolute_schema, - filter_errors=True): - """Returns a list of error messages from all subschema validations. - - Recurses the error tree and adds one message per sub error. That list can - get long, because jsonschema also tests the hypothesis that the provided - network element type is wrong (e.g. "ovs_bridge" instead of "ovs_bond"). - Setting `filter_errors=True` assumes the type, if specified, is correct and - therefore produces a much shorter list of more relevant results. - """ - - if not error.context: - return [] - - sub_errors = error.context - if filter_errors: - if (absolute_schema_path[-1] in ['oneOf', 'anyOf'] and - isinstance(error.instance, collections.abc.Mapping) and - 'type' in error.instance): - found, index = _find_type_in_schema_list( - error.validator_value, error.instance['type']) - if found: - sub_errors = [i for i in sub_errors if ( - i.schema_path[0] == index)] - - details = [] - sub_errors = sorted(sub_errors, key=lambda e: e.schema_path) - for sub_error in sub_errors: - schema_path = collections.deque(absolute_schema_path) - schema_path.extend(sub_error.schema_path) - details.append("{} {}: {}".format( - '-' * depth, - _pretty_print_schema_path(schema_path, absolute_schema), - _get_consistent_error_message(sub_error))) - details.extend(_get_detailed_errors( - sub_error, depth + 1, schema_path, absolute_schema, - filter_errors)) - return details - - -def _find_type_in_schema_list(schemas, type_to_find): - """Finds an object of a given type in an anyOf/oneOf array. - - Returns a tuple (`found`, `index`), where `found` indicates whether - on object of type `type_to_find` was found in the `schemas` array. - If so, `index` contains the object's position in the array. - """ - for index, schema in enumerate(schemas): - if not isinstance(schema, collections.abc.Mapping): - continue - if ('$ref' in schema and - schema['$ref'].split('/')[-1] == type_to_find): - return (True, index) - if ('properties' in schema and 'type' in schema['properties'] and - schema['properties']['type'] == type_to_find): - return (True, index) - return (False, 0) - - -def _pretty_print_schema_path(absolute_schema_path, absolute_schema): - """Returns a representation of the schema path that's easier to read. - - For example: - >>> _pretty_print_schema_path("items/oneOf/0/properties/use_dhcp/oneOf/2") - "items/oneOf/interface/use_dhcp/oneOf/param" - """ - - pretty_path = [] - current_path = [] - current_schema = absolute_schema - for item in absolute_schema_path: - if item not in ["properties"]: - pretty_path.append(item) - current_path.append(item) - current_schema = current_schema[item] - if (isinstance(current_schema, collections.abc.Mapping) and - '$ref' in current_schema): - if (isinstance(pretty_path[-1], int) and - pretty_path[-2] in ['oneOf', 'anyOf']): - pretty_path[-1] = current_schema['$ref'].split('/')[-1] - current_path = current_schema['$ref'].split('/') - current_schema = absolute_schema - for i in current_path[1:]: - current_schema = current_schema[i] - return '/'.join([str(x) for x in pretty_path]) diff --git a/os_net_config/version.py b/os_net_config/version.py deleted file mode 100644 index 2af627cb..00000000 --- a/os_net_config/version.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- 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. - -import pbr.version - -version_info = pbr.version.VersionInfo('os-net-config') diff --git a/releasenotes/notes/add-neutron-route-schema-support-e8e20a8c3b79d14d.yaml b/releasenotes/notes/add-neutron-route-schema-support-e8e20a8c3b79d14d.yaml deleted file mode 100644 index 035af147..00000000 --- a/releasenotes/notes/add-neutron-route-schema-support-e8e20a8c3b79d14d.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -features: - - | - Adds support to use ``destination`` and ``nexthop`` as keys in the - ``Route`` objects. ``destination`` maps to ``ip_netmask`` and ``nexthop`` - maps to ``next_hop``. Neutron Route objects use ``destination`` and - ``nexthop``, supporting the same schema allow passing a neutron route - directly to os-net-config. diff --git a/releasenotes/notes/add-pci-address-in-sriov-config-06016e4e69b322ca.yaml b/releasenotes/notes/add-pci-address-in-sriov-config-06016e4e69b322ca.yaml deleted file mode 100644 index 7a403cc1..00000000 --- a/releasenotes/notes/add-pci-address-in-sriov-config-06016e4e69b322ca.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - | - Adding PCI address of each VF to sriov_config.yaml. This information - could be used in deriving the PCI passthrough whitelist. diff --git a/releasenotes/notes/add_contrail_vrouter_vlan_linux_bond_type-0a89f3499a7ab08b.yaml b/releasenotes/notes/add_contrail_vrouter_vlan_linux_bond_type-0a89f3499a7ab08b.yaml deleted file mode 100644 index 37d52efd..00000000 --- a/releasenotes/notes/add_contrail_vrouter_vlan_linux_bond_type-0a89f3499a7ab08b.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -issues: - - | - Currently the member interface for a contrail vrouter interface can only - be of type interface. Types vlan and linux_bond are needed. -fixes: - - | - This fix adds support for member interfaces of type vlan and linux_bond diff --git a/releasenotes/notes/allow-list-of-routes-to-be-empty-323690796760630d.yaml b/releasenotes/notes/allow-list-of-routes-to-be-empty-323690796760630d.yaml deleted file mode 100644 index 9816cba7..00000000 --- a/releasenotes/notes/allow-list-of-routes-to-be-empty-323690796760630d.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -other: - - | - The schema now allow the ``routes`` option to be an empty list. (Previously - at least one route was was required.) Bug: `1792992 - _`. diff --git a/releasenotes/notes/check-ovs-ef665418762ca123.yaml b/releasenotes/notes/check-ovs-ef665418762ca123.yaml deleted file mode 100644 index 442de8db..00000000 --- a/releasenotes/notes/check-ovs-ef665418762ca123.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -fixes: - - OVS is not required for os-net-config to run but some objects (OvsBond, - OvsBridge etc.) rely on it being installed. This adds a check to ensure - OVS is installed before creating objects that need it. diff --git a/releasenotes/notes/dpdk-on-mellanox-nics-1d8fdb843a4e2b60.yaml b/releasenotes/notes/dpdk-on-mellanox-nics-1d8fdb843a4e2b60.yaml deleted file mode 100644 index 6728a343..00000000 --- a/releasenotes/notes/dpdk-on-mellanox-nics-1d8fdb843a4e2b60.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - | - Adding dpdk support in meallnox nics. - Dpdk now fully suuported in mellanox nics. diff --git a/releasenotes/notes/enable-setting-domain-5557e2441c23a5a5.yaml b/releasenotes/notes/enable-setting-domain-5557e2441c23a5a5.yaml deleted file mode 100644 index 394953ad..00000000 --- a/releasenotes/notes/enable-setting-domain-5557e2441c23a5a5.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - | - A key called "domain" is now available for interfaces. This allows the - setting of a domain for an ifcfg configuration, which will aide DNS search. diff --git a/releasenotes/notes/log-info-nic-discovery-f54ace7639890fdf.yaml b/releasenotes/notes/log-info-nic-discovery-f54ace7639890fdf.yaml deleted file mode 100644 index 569247e0..00000000 --- a/releasenotes/notes/log-info-nic-discovery-f54ace7639890fdf.yaml +++ /dev/null @@ -1,9 +0,0 @@ ---- -fixes: - - | - Getting the ordered, active, and available nics has been traditionally one - of the parts of os-net-config that can cause issues due to either user - error or bugs. There are helpful log messages to log what is going on in - the logic, but it's all hidden behind the DEBUG log level. These messages - should be INFO instead of DEBUG. It's much more user friendly when there - are issues instead of having to rerun with --debug. diff --git a/releasenotes/notes/log-mapping-file-8b2a9d8f6a81ba99.yaml b/releasenotes/notes/log-mapping-file-8b2a9d8f6a81ba99.yaml deleted file mode 100644 index 0b1cc846..00000000 --- a/releasenotes/notes/log-mapping-file-8b2a9d8f6a81ba99.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -fixes: - - | - os-net-config always logs the message "Using mapping file at: - /etc/os-net-config/mapping.yaml" even if the file does not exist, in which - case it's not actually being used at all. Move the log message to only be - shown if the mapping file actually exists and is used. In the case where no - mapping file is used, also log a message indicating such. diff --git a/releasenotes/notes/modify-interface-without-restart-d55949572017d52f.yaml b/releasenotes/notes/modify-interface-without-restart-d55949572017d52f.yaml deleted file mode 100644 index 4dc25454..00000000 --- a/releasenotes/notes/modify-interface-without-restart-d55949572017d52f.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -features: - - | - Some changes can now be made to interfaces without restarting. Changes to - routes, IP addresses, netmask, or MTU will now be applied using iproute2 - without restarting the interface, and the ifcfg file will be updated. -other: - - | - Since this change uses iproute2 to make changes to live interfaces, it - does not allow MTU on DPDK interfaces to be modified in place. DPDK - requires that ovs-vsctl be run to modify MTU. For DPDK interfaces, MTU - changes will result in an interface restart. diff --git a/releasenotes/notes/policy-based-routing-3fa1200ae155bbee.yaml b/releasenotes/notes/policy-based-routing-3fa1200ae155bbee.yaml deleted file mode 100644 index a8a1d6fc..00000000 --- a/releasenotes/notes/policy-based-routing-3fa1200ae155bbee.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -features: - - | - Support for configuring policy-based routing has been added. A new - top-level object "route_table" has been added, which allows the user to - add tables to the system route table at /etc/iproute2/rt_tables. Routes - have a new "table" property for specifying which table to apply the route. - Interfaces now have a "rules" property that allows the user to add - arbitrary rules for when the system should use a particular routing table, - such as input interface or source IP address. diff --git a/releasenotes/notes/restart-ivs-nvfswitch-after-change-0825ea78aae8f138.yaml b/releasenotes/notes/restart-ivs-nvfswitch-after-change-0825ea78aae8f138.yaml deleted file mode 100644 index 57fd2b72..00000000 --- a/releasenotes/notes/restart-ivs-nvfswitch-after-change-0825ea78aae8f138.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -fixes: - - When the ivs interface (or nfvswitch) configuration changes, - ivs (or nvfswitch) needs to be restarted in order to pick - up the new configuration. diff --git a/releasenotes/notes/retry_ovs-appctl-6734b087ab6db80b.yaml b/releasenotes/notes/retry_ovs-appctl-6734b087ab6db80b.yaml deleted file mode 100644 index 4e7efbf4..00000000 --- a/releasenotes/notes/retry_ovs-appctl-6734b087ab6db80b.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -fixes: - - The ovs-appctl command may fail, particularly when setting an - interface as a slave in a bond if the primary interface is not - yet up. Retry the ovs-appctl command and log a failure if the - command still fails. diff --git a/releasenotes/notes/sriov-vf-in-hosts-529c2bf0cb3294b3.yaml b/releasenotes/notes/sriov-vf-in-hosts-529c2bf0cb3294b3.yaml deleted file mode 100644 index 5db4f1f6..00000000 --- a/releasenotes/notes/sriov-vf-in-hosts-529c2bf0cb3294b3.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -features: - - | - sriov_pf and sriov_vf object types are added to allow configuration and - usage of the SR-IOV PF and VF devices in the host machine. The sriov_config - service file shall be used to reconfigure the SR-IOV devices after reboots. - VLAN suport for SR-IOV VF device is not available in this patch. diff --git a/releasenotes/source/_static/.placeholder b/releasenotes/source/_static/.placeholder deleted file mode 100644 index e69de29b..00000000 diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py deleted file mode 100644 index 0f23634f..00000000 --- a/releasenotes/source/conf.py +++ /dev/null @@ -1,189 +0,0 @@ -# -*- coding: utf-8 -*- -# 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. - -# Bashate Release Notes documentation build configuration file, created by -# sphinx-quickstart on Tue Nov 3 17:40:50 2015. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'openstackdocstheme', - 'reno.sphinxext', -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -# source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = 'os-net-config Release Notes' -copyright = '2018, OpenStackFoundation' - -# openstackdocstheme options -openstackdocs_repo_name = 'openstack/os-net-config' -openstackdocs_auto_name = False -openstackdocs_bug_project = 'os-net-config' -openstackdocs_bug_tag = '' - -# Release notes are version independent -# The full version, including alpha/beta/rc tags. -release = '' -# The short X.Y version. -version = '' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -# today = '' -# Else, today_fmt is used as the format for a strftime call. -# today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = [] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -# default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -# add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -# add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -# show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'native' - -# A list of ignored prefixes for module index sorting. -# modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -# keep_warnings = False - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'openstackdocs' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -# html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -# html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -# html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -# html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -# html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -# html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -# html_extra_path = [] - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -# html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -# html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -# html_additional_pages = {} - -# If false, no module index is generated. -# html_domain_indices = True - -# If false, no index is generated. -# html_use_index = True - -# If true, the index is split into individual pages for each letter. -# html_split_index = False - -# If true, links to the reST sources are added to the pages. -# html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -# html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -# html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -# html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -# html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = '%sdoc' % project diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst deleted file mode 100644 index 00ee9ab9..00000000 --- a/releasenotes/source/index.rst +++ /dev/null @@ -1,16 +0,0 @@ -=========================== -os-net-config Release Notes -=========================== - -.. toctree:: - :maxdepth: 1 - - unreleased - zed - wallaby - victoria - ussuri - train - stein - rocky - queens diff --git a/releasenotes/source/queens.rst b/releasenotes/source/queens.rst deleted file mode 100644 index 36ac6160..00000000 --- a/releasenotes/source/queens.rst +++ /dev/null @@ -1,6 +0,0 @@ -=================================== - Queens Series Release Notes -=================================== - -.. release-notes:: - :branch: stable/queens diff --git a/releasenotes/source/rocky.rst b/releasenotes/source/rocky.rst deleted file mode 100644 index 40dd517b..00000000 --- a/releasenotes/source/rocky.rst +++ /dev/null @@ -1,6 +0,0 @@ -=================================== - Rocky Series Release Notes -=================================== - -.. release-notes:: - :branch: stable/rocky diff --git a/releasenotes/source/stein.rst b/releasenotes/source/stein.rst deleted file mode 100644 index efaceb66..00000000 --- a/releasenotes/source/stein.rst +++ /dev/null @@ -1,6 +0,0 @@ -=================================== - Stein Series Release Notes -=================================== - -.. release-notes:: - :branch: stable/stein diff --git a/releasenotes/source/train.rst b/releasenotes/source/train.rst deleted file mode 100644 index 58390039..00000000 --- a/releasenotes/source/train.rst +++ /dev/null @@ -1,6 +0,0 @@ -========================== -Train Series Release Notes -========================== - -.. release-notes:: - :branch: stable/train diff --git a/releasenotes/source/unreleased.rst b/releasenotes/source/unreleased.rst deleted file mode 100644 index 3dd6e1c2..00000000 --- a/releasenotes/source/unreleased.rst +++ /dev/null @@ -1,5 +0,0 @@ -============================== - Current Series Release Notes -============================== - -.. toctree:: diff --git a/releasenotes/source/ussuri.rst b/releasenotes/source/ussuri.rst deleted file mode 100644 index e21e50e0..00000000 --- a/releasenotes/source/ussuri.rst +++ /dev/null @@ -1,6 +0,0 @@ -=========================== -Ussuri Series Release Notes -=========================== - -.. release-notes:: - :branch: stable/ussuri diff --git a/releasenotes/source/victoria.rst b/releasenotes/source/victoria.rst deleted file mode 100644 index 4efc7b6f..00000000 --- a/releasenotes/source/victoria.rst +++ /dev/null @@ -1,6 +0,0 @@ -============================= -Victoria Series Release Notes -============================= - -.. release-notes:: - :branch: stable/victoria diff --git a/releasenotes/source/wallaby.rst b/releasenotes/source/wallaby.rst deleted file mode 100644 index d77b5659..00000000 --- a/releasenotes/source/wallaby.rst +++ /dev/null @@ -1,6 +0,0 @@ -============================ -Wallaby Series Release Notes -============================ - -.. release-notes:: - :branch: stable/wallaby diff --git a/releasenotes/source/zed.rst b/releasenotes/source/zed.rst deleted file mode 100644 index 9608c05e..00000000 --- a/releasenotes/source/zed.rst +++ /dev/null @@ -1,6 +0,0 @@ -======================== -Zed Series Release Notes -======================== - -.. release-notes:: - :branch: stable/zed diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index ae0ac001..00000000 --- a/requirements.txt +++ /dev/null @@ -1,10 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. -pbr!=2.1.0,>=2.0.0 # Apache-2.0 -netaddr>=0.7.13 # BSD -oslo.concurrency>=3.26.0 # Apache-2.0 -oslo.utils>=3.33.0 # Apache-2.0 -PyYAML>=3.10.0 # MIT -jsonschema>=3.2.0 # MIT -pyudev>=0.16.1 # LGPLv2.1+ diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index d27ab8fb..00000000 --- a/setup.cfg +++ /dev/null @@ -1,31 +0,0 @@ -[metadata] -name = os-net-config -summary = OpenStack network configuration -description_file = - README.rst -author = OpenStack -author_email = openstack-discuss@lists.openstack.org -license = Apache License (2.0) -home_page = https://opendev.org/openstack/os-net-config -classifier = - Environment :: OpenStack - Intended Audience :: Developers - Intended Audience :: System Administrators - License :: OSI Approved :: Apache Software License - Operating System :: OS Independent - Programming Language :: Python - Programming Language :: Python :: Implementation :: CPython - Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - -[files] -packages = - os_net_config - -[entry_points] -console_scripts = - os-net-config = os_net_config.cli:main - os-net-config-sriov = os_net_config.sriov_config:main - os-net-config-sriov-bind = os_net_config.sriov_bind_config:main diff --git a/setup.py b/setup.py deleted file mode 100644 index 31d6ada1..00000000 --- a/setup.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# 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. - -import setuptools - -setuptools.setup( - setup_requires=['pbr>=2.0.0'], - py_modules=[], - pbr=True) diff --git a/test-requirements.txt b/test-requirements.txt deleted file mode 100644 index 37c07233..00000000 --- a/test-requirements.txt +++ /dev/null @@ -1,12 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. -hacking>=3.0.1,<3.1.0 # Apache-2.0 - -coverage>=4.0 # Apache-2.0 -fixtures>=3.0.0 # Apache-2.0/BSD -python-subunit>=0.0.18 # Apache-2.0/BSD -stestr>=2.0.0 # Apache-2.0 -testscenarios>=0.4 # Apache-2.0/BSD -testtools>=1.4.0 # MIT -reno>=3.1.0 # Apache-2.0 diff --git a/tox.ini b/tox.ini deleted file mode 100644 index d08361ab..00000000 --- a/tox.ini +++ /dev/null @@ -1,45 +0,0 @@ -[tox] -minversion = 3.18.0 -envlist = docs,linters,pep8 -skipsdist = True -ignore_basepython_conflict = True - -[testenv] -usedevelop = True -basepython = python3 -sitepackages = True -setenv = - VIRTUAL_ENV={envdir} -deps = - -r{toxinidir}/requirements.txt - -r{toxinidir}/test-requirements.txt -commands = - stestr run --slowest {posargs} - -[testenv:pep8] -commands = flake8 - -[testenv:venv] -commands = {posargs} - -[testenv:cover] -setenv = - PYTHON=coverage run --source os_net_config --parallel-mode -commands = - stestr run {posargs} - coverage combine - coverage html -d cover - coverage xml -o cover/coverage.xml - -[testenv:docs] -deps = -r{toxinidir}/doc/requirements.txt -commands = - sphinx-build -W -b html -d doc/build/doctrees doc/source doc/build/html - -[flake8] -# E123, E125 skipped as they are invalid PEP-8. -# W504 line break after binary operator -show-source = True -ignore = E123,E125,W504 -builtins = _ -exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build diff --git a/zuul.d/layout.yaml b/zuul.d/layout.yaml deleted file mode 100644 index 5d4929a5..00000000 --- a/zuul.d/layout.yaml +++ /dev/null @@ -1,23 +0,0 @@ ---- -- project: - queue: tripleo - templates: - - check-requirements - - publish-openstack-docs-pti - - release-notes-jobs-python3 - check: - jobs: - - openstack-tox-pep8: &nodes - nodeset: centos-9-stream - - openstack-tox-py39: *nodes - - openstack-tox-docs: *nodes - - openstack-tox-cover: *nodes - gate: - jobs: - - openstack-tox-pep8: *nodes - - openstack-tox-py39: *nodes - - openstack-tox-docs: *nodes - post: - jobs: - - publish-openstack-python-branch-tarball -