""" NETCONF for APK Distributions server: ietf-ip module Copyright © 2020 Adélie Software in the Public Benefit, Inc. Released under the terms of the NCSA license. See the LICENSE file included with this source distribution for more information. SPDX-License-Identifier: NCSA """ import logging from lxml.etree import QName # pylint: disable=E0611 from netconf import util from ncserver.base.modman import MODMAN from ncserver.base.util import _ LOGGER = logging.getLogger(__name__) """The object used for logging informational messages.""" M_ABI_VERSION = 1 """The ABI version of this NETCONF module.""" M_PREFIX = "ip" """The XML tag prefix for this module's tags.""" M_NS = "urn:ietf:params:xml:ns:yang:ietf-ip" """The XML namespace for this module.""" M_NAME = "ietf-ip" """The YANG model name for this module.""" M_REVISION = "2018-02-22" """The YANG revision date for this module.""" M_IMPORTS = { 'ietf-inet-types@2013-07-15': { 'ns': "urn:ietf:params:xml:ns:yang:ietf-inet-types", 'prefix': "inet" }, 'ietf-yang-types@2013-07-15': { 'ns': "urn:ietf:params:xml:ns:yang:ietf-yang-types", 'prefix': "yang" } } """The imported YANG modules for this module.""" M_FEATURES = ('ipv6-privacy-autoconf',) """The supported features declared in YANG for this module.""" IF_NS = "urn:ietf:params:xml:ns:yang:ietf-interfaces" """The namespace of the ietf-interfaces module.""" M_AUGMENTS = (IF_NS,) """The namespaces that this YANG module augments.""" def _get_ifaces(node): """Retrieve the /if:interfaces node.""" ifaces = node.find('{'+IF_NS+'}interfaces') if ifaces is None: LOGGER.error(_("interfaces node not found: " "This module requires ietf-interfaces to be loaded")) return ifaces def _get_nmsa(): """Retrieve our NMSA module handle.""" nmsa_ns = "http://netconf.adelielinux.org/ns/netmgmt" nmsa = MODMAN._module_for_ns(nmsa_ns) # pylint: disable=W0212 return nmsa def from_bool(value: bool) -> str: """Turn a Python bool into an XML bool.""" return str(value).lower() def _add_ipv4(iface, getter): """Add IPv4 configuration nodes.""" name = iface.find('{'+IF_NS+'}name').text ipv4 = util.subelm(iface, 'ip:ipv4') #ipv4.append(util.leaf_elm('ip:enabled', # from_bool(getter(name, 'ipv4_enabled')))) ipv4.append(util.leaf_elm('ip:forwarding', from_bool(getter(name, 'ipv4_forwarding')))) v4mtu = getter(name, 'ipv4_mtu') if v4mtu is not None: ipv4.append(util.leaf_elm('ip:mtu', v4mtu - 28)) return ipv4 def _add_ipv6(iface, getter): """Add IPv6 configuration nodes.""" name = iface.find('{'+IF_NS+'}name').text ipv6 = util.subelm(iface, 'ip:ipv6') ipv6.append(util.leaf_elm('ip:enabled', from_bool(getter(name, 'ipv6_enabled')))) ipv6.append(util.leaf_elm('ip:forwarding', from_bool(getter(name, 'ipv6_forwarding')))) v6mtu = getter(name, 'ipv6_mtu') if v6mtu is not None: ipv6.append(util.leaf_elm('ip:mtu', v6mtu)) ipv6.append( util.leaf_elm('ip:dup-addr-detect-transmits', getter(name, 'ipv6_dad_xmit')) ) if any((getter(name, 'ipv6_slaac_globaladdr'), getter(name, 'ipv6_slaac_tempaddr'))): autoconf = util.subelm(ipv6, 'ip:autoconf') autoconf.append(util.leaf_elm('ip:create-global-addresses', from_bool( getter(name, 'ipv6_slaac_globaladdr') ))) autoconf.append(util.leaf_elm('ip:create-temporary-addresses', from_bool( getter(name, 'ipv6_slaac_tempaddr') ))) autoconf.append(util.leaf_elm('ip:temporary-valid-lifetime', getter(name, 'ipv6_slaac_validlft'))) autoconf.append(util.leaf_elm('ip:temporary-preferred-lifetime', getter(name, 'ipv6_slaac_preflft'))) return ipv6 def running(node): """Retrieve the IP configuration for this device.""" ifaces = _get_ifaces(node) nmsa = _get_nmsa() if None in (ifaces, nmsa): # We can't retrieve configuration unless both the ietf-interfaces and # the NMSA module is loaded. return for iface in ifaces.iterchildren(): name = iface.find('{'+IF_NS+'}name').text # IPv4 ipv4 = _add_ipv4(iface, nmsa.get_param) for address in nmsa.list_addresses(name): # Only IPv4 addresses count. if '.' not in address: continue ipaddr, subnet = address.split('/') addr = util.subelm(ipv4, 'ip:address') addr.append(util.leaf_elm('ip:ip', ipaddr)) addr.append(util.leaf_elm('ip:prefix-length', subnet)) # No neighbor support. # IPv6 ipv6 = _add_ipv6(iface, nmsa.get_param) for address in nmsa.list_addresses(name): # Only IPv6 addesses count. if ':' not in address: continue ipaddr, length = address.split('/') addr = util.subelm(ipv6, 'ip:address') addr.append(util.leaf_elm('ip:ip', ipaddr)) addr.append(util.leaf_elm('ip:prefix-length', length)) # No neighbor support. def operational(node): """Retrieve the IP state for this device.""" ifaces = _get_ifaces(node) nmsa = _get_nmsa() if None in (ifaces, nmsa): # We can't retrieve configuration unless both the ietf-interfaces and # the NMSA module is loaded. return for iface in ifaces.iterchildren(): # IPv4 _add_ipv4(iface, nmsa.curr_param) # IPv6 _add_ipv6(iface, nmsa.curr_param) def edit(session, rpc, node, def_op): """Edit the IP configuration for this device."""