JumpAvg: Fix string format
[csit.git] / resources / libraries / python / LoadBalancerUtil.py
1 # Copyright (c) 2021 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
16 from ipaddress import ip_address
17 from socket import htonl
18
19 from resources.libraries.python.topology import NodeType, Topology
20 from resources.libraries.python.PapiExecutor import PapiSocketExecutor
21
22
23 class 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             )