# (c) Copyright IBM Corp. 2020 All Rights Reserved # # Author: Aman Kumar Sinha # # This file is part of cloud-init. See LICENSE file for license information. """ Refresh IPv6 interface and RMC ------------------------------ **Summary:** Ensure Network Manager is not managing IPv6 interface This module is IBM PowerVM Hypervisor specific Reliable Scalable Cluster Technology (RSCT) is a set of software components that together provide a comprehensive clustering environment(RAS features) for IBM PowerVM based virtual machines. RSCT includes the Resource Monitoring and Control (RMC) subsystem. RMC is a generalized framework used for managing, monitoring, and manipulating resources. RMC runs as a daemon process on individual machines and needs creation of unique node id and restarts during VM boot. More details refer https://www.ibm.com/support/knowledgecenter/en/SGVKBA_3.2/admin/bl503_ovrv.htm This module handles - Refreshing RMC - Disabling NetworkManager from handling IPv6 interface, as IPv6 interface is used for communication between RMC daemon and PowerVM hypervisor. **Internal name:** ``cc_refresh_rmc_and_interface`` **Module frequency:** per always **Supported distros:** RHEL """ from cloudinit import log as logging from cloudinit.settings import PER_ALWAYS from cloudinit import util from cloudinit import subp from cloudinit import netinfo import errno frequency = PER_ALWAYS LOG = logging.getLogger(__name__) # Ensure that /opt/rsct/bin has been added to standard PATH of the # distro. The symlink to rmcctrl is /usr/sbin/rsct/bin/rmcctrl . RMCCTRL = 'rmcctrl' def handle(name, _cfg, _cloud, _log, _args): if not subp.which(RMCCTRL): LOG.debug("No '%s' in path, disabled", RMCCTRL) return LOG.debug( 'Making the IPv6 up explicitly. ' 'Ensuring IPv6 interface is not being handled by NetworkManager ' 'and it is restarted to re-establish the communication with ' 'the hypervisor') ifaces = find_ipv6_ifaces() # Setting NM_CONTROLLED=no for IPv6 interface # making it down and up if len(ifaces) == 0: LOG.debug("Did not find any interfaces with ipv6 addresses.") else: for iface in ifaces: refresh_ipv6(iface) disable_ipv6(sysconfig_path(iface)) restart_network_manager() def find_ipv6_ifaces(): info = netinfo.netdev_info() ifaces = [] for iface, data in info.items(): if iface == "lo": LOG.debug('Skipping localhost interface') if len(data.get("ipv4", [])) != 0: # skip this interface, as it has ipv4 addrs continue ifaces.append(iface) return ifaces def refresh_ipv6(interface): # IPv6 interface is explicitly brought up, subsequent to which the # RMC services are restarted to re-establish the communication with # the hypervisor. subp.subp(['ip', 'link', 'set', interface, 'down']) subp.subp(['ip', 'link', 'set', interface, 'up']) def sysconfig_path(iface): return '/etc/sysconfig/network-scripts/ifcfg-' + iface def restart_network_manager(): subp.subp(['systemctl', 'restart', 'NetworkManager']) def disable_ipv6(iface_file): # Ensuring that the communication b/w the hypervisor and VM is not # interrupted due to NetworkManager. For this purpose, as part of # this function, the NM_CONTROLLED is explicitly set to No for IPV6 # interface and NetworkManager is restarted. try: contents = util.load_file(iface_file) except IOError as e: if e.errno == errno.ENOENT: LOG.debug("IPv6 interface file %s does not exist\n", iface_file) else: raise e if 'IPV6INIT' not in contents: LOG.debug("Interface file %s did not have IPV6INIT", iface_file) return LOG.debug("Editing interface file %s ", iface_file) # Dropping any NM_CONTROLLED or IPV6 lines from IPv6 interface file. lines = contents.splitlines() lines = [line for line in lines if not search(line)] lines.append("NM_CONTROLLED=no") with open(iface_file, "w") as fp: fp.write("\n".join(lines) + "\n") def search(contents): # Search for any NM_CONTROLLED or IPV6 lines in IPv6 interface file. return( contents.startswith("IPV6ADDR") or contents.startswith("IPADDR6") or contents.startswith("IPV6INIT") or contents.startswith("NM_CONTROLLED")) def refresh_rmc(): # To make a healthy connection between RMC daemon and hypervisor we # refresh RMC. With refreshing RMC we are ensuring that making IPv6 # down and up shouldn't impact communication between RMC daemon and # hypervisor. # -z : stop Resource Monitoring & Control subsystem and all resource # managers, but the command does not return control to the user # until the subsystem and all resource managers are stopped. # -s : start Resource Monitoring & Control subsystem. try: subp.subp([RMCCTRL, '-z']) subp.subp([RMCCTRL, '-s']) except Exception: util.logexc(LOG, 'Failed to refresh the RMC subsystem.') raise