4 object abstractions for representing IP routes in VPP
7 from vpp_object import *
8 from socket import inet_pton, inet_ntop, AF_INET, AF_INET6
11 # from vnet/vnet/mpls/mpls_types.h
12 MPLS_IETF_MAX_LABEL = 0xfffff
13 MPLS_LABEL_INVALID = MPLS_IETF_MAX_LABEL + 1
17 MFIB_ITF_FLAG_NONE = 0
18 MFIB_ITF_FLAG_NEGATE_SIGNAL = 1
19 MFIB_ITF_FLAG_ACCEPT = 2
20 MFIB_ITF_FLAG_FORWARD = 4
21 MFIB_ITF_FLAG_SIGNAL_PRESENT = 8
22 MFIB_ITF_FLAG_INTERNAL_COPY = 16
25 class MRouteEntryFlags:
26 MFIB_ENTRY_FLAG_NONE = 0
27 MFIB_ENTRY_FLAG_SIGNAL = 1
28 MFIB_ENTRY_FLAG_DROP = 2
29 MFIB_ENTRY_FLAG_CONNECTED = 4
30 MFIB_ENTRY_FLAG_INHERIT_ACCEPT = 8
38 def ip_to_dpo_proto(addr):
40 return DpoProto.DPO_PROTO_IP6
42 return DpoProto.DPO_PROTO_IP4
45 def find_route(test, ip_addr, len, table_id=0, inet=AF_INET):
48 routes = test.vapi.ip_fib_dump()
51 routes = test.vapi.ip6_fib_dump()
53 route_addr = inet_pton(inet, ip_addr)
55 if route_addr == e.address[:s] \
56 and len == e.address_length \
57 and table_id == e.table_id:
62 def find_mroute(test, grp_addr, src_addr, grp_addr_len,
63 table_id=0, inet=AF_INET):
66 routes = test.vapi.ip_mfib_dump()
69 routes = test.vapi.ip6_mfib_dump()
70 gaddr = inet_pton(inet, grp_addr)
71 saddr = inet_pton(inet, src_addr)
73 if gaddr == e.grp_address[:s] \
74 and grp_addr_len == e.address_length \
75 and saddr == e.src_address[:s] \
76 and table_id == e.table_id:
81 def fib_interface_ip_prefix(test, address, length, sw_if_index):
82 vp = VppIpPrefix(address, length)
83 addrs = test.vapi.ip_address_dump(sw_if_index, is_ipv6=vp.is_ip6)
91 if a.prefix_length == length and \
92 a.sw_if_index == sw_if_index and \
98 class VppIpTable(VppObject):
105 self.table_id = table_id
108 def add_vpp_config(self):
109 self._test.vapi.ip_table_add_del(
113 self._test.registry.register(self, self._test.logger)
115 def remove_vpp_config(self):
116 self._test.vapi.ip_table_add_del(
121 def query_vpp_config(self):
122 if self.table_id == 0:
123 # the default table always exists
125 # find the default route
126 return find_route(self._test,
127 "::" if self.is_ip6 else "0.0.0.0",
130 inet=AF_INET6 if self.is_ip6 == 1 else AF_INET)
133 return self.object_id()
136 return ("table-%s-%d" %
137 ("v6" if self.is_ip6 == 1 else "v4",
141 class VppIpInterfaceAddress(VppObject):
143 def __init__(self, test, intf, addr, len):
146 self.prefix = VppIpPrefix(addr, len)
148 def add_vpp_config(self):
149 self._test.vapi.sw_interface_add_del_address(
150 self.intf.sw_if_index,
154 is_ipv6=self.prefix.is_ip6)
155 self._test.registry.register(self, self._test.logger)
157 def remove_vpp_config(self):
158 self._test.vapi.sw_interface_add_del_address(
159 self.intf.sw_if_index,
163 is_ipv6=self.prefix.is_ip6)
165 def query_vpp_config(self):
166 return fib_interface_ip_prefix(self._test,
169 self.intf.sw_if_index)
172 return self.object_id()
175 return "interface-ip-%s-%s" % (self.intf, self.prefix)
178 class VppIpInterfaceBind(VppObject):
180 def __init__(self, test, intf, table):
185 def add_vpp_config(self):
186 if self.table.is_ip6:
187 self.intf.set_table_ip6(self.table.table_id)
189 self.intf.set_table_ip4(self.table.table_id)
190 self._test.registry.register(self, self._test.logger)
192 def remove_vpp_config(self):
193 if 0 == self.table.table_id:
195 if self.table.is_ip6:
196 self.intf.set_table_ip6(0)
198 self.intf.set_table_ip4(0)
200 def query_vpp_config(self):
201 if 0 == self.table.table_id:
203 return self._test.vapi.sw_interface_get_table(
204 self.intf.sw_if_index,
205 self.table.is_ip6).vrf_id == self.table.table_id
208 return self.object_id()
211 return "interface-bind-%s-%s" % (self.intf, self.table)
214 class VppMplsLabel(object):
215 def __init__(self, value, mode=MplsLspMode.PIPE, ttl=64, exp=0):
222 is_uniform = 0 if self.mode is MplsLspMode.PIPE else 1
223 return {'label': self.value,
226 'is_uniform': is_uniform}
229 class VppRoutePath(object):
237 nh_via_label=MPLS_LABEL_INVALID,
241 is_resolve_attached=0,
245 next_hop_id=0xffffffff,
246 proto=DpoProto.DPO_PROTO_IP4):
247 self.nh_itf = nh_sw_if_index
248 self.nh_table_id = nh_table_id
249 self.nh_via_label = nh_via_label
250 self.nh_labels = labels
254 if self.proto is DpoProto.DPO_PROTO_IP6:
255 self.nh_addr = inet_pton(AF_INET6, nh_addr)
256 elif self.proto is DpoProto.DPO_PROTO_IP4:
257 self.nh_addr = inet_pton(AF_INET, nh_addr)
259 self.nh_addr = inet_pton(AF_INET6, "::")
260 self.is_resolve_host = is_resolve_host
261 self.is_resolve_attached = is_resolve_attached
262 self.is_interface_rx = is_interface_rx
263 self.is_source_lookup = is_source_lookup
268 self.is_udp_encap = is_udp_encap
269 self.next_hop_id = next_hop_id
272 def encode_labels(self):
274 for l in self.nh_labels:
275 if type(l) == VppMplsLabel:
276 lstack.append(l.encode())
278 lstack.append({'label': l,
283 return {'next_hop': self.nh_addr,
287 'table_id': self.nh_table_id,
288 'next_hop_id': self.next_hop_id,
289 'sw_if_index': self.nh_itf,
291 'is_udp_encap': self.is_udp_encap,
292 'n_labels': len(self.nh_labels),
293 'label_stack': self.encode_labels()}
295 def __eq__(self, other):
296 return self.nh_addr == other.nh_addr
299 class VppMRoutePath(VppRoutePath):
301 def __init__(self, nh_sw_if_index, flags,
303 proto=DpoProto.DPO_PROTO_IP4,
306 nh = "::" if proto is DpoProto.DPO_PROTO_IP6 else "0.0.0.0"
307 super(VppMRoutePath, self).__init__(nh,
310 self.nh_i_flags = flags
311 self.bier_imp = bier_imp
314 class VppIpRoute(VppObject):
319 def __init__(self, test, dest_addr,
320 dest_addr_len, paths, table_id=0, is_ip6=0, is_local=0,
321 is_unreach=0, is_prohibit=0, is_drop=0):
324 self.dest_addr_len = dest_addr_len
325 self.table_id = table_id
327 self.is_local = is_local
328 self.is_unreach = is_unreach
329 self.is_prohibit = is_prohibit
330 self.is_drop = is_drop
331 self.dest_addr_p = dest_addr
333 self.dest_addr = inet_pton(AF_INET6, dest_addr)
335 self.dest_addr = inet_pton(AF_INET, dest_addr)
337 def modify(self, paths, is_local=0,
338 is_unreach=0, is_prohibit=0):
340 self.is_local = is_local
341 self.is_unreach = is_unreach
342 self.is_prohibit = is_prohibit
344 def add_vpp_config(self):
345 if self.is_local or self.is_unreach or \
346 self.is_prohibit or self.is_drop:
347 r = self._test.vapi.ip_add_del_route(
350 inet_pton(AF_INET6, "::"),
352 is_local=self.is_local,
353 is_unreach=self.is_unreach,
354 is_prohibit=self.is_prohibit,
355 is_drop=self.is_drop,
356 table_id=self.table_id,
359 for path in self.paths:
360 lstack = path.encode_labels()
362 r = self._test.vapi.ip_add_del_route(
367 table_id=self.table_id,
368 next_hop_out_label_stack=lstack,
369 next_hop_n_out_labels=len(lstack),
370 next_hop_via_label=path.nh_via_label,
371 next_hop_table_id=path.nh_table_id,
372 next_hop_id=path.next_hop_id,
375 is_resolve_host=path.is_resolve_host,
376 is_resolve_attached=path.is_resolve_attached,
377 is_source_lookup=path.is_source_lookup,
378 is_udp_encap=path.is_udp_encap,
379 is_multipath=1 if len(self.paths) > 1 else 0)
380 self.stats_index = r.stats_index
381 self._test.registry.register(self, self._test.logger)
383 def remove_vpp_config(self):
384 if self.is_local or self.is_unreach or \
385 self.is_prohibit or self.is_drop:
386 self._test.vapi.ip_add_del_route(
389 inet_pton(AF_INET6, "::"),
391 is_local=self.is_local,
392 is_unreach=self.is_unreach,
393 is_prohibit=self.is_prohibit,
395 table_id=self.table_id,
398 for path in self.paths:
399 self._test.vapi.ip_add_del_route(
404 table_id=self.table_id,
405 next_hop_table_id=path.nh_table_id,
406 next_hop_via_label=path.nh_via_label,
407 next_hop_id=path.next_hop_id,
409 is_udp_encap=path.is_udp_encap,
413 def query_vpp_config(self):
414 return find_route(self._test,
418 inet=AF_INET6 if self.is_ip6 == 1 else AF_INET)
421 return self.object_id()
429 def get_stats_to(self):
430 c = self._test.statistics.get_counter("/net/route/to")
431 return c[0][self.stats_index]
433 def get_stats_via(self):
434 c = self._test.statistics.get_counter("/net/route/via")
435 return c[0][self.stats_index]
438 class VppIpMRoute(VppObject):
443 def __init__(self, test, src_addr, grp_addr,
444 grp_addr_len, e_flags, paths, table_id=0,
448 self.grp_addr_len = grp_addr_len
449 self.table_id = table_id
450 self.e_flags = e_flags
454 self.grp_addr_p = grp_addr
455 self.src_addr_p = src_addr
457 self.grp_addr = inet_pton(AF_INET6, grp_addr)
458 self.src_addr = inet_pton(AF_INET6, src_addr)
460 self.grp_addr = inet_pton(AF_INET, grp_addr)
461 self.src_addr = inet_pton(AF_INET, src_addr)
463 def add_vpp_config(self):
464 for path in self.paths:
465 r = self._test.vapi.ip_mroute_add_del(self.src_addr,
473 bier_imp=path.bier_imp,
475 table_id=self.table_id,
477 self.stats_index = r.stats_index
478 self._test.registry.register(self, self._test.logger)
480 def remove_vpp_config(self):
481 for path in self.paths:
482 self._test.vapi.ip_mroute_add_del(self.src_addr,
490 table_id=self.table_id,
491 bier_imp=path.bier_imp,
495 def update_entry_flags(self, flags):
497 self._test.vapi.ip_mroute_add_del(self.src_addr,
505 table_id=self.table_id,
508 def update_rpf_id(self, rpf_id):
510 self._test.vapi.ip_mroute_add_del(self.src_addr,
519 table_id=self.table_id,
522 def update_path_flags(self, itf, flags):
523 for path in self.paths:
524 if path.nh_itf == itf:
525 path.nh_i_flags = flags
527 self._test.vapi.ip_mroute_add_del(self.src_addr,
535 table_id=self.table_id,
538 def query_vpp_config(self):
539 return find_mroute(self._test,
544 inet=AF_INET6 if self.is_ip6 == 1 else AF_INET)
547 return self.object_id()
551 return ("%d:(%s,%s/%d)"
553 inet_ntop(AF_INET6, self.src_addr),
554 inet_ntop(AF_INET6, self.grp_addr),
557 return ("%d:(%s,%s/%d)"
559 inet_ntop(AF_INET, self.src_addr),
560 inet_ntop(AF_INET, self.grp_addr),
564 c = self._test.statistics.get_counter("/net/mroute")
565 return c[0][self.stats_index]
568 class VppMFibSignal(object):
569 def __init__(self, test, route, interface, packet):
571 self.interface = interface
575 def compare(self, signal):
576 self.test.assertEqual(self.interface, signal.sw_if_index)
577 self.test.assertEqual(self.route.table_id, signal.table_id)
578 self.test.assertEqual(self.route.grp_addr_len,
579 signal.grp_address_len)
580 for i in range(self.route.grp_addr_len / 8):
581 self.test.assertEqual(self.route.grp_addr[i],
582 signal.grp_address[i])
583 if (self.route.grp_addr_len > 32):
585 self.test.assertEqual(self.route.src_addr[i],
586 signal.src_address[i])
589 class VppMplsIpBind(VppObject):
594 def __init__(self, test, local_label, dest_addr, dest_addr_len,
595 table_id=0, ip_table_id=0, is_ip6=0):
597 self.dest_addr_len = dest_addr_len
598 self.dest_addr = dest_addr
599 self.local_label = local_label
600 self.table_id = table_id
601 self.ip_table_id = ip_table_id
604 self.dest_addrn = inet_pton(AF_INET6, dest_addr)
606 self.dest_addrn = inet_pton(AF_INET, dest_addr)
608 def add_vpp_config(self):
609 self._test.vapi.mpls_ip_bind_unbind(self.local_label,
612 table_id=self.table_id,
613 ip_table_id=self.ip_table_id,
614 is_ip4=(self.is_ip6 == 0))
615 self._test.registry.register(self, self._test.logger)
617 def remove_vpp_config(self):
618 self._test.vapi.mpls_ip_bind_unbind(self.local_label,
621 table_id=self.table_id,
622 ip_table_id=self.ip_table_id,
624 is_ip4=(self.is_ip6 == 0))
626 def query_vpp_config(self):
627 dump = self._test.vapi.mpls_fib_dump()
629 if self.local_label == e.label \
630 and self.table_id == e.table_id:
635 return self.object_id()
638 return ("%d:%s binds %d:%s/%d"
646 class VppMplsTable(VppObject):
652 self.table_id = table_id
654 def add_vpp_config(self):
655 self._test.vapi.mpls_table_add_del(
658 self._test.registry.register(self, self._test.logger)
660 def remove_vpp_config(self):
661 self._test.vapi.mpls_table_add_del(
665 def query_vpp_config(self):
666 # find the default route
667 dump = self._test.vapi.mpls_fib_dump()
673 return self.object_id()
676 return ("table-mpls-%d" % (self.table_id))
679 class VppMplsRoute(VppObject):
684 def __init__(self, test, local_label, eos_bit, paths, table_id=0,
688 self.local_label = local_label
689 self.eos_bit = eos_bit
690 self.table_id = table_id
691 self.is_multicast = is_multicast
693 def add_vpp_config(self):
694 is_multipath = len(self.paths) > 1
695 for path in self.paths:
696 lstack = path.encode_labels()
698 r = self._test.vapi.mpls_route_add_del(
704 is_multicast=self.is_multicast,
705 is_multipath=is_multipath,
706 table_id=self.table_id,
707 is_interface_rx=path.is_interface_rx,
708 is_rpf_id=path.is_rpf_id,
709 next_hop_out_label_stack=lstack,
710 next_hop_n_out_labels=len(lstack),
711 next_hop_via_label=path.nh_via_label,
712 next_hop_table_id=path.nh_table_id)
713 self.stats_index = r.stats_index
714 self._test.registry.register(self, self._test.logger)
716 def remove_vpp_config(self):
717 for path in self.paths:
718 self._test.vapi.mpls_route_add_del(self.local_label,
723 is_rpf_id=path.is_rpf_id,
724 table_id=self.table_id,
727 def query_vpp_config(self):
728 dump = self._test.vapi.mpls_fib_dump()
730 if self.local_label == e.label \
731 and self.eos_bit == e.eos_bit \
732 and self.table_id == e.table_id:
737 return self.object_id()
745 def get_stats_to(self):
746 c = self._test.statistics.get_counter("/net/route/to")
747 return c[0][self.stats_index]
749 def get_stats_via(self):
750 c = self._test.statistics.get_counter("/net/route/via")
751 return c[0][self.stats_index]