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