aboutsummaryrefslogtreecommitdiffstats
path: root/resources/libraries/python/GeneveUtil.py
blob: d7266f58fa7a84433e2c2205372f54a62d26284b (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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# Copyright (c) 2021 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.

"""VPP GENEVE Plugin utilities library."""

from ipaddress import ip_address

from resources.libraries.python.Constants import Constants
from resources.libraries.python.InterfaceUtil import InterfaceUtil
from resources.libraries.python.IPAddress import IPAddress
from resources.libraries.python.IPUtil import IPUtil
from resources.libraries.python.PapiExecutor import PapiSocketExecutor
from resources.libraries.python.topology import Topology


class GeneveUtil:
    """VPP GENEVE Plugin Keywords."""

    @staticmethod
    def add_geneve_tunnel(
            node, local_address, remote_address, vni, multicast_if=None,
            encap_vrf=0, l3_mode=False, next_index=None):
        """Add GENEVE tunnel on the specified VPP node.

        :param node: Topology node.
        :param local_address: Local IP address.
        :param remote_address: Remote IP address.
        :param vni: Virtual network ID.
        :param multicast_if: Interface key of multicast interface; used only if
            remote is multicast. (Default value = None)
        :param encap_vrf: The FIB ID for sending unicast GENEVE encap packets or
            receiving multicast packets. (Default value = 0)
        :param l3_mode: Use geneve tunnel in L3 mode (ip routing) if Tue else in
            L2 mode (L2 switching). (Default value = False)
        :param next_index: The index of the next node.
        :type node: dict
        :type local_address: str
        :type remote_address: str
        :type vni: int
        :type multicast_if: str
        :type encap_vrf: int
        :type l3_mode: bool
        :type next_index: int
        :returns: SW interface index of created geneve tunnel.
        :rtype: int
        """
        cmd = u"geneve_add_del_tunnel2"
        args = dict(
            is_add=True,
            local_address=IPAddress.create_ip_address_object(
                ip_address(local_address)
            ),
            remote_address=IPAddress.create_ip_address_object(
                ip_address(remote_address)
            ),
            mcast_sw_if_index=Topology.get_interface_sw_index(
                node, multicast_if
            ) if multicast_if else Constants.BITWISE_NON_ZERO,
            encap_vrf_id=int(encap_vrf),
            decap_next_index=next_index if l3_mode
            else Constants.BITWISE_NON_ZERO,
            vni=int(vni),
            l3_mode=l3_mode
        )
        err_msg = f"Failed to configure GENEVE tunnel on host {node[u'host']}!"
        with PapiSocketExecutor(node) as papi_exec:
            sw_if_index = papi_exec.add(cmd, **args).get_sw_if_index(err_msg)

        if_key = Topology.add_new_port(node, u"geneve_tunnel")
        Topology.update_interface_sw_if_index(node, if_key, sw_if_index)

        ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_index)
        Topology.update_interface_name(node, if_key, ifc_name)

        ifc_mac = InterfaceUtil.vpp_get_interface_mac(node, sw_if_index)
        Topology.update_interface_mac_address(node, if_key, ifc_mac)

        return sw_if_index

    @staticmethod
    def enable_interface_geneve_bypass(node, interface, is_ipv6=False):
        """Add ipv4/ipv6-geneve-bypass graph node for a given interface on
        the specified VPP node.

        :param node: Topology node.
        :param interface: Interface key from topology file of interface
            to add geneve bypass node for.
        :param is_ipv6: Enable ipv6-geneve-bypass graph node if True else enable
            ipv4-geneve-bypass graph node.
        :type node: dict
        :type interface: str
        :type is_ipv6: bool
        """
        cmd = u"sw_interface_set_geneve_bypass"
        args = dict(
            is_ipv6=is_ipv6,
            enable=True,
            sw_if_index=Topology.get_interface_sw_index(node, interface)
        )
        err_msg = (
            f"Failed to enable {u'ipv6' if is_ipv6 else u'ipv4'}-geneve-bypass "
            f"on interface {interface} on host {node[u'host']}!"
        )
        with PapiSocketExecutor(node) as papi_exec:
            papi_exec.add(cmd, **args).get_reply(err_msg)

    @staticmethod
    def show_geneve_tunnel_data(node):
        """Show the GENEVE tunnels data.

        :param node: DUT node.
        :type node: dict
        """
        cmds = [
            u"geneve_tunnel_dump",
        ]
        PapiSocketExecutor.dump_and_log(node, cmds)

    @staticmethod
    def vpp_geneve_add_multiple_tunnels(
            node, gen_tunnel, n_tunnels, dut_if1, dut_if2, tg_if1_ip4,
            tg_if2_ip4, tg_pf2_mac, next_idx):
        """Create multiple GENEVE tunnels.

        :param node: DUT node.
        :param gen_tunnel: Parameters of the GENEVE tunnel.
        :param n_tunnels: Number of tunnels.
        :param dut_if1: The first DUT interface.
        :param dut_if2: The second DUT interface.
        :param tg_if1_ip4: TG interface 1 IP address.
        :param tg_if2_ip4: TG interface 2 IP address.
        :param tg_pf2_mac: TG interface 2 MAC address.
        :param next_idx: The index of the next node.
        :type node: dict
        :type gen_tunnel: dict
        :type n_tunnels: int
        :type dut_if1: str
        :type dut_if2: str
        :type tg_if1_ip4: str
        :type tg_if2_ip4: str
        :type tg_pf2_mac: str
        :type next_idx: int
        """

        src_ip_int = IPUtil.ip_to_int(gen_tunnel[u"src_ip"])
        dst_ip_int = IPUtil.ip_to_int(gen_tunnel[u"dst_ip"])
        if_ip_int = IPUtil.ip_to_int(gen_tunnel[u"if_ip"])

        for idx in range(n_tunnels):
            src_ip = IPUtil.int_to_ip(src_ip_int + idx * 256)
            dst_ip = IPUtil.int_to_ip(dst_ip_int + idx * 256)
            if_ip = IPUtil.int_to_ip(if_ip_int + idx * 256)

            IPUtil.vpp_route_add(
                node, src_ip, gen_tunnel[u"ip_mask"],
                gateway=tg_if1_ip4, interface=dut_if1
            )
            tunnel_sw_index = GeneveUtil.add_geneve_tunnel(
                node, gen_tunnel[u"local"], gen_tunnel[u"remote"],
                gen_tunnel[u"vni"] + idx, l3_mode=True, next_index=next_idx
            )
            tunnel_if_key = Topology.get_interface_by_sw_index(
                node, tunnel_sw_index
            )
            tunnel_if_mac = Topology.get_interface_mac(
                node, tunnel_if_key
            )
            IPUtil.vpp_interface_set_ip_address(node, tunnel_if_key, if_ip, 24)
            IPUtil.vpp_add_ip_neighbor(
                node, tunnel_if_key, tg_if2_ip4, tg_pf2_mac
            )
            IPUtil.vpp_route_add(
                node, dst_ip, gen_tunnel[u"ip_mask"],
                gateway=tg_if2_ip4, interface=tunnel_if_key
            )
            IPUtil.vpp_route_add(
                node, gen_tunnel[u"remote"], 32,
                gateway=tg_if2_ip4, interface=dut_if2
            )
            IPUtil.vpp_add_ip_neighbor(
                node, tunnel_if_key, gen_tunnel[u"local"], tunnel_if_mac
            )
            IPUtil.vpp_route_add(
                node, gen_tunnel[u"local"], 32, gateway=if_ip
            )
            InterfaceUtil.set_interface_state(node, tunnel_if_key, u"up")