os-vif 4.2.1__tar.gz → 4.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of os-vif might be problematic. Click here for more details.

Files changed (187) hide show
  1. {os_vif-4.2.1 → os_vif-4.3.0}/.zuul.yaml +0 -11
  2. {os_vif-4.2.1 → os_vif-4.3.0}/AUTHORS +2 -0
  3. {os_vif-4.2.1 → os_vif-4.3.0}/ChangeLog +10 -0
  4. {os_vif-4.2.1 → os_vif-4.3.0}/PKG-INFO +11 -2
  5. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/internal/ip/ip_command.py +6 -2
  6. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/internal/ip/linux/impl_pyroute2.py +10 -1
  7. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/objects/vif.py +25 -5
  8. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/tests/functional/internal/command/ip/test_impl_pyroute2.py +111 -0
  9. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/tests/unit/internal/ip/linux/test_impl_pyroute2.py +66 -0
  10. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/tests/unit/test_objects.py +60 -3
  11. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif.egg-info/PKG-INFO +11 -2
  12. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif.egg-info/SOURCES.txt +2 -0
  13. os_vif-4.3.0/os_vif.egg-info/pbr.json +1 -0
  14. os_vif-4.3.0/releasenotes/notes/add-tap-creation-support-2069718-abc123.yaml +24 -0
  15. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/source/2024.1.rst +1 -1
  16. os_vif-4.3.0/releasenotes/source/2025.2.rst +6 -0
  17. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/source/index.rst +1 -0
  18. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_ovs/exception.py +6 -0
  19. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_ovs/linux_net.py +23 -0
  20. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_ovs/ovs.py +58 -1
  21. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_ovs/tests/functional/ovsdb/test_ovsdb_lib.py +1 -6
  22. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_ovs/tests/functional/test_plugin.py +57 -0
  23. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_ovs/tests/unit/test_linux_net.py +44 -0
  24. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_ovs/tests/unit/test_plugin.py +266 -0
  25. os_vif-4.2.1/os_vif.egg-info/pbr.json +0 -1
  26. {os_vif-4.2.1 → os_vif-4.3.0}/.coveragerc +0 -0
  27. {os_vif-4.2.1 → os_vif-4.3.0}/.mailmap +0 -0
  28. {os_vif-4.2.1 → os_vif-4.3.0}/.pre-commit-config.yaml +0 -0
  29. {os_vif-4.2.1 → os_vif-4.3.0}/.stestr.conf +0 -0
  30. {os_vif-4.2.1 → os_vif-4.3.0}/CONTRIBUTING.rst +0 -0
  31. {os_vif-4.2.1 → os_vif-4.3.0}/HACKING.rst +0 -0
  32. {os_vif-4.2.1 → os_vif-4.3.0}/LICENSE +0 -0
  33. {os_vif-4.2.1 → os_vif-4.3.0}/README.rst +0 -0
  34. {os_vif-4.2.1 → os_vif-4.3.0}/bindep.txt +0 -0
  35. {os_vif-4.2.1 → os_vif-4.3.0}/doc/requirements.txt +0 -0
  36. {os_vif-4.2.1 → os_vif-4.3.0}/doc/source/conf.py +0 -0
  37. {os_vif-4.2.1 → os_vif-4.3.0}/doc/source/contributor/contributing.rst +0 -0
  38. {os_vif-4.2.1 → os_vif-4.3.0}/doc/source/index.rst +0 -0
  39. {os_vif-4.2.1 → os_vif-4.3.0}/doc/source/reference/glossary.rst +0 -0
  40. {os_vif-4.2.1 → os_vif-4.3.0}/doc/source/user/host-info.rst +0 -0
  41. {os_vif-4.2.1 → os_vif-4.3.0}/doc/source/user/plugins/linux-bridge.rst +0 -0
  42. {os_vif-4.2.1 → os_vif-4.3.0}/doc/source/user/plugins/noop.rst +0 -0
  43. {os_vif-4.2.1 → os_vif-4.3.0}/doc/source/user/plugins/ovs.rst +0 -0
  44. {os_vif-4.2.1 → os_vif-4.3.0}/doc/source/user/usage.rst +0 -0
  45. {os_vif-4.2.1 → os_vif-4.3.0}/doc/source/user/vif-types.rst +0 -0
  46. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/__init__.py +0 -0
  47. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/exception.py +0 -0
  48. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/i18n.py +0 -0
  49. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/internal/__init__.py +0 -0
  50. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/internal/ip/__init__.py +0 -0
  51. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/internal/ip/api.py +0 -0
  52. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/internal/ip/linux/__init__.py +0 -0
  53. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/objects/__init__.py +0 -0
  54. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/objects/base.py +0 -0
  55. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/objects/fields.py +0 -0
  56. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/objects/fixed_ip.py +0 -0
  57. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/objects/host_info.py +0 -0
  58. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/objects/instance_info.py +0 -0
  59. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/objects/network.py +0 -0
  60. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/objects/route.py +0 -0
  61. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/objects/subnet.py +0 -0
  62. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/opts.py +0 -0
  63. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/plugin.py +0 -0
  64. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/tests/__init__.py +0 -0
  65. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/tests/functional/__init__.py +0 -0
  66. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/tests/functional/base.py +0 -0
  67. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/tests/functional/internal/__init__.py +0 -0
  68. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/tests/functional/internal/command/__init__.py +0 -0
  69. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/tests/functional/internal/command/ip/__init__.py +0 -0
  70. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/tests/functional/privsep.py +0 -0
  71. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/tests/unit/__init__.py +0 -0
  72. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/tests/unit/base.py +0 -0
  73. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/tests/unit/internal/__init__.py +0 -0
  74. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/tests/unit/internal/ip/__init__.py +0 -0
  75. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/tests/unit/internal/ip/linux/__init__.py +0 -0
  76. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/tests/unit/internal/ip/test_api.py +0 -0
  77. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/tests/unit/test_base.py +0 -0
  78. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/tests/unit/test_exception.py +0 -0
  79. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/tests/unit/test_host_info.py +0 -0
  80. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/tests/unit/test_os_vif.py +0 -0
  81. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/tests/unit/test_vif.py +0 -0
  82. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/utils.py +0 -0
  83. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif/version.py +0 -0
  84. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif.egg-info/dependency_links.txt +0 -0
  85. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif.egg-info/entry_points.txt +0 -0
  86. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif.egg-info/not-zip-safe +0 -0
  87. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif.egg-info/requires.txt +0 -0
  88. {os_vif-4.2.1 → os_vif-4.3.0}/os_vif.egg-info/top_level.txt +0 -0
  89. {os_vif-4.2.1 → os_vif-4.3.0}/playbooks/openstack-tox-functional-ovs-with-sudo/Debian.yaml +0 -0
  90. {os_vif-4.2.1 → os_vif-4.3.0}/playbooks/openstack-tox-functional-ovs-with-sudo/Gentoo.yaml +0 -0
  91. {os_vif-4.2.1 → os_vif-4.3.0}/playbooks/openstack-tox-functional-ovs-with-sudo/RedHat.yaml +0 -0
  92. {os_vif-4.2.1 → os_vif-4.3.0}/playbooks/openstack-tox-functional-ovs-with-sudo/Suse.yaml +0 -0
  93. {os_vif-4.2.1 → os_vif-4.3.0}/playbooks/openstack-tox-functional-ovs-with-sudo/pre.yaml +0 -0
  94. {os_vif-4.2.1 → os_vif-4.3.0}/pyproject.toml +0 -0
  95. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/OVSVif-hybrid-unplug-f37bf57bc8e913de.yaml +0 -0
  96. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/add-abstract-ovsdb-api-8f04df58d4ed5b73.yaml +0 -0
  97. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/add-fast-path-vhostuser-support-fe87e558326909b6.yaml +0 -0
  98. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/add-no-op-plugin-763a6703e7328a24.yaml +0 -0
  99. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/add-ovs-representor-portprofile-5f8290e5a40bf0a4.yaml +0 -0
  100. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/add-ovs-vhostuser-support-2ba8de51c1f3a244.yaml +0 -0
  101. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/add-ovsdb-native-322fffb49c91503d.yaml +0 -0
  102. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/always-plug-vifs-for-ovs-1d033fc49a9c6c4e.yaml +0 -0
  103. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/brctl-removal-a5b0e69b865afa57.yaml +0 -0
  104. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/bug-1892132-812e6d5ce0588ebb.yaml +0 -0
  105. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/contextlib-and-nested-with-statements-2747a9ebb9a5bfd7.yaml +0 -0
  106. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/default-qos-policy-for-ovs-26f8806046a59c82.yaml +0 -0
  107. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/default-to-native-ovsdb-driver-112fb5adf6e19a30.yaml +0 -0
  108. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/deprecate-linuxbridge-support-d278d4bbdff8e8bc.yaml +0 -0
  109. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/deprecate-windows-support-49f5ca1b1a1f4d66.yaml +0 -0
  110. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/do-not-force-mac-ageing-c6e8d750130c5740.yaml +0 -0
  111. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/drop-py36-support-0e9b07073f6ad73f.yaml +0 -0
  112. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/drop-python2-support-7a4bc7d31253c1e5.yaml +0 -0
  113. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/ensure-ovs-bridge-a0c1b51f469c92d0.yaml +0 -0
  114. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/extend-vhostuser-object-fada14a1457d4e56.yaml +0 -0
  115. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/fix-broken-dataplane-on-nova-restart-with-isolate_vif-71617a41741b33e8.yaml +0 -0
  116. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/fix-ovs-plugin-describe-049750609559f1ba.yaml +0 -0
  117. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/fix-stevedore-entrypoints-8002ec7a5166c977.yaml +0 -0
  118. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/fix-vif-openvswitch-fa0d19be9dd668e1.yaml +0 -0
  119. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/generic-datapath-offloads-41cabb6842b41533.yaml +0 -0
  120. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/initial-release-2c71d6bbf55f763b.yaml +0 -0
  121. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/oslo-config-opts-entrypoints-e83f907b686d774a.yaml +0 -0
  122. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/per-port-bridge-c6a50179a0256de3.yaml +0 -0
  123. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/port-profile-info-linux-bridge-4800f5a0b7328615.yaml +0 -0
  124. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/port-profile-info-ovs-63b46a3eafc11de2.yaml +0 -0
  125. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/prevent-lb-reply-arp-6459133bfb056069.yaml +0 -0
  126. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/remove-py38-e0701b3363079bbf.yaml +0 -0
  127. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/remove-windows-23df1c587d505d72.yaml +0 -0
  128. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/remove_iptools_implementation-2eb866573a680e61.yaml +0 -0
  129. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/revert-always-plug-port-for-ovs-hybrid-plug-false-dc015985cbc5443b.yaml +0 -0
  130. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/vhost-user-mtu-support-cbc7d02a6665fab1.yaml +0 -0
  131. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/notes/vhost-user-reconnect-fa4cbb731b787f71.yaml +0 -0
  132. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/source/2023.1.rst +0 -0
  133. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/source/2023.2.rst +0 -0
  134. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/source/2024.2.rst +0 -0
  135. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/source/2025.1.rst +0 -0
  136. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/source/_static/.placeholder +0 -0
  137. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/source/_templates/.placeholder +0 -0
  138. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/source/conf.py +0 -0
  139. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/source/newton.rst +0 -0
  140. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/source/ocata.rst +0 -0
  141. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/source/pike.rst +0 -0
  142. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/source/queens.rst +0 -0
  143. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/source/rocky.rst +0 -0
  144. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/source/stein.rst +0 -0
  145. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/source/train.rst +0 -0
  146. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/source/unreleased.rst +0 -0
  147. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/source/ussuri.rst +0 -0
  148. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/source/victoria.rst +0 -0
  149. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/source/wallaby.rst +0 -0
  150. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/source/xena.rst +0 -0
  151. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/source/yoga.rst +0 -0
  152. {os_vif-4.2.1 → os_vif-4.3.0}/releasenotes/source/zed.rst +0 -0
  153. {os_vif-4.2.1 → os_vif-4.3.0}/requirements.txt +0 -0
  154. {os_vif-4.2.1 → os_vif-4.3.0}/setup.cfg +0 -0
  155. {os_vif-4.2.1 → os_vif-4.3.0}/setup.py +0 -0
  156. {os_vif-4.2.1 → os_vif-4.3.0}/test-requirements.txt +0 -0
  157. {os_vif-4.2.1 → os_vif-4.3.0}/tox.ini +0 -0
  158. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_linux_bridge/__init__.py +0 -0
  159. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_linux_bridge/constants.py +0 -0
  160. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_linux_bridge/iptables.py +0 -0
  161. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_linux_bridge/linux_bridge.py +0 -0
  162. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_linux_bridge/linux_net.py +0 -0
  163. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_linux_bridge/privsep.py +0 -0
  164. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_linux_bridge/tests/__init__.py +0 -0
  165. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_linux_bridge/tests/unit/__init__.py +0 -0
  166. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_linux_bridge/tests/unit/test_linux_net.py +0 -0
  167. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_linux_bridge/tests/unit/test_plugin.py +0 -0
  168. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_noop/__init__.py +0 -0
  169. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_noop/noop.py +0 -0
  170. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_noop/tests/__init__.py +0 -0
  171. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_noop/tests/unit/__init__.py +0 -0
  172. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_noop/tests/unit/test_plugin.py +0 -0
  173. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_ovs/__init__.py +0 -0
  174. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_ovs/constants.py +0 -0
  175. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_ovs/ovsdb/__init__.py +0 -0
  176. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_ovs/ovsdb/api.py +0 -0
  177. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_ovs/ovsdb/impl_idl.py +0 -0
  178. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_ovs/ovsdb/impl_vsctl.py +0 -0
  179. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_ovs/ovsdb/ovsdb_lib.py +0 -0
  180. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_ovs/privsep.py +0 -0
  181. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_ovs/tests/__init__.py +0 -0
  182. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_ovs/tests/functional/__init__.py +0 -0
  183. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_ovs/tests/functional/base.py +0 -0
  184. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_ovs/tests/functional/ovsdb/__init__.py +0 -0
  185. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_ovs/tests/unit/__init__.py +0 -0
  186. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_ovs/tests/unit/ovsdb/__init__.py +0 -0
  187. {os_vif-4.2.1 → os_vif-4.3.0}/vif_plug_ovs/tests/unit/ovsdb/test_ovsdb_lib.py +0 -0
@@ -119,15 +119,6 @@
119
119
  os_vif_ovs:
120
120
  per_port_bridge: true
121
121
 
122
- # TODO(gmann): As per the 2025.1 testing runtime, we need to run at least
123
- # one job on Focal. This job can be removed in the nexy cycle (2025.2)
124
- - job:
125
- name: os-vif-ovn-ubuntu-jammy
126
- description: |
127
- os-vif ovn job (tests hybrid-plug=false) testing on Ubuntu Focal(20.04)
128
- parent: os-vif-ovn
129
- nodeset: openstack-single-node-jammy
130
-
131
122
  - project:
132
123
  templates:
133
124
  - check-requirements
@@ -139,11 +130,9 @@
139
130
  jobs:
140
131
  - openstack-tox-functional-ovs-with-sudo
141
132
  - os-vif-ovn
142
- - os-vif-ovn-ubuntu-jammy
143
133
  - os-vif-ovs-iptables
144
134
  gate:
145
135
  jobs:
146
136
  - openstack-tox-functional-ovs-with-sudo
147
137
  - os-vif-ovn
148
- - os-vif-ovn-ubuntu-jammy
149
138
  - os-vif-ovs-iptables
@@ -1,8 +1,10 @@
1
1
  Adrian Chiris <adrianc@mellanox.com>
2
+ Adrien Cunin <a.cunin@syseleven.de>
2
3
  Alin Balutoiu <abalutoiu@cloudbasesolutions.com>
3
4
  Andreas Jaeger <aj@suse.com>
4
5
  Balazs Gibizer <gibi@redhat.com>
5
6
  Bence Romsics <bence.romsics@gmail.com>
7
+ Bodo Petermann <b.petermann@syseleven.de>
6
8
  Brian Haley <brian.haley@hpe.com>
7
9
  Cao Xuan Hoang <hoangcx@vn.fujitsu.com>
8
10
  Carlos Goncalves <cgoncalves@redhat.com>
@@ -1,6 +1,16 @@
1
1
  CHANGES
2
2
  =======
3
3
 
4
+ 4.3.0
5
+ -----
6
+
7
+ * Add TAP device pre-creation support for OVS/OVN
8
+ * Fixed bridge name when per\_port\_bridge is used
9
+ * Stabilize functional test
10
+ * reno: Update master for unmaintained/2024.1
11
+ * Update master for stable/2025.2
12
+ * Remove remaining job with Ubuntu Jammy (22.04)
13
+
4
14
  4.2.1
5
15
  -----
6
16
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: os_vif
3
- Version: 4.2.1
3
+ Version: 4.3.0
4
4
  Summary: A library for plugging and unplugging virtual interfaces in OpenStack.
5
5
  Home-page: https://docs.openstack.org/os-vif/latest/
6
6
  Author: OpenStack
@@ -33,6 +33,15 @@ Requires-Dist: ovsdbapp>=0.12.1
33
33
  Requires-Dist: pyroute2>=0.5.2
34
34
  Requires-Dist: stevedore>=1.20.0
35
35
  Requires-Dist: debtcollector>=1.19.0
36
+ Dynamic: author
37
+ Dynamic: author-email
38
+ Dynamic: classifier
39
+ Dynamic: description
40
+ Dynamic: home-page
41
+ Dynamic: license-file
42
+ Dynamic: requires-dist
43
+ Dynamic: requires-python
44
+ Dynamic: summary
36
45
 
37
46
  ========================
38
47
  Team and repository tags
@@ -18,6 +18,7 @@ class IpCommand(metaclass=abc.ABCMeta):
18
18
  TYPE_VETH = 'veth'
19
19
  TYPE_VLAN = 'vlan'
20
20
  TYPE_BRIDGE = 'bridge'
21
+ TYPE_TUNTAP = 'tuntap'
21
22
 
22
23
  @abc.abstractmethod
23
24
  def set(self, device, check_exit_code=None, state=None, mtu=None,
@@ -37,11 +38,12 @@ class IpCommand(metaclass=abc.ABCMeta):
37
38
 
38
39
  @abc.abstractmethod
39
40
  def add(self, device, dev_type, check_exit_code=None, peer=None, link=None,
40
- vlan_id=None, ageing=None):
41
+ vlan_id=None, ageing=None, mode=None, multiqueue=False):
41
42
  """Method to add an interface.
42
43
 
43
44
  :param device: A network device (string)
44
- :param dev_type: String network device type (TYPE_VETH, TYPE_VLAN)
45
+ :param dev_type: String network device type (TYPE_VETH, TYPE_VLAN,
46
+ TYPE_BRIDGE, TYPE_TUNTAP)
45
47
  :param check_exit_code: List of integers of allowed execution exit
46
48
  codes
47
49
  :param peer: String peer name, for veth interfaces
@@ -50,6 +52,8 @@ class IpCommand(metaclass=abc.ABCMeta):
50
52
  :param vlan_id: Integer VLAN ID for VLAN devices
51
53
  :param ageing: integer value in seconds before learned
52
54
  mac addresses are forgotten.
55
+ :param mode: String mode for tuntap devices ('tap' or 'tun')
56
+ :param multiqueue: Boolean to enable multiqueue for tuntap devices
53
57
  :return: status of the command execution
54
58
  """
55
59
 
@@ -74,7 +74,7 @@ class PyRoute2(ip_command.IpCommand):
74
74
  return idx[0]
75
75
 
76
76
  def add(self, device, dev_type, check_exit_code=None, peer=None, link=None,
77
- vlan_id=None, ageing=None):
77
+ vlan_id=None, ageing=None, mode=None, multiqueue=False):
78
78
  check_exit_code = check_exit_code or []
79
79
  with iproute.IPRoute() as ip:
80
80
  args = {'ifname': device,
@@ -102,6 +102,15 @@ class PyRoute2(ip_command.IpCommand):
102
102
  # what policy to use and keep this code generic.
103
103
  if ageing is not None:
104
104
  args['IFLA_BR_AGEING_TIME'] = ageing
105
+ elif self.TYPE_TUNTAP == dev_type:
106
+ # Set mode (default to 'tap' if not specified)
107
+ # This matches the 'ip tuntap add' command behavior
108
+ tap_mode = mode if mode else 'tap'
109
+ args['mode'] = tap_mode
110
+ # Enable multiqueue if requested
111
+ # This sets the IFF_MULTI_QUEUE flag in IFTUN_IFR
112
+ if multiqueue:
113
+ args['multi_queue'] = True
105
114
  else:
106
115
  raise exception.NetworkInterfaceTypeNotDefined(type=dev_type)
107
116
 
@@ -327,7 +327,8 @@ class VIFPortProfileOpenVSwitch(VIFPortProfileBase):
327
327
  # Version 1.1: Added 'datapath_type'
328
328
  # Version 1.2: VIFPortProfileBase updated to 1.1 from 1.0
329
329
  # Version 1.3: Added 'create_port'
330
- VERSION = '1.3'
330
+ # Version 1.4: Added 'create_tap' and 'multiqueue'
331
+ VERSION = '1.4'
331
332
 
332
333
  fields = {
333
334
  #: A UUID to uniquely identify the interface. If omitted one will be
@@ -342,10 +343,21 @@ class VIFPortProfileOpenVSwitch(VIFPortProfileBase):
342
343
 
343
344
  #: Whether the os-vif plugin should add the port to the bridge.
344
345
  'create_port': fields.BooleanField(default=False),
346
+
347
+ #: Whether the os-vif plugin should create the TAP device.
348
+ 'create_tap': fields.BooleanField(default=False),
349
+
350
+ #: Whether to enable multiqueue on the TAP device.
351
+ 'multiqueue': fields.BooleanField(default=False),
345
352
  }
346
353
 
347
354
  def obj_make_compatible(self, primitive, target_version):
348
355
  target_version = versionutils.convert_version_to_tuple(target_version)
356
+ if target_version < (1, 4):
357
+ if 'create_tap' in primitive:
358
+ del primitive['create_tap']
359
+ if 'multiqueue' in primitive:
360
+ del primitive['multiqueue']
349
361
  if target_version < (1, 3) and 'create_port' in primitive:
350
362
  del primitive['create_port']
351
363
  if target_version < (1, 1) and 'datapath_type' in primitive:
@@ -370,7 +382,8 @@ class VIFPortProfileFPOpenVSwitch(VIFPortProfileOpenVSwitch):
370
382
  # Version 1.1: VIFPortProfileOpenVSwitch updated to 1.1 from 1.0
371
383
  # Version 1.2: VIFPortProfileOpenVSwitch updated to 1.2 from 1.1
372
384
  # Version 1.3: VIFPortProfileOpenVSwitch updated to 1.3 from 1.2
373
- VERSION = '1.3'
385
+ # Version 1.4: VIFPortProfileOpenVSwitch updated to 1.4 from 1.3
386
+ VERSION = '1.4'
374
387
 
375
388
  fields = {
376
389
  #: Name of the bridge (managed by fast path) to connect to.
@@ -391,9 +404,12 @@ class VIFPortProfileFPOpenVSwitch(VIFPortProfileOpenVSwitch):
391
404
  elif target_version < (1, 3):
392
405
  super(VIFPortProfileFPOpenVSwitch, self).obj_make_compatible(
393
406
  primitive, '1.2')
394
- else:
407
+ elif target_version < (1, 4):
395
408
  super(VIFPortProfileFPOpenVSwitch, self).obj_make_compatible(
396
409
  primitive, '1.3')
410
+ else:
411
+ super(VIFPortProfileFPOpenVSwitch, self).obj_make_compatible(
412
+ primitive, '1.4')
397
413
 
398
414
 
399
415
  @removals.removed_class("VIFPortProfileOVSRepresentor",
@@ -421,7 +437,8 @@ class VIFPortProfileOVSRepresentor(VIFPortProfileOpenVSwitch):
421
437
  # Version 1.1: VIFPortProfileOpenVSwitch updated to 1.1 from 1.0
422
438
  # Version 1.2: VIFPortProfileOpenVSwitch updated to 1.2 from 1.1
423
439
  # Version 1.3: VIFPortProfileOpenVSwitch updated to 1.3 from 1.2
424
- VERSION = '1.3'
440
+ # Version 1.4: VIFPortProfileOpenVSwitch updated to 1.4 from 1.3
441
+ VERSION = '1.4'
425
442
 
426
443
  fields = {
427
444
  #: Name to set on the representor (if set).
@@ -442,9 +459,12 @@ class VIFPortProfileOVSRepresentor(VIFPortProfileOpenVSwitch):
442
459
  elif target_version < (1, 3):
443
460
  super(VIFPortProfileOVSRepresentor, self).obj_make_compatible(
444
461
  primitive, '1.2')
445
- else:
462
+ elif target_version < (1, 4):
446
463
  super(VIFPortProfileOVSRepresentor, self).obj_make_compatible(
447
464
  primitive, '1.3')
465
+ else:
466
+ super(VIFPortProfileOVSRepresentor, self).obj_make_compatible(
467
+ primitive, '1.4')
448
468
 
449
469
 
450
470
  @base.VersionedObjectRegistry.register
@@ -81,6 +81,22 @@ class ShellIpCommands(object):
81
81
  return
82
82
  return match.group('state')
83
83
 
84
+ def is_admin_up(self, device):
85
+ """Check if device is administratively up (UP flag set).
86
+
87
+ This differs from show_state() which returns the operational state.
88
+ TAP devices without a carrier will have state=DOWN but can still
89
+ be administratively UP (UP in flags like <NO-CARRIER,BROADCAST,UP>).
90
+ """
91
+ # Flags are in angle brackets on the first line, e.g. <NO-CARRIER,UP>
92
+ first_line = self.show_device(device)[0]
93
+ regex = re.compile(r".*<(?P<flags>[^>]+)>")
94
+ match = regex.match(first_line)
95
+ if match is None:
96
+ return False
97
+ flags = match.group('flags').split(',')
98
+ return 'UP' in flags
99
+
84
100
  def show_promisc(self, device):
85
101
  regex = re.compile(r".*(PROMISC)")
86
102
  match = regex.match(self.show_device(device)[0])
@@ -263,3 +279,98 @@ class TestIpCommand(ShellIpCommands, base.BaseFunctionalTestCase):
263
279
  _ip_cmd_set(device, master=bridge)
264
280
  path = "/sys/class/net/{}/brif/{}".format(bridge, device)
265
281
  self.assertTrue(os.path.exists(path))
282
+
283
+ def test_add_tap(self):
284
+ """Test creating a tap device."""
285
+ device = "test_tap_1"
286
+ self.addCleanup(self.del_device, device)
287
+ _ip_cmd_add(device, 'tuntap', mode='tap')
288
+ self.assertTrue(self.exist_device(device))
289
+
290
+ # Verify it's a tap device by checking /sys/class/net/<dev>/tun_flags
291
+ tun_flags_path = "/sys/class/net/{}/tun_flags".format(device)
292
+ if os.path.exists(tun_flags_path):
293
+ with open(tun_flags_path, 'r') as f:
294
+ flags_hex = f.read().strip()
295
+ flags = int(flags_hex, 16)
296
+ # IFF_TAP = 0x0002
297
+ IFF_TAP = 0x0002
298
+ self.assertTrue(flags & IFF_TAP,
299
+ "TAP flag not set. Flags: {}".format(flags_hex))
300
+
301
+ def test_add_tap_with_multiqueue(self):
302
+ """Test creating a tap device with multiqueue parameter.
303
+
304
+ Note: The IFF_MULTI_QUEUE flag (0x0100) cannot be set via netlink.
305
+ It is only set when a process opens /dev/net/tun with the
306
+ IFF_MULTI_QUEUE flag in the ioctl. Libvirt sets this when attaching
307
+ to the TAP device. This test verifies that:
308
+ 1. The TAP device can be created with multiqueue=True without error
309
+ 2. The device is properly created as a TAP device
310
+ """
311
+ device = "test_tap_mq"
312
+ self.addCleanup(self.del_device, device)
313
+ _ip_cmd_add(device, 'tuntap', mode='tap', multiqueue=True)
314
+ self.assertTrue(self.exist_device(device))
315
+
316
+ # Verify it's a tap device by checking /sys/class/net/<dev>/tun_flags
317
+ tun_flags_path = "/sys/class/net/{}/tun_flags".format(device)
318
+ if os.path.exists(tun_flags_path):
319
+ with open(tun_flags_path, 'r') as f:
320
+ flags_hex = f.read().strip()
321
+ flags = int(flags_hex, 16)
322
+ # IFF_TAP = 0x0002 - verify it's a TAP device
323
+ IFF_TAP = 0x0002
324
+ self.assertTrue(
325
+ flags & IFF_TAP,
326
+ "TAP flag not set. Flags: %s" % flags_hex)
327
+
328
+ def test_add_tap_idempotent(self):
329
+ """Test tap device creation is idempotent with exit code handling."""
330
+ device = "test_tap_idemp"
331
+ self.addCleanup(self.del_device, device)
332
+
333
+ # Create the device
334
+ _ip_cmd_add(device, 'tuntap', mode='tap')
335
+ self.assertTrue(self.exist_device(device))
336
+
337
+ # Try to create again with EEXIST in check_exit_code (17)
338
+ # This should not raise an exception
339
+ _ip_cmd_add(device, 'tuntap', mode='tap', check_exit_code=[0, 17])
340
+ self.assertTrue(self.exist_device(device))
341
+
342
+ def test_add_tun_device(self):
343
+ """Test creating a tun device (not tap)."""
344
+ device = "test_tun_1"
345
+ self.addCleanup(self.del_device, device)
346
+ _ip_cmd_add(device, 'tuntap', mode='tun')
347
+ self.assertTrue(self.exist_device(device))
348
+
349
+ # Verify it's a tun device
350
+ tun_flags_path = "/sys/class/net/{}/tun_flags".format(device)
351
+ if os.path.exists(tun_flags_path):
352
+ with open(tun_flags_path, 'r') as f:
353
+ flags_hex = f.read().strip()
354
+ flags = int(flags_hex, 16)
355
+ # IFF_TUN = 0x0001
356
+ IFF_TUN = 0x0001
357
+ self.assertTrue(flags & IFF_TUN,
358
+ "TUN flag not set. Flags: {}".format(flags_hex))
359
+
360
+ def test_tap_set_properties(self):
361
+ """Test setting properties on a tap device."""
362
+ device = "test_tap_props"
363
+ mac = "36:a7:e4:f9:01:02"
364
+ self.addCleanup(self.del_device, device)
365
+
366
+ # Create tap device
367
+ _ip_cmd_add(device, 'tuntap', mode='tap')
368
+ self.assertTrue(self.exist_device(device))
369
+
370
+ # Set MAC address and state
371
+ _ip_cmd_set(device, address=mac, state='up')
372
+ # TAP devices without a carrier will show state=DOWN but should be
373
+ # administratively UP (UP flag in interface flags)
374
+ self.assertTrue(self.is_admin_up(device),
375
+ "Device should be administratively UP")
376
+ self.assertEqual(mac, self.show_mac(device))
@@ -175,3 +175,69 @@ class TestIpCommand(base.TestCase):
175
175
 
176
176
  self.assertRaises(ipexc.NetlinkError, self.ip.delete, self.DEVICE,
177
177
  check_exit_code=[self.OTHER_ERROR_CODE])
178
+
179
+ def test_add_tap(self):
180
+ """Test creating a basic tap device."""
181
+ self.ip.add(self.DEVICE, 'tuntap', mode='tap')
182
+ args = {'ifname': self.DEVICE,
183
+ 'kind': 'tuntap',
184
+ 'mode': 'tap'}
185
+ self.ip_link.assert_called_once_with('add', **args)
186
+
187
+ def test_add_tap_default_mode(self):
188
+ """Test creating tap device with default mode (should be 'tap')."""
189
+ self.ip.add(self.DEVICE, 'tuntap')
190
+ args = {'ifname': self.DEVICE,
191
+ 'kind': 'tuntap',
192
+ 'mode': 'tap'}
193
+ self.ip_link.assert_called_once_with('add', **args)
194
+
195
+ def test_add_tap_with_multiqueue(self):
196
+ """Test creating tap device with multiqueue enabled."""
197
+ self.ip.add(self.DEVICE, 'tuntap', mode='tap', multiqueue=True)
198
+
199
+ # Verify the call includes multiqueue flag
200
+ args = {'ifname': self.DEVICE,
201
+ 'kind': 'tuntap',
202
+ 'mode': 'tap',
203
+ 'multi_queue': True}
204
+ self.ip_link.assert_called_once_with('add', **args)
205
+
206
+ def test_add_tun_device(self):
207
+ """Test creating a tun device (not tap)."""
208
+ self.ip.add(self.DEVICE, 'tuntap', mode='tun')
209
+ args = {'ifname': self.DEVICE,
210
+ 'kind': 'tuntap',
211
+ 'mode': 'tun'}
212
+ self.ip_link.assert_called_once_with('add', **args)
213
+
214
+ def test_add_tap_exit_code(self):
215
+ """Test tap device creation with exit code handling."""
216
+ self.ip_link.side_effect = ipexc.NetlinkError(self.ERROR_CODE,
217
+ msg="Error message")
218
+
219
+ # Should not raise when error code matches
220
+ self.ip.add(self.DEVICE, 'tuntap', mode='tap',
221
+ check_exit_code=[self.ERROR_CODE])
222
+ self.ip_link.assert_called_once()
223
+
224
+ # Should raise when exit code doesn't match
225
+ self.assertRaises(
226
+ ipexc.NetlinkError,
227
+ self.ip.add, self.DEVICE, 'tuntap', mode='tap',
228
+ check_exit_code=[self.OTHER_ERROR_CODE])
229
+
230
+ def test_set_no_multiqueue_parameter(self):
231
+ """Verify set() no longer accepts multiqueue parameter."""
232
+ with mock.patch.object(
233
+ iproute.IPRoute, 'link_lookup', return_value=[1],
234
+ create=True):
235
+ self.ip_link.return_value = [{'flags': 0}]
236
+
237
+ # Should work without multiqueue
238
+ self.ip.set(self.DEVICE, state=self.UP, mtu=self.MTU,
239
+ address=self.MAC)
240
+
241
+ # Should raise TypeError if multiqueue is passed
242
+ self.assertRaises(TypeError, self.ip.set, self.DEVICE,
243
+ multiqueue=True)
@@ -40,12 +40,12 @@ object_data = {
40
40
  'VIFPortProfile8021Qbg': '1.1-b3011621809dca9216b50579ce9d6b19',
41
41
  'VIFPortProfile8021Qbh': '1.1-226b61b2e76ba452f7b31530cff80ac9',
42
42
  'VIFPortProfileBase': '1.1-4982d1621df12ebd1f3b07948f3d0e5f',
43
- 'VIFPortProfileOpenVSwitch': '1.3-1ad9a350a9cae19c977d21fcce7c8c7f',
44
- 'VIFPortProfileFPOpenVSwitch': '1.3-06c425743430e7702ef112e09b987346',
43
+ 'VIFPortProfileOpenVSwitch': '1.4-54fb321f2b70c37d392fadc226c889e7',
44
+ 'VIFPortProfileFPOpenVSwitch': '1.4-20904c1dcdac0641cabf7b02525973bd',
45
45
  'VIFPortProfileFPBridge': '1.1-49f1952bf50bab7a95112c908534751f',
46
46
  'VIFPortProfileFPTap': '1.1-fd178229477604dfb65de5ce929488e5',
47
47
  'VIFVHostUser': '1.1-1f95b43be1f884f090ca1f4d79adfd35',
48
- 'VIFPortProfileOVSRepresentor': '1.3-f625e17143473b93d6c7f97ded9f785a',
48
+ 'VIFPortProfileOVSRepresentor': '1.4-82b7292ee4cd6f808b724d2f5648932b',
49
49
  'VIFNestedDPDK': '1.0-fdbaf6b20afd116529929b21aa7158dc',
50
50
  'VIFPortProfileK8sDPDK': '1.1-e2a2abd112b14e0239e76b99d9b252ae',
51
51
  'DatapathOffloadBase': '1.0-77509ea1ea0dd750d5864b9bd87d3f9d',
@@ -78,3 +78,60 @@ class TestObjectVersions(base.TestCase):
78
78
  self.assertIn('vif_name', primitive)
79
79
  vif.obj_make_compatible(primitive, '1.0')
80
80
  self.assertNotIn('vif_name', primitive)
81
+
82
+ def test_vif_port_profile_ovs_obj_make_compatible_1_4(self):
83
+ """Test obj_make_compatible removes create_tap and multiqueue for
84
+ versions < 1.4.
85
+ """
86
+ profile = objects.vif.VIFPortProfileOpenVSwitch(
87
+ interface_id='e65867e0-9340-4a7f-a256-09af6eb7a3aa',
88
+ create_tap=True,
89
+ multiqueue=True)
90
+ primitive = profile.obj_to_primitive()['versioned_object.data']
91
+ self.assertIn('create_tap', primitive)
92
+ self.assertIn('multiqueue', primitive)
93
+
94
+ # For version 1.3, both create_tap and multiqueue should be removed
95
+ profile.obj_make_compatible(primitive, '1.3')
96
+ self.assertNotIn('create_tap', primitive)
97
+ self.assertNotIn('multiqueue', primitive)
98
+
99
+ def test_vif_port_profile_ovs_obj_make_compatible_1_3(self):
100
+ """Test obj_make_compatible removes create_port for versions < 1.3."""
101
+ profile = objects.vif.VIFPortProfileOpenVSwitch(
102
+ interface_id='e65867e0-9340-4a7f-a256-09af6eb7a3aa',
103
+ create_port=True)
104
+ primitive = profile.obj_to_primitive()['versioned_object.data']
105
+ self.assertIn('create_port', primitive)
106
+
107
+ # For version 1.2, create_port should be removed
108
+ profile.obj_make_compatible(primitive, '1.2')
109
+ self.assertNotIn('create_port', primitive)
110
+
111
+ def test_vif_port_profile_ovs_create_tap_multiqueue_fields(self):
112
+ """Test that create_tap and multiqueue fields can be set."""
113
+ profile = objects.vif.VIFPortProfileOpenVSwitch(
114
+ interface_id='e65867e0-9340-4a7f-a256-09af6eb7a3aa',
115
+ create_tap=True,
116
+ multiqueue=True)
117
+ self.assertTrue(profile.create_tap)
118
+ self.assertTrue(profile.multiqueue)
119
+
120
+ # Test explicitly set default values
121
+ profile_default = objects.vif.VIFPortProfileOpenVSwitch(
122
+ interface_id='e65867e0-9340-4a7f-a256-09af6eb7a3aa',
123
+ create_tap=False,
124
+ multiqueue=False)
125
+ self.assertFalse(profile_default.create_tap)
126
+ self.assertFalse(profile_default.multiqueue)
127
+
128
+ def test_vif_port_profile_ovs_in_operator(self):
129
+ """Test that 'in' operator works for checking field existence."""
130
+ profile = objects.vif.VIFPortProfileOpenVSwitch(
131
+ interface_id='e65867e0-9340-4a7f-a256-09af6eb7a3aa',
132
+ create_tap=True,
133
+ multiqueue=True)
134
+ self.assertIn('create_tap', profile)
135
+ self.assertIn('multiqueue', profile)
136
+ self.assertIn('interface_id', profile)
137
+ self.assertNotIn('nonexistent_field', profile)
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: os_vif
3
- Version: 4.2.1
3
+ Version: 4.3.0
4
4
  Summary: A library for plugging and unplugging virtual interfaces in OpenStack.
5
5
  Home-page: https://docs.openstack.org/os-vif/latest/
6
6
  Author: OpenStack
@@ -33,6 +33,15 @@ Requires-Dist: ovsdbapp>=0.12.1
33
33
  Requires-Dist: pyroute2>=0.5.2
34
34
  Requires-Dist: stevedore>=1.20.0
35
35
  Requires-Dist: debtcollector>=1.19.0
36
+ Dynamic: author
37
+ Dynamic: author-email
38
+ Dynamic: classifier
39
+ Dynamic: description
40
+ Dynamic: home-page
41
+ Dynamic: license-file
42
+ Dynamic: requires-dist
43
+ Dynamic: requires-python
44
+ Dynamic: summary
36
45
 
37
46
  ========================
38
47
  Team and repository tags
@@ -91,6 +91,7 @@ releasenotes/notes/add-no-op-plugin-763a6703e7328a24.yaml
91
91
  releasenotes/notes/add-ovs-representor-portprofile-5f8290e5a40bf0a4.yaml
92
92
  releasenotes/notes/add-ovs-vhostuser-support-2ba8de51c1f3a244.yaml
93
93
  releasenotes/notes/add-ovsdb-native-322fffb49c91503d.yaml
94
+ releasenotes/notes/add-tap-creation-support-2069718-abc123.yaml
94
95
  releasenotes/notes/always-plug-vifs-for-ovs-1d033fc49a9c6c4e.yaml
95
96
  releasenotes/notes/brctl-removal-a5b0e69b865afa57.yaml
96
97
  releasenotes/notes/bug-1892132-812e6d5ce0588ebb.yaml
@@ -126,6 +127,7 @@ releasenotes/source/2023.2.rst
126
127
  releasenotes/source/2024.1.rst
127
128
  releasenotes/source/2024.2.rst
128
129
  releasenotes/source/2025.1.rst
130
+ releasenotes/source/2025.2.rst
129
131
  releasenotes/source/conf.py
130
132
  releasenotes/source/index.rst
131
133
  releasenotes/source/newton.rst
@@ -0,0 +1 @@
1
+ {"git_version": "8cbe6ee", "is_release": true}
@@ -0,0 +1,24 @@
1
+ ---
2
+ features:
3
+ - |
4
+ Added support for os-vif to pre-create TAP devices when using OVS/OVN.
5
+ The ``VIFPortProfileOpenVSwitch`` object now supports two new fields:
6
+
7
+ * ``create_tap``: When set to ``True``, os-vif will create the TAP device
8
+ with the correct MAC address and MTU before adding it to OVS.
9
+ * ``multiqueue``: When set to ``True`` along with ``create_tap``, the TAP
10
+ device will be created with multiqueue support enabled for improved
11
+ performance with multiple vCPUs. The multiqueue setting is determined
12
+ by Nova from the ``hw:vif_multiqueue_enabled`` flavor extra spec or
13
+ image property.
14
+
15
+ When the ``[ovn]/ovs_create_tap`` config option is enabled in
16
+ Neutron's ML2/OVN mechanism driver, Neutron sets the ``ovs_create_tap``
17
+ flag in the vif_details during port binding. Nova then reads this value and
18
+ propagates it to os-vif via the ``create_tap`` field, and configures
19
+ libvirt with ``managed="no"`` so it uses the pre-created TAP device. This
20
+ reduces live migration downtime by ensuring the network is fully wired
21
+ before the VM starts.
22
+
23
+ See `bug 2069718 <https://bugs.launchpad.net/neutron/+bug/2069718>`_.
24
+
@@ -3,4 +3,4 @@
3
3
  ===========================
4
4
 
5
5
  .. release-notes::
6
- :branch: stable/2024.1
6
+ :branch: unmaintained/2024.1
@@ -0,0 +1,6 @@
1
+ ===========================
2
+ 2025.2 Series Release Notes
3
+ ===========================
4
+
5
+ .. release-notes::
6
+ :branch: stable/2025.2
@@ -6,6 +6,7 @@ Release Notes
6
6
  :maxdepth: 1
7
7
 
8
8
  unreleased
9
+ 2025.2
9
10
  2025.1
10
11
  2024.2
11
12
  2024.1
@@ -35,3 +35,9 @@ class RepresentorNotFound(osv_exception.ExceptionBase):
35
35
 
36
36
  class PciDeviceNotFoundById(osv_exception.ExceptionBase):
37
37
  msg_fmt = _("PCI device %(id)s not found")
38
+
39
+
40
+ class TapCreationNotSupported(osv_exception.ExceptionBase):
41
+ msg_fmt = _('Tap device creation requested for unsupported VIF type. '
42
+ 'create_tap is only supported for VIFOpenVSwitch, got '
43
+ '%(vif_type)s')
@@ -90,6 +90,29 @@ def update_veth_pair(dev1_name, dev2_name, mtu):
90
90
  _update_device_mtu(dev, mtu)
91
91
 
92
92
 
93
+ @privsep.vif_plug.entrypoint
94
+ def create_tap(dev, mtu, mac, multiqueue=False):
95
+ """Create a tap device with the specified configuration.
96
+
97
+ Creates a tap device using pyroute2's netlink interface, with optional
98
+ multiqueue support for better performance with multiple VCPUs.
99
+
100
+ :param dev: Device name (string)
101
+ :param mtu: MTU value (integer)
102
+ :param mac: MAC address (string)
103
+ :param multiqueue: Enable multiqueue support (boolean, default False)
104
+ Requires Linux kernel 3.8+
105
+ """
106
+ # Create the tap device with optional multiqueue support
107
+ # Use check_exit_code=[0, 17] to handle EEXIST (device already exists)
108
+ ip_lib.add(dev, 'tuntap', mode='tap', multiqueue=multiqueue,
109
+ check_exit_code=[0, 17])
110
+ # Configure the device state and MAC address
111
+ ip_lib.set(dev, state='up', address=mac, check_exit_code=[0, 2, 254])
112
+ # Set MTU if specified
113
+ _update_device_mtu(dev, mtu)
114
+
115
+
93
116
  def _disable_ipv6(bridge):
94
117
  """Disable ipv6 if available for bridge. Must be called from
95
118
  privsep context.