# Copyright (c) 2017 Cisco and/or its affiliates. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at: # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Keywords used for setup and testing of Honeycomb's control-plane interface using IPv6. """ from resources.libraries.python.ssh import SSH class IPv6Management(object): """Utilities for managing IPv6 contol-plane interfaces.""" def __init__(self): pass @staticmethod def get_interface_name_by_mac(node, mac): """Get the name of an interface using its MAC address. :param node: Node in topology. :param mac: MAC address. :type node: dict :type mac: str :returns: Name of the interface. :rtype: str :raises RuntimeError: If no interface is found. """ cmd = " | ".join([ "fgrep -ls '{0}' /sys/class/net/*/address".format(mac), "awk -F '/' '{print $5}'" ]) ssh = SSH() ssh.connect(node) ret_code, stdout, _ = ssh.exec_command(cmd) if ret_code == 0: return stdout.strip() else: raise RuntimeError("No interface found using the specified MAC " "address.") @staticmethod def clear_interface_configuration(node, interface): """Remove all configured IP addresses from the specified interface and set it into down state. :param node: Node in topology. :param interface: Name of an interface on the node. :type node: dict :type interface: str :raises RuntimeError: If the configuration could not be cleared. """ cmd = " && ".join([ "sudo ip addr flush dev {interface}".format(interface=interface), "sudo ip link set dev {interface} down".format(interface=interface) ]) ssh = SSH() ssh.connect(node) ret_code, _, _ = ssh.exec_command(cmd) if ret_code != 0: raise RuntimeError("Could not clear interface configuration.") @staticmethod def set_management_interface_address(node, interface, address, prefix): """Configure an IP address on the specified interface. :param node: Node in topology. :param interface: Name of an interface on the node. :param address: IP address to configure. :param prefix: IP network prefix. :type node: dict :type interface: str :type address: str :type prefix: int :raises RuntimeError: If the configuration fails. """ ssh = SSH() ssh.connect(node) # Enable IPv6 for only the specified interface cmd = "sudo sysctl net.ipv6.conf.{0}.disable_ipv6=0".format(interface) ret_code, _, _ = ssh.exec_command(cmd) if ret_code != 0: raise RuntimeError("Could not enable IPv6 on interface.") # Configure IPv6 address on the interface cmd = "sudo ip address add {address}/{prefix} dev {interface}".format( interface=interface, address=address, prefix=prefix) ret_code, _, _ = ssh.exec_command(cmd) if ret_code != 0: raise RuntimeError("Could not configure IP address on interface.") # Set the interface up cmd = "sudo ip link set {interface} up".format(interface=interface) ret_code, _, _ = ssh.exec_command(cmd) if ret_code != 0: raise RuntimeError("Could not change the interface to 'up' state.") @staticmethod def configure_control_interface_tunnel(node, src_port, dst_ip, dst_port): """Configure a tunnel on the specified node, tunelling any IPv4 traffic from one port to the specified address. :param node: Node in topology. :param src_port: Port to tunnel traffic from. :param dst_ip: IP address to tunnel traffic to. :param dst_port: Port to tunnel traffic to. :type node: dict :type src_port: int :type dst_ip: str :type dst_port: int :raises RuntimeError: If tunnel creation is not successful. """ cmd = "nohup socat TCP4-LISTEN:{src_port},fork,su=nobody " \ "TCP6:[{dst_ip}]:{dst_port} $@ > " \ "/tmp/socat.log 2>&1 &".format( src_port=src_port, dst_ip=dst_ip, dst_port=dst_port) ssh = SSH() ssh.connect(node) ret_code, _, _ = ssh.exec_command_sudo(cmd) if ret_code != 0: raise RuntimeError("Could not configure tunnel.")