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