blob: b60594852750fb0a22d33d7ecbab6e8497808458 [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 Ranns097fa662018-05-01 05:17:55 -070023class FibPathProto:
24 FIB_PATH_NH_PROTO_IP4 = 0
25 FIB_PATH_NH_PROTO_IP6 = 1
26 FIB_PATH_NH_PROTO_MPLS = 2
27 FIB_PATH_NH_PROTO_ETHERNET = 3
28 FIB_PATH_NH_PROTO_BIER = 4
29 FIB_PATH_NH_PROTO_NSH = 5
30
31
32class FibPathType:
33 FIB_PATH_TYPE_NORMAL = 0
34 FIB_PATH_TYPE_LOCAL = 1
35 FIB_PATH_TYPE_DROP = 2
36 FIB_PATH_TYPE_UDP_ENCAP = 3
37 FIB_PATH_TYPE_BIER_IMP = 4
38 FIB_PATH_TYPE_ICMP_UNREACH = 5
39 FIB_PATH_TYPE_ICMP_PROHIBIT = 6
40 FIB_PATH_TYPE_SOURCE_LOOKUP = 7
41 FIB_PATH_TYPE_DVR = 8
42 FIB_PATH_TYPE_INTERFACE_RX = 9
43 FIB_PATH_TYPE_CLASSIFY = 10
44
45
46class FibPathFlags:
47 FIB_PATH_FLAG_NONE = 0
48 FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED = 1
49 FIB_PATH_FLAG_RESOLVE_VIA_HOST = 2
Neale Ranns1dbcf302019-07-19 11:44:53 +000050 FIB_PATH_FLAG_POP_PW_CW = 4
Neale Ranns097fa662018-05-01 05:17:55 -070051
52
Neale Ranns31ed7442018-02-23 05:29:09 -080053class MplsLspMode:
54 PIPE = 0
55 UNIFORM = 1
56
57
Neale Rannsefd7bc22019-11-11 08:32:34 +000058def mk_network(addr, len):
59 if ip_address(text_type(addr)).version == 4:
60 return IPv4Network("%s/%d" % (addr, len), strict=False)
61 else:
62 return IPv6Network("%s/%d" % (addr, len), strict=False)
63
64
Neale Ranns93cc3ee2018-10-10 07:22:51 -070065def ip_to_dpo_proto(addr):
Paul Vinciguerrabeded852019-03-01 10:35:55 -080066 if addr.version == 6:
Neale Ranns93cc3ee2018-10-10 07:22:51 -070067 return DpoProto.DPO_PROTO_IP6
68 else:
69 return DpoProto.DPO_PROTO_IP4
70
71
Neale Ranns097fa662018-05-01 05:17:55 -070072def address_proto(ip_addr):
Ole Troan6e6ad642020-02-04 13:28:13 +010073 if ip_addr.ip_addr.version == 4:
Neale Ranns097fa662018-05-01 05:17:55 -070074 return FibPathProto.FIB_PATH_NH_PROTO_IP4
Neale Rannsb3b2de72017-03-08 05:17:22 -080075 else:
Neale Ranns097fa662018-05-01 05:17:55 -070076 return FibPathProto.FIB_PATH_NH_PROTO_IP6
Neale Rannsb3b2de72017-03-08 05:17:22 -080077
Neale Ranns097fa662018-05-01 05:17:55 -070078
Neale Ranns59f71132020-04-08 12:19:38 +000079def find_route(test, addr, len, table_id=0, sw_if_index=None):
Neale Rannsefd7bc22019-11-11 08:32:34 +000080 prefix = mk_network(addr, len)
Neale Ranns097fa662018-05-01 05:17:55 -070081
Ole Troan6e6ad642020-02-04 13:28:13 +010082 if 4 == prefix.version:
Neale Ranns097fa662018-05-01 05:17:55 -070083 routes = test.vapi.ip_route_dump(table_id, False)
Neale Ranns097fa662018-05-01 05:17:55 -070084 else:
85 routes = test.vapi.ip_route_dump(table_id, True)
Neale Ranns097fa662018-05-01 05:17:55 -070086
Neale Rannsb3b2de72017-03-08 05:17:22 -080087 for e in routes:
Neale Ranns097fa662018-05-01 05:17:55 -070088 if table_id == e.route.table_id \
Neale Rannsefd7bc22019-11-11 08:32:34 +000089 and str(e.route.prefix) == str(prefix):
Neale Ranns59f71132020-04-08 12:19:38 +000090 if not sw_if_index:
91 return True
92 else:
93 # should be only one path if the user is looking
94 # for the interface the route is reachable through
95 if e.route.n_paths != 1:
96 return False
97 else:
98 return (e.route.paths[0].sw_if_index == sw_if_index)
99
Neale Rannsb3b2de72017-03-08 05:17:22 -0800100 return False
101
102
Neale Ranns9db6ada2019-11-08 12:42:31 +0000103def find_route_in_dump(dump, route, table):
104 for r in dump:
105 if table.table_id == r.route.table_id \
106 and route.prefix == r.route.prefix:
107 if len(route.paths) == r.route.n_paths:
108 return True
109 return False
110
111
112def find_mroute_in_dump(dump, route, table):
113 for r in dump:
114 if table.table_id == r.route.table_id \
115 and route.prefix == r.route.prefix:
116 return True
117 return False
118
119
Neale Ranns947ea622018-06-07 23:48:20 -0700120def find_mroute(test, grp_addr, src_addr, grp_addr_len,
Neale Ranns097fa662018-05-01 05:17:55 -0700121 table_id=0):
122 ip_mprefix = VppIpMPrefix(text_type(src_addr),
123 text_type(grp_addr),
124 grp_addr_len)
125
Ole Troan6e6ad642020-02-04 13:28:13 +0100126 if 4 == ip_mprefix.version:
Neale Ranns097fa662018-05-01 05:17:55 -0700127 routes = test.vapi.ip_mroute_dump(table_id, False)
Neale Ranns947ea622018-06-07 23:48:20 -0700128 else:
Neale Ranns097fa662018-05-01 05:17:55 -0700129 routes = test.vapi.ip_mroute_dump(table_id, True)
130
Neale Ranns947ea622018-06-07 23:48:20 -0700131 for e in routes:
Neale Ranns097fa662018-05-01 05:17:55 -0700132 if table_id == e.route.table_id and ip_mprefix == e.route.prefix:
Neale Ranns947ea622018-06-07 23:48:20 -0700133 return True
134 return False
135
136
Neale Ranns775f73c2018-12-20 03:01:49 -0800137def find_mpls_route(test, table_id, label, eos_bit, paths=None):
Neale Ranns097fa662018-05-01 05:17:55 -0700138 dump = test.vapi.mpls_route_dump(table_id)
Neale Ranns775f73c2018-12-20 03:01:49 -0800139 for e in dump:
Neale Ranns097fa662018-05-01 05:17:55 -0700140 if label == e.mr_route.mr_label \
141 and eos_bit == e.mr_route.mr_eos \
142 and table_id == e.mr_route.mr_table_id:
Neale Ranns775f73c2018-12-20 03:01:49 -0800143 if not paths:
144 return True
145 else:
Neale Ranns097fa662018-05-01 05:17:55 -0700146 if (len(paths) != len(e.mr_route.mr_paths)):
Neale Ranns775f73c2018-12-20 03:01:49 -0800147 return False
148 for i in range(len(paths)):
Neale Ranns097fa662018-05-01 05:17:55 -0700149 if (paths[i] != e.mr_route.mr_paths[i]):
Neale Ranns775f73c2018-12-20 03:01:49 -0800150 return False
151 return True
152 return False
153
154
Neale Rannsefd7bc22019-11-11 08:32:34 +0000155def fib_interface_ip_prefix(test, addr, len, sw_if_index):
156 # can't use python net here since we need the host bits in the prefix
157 prefix = "%s/%d" % (addr, len)
158 addrs = test.vapi.ip_address_dump(
159 sw_if_index,
160 is_ipv6=(6 == ip_address(addr).version))
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700161
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700162 for a in addrs:
Neale Ranns097fa662018-05-01 05:17:55 -0700163 if a.sw_if_index == sw_if_index and \
Neale Rannsefd7bc22019-11-11 08:32:34 +0000164 str(a.prefix) == prefix:
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700165 return True
166 return False
167
168
Neale Ranns15002542017-09-10 04:39:11 -0700169class VppIpTable(VppObject):
170
171 def __init__(self,
172 test,
173 table_id,
Neale Ranns256b67b2020-09-02 14:46:53 +0000174 is_ip6=0,
175 register=True):
Neale Ranns15002542017-09-10 04:39:11 -0700176 self._test = test
177 self.table_id = table_id
178 self.is_ip6 = is_ip6
Neale Ranns256b67b2020-09-02 14:46:53 +0000179 self.register = register
Neale Ranns15002542017-09-10 04:39:11 -0700180
181 def add_vpp_config(self):
Neale Ranns9db6ada2019-11-08 12:42:31 +0000182 self._test.vapi.ip_table_add_del(is_add=1,
183 table={'is_ip6': self.is_ip6,
184 'table_id': self.table_id})
Neale Ranns256b67b2020-09-02 14:46:53 +0000185 if self.register:
186 self._test.registry.register(self, self._test.logger)
Neale Ranns9db6ada2019-11-08 12:42:31 +0000187 return self
Neale Ranns15002542017-09-10 04:39:11 -0700188
189 def remove_vpp_config(self):
Neale Ranns9db6ada2019-11-08 12:42:31 +0000190 self._test.vapi.ip_table_add_del(is_add=0,
191 table={'is_ip6': self.is_ip6,
192 'table_id': self.table_id})
193
194 def replace_begin(self):
195 self._test.vapi.ip_table_replace_begin(
196 table={'is_ip6': self.is_ip6,
197 'table_id': self.table_id})
198
199 def replace_end(self):
200 self._test.vapi.ip_table_replace_end(
201 table={'is_ip6': self.is_ip6,
202 'table_id': self.table_id})
203
204 def flush(self):
205 self._test.vapi.ip_table_flush(table={'is_ip6': self.is_ip6,
206 'table_id': self.table_id})
207
208 def dump(self):
209 return self._test.vapi.ip_route_dump(self.table_id, self.is_ip6)
210
211 def mdump(self):
212 return self._test.vapi.ip_mroute_dump(self.table_id, self.is_ip6)
Neale Ranns15002542017-09-10 04:39:11 -0700213
214 def query_vpp_config(self):
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700215 if self.table_id == 0:
216 # the default table always exists
217 return False
Neale Ranns15002542017-09-10 04:39:11 -0700218 # find the default route
219 return find_route(self._test,
220 "::" if self.is_ip6 else "0.0.0.0",
221 0,
Neale Ranns097fa662018-05-01 05:17:55 -0700222 self.table_id)
Neale Ranns15002542017-09-10 04:39:11 -0700223
Neale Ranns15002542017-09-10 04:39:11 -0700224 def object_id(self):
225 return ("table-%s-%d" %
226 ("v6" if self.is_ip6 == 1 else "v4",
227 self.table_id))
228
229
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700230class VppIpInterfaceAddress(VppObject):
231
Neale Ranns59f71132020-04-08 12:19:38 +0000232 def __init__(self, test, intf, addr, len, bind=None):
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700233 self._test = test
234 self.intf = intf
Neale Rannsefd7bc22019-11-11 08:32:34 +0000235 self.addr = addr
236 self.len = len
237 self.prefix = "%s/%d" % (addr, len)
Neale Ranns59f71132020-04-08 12:19:38 +0000238 self.host_len = ip_network(self.prefix, strict=False).max_prefixlen
239 self.table_id = 0
240 if bind:
241 self.table_id = bind.table.table_id
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700242
243 def add_vpp_config(self):
244 self._test.vapi.sw_interface_add_del_address(
Neale Rannsefd7bc22019-11-11 08:32:34 +0000245 sw_if_index=self.intf.sw_if_index, prefix=self.prefix,
Ole Troan9a475372019-03-05 16:58:24 +0100246 is_add=1)
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700247 self._test.registry.register(self, self._test.logger)
Neale Ranns9efcee62019-11-26 19:30:08 +0000248 return self
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700249
250 def remove_vpp_config(self):
251 self._test.vapi.sw_interface_add_del_address(
Neale Rannsefd7bc22019-11-11 08:32:34 +0000252 sw_if_index=self.intf.sw_if_index, prefix=self.prefix,
Ole Troan9a475372019-03-05 16:58:24 +0100253 is_add=0)
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700254
255 def query_vpp_config(self):
Neale Ranns59f71132020-04-08 12:19:38 +0000256 # search for the IP address mapping and the two expected
257 # FIB entries
258 v = ip_address(self.addr).version
259
260 if ((v == 4 and self.len < 31) or (v == 6 and self.len < 127)):
261 return (fib_interface_ip_prefix(self._test,
262 self.addr,
263 self.len,
264 self.intf.sw_if_index) &
265 find_route(self._test,
266 self.addr,
267 self.len,
268 table_id=self.table_id,
269 sw_if_index=self.intf.sw_if_index) &
270 find_route(self._test,
271 self.addr,
272 self.host_len,
273 table_id=self.table_id,
274 sw_if_index=self.intf.sw_if_index))
275 else:
276 return (fib_interface_ip_prefix(self._test,
277 self.addr,
278 self.len,
279 self.intf.sw_if_index) &
280 find_route(self._test,
281 self.addr,
282 self.host_len,
283 table_id=self.table_id,
284 sw_if_index=self.intf.sw_if_index))
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700285
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700286 def object_id(self):
Neale Ranns59f71132020-04-08 12:19:38 +0000287 return "interface-ip-%s-%d-%s" % (self.intf,
288 self.table_id,
289 self.prefix)
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700290
291
Neale Rannsec40a7d2020-04-23 07:36:12 +0000292class VppIp6LinkLocalAddress(VppObject):
293
294 def __init__(self, test, intf, addr):
295 self._test = test
296 self.intf = intf
297 self.addr = addr
298
299 def add_vpp_config(self):
300 self._test.vapi.sw_interface_ip6_set_link_local_address(
301 sw_if_index=self.intf.sw_if_index, ip=self.addr)
302 self._test.registry.register(self, self._test.logger)
303 return self
304
305 def remove_vpp_config(self):
306 # link locals can't be removed, only changed
307 pass
308
309 def query_vpp_config(self):
310 # no API to query
311 return False
312
313 def object_id(self):
314 return "ip6-link-local-%s-%s" % (self.intf, self.addr)
315
316
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700317class VppIpInterfaceBind(VppObject):
318
319 def __init__(self, test, intf, table):
320 self._test = test
321 self.intf = intf
322 self.table = table
323
324 def add_vpp_config(self):
325 if self.table.is_ip6:
326 self.intf.set_table_ip6(self.table.table_id)
327 else:
328 self.intf.set_table_ip4(self.table.table_id)
329 self._test.registry.register(self, self._test.logger)
Neale Ranns59f71132020-04-08 12:19:38 +0000330 return self
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700331
332 def remove_vpp_config(self):
333 if 0 == self.table.table_id:
334 return
335 if self.table.is_ip6:
336 self.intf.set_table_ip6(0)
337 else:
338 self.intf.set_table_ip4(0)
339
340 def query_vpp_config(self):
341 if 0 == self.table.table_id:
342 return False
343 return self._test.vapi.sw_interface_get_table(
344 self.intf.sw_if_index,
345 self.table.is_ip6).vrf_id == self.table.table_id
346
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700347 def object_id(self):
348 return "interface-bind-%s-%s" % (self.intf, self.table)
349
350
Paul Vinciguerrae061dad2020-12-04 14:57:51 -0500351class VppMplsLabel:
Neale Ranns31ed7442018-02-23 05:29:09 -0800352 def __init__(self, value, mode=MplsLspMode.PIPE, ttl=64, exp=0):
353 self.value = value
354 self.mode = mode
355 self.ttl = ttl
356 self.exp = exp
357
358 def encode(self):
359 is_uniform = 0 if self.mode is MplsLspMode.PIPE else 1
360 return {'label': self.value,
361 'ttl': self.ttl,
362 'exp': self.exp,
363 'is_uniform': is_uniform}
364
Neale Ranns775f73c2018-12-20 03:01:49 -0800365 def __eq__(self, other):
366 if isinstance(other, self.__class__):
367 return (self.value == other.value and
368 self.ttl == other.ttl and
369 self.exp == other.exp and
370 self.mode == other.mode)
371 elif hasattr(other, 'label'):
372 return (self.value == other.label and
373 self.ttl == other.ttl and
374 self.exp == other.exp and
375 (self.mode == MplsLspMode.UNIFORM) == other.is_uniform)
376 else:
377 return False
378
379 def __ne__(self, other):
380 return not (self == other)
381
Neale Ranns31ed7442018-02-23 05:29:09 -0800382
Paul Vinciguerrae061dad2020-12-04 14:57:51 -0500383class VppFibPathNextHop:
Neale Ranns097fa662018-05-01 05:17:55 -0700384 def __init__(self, addr,
385 via_label=MPLS_LABEL_INVALID,
386 next_hop_id=INVALID_INDEX):
387 self.addr = VppIpAddressUnion(addr)
388 self.via_label = via_label
389 self.obj_id = next_hop_id
390
391 def encode(self):
392 if self.via_label is not MPLS_LABEL_INVALID:
393 return {'via_label': self.via_label}
394 if self.obj_id is not INVALID_INDEX:
395 return {'obj_id': self.obj_id}
396 else:
397 return {'address': self.addr.encode()}
398
399 def proto(self):
400 if self.via_label is MPLS_LABEL_INVALID:
401 return address_proto(self.addr)
402 else:
403 return FibPathProto.FIB_PATH_NH_PROTO_MPLS
404
405 def __eq__(self, other):
406 if not isinstance(other, self.__class__):
407 # try the other instance's __eq__.
408 return NotImplemented
409 return (self.addr == other.addr and
410 self.via_label == other.via_label and
411 self.obj_id == other.obj_id)
412
413
Paul Vinciguerrae061dad2020-12-04 14:57:51 -0500414class VppRoutePath:
Neale Rannsad422ed2016-11-02 14:20:04 +0000415
Klement Sekerada505f62017-01-04 12:58:53 +0100416 def __init__(
417 self,
418 nh_addr,
419 nh_sw_if_index,
420 nh_table_id=0,
421 labels=[],
Neale Rannsfca0c242017-01-13 07:57:46 -0800422 nh_via_label=MPLS_LABEL_INVALID,
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800423 rpf_id=0,
Neale Ranns097fa662018-05-01 05:17:55 -0700424 next_hop_id=INVALID_INDEX,
425 proto=None,
426 flags=FibPathFlags.FIB_PATH_FLAG_NONE,
427 type=FibPathType.FIB_PATH_TYPE_NORMAL):
Neale Ranns177bbdc2016-11-15 09:46:51 +0000428 self.nh_itf = nh_sw_if_index
429 self.nh_table_id = nh_table_id
Neale Rannsad422ed2016-11-02 14:20:04 +0000430 self.nh_labels = labels
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800431 self.weight = 1
432 self.rpf_id = rpf_id
Neale Ranns097fa662018-05-01 05:17:55 -0700433 self.proto = proto
434 self.flags = flags
435 self.type = type
436 self.nh = VppFibPathNextHop(nh_addr, nh_via_label, next_hop_id)
437 if proto is None:
438 self.proto = self.nh.proto()
Neale Ranns31426c62017-05-24 10:32:58 -0700439 else:
Neale Ranns097fa662018-05-01 05:17:55 -0700440 self.proto = proto
Neale Ranns810086d2017-11-05 16:26:46 -0800441 self.next_hop_id = next_hop_id
Neale Ranns177bbdc2016-11-15 09:46:51 +0000442
Neale Ranns097fa662018-05-01 05:17:55 -0700443 def encode_labels(self):
Neale Ranns31ed7442018-02-23 05:29:09 -0800444 lstack = []
445 for l in self.nh_labels:
446 if type(l) == VppMplsLabel:
447 lstack.append(l.encode())
448 else:
449 lstack.append({'label': l,
450 'ttl': 255})
Neale Ranns097fa662018-05-01 05:17:55 -0700451 while (len(lstack) < 16):
452 lstack.append({})
453
Neale Ranns31ed7442018-02-23 05:29:09 -0800454 return lstack
455
Neale Ranns097fa662018-05-01 05:17:55 -0700456 def encode(self):
457 return {'weight': 1,
Neale Ranns2303cb12018-02-21 04:57:17 -0800458 'preference': 0,
459 'table_id': self.nh_table_id,
Neale Ranns097fa662018-05-01 05:17:55 -0700460 'nh': self.nh.encode(),
Neale Ranns2303cb12018-02-21 04:57:17 -0800461 'next_hop_id': self.next_hop_id,
462 'sw_if_index': self.nh_itf,
Neale Ranns097fa662018-05-01 05:17:55 -0700463 'rpf_id': self.rpf_id,
464 'proto': self.proto,
465 'type': self.type,
466 'flags': self.flags,
Neale Ranns2303cb12018-02-21 04:57:17 -0800467 'n_labels': len(self.nh_labels),
Neale Ranns097fa662018-05-01 05:17:55 -0700468 'label_stack': self.encode_labels()}
Neale Ranns2303cb12018-02-21 04:57:17 -0800469
Neale Rannsef90ed02018-09-13 08:45:12 -0700470 def __eq__(self, other):
Neale Ranns775f73c2018-12-20 03:01:49 -0800471 if isinstance(other, self.__class__):
Neale Ranns097fa662018-05-01 05:17:55 -0700472 return self.nh == other.nh
Neale Ranns775f73c2018-12-20 03:01:49 -0800473 elif hasattr(other, 'sw_if_index'):
474 # vl_api_fib_path_t
475 if (len(self.nh_labels) != other.n_labels):
476 return False
477 for i in range(len(self.nh_labels)):
478 if (self.nh_labels[i] != other.label_stack[i]):
479 return False
480 return self.nh_itf == other.sw_if_index
481 else:
482 return False
483
484 def __ne__(self, other):
485 return not (self == other)
Neale Rannsef90ed02018-09-13 08:45:12 -0700486
Neale Ranns177bbdc2016-11-15 09:46:51 +0000487
Neale Ranns5a8123b2017-01-26 01:18:23 -0800488class VppMRoutePath(VppRoutePath):
Neale Ranns32e1c012016-11-22 17:07:28 +0000489
Neale Rannsd792d9c2017-10-21 10:53:20 -0700490 def __init__(self, nh_sw_if_index, flags,
Neale Rannse821ab12017-06-01 07:45:05 -0700491 nh=None,
Neale Ranns097fa662018-05-01 05:17:55 -0700492 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
493 type=FibPathType.FIB_PATH_TYPE_NORMAL,
494 bier_imp=INVALID_INDEX):
Neale Rannse821ab12017-06-01 07:45:05 -0700495 if not nh:
Neale Ranns097fa662018-05-01 05:17:55 -0700496 nh = "::" if proto is FibPathProto.FIB_PATH_NH_PROTO_IP6 \
497 else "0.0.0.0"
Neale Rannse821ab12017-06-01 07:45:05 -0700498 super(VppMRoutePath, self).__init__(nh,
499 nh_sw_if_index,
Neale Ranns097fa662018-05-01 05:17:55 -0700500 proto=proto,
501 type=type,
502 next_hop_id=bier_imp)
Neale Ranns32e1c012016-11-22 17:07:28 +0000503 self.nh_i_flags = flags
Neale Rannsd792d9c2017-10-21 10:53:20 -0700504 self.bier_imp = bier_imp
Neale Ranns32e1c012016-11-22 17:07:28 +0000505
Neale Ranns097fa662018-05-01 05:17:55 -0700506 def encode(self):
507 return {'path': super(VppMRoutePath, self).encode(),
508 'itf_flags': self.nh_i_flags}
509
Neale Ranns32e1c012016-11-22 17:07:28 +0000510
Neale Ranns5a8123b2017-01-26 01:18:23 -0800511class VppIpRoute(VppObject):
Neale Ranns177bbdc2016-11-15 09:46:51 +0000512 """
513 IP Route
514 """
515
516 def __init__(self, test, dest_addr,
Neale Ranns097fa662018-05-01 05:17:55 -0700517 dest_addr_len, paths, table_id=0, register=True):
Neale Ranns177bbdc2016-11-15 09:46:51 +0000518 self._test = test
519 self.paths = paths
Neale Ranns177bbdc2016-11-15 09:46:51 +0000520 self.table_id = table_id
Neale Rannsefd7bc22019-11-11 08:32:34 +0000521 self.prefix = mk_network(dest_addr, dest_addr_len)
Neale Ranns097fa662018-05-01 05:17:55 -0700522 self.register = register
Paul Vinciguerra941da4a2019-06-18 07:57:53 -0400523 self.stats_index = None
Neale Rannsc2ac2352019-07-02 14:33:29 +0000524 self.modified = False
Neale Ranns177bbdc2016-11-15 09:46:51 +0000525
Neale Ranns097fa662018-05-01 05:17:55 -0700526 self.encoded_paths = []
527 for path in self.paths:
528 self.encoded_paths.append(path.encode())
529
530 def __eq__(self, other):
531 if self.table_id == other.table_id and \
532 self.prefix == other.prefix:
533 return True
534 return False
535
536 def modify(self, paths):
Neale Ranns69b7aa42017-03-10 03:04:12 -0800537 self.paths = paths
Neale Ranns097fa662018-05-01 05:17:55 -0700538 self.encoded_paths = []
539 for path in self.paths:
540 self.encoded_paths.append(path.encode())
Neale Rannsc2ac2352019-07-02 14:33:29 +0000541 self.modified = True
Neale Ranns097fa662018-05-01 05:17:55 -0700542
543 self._test.vapi.ip_route_add_del(route={'table_id': self.table_id,
Neale Rannsefd7bc22019-11-11 08:32:34 +0000544 'prefix': self.prefix,
Neale Ranns097fa662018-05-01 05:17:55 -0700545 'n_paths': len(
546 self.encoded_paths),
547 'paths': self.encoded_paths,
548 },
549 is_add=1,
550 is_multipath=0)
Neale Ranns69b7aa42017-03-10 03:04:12 -0800551
Neale Ranns177bbdc2016-11-15 09:46:51 +0000552 def add_vpp_config(self):
Neale Ranns097fa662018-05-01 05:17:55 -0700553 r = self._test.vapi.ip_route_add_del(
554 route={'table_id': self.table_id,
Neale Rannsefd7bc22019-11-11 08:32:34 +0000555 'prefix': self.prefix,
Neale Ranns097fa662018-05-01 05:17:55 -0700556 'n_paths': len(self.encoded_paths),
557 'paths': self.encoded_paths,
558 },
559 is_add=1,
560 is_multipath=0)
Neale Ranns008dbe12018-09-07 09:32:36 -0700561 self.stats_index = r.stats_index
Neale Ranns097fa662018-05-01 05:17:55 -0700562 if self.register:
563 self._test.registry.register(self, self._test.logger)
Neale Ranns9db6ada2019-11-08 12:42:31 +0000564 return self
Neale Ranns177bbdc2016-11-15 09:46:51 +0000565
566 def remove_vpp_config(self):
Neale Rannsc2ac2352019-07-02 14:33:29 +0000567 # there's no need to issue different deletes for modified routes
568 # we do this only to test the two different ways to delete routes
569 # eiter by passing all the paths to remove and mutlipath=1 or
570 # passing no paths and multipath=0
571 if self.modified:
572 self._test.vapi.ip_route_add_del(
573 route={'table_id': self.table_id,
Neale Rannsefd7bc22019-11-11 08:32:34 +0000574 'prefix': self.prefix,
Neale Rannsc2ac2352019-07-02 14:33:29 +0000575 'n_paths': len(
576 self.encoded_paths),
577 'paths': self.encoded_paths},
578 is_add=0,
579 is_multipath=1)
580 else:
581 self._test.vapi.ip_route_add_del(
582 route={'table_id': self.table_id,
Neale Rannsefd7bc22019-11-11 08:32:34 +0000583 'prefix': self.prefix,
Neale Rannsc2ac2352019-07-02 14:33:29 +0000584 'n_paths': 0},
585 is_add=0,
586 is_multipath=0)
Neale Rannsad422ed2016-11-02 14:20:04 +0000587
Neale Ranns5a8123b2017-01-26 01:18:23 -0800588 def query_vpp_config(self):
Neale Rannsb3b2de72017-03-08 05:17:22 -0800589 return find_route(self._test,
Neale Rannsefd7bc22019-11-11 08:32:34 +0000590 self.prefix.network_address,
591 self.prefix.prefixlen,
Neale Ranns097fa662018-05-01 05:17:55 -0700592 self.table_id)
Neale Rannsad422ed2016-11-02 14:20:04 +0000593
Neale Ranns5a8123b2017-01-26 01:18:23 -0800594 def object_id(self):
Neale Rannsefd7bc22019-11-11 08:32:34 +0000595 return ("%s:table-%d-%s" % (
596 'ip6-route' if self.prefix.version == 6 else 'ip-route',
Paul Vinciguerra941da4a2019-06-18 07:57:53 -0400597 self.table_id,
Neale Rannsefd7bc22019-11-11 08:32:34 +0000598 self.prefix))
Neale Ranns5a8123b2017-01-26 01:18:23 -0800599
Neale Ranns008dbe12018-09-07 09:32:36 -0700600 def get_stats_to(self):
601 c = self._test.statistics.get_counter("/net/route/to")
602 return c[0][self.stats_index]
603
604 def get_stats_via(self):
605 c = self._test.statistics.get_counter("/net/route/via")
606 return c[0][self.stats_index]
607
Neale Ranns5a8123b2017-01-26 01:18:23 -0800608
Neale Ranns976b2592019-12-04 06:11:00 +0000609class VppIpRouteV2(VppObject):
610 """
611 IP Route V2
612 """
613
614 def __init__(self, test, dest_addr,
615 dest_addr_len, paths, table_id=0,
616 register=True, src=0):
617 self._test = test
618 self.paths = paths
619 self.table_id = table_id
620 self.prefix = mk_network(dest_addr, dest_addr_len)
621 self.register = register
622 self.stats_index = None
623 self.modified = False
624 self.src = src
625
626 self.encoded_paths = []
627 for path in self.paths:
628 self.encoded_paths.append(path.encode())
629
630 def __eq__(self, other):
631 if self.table_id == other.table_id and \
632 self.prefix == other.prefix:
633 return True
634 return False
635
636 def modify(self, paths):
637 self.paths = paths
638 self.encoded_paths = []
639 for path in self.paths:
640 self.encoded_paths.append(path.encode())
641 self.modified = True
642
643 self._test.vapi.ip_route_add_del_v2(route={'table_id': self.table_id,
644 'prefix': self.prefix,
645 'src': self.src,
646 'n_paths': len(
647 self.encoded_paths),
648 'paths': self.encoded_paths,
649 },
650 is_add=1,
651 is_multipath=0)
652
653 def add_vpp_config(self):
654 r = self._test.vapi.ip_route_add_del_v2(
655 route={'table_id': self.table_id,
656 'prefix': self.prefix,
657 'n_paths': len(self.encoded_paths),
658 'paths': self.encoded_paths,
659 'src': self.src,
660 },
661 is_add=1,
662 is_multipath=0)
663 self.stats_index = r.stats_index
664 if self.register:
665 self._test.registry.register(self, self._test.logger)
666 return self
667
668 def remove_vpp_config(self):
669 # there's no need to issue different deletes for modified routes
670 # we do this only to test the two different ways to delete routes
671 # eiter by passing all the paths to remove and mutlipath=1 or
672 # passing no paths and multipath=0
673 if self.modified:
674 self._test.vapi.ip_route_add_del_v2(
675 route={'table_id': self.table_id,
676 'prefix': self.prefix,
677 'src': self.src,
678 'n_paths': len(
679 self.encoded_paths),
680 'paths': self.encoded_paths},
681 is_add=0,
682 is_multipath=1)
683 else:
684 self._test.vapi.ip_route_add_del_v2(
685 route={'table_id': self.table_id,
686 'prefix': self.prefix,
687 'src': self.src,
688 'n_paths': 0},
689 is_add=0,
690 is_multipath=0)
691
692 def query_vpp_config(self):
693 return find_route(self._test,
694 self.prefix.network_address,
695 self.prefix.prefixlen,
696 self.table_id)
697
698 def object_id(self):
699 return ("%s:table-%d-%s" % (
700 'ip6-route' if self.prefix.version == 6 else 'ip-route',
701 self.table_id,
702 self.prefix))
703
704 def get_stats_to(self):
705 c = self._test.statistics.get_counter("/net/route/to")
706 return c[0][self.stats_index]
707
708 def get_stats_via(self):
709 c = self._test.statistics.get_counter("/net/route/via")
710 return c[0][self.stats_index]
711
712
Neale Ranns5a8123b2017-01-26 01:18:23 -0800713class VppIpMRoute(VppObject):
Neale Ranns32e1c012016-11-22 17:07:28 +0000714 """
715 IP Multicast Route
716 """
717
718 def __init__(self, test, src_addr, grp_addr,
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800719 grp_addr_len, e_flags, paths, table_id=0,
Neale Ranns097fa662018-05-01 05:17:55 -0700720 rpf_id=0):
Neale Ranns32e1c012016-11-22 17:07:28 +0000721 self._test = test
722 self.paths = paths
Neale Ranns32e1c012016-11-22 17:07:28 +0000723 self.table_id = table_id
724 self.e_flags = e_flags
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800725 self.rpf_id = rpf_id
Neale Ranns32e1c012016-11-22 17:07:28 +0000726
Neale Ranns097fa662018-05-01 05:17:55 -0700727 self.prefix = VppIpMPrefix(src_addr, grp_addr, grp_addr_len)
728 self.encoded_paths = []
729 for path in self.paths:
730 self.encoded_paths.append(path.encode())
Neale Ranns32e1c012016-11-22 17:07:28 +0000731
Paul Vinciguerrae64e5ff2020-04-28 00:27:38 -0400732 def encode(self, paths=None):
733 _paths = self.encoded_paths if paths is None else paths
734 return {'table_id': self.table_id,
735 'entry_flags': self.e_flags,
736 'rpf_id': self.rpf_id,
737 'prefix': self.prefix.encode(),
738 'n_paths': len(_paths),
739 'paths': _paths,
740 }
741
Neale Ranns32e1c012016-11-22 17:07:28 +0000742 def add_vpp_config(self):
Paul Vinciguerrae64e5ff2020-04-28 00:27:38 -0400743 r = self._test.vapi.ip_mroute_add_del(route=self.encode(),
744 is_multipath=1,
Neale Ranns097fa662018-05-01 05:17:55 -0700745 is_add=1)
746 self.stats_index = r.stats_index
Neale Ranns5a8123b2017-01-26 01:18:23 -0800747 self._test.registry.register(self, self._test.logger)
Neale Ranns9db6ada2019-11-08 12:42:31 +0000748 return self
Neale Ranns32e1c012016-11-22 17:07:28 +0000749
750 def remove_vpp_config(self):
Paul Vinciguerrae64e5ff2020-04-28 00:27:38 -0400751 self._test.vapi.ip_mroute_add_del(route=self.encode(),
752 is_multipath=1,
Neale Ranns097fa662018-05-01 05:17:55 -0700753 is_add=0)
Neale Ranns32e1c012016-11-22 17:07:28 +0000754
755 def update_entry_flags(self, flags):
756 self.e_flags = flags
Paul Vinciguerrae64e5ff2020-04-28 00:27:38 -0400757 self._test.vapi.ip_mroute_add_del(route=self.encode(paths=[]),
758 is_multipath=1,
Neale Ranns097fa662018-05-01 05:17:55 -0700759 is_add=1)
Neale Ranns32e1c012016-11-22 17:07:28 +0000760
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800761 def update_rpf_id(self, rpf_id):
762 self.rpf_id = rpf_id
Paul Vinciguerrae64e5ff2020-04-28 00:27:38 -0400763 self._test.vapi.ip_mroute_add_del(route=self.encode(paths=[]),
764 is_multipath=1,
Neale Ranns097fa662018-05-01 05:17:55 -0700765 is_add=1)
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800766
Neale Ranns32e1c012016-11-22 17:07:28 +0000767 def update_path_flags(self, itf, flags):
Neale Ranns097fa662018-05-01 05:17:55 -0700768 for p in range(len(self.paths)):
769 if self.paths[p].nh_itf == itf:
770 self.paths[p].nh_i_flags = flags
Paul Vinciguerra6230b9d2020-04-28 11:23:31 -0400771 self.encoded_paths[p] = self.paths[p].encode()
772 break
Neale Ranns097fa662018-05-01 05:17:55 -0700773
Paul Vinciguerrae64e5ff2020-04-28 00:27:38 -0400774 self._test.vapi.ip_mroute_add_del(
775 route=self.encode(
776 paths=[self.encoded_paths[p]]),
777 is_add=1,
778 is_multipath=0)
Neale Ranns32e1c012016-11-22 17:07:28 +0000779
Neale Ranns5a8123b2017-01-26 01:18:23 -0800780 def query_vpp_config(self):
Neale Ranns947ea622018-06-07 23:48:20 -0700781 return find_mroute(self._test,
Neale Ranns097fa662018-05-01 05:17:55 -0700782 self.prefix.gaddr,
783 self.prefix.saddr,
784 self.prefix.length,
785 self.table_id)
Neale Ranns32e1c012016-11-22 17:07:28 +0000786
Neale Ranns5a8123b2017-01-26 01:18:23 -0800787 def object_id(self):
Neale Ranns097fa662018-05-01 05:17:55 -0700788 return ("%d:(%s,%s/%d)" % (self.table_id,
789 self.prefix.saddr,
790 self.prefix.gaddr,
791 self.prefix.length))
Neale Ranns5a8123b2017-01-26 01:18:23 -0800792
Neale Ranns28c142e2018-09-07 09:37:07 -0700793 def get_stats(self):
794 c = self._test.statistics.get_counter("/net/mroute")
795 return c[0][self.stats_index]
796
Neale Ranns5a8123b2017-01-26 01:18:23 -0800797
Paul Vinciguerrae061dad2020-12-04 14:57:51 -0500798class VppMFibSignal:
Neale Ranns32e1c012016-11-22 17:07:28 +0000799 def __init__(self, test, route, interface, packet):
800 self.route = route
801 self.interface = interface
802 self.packet = packet
803 self.test = test
804
805 def compare(self, signal):
806 self.test.assertEqual(self.interface, signal.sw_if_index)
807 self.test.assertEqual(self.route.table_id, signal.table_id)
Neale Ranns097fa662018-05-01 05:17:55 -0700808 self.test.assertEqual(self.route.prefix, signal.prefix)
Neale Ranns32e1c012016-11-22 17:07:28 +0000809
810
Neale Ranns5a8123b2017-01-26 01:18:23 -0800811class VppMplsIpBind(VppObject):
Neale Rannsad422ed2016-11-02 14:20:04 +0000812 """
813 MPLS to IP Binding
814 """
815
Neale Ranns5a8123b2017-01-26 01:18:23 -0800816 def __init__(self, test, local_label, dest_addr, dest_addr_len,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700817 table_id=0, ip_table_id=0, is_ip6=0):
Neale Rannsad422ed2016-11-02 14:20:04 +0000818 self._test = test
Neale Rannsad422ed2016-11-02 14:20:04 +0000819 self.dest_addr_len = dest_addr_len
Neale Rannsf12a83f2017-04-18 09:09:40 -0700820 self.dest_addr = dest_addr
Neale Ranns097fa662018-05-01 05:17:55 -0700821 self.ip_addr = ip_address(text_type(dest_addr))
Neale Rannsad422ed2016-11-02 14:20:04 +0000822 self.local_label = local_label
Neale Ranns5a8123b2017-01-26 01:18:23 -0800823 self.table_id = table_id
824 self.ip_table_id = ip_table_id
Neale Rannsefd7bc22019-11-11 08:32:34 +0000825 self.prefix = mk_network(dest_addr, dest_addr_len)
Neale Rannsad422ed2016-11-02 14:20:04 +0000826
827 def add_vpp_config(self):
828 self._test.vapi.mpls_ip_bind_unbind(self.local_label,
Neale Rannsefd7bc22019-11-11 08:32:34 +0000829 self.prefix,
Neale Ranns5a8123b2017-01-26 01:18:23 -0800830 table_id=self.table_id,
Neale Ranns097fa662018-05-01 05:17:55 -0700831 ip_table_id=self.ip_table_id)
Neale Ranns5a8123b2017-01-26 01:18:23 -0800832 self._test.registry.register(self, self._test.logger)
Neale Rannsad422ed2016-11-02 14:20:04 +0000833
834 def remove_vpp_config(self):
835 self._test.vapi.mpls_ip_bind_unbind(self.local_label,
Neale Rannsefd7bc22019-11-11 08:32:34 +0000836 self.prefix,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700837 table_id=self.table_id,
838 ip_table_id=self.ip_table_id,
Neale Ranns097fa662018-05-01 05:17:55 -0700839 is_bind=0)
Neale Rannsad422ed2016-11-02 14:20:04 +0000840
Neale Ranns5a8123b2017-01-26 01:18:23 -0800841 def query_vpp_config(self):
Neale Ranns097fa662018-05-01 05:17:55 -0700842 dump = self._test.vapi.mpls_route_dump(self.table_id)
Neale Ranns5a8123b2017-01-26 01:18:23 -0800843 for e in dump:
Neale Ranns097fa662018-05-01 05:17:55 -0700844 if self.local_label == e.mr_route.mr_label \
845 and self.table_id == e.mr_route.mr_table_id:
Neale Ranns5a8123b2017-01-26 01:18:23 -0800846 return True
847 return False
Neale Rannsad422ed2016-11-02 14:20:04 +0000848
Neale Ranns5a8123b2017-01-26 01:18:23 -0800849 def object_id(self):
850 return ("%d:%s binds %d:%s/%d"
851 % (self.table_id,
852 self.local_label,
853 self.ip_table_id,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700854 self.dest_addr,
Neale Ranns5a8123b2017-01-26 01:18:23 -0800855 self.dest_addr_len))
856
857
Neale Ranns15002542017-09-10 04:39:11 -0700858class VppMplsTable(VppObject):
859
860 def __init__(self,
861 test,
862 table_id):
863 self._test = test
864 self.table_id = table_id
865
866 def add_vpp_config(self):
867 self._test.vapi.mpls_table_add_del(
868 self.table_id,
869 is_add=1)
870 self._test.registry.register(self, self._test.logger)
871
872 def remove_vpp_config(self):
873 self._test.vapi.mpls_table_add_del(
874 self.table_id,
875 is_add=0)
876
877 def query_vpp_config(self):
Neale Ranns097fa662018-05-01 05:17:55 -0700878 dump = self._test.vapi.mpls_table_dump()
879 for d in dump:
880 if d.mt_table.mt_table_id == self.table_id:
881 return True
Neale Ranns15002542017-09-10 04:39:11 -0700882 return False
883
Neale Ranns15002542017-09-10 04:39:11 -0700884 def object_id(self):
885 return ("table-mpls-%d" % (self.table_id))
886
887
Neale Ranns5a8123b2017-01-26 01:18:23 -0800888class VppMplsRoute(VppObject):
Neale Rannsad422ed2016-11-02 14:20:04 +0000889 """
Neale Ranns5a8123b2017-01-26 01:18:23 -0800890 MPLS Route/LSP
Neale Rannsad422ed2016-11-02 14:20:04 +0000891 """
892
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800893 def __init__(self, test, local_label, eos_bit, paths, table_id=0,
Neale Ranns097fa662018-05-01 05:17:55 -0700894 is_multicast=0,
895 eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP4):
Neale Rannsad422ed2016-11-02 14:20:04 +0000896 self._test = test
897 self.paths = paths
898 self.local_label = local_label
899 self.eos_bit = eos_bit
Neale Ranns097fa662018-05-01 05:17:55 -0700900 self.eos_proto = eos_proto
Neale Rannsad422ed2016-11-02 14:20:04 +0000901 self.table_id = table_id
Neale Ranns0f26c5a2017-03-01 15:12:11 -0800902 self.is_multicast = is_multicast
Neale Rannsad422ed2016-11-02 14:20:04 +0000903
904 def add_vpp_config(self):
Neale Ranns097fa662018-05-01 05:17:55 -0700905 paths = []
Neale Rannsad422ed2016-11-02 14:20:04 +0000906 for path in self.paths:
Neale Ranns097fa662018-05-01 05:17:55 -0700907 paths.append(path.encode())
Neale Ranns31ed7442018-02-23 05:29:09 -0800908
Neale Ranns097fa662018-05-01 05:17:55 -0700909 r = self._test.vapi.mpls_route_add_del(self.table_id,
910 self.local_label,
911 self.eos_bit,
912 self.eos_proto,
913 self.is_multicast,
914 paths, 1, 0)
Neale Ranns008dbe12018-09-07 09:32:36 -0700915 self.stats_index = r.stats_index
Neale Ranns5a8123b2017-01-26 01:18:23 -0800916 self._test.registry.register(self, self._test.logger)
Neale Rannsad422ed2016-11-02 14:20:04 +0000917
918 def remove_vpp_config(self):
Neale Ranns097fa662018-05-01 05:17:55 -0700919 paths = []
Neale Rannsad422ed2016-11-02 14:20:04 +0000920 for path in self.paths:
Neale Ranns097fa662018-05-01 05:17:55 -0700921 paths.append(path.encode())
922
923 self._test.vapi.mpls_route_add_del(self.table_id,
924 self.local_label,
925 self.eos_bit,
926 self.eos_proto,
927 self.is_multicast,
928 paths, 0, 0)
Neale Ranns5a8123b2017-01-26 01:18:23 -0800929
930 def query_vpp_config(self):
Neale Ranns775f73c2018-12-20 03:01:49 -0800931 return find_mpls_route(self._test, self.table_id,
932 self.local_label, self.eos_bit)
Neale Ranns5a8123b2017-01-26 01:18:23 -0800933
Neale Ranns5a8123b2017-01-26 01:18:23 -0800934 def object_id(self):
Paul Vinciguerra941da4a2019-06-18 07:57:53 -0400935 return ("mpls-route-%d:%s/%d"
Neale Ranns5a8123b2017-01-26 01:18:23 -0800936 % (self.table_id,
937 self.local_label,
Ole Troan9a475372019-03-05 16:58:24 +0100938 20 + self.eos_bit))
Neale Ranns008dbe12018-09-07 09:32:36 -0700939
940 def get_stats_to(self):
941 c = self._test.statistics.get_counter("/net/route/to")
942 return c[0][self.stats_index]
943
944 def get_stats_via(self):
945 c = self._test.statistics.get_counter("/net/route/via")
946 return c[0][self.stats_index]