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