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