def validate_route_nexthops(routes, interfaces, sources, enable_color, quiet=False): """ Validate between fib routes and lm interfaces :param routes: list network_types.UnicastRoute (structured routes) :param interfaces: dict<interface-name, InterfaceDetail> """ # record invalid routes in dict<error, list<route_db>> invalid_routes = defaultdict(list) # define error types MISSING_NEXTHOP = "Nexthop does not exist" INVALID_SUBNET = "Nexthop address is not in the same subnet as interface" INVALID_LINK_LOCAL = "Nexthop address is not link local" # return error type error_msg = [] for route in routes: dest = ipnetwork.sprint_prefix(route.dest) # record invalid nexthops in dict<error, list<nexthops>> invalid_nexthop = defaultdict(list) for nextHop in get_route_nexthops(route): nh = nextHop.address if nh.ifName not in interfaces or not interfaces[ nh.ifName].info.isUp: invalid_nexthop[MISSING_NEXTHOP].append( ip_nexthop_to_str(nextHop)) continue # if nexthop addr is v4, make sure it belongs to same subnets as # interface addr if ipnetwork.ip_version(nh.addr) == 4: networks = interfaces[nh.ifName].info.networks if networks is None: # maintain backward compatbility networks = [] for prefix in networks: if ipnetwork.ip_version( prefix.prefixAddress.addr ) == 4 and not ipnetwork.is_same_subnet( nh.addr, prefix.prefixAddress.addr, "31"): invalid_nexthop[INVALID_SUBNET].append( ip_nexthop_to_str(nextHop)) # if nexthop addr is v6, make sure it's a link local addr elif ipnetwork.ip_version( nh.addr) == 6 and not ipnetwork.is_link_local(nh.addr): invalid_nexthop[INVALID_LINK_LOCAL].append( ip_nexthop_to_str(nextHop)) # build routes per error type for k, v in invalid_nexthop.items(): invalid_routes[k].extend(build_routes([dest], v)) # if all good, then return early if not invalid_routes: if not quiet: if enable_color: click.echo(click.style("PASS", bg="green", fg="black")) else: click.echo("PASS") print("Route validation successful") return True, error_msg # Something failed.. report it if not quiet: if enable_color: click.echo(click.style("FAIL", bg="red", fg="black")) else: click.echo("FAIL") print("Route validation failed") # Output report per error type for err, route_db in invalid_routes.items(): caption = "Error: {}".format(err) if not quiet: print_unicast_routes(caption, route_db) else: error_msg.append(caption) return False, error_msg
def validate_route_nexthops(routes, interfaces, sources, enable_color, quiet=False): ''' Validate between fib routes and lm interfaces :param routes: list ip_types.UnicastRoute (structured routes) :param interfaces: dict<interface-name, InterfaceDetail> ''' # record invalid routes in dict<error, list<route_db>> invalid_routes = defaultdict(list) # define error types MISSING_NEXTHOP = 'Nexthop does not exist' INVALID_SUBNET = 'Nexthop address is not in the same subnet as interface' INVALID_LINK_LOCAL = 'Nexthop address is not link local' # return error type error_msg = [] for route in routes: dest = ipnetwork.sprint_prefix(route.dest) # record invalid nexthops in dict<error, list<nexthops>> invalid_nexthop = defaultdict(list) for nh in route.nexthops: if nh.ifName not in interfaces or not interfaces[nh.ifName].info.isUp: invalid_nexthop[MISSING_NEXTHOP].append(ip_nexthop_to_str(nh)) continue # if nexthop addr is v4, make sure it belongs to same subnets as # interface addr if ipnetwork.ip_version(nh.addr) == 4: for addr in interfaces[nh.ifName].info.v4Addrs: if not ipnetwork.is_same_subnet(nh.addr, addr.addr, '31'): invalid_nexthop[INVALID_SUBNET].append(ip_nexthop_to_str(nh)) # if nexthop addr is v6, make sure it's a link local addr elif (ipnetwork.ip_version(nh.addr) == 6 and not ipnetwork.is_link_local(nh.addr)): invalid_nexthop[INVALID_LINK_LOCAL].append(ip_nexthop_to_str(nh)) # build routes per error type for k, v in invalid_nexthop.items(): invalid_routes[k].extend(build_routes([dest], v)) # if all good, then return early if not invalid_routes: if not quiet: if enable_color: click.echo(click.style('PASS', bg='green', fg='black')) else: click.echo('PASS') print('Route validation successful') return True, error_msg # Something failed.. report it if not quiet: if enable_color: click.echo(click.style('FAIL', bg='red', fg='black')) else: click.echo('FAIL') print('Route validation failed') # Output report per error type for err, route_db in invalid_routes.items(): caption = 'Error: {}'.format(err) if not quiet: print_routes(caption, route_db) else: error_msg.append(caption) return False, error_msg