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