666b6e636dc95f8277e7d97809a9f45ba1773af8
[csit.git] / resources / libraries / python / LispSetup.py
1 # Copyright (c) 2016-2019 Cisco 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 """Library to set up Lisp in topology."""
15
16 from ipaddress import ip_address
17
18 from resources.libraries.python.L2Util import L2Util
19 from resources.libraries.python.PapiExecutor import PapiSocketExecutor
20 from resources.libraries.python.topology import NodeType
21
22
23 class LispStatus:
24     """Class for lisp API."""
25
26     @staticmethod
27     def vpp_lisp_enable_disable(node, state):
28         """Enable/Disable lisp in the VPP node in topology.
29
30         :param node: Node of the test topology.
31         :param state: State of the lisp, enable or disable.
32         :type node: dict
33         :type state: str
34         """
35         args = dict(is_en=0 if state == u"disable" else 1)
36
37         cmd = u"lisp_enable_disable"
38         err_msg = f"Failed to set LISP status on host {node[u'host']}"
39
40         with PapiSocketExecutor(node) as papi_exec:
41             papi_exec.add(cmd, **args).get_reply(err_msg)
42
43 class LispRemoteMapping:
44     """Class for lisp remote mapping API."""
45
46     @staticmethod
47     def vpp_add_lisp_remote_mapping(
48             node, vni, deid, deid_prefix, seid, seid_prefix, rloc,
49             is_mac=False):
50         """Add lisp remote mapping on the VPP node in topology.
51
52         :param node: VPP node.
53         :param vni: Vni.
54         :param deid: Destination eid address.
55         :param deid_prefix: Destination eid address prefix_len.
56         :param seid: Source eid address.
57         :param seid_prefix: Source eid address prefix_len.
58         :param rloc: Receiver locator.
59         :param is_mac: Set to True if the deid/seid is MAC address.
60         :type node: dict
61         :type vni: int
62         :type deid: str
63         :type deid_prefix: int
64         :type seid: str
65         :type seid_prefix: int
66         :type rloc: str
67         :type is_mac: bool
68         """
69         if not is_mac:
70             eid_type = 0 if ip_address(deid).version == 4 else 1
71             eid_packed = ip_address(deid).packed
72             seid_packed = ip_address(seid).packed
73             eid_len = deid_prefix
74             seid_len = seid_prefix
75         else:
76             eid_type = 2
77             eid_packed = L2Util.mac_to_bin(deid)
78             seid_packed = L2Util.mac_to_bin(seid)
79             eid_len = 0
80             seid_len = 0
81
82         rlocs = [
83             dict(
84                 is_ip4=1 if ip_address(rloc).version == 4 else 0,
85                 addr=ip_address(rloc).packed
86             )
87         ]
88
89         args = dict(
90             is_add=1,
91             is_src_dst=1,
92             vni=int(vni),
93             eid_type=eid_type,
94             eid=eid_packed,
95             eid_len=eid_len,
96             seid=seid_packed,
97             seid_len=seid_len,
98             rloc_num=1,
99             rlocs=rlocs
100         )
101
102         cmd = u"lisp_add_del_remote_mapping"
103         err_msg = f"Failed to add remote mapping on host {node[u'host']}"
104
105         with PapiSocketExecutor(node) as papi_exec:
106             papi_exec.add(cmd, **args).get_reply(err_msg)
107
108     @staticmethod
109     def vpp_del_lisp_remote_mapping(
110             node, vni, deid, deid_prefix, seid, seid_prefix, rloc):
111         """Delete lisp remote mapping on the VPP node in topology.
112
113         :param node: VPP node.
114         :param vni: Vni.
115         :param deid: Destination eid address.
116         :param deid_prefix: Destination eid address prefix_len.
117         :param seid: Source eid address.
118         :param seid_prefix: Source eid address prefix_len.
119         :param rloc: Receiver locator.
120         :type node: dict
121         :type vni: int
122         :type deid: str
123         :type deid_prefix: int
124         :type seid: str
125         :type seid_prefix: int
126         :type rloc: str
127         """
128         # used only with IPs
129         is_mac = False
130
131         if not is_mac:
132             eid_type = 0 if ip_address(deid).version == 4 else 1
133             eid_packed = ip_address(deid).packed
134             seid_packed = ip_address(seid).packed
135             eid_len = deid_prefix
136             seid_len = seid_prefix
137         else:
138             eid_type = 2
139             eid_packed = L2Util.mac_to_bin(deid)
140             seid_packed = L2Util.mac_to_bin(seid)
141             eid_len = 0
142             seid_len = 0
143
144         rlocs = [
145             dict(
146                 is_ip4=1 if ip_address(str(rloc)).version == 4 else 0,
147                 addr=ip_address(str(rloc)).packed
148             )
149         ]
150
151         args = dict(
152             is_add=0,
153             is_src_dst=1,
154             vni=int(vni),
155             eid_type=eid_type,
156             eid=eid_packed,
157             eid_len=eid_len,
158             seid=seid_packed,
159             seid_len=seid_len,
160             rloc_num=1,
161             rlocs=rlocs
162         )
163
164         cmd = u"lisp_add_del_remote_mapping"
165         err_msg = f"Failed to delete remote mapping on host {node[u'host']}"
166
167         with PapiSocketExecutor(node) as papi_exec:
168             papi_exec.add(cmd, **args).get_reply(err_msg)
169
170 class LispAdjacency:
171     """Class for lisp adjacency API."""
172
173     @staticmethod
174     def vpp_add_lisp_adjacency(
175             node, vni, deid, deid_prefix, seid, seid_prefix, is_mac=False):
176         """Add lisp adjacency on the VPP node in topology.
177
178         :param node: VPP node.
179         :param vni: Vni.
180         :param deid: Destination eid address.
181         :param deid_prefix: Destination eid address prefix_len.
182         :param seid: Source eid address.
183         :param seid_prefix: Source eid address prefix_len.
184         :param is_mac: Set to True if the deid/seid is MAC address.
185         :type node: dict
186         :type vni: int
187         :type deid: str
188         :type deid_prefix: int
189         :type seid: str
190         :type seid_prefix: int
191         :type is_mac: bool
192         """
193         if not is_mac:
194             eid_type = 0 if ip_address(deid).version == 4 else 1
195             reid = ip_address(deid).packed
196             leid = ip_address(seid).packed
197             reid_len = deid_prefix
198             leid_len = seid_prefix
199         else:
200             eid_type = 2
201             reid = L2Util.mac_to_bin(deid)
202             leid = L2Util.mac_to_bin(seid)
203             reid_len = 0
204             leid_len = 0
205
206         args = dict(
207             is_add=1,
208             vni=int(vni),
209             eid_type=eid_type,
210             reid=reid,
211             reid_len=reid_len,
212             leid=leid,
213             leid_len=leid_len
214         )
215
216         cmd = u"lisp_add_del_adjacency"
217         err_msg = f"Failed to add lisp adjacency on host {node[u'host']}"
218
219         with PapiSocketExecutor(node) as papi_exec:
220             papi_exec.add(cmd, **args).get_reply(err_msg)
221
222     @staticmethod
223     def vpp_del_lisp_adjacency(
224             node, vni, deid, deid_prefix, seid, seid_prefix):
225         """Delete lisp adjacency on the VPP node in topology.
226
227         :param node: VPP node.
228         :param vni: Vni.
229         :param deid: Destination eid address.
230         :param deid_prefix: Destination eid address prefix_len.
231         :param seid: Source eid address.
232         :param seid_prefix: Source eid address prefix_len.
233         :type node: dict
234         :type vni: int
235         :type deid: str
236         :type deid_prefix: int
237         :type seid: str
238         :type seid_prefix: int
239         """
240         # used only with IPs
241         is_mac = False
242
243         if not is_mac:
244             eid_type = 0 if ip_address(deid).version == 4 else 1
245             reid = ip_address(deid).packed
246             leid = ip_address(seid).packed
247             reid_len = deid_prefix
248             leid_len = seid_prefix
249         else:
250             eid_type = 2
251             reid = L2Util.mac_to_bin(deid)
252             leid = L2Util.mac_to_bin(seid)
253             reid_len = 0
254             leid_len = 0
255
256         args = dict(
257             is_add=0,
258             vni=int(vni),
259             eid_type=eid_type,
260             reid=reid,
261             reid_len=reid_len,
262             leid=leid,
263             leid_len=leid_len
264         )
265
266         cmd = u"lisp_add_del_adjacency"
267         err_msg = f"Failed to delete lisp adjacency on host {node[u'host']}"
268
269         with PapiSocketExecutor(node) as papi_exec:
270             papi_exec.add(cmd, **args).get_reply(err_msg)
271
272 class LispGpeStatus:
273     """Clas for LISP GPE status manipulation."""
274
275     @staticmethod
276     def vpp_lisp_gpe_enable_disable(node, state):
277         """Change the state of LISP GPE - enable or disable.
278
279         :param node: VPP node.
280         :param state: Requested state - enable or disable.
281         :type node: dict
282         :type state: str
283         """
284         args = dict(is_en=0 if state == u"disable" else 1)
285
286         cmd = u"gpe_enable_disable"
287         err_msg = f"Failed to set LISP GPE status on host {node[u'host']}"
288
289         with PapiSocketExecutor(node) as papi_exec:
290             papi_exec.add(cmd, **args).get_reply(err_msg)
291
292 class LispGpeForwardEntry:
293     """The functionality needed for these methods is not implemented in VPP
294     (VAT). Bug https://jira.fd.io/browse/VPP-334 was open to cover this issue.
295
296     TODO: Implement when VPP-334 is fixed.
297     """
298
299     @staticmethod
300     def add_lisp_gpe_forward_entry(node, *args):
301         """Not implemented"""
302         # TODO: Implement when VPP-334 is fixed.
303
304     @staticmethod
305     def del_lisp_gpe_forward_entry(node, *args):
306         """Not implemented"""
307         # TODO: Implement when VPP-334 is fixed.
308
309
310 class LispMapResolver:
311     """Class for Lisp map resolver API."""
312
313     @staticmethod
314     def vpp_add_map_resolver(node, map_resolver_ip):
315         """Set lisp map resolver on the VPP node in topology.
316
317         :param node: VPP node.
318         :param map_resolver_ip: IP address of the map resolver.
319         :type node: dict
320         :type map_resolver_ip: str
321         """
322         args = dict(
323             is_add=1,
324             is_ipv6=0 if ip_address(map_resolver_ip).version == 4 else 1,
325             ip_address=ip_address(map_resolver_ip).packed
326         )
327
328         cmd = u"lisp_add_del_map_resolver"
329         err_msg = f"Failed to add map resolver on host {node[u'host']}"
330
331         with PapiSocketExecutor(node) as papi_exec:
332             papi_exec.add(cmd, **args).get_reply(err_msg)
333
334     @staticmethod
335     def vpp_del_map_resolver(node, map_resolver_ip):
336         """Unset lisp map resolver on the VPP node in topology.
337
338         :param node: VPP node.
339         :param map_resolver_ip: IP address of the map resolver.
340         :type node: dict
341         :type map_resolver_ip: str
342         """
343         args = dict(
344             is_add=0,
345             is_ipv6=0 if ip_address(map_resolver_ip).version == 4 else 1,
346             ip_address=ip_address(map_resolver_ip).packed
347         )
348
349         cmd = u"lisp_add_del_map_resolver"
350         err_msg = f"Failed to delete map resolver on host {node[u'host']}"
351
352         with PapiSocketExecutor(node) as papi_exec:
353             papi_exec.add(cmd, **args).get_reply(err_msg)
354
355 class LispLocalEid:
356     """Class for Lisp local eid API."""
357
358     @staticmethod
359     def vpp_add_lisp_local_eid(
360             node, locator_set_name, vni, eid, prefix_len=None):
361         """Set lisp eid address on the VPP node in topology.
362
363         :param node: VPP node.
364         :param locator_set_name: Name of the locator_set.
365         :param vni: vni value.
366         :param eid: Eid value.
367         :param prefix_len: prefix len if the eid is IP address.
368         :type node: dict
369         :type locator_set_name: str
370         :type vni: int
371         :type eid: str
372         :type prefix_len: int
373         """
374         if prefix_len:
375             eid_type = 0 if ip_address(eid).version == 4 else 1
376             eid_packed = ip_address(eid).packed
377         else:
378             eid_type = 2
379             eid_packed = L2Util.mac_to_bin(eid)
380
381         args = dict(
382             is_add=1,
383             eid_type=eid_type,
384             eid=eid_packed,
385             prefix_len=prefix_len,
386             locator_set_name=locator_set_name,
387             vni=int(vni)
388         )
389
390         cmd = u"lisp_add_del_local_eid"
391         err_msg = f"Failed to add local eid on host {node[u'host']}"
392
393         with PapiSocketExecutor(node) as papi_exec:
394             papi_exec.add(cmd, **args).get_reply(err_msg)
395
396     @staticmethod
397     def vpp_del_lisp_local_eid(
398             node, locator_set_name, vni, eid, prefix_len=None):
399         """Set lisp eid addres on the VPP node in topology.
400
401         :param node: VPP node.
402         :param locator_set_name: Name of the locator_set.
403         :param vni: vni value.
404         :param eid: Eid value.
405         :param prefix_len: prefix len if the eid is IP address.
406         :type node: dict
407         :type locator_set_name: str
408         :type vni: int
409         :type eid: str
410         :type prefix_len: int
411         """
412         if prefix_len:
413             eid_type = 0 if ip_address(eid).version == 4 else 1
414             eid_packed = ip_address(eid).packed
415         else:
416             eid_type = 2
417             eid_packed = L2Util.mac_to_bin(eid)
418
419         args = dict(
420             is_add=0,
421             eid_type=eid_type,
422             eid=eid_packed,
423             prefix_len=prefix_len,
424             locator_set_name=locator_set_name,
425             vni=int(vni)
426         )
427
428         cmd = u"lisp_add_del_local_eid"
429         err_msg = f"Failed to delete local eid on host {node[u'host']}"
430
431         with PapiSocketExecutor(node) as papi_exec:
432             papi_exec.add(cmd, **args).get_reply(err_msg)
433
434 class LispLocator:
435     """Class for the Lisp Locator API."""
436
437     @staticmethod
438     def vpp_add_lisp_locator(node, locator_name, sw_if_index, priority, weight):
439         """Set lisp locator on the VPP node in topology.
440
441         :param node: VPP node.
442         :param locator_name: Name of the locator_set.
443         :param sw_if_index: sw_if_index if the interface.
444         :param priority: priority of the locator.
445         :param weight: weight of the locator.
446         :type node: dict
447         :type locator_name: str
448         :type sw_if_index: int
449         :type priority: int
450         :type weight: int
451         """
452
453         args = dict(
454             is_add=1,
455             locator_set_name=locator_name,
456             sw_if_index=sw_if_index,
457             priority=priority,
458             weight=weight
459         )
460
461         cmd = u"lisp_add_del_locator"
462         err_msg = f"Failed to add locator on host {node[u'host']}"
463
464         with PapiSocketExecutor(node) as papi_exec:
465             papi_exec.add(cmd, **args).get_reply(err_msg)
466
467     @staticmethod
468     def vpp_del_lisp_locator(node, locator_name, sw_if_index, priority, weight):
469         """Unset lisp locator on the VPP node in topology.
470
471         :param node: VPP node.
472         :param locator_name: Name of the locator_set.
473         :param sw_if_index: sw_if_index if the interface.
474         :param priority: priority of the locator.
475         :param weight: weight of the locator.
476         :type node: dict
477         :type locator_name: str
478         :type sw_if_index: int
479         :type priority: int
480         :type weight: int
481         """
482         args = dict(
483             is_add=0,
484             locator_set_name=locator_name,
485             sw_if_index=sw_if_index,
486             priority=priority,
487             weight=weight
488         )
489
490         cmd = u"lisp_add_del_locator"
491         err_msg = f"Failed to delete locator on host {node[u'host']}"
492
493         with PapiSocketExecutor(node) as papi_exec:
494             papi_exec.add(cmd, **args).get_reply(err_msg)
495
496 class LispLocatorSet:
497     """Class for Lisp Locator Set API."""
498
499     @staticmethod
500     def vpp_add_lisp_locator_set(node, name):
501         """Add lisp locator_set on VPP.
502
503         :param node: VPP node.
504         :param name: VPP locator name.
505         :type node: dict
506         :type name: str
507         """
508         args = dict(
509             is_add=1,
510             locator_set_name=name,
511             locator_num=0,
512             locators=[]
513         )
514
515         cmd = u"lisp_add_del_locator_set"
516         err_msg = f"Failed to add locator set on host {node[u'host']}"
517
518         with PapiSocketExecutor(node) as papi_exec:
519             papi_exec.add(cmd, **args).get_reply(err_msg)
520
521     @staticmethod
522     def vpp_del_lisp_locator_set(node, name):
523         """Del lisp locator_set on VPP.
524
525         :param node: VPP node.
526         :param name: VPP locator name.
527         :type node: dict
528         :type name: str
529         """
530         args = dict(
531             is_add=0,
532             locator_set_name=name,
533             locator_num=0,
534             locators=[]
535         )
536
537         cmd = u"lisp_add_del_locator_set"
538         err_msg = f"Failed to delete locator set on host {node[u'host']}"
539
540         with PapiSocketExecutor(node) as papi_exec:
541             papi_exec.add(cmd, **args).get_reply(err_msg)
542
543 class LispSetup:
544     """Lisp setup in topology."""
545
546     @staticmethod
547     def vpp_set_lisp_locator_set(node, locator_set_list):
548         """Set lisp locator_sets on VPP node in topology.
549
550         :param node: VPP node.
551         :param locator_set_list: List of locator_set.
552         :type node: dict
553         :type locator_set_list: list
554         """
555
556         if node[u"type"] != NodeType.DUT:
557             raise ValueError(u"Node is not DUT")
558
559         lisp_locator = LispLocator()
560         lisp_locator_set = LispLocatorSet()
561         for locator_set in locator_set_list:
562             locator_set_name = locator_set.get(u"locator-set")
563             locator_list = locator_set.get(u"locator")
564             lisp_locator_set.vpp_add_lisp_locator_set(node, locator_set_name)
565             for locator in locator_list:
566                 sw_if_index = locator.get(u"locator-index")
567                 priority = locator.get(u"priority")
568                 weight = locator.get(u"weight")
569                 lisp_locator.vpp_add_lisp_locator(
570                     node, locator_set_name, sw_if_index, priority, weight
571                 )
572
573     @staticmethod
574     def vpp_unset_lisp_locator_set(node, locator_set_list):
575         """Unset lisp locator_sets on VPP node in topology.
576
577         :param node: VPP node.
578         :param locator_set_list: List of locator_set.
579         :type node: dict
580         :type locator_set_list: list
581         """
582         if node[u"type"] != NodeType.DUT:
583             raise ValueError(u"Lisp locator set, node is not DUT")
584
585         lisp_locator = LispLocator()
586         lisp_locator_set = LispLocatorSet()
587         for locator_set in locator_set_list:
588             locator_set_name = locator_set.get(u"locator-set")
589             locator_list = locator_set.get(u"locator")
590             for locator in locator_list:
591                 sw_if_index = locator.get(u"locator-index")
592                 priority = locator.get(u"priority")
593                 weight = locator.get(u"weight")
594                 lisp_locator.vpp_del_lisp_locator(
595                     node, locator_set_name, sw_if_index, priority, weight
596                 )
597
598             lisp_locator_set.vpp_del_lisp_locator_set(node, locator_set_name)
599
600     @staticmethod
601     def vpp_set_lisp_eid_table(node, eid_table):
602         """Set lisp eid tables on VPP node in topology.
603
604         :param node: VPP node.
605         :param eid_table: Dictionary containing information of eid_table.
606         :type node: dict
607         :type eid_table: dict
608         """
609         if node[u"type"] != NodeType.DUT:
610             raise ValueError(u"Node is not DUT")
611
612         lisp_locator_set = LispLocatorSet()
613         lisp_eid = LispLocalEid()
614         for eid in eid_table:
615             vni = eid.get(u"vni")
616             eid_address = eid.get(u"eid")
617             eid_prefix_len = eid.get(u"eid-prefix-len")
618             locator_set_name = eid.get(u"locator-set")
619             lisp_locator_set.vpp_add_lisp_locator_set(node, locator_set_name)
620             lisp_eid.vpp_add_lisp_local_eid(
621                 node, locator_set_name, vni, eid_address, eid_prefix_len
622             )
623
624     @staticmethod
625     def vpp_unset_lisp_eid_table(node, eid_table):
626         """Unset lisp eid tables on VPP node in topology.
627
628         :param node: VPP node.
629         :param eid_table: Dictionary containing information of eid_table.
630         :type node: dict
631         :type eid_table: dict
632         """
633         if node[u"type"] != NodeType.DUT:
634             raise ValueError(u"Node is not DUT")
635
636         locator_set_list = []
637         lisp_locator_set = LispLocatorSet()
638         lisp_eid = LispLocalEid()
639         for eid in eid_table:
640             vni = eid.get(u"vni")
641             eid_address = eid.get(u"eid")
642             eid_prefix_len = eid.get(u"eid-prefix-len")
643             locator_set_name = eid.get(u"locator-set")
644             if locator_set_name not in locator_set_list:
645                 locator_set_list.append(locator_set_name)
646
647             lisp_eid.vpp_del_lisp_local_eid(
648                 node, locator_set_name, vni, eid_address, eid_prefix_len
649             )
650
651         for locator_set_name in locator_set_list:
652             lisp_locator_set.vpp_del_lisp_locator_set(node, locator_set_name)
653
654     @staticmethod
655     def vpp_set_lisp_map_resolver(node, map_resolver):
656         """Set lisp map resolvers on VPP node in topology.
657
658         :param node: VPP node.
659         :param map_resolver: Dictionary containing information of map resolver.
660         :type node: dict
661         :type map_resolver: dict
662         """
663         lisp_map_res = LispMapResolver()
664         for map_ip in map_resolver:
665             lisp_map_res.vpp_add_map_resolver(node, map_ip.get(u"map resolver"))
666
667     @staticmethod
668     def vpp_unset_lisp_map_resolver(node, map_resolver):
669         """Unset lisp map resolvers on VPP node in topology.
670
671         :param node: VPP node.
672         :param map_resolver: Dictionary containing information of map resolver.
673         :type node: dict
674         :type map_resolver: dict
675         """
676         lisp_map_res = LispMapResolver()
677         for map_ip in map_resolver:
678             lisp_map_res.vpp_del_map_resolver(node, map_ip.get(u"map resolver"))
679
680 class LispEidTableMap:
681     """
682     Class for EID table map.
683     """
684
685     @staticmethod
686     def vpp_lisp_eid_table_mapping(node, vni, bd_id=None, vrf=None):
687         """
688         Map LISP VNI to either bridge domain ID, or VRF ID.
689
690         :param node: VPP node.
691         :param vni: Lisp VNI.
692         :param bd_id: Bridge domain ID.
693         :param vrf: VRF id.
694         :type node: dict
695         :type vni: int
696         :type bd_id: int
697         :type vrf: int
698         """
699         # adding default mapping vni=0, vrf=0 needs to be skipped
700         skip = False
701
702         if bd_id:
703             is_l2 = 1
704             dp_table = bd_id
705         else:
706             is_l2 = 0
707             dp_table = vrf
708             # skip adding default mapping
709             if (int(vrf) == 0) and (int(vni) == 0):
710                 skip = True
711
712         args = dict(
713             is_add=1,
714             vni=int(vni),
715             dp_table=int(dp_table),
716             is_l2=is_l2
717         )
718
719         cmd = u"lisp_eid_table_add_del_map"
720         err_msg = f"Failed to add eid table map on host {node[u'host']}"
721
722         if not skip:
723             with PapiSocketExecutor(node) as papi_exec:
724                 papi_exec.add(cmd, **args).get_reply(err_msg)