1 /* $OpenBSD: output.c,v 1.56 2024/10/01 18:33:16 claudio Exp $ */
2
3 /*
4 * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
5 * Copyright (c) 2004-2019 Claudio Jeker <claudio@openbsd.org>
6 * Copyright (c) 2016 Job Snijders <job@instituut.net>
7 * Copyright (c) 2016 Peter Hessler <phessler@openbsd.org>
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 */
21
22 #include <endian.h>
23 #include <err.h>
24 #include <math.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "bgpd.h"
30 #include "session.h"
31 #include "rde.h"
32
33 #include "bgpctl.h"
34 #include "parser.h"
35
36 static void
show_head(struct parse_result * res)37 show_head(struct parse_result *res)
38 {
39 switch (res->action) {
40 case SHOW:
41 case SHOW_SUMMARY:
42 printf("%-20s %8s %10s %10s %5s %-8s %s\n", "Neighbor", "AS",
43 "MsgRcvd", "MsgSent", "OutQ", "Up/Down", "State/PrfRcvd");
44 break;
45 case SHOW_FIB:
46 printf("flags: B = BGP, C = Connected, S = Static\n");
47 printf(" N = BGP Nexthop reachable via this route\n");
48 printf(" r = reject route, b = blackhole route\n\n");
49 printf("%-5s %-4s %-32s %-32s\n", "flags", "prio",
50 "destination", "gateway");
51 break;
52 case SHOW_FIB_TABLES:
53 printf("%-5s %-20s %-8s\n", "Table", "Description", "State");
54 break;
55 case SHOW_NEXTHOP:
56 printf("Flags: * = nexthop valid\n");
57 printf("\n %-15s %-19s%-4s %-15s %-20s\n", "Nexthop", "Route",
58 "Prio", "Gateway", "Iface");
59 break;
60 case SHOW_INTERFACE:
61 printf("%-15s%-9s%-9s%-7s%s\n", "Interface", "rdomain",
62 "Nexthop", "Flags", "Link state");
63 break;
64 case SHOW_RIB:
65 if (res->flags & F_CTL_DETAIL)
66 break;
67 printf("flags: "
68 "* = Valid, > = Selected, I = via IBGP, A = Announced,\n"
69 " S = Stale, E = Error, F = Filtered\n");
70 printf("origin validation state: "
71 "N = not-found, V = valid, ! = invalid\n");
72 printf("aspa validation state: "
73 "? = unknown, V = valid, ! = invalid\n");
74 printf("origin: i = IGP, e = EGP, ? = Incomplete\n\n");
75 printf("%-5s %3s %-20s %-15s %5s %5s %s\n",
76 "flags", "vs", "destination", "gateway", "lpref", "med",
77 "aspath origin");
78 break;
79 case SHOW_SET:
80 printf("%-6s %-34s %7s %7s %6s %11s\n", "Type", "Name",
81 "#IPv4", "#IPv6", "#ASnum", "Last Change");
82 break;
83 case NETWORK_SHOW:
84 printf("flags: S = Static\n");
85 printf("%-5s %-4s %-32s %-32s\n", "flags", "prio",
86 "destination", "gateway");
87 break;
88 case FLOWSPEC_SHOW:
89 printf("flags: S = Static\n");
90 default:
91 break;
92 }
93 }
94
95 static void
show_summary(struct peer * p)96 show_summary(struct peer *p)
97 {
98 char *s;
99 const char *a;
100 size_t alen;
101
102 s = fmt_peer(p->conf.descr, &p->conf.remote_addr,
103 p->conf.remote_masklen);
104
105 a = log_as(p->conf.remote_as);
106 alen = strlen(a);
107 /* max displayed length of the peers name is 28 */
108 if (alen < 28) {
109 if (strlen(s) > 28 - alen)
110 s[28 - alen] = '\0';
111 } else
112 alen = 0;
113
114 printf("%-*s %s %10llu %10llu %5u %-8s ",
115 (28 - (int)alen), s, a,
116 p->stats.msg_rcvd_open + p->stats.msg_rcvd_notification +
117 p->stats.msg_rcvd_update + p->stats.msg_rcvd_keepalive +
118 p->stats.msg_rcvd_rrefresh,
119 p->stats.msg_sent_open + p->stats.msg_sent_notification +
120 p->stats.msg_sent_update + p->stats.msg_sent_keepalive +
121 p->stats.msg_sent_rrefresh,
122 p->stats.msg_queue_len,
123 fmt_monotime(p->stats.last_updown));
124 if (p->state == STATE_ESTABLISHED) {
125 printf("%6u", p->stats.prefix_cnt);
126 if (p->conf.max_prefix != 0)
127 printf("/%u", p->conf.max_prefix);
128 } else if (p->conf.template)
129 printf("Template");
130 else
131 printf("%s", statenames[p->state]);
132 printf("\n");
133 free(s);
134 }
135
136 static void
show_neighbor_capa_mp(struct capabilities * capa)137 show_neighbor_capa_mp(struct capabilities *capa)
138 {
139 int comma;
140 uint8_t i;
141
142 printf(" Multiprotocol extensions: ");
143 for (i = AID_MIN, comma = 0; i < AID_MAX; i++)
144 if (capa->mp[i]) {
145 printf("%s%s", comma ? ", " : "", aid2str(i));
146 comma = 1;
147 }
148 printf("\n");
149 }
150
151 static void
show_neighbor_capa_add_path(struct capabilities * capa)152 show_neighbor_capa_add_path(struct capabilities *capa)
153 {
154 const char *mode;
155 int comma;
156 uint8_t i;
157
158 printf(" Add-path: ");
159 for (i = AID_MIN, comma = 0; i < AID_MAX; i++) {
160 switch (capa->add_path[i]) {
161 case 0:
162 default:
163 continue;
164 case CAPA_AP_RECV:
165 mode = "recv";
166 break;
167 case CAPA_AP_SEND:
168 mode = "send";
169 break;
170 case CAPA_AP_BIDIR:
171 mode = "bidir";
172 }
173 printf("%s%s %s", comma ? ", " : "", aid2str(i), mode);
174 comma = 1;
175 }
176 printf("\n");
177 }
178
179 static void
show_neighbor_capa_restart(struct capabilities * capa)180 show_neighbor_capa_restart(struct capabilities *capa)
181 {
182 int comma;
183 uint8_t i;
184
185 printf(" Graceful Restart");
186 if (capa->grestart.timeout)
187 printf(": Timeout: %d, ", capa->grestart.timeout);
188 for (i = AID_MIN, comma = 0; i < AID_MAX; i++)
189 if (capa->grestart.flags[i] & CAPA_GR_PRESENT) {
190 if (!comma &&
191 capa->grestart.flags[i] & CAPA_GR_RESTART)
192 printf("restarted, ");
193 if (comma)
194 printf(", ");
195 printf("%s", aid2str(i));
196 if (capa->grestart.flags[i] & CAPA_GR_FORWARD)
197 printf(" (preserved)");
198 comma = 1;
199 }
200 printf("\n");
201 }
202
203 static void
show_neighbor_msgstats(struct peer * p)204 show_neighbor_msgstats(struct peer *p)
205 {
206 printf(" Message statistics:\n");
207 printf(" %-15s %-10s %-10s\n", "", "Sent", "Received");
208 printf(" %-15s %10llu %10llu\n", "Opens",
209 p->stats.msg_sent_open, p->stats.msg_rcvd_open);
210 printf(" %-15s %10llu %10llu\n", "Notifications",
211 p->stats.msg_sent_notification, p->stats.msg_rcvd_notification);
212 printf(" %-15s %10llu %10llu\n", "Updates",
213 p->stats.msg_sent_update, p->stats.msg_rcvd_update);
214 printf(" %-15s %10llu %10llu\n", "Keepalives",
215 p->stats.msg_sent_keepalive, p->stats.msg_rcvd_keepalive);
216 printf(" %-15s %10llu %10llu\n", "Route Refresh",
217 p->stats.msg_sent_rrefresh, p->stats.msg_rcvd_rrefresh);
218 printf(" %-15s %10llu %10llu\n\n", "Total",
219 p->stats.msg_sent_open + p->stats.msg_sent_notification +
220 p->stats.msg_sent_update + p->stats.msg_sent_keepalive +
221 p->stats.msg_sent_rrefresh,
222 p->stats.msg_rcvd_open + p->stats.msg_rcvd_notification +
223 p->stats.msg_rcvd_update + p->stats.msg_rcvd_keepalive +
224 p->stats.msg_rcvd_rrefresh);
225 printf(" Update statistics:\n");
226 printf(" %-15s %-10s %-10s %-10s\n", "", "Sent", "Received",
227 "Pending");
228 printf(" %-15s %10u %10u\n", "Prefixes",
229 p->stats.prefix_out_cnt, p->stats.prefix_cnt);
230 printf(" %-15s %10llu %10llu %10u\n", "Updates",
231 p->stats.prefix_sent_update, p->stats.prefix_rcvd_update,
232 p->stats.pending_update);
233 printf(" %-15s %10llu %10llu %10u\n", "Withdraws",
234 p->stats.prefix_sent_withdraw, p->stats.prefix_rcvd_withdraw,
235 p->stats.pending_withdraw);
236 printf(" %-15s %10llu %10llu\n", "End-of-Rib",
237 p->stats.prefix_sent_eor, p->stats.prefix_rcvd_eor);
238 printf(" Route Refresh statistics:\n");
239 printf(" %-15s %10llu %10llu\n", "Request",
240 p->stats.refresh_sent_req, p->stats.refresh_rcvd_req);
241 printf(" %-15s %10llu %10llu\n", "Begin-of-RR",
242 p->stats.refresh_sent_borr, p->stats.refresh_rcvd_borr);
243 printf(" %-15s %10llu %10llu\n", "End-of-RR",
244 p->stats.refresh_sent_eorr, p->stats.refresh_rcvd_eorr);
245 }
246
247 static void
show_neighbor_full(struct peer * p,struct parse_result * res)248 show_neighbor_full(struct peer *p, struct parse_result *res)
249 {
250 const char *errstr;
251 struct in_addr ina;
252 char *s;
253 int hascapamp, hascapaap;
254 uint8_t i;
255
256 if ((p->conf.remote_addr.aid == AID_INET &&
257 p->conf.remote_masklen != 32) ||
258 (p->conf.remote_addr.aid == AID_INET6 &&
259 p->conf.remote_masklen != 128)) {
260 if (asprintf(&s, "%s/%u",
261 log_addr(&p->conf.remote_addr),
262 p->conf.remote_masklen) == -1)
263 err(1, NULL);
264 } else if ((s = strdup(log_addr(&p->conf.remote_addr))) == NULL)
265 err(1, "strdup");
266
267 printf("BGP neighbor is %s, ", s);
268 free(s);
269 if (p->conf.remote_as == 0 && p->conf.template)
270 printf("remote AS: accept any");
271 else
272 printf("remote AS %s", log_as(p->conf.remote_as));
273 if (p->conf.template)
274 printf(", Template");
275 if (p->template)
276 printf(", Cloned");
277 if (p->conf.passive)
278 printf(", Passive");
279 if (p->conf.ebgp && p->conf.distance > 1)
280 printf(", Multihop (%u)", (int)p->conf.distance);
281 printf("\n");
282 if (p->conf.descr[0])
283 printf(" Description: %s\n", p->conf.descr);
284 if (p->conf.ebgp && p->conf.role != ROLE_NONE)
285 printf(" Role: %s\n", log_policy(p->conf.role));
286 if (p->conf.max_prefix) {
287 printf(" Max-prefix: %u", p->conf.max_prefix);
288 if (p->conf.max_prefix_restart)
289 printf(" (restart %u)",
290 p->conf.max_prefix_restart);
291 }
292 if (p->conf.max_out_prefix) {
293 printf(" Max-prefix out: %u", p->conf.max_out_prefix);
294 if (p->conf.max_out_prefix_restart)
295 printf(" (restart %u)",
296 p->conf.max_out_prefix_restart);
297 }
298 if (p->conf.max_prefix || p->conf.max_out_prefix)
299 printf("\n");
300
301 if (p->state == STATE_ESTABLISHED) {
302 ina.s_addr = htonl(p->remote_bgpid);
303 printf(" BGP version 4, remote router-id %s",
304 inet_ntoa(ina));
305 printf("%s\n", fmt_auth_method(p->auth_conf.method));
306 }
307 printf(" BGP state = %s", statenames[p->state]);
308 if (p->conf.down) {
309 printf(", marked down");
310 }
311 if (p->conf.reason[0]) {
312 printf(" with shutdown reason \"%s\"",
313 log_reason(p->conf.reason));
314 }
315 if (p->stats.last_updown != 0)
316 printf(", %s for %s",
317 p->state == STATE_ESTABLISHED ? "up" : "down",
318 fmt_monotime(p->stats.last_updown));
319 printf("\n");
320 printf(" Last read %s, holdtime %us, keepalive interval %us\n",
321 fmt_monotime(p->stats.last_read),
322 p->holdtime, p->holdtime/3);
323 printf(" Last write %s\n", fmt_monotime(p->stats.last_write));
324
325 hascapamp = 0;
326 hascapaap = 0;
327 for (i = AID_MIN; i < AID_MAX; i++) {
328 if (p->capa.peer.mp[i])
329 hascapamp = 1;
330 if (p->capa.peer.add_path[i])
331 hascapaap = 1;
332 }
333 if (hascapamp || hascapaap || p->capa.peer.grestart.restart ||
334 p->capa.peer.refresh || p->capa.peer.enhanced_rr ||
335 p->capa.peer.as4byte || p->capa.peer.policy) {
336 printf(" Neighbor capabilities:\n");
337 if (hascapamp)
338 show_neighbor_capa_mp(&p->capa.peer);
339 if (p->capa.peer.as4byte)
340 printf(" 4-byte AS numbers\n");
341 if (p->capa.peer.refresh)
342 printf(" Route Refresh\n");
343 if (p->capa.peer.enhanced_rr)
344 printf(" Enhanced Route Refresh\n");
345 if (p->capa.peer.grestart.restart)
346 show_neighbor_capa_restart(&p->capa.peer);
347 if (hascapaap)
348 show_neighbor_capa_add_path(&p->capa.peer);
349 if (p->capa.peer.policy)
350 printf(" Open Policy role %s (local %s)\n",
351 log_policy(p->remote_role),
352 log_policy(p->conf.role));
353 }
354
355 hascapamp = 0;
356 hascapaap = 0;
357 for (i = AID_MIN; i < AID_MAX; i++) {
358 if (p->capa.neg.mp[i])
359 hascapamp = 1;
360 if (p->capa.neg.add_path[i])
361 hascapaap = 1;
362 }
363 if (hascapamp || hascapaap || p->capa.neg.grestart.restart ||
364 p->capa.neg.refresh || p->capa.neg.enhanced_rr ||
365 p->capa.neg.as4byte || p->capa.neg.policy) {
366 printf(" Negotiated capabilities:\n");
367 if (hascapamp)
368 show_neighbor_capa_mp(&p->capa.neg);
369 if (p->capa.neg.as4byte)
370 printf(" 4-byte AS numbers\n");
371 if (p->capa.neg.refresh)
372 printf(" Route Refresh\n");
373 if (p->capa.neg.enhanced_rr)
374 printf(" Enhanced Route Refresh\n");
375 if (p->capa.neg.grestart.restart)
376 show_neighbor_capa_restart(&p->capa.neg);
377 if (hascapaap)
378 show_neighbor_capa_add_path(&p->capa.neg);
379 if (p->capa.neg.policy)
380 printf(" Open Policy role %s (local %s)\n",
381 log_policy(p->remote_role),
382 log_policy(p->conf.role));
383 }
384 printf("\n");
385
386 if (res->action == SHOW_NEIGHBOR_TIMERS)
387 return;
388
389 show_neighbor_msgstats(p);
390 printf("\n");
391
392 errstr = fmt_errstr(p->stats.last_sent_errcode,
393 p->stats.last_sent_suberr);
394 if (errstr)
395 printf(" Last error sent: %s\n", errstr);
396 errstr = fmt_errstr(p->stats.last_rcvd_errcode,
397 p->stats.last_rcvd_suberr);
398 if (errstr)
399 printf(" Last error received: %s\n", errstr);
400 if (p->stats.last_reason[0]) {
401 printf(" Last received shutdown reason: \"%s\"\n",
402 log_reason(p->stats.last_reason));
403 }
404
405 if (p->state >= STATE_OPENSENT) {
406 printf(" Local host: %20s, Local port: %5u\n",
407 log_addr(&p->local), p->local_port);
408
409 printf(" Remote host: %20s, Remote port: %5u\n",
410 log_addr(&p->remote), p->remote_port);
411 printf("\n");
412 }
413 }
414
415 static void
show_neighbor(struct peer * p,struct parse_result * res)416 show_neighbor(struct peer *p, struct parse_result *res)
417 {
418 char *s;
419
420 switch (res->action) {
421 case SHOW:
422 case SHOW_SUMMARY:
423 show_summary(p);
424 break;
425 case SHOW_SUMMARY_TERSE:
426 s = fmt_peer(p->conf.descr, &p->conf.remote_addr,
427 p->conf.remote_masklen);
428 printf("%s %s %s\n", s, log_as(p->conf.remote_as),
429 p->conf.template ? "Template" : statenames[p->state]);
430 free(s);
431 break;
432 case SHOW_NEIGHBOR:
433 case SHOW_NEIGHBOR_TIMERS:
434 show_neighbor_full(p, res);
435 break;
436 case SHOW_NEIGHBOR_TERSE:
437 s = fmt_peer(NULL, &p->conf.remote_addr,
438 p->conf.remote_masklen);
439 printf("%llu %llu %llu %llu %llu %llu %llu %llu %llu "
440 "%llu %u %u %llu %llu %llu %llu %s %s \"%s\"\n",
441 p->stats.msg_sent_open, p->stats.msg_rcvd_open,
442 p->stats.msg_sent_notification,
443 p->stats.msg_rcvd_notification,
444 p->stats.msg_sent_update, p->stats.msg_rcvd_update,
445 p->stats.msg_sent_keepalive, p->stats.msg_rcvd_keepalive,
446 p->stats.msg_sent_rrefresh, p->stats.msg_rcvd_rrefresh,
447 p->stats.prefix_cnt, p->conf.max_prefix,
448 p->stats.prefix_sent_update, p->stats.prefix_rcvd_update,
449 p->stats.prefix_sent_withdraw,
450 p->stats.prefix_rcvd_withdraw, s,
451 log_as(p->conf.remote_as), p->conf.descr);
452 free(s);
453 break;
454 default:
455 break;
456 }
457 }
458
459 static void
show_timer(struct ctl_timer * t)460 show_timer(struct ctl_timer *t)
461 {
462 printf(" %-20s ", timernames[t->type]);
463
464 if (t->val <= 0)
465 printf("%-20s\n", "due");
466 else
467 printf("due in %-13s\n", fmt_timeframe(t->val));
468 }
469
470 static void
show_fib(struct kroute_full * kf)471 show_fib(struct kroute_full *kf)
472 {
473 char *p;
474
475 if (asprintf(&p, "%s/%u", log_addr(&kf->prefix), kf->prefixlen) == -1)
476 err(1, NULL);
477 printf("%-5s %4i %-32s ", fmt_fib_flags(kf->flags), kf->priority, p);
478 free(p);
479
480 if (kf->flags & F_CONNECTED)
481 printf("link#%u", kf->ifindex);
482 else
483 printf("%s", log_addr(&kf->nexthop));
484 if (kf->flags & F_MPLS)
485 printf(" mpls %d", ntohl(kf->mplslabel) >> MPLS_LABEL_OFFSET);
486 printf("\n");
487 }
488
489 static void
show_fib_table(struct ktable * kt)490 show_fib_table(struct ktable *kt)
491 {
492 printf("%5i %-20s %-8s%s\n", kt->rtableid, kt->descr,
493 kt->fib_sync ? "coupled" : "decoupled",
494 kt->fib_sync != kt->fib_conf ? "*" : "");
495 }
496
497 static void
print_flowspec_list(struct flowspec * f,int type,int is_v6)498 print_flowspec_list(struct flowspec *f, int type, int is_v6)
499 {
500 const uint8_t *comp;
501 const char *fmt;
502 int complen, off = 0;
503
504 if (flowspec_get_component(f->data, f->len, type, is_v6,
505 &comp, &complen) != 1)
506 return;
507
508 printf("%s ", flowspec_fmt_label(type));
509 fmt = flowspec_fmt_num_op(comp, complen, &off);
510 if (off == -1) {
511 printf("%s ", fmt);
512 } else {
513 printf("{ %s ", fmt);
514 do {
515 fmt = flowspec_fmt_num_op(comp, complen, &off);
516 printf("%s ", fmt);
517 } while (off != -1);
518 printf("} ");
519 }
520 }
521
522 static void
print_flowspec_flags(struct flowspec * f,int type,int is_v6)523 print_flowspec_flags(struct flowspec *f, int type, int is_v6)
524 {
525 const uint8_t *comp;
526 const char *fmt, *flags;
527 int complen, off = 0;
528
529 switch (type) {
530 case FLOWSPEC_TYPE_TCP_FLAGS:
531 flags = FLOWSPEC_TCP_FLAG_STRING;
532 break;
533 case FLOWSPEC_TYPE_FRAG:
534 if (!is_v6)
535 flags = FLOWSPEC_FRAG_STRING4;
536 else
537 flags = FLOWSPEC_FRAG_STRING6;
538 break;
539 default:
540 printf("??? ");
541 return;
542 }
543
544 if (flowspec_get_component(f->data, f->len, type, is_v6,
545 &comp, &complen) != 1)
546 return;
547
548 printf("%s ", flowspec_fmt_label(type));
549
550 fmt = flowspec_fmt_bin_op(comp, complen, &off, flags);
551 if (off == -1) {
552 printf("%s ", fmt);
553 } else {
554 printf("{ %s ", fmt);
555 do {
556 fmt = flowspec_fmt_bin_op(comp, complen, &off, flags);
557 printf("%s ", fmt);
558 } while (off != -1);
559 printf("} ");
560 }
561 }
562
563 static void
print_flowspec_addr(struct flowspec * f,int type,int is_v6)564 print_flowspec_addr(struct flowspec *f, int type, int is_v6)
565 {
566 struct bgpd_addr addr;
567 uint8_t plen;
568
569 flowspec_get_addr(f->data, f->len, type, is_v6, &addr, &plen, NULL);
570 if (plen == 0)
571 printf("%s any ", flowspec_fmt_label(type));
572 else
573 printf("%s %s/%u ", flowspec_fmt_label(type),
574 log_addr(&addr), plen);
575 }
576
577 static void
show_flowspec(struct flowspec * f)578 show_flowspec(struct flowspec *f)
579 {
580 int is_v6 = (f->aid == AID_FLOWSPECv6);
581
582 printf("%-5s ", fmt_fib_flags(f->flags));
583 print_flowspec_list(f, FLOWSPEC_TYPE_PROTO, is_v6);
584
585 print_flowspec_addr(f, FLOWSPEC_TYPE_SOURCE, is_v6);
586 print_flowspec_list(f, FLOWSPEC_TYPE_SRC_PORT, is_v6);
587
588 print_flowspec_addr(f, FLOWSPEC_TYPE_DEST, is_v6);
589 print_flowspec_list(f, FLOWSPEC_TYPE_DST_PORT, is_v6);
590
591 print_flowspec_list(f, FLOWSPEC_TYPE_DSCP, is_v6);
592 print_flowspec_list(f, FLOWSPEC_TYPE_PKT_LEN, is_v6);
593 print_flowspec_flags(f, FLOWSPEC_TYPE_TCP_FLAGS, is_v6);
594 print_flowspec_flags(f, FLOWSPEC_TYPE_FRAG, is_v6);
595 /* TODO: fixup the code handling to be like in the parser */
596 print_flowspec_list(f, FLOWSPEC_TYPE_ICMP_TYPE, is_v6);
597 print_flowspec_list(f, FLOWSPEC_TYPE_ICMP_CODE, is_v6);
598
599 printf("\n");
600 }
601
602 static void
show_nexthop(struct ctl_show_nexthop * nh)603 show_nexthop(struct ctl_show_nexthop *nh)
604 {
605 char *s;
606
607 printf("%s %-15s ", nh->valid ? "*" : " ", log_addr(&nh->addr));
608 if (!nh->krvalid) {
609 printf("\n");
610 return;
611 }
612 if (asprintf(&s, "%s/%u", log_addr(&nh->kr.prefix),
613 nh->kr.prefixlen) == -1)
614 err(1, NULL);
615 printf("%-20s", s);
616 free(s);
617 printf("%3i %-15s ", nh->kr.priority,
618 nh->kr.flags & F_CONNECTED ? "connected" :
619 log_addr(&nh->kr.nexthop));
620
621 if (nh->iface.ifname[0]) {
622 printf("%s (%s, %s)", nh->iface.ifname,
623 nh->iface.is_up ? "UP" : "DOWN",
624 nh->iface.baudrate ?
625 get_baudrate(nh->iface.baudrate, "bps") :
626 nh->iface.linkstate);
627 }
628 printf("\n");
629 }
630
631 static void
show_interface(struct ctl_show_interface * iface)632 show_interface(struct ctl_show_interface *iface)
633 {
634 printf("%-15s", iface->ifname);
635 printf("%-9u", iface->rdomain);
636 printf("%-9s", iface->nh_reachable ? "ok" : "invalid");
637 printf("%-7s", iface->is_up ? "UP" : "");
638
639 if (iface->media[0])
640 printf("%s, ", iface->media);
641 printf("%s", iface->linkstate);
642
643 if (iface->baudrate > 0)
644 printf(", %s", get_baudrate(iface->baudrate, "Bit/s"));
645 printf("\n");
646 }
647
648 static void
show_communities(struct ibuf * data,struct parse_result * res)649 show_communities(struct ibuf *data, struct parse_result *res)
650 {
651 struct community c;
652 uint64_t ext;
653 uint8_t type = 0;
654
655 while (ibuf_size(data) != 0) {
656 if (ibuf_get(data, &c, sizeof(c)) == -1) {
657 warn("communities");
658 break;
659 }
660
661 if (type != c.flags) {
662 if (type != 0)
663 printf("%c", EOL0(res->flags));
664 printf(" %s:", fmt_attr(c.flags,
665 ATTR_OPTIONAL | ATTR_TRANSITIVE));
666 type = c.flags;
667 }
668
669 switch (c.flags) {
670 case COMMUNITY_TYPE_BASIC:
671 printf(" %s", fmt_community(c.data1, c.data2));
672 break;
673 case COMMUNITY_TYPE_LARGE:
674 printf(" %s",
675 fmt_large_community(c.data1, c.data2, c.data3));
676 break;
677 case COMMUNITY_TYPE_EXT:
678 ext = (uint64_t)c.data3 << 48;
679 switch ((c.data3 >> 8) & EXT_COMMUNITY_VALUE) {
680 case EXT_COMMUNITY_TRANS_TWO_AS:
681 case EXT_COMMUNITY_TRANS_OPAQUE:
682 case EXT_COMMUNITY_TRANS_EVPN:
683 ext |= ((uint64_t)c.data1 & 0xffff) << 32;
684 ext |= (uint64_t)c.data2;
685 break;
686 case EXT_COMMUNITY_TRANS_FOUR_AS:
687 case EXT_COMMUNITY_TRANS_IPV4:
688 ext |= (uint64_t)c.data1 << 16;
689 ext |= (uint64_t)c.data2 & 0xffff;
690 break;
691 }
692 printf(" %s", fmt_ext_community(ext));
693 break;
694 }
695 }
696
697 printf("%c", EOL0(res->flags));
698 }
699
700 static void
show_community(struct ibuf * buf)701 show_community(struct ibuf *buf)
702 {
703 uint16_t a, v;
704
705 while (ibuf_size(buf) > 0) {
706 if (ibuf_get_n16(buf, &a) == -1 ||
707 ibuf_get_n16(buf, &v) == -1) {
708 printf("bad length");
709 return;
710 }
711 printf("%s", fmt_community(a, v));
712
713 if (ibuf_size(buf) > 0)
714 printf(" ");
715 }
716 }
717
718 static void
show_large_community(struct ibuf * buf)719 show_large_community(struct ibuf *buf)
720 {
721 uint32_t a, l1, l2;
722
723 while (ibuf_size(buf) > 0) {
724 if (ibuf_get_n32(buf, &a) == -1 ||
725 ibuf_get_n32(buf, &l1) == -1 ||
726 ibuf_get_n32(buf, &l2) == -1) {
727 printf("bad length");
728 return;
729 }
730 printf("%s", fmt_large_community(a, l1, l2));
731
732 if (ibuf_size(buf) > 0)
733 printf(" ");
734 }
735 }
736
737 static void
show_ext_community(struct ibuf * buf)738 show_ext_community(struct ibuf *buf)
739 {
740 uint64_t ext;
741
742 while (ibuf_size(buf) > 0) {
743 if (ibuf_get_n64(buf, &ext) == -1) {
744 printf("bad length");
745 return;
746 }
747 printf("%s", fmt_ext_community(ext));
748
749 if (ibuf_size(buf) > 0)
750 printf(" ");
751 }
752 }
753
754 static void
show_attr(struct ibuf * buf,int reqflags,int addpath)755 show_attr(struct ibuf *buf, int reqflags, int addpath)
756 {
757 struct in_addr id;
758 struct bgpd_addr prefix;
759 struct ibuf asbuf, *path = NULL;
760 char *aspath;
761 size_t i, alen;
762 uint32_t as, pathid, val;
763 uint16_t short_as, afi;
764 uint8_t flags, type, safi, aid, prefixlen, origin, b;
765 int e2, e4;
766
767 if (ibuf_get_n8(buf, &flags) == -1 ||
768 ibuf_get_n8(buf, &type) == -1)
769 goto bad_len;
770
771 /* get the attribute length */
772 if (flags & ATTR_EXTLEN) {
773 uint16_t attr_len;
774 if (ibuf_get_n16(buf, &attr_len) == -1)
775 goto bad_len;
776 alen = attr_len;
777 } else {
778 uint8_t attr_len;
779 if (ibuf_get_n8(buf, &attr_len) == -1)
780 goto bad_len;
781 alen = attr_len;
782 }
783
784 /* bad imsg len how can that happen!? */
785 if (alen > ibuf_size(buf))
786 goto bad_len;
787
788 printf(" %s: ", fmt_attr(type, flags));
789
790 switch (type) {
791 case ATTR_ORIGIN:
792 if (alen != 1 || ibuf_get_n8(buf, &origin) == -1)
793 goto bad_len;
794 printf("%s", fmt_origin(origin, 0));
795 break;
796 case ATTR_ASPATH:
797 case ATTR_AS4_PATH:
798 /* prefer 4-byte AS here */
799 e4 = aspath_verify(buf, 1, 0);
800 e2 = aspath_verify(buf, 0, 0);
801 if (e4 == 0 || e4 == AS_ERR_SOFT) {
802 ibuf_from_ibuf(&asbuf, buf);
803 } else if (e2 == 0 || e2 == AS_ERR_SOFT) {
804 if ((path = aspath_inflate(buf)) == NULL) {
805 printf("aspath_inflate failed");
806 break;
807 }
808 ibuf_from_ibuf(&asbuf, path);
809 } else {
810 printf("bad AS-Path");
811 break;
812 }
813 if (aspath_asprint(&aspath, &asbuf) == -1)
814 err(1, NULL);
815 printf("%s", aspath);
816 free(aspath);
817 ibuf_free(path);
818 break;
819 case ATTR_NEXTHOP:
820 case ATTR_ORIGINATOR_ID:
821 if (alen != 4 || ibuf_get(buf, &id, sizeof(id)) == -1)
822 goto bad_len;
823 printf("%s", inet_ntoa(id));
824 break;
825 case ATTR_MED:
826 case ATTR_LOCALPREF:
827 if (alen != 4 || ibuf_get_n32(buf, &val) == -1)
828 goto bad_len;
829 printf("%u", val);
830 break;
831 case ATTR_AGGREGATOR:
832 case ATTR_AS4_AGGREGATOR:
833 if (alen == 8) {
834 if (ibuf_get_n32(buf, &as) == -1 ||
835 ibuf_get(buf, &id, sizeof(id)) == -1)
836 goto bad_len;
837 } else if (alen == 6) {
838 if (ibuf_get_n16(buf, &short_as) == -1 ||
839 ibuf_get(buf, &id, sizeof(id)) == -1)
840 goto bad_len;
841 as = short_as;
842 } else {
843 goto bad_len;
844 }
845 printf("%s [%s]", log_as(as), inet_ntoa(id));
846 break;
847 case ATTR_COMMUNITIES:
848 show_community(buf);
849 break;
850 case ATTR_CLUSTER_LIST:
851 while (ibuf_size(buf) > 0) {
852 if (ibuf_get(buf, &id, sizeof(id)) == -1)
853 goto bad_len;
854 printf(" %s", inet_ntoa(id));
855 }
856 break;
857 case ATTR_MP_REACH_NLRI:
858 case ATTR_MP_UNREACH_NLRI:
859 if (ibuf_get_n16(buf, &afi) == -1 ||
860 ibuf_get_n8(buf, &safi) == -1)
861 goto bad_len;
862
863 if (afi2aid(afi, safi, &aid) == -1) {
864 printf("bad AFI/SAFI pair");
865 break;
866 }
867 printf(" %s", aid2str(aid));
868
869 if (type == ATTR_MP_REACH_NLRI) {
870 struct bgpd_addr nexthop;
871 uint8_t nhlen;
872 if (ibuf_get_n8(buf, &nhlen) == -1)
873 goto bad_len;
874 memset(&nexthop, 0, sizeof(nexthop));
875 switch (aid) {
876 case AID_INET6:
877 nexthop.aid = aid;
878 if (nhlen != 16 && nhlen != 32)
879 goto bad_len;
880 if (ibuf_get(buf, &nexthop.v6,
881 sizeof(nexthop.v6)) == -1)
882 goto bad_len;
883 break;
884 case AID_VPN_IPv4:
885 if (nhlen != 12)
886 goto bad_len;
887 nexthop.aid = AID_INET;
888 if (ibuf_skip(buf, sizeof(uint64_t)) == -1 ||
889 ibuf_get(buf, &nexthop.v4,
890 sizeof(nexthop.v4)) == -1)
891 goto bad_len;
892 break;
893 case AID_VPN_IPv6:
894 if (nhlen != 24)
895 goto bad_len;
896 nexthop.aid = AID_INET6;
897 if (ibuf_skip(buf, sizeof(uint64_t)) == -1 ||
898 ibuf_get(buf, &nexthop.v6,
899 sizeof(nexthop.v6)) == -1)
900 goto bad_len;
901 break;
902 default:
903 printf("unhandled AID #%u", aid);
904 goto done;
905 }
906 /* ignore reserved (old SNPA) field as per RFC4760 */
907 if (ibuf_skip(buf, 1) == -1)
908 goto bad_len;
909
910 printf(" nexthop: %s", log_addr(&nexthop));
911 }
912
913 while (ibuf_size(buf) > 0) {
914 if (addpath)
915 if (ibuf_get_n32(buf, &pathid) == -1)
916 goto bad_len;
917 switch (aid) {
918 case AID_INET6:
919 if (nlri_get_prefix6(buf, &prefix,
920 &prefixlen) == -1)
921 goto bad_len;
922 break;
923 case AID_VPN_IPv4:
924 if (nlri_get_vpn4(buf, &prefix,
925 &prefixlen, 1) == -1)
926 goto bad_len;
927 break;
928 case AID_VPN_IPv6:
929 if (nlri_get_vpn6(buf, &prefix,
930 &prefixlen, 1) == -1)
931 goto bad_len;
932 break;
933 default:
934 printf("unhandled AID #%u", aid);
935 goto done;
936 }
937 printf(" %s/%u", log_addr(&prefix), prefixlen);
938 if (addpath)
939 printf(" path-id %u", pathid);
940 }
941 break;
942 case ATTR_EXT_COMMUNITIES:
943 show_ext_community(buf);
944 break;
945 case ATTR_LARGE_COMMUNITIES:
946 show_large_community(buf);
947 break;
948 case ATTR_OTC:
949 if (alen != 4 || ibuf_get_n32(buf, &as) == -1)
950 goto bad_len;
951 printf("%s", log_as(as));
952 break;
953 case ATTR_ATOMIC_AGGREGATE:
954 default:
955 printf(" len %zu", alen);
956 if (alen) {
957 printf(":");
958 for (i = 0; i < alen; i++) {
959 if (ibuf_get_n8(buf, &b) == -1)
960 goto bad_len;
961 printf(" %02x", b);
962 }
963 }
964 break;
965 }
966
967 done:
968 printf("%c", EOL0(reqflags));
969 return;
970
971 bad_len:
972 printf("bad length%c", EOL0(reqflags));
973 }
974
975 static void
show_rib_brief(struct ctl_show_rib * r,struct ibuf * asbuf)976 show_rib_brief(struct ctl_show_rib *r, struct ibuf *asbuf)
977 {
978 char *p, *aspath;
979
980 if (asprintf(&p, "%s/%u", log_addr(&r->prefix), r->prefixlen) == -1)
981 err(1, NULL);
982 printf("%s %s-%s %-20s %-15s %5u %5u ",
983 fmt_flags(r->flags, 1), fmt_ovs(r->roa_validation_state, 1),
984 fmt_avs(r->aspa_validation_state, 1), p,
985 log_addr(&r->exit_nexthop), r->local_pref, r->med);
986 free(p);
987
988 if (aspath_asprint(&aspath, asbuf) == -1)
989 err(1, NULL);
990 if (strlen(aspath) > 0)
991 printf("%s ", aspath);
992 free(aspath);
993
994 printf("%s\n", fmt_origin(r->origin, 1));
995 }
996
997 static void
show_rib_detail(struct ctl_show_rib * r,struct ibuf * asbuf,int flag0)998 show_rib_detail(struct ctl_show_rib *r, struct ibuf *asbuf, int flag0)
999 {
1000 struct in_addr id;
1001 char *aspath, *s;
1002
1003 printf("\nBGP routing table entry for %s/%u%c",
1004 log_addr(&r->prefix), r->prefixlen,
1005 EOL0(flag0));
1006
1007 if (aspath_asprint(&aspath, asbuf) == -1)
1008 err(1, NULL);
1009 if (strlen(aspath) > 0)
1010 printf(" %s%c", aspath, EOL0(flag0));
1011 free(aspath);
1012
1013 s = fmt_peer(r->descr, &r->remote_addr, -1);
1014 id.s_addr = htonl(r->remote_id);
1015 printf(" Nexthop %s ", log_addr(&r->exit_nexthop));
1016 printf("(via %s) Neighbor %s (%s)", log_addr(&r->true_nexthop), s,
1017 inet_ntoa(id));
1018 if (r->flags & F_PREF_PATH_ID)
1019 printf(" Path-Id: %u", r->path_id);
1020 printf("%c", EOL0(flag0));
1021 free(s);
1022
1023 printf(" Origin %s, metric %u, localpref %u, weight %u, ovs %s, ",
1024 fmt_origin(r->origin, 0), r->med, r->local_pref, r->weight,
1025 fmt_ovs(r->roa_validation_state, 0));
1026 printf("avs %s, %s", fmt_avs(r->aspa_validation_state, 0),
1027 fmt_flags(r->flags, 0));
1028
1029 printf("%c Last update: %s ago%c", EOL0(flag0),
1030 fmt_timeframe(r->age), EOL0(flag0));
1031 }
1032
1033 static void
show_rib(struct ctl_show_rib * r,struct ibuf * aspath,struct parse_result * res)1034 show_rib(struct ctl_show_rib *r, struct ibuf *aspath, struct parse_result *res)
1035 {
1036 if (res->flags & F_CTL_DETAIL)
1037 show_rib_detail(r, aspath, res->flags);
1038 else
1039 show_rib_brief(r, aspath);
1040 }
1041
1042 static void
show_rib_mem(struct rde_memstats * stats)1043 show_rib_mem(struct rde_memstats *stats)
1044 {
1045 size_t pts = 0;
1046 int i;
1047
1048 printf("RDE memory statistics\n");
1049 for (i = 0; i < AID_MAX; i++) {
1050 if (stats->pt_cnt[i] == 0)
1051 continue;
1052 pts += stats->pt_size[i];
1053 printf("%10lld %s network entries using %s of memory\n",
1054 stats->pt_cnt[i], aid_vals[i].name,
1055 fmt_mem(stats->pt_size[i]));
1056 }
1057 printf("%10lld rib entries using %s of memory\n",
1058 stats->rib_cnt, fmt_mem(stats->rib_cnt *
1059 sizeof(struct rib_entry)));
1060 printf("%10lld prefix entries using %s of memory\n",
1061 stats->prefix_cnt, fmt_mem(stats->prefix_cnt *
1062 sizeof(struct prefix)));
1063 printf("%10lld BGP path attribute entries using %s of memory\n",
1064 stats->path_cnt, fmt_mem(stats->path_cnt *
1065 sizeof(struct rde_aspath)));
1066 printf("\t and holding %lld references\n",
1067 stats->path_refs);
1068 printf("%10lld BGP AS-PATH attribute entries using "
1069 "%s of memory\n", stats->aspath_cnt, fmt_mem(stats->aspath_size));
1070 printf("%10lld entries for %lld BGP communities "
1071 "using %s of memory\n", stats->comm_cnt, stats->comm_nmemb,
1072 fmt_mem(stats->comm_cnt * sizeof(struct rde_community) +
1073 stats->comm_size * sizeof(struct community)));
1074 printf("\t and holding %lld references\n",
1075 stats->comm_refs);
1076 printf("%10lld BGP attributes entries using %s of memory\n",
1077 stats->attr_cnt, fmt_mem(stats->attr_cnt *
1078 sizeof(struct attr)));
1079 printf("\t and holding %lld references\n",
1080 stats->attr_refs);
1081 printf("%10lld BGP attributes using %s of memory\n",
1082 stats->attr_dcnt, fmt_mem(stats->attr_data));
1083 printf("%10lld as-set elements in %lld tables using "
1084 "%s of memory\n", stats->aset_nmemb, stats->aset_cnt,
1085 fmt_mem(stats->aset_size));
1086 printf("%10lld prefix-set elements using %s of memory\n",
1087 stats->pset_cnt, fmt_mem(stats->pset_size));
1088 printf("RIB using %s of memory\n", fmt_mem(pts +
1089 stats->prefix_cnt * sizeof(struct prefix) +
1090 stats->rib_cnt * sizeof(struct rib_entry) +
1091 stats->path_cnt * sizeof(struct rde_aspath) +
1092 stats->aspath_size + stats->attr_cnt * sizeof(struct attr) +
1093 stats->attr_data));
1094 printf("Sets using %s of memory\n", fmt_mem(stats->aset_size +
1095 stats->pset_size));
1096 }
1097
1098 static void
show_rib_set(struct ctl_show_set * set)1099 show_rib_set(struct ctl_show_set *set)
1100 {
1101 char buf[64];
1102
1103 if (set->type == ASNUM_SET || set->type == ASPA_SET)
1104 snprintf(buf, sizeof(buf), "%7s %7s %6zu",
1105 "-", "-", set->as_cnt);
1106 else
1107 snprintf(buf, sizeof(buf), "%7zu %7zu %6s",
1108 set->v4_cnt, set->v6_cnt, "-");
1109
1110 printf("%-6s %-34s %s %11s\n", fmt_set_type(set), set->name,
1111 buf, fmt_monotime(set->lastchange));
1112 }
1113
1114 static void
show_rtr(struct ctl_show_rtr * rtr)1115 show_rtr(struct ctl_show_rtr *rtr)
1116 {
1117 static int not_first;
1118
1119 if (not_first)
1120 printf("\n");
1121 not_first = 1;
1122
1123 printf("RTR neighbor is %s, port %u\n",
1124 log_addr(&rtr->remote_addr), rtr->remote_port);
1125 printf(" State: %s\n", rtr->state);
1126 if (rtr->descr[0])
1127 printf(" Description: %s\n", rtr->descr);
1128 if (rtr->local_addr.aid != AID_UNSPEC)
1129 printf(" Local Address: %s\n", log_addr(&rtr->local_addr));
1130 if (rtr->session_id != -1)
1131 printf(" Version: %u min %u Session ID: %d Serial #: %u\n",
1132 rtr->version, rtr->min_version, rtr->session_id,
1133 rtr->serial);
1134 printf(" Refresh: %u, Retry: %u, Expire: %u\n",
1135 rtr->refresh, rtr->retry, rtr->expire);
1136
1137 if (rtr->last_sent_error != NO_ERROR) {
1138 printf(" Last sent error: %s\n",
1139 log_rtr_error(rtr->last_sent_error));
1140 if (rtr->last_sent_msg[0])
1141 printf(" with reason \"%s\"\n",
1142 log_reason(rtr->last_sent_msg));
1143 }
1144 if (rtr->last_recv_error != NO_ERROR) {
1145 printf(" Last received error: %s\n",
1146 log_rtr_error(rtr->last_recv_error));
1147 if (rtr->last_recv_msg[0])
1148 printf(" with reason \"%s\"\n",
1149 log_reason(rtr->last_recv_msg));
1150 }
1151
1152 printf("\n");
1153 }
1154
1155 static void
show_result(u_int rescode)1156 show_result(u_int rescode)
1157 {
1158 if (rescode == 0)
1159 printf("request processed\n");
1160 else if (rescode >=
1161 sizeof(ctl_res_strerror)/sizeof(ctl_res_strerror[0]))
1162 printf("unknown result error code %u\n", rescode);
1163 else
1164 printf("%s\n", ctl_res_strerror[rescode]);
1165 }
1166
1167 static void
show_tail(void)1168 show_tail(void)
1169 {
1170 /* nothing */
1171 }
1172
1173 const struct output show_output = {
1174 .head = show_head,
1175 .neighbor = show_neighbor,
1176 .timer = show_timer,
1177 .fib = show_fib,
1178 .fib_table = show_fib_table,
1179 .flowspec = show_flowspec,
1180 .nexthop = show_nexthop,
1181 .interface = show_interface,
1182 .communities = show_communities,
1183 .attr = show_attr,
1184 .rib = show_rib,
1185 .rib_mem = show_rib_mem,
1186 .set = show_rib_set,
1187 .rtr = show_rtr,
1188 .result = show_result,
1189 .tail = show_tail,
1190 };
1191