diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2019-12-20 09:16:06 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2019-12-20 09:16:06 +0000 |
commit | d14e855632420b62f113ed384ede508cb18f7ade (patch) | |
tree | 88a498b6b747e8ff434140637e0479f028fcf63f /usr.sbin/bgpctl | |
parent | 434ccc58fa9284997e58459dfa92d8398384c89c (diff) |
Split out show functions into a new file called output.c
OK benno@
Diffstat (limited to 'usr.sbin/bgpctl')
-rw-r--r-- | usr.sbin/bgpctl/Makefile | 4 | ||||
-rw-r--r-- | usr.sbin/bgpctl/bgpctl.c | 536 | ||||
-rw-r--r-- | usr.sbin/bgpctl/bgpctl.h | 48 | ||||
-rw-r--r-- | usr.sbin/bgpctl/output.c | 522 |
4 files changed, 577 insertions, 533 deletions
diff --git a/usr.sbin/bgpctl/Makefile b/usr.sbin/bgpctl/Makefile index 272a56d8f82..36167ef73b1 100644 --- a/usr.sbin/bgpctl/Makefile +++ b/usr.sbin/bgpctl/Makefile @@ -1,9 +1,9 @@ -# $OpenBSD: Makefile,v 1.15 2019/06/25 07:44:20 claudio Exp $ +# $OpenBSD: Makefile,v 1.16 2019/12/20 09:16:05 claudio Exp $ .PATH: ${.CURDIR}/../bgpd PROG= bgpctl -SRCS= bgpctl.c parser.c mrtparser.c util.c +SRCS= bgpctl.c output.c parser.c mrtparser.c util.c CFLAGS+= -Wall CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes CFLAGS+= -Wmissing-declarations diff --git a/usr.sbin/bgpctl/bgpctl.c b/usr.sbin/bgpctl/bgpctl.c index 1d1dfacb5d5..96527b41658 100644 --- a/usr.sbin/bgpctl/bgpctl.c +++ b/usr.sbin/bgpctl/bgpctl.c @@ -1,7 +1,8 @@ -/* $OpenBSD: bgpctl.c,v 1.253 2019/12/20 07:18:51 claudio Exp $ */ +/* $OpenBSD: bgpctl.c,v 1.254 2019/12/20 09:16:05 claudio Exp $ */ /* * Copyright (c) 2003 Henning Brauer <henning@openbsd.org> + * Copyright (c) 2004-2019 Claudio Jeker <claudio@openbsd.org> * Copyright (c) 2016 Job Snijders <job@instituut.net> * Copyright (c) 2016 Peter Hessler <phessler@openbsd.org> * @@ -38,49 +39,20 @@ #include "bgpd.h" #include "session.h" #include "rde.h" + +#include "bgpctl.h" #include "parser.h" #include "mrtparser.h" -enum neighbor_views { - NV_DEFAULT, - NV_TIMERS -}; - -#define EOL0(flag) ((flag & F_CTL_SSV) ? ';' : '\n') - int main(int, char *[]); int show(struct imsg *, struct parse_result *); -char *fmt_peer(const char *, const struct bgpd_addr *, int); -void show_summary(struct peer *); -void show_neighbor_full(struct peer *, struct parse_result *); -void show_neighbor(struct peer *, struct parse_result *res); -void print_neighbor_capa_mp(struct peer *); -void print_neighbor_capa_restart(struct peer *); -void print_neighbor_msgstats(struct peer *); void print_timer(const char *, time_t); -const char *fmt_timeframe(time_t t); -void show_fib_flags(u_int16_t); -void show_fib(struct kroute_full *); -void show_fib_table(struct ktable *); -void show_nexthop(struct ctl_show_nexthop *); -void show_interface(struct ctl_show_interface *); -void print_prefix(struct bgpd_addr *, u_int8_t, u_int8_t, u_int8_t); -const char * print_origin(u_int8_t, int); -const char * print_ovs(u_int8_t, int); -void print_flags(u_int8_t, int); -void show_rib(struct ctl_show_rib *, u_char *, size_t, - struct parse_result *); -void show_rib_brief(struct ctl_show_rib *, u_char *, size_t); -void show_rib_detail(struct ctl_show_rib *, u_char *, size_t, int); void show_attr(void *, u_int16_t, int); void show_communities(u_char *, size_t, int); void show_community(u_char *, u_int16_t); void show_large_community(u_char *, u_int16_t); void show_ext_community(u_char *, u_int16_t); -void show_rib_mem(struct rde_memstats *); -void show_rib_hash(struct rde_hashstats *); void send_filterset(struct imsgbuf *, struct filter_set_head *); -const char *get_errstr(u_int8_t, u_int8_t); void show_mrt_dump_neighbors(struct mrt_rib *, struct mrt_peer *, void *); void show_mrt_dump(struct mrt_rib *, struct mrt_peer *, void *); @@ -89,10 +61,7 @@ void show_mrt_state(struct mrt_bgp_state *, void *); void show_mrt_msg(struct mrt_bgp_msg *, void *); const char *msg_type(u_int8_t); void network_bulk(struct parse_result *); -const char *print_auth_method(enum auth_method); int match_aspath(void *, u_int16_t, struct filter_as *); -void show_head(struct parse_result *); -void show_result(u_int); struct imsgbuf *ibuf; struct mrt_parser show_mrt = { show_mrt_dump, show_mrt_state, show_mrt_msg }; @@ -537,46 +506,6 @@ fmt_peer(const char *descr, const struct bgpd_addr *remote_addr, return (p); } -void -show_summary(struct peer *p) -{ - char *s; - const char *a; - size_t alen; - - s = fmt_peer(p->conf.descr, &p->conf.remote_addr, - p->conf.remote_masklen); - - a = log_as(p->conf.remote_as); - alen = strlen(a); - /* max displayed length of the peers name is 28 */ - if (alen < 28) { - if (strlen(s) > 28 - alen) - s[28 - alen] = '\0'; - } else - alen = 0; - - printf("%-*s %s %10llu %10llu %5u %-8s ", - (28 - (int)alen), s, a, - p->stats.msg_rcvd_open + p->stats.msg_rcvd_notification + - p->stats.msg_rcvd_update + p->stats.msg_rcvd_keepalive + - p->stats.msg_rcvd_rrefresh, - p->stats.msg_sent_open + p->stats.msg_sent_notification + - p->stats.msg_sent_update + p->stats.msg_sent_keepalive + - p->stats.msg_sent_rrefresh, - p->wbuf.queued, - fmt_timeframe(p->stats.last_updown)); - if (p->state == STATE_ESTABLISHED) { - printf("%6u", p->stats.prefix_cnt); - if (p->conf.max_prefix != 0) - printf("/%u", p->conf.max_prefix); - } else if (p->conf.template) - printf("Template"); - else - printf("%s", statenames[p->state]); - printf("\n"); -} - const char * print_auth_method(enum auth_method method) { @@ -598,162 +527,6 @@ print_auth_method(enum auth_method method) } void -show_neighbor_full(struct peer *p, struct parse_result *res) -{ - struct in_addr ina; - char *s; - int hascapamp = 0; - u_int8_t i; - - if ((p->conf.remote_addr.aid == AID_INET && - p->conf.remote_masklen != 32) || - (p->conf.remote_addr.aid == AID_INET6 && - p->conf.remote_masklen != 128)) { - if (asprintf(&s, "%s/%u", - log_addr(&p->conf.remote_addr), - p->conf.remote_masklen) == -1) - err(1, NULL); - } else if ((s = strdup(log_addr(&p->conf.remote_addr))) == NULL) - err(1, "strdup"); - - ina.s_addr = p->remote_bgpid; - printf("BGP neighbor is %s, ", s); - free(s); - if (p->conf.remote_as == 0 && p->conf.template) - printf("remote AS: accept any"); - else - printf("remote AS %s", log_as(p->conf.remote_as)); - if (p->conf.template) - printf(", Template"); - if (p->template) - printf(", Cloned"); - if (p->conf.passive) - printf(", Passive"); - if (p->conf.ebgp && p->conf.distance > 1) - printf(", Multihop (%u)", (int)p->conf.distance); - printf("\n"); - if (p->conf.descr[0]) - printf(" Description: %s\n", p->conf.descr); - if (p->conf.max_prefix) { - printf(" Max-prefix: %u", p->conf.max_prefix); - if (p->conf.max_prefix_restart) - printf(" (restart %u)", - p->conf.max_prefix_restart); - printf("\n"); - } - printf(" BGP version 4, remote router-id %s", - inet_ntoa(ina)); - printf("%s\n", print_auth_method(p->auth.method)); - printf(" BGP state = %s", statenames[p->state]); - if (p->conf.down) { - printf(", marked down"); - if (*(p->conf.shutcomm)) { - printf(" with shutdown reason \"%s\"", - log_shutcomm(p->conf.shutcomm)); - } - } - if (p->stats.last_updown != 0) - printf(", %s for %s", - p->state == STATE_ESTABLISHED ? "up" : "down", - fmt_timeframe(p->stats.last_updown)); - printf("\n"); - printf(" Last read %s, holdtime %us, keepalive interval %us\n", - fmt_timeframe(p->stats.last_read), - p->holdtime, p->holdtime/3); - for (i = 0; i < AID_MAX; i++) - if (p->capa.peer.mp[i]) - hascapamp = 1; - if (hascapamp || p->capa.peer.refresh || - p->capa.peer.grestart.restart || p->capa.peer.as4byte) { - printf(" Neighbor capabilities:\n"); - if (hascapamp) { - printf(" Multiprotocol extensions: "); - print_neighbor_capa_mp(p); - printf("\n"); - } - if (p->capa.peer.refresh) - printf(" Route Refresh\n"); - if (p->capa.peer.grestart.restart) { - printf(" Graceful Restart"); - print_neighbor_capa_restart(p); - printf("\n"); - } - if (p->capa.peer.as4byte) - printf(" 4-byte AS numbers\n"); - } - printf("\n"); - - if (res->action == SHOW_NEIGHBOR_TIMERS) - return; - - print_neighbor_msgstats(p); - printf("\n"); - if (*(p->stats.last_shutcomm)) { - printf(" Last received shutdown reason: \"%s\"\n", - log_shutcomm(p->stats.last_shutcomm)); - } - if (p->state == STATE_IDLE) { - static const char *errstr; - - errstr = get_errstr(p->stats.last_sent_errcode, - p->stats.last_sent_suberr); - if (errstr) - printf(" Last error: %s\n\n", errstr); - } else { - printf(" Local host: %20s, Local port: %5u\n", - log_addr(&p->local), p->local_port); - - printf(" Remote host: %20s, Remote port: %5u\n", - log_addr(&p->remote), p->remote_port); - printf("\n"); - } -} - -void -show_neighbor(struct peer *p, struct parse_result *res) -{ - char *s; - - switch (res->action) { - case SHOW: - case SHOW_SUMMARY: - show_summary(p); - break; - case SHOW_SUMMARY_TERSE: - s = fmt_peer(p->conf.descr, &p->conf.remote_addr, - p->conf.remote_masklen); - printf("%s %s %s\n", s, log_as(p->conf.remote_as), - p->conf.template ? "Template" : statenames[p->state]); - free(s); - break; - case SHOW_NEIGHBOR: - case SHOW_NEIGHBOR_TIMERS: - show_neighbor_full(p, res); - break; - case SHOW_NEIGHBOR_TERSE: - s = fmt_peer(NULL, &p->conf.remote_addr, - p->conf.remote_masklen); - printf("%llu %llu %llu %llu %llu %llu %llu %llu %llu " - "%llu %u %u %llu %llu %llu %llu %s %s \"%s\"\n", - p->stats.msg_sent_open, p->stats.msg_rcvd_open, - p->stats.msg_sent_notification, - p->stats.msg_rcvd_notification, - p->stats.msg_sent_update, p->stats.msg_rcvd_update, - p->stats.msg_sent_keepalive, p->stats.msg_rcvd_keepalive, - p->stats.msg_sent_rrefresh, p->stats.msg_rcvd_rrefresh, - p->stats.prefix_cnt, p->conf.max_prefix, - p->stats.prefix_sent_update, p->stats.prefix_rcvd_update, - p->stats.prefix_sent_withdraw, - p->stats.prefix_rcvd_withdraw, s, - log_as(p->conf.remote_as), p->conf.descr); - free(s); - break; - default: - break; - } -} - -void print_neighbor_capa_mp(struct peer *p) { int comma; @@ -919,99 +692,6 @@ show_fib_flags(u_int16_t flags) } void -show_fib(struct kroute_full *kf) -{ - char *p; - - show_fib_flags(kf->flags); - - if (asprintf(&p, "%s/%u", log_addr(&kf->prefix), kf->prefixlen) == -1) - err(1, NULL); - printf("%4i %-20s ", kf->priority, p); - free(p); - - if (kf->flags & F_CONNECTED) - printf("link#%u", kf->ifindex); - else - printf("%s", log_addr(&kf->nexthop)); - printf("\n"); -} - -void -show_fib_table(struct ktable *kt) -{ - printf("%5i %-20s %-8s%s\n", kt->rtableid, kt->descr, - kt->fib_sync ? "coupled" : "decoupled", - kt->fib_sync != kt->fib_conf ? "*" : ""); -} - -void -show_nexthop(struct ctl_show_nexthop *nh) -{ - struct kroute *k; - struct kroute6 *k6; - char *s; - - printf("%s %-15s ", nh->valid ? "*" : " ", log_addr(&nh->addr)); - if (!nh->krvalid) { - printf("\n"); - return; - } - switch (nh->addr.aid) { - case AID_INET: - k = &nh->kr.kr4; - if (asprintf(&s, "%s/%u", inet_ntoa(k->prefix), - k->prefixlen) == -1) - err(1, NULL); - printf("%-20s", s); - free(s); - printf("%3i %-15s ", k->priority, - k->flags & F_CONNECTED ? "connected" : - inet_ntoa(k->nexthop)); - break; - case AID_INET6: - k6 = &nh->kr.kr6; - if (asprintf(&s, "%s/%u", log_in6addr(&k6->prefix), - k6->prefixlen) == -1) - err(1, NULL); - printf("%-20s", s); - free(s); - printf("%3i %-15s ", k6->priority, - k6->flags & F_CONNECTED ? "connected" : - log_in6addr(&k6->nexthop)); - break; - default: - printf("unknown address family\n"); - return; - } - if (nh->iface.ifname[0]) { - printf("%s (%s, %s)", nh->iface.ifname, - nh->iface.is_up ? "UP" : "DOWN", - nh->iface.baudrate ? - get_baudrate(nh->iface.baudrate, "bps") : - nh->iface.linkstate); - } - printf("\n"); -} - -void -show_interface(struct ctl_show_interface *iface) -{ - printf("%-15s", iface->ifname); - printf("%-9u", iface->rdomain); - printf("%-9s", iface->nh_reachable ? "ok" : "invalid"); - printf("%-7s", iface->is_up ? "UP" : ""); - - if (iface->media[0]) - printf("%s, ", iface->media); - printf("%s", iface->linkstate); - - if (iface->baudrate > 0) - printf(", %s", get_baudrate(iface->baudrate, "Bit/s")); - printf("\n"); -} - -void print_prefix(struct bgpd_addr *prefix, u_int8_t prefixlen, u_int8_t flags, u_int8_t ovs) { @@ -1090,74 +770,6 @@ print_ovs(u_int8_t validation_state, int sum) } } -void -show_rib(struct ctl_show_rib *r, u_char *asdata, size_t aslen, - struct parse_result *res) -{ - if (res->flags & F_CTL_DETAIL) - show_rib_detail(r, asdata, aslen, res->flags); - else - show_rib_brief(r, asdata, aslen); -} - -void -show_rib_brief(struct ctl_show_rib *r, u_char *asdata, size_t aslen) -{ - char *aspath; - - print_prefix(&r->prefix, r->prefixlen, r->flags, r->validation_state); - printf(" %-15s ", log_addr(&r->exit_nexthop)); - printf(" %5u %5u ", r->local_pref, r->med); - - if (aspath_asprint(&aspath, asdata, aslen) == -1) - err(1, NULL); - if (strlen(aspath) > 0) - printf("%s ", aspath); - free(aspath); - - printf("%s\n", print_origin(r->origin, 1)); -} - -void -show_rib_detail(struct ctl_show_rib *r, u_char *asdata, size_t aslen, - int flag0) -{ - struct in_addr id; - char *aspath, *s; - time_t now; - - printf("\nBGP routing table entry for %s/%u%c", - log_addr(&r->prefix), r->prefixlen, - EOL0(flag0)); - - if (aspath_asprint(&aspath, asdata, aslen) == -1) - err(1, NULL); - if (strlen(aspath) > 0) - printf(" %s%c", aspath, EOL0(flag0)); - free(aspath); - - s = fmt_peer(r->descr, &r->remote_addr, -1); - printf(" Nexthop %s ", log_addr(&r->exit_nexthop)); - printf("(via %s) Neighbor %s (", log_addr(&r->true_nexthop), s); - free(s); - id.s_addr = htonl(r->remote_id); - printf("%s)%c", inet_ntoa(id), EOL0(flag0)); - - printf(" Origin %s, metric %u, localpref %u, weight %u, ovs %s, ", - print_origin(r->origin, 0), r->med, r->local_pref, r->weight, - print_ovs(r->validation_state, 0)); - print_flags(r->flags, 0); - - now = time(NULL); - if (now > r->lastchange) - now -= r->lastchange; - else - now = 0; - - printf("%c Last update: %s ago%c", EOL0(flag0), - fmt_timeframe_core(now), EOL0(flag0)); -} - static const char * print_attr(u_int8_t type, u_int8_t flags) { @@ -1672,7 +1284,7 @@ show_ext_community(u_char *data, u_int16_t len) } } -static char * +const char * fmt_mem(long long num) { static char buf[16]; @@ -1684,79 +1296,6 @@ fmt_mem(long long num) } void -show_rib_mem(struct rde_memstats *stats) -{ - static size_t pt_sizes[AID_MAX] = AID_PTSIZE; - size_t pts = 0; - int i; - - printf("RDE memory statistics\n"); - for (i = 0; i < AID_MAX; i++) { - if (stats->pt_cnt[i] == 0) - continue; - pts += stats->pt_cnt[i] * pt_sizes[i]; - printf("%10lld %s network entries using %s of memory\n", - stats->pt_cnt[i], aid_vals[i].name, - fmt_mem(stats->pt_cnt[i] * pt_sizes[i])); - } - printf("%10lld rib entries using %s of memory\n", - stats->rib_cnt, fmt_mem(stats->rib_cnt * - sizeof(struct rib_entry))); - printf("%10lld prefix entries using %s of memory\n", - stats->prefix_cnt, fmt_mem(stats->prefix_cnt * - sizeof(struct prefix))); - printf("%10lld BGP path attribute entries using %s of memory\n", - stats->path_cnt, fmt_mem(stats->path_cnt * - sizeof(struct rde_aspath))); - printf("\t and holding %lld references\n", - stats->path_refs); - printf("%10lld BGP AS-PATH attribute entries using " - "%s of memory\n\t and holding %lld references\n", - stats->aspath_cnt, fmt_mem(stats->aspath_size), - stats->aspath_refs); - printf("%10lld entries for %lld BGP communities " - "using %s of memory\n", stats->comm_cnt, stats->comm_nmemb, - fmt_mem(stats->comm_cnt * sizeof(struct rde_community) + - stats->comm_size * sizeof(struct community))); - printf("\t and holding %lld references\n", - stats->comm_refs); - printf("%10lld BGP attributes entries using %s of memory\n", - stats->attr_cnt, fmt_mem(stats->attr_cnt * - sizeof(struct attr))); - printf("\t and holding %lld references\n", - stats->attr_refs); - printf("%10lld BGP attributes using %s of memory\n", - stats->attr_dcnt, fmt_mem(stats->attr_data)); - printf("%10lld as-set elements in %lld tables using " - "%s of memory\n", stats->aset_nmemb, stats->aset_cnt, - fmt_mem(stats->aset_size)); - printf("%10lld prefix-set elements using %s of memory\n", - stats->pset_cnt, fmt_mem(stats->pset_size)); - printf("RIB using %s of memory\n", fmt_mem(pts + - stats->prefix_cnt * sizeof(struct prefix) + - stats->rib_cnt * sizeof(struct rib_entry) + - stats->path_cnt * sizeof(struct rde_aspath) + - stats->aspath_size + stats->attr_cnt * sizeof(struct attr) + - stats->attr_data)); - printf("Sets using %s of memory\n", fmt_mem(stats->aset_size + - stats->pset_size)); - printf("\nRDE hash statistics\n"); -} - -void -show_rib_hash(struct rde_hashstats *hash) -{ - double avg, dev; - - printf("\t%s: size %lld, %lld entries\n", hash->name, hash->num, - hash->sum); - avg = (double)hash->sum / (double)hash->num; - dev = sqrt(fmax(0, hash->sumq / hash->num - avg * avg)); - printf("\t min %lld max %lld avg/std-dev = %.3f/%.3f\n", - hash->min, hash->max, avg, dev); -} - -void send_filterset(struct imsgbuf *i, struct filter_set_head *set) { struct filter_set *s; @@ -2580,68 +2119,3 @@ match_aspath(void *data, u_int16_t len, struct filter_as *f) } return (0); } - -void -show_head(struct parse_result *res) -{ - switch (res->action) { - case SHOW: - case SHOW_SUMMARY: - printf("%-20s %8s %10s %10s %5s %-8s %s\n", "Neighbor", "AS", - "MsgRcvd", "MsgSent", "OutQ", "Up/Down", "State/PrfRcvd"); - break; - case SHOW_FIB: - printf("flags: * = valid, B = BGP, C = Connected, " - "S = Static, D = Dynamic\n"); - printf(" " - "N = BGP Nexthop reachable via this route\n"); - printf(" r = reject route, b = blackhole route\n\n"); - printf("flags prio destination gateway\n"); - break; - case SHOW_FIB_TABLES: - printf("%-5s %-20s %-8s\n", "Table", "Description", "State"); - break; - case SHOW_NEXTHOP: - printf("Flags: * = nexthop valid\n"); - printf("\n %-15s %-19s%-4s %-15s %-20s\n", "Nexthop", "Route", - "Prio", "Gateway", "Iface"); - break; - case SHOW_INTERFACE: - printf("%-15s%-9s%-9s%-7s%s\n", "Interface", "rdomain", - "Nexthop", "Flags", "Link state"); - break; - case SHOW_RIB: - if (res->flags & F_CTL_DETAIL) - break; - printf("flags: " - "* = Valid, > = Selected, I = via IBGP, A = Announced,\n" - " S = Stale, E = Error\n"); - printf("origin validation state: " - "N = not-found, V = valid, ! = invalid\n"); - printf("origin: i = IGP, e = EGP, ? = Incomplete\n\n"); - printf("%-5s %3s %-20s %-15s %5s %5s %s\n", - "flags", "ovs", "destination", "gateway", "lpref", "med", - "aspath origin"); - break; - case NETWORK_SHOW: - printf("flags: S = Static\n"); - printf("flags prio destination gateway\n"); - break; - default: - break; - } -} - -void -show_result(u_int rescode) -{ - if (rescode == 0) - printf("request processed\n"); - else { - if (rescode > - sizeof(ctl_res_strerror)/sizeof(ctl_res_strerror[0])) - printf("unknown result error code %u\n", rescode); - else - printf("%s\n", ctl_res_strerror[rescode]); - } -} diff --git a/usr.sbin/bgpctl/bgpctl.h b/usr.sbin/bgpctl/bgpctl.h new file mode 100644 index 00000000000..59ed69b2b2e --- /dev/null +++ b/usr.sbin/bgpctl/bgpctl.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +struct parse_result; +void show_head(struct parse_result *); +void show_neighbor(struct peer *, struct parse_result *); +void show_fib(struct kroute_full *); +void show_fib_table(struct ktable *); +void show_nexthop(struct ctl_show_nexthop *); +void show_interface(struct ctl_show_interface *); +void show_rib(struct ctl_show_rib *, u_char *, size_t, + struct parse_result *); +void show_rib_hash(struct rde_hashstats *); +void show_rib_mem(struct rde_memstats *); +void show_result(u_int); + + +#define EOL0(flag) ((flag & F_CTL_SSV) ? ';' : '\n') + +void print_prefix(struct bgpd_addr *, u_int8_t, u_int8_t, u_int8_t); +void print_neighbor_capa_mp(struct peer *); +void print_neighbor_capa_restart(struct peer *); +void print_neighbor_msgstats(struct peer *); +void print_flags(u_int8_t, int); +void show_fib_flags(u_int16_t); + +const char *print_ovs(u_int8_t, int); +const char *print_origin(u_int8_t, int); +const char *print_auth_method(enum auth_method); +const char *fmt_mem(long long); + +const char *fmt_timeframe(time_t); +char *fmt_peer(const char *, const struct bgpd_addr *, int); +const char *get_errstr(u_int8_t, u_int8_t); + diff --git a/usr.sbin/bgpctl/output.c b/usr.sbin/bgpctl/output.c new file mode 100644 index 00000000000..5033bb033fd --- /dev/null +++ b/usr.sbin/bgpctl/output.c @@ -0,0 +1,522 @@ +/* $OpenBSD: output.c,v 1.1 2019/12/20 09:16:05 claudio Exp $ */ + +/* + * Copyright (c) 2003 Henning Brauer <henning@openbsd.org> + * Copyright (c) 2004-2019 Claudio Jeker <claudio@openbsd.org> + * Copyright (c) 2016 Job Snijders <job@instituut.net> + * Copyright (c) 2016 Peter Hessler <phessler@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <err.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "bgpd.h" +#include "session.h" +#include "rde.h" + +#include "bgpctl.h" +#include "parser.h" + +void +show_head(struct parse_result *res) +{ + switch (res->action) { + case SHOW: + case SHOW_SUMMARY: + printf("%-20s %8s %10s %10s %5s %-8s %s\n", "Neighbor", "AS", + "MsgRcvd", "MsgSent", "OutQ", "Up/Down", "State/PrfRcvd"); + break; + case SHOW_FIB: + printf("flags: * = valid, B = BGP, C = Connected, " + "S = Static, D = Dynamic\n"); + printf(" " + "N = BGP Nexthop reachable via this route\n"); + printf(" r = reject route, b = blackhole route\n\n"); + printf("flags prio destination gateway\n"); + break; + case SHOW_FIB_TABLES: + printf("%-5s %-20s %-8s\n", "Table", "Description", "State"); + break; + case SHOW_NEXTHOP: + printf("Flags: * = nexthop valid\n"); + printf("\n %-15s %-19s%-4s %-15s %-20s\n", "Nexthop", "Route", + "Prio", "Gateway", "Iface"); + break; + case SHOW_INTERFACE: + printf("%-15s%-9s%-9s%-7s%s\n", "Interface", "rdomain", + "Nexthop", "Flags", "Link state"); + break; + case SHOW_RIB: + if (res->flags & F_CTL_DETAIL) + break; + printf("flags: " + "* = Valid, > = Selected, I = via IBGP, A = Announced,\n" + " S = Stale, E = Error\n"); + printf("origin validation state: " + "N = not-found, V = valid, ! = invalid\n"); + printf("origin: i = IGP, e = EGP, ? = Incomplete\n\n"); + printf("%-5s %3s %-20s %-15s %5s %5s %s\n", + "flags", "ovs", "destination", "gateway", "lpref", "med", + "aspath origin"); + break; + case NETWORK_SHOW: + printf("flags: S = Static\n"); + printf("flags prio destination gateway\n"); + break; + default: + break; + } +} + +static void +show_summary(struct peer *p) +{ + char *s; + const char *a; + size_t alen; + + s = fmt_peer(p->conf.descr, &p->conf.remote_addr, + p->conf.remote_masklen); + + a = log_as(p->conf.remote_as); + alen = strlen(a); + /* max displayed length of the peers name is 28 */ + if (alen < 28) { + if (strlen(s) > 28 - alen) + s[28 - alen] = '\0'; + } else + alen = 0; + + printf("%-*s %s %10llu %10llu %5u %-8s ", + (28 - (int)alen), s, a, + p->stats.msg_rcvd_open + p->stats.msg_rcvd_notification + + p->stats.msg_rcvd_update + p->stats.msg_rcvd_keepalive + + p->stats.msg_rcvd_rrefresh, + p->stats.msg_sent_open + p->stats.msg_sent_notification + + p->stats.msg_sent_update + p->stats.msg_sent_keepalive + + p->stats.msg_sent_rrefresh, + p->wbuf.queued, + fmt_timeframe(p->stats.last_updown)); + if (p->state == STATE_ESTABLISHED) { + printf("%6u", p->stats.prefix_cnt); + if (p->conf.max_prefix != 0) + printf("/%u", p->conf.max_prefix); + } else if (p->conf.template) + printf("Template"); + else + printf("%s", statenames[p->state]); + printf("\n"); + free(s); +} + +static void +show_neighbor_full(struct peer *p, struct parse_result *res) +{ + struct in_addr ina; + char *s; + int hascapamp = 0; + u_int8_t i; + + if ((p->conf.remote_addr.aid == AID_INET && + p->conf.remote_masklen != 32) || + (p->conf.remote_addr.aid == AID_INET6 && + p->conf.remote_masklen != 128)) { + if (asprintf(&s, "%s/%u", + log_addr(&p->conf.remote_addr), + p->conf.remote_masklen) == -1) + err(1, NULL); + } else if ((s = strdup(log_addr(&p->conf.remote_addr))) == NULL) + err(1, "strdup"); + + ina.s_addr = p->remote_bgpid; + printf("BGP neighbor is %s, ", s); + free(s); + if (p->conf.remote_as == 0 && p->conf.template) + printf("remote AS: accept any"); + else + printf("remote AS %s", log_as(p->conf.remote_as)); + if (p->conf.template) + printf(", Template"); + if (p->template) + printf(", Cloned"); + if (p->conf.passive) + printf(", Passive"); + if (p->conf.ebgp && p->conf.distance > 1) + printf(", Multihop (%u)", (int)p->conf.distance); + printf("\n"); + if (p->conf.descr[0]) + printf(" Description: %s\n", p->conf.descr); + if (p->conf.max_prefix) { + printf(" Max-prefix: %u", p->conf.max_prefix); + if (p->conf.max_prefix_restart) + printf(" (restart %u)", + p->conf.max_prefix_restart); + printf("\n"); + } + printf(" BGP version 4, remote router-id %s", + inet_ntoa(ina)); + printf("%s\n", print_auth_method(p->auth.method)); + printf(" BGP state = %s", statenames[p->state]); + if (p->conf.down) { + printf(", marked down"); + if (*(p->conf.shutcomm)) { + printf(" with shutdown reason \"%s\"", + log_shutcomm(p->conf.shutcomm)); + } + } + if (p->stats.last_updown != 0) + printf(", %s for %s", + p->state == STATE_ESTABLISHED ? "up" : "down", + fmt_timeframe(p->stats.last_updown)); + printf("\n"); + printf(" Last read %s, holdtime %us, keepalive interval %us\n", + fmt_timeframe(p->stats.last_read), + p->holdtime, p->holdtime/3); + for (i = 0; i < AID_MAX; i++) + if (p->capa.peer.mp[i]) + hascapamp = 1; + if (hascapamp || p->capa.peer.refresh || + p->capa.peer.grestart.restart || p->capa.peer.as4byte) { + printf(" Neighbor capabilities:\n"); + if (hascapamp) { + printf(" Multiprotocol extensions: "); + print_neighbor_capa_mp(p); + printf("\n"); + } + if (p->capa.peer.refresh) + printf(" Route Refresh\n"); + if (p->capa.peer.grestart.restart) { + printf(" Graceful Restart"); + print_neighbor_capa_restart(p); + printf("\n"); + } + if (p->capa.peer.as4byte) + printf(" 4-byte AS numbers\n"); + } + printf("\n"); + + if (res->action == SHOW_NEIGHBOR_TIMERS) + return; + + print_neighbor_msgstats(p); + printf("\n"); + if (*(p->stats.last_shutcomm)) { + printf(" Last received shutdown reason: \"%s\"\n", + log_shutcomm(p->stats.last_shutcomm)); + } + if (p->state == STATE_IDLE) { + static const char *errstr; + + errstr = get_errstr(p->stats.last_sent_errcode, + p->stats.last_sent_suberr); + if (errstr) + printf(" Last error: %s\n\n", errstr); + } else { + printf(" Local host: %20s, Local port: %5u\n", + log_addr(&p->local), p->local_port); + + printf(" Remote host: %20s, Remote port: %5u\n", + log_addr(&p->remote), p->remote_port); + printf("\n"); + } +} + +void +show_neighbor(struct peer *p, struct parse_result *res) +{ + char *s; + + switch (res->action) { + case SHOW: + case SHOW_SUMMARY: + show_summary(p); + break; + case SHOW_SUMMARY_TERSE: + s = fmt_peer(p->conf.descr, &p->conf.remote_addr, + p->conf.remote_masklen); + printf("%s %s %s\n", s, log_as(p->conf.remote_as), + p->conf.template ? "Template" : statenames[p->state]); + free(s); + break; + case SHOW_NEIGHBOR: + case SHOW_NEIGHBOR_TIMERS: + show_neighbor_full(p, res); + break; + case SHOW_NEIGHBOR_TERSE: + s = fmt_peer(NULL, &p->conf.remote_addr, + p->conf.remote_masklen); + printf("%llu %llu %llu %llu %llu %llu %llu %llu %llu " + "%llu %u %u %llu %llu %llu %llu %s %s \"%s\"\n", + p->stats.msg_sent_open, p->stats.msg_rcvd_open, + p->stats.msg_sent_notification, + p->stats.msg_rcvd_notification, + p->stats.msg_sent_update, p->stats.msg_rcvd_update, + p->stats.msg_sent_keepalive, p->stats.msg_rcvd_keepalive, + p->stats.msg_sent_rrefresh, p->stats.msg_rcvd_rrefresh, + p->stats.prefix_cnt, p->conf.max_prefix, + p->stats.prefix_sent_update, p->stats.prefix_rcvd_update, + p->stats.prefix_sent_withdraw, + p->stats.prefix_rcvd_withdraw, s, + log_as(p->conf.remote_as), p->conf.descr); + free(s); + break; + default: + break; + } +} + +void +show_fib(struct kroute_full *kf) +{ + char *p; + + show_fib_flags(kf->flags); + + if (asprintf(&p, "%s/%u", log_addr(&kf->prefix), kf->prefixlen) == -1) + err(1, NULL); + printf("%4i %-20s ", kf->priority, p); + free(p); + + if (kf->flags & F_CONNECTED) + printf("link#%u", kf->ifindex); + else + printf("%s", log_addr(&kf->nexthop)); + printf("\n"); +} + +void +show_fib_table(struct ktable *kt) +{ + printf("%5i %-20s %-8s%s\n", kt->rtableid, kt->descr, + kt->fib_sync ? "coupled" : "decoupled", + kt->fib_sync != kt->fib_conf ? "*" : ""); +} + +void +show_nexthop(struct ctl_show_nexthop *nh) +{ + struct kroute *k; + struct kroute6 *k6; + char *s; + + printf("%s %-15s ", nh->valid ? "*" : " ", log_addr(&nh->addr)); + if (!nh->krvalid) { + printf("\n"); + return; + } + switch (nh->addr.aid) { + case AID_INET: + k = &nh->kr.kr4; + if (asprintf(&s, "%s/%u", inet_ntoa(k->prefix), + k->prefixlen) == -1) + err(1, NULL); + printf("%-20s", s); + free(s); + printf("%3i %-15s ", k->priority, + k->flags & F_CONNECTED ? "connected" : + inet_ntoa(k->nexthop)); + break; + case AID_INET6: + k6 = &nh->kr.kr6; + if (asprintf(&s, "%s/%u", log_in6addr(&k6->prefix), + k6->prefixlen) == -1) + err(1, NULL); + printf("%-20s", s); + free(s); + printf("%3i %-15s ", k6->priority, + k6->flags & F_CONNECTED ? "connected" : + log_in6addr(&k6->nexthop)); + break; + default: + printf("unknown address family\n"); + return; + } + if (nh->iface.ifname[0]) { + printf("%s (%s, %s)", nh->iface.ifname, + nh->iface.is_up ? "UP" : "DOWN", + nh->iface.baudrate ? + get_baudrate(nh->iface.baudrate, "bps") : + nh->iface.linkstate); + } + printf("\n"); +} + +void +show_interface(struct ctl_show_interface *iface) +{ + printf("%-15s", iface->ifname); + printf("%-9u", iface->rdomain); + printf("%-9s", iface->nh_reachable ? "ok" : "invalid"); + printf("%-7s", iface->is_up ? "UP" : ""); + + if (iface->media[0]) + printf("%s, ", iface->media); + printf("%s", iface->linkstate); + + if (iface->baudrate > 0) + printf(", %s", get_baudrate(iface->baudrate, "Bit/s")); + printf("\n"); +} + +static void +show_rib_brief(struct ctl_show_rib *r, u_char *asdata, size_t aslen) +{ + char *aspath; + + print_prefix(&r->prefix, r->prefixlen, r->flags, r->validation_state); + printf(" %-15s ", log_addr(&r->exit_nexthop)); + printf(" %5u %5u ", r->local_pref, r->med); + + if (aspath_asprint(&aspath, asdata, aslen) == -1) + err(1, NULL); + if (strlen(aspath) > 0) + printf("%s ", aspath); + free(aspath); + + printf("%s\n", print_origin(r->origin, 1)); +} + +static void +show_rib_detail(struct ctl_show_rib *r, u_char *asdata, size_t aslen, + int flag0) +{ + struct in_addr id; + char *aspath, *s; + + printf("\nBGP routing table entry for %s/%u%c", + log_addr(&r->prefix), r->prefixlen, + EOL0(flag0)); + + if (aspath_asprint(&aspath, asdata, aslen) == -1) + err(1, NULL); + if (strlen(aspath) > 0) + printf(" %s%c", aspath, EOL0(flag0)); + free(aspath); + + s = fmt_peer(r->descr, &r->remote_addr, -1); + printf(" Nexthop %s ", log_addr(&r->exit_nexthop)); + printf("(via %s) Neighbor %s (", log_addr(&r->true_nexthop), s); + free(s); + id.s_addr = htonl(r->remote_id); + printf("%s)%c", inet_ntoa(id), EOL0(flag0)); + + printf(" Origin %s, metric %u, localpref %u, weight %u, ovs %s, ", + print_origin(r->origin, 0), r->med, r->local_pref, r->weight, + print_ovs(r->validation_state, 0)); + print_flags(r->flags, 0); + + printf("%c Last update: %s ago%c", EOL0(flag0), + fmt_timeframe(r->lastchange), EOL0(flag0)); +} + +void +show_rib(struct ctl_show_rib *r, u_char *asdata, size_t aslen, + struct parse_result *res) +{ + if (res->flags & F_CTL_DETAIL) + show_rib_detail(r, asdata, aslen, res->flags); + else + show_rib_brief(r, asdata, aslen); +} + +void +show_rib_mem(struct rde_memstats *stats) +{ + static size_t pt_sizes[AID_MAX] = AID_PTSIZE; + size_t pts = 0; + int i; + + printf("RDE memory statistics\n"); + for (i = 0; i < AID_MAX; i++) { + if (stats->pt_cnt[i] == 0) + continue; + pts += stats->pt_cnt[i] * pt_sizes[i]; + printf("%10lld %s network entries using %s of memory\n", + stats->pt_cnt[i], aid_vals[i].name, + fmt_mem(stats->pt_cnt[i] * pt_sizes[i])); + } + printf("%10lld rib entries using %s of memory\n", + stats->rib_cnt, fmt_mem(stats->rib_cnt * + sizeof(struct rib_entry))); + printf("%10lld prefix entries using %s of memory\n", + stats->prefix_cnt, fmt_mem(stats->prefix_cnt * + sizeof(struct prefix))); + printf("%10lld BGP path attribute entries using %s of memory\n", + stats->path_cnt, fmt_mem(stats->path_cnt * + sizeof(struct rde_aspath))); + printf("\t and holding %lld references\n", + stats->path_refs); + printf("%10lld BGP AS-PATH attribute entries using " + "%s of memory\n\t and holding %lld references\n", + stats->aspath_cnt, fmt_mem(stats->aspath_size), + stats->aspath_refs); + printf("%10lld entries for %lld BGP communities " + "using %s of memory\n", stats->comm_cnt, stats->comm_nmemb, + fmt_mem(stats->comm_cnt * sizeof(struct rde_community) + + stats->comm_size * sizeof(struct community))); + printf("\t and holding %lld references\n", + stats->comm_refs); + printf("%10lld BGP attributes entries using %s of memory\n", + stats->attr_cnt, fmt_mem(stats->attr_cnt * + sizeof(struct attr))); + printf("\t and holding %lld references\n", + stats->attr_refs); + printf("%10lld BGP attributes using %s of memory\n", + stats->attr_dcnt, fmt_mem(stats->attr_data)); + printf("%10lld as-set elements in %lld tables using " + "%s of memory\n", stats->aset_nmemb, stats->aset_cnt, + fmt_mem(stats->aset_size)); + printf("%10lld prefix-set elements using %s of memory\n", + stats->pset_cnt, fmt_mem(stats->pset_size)); + printf("RIB using %s of memory\n", fmt_mem(pts + + stats->prefix_cnt * sizeof(struct prefix) + + stats->rib_cnt * sizeof(struct rib_entry) + + stats->path_cnt * sizeof(struct rde_aspath) + + stats->aspath_size + stats->attr_cnt * sizeof(struct attr) + + stats->attr_data)); + printf("Sets using %s of memory\n", fmt_mem(stats->aset_size + + stats->pset_size)); + printf("\nRDE hash statistics\n"); +} + +void +show_rib_hash(struct rde_hashstats *hash) +{ + double avg, dev; + + printf("\t%s: size %lld, %lld entries\n", hash->name, hash->num, + hash->sum); + avg = (double)hash->sum / (double)hash->num; + dev = sqrt(fmax(0, hash->sumq / hash->num - avg * avg)); + printf("\t min %lld max %lld avg/std-dev = %.3f/%.3f\n", + hash->min, hash->max, avg, dev); +} + +void +show_result(u_int rescode) +{ + if (rescode == 0) + printf("request processed\n"); + else { + if (rescode > + sizeof(ctl_res_strerror)/sizeof(ctl_res_strerror[0])) + printf("unknown result error code %u\n", rescode); + else + printf("%s\n", ctl_res_strerror[rescode]); + } +} |