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