From 6ed93f844874622ca1487281b42a9e799e4e8795 Mon Sep 17 00:00:00 2001 From: Ghanshyam Mann Date: Sat, 24 Feb 2024 11:32:07 -0800 Subject: [PATCH] Retire Tripleo: remove repo content TripleO project is retiring - https://review.opendev.org/c/openstack/governance/+/905145 this commit remove the content of this project repo Change-Id: I9da248ee774c038c99bf452898ac8658aa337aad --- .coveragerc | 7 - .gitignore | 53 - .mailmap | 3 - .stestr.conf | 4 - CONTRIBUTING.rst | 16 - HACKING.rst | 4 - LICENSE | 175 - README.rst | 42 +- babel.cfg | 1 - bindep.txt | 9 - doc/requirements.txt | 2 - doc/source/conf.py | 81 - doc/source/config.rst | 487 --- doc/source/contributing.rst | 4 - doc/source/examples.rst | 206 -- doc/source/index.rst | 26 - doc/source/installation.rst | 12 - doc/source/readme.rst | 1 - doc/source/usage.rst | 80 - etc/os-net-config/samples/bond.json | 19 - etc/os-net-config/samples/bond.yaml | 17 - etc/os-net-config/samples/bond_mapped.yaml | 23 - etc/os-net-config/samples/bridge_dhcp.json | 17 - etc/os-net-config/samples/bridge_dhcp.yaml | 11 - .../samples/bridge_fail_mode.json | 15 - .../samples/bridge_fail_mode.yaml | 10 - .../samples/bridge_ovs_extra.json | 18 - .../samples/bridge_ovs_extra.yaml | 12 - etc/os-net-config/samples/bridge_vlan.json | 29 - etc/os-net-config/samples/bridge_vlan.yaml | 22 - .../samples/contrail_vrouter.json | 14 - .../samples/contrail_vrouter.yaml | 9 - .../samples/contrail_vrouter_dpdk.json | 15 - .../samples/contrail_vrouter_dpdk.yaml | 10 - .../samples/contrail_vrouter_dpdk_bond.json | 20 - .../samples/contrail_vrouter_dpdk_bond.yaml | 14 - .../samples/contrail_vrouter_vlan.json | 15 - .../samples/contrail_vrouter_vlan.yaml | 10 - .../samples/ib_child_interface.json | 20 - .../samples/ib_child_interface.yaml | 18 - etc/os-net-config/samples/ib_interface.json | 26 - etc/os-net-config/samples/ib_interface.yaml | 18 - etc/os-net-config/samples/interface.json | 40 - etc/os-net-config/samples/interface.yaml | 30 - etc/os-net-config/samples/ivs.json | 37 - etc/os-net-config/samples/ivs.yaml | 24 - etc/os-net-config/samples/linux_bond.yaml | 13 - .../samples/linux_bond_networkmanager.yaml | 18 - etc/os-net-config/samples/linux_bridge.yaml | 9 - etc/os-net-config/samples/linux_tap.json | 8 - etc/os-net-config/samples/linux_tap.yaml | 6 - etc/os-net-config/samples/mapping.yaml | 12 - .../samples/mapping_mnemonic.yaml | 8 - etc/os-net-config/samples/mapping_report.yaml | 5 - etc/os-net-config/samples/nfvswitch.json | 38 - etc/os-net-config/samples/nfvswitch.yaml | 25 - etc/os-net-config/samples/ovs_dpdk.json | 24 - etc/os-net-config/samples/ovs_dpdk.yaml | 32 - etc/os-net-config/samples/ovs_dpdk_bond.json | 37 - etc/os-net-config/samples/ovs_dpdk_bond.yaml | 40 - etc/os-net-config/samples/ovs_patch_port.json | 37 - etc/os-net-config/samples/ovs_patch_port.yaml | 23 - etc/os-net-config/samples/routes.yaml | 52 - etc/os-net-config/samples/sriov_pf.json | 130 - etc/os-net-config/samples/sriov_pf.yaml | 158 - .../samples/sriov_pf_ovs_dpdk.json | 102 - .../samples/sriov_pf_ovs_dpdk.yaml | 129 - .../samples/sriov_pf_switchdev.json | 85 - .../samples/sriov_pf_switchdev.yaml | 90 - etc/os-net-config/samples/team.json | 13 - etc/os-net-config/samples/team.yaml | 18 - etc/os-net-config/samples/vdpa.json | 28 - etc/os-net-config/samples/vdpa.yaml | 31 - etc/os-net-config/samples/vpp_bond.json | 23 - etc/os-net-config/samples/vpp_bond.yaml | 17 - etc/os-net-config/samples/vpp_interface.json | 14 - etc/os-net-config/samples/vpp_interface.yaml | 18 - os_net_config/__init__.py | 387 --- os_net_config/cli.py | 365 --- os_net_config/common.py | 302 -- os_net_config/impl_eni.py | 256 -- os_net_config/impl_ifcfg.py | 2011 ------------ os_net_config/impl_iproute.py | 21 - os_net_config/impl_nmstate.py | 1621 --------- os_net_config/objects.py | 1966 ----------- os_net_config/schema.yaml | 1592 --------- os_net_config/sriov_bind_config.py | 137 - os_net_config/sriov_config.py | 816 ----- os_net_config/tests/__init__.py | 0 os_net_config/tests/base.py | 77 - .../environment/netinfo_running_info_1.yaml | 438 --- os_net_config/tests/test_cli.py | 451 --- os_net_config/tests/test_impl_eni.py | 407 --- os_net_config/tests/test_impl_ifcfg.py | 2897 ----------------- os_net_config/tests/test_impl_nmstate.py | 1589 --------- os_net_config/tests/test_objects.py | 2521 -------------- os_net_config/tests/test_os_net_config.py | 30 - os_net_config/tests/test_sriov_bind_config.py | 53 - os_net_config/tests/test_sriov_config.py | 628 ---- os_net_config/tests/test_utils.py | 1015 ------ os_net_config/tests/test_validator.py | 463 --- os_net_config/utils.py | 865 ----- os_net_config/validator.py | 182 -- os_net_config/version.py | 19 - ...route-schema-support-e8e20a8c3b79d14d.yaml | 8 - ...ress-in-sriov-config-06016e4e69b322ca.yaml | 5 - ...vlan_linux_bond_type-0a89f3499a7ab08b.yaml | 8 - ...f-routes-to-be-empty-323690796760630d.yaml | 6 - .../notes/check-ovs-ef665418762ca123.yaml | 5 - ...pdk-on-mellanox-nics-1d8fdb843a4e2b60.yaml | 5 - ...nable-setting-domain-5557e2441c23a5a5.yaml | 5 - ...g-info-nic-discovery-f54ace7639890fdf.yaml | 9 - .../log-mapping-file-8b2a9d8f6a81ba99.yaml | 8 - ...face-without-restart-d55949572017d52f.yaml | 12 - ...policy-based-routing-3fa1200ae155bbee.yaml | 10 - ...fswitch-after-change-0825ea78aae8f138.yaml | 5 - .../retry_ovs-appctl-6734b087ab6db80b.yaml | 6 - .../sriov-vf-in-hosts-529c2bf0cb3294b3.yaml | 7 - releasenotes/source/_static/.placeholder | 0 releasenotes/source/conf.py | 189 -- releasenotes/source/index.rst | 16 - releasenotes/source/queens.rst | 6 - releasenotes/source/rocky.rst | 6 - releasenotes/source/stein.rst | 6 - releasenotes/source/train.rst | 6 - releasenotes/source/unreleased.rst | 5 - releasenotes/source/ussuri.rst | 6 - releasenotes/source/victoria.rst | 6 - releasenotes/source/wallaby.rst | 6 - releasenotes/source/zed.rst | 6 - requirements.txt | 10 - setup.cfg | 31 - setup.py | 21 - test-requirements.txt | 12 - tox.ini | 45 - zuul.d/layout.yaml | 23 - 136 files changed, 8 insertions(+), 24569 deletions(-) delete mode 100644 .coveragerc delete mode 100644 .gitignore delete mode 100644 .mailmap delete mode 100644 .stestr.conf delete mode 100644 CONTRIBUTING.rst delete mode 100644 HACKING.rst delete mode 100644 LICENSE delete mode 100644 babel.cfg delete mode 100644 bindep.txt delete mode 100644 doc/requirements.txt delete mode 100755 doc/source/conf.py delete mode 100644 doc/source/config.rst delete mode 100644 doc/source/contributing.rst delete mode 100644 doc/source/examples.rst delete mode 100644 doc/source/index.rst delete mode 100644 doc/source/installation.rst delete mode 100644 doc/source/readme.rst delete mode 100644 doc/source/usage.rst delete mode 100644 etc/os-net-config/samples/bond.json delete mode 100644 etc/os-net-config/samples/bond.yaml delete mode 100644 etc/os-net-config/samples/bond_mapped.yaml delete mode 100644 etc/os-net-config/samples/bridge_dhcp.json delete mode 100644 etc/os-net-config/samples/bridge_dhcp.yaml delete mode 100644 etc/os-net-config/samples/bridge_fail_mode.json delete mode 100644 etc/os-net-config/samples/bridge_fail_mode.yaml delete mode 100644 etc/os-net-config/samples/bridge_ovs_extra.json delete mode 100644 etc/os-net-config/samples/bridge_ovs_extra.yaml delete mode 100644 etc/os-net-config/samples/bridge_vlan.json delete mode 100644 etc/os-net-config/samples/bridge_vlan.yaml delete mode 100644 etc/os-net-config/samples/contrail_vrouter.json delete mode 100644 etc/os-net-config/samples/contrail_vrouter.yaml delete mode 100644 etc/os-net-config/samples/contrail_vrouter_dpdk.json delete mode 100644 etc/os-net-config/samples/contrail_vrouter_dpdk.yaml delete mode 100644 etc/os-net-config/samples/contrail_vrouter_dpdk_bond.json delete mode 100644 etc/os-net-config/samples/contrail_vrouter_dpdk_bond.yaml delete mode 100644 etc/os-net-config/samples/contrail_vrouter_vlan.json delete mode 100644 etc/os-net-config/samples/contrail_vrouter_vlan.yaml delete mode 100644 etc/os-net-config/samples/ib_child_interface.json delete mode 100644 etc/os-net-config/samples/ib_child_interface.yaml delete mode 100644 etc/os-net-config/samples/ib_interface.json delete mode 100644 etc/os-net-config/samples/ib_interface.yaml delete mode 100644 etc/os-net-config/samples/interface.json delete mode 100644 etc/os-net-config/samples/interface.yaml delete mode 100644 etc/os-net-config/samples/ivs.json delete mode 100644 etc/os-net-config/samples/ivs.yaml delete mode 100644 etc/os-net-config/samples/linux_bond.yaml delete mode 100644 etc/os-net-config/samples/linux_bond_networkmanager.yaml delete mode 100644 etc/os-net-config/samples/linux_bridge.yaml delete mode 100644 etc/os-net-config/samples/linux_tap.json delete mode 100644 etc/os-net-config/samples/linux_tap.yaml delete mode 100644 etc/os-net-config/samples/mapping.yaml delete mode 100644 etc/os-net-config/samples/mapping_mnemonic.yaml delete mode 100644 etc/os-net-config/samples/mapping_report.yaml delete mode 100644 etc/os-net-config/samples/nfvswitch.json delete mode 100644 etc/os-net-config/samples/nfvswitch.yaml delete mode 100644 etc/os-net-config/samples/ovs_dpdk.json delete mode 100644 etc/os-net-config/samples/ovs_dpdk.yaml delete mode 100644 etc/os-net-config/samples/ovs_dpdk_bond.json delete mode 100644 etc/os-net-config/samples/ovs_dpdk_bond.yaml delete mode 100644 etc/os-net-config/samples/ovs_patch_port.json delete mode 100644 etc/os-net-config/samples/ovs_patch_port.yaml delete mode 100644 etc/os-net-config/samples/routes.yaml delete mode 100644 etc/os-net-config/samples/sriov_pf.json delete mode 100644 etc/os-net-config/samples/sriov_pf.yaml delete mode 100644 etc/os-net-config/samples/sriov_pf_ovs_dpdk.json delete mode 100644 etc/os-net-config/samples/sriov_pf_ovs_dpdk.yaml delete mode 100644 etc/os-net-config/samples/sriov_pf_switchdev.json delete mode 100644 etc/os-net-config/samples/sriov_pf_switchdev.yaml delete mode 100644 etc/os-net-config/samples/team.json delete mode 100644 etc/os-net-config/samples/team.yaml delete mode 100644 etc/os-net-config/samples/vdpa.json delete mode 100644 etc/os-net-config/samples/vdpa.yaml delete mode 100644 etc/os-net-config/samples/vpp_bond.json delete mode 100644 etc/os-net-config/samples/vpp_bond.yaml delete mode 100644 etc/os-net-config/samples/vpp_interface.json delete mode 100644 etc/os-net-config/samples/vpp_interface.yaml delete mode 100644 os_net_config/__init__.py delete mode 100644 os_net_config/cli.py delete mode 100644 os_net_config/common.py delete mode 100644 os_net_config/impl_eni.py delete mode 100644 os_net_config/impl_ifcfg.py delete mode 100644 os_net_config/impl_iproute.py delete mode 100644 os_net_config/impl_nmstate.py delete mode 100644 os_net_config/objects.py delete mode 100644 os_net_config/schema.yaml delete mode 100644 os_net_config/sriov_bind_config.py delete mode 100644 os_net_config/sriov_config.py delete mode 100644 os_net_config/tests/__init__.py delete mode 100644 os_net_config/tests/base.py delete mode 100644 os_net_config/tests/environment/netinfo_running_info_1.yaml delete mode 100644 os_net_config/tests/test_cli.py delete mode 100644 os_net_config/tests/test_impl_eni.py delete mode 100644 os_net_config/tests/test_impl_ifcfg.py delete mode 100644 os_net_config/tests/test_impl_nmstate.py delete mode 100644 os_net_config/tests/test_objects.py delete mode 100644 os_net_config/tests/test_os_net_config.py delete mode 100644 os_net_config/tests/test_sriov_bind_config.py delete mode 100644 os_net_config/tests/test_sriov_config.py delete mode 100644 os_net_config/tests/test_utils.py delete mode 100644 os_net_config/tests/test_validator.py delete mode 100644 os_net_config/utils.py delete mode 100644 os_net_config/validator.py delete mode 100644 os_net_config/version.py delete mode 100644 releasenotes/notes/add-neutron-route-schema-support-e8e20a8c3b79d14d.yaml delete mode 100644 releasenotes/notes/add-pci-address-in-sriov-config-06016e4e69b322ca.yaml delete mode 100644 releasenotes/notes/add_contrail_vrouter_vlan_linux_bond_type-0a89f3499a7ab08b.yaml delete mode 100644 releasenotes/notes/allow-list-of-routes-to-be-empty-323690796760630d.yaml delete mode 100644 releasenotes/notes/check-ovs-ef665418762ca123.yaml delete mode 100644 releasenotes/notes/dpdk-on-mellanox-nics-1d8fdb843a4e2b60.yaml delete mode 100644 releasenotes/notes/enable-setting-domain-5557e2441c23a5a5.yaml delete mode 100644 releasenotes/notes/log-info-nic-discovery-f54ace7639890fdf.yaml delete mode 100644 releasenotes/notes/log-mapping-file-8b2a9d8f6a81ba99.yaml delete mode 100644 releasenotes/notes/modify-interface-without-restart-d55949572017d52f.yaml delete mode 100644 releasenotes/notes/policy-based-routing-3fa1200ae155bbee.yaml delete mode 100644 releasenotes/notes/restart-ivs-nvfswitch-after-change-0825ea78aae8f138.yaml delete mode 100644 releasenotes/notes/retry_ovs-appctl-6734b087ab6db80b.yaml delete mode 100644 releasenotes/notes/sriov-vf-in-hosts-529c2bf0cb3294b3.yaml delete mode 100644 releasenotes/source/_static/.placeholder delete mode 100644 releasenotes/source/conf.py delete mode 100644 releasenotes/source/index.rst delete mode 100644 releasenotes/source/queens.rst delete mode 100644 releasenotes/source/rocky.rst delete mode 100644 releasenotes/source/stein.rst delete mode 100644 releasenotes/source/train.rst delete mode 100644 releasenotes/source/unreleased.rst delete mode 100644 releasenotes/source/ussuri.rst delete mode 100644 releasenotes/source/victoria.rst delete mode 100644 releasenotes/source/wallaby.rst delete mode 100644 releasenotes/source/zed.rst delete mode 100644 requirements.txt delete mode 100644 setup.cfg delete mode 100644 setup.py delete mode 100644 test-requirements.txt delete mode 100644 tox.ini delete mode 100644 zuul.d/layout.yaml 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 -