From 20f621542be67d825aaabf0b6deff8d3e6006440 Mon Sep 17 00:00:00 2001
From: "A. Wilcox" <AWilcox@Wilcox-Tech.com>
Date: Mon, 23 Nov 2020 20:06:01 -0600
Subject: ifupdown-ng NMSA: Add many more parameters

---
 ncserver/module/nms_ifupdownng.py | 86 ++++++++++++++++++++++++++++++++++++---
 1 file changed, 80 insertions(+), 6 deletions(-)

diff --git a/ncserver/module/nms_ifupdownng.py b/ncserver/module/nms_ifupdownng.py
index 5f87e8c..268a1fa 100644
--- a/ncserver/module/nms_ifupdownng.py
+++ b/ncserver/module/nms_ifupdownng.py
@@ -219,12 +219,14 @@ def _load_sysctl_cfg() -> dict:
 #############################
 
 _ENI_MAPPING = {'description': 'netconf-description',
-                    'enabled': 'auto'}
+                'enabled': 'auto',
+                'ipv4_mtu': 'mtu'}
 """Mapping of NMSA keys to /e/n/i keys."""
 
 
 _SYSCTL_MAPPING = {
     'ipv4_forwarding': 'net.ipv4.conf.{_if}.forwarding',
+    'ipv6_enabled': 'net.ipv6.conf.{_if}.disable_ipv6',
     'ipv6_forwarding': 'net.ipv6.conf.{_if}.forwarding',
     'ipv6_mtu': 'net.ipv6.conf.{_if}.mtu',
     'ipv6_dad_xmit': 'net.ipv6.conf.{_if}.dad_transmits',
@@ -257,6 +259,20 @@ def get_sysctl_bool(iface: str, parameter: str) -> bool:
     return False
 
 
+def get_sysctl_int(iface: str, parameter: str) -> int:
+    """Retrieve the specified integer from sysctl.conf."""
+    value = get_sysctl(iface, parameter)
+    if value is None:
+        return None
+
+    return int(value)
+
+
+def get_ipv6en(iface: str, parameter: str):
+    """Retrieve IPv6 enablement status for the specified interface."""
+    return not get_sysctl_bool(iface, parameter)
+
+
 def live_sysctl(iface: str, parameter: str):
     """Retrieve the live value of a parameter from /proc/sys."""
     key = _SYSCTL_MAPPING[parameter].format(_if=iface)
@@ -266,17 +282,34 @@ def live_sysctl(iface: str, parameter: str):
         with open(path, 'r') as sysctl:
             return sysctl.read().strip()
 
+    LOGGER.error(_("kernel does not know %s"), parameter)
     return None
 
 
 def live_sysctl_bool(iface: str, parameter: str) -> bool:
     """Retrieve a live boolean value from /proc/sys."""
     value = live_sysctl(iface, parameter)
-    if value is not None and value == '1':
+    if value is None:
+        return None
+    if value == '1':
         return True
     return False
 
 
+def live_sysctl_int(iface: str, parameter: str) -> int:
+    """Retrieve a live integer from /proc/sys."""
+    value = live_sysctl(iface, parameter)
+    if value is None:
+        return None
+
+    return int(value)
+
+
+def live_ipv6en(iface: str, parameter: str):
+    """Retrieve current IPv6 status for the specified interface."""
+    return not live_sysctl_bool(iface, parameter)
+
+
 def live_enabled(iface: str, _):
     """Determine if the interface is enabled or not."""
     statepath = _iface_path(iface) / "operstate"
@@ -287,6 +320,18 @@ def live_enabled(iface: str, _):
     return False
 
 
+def live_ipv4_mtu(iface: str, _):
+    """Determine the IPv4 MTU for the interface."""
+    mtupath = _iface_path(iface) / "mtu"
+    if mtupath.exists():
+        with open(mtupath, 'r') as mtu_file:
+            return int(mtu_file.read().strip())
+
+    # Linux kernel: net/ethernet/eth.c line 367
+    #               include/uapi/linux/if_ether.h line 36
+    return 1500
+
+
 # # # # Setters # # # #
 
 def set_sysctl(iface: str, parameter: str, value):
@@ -305,6 +350,16 @@ def set_sysctl_bool(iface: str, parameter: str, value: bool):
     set_sysctl(iface, parameter, real)
 
 
+def set_sysctl_int(iface: str, parameter: str, value: int):
+    """Set an integer sysctl value."""
+    set_sysctl(iface, parameter, str(value))
+
+
+def set_ipv6en(iface: str, parameter: str, value: bool):
+    """Set IPv6 enabled/disabled for the specified interface."""
+    set_sysctl_bool(iface, parameter, not value)
+
+
 def set_desc(iface: str, _, value: str):
     """Set the description for the specified interface."""
     _replace_one(iface, 'netconf-description', value)
@@ -315,6 +370,11 @@ def set_auto(iface: str, _, value: bool):
     _replace_one(iface, 'auto', str(value).lower())
 
 
+def set_ipv4_mtu(iface: str, _, value: int):
+    """Set the MTU for the specified interface."""
+    _replace_one(iface, 'mtu', str(value))
+
+
 # # # # Unsetters # # # #
 
 def unset_one_eni(iface: str, parameter: str):
@@ -331,11 +391,25 @@ def unset_sysctl(iface: str, parameter: str):
 
 _PARAMETERS = {
     # "name": (getter, live getter, setter, unsetter)
-    "description": (get_one_eni, get_one_eni, set_desc, unset_one_eni),
-    "enabled": (get_one_eni, live_enabled, set_auto, unset_one_eni),
+    'description':         (get_one_eni, get_one_eni, set_desc, unset_one_eni),
+    'enabled':             (get_one_eni, live_enabled,
+                            set_auto, unset_one_eni),
     # XXX TODO: ipv4_enabled
-    "ipv4_forwarding": (get_sysctl_bool, live_sysctl_bool,
-                        set_sysctl_bool, unset_sysctl)
+    'ipv4_forwarding':     (get_sysctl_bool, live_sysctl_bool,
+                            set_sysctl_bool, unset_sysctl),
+    'ipv4_mtu':            (get_one_eni, live_ipv4_mtu,
+                            set_ipv4_mtu, unset_one_eni),
+    'ipv6_enabled':        (get_ipv6en, live_ipv6en, set_ipv6en, unset_sysctl),
+    'ipv6_forwarding':     (get_sysctl_bool, live_sysctl_bool,
+                            set_sysctl_bool, unset_sysctl),
+    'ipv6_mtu':            (get_sysctl_int, live_sysctl_int,
+                            set_sysctl_int, unset_sysctl),
+    'ipv6_dad_xmit':       (get_sysctl_int, live_sysctl_int,
+                            set_sysctl_int, unset_sysctl),
+    'ipv6_slaac_validlft': (get_sysctl_int, live_sysctl_int,
+                            set_sysctl_int, unset_sysctl),
+    'ipv6_slaac_preflft':  (get_sysctl_int, live_sysctl_int,
+                            set_sysctl_int, unset_sysctl)
 }
 """Describes all supported parameters and their methods."""
 
-- 
cgit v1.2.3-70-g09d2