aboutsummaryrefslogtreecommitdiffstats
path: root/resources/libraries/python/honeycomb/IPv6Management.py
blob: deec041103d809be5b1cbbf9f2f94ff0dc121f49 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# 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.")