blob: 4675db5c5a68c004e5b5d314a026f60ffb53cb87 [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,
Neale Ranns256b67b2020-09-02 14:46:53 +0000191 is_ip6=0,
192 register=True):
Neale Ranns15002542017-09-10 04:39:11 -0700193 self._test = test
194 self.table_id = table_id
195 self.is_ip6 = is_ip6
Neale Ranns256b67b2020-09-02 14:46:53 +0000196 self.register = register
Neale Ranns15002542017-09-10 04:39:11 -0700197
198 def add_vpp_config(self):
Neale Ranns9db6ada2019-11-08 12:42:31 +0000199 self._test.vapi.ip_table_add_del(is_add=1,
200 table={'is_ip6': self.is_ip6,
201 'table_id': self.table_id})
Neale Ranns256b67b2020-09-02 14:46:53 +0000202 if self.register:
203 self._test.registry.register(self, self._test.logger)
Neale Ranns9db6ada2019-11-08 12:42:31 +0000204 return self
Neale Ranns15002542017-09-10 04:39:11 -0700205
206 def remove_vpp_config(self):
Neale Ranns9db6ada2019-11-08 12:42:31 +0000207 self._test.vapi.ip_table_add_del(is_add=0,
208 table={'is_ip6': self.is_ip6,
209 'table_id': self.table_id})
210
211 def replace_begin(self):
212 self._test.vapi.ip_table_replace_begin(
213 table={'is_ip6': self.is_ip6,
214 'table_id': self.table_id})
215
216 def replace_end(self):
217 self._test.vapi.ip_table_replace_end(
218 table={'is_ip6': self.is_ip6,
219 'table_id': self.table_id})
220
221 def flush(self):
222 self._test.vapi.ip_table_flush(table={'is_ip6': self.is_ip6,
223 'table_id': self.table_id})
224
225 def dump(self):
226 return self._test.vapi.ip_route_dump(self.table_id, self.is_ip6)
227
228 def mdump(self):
229 return self._test.vapi.ip_mroute_dump(self.table_id, self.is_ip6)
Neale Ranns15002542017-09-10 04:39:11 -0700230
231 def query_vpp_config(self):
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700232 if self.table_id == 0:
233 # the default table always exists
234 return False
Neale Ranns15002542017-09-10 04:39:11 -0700235 # find the default route
236 return find_route(self._test,
237 "::" if self.is_ip6 else "0.0.0.0",
238 0,
Neale Ranns097fa662018-05-01 05:17:55 -0700239 self.table_id)
Neale Ranns15002542017-09-10 04:39:11 -0700240
Neale Ranns15002542017-09-10 04:39:11 -0700241 def object_id(self):
242 return ("table-%s-%d" %
243 ("v6" if self.is_ip6 == 1 else "v4",
244 self.table_id))
245
246
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700247class VppIpInterfaceAddress(VppObject):
248
Neale Ranns59f71132020-04-08 12:19:38 +0000249 def __init__(self, test, intf, addr, len, bind=None):
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700250 self._test = test
251 self.intf = intf
Neale Rannsefd7bc22019-11-11 08:32:34 +0000252 self.addr = addr
253 self.len = len
254 self.prefix = "%s/%d" % (addr, len)
Neale Ranns59f71132020-04-08 12:19:38 +0000255 self.host_len = ip_network(self.prefix, strict=False).max_prefixlen
256 self.table_id = 0
257 if bind:
258 self.table_id = bind.table.table_id
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700259
260 def add_vpp_config(self):
261 self._test.vapi.sw_interface_add_del_address(
Neale Rannsefd7bc22019-11-11 08:32:34 +0000262 sw_if_index=self.intf.sw_if_index, prefix=self.prefix,
Ole Troan9a475372019-03-05 16:58:24 +0100263 is_add=1)
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700264 self._test.registry.register(self, self._test.logger)
Neale Ranns9efcee62019-11-26 19:30:08 +0000265 return self
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700266
267 def remove_vpp_config(self):
268 self._test.vapi.sw_interface_add_del_address(
Neale Rannsefd7bc22019-11-11 08:32:34 +0000269 sw_if_index=self.intf.sw_if_index, prefix=self.prefix,
Ole Troan9a475372019-03-05 16:58:24 +0100270 is_add=0)
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700271
272 def query_vpp_config(self):
Neale Ranns59f71132020-04-08 12:19:38 +0000273 # search for the IP address mapping and the two expected
274 # FIB entries
275 v = ip_address(self.addr).version
276
277 if ((v == 4 and self.len < 31) or (v == 6 and self.len < 127)):
278 return (fib_interface_ip_prefix(self._test,
279 self.addr,
280 self.len,
281 self.intf.sw_if_index) &
282 find_route(self._test,
283 self.addr,
284 self.len,
285 table_id=self.table_id,
286 sw_if_index=self.intf.sw_if_index) &
287 find_route(self._test,
288 self.addr,
289 self.host_len,
290 table_id=self.table_id,
291 sw_if_index=self.intf.sw_if_index))
292 else:
293 return (fib_interface_ip_prefix(self._test,
294 self.addr,
295 self.len,
296 self.intf.sw_if_index) &
297 find_route(self._test,
298 self.addr,
299 self.host_len,
300 table_id=self.table_id,
301 sw_if_index=self.intf.sw_if_index))
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700302
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700303 def object_id(self):
Neale Ranns59f71132020-04-08 12:19:38 +0000304 return "interface-ip-%s-%d-%s" % (self.intf,
305 self.table_id,
306 self.prefix)
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700307
308
Neale Rannsec40a7d2020-04-23 07:36:12 +0000309class VppIp6LinkLocalAddress(VppObject):
310
311 def __init__(self, test, intf, addr):
312 self._test = test
313 self.intf = intf
314 self.addr = addr
315
316 def add_vpp_config(self):
317 self._test.vapi.sw_interface_ip6_set_link_local_address(
318 sw_if_index=self.intf.sw_if_index, ip=self.addr)
319 self._test.registry.register(self, self._test.logger)
320 return self
321
322 def remove_vpp_config(self):
323 # link locals can't be removed, only changed
324 pass
325
326 def query_vpp_config(self):
327 # no API to query
328 return False
329
330 def object_id(self):
331 return "ip6-link-local-%s-%s" % (self.intf, self.addr)
332
333
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700334class VppIpInterfaceBind(VppObject):
335
336 def __init__(self, test, intf, table):
337 self._test = test
338 self.intf = intf
339 self.table = table
340
341 def add_vpp_config(self):
342 if self.table.is_ip6:
343 self.intf.set_table_ip6(self.table.table_id)
344 else:
345 self.intf.set_table_ip4(self.table.table_id)
346 self._test.registry.register(self, self._test.logger)
Neale Ranns59f71132020-04-08 12:19:38 +0000347 return self
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700348
349 def remove_vpp_config(self):
350 if 0 == self.table.table_id:
351 return
352 if self.table.is_ip6:
353 self.intf.set_table_ip6(0)
354 else:
355 self.intf.set_table_ip4(0)
356
357 def query_vpp_config(self):
358 if 0 == self.table.table_id:
359 return False
360 return self._test.vapi.sw_interface_get_table(
361 self.intf.sw_if_index,
362 self.table.is_ip6).vrf_id == self.table.table_id
363
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700364 def object_id(self):
365 return "interface-bind-%s-%s" % (self.intf, self.table)
366
367
Neale Ranns31ed7442018-02-23 05:29:09 -0800368class VppMplsLabel(object):
369 def __init__(self, value, mode=MplsLspMode.PIPE, ttl=64, exp=0):
370 self.value = value
371 self.mode = mode
372 self.ttl = ttl
373 self.exp = exp
374
375 def encode(self):
376 is_uniform = 0 if self.mode is MplsLspMode.PIPE else 1
377 return {'label': self.value,
378 'ttl': self.ttl,
379 'exp': self.exp,
380 'is_uniform': is_uniform}
381
Neale Ranns775f73c2018-12-20 03:01:49 -0800382 def __eq__(self, other):
383 if isinstance(other, self.__class__):
384 return (self.value == other.value and
385 self.ttl == other.ttl and
386 self.exp == other.exp and
387 self.mode == other.mode)
388 elif hasattr(other, 'label'):
389 return (self.value == other.label and
390 self.ttl == other.ttl and
391 self.exp == other.exp and
392 (self.mode == MplsLspMode.UNIFORM) == other.is_uniform)
393 else:
394 return False
395
396 def __ne__(self, other):
397 return not (self == other)
398
Neale Ranns31ed7442018-02-23 05:29:09 -0800399
Neale Ranns097fa662018-05-01 05:17:55 -0700400class VppFibPathNextHop(object):
401 def __init__(self, addr,
402 via_label=MPLS_LABEL_INVALID,
403 next_hop_id=INVALID_INDEX):
404 self.addr = VppIpAddressUnion(addr)
405 self.via_label = via_label
406 self.obj_id = next_hop_id
407
408 def encode(self):
409 if self.via_label is not MPLS_LABEL_INVALID:
410 return {'via_label': self.via_label}
411 if self.obj_id is not INVALID_INDEX:
412 return {'obj_id': self.obj_id}
413 else:
414 return {'address': self.addr.encode()}
415
416 def proto(self):
417 if self.via_label is MPLS_LABEL_INVALID:
418 return address_proto(self.addr)
419 else:
420 return FibPathProto.FIB_PATH_NH_PROTO_MPLS
421
422 def __eq__(self, other):
423 if not isinstance(other, self.__class__):
424 # try the other instance's __eq__.
425 return NotImplemented
426 return (self.addr == other.addr and
427 self.via_label == other.via_label and
428 self.obj_id == other.obj_id)
429
430
Neale Ranns5a8123b2017-01-26 01:18:23 -0800431class VppRoutePath(object):
Neale Rannsad422ed2016-11-02 14:20:04 +0000432
Klement Sekerada505f62017-01-04 12:58:53 +0100433 def __init__(
434 self,
435 nh_addr,
436 nh_sw_if_index,
437 nh_table_id=0,
438 labels=[],
Neale Rannsfca0c242017-01-13 07:57:46 -0800439 nh_via_label=MPLS_LABEL_INVALID,
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800440 rpf_id=0,
Neale Ranns097fa662018-05-01 05:17:55 -0700441 next_hop_id=INVALID_INDEX,
442 proto=None,
443 flags=FibPathFlags.FIB_PATH_FLAG_NONE,
444 type=FibPathType.FIB_PATH_TYPE_NORMAL):
Neale Ranns177bbdc2016-11-15 09:46:51 +0000445 self.nh_itf = nh_sw_if_index
446 self.nh_table_id = nh_table_id
Neale Rannsad422ed2016-11-02 14:20:04 +0000447 self.nh_labels = labels
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800448 self.weight = 1
449 self.rpf_id = rpf_id
Neale Ranns097fa662018-05-01 05:17:55 -0700450 self.proto = proto
451 self.flags = flags
452 self.type = type
453 self.nh = VppFibPathNextHop(nh_addr, nh_via_label, next_hop_id)
454 if proto is None:
455 self.proto = self.nh.proto()
Neale Ranns31426c62017-05-24 10:32:58 -0700456 else:
Neale Ranns097fa662018-05-01 05:17:55 -0700457 self.proto = proto
Neale Ranns810086d2017-11-05 16:26:46 -0800458 self.next_hop_id = next_hop_id
Neale Ranns177bbdc2016-11-15 09:46:51 +0000459
Neale Ranns097fa662018-05-01 05:17:55 -0700460 def encode_labels(self):
Neale Ranns31ed7442018-02-23 05:29:09 -0800461 lstack = []
462 for l in self.nh_labels:
463 if type(l) == VppMplsLabel:
464 lstack.append(l.encode())
465 else:
466 lstack.append({'label': l,
467 'ttl': 255})
Neale Ranns097fa662018-05-01 05:17:55 -0700468 while (len(lstack) < 16):
469 lstack.append({})
470
Neale Ranns31ed7442018-02-23 05:29:09 -0800471 return lstack
472
Neale Ranns097fa662018-05-01 05:17:55 -0700473 def encode(self):
474 return {'weight': 1,
Neale Ranns2303cb12018-02-21 04:57:17 -0800475 'preference': 0,
476 'table_id': self.nh_table_id,
Neale Ranns097fa662018-05-01 05:17:55 -0700477 'nh': self.nh.encode(),
Neale Ranns2303cb12018-02-21 04:57:17 -0800478 'next_hop_id': self.next_hop_id,
479 'sw_if_index': self.nh_itf,
Neale Ranns097fa662018-05-01 05:17:55 -0700480 'rpf_id': self.rpf_id,
481 'proto': self.proto,
482 'type': self.type,
483 'flags': self.flags,
Neale Ranns2303cb12018-02-21 04:57:17 -0800484 'n_labels': len(self.nh_labels),
Neale Ranns097fa662018-05-01 05:17:55 -0700485 'label_stack': self.encode_labels()}
Neale Ranns2303cb12018-02-21 04:57:17 -0800486
Neale Rannsef90ed02018-09-13 08:45:12 -0700487 def __eq__(self, other):
Neale Ranns775f73c2018-12-20 03:01:49 -0800488 if isinstance(other, self.__class__):
Neale Ranns097fa662018-05-01 05:17:55 -0700489 return self.nh == other.nh
Neale Ranns775f73c2018-12-20 03:01:49 -0800490 elif hasattr(other, 'sw_if_index'):
491 # vl_api_fib_path_t
492 if (len(self.nh_labels) != other.n_labels):
493 return False
494 for i in range(len(self.nh_labels)):
495 if (self.nh_labels[i] != other.label_stack[i]):
496 return False
497 return self.nh_itf == other.sw_if_index
498 else:
499 return False
500
501 def __ne__(self, other):
502 return not (self == other)
Neale Rannsef90ed02018-09-13 08:45:12 -0700503
Neale Ranns177bbdc2016-11-15 09:46:51 +0000504
Neale Ranns5a8123b2017-01-26 01:18:23 -0800505class VppMRoutePath(VppRoutePath):
Neale Ranns32e1c012016-11-22 17:07:28 +0000506
Neale Rannsd792d9c2017-10-21 10:53:20 -0700507 def __init__(self, nh_sw_if_index, flags,
Neale Rannse821ab12017-06-01 07:45:05 -0700508 nh=None,
Neale Ranns097fa662018-05-01 05:17:55 -0700509 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
510 type=FibPathType.FIB_PATH_TYPE_NORMAL,
511 bier_imp=INVALID_INDEX):
Neale Rannse821ab12017-06-01 07:45:05 -0700512 if not nh:
Neale Ranns097fa662018-05-01 05:17:55 -0700513 nh = "::" if proto is FibPathProto.FIB_PATH_NH_PROTO_IP6 \
514 else "0.0.0.0"
Neale Rannse821ab12017-06-01 07:45:05 -0700515 super(VppMRoutePath, self).__init__(nh,
516 nh_sw_if_index,
Neale Ranns097fa662018-05-01 05:17:55 -0700517 proto=proto,
518 type=type,
519 next_hop_id=bier_imp)
Neale Ranns32e1c012016-11-22 17:07:28 +0000520 self.nh_i_flags = flags
Neale Rannsd792d9c2017-10-21 10:53:20 -0700521 self.bier_imp = bier_imp
Neale Ranns32e1c012016-11-22 17:07:28 +0000522
Neale Ranns097fa662018-05-01 05:17:55 -0700523 def encode(self):
524 return {'path': super(VppMRoutePath, self).encode(),
525 'itf_flags': self.nh_i_flags}
526
Neale Ranns32e1c012016-11-22 17:07:28 +0000527
Neale Ranns5a8123b2017-01-26 01:18:23 -0800528class VppIpRoute(VppObject):
Neale Ranns177bbdc2016-11-15 09:46:51 +0000529 """
530 IP Route
531 """
532
533 def __init__(self, test, dest_addr,
Neale Ranns097fa662018-05-01 05:17:55 -0700534 dest_addr_len, paths, table_id=0, register=True):
Neale Ranns177bbdc2016-11-15 09:46:51 +0000535 self._test = test
536 self.paths = paths
Neale Ranns177bbdc2016-11-15 09:46:51 +0000537 self.table_id = table_id
Neale Rannsefd7bc22019-11-11 08:32:34 +0000538 self.prefix = mk_network(dest_addr, dest_addr_len)
Neale Ranns097fa662018-05-01 05:17:55 -0700539 self.register = register
Paul Vinciguerra941da4a2019-06-18 07:57:53 -0400540 self.stats_index = None
Neale Rannsc2ac2352019-07-02 14:33:29 +0000541 self.modified = False
Neale Ranns177bbdc2016-11-15 09:46:51 +0000542
Neale Ranns097fa662018-05-01 05:17:55 -0700543 self.encoded_paths = []
544 for path in self.paths:
545 self.encoded_paths.append(path.encode())
546
547 def __eq__(self, other):
548 if self.table_id == other.table_id and \
549 self.prefix == other.prefix:
550 return True
551 return False
552
553 def modify(self, paths):
Neale Ranns69b7aa42017-03-10 03:04:12 -0800554 self.paths = paths
Neale Ranns097fa662018-05-01 05:17:55 -0700555 self.encoded_paths = []
556 for path in self.paths:
557 self.encoded_paths.append(path.encode())
Neale Rannsc2ac2352019-07-02 14:33:29 +0000558 self.modified = True
Neale Ranns097fa662018-05-01 05:17:55 -0700559
560 self._test.vapi.ip_route_add_del(route={'table_id': self.table_id,
Neale Rannsefd7bc22019-11-11 08:32:34 +0000561 'prefix': self.prefix,
Neale Ranns097fa662018-05-01 05:17:55 -0700562 'n_paths': len(
563 self.encoded_paths),
564 'paths': self.encoded_paths,
565 },
566 is_add=1,
567 is_multipath=0)
Neale Ranns69b7aa42017-03-10 03:04:12 -0800568
Neale Ranns177bbdc2016-11-15 09:46:51 +0000569 def add_vpp_config(self):
Neale Ranns097fa662018-05-01 05:17:55 -0700570 r = self._test.vapi.ip_route_add_del(
571 route={'table_id': self.table_id,
Neale Rannsefd7bc22019-11-11 08:32:34 +0000572 'prefix': self.prefix,
Neale Ranns097fa662018-05-01 05:17:55 -0700573 'n_paths': len(self.encoded_paths),
574 'paths': self.encoded_paths,
575 },
576 is_add=1,
577 is_multipath=0)
Neale Ranns008dbe12018-09-07 09:32:36 -0700578 self.stats_index = r.stats_index
Neale Ranns097fa662018-05-01 05:17:55 -0700579 if self.register:
580 self._test.registry.register(self, self._test.logger)
Neale Ranns9db6ada2019-11-08 12:42:31 +0000581 return self
Neale Ranns177bbdc2016-11-15 09:46:51 +0000582
583 def remove_vpp_config(self):
Neale Rannsc2ac2352019-07-02 14:33:29 +0000584 # there's no need to issue different deletes for modified routes
585 # we do this only to test the two different ways to delete routes
586 # eiter by passing all the paths to remove and mutlipath=1 or
587 # passing no paths and multipath=0
588 if self.modified:
589 self._test.vapi.ip_route_add_del(
590 route={'table_id': self.table_id,
Neale Rannsefd7bc22019-11-11 08:32:34 +0000591 'prefix': self.prefix,
Neale Rannsc2ac2352019-07-02 14:33:29 +0000592 'n_paths': len(
593 self.encoded_paths),
594 'paths': self.encoded_paths},
595 is_add=0,
596 is_multipath=1)
597 else:
598 self._test.vapi.ip_route_add_del(
599 route={'table_id': self.table_id,
Neale Rannsefd7bc22019-11-11 08:32:34 +0000600 'prefix': self.prefix,
Neale Rannsc2ac2352019-07-02 14:33:29 +0000601 'n_paths': 0},
602 is_add=0,
603 is_multipath=0)
Neale Rannsad422ed2016-11-02 14:20:04 +0000604
Neale Ranns5a8123b2017-01-26 01:18:23 -0800605 def query_vpp_config(self):
Neale Rannsb3b2de72017-03-08 05:17:22 -0800606 return find_route(self._test,
Neale Rannsefd7bc22019-11-11 08:32:34 +0000607 self.prefix.network_address,
608 self.prefix.prefixlen,
Neale Ranns097fa662018-05-01 05:17:55 -0700609 self.table_id)
Neale Rannsad422ed2016-11-02 14:20:04 +0000610
Neale Ranns5a8123b2017-01-26 01:18:23 -0800611 def object_id(self):
Neale Rannsefd7bc22019-11-11 08:32:34 +0000612 return ("%s:table-%d-%s" % (
613 'ip6-route' if self.prefix.version == 6 else 'ip-route',
Paul Vinciguerra941da4a2019-06-18 07:57:53 -0400614 self.table_id,
Neale Rannsefd7bc22019-11-11 08:32:34 +0000615 self.prefix))
Neale Ranns5a8123b2017-01-26 01:18:23 -0800616
Neale Ranns008dbe12018-09-07 09:32:36 -0700617 def get_stats_to(self):
618 c = self._test.statistics.get_counter("/net/route/to")
619 return c[0][self.stats_index]
620
621 def get_stats_via(self):
622 c = self._test.statistics.get_counter("/net/route/via")
623 return c[0][self.stats_index]
624
Neale Ranns5a8123b2017-01-26 01:18:23 -0800625
626class VppIpMRoute(VppObject):
Neale Ranns32e1c012016-11-22 17:07:28 +0000627 """
628 IP Multicast Route
629 """
630
631 def __init__(self, test, src_addr, grp_addr,
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800632 grp_addr_len, e_flags, paths, table_id=0,
Neale Ranns097fa662018-05-01 05:17:55 -0700633 rpf_id=0):
Neale Ranns32e1c012016-11-22 17:07:28 +0000634 self._test = test
635 self.paths = paths
Neale Ranns32e1c012016-11-22 17:07:28 +0000636 self.table_id = table_id
637 self.e_flags = e_flags
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800638 self.rpf_id = rpf_id
Neale Ranns32e1c012016-11-22 17:07:28 +0000639
Neale Ranns097fa662018-05-01 05:17:55 -0700640 self.prefix = VppIpMPrefix(src_addr, grp_addr, grp_addr_len)
641 self.encoded_paths = []
642 for path in self.paths:
643 self.encoded_paths.append(path.encode())
Neale Ranns32e1c012016-11-22 17:07:28 +0000644
Paul Vinciguerrae64e5ff2020-04-28 00:27:38 -0400645 def encode(self, paths=None):
646 _paths = self.encoded_paths if paths is None else paths
647 return {'table_id': self.table_id,
648 'entry_flags': self.e_flags,
649 'rpf_id': self.rpf_id,
650 'prefix': self.prefix.encode(),
651 'n_paths': len(_paths),
652 'paths': _paths,
653 }
654
Neale Ranns32e1c012016-11-22 17:07:28 +0000655 def add_vpp_config(self):
Paul Vinciguerrae64e5ff2020-04-28 00:27:38 -0400656 r = self._test.vapi.ip_mroute_add_del(route=self.encode(),
657 is_multipath=1,
Neale Ranns097fa662018-05-01 05:17:55 -0700658 is_add=1)
659 self.stats_index = r.stats_index
Neale Ranns5a8123b2017-01-26 01:18:23 -0800660 self._test.registry.register(self, self._test.logger)
Neale Ranns9db6ada2019-11-08 12:42:31 +0000661 return self
Neale Ranns32e1c012016-11-22 17:07:28 +0000662
663 def remove_vpp_config(self):
Paul Vinciguerrae64e5ff2020-04-28 00:27:38 -0400664 self._test.vapi.ip_mroute_add_del(route=self.encode(),
665 is_multipath=1,
Neale Ranns097fa662018-05-01 05:17:55 -0700666 is_add=0)
Neale Ranns32e1c012016-11-22 17:07:28 +0000667
668 def update_entry_flags(self, flags):
669 self.e_flags = flags
Paul Vinciguerrae64e5ff2020-04-28 00:27:38 -0400670 self._test.vapi.ip_mroute_add_del(route=self.encode(paths=[]),
671 is_multipath=1,
Neale Ranns097fa662018-05-01 05:17:55 -0700672 is_add=1)
Neale Ranns32e1c012016-11-22 17:07:28 +0000673
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800674 def update_rpf_id(self, rpf_id):
675 self.rpf_id = rpf_id
Paul Vinciguerrae64e5ff2020-04-28 00:27:38 -0400676 self._test.vapi.ip_mroute_add_del(route=self.encode(paths=[]),
677 is_multipath=1,
Neale Ranns097fa662018-05-01 05:17:55 -0700678 is_add=1)
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800679
Neale Ranns32e1c012016-11-22 17:07:28 +0000680 def update_path_flags(self, itf, flags):
Neale Ranns097fa662018-05-01 05:17:55 -0700681 for p in range(len(self.paths)):
682 if self.paths[p].nh_itf == itf:
683 self.paths[p].nh_i_flags = flags
Paul Vinciguerra6230b9d2020-04-28 11:23:31 -0400684 self.encoded_paths[p] = self.paths[p].encode()
685 break
Neale Ranns097fa662018-05-01 05:17:55 -0700686
Paul Vinciguerrae64e5ff2020-04-28 00:27:38 -0400687 self._test.vapi.ip_mroute_add_del(
688 route=self.encode(
689 paths=[self.encoded_paths[p]]),
690 is_add=1,
691 is_multipath=0)
Neale Ranns32e1c012016-11-22 17:07:28 +0000692
Neale Ranns5a8123b2017-01-26 01:18:23 -0800693 def query_vpp_config(self):
Neale Ranns947ea622018-06-07 23:48:20 -0700694 return find_mroute(self._test,
Neale Ranns097fa662018-05-01 05:17:55 -0700695 self.prefix.gaddr,
696 self.prefix.saddr,
697 self.prefix.length,
698 self.table_id)
Neale Ranns32e1c012016-11-22 17:07:28 +0000699
Neale Ranns5a8123b2017-01-26 01:18:23 -0800700 def object_id(self):
Neale Ranns097fa662018-05-01 05:17:55 -0700701 return ("%d:(%s,%s/%d)" % (self.table_id,
702 self.prefix.saddr,
703 self.prefix.gaddr,
704 self.prefix.length))
Neale Ranns5a8123b2017-01-26 01:18:23 -0800705
Neale Ranns28c142e2018-09-07 09:37:07 -0700706 def get_stats(self):
707 c = self._test.statistics.get_counter("/net/mroute")
708 return c[0][self.stats_index]
709
Neale Ranns5a8123b2017-01-26 01:18:23 -0800710
711class VppMFibSignal(object):
Neale Ranns32e1c012016-11-22 17:07:28 +0000712 def __init__(self, test, route, interface, packet):
713 self.route = route
714 self.interface = interface
715 self.packet = packet
716 self.test = test
717
718 def compare(self, signal):
719 self.test.assertEqual(self.interface, signal.sw_if_index)
720 self.test.assertEqual(self.route.table_id, signal.table_id)
Neale Ranns097fa662018-05-01 05:17:55 -0700721 self.test.assertEqual(self.route.prefix, signal.prefix)
Neale Ranns32e1c012016-11-22 17:07:28 +0000722
723
Neale Ranns5a8123b2017-01-26 01:18:23 -0800724class VppMplsIpBind(VppObject):
Neale Rannsad422ed2016-11-02 14:20:04 +0000725 """
726 MPLS to IP Binding
727 """
728
Neale Ranns5a8123b2017-01-26 01:18:23 -0800729 def __init__(self, test, local_label, dest_addr, dest_addr_len,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700730 table_id=0, ip_table_id=0, is_ip6=0):
Neale Rannsad422ed2016-11-02 14:20:04 +0000731 self._test = test
Neale Rannsad422ed2016-11-02 14:20:04 +0000732 self.dest_addr_len = dest_addr_len
Neale Rannsf12a83f2017-04-18 09:09:40 -0700733 self.dest_addr = dest_addr
Neale Ranns097fa662018-05-01 05:17:55 -0700734 self.ip_addr = ip_address(text_type(dest_addr))
Neale Rannsad422ed2016-11-02 14:20:04 +0000735 self.local_label = local_label
Neale Ranns5a8123b2017-01-26 01:18:23 -0800736 self.table_id = table_id
737 self.ip_table_id = ip_table_id
Neale Rannsefd7bc22019-11-11 08:32:34 +0000738 self.prefix = mk_network(dest_addr, dest_addr_len)
Neale Rannsad422ed2016-11-02 14:20:04 +0000739
740 def add_vpp_config(self):
741 self._test.vapi.mpls_ip_bind_unbind(self.local_label,
Neale Rannsefd7bc22019-11-11 08:32:34 +0000742 self.prefix,
Neale Ranns5a8123b2017-01-26 01:18:23 -0800743 table_id=self.table_id,
Neale Ranns097fa662018-05-01 05:17:55 -0700744 ip_table_id=self.ip_table_id)
Neale Ranns5a8123b2017-01-26 01:18:23 -0800745 self._test.registry.register(self, self._test.logger)
Neale Rannsad422ed2016-11-02 14:20:04 +0000746
747 def remove_vpp_config(self):
748 self._test.vapi.mpls_ip_bind_unbind(self.local_label,
Neale Rannsefd7bc22019-11-11 08:32:34 +0000749 self.prefix,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700750 table_id=self.table_id,
751 ip_table_id=self.ip_table_id,
Neale Ranns097fa662018-05-01 05:17:55 -0700752 is_bind=0)
Neale Rannsad422ed2016-11-02 14:20:04 +0000753
Neale Ranns5a8123b2017-01-26 01:18:23 -0800754 def query_vpp_config(self):
Neale Ranns097fa662018-05-01 05:17:55 -0700755 dump = self._test.vapi.mpls_route_dump(self.table_id)
Neale Ranns5a8123b2017-01-26 01:18:23 -0800756 for e in dump:
Neale Ranns097fa662018-05-01 05:17:55 -0700757 if self.local_label == e.mr_route.mr_label \
758 and self.table_id == e.mr_route.mr_table_id:
Neale Ranns5a8123b2017-01-26 01:18:23 -0800759 return True
760 return False
Neale Rannsad422ed2016-11-02 14:20:04 +0000761
Neale Ranns5a8123b2017-01-26 01:18:23 -0800762 def object_id(self):
763 return ("%d:%s binds %d:%s/%d"
764 % (self.table_id,
765 self.local_label,
766 self.ip_table_id,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700767 self.dest_addr,
Neale Ranns5a8123b2017-01-26 01:18:23 -0800768 self.dest_addr_len))
769
770
Neale Ranns15002542017-09-10 04:39:11 -0700771class VppMplsTable(VppObject):
772
773 def __init__(self,
774 test,
775 table_id):
776 self._test = test
777 self.table_id = table_id
778
779 def add_vpp_config(self):
780 self._test.vapi.mpls_table_add_del(
781 self.table_id,
782 is_add=1)
783 self._test.registry.register(self, self._test.logger)
784
785 def remove_vpp_config(self):
786 self._test.vapi.mpls_table_add_del(
787 self.table_id,
788 is_add=0)
789
790 def query_vpp_config(self):
Neale Ranns097fa662018-05-01 05:17:55 -0700791 dump = self._test.vapi.mpls_table_dump()
792 for d in dump:
793 if d.mt_table.mt_table_id == self.table_id:
794 return True
Neale Ranns15002542017-09-10 04:39:11 -0700795 return False
796
Neale Ranns15002542017-09-10 04:39:11 -0700797 def object_id(self):
798 return ("table-mpls-%d" % (self.table_id))
799
800
Neale Ranns5a8123b2017-01-26 01:18:23 -0800801class VppMplsRoute(VppObject):
Neale Rannsad422ed2016-11-02 14:20:04 +0000802 """
Neale Ranns5a8123b2017-01-26 01:18:23 -0800803 MPLS Route/LSP
Neale Rannsad422ed2016-11-02 14:20:04 +0000804 """
805
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800806 def __init__(self, test, local_label, eos_bit, paths, table_id=0,
Neale Ranns097fa662018-05-01 05:17:55 -0700807 is_multicast=0,
808 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP4):
Neale Rannsad422ed2016-11-02 14:20:04 +0000809 self._test = test
810 self.paths = paths
811 self.local_label = local_label
812 self.eos_bit = eos_bit
Neale Ranns097fa662018-05-01 05:17:55 -0700813 self.eos_proto = eos_proto
Neale Rannsad422ed2016-11-02 14:20:04 +0000814 self.table_id = table_id
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800815 self.is_multicast = is_multicast
Neale Rannsad422ed2016-11-02 14:20:04 +0000816
817 def add_vpp_config(self):
Neale Ranns097fa662018-05-01 05:17:55 -0700818 paths = []
Neale Rannsad422ed2016-11-02 14:20:04 +0000819 for path in self.paths:
Neale Ranns097fa662018-05-01 05:17:55 -0700820 paths.append(path.encode())
Neale Ranns31ed7442018-02-23 05:29:09 -0800821
Neale Ranns097fa662018-05-01 05:17:55 -0700822 r = self._test.vapi.mpls_route_add_del(self.table_id,
823 self.local_label,
824 self.eos_bit,
825 self.eos_proto,
826 self.is_multicast,
827 paths, 1, 0)
Neale Ranns008dbe12018-09-07 09:32:36 -0700828 self.stats_index = r.stats_index
Neale Ranns5a8123b2017-01-26 01:18:23 -0800829 self._test.registry.register(self, self._test.logger)
Neale Rannsad422ed2016-11-02 14:20:04 +0000830
831 def remove_vpp_config(self):
Neale Ranns097fa662018-05-01 05:17:55 -0700832 paths = []
Neale Rannsad422ed2016-11-02 14:20:04 +0000833 for path in self.paths:
Neale Ranns097fa662018-05-01 05:17:55 -0700834 paths.append(path.encode())
835
836 self._test.vapi.mpls_route_add_del(self.table_id,
837 self.local_label,
838 self.eos_bit,
839 self.eos_proto,
840 self.is_multicast,
841 paths, 0, 0)
Neale Ranns5a8123b2017-01-26 01:18:23 -0800842
843 def query_vpp_config(self):
Neale Ranns775f73c2018-12-20 03:01:49 -0800844 return find_mpls_route(self._test, self.table_id,
845 self.local_label, self.eos_bit)
Neale Ranns5a8123b2017-01-26 01:18:23 -0800846
Neale Ranns5a8123b2017-01-26 01:18:23 -0800847 def object_id(self):
Paul Vinciguerra941da4a2019-06-18 07:57:53 -0400848 return ("mpls-route-%d:%s/%d"
Neale Ranns5a8123b2017-01-26 01:18:23 -0800849 % (self.table_id,
850 self.local_label,
Ole Troan9a475372019-03-05 16:58:24 +0100851 20 + self.eos_bit))
Neale Ranns008dbe12018-09-07 09:32:36 -0700852
853 def get_stats_to(self):
854 c = self._test.statistics.get_counter("/net/route/to")
855 return c[0][self.stats_index]
856
857 def get_stats_via(self):
858 c = self._test.statistics.get_counter("/net/route/via")
859 return c[0][self.stats_index]