xref: /freebsd/sys/net/route/route_ddb.c (revision 4d846d26)
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 __FBSDID("$FreeBSD$");
30fc88ecd3SAlexander V. Chernikov #include "opt_inet.h"
31fc88ecd3SAlexander V. Chernikov #include "opt_inet6.h"
32fc88ecd3SAlexander V. Chernikov 
334f08f052SAlexander V. Chernikov #include <sys/ctype.h>
34fc88ecd3SAlexander V. Chernikov #include <sys/param.h>
35fc88ecd3SAlexander V. Chernikov #include <sys/systm.h>
36fc88ecd3SAlexander V. Chernikov #include <sys/malloc.h>
37fc88ecd3SAlexander V. Chernikov #include <sys/mbuf.h>
38fc88ecd3SAlexander V. Chernikov #include <sys/socket.h>
39fc88ecd3SAlexander V. Chernikov #include <sys/sysctl.h>
40fc88ecd3SAlexander V. Chernikov #include <sys/syslog.h>
41fc88ecd3SAlexander V. Chernikov #include <sys/kernel.h>
42fc88ecd3SAlexander V. Chernikov #include <sys/lock.h>
43fc88ecd3SAlexander V. Chernikov #include <sys/rmlock.h>
44fc88ecd3SAlexander V. Chernikov 
45fc88ecd3SAlexander V. Chernikov #include <ddb/ddb.h>
46fc88ecd3SAlexander V. Chernikov #include <ddb/db_lex.h>
47fc88ecd3SAlexander V. Chernikov 
48fc88ecd3SAlexander V. Chernikov #include <net/if.h>
49fc88ecd3SAlexander V. Chernikov #include <net/if_var.h>
502c2b37adSJustin Hibbits #include <net/if_private.h>
51fc88ecd3SAlexander V. Chernikov #include <net/if_dl.h>
52fc88ecd3SAlexander V. Chernikov #include <net/route.h>
53fc88ecd3SAlexander V. Chernikov #include <net/route/nhop.h>
54da187ddbSAlexander V. Chernikov #include <net/route/route_ctl.h>
55656442a7SAlexander V. Chernikov #include <net/route/route_var.h>
56fc88ecd3SAlexander V. Chernikov 
57fc88ecd3SAlexander V. Chernikov /*
58fc88ecd3SAlexander V. Chernikov  * Unfortunately, RTF_ values are expressed as raw masks rather than powers of
59fc88ecd3SAlexander V. Chernikov  * 2, so we cannot use them as nice C99 initializer indices below.
60fc88ecd3SAlexander V. Chernikov  */
61fc88ecd3SAlexander V. Chernikov static const char * const rtf_flag_strings[] = {
62fc88ecd3SAlexander V. Chernikov 	"UP",
63fc88ecd3SAlexander V. Chernikov 	"GATEWAY",
64fc88ecd3SAlexander V. Chernikov 	"HOST",
65fc88ecd3SAlexander V. Chernikov 	"REJECT",
66fc88ecd3SAlexander V. Chernikov 	"DYNAMIC",
67fc88ecd3SAlexander V. Chernikov 	"MODIFIED",
68fc88ecd3SAlexander V. Chernikov 	"DONE",
69fc88ecd3SAlexander V. Chernikov 	"UNUSED_0x80",
70fc88ecd3SAlexander V. Chernikov 	"UNUSED_0x100",
71fc88ecd3SAlexander V. Chernikov 	"XRESOLVE",
72fc88ecd3SAlexander V. Chernikov 	"LLDATA",
73fc88ecd3SAlexander V. Chernikov 	"STATIC",
74fc88ecd3SAlexander V. Chernikov 	"BLACKHOLE",
75fc88ecd3SAlexander V. Chernikov 	"UNUSED_0x2000",
76fc88ecd3SAlexander V. Chernikov 	"PROTO2",
77fc88ecd3SAlexander V. Chernikov 	"PROTO1",
78fc88ecd3SAlexander V. Chernikov 	"UNUSED_0x10000",
79fc88ecd3SAlexander V. Chernikov 	"UNUSED_0x20000",
80fc88ecd3SAlexander V. Chernikov 	"PROTO3",
81fc88ecd3SAlexander V. Chernikov 	"FIXEDMTU",
82fc88ecd3SAlexander V. Chernikov 	"PINNED",
83fc88ecd3SAlexander V. Chernikov 	"LOCAL",
84fc88ecd3SAlexander V. Chernikov 	"BROADCAST",
85fc88ecd3SAlexander V. Chernikov 	"MULTICAST",
86fc88ecd3SAlexander V. Chernikov 	/* Big gap. */
87fc88ecd3SAlexander V. Chernikov 	[28] = "STICKY",
88fc88ecd3SAlexander V. Chernikov 	[30] = "RNH_LOCKED",
89fc88ecd3SAlexander V. Chernikov 	[31] = "GWFLAG_COMPAT",
90fc88ecd3SAlexander V. Chernikov };
91fc88ecd3SAlexander V. Chernikov 
92fc88ecd3SAlexander V. Chernikov static const char * __pure
93fc88ecd3SAlexander V. Chernikov rt_flag_name(unsigned idx)
94fc88ecd3SAlexander V. Chernikov {
95fc88ecd3SAlexander V. Chernikov 	if (idx >= nitems(rtf_flag_strings))
96fc88ecd3SAlexander V. Chernikov 		return ("INVALID_FLAG");
97fc88ecd3SAlexander V. Chernikov 	if (rtf_flag_strings[idx] == NULL)
98fc88ecd3SAlexander V. Chernikov 		return ("UNKNOWN");
99fc88ecd3SAlexander V. Chernikov 	return (rtf_flag_strings[idx]);
100fc88ecd3SAlexander V. Chernikov }
101fc88ecd3SAlexander V. Chernikov 
102fc88ecd3SAlexander V. Chernikov static void
103fc88ecd3SAlexander V. Chernikov rt_dumpaddr_ddb(const char *name, const struct sockaddr *sa)
104fc88ecd3SAlexander V. Chernikov {
105fc88ecd3SAlexander V. Chernikov 	char buf[INET6_ADDRSTRLEN], *res;
106fc88ecd3SAlexander V. Chernikov 
107fc88ecd3SAlexander V. Chernikov 	res = NULL;
108fc88ecd3SAlexander V. Chernikov 	if (sa == NULL)
109fc88ecd3SAlexander V. Chernikov 		res = "NULL";
110fc88ecd3SAlexander V. Chernikov 	else if (sa->sa_family == AF_INET) {
111fc88ecd3SAlexander V. Chernikov 		res = inet_ntop(AF_INET,
112fc88ecd3SAlexander V. Chernikov 		    &((const struct sockaddr_in *)sa)->sin_addr,
113fc88ecd3SAlexander V. Chernikov 		    buf, sizeof(buf));
114fc88ecd3SAlexander V. Chernikov 	} else if (sa->sa_family == AF_INET6) {
115fc88ecd3SAlexander V. Chernikov 		res = inet_ntop(AF_INET6,
116fc88ecd3SAlexander V. Chernikov 		    &((const struct sockaddr_in6 *)sa)->sin6_addr,
117fc88ecd3SAlexander V. Chernikov 		    buf, sizeof(buf));
118fc88ecd3SAlexander V. Chernikov 	} else if (sa->sa_family == AF_LINK) {
119fc88ecd3SAlexander V. Chernikov 		res = "on link";
120fc88ecd3SAlexander V. Chernikov 	}
121fc88ecd3SAlexander V. Chernikov 
122fc88ecd3SAlexander V. Chernikov 	if (res != NULL) {
123fc88ecd3SAlexander V. Chernikov 		db_printf("%s <%s> ", name, res);
124fc88ecd3SAlexander V. Chernikov 		return;
125fc88ecd3SAlexander V. Chernikov 	}
126fc88ecd3SAlexander V. Chernikov 
127fc88ecd3SAlexander V. Chernikov 	db_printf("%s <af:%d> ", name, sa->sa_family);
128fc88ecd3SAlexander V. Chernikov }
129fc88ecd3SAlexander V. Chernikov 
130fc88ecd3SAlexander V. Chernikov static int
131fc88ecd3SAlexander V. Chernikov rt_dumpentry_ddb(struct radix_node *rn, void *arg __unused)
132fc88ecd3SAlexander V. Chernikov {
133fc88ecd3SAlexander V. Chernikov 	struct sockaddr_storage ss;
134fc88ecd3SAlexander V. Chernikov 	struct rtentry *rt;
1358c61eb21SAlexander V. Chernikov 	struct nhop_object *nh;
136fc88ecd3SAlexander V. Chernikov 	int flags, idx;
137fc88ecd3SAlexander V. Chernikov 
138fc88ecd3SAlexander V. Chernikov 	/* If RNTORT is important, put it in a header. */
139fc88ecd3SAlexander V. Chernikov 	rt = (void *)rn;
1408c61eb21SAlexander V. Chernikov 	nh = (struct nhop_object *)rt->rt_nhop;
141fc88ecd3SAlexander V. Chernikov 
142fc88ecd3SAlexander V. Chernikov 	rt_dumpaddr_ddb("dst", rt_key(rt));
143fc88ecd3SAlexander V. Chernikov 	rt_dumpaddr_ddb("gateway", &rt->rt_nhop->gw_sa);
144fc88ecd3SAlexander V. Chernikov 	rt_dumpaddr_ddb("netmask", rtsock_fix_netmask(rt_key(rt), rt_mask(rt),
145fc88ecd3SAlexander V. Chernikov 	    &ss));
1468c61eb21SAlexander V. Chernikov 	if ((nh->nh_ifp->if_flags & IFF_DYING) == 0) {
1478c61eb21SAlexander V. Chernikov 		rt_dumpaddr_ddb("ifp", nh->nh_ifp->if_addr->ifa_addr);
1488c61eb21SAlexander V. Chernikov 		rt_dumpaddr_ddb("ifa", nh->nh_ifa->ifa_addr);
149fc88ecd3SAlexander V. Chernikov 	}
150fc88ecd3SAlexander V. Chernikov 
151fc88ecd3SAlexander V. Chernikov 	db_printf("flags ");
15293bfd365SAlexander V. Chernikov 	flags = rt->rte_flags | nhop_get_rtflags(nh);
153fc88ecd3SAlexander V. Chernikov 	if (flags == 0)
154fc88ecd3SAlexander V. Chernikov 		db_printf("none");
155fc88ecd3SAlexander V. Chernikov 
156fc88ecd3SAlexander V. Chernikov 	while ((idx = ffs(flags)) > 0) {
157fc88ecd3SAlexander V. Chernikov 		idx--;
158fc88ecd3SAlexander V. Chernikov 
159fc88ecd3SAlexander V. Chernikov 		db_printf("%s", rt_flag_name(idx));
160fc88ecd3SAlexander V. Chernikov 		flags &= ~(1ul << idx);
16193bfd365SAlexander V. Chernikov 		if (flags != 0)
16293bfd365SAlexander V. Chernikov 			db_printf(",");
163fc88ecd3SAlexander V. Chernikov 	}
164fc88ecd3SAlexander V. Chernikov 
165fc88ecd3SAlexander V. Chernikov 	db_printf("\n");
166fc88ecd3SAlexander V. Chernikov 	return (0);
167fc88ecd3SAlexander V. Chernikov }
168fc88ecd3SAlexander V. Chernikov 
169fc88ecd3SAlexander V. Chernikov DB_SHOW_COMMAND(routetable, db_show_routetable_cmd)
170fc88ecd3SAlexander V. Chernikov {
171fc88ecd3SAlexander V. Chernikov 	struct rib_head *rnh;
172fc88ecd3SAlexander V. Chernikov 	int error, i, lim;
173fc88ecd3SAlexander V. Chernikov 
174fc88ecd3SAlexander V. Chernikov 	if (have_addr)
175fc88ecd3SAlexander V. Chernikov 		i = lim = addr;
176fc88ecd3SAlexander V. Chernikov 	else {
177fc88ecd3SAlexander V. Chernikov 		i = 1;
178fc88ecd3SAlexander V. Chernikov 		lim = AF_MAX;
179fc88ecd3SAlexander V. Chernikov 	}
180fc88ecd3SAlexander V. Chernikov 
181fc88ecd3SAlexander V. Chernikov 	for (; i <= lim; i++) {
182fc88ecd3SAlexander V. Chernikov 		rnh = rt_tables_get_rnh(0, i);
183fc88ecd3SAlexander V. Chernikov 		if (rnh == NULL) {
184fc88ecd3SAlexander V. Chernikov 			if (have_addr) {
185fc88ecd3SAlexander V. Chernikov 				db_printf("%s: AF %d not supported?\n",
186fc88ecd3SAlexander V. Chernikov 				    __func__, i);
187fc88ecd3SAlexander V. Chernikov 				break;
188fc88ecd3SAlexander V. Chernikov 			}
189fc88ecd3SAlexander V. Chernikov 			continue;
190fc88ecd3SAlexander V. Chernikov 		}
191fc88ecd3SAlexander V. Chernikov 
192fc88ecd3SAlexander V. Chernikov 		if (!have_addr && i > 1)
193fc88ecd3SAlexander V. Chernikov 			db_printf("\n");
194fc88ecd3SAlexander V. Chernikov 
195fc88ecd3SAlexander V. Chernikov 		db_printf("Route table for AF %d%s%s%s:\n", i,
196fc88ecd3SAlexander V. Chernikov 		    (i == AF_INET || i == AF_INET6) ? " (" : "",
197fc88ecd3SAlexander V. Chernikov 		    (i == AF_INET) ? "INET" : (i == AF_INET6) ? "INET6" : "",
198fc88ecd3SAlexander V. Chernikov 		    (i == AF_INET || i == AF_INET6) ? ")" : "");
199fc88ecd3SAlexander V. Chernikov 
200fc88ecd3SAlexander V. Chernikov 		error = rnh->rnh_walktree(&rnh->head, rt_dumpentry_ddb, NULL);
201fc88ecd3SAlexander V. Chernikov 		if (error != 0)
202fc88ecd3SAlexander V. Chernikov 			db_printf("%s: walktree(%d): %d\n", __func__, i,
203fc88ecd3SAlexander V. Chernikov 			    error);
204fc88ecd3SAlexander V. Chernikov 	}
205fc88ecd3SAlexander V. Chernikov }
206fc88ecd3SAlexander V. Chernikov 
207258958b3SMitchell Horne DB_SHOW_COMMAND_FLAGS(route, db_show_route_cmd, CS_OWN)
208fc88ecd3SAlexander V. Chernikov {
2094f08f052SAlexander V. Chernikov 	char abuf[INET6_ADDRSTRLEN], *buf, *end;
210d94be4ccSAlexander V. Chernikov 	struct rib_head *rh;
211d94be4ccSAlexander V. Chernikov 	struct radix_node *rn;
2124f08f052SAlexander V. Chernikov 	void *dst_addrp;
213fc88ecd3SAlexander V. Chernikov 	struct rtentry *rt;
214fc88ecd3SAlexander V. Chernikov 	union {
215fc88ecd3SAlexander V. Chernikov 		struct sockaddr_in dest_sin;
216fc88ecd3SAlexander V. Chernikov 		struct sockaddr_in6 dest_sin6;
217fc88ecd3SAlexander V. Chernikov 	} u;
2184f08f052SAlexander V. Chernikov 	int af;
219fc88ecd3SAlexander V. Chernikov 
2204f08f052SAlexander V. Chernikov 	buf = db_get_line();
221fc88ecd3SAlexander V. Chernikov 
2224f08f052SAlexander V. Chernikov 	/* Remove whitespaces from both ends */
2234f08f052SAlexander V. Chernikov 	end = buf + strlen(buf) - 1;
2244f08f052SAlexander V. Chernikov 	for (; (end >= buf) && (*end=='\n' || isspace(*end)); end--)
2254f08f052SAlexander V. Chernikov 		*end = '\0';
2264f08f052SAlexander V. Chernikov 	while (isspace(*buf))
2274f08f052SAlexander V. Chernikov 		buf++;
228fc88ecd3SAlexander V. Chernikov 
2294f08f052SAlexander V. Chernikov 	/* Determine AF */
2304f08f052SAlexander V. Chernikov 	if (strchr(buf, ':') != NULL) {
231fc88ecd3SAlexander V. Chernikov 		af = AF_INET6;
2324f08f052SAlexander V. Chernikov 		u.dest_sin6.sin6_family = af;
2334f08f052SAlexander V. Chernikov 		u.dest_sin6.sin6_len = sizeof(struct sockaddr_in6);
234fc88ecd3SAlexander V. Chernikov 		dst_addrp = &u.dest_sin6.sin6_addr;
235fc88ecd3SAlexander V. Chernikov 	} else {
2364f08f052SAlexander V. Chernikov 		af = AF_INET;
2374f08f052SAlexander V. Chernikov 		u.dest_sin.sin_family = af;
2384f08f052SAlexander V. Chernikov 		u.dest_sin.sin_len = sizeof(struct sockaddr_in);
2394f08f052SAlexander V. Chernikov 		dst_addrp = &u.dest_sin.sin_addr;
240fc88ecd3SAlexander V. Chernikov 	}
241fc88ecd3SAlexander V. Chernikov 
2424f08f052SAlexander V. Chernikov 	if (inet_pton(af, buf, dst_addrp) != 1)
2434f08f052SAlexander V. Chernikov 		goto usage;
2444f08f052SAlexander V. Chernikov 
2454f08f052SAlexander V. Chernikov 	if (inet_ntop(af, dst_addrp, abuf, sizeof(abuf)) != NULL)
2464f08f052SAlexander V. Chernikov 		db_printf("Looking up route to destination '%s'\n", abuf);
247fc88ecd3SAlexander V. Chernikov 
248d94be4ccSAlexander V. Chernikov 	rt = NULL;
249fc88ecd3SAlexander V. Chernikov 	CURVNET_SET(vnet0);
250d94be4ccSAlexander V. Chernikov 
251d94be4ccSAlexander V. Chernikov 	rh = rt_tables_get_rnh(RT_DEFAULT_FIB, af);
252d94be4ccSAlexander V. Chernikov 
253d94be4ccSAlexander V. Chernikov 	rn = rh->rnh_matchaddr(&u, &rh->head);
254d94be4ccSAlexander V. Chernikov 	if (rn && ((rn->rn_flags & RNF_ROOT) == 0))
255d94be4ccSAlexander V. Chernikov 		rt = (struct rtentry *)rn;
256d94be4ccSAlexander V. Chernikov 
257fc88ecd3SAlexander V. Chernikov 	CURVNET_RESTORE();
258fc88ecd3SAlexander V. Chernikov 
259fc88ecd3SAlexander V. Chernikov 	if (rt == NULL) {
260fc88ecd3SAlexander V. Chernikov 		db_printf("Could not get route for that server.\n");
261fc88ecd3SAlexander V. Chernikov 		return;
262fc88ecd3SAlexander V. Chernikov 	}
263fc88ecd3SAlexander V. Chernikov 
264fc88ecd3SAlexander V. Chernikov 	rt_dumpentry_ddb((void *)rt, NULL);
265fc88ecd3SAlexander V. Chernikov 
266fc88ecd3SAlexander V. Chernikov 	return;
267fc88ecd3SAlexander V. Chernikov usage:
268fc88ecd3SAlexander V. Chernikov 	db_printf("Usage: 'show route <address>'\n"
2694f08f052SAlexander V. Chernikov 	    "  Currently accepts only IPv4 and IPv6 addresses\n");
270fc88ecd3SAlexander V. Chernikov 	db_skip_to_eol();
271fc88ecd3SAlexander V. Chernikov }
272