BIER: missing endian swap for imposition object in API return
[vpp.git] / test / vpp_ip_route.py
1 """
2   IP Routes
3
4   object abstractions for representing IP routes in VPP
5 """
6
7 from vpp_object import *
8 from socket import inet_pton, inet_ntop, AF_INET, AF_INET6
9
10 # from vnet/vnet/mpls/mpls_types.h
11 MPLS_IETF_MAX_LABEL = 0xfffff
12 MPLS_LABEL_INVALID = MPLS_IETF_MAX_LABEL + 1
13
14
15 class MRouteItfFlags:
16     MFIB_ITF_FLAG_NONE = 0
17     MFIB_ITF_FLAG_NEGATE_SIGNAL = 1
18     MFIB_ITF_FLAG_ACCEPT = 2
19     MFIB_ITF_FLAG_FORWARD = 4
20     MFIB_ITF_FLAG_SIGNAL_PRESENT = 8
21     MFIB_ITF_FLAG_INTERNAL_COPY = 16
22
23
24 class MRouteEntryFlags:
25     MFIB_ENTRY_FLAG_NONE = 0
26     MFIB_ENTRY_FLAG_SIGNAL = 1
27     MFIB_ENTRY_FLAG_DROP = 2
28     MFIB_ENTRY_FLAG_CONNECTED = 4
29     MFIB_ENTRY_FLAG_INHERIT_ACCEPT = 8
30
31
32 class DpoProto:
33     DPO_PROTO_IP4 = 0
34     DPO_PROTO_IP6 = 1
35     DPO_PROTO_MPLS = 2
36     DPO_PROTO_ETHERNET = 3
37     DPO_PROTO_BIER = 4
38     DPO_PROTO_NSH = 5
39
40
41 def find_route(test, ip_addr, len, table_id=0, inet=AF_INET):
42     if inet == AF_INET:
43         s = 4
44         routes = test.vapi.ip_fib_dump()
45     else:
46         s = 16
47         routes = test.vapi.ip6_fib_dump()
48
49     route_addr = inet_pton(inet, ip_addr)
50     for e in routes:
51         if route_addr == e.address[:s] \
52            and len == e.address_length \
53            and table_id == e.table_id:
54             return True
55     return False
56
57
58 class VppIpTable(VppObject):
59
60     def __init__(self,
61                  test,
62                  table_id,
63                  is_ip6=0):
64         self._test = test
65         self.table_id = table_id
66         self.is_ip6 = is_ip6
67
68     def add_vpp_config(self):
69         self._test.vapi.ip_table_add_del(
70             self.table_id,
71             is_ipv6=self.is_ip6,
72             is_add=1)
73         self._test.registry.register(self, self._test.logger)
74
75     def remove_vpp_config(self):
76         self._test.vapi.ip_table_add_del(
77             self.table_id,
78             is_ipv6=self.is_ip6,
79             is_add=0)
80
81     def query_vpp_config(self):
82         # find the default route
83         return find_route(self._test,
84                           "::" if self.is_ip6 else "0.0.0.0",
85                           0,
86                           self.table_id,
87                           inet=AF_INET6 if self.is_ip6 == 1 else AF_INET)
88
89     def __str__(self):
90         return self.object_id()
91
92     def object_id(self):
93         return ("table-%s-%d" %
94                 ("v6" if self.is_ip6 == 1 else "v4",
95                  self.table_id))
96
97
98 class VppRoutePath(object):
99
100     def __init__(
101             self,
102             nh_addr,
103             nh_sw_if_index,
104             nh_table_id=0,
105             labels=[],
106             nh_via_label=MPLS_LABEL_INVALID,
107             rpf_id=0,
108             is_interface_rx=0,
109             is_resolve_host=0,
110             is_resolve_attached=0,
111             is_source_lookup=0,
112             is_udp_encap=0,
113             next_hop_id=0xffffffff,
114             proto=DpoProto.DPO_PROTO_IP4):
115         self.nh_itf = nh_sw_if_index
116         self.nh_table_id = nh_table_id
117         self.nh_via_label = nh_via_label
118         self.nh_labels = labels
119         self.weight = 1
120         self.rpf_id = rpf_id
121         self.proto = proto
122         if self.proto is DpoProto.DPO_PROTO_IP6:
123             self.nh_addr = inet_pton(AF_INET6, nh_addr)
124         elif self.proto is DpoProto.DPO_PROTO_IP4:
125             self.nh_addr = inet_pton(AF_INET, nh_addr)
126         else:
127             self.nh_addr = inet_pton(AF_INET6, "::")
128         self.is_resolve_host = is_resolve_host
129         self.is_resolve_attached = is_resolve_attached
130         self.is_interface_rx = is_interface_rx
131         self.is_source_lookup = is_source_lookup
132         self.is_rpf_id = 0
133         if rpf_id != 0:
134             self.is_rpf_id = 1
135             self.nh_itf = rpf_id
136         self.is_udp_encap = is_udp_encap
137         self.next_hop_id = next_hop_id
138
139
140 class VppMRoutePath(VppRoutePath):
141
142     def __init__(self, nh_sw_if_index, flags,
143                  proto=DpoProto.DPO_PROTO_IP4,
144                  bier_imp=0):
145         super(VppMRoutePath, self).__init__(
146             "::" if proto is DpoProto.DPO_PROTO_IP6 else "0.0.0.0",
147             nh_sw_if_index,
148             proto=proto)
149         self.nh_i_flags = flags
150         self.bier_imp = bier_imp
151
152
153 class VppIpRoute(VppObject):
154     """
155     IP Route
156     """
157
158     def __init__(self, test, dest_addr,
159                  dest_addr_len, paths, table_id=0, is_ip6=0, is_local=0,
160                  is_unreach=0, is_prohibit=0):
161         self._test = test
162         self.paths = paths
163         self.dest_addr_len = dest_addr_len
164         self.table_id = table_id
165         self.is_ip6 = is_ip6
166         self.is_local = is_local
167         self.is_unreach = is_unreach
168         self.is_prohibit = is_prohibit
169         self.dest_addr_p = dest_addr
170         if is_ip6:
171             self.dest_addr = inet_pton(AF_INET6, dest_addr)
172         else:
173             self.dest_addr = inet_pton(AF_INET, dest_addr)
174
175     def modify(self, paths, is_local=0,
176                is_unreach=0, is_prohibit=0):
177         self.paths = paths
178         self.is_local = is_local
179         self.is_unreach = is_unreach
180         self.is_prohibit = is_prohibit
181
182     def add_vpp_config(self):
183         if self.is_local or self.is_unreach or self.is_prohibit:
184             self._test.vapi.ip_add_del_route(
185                 self.dest_addr,
186                 self.dest_addr_len,
187                 inet_pton(AF_INET6, "::"),
188                 0xffffffff,
189                 is_local=self.is_local,
190                 is_unreach=self.is_unreach,
191                 is_prohibit=self.is_prohibit,
192                 table_id=self.table_id,
193                 is_ipv6=self.is_ip6)
194         else:
195             for path in self.paths:
196                 self._test.vapi.ip_add_del_route(
197                     self.dest_addr,
198                     self.dest_addr_len,
199                     path.nh_addr,
200                     path.nh_itf,
201                     table_id=self.table_id,
202                     next_hop_out_label_stack=path.nh_labels,
203                     next_hop_n_out_labels=len(
204                         path.nh_labels),
205                     next_hop_via_label=path.nh_via_label,
206                     next_hop_table_id=path.nh_table_id,
207                     next_hop_id=path.next_hop_id,
208                     is_ipv6=self.is_ip6,
209                     is_l2_bridged=1
210                     if path.proto == DpoProto.DPO_PROTO_ETHERNET else 0,
211                     is_resolve_host=path.is_resolve_host,
212                     is_resolve_attached=path.is_resolve_attached,
213                     is_source_lookup=path.is_source_lookup,
214                     is_udp_encap=path.is_udp_encap,
215                     is_multipath=1 if len(self.paths) > 1 else 0)
216         self._test.registry.register(self, self._test.logger)
217
218     def remove_vpp_config(self):
219         if self.is_local or self.is_unreach or self.is_prohibit:
220             self._test.vapi.ip_add_del_route(
221                 self.dest_addr,
222                 self.dest_addr_len,
223                 inet_pton(AF_INET6, "::"),
224                 0xffffffff,
225                 is_local=self.is_local,
226                 is_unreach=self.is_unreach,
227                 is_prohibit=self.is_prohibit,
228                 is_add=0,
229                 table_id=self.table_id,
230                 is_ipv6=self.is_ip6)
231         else:
232             for path in self.paths:
233                 self._test.vapi.ip_add_del_route(
234                     self.dest_addr,
235                     self.dest_addr_len,
236                     path.nh_addr,
237                     path.nh_itf,
238                     table_id=self.table_id,
239                     next_hop_table_id=path.nh_table_id,
240                     next_hop_via_label=path.nh_via_label,
241                     next_hop_id=path.next_hop_id,
242                     is_add=0,
243                     is_udp_encap=path.is_udp_encap,
244                     is_ipv6=self.is_ip6)
245
246     def query_vpp_config(self):
247         return find_route(self._test,
248                           self.dest_addr_p,
249                           self.dest_addr_len,
250                           self.table_id,
251                           inet=AF_INET6 if self.is_ip6 == 1 else AF_INET)
252
253     def __str__(self):
254         return self.object_id()
255
256     def object_id(self):
257         return ("%d:%s/%d"
258                 % (self.table_id,
259                    self.dest_addr_p,
260                    self.dest_addr_len))
261
262
263 class VppIpMRoute(VppObject):
264     """
265     IP Multicast Route
266     """
267
268     def __init__(self, test, src_addr, grp_addr,
269                  grp_addr_len, e_flags, paths, table_id=0,
270                  rpf_id=0, is_ip6=0):
271         self._test = test
272         self.paths = paths
273         self.grp_addr_len = grp_addr_len
274         self.table_id = table_id
275         self.e_flags = e_flags
276         self.is_ip6 = is_ip6
277         self.rpf_id = rpf_id
278
279         if is_ip6:
280             self.grp_addr = inet_pton(AF_INET6, grp_addr)
281             self.src_addr = inet_pton(AF_INET6, src_addr)
282         else:
283             self.grp_addr = inet_pton(AF_INET, grp_addr)
284             self.src_addr = inet_pton(AF_INET, src_addr)
285
286     def add_vpp_config(self):
287         for path in self.paths:
288             self._test.vapi.ip_mroute_add_del(self.src_addr,
289                                               self.grp_addr,
290                                               self.grp_addr_len,
291                                               self.e_flags,
292                                               path.proto,
293                                               path.nh_itf,
294                                               path.nh_i_flags,
295                                               bier_imp=path.bier_imp,
296                                               rpf_id=self.rpf_id,
297                                               table_id=self.table_id,
298                                               is_ipv6=self.is_ip6)
299         self._test.registry.register(self, self._test.logger)
300
301     def remove_vpp_config(self):
302         for path in self.paths:
303             self._test.vapi.ip_mroute_add_del(self.src_addr,
304                                               self.grp_addr,
305                                               self.grp_addr_len,
306                                               self.e_flags,
307                                               path.proto,
308                                               path.nh_itf,
309                                               path.nh_i_flags,
310                                               table_id=self.table_id,
311                                               bier_imp=path.bier_imp,
312                                               is_add=0,
313                                               is_ipv6=self.is_ip6)
314
315     def update_entry_flags(self, flags):
316         self.e_flags = flags
317         self._test.vapi.ip_mroute_add_del(self.src_addr,
318                                           self.grp_addr,
319                                           self.grp_addr_len,
320                                           self.e_flags,
321                                           0,
322                                           0xffffffff,
323                                           0,
324                                           table_id=self.table_id,
325                                           is_ipv6=self.is_ip6)
326
327     def update_rpf_id(self, rpf_id):
328         self.rpf_id = rpf_id
329         self._test.vapi.ip_mroute_add_del(self.src_addr,
330                                           self.grp_addr,
331                                           self.grp_addr_len,
332                                           self.e_flags,
333                                           0,
334                                           0xffffffff,
335                                           0,
336                                           rpf_id=self.rpf_id,
337                                           table_id=self.table_id,
338                                           is_ipv6=self.is_ip6)
339
340     def update_path_flags(self, itf, flags):
341         for path in self.paths:
342             if path.nh_itf == itf:
343                 path.nh_i_flags = flags
344                 break
345         self._test.vapi.ip_mroute_add_del(self.src_addr,
346                                           self.grp_addr,
347                                           self.grp_addr_len,
348                                           self.e_flags,
349                                           path.proto,
350                                           path.nh_itf,
351                                           path.nh_i_flags,
352                                           table_id=self.table_id,
353                                           is_ipv6=self.is_ip6)
354
355     def query_vpp_config(self):
356         if self.is_ip6:
357             dump = self._test.vapi.ip6_mfib_dump()
358         else:
359             dump = self._test.vapi.ip_mfib_dump()
360         for e in dump:
361             if self.grp_addr == e.grp_address \
362                and self.grp_addr_len == e.address_length \
363                and self.src_addr == e.src_address \
364                and self.table_id == e.table_id:
365                 return True
366         return False
367
368     def __str__(self):
369         return self.object_id()
370
371     def object_id(self):
372         if self.is_ip6:
373             return ("%d:(%s,%s/%d)"
374                     % (self.table_id,
375                        inet_ntop(AF_INET6, self.src_addr),
376                        inet_ntop(AF_INET6, self.grp_addr),
377                        self.grp_addr_len))
378         else:
379             return ("%d:(%s,%s/%d)"
380                     % (self.table_id,
381                        inet_ntop(AF_INET, self.src_addr),
382                        inet_ntop(AF_INET, self.grp_addr),
383                        self.grp_addr_len))
384
385
386 class VppMFibSignal(object):
387     def __init__(self, test, route, interface, packet):
388         self.route = route
389         self.interface = interface
390         self.packet = packet
391         self.test = test
392
393     def compare(self, signal):
394         self.test.assertEqual(self.interface, signal.sw_if_index)
395         self.test.assertEqual(self.route.table_id, signal.table_id)
396         self.test.assertEqual(self.route.grp_addr_len,
397                               signal.grp_address_len)
398         for i in range(self.route.grp_addr_len / 8):
399             self.test.assertEqual(self.route.grp_addr[i],
400                                   signal.grp_address[i])
401         if (self.route.grp_addr_len > 32):
402             for i in range(4):
403                 self.test.assertEqual(self.route.src_addr[i],
404                                       signal.src_address[i])
405
406
407 class VppMplsIpBind(VppObject):
408     """
409     MPLS to IP Binding
410     """
411
412     def __init__(self, test, local_label, dest_addr, dest_addr_len,
413                  table_id=0, ip_table_id=0, is_ip6=0):
414         self._test = test
415         self.dest_addr_len = dest_addr_len
416         self.dest_addr = dest_addr
417         self.local_label = local_label
418         self.table_id = table_id
419         self.ip_table_id = ip_table_id
420         self.is_ip6 = is_ip6
421         if is_ip6:
422             self.dest_addrn = inet_pton(AF_INET6, dest_addr)
423         else:
424             self.dest_addrn = inet_pton(AF_INET, dest_addr)
425
426     def add_vpp_config(self):
427         self._test.vapi.mpls_ip_bind_unbind(self.local_label,
428                                             self.dest_addrn,
429                                             self.dest_addr_len,
430                                             table_id=self.table_id,
431                                             ip_table_id=self.ip_table_id,
432                                             is_ip4=(self.is_ip6 == 0))
433         self._test.registry.register(self, self._test.logger)
434
435     def remove_vpp_config(self):
436         self._test.vapi.mpls_ip_bind_unbind(self.local_label,
437                                             self.dest_addrn,
438                                             self.dest_addr_len,
439                                             table_id=self.table_id,
440                                             ip_table_id=self.ip_table_id,
441                                             is_bind=0,
442                                             is_ip4=(self.is_ip6 == 0))
443
444     def query_vpp_config(self):
445         dump = self._test.vapi.mpls_fib_dump()
446         for e in dump:
447             if self.local_label == e.label \
448                and self.table_id == e.table_id:
449                 return True
450         return False
451
452     def __str__(self):
453         return self.object_id()
454
455     def object_id(self):
456         return ("%d:%s binds %d:%s/%d"
457                 % (self.table_id,
458                    self.local_label,
459                    self.ip_table_id,
460                    self.dest_addr,
461                    self.dest_addr_len))
462
463
464 class VppMplsTable(VppObject):
465
466     def __init__(self,
467                  test,
468                  table_id):
469         self._test = test
470         self.table_id = table_id
471
472     def add_vpp_config(self):
473         self._test.vapi.mpls_table_add_del(
474             self.table_id,
475             is_add=1)
476         self._test.registry.register(self, self._test.logger)
477
478     def remove_vpp_config(self):
479         self._test.vapi.mpls_table_add_del(
480             self.table_id,
481             is_add=0)
482
483     def query_vpp_config(self):
484         # find the default route
485         dump = self._test.vapi.mpls_fib_dump()
486         if len(dump):
487             return True
488         return False
489
490     def __str__(self):
491         return self.object_id()
492
493     def object_id(self):
494         return ("table-mpls-%d" % (self.table_id))
495
496
497 class VppMplsRoute(VppObject):
498     """
499     MPLS Route/LSP
500     """
501
502     def __init__(self, test, local_label, eos_bit, paths, table_id=0,
503                  is_multicast=0):
504         self._test = test
505         self.paths = paths
506         self.local_label = local_label
507         self.eos_bit = eos_bit
508         self.table_id = table_id
509         self.is_multicast = is_multicast
510
511     def add_vpp_config(self):
512         is_multipath = len(self.paths) > 1
513         for path in self.paths:
514             self._test.vapi.mpls_route_add_del(
515                 self.local_label,
516                 self.eos_bit,
517                 path.proto,
518                 path.nh_addr,
519                 path.nh_itf,
520                 is_multicast=self.is_multicast,
521                 is_multipath=is_multipath,
522                 table_id=self.table_id,
523                 is_interface_rx=path.is_interface_rx,
524                 is_rpf_id=path.is_rpf_id,
525                 next_hop_out_label_stack=path.nh_labels,
526                 next_hop_n_out_labels=len(
527                     path.nh_labels),
528                 next_hop_via_label=path.nh_via_label,
529                 next_hop_table_id=path.nh_table_id)
530         self._test.registry.register(self, self._test.logger)
531
532     def remove_vpp_config(self):
533         for path in self.paths:
534             self._test.vapi.mpls_route_add_del(self.local_label,
535                                                self.eos_bit,
536                                                path.proto,
537                                                path.nh_addr,
538                                                path.nh_itf,
539                                                is_rpf_id=path.is_rpf_id,
540                                                table_id=self.table_id,
541                                                is_add=0)
542
543     def query_vpp_config(self):
544         dump = self._test.vapi.mpls_fib_dump()
545         for e in dump:
546             if self.local_label == e.label \
547                and self.eos_bit == e.eos_bit \
548                and self.table_id == e.table_id:
549                 return True
550         return False
551
552     def __str__(self):
553         return self.object_id()
554
555     def object_id(self):
556         return ("%d:%s/%d"
557                 % (self.table_id,
558                    self.local_label,
559                    20+self.eos_bit))