]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tests/sys/net/routing/rtsock_print.h
zfs: merge openzfs/zfs@ef83e07db (zfs-2.1-release) into stable/13
[FreeBSD/FreeBSD.git] / tests / sys / net / routing / rtsock_print.h
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2019 Alexander V. Chernikov
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  * $FreeBSD$
28  */
29
30 #ifndef _NET_ROUTING_RTSOCK_PRINT_H_
31 #define _NET_ROUTING_RTSOCK_PRINT_H_
32
33
34 #define RLOG(_fmt, ...) printf("%s: " _fmt "\n", __func__, ##__VA_ARGS__)
35 #define RLOG_ERRNO(_fmt, ...)   do {                    \
36         printf("%s: " _fmt, __func__, ##__VA_ARGS__);   \
37         printf(": %s\n", strerror(errno));              \
38 } while(0)
39
40 #define RTSOCK_ATF_REQUIRE_MSG(_rtm, _cond, _fmt, ...)   do {   \
41         if (!(_cond)) {                                         \
42                 printf("-- CONDITION FAILED, rtm dump  --\n\n");\
43                 rtsock_print_message(_rtm);                     \
44                 rtsock_print_table(AF_INET);                    \
45                 rtsock_print_table(AF_INET6);                   \
46                 printf("===================================\n");\
47         }                                                       \
48         ATF_REQUIRE_MSG(_cond, _fmt, ##__VA_ARGS__);            \
49 } while (0);
50
51 #define RTSOCKHD_ATF_REQUIRE_MSG(_rtm, _cond, _fmt, ...) do {   \
52         if (!(_cond)) {                                         \
53                 printf("-- CONDITION FAILED, rtm hexdump--\n\n");\
54                 rtsock_print_message_hd(_rtm);                          \
55         }                                                       \
56         ATF_REQUIRE_MSG(_cond, _fmt, ##__VA_ARGS__);            \
57 } while (0);
58
59
60 /* from route.c */
61 static const char *const msgtypes[] = {
62         "",
63         "RTM_ADD",
64         "RTM_DELETE",
65         "RTM_CHANGE",
66         "RTM_GET",
67         "RTM_LOSING",
68         "RTM_REDIRECT",
69         "RTM_MISS",
70         "RTM_LOCK",
71         "RTM_OLDADD",
72         "RTM_OLDDEL",
73         "RTM_RESOLVE",
74         "RTM_NEWADDR",
75         "RTM_DELADDR",
76         "RTM_IFINFO",
77         "RTM_NEWMADDR",
78         "RTM_DELMADDR",
79         "RTM_IFANNOUNCE",
80         "RTM_IEEE80211",
81 };
82
83 static const char metricnames[] =
84     "\011weight\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire"
85     "\1mtu";
86 static const char routeflags[] =
87     "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE"
88     "\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE"
89     "\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3"
90     "\024FIXEDMTU\025PINNED\026LOCAL\027BROADCAST\030MULTICAST\035STICKY";
91 static const char ifnetflags[] =
92     "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
93     "\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
94     "\017LINK2\020MULTICAST";
95 static const char addrnames[] =
96     "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
97
98 static int
99 _printb(char *buf, size_t bufsize, int b, const char *str)
100 {
101         int i;
102         int gotsome = 0;
103
104         char *pbuf = buf;
105
106         if (b == 0) {
107                 *pbuf = '\0';
108                 return (0);
109         }
110         while ((i = *str++) != 0) {
111                 if (b & (1 << (i-1))) {
112                         if (gotsome == 0)
113                                 i = '<';
114                         else
115                                 i = ',';
116                         *pbuf++ = i;
117                         gotsome = 1;
118                         for (; (i = *str) > 32; str++)
119                                 *pbuf++ = i;
120                 } else
121                         while (*str > 32)
122                                 str++;
123         }
124         if (gotsome)
125                 *pbuf++ = '>';
126         *pbuf = '\0';
127
128         return (int)(pbuf - buf);
129 }
130
131 const char *
132 rtsock_print_cmdtype(int cmd)
133 {
134
135         return (msgtypes[cmd]);
136 }
137
138 char *
139 rtsock_print_rtm_flags(char *buf, int buflen, int rtm_flags)
140 {
141
142         _printb(buf, buflen, rtm_flags, routeflags);
143         return (buf);
144 }
145
146
147 #define _PRINTX(fmt, ...)       do {                            \
148         one_len = snprintf(ptr, rem_len, fmt, __VA_ARGS__);     \
149         ptr += one_len;                                         \
150         rem_len -= one_len;                                     \
151 } while(0)
152
153
154 void
155 sa_print_hd(char *buf, int buflen, const char *data, int len)
156 {
157         char *ptr;
158         int one_len, rem_len;
159
160         ptr = buf;
161         rem_len = buflen;
162
163         const char *last_char = NULL;
164         unsigned char v;
165         int repeat_count = 0;
166         for (int i = 0; i < len; i++) {
167                 if (last_char && *last_char == data[i] && data[i] == 0x00) {
168                         repeat_count++;
169                         continue;
170                 }
171
172                 if (repeat_count > 1) {
173                         _PRINTX("{%d}", repeat_count);
174                         repeat_count = 0;
175                 }
176
177                 v = ((const unsigned char *)data)[i];
178                 if (last_char == NULL)
179                         _PRINTX("x%02X", v);
180                 else
181                         _PRINTX(", x%02X", v);
182
183                 last_char = &data[i];
184                 repeat_count = 1;
185         }
186
187         if (repeat_count > 1)
188                 snprintf(ptr, rem_len, "{%d}", repeat_count);
189 }
190
191 #undef _PRINTX
192
193 void
194 sa_print(const struct sockaddr *sa, int include_hexdump)
195 {
196         char hdbuf[512], abuf[64];
197         char ifbuf[128];
198         const struct sockaddr_dl *sdl;
199         const struct sockaddr_in6 *sin6;
200         const struct sockaddr_in *sin;
201         int i;
202
203         switch (sa->sa_family) {
204                 case AF_INET:
205                         sin = (struct sockaddr_in *)sa;
206                         inet_ntop(AF_INET, &sin->sin_addr, abuf, sizeof(abuf));
207                         printf(" af=inet len=%d addr=%s", sa->sa_len, abuf);
208                         break;
209                 case AF_INET6:
210                         sin6 = (struct sockaddr_in6 *)sa;
211                         inet_ntop(AF_INET6, &sin6->sin6_addr, abuf, sizeof(abuf));
212                         int scope_id = sin6->sin6_scope_id;
213                         printf(" af=inet6 len=%d addr=%s", sa->sa_len, abuf);
214                         if (scope_id != 0) {
215                                 memset(ifbuf, 0, sizeof(ifbuf));
216                                 if_indextoname(scope_id, ifbuf);
217                                 printf(" scope_id=%d if_name=%s", scope_id, ifbuf);
218                         }
219                         break;
220                 case AF_LINK:
221                         sdl = (const struct sockaddr_dl *)sa;
222                         int sdl_index = sdl->sdl_index;
223                         if (sdl_index != 0) {
224                                 memset(ifbuf, 0, sizeof(ifbuf));
225                                 if_indextoname(sdl_index, ifbuf);
226                                 printf(" af=link len=%d sdl_index=%d if_name=%s", sdl->sdl_len, sdl_index, ifbuf);
227                         }
228                         if (sdl->sdl_nlen) {
229                                 char _ifname[IFNAMSIZ];
230                                 memcpy(_ifname, sdl->sdl_data, sdl->sdl_nlen);
231                                 _ifname[sdl->sdl_nlen] = '\0';
232                                 printf(" name=%s", _ifname);
233                         }
234                         if (sdl->sdl_alen) {
235                                 printf(" addr=");
236                                 const char *lladdr = LLADDR(sdl);
237                                 for (int i = 0; i < sdl->sdl_alen; i++) {
238                                         if (i + 1 < sdl->sdl_alen)
239                                                 printf("%02X:", ((const unsigned char *)lladdr)[i]);
240                                         else
241                                                 printf("%02X", ((const unsigned char *)lladdr)[i]);
242                                 }
243                         }
244                         break;
245                 default:
246                         printf(" af=%d len=%d", sa->sa_family, sa->sa_len);
247         }
248
249         if (include_hexdump) {
250                 sa_print_hd(hdbuf, sizeof(hdbuf), ((char *)sa), sa->sa_len);
251                 printf(" hd={%s}", hdbuf);
252         }
253         printf("\n");
254 }
255
256 /*
257 got message of size 240 on Mon Dec 16 09:23:31 2019
258 RTM_ADD: Add Route: len 240, pid: 25534, seq 2, errno 0, flags:<HOST,DONE,LLINFO,STATIC>
259 locks:  inits:
260 sockaddrs: <DST,GATEWAY>
261 */
262
263 void
264 rtsock_print_rtm(struct rt_msghdr *rtm)
265 {
266         struct timeval tv;
267         struct tm tm_res;
268         char buf[64];
269
270         gettimeofday(&tv, NULL);
271         localtime_r(&tv.tv_sec, &tm_res);
272         strftime(buf, sizeof(buf), "%F %T", &tm_res);
273         printf("Got message of size %hu on %s\n", rtm->rtm_msglen, buf);
274
275         char flags_buf[256];
276         rtsock_print_rtm_flags(flags_buf, sizeof(flags_buf), rtm->rtm_flags);
277
278         printf("%s: len %hu, pid: %d, seq %d, errno %d, flags: %s\n", msgtypes[rtm->rtm_type],
279                 rtm->rtm_msglen, rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno, flags_buf);
280
281         if (rtm->rtm_inits > 0) {
282                 _printb(flags_buf, sizeof(flags_buf), rtm->rtm_inits, metricnames);
283                 printf("metrics: %s\n", flags_buf);
284                 if (rtm->rtm_inits & RTV_MTU)
285                         printf("mtu: %lu\n", rtm->rtm_rmx.rmx_mtu);
286                 if (rtm->rtm_inits & RTV_EXPIRE) {
287                         struct timeval tv;
288                         gettimeofday(&tv, NULL);
289                         printf("expire: %d (%lu raw)\n",
290                             (int)(rtm->rtm_rmx.rmx_expire - tv.tv_sec), rtm->rtm_rmx.rmx_expire);
291                 }
292         }
293
294         _printb(flags_buf, sizeof(flags_buf), rtm->rtm_addrs, addrnames);
295         printf("sockaddrs: 0x%X %s\n", rtm->rtm_addrs, flags_buf);
296
297         char *ptr = (char *)(rtm + 1);
298         for (int i = 0; i < RTAX_MAX; i++) {
299                 if (rtm->rtm_addrs & (1 << i)) {
300                         struct sockaddr *sa = (struct sockaddr *)ptr;
301                         sa_print(sa, 1);
302
303                         /* add */
304                         ptr += ALIGN(((struct sockaddr *)ptr)->sa_len);
305                 }
306         }
307
308         printf("\n");
309
310 }
311
312 void
313 rtsock_print_ifa(struct ifa_msghdr *ifam)
314 {
315         struct timeval tv;
316         struct tm tm_res;
317         char buf[64];
318
319         gettimeofday(&tv, NULL);
320         localtime_r(&tv.tv_sec, &tm_res);
321         strftime(buf, sizeof(buf), "%F %T", &tm_res);
322         printf("Got message of size %hu on %s\n", ifam->ifam_msglen, buf);
323
324         char flags_buf[256];
325         _printb(flags_buf, sizeof(flags_buf), ifam->ifam_flags, routeflags);
326
327         printf("%s: len %hu, ifindex: %d, flags: %s\n", msgtypes[ifam->ifam_type],
328                 ifam->ifam_msglen, ifam->ifam_index, flags_buf);
329
330         _printb(flags_buf, sizeof(flags_buf), ifam->ifam_addrs, addrnames);
331         printf("sockaddrs: 0x%X %s\n", ifam->ifam_addrs, flags_buf);
332
333         char *ptr = (char *)(ifam + 1);
334         for (int i = 0; i < RTAX_MAX; i++) {
335                 if (ifam->ifam_addrs & (1 << i)) {
336                         struct sockaddr *sa = (struct sockaddr *)ptr;
337                         sa_print(sa, 1);
338
339                         /* add */
340                         ptr += ALIGN(((struct sockaddr *)ptr)->sa_len);
341                 }
342         }
343
344         printf("\n");
345
346 }
347
348 void
349 rtsock_print_message_hd(struct rt_msghdr *rtm)
350 {
351         struct timeval tv;
352         struct tm tm_res;
353         char buf[64];
354         char dumpbuf[2048];
355
356         gettimeofday(&tv, NULL);
357         localtime_r(&tv.tv_sec, &tm_res);
358         strftime(buf, sizeof(buf), "%F %T", &tm_res);
359         printf("Got message type %s of size %hu on %s\n",
360             rtsock_print_cmdtype(rtm->rtm_type),
361             rtm->rtm_msglen, buf);
362
363         sa_print_hd(dumpbuf, sizeof(dumpbuf), (char *)rtm, rtm->rtm_msglen);
364         printf(" %s\n", dumpbuf);
365 }
366
367 void
368 rtsock_print_message(struct rt_msghdr *rtm)
369 {
370
371         switch (rtm->rtm_type) {
372         case RTM_GET:
373         case RTM_ADD:
374         case RTM_DELETE:
375         case RTM_CHANGE:
376                 rtsock_print_rtm(rtm);
377                 break;
378         case RTM_DELADDR:
379         case RTM_NEWADDR:
380                 rtsock_print_ifa((struct ifa_msghdr *)rtm);
381                 break;
382         default:
383                 printf("unknown rt message type %X\n", rtm->rtm_type);
384         }
385 }
386
387 static void
388 print_command(char *cmd)
389 {
390         char line[1024];
391
392         FILE *fp = popen(cmd, "r");
393         if (fp != NULL) {
394                 while (fgets(line, sizeof(line), fp) != NULL)
395                         printf("%s", line);
396                 pclose(fp);
397         }
398 }
399
400 void
401 rtsock_print_table(int family)
402 {
403         char cmdbuf[128];
404         char *key = (family == AF_INET) ? "4" : "6";
405
406         snprintf(cmdbuf, sizeof(cmdbuf), "/usr/bin/netstat -%srnW", key);
407         printf("==== %s ===\n", cmdbuf);
408         print_command(cmdbuf);
409         snprintf(cmdbuf, sizeof(cmdbuf), "/usr/bin/netstat -%sonW", key);
410         printf("==== %s ===\n", cmdbuf);
411         print_command(cmdbuf);
412 }
413
414 #endif