LoadBalancerUtil.py revision 8aa83d92
1# Copyright (c) 2019 Intel and/or its affiliates.
2# Licensed under the Apache License, Version 2.0 (the "License");
3# you may not use this file except in compliance with the License.
4# You may obtain a copy of the License at:
5#
6#     http://www.apache.org/licenses/LICENSE-2.0
7#
8# Unless required by applicable law or agreed to in writing, software
9# distributed under the License is distributed on an "AS IS" BASIS,
10# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11# See the License for the specific language governing permissions and
12# limitations under the License.
13
14"""Loadbalancer util library."""
15
16from ipaddress import ip_address
17from socket import htonl
18
19from resources.libraries.python.topology import NodeType, Topology
20from resources.libraries.python.PapiExecutor import PapiSocketExecutor
21
22
23class LoadBalancerUtil:
24    """Basic Loadbalancer parameter configuration."""
25
26    @staticmethod
27    def vpp_lb_conf(node, **kwargs):
28        """Config global parameters for loadbalancer.
29
30        :param node: Node where the interface is.
31        :param kwargs: Optional key-value arguments:
32
33            ip4_src_addr: IPv4 address to be used as source for IPv4 traffic.
34                          (str)
35            ip6_src_addr: IPv6 address to be used as source for IPv6 traffic.
36                          (str)
37            flow_timeout: Time in seconds after which, if no packet is received
38                          for a given flow, the flow is removed from the
39                          established flow table. (int)
40            buckets_per_core: Number of buckets *per worker thread* in the
41                              established flow table (int)
42
43        :type node: dict
44        :type kwargs: dict
45        :returns: Nothing.
46        :raises ValueError: If the node has an unknown node type.
47        """
48        if node[u"type"] == NodeType.DUT:
49            ip4_src_addr = ip_address(
50                kwargs.pop(u"ip4_src_addr", u"255.255.255.255")
51            )
52            ip6_src_addr = ip_address(
53                kwargs.pop(
54                    u"ip6_src_addr", u"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
55                )
56            )
57            flow_timeout = kwargs.pop(u"flow_timeout", 40)
58            sticky_buckets_per_core = kwargs.pop(u"buckets_per_core", 1024)
59
60            cmd = u"lb_conf"
61            err_msg = f"Failed to set lb conf on host {node[u'host']}"
62            args = dict(
63                ip4_src_address=str(ip4_src_addr),
64                ip6_src_address=str(ip6_src_addr),
65                sticky_buckets_per_core=sticky_buckets_per_core,
66                flow_timeout=flow_timeout
67            )
68
69            with PapiSocketExecutor(node) as papi_exec:
70                papi_exec.add(cmd, **args).get_reply(err_msg)
71        else:
72            raise ValueError(
73                f"Node {node[u'host']} has unknown NodeType: '{node[u'type']}'"
74            )
75
76    @staticmethod
77    def vpp_lb_add_del_vip(node, **kwargs):
78        """Config vip for loadbalancer.
79
80        :param node: Node where the interface is.
81        :param kwargs: Optional key-value arguments:
82
83            vip_addr: IPv4 address to be used as source for IPv4 traffic. (str)
84            protocol: tcp or udp. (int)
85            port: destination port. (int)
86            encap: encap is ip4 GRE(0) or ip6 (1GRE) or L3DSR(2) or NAT4(3) or
87                   NAT6(4). (int)
88            dscp: dscp bit corresponding to VIP
89            type: service type
90            target_port: Pod's port corresponding to specific service
91            node_port: Node's port
92            new_len: Size of the new connections flow table used
93                     for this VIP
94            is_del: 1 if the VIP should be removed otherwise 0.
95
96        :type node: dict
97        :type kwargs: dict
98        :returns: Nothing.
99        :raises ValueError: If the node has an unknown node type.
100        """
101        if node[u"type"] == NodeType.DUT:
102            vip_addr = kwargs.pop(u"vip_addr", "0.0.0.0")
103            protocol = kwargs.pop(u"protocol", 255)
104            port = kwargs.pop(u"port", 0)
105            encap = kwargs.pop(u"encap", 0)
106            dscp = kwargs.pop(u"dscp", 0)
107            srv_type = kwargs.pop(u"srv_type", 0)
108            target_port = kwargs.pop(u"target_port", 0)
109            node_port = kwargs.pop(u"node_port", 0)
110            new_len = kwargs.pop(u"new_len", 1024)
111            is_del = kwargs.pop(u"is_del", 0)
112
113            cmd = u"lb_add_del_vip"
114            err_msg = f"Failed to add vip on host {node[u'host']}"
115
116            vip_addr = ip_address(vip_addr).packed
117            args = dict(
118                pfx={
119                    u"len": 128,
120                    u"address": {u"un": {u"ip4": vip_addr}, u"af": 0}
121                },
122                protocol=protocol,
123                port=port,
124                encap=htonl(encap),
125                dscp=dscp,
126                type=srv_type,
127                target_port=target_port,
128                node_port=node_port,
129                new_flows_table_length=int(new_len),
130                is_del=is_del
131            )
132
133            with PapiSocketExecutor(node) as papi_exec:
134                papi_exec.add(cmd, **args).get_reply(err_msg)
135        else:
136            raise ValueError(
137                f"Node {node[u'host']} has unknown NodeType: '{node[u'type']}'"
138            )
139
140    @staticmethod
141    def vpp_lb_add_del_as(node, **kwargs):
142        """Config AS for Loadbalancer.
143
144        :param node: Node where the interface is.
145        :param kwargs: Optional key-value arguments:
146
147            vip_addr: IPv4 address to be used as source for IPv4 traffic. (str)
148            protocol: tcp or udp. (int)
149            port: destination port. (int)
150            as_addr: The application server address. (str)
151            is_del: 1 if the VIP should be removed otherwise 0. (int)
152            is_flush: 1 if the sessions related to this AS should be flushed
153                      otherwise 0. (int)
154
155        :type node: dict
156        :type kwargs: dict
157        :returns: Nothing.
158        :raises ValueError: If the node has an unknown node type.
159        """
160        if node[u"type"] == NodeType.DUT:
161            cmd = u"lb_add_del_as"
162            err_msg = f"Failed to add lb as on host {node[u'host']}"
163
164            vip_addr = kwargs.pop(u"vip_addr", "0.0.0.0")
165            protocol = kwargs.pop(u"protocol", 255)
166            port = kwargs.pop(u"port", 0)
167            as_addr = kwargs.pop(u"as_addr", u"0.0.0.0")
168            is_del = kwargs.pop(u"is_del", 0)
169            is_flush = kwargs.pop(u"is_flush", 0)
170
171            vip_addr = ip_address(vip_addr).packed
172            as_addr = ip_address(as_addr).packed
173
174            args = dict(
175                pfx={
176                    u"len": 128,
177                    u"address": {u"un": {u"ip4": vip_addr}, u"af": 0}
178                },
179                protocol=protocol,
180                port=port,
181                as_address={u"un": {u"ip4": as_addr}, u"af": 0},
182                is_del=is_del,
183                is_flush=is_flush
184            )
185
186            with PapiSocketExecutor(node) as papi_exec:
187                papi_exec.add(cmd, **args).get_reply(err_msg)
188        else:
189            raise ValueError(
190                f"Node {node[u'host']} has unknown NodeType: '{node[u'type']}'"
191            )
192
193    @staticmethod
194    def vpp_lb_add_del_intf_nat4(node, **kwargs):
195        """Enable/disable NAT4 feature on the interface.
196
197        :param node: Node where the interface is.
198        :param kwargs: Optional key-value arguments:
199
200            is_add: true if add, false if delete. (bool)
201            interface: software index of the interface. (int)
202
203        :type node: dict
204        :type kwargs: dict
205        :returns: Nothing.
206        :raises ValueError: If the node has an unknown node type.
207        """
208        if node[u"type"] == NodeType.DUT:
209            cmd = u"lb_add_del_intf_nat4"
210            err_msg = f"Failed to add interface nat4 on host {node[u'host']}"
211
212            is_add = kwargs.pop(u"is_add", True)
213            interface = kwargs.pop(u"interface", 0)
214            sw_if_index = Topology.get_interface_sw_index(node, interface)
215            args = dict(
216                is_add=is_add,
217                sw_if_index=sw_if_index
218            )
219
220            with PapiSocketExecutor(node) as papi_exec:
221                papi_exec.add(cmd, **args).get_reply(err_msg)
222        else:
223            raise ValueError(
224                f"Node {node[u'host']} has unknown NodeType: '{node[u'type']}'"
225            )
226