diff options
author | Daniel Watkins <oddbloke@ubuntu.com> | 2021-03-08 12:50:57 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-08 12:50:57 -0500 |
commit | 121bc04cdf0e6732fe143b7419131dc250c13384 (patch) | |
tree | 42a7cb52cd830f698c961703a0f4109b3934452e /cloudinit/net/__init__.py | |
parent | 106c57d511b862177c8356685cf6d49ddd6cb55f (diff) | |
download | vyos-cloud-init-121bc04cdf0e6732fe143b7419131dc250c13384.tar.gz vyos-cloud-init-121bc04cdf0e6732fe143b7419131dc250c13384.zip |
net: exclude OVS internal interfaces in get_interfaces (#829)
`get_interfaces` is used to in two ways, broadly: firstly, to determine
the available interfaces when converting cloud network configuration
formats to cloud-init's network configuration formats; and, secondly, to
ensure that any interfaces which are specified in network configuration
are (a) available, and (b) named correctly. The first of these is
unaffected by this commit, as no clouds support Open vSwitch
configuration in their network configuration formats.
For the second, we check that MAC addresses of physical devices are
unique. In some OVS configurations, there are OVS-created devices which
have duplicate MAC addresses, either with each other or with physical
devices. As these interfaces are created by OVS, we can be confident
that (a) they will be available when appropriate, and (b) that OVS will
name them correctly. As such, this commit excludes any OVS-internal
interfaces from the set of interfaces returned by `get_interfaces`.
LP: #1912844
Diffstat (limited to 'cloudinit/net/__init__.py')
-rw-r--r-- | cloudinit/net/__init__.py | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/cloudinit/net/__init__.py b/cloudinit/net/__init__.py index de65e7af..385b7bcc 100644 --- a/cloudinit/net/__init__.py +++ b/cloudinit/net/__init__.py @@ -6,6 +6,7 @@ # This file is part of cloud-init. See LICENSE file for license information. import errno +import functools import ipaddress import logging import os @@ -19,6 +20,19 @@ from cloudinit.url_helper import UrlError, readurl LOG = logging.getLogger(__name__) SYS_CLASS_NET = "/sys/class/net/" DEFAULT_PRIMARY_INTERFACE = 'eth0' +OVS_INTERNAL_INTERFACE_LOOKUP_CMD = [ + "ovs-vsctl", + "--format", + "csv", + "--no-headings", + "--timeout", + "10", + "--columns", + "name", + "find", + "interface", + "type=internal", +] def natural_sort_key(s, _nsre=re.compile('([0-9]+)')): @@ -133,6 +147,52 @@ def master_is_openvswitch(devname): return os.path.exists(ovs_path) +@functools.lru_cache(maxsize=None) +def openvswitch_is_installed() -> bool: + """Return a bool indicating if Open vSwitch is installed in the system.""" + ret = bool(subp.which("ovs-vsctl")) + if not ret: + LOG.debug( + "ovs-vsctl not in PATH; not detecting Open vSwitch interfaces" + ) + return ret + + +@functools.lru_cache(maxsize=None) +def get_ovs_internal_interfaces() -> list: + """Return a list of the names of OVS internal interfaces on the system. + + These will all be strings, and are used to exclude OVS-specific interface + from cloud-init's network configuration handling. + """ + try: + out, _err = subp.subp(OVS_INTERNAL_INTERFACE_LOOKUP_CMD) + except subp.ProcessExecutionError as exc: + if "database connection failed" in exc.stderr: + LOG.info( + "Open vSwitch is not yet up; no interfaces will be detected as" + " OVS-internal" + ) + return [] + raise + else: + return out.splitlines() + + +def is_openvswitch_internal_interface(devname: str) -> bool: + """Returns True if this is an OVS internal interface. + + If OVS is not installed or not yet running, this will return False. + """ + if not openvswitch_is_installed(): + return False + ovs_bridges = get_ovs_internal_interfaces() + if devname in ovs_bridges: + LOG.debug("Detected %s as an OVS interface", devname) + return True + return False + + def is_netfailover(devname, driver=None): """ netfailover driver uses 3 nics, master, primary and standby. this returns True if the device is either the primary or standby @@ -884,6 +944,8 @@ def get_interfaces(blacklist_drivers=None) -> list: # skip nics that have no mac (00:00....) if name != 'lo' and mac == zero_mac[:len(mac)]: continue + if is_openvswitch_internal_interface(name): + continue # skip nics that have drivers blacklisted driver = device_driver(name) if driver in blacklist_drivers: |