test/vpp_ip.py: Correct usage of 'is'
[vpp.git] / test / vpp_ip_route.py
1 """
2   IP Routes
3
4   object abstractions for representing IP routes in VPP
5 """
6
7 from vpp_object import *
8 from socket import inet_pton, inet_ntop, AF_INET, AF_INET6
9 from vpp_ip import *
10
11 # from vnet/vnet/mpls/mpls_types.h
12 MPLS_IETF_MAX_LABEL = 0xfffff
13 MPLS_LABEL_INVALID = MPLS_IETF_MAX_LABEL + 1
14
15
16 class MRouteItfFlags:
17     MFIB_ITF_FLAG_NONE = 0
18     MFIB_ITF_FLAG_NEGATE_SIGNAL = 1
19     MFIB_ITF_FLAG_ACCEPT = 2
20     MFIB_ITF_FLAG_FORWARD = 4
21     MFIB_ITF_FLAG_SIGNAL_PRESENT = 8
22     MFIB_ITF_FLAG_INTERNAL_COPY = 16
23
24
25 class MRouteEntryFlags:
26     MFIB_ENTRY_FLAG_NONE = 0
27     MFIB_ENTRY_FLAG_SIGNAL = 1
28     MFIB_ENTRY_FLAG_DROP = 2
29     MFIB_ENTRY_FLAG_CONNECTED = 4
30     MFIB_ENTRY_FLAG_INHERIT_ACCEPT = 8
31
32
33 class MplsLspMode:
34     PIPE = 0
35     UNIFORM = 1
36
37
38 def ip_to_dpo_proto(addr):
39     if addr.version is 6:
40         return DpoProto.DPO_PROTO_IP6
41     else:
42         return DpoProto.DPO_PROTO_IP4
43
44
45 def find_route(test, ip_addr, len, table_id=0, inet=AF_INET):
46     if inet == AF_INET:
47         s = 4
48         routes = test.vapi.ip_fib_dump()
49     else:
50         s = 16
51         routes = test.vapi.ip6_fib_dump()
52
53     route_addr = inet_pton(inet, ip_addr)
54     for e in routes:
55         if route_addr == e.address[:s] \
56            and len == e.address_length \
57            and table_id == e.table_id:
58             return True
59     return False
60
61
62 def find_mroute(test, grp_addr, src_addr, grp_addr_len,
63                 table_id=0, inet=AF_INET):
64     if inet == AF_INET:
65         s = 4
66         routes = test.vapi.ip_mfib_dump()
67     else:
68         s = 16
69         routes = test.vapi.ip6_mfib_dump()
70     gaddr = inet_pton(inet, grp_addr)
71     saddr = inet_pton(inet, src_addr)
72     for e in routes:
73         if gaddr == e.grp_address[:s] \
74            and grp_addr_len == e.address_length \
75            and saddr == e.src_address[:s] \
76            and table_id == e.table_id:
77             return True
78     return False
79
80
81 def fib_interface_ip_prefix(test, address, length, sw_if_index):
82     vp = VppIpPrefix(address, length)
83     addrs = test.vapi.ip_address_dump(sw_if_index, is_ipv6=vp.is_ip6)
84
85     if vp.is_ip6:
86         n = 16
87     else:
88         n = 4
89
90     for a in addrs:
91         if a.prefix_length == length and \
92            a.sw_if_index == sw_if_index and \
93            a.ip[:n] == vp.bytes:
94             return True
95     return False
96
97
98 class VppIpTable(VppObject):
99
100     def __init__(self,
101                  test,
102                  table_id,
103                  is_ip6=0):
104         self._test = test
105         self.table_id = table_id
106         self.is_ip6 = is_ip6
107
108     def add_vpp_config(self):
109         self._test.vapi.ip_table_add_del(
110             self.table_id,
111             is_ipv6=self.is_ip6,
112             is_add=1)
113         self._test.registry.register(self, self._test.logger)
114
115     def remove_vpp_config(self):
116         self._test.vapi.ip_table_add_del(
117             self.table_id,
118             is_ipv6=self.is_ip6,
119             is_add=0)
120
121     def query_vpp_config(self):
122         if self.table_id == 0:
123             # the default table always exists
124             return False
125         # find the default route
126         return find_route(self._test,
127                           "::" if self.is_ip6 else "0.0.0.0",
128                           0,
129                           self.table_id,
130                           inet=AF_INET6 if self.is_ip6 == 1 else AF_INET)
131
132     def __str__(self):
133         return self.object_id()
134
135     def object_id(self):
136         return ("table-%s-%d" %
137                 ("v6" if self.is_ip6 == 1 else "v4",
138                  self.table_id))
139
140
141 class VppIpInterfaceAddress(VppObject):
142
143     def __init__(self, test, intf, addr, len):
144         self._test = test
145         self.intf = intf
146         self.prefix = VppIpPrefix(addr, len)
147
148     def add_vpp_config(self):
149         self._test.vapi.sw_interface_add_del_address(
150             self.intf.sw_if_index,
151             self.prefix.bytes,
152             self.prefix.length,
153             is_add=1,
154             is_ipv6=self.prefix.is_ip6)
155         self._test.registry.register(self, self._test.logger)
156
157     def remove_vpp_config(self):
158         self._test.vapi.sw_interface_add_del_address(
159             self.intf.sw_if_index,
160             self.prefix.bytes,
161             self.prefix.length,
162             is_add=0,
163             is_ipv6=self.prefix.is_ip6)
164
165     def query_vpp_config(self):
166         return fib_interface_ip_prefix(self._test,
167                                        self.prefix.address,
168                                        self.prefix.length,
169                                        self.intf.sw_if_index)
170
171     def __str__(self):
172         return self.object_id()
173
174     def object_id(self):
175         return "interface-ip-%s-%s" % (self.intf, self.prefix)
176
177
178 class VppIpInterfaceBind(VppObject):
179
180     def __init__(self, test, intf, table):
181         self._test = test
182         self.intf = intf
183         self.table = table
184
185     def add_vpp_config(self):
186         if self.table.is_ip6:
187             self.intf.set_table_ip6(self.table.table_id)
188         else:
189             self.intf.set_table_ip4(self.table.table_id)
190         self._test.registry.register(self, self._test.logger)
191
192     def remove_vpp_config(self):
193         if 0 == self.table.table_id:
194             return
195         if self.table.is_ip6:
196             self.intf.set_table_ip6(0)
197         else:
198             self.intf.set_table_ip4(0)
199
200     def query_vpp_config(self):
201         if 0 == self.table.table_id:
202             return False
203         return self._test.vapi.sw_interface_get_table(
204             self.intf.sw_if_index,
205             self.table.is_ip6).vrf_id == self.table.table_id
206
207     def __str__(self):
208         return self.object_id()
209
210     def object_id(self):
211         return "interface-bind-%s-%s" % (self.intf, self.table)
212
213
214 class VppMplsLabel(object):
215     def __init__(self, value, mode=MplsLspMode.PIPE, ttl=64, exp=0):
216         self.value = value
217         self.mode = mode
218         self.ttl = ttl
219         self.exp = exp
220
221     def encode(self):
222         is_uniform = 0 if self.mode is MplsLspMode.PIPE else 1
223         return {'label': self.value,
224                 'ttl': self.ttl,
225                 'exp': self.exp,
226                 'is_uniform': is_uniform}
227
228
229 class VppRoutePath(object):
230
231     def __init__(
232             self,
233             nh_addr,
234             nh_sw_if_index,
235             nh_table_id=0,
236             labels=[],
237             nh_via_label=MPLS_LABEL_INVALID,
238             rpf_id=0,
239             is_interface_rx=0,
240             is_resolve_host=0,
241             is_resolve_attached=0,
242             is_source_lookup=0,
243             is_udp_encap=0,
244             is_dvr=0,
245             next_hop_id=0xffffffff,
246             proto=DpoProto.DPO_PROTO_IP4):
247         self.nh_itf = nh_sw_if_index
248         self.nh_table_id = nh_table_id
249         self.nh_via_label = nh_via_label
250         self.nh_labels = labels
251         self.weight = 1
252         self.rpf_id = rpf_id
253         self.proto = proto
254         if self.proto is DpoProto.DPO_PROTO_IP6:
255             self.nh_addr = inet_pton(AF_INET6, nh_addr)
256         elif self.proto is DpoProto.DPO_PROTO_IP4:
257             self.nh_addr = inet_pton(AF_INET, nh_addr)
258         else:
259             self.nh_addr = inet_pton(AF_INET6, "::")
260         self.is_resolve_host = is_resolve_host
261         self.is_resolve_attached = is_resolve_attached
262         self.is_interface_rx = is_interface_rx
263         self.is_source_lookup = is_source_lookup
264         self.is_rpf_id = 0
265         if rpf_id != 0:
266             self.is_rpf_id = 1
267             self.nh_itf = rpf_id
268         self.is_udp_encap = is_udp_encap
269         self.next_hop_id = next_hop_id
270         self.is_dvr = is_dvr
271
272     def encode_labels(self):
273         lstack = []
274         for l in self.nh_labels:
275             if type(l) == VppMplsLabel:
276                 lstack.append(l.encode())
277             else:
278                 lstack.append({'label': l,
279                                'ttl': 255})
280         return lstack
281
282     def encode(self):
283         return {'next_hop': self.nh_addr,
284                 'weight': 1,
285                 'afi': 0,
286                 'preference': 0,
287                 'table_id': self.nh_table_id,
288                 'next_hop_id': self.next_hop_id,
289                 'sw_if_index': self.nh_itf,
290                 'afi': self.proto,
291                 'is_udp_encap': self.is_udp_encap,
292                 'n_labels': len(self.nh_labels),
293                 'label_stack': self.encode_labels()}
294
295     def __eq__(self, other):
296         return self.nh_addr == other.nh_addr
297
298
299 class VppMRoutePath(VppRoutePath):
300
301     def __init__(self, nh_sw_if_index, flags,
302                  nh=None,
303                  proto=DpoProto.DPO_PROTO_IP4,
304                  bier_imp=0):
305         if not nh:
306             nh = "::" if proto is DpoProto.DPO_PROTO_IP6 else "0.0.0.0"
307         super(VppMRoutePath, self).__init__(nh,
308                                             nh_sw_if_index,
309                                             proto=proto)
310         self.nh_i_flags = flags
311         self.bier_imp = bier_imp
312
313
314 class VppIpRoute(VppObject):
315     """
316     IP Route
317     """
318
319     def __init__(self, test, dest_addr,
320                  dest_addr_len, paths, table_id=0, is_ip6=0, is_local=0,
321                  is_unreach=0, is_prohibit=0, is_drop=0):
322         self._test = test
323         self.paths = paths
324         self.dest_addr_len = dest_addr_len
325         self.table_id = table_id
326         self.is_ip6 = is_ip6
327         self.is_local = is_local
328         self.is_unreach = is_unreach
329         self.is_prohibit = is_prohibit
330         self.is_drop = is_drop
331         self.dest_addr_p = dest_addr
332         if is_ip6:
333             self.dest_addr = inet_pton(AF_INET6, dest_addr)
334         else:
335             self.dest_addr = inet_pton(AF_INET, dest_addr)
336
337     def modify(self, paths, is_local=0,
338                is_unreach=0, is_prohibit=0):
339         self.paths = paths
340         self.is_local = is_local
341         self.is_unreach = is_unreach
342         self.is_prohibit = is_prohibit
343
344     def add_vpp_config(self):
345         if self.is_local or self.is_unreach or \
346            self.is_prohibit or self.is_drop:
347             r = self._test.vapi.ip_add_del_route(
348                 self.dest_addr,
349                 self.dest_addr_len,
350                 inet_pton(AF_INET6, "::"),
351                 0xffffffff,
352                 is_local=self.is_local,
353                 is_unreach=self.is_unreach,
354                 is_prohibit=self.is_prohibit,
355                 is_drop=self.is_drop,
356                 table_id=self.table_id,
357                 is_ipv6=self.is_ip6)
358         else:
359             for path in self.paths:
360                 lstack = path.encode_labels()
361
362                 r = self._test.vapi.ip_add_del_route(
363                     self.dest_addr,
364                     self.dest_addr_len,
365                     path.nh_addr,
366                     path.nh_itf,
367                     table_id=self.table_id,
368                     next_hop_out_label_stack=lstack,
369                     next_hop_n_out_labels=len(lstack),
370                     next_hop_via_label=path.nh_via_label,
371                     next_hop_table_id=path.nh_table_id,
372                     next_hop_id=path.next_hop_id,
373                     is_ipv6=self.is_ip6,
374                     is_dvr=path.is_dvr,
375                     is_resolve_host=path.is_resolve_host,
376                     is_resolve_attached=path.is_resolve_attached,
377                     is_source_lookup=path.is_source_lookup,
378                     is_udp_encap=path.is_udp_encap,
379                     is_multipath=1 if len(self.paths) > 1 else 0)
380         self.stats_index = r.stats_index
381         self._test.registry.register(self, self._test.logger)
382
383     def remove_vpp_config(self):
384         if self.is_local or self.is_unreach or \
385            self.is_prohibit or self.is_drop:
386             self._test.vapi.ip_add_del_route(
387                 self.dest_addr,
388                 self.dest_addr_len,
389                 inet_pton(AF_INET6, "::"),
390                 0xffffffff,
391                 is_local=self.is_local,
392                 is_unreach=self.is_unreach,
393                 is_prohibit=self.is_prohibit,
394                 is_add=0,
395                 table_id=self.table_id,
396                 is_ipv6=self.is_ip6)
397         else:
398             for path in self.paths:
399                 self._test.vapi.ip_add_del_route(
400                     self.dest_addr,
401                     self.dest_addr_len,
402                     path.nh_addr,
403                     path.nh_itf,
404                     table_id=self.table_id,
405                     next_hop_table_id=path.nh_table_id,
406                     next_hop_via_label=path.nh_via_label,
407                     next_hop_id=path.next_hop_id,
408                     is_add=0,
409                     is_udp_encap=path.is_udp_encap,
410                     is_ipv6=self.is_ip6,
411                     is_dvr=path.is_dvr)
412
413     def query_vpp_config(self):
414         return find_route(self._test,
415                           self.dest_addr_p,
416                           self.dest_addr_len,
417                           self.table_id,
418                           inet=AF_INET6 if self.is_ip6 == 1 else AF_INET)
419
420     def __str__(self):
421         return self.object_id()
422
423     def object_id(self):
424         return ("%d:%s/%d"
425                 % (self.table_id,
426                    self.dest_addr_p,
427                    self.dest_addr_len))
428
429     def get_stats_to(self):
430         c = self._test.statistics.get_counter("/net/route/to")
431         return c[0][self.stats_index]
432
433     def get_stats_via(self):
434         c = self._test.statistics.get_counter("/net/route/via")
435         return c[0][self.stats_index]
436
437
438 class VppIpMRoute(VppObject):
439     """
440     IP Multicast Route
441     """
442
443     def __init__(self, test, src_addr, grp_addr,
444                  grp_addr_len, e_flags, paths, table_id=0,
445                  rpf_id=0, is_ip6=0):
446         self._test = test
447         self.paths = paths
448         self.grp_addr_len = grp_addr_len
449         self.table_id = table_id
450         self.e_flags = e_flags
451         self.is_ip6 = is_ip6
452         self.rpf_id = rpf_id
453
454         self.grp_addr_p = grp_addr
455         self.src_addr_p = src_addr
456         if is_ip6:
457             self.grp_addr = inet_pton(AF_INET6, grp_addr)
458             self.src_addr = inet_pton(AF_INET6, src_addr)
459         else:
460             self.grp_addr = inet_pton(AF_INET, grp_addr)
461             self.src_addr = inet_pton(AF_INET, src_addr)
462
463     def add_vpp_config(self):
464         for path in self.paths:
465             r = self._test.vapi.ip_mroute_add_del(self.src_addr,
466                                                   self.grp_addr,
467                                                   self.grp_addr_len,
468                                                   self.e_flags,
469                                                   path.proto,
470                                                   path.nh_itf,
471                                                   path.nh_addr,
472                                                   path.nh_i_flags,
473                                                   bier_imp=path.bier_imp,
474                                                   rpf_id=self.rpf_id,
475                                                   table_id=self.table_id,
476                                                   is_ipv6=self.is_ip6)
477             self.stats_index = r.stats_index
478         self._test.registry.register(self, self._test.logger)
479
480     def remove_vpp_config(self):
481         for path in self.paths:
482             self._test.vapi.ip_mroute_add_del(self.src_addr,
483                                               self.grp_addr,
484                                               self.grp_addr_len,
485                                               self.e_flags,
486                                               path.proto,
487                                               path.nh_itf,
488                                               path.nh_addr,
489                                               path.nh_i_flags,
490                                               table_id=self.table_id,
491                                               bier_imp=path.bier_imp,
492                                               is_add=0,
493                                               is_ipv6=self.is_ip6)
494
495     def update_entry_flags(self, flags):
496         self.e_flags = flags
497         self._test.vapi.ip_mroute_add_del(self.src_addr,
498                                           self.grp_addr,
499                                           self.grp_addr_len,
500                                           self.e_flags,
501                                           0,
502                                           0xffffffff,
503                                           "",
504                                           0,
505                                           table_id=self.table_id,
506                                           is_ipv6=self.is_ip6)
507
508     def update_rpf_id(self, rpf_id):
509         self.rpf_id = rpf_id
510         self._test.vapi.ip_mroute_add_del(self.src_addr,
511                                           self.grp_addr,
512                                           self.grp_addr_len,
513                                           self.e_flags,
514                                           0,
515                                           0xffffffff,
516                                           "",
517                                           0,
518                                           rpf_id=self.rpf_id,
519                                           table_id=self.table_id,
520                                           is_ipv6=self.is_ip6)
521
522     def update_path_flags(self, itf, flags):
523         for path in self.paths:
524             if path.nh_itf == itf:
525                 path.nh_i_flags = flags
526                 break
527         self._test.vapi.ip_mroute_add_del(self.src_addr,
528                                           self.grp_addr,
529                                           self.grp_addr_len,
530                                           self.e_flags,
531                                           path.proto,
532                                           path.nh_itf,
533                                           path.nh_addr,
534                                           path.nh_i_flags,
535                                           table_id=self.table_id,
536                                           is_ipv6=self.is_ip6)
537
538     def query_vpp_config(self):
539         return find_mroute(self._test,
540                            self.grp_addr_p,
541                            self.src_addr_p,
542                            self.grp_addr_len,
543                            self.table_id,
544                            inet=AF_INET6 if self.is_ip6 == 1 else AF_INET)
545
546     def __str__(self):
547         return self.object_id()
548
549     def object_id(self):
550         if self.is_ip6:
551             return ("%d:(%s,%s/%d)"
552                     % (self.table_id,
553                        inet_ntop(AF_INET6, self.src_addr),
554                        inet_ntop(AF_INET6, self.grp_addr),
555                        self.grp_addr_len))
556         else:
557             return ("%d:(%s,%s/%d)"
558                     % (self.table_id,
559                        inet_ntop(AF_INET, self.src_addr),
560                        inet_ntop(AF_INET, self.grp_addr),
561                        self.grp_addr_len))
562
563     def get_stats(self):
564         c = self._test.statistics.get_counter("/net/mroute")
565         return c[0][self.stats_index]
566
567
568 class VppMFibSignal(object):
569     def __init__(self, test, route, interface, packet):
570         self.route = route
571         self.interface = interface
572         self.packet = packet
573         self.test = test
574
575     def compare(self, signal):
576         self.test.assertEqual(self.interface, signal.sw_if_index)
577         self.test.assertEqual(self.route.table_id, signal.table_id)
578         self.test.assertEqual(self.route.grp_addr_len,
579                               signal.grp_address_len)
580         for i in range(self.route.grp_addr_len / 8):
581             self.test.assertEqual(self.route.grp_addr[i],
582                                   signal.grp_address[i])
583         if (self.route.grp_addr_len > 32):
584             for i in range(4):
585                 self.test.assertEqual(self.route.src_addr[i],
586                                       signal.src_address[i])
587
588
589 class VppMplsIpBind(VppObject):
590     """
591     MPLS to IP Binding
592     """
593
594     def __init__(self, test, local_label, dest_addr, dest_addr_len,
595                  table_id=0, ip_table_id=0, is_ip6=0):
596         self._test = test
597         self.dest_addr_len = dest_addr_len
598         self.dest_addr = dest_addr
599         self.local_label = local_label
600         self.table_id = table_id
601         self.ip_table_id = ip_table_id
602         self.is_ip6 = is_ip6
603         if is_ip6:
604             self.dest_addrn = inet_pton(AF_INET6, dest_addr)
605         else:
606             self.dest_addrn = inet_pton(AF_INET, dest_addr)
607
608     def add_vpp_config(self):
609         self._test.vapi.mpls_ip_bind_unbind(self.local_label,
610                                             self.dest_addrn,
611                                             self.dest_addr_len,
612                                             table_id=self.table_id,
613                                             ip_table_id=self.ip_table_id,
614                                             is_ip4=(self.is_ip6 == 0))
615         self._test.registry.register(self, self._test.logger)
616
617     def remove_vpp_config(self):
618         self._test.vapi.mpls_ip_bind_unbind(self.local_label,
619                                             self.dest_addrn,
620                                             self.dest_addr_len,
621                                             table_id=self.table_id,
622                                             ip_table_id=self.ip_table_id,
623                                             is_bind=0,
624                                             is_ip4=(self.is_ip6 == 0))
625
626     def query_vpp_config(self):
627         dump = self._test.vapi.mpls_fib_dump()
628         for e in dump:
629             if self.local_label == e.label \
630                and self.table_id == e.table_id:
631                 return True
632         return False
633
634     def __str__(self):
635         return self.object_id()
636
637     def object_id(self):
638         return ("%d:%s binds %d:%s/%d"
639                 % (self.table_id,
640                    self.local_label,
641                    self.ip_table_id,
642                    self.dest_addr,
643                    self.dest_addr_len))
644
645
646 class VppMplsTable(VppObject):
647
648     def __init__(self,
649                  test,
650                  table_id):
651         self._test = test
652         self.table_id = table_id
653
654     def add_vpp_config(self):
655         self._test.vapi.mpls_table_add_del(
656             self.table_id,
657             is_add=1)
658         self._test.registry.register(self, self._test.logger)
659
660     def remove_vpp_config(self):
661         self._test.vapi.mpls_table_add_del(
662             self.table_id,
663             is_add=0)
664
665     def query_vpp_config(self):
666         # find the default route
667         dump = self._test.vapi.mpls_fib_dump()
668         if len(dump):
669             return True
670         return False
671
672     def __str__(self):
673         return self.object_id()
674
675     def object_id(self):
676         return ("table-mpls-%d" % (self.table_id))
677
678
679 class VppMplsRoute(VppObject):
680     """
681     MPLS Route/LSP
682     """
683
684     def __init__(self, test, local_label, eos_bit, paths, table_id=0,
685                  is_multicast=0):
686         self._test = test
687         self.paths = paths
688         self.local_label = local_label
689         self.eos_bit = eos_bit
690         self.table_id = table_id
691         self.is_multicast = is_multicast
692
693     def add_vpp_config(self):
694         is_multipath = len(self.paths) > 1
695         for path in self.paths:
696             lstack = path.encode_labels()
697
698             r = self._test.vapi.mpls_route_add_del(
699                 self.local_label,
700                 self.eos_bit,
701                 path.proto,
702                 path.nh_addr,
703                 path.nh_itf,
704                 is_multicast=self.is_multicast,
705                 is_multipath=is_multipath,
706                 table_id=self.table_id,
707                 is_interface_rx=path.is_interface_rx,
708                 is_rpf_id=path.is_rpf_id,
709                 next_hop_out_label_stack=lstack,
710                 next_hop_n_out_labels=len(lstack),
711                 next_hop_via_label=path.nh_via_label,
712                 next_hop_table_id=path.nh_table_id)
713         self.stats_index = r.stats_index
714         self._test.registry.register(self, self._test.logger)
715
716     def remove_vpp_config(self):
717         for path in self.paths:
718             self._test.vapi.mpls_route_add_del(self.local_label,
719                                                self.eos_bit,
720                                                path.proto,
721                                                path.nh_addr,
722                                                path.nh_itf,
723                                                is_rpf_id=path.is_rpf_id,
724                                                table_id=self.table_id,
725                                                is_add=0)
726
727     def query_vpp_config(self):
728         dump = self._test.vapi.mpls_fib_dump()
729         for e in dump:
730             if self.local_label == e.label \
731                and self.eos_bit == e.eos_bit \
732                and self.table_id == e.table_id:
733                 return True
734         return False
735
736     def __str__(self):
737         return self.object_id()
738
739     def object_id(self):
740         return ("%d:%s/%d"
741                 % (self.table_id,
742                    self.local_label,
743                    20+self.eos_bit))
744
745     def get_stats_to(self):
746         c = self._test.statistics.get_counter("/net/route/to")
747         return c[0][self.stats_index]
748
749     def get_stats_via(self):
750         c = self._test.statistics.get_counter("/net/route/via")
751         return c[0][self.stats_index]