X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=test%2Fvpp_ip_route.py;h=06a963cfd88b37292edf79a1996da76d36f39dd5;hb=4941afb4f96a20df7dc8b6688f7921a3d713b77d;hp=75f400f1dc0dc1c65b0e83903f70f841dd3f7daf;hpb=cb630ff691264f7ea4a0f52cc6faa87fcdaa1a40;p=vpp.git diff --git a/test/vpp_ip_route.py b/test/vpp_ip_route.py index 75f400f1dc0..06a963cfd88 100644 --- a/test/vpp_ip_route.py +++ b/test/vpp_ip_route.py @@ -4,113 +4,1001 @@ object abstractions for representing IP routes in VPP """ -import socket +from vpp_object import VppObject +from vpp_ip import DpoProto, INVALID_INDEX, VppIpAddressUnion, VppIpMPrefix +from ipaddress import ip_network, ip_address, IPv4Network, IPv6Network +from vpp_papi_exceptions import UnexpectedApiReturnValueError # from vnet/vnet/mpls/mpls_types.h -MPLS_IETF_MAX_LABEL = 0xfffff +MPLS_IETF_MAX_LABEL = 0xFFFFF MPLS_LABEL_INVALID = MPLS_IETF_MAX_LABEL + 1 +try: + text_type = unicode +except NameError: + text_type = str -class RoutePath: - def __init__(self, nh_addr, nh_sw_if_index, nh_table_id=0, labels=[], nh_via_label=MPLS_LABEL_INVALID): - self.nh_addr = socket.inet_pton(socket.AF_INET, nh_addr) +class FibPathProto: + FIB_PATH_NH_PROTO_IP4 = 0 + FIB_PATH_NH_PROTO_IP6 = 1 + FIB_PATH_NH_PROTO_MPLS = 2 + FIB_PATH_NH_PROTO_ETHERNET = 3 + FIB_PATH_NH_PROTO_BIER = 4 + FIB_PATH_NH_PROTO_NSH = 5 + + +class FibPathType: + FIB_PATH_TYPE_NORMAL = 0 + FIB_PATH_TYPE_LOCAL = 1 + FIB_PATH_TYPE_DROP = 2 + FIB_PATH_TYPE_UDP_ENCAP = 3 + FIB_PATH_TYPE_BIER_IMP = 4 + FIB_PATH_TYPE_ICMP_UNREACH = 5 + FIB_PATH_TYPE_ICMP_PROHIBIT = 6 + FIB_PATH_TYPE_SOURCE_LOOKUP = 7 + FIB_PATH_TYPE_DVR = 8 + FIB_PATH_TYPE_INTERFACE_RX = 9 + FIB_PATH_TYPE_CLASSIFY = 10 + + +class FibPathFlags: + FIB_PATH_FLAG_NONE = 0 + FIB_PATH_FLAG_RESOLVE_VIA_ATTACHED = 1 + FIB_PATH_FLAG_RESOLVE_VIA_HOST = 2 + FIB_PATH_FLAG_POP_PW_CW = 4 + + +class MplsLspMode: + PIPE = 0 + UNIFORM = 1 + + +def mk_network(addr, len): + if ip_address(text_type(addr)).version == 4: + return IPv4Network("%s/%d" % (addr, len), strict=False) + else: + return IPv6Network("%s/%d" % (addr, len), strict=False) + + +def ip_to_dpo_proto(addr): + if addr.version == 6: + return DpoProto.DPO_PROTO_IP6 + else: + return DpoProto.DPO_PROTO_IP4 + + +def address_proto(ip_addr): + if ip_addr.ip_addr.version == 4: + return FibPathProto.FIB_PATH_NH_PROTO_IP4 + else: + return FibPathProto.FIB_PATH_NH_PROTO_IP6 + + +def find_route(test, addr, len, table_id=0, sw_if_index=None): + prefix = mk_network(addr, len) + + if 4 == prefix.version: + routes = test.vapi.ip_route_dump(table_id, False) + else: + routes = test.vapi.ip_route_dump(table_id, True) + + for e in routes: + if table_id == e.route.table_id and str(e.route.prefix) == str(prefix): + if not sw_if_index: + return True + else: + # should be only one path if the user is looking + # for the interface the route is reachable through + if e.route.n_paths != 1: + return False + else: + return e.route.paths[0].sw_if_index == sw_if_index + + return False + + +def find_route_in_dump(dump, route, table): + for r in dump: + if table.table_id == r.route.table_id and route.prefix == r.route.prefix: + if len(route.paths) == r.route.n_paths: + return True + return False + + +def find_mroute_in_dump(dump, route, table): + for r in dump: + if table.table_id == r.route.table_id and route.prefix == r.route.prefix: + return True + return False + + +def find_mroute(test, grp_addr, src_addr, grp_addr_len, table_id=0): + ip_mprefix = VppIpMPrefix(text_type(src_addr), text_type(grp_addr), grp_addr_len) + + if 4 == ip_mprefix.version: + routes = test.vapi.ip_mroute_dump(table_id, False) + else: + routes = test.vapi.ip_mroute_dump(table_id, True) + + for e in routes: + if table_id == e.route.table_id and ip_mprefix == e.route.prefix: + return True + return False + + +def find_mpls_route(test, table_id, label, eos_bit, paths=None): + dump = test.vapi.mpls_route_dump(table_id) + for e in dump: + if ( + label == e.mr_route.mr_label + and eos_bit == e.mr_route.mr_eos + and table_id == e.mr_route.mr_table_id + ): + if not paths: + return True + else: + if len(paths) != len(e.mr_route.mr_paths): + return False + for i in range(len(paths)): + if paths[i] != e.mr_route.mr_paths[i]: + return False + return True + return False + + +def fib_interface_ip_prefix(test, addr, len, sw_if_index): + # can't use python net here since we need the host bits in the prefix + prefix = "%s/%d" % (addr, len) + addrs = test.vapi.ip_address_dump( + sw_if_index, is_ipv6=(6 == ip_address(addr).version) + ) + + for a in addrs: + if a.sw_if_index == sw_if_index and str(a.prefix) == prefix: + return True + return False + + +class VppIpTable(VppObject): + def __init__(self, test, table_id, is_ip6=0, register=True): + self._test = test + self.table_id = table_id + self.is_ip6 = is_ip6 + self.register = register + + def add_vpp_config(self): + self._test.vapi.ip_table_add_del( + is_add=1, table={"is_ip6": self.is_ip6, "table_id": self.table_id} + ) + if self.register: + self._test.registry.register(self, self._test.logger) + return self + + def remove_vpp_config(self): + self._test.vapi.ip_table_add_del( + is_add=0, table={"is_ip6": self.is_ip6, "table_id": self.table_id} + ) + + def replace_begin(self): + self._test.vapi.ip_table_replace_begin( + table={"is_ip6": self.is_ip6, "table_id": self.table_id} + ) + + def replace_end(self): + self._test.vapi.ip_table_replace_end( + table={"is_ip6": self.is_ip6, "table_id": self.table_id} + ) + + def flush(self): + self._test.vapi.ip_table_flush( + table={"is_ip6": self.is_ip6, "table_id": self.table_id} + ) + + def dump(self): + return self._test.vapi.ip_route_dump(self.table_id, self.is_ip6) + + def mdump(self): + return self._test.vapi.ip_mroute_dump(self.table_id, self.is_ip6) + + def query_vpp_config(self): + if self.table_id == 0: + # the default table always exists + return False + # find the default route + return find_route( + self._test, "::" if self.is_ip6 else "0.0.0.0", 0, self.table_id + ) + + def object_id(self): + return "table-%s-%d" % ("v6" if self.is_ip6 == 1 else "v4", self.table_id) + + +class VppIpInterfaceAddress(VppObject): + def __init__(self, test, intf, addr, len, bind=None): + self._test = test + self.intf = intf + self.addr = addr + self.len = len + self.prefix = "%s/%d" % (addr, len) + self.host_len = ip_network(self.prefix, strict=False).max_prefixlen + self.table_id = 0 + if bind: + self.table_id = bind.table.table_id + + def add_vpp_config(self): + self._test.vapi.sw_interface_add_del_address( + sw_if_index=self.intf.sw_if_index, prefix=self.prefix, is_add=1 + ) + self._test.registry.register(self, self._test.logger) + return self + + def remove_vpp_config(self): + self._test.vapi.sw_interface_add_del_address( + sw_if_index=self.intf.sw_if_index, prefix=self.prefix, is_add=0 + ) + + def query_vpp_config(self): + # search for the IP address mapping and the two expected + # FIB entries + v = ip_address(self.addr).version + + if (v == 4 and self.len < 31) or (v == 6 and self.len < 127): + return ( + fib_interface_ip_prefix( + self._test, self.addr, self.len, self.intf.sw_if_index + ) + & find_route( + self._test, + self.addr, + self.len, + table_id=self.table_id, + sw_if_index=self.intf.sw_if_index, + ) + & find_route( + self._test, + self.addr, + self.host_len, + table_id=self.table_id, + sw_if_index=self.intf.sw_if_index, + ) + ) + else: + return fib_interface_ip_prefix( + self._test, self.addr, self.len, self.intf.sw_if_index + ) & find_route( + self._test, + self.addr, + self.host_len, + table_id=self.table_id, + sw_if_index=self.intf.sw_if_index, + ) + + def object_id(self): + return "interface-ip-%s-%d-%s" % (self.intf, self.table_id, self.prefix) + + +class VppIp6LinkLocalAddress(VppObject): + def __init__(self, test, intf, addr): + self._test = test + self.intf = intf + self.addr = addr + + def add_vpp_config(self): + self._test.vapi.sw_interface_ip6_set_link_local_address( + sw_if_index=self.intf.sw_if_index, ip=self.addr + ) + self._test.registry.register(self, self._test.logger) + return self + + def remove_vpp_config(self): + # link locals can't be removed, only changed + pass + + def query_vpp_config(self): + # no API to query + return False + + def object_id(self): + return "ip6-link-local-%s-%s" % (self.intf, self.addr) + + +class VppIpInterfaceBind(VppObject): + def __init__(self, test, intf, table): + self._test = test + self.intf = intf + self.table = table + + def add_vpp_config(self): + if self.table.is_ip6: + self.intf.set_table_ip6(self.table.table_id) + else: + self.intf.set_table_ip4(self.table.table_id) + self._test.registry.register(self, self._test.logger) + return self + + def remove_vpp_config(self): + if 0 == self.table.table_id: + return + if self.table.is_ip6: + self.intf.set_table_ip6(0) + else: + self.intf.set_table_ip4(0) + + def query_vpp_config(self): + if 0 == self.table.table_id: + return False + try: + return ( + self._test.vapi.sw_interface_get_table( + self.intf.sw_if_index, self.table.is_ip6 + ).vrf_id + == self.table.table_id + ) + except UnexpectedApiReturnValueError as e: + if e.retval == -2: # INVALID_SW_IF_INDEX + return False + raise + + def object_id(self): + return "interface-bind-%s-%s" % (self.intf, self.table) + + +class VppMplsLabel: + def __init__(self, value, mode=MplsLspMode.PIPE, ttl=64, exp=0): + self.value = value + self.mode = mode + self.ttl = ttl + self.exp = exp + + def encode(self): + is_uniform = 0 if self.mode is MplsLspMode.PIPE else 1 + return { + "label": self.value, + "ttl": self.ttl, + "exp": self.exp, + "is_uniform": is_uniform, + } + + def __eq__(self, other): + if isinstance(other, self.__class__): + return ( + self.value == other.value + and self.ttl == other.ttl + and self.exp == other.exp + and self.mode == other.mode + ) + elif hasattr(other, "label"): + return ( + self.value == other.label + and self.ttl == other.ttl + and self.exp == other.exp + and (self.mode == MplsLspMode.UNIFORM) == other.is_uniform + ) + else: + return False + + def __ne__(self, other): + return not (self == other) + + +class VppFibPathNextHop: + def __init__(self, addr, via_label=MPLS_LABEL_INVALID, next_hop_id=INVALID_INDEX): + self.addr = VppIpAddressUnion(addr) + self.via_label = via_label + self.obj_id = next_hop_id + + def encode(self): + if self.via_label is not MPLS_LABEL_INVALID: + return {"via_label": self.via_label} + if self.obj_id is not INVALID_INDEX: + return {"obj_id": self.obj_id} + else: + return {"address": self.addr.encode()} + + def proto(self): + if self.via_label is MPLS_LABEL_INVALID: + return address_proto(self.addr) + else: + return FibPathProto.FIB_PATH_NH_PROTO_MPLS + + def __eq__(self, other): + if not isinstance(other, self.__class__): + # try the other instance's __eq__. + return NotImplemented + return ( + self.addr == other.addr + and self.via_label == other.via_label + and self.obj_id == other.obj_id + ) + + +class VppRoutePath: + def __init__( + self, + nh_addr, + nh_sw_if_index, + nh_table_id=0, + labels=[], + nh_via_label=MPLS_LABEL_INVALID, + rpf_id=0, + next_hop_id=INVALID_INDEX, + proto=None, + flags=FibPathFlags.FIB_PATH_FLAG_NONE, + type=FibPathType.FIB_PATH_TYPE_NORMAL, + ): self.nh_itf = nh_sw_if_index self.nh_table_id = nh_table_id - self.nh_via_label = nh_via_label self.nh_labels = labels + self.weight = 1 + self.rpf_id = rpf_id + self.proto = proto + self.flags = flags + self.type = type + self.nh = VppFibPathNextHop(nh_addr, nh_via_label, next_hop_id) + if proto is None: + self.proto = self.nh.proto() + else: + self.proto = proto + self.next_hop_id = next_hop_id + def encode_labels(self): + lstack = [] + for l in self.nh_labels: + if type(l) == VppMplsLabel: + lstack.append(l.encode()) + else: + lstack.append({"label": l, "ttl": 255}) + while len(lstack) < 16: + lstack.append({}) -class IpRoute: + return lstack + + def encode(self): + return { + "weight": 1, + "preference": 0, + "table_id": self.nh_table_id, + "nh": self.nh.encode(), + "next_hop_id": self.next_hop_id, + "sw_if_index": self.nh_itf, + "rpf_id": self.rpf_id, + "proto": self.proto, + "type": self.type, + "flags": self.flags, + "n_labels": len(self.nh_labels), + "label_stack": self.encode_labels(), + } + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.nh == other.nh + elif hasattr(other, "sw_if_index"): + # vl_api_fib_path_t + if len(self.nh_labels) != other.n_labels: + return False + for i in range(len(self.nh_labels)): + if self.nh_labels[i] != other.label_stack[i]: + return False + return self.nh_itf == other.sw_if_index + else: + return False + + def __ne__(self, other): + return not (self == other) + + +class VppMRoutePath(VppRoutePath): + def __init__( + self, + nh_sw_if_index, + flags, + nh=None, + proto=FibPathProto.FIB_PATH_NH_PROTO_IP4, + type=FibPathType.FIB_PATH_TYPE_NORMAL, + bier_imp=INVALID_INDEX, + ): + if not nh: + nh = "::" if proto is FibPathProto.FIB_PATH_NH_PROTO_IP6 else "0.0.0.0" + super(VppMRoutePath, self).__init__( + nh, nh_sw_if_index, proto=proto, type=type, next_hop_id=bier_imp + ) + self.nh_i_flags = flags + self.bier_imp = bier_imp + + def encode(self): + return { + "path": super(VppMRoutePath, self).encode(), + "itf_flags": self.nh_i_flags, + } + + +class VppIpRoute(VppObject): """ IP Route """ - def __init__(self, test, dest_addr, - dest_addr_len, paths, table_id=0): + def __init__( + self, test, dest_addr, dest_addr_len, paths, table_id=0, register=True + ): self._test = test self.paths = paths - self.dest_addr = socket.inet_pton(socket.AF_INET, dest_addr) - self.dest_addr_len = dest_addr_len self.table_id = table_id + self.prefix = mk_network(dest_addr, dest_addr_len) + self.register = register + self.stats_index = None + self.modified = False + + self.encoded_paths = [] + for path in self.paths: + self.encoded_paths.append(path.encode()) + + def __eq__(self, other): + if self.table_id == other.table_id and self.prefix == other.prefix: + return True + return False + + def modify(self, paths): + self.paths = paths + self.encoded_paths = [] + for path in self.paths: + self.encoded_paths.append(path.encode()) + self.modified = True + + self._test.vapi.ip_route_add_del( + route={ + "table_id": self.table_id, + "prefix": self.prefix, + "n_paths": len(self.encoded_paths), + "paths": self.encoded_paths, + }, + is_add=1, + is_multipath=0, + ) def add_vpp_config(self): + r = self._test.vapi.ip_route_add_del( + route={ + "table_id": self.table_id, + "prefix": self.prefix, + "n_paths": len(self.encoded_paths), + "paths": self.encoded_paths, + }, + is_add=1, + is_multipath=0, + ) + self.stats_index = r.stats_index + if self.register: + self._test.registry.register(self, self._test.logger) + return self + + def remove_vpp_config(self): + # there's no need to issue different deletes for modified routes + # we do this only to test the two different ways to delete routes + # eiter by passing all the paths to remove and mutlipath=1 or + # passing no paths and multipath=0 + if self.modified: + self._test.vapi.ip_route_add_del( + route={ + "table_id": self.table_id, + "prefix": self.prefix, + "n_paths": len(self.encoded_paths), + "paths": self.encoded_paths, + }, + is_add=0, + is_multipath=1, + ) + else: + self._test.vapi.ip_route_add_del( + route={"table_id": self.table_id, "prefix": self.prefix, "n_paths": 0}, + is_add=0, + is_multipath=0, + ) + + def query_vpp_config(self): + return find_route( + self._test, + self.prefix.network_address, + self.prefix.prefixlen, + self.table_id, + ) + + def object_id(self): + return "%s:table-%d-%s" % ( + "ip6-route" if self.prefix.version == 6 else "ip-route", + self.table_id, + self.prefix, + ) + + def get_stats_to(self): + c = self._test.statistics.get_counter("/net/route/to") + return c[0][self.stats_index] + + def get_stats_via(self): + c = self._test.statistics.get_counter("/net/route/via") + return c[0][self.stats_index] + + +class VppIpRouteV2(VppObject): + """ + IP Route V2 + """ + + def __init__( + self, test, dest_addr, dest_addr_len, paths, table_id=0, register=True, src=0 + ): + self._test = test + self.paths = paths + self.table_id = table_id + self.prefix = mk_network(dest_addr, dest_addr_len) + self.register = register + self.stats_index = None + self.modified = False + self.src = src + + self.encoded_paths = [] for path in self.paths: - self._test.vapi.ip_add_del_route(self.dest_addr, - self.dest_addr_len, - path.nh_addr, - path.nh_itf, - table_id=self.table_id, - next_hop_out_label_stack=path.nh_labels, - next_hop_n_out_labels=len( - path.nh_labels), - next_hop_via_label=path.nh_via_label) + self.encoded_paths.append(path.encode()) + + def __eq__(self, other): + if self.table_id == other.table_id and self.prefix == other.prefix: + return True + return False + + def modify(self, paths): + self.paths = paths + self.encoded_paths = [] + for path in self.paths: + self.encoded_paths.append(path.encode()) + self.modified = True + + self._test.vapi.ip_route_add_del_v2( + route={ + "table_id": self.table_id, + "prefix": self.prefix, + "src": self.src, + "n_paths": len(self.encoded_paths), + "paths": self.encoded_paths, + }, + is_add=1, + is_multipath=0, + ) + + def add_vpp_config(self): + r = self._test.vapi.ip_route_add_del_v2( + route={ + "table_id": self.table_id, + "prefix": self.prefix, + "n_paths": len(self.encoded_paths), + "paths": self.encoded_paths, + "src": self.src, + }, + is_add=1, + is_multipath=0, + ) + self.stats_index = r.stats_index + if self.register: + self._test.registry.register(self, self._test.logger) + return self def remove_vpp_config(self): + # there's no need to issue different deletes for modified routes + # we do this only to test the two different ways to delete routes + # eiter by passing all the paths to remove and mutlipath=1 or + # passing no paths and multipath=0 + if self.modified: + self._test.vapi.ip_route_add_del_v2( + route={ + "table_id": self.table_id, + "prefix": self.prefix, + "src": self.src, + "n_paths": len(self.encoded_paths), + "paths": self.encoded_paths, + }, + is_add=0, + is_multipath=1, + ) + else: + self._test.vapi.ip_route_add_del_v2( + route={ + "table_id": self.table_id, + "prefix": self.prefix, + "src": self.src, + "n_paths": 0, + }, + is_add=0, + is_multipath=0, + ) + + def query_vpp_config(self): + return find_route( + self._test, + self.prefix.network_address, + self.prefix.prefixlen, + self.table_id, + ) + + def object_id(self): + return "%s:table-%d-%s" % ( + "ip6-route" if self.prefix.version == 6 else "ip-route", + self.table_id, + self.prefix, + ) + + def get_stats_to(self): + c = self._test.statistics.get_counter("/net/route/to") + return c[0][self.stats_index] + + def get_stats_via(self): + c = self._test.statistics.get_counter("/net/route/via") + return c[0][self.stats_index] + + +class VppIpMRoute(VppObject): + """ + IP Multicast Route + """ + + def __init__( + self, + test, + src_addr, + grp_addr, + grp_addr_len, + e_flags, + paths, + table_id=0, + rpf_id=0, + ): + self._test = test + self.paths = paths + self.table_id = table_id + self.e_flags = e_flags + self.rpf_id = rpf_id + + self.prefix = VppIpMPrefix(src_addr, grp_addr, grp_addr_len) + self.encoded_paths = [] for path in self.paths: - self._test.vapi.ip_add_del_route(self.dest_addr, - self.dest_addr_len, - path.nh_addr, - path.nh_itf, - table_id=self.table_id, - is_add=0) + self.encoded_paths.append(path.encode()) + + def encode(self, paths=None): + _paths = self.encoded_paths if paths is None else paths + return { + "table_id": self.table_id, + "entry_flags": self.e_flags, + "rpf_id": self.rpf_id, + "prefix": self.prefix.encode(), + "n_paths": len(_paths), + "paths": _paths, + } + + def add_vpp_config(self): + r = self._test.vapi.ip_mroute_add_del( + route=self.encode(), is_multipath=1, is_add=1 + ) + self.stats_index = r.stats_index + self._test.registry.register(self, self._test.logger) + return self + + def remove_vpp_config(self): + self._test.vapi.ip_mroute_add_del(route=self.encode(), is_multipath=1, is_add=0) + + def update_entry_flags(self, flags): + self.e_flags = flags + self._test.vapi.ip_mroute_add_del( + route=self.encode(paths=[]), is_multipath=1, is_add=1 + ) + + def update_rpf_id(self, rpf_id): + self.rpf_id = rpf_id + self._test.vapi.ip_mroute_add_del( + route=self.encode(paths=[]), is_multipath=1, is_add=1 + ) + + def update_path_flags(self, itf, flags): + for p in range(len(self.paths)): + if self.paths[p].nh_itf == itf: + self.paths[p].nh_i_flags = flags + self.encoded_paths[p] = self.paths[p].encode() + break + + self._test.vapi.ip_mroute_add_del( + route=self.encode(paths=[self.encoded_paths[p]]), is_add=1, is_multipath=0 + ) + + def query_vpp_config(self): + return find_mroute( + self._test, + self.prefix.gaddr, + self.prefix.saddr, + self.prefix.length, + self.table_id, + ) + + def object_id(self): + return "%d:(%s,%s/%d)" % ( + self.table_id, + self.prefix.saddr, + self.prefix.gaddr, + self.prefix.length, + ) + + def get_stats(self): + c = self._test.statistics.get_counter("/net/mroute") + return c[0][self.stats_index] + +class VppMFibSignal: + def __init__(self, test, route, interface, packet): + self.route = route + self.interface = interface + self.packet = packet + self.test = test -class MplsIpBind: + def compare(self, signal): + self.test.assertEqual(self.interface, signal.sw_if_index) + self.test.assertEqual(self.route.table_id, signal.table_id) + self.test.assertEqual(self.route.prefix, signal.prefix) + + +class VppMplsIpBind(VppObject): """ MPLS to IP Binding """ - def __init__(self, test, local_label, dest_addr, dest_addr_len): + def __init__( + self, + test, + local_label, + dest_addr, + dest_addr_len, + table_id=0, + ip_table_id=0, + is_ip6=0, + ): self._test = test - self.dest_addr = socket.inet_pton(socket.AF_INET, dest_addr) self.dest_addr_len = dest_addr_len + self.dest_addr = dest_addr + self.ip_addr = ip_address(text_type(dest_addr)) self.local_label = local_label + self.table_id = table_id + self.ip_table_id = ip_table_id + self.prefix = mk_network(dest_addr, dest_addr_len) def add_vpp_config(self): - self._test.vapi.mpls_ip_bind_unbind(self.local_label, - self.dest_addr, - self.dest_addr_len) + self._test.vapi.mpls_ip_bind_unbind( + self.local_label, + self.prefix, + table_id=self.table_id, + ip_table_id=self.ip_table_id, + ) + self._test.registry.register(self, self._test.logger) def remove_vpp_config(self): - self._test.vapi.mpls_ip_bind_unbind(self.local_label, - self.dest_addr, - self.dest_addr_len, - is_bind=0) + self._test.vapi.mpls_ip_bind_unbind( + self.local_label, + self.prefix, + table_id=self.table_id, + ip_table_id=self.ip_table_id, + is_bind=0, + ) + def query_vpp_config(self): + dump = self._test.vapi.mpls_route_dump(self.table_id) + for e in dump: + if ( + self.local_label == e.mr_route.mr_label + and self.table_id == e.mr_route.mr_table_id + ): + return True + return False -class MplsRoute: + def object_id(self): + return "%d:%s binds %d:%s/%d" % ( + self.table_id, + self.local_label, + self.ip_table_id, + self.dest_addr, + self.dest_addr_len, + ) + + +class VppMplsTable(VppObject): + def __init__(self, test, table_id): + self._test = test + self.table_id = table_id + + def add_vpp_config(self): + self._test.vapi.mpls_table_add_del(self.table_id, is_add=1) + self._test.registry.register(self, self._test.logger) + + def remove_vpp_config(self): + self._test.vapi.mpls_table_add_del(self.table_id, is_add=0) + + def query_vpp_config(self): + dump = self._test.vapi.mpls_table_dump() + for d in dump: + if d.mt_table.mt_table_id == self.table_id: + return True + return False + + def object_id(self): + return "table-mpls-%d" % (self.table_id) + + +class VppMplsRoute(VppObject): """ - MPLS Route + MPLS Route/LSP """ - def __init__(self, test, local_label, eos_bit, paths, table_id=0): + def __init__( + self, + test, + local_label, + eos_bit, + paths, + table_id=0, + is_multicast=0, + eos_proto=FibPathProto.FIB_PATH_NH_PROTO_IP4, + ): self._test = test self.paths = paths self.local_label = local_label self.eos_bit = eos_bit + self.eos_proto = eos_proto self.table_id = table_id + self.is_multicast = is_multicast def add_vpp_config(self): + paths = [] for path in self.paths: - self._test.vapi.mpls_route_add_del(self.local_label, - self.eos_bit, - 1, - path.nh_addr, - path.nh_itf, - table_id=self.table_id, - next_hop_out_label_stack=path.nh_labels, - next_hop_n_out_labels=len( - path.nh_labels), - next_hop_via_label=path.nh_via_label, - next_hop_table_id=path.nh_table_id) + paths.append(path.encode()) + + r = self._test.vapi.mpls_route_add_del( + self.table_id, + self.local_label, + self.eos_bit, + self.eos_proto, + self.is_multicast, + paths, + 1, + 0, + ) + self.stats_index = r.stats_index + self._test.registry.register(self, self._test.logger) def remove_vpp_config(self): + paths = [] for path in self.paths: - self._test.vapi.mpls_route_add_del(self.local_label, - self.eos_bit, - 1, - path.nh_addr, - path.nh_itf, - table_id=self.table_id, - is_add=0) + paths.append(path.encode()) + + self._test.vapi.mpls_route_add_del( + self.table_id, + self.local_label, + self.eos_bit, + self.eos_proto, + self.is_multicast, + paths, + 0, + 0, + ) + + def query_vpp_config(self): + return find_mpls_route( + self._test, self.table_id, self.local_label, self.eos_bit + ) + + def object_id(self): + return "mpls-route-%d:%s/%d" % ( + self.table_id, + self.local_label, + 20 + self.eos_bit, + ) + + def get_stats_to(self): + c = self._test.statistics.get_counter("/net/route/to") + return c[0][self.stats_index] + + def get_stats_via(self): + c = self._test.statistics.get_counter("/net/route/via") + return c[0][self.stats_index]