Date: Tue, 28 Apr 2020 20:00:17 +0000 (UTC) From: "Alexander V. Chernikov" <melifaro@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r360450 - in head/sys: conf net net/route Message-ID: <202004282000.03SK0HK1055981@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: melifaro Date: Tue Apr 28 20:00:17 2020 New Revision: 360450 URL: https://svnweb.freebsd.org/changeset/base/360450 Log: Move route-specific ddb commands to route/route_ddb.c Currently functionality resides in rtsock.c, which is a controlling interface, partially external to the routing subsystem. Additionally, DDB-supporting functionality is > 100SLOC, which deserves a separate file. Given that, move this functionality to a newly-created net/route/ subdir. Reviewed by: cem Differential Revision: https://reviews.freebsd.org/D24561 Added: head/sys/net/route/route_ddb.c (contents, props changed) Modified: head/sys/conf/files head/sys/net/route.h head/sys/net/rtsock.c Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Tue Apr 28 19:14:09 2020 (r360449) +++ head/sys/conf/files Tue Apr 28 20:00:17 2020 (r360450) @@ -4095,6 +4095,7 @@ net/route/nhop.c standard net/route/nhop_ctl.c standard net/route/nhop_utils.c standard net/route/route_ctl.c standard +net/route/route_ddb.c optional ddb net/route/route_helpers.c standard net/route/route_temporal.c standard net/rss_config.c optional inet rss | inet6 rss Modified: head/sys/net/route.h ============================================================================== --- head/sys/net/route.h Tue Apr 28 19:14:09 2020 (r360449) +++ head/sys/net/route.h Tue Apr 28 20:00:17 2020 (r360450) @@ -388,6 +388,8 @@ int rtsock_addrmsg(int, struct ifaddr *, int); int rtsock_routemsg(int, struct rtentry *, struct ifnet *ifp, int, int); int rtsock_routemsg_info(int, struct rt_addrinfo *, int); +struct sockaddr *rtsock_fix_netmask(const struct sockaddr *dst, + const struct sockaddr *smask, struct sockaddr_storage *dmask); /* * Note the following locking behavior: * Added: head/sys/net/route/route_ddb.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/net/route/route_ddb.c Tue Apr 28 20:00:17 2020 (r360450) @@ -0,0 +1,458 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright 2019 Conrad Meyer <cem@FreeBSD.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); +#include "opt_inet.h" +#include "opt_inet6.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/sysctl.h> +#include <sys/syslog.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/rmlock.h> + +#include <ddb/ddb.h> +#include <ddb/db_lex.h> + +#include <net/if.h> +#include <net/if_var.h> +#include <net/if_dl.h> +#include <net/vnet.h> +#include <net/route.h> +#include <net/route/route_var.h> +#include <net/route/nhop.h> +#include <netinet/in.h> + +/* + * Unfortunately, RTF_ values are expressed as raw masks rather than powers of + * 2, so we cannot use them as nice C99 initializer indices below. + */ +static const char * const rtf_flag_strings[] = { + "UP", + "GATEWAY", + "HOST", + "REJECT", + "DYNAMIC", + "MODIFIED", + "DONE", + "UNUSED_0x80", + "UNUSED_0x100", + "XRESOLVE", + "LLDATA", + "STATIC", + "BLACKHOLE", + "UNUSED_0x2000", + "PROTO2", + "PROTO1", + "UNUSED_0x10000", + "UNUSED_0x20000", + "PROTO3", + "FIXEDMTU", + "PINNED", + "LOCAL", + "BROADCAST", + "MULTICAST", + /* Big gap. */ + [28] = "STICKY", + [30] = "RNH_LOCKED", + [31] = "GWFLAG_COMPAT", +}; + +static const char * __pure +rt_flag_name(unsigned idx) +{ + if (idx >= nitems(rtf_flag_strings)) + return ("INVALID_FLAG"); + if (rtf_flag_strings[idx] == NULL) + return ("UNKNOWN"); + return (rtf_flag_strings[idx]); +} + +static void +rt_dumpaddr_ddb(const char *name, const struct sockaddr *sa) +{ + char buf[INET6_ADDRSTRLEN], *res; + + res = NULL; + if (sa == NULL) + res = "NULL"; + else if (sa->sa_family == AF_INET) { + res = inet_ntop(AF_INET, + &((const struct sockaddr_in *)sa)->sin_addr, + buf, sizeof(buf)); + } else if (sa->sa_family == AF_INET6) { + res = inet_ntop(AF_INET6, + &((const struct sockaddr_in6 *)sa)->sin6_addr, + buf, sizeof(buf)); + } else if (sa->sa_family == AF_LINK) { + res = "on link"; + } + + if (res != NULL) { + db_printf("%s <%s> ", name, res); + return; + } + + db_printf("%s <af:%d> ", name, sa->sa_family); +} + +static int +rt_dumpentry_ddb(struct radix_node *rn, void *arg __unused) +{ + struct sockaddr_storage ss; + struct rtentry *rt; + int flags, idx; + + /* If RNTORT is important, put it in a header. */ + rt = (void *)rn; + + rt_dumpaddr_ddb("dst", rt_key(rt)); + rt_dumpaddr_ddb("gateway", &rt->rt_nhop->gw_sa); + rt_dumpaddr_ddb("netmask", rtsock_fix_netmask(rt_key(rt), rt_mask(rt), + &ss)); + if (rt->rt_ifp != NULL && (rt->rt_ifp->if_flags & IFF_DYING) == 0) { + rt_dumpaddr_ddb("ifp", rt->rt_ifp->if_addr->ifa_addr); + rt_dumpaddr_ddb("ifa", rt->rt_ifa->ifa_addr); + } + + db_printf("flags "); + flags = rt->rt_flags; + if (flags == 0) + db_printf("none"); + + while ((idx = ffs(flags)) > 0) { + idx--; + + if (flags != rt->rt_flags) + db_printf(","); + db_printf("%s", rt_flag_name(idx)); + + flags &= ~(1ul << idx); + } + + db_printf("\n"); + return (0); +} + +DB_SHOW_COMMAND(routetable, db_show_routetable_cmd) +{ + struct rib_head *rnh; + int error, i, lim; + + if (have_addr) + i = lim = addr; + else { + i = 1; + lim = AF_MAX; + } + + for (; i <= lim; i++) { + rnh = rt_tables_get_rnh(0, i); + if (rnh == NULL) { + if (have_addr) { + db_printf("%s: AF %d not supported?\n", + __func__, i); + break; + } + continue; + } + + if (!have_addr && i > 1) + db_printf("\n"); + + db_printf("Route table for AF %d%s%s%s:\n", i, + (i == AF_INET || i == AF_INET6) ? " (" : "", + (i == AF_INET) ? "INET" : (i == AF_INET6) ? "INET6" : "", + (i == AF_INET || i == AF_INET6) ? ")" : ""); + + error = rnh->rnh_walktree(&rnh->head, rt_dumpentry_ddb, NULL); + if (error != 0) + db_printf("%s: walktree(%d): %d\n", __func__, i, + error); + } +} + +_DB_FUNC(_show, route, db_show_route_cmd, db_show_table, CS_OWN, NULL) +{ + char buf[INET6_ADDRSTRLEN], *bp; + const void *dst_addrp; + struct sockaddr *dstp; + struct rtentry *rt; + union { + struct sockaddr_in dest_sin; + struct sockaddr_in6 dest_sin6; + } u; + uint16_t hextets[8]; + unsigned i, tets; + int t, af, exp, tokflags; + + /* + * Undecoded address family. No double-colon expansion seen yet. + */ + af = -1; + exp = -1; + /* Assume INET6 to start; we can work back if guess was wrong. */ + tokflags = DRT_WSPACE | DRT_HEX | DRT_HEXADECIMAL; + + /* + * db_command has lexed 'show route' for us. + */ + t = db_read_token_flags(tokflags); + if (t == tWSPACE) + t = db_read_token_flags(tokflags); + + /* + * tEOL: Just 'show route' isn't a valid mode. + * tMINUS: It's either '-h' or some invalid option. Regardless, usage. + */ + if (t == tEOL || t == tMINUS) + goto usage; + + db_unread_token(t); + + tets = nitems(hextets); + + /* + * Each loop iteration, we expect to read one octet (v4) or hextet + * (v6), followed by an appropriate field separator ('.' or ':' or + * '::'). + * + * At the start of each loop, we're looking for a number (octet or + * hextet). + * + * INET6 addresses have a special case where they may begin with '::'. + */ + for (i = 0; i < tets; i++) { + t = db_read_token_flags(tokflags); + + if (t == tCOLONCOLON) { + /* INET6 with leading '::' or invalid. */ + if (i != 0) { + db_printf("Parse error: unexpected extra " + "colons.\n"); + goto exit; + } + + af = AF_INET6; + exp = i; + hextets[i] = 0; + continue; + } else if (t == tNUMBER) { + /* + * Lexer separates out '-' as tMINUS, but make the + * assumption explicit here. + */ + MPASS(db_tok_number >= 0); + + if (af == AF_INET && db_tok_number > UINT8_MAX) { + db_printf("Not a valid v4 octet: %ld\n", + (long)db_tok_number); + goto exit; + } + hextets[i] = db_tok_number; + } else if (t == tEOL) { + /* + * We can only detect the end of an IPv6 address in + * compact representation with EOL. + */ + if (af != AF_INET6 || exp < 0) { + db_printf("Parse failed. Got unexpected EOF " + "when the address is not a compact-" + "representation IPv6 address.\n"); + goto exit; + } + break; + } else { + db_printf("Parse failed. Unexpected token %d.\n", t); + goto exit; + } + + /* Next, look for a separator, if appropriate. */ + if (i == tets - 1) + continue; + + t = db_read_token_flags(tokflags); + if (af < 0) { + if (t == tCOLON) { + af = AF_INET6; + continue; + } + if (t == tCOLONCOLON) { + af = AF_INET6; + i++; + hextets[i] = 0; + exp = i; + continue; + } + if (t == tDOT) { + unsigned hn, dn; + + af = AF_INET; + /* Need to fixup the first parsed number. */ + if (hextets[0] > 0x255 || + (hextets[0] & 0xf0) > 0x90 || + (hextets[0] & 0xf) > 9) { + db_printf("Not a valid v4 octet: %x\n", + hextets[0]); + goto exit; + } + + hn = hextets[0]; + dn = (hn >> 8) * 100 + + ((hn >> 4) & 0xf) * 10 + + (hn & 0xf); + + hextets[0] = dn; + + /* Switch to decimal for remaining octets. */ + tokflags &= ~DRT_RADIX_MASK; + tokflags |= DRT_DECIMAL; + + tets = 4; + continue; + } + + db_printf("Parse error. Unexpected token %d.\n", t); + goto exit; + } else if (af == AF_INET) { + if (t == tDOT) + continue; + db_printf("Expected '.' (%d) between octets but got " + "(%d).\n", tDOT, t); + goto exit; + + } else if (af == AF_INET6) { + if (t == tCOLON) + continue; + if (t == tCOLONCOLON) { + if (exp < 0) { + i++; + hextets[i] = 0; + exp = i; + continue; + } + db_printf("Got bogus second '::' in v6 " + "address.\n"); + goto exit; + } + if (t == tEOL) { + /* + * Handle in the earlier part of the loop + * because we need to handle trailing :: too. + */ + db_unread_token(t); + continue; + } + + db_printf("Expected ':' (%d) or '::' (%d) between " + "hextets but got (%d).\n", tCOLON, tCOLONCOLON, t); + goto exit; + } + } + + /* Check for trailing garbage. */ + if (i == tets) { + t = db_read_token_flags(tokflags); + if (t != tEOL) { + db_printf("Got unexpected garbage after address " + "(%d).\n", t); + goto exit; + } + } + + /* + * Need to expand compact INET6 addresses. + * + * Technically '::' for a single ':0:' is MUST NOT but just in case, + * don't bother expanding that form (exp >= 0 && i == tets case). + */ + if (af == AF_INET6 && exp >= 0 && i < tets) { + if (exp + 1 < i) { + memmove(&hextets[exp + 1 + (nitems(hextets) - i)], + &hextets[exp + 1], + (i - (exp + 1)) * sizeof(hextets[0])); + } + memset(&hextets[exp + 1], 0, (nitems(hextets) - i) * + sizeof(hextets[0])); + } + + memset(&u, 0, sizeof(u)); + if (af == AF_INET) { + u.dest_sin.sin_family = AF_INET; + u.dest_sin.sin_len = sizeof(u.dest_sin); + u.dest_sin.sin_addr.s_addr = htonl( + ((uint32_t)hextets[0] << 24) | + ((uint32_t)hextets[1] << 16) | + ((uint32_t)hextets[2] << 8) | + (uint32_t)hextets[3]); + dstp = (void *)&u.dest_sin; + dst_addrp = &u.dest_sin.sin_addr; + } else if (af == AF_INET6) { + u.dest_sin6.sin6_family = AF_INET6; + u.dest_sin6.sin6_len = sizeof(u.dest_sin6); + for (i = 0; i < nitems(hextets); i++) + u.dest_sin6.sin6_addr.s6_addr16[i] = htons(hextets[i]); + dstp = (void *)&u.dest_sin6; + dst_addrp = &u.dest_sin6.sin6_addr; + } else { + MPASS(false); + /* UNREACHABLE */ + /* Appease Clang false positive: */ + dstp = NULL; + } + + bp = inet_ntop(af, dst_addrp, buf, sizeof(buf)); + if (bp != NULL) + db_printf("Looking up route to destination '%s'\n", bp); + + CURVNET_SET(vnet0); + rt = rtalloc1(dstp, 0, RTF_RNH_LOCKED); + CURVNET_RESTORE(); + + if (rt == NULL) { + db_printf("Could not get route for that server.\n"); + return; + } + + rt_dumpentry_ddb((void *)rt, NULL); + RTFREE_LOCKED(rt); + + return; +usage: + db_printf("Usage: 'show route <address>'\n" + " Currently accepts only dotted-decimal INET or colon-separated\n" + " hextet INET6 addresses.\n"); +exit: + db_skip_to_eol(); +} + Modified: head/sys/net/rtsock.c ============================================================================== --- head/sys/net/rtsock.c Tue Apr 28 19:14:09 2020 (r360449) +++ head/sys/net/rtsock.c Tue Apr 28 20:00:17 2020 (r360450) @@ -54,11 +54,6 @@ #include <sys/sysctl.h> #include <sys/systm.h> -#ifdef DDB -#include <ddb/ddb.h> -#include <ddb/db_lex.h> -#endif - #include <net/if.h> #include <net/if_var.h> #include <net/if_dl.h> @@ -68,6 +63,9 @@ #include <net/raw_cb.h> #include <net/route.h> #include <net/route/route_var.h> +#ifdef RADIX_MPATH +#include <net/radix_mpath.h> +#endif #include <net/vnet.h> #include <netinet/in.h> @@ -182,8 +180,6 @@ static int sysctl_ifmalist(int af, struct walkarg *w); static int route_output(struct mbuf *m, struct socket *so, ...); static void rt_getmetrics(const struct rtentry *rt, struct rt_metrics *out); static void rt_dispatch(struct mbuf *, sa_family_t); -static struct sockaddr *rtsock_fix_netmask(struct sockaddr *dst, - struct sockaddr *smask, struct sockaddr_storage *dmask); static int handle_rtm_get(struct rt_addrinfo *info, u_int fibnum, struct rt_msghdr *rtm, struct rtentry **ret_nrt); static int update_rtm_from_rte(struct rt_addrinfo *info, @@ -1136,8 +1132,8 @@ rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinf * Fill in @dmask with valid netmask leaving original @smask * intact. Mostly used with radix netmasks. */ -static struct sockaddr * -rtsock_fix_netmask(struct sockaddr *dst, struct sockaddr *smask, +struct sockaddr * +rtsock_fix_netmask(const struct sockaddr *dst, const struct sockaddr *smask, struct sockaddr_storage *dmask) { if (dst == NULL || smask == NULL) @@ -2164,407 +2160,3 @@ static struct domain routedomain = { VNET_DOMAIN_SET(route); -#ifdef DDB -/* - * Unfortunately, RTF_ values are expressed as raw masks rather than powers of - * 2, so we cannot use them as nice C99 initializer indices below. - */ -static const char * const rtf_flag_strings[] = { - "UP", - "GATEWAY", - "HOST", - "REJECT", - "DYNAMIC", - "MODIFIED", - "DONE", - "UNUSED_0x80", - "UNUSED_0x100", - "XRESOLVE", - "LLDATA", - "STATIC", - "BLACKHOLE", - "UNUSED_0x2000", - "PROTO2", - "PROTO1", - "UNUSED_0x10000", - "UNUSED_0x20000", - "PROTO3", - "FIXEDMTU", - "PINNED", - "LOCAL", - "BROADCAST", - "MULTICAST", - /* Big gap. */ - [28] = "STICKY", - [30] = "RNH_LOCKED", - [31] = "GWFLAG_COMPAT", -}; - -static const char * __pure -rt_flag_name(unsigned idx) -{ - if (idx >= nitems(rtf_flag_strings)) - return ("INVALID_FLAG"); - if (rtf_flag_strings[idx] == NULL) - return ("UNKNOWN"); - return (rtf_flag_strings[idx]); -} - -static void -rt_dumpaddr_ddb(const char *name, const struct sockaddr *sa) -{ - char buf[INET6_ADDRSTRLEN], *res; - - res = NULL; - if (sa == NULL) - res = "NULL"; - else if (sa->sa_family == AF_INET) { - res = inet_ntop(AF_INET, - &((const struct sockaddr_in *)sa)->sin_addr, - buf, sizeof(buf)); - } else if (sa->sa_family == AF_INET6) { - res = inet_ntop(AF_INET6, - &((const struct sockaddr_in6 *)sa)->sin6_addr, - buf, sizeof(buf)); - } else if (sa->sa_family == AF_LINK) { - res = "on link"; - } - - if (res != NULL) { - db_printf("%s <%s> ", name, res); - return; - } - - db_printf("%s <af:%d> ", name, sa->sa_family); -} - -static int -rt_dumpentry_ddb(struct radix_node *rn, void *arg __unused) -{ - struct sockaddr_storage ss; - struct rtentry *rt; - int flags, idx; - - /* If RNTORT is important, put it in a header. */ - rt = (void *)rn; - - rt_dumpaddr_ddb("dst", rt_key(rt)); - rt_dumpaddr_ddb("gateway", &rt->rt_nhop->gw_sa); - rt_dumpaddr_ddb("netmask", rtsock_fix_netmask(rt_key(rt), rt_mask(rt), - &ss)); - if (rt->rt_ifp != NULL && (rt->rt_ifp->if_flags & IFF_DYING) == 0) { - rt_dumpaddr_ddb("ifp", rt->rt_ifp->if_addr->ifa_addr); - rt_dumpaddr_ddb("ifa", rt->rt_ifa->ifa_addr); - } - - db_printf("flags "); - flags = rt->rt_flags; - if (flags == 0) - db_printf("none"); - - while ((idx = ffs(flags)) > 0) { - idx--; - - if (flags != rt->rt_flags) - db_printf(","); - db_printf("%s", rt_flag_name(idx)); - - flags &= ~(1ul << idx); - } - - db_printf("\n"); - return (0); -} - -DB_SHOW_COMMAND(routetable, db_show_routetable_cmd) -{ - struct rib_head *rnh; - int error, i, lim; - - if (have_addr) - i = lim = addr; - else { - i = 1; - lim = AF_MAX; - } - - for (; i <= lim; i++) { - rnh = rt_tables_get_rnh(0, i); - if (rnh == NULL) { - if (have_addr) { - db_printf("%s: AF %d not supported?\n", - __func__, i); - break; - } - continue; - } - - if (!have_addr && i > 1) - db_printf("\n"); - - db_printf("Route table for AF %d%s%s%s:\n", i, - (i == AF_INET || i == AF_INET6) ? " (" : "", - (i == AF_INET) ? "INET" : (i == AF_INET6) ? "INET6" : "", - (i == AF_INET || i == AF_INET6) ? ")" : ""); - - error = rnh->rnh_walktree(&rnh->head, rt_dumpentry_ddb, NULL); - if (error != 0) - db_printf("%s: walktree(%d): %d\n", __func__, i, - error); - } -} - -_DB_FUNC(_show, route, db_show_route_cmd, db_show_table, CS_OWN, NULL) -{ - char buf[INET6_ADDRSTRLEN], *bp; - const void *dst_addrp; - struct sockaddr *dstp; - struct rtentry *rt; - union { - struct sockaddr_in dest_sin; - struct sockaddr_in6 dest_sin6; - } u; - uint16_t hextets[8]; - unsigned i, tets; - int t, af, exp, tokflags; - - /* - * Undecoded address family. No double-colon expansion seen yet. - */ - af = -1; - exp = -1; - /* Assume INET6 to start; we can work back if guess was wrong. */ - tokflags = DRT_WSPACE | DRT_HEX | DRT_HEXADECIMAL; - - /* - * db_command has lexed 'show route' for us. - */ - t = db_read_token_flags(tokflags); - if (t == tWSPACE) - t = db_read_token_flags(tokflags); - - /* - * tEOL: Just 'show route' isn't a valid mode. - * tMINUS: It's either '-h' or some invalid option. Regardless, usage. - */ - if (t == tEOL || t == tMINUS) - goto usage; - - db_unread_token(t); - - tets = nitems(hextets); - - /* - * Each loop iteration, we expect to read one octet (v4) or hextet - * (v6), followed by an appropriate field separator ('.' or ':' or - * '::'). - * - * At the start of each loop, we're looking for a number (octet or - * hextet). - * - * INET6 addresses have a special case where they may begin with '::'. - */ - for (i = 0; i < tets; i++) { - t = db_read_token_flags(tokflags); - - if (t == tCOLONCOLON) { - /* INET6 with leading '::' or invalid. */ - if (i != 0) { - db_printf("Parse error: unexpected extra " - "colons.\n"); - goto exit; - } - - af = AF_INET6; - exp = i; - hextets[i] = 0; - continue; - } else if (t == tNUMBER) { - /* - * Lexer separates out '-' as tMINUS, but make the - * assumption explicit here. - */ - MPASS(db_tok_number >= 0); - - if (af == AF_INET && db_tok_number > UINT8_MAX) { - db_printf("Not a valid v4 octet: %ld\n", - (long)db_tok_number); - goto exit; - } - hextets[i] = db_tok_number; - } else if (t == tEOL) { - /* - * We can only detect the end of an IPv6 address in - * compact representation with EOL. - */ - if (af != AF_INET6 || exp < 0) { - db_printf("Parse failed. Got unexpected EOF " - "when the address is not a compact-" - "representation IPv6 address.\n"); - goto exit; - } - break; - } else { - db_printf("Parse failed. Unexpected token %d.\n", t); - goto exit; - } - - /* Next, look for a separator, if appropriate. */ - if (i == tets - 1) - continue; - - t = db_read_token_flags(tokflags); - if (af < 0) { - if (t == tCOLON) { - af = AF_INET6; - continue; - } - if (t == tCOLONCOLON) { - af = AF_INET6; - i++; - hextets[i] = 0; - exp = i; - continue; - } - if (t == tDOT) { - unsigned hn, dn; - - af = AF_INET; - /* Need to fixup the first parsed number. */ - if (hextets[0] > 0x255 || - (hextets[0] & 0xf0) > 0x90 || - (hextets[0] & 0xf) > 9) { - db_printf("Not a valid v4 octet: %x\n", - hextets[0]); - goto exit; - } - - hn = hextets[0]; - dn = (hn >> 8) * 100 + - ((hn >> 4) & 0xf) * 10 + - (hn & 0xf); - - hextets[0] = dn; - - /* Switch to decimal for remaining octets. */ - tokflags &= ~DRT_RADIX_MASK; - tokflags |= DRT_DECIMAL; - - tets = 4; - continue; - } - - db_printf("Parse error. Unexpected token %d.\n", t); - goto exit; - } else if (af == AF_INET) { - if (t == tDOT) - continue; - db_printf("Expected '.' (%d) between octets but got " - "(%d).\n", tDOT, t); - goto exit; - - } else if (af == AF_INET6) { - if (t == tCOLON) - continue; - if (t == tCOLONCOLON) { - if (exp < 0) { - i++; - hextets[i] = 0; - exp = i; - continue; - } - db_printf("Got bogus second '::' in v6 " - "address.\n"); - goto exit; - } - if (t == tEOL) { - /* - * Handle in the earlier part of the loop - * because we need to handle trailing :: too. - */ - db_unread_token(t); - continue; - } - - db_printf("Expected ':' (%d) or '::' (%d) between " - "hextets but got (%d).\n", tCOLON, tCOLONCOLON, t); - goto exit; - } - } - - /* Check for trailing garbage. */ - if (i == tets) { - t = db_read_token_flags(tokflags); - if (t != tEOL) { - db_printf("Got unexpected garbage after address " - "(%d).\n", t); - goto exit; - } - } - - /* - * Need to expand compact INET6 addresses. - * - * Technically '::' for a single ':0:' is MUST NOT but just in case, - * don't bother expanding that form (exp >= 0 && i == tets case). - */ - if (af == AF_INET6 && exp >= 0 && i < tets) { - if (exp + 1 < i) { - memmove(&hextets[exp + 1 + (nitems(hextets) - i)], - &hextets[exp + 1], - (i - (exp + 1)) * sizeof(hextets[0])); - } - memset(&hextets[exp + 1], 0, (nitems(hextets) - i) * - sizeof(hextets[0])); - } - - memset(&u, 0, sizeof(u)); - if (af == AF_INET) { - u.dest_sin.sin_family = AF_INET; - u.dest_sin.sin_len = sizeof(u.dest_sin); - u.dest_sin.sin_addr.s_addr = htonl( - ((uint32_t)hextets[0] << 24) | - ((uint32_t)hextets[1] << 16) | - ((uint32_t)hextets[2] << 8) | - (uint32_t)hextets[3]); - dstp = (void *)&u.dest_sin; - dst_addrp = &u.dest_sin.sin_addr; - } else if (af == AF_INET6) { - u.dest_sin6.sin6_family = AF_INET6; - u.dest_sin6.sin6_len = sizeof(u.dest_sin6); - for (i = 0; i < nitems(hextets); i++) - u.dest_sin6.sin6_addr.s6_addr16[i] = htons(hextets[i]); - dstp = (void *)&u.dest_sin6; - dst_addrp = &u.dest_sin6.sin6_addr; - } else { - MPASS(false); - /* UNREACHABLE */ - /* Appease Clang false positive: */ - dstp = NULL; - } - - bp = inet_ntop(af, dst_addrp, buf, sizeof(buf)); - if (bp != NULL) - db_printf("Looking up route to destination '%s'\n", bp); - - CURVNET_SET(vnet0); - rt = rtalloc1(dstp, 0, RTF_RNH_LOCKED); - CURVNET_RESTORE(); - - if (rt == NULL) { - db_printf("Could not get route for that server.\n"); - return; - } - - rt_dumpentry_ddb((void *)rt, NULL); - RTFREE_LOCKED(rt); - - return; -usage: - db_printf("Usage: 'show route <address>'\n" - " Currently accepts only dotted-decimal INET or colon-separated\n" - " hextet INET6 addresses.\n"); -exit: - db_skip_to_eol(); -} -#endif
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202004282000.03SK0HK1055981>