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