xref: /openbsd-src/usr.sbin/bgpctl/output.c (revision 34605cdf49cb47f30a02be1cc83a51eeaf125770)
1*34605cdfSclaudio /*	$OpenBSD: output.c,v 1.59 2025/01/29 13:14:41 claudio Exp $ */
26671ac0bSclaudio 
36671ac0bSclaudio /*
46671ac0bSclaudio  * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
56671ac0bSclaudio  * Copyright (c) 2004-2019 Claudio Jeker <claudio@openbsd.org>
66671ac0bSclaudio  * Copyright (c) 2016 Job Snijders <job@instituut.net>
76671ac0bSclaudio  * Copyright (c) 2016 Peter Hessler <phessler@openbsd.org>
86671ac0bSclaudio  *
96671ac0bSclaudio  * Permission to use, copy, modify, and distribute this software for any
106671ac0bSclaudio  * purpose with or without fee is hereby granted, provided that the above
116671ac0bSclaudio  * copyright notice and this permission notice appear in all copies.
126671ac0bSclaudio  *
136671ac0bSclaudio  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
146671ac0bSclaudio  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
156671ac0bSclaudio  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
166671ac0bSclaudio  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
176671ac0bSclaudio  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
186671ac0bSclaudio  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
196671ac0bSclaudio  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
206671ac0bSclaudio  */
216671ac0bSclaudio 
2224e1c343Sclaudio #include <endian.h>
236671ac0bSclaudio #include <err.h>
246671ac0bSclaudio #include <math.h>
256671ac0bSclaudio #include <stdio.h>
266671ac0bSclaudio #include <stdlib.h>
276671ac0bSclaudio #include <string.h>
286671ac0bSclaudio 
296671ac0bSclaudio #include "bgpd.h"
306671ac0bSclaudio #include "session.h"
316671ac0bSclaudio #include "rde.h"
326671ac0bSclaudio 
336671ac0bSclaudio #include "bgpctl.h"
346671ac0bSclaudio #include "parser.h"
356671ac0bSclaudio 
36d30a810dSclaudio static void
376671ac0bSclaudio show_head(struct parse_result *res)
386671ac0bSclaudio {
396671ac0bSclaudio 	switch (res->action) {
406671ac0bSclaudio 	case SHOW:
416671ac0bSclaudio 	case SHOW_SUMMARY:
426671ac0bSclaudio 		printf("%-20s %8s %10s %10s %5s %-8s %s\n", "Neighbor", "AS",
436671ac0bSclaudio 		    "MsgRcvd", "MsgSent", "OutQ", "Up/Down", "State/PrfRcvd");
446671ac0bSclaudio 		break;
456671ac0bSclaudio 	case SHOW_FIB:
460d49b5f3Sclaudio 		printf("flags: B = BGP, C = Connected, S = Static\n");
471c48363bSclaudio 		printf("       N = BGP Nexthop reachable via this route\n");
486671ac0bSclaudio 		printf("       r = reject route, b = blackhole route\n\n");
490d49b5f3Sclaudio 		printf("%-5s %-4s %-32s %-32s\n", "flags", "prio",
500d49b5f3Sclaudio 		    "destination", "gateway");
516671ac0bSclaudio 		break;
526671ac0bSclaudio 	case SHOW_FIB_TABLES:
536671ac0bSclaudio 		printf("%-5s %-20s %-8s\n", "Table", "Description", "State");
546671ac0bSclaudio 		break;
556671ac0bSclaudio 	case SHOW_NEXTHOP:
566671ac0bSclaudio 		printf("Flags: * = nexthop valid\n");
576671ac0bSclaudio 		printf("\n  %-15s %-19s%-4s %-15s %-20s\n", "Nexthop", "Route",
586671ac0bSclaudio 		     "Prio", "Gateway", "Iface");
596671ac0bSclaudio 		break;
606671ac0bSclaudio 	case SHOW_INTERFACE:
616671ac0bSclaudio 		printf("%-15s%-9s%-9s%-7s%s\n", "Interface", "rdomain",
626671ac0bSclaudio 		    "Nexthop", "Flags", "Link state");
636671ac0bSclaudio 		break;
646671ac0bSclaudio 	case SHOW_RIB:
656671ac0bSclaudio 		if (res->flags & F_CTL_DETAIL)
666671ac0bSclaudio 			break;
676671ac0bSclaudio 		printf("flags: "
686671ac0bSclaudio 		    "* = Valid, > = Selected, I = via IBGP, A = Announced,\n"
69*34605cdfSclaudio 		    "       S = Stale, E = Error, F = Filtered, L = Leaked\n");
706671ac0bSclaudio 		printf("origin validation state: "
716671ac0bSclaudio 		    "N = not-found, V = valid, ! = invalid\n");
7250d35cacSclaudio 		printf("aspa validation state: "
7350d35cacSclaudio 		    "? = unknown, V = valid, ! = invalid\n");
746671ac0bSclaudio 		printf("origin: i = IGP, e = EGP, ? = Incomplete\n\n");
756671ac0bSclaudio 		printf("%-5s %3s %-20s %-15s  %5s %5s %s\n",
7650d35cacSclaudio 		    "flags", "vs", "destination", "gateway", "lpref", "med",
776671ac0bSclaudio 		    "aspath origin");
786671ac0bSclaudio 		break;
79413f97b7Sclaudio 	case SHOW_SET:
80413f97b7Sclaudio 		printf("%-6s %-34s %7s %7s %6s %11s\n", "Type", "Name",
81413f97b7Sclaudio 		    "#IPv4", "#IPv6", "#ASnum", "Last Change");
82413f97b7Sclaudio 		break;
836671ac0bSclaudio 	case NETWORK_SHOW:
846671ac0bSclaudio 		printf("flags: S = Static\n");
851c48363bSclaudio 		printf("%-5s %-4s %-32s %-32s\n", "flags", "prio",
861c48363bSclaudio 		    "destination", "gateway");
876671ac0bSclaudio 		break;
885fed6b04Sclaudio 	case FLOWSPEC_SHOW:
895fed6b04Sclaudio 		printf("flags: S = Static\n");
906671ac0bSclaudio 	default:
916671ac0bSclaudio 		break;
926671ac0bSclaudio 	}
936671ac0bSclaudio }
946671ac0bSclaudio 
956671ac0bSclaudio static void
966671ac0bSclaudio show_summary(struct peer *p)
976671ac0bSclaudio {
986671ac0bSclaudio 	char		*s;
996671ac0bSclaudio 	const char	*a;
1006671ac0bSclaudio 	size_t		alen;
1016671ac0bSclaudio 
1026671ac0bSclaudio 	s = fmt_peer(p->conf.descr, &p->conf.remote_addr,
1036671ac0bSclaudio 	    p->conf.remote_masklen);
1046671ac0bSclaudio 
1056671ac0bSclaudio 	a = log_as(p->conf.remote_as);
1066671ac0bSclaudio 	alen = strlen(a);
1076671ac0bSclaudio 	/* max displayed length of the peers name is 28 */
1086671ac0bSclaudio 	if (alen < 28) {
1096671ac0bSclaudio 		if (strlen(s) > 28 - alen)
1106671ac0bSclaudio 			s[28 - alen] = '\0';
1116671ac0bSclaudio 	} else
1126671ac0bSclaudio 		alen = 0;
1136671ac0bSclaudio 
1146671ac0bSclaudio 	printf("%-*s %s %10llu %10llu %5u %-8s ",
1156671ac0bSclaudio 	    (28 - (int)alen), s, a,
1166671ac0bSclaudio 	    p->stats.msg_rcvd_open + p->stats.msg_rcvd_notification +
1176671ac0bSclaudio 	    p->stats.msg_rcvd_update + p->stats.msg_rcvd_keepalive +
1186671ac0bSclaudio 	    p->stats.msg_rcvd_rrefresh,
1196671ac0bSclaudio 	    p->stats.msg_sent_open + p->stats.msg_sent_notification +
1206671ac0bSclaudio 	    p->stats.msg_sent_update + p->stats.msg_sent_keepalive +
1216671ac0bSclaudio 	    p->stats.msg_sent_rrefresh,
12264f32adaSclaudio 	    p->stats.msg_queue_len,
123e67b1a58Sclaudio 	    fmt_monotime(p->stats.last_updown));
1246671ac0bSclaudio 	if (p->state == STATE_ESTABLISHED) {
1256671ac0bSclaudio 		printf("%6u", p->stats.prefix_cnt);
1266671ac0bSclaudio 		if (p->conf.max_prefix != 0)
1276671ac0bSclaudio 			printf("/%u", p->conf.max_prefix);
1286671ac0bSclaudio 	} else if (p->conf.template)
1296671ac0bSclaudio 		printf("Template");
1306671ac0bSclaudio 	else
1316671ac0bSclaudio 		printf("%s", statenames[p->state]);
1326671ac0bSclaudio 	printf("\n");
1336671ac0bSclaudio 	free(s);
1346671ac0bSclaudio }
1356671ac0bSclaudio 
1366671ac0bSclaudio static void
1374821c8fcSclaudio show_neighbor_capa_mp(struct capabilities *capa)
13804d0a88fSclaudio {
13904d0a88fSclaudio 	int	comma;
14059154960Sclaudio 	uint8_t	i;
14104d0a88fSclaudio 
14204d0a88fSclaudio 	printf("    Multiprotocol extensions: ");
143ecfba8dbSclaudio 	for (i = AID_MIN, comma = 0; i < AID_MAX; i++)
1444821c8fcSclaudio 		if (capa->mp[i]) {
14504d0a88fSclaudio 			printf("%s%s", comma ? ", " : "", aid2str(i));
14604d0a88fSclaudio 			comma = 1;
14704d0a88fSclaudio 		}
14804d0a88fSclaudio 	printf("\n");
14904d0a88fSclaudio }
15004d0a88fSclaudio 
15104d0a88fSclaudio static void
152b6faf4c9Sclaudio show_neighbor_capa_add_path(struct capabilities *capa)
153b6faf4c9Sclaudio {
154b6faf4c9Sclaudio 	const char	*mode;
155b6faf4c9Sclaudio 	int		comma;
15659154960Sclaudio 	uint8_t		i;
157b6faf4c9Sclaudio 
158b6faf4c9Sclaudio 	printf("    Add-path: ");
159ecfba8dbSclaudio 	for (i = AID_MIN, comma = 0; i < AID_MAX; i++) {
160b6faf4c9Sclaudio 		switch (capa->add_path[i]) {
161b6faf4c9Sclaudio 		case 0:
162b6faf4c9Sclaudio 		default:
163b6faf4c9Sclaudio 			continue;
164b6faf4c9Sclaudio 		case CAPA_AP_RECV:
165b6faf4c9Sclaudio 			mode = "recv";
166b6faf4c9Sclaudio 			break;
167b6faf4c9Sclaudio 		case CAPA_AP_SEND:
168b6faf4c9Sclaudio 			mode = "send";
169b6faf4c9Sclaudio 			break;
170b6faf4c9Sclaudio 		case CAPA_AP_BIDIR:
171b6faf4c9Sclaudio 			mode = "bidir";
172b6faf4c9Sclaudio 		}
173b6faf4c9Sclaudio 		printf("%s%s %s", comma ? ", " : "", aid2str(i), mode);
174b6faf4c9Sclaudio 		comma = 1;
175b6faf4c9Sclaudio 	}
176b6faf4c9Sclaudio 	printf("\n");
177b6faf4c9Sclaudio }
178b6faf4c9Sclaudio 
179b6faf4c9Sclaudio static void
1804821c8fcSclaudio show_neighbor_capa_restart(struct capabilities *capa)
18104d0a88fSclaudio {
18204d0a88fSclaudio 	int	comma;
18359154960Sclaudio 	uint8_t	i;
18404d0a88fSclaudio 
1852364114aSclaudio 	printf("    Graceful Restart: ");
1864821c8fcSclaudio 	if (capa->grestart.timeout)
1872364114aSclaudio 		printf("timeout: %d, ", capa->grestart.timeout);
1882364114aSclaudio 	if (capa->grestart.grnotification)
1892364114aSclaudio 		printf("graceful notification, ");
190ecfba8dbSclaudio 	for (i = AID_MIN, comma = 0; i < AID_MAX; i++)
1914821c8fcSclaudio 		if (capa->grestart.flags[i] & CAPA_GR_PRESENT) {
19204d0a88fSclaudio 			if (!comma &&
1934821c8fcSclaudio 			    capa->grestart.flags[i] & CAPA_GR_RESTART)
19404d0a88fSclaudio 				printf("restarted, ");
19504d0a88fSclaudio 			if (comma)
19604d0a88fSclaudio 				printf(", ");
19704d0a88fSclaudio 			printf("%s", aid2str(i));
1984821c8fcSclaudio 			if (capa->grestart.flags[i] & CAPA_GR_FORWARD)
19904d0a88fSclaudio 				printf(" (preserved)");
20004d0a88fSclaudio 			comma = 1;
20104d0a88fSclaudio 		}
20204d0a88fSclaudio 	printf("\n");
20304d0a88fSclaudio }
20404d0a88fSclaudio 
20504d0a88fSclaudio static void
20604d0a88fSclaudio show_neighbor_msgstats(struct peer *p)
20704d0a88fSclaudio {
20804d0a88fSclaudio 	printf("  Message statistics:\n");
20904d0a88fSclaudio 	printf("  %-15s %-10s %-10s\n", "", "Sent", "Received");
21004d0a88fSclaudio 	printf("  %-15s %10llu %10llu\n", "Opens",
21104d0a88fSclaudio 	    p->stats.msg_sent_open, p->stats.msg_rcvd_open);
21204d0a88fSclaudio 	printf("  %-15s %10llu %10llu\n", "Notifications",
21304d0a88fSclaudio 	    p->stats.msg_sent_notification, p->stats.msg_rcvd_notification);
21404d0a88fSclaudio 	printf("  %-15s %10llu %10llu\n", "Updates",
21504d0a88fSclaudio 	    p->stats.msg_sent_update, p->stats.msg_rcvd_update);
21604d0a88fSclaudio 	printf("  %-15s %10llu %10llu\n", "Keepalives",
21704d0a88fSclaudio 	    p->stats.msg_sent_keepalive, p->stats.msg_rcvd_keepalive);
21804d0a88fSclaudio 	printf("  %-15s %10llu %10llu\n", "Route Refresh",
21904d0a88fSclaudio 	    p->stats.msg_sent_rrefresh, p->stats.msg_rcvd_rrefresh);
22004d0a88fSclaudio 	printf("  %-15s %10llu %10llu\n\n", "Total",
22104d0a88fSclaudio 	    p->stats.msg_sent_open + p->stats.msg_sent_notification +
22204d0a88fSclaudio 	    p->stats.msg_sent_update + p->stats.msg_sent_keepalive +
22304d0a88fSclaudio 	    p->stats.msg_sent_rrefresh,
22404d0a88fSclaudio 	    p->stats.msg_rcvd_open + p->stats.msg_rcvd_notification +
22504d0a88fSclaudio 	    p->stats.msg_rcvd_update + p->stats.msg_rcvd_keepalive +
22604d0a88fSclaudio 	    p->stats.msg_rcvd_rrefresh);
22704d0a88fSclaudio 	printf("  Update statistics:\n");
2286c560a4bSclaudio 	printf("  %-15s %-10s %-10s %-10s\n", "", "Sent", "Received",
2296c560a4bSclaudio 	    "Pending");
23004d0a88fSclaudio 	printf("  %-15s %10u %10u\n", "Prefixes",
23104d0a88fSclaudio 	    p->stats.prefix_out_cnt, p->stats.prefix_cnt);
2326c560a4bSclaudio 	printf("  %-15s %10llu %10llu %10u\n", "Updates",
2336c560a4bSclaudio 	    p->stats.prefix_sent_update, p->stats.prefix_rcvd_update,
2346c560a4bSclaudio 	    p->stats.pending_update);
2356c560a4bSclaudio 	printf("  %-15s %10llu %10llu %10u\n", "Withdraws",
2366c560a4bSclaudio 	    p->stats.prefix_sent_withdraw, p->stats.prefix_rcvd_withdraw,
2376c560a4bSclaudio 	    p->stats.pending_withdraw);
23804d0a88fSclaudio 	printf("  %-15s %10llu %10llu\n", "End-of-Rib",
23904d0a88fSclaudio 	    p->stats.prefix_sent_eor, p->stats.prefix_rcvd_eor);
240b6faf4c9Sclaudio 	printf("  Route Refresh statistics:\n");
241b6faf4c9Sclaudio 	printf("  %-15s %10llu %10llu\n", "Request",
242b6faf4c9Sclaudio 	    p->stats.refresh_sent_req, p->stats.refresh_rcvd_req);
243b6faf4c9Sclaudio 	printf("  %-15s %10llu %10llu\n", "Begin-of-RR",
244b6faf4c9Sclaudio 	    p->stats.refresh_sent_borr, p->stats.refresh_rcvd_borr);
245b6faf4c9Sclaudio 	printf("  %-15s %10llu %10llu\n", "End-of-RR",
246b6faf4c9Sclaudio 	    p->stats.refresh_sent_eorr, p->stats.refresh_rcvd_eorr);
24704d0a88fSclaudio }
24804d0a88fSclaudio 
24904d0a88fSclaudio static void
2506671ac0bSclaudio show_neighbor_full(struct peer *p, struct parse_result *res)
2516671ac0bSclaudio {
252ac87c040Sclaudio 	const char	*errstr;
2536671ac0bSclaudio 	struct in_addr	 ina;
2546671ac0bSclaudio 	char		*s;
255b6faf4c9Sclaudio 	int		 hascapamp, hascapaap;
25659154960Sclaudio 	uint8_t		 i;
2576671ac0bSclaudio 
2586671ac0bSclaudio 	if ((p->conf.remote_addr.aid == AID_INET &&
2596671ac0bSclaudio 	    p->conf.remote_masklen != 32) ||
2606671ac0bSclaudio 	    (p->conf.remote_addr.aid == AID_INET6 &&
2616671ac0bSclaudio 	    p->conf.remote_masklen != 128)) {
2626671ac0bSclaudio 		if (asprintf(&s, "%s/%u",
2636671ac0bSclaudio 		    log_addr(&p->conf.remote_addr),
2646671ac0bSclaudio 		    p->conf.remote_masklen) == -1)
2656671ac0bSclaudio 			err(1, NULL);
2666671ac0bSclaudio 	} else if ((s = strdup(log_addr(&p->conf.remote_addr))) == NULL)
2676671ac0bSclaudio 			err(1, "strdup");
2686671ac0bSclaudio 
2696671ac0bSclaudio 	printf("BGP neighbor is %s, ", s);
2706671ac0bSclaudio 	free(s);
2716671ac0bSclaudio 	if (p->conf.remote_as == 0 && p->conf.template)
2726671ac0bSclaudio 		printf("remote AS: accept any");
2736671ac0bSclaudio 	else
2746671ac0bSclaudio 		printf("remote AS %s", log_as(p->conf.remote_as));
2756671ac0bSclaudio 	if (p->conf.template)
2766671ac0bSclaudio 		printf(", Template");
2776671ac0bSclaudio 	if (p->template)
2786671ac0bSclaudio 		printf(", Cloned");
2796671ac0bSclaudio 	if (p->conf.passive)
2806671ac0bSclaudio 		printf(", Passive");
2816671ac0bSclaudio 	if (p->conf.ebgp && p->conf.distance > 1)
2826671ac0bSclaudio 		printf(", Multihop (%u)", (int)p->conf.distance);
2836671ac0bSclaudio 	printf("\n");
2846671ac0bSclaudio 	if (p->conf.descr[0])
2856671ac0bSclaudio 		printf(" Description: %s\n", p->conf.descr);
2861d3c7c09Sclaudio 	if (p->conf.ebgp && p->conf.role != ROLE_NONE)
2871d3c7c09Sclaudio 		printf(" Role: %s\n", log_policy(p->conf.role));
2886671ac0bSclaudio 	if (p->conf.max_prefix) {
2896671ac0bSclaudio 		printf(" Max-prefix: %u", p->conf.max_prefix);
2906671ac0bSclaudio 		if (p->conf.max_prefix_restart)
2916671ac0bSclaudio 			printf(" (restart %u)",
2926671ac0bSclaudio 			    p->conf.max_prefix_restart);
2936671ac0bSclaudio 	}
294a93f6d85Sclaudio 	if (p->conf.max_out_prefix) {
295a93f6d85Sclaudio 		printf(" Max-prefix out: %u", p->conf.max_out_prefix);
296a93f6d85Sclaudio 		if (p->conf.max_out_prefix_restart)
297a93f6d85Sclaudio 			printf(" (restart %u)",
298a93f6d85Sclaudio 			    p->conf.max_out_prefix_restart);
299a93f6d85Sclaudio 	}
300a93f6d85Sclaudio 	if (p->conf.max_prefix || p->conf.max_out_prefix)
301a93f6d85Sclaudio 		printf("\n");
302a93f6d85Sclaudio 
303ac87c040Sclaudio 	if (p->state == STATE_ESTABLISHED) {
304765bd20aSclaudio 		ina.s_addr = htonl(p->remote_bgpid);
3056671ac0bSclaudio 		printf("  BGP version 4, remote router-id %s",
3066671ac0bSclaudio 		    inet_ntoa(ina));
307d3e7ac16Sclaudio 		printf("%s\n", fmt_auth_method(p->auth_conf.method));
308ac87c040Sclaudio 	}
3096671ac0bSclaudio 	printf("  BGP state = %s", statenames[p->state]);
3106671ac0bSclaudio 	if (p->conf.down) {
3116671ac0bSclaudio 		printf(", marked down");
312ac87c040Sclaudio 	}
31369d2b5abSclaudio 	if (p->conf.reason[0]) {
3146671ac0bSclaudio 		printf(" with shutdown reason \"%s\"",
315a78f83ceSderaadt 		    log_reason(p->conf.reason));
3166671ac0bSclaudio 	}
3176671ac0bSclaudio 	if (p->stats.last_updown != 0)
3186671ac0bSclaudio 		printf(", %s for %s",
3196671ac0bSclaudio 		    p->state == STATE_ESTABLISHED ? "up" : "down",
320e67b1a58Sclaudio 		    fmt_monotime(p->stats.last_updown));
3216671ac0bSclaudio 	printf("\n");
3226671ac0bSclaudio 	printf("  Last read %s, holdtime %us, keepalive interval %us\n",
323e67b1a58Sclaudio 	    fmt_monotime(p->stats.last_read),
3246671ac0bSclaudio 	    p->holdtime, p->holdtime/3);
325e67b1a58Sclaudio 	printf("  Last write %s\n", fmt_monotime(p->stats.last_write));
326b6faf4c9Sclaudio 
327b6faf4c9Sclaudio 	hascapamp = 0;
328b6faf4c9Sclaudio 	hascapaap = 0;
329b6faf4c9Sclaudio 	for (i = AID_MIN; i < AID_MAX; i++) {
3306671ac0bSclaudio 		if (p->capa.peer.mp[i])
3316671ac0bSclaudio 			hascapamp = 1;
332b6faf4c9Sclaudio 		if (p->capa.peer.add_path[i])
333b6faf4c9Sclaudio 			hascapaap = 1;
334b6faf4c9Sclaudio 	}
335b6faf4c9Sclaudio 	if (hascapamp || hascapaap || p->capa.peer.grestart.restart ||
336b6faf4c9Sclaudio 	    p->capa.peer.refresh || p->capa.peer.enhanced_rr ||
3371d3c7c09Sclaudio 	    p->capa.peer.as4byte || p->capa.peer.policy) {
3386671ac0bSclaudio 		printf("  Neighbor capabilities:\n");
33904d0a88fSclaudio 		if (hascapamp)
3404821c8fcSclaudio 			show_neighbor_capa_mp(&p->capa.peer);
3416671ac0bSclaudio 		if (p->capa.peer.as4byte)
3426671ac0bSclaudio 			printf("    4-byte AS numbers\n");
343b6faf4c9Sclaudio 		if (p->capa.peer.refresh)
344b6faf4c9Sclaudio 			printf("    Route Refresh\n");
345b6faf4c9Sclaudio 		if (p->capa.peer.enhanced_rr)
346b6faf4c9Sclaudio 			printf("    Enhanced Route Refresh\n");
34782293aebSclaudio 		if (p->capa.peer.ext_msg)
34882293aebSclaudio 			printf("    Extended message\n");
349b6faf4c9Sclaudio 		if (p->capa.peer.grestart.restart)
350b6faf4c9Sclaudio 			show_neighbor_capa_restart(&p->capa.peer);
351b6faf4c9Sclaudio 		if (hascapaap)
352b6faf4c9Sclaudio 			show_neighbor_capa_add_path(&p->capa.peer);
3531d3c7c09Sclaudio 		if (p->capa.peer.policy)
354135bf897Sclaudio 			printf("    Open Policy role %s (local %s)\n",
3551d3c7c09Sclaudio 			    log_policy(p->remote_role),
3561d3c7c09Sclaudio 			    log_policy(p->conf.role));
3576671ac0bSclaudio 	}
358b6faf4c9Sclaudio 
359b6faf4c9Sclaudio 	hascapamp = 0;
360b6faf4c9Sclaudio 	hascapaap = 0;
361b6faf4c9Sclaudio 	for (i = AID_MIN; i < AID_MAX; i++) {
3624821c8fcSclaudio 		if (p->capa.neg.mp[i])
3634821c8fcSclaudio 			hascapamp = 1;
364b6faf4c9Sclaudio 		if (p->capa.neg.add_path[i])
365b6faf4c9Sclaudio 			hascapaap = 1;
366b6faf4c9Sclaudio 	}
367b6faf4c9Sclaudio 	if (hascapamp || hascapaap || p->capa.neg.grestart.restart ||
368b6faf4c9Sclaudio 	    p->capa.neg.refresh || p->capa.neg.enhanced_rr ||
3691d3c7c09Sclaudio 	    p->capa.neg.as4byte || p->capa.neg.policy) {
3704821c8fcSclaudio 		printf("  Negotiated capabilities:\n");
3714821c8fcSclaudio 		if (hascapamp)
3724821c8fcSclaudio 			show_neighbor_capa_mp(&p->capa.neg);
3734821c8fcSclaudio 		if (p->capa.neg.as4byte)
3744821c8fcSclaudio 			printf("    4-byte AS numbers\n");
375b6faf4c9Sclaudio 		if (p->capa.neg.refresh)
376b6faf4c9Sclaudio 			printf("    Route Refresh\n");
377b6faf4c9Sclaudio 		if (p->capa.neg.enhanced_rr)
378b6faf4c9Sclaudio 			printf("    Enhanced Route Refresh\n");
37982293aebSclaudio 		if (p->capa.neg.ext_msg)
38082293aebSclaudio 			printf("    Extended message\n");
381b6faf4c9Sclaudio 		if (p->capa.neg.grestart.restart)
382b6faf4c9Sclaudio 			show_neighbor_capa_restart(&p->capa.neg);
383b6faf4c9Sclaudio 		if (hascapaap)
384b6faf4c9Sclaudio 			show_neighbor_capa_add_path(&p->capa.neg);
3851d3c7c09Sclaudio 		if (p->capa.neg.policy)
386135bf897Sclaudio 			printf("    Open Policy role %s (local %s)\n",
3871d3c7c09Sclaudio 			    log_policy(p->remote_role),
3881d3c7c09Sclaudio 			    log_policy(p->conf.role));
3894821c8fcSclaudio 	}
3906671ac0bSclaudio 	printf("\n");
3916671ac0bSclaudio 
3926671ac0bSclaudio 	if (res->action == SHOW_NEIGHBOR_TIMERS)
3936671ac0bSclaudio 		return;
3946671ac0bSclaudio 
39504d0a88fSclaudio 	show_neighbor_msgstats(p);
3966671ac0bSclaudio 	printf("\n");
3976671ac0bSclaudio 
39804d0a88fSclaudio 	errstr = fmt_errstr(p->stats.last_sent_errcode,
3996671ac0bSclaudio 	    p->stats.last_sent_suberr);
4006671ac0bSclaudio 	if (errstr)
401ac87c040Sclaudio 		printf("  Last error sent: %s\n", errstr);
40204d0a88fSclaudio 	errstr = fmt_errstr(p->stats.last_rcvd_errcode,
403d7a3f515Sclaudio 	    p->stats.last_rcvd_suberr);
404d7a3f515Sclaudio 	if (errstr)
405ac87c040Sclaudio 		printf("  Last error received: %s\n", errstr);
406d6291362Sclaudio 	if (p->stats.last_reason[0]) {
407d6291362Sclaudio 		printf("  Last received shutdown reason: \"%s\"\n",
408d6291362Sclaudio 		    log_reason(p->stats.last_reason));
409d6291362Sclaudio 	}
410ac87c040Sclaudio 
411ac87c040Sclaudio 	if (p->state >= STATE_OPENSENT) {
4126671ac0bSclaudio 		printf("  Local host:  %20s, Local port:  %5u\n",
4136671ac0bSclaudio 		    log_addr(&p->local), p->local_port);
4146671ac0bSclaudio 
4156671ac0bSclaudio 		printf("  Remote host: %20s, Remote port: %5u\n",
4166671ac0bSclaudio 		    log_addr(&p->remote), p->remote_port);
4176671ac0bSclaudio 		printf("\n");
4186671ac0bSclaudio 	}
4196671ac0bSclaudio }
4206671ac0bSclaudio 
421d30a810dSclaudio static void
4226671ac0bSclaudio show_neighbor(struct peer *p, struct parse_result *res)
4236671ac0bSclaudio {
4246671ac0bSclaudio 	char *s;
4256671ac0bSclaudio 
4266671ac0bSclaudio 	switch (res->action) {
4276671ac0bSclaudio 	case SHOW:
4286671ac0bSclaudio 	case SHOW_SUMMARY:
4296671ac0bSclaudio 		show_summary(p);
4306671ac0bSclaudio 		break;
4316671ac0bSclaudio 	case SHOW_SUMMARY_TERSE:
4326671ac0bSclaudio 		s = fmt_peer(p->conf.descr, &p->conf.remote_addr,
4336671ac0bSclaudio 		    p->conf.remote_masklen);
4346671ac0bSclaudio 		printf("%s %s %s\n", s, log_as(p->conf.remote_as),
4356671ac0bSclaudio 		    p->conf.template ? "Template" : statenames[p->state]);
4366671ac0bSclaudio 		free(s);
4376671ac0bSclaudio 		break;
4386671ac0bSclaudio 	case SHOW_NEIGHBOR:
4396671ac0bSclaudio 	case SHOW_NEIGHBOR_TIMERS:
4406671ac0bSclaudio 		show_neighbor_full(p, res);
4416671ac0bSclaudio 		break;
4426671ac0bSclaudio 	case SHOW_NEIGHBOR_TERSE:
4436671ac0bSclaudio 		s = fmt_peer(NULL, &p->conf.remote_addr,
4446671ac0bSclaudio 		    p->conf.remote_masklen);
4456671ac0bSclaudio 		printf("%llu %llu %llu %llu %llu %llu %llu %llu %llu "
4466671ac0bSclaudio 		    "%llu %u %u %llu %llu %llu %llu %s %s \"%s\"\n",
4476671ac0bSclaudio 		    p->stats.msg_sent_open, p->stats.msg_rcvd_open,
4486671ac0bSclaudio 		    p->stats.msg_sent_notification,
4496671ac0bSclaudio 		    p->stats.msg_rcvd_notification,
4506671ac0bSclaudio 		    p->stats.msg_sent_update, p->stats.msg_rcvd_update,
4516671ac0bSclaudio 		    p->stats.msg_sent_keepalive, p->stats.msg_rcvd_keepalive,
4526671ac0bSclaudio 		    p->stats.msg_sent_rrefresh, p->stats.msg_rcvd_rrefresh,
4536671ac0bSclaudio 		    p->stats.prefix_cnt, p->conf.max_prefix,
4546671ac0bSclaudio 		    p->stats.prefix_sent_update, p->stats.prefix_rcvd_update,
4556671ac0bSclaudio 		    p->stats.prefix_sent_withdraw,
4566671ac0bSclaudio 		    p->stats.prefix_rcvd_withdraw, s,
4576671ac0bSclaudio 		    log_as(p->conf.remote_as), p->conf.descr);
4586671ac0bSclaudio 		free(s);
4596671ac0bSclaudio 		break;
4606671ac0bSclaudio 	default:
4616671ac0bSclaudio 		break;
4626671ac0bSclaudio 	}
4636671ac0bSclaudio }
4646671ac0bSclaudio 
465d30a810dSclaudio static void
466cc406fb9Sclaudio show_timer(struct ctl_timer *t)
467cc406fb9Sclaudio {
468cc406fb9Sclaudio 	printf("  %-20s ", timernames[t->type]);
469cc406fb9Sclaudio 
470cc406fb9Sclaudio 	if (t->val <= 0)
471cc406fb9Sclaudio 		printf("%-20s\n", "due");
472cc406fb9Sclaudio 	else
473e67b1a58Sclaudio 		printf("due in %-13s\n", fmt_timeframe(t->val));
474cc406fb9Sclaudio }
475cc406fb9Sclaudio 
476d30a810dSclaudio static void
4776671ac0bSclaudio show_fib(struct kroute_full *kf)
4786671ac0bSclaudio {
4796671ac0bSclaudio 	char	*p;
4806671ac0bSclaudio 
4816671ac0bSclaudio 	if (asprintf(&p, "%s/%u", log_addr(&kf->prefix), kf->prefixlen) == -1)
4826671ac0bSclaudio 		err(1, NULL);
4830d49b5f3Sclaudio 	printf("%-5s %4i %-32s ", fmt_fib_flags(kf->flags), kf->priority, p);
4846671ac0bSclaudio 	free(p);
4856671ac0bSclaudio 
4866671ac0bSclaudio 	if (kf->flags & F_CONNECTED)
4876671ac0bSclaudio 		printf("link#%u", kf->ifindex);
4886671ac0bSclaudio 	else
4896671ac0bSclaudio 		printf("%s", log_addr(&kf->nexthop));
4901edf3470Sclaudio 	if (kf->flags & F_MPLS)
4911edf3470Sclaudio 		printf(" mpls %d", ntohl(kf->mplslabel) >> MPLS_LABEL_OFFSET);
4926671ac0bSclaudio 	printf("\n");
4936671ac0bSclaudio }
4946671ac0bSclaudio 
495d30a810dSclaudio static void
4966671ac0bSclaudio show_fib_table(struct ktable *kt)
4976671ac0bSclaudio {
4986671ac0bSclaudio 	printf("%5i %-20s %-8s%s\n", kt->rtableid, kt->descr,
4996671ac0bSclaudio 	    kt->fib_sync ? "coupled" : "decoupled",
5006671ac0bSclaudio 	    kt->fib_sync != kt->fib_conf ? "*" : "");
5016671ac0bSclaudio }
5026671ac0bSclaudio 
503d30a810dSclaudio static void
5045fed6b04Sclaudio print_flowspec_list(struct flowspec *f, int type, int is_v6)
5055fed6b04Sclaudio {
5065fed6b04Sclaudio 	const uint8_t *comp;
5075fed6b04Sclaudio 	const char *fmt;
5085fed6b04Sclaudio 	int complen, off = 0;
5095fed6b04Sclaudio 
5105fed6b04Sclaudio 	if (flowspec_get_component(f->data, f->len, type, is_v6,
5115fed6b04Sclaudio 	    &comp, &complen) != 1)
5125fed6b04Sclaudio 		return;
5135fed6b04Sclaudio 
5145fed6b04Sclaudio 	printf("%s ", flowspec_fmt_label(type));
5155fed6b04Sclaudio 	fmt = flowspec_fmt_num_op(comp, complen, &off);
5165fed6b04Sclaudio 	if (off == -1) {
5175fed6b04Sclaudio 		printf("%s ", fmt);
5185fed6b04Sclaudio 	} else {
5195fed6b04Sclaudio 		printf("{ %s ", fmt);
5205fed6b04Sclaudio 		do {
5215fed6b04Sclaudio 			fmt = flowspec_fmt_num_op(comp, complen, &off);
5225fed6b04Sclaudio 			printf("%s ", fmt);
5235fed6b04Sclaudio 		} while (off != -1);
5245fed6b04Sclaudio 		printf("} ");
5255fed6b04Sclaudio 	}
5265fed6b04Sclaudio }
5275fed6b04Sclaudio 
5285fed6b04Sclaudio static void
5295fed6b04Sclaudio print_flowspec_flags(struct flowspec *f, int type, int is_v6)
5305fed6b04Sclaudio {
5315fed6b04Sclaudio 	const uint8_t *comp;
5325fed6b04Sclaudio 	const char *fmt, *flags;
5335fed6b04Sclaudio 	int complen, off = 0;
5345fed6b04Sclaudio 
5355fed6b04Sclaudio 	switch (type) {
5365fed6b04Sclaudio 	case FLOWSPEC_TYPE_TCP_FLAGS:
5375fed6b04Sclaudio 		flags = FLOWSPEC_TCP_FLAG_STRING;
5385fed6b04Sclaudio 		break;
5395fed6b04Sclaudio 	case FLOWSPEC_TYPE_FRAG:
5405fed6b04Sclaudio 		if (!is_v6)
5415fed6b04Sclaudio 			flags = FLOWSPEC_FRAG_STRING4;
5425fed6b04Sclaudio 		else
5435fed6b04Sclaudio 			flags = FLOWSPEC_FRAG_STRING6;
5445fed6b04Sclaudio 		break;
5455cff40bcSclaudio 	default:
5465cff40bcSclaudio 		printf("??? ");
5475cff40bcSclaudio 		return;
5485fed6b04Sclaudio 	}
5495fed6b04Sclaudio 
5505cff40bcSclaudio 	if (flowspec_get_component(f->data, f->len, type, is_v6,
5515cff40bcSclaudio 	    &comp, &complen) != 1)
5525cff40bcSclaudio 		return;
5535cff40bcSclaudio 
5545cff40bcSclaudio 	printf("%s ", flowspec_fmt_label(type));
5555cff40bcSclaudio 
5565fed6b04Sclaudio 	fmt = flowspec_fmt_bin_op(comp, complen, &off, flags);
5575fed6b04Sclaudio 	if (off == -1) {
5585fed6b04Sclaudio 		printf("%s ", fmt);
5595fed6b04Sclaudio 	} else {
5605fed6b04Sclaudio 		printf("{ %s ", fmt);
5615fed6b04Sclaudio 		do {
5625fed6b04Sclaudio 			fmt = flowspec_fmt_bin_op(comp, complen, &off, flags);
5635fed6b04Sclaudio 			printf("%s ", fmt);
5645fed6b04Sclaudio 		} while (off != -1);
5655fed6b04Sclaudio 		printf("} ");
5665fed6b04Sclaudio 	}
5675fed6b04Sclaudio }
5685fed6b04Sclaudio 
5695fed6b04Sclaudio static void
5705fed6b04Sclaudio print_flowspec_addr(struct flowspec *f, int type, int is_v6)
5715fed6b04Sclaudio {
5725fed6b04Sclaudio 	struct bgpd_addr addr;
5735fed6b04Sclaudio 	uint8_t plen;
5745fed6b04Sclaudio 
5755fed6b04Sclaudio 	flowspec_get_addr(f->data, f->len, type, is_v6, &addr, &plen, NULL);
5765fed6b04Sclaudio 	if (plen == 0)
5775fed6b04Sclaudio 		printf("%s any ", flowspec_fmt_label(type));
5785fed6b04Sclaudio 	else
5795fed6b04Sclaudio 		printf("%s %s/%u ", flowspec_fmt_label(type),
5805fed6b04Sclaudio 		    log_addr(&addr), plen);
5815fed6b04Sclaudio }
5825fed6b04Sclaudio 
5835fed6b04Sclaudio static void
5845fed6b04Sclaudio show_flowspec(struct flowspec *f)
5855fed6b04Sclaudio {
5865fed6b04Sclaudio 	int is_v6 = (f->aid == AID_FLOWSPECv6);
5875fed6b04Sclaudio 
5885fed6b04Sclaudio 	printf("%-5s ", fmt_fib_flags(f->flags));
5895fed6b04Sclaudio 	print_flowspec_list(f, FLOWSPEC_TYPE_PROTO, is_v6);
5905fed6b04Sclaudio 
5915fed6b04Sclaudio 	print_flowspec_addr(f, FLOWSPEC_TYPE_SOURCE, is_v6);
5925fed6b04Sclaudio 	print_flowspec_list(f, FLOWSPEC_TYPE_SRC_PORT, is_v6);
5935fed6b04Sclaudio 
5945fed6b04Sclaudio 	print_flowspec_addr(f, FLOWSPEC_TYPE_DEST, is_v6);
5955fed6b04Sclaudio 	print_flowspec_list(f, FLOWSPEC_TYPE_DST_PORT, is_v6);
5965fed6b04Sclaudio 
5975fed6b04Sclaudio 	print_flowspec_list(f, FLOWSPEC_TYPE_DSCP, is_v6);
5985fed6b04Sclaudio 	print_flowspec_list(f, FLOWSPEC_TYPE_PKT_LEN, is_v6);
5995fed6b04Sclaudio 	print_flowspec_flags(f, FLOWSPEC_TYPE_TCP_FLAGS, is_v6);
6005fed6b04Sclaudio 	print_flowspec_flags(f, FLOWSPEC_TYPE_FRAG, is_v6);
6015fed6b04Sclaudio 	/* TODO: fixup the code handling to be like in the parser */
6025fed6b04Sclaudio 	print_flowspec_list(f, FLOWSPEC_TYPE_ICMP_TYPE, is_v6);
6035fed6b04Sclaudio 	print_flowspec_list(f, FLOWSPEC_TYPE_ICMP_CODE, is_v6);
6045fed6b04Sclaudio 
6055fed6b04Sclaudio 	printf("\n");
6065fed6b04Sclaudio }
6075fed6b04Sclaudio 
6085fed6b04Sclaudio static void
6096671ac0bSclaudio show_nexthop(struct ctl_show_nexthop *nh)
6106671ac0bSclaudio {
6116671ac0bSclaudio 	char		*s;
6126671ac0bSclaudio 
6136671ac0bSclaudio 	printf("%s %-15s ", nh->valid ? "*" : " ", log_addr(&nh->addr));
6146671ac0bSclaudio 	if (!nh->krvalid) {
6156671ac0bSclaudio 		printf("\n");
6166671ac0bSclaudio 		return;
6176671ac0bSclaudio 	}
618fe65f56aSclaudio 	if (asprintf(&s, "%s/%u", log_addr(&nh->kr.prefix),
619fe65f56aSclaudio 	    nh->kr.prefixlen) == -1)
6206671ac0bSclaudio 		err(1, NULL);
6216671ac0bSclaudio 	printf("%-20s", s);
6226671ac0bSclaudio 	free(s);
623fe65f56aSclaudio 	printf("%3i %-15s ", nh->kr.priority,
624fe65f56aSclaudio 	    nh->kr.flags & F_CONNECTED ? "connected" :
625fe65f56aSclaudio 	    log_addr(&nh->kr.nexthop));
626fe65f56aSclaudio 
6276671ac0bSclaudio 	if (nh->iface.ifname[0]) {
6286671ac0bSclaudio 		printf("%s (%s, %s)", nh->iface.ifname,
6296671ac0bSclaudio 		    nh->iface.is_up ? "UP" : "DOWN",
6306671ac0bSclaudio 		    nh->iface.baudrate ?
6316671ac0bSclaudio 		    get_baudrate(nh->iface.baudrate, "bps") :
6326671ac0bSclaudio 		    nh->iface.linkstate);
6336671ac0bSclaudio 	}
6346671ac0bSclaudio 	printf("\n");
6356671ac0bSclaudio }
6366671ac0bSclaudio 
637d30a810dSclaudio static void
6386671ac0bSclaudio show_interface(struct ctl_show_interface *iface)
6396671ac0bSclaudio {
6406671ac0bSclaudio 	printf("%-15s", iface->ifname);
6416671ac0bSclaudio 	printf("%-9u", iface->rdomain);
6426671ac0bSclaudio 	printf("%-9s", iface->nh_reachable ? "ok" : "invalid");
6436671ac0bSclaudio 	printf("%-7s", iface->is_up ? "UP" : "");
6446671ac0bSclaudio 
6456671ac0bSclaudio 	if (iface->media[0])
6466671ac0bSclaudio 		printf("%s, ", iface->media);
6476671ac0bSclaudio 	printf("%s", iface->linkstate);
6486671ac0bSclaudio 
6496671ac0bSclaudio 	if (iface->baudrate > 0)
6506671ac0bSclaudio 		printf(", %s", get_baudrate(iface->baudrate, "Bit/s"));
6516671ac0bSclaudio 	printf("\n");
6526671ac0bSclaudio }
6536671ac0bSclaudio 
654d30a810dSclaudio static void
6554b4c1963Sclaudio show_communities(struct ibuf *data, struct parse_result *res)
65604d0a88fSclaudio {
65704d0a88fSclaudio 	struct community c;
65859154960Sclaudio 	uint64_t ext;
65959154960Sclaudio 	uint8_t type = 0;
66004d0a88fSclaudio 
6614b4c1963Sclaudio 	while (ibuf_size(data) != 0) {
6624b4c1963Sclaudio 		if (ibuf_get(data, &c, sizeof(c)) == -1) {
6634b4c1963Sclaudio 			warn("communities");
6644b4c1963Sclaudio 			break;
6654b4c1963Sclaudio 		}
66604d0a88fSclaudio 
667ac87c040Sclaudio 		if (type != c.flags) {
66804d0a88fSclaudio 			if (type != 0)
66904d0a88fSclaudio 				printf("%c", EOL0(res->flags));
670ac87c040Sclaudio 			printf("    %s:", fmt_attr(c.flags,
67104d0a88fSclaudio 			    ATTR_OPTIONAL | ATTR_TRANSITIVE));
672ac87c040Sclaudio 			type = c.flags;
67304d0a88fSclaudio 		}
67404d0a88fSclaudio 
675ac87c040Sclaudio 		switch (c.flags) {
67604d0a88fSclaudio 		case COMMUNITY_TYPE_BASIC:
67704d0a88fSclaudio 			printf(" %s", fmt_community(c.data1, c.data2));
67804d0a88fSclaudio 			break;
67904d0a88fSclaudio 		case COMMUNITY_TYPE_LARGE:
68004d0a88fSclaudio 			printf(" %s",
68104d0a88fSclaudio 			    fmt_large_community(c.data1, c.data2, c.data3));
68204d0a88fSclaudio 			break;
68304d0a88fSclaudio 		case COMMUNITY_TYPE_EXT:
68459154960Sclaudio 			ext = (uint64_t)c.data3 << 48;
685c2371130Sclaudio 			switch ((c.data3 >> 8) & EXT_COMMUNITY_VALUE) {
68604d0a88fSclaudio 			case EXT_COMMUNITY_TRANS_TWO_AS:
68704d0a88fSclaudio 			case EXT_COMMUNITY_TRANS_OPAQUE:
68804d0a88fSclaudio 			case EXT_COMMUNITY_TRANS_EVPN:
68959154960Sclaudio 				ext |= ((uint64_t)c.data1 & 0xffff) << 32;
69059154960Sclaudio 				ext |= (uint64_t)c.data2;
69104d0a88fSclaudio 				break;
69204d0a88fSclaudio 			case EXT_COMMUNITY_TRANS_FOUR_AS:
69304d0a88fSclaudio 			case EXT_COMMUNITY_TRANS_IPV4:
69459154960Sclaudio 				ext |= (uint64_t)c.data1 << 16;
69559154960Sclaudio 				ext |= (uint64_t)c.data2 & 0xffff;
69604d0a88fSclaudio 				break;
69704d0a88fSclaudio 			}
6984b4c1963Sclaudio 			printf(" %s", fmt_ext_community(ext));
69904d0a88fSclaudio 			break;
70004d0a88fSclaudio 		}
70104d0a88fSclaudio 	}
70204d0a88fSclaudio 
70304d0a88fSclaudio 	printf("%c", EOL0(res->flags));
70404d0a88fSclaudio }
70504d0a88fSclaudio 
70604d0a88fSclaudio static void
707dd147aaaSclaudio show_community(struct ibuf *buf)
70804d0a88fSclaudio {
70959154960Sclaudio 	uint16_t	a, v;
71004d0a88fSclaudio 
711dd147aaaSclaudio 	while (ibuf_size(buf) > 0) {
712dd147aaaSclaudio 		if (ibuf_get_n16(buf, &a) == -1 ||
713dd147aaaSclaudio 		    ibuf_get_n16(buf, &v) == -1) {
714ac87c040Sclaudio 			printf("bad length");
71504d0a88fSclaudio 			return;
716ac87c040Sclaudio 		}
71704d0a88fSclaudio 		printf("%s", fmt_community(a, v));
71804d0a88fSclaudio 
719dd147aaaSclaudio 		if (ibuf_size(buf) > 0)
72004d0a88fSclaudio 			printf(" ");
72104d0a88fSclaudio 	}
72204d0a88fSclaudio }
72304d0a88fSclaudio 
72404d0a88fSclaudio static void
725dd147aaaSclaudio show_large_community(struct ibuf *buf)
72604d0a88fSclaudio {
72759154960Sclaudio 	uint32_t	a, l1, l2;
72804d0a88fSclaudio 
729dd147aaaSclaudio 	while (ibuf_size(buf) > 0) {
730dd147aaaSclaudio 		if (ibuf_get_n32(buf, &a) == -1 ||
731dd147aaaSclaudio 		    ibuf_get_n32(buf, &l1) == -1 ||
732dd147aaaSclaudio 		    ibuf_get_n32(buf, &l2) == -1) {
733ac87c040Sclaudio 			printf("bad length");
73404d0a88fSclaudio 			return;
735ac87c040Sclaudio 		}
73604d0a88fSclaudio 		printf("%s", fmt_large_community(a, l1, l2));
73704d0a88fSclaudio 
738dd147aaaSclaudio 		if (ibuf_size(buf) > 0)
73904d0a88fSclaudio 			printf(" ");
74004d0a88fSclaudio 	}
74104d0a88fSclaudio }
74204d0a88fSclaudio 
74304d0a88fSclaudio static void
744dd147aaaSclaudio show_ext_community(struct ibuf *buf)
74504d0a88fSclaudio {
7464b4c1963Sclaudio 	uint64_t	ext;
74704d0a88fSclaudio 
748dd147aaaSclaudio 	while (ibuf_size(buf) > 0) {
749dd147aaaSclaudio 		if (ibuf_get_n64(buf, &ext) == -1) {
750ac87c040Sclaudio 			printf("bad length");
75104d0a88fSclaudio 			return;
752ac87c040Sclaudio 		}
7534b4c1963Sclaudio 		printf("%s", fmt_ext_community(ext));
75404d0a88fSclaudio 
755dd147aaaSclaudio 		if (ibuf_size(buf) > 0)
75604d0a88fSclaudio 			printf(" ");
75704d0a88fSclaudio 	}
75804d0a88fSclaudio }
75904d0a88fSclaudio 
760d30a810dSclaudio static void
761dd147aaaSclaudio show_attr(struct ibuf *buf, int reqflags, int addpath)
76204d0a88fSclaudio {
76304d0a88fSclaudio 	struct in_addr	 id;
76404d0a88fSclaudio 	struct bgpd_addr prefix;
765dd147aaaSclaudio 	struct ibuf	 asbuf, *path = NULL;
76604d0a88fSclaudio 	char		*aspath;
767dd147aaaSclaudio 	size_t		 i, alen;
768dd147aaaSclaudio 	uint32_t	 as, pathid, val;
769dd147aaaSclaudio 	uint16_t	 short_as, afi;
770dd147aaaSclaudio 	uint8_t		 flags, type, safi, aid, prefixlen, origin, b;
771dd147aaaSclaudio 	int		 e2, e4;
77204d0a88fSclaudio 
773dd147aaaSclaudio 	if (ibuf_get_n8(buf, &flags) == -1 ||
774dd147aaaSclaudio 	    ibuf_get_n8(buf, &type) == -1)
775dd147aaaSclaudio 		goto bad_len;
77604d0a88fSclaudio 
77704d0a88fSclaudio 	/* get the attribute length */
77804d0a88fSclaudio 	if (flags & ATTR_EXTLEN) {
779dd147aaaSclaudio 		uint16_t attr_len;
780dd147aaaSclaudio 		if (ibuf_get_n16(buf, &attr_len) == -1)
781dd147aaaSclaudio 			goto bad_len;
782dd147aaaSclaudio 		alen = attr_len;
78304d0a88fSclaudio 	} else {
784dd147aaaSclaudio 		uint8_t attr_len;
785dd147aaaSclaudio 		if (ibuf_get_n8(buf, &attr_len) == -1)
786dd147aaaSclaudio 			goto bad_len;
787dd147aaaSclaudio 		alen = attr_len;
78804d0a88fSclaudio 	}
78904d0a88fSclaudio 
79004d0a88fSclaudio 	/* bad imsg len how can that happen!? */
791dd147aaaSclaudio 	if (alen > ibuf_size(buf))
792dd147aaaSclaudio 		goto bad_len;
79304d0a88fSclaudio 
79404d0a88fSclaudio 	printf("    %s: ", fmt_attr(type, flags));
79504d0a88fSclaudio 
79604d0a88fSclaudio 	switch (type) {
79704d0a88fSclaudio 	case ATTR_ORIGIN:
798dd147aaaSclaudio 		if (alen != 1 || ibuf_get_n8(buf, &origin) == -1)
799dd147aaaSclaudio 			goto bad_len;
800dd147aaaSclaudio 		printf("%s", fmt_origin(origin, 0));
80104d0a88fSclaudio 		break;
80204d0a88fSclaudio 	case ATTR_ASPATH:
80304d0a88fSclaudio 	case ATTR_AS4_PATH:
80404d0a88fSclaudio 		/* prefer 4-byte AS here */
80546d5331aSclaudio 		e4 = aspath_verify(buf, 1, 0);
80646d5331aSclaudio 		e2 = aspath_verify(buf, 0, 0);
80704d0a88fSclaudio 		if (e4 == 0 || e4 == AS_ERR_SOFT) {
80846d5331aSclaudio 			ibuf_from_ibuf(&asbuf, buf);
80904d0a88fSclaudio 		} else if (e2 == 0 || e2 == AS_ERR_SOFT) {
81046d5331aSclaudio 			if ((path = aspath_inflate(buf)) == NULL) {
81146d5331aSclaudio 				printf("aspath_inflate failed");
81246d5331aSclaudio 				break;
81346d5331aSclaudio 			}
81446d5331aSclaudio 			ibuf_from_ibuf(&asbuf, path);
81504d0a88fSclaudio 		} else {
81604d0a88fSclaudio 			printf("bad AS-Path");
81704d0a88fSclaudio 			break;
81804d0a88fSclaudio 		}
81946d5331aSclaudio 		if (aspath_asprint(&aspath, &asbuf) == -1)
82004d0a88fSclaudio 			err(1, NULL);
82104d0a88fSclaudio 		printf("%s", aspath);
82204d0a88fSclaudio 		free(aspath);
82346d5331aSclaudio 		ibuf_free(path);
82404d0a88fSclaudio 		break;
82504d0a88fSclaudio 	case ATTR_NEXTHOP:
826dd147aaaSclaudio 	case ATTR_ORIGINATOR_ID:
827dd147aaaSclaudio 		if (alen != 4 || ibuf_get(buf, &id, sizeof(id)) == -1)
828dd147aaaSclaudio 			goto bad_len;
82904d0a88fSclaudio 		printf("%s", inet_ntoa(id));
83004d0a88fSclaudio 		break;
83104d0a88fSclaudio 	case ATTR_MED:
83204d0a88fSclaudio 	case ATTR_LOCALPREF:
833dd147aaaSclaudio 		if (alen != 4 || ibuf_get_n32(buf, &val) == -1)
834dd147aaaSclaudio 			goto bad_len;
83504d0a88fSclaudio 		printf("%u", val);
83604d0a88fSclaudio 		break;
83704d0a88fSclaudio 	case ATTR_AGGREGATOR:
83804d0a88fSclaudio 	case ATTR_AS4_AGGREGATOR:
83904d0a88fSclaudio 		if (alen == 8) {
840dd147aaaSclaudio 			if (ibuf_get_n32(buf, &as) == -1 ||
841dd147aaaSclaudio 			    ibuf_get(buf, &id, sizeof(id)) == -1)
842dd147aaaSclaudio 				goto bad_len;
84304d0a88fSclaudio 		} else if (alen == 6) {
844dd147aaaSclaudio 			if (ibuf_get_n16(buf, &short_as) == -1 ||
845dd147aaaSclaudio 			    ibuf_get(buf, &id, sizeof(id)) == -1)
846dd147aaaSclaudio 				goto bad_len;
847dd147aaaSclaudio 			as = short_as;
84804d0a88fSclaudio 		} else {
849dd147aaaSclaudio 			goto bad_len;
85004d0a88fSclaudio 		}
85104d0a88fSclaudio 		printf("%s [%s]", log_as(as), inet_ntoa(id));
85204d0a88fSclaudio 		break;
85304d0a88fSclaudio 	case ATTR_COMMUNITIES:
854dd147aaaSclaudio 		show_community(buf);
85504d0a88fSclaudio 		break;
85604d0a88fSclaudio 	case ATTR_CLUSTER_LIST:
857dd147aaaSclaudio 		while (ibuf_size(buf) > 0) {
858dd147aaaSclaudio 			if (ibuf_get(buf, &id, sizeof(id)) == -1)
859dd147aaaSclaudio 				goto bad_len;
86004d0a88fSclaudio 			printf(" %s", inet_ntoa(id));
86104d0a88fSclaudio 		}
86204d0a88fSclaudio 		break;
86304d0a88fSclaudio 	case ATTR_MP_REACH_NLRI:
86404d0a88fSclaudio 	case ATTR_MP_UNREACH_NLRI:
865dd147aaaSclaudio 		if (ibuf_get_n16(buf, &afi) == -1 ||
866dd147aaaSclaudio 		    ibuf_get_n8(buf, &safi) == -1)
867dd147aaaSclaudio 			goto bad_len;
86804d0a88fSclaudio 
86904d0a88fSclaudio 		if (afi2aid(afi, safi, &aid) == -1) {
87004d0a88fSclaudio 			printf("bad AFI/SAFI pair");
87104d0a88fSclaudio 			break;
87204d0a88fSclaudio 		}
87304d0a88fSclaudio 		printf(" %s", aid2str(aid));
87404d0a88fSclaudio 
87504d0a88fSclaudio 		if (type == ATTR_MP_REACH_NLRI) {
87604d0a88fSclaudio 			struct bgpd_addr nexthop;
87759154960Sclaudio 			uint8_t nhlen;
878dd147aaaSclaudio 			if (ibuf_get_n8(buf, &nhlen) == -1)
87904d0a88fSclaudio 				goto bad_len;
880ac87c040Sclaudio 			memset(&nexthop, 0, sizeof(nexthop));
88104d0a88fSclaudio 			switch (aid) {
88204d0a88fSclaudio 			case AID_INET6:
88304d0a88fSclaudio 				nexthop.aid = aid;
88404d0a88fSclaudio 				if (nhlen != 16 && nhlen != 32)
88504d0a88fSclaudio 					goto bad_len;
886dd147aaaSclaudio 				if (ibuf_get(buf, &nexthop.v6,
887dd147aaaSclaudio 				    sizeof(nexthop.v6)) == -1)
888dd147aaaSclaudio 					goto bad_len;
88904d0a88fSclaudio 				break;
89004d0a88fSclaudio 			case AID_VPN_IPv4:
89104d0a88fSclaudio 				if (nhlen != 12)
89204d0a88fSclaudio 					goto bad_len;
89304d0a88fSclaudio 				nexthop.aid = AID_INET;
894dd147aaaSclaudio 				if (ibuf_skip(buf, sizeof(uint64_t)) == -1 ||
895dd147aaaSclaudio 				    ibuf_get(buf, &nexthop.v4,
896dd147aaaSclaudio 				    sizeof(nexthop.v4)) == -1)
897dd147aaaSclaudio 					goto bad_len;
89804d0a88fSclaudio 				break;
899ac87c040Sclaudio 			case AID_VPN_IPv6:
900ac87c040Sclaudio 				if (nhlen != 24)
901ac87c040Sclaudio 					goto bad_len;
902ac87c040Sclaudio 				nexthop.aid = AID_INET6;
903dd147aaaSclaudio 				if (ibuf_skip(buf, sizeof(uint64_t)) == -1 ||
904dd147aaaSclaudio 				    ibuf_get(buf, &nexthop.v6,
905dd147aaaSclaudio 				    sizeof(nexthop.v6)) == -1)
906dd147aaaSclaudio 					goto bad_len;
907ac87c040Sclaudio 				break;
90804d0a88fSclaudio 			default:
90904d0a88fSclaudio 				printf("unhandled AID #%u", aid);
91004d0a88fSclaudio 				goto done;
91104d0a88fSclaudio 			}
91204d0a88fSclaudio 			/* ignore reserved (old SNPA) field as per RFC4760 */
913dd147aaaSclaudio 			if (ibuf_skip(buf, 1) == -1)
914dd147aaaSclaudio 				goto bad_len;
91504d0a88fSclaudio 
91604d0a88fSclaudio 			printf(" nexthop: %s", log_addr(&nexthop));
91704d0a88fSclaudio 		}
91804d0a88fSclaudio 
9195ad4fcbaSclaudio 		while (ibuf_size(buf) > 0) {
9205ad4fcbaSclaudio 			if (addpath)
9215ad4fcbaSclaudio 				if (ibuf_get_n32(buf, &pathid) == -1)
9225ad4fcbaSclaudio 					goto bad_len;
92304d0a88fSclaudio 			switch (aid) {
92404d0a88fSclaudio 			case AID_INET6:
9255ad4fcbaSclaudio 				if (nlri_get_prefix6(buf, &prefix,
9265ad4fcbaSclaudio 				    &prefixlen) == -1)
9275ad4fcbaSclaudio 					goto bad_len;
92804d0a88fSclaudio 				break;
92904d0a88fSclaudio 			case AID_VPN_IPv4:
9305ad4fcbaSclaudio 				if (nlri_get_vpn4(buf, &prefix,
9315ad4fcbaSclaudio 				    &prefixlen, 1) == -1)
9325ad4fcbaSclaudio 					goto bad_len;
93304d0a88fSclaudio 				break;
934ac87c040Sclaudio 			case AID_VPN_IPv6:
9355ad4fcbaSclaudio 				if (nlri_get_vpn6(buf, &prefix,
9365ad4fcbaSclaudio 				    &prefixlen, 1) == -1)
9375ad4fcbaSclaudio 					goto bad_len;
938ac87c040Sclaudio 				break;
93904d0a88fSclaudio 			default:
94004d0a88fSclaudio 				printf("unhandled AID #%u", aid);
94104d0a88fSclaudio 				goto done;
94204d0a88fSclaudio 			}
94304d0a88fSclaudio 			printf(" %s/%u", log_addr(&prefix), prefixlen);
9449e59dee7Sclaudio 			if (addpath)
9459e59dee7Sclaudio 				printf(" path-id %u", pathid);
94604d0a88fSclaudio 		}
94704d0a88fSclaudio 		break;
94804d0a88fSclaudio 	case ATTR_EXT_COMMUNITIES:
949dd147aaaSclaudio 		show_ext_community(buf);
95004d0a88fSclaudio 		break;
95104d0a88fSclaudio 	case ATTR_LARGE_COMMUNITIES:
952dd147aaaSclaudio 		show_large_community(buf);
95304d0a88fSclaudio 		break;
954135bf897Sclaudio 	case ATTR_OTC:
955dd147aaaSclaudio 		if (alen != 4 || ibuf_get_n32(buf, &as) == -1)
956dd147aaaSclaudio 			goto bad_len;
957135bf897Sclaudio 		printf("%s", log_as(as));
958135bf897Sclaudio 		break;
95904d0a88fSclaudio 	case ATTR_ATOMIC_AGGREGATE:
96004d0a88fSclaudio 	default:
961dd147aaaSclaudio 		printf(" len %zu", alen);
96204d0a88fSclaudio 		if (alen) {
96304d0a88fSclaudio 			printf(":");
964dd147aaaSclaudio 			for (i = 0; i < alen; i++) {
965dd147aaaSclaudio 				if (ibuf_get_n8(buf, &b) == -1)
966dd147aaaSclaudio 					goto bad_len;
967dd147aaaSclaudio 				printf(" %02x", b);
968dd147aaaSclaudio 			}
96904d0a88fSclaudio 		}
97004d0a88fSclaudio 		break;
97104d0a88fSclaudio 	}
972dd147aaaSclaudio 
97304d0a88fSclaudio  done:
97452d49889Sclaudio 	printf("%c", EOL0(reqflags));
975dd147aaaSclaudio 	return;
976dd147aaaSclaudio 
977dd147aaaSclaudio  bad_len:
978dd147aaaSclaudio 	printf("bad length%c", EOL0(reqflags));
97904d0a88fSclaudio }
98004d0a88fSclaudio 
9816671ac0bSclaudio static void
98246d5331aSclaudio show_rib_brief(struct ctl_show_rib *r, struct ibuf *asbuf)
9836671ac0bSclaudio {
98404d0a88fSclaudio 	char *p, *aspath;
9856671ac0bSclaudio 
98604d0a88fSclaudio 	if (asprintf(&p, "%s/%u", log_addr(&r->prefix), r->prefixlen) == -1)
98704d0a88fSclaudio 		err(1, NULL);
98850d35cacSclaudio 	printf("%s %s-%s %-20s %-15s %5u %5u ",
98950d35cacSclaudio 	    fmt_flags(r->flags, 1), fmt_ovs(r->roa_validation_state, 1),
99050d35cacSclaudio 	    fmt_avs(r->aspa_validation_state, 1), p,
99104d0a88fSclaudio 	    log_addr(&r->exit_nexthop), r->local_pref, r->med);
99204d0a88fSclaudio 	free(p);
9936671ac0bSclaudio 
99446d5331aSclaudio 	if (aspath_asprint(&aspath, asbuf) == -1)
9956671ac0bSclaudio 		err(1, NULL);
9966671ac0bSclaudio 	if (strlen(aspath) > 0)
9976671ac0bSclaudio 		printf("%s ", aspath);
9986671ac0bSclaudio 	free(aspath);
9996671ac0bSclaudio 
100004d0a88fSclaudio 	printf("%s\n", fmt_origin(r->origin, 1));
10016671ac0bSclaudio }
10026671ac0bSclaudio 
10036671ac0bSclaudio static void
100446d5331aSclaudio show_rib_detail(struct ctl_show_rib *r, struct ibuf *asbuf, int flag0)
10056671ac0bSclaudio {
10066671ac0bSclaudio 	struct in_addr		 id;
10076671ac0bSclaudio 	char			*aspath, *s;
10086671ac0bSclaudio 
10096671ac0bSclaudio 	printf("\nBGP routing table entry for %s/%u%c",
10106671ac0bSclaudio 	    log_addr(&r->prefix), r->prefixlen,
10116671ac0bSclaudio 	    EOL0(flag0));
10126671ac0bSclaudio 
101346d5331aSclaudio 	if (aspath_asprint(&aspath, asbuf) == -1)
10146671ac0bSclaudio 		err(1, NULL);
10156671ac0bSclaudio 	if (strlen(aspath) > 0)
10166671ac0bSclaudio 		printf("    %s%c", aspath, EOL0(flag0));
10176671ac0bSclaudio 	free(aspath);
10186671ac0bSclaudio 
10196671ac0bSclaudio 	s = fmt_peer(r->descr, &r->remote_addr, -1);
10206671ac0bSclaudio 	id.s_addr = htonl(r->remote_id);
1021929193c3Sclaudio 	printf("    Nexthop %s ", log_addr(&r->exit_nexthop));
1022929193c3Sclaudio 	printf("(via %s) Neighbor %s (%s)", log_addr(&r->true_nexthop), s,
1023929193c3Sclaudio 	    inet_ntoa(id));
10249e59dee7Sclaudio 	if (r->flags & F_PREF_PATH_ID)
1025929193c3Sclaudio 		printf(" Path-Id: %u", r->path_id);
1026929193c3Sclaudio 	printf("%c", EOL0(flag0));
1027929193c3Sclaudio 	free(s);
10286671ac0bSclaudio 
10296671ac0bSclaudio 	printf("    Origin %s, metric %u, localpref %u, weight %u, ovs %s, ",
103004d0a88fSclaudio 	    fmt_origin(r->origin, 0), r->med, r->local_pref, r->weight,
103150d35cacSclaudio 	    fmt_ovs(r->roa_validation_state, 0));
103229100734Sjob 	printf("avs %s, %s", fmt_avs(r->aspa_validation_state, 0),
103350d35cacSclaudio 	    fmt_flags(r->flags, 0));
10346671ac0bSclaudio 
10356671ac0bSclaudio 	printf("%c    Last update: %s ago%c", EOL0(flag0),
1036e67b1a58Sclaudio 	    fmt_timeframe(r->age), EOL0(flag0));
10376671ac0bSclaudio }
10386671ac0bSclaudio 
1039d30a810dSclaudio static void
104046d5331aSclaudio show_rib(struct ctl_show_rib *r, struct ibuf *aspath, struct parse_result *res)
10416671ac0bSclaudio {
10426671ac0bSclaudio 	if (res->flags & F_CTL_DETAIL)
104346d5331aSclaudio 		show_rib_detail(r, aspath, res->flags);
10446671ac0bSclaudio 	else
104546d5331aSclaudio 		show_rib_brief(r, aspath);
10466671ac0bSclaudio }
10476671ac0bSclaudio 
1048d30a810dSclaudio static void
10496671ac0bSclaudio show_rib_mem(struct rde_memstats *stats)
10506671ac0bSclaudio {
10516671ac0bSclaudio 	size_t			pts = 0;
10526671ac0bSclaudio 	int			i;
10536671ac0bSclaudio 
10546671ac0bSclaudio 	printf("RDE memory statistics\n");
10556671ac0bSclaudio 	for (i = 0; i < AID_MAX; i++) {
10566671ac0bSclaudio 		if (stats->pt_cnt[i] == 0)
10576671ac0bSclaudio 			continue;
1058093d1e70Sclaudio 		pts += stats->pt_size[i];
10596671ac0bSclaudio 		printf("%10lld %s network entries using %s of memory\n",
10606671ac0bSclaudio 		    stats->pt_cnt[i], aid_vals[i].name,
1061093d1e70Sclaudio 		    fmt_mem(stats->pt_size[i]));
10626671ac0bSclaudio 	}
10636671ac0bSclaudio 	printf("%10lld rib entries using %s of memory\n",
10646671ac0bSclaudio 	    stats->rib_cnt, fmt_mem(stats->rib_cnt *
10656671ac0bSclaudio 	    sizeof(struct rib_entry)));
10666671ac0bSclaudio 	printf("%10lld prefix entries using %s of memory\n",
10676671ac0bSclaudio 	    stats->prefix_cnt, fmt_mem(stats->prefix_cnt *
10686671ac0bSclaudio 	    sizeof(struct prefix)));
10696671ac0bSclaudio 	printf("%10lld BGP path attribute entries using %s of memory\n",
10706671ac0bSclaudio 	    stats->path_cnt, fmt_mem(stats->path_cnt *
10716671ac0bSclaudio 	    sizeof(struct rde_aspath)));
10726671ac0bSclaudio 	printf("\t   and holding %lld references\n",
10736671ac0bSclaudio 	    stats->path_refs);
10746671ac0bSclaudio 	printf("%10lld BGP AS-PATH attribute entries using "
1075a03ec1fdSclaudio 	    "%s of memory\n", stats->aspath_cnt, fmt_mem(stats->aspath_size));
10766671ac0bSclaudio 	printf("%10lld entries for %lld BGP communities "
10776671ac0bSclaudio 	    "using %s of memory\n", stats->comm_cnt, stats->comm_nmemb,
10786671ac0bSclaudio 	    fmt_mem(stats->comm_cnt * sizeof(struct rde_community) +
10796671ac0bSclaudio 	    stats->comm_size * sizeof(struct community)));
10806671ac0bSclaudio 	printf("\t   and holding %lld references\n",
10816671ac0bSclaudio 	    stats->comm_refs);
10826671ac0bSclaudio 	printf("%10lld BGP attributes entries using %s of memory\n",
10836671ac0bSclaudio 	    stats->attr_cnt, fmt_mem(stats->attr_cnt *
10846671ac0bSclaudio 	    sizeof(struct attr)));
10856671ac0bSclaudio 	printf("\t   and holding %lld references\n",
10866671ac0bSclaudio 	    stats->attr_refs);
10876671ac0bSclaudio 	printf("%10lld BGP attributes using %s of memory\n",
10886671ac0bSclaudio 	    stats->attr_dcnt, fmt_mem(stats->attr_data));
10896671ac0bSclaudio 	printf("%10lld as-set elements in %lld tables using "
10906671ac0bSclaudio 	    "%s of memory\n", stats->aset_nmemb, stats->aset_cnt,
10916671ac0bSclaudio 	    fmt_mem(stats->aset_size));
10926671ac0bSclaudio 	printf("%10lld prefix-set elements using %s of memory\n",
10936671ac0bSclaudio 	    stats->pset_cnt, fmt_mem(stats->pset_size));
10946671ac0bSclaudio 	printf("RIB using %s of memory\n", fmt_mem(pts +
10956671ac0bSclaudio 	    stats->prefix_cnt * sizeof(struct prefix) +
10966671ac0bSclaudio 	    stats->rib_cnt * sizeof(struct rib_entry) +
10976671ac0bSclaudio 	    stats->path_cnt * sizeof(struct rde_aspath) +
10986671ac0bSclaudio 	    stats->aspath_size + stats->attr_cnt * sizeof(struct attr) +
10996671ac0bSclaudio 	    stats->attr_data));
11006671ac0bSclaudio 	printf("Sets using %s of memory\n", fmt_mem(stats->aset_size +
11016671ac0bSclaudio 	    stats->pset_size));
11026671ac0bSclaudio }
11036671ac0bSclaudio 
1104d30a810dSclaudio static void
1105413f97b7Sclaudio show_rib_set(struct ctl_show_set *set)
1106413f97b7Sclaudio {
1107413f97b7Sclaudio 	char buf[64];
1108413f97b7Sclaudio 
1109c4f772fdSclaudio 	if (set->type == ASNUM_SET || set->type == ASPA_SET)
1110413f97b7Sclaudio 		snprintf(buf, sizeof(buf), "%7s %7s %6zu",
1111413f97b7Sclaudio 		    "-", "-", set->as_cnt);
1112413f97b7Sclaudio 	else
1113413f97b7Sclaudio 		snprintf(buf, sizeof(buf), "%7zu %7zu %6s",
1114413f97b7Sclaudio 		    set->v4_cnt, set->v6_cnt, "-");
1115413f97b7Sclaudio 
1116413f97b7Sclaudio 	printf("%-6s %-34s %s %11s\n", fmt_set_type(set), set->name,
1117413f97b7Sclaudio 	    buf, fmt_monotime(set->lastchange));
1118413f97b7Sclaudio }
1119413f97b7Sclaudio 
1120413f97b7Sclaudio static void
112169d2b5abSclaudio show_rtr(struct ctl_show_rtr *rtr)
112269d2b5abSclaudio {
112369d2b5abSclaudio 	static int not_first;
112469d2b5abSclaudio 
112569d2b5abSclaudio 	if (not_first)
112669d2b5abSclaudio 		printf("\n");
112769d2b5abSclaudio 	not_first = 1;
112869d2b5abSclaudio 
112969d2b5abSclaudio 	printf("RTR neighbor is %s, port %u\n",
113069d2b5abSclaudio 	    log_addr(&rtr->remote_addr), rtr->remote_port);
11318167eafeSclaudio 	printf(" State: %s\n", rtr->state);
113269d2b5abSclaudio 	if (rtr->descr[0])
113369d2b5abSclaudio 		printf(" Description: %s\n", rtr->descr);
113469d2b5abSclaudio 	if (rtr->local_addr.aid != AID_UNSPEC)
113569d2b5abSclaudio 		printf(" Local Address: %s\n", log_addr(&rtr->local_addr));
113669d2b5abSclaudio 	if (rtr->session_id != -1)
1137282ccd24Sclaudio 		printf(" Version: %u min %u Session ID: %d Serial #: %u\n",
1138282ccd24Sclaudio 		    rtr->version, rtr->min_version, rtr->session_id,
1139282ccd24Sclaudio 		    rtr->serial);
114069d2b5abSclaudio 	printf(" Refresh: %u, Retry: %u, Expire: %u\n",
114169d2b5abSclaudio 	    rtr->refresh, rtr->retry, rtr->expire);
114269d2b5abSclaudio 
114369d2b5abSclaudio 	if (rtr->last_sent_error != NO_ERROR) {
114469d2b5abSclaudio 		printf(" Last sent error: %s\n",
114569d2b5abSclaudio 		    log_rtr_error(rtr->last_sent_error));
114669d2b5abSclaudio 		if (rtr->last_sent_msg[0])
11472d7da873Sclaudio 			printf("   with reason \"%s\"\n",
114869d2b5abSclaudio 			    log_reason(rtr->last_sent_msg));
114969d2b5abSclaudio 	}
115069d2b5abSclaudio 	if (rtr->last_recv_error != NO_ERROR) {
115169d2b5abSclaudio 		printf(" Last received error: %s\n",
115269d2b5abSclaudio 		    log_rtr_error(rtr->last_recv_error));
115369d2b5abSclaudio 		if (rtr->last_recv_msg[0])
11542d7da873Sclaudio 			printf("   with reason \"%s\"\n",
115569d2b5abSclaudio 			    log_reason(rtr->last_recv_msg));
115669d2b5abSclaudio 	}
115769d2b5abSclaudio 
115869d2b5abSclaudio 	printf("\n");
115969d2b5abSclaudio }
116069d2b5abSclaudio 
116169d2b5abSclaudio static void
11626671ac0bSclaudio show_result(u_int rescode)
11636671ac0bSclaudio {
11646671ac0bSclaudio 	if (rescode == 0)
11656671ac0bSclaudio 		printf("request processed\n");
1166c2102d68Sjsg 	else if (rescode >=
11676671ac0bSclaudio 	    sizeof(ctl_res_strerror)/sizeof(ctl_res_strerror[0]))
11686671ac0bSclaudio 		printf("unknown result error code %u\n", rescode);
11696671ac0bSclaudio 	else
11706671ac0bSclaudio 		printf("%s\n", ctl_res_strerror[rescode]);
11716671ac0bSclaudio }
1172d30a810dSclaudio 
1173d30a810dSclaudio static void
1174d30a810dSclaudio show_tail(void)
1175d30a810dSclaudio {
1176d30a810dSclaudio 	/* nothing */
1177d30a810dSclaudio }
1178d30a810dSclaudio 
1179d30a810dSclaudio const struct output show_output = {
1180d30a810dSclaudio 	.head = show_head,
1181d30a810dSclaudio 	.neighbor = show_neighbor,
1182d30a810dSclaudio 	.timer = show_timer,
1183d30a810dSclaudio 	.fib = show_fib,
1184d30a810dSclaudio 	.fib_table = show_fib_table,
11855fed6b04Sclaudio 	.flowspec = show_flowspec,
1186d30a810dSclaudio 	.nexthop = show_nexthop,
1187d30a810dSclaudio 	.interface = show_interface,
1188d30a810dSclaudio 	.communities = show_communities,
1189d30a810dSclaudio 	.attr = show_attr,
1190d30a810dSclaudio 	.rib = show_rib,
1191d30a810dSclaudio 	.rib_mem = show_rib_mem,
1192413f97b7Sclaudio 	.set = show_rib_set,
119369d2b5abSclaudio 	.rtr = show_rtr,
1194d30a810dSclaudio 	.result = show_result,
119577a10e6fSclaudio 	.tail = show_tail,
1196d30a810dSclaudio };
1197