xref: /freebsd/sys/net/route/route_ddb.c (revision 685dc743)
1fc88ecd3SAlexander V. Chernikov /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3fc88ecd3SAlexander V. Chernikov  *
4fc88ecd3SAlexander V. Chernikov  * Copyright 2019 Conrad Meyer <cem@FreeBSD.org>
5fc88ecd3SAlexander V. Chernikov  *
6fc88ecd3SAlexander V. Chernikov  * Redistribution and use in source and binary forms, with or without
7fc88ecd3SAlexander V. Chernikov  * modification, are permitted provided that the following conditions
8fc88ecd3SAlexander V. Chernikov  * are met:
9fc88ecd3SAlexander V. Chernikov  * 1. Redistributions of source code must retain the above copyright
10fc88ecd3SAlexander V. Chernikov  *    notice, this list of conditions and the following disclaimer.
11fc88ecd3SAlexander V. Chernikov  * 2. Redistributions in binary form must reproduce the above copyright
12fc88ecd3SAlexander V. Chernikov  *    notice, this list of conditions and the following disclaimer in the
13fc88ecd3SAlexander V. Chernikov  *    documentation and/or other materials provided with the distribution.
14fc88ecd3SAlexander V. Chernikov  *
15fc88ecd3SAlexander V. Chernikov  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16fc88ecd3SAlexander V. Chernikov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17fc88ecd3SAlexander V. Chernikov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18fc88ecd3SAlexander V. Chernikov  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19fc88ecd3SAlexander V. Chernikov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20fc88ecd3SAlexander V. Chernikov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21fc88ecd3SAlexander V. Chernikov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22fc88ecd3SAlexander V. Chernikov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23fc88ecd3SAlexander V. Chernikov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24fc88ecd3SAlexander V. Chernikov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25fc88ecd3SAlexander V. Chernikov  * SUCH DAMAGE.
26fc88ecd3SAlexander V. Chernikov  */
27fc88ecd3SAlexander V. Chernikov 
28fc88ecd3SAlexander V. Chernikov #include <sys/cdefs.h>
29fc88ecd3SAlexander V. Chernikov #include "opt_inet.h"
30fc88ecd3SAlexander V. Chernikov #include "opt_inet6.h"
31fc88ecd3SAlexander V. Chernikov 
324f08f052SAlexander V. Chernikov #include <sys/ctype.h>
33fc88ecd3SAlexander V. Chernikov #include <sys/param.h>
34fc88ecd3SAlexander V. Chernikov #include <sys/systm.h>
35fc88ecd3SAlexander V. Chernikov #include <sys/malloc.h>
36fc88ecd3SAlexander V. Chernikov #include <sys/mbuf.h>
37fc88ecd3SAlexander V. Chernikov #include <sys/socket.h>
38fc88ecd3SAlexander V. Chernikov #include <sys/sysctl.h>
39fc88ecd3SAlexander V. Chernikov #include <sys/syslog.h>
40fc88ecd3SAlexander V. Chernikov #include <sys/kernel.h>
41fc88ecd3SAlexander V. Chernikov #include <sys/lock.h>
42fc88ecd3SAlexander V. Chernikov #include <sys/rmlock.h>
43fc88ecd3SAlexander V. Chernikov 
44fc88ecd3SAlexander V. Chernikov #include <ddb/ddb.h>
45fc88ecd3SAlexander V. Chernikov #include <ddb/db_lex.h>
46fc88ecd3SAlexander V. Chernikov 
47fc88ecd3SAlexander V. Chernikov #include <net/if.h>
48fc88ecd3SAlexander V. Chernikov #include <net/if_var.h>
492c2b37adSJustin Hibbits #include <net/if_private.h>
50fc88ecd3SAlexander V. Chernikov #include <net/if_dl.h>
51fc88ecd3SAlexander V. Chernikov #include <net/route.h>
52fc88ecd3SAlexander V. Chernikov #include <net/route/nhop.h>
53da187ddbSAlexander V. Chernikov #include <net/route/route_ctl.h>
54656442a7SAlexander V. Chernikov #include <net/route/route_var.h>
55fc88ecd3SAlexander V. Chernikov 
56fc88ecd3SAlexander V. Chernikov /*
57fc88ecd3SAlexander V. Chernikov  * Unfortunately, RTF_ values are expressed as raw masks rather than powers of
58fc88ecd3SAlexander V. Chernikov  * 2, so we cannot use them as nice C99 initializer indices below.
59fc88ecd3SAlexander V. Chernikov  */
60fc88ecd3SAlexander V. Chernikov static const char * const rtf_flag_strings[] = {
61fc88ecd3SAlexander V. Chernikov 	"UP",
62fc88ecd3SAlexander V. Chernikov 	"GATEWAY",
63fc88ecd3SAlexander V. Chernikov 	"HOST",
64fc88ecd3SAlexander V. Chernikov 	"REJECT",
65fc88ecd3SAlexander V. Chernikov 	"DYNAMIC",
66fc88ecd3SAlexander V. Chernikov 	"MODIFIED",
67fc88ecd3SAlexander V. Chernikov 	"DONE",
68fc88ecd3SAlexander V. Chernikov 	"UNUSED_0x80",
69fc88ecd3SAlexander V. Chernikov 	"UNUSED_0x100",
70fc88ecd3SAlexander V. Chernikov 	"XRESOLVE",
71fc88ecd3SAlexander V. Chernikov 	"LLDATA",
72fc88ecd3SAlexander V. Chernikov 	"STATIC",
73fc88ecd3SAlexander V. Chernikov 	"BLACKHOLE",
74fc88ecd3SAlexander V. Chernikov 	"UNUSED_0x2000",
75fc88ecd3SAlexander V. Chernikov 	"PROTO2",
76fc88ecd3SAlexander V. Chernikov 	"PROTO1",
77fc88ecd3SAlexander V. Chernikov 	"UNUSED_0x10000",
78fc88ecd3SAlexander V. Chernikov 	"UNUSED_0x20000",
79fc88ecd3SAlexander V. Chernikov 	"PROTO3",
80fc88ecd3SAlexander V. Chernikov 	"FIXEDMTU",
81fc88ecd3SAlexander V. Chernikov 	"PINNED",
82fc88ecd3SAlexander V. Chernikov 	"LOCAL",
83fc88ecd3SAlexander V. Chernikov 	"BROADCAST",
84fc88ecd3SAlexander V. Chernikov 	"MULTICAST",
85fc88ecd3SAlexander V. Chernikov 	/* Big gap. */
86fc88ecd3SAlexander V. Chernikov 	[28] = "STICKY",
87fc88ecd3SAlexander V. Chernikov 	[30] = "RNH_LOCKED",
88fc88ecd3SAlexander V. Chernikov 	[31] = "GWFLAG_COMPAT",
89fc88ecd3SAlexander V. Chernikov };
90fc88ecd3SAlexander V. Chernikov 
91fc88ecd3SAlexander V. Chernikov static const char * __pure
rt_flag_name(unsigned idx)92fc88ecd3SAlexander V. Chernikov rt_flag_name(unsigned idx)
93fc88ecd3SAlexander V. Chernikov {
94fc88ecd3SAlexander V. Chernikov 	if (idx >= nitems(rtf_flag_strings))
95fc88ecd3SAlexander V. Chernikov 		return ("INVALID_FLAG");
96fc88ecd3SAlexander V. Chernikov 	if (rtf_flag_strings[idx] == NULL)
97fc88ecd3SAlexander V. Chernikov 		return ("UNKNOWN");
98fc88ecd3SAlexander V. Chernikov 	return (rtf_flag_strings[idx]);
99fc88ecd3SAlexander V. Chernikov }
100fc88ecd3SAlexander V. Chernikov 
101fc88ecd3SAlexander V. Chernikov static void
rt_dumpaddr_ddb(const char * name,const struct sockaddr * sa)102fc88ecd3SAlexander V. Chernikov rt_dumpaddr_ddb(const char *name, const struct sockaddr *sa)
103fc88ecd3SAlexander V. Chernikov {
104fc88ecd3SAlexander V. Chernikov 	char buf[INET6_ADDRSTRLEN], *res;
105fc88ecd3SAlexander V. Chernikov 
106fc88ecd3SAlexander V. Chernikov 	res = NULL;
107fc88ecd3SAlexander V. Chernikov 	if (sa == NULL)
108fc88ecd3SAlexander V. Chernikov 		res = "NULL";
109fc88ecd3SAlexander V. Chernikov 	else if (sa->sa_family == AF_INET) {
110fc88ecd3SAlexander V. Chernikov 		res = inet_ntop(AF_INET,
111fc88ecd3SAlexander V. Chernikov 		    &((const struct sockaddr_in *)sa)->sin_addr,
112fc88ecd3SAlexander V. Chernikov 		    buf, sizeof(buf));
113fc88ecd3SAlexander V. Chernikov 	} else if (sa->sa_family == AF_INET6) {
114fc88ecd3SAlexander V. Chernikov 		res = inet_ntop(AF_INET6,
115fc88ecd3SAlexander V. Chernikov 		    &((const struct sockaddr_in6 *)sa)->sin6_addr,
116fc88ecd3SAlexander V. Chernikov 		    buf, sizeof(buf));
117fc88ecd3SAlexander V. Chernikov 	} else if (sa->sa_family == AF_LINK) {
118fc88ecd3SAlexander V. Chernikov 		res = "on link";
119fc88ecd3SAlexander V. Chernikov 	}
120fc88ecd3SAlexander V. Chernikov 
121fc88ecd3SAlexander V. Chernikov 	if (res != NULL) {
122fc88ecd3SAlexander V. Chernikov 		db_printf("%s <%s> ", name, res);
123fc88ecd3SAlexander V. Chernikov 		return;
124fc88ecd3SAlexander V. Chernikov 	}
125fc88ecd3SAlexander V. Chernikov 
126fc88ecd3SAlexander V. Chernikov 	db_printf("%s <af:%d> ", name, sa->sa_family);
127fc88ecd3SAlexander V. Chernikov }
128fc88ecd3SAlexander V. Chernikov 
129fc88ecd3SAlexander V. Chernikov static int
rt_dumpentry_ddb(struct radix_node * rn,void * arg __unused)130fc88ecd3SAlexander V. Chernikov rt_dumpentry_ddb(struct radix_node *rn, void *arg __unused)
131fc88ecd3SAlexander V. Chernikov {
132fc88ecd3SAlexander V. Chernikov 	struct sockaddr_storage ss;
133fc88ecd3SAlexander V. Chernikov 	struct rtentry *rt;
1348c61eb21SAlexander V. Chernikov 	struct nhop_object *nh;
135fc88ecd3SAlexander V. Chernikov 	int flags, idx;
136fc88ecd3SAlexander V. Chernikov 
137fc88ecd3SAlexander V. Chernikov 	/* If RNTORT is important, put it in a header. */
138fc88ecd3SAlexander V. Chernikov 	rt = (void *)rn;
1398c61eb21SAlexander V. Chernikov 	nh = (struct nhop_object *)rt->rt_nhop;
140fc88ecd3SAlexander V. Chernikov 
141fc88ecd3SAlexander V. Chernikov 	rt_dumpaddr_ddb("dst", rt_key(rt));
142fc88ecd3SAlexander V. Chernikov 	rt_dumpaddr_ddb("gateway", &rt->rt_nhop->gw_sa);
143fc88ecd3SAlexander V. Chernikov 	rt_dumpaddr_ddb("netmask", rtsock_fix_netmask(rt_key(rt), rt_mask(rt),
144fc88ecd3SAlexander V. Chernikov 	    &ss));
1458c61eb21SAlexander V. Chernikov 	if ((nh->nh_ifp->if_flags & IFF_DYING) == 0) {
1468c61eb21SAlexander V. Chernikov 		rt_dumpaddr_ddb("ifp", nh->nh_ifp->if_addr->ifa_addr);
1478c61eb21SAlexander V. Chernikov 		rt_dumpaddr_ddb("ifa", nh->nh_ifa->ifa_addr);
148fc88ecd3SAlexander V. Chernikov 	}
149fc88ecd3SAlexander V. Chernikov 
150fc88ecd3SAlexander V. Chernikov 	db_printf("flags ");
15193bfd365SAlexander V. Chernikov 	flags = rt->rte_flags | nhop_get_rtflags(nh);
152fc88ecd3SAlexander V. Chernikov 	if (flags == 0)
153fc88ecd3SAlexander V. Chernikov 		db_printf("none");
154fc88ecd3SAlexander V. Chernikov 
155fc88ecd3SAlexander V. Chernikov 	while ((idx = ffs(flags)) > 0) {
156fc88ecd3SAlexander V. Chernikov 		idx--;
157fc88ecd3SAlexander V. Chernikov 
158fc88ecd3SAlexander V. Chernikov 		db_printf("%s", rt_flag_name(idx));
159fc88ecd3SAlexander V. Chernikov 		flags &= ~(1ul << idx);
16093bfd365SAlexander V. Chernikov 		if (flags != 0)
16193bfd365SAlexander V. Chernikov 			db_printf(",");
162fc88ecd3SAlexander V. Chernikov 	}
163fc88ecd3SAlexander V. Chernikov 
164fc88ecd3SAlexander V. Chernikov 	db_printf("\n");
165fc88ecd3SAlexander V. Chernikov 	return (0);
166fc88ecd3SAlexander V. Chernikov }
167fc88ecd3SAlexander V. Chernikov 
DB_SHOW_COMMAND(routetable,db_show_routetable)168884eaacdSJohn Baldwin DB_SHOW_COMMAND(routetable, db_show_routetable)
169fc88ecd3SAlexander V. Chernikov {
170fc88ecd3SAlexander V. Chernikov 	struct rib_head *rnh;
171fc88ecd3SAlexander V. Chernikov 	int error, i, lim;
172fc88ecd3SAlexander V. Chernikov 
173fc88ecd3SAlexander V. Chernikov 	if (have_addr)
174fc88ecd3SAlexander V. Chernikov 		i = lim = addr;
175fc88ecd3SAlexander V. Chernikov 	else {
176fc88ecd3SAlexander V. Chernikov 		i = 1;
177fc88ecd3SAlexander V. Chernikov 		lim = AF_MAX;
178fc88ecd3SAlexander V. Chernikov 	}
179fc88ecd3SAlexander V. Chernikov 
180fc88ecd3SAlexander V. Chernikov 	for (; i <= lim; i++) {
181fc88ecd3SAlexander V. Chernikov 		rnh = rt_tables_get_rnh(0, i);
182fc88ecd3SAlexander V. Chernikov 		if (rnh == NULL) {
183fc88ecd3SAlexander V. Chernikov 			if (have_addr) {
184fc88ecd3SAlexander V. Chernikov 				db_printf("%s: AF %d not supported?\n",
185fc88ecd3SAlexander V. Chernikov 				    __func__, i);
186fc88ecd3SAlexander V. Chernikov 				break;
187fc88ecd3SAlexander V. Chernikov 			}
188fc88ecd3SAlexander V. Chernikov 			continue;
189fc88ecd3SAlexander V. Chernikov 		}
190fc88ecd3SAlexander V. Chernikov 
191fc88ecd3SAlexander V. Chernikov 		if (!have_addr && i > 1)
192fc88ecd3SAlexander V. Chernikov 			db_printf("\n");
193fc88ecd3SAlexander V. Chernikov 
194fc88ecd3SAlexander V. Chernikov 		db_printf("Route table for AF %d%s%s%s:\n", i,
195fc88ecd3SAlexander V. Chernikov 		    (i == AF_INET || i == AF_INET6) ? " (" : "",
196fc88ecd3SAlexander V. Chernikov 		    (i == AF_INET) ? "INET" : (i == AF_INET6) ? "INET6" : "",
197fc88ecd3SAlexander V. Chernikov 		    (i == AF_INET || i == AF_INET6) ? ")" : "");
198fc88ecd3SAlexander V. Chernikov 
199fc88ecd3SAlexander V. Chernikov 		error = rnh->rnh_walktree(&rnh->head, rt_dumpentry_ddb, NULL);
200fc88ecd3SAlexander V. Chernikov 		if (error != 0)
201fc88ecd3SAlexander V. Chernikov 			db_printf("%s: walktree(%d): %d\n", __func__, i,
202fc88ecd3SAlexander V. Chernikov 			    error);
203fc88ecd3SAlexander V. Chernikov 	}
204fc88ecd3SAlexander V. Chernikov }
205fc88ecd3SAlexander V. Chernikov 
DB_SHOW_COMMAND_FLAGS(route,db_show_route,CS_OWN)206884eaacdSJohn Baldwin DB_SHOW_COMMAND_FLAGS(route, db_show_route, CS_OWN)
207fc88ecd3SAlexander V. Chernikov {
2084f08f052SAlexander V. Chernikov 	char abuf[INET6_ADDRSTRLEN], *buf, *end;
209d94be4ccSAlexander V. Chernikov 	struct rib_head *rh;
210d94be4ccSAlexander V. Chernikov 	struct radix_node *rn;
2114f08f052SAlexander V. Chernikov 	void *dst_addrp;
212fc88ecd3SAlexander V. Chernikov 	struct rtentry *rt;
213fc88ecd3SAlexander V. Chernikov 	union {
214fc88ecd3SAlexander V. Chernikov 		struct sockaddr_in dest_sin;
215fc88ecd3SAlexander V. Chernikov 		struct sockaddr_in6 dest_sin6;
216fc88ecd3SAlexander V. Chernikov 	} u;
2174f08f052SAlexander V. Chernikov 	int af;
218fc88ecd3SAlexander V. Chernikov 
2194f08f052SAlexander V. Chernikov 	buf = db_get_line();
220fc88ecd3SAlexander V. Chernikov 
2214f08f052SAlexander V. Chernikov 	/* Remove whitespaces from both ends */
2224f08f052SAlexander V. Chernikov 	end = buf + strlen(buf) - 1;
2234f08f052SAlexander V. Chernikov 	for (; (end >= buf) && (*end=='\n' || isspace(*end)); end--)
2244f08f052SAlexander V. Chernikov 		*end = '\0';
2254f08f052SAlexander V. Chernikov 	while (isspace(*buf))
2264f08f052SAlexander V. Chernikov 		buf++;
227fc88ecd3SAlexander V. Chernikov 
2284f08f052SAlexander V. Chernikov 	/* Determine AF */
2294f08f052SAlexander V. Chernikov 	if (strchr(buf, ':') != NULL) {
230fc88ecd3SAlexander V. Chernikov 		af = AF_INET6;
2314f08f052SAlexander V. Chernikov 		u.dest_sin6.sin6_family = af;
2324f08f052SAlexander V. Chernikov 		u.dest_sin6.sin6_len = sizeof(struct sockaddr_in6);
233fc88ecd3SAlexander V. Chernikov 		dst_addrp = &u.dest_sin6.sin6_addr;
234fc88ecd3SAlexander V. Chernikov 	} else {
2354f08f052SAlexander V. Chernikov 		af = AF_INET;
2364f08f052SAlexander V. Chernikov 		u.dest_sin.sin_family = af;
2374f08f052SAlexander V. Chernikov 		u.dest_sin.sin_len = sizeof(struct sockaddr_in);
2384f08f052SAlexander V. Chernikov 		dst_addrp = &u.dest_sin.sin_addr;
239fc88ecd3SAlexander V. Chernikov 	}
240fc88ecd3SAlexander V. Chernikov 
2414f08f052SAlexander V. Chernikov 	if (inet_pton(af, buf, dst_addrp) != 1)
2424f08f052SAlexander V. Chernikov 		goto usage;
2434f08f052SAlexander V. Chernikov 
2444f08f052SAlexander V. Chernikov 	if (inet_ntop(af, dst_addrp, abuf, sizeof(abuf)) != NULL)
2454f08f052SAlexander V. Chernikov 		db_printf("Looking up route to destination '%s'\n", abuf);
246fc88ecd3SAlexander V. Chernikov 
247d94be4ccSAlexander V. Chernikov 	rt = NULL;
248fc88ecd3SAlexander V. Chernikov 	CURVNET_SET(vnet0);
249d94be4ccSAlexander V. Chernikov 
250d94be4ccSAlexander V. Chernikov 	rh = rt_tables_get_rnh(RT_DEFAULT_FIB, af);
251d94be4ccSAlexander V. Chernikov 
252d94be4ccSAlexander V. Chernikov 	rn = rh->rnh_matchaddr(&u, &rh->head);
253d94be4ccSAlexander V. Chernikov 	if (rn && ((rn->rn_flags & RNF_ROOT) == 0))
254d94be4ccSAlexander V. Chernikov 		rt = (struct rtentry *)rn;
255d94be4ccSAlexander V. Chernikov 
256fc88ecd3SAlexander V. Chernikov 	CURVNET_RESTORE();
257fc88ecd3SAlexander V. Chernikov 
258fc88ecd3SAlexander V. Chernikov 	if (rt == NULL) {
259fc88ecd3SAlexander V. Chernikov 		db_printf("Could not get route for that server.\n");
260fc88ecd3SAlexander V. Chernikov 		return;
261fc88ecd3SAlexander V. Chernikov 	}
262fc88ecd3SAlexander V. Chernikov 
263fc88ecd3SAlexander V. Chernikov 	rt_dumpentry_ddb((void *)rt, NULL);
264fc88ecd3SAlexander V. Chernikov 
265fc88ecd3SAlexander V. Chernikov 	return;
266fc88ecd3SAlexander V. Chernikov usage:
267fc88ecd3SAlexander V. Chernikov 	db_printf("Usage: 'show route <address>'\n"
2684f08f052SAlexander V. Chernikov 	    "  Currently accepts only IPv4 and IPv6 addresses\n");
269fc88ecd3SAlexander V. Chernikov 	db_skip_to_eol();
270fc88ecd3SAlexander V. Chernikov }
271