blob: cd70b38101aaa268b7be7df6e80cefdc4a345831 [file] [log] [blame]
Neale Ranns177bbdc2016-11-15 09:46:51 +00001"""
2 IP Routes
3
4 object abstractions for representing IP routes in VPP
5"""
6
Paul Vinciguerraa279d9c2019-02-28 09:00:09 -08007from vpp_object import VppObject
Neale Rannsb3b2de72017-03-08 05:17:22 -08008from socket import inet_pton, inet_ntop, AF_INET, AF_INET6
Neale Rannsefd7bc22019-11-11 08:32:34 +00009from vpp_ip import DpoProto, INVALID_INDEX, VppIpAddressUnion, \
Neale Ranns097fa662018-05-01 05:17:55 -070010 VppIpMPrefix
Neale Ranns59f71132020-04-08 12:19:38 +000011from ipaddress import ip_network, ip_address, IPv4Network, IPv6Network
Neale Ranns177bbdc2016-11-15 09:46:51 +000012
Neale Rannsad422ed2016-11-02 14:20:04 +000013# from vnet/vnet/mpls/mpls_types.h
14MPLS_IETF_MAX_LABEL = 0xfffff
15MPLS_LABEL_INVALID = MPLS_IETF_MAX_LABEL + 1
Neale Ranns177bbdc2016-11-15 09:46:51 +000016
Neale Ranns097fa662018-05-01 05:17:55 -070017try:
18 text_type = unicode
19except NameError:
20 text_type = str
21
Neale Ranns177bbdc2016-11-15 09:46:51 +000022
Neale Ranns180279b2017-03-16 15:49:09 -040023class MRouteItfFlags:
24 MFIB_ITF_FLAG_NONE = 0
25 MFIB_ITF_FLAG_NEGATE_SIGNAL = 1
26 MFIB_ITF_FLAG_ACCEPT = 2
27 MFIB_ITF_FLAG_FORWARD = 4
28 MFIB_ITF_FLAG_SIGNAL_PRESENT = 8
29 MFIB_ITF_FLAG_INTERNAL_COPY = 16
30
31
32class MRouteEntryFlags:
33 MFIB_ENTRY_FLAG_NONE = 0
34 MFIB_ENTRY_FLAG_SIGNAL = 1
35 MFIB_ENTRY_FLAG_DROP = 2
36 MFIB_ENTRY_FLAG_CONNECTED = 4
37 MFIB_ENTRY_FLAG_INHERIT_ACCEPT = 8
38
39
Neale Ranns097fa662018-05-01 05:17:55 -070040class FibPathProto:
41 FIB_PATH_NH_PROTO_IP4 = 0
42 FIB_PATH_NH_PROTO_IP6 = 1
43 FIB_PATH_NH_PROTO_MPLS = 2
44 FIB_PATH_NH_PROTO_ETHERNET = 3
45 FIB_PATH_NH_PROTO_BIER = 4
46 FIB_PATH_NH_PROTO_NSH = 5
47
48
49class FibPathType:
50 FIB_PATH_TYPE_NORMAL = 0
51 FIB_PATH_TYPE_LOCAL = 1
52 FIB_PATH_TYPE_DROP = 2
53 FIB_PATH_TYPE_UDP_ENCAP = 3
54 FIB_PATH_TYPE_BIER_IMP = 4
55 FIB_PATH_TYPE_ICMP_UNREACH = 5
56 FIB_PATH_TYPE_ICMP_PROHIBIT = 6
57 FIB_PATH_TYPE_SOURCE_LOOKUP = 7
58 FIB_PATH_TYPE_DVR = 8
59 FIB_PATH_TYPE_INTERFACE_RX = 9
60 FIB_PATH_TYPE_CLASSIFY = 10
61
62
63class FibPathFlags:
64 FIB_PATH_FLAG_NONE = 0
65 FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED = 1
66 FIB_PATH_FLAG_RESOLVE_VIA_HOST = 2
Neale Ranns1dbcf302019-07-19 11:44:53 +000067 FIB_PATH_FLAG_POP_PW_CW = 4
Neale Ranns097fa662018-05-01 05:17:55 -070068
69
Neale Ranns31ed7442018-02-23 05:29:09 -080070class MplsLspMode:
71 PIPE = 0
72 UNIFORM = 1
73
74
Neale Rannsefd7bc22019-11-11 08:32:34 +000075def mk_network(addr, len):
76 if ip_address(text_type(addr)).version == 4:
77 return IPv4Network("%s/%d" % (addr, len), strict=False)
78 else:
79 return IPv6Network("%s/%d" % (addr, len), strict=False)
80
81
Neale Ranns93cc3ee2018-10-10 07:22:51 -070082def ip_to_dpo_proto(addr):
Paul Vinciguerrabeded852019-03-01 10:35:55 -080083 if addr.version == 6:
Neale Ranns93cc3ee2018-10-10 07:22:51 -070084 return DpoProto.DPO_PROTO_IP6
85 else:
86 return DpoProto.DPO_PROTO_IP4
87
88
Neale Ranns097fa662018-05-01 05:17:55 -070089def address_proto(ip_addr):
Ole Troan6e6ad642020-02-04 13:28:13 +010090 if ip_addr.ip_addr.version == 4:
Neale Ranns097fa662018-05-01 05:17:55 -070091 return FibPathProto.FIB_PATH_NH_PROTO_IP4
Neale Rannsb3b2de72017-03-08 05:17:22 -080092 else:
Neale Ranns097fa662018-05-01 05:17:55 -070093 return FibPathProto.FIB_PATH_NH_PROTO_IP6
Neale Rannsb3b2de72017-03-08 05:17:22 -080094
Neale Ranns097fa662018-05-01 05:17:55 -070095
Neale Ranns59f71132020-04-08 12:19:38 +000096def find_route(test, addr, len, table_id=0, sw_if_index=None):
Neale Rannsefd7bc22019-11-11 08:32:34 +000097 prefix = mk_network(addr, len)
Neale Ranns097fa662018-05-01 05:17:55 -070098
Ole Troan6e6ad642020-02-04 13:28:13 +010099 if 4 == prefix.version:
Neale Ranns097fa662018-05-01 05:17:55 -0700100 routes = test.vapi.ip_route_dump(table_id, False)
Neale Ranns097fa662018-05-01 05:17:55 -0700101 else:
102 routes = test.vapi.ip_route_dump(table_id, True)
Neale Ranns097fa662018-05-01 05:17:55 -0700103
Neale Rannsb3b2de72017-03-08 05:17:22 -0800104 for e in routes:
Neale Ranns097fa662018-05-01 05:17:55 -0700105 if table_id == e.route.table_id \
Neale Rannsefd7bc22019-11-11 08:32:34 +0000106 and str(e.route.prefix) == str(prefix):
Neale Ranns59f71132020-04-08 12:19:38 +0000107 if not sw_if_index:
108 return True
109 else:
110 # should be only one path if the user is looking
111 # for the interface the route is reachable through
112 if e.route.n_paths != 1:
113 return False
114 else:
115 return (e.route.paths[0].sw_if_index == sw_if_index)
116
Neale Rannsb3b2de72017-03-08 05:17:22 -0800117 return False
118
119
Neale Ranns9db6ada2019-11-08 12:42:31 +0000120def find_route_in_dump(dump, route, table):
121 for r in dump:
122 if table.table_id == r.route.table_id \
123 and route.prefix == r.route.prefix:
124 if len(route.paths) == r.route.n_paths:
125 return True
126 return False
127
128
129def find_mroute_in_dump(dump, route, table):
130 for r in dump:
131 if table.table_id == r.route.table_id \
132 and route.prefix == r.route.prefix:
133 return True
134 return False
135
136
Neale Ranns947ea622018-06-07 23:48:20 -0700137def find_mroute(test, grp_addr, src_addr, grp_addr_len,
Neale Ranns097fa662018-05-01 05:17:55 -0700138 table_id=0):
139 ip_mprefix = VppIpMPrefix(text_type(src_addr),
140 text_type(grp_addr),
141 grp_addr_len)
142
Ole Troan6e6ad642020-02-04 13:28:13 +0100143 if 4 == ip_mprefix.version:
Neale Ranns097fa662018-05-01 05:17:55 -0700144 routes = test.vapi.ip_mroute_dump(table_id, False)
Neale Ranns947ea622018-06-07 23:48:20 -0700145 else:
Neale Ranns097fa662018-05-01 05:17:55 -0700146 routes = test.vapi.ip_mroute_dump(table_id, True)
147
Neale Ranns947ea622018-06-07 23:48:20 -0700148 for e in routes:
Neale Ranns097fa662018-05-01 05:17:55 -0700149 if table_id == e.route.table_id and ip_mprefix == e.route.prefix:
Neale Ranns947ea622018-06-07 23:48:20 -0700150 return True
151 return False
152
153
Neale Ranns775f73c2018-12-20 03:01:49 -0800154def find_mpls_route(test, table_id, label, eos_bit, paths=None):
Neale Ranns097fa662018-05-01 05:17:55 -0700155 dump = test.vapi.mpls_route_dump(table_id)
Neale Ranns775f73c2018-12-20 03:01:49 -0800156 for e in dump:
Neale Ranns097fa662018-05-01 05:17:55 -0700157 if label == e.mr_route.mr_label \
158 and eos_bit == e.mr_route.mr_eos \
159 and table_id == e.mr_route.mr_table_id:
Neale Ranns775f73c2018-12-20 03:01:49 -0800160 if not paths:
161 return True
162 else:
Neale Ranns097fa662018-05-01 05:17:55 -0700163 if (len(paths) != len(e.mr_route.mr_paths)):
Neale Ranns775f73c2018-12-20 03:01:49 -0800164 return False
165 for i in range(len(paths)):
Neale Ranns097fa662018-05-01 05:17:55 -0700166 if (paths[i] != e.mr_route.mr_paths[i]):
Neale Ranns775f73c2018-12-20 03:01:49 -0800167 return False
168 return True
169 return False
170
171
Neale Rannsefd7bc22019-11-11 08:32:34 +0000172def fib_interface_ip_prefix(test, addr, len, sw_if_index):
173 # can't use python net here since we need the host bits in the prefix
174 prefix = "%s/%d" % (addr, len)
175 addrs = test.vapi.ip_address_dump(
176 sw_if_index,
177 is_ipv6=(6 == ip_address(addr).version))
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700178
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700179 for a in addrs:
Neale Ranns097fa662018-05-01 05:17:55 -0700180 if a.sw_if_index == sw_if_index and \
Neale Rannsefd7bc22019-11-11 08:32:34 +0000181 str(a.prefix) == prefix:
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700182 return True
183 return False
184
185
Neale Ranns15002542017-09-10 04:39:11 -0700186class VppIpTable(VppObject):
187
188 def __init__(self,
189 test,
190 table_id,
191 is_ip6=0):
192 self._test = test
193 self.table_id = table_id
194 self.is_ip6 = is_ip6
195
196 def add_vpp_config(self):
Neale Ranns9db6ada2019-11-08 12:42:31 +0000197 self._test.vapi.ip_table_add_del(is_add=1,
198 table={'is_ip6': self.is_ip6,
199 'table_id': self.table_id})
Neale Ranns15002542017-09-10 04:39:11 -0700200 self._test.registry.register(self, self._test.logger)
Neale Ranns9db6ada2019-11-08 12:42:31 +0000201 return self
Neale Ranns15002542017-09-10 04:39:11 -0700202
203 def remove_vpp_config(self):
Neale Ranns9db6ada2019-11-08 12:42:31 +0000204 self._test.vapi.ip_table_add_del(is_add=0,
205 table={'is_ip6': self.is_ip6,
206 'table_id': self.table_id})
207
208 def replace_begin(self):
209 self._test.vapi.ip_table_replace_begin(
210 table={'is_ip6': self.is_ip6,
211 'table_id': self.table_id})
212
213 def replace_end(self):
214 self._test.vapi.ip_table_replace_end(
215 table={'is_ip6': self.is_ip6,
216 'table_id': self.table_id})
217
218 def flush(self):
219 self._test.vapi.ip_table_flush(table={'is_ip6': self.is_ip6,
220 'table_id': self.table_id})
221
222 def dump(self):
223 return self._test.vapi.ip_route_dump(self.table_id, self.is_ip6)
224
225 def mdump(self):
226 return self._test.vapi.ip_mroute_dump(self.table_id, self.is_ip6)
Neale Ranns15002542017-09-10 04:39:11 -0700227
228 def query_vpp_config(self):
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700229 if self.table_id == 0:
230 # the default table always exists
231 return False
Neale Ranns15002542017-09-10 04:39:11 -0700232 # find the default route
233 return find_route(self._test,
234 "::" if self.is_ip6 else "0.0.0.0",
235 0,
Neale Ranns097fa662018-05-01 05:17:55 -0700236 self.table_id)
Neale Ranns15002542017-09-10 04:39:11 -0700237
Neale Ranns15002542017-09-10 04:39:11 -0700238 def object_id(self):
239 return ("table-%s-%d" %
240 ("v6" if self.is_ip6 == 1 else "v4",
241 self.table_id))
242
243
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700244class VppIpInterfaceAddress(VppObject):
245
Neale Ranns59f71132020-04-08 12:19:38 +0000246 def __init__(self, test, intf, addr, len, bind=None):
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700247 self._test = test
248 self.intf = intf
Neale Rannsefd7bc22019-11-11 08:32:34 +0000249 self.addr = addr
250 self.len = len
251 self.prefix = "%s/%d" % (addr, len)
Neale Ranns59f71132020-04-08 12:19:38 +0000252 self.host_len = ip_network(self.prefix, strict=False).max_prefixlen
253 self.table_id = 0
254 if bind:
255 self.table_id = bind.table.table_id
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700256
257 def add_vpp_config(self):
258 self._test.vapi.sw_interface_add_del_address(
Neale Rannsefd7bc22019-11-11 08:32:34 +0000259 sw_if_index=self.intf.sw_if_index, prefix=self.prefix,
Ole Troan9a475372019-03-05 16:58:24 +0100260 is_add=1)
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700261 self._test.registry.register(self, self._test.logger)
Neale Ranns9efcee62019-11-26 19:30:08 +0000262 return self
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700263
264 def remove_vpp_config(self):
265 self._test.vapi.sw_interface_add_del_address(
Neale Rannsefd7bc22019-11-11 08:32:34 +0000266 sw_if_index=self.intf.sw_if_index, prefix=self.prefix,
Ole Troan9a475372019-03-05 16:58:24 +0100267 is_add=0)
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700268
269 def query_vpp_config(self):
Neale Ranns59f71132020-04-08 12:19:38 +0000270 # search for the IP address mapping and the two expected
271 # FIB entries
272 v = ip_address(self.addr).version
273
274 if ((v == 4 and self.len < 31) or (v == 6 and self.len < 127)):
275 return (fib_interface_ip_prefix(self._test,
276 self.addr,
277 self.len,
278 self.intf.sw_if_index) &
279 find_route(self._test,
280 self.addr,
281 self.len,
282 table_id=self.table_id,
283 sw_if_index=self.intf.sw_if_index) &
284 find_route(self._test,
285 self.addr,
286 self.host_len,
287 table_id=self.table_id,
288 sw_if_index=self.intf.sw_if_index))
289 else:
290 return (fib_interface_ip_prefix(self._test,
291 self.addr,
292 self.len,
293 self.intf.sw_if_index) &
294 find_route(self._test,
295 self.addr,
296 self.host_len,
297 table_id=self.table_id,
298 sw_if_index=self.intf.sw_if_index))
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700299
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700300 def object_id(self):
Neale Ranns59f71132020-04-08 12:19:38 +0000301 return "interface-ip-%s-%d-%s" % (self.intf,
302 self.table_id,
303 self.prefix)
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700304
305
Neale Rannsec40a7d2020-04-23 07:36:12 +0000306class VppIp6LinkLocalAddress(VppObject):
307
308 def __init__(self, test, intf, addr):
309 self._test = test
310 self.intf = intf
311 self.addr = addr
312
313 def add_vpp_config(self):
314 self._test.vapi.sw_interface_ip6_set_link_local_address(
315 sw_if_index=self.intf.sw_if_index, ip=self.addr)
316 self._test.registry.register(self, self._test.logger)
317 return self
318
319 def remove_vpp_config(self):
320 # link locals can't be removed, only changed
321 pass
322
323 def query_vpp_config(self):
324 # no API to query
325 return False
326
327 def object_id(self):
328 return "ip6-link-local-%s-%s" % (self.intf, self.addr)
329
330
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700331class VppIpInterfaceBind(VppObject):
332
333 def __init__(self, test, intf, table):
334 self._test = test
335 self.intf = intf
336 self.table = table
337
338 def add_vpp_config(self):
339 if self.table.is_ip6:
340 self.intf.set_table_ip6(self.table.table_id)
341 else:
342 self.intf.set_table_ip4(self.table.table_id)
343 self._test.registry.register(self, self._test.logger)
Neale Ranns59f71132020-04-08 12:19:38 +0000344 return self
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700345
346 def remove_vpp_config(self):
347 if 0 == self.table.table_id:
348 return
349 if self.table.is_ip6:
350 self.intf.set_table_ip6(0)
351 else:
352 self.intf.set_table_ip4(0)
353
354 def query_vpp_config(self):
355 if 0 == self.table.table_id:
356 return False
357 return self._test.vapi.sw_interface_get_table(
358 self.intf.sw_if_index,
359 self.table.is_ip6).vrf_id == self.table.table_id
360
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700361 def object_id(self):
362 return "interface-bind-%s-%s" % (self.intf, self.table)
363
364
Neale Ranns31ed7442018-02-23 05:29:09 -0800365class VppMplsLabel(object):
366 def __init__(self, value, mode=MplsLspMode.PIPE, ttl=64, exp=0):
367 self.value = value
368 self.mode = mode
369 self.ttl = ttl
370 self.exp = exp
371
372 def encode(self):
373 is_uniform = 0 if self.mode is MplsLspMode.PIPE else 1
374 return {'label': self.value,
375 'ttl': self.ttl,
376 'exp': self.exp,
377 'is_uniform': is_uniform}
378
Neale Ranns775f73c2018-12-20 03:01:49 -0800379 def __eq__(self, other):
380 if isinstance(other, self.__class__):
381 return (self.value == other.value and
382 self.ttl == other.ttl and
383 self.exp == other.exp and
384 self.mode == other.mode)
385 elif hasattr(other, 'label'):
386 return (self.value == other.label and
387 self.ttl == other.ttl and
388 self.exp == other.exp and
389 (self.mode == MplsLspMode.UNIFORM) == other.is_uniform)
390 else:
391 return False
392
393 def __ne__(self, other):
394 return not (self == other)
395
Neale Ranns31ed7442018-02-23 05:29:09 -0800396
Neale Ranns097fa662018-05-01 05:17:55 -0700397class VppFibPathNextHop(object):
398 def __init__(self, addr,
399 via_label=MPLS_LABEL_INVALID,
400 next_hop_id=INVALID_INDEX):
401 self.addr = VppIpAddressUnion(addr)
402 self.via_label = via_label
403 self.obj_id = next_hop_id
404
405 def encode(self):
406 if self.via_label is not MPLS_LABEL_INVALID:
407 return {'via_label': self.via_label}
408 if self.obj_id is not INVALID_INDEX:
409 return {'obj_id': self.obj_id}
410 else:
411 return {'address': self.addr.encode()}
412
413 def proto(self):
414 if self.via_label is MPLS_LABEL_INVALID:
415 return address_proto(self.addr)
416 else:
417 return FibPathProto.FIB_PATH_NH_PROTO_MPLS
418
419 def __eq__(self, other):
420 if not isinstance(other, self.__class__):
421 # try the other instance's __eq__.
422 return NotImplemented
423 return (self.addr == other.addr and
424 self.via_label == other.via_label and
425 self.obj_id == other.obj_id)
426
427
Neale Ranns5a8123b2017-01-26 01:18:23 -0800428class VppRoutePath(object):
Neale Rannsad422ed2016-11-02 14:20:04 +0000429
Klement Sekerada505f62017-01-04 12:58:53 +0100430 def __init__(
431 self,
432 nh_addr,
433 nh_sw_if_index,
434 nh_table_id=0,
435 labels=[],
Neale Rannsfca0c242017-01-13 07:57:46 -0800436 nh_via_label=MPLS_LABEL_INVALID,
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800437 rpf_id=0,
Neale Ranns097fa662018-05-01 05:17:55 -0700438 next_hop_id=INVALID_INDEX,
439 proto=None,
440 flags=FibPathFlags.FIB_PATH_FLAG_NONE,
441 type=FibPathType.FIB_PATH_TYPE_NORMAL):
Neale Ranns177bbdc2016-11-15 09:46:51 +0000442 self.nh_itf = nh_sw_if_index
443 self.nh_table_id = nh_table_id
Neale Rannsad422ed2016-11-02 14:20:04 +0000444 self.nh_labels = labels
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800445 self.weight = 1
446 self.rpf_id = rpf_id
Neale Ranns097fa662018-05-01 05:17:55 -0700447 self.proto = proto
448 self.flags = flags
449 self.type = type
450 self.nh = VppFibPathNextHop(nh_addr, nh_via_label, next_hop_id)
451 if proto is None:
452 self.proto = self.nh.proto()
Neale Ranns31426c62017-05-24 10:32:58 -0700453 else:
Neale Ranns097fa662018-05-01 05:17:55 -0700454 self.proto = proto
Neale Ranns810086d2017-11-05 16:26:46 -0800455 self.next_hop_id = next_hop_id
Neale Ranns177bbdc2016-11-15 09:46:51 +0000456
Neale Ranns097fa662018-05-01 05:17:55 -0700457 def encode_labels(self):
Neale Ranns31ed7442018-02-23 05:29:09 -0800458 lstack = []
459 for l in self.nh_labels:
460 if type(l) == VppMplsLabel:
461 lstack.append(l.encode())
462 else:
463 lstack.append({'label': l,
464 'ttl': 255})
Neale Ranns097fa662018-05-01 05:17:55 -0700465 while (len(lstack) < 16):
466 lstack.append({})
467
Neale Ranns31ed7442018-02-23 05:29:09 -0800468 return lstack
469
Neale Ranns097fa662018-05-01 05:17:55 -0700470 def encode(self):
471 return {'weight': 1,
Neale Ranns2303cb12018-02-21 04:57:17 -0800472 'preference': 0,
473 'table_id': self.nh_table_id,
Neale Ranns097fa662018-05-01 05:17:55 -0700474 'nh': self.nh.encode(),
Neale Ranns2303cb12018-02-21 04:57:17 -0800475 'next_hop_id': self.next_hop_id,
476 'sw_if_index': self.nh_itf,
Neale Ranns097fa662018-05-01 05:17:55 -0700477 'rpf_id': self.rpf_id,
478 'proto': self.proto,
479 'type': self.type,
480 'flags': self.flags,
Neale Ranns2303cb12018-02-21 04:57:17 -0800481 'n_labels': len(self.nh_labels),
Neale Ranns097fa662018-05-01 05:17:55 -0700482 'label_stack': self.encode_labels()}
Neale Ranns2303cb12018-02-21 04:57:17 -0800483
Neale Rannsef90ed02018-09-13 08:45:12 -0700484 def __eq__(self, other):
Neale Ranns775f73c2018-12-20 03:01:49 -0800485 if isinstance(other, self.__class__):
Neale Ranns097fa662018-05-01 05:17:55 -0700486 return self.nh == other.nh
Neale Ranns775f73c2018-12-20 03:01:49 -0800487 elif hasattr(other, 'sw_if_index'):
488 # vl_api_fib_path_t
489 if (len(self.nh_labels) != other.n_labels):
490 return False
491 for i in range(len(self.nh_labels)):
492 if (self.nh_labels[i] != other.label_stack[i]):
493 return False
494 return self.nh_itf == other.sw_if_index
495 else:
496 return False
497
498 def __ne__(self, other):
499 return not (self == other)
Neale Rannsef90ed02018-09-13 08:45:12 -0700500
Neale Ranns177bbdc2016-11-15 09:46:51 +0000501
Neale Ranns5a8123b2017-01-26 01:18:23 -0800502class VppMRoutePath(VppRoutePath):
Neale Ranns32e1c012016-11-22 17:07:28 +0000503
Neale Rannsd792d9c2017-10-21 10:53:20 -0700504 def __init__(self, nh_sw_if_index, flags,
Neale Rannse821ab12017-06-01 07:45:05 -0700505 nh=None,
Neale Ranns097fa662018-05-01 05:17:55 -0700506 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
507 type=FibPathType.FIB_PATH_TYPE_NORMAL,
508 bier_imp=INVALID_INDEX):
Neale Rannse821ab12017-06-01 07:45:05 -0700509 if not nh:
Neale Ranns097fa662018-05-01 05:17:55 -0700510 nh = "::" if proto is FibPathProto.FIB_PATH_NH_PROTO_IP6 \
511 else "0.0.0.0"
Neale Rannse821ab12017-06-01 07:45:05 -0700512 super(VppMRoutePath, self).__init__(nh,
513 nh_sw_if_index,
Neale Ranns097fa662018-05-01 05:17:55 -0700514 proto=proto,
515 type=type,
516 next_hop_id=bier_imp)
Neale Ranns32e1c012016-11-22 17:07:28 +0000517 self.nh_i_flags = flags
Neale Rannsd792d9c2017-10-21 10:53:20 -0700518 self.bier_imp = bier_imp
Neale Ranns32e1c012016-11-22 17:07:28 +0000519
Neale Ranns097fa662018-05-01 05:17:55 -0700520 def encode(self):
521 return {'path': super(VppMRoutePath, self).encode(),
522 'itf_flags': self.nh_i_flags}
523
Neale Ranns32e1c012016-11-22 17:07:28 +0000524
Neale Ranns5a8123b2017-01-26 01:18:23 -0800525class VppIpRoute(VppObject):
Neale Ranns177bbdc2016-11-15 09:46:51 +0000526 """
527 IP Route
528 """
529
530 def __init__(self, test, dest_addr,
Neale Ranns097fa662018-05-01 05:17:55 -0700531 dest_addr_len, paths, table_id=0, register=True):
Neale Ranns177bbdc2016-11-15 09:46:51 +0000532 self._test = test
533 self.paths = paths
Neale Ranns177bbdc2016-11-15 09:46:51 +0000534 self.table_id = table_id
Neale Rannsefd7bc22019-11-11 08:32:34 +0000535 self.prefix = mk_network(dest_addr, dest_addr_len)
Neale Ranns097fa662018-05-01 05:17:55 -0700536 self.register = register
Paul Vinciguerra941da4a2019-06-18 07:57:53 -0400537 self.stats_index = None
Neale Rannsc2ac2352019-07-02 14:33:29 +0000538 self.modified = False
Neale Ranns177bbdc2016-11-15 09:46:51 +0000539
Neale Ranns097fa662018-05-01 05:17:55 -0700540 self.encoded_paths = []
541 for path in self.paths:
542 self.encoded_paths.append(path.encode())
543
544 def __eq__(self, other):
545 if self.table_id == other.table_id and \
546 self.prefix == other.prefix:
547 return True
548 return False
549
550 def modify(self, paths):
Neale Ranns69b7aa42017-03-10 03:04:12 -0800551 self.paths = paths
Neale Ranns097fa662018-05-01 05:17:55 -0700552 self.encoded_paths = []
553 for path in self.paths:
554 self.encoded_paths.append(path.encode())
Neale Rannsc2ac2352019-07-02 14:33:29 +0000555 self.modified = True
Neale Ranns097fa662018-05-01 05:17:55 -0700556
557 self._test.vapi.ip_route_add_del(route={'table_id': self.table_id,
Neale Rannsefd7bc22019-11-11 08:32:34 +0000558 'prefix': self.prefix,
Neale Ranns097fa662018-05-01 05:17:55 -0700559 'n_paths': len(
560 self.encoded_paths),
561 'paths': self.encoded_paths,
562 },
563 is_add=1,
564 is_multipath=0)
Neale Ranns69b7aa42017-03-10 03:04:12 -0800565
Neale Ranns177bbdc2016-11-15 09:46:51 +0000566 def add_vpp_config(self):
Neale Ranns097fa662018-05-01 05:17:55 -0700567 r = self._test.vapi.ip_route_add_del(
568 route={'table_id': self.table_id,
Neale Rannsefd7bc22019-11-11 08:32:34 +0000569 'prefix': self.prefix,
Neale Ranns097fa662018-05-01 05:17:55 -0700570 'n_paths': len(self.encoded_paths),
571 'paths': self.encoded_paths,
572 },
573 is_add=1,
574 is_multipath=0)
Neale Ranns008dbe12018-09-07 09:32:36 -0700575 self.stats_index = r.stats_index
Neale Ranns097fa662018-05-01 05:17:55 -0700576 if self.register:
577 self._test.registry.register(self, self._test.logger)
Neale Ranns9db6ada2019-11-08 12:42:31 +0000578 return self
Neale Ranns177bbdc2016-11-15 09:46:51 +0000579
580 def remove_vpp_config(self):
Neale Rannsc2ac2352019-07-02 14:33:29 +0000581 # there's no need to issue different deletes for modified routes
582 # we do this only to test the two different ways to delete routes
583 # eiter by passing all the paths to remove and mutlipath=1 or
584 # passing no paths and multipath=0
585 if self.modified:
586 self._test.vapi.ip_route_add_del(
587 route={'table_id': self.table_id,
Neale Rannsefd7bc22019-11-11 08:32:34 +0000588 'prefix': self.prefix,
Neale Rannsc2ac2352019-07-02 14:33:29 +0000589 'n_paths': len(
590 self.encoded_paths),
591 'paths': self.encoded_paths},
592 is_add=0,
593 is_multipath=1)
594 else:
595 self._test.vapi.ip_route_add_del(
596 route={'table_id': self.table_id,
Neale Rannsefd7bc22019-11-11 08:32:34 +0000597 'prefix': self.prefix,
Neale Rannsc2ac2352019-07-02 14:33:29 +0000598 'n_paths': 0},
599 is_add=0,
600 is_multipath=0)
Neale Rannsad422ed2016-11-02 14:20:04 +0000601
Neale Ranns5a8123b2017-01-26 01:18:23 -0800602 def query_vpp_config(self):
Neale Rannsb3b2de72017-03-08 05:17:22 -0800603 return find_route(self._test,
Neale Rannsefd7bc22019-11-11 08:32:34 +0000604 self.prefix.network_address,
605 self.prefix.prefixlen,
Neale Ranns097fa662018-05-01 05:17:55 -0700606 self.table_id)
Neale Rannsad422ed2016-11-02 14:20:04 +0000607
Neale Ranns5a8123b2017-01-26 01:18:23 -0800608 def object_id(self):
Neale Rannsefd7bc22019-11-11 08:32:34 +0000609 return ("%s:table-%d-%s" % (
610 'ip6-route' if self.prefix.version == 6 else 'ip-route',
Paul Vinciguerra941da4a2019-06-18 07:57:53 -0400611 self.table_id,
Neale Rannsefd7bc22019-11-11 08:32:34 +0000612 self.prefix))
Neale Ranns5a8123b2017-01-26 01:18:23 -0800613
Neale Ranns008dbe12018-09-07 09:32:36 -0700614 def get_stats_to(self):
615 c = self._test.statistics.get_counter("/net/route/to")
616 return c[0][self.stats_index]
617
618 def get_stats_via(self):
619 c = self._test.statistics.get_counter("/net/route/via")
620 return c[0][self.stats_index]
621
Neale Ranns5a8123b2017-01-26 01:18:23 -0800622
623class VppIpMRoute(VppObject):
Neale Ranns32e1c012016-11-22 17:07:28 +0000624 """
625 IP Multicast Route
626 """
627
628 def __init__(self, test, src_addr, grp_addr,
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800629 grp_addr_len, e_flags, paths, table_id=0,
Neale Ranns097fa662018-05-01 05:17:55 -0700630 rpf_id=0):
Neale Ranns32e1c012016-11-22 17:07:28 +0000631 self._test = test
632 self.paths = paths
Neale Ranns32e1c012016-11-22 17:07:28 +0000633 self.table_id = table_id
634 self.e_flags = e_flags
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800635 self.rpf_id = rpf_id
Neale Ranns32e1c012016-11-22 17:07:28 +0000636
Neale Ranns097fa662018-05-01 05:17:55 -0700637 self.prefix = VppIpMPrefix(src_addr, grp_addr, grp_addr_len)
638 self.encoded_paths = []
639 for path in self.paths:
640 self.encoded_paths.append(path.encode())
Neale Ranns32e1c012016-11-22 17:07:28 +0000641
Paul Vinciguerrae64e5ff2020-04-28 00:27:38 -0400642 def encode(self, paths=None):
643 _paths = self.encoded_paths if paths is None else paths
644 return {'table_id': self.table_id,
645 'entry_flags': self.e_flags,
646 'rpf_id': self.rpf_id,
647 'prefix': self.prefix.encode(),
648 'n_paths': len(_paths),
649 'paths': _paths,
650 }
651
Neale Ranns32e1c012016-11-22 17:07:28 +0000652 def add_vpp_config(self):
Paul Vinciguerrae64e5ff2020-04-28 00:27:38 -0400653 r = self._test.vapi.ip_mroute_add_del(route=self.encode(),
654 is_multipath=1,
Neale Ranns097fa662018-05-01 05:17:55 -0700655 is_add=1)
656 self.stats_index = r.stats_index
Neale Ranns5a8123b2017-01-26 01:18:23 -0800657 self._test.registry.register(self, self._test.logger)
Neale Ranns9db6ada2019-11-08 12:42:31 +0000658 return self
Neale Ranns32e1c012016-11-22 17:07:28 +0000659
660 def remove_vpp_config(self):
Paul Vinciguerrae64e5ff2020-04-28 00:27:38 -0400661 self._test.vapi.ip_mroute_add_del(route=self.encode(),
662 is_multipath=1,
Neale Ranns097fa662018-05-01 05:17:55 -0700663 is_add=0)
Neale Ranns32e1c012016-11-22 17:07:28 +0000664
665 def update_entry_flags(self, flags):
666 self.e_flags = flags
Paul Vinciguerrae64e5ff2020-04-28 00:27:38 -0400667 self._test.vapi.ip_mroute_add_del(route=self.encode(paths=[]),
668 is_multipath=1,
Neale Ranns097fa662018-05-01 05:17:55 -0700669 is_add=1)
Neale Ranns32e1c012016-11-22 17:07:28 +0000670
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800671 def update_rpf_id(self, rpf_id):
672 self.rpf_id = rpf_id
Paul Vinciguerrae64e5ff2020-04-28 00:27:38 -0400673 self._test.vapi.ip_mroute_add_del(route=self.encode(paths=[]),
674 is_multipath=1,
Neale Ranns097fa662018-05-01 05:17:55 -0700675 is_add=1)
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800676
Neale Ranns32e1c012016-11-22 17:07:28 +0000677 def update_path_flags(self, itf, flags):
Neale Ranns097fa662018-05-01 05:17:55 -0700678 for p in range(len(self.paths)):
679 if self.paths[p].nh_itf == itf:
680 self.paths[p].nh_i_flags = flags
Paul Vinciguerra6230b9d2020-04-28 11:23:31 -0400681 self.encoded_paths[p] = self.paths[p].encode()
682 break
Neale Ranns097fa662018-05-01 05:17:55 -0700683
Paul Vinciguerrae64e5ff2020-04-28 00:27:38 -0400684 self._test.vapi.ip_mroute_add_del(
685 route=self.encode(
686 paths=[self.encoded_paths[p]]),
687 is_add=1,
688 is_multipath=0)
Neale Ranns32e1c012016-11-22 17:07:28 +0000689
Neale Ranns5a8123b2017-01-26 01:18:23 -0800690 def query_vpp_config(self):
Neale Ranns947ea622018-06-07 23:48:20 -0700691 return find_mroute(self._test,
Neale Ranns097fa662018-05-01 05:17:55 -0700692 self.prefix.gaddr,
693 self.prefix.saddr,
694 self.prefix.length,
695 self.table_id)
Neale Ranns32e1c012016-11-22 17:07:28 +0000696
Neale Ranns5a8123b2017-01-26 01:18:23 -0800697 def object_id(self):
Neale Ranns097fa662018-05-01 05:17:55 -0700698 return ("%d:(%s,%s/%d)" % (self.table_id,
699 self.prefix.saddr,
700 self.prefix.gaddr,
701 self.prefix.length))
Neale Ranns5a8123b2017-01-26 01:18:23 -0800702
Neale Ranns28c142e2018-09-07 09:37:07 -0700703 def get_stats(self):
704 c = self._test.statistics.get_counter("/net/mroute")
705 return c[0][self.stats_index]
706
Neale Ranns5a8123b2017-01-26 01:18:23 -0800707
708class VppMFibSignal(object):
Neale Ranns32e1c012016-11-22 17:07:28 +0000709 def __init__(self, test, route, interface, packet):
710 self.route = route
711 self.interface = interface
712 self.packet = packet
713 self.test = test
714
715 def compare(self, signal):
716 self.test.assertEqual(self.interface, signal.sw_if_index)
717 self.test.assertEqual(self.route.table_id, signal.table_id)
Neale Ranns097fa662018-05-01 05:17:55 -0700718 self.test.assertEqual(self.route.prefix, signal.prefix)
Neale Ranns32e1c012016-11-22 17:07:28 +0000719
720
Neale Ranns5a8123b2017-01-26 01:18:23 -0800721class VppMplsIpBind(VppObject):
Neale Rannsad422ed2016-11-02 14:20:04 +0000722 """
723 MPLS to IP Binding
724 """
725
Neale Ranns5a8123b2017-01-26 01:18:23 -0800726 def __init__(self, test, local_label, dest_addr, dest_addr_len,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700727 table_id=0, ip_table_id=0, is_ip6=0):
Neale Rannsad422ed2016-11-02 14:20:04 +0000728 self._test = test
Neale Rannsad422ed2016-11-02 14:20:04 +0000729 self.dest_addr_len = dest_addr_len
Neale Rannsf12a83f2017-04-18 09:09:40 -0700730 self.dest_addr = dest_addr
Neale Ranns097fa662018-05-01 05:17:55 -0700731 self.ip_addr = ip_address(text_type(dest_addr))
Neale Rannsad422ed2016-11-02 14:20:04 +0000732 self.local_label = local_label
Neale Ranns5a8123b2017-01-26 01:18:23 -0800733 self.table_id = table_id
734 self.ip_table_id = ip_table_id
Neale Rannsefd7bc22019-11-11 08:32:34 +0000735 self.prefix = mk_network(dest_addr, dest_addr_len)
Neale Rannsad422ed2016-11-02 14:20:04 +0000736
737 def add_vpp_config(self):
738 self._test.vapi.mpls_ip_bind_unbind(self.local_label,
Neale Rannsefd7bc22019-11-11 08:32:34 +0000739 self.prefix,
Neale Ranns5a8123b2017-01-26 01:18:23 -0800740 table_id=self.table_id,
Neale Ranns097fa662018-05-01 05:17:55 -0700741 ip_table_id=self.ip_table_id)
Neale Ranns5a8123b2017-01-26 01:18:23 -0800742 self._test.registry.register(self, self._test.logger)
Neale Rannsad422ed2016-11-02 14:20:04 +0000743
744 def remove_vpp_config(self):
745 self._test.vapi.mpls_ip_bind_unbind(self.local_label,
Neale Rannsefd7bc22019-11-11 08:32:34 +0000746 self.prefix,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700747 table_id=self.table_id,
748 ip_table_id=self.ip_table_id,
Neale Ranns097fa662018-05-01 05:17:55 -0700749 is_bind=0)
Neale Rannsad422ed2016-11-02 14:20:04 +0000750
Neale Ranns5a8123b2017-01-26 01:18:23 -0800751 def query_vpp_config(self):
Neale Ranns097fa662018-05-01 05:17:55 -0700752 dump = self._test.vapi.mpls_route_dump(self.table_id)
Neale Ranns5a8123b2017-01-26 01:18:23 -0800753 for e in dump:
Neale Ranns097fa662018-05-01 05:17:55 -0700754 if self.local_label == e.mr_route.mr_label \
755 and self.table_id == e.mr_route.mr_table_id:
Neale Ranns5a8123b2017-01-26 01:18:23 -0800756 return True
757 return False
Neale Rannsad422ed2016-11-02 14:20:04 +0000758
Neale Ranns5a8123b2017-01-26 01:18:23 -0800759 def object_id(self):
760 return ("%d:%s binds %d:%s/%d"
761 % (self.table_id,
762 self.local_label,
763 self.ip_table_id,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700764 self.dest_addr,
Neale Ranns5a8123b2017-01-26 01:18:23 -0800765 self.dest_addr_len))
766
767
Neale Ranns15002542017-09-10 04:39:11 -0700768class VppMplsTable(VppObject):
769
770 def __init__(self,
771 test,
772 table_id):
773 self._test = test
774 self.table_id = table_id
775
776 def add_vpp_config(self):
777 self._test.vapi.mpls_table_add_del(
778 self.table_id,
779 is_add=1)
780 self._test.registry.register(self, self._test.logger)
781
782 def remove_vpp_config(self):
783 self._test.vapi.mpls_table_add_del(
784 self.table_id,
785 is_add=0)
786
787 def query_vpp_config(self):
Neale Ranns097fa662018-05-01 05:17:55 -0700788 dump = self._test.vapi.mpls_table_dump()
789 for d in dump:
790 if d.mt_table.mt_table_id == self.table_id:
791 return True
Neale Ranns15002542017-09-10 04:39:11 -0700792 return False
793
Neale Ranns15002542017-09-10 04:39:11 -0700794 def object_id(self):
795 return ("table-mpls-%d" % (self.table_id))
796
797
Neale Ranns5a8123b2017-01-26 01:18:23 -0800798class VppMplsRoute(VppObject):
Neale Rannsad422ed2016-11-02 14:20:04 +0000799 """
Neale Ranns5a8123b2017-01-26 01:18:23 -0800800 MPLS Route/LSP
Neale Rannsad422ed2016-11-02 14:20:04 +0000801 """
802
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800803 def __init__(self, test, local_label, eos_bit, paths, table_id=0,
Neale Ranns097fa662018-05-01 05:17:55 -0700804 is_multicast=0,
805 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP4):
Neale Rannsad422ed2016-11-02 14:20:04 +0000806 self._test = test
807 self.paths = paths
808 self.local_label = local_label
809 self.eos_bit = eos_bit
Neale Ranns097fa662018-05-01 05:17:55 -0700810 self.eos_proto = eos_proto
Neale Rannsad422ed2016-11-02 14:20:04 +0000811 self.table_id = table_id
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800812 self.is_multicast = is_multicast
Neale Rannsad422ed2016-11-02 14:20:04 +0000813
814 def add_vpp_config(self):
Neale Ranns097fa662018-05-01 05:17:55 -0700815 paths = []
Neale Rannsad422ed2016-11-02 14:20:04 +0000816 for path in self.paths:
Neale Ranns097fa662018-05-01 05:17:55 -0700817 paths.append(path.encode())
Neale Ranns31ed7442018-02-23 05:29:09 -0800818
Neale Ranns097fa662018-05-01 05:17:55 -0700819 r = self._test.vapi.mpls_route_add_del(self.table_id,
820 self.local_label,
821 self.eos_bit,
822 self.eos_proto,
823 self.is_multicast,
824 paths, 1, 0)
Neale Ranns008dbe12018-09-07 09:32:36 -0700825 self.stats_index = r.stats_index
Neale Ranns5a8123b2017-01-26 01:18:23 -0800826 self._test.registry.register(self, self._test.logger)
Neale Rannsad422ed2016-11-02 14:20:04 +0000827
828 def remove_vpp_config(self):
Neale Ranns097fa662018-05-01 05:17:55 -0700829 paths = []
Neale Rannsad422ed2016-11-02 14:20:04 +0000830 for path in self.paths:
Neale Ranns097fa662018-05-01 05:17:55 -0700831 paths.append(path.encode())
832
833 self._test.vapi.mpls_route_add_del(self.table_id,
834 self.local_label,
835 self.eos_bit,
836 self.eos_proto,
837 self.is_multicast,
838 paths, 0, 0)
Neale Ranns5a8123b2017-01-26 01:18:23 -0800839
840 def query_vpp_config(self):
Neale Ranns775f73c2018-12-20 03:01:49 -0800841 return find_mpls_route(self._test, self.table_id,
842 self.local_label, self.eos_bit)
Neale Ranns5a8123b2017-01-26 01:18:23 -0800843
Neale Ranns5a8123b2017-01-26 01:18:23 -0800844 def object_id(self):
Paul Vinciguerra941da4a2019-06-18 07:57:53 -0400845 return ("mpls-route-%d:%s/%d"
Neale Ranns5a8123b2017-01-26 01:18:23 -0800846 % (self.table_id,
847 self.local_label,
Ole Troan9a475372019-03-05 16:58:24 +0100848 20 + self.eos_bit))
Neale Ranns008dbe12018-09-07 09:32:36 -0700849
850 def get_stats_to(self):
851 c = self._test.statistics.get_counter("/net/route/to")
852 return c[0][self.stats_index]
853
854 def get_stats_via(self):
855 c = self._test.statistics.get_counter("/net/route/via")
856 return c[0][self.stats_index]