Blame SOURCES/BZ_1817466-use-kernel-runtime-bridge-status.patch

8f4f2d
From 3b5cfe36b1b754369cb8d3cc0d461068bf6bb8aa Mon Sep 17 00:00:00 2001
8f4f2d
From: Fernando Fernandez Mancera <ffmancera@riseup.net>
8f4f2d
Date: Wed, 25 Mar 2020 12:21:15 +0100
8f4f2d
Subject: [PATCH 06/10] nm.bridge: get ports from sysfs
8f4f2d
8f4f2d
Unmanaged ports were not being shown when showing or editting the
8f4f2d
bridge. In order to fix that, nmstate is retrieving the bridge ports
8f4f2d
from sysfs instead of NetworkManager on-disk configuration.
8f4f2d
8f4f2d
Ref: https://bugzilla.redhat.com/1806452
8f4f2d
8f4f2d
Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
8f4f2d
---
8f4f2d
 libnmstate/nm/bridge.py                | 55 +++++++++++++++++---------
8f4f2d
 tests/integration/linux_bridge_test.py | 34 ++++++++++++++++
8f4f2d
 2 files changed, 71 insertions(+), 18 deletions(-)
8f4f2d
8f4f2d
diff --git a/libnmstate/nm/bridge.py b/libnmstate/nm/bridge.py
8f4f2d
index e0ab8e4..672214d 100644
8f4f2d
--- a/libnmstate/nm/bridge.py
8f4f2d
+++ b/libnmstate/nm/bridge.py
8f4f2d
@@ -17,6 +17,9 @@
8f4f2d
 # along with this program. If not, see <https://www.gnu.org/licenses/>.
8f4f2d
 #
8f4f2d
 
8f4f2d
+import glob
8f4f2d
+import os
8f4f2d
+
8f4f2d
 from libnmstate.error import NmstateNotImplementedError
8f4f2d
 from libnmstate.nm import connection
8f4f2d
 from libnmstate.nm import nmclient
8f4f2d
@@ -25,6 +28,12 @@ from libnmstate.schema import LinuxBridge as LB
8f4f2d
 
8f4f2d
 BRIDGE_TYPE = "bridge"
8f4f2d
 
8f4f2d
+BRIDGE_PORT_NMSTATE_TO_SYSFS = {
8f4f2d
+    LB.Port.STP_HAIRPIN_MODE: "hairpin_mode",
8f4f2d
+    LB.Port.STP_PATH_COST: "path_cost",
8f4f2d
+    LB.Port.STP_PRIORITY: "priority",
8f4f2d
+}
8f4f2d
+
8f4f2d
 
8f4f2d
 def create_setting(options, base_con_profile):
8f4f2d
     bridge_setting = _get_current_bridge_setting(base_con_profile)
8f4f2d
@@ -106,10 +115,10 @@ def get_info(nmdev):
8f4f2d
     if not bridge_setting:
8f4f2d
         return info
8f4f2d
 
8f4f2d
-    port_profiles = _get_slave_profiles(nmdev)
8f4f2d
+    port_names_sysfs = _get_slaves_names_from_sysfs(nmdev.get_iface())
8f4f2d
     props = bridge_setting.props
8f4f2d
     info[LB.CONFIG_SUBTREE] = {
8f4f2d
-        LB.PORT_SUBTREE: _get_bridge_ports_info(port_profiles),
8f4f2d
+        LB.PORT_SUBTREE: _get_bridge_ports_info(port_names_sysfs),
8f4f2d
         LB.OPTIONS_SUBTREE: {
8f4f2d
             LB.Options.MAC_AGEING_TIME: props.ageing_time,
8f4f2d
             LB.Options.GROUP_FORWARD_MASK: props.group_forward_mask,
8f4f2d
@@ -139,25 +148,35 @@ def _get_bridge_setting(nmdev):
8f4f2d
     return bridge_setting
8f4f2d
 
8f4f2d
 
8f4f2d
-def _get_bridge_ports_info(port_profiles):
8f4f2d
-    ports_info = []
8f4f2d
-    for p in port_profiles:
8f4f2d
-        port_info = _get_bridge_port_info(p)
8f4f2d
-        if port_info:
8f4f2d
-            ports_info.append(port_info)
8f4f2d
-    return ports_info
8f4f2d
+def _get_bridge_ports_info(port_names_sysfs):
8f4f2d
+    return [_get_bridge_port_info(name) for name in port_names_sysfs]
8f4f2d
 
8f4f2d
 
8f4f2d
-def _get_bridge_port_info(port_profile):
8f4f2d
-    """Report port information."""
8f4f2d
+def _get_bridge_port_info(port_name):
8f4f2d
+    """Report port runtime information from sysfs."""
8f4f2d
+    port = {LB.Port.NAME: port_name}
8f4f2d
+    for option, option_sysfs in BRIDGE_PORT_NMSTATE_TO_SYSFS.items():
8f4f2d
+        sysfs_path = f"/sys/class/net/{port_name}/brport/{option_sysfs}"
8f4f2d
+        with open(sysfs_path) as f:
8f4f2d
+            option_value = int(f.read())
8f4f2d
+            if option == LB.Port.STP_HAIRPIN_MODE:
8f4f2d
+                option_value = bool(option_value)
8f4f2d
+        port[option] = option_value
8f4f2d
+    return port
8f4f2d
 
8f4f2d
-    port_setting = port_profile.get_setting_bridge_port()
8f4f2d
-    return {
8f4f2d
-        LB.Port.NAME: port_profile.get_interface_name(),
8f4f2d
-        LB.Port.STP_PRIORITY: port_setting.props.priority,
8f4f2d
-        LB.Port.STP_HAIRPIN_MODE: port_setting.props.hairpin_mode,
8f4f2d
-        LB.Port.STP_PATH_COST: port_setting.props.path_cost,
8f4f2d
-    }
8f4f2d
+
8f4f2d
+def _get_slaves_names_from_sysfs(master):
8f4f2d
+    """
8f4f2d
+    We need to use glob in order to get the slaves name due to bug in
8f4f2d
+    NetworkManager.
8f4f2d
+    Ref: https://bugzilla.redhat.com/show_bug.cgi?id=1809547
8f4f2d
+    """
8f4f2d
+    slaves = []
8f4f2d
+    for sysfs_slave in glob.iglob(f"/sys/class/net/{master}/lower_*"):
8f4f2d
+        # The format is lower_<iface>, we need to remove the "lower_" prefix
8f4f2d
+        prefix_length = len("lower_")
8f4f2d
+        slaves.append(os.path.basename(sysfs_slave)[prefix_length:])
8f4f2d
+    return slaves
8f4f2d
 
8f4f2d
 
8f4f2d
 def _get_slave_profiles(master_device):
8f4f2d
-- 
8f4f2d
2.25.1
8f4f2d