summaryrefslogtreecommitdiff
path: root/net/openbgpd/files/patch-bgpctl_bgpctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/openbgpd/files/patch-bgpctl_bgpctl.c')
-rw-r--r--net/openbgpd/files/patch-bgpctl_bgpctl.c1529
1 files changed, 1529 insertions, 0 deletions
diff --git a/net/openbgpd/files/patch-bgpctl_bgpctl.c b/net/openbgpd/files/patch-bgpctl_bgpctl.c
new file mode 100644
index 000000000000..1553efc83281
--- /dev/null
+++ b/net/openbgpd/files/patch-bgpctl_bgpctl.c
@@ -0,0 +1,1529 @@
+Index: bgpctl/bgpctl.c
+===================================================================
+RCS file: /home/cvs/private/hrs/openbgpd/bgpctl/bgpctl.c,v
+retrieving revision 1.1.1.7
+retrieving revision 1.10
+diff -u -p -r1.1.1.7 -r1.10
+--- bgpctl/bgpctl.c 14 Feb 2010 20:20:14 -0000 1.1.1.7
++++ bgpctl/bgpctl.c 8 Dec 2012 20:17:55 -0000 1.10
+@@ -1,4 +1,4 @@
+-/* $OpenBSD: bgpctl.c,v 1.142 2009/06/06 06:33:15 eric Exp $ */
++/* $OpenBSD: bgpctl.c,v 1.167 2012/11/15 19:55:08 sthen Exp $ */
+
+ /*
+ * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
+@@ -16,11 +16,19 @@
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
++#if defined(__FreeBSD__) /* compat */
++#include "openbsd-compat.h"
++#endif /* defined(__FreeBSD__) */
++
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <sys/un.h>
+ #include <net/if.h>
++#if defined(__FreeBSD__) /* net/if_media.h */
++#include "if_media.h"
++#else
+ #include <net/if_media.h>
++#endif /* defined(__FreeBSD__) */
+ #include <net/if_types.h>
+
+ #include <err.h>
+@@ -29,7 +37,11 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <unistd.h>
++#if defined(__FreeBSD__) /* util.h */
++#include "util.h"
++#else
+ #include <util.h>
++#endif /* defined(__FreeBSD__) */
+
+ #include "bgpd.h"
+ #include "session.h"
+@@ -37,6 +49,11 @@
+ #include "log.h"
+ #include "parser.h"
+ #include "irrfilter.h"
++#include "mrtparser.h"
++
++#if defined(__FreeBSD__) /* FreeBSD has no LINK_STATE_IS_UP macro. */
++#define LINK_STATE_IS_UP(_s) ((_s) >= LINK_STATE_UP)
++#endif /* defined(__FreeBSD__) */
+
+ enum neighbor_views {
+ NV_DEFAULT,
+@@ -50,12 +67,14 @@ int show_summary_msg(struct imsg *, in
+ int show_summary_terse_msg(struct imsg *, int);
+ int show_neighbor_terse(struct imsg *);
+ int show_neighbor_msg(struct imsg *, enum neighbor_views);
+-void print_neighbor_capa_mp_safi(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_timer(const char *, time_t);
+ static char *fmt_timeframe(time_t t);
+ static char *fmt_timeframe_core(time_t t);
+ void show_fib_head(void);
++void show_fib_tables_head(void);
+ void show_network_head(void);
+ void show_fib_flags(u_int16_t);
+ int show_fib_msg(struct imsg *);
+@@ -65,7 +84,7 @@ void show_interface_head(void);
+ int ift2ifm(int);
+ const char * get_media_descr(int);
+ const char * get_linkstate(int, int);
+-void print_baudrate(u_int64_t);
++const char * get_baudrate(u_int64_t, char *);
+ int show_interface_msg(struct imsg *);
+ void show_rib_summary_head(void);
+ void print_prefix(struct bgpd_addr *, u_int8_t, u_int8_t);
+@@ -73,16 +92,25 @@ const char * print_origin(u_int8_t, int
+ void print_flags(u_int8_t, int);
+ int show_rib_summary_msg(struct imsg *);
+ int show_rib_detail_msg(struct imsg *, int);
++void show_rib_brief(struct ctl_show_rib *, u_char *);
++void show_rib_detail(struct ctl_show_rib *, u_char *, int);
++void show_attr(void *, u_int16_t);
+ void show_community(u_char *, u_int16_t);
+-const char *get_ext_subtype(u_int8_t);
+ void show_ext_community(u_char *, u_int16_t);
+ char *fmt_mem(int64_t);
+ int show_rib_memory_msg(struct imsg *);
+ void send_filterset(struct imsgbuf *, struct filter_set_head *);
+ static const char *get_errstr(u_int8_t, u_int8_t);
+ int show_result(struct imsg *);
++void show_mrt_dump(struct mrt_rib *, struct mrt_peer *, void *);
++void network_mrt_dump(struct mrt_rib *, struct mrt_peer *, void *);
++void show_mrt_state(struct mrt_bgp_state *, void *);
++void show_mrt_msg(struct mrt_bgp_msg *, void *);
++void mrt_to_bgpd_addr(union mrt_addr *, struct bgpd_addr *);
+
+ struct imsgbuf *ibuf;
++struct mrt_parser show_mrt = { show_mrt_dump, show_mrt_state, show_mrt_msg };
++struct mrt_parser net_mrt = { network_mrt_dump, NULL, NULL };
+
+ __dead void
+ usage(void)
+@@ -98,7 +126,7 @@ int
+ main(int argc, char *argv[])
+ {
+ struct sockaddr_un sun;
+- int fd, n, done, ch, nodescr = 0;
++ int fd, n, done, ch, nodescr = 0, verbose = 0;
+ struct imsg imsg;
+ struct network_config net;
+ struct parse_result *res;
+@@ -128,8 +156,11 @@ main(int argc, char *argv[])
+ if ((res = parse(argc, argv)) == NULL)
+ exit(1);
+
+- if (res->action == IRRFILTER)
++ if (res->action == IRRFILTER) {
++ if (!(res->flags & (F_IPV4|F_IPV6)))
++ res->flags |= (F_IPV4|F_IPV6);
+ irr_main(res->as.as, res->flags, res->irr_outdir);
++ }
+
+ memcpy(&neighbor.addr, &res->peeraddr, sizeof(neighbor.addr));
+ strlcpy(neighbor.descr, res->peerdesc, sizeof(neighbor.descr));
+@@ -154,7 +185,7 @@ main(int argc, char *argv[])
+ case NONE:
+ case IRRFILTER:
+ usage();
+- /* not reached */
++ /* NOTREACHED */
+ case SHOW:
+ case SHOW_SUMMARY:
+ imsg_compose(ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1, NULL, 0);
+@@ -164,24 +195,32 @@ main(int argc, char *argv[])
+ imsg_compose(ibuf, IMSG_CTL_SHOW_TERSE, 0, 0, -1, NULL, 0);
+ break;
+ case SHOW_FIB:
+- if (!res->addr.af) {
+- struct buf *msg;
+-
+- if ((msg = imsg_create(ibuf, IMSG_CTL_KROUTE, 0, 0,
+- sizeof(res->flags) + sizeof(res->af))) == NULL)
++ if (!res->addr.aid) {
++ struct ibuf *msg;
++ sa_family_t af;
++
++ af = aid2af(res->aid);
++ if ((msg = imsg_create(ibuf, IMSG_CTL_KROUTE,
++ res->rtableid, 0, sizeof(res->flags) +
++ sizeof(af))) == NULL)
+ errx(1, "imsg_create failure");
+ if (imsg_add(msg, &res->flags, sizeof(res->flags)) ==
+ -1 ||
+- imsg_add(msg, &res->af, sizeof(res->af)) == -1)
++ imsg_add(msg, &af, sizeof(af)) == -1)
+ errx(1, "imsg_add failure");
+ imsg_close(ibuf, msg);
+ } else
+- imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, 0, 0, -1,
+- &res->addr, sizeof(res->addr));
++ imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, res->rtableid,
++ 0, -1, &res->addr, sizeof(res->addr));
+ show_fib_head();
+ break;
++ case SHOW_FIB_TABLES:
++ imsg_compose(ibuf, IMSG_CTL_SHOW_FIB_TABLES, 0, 0, -1, NULL, 0);
++ show_fib_tables_head();
++ break;
+ case SHOW_NEXTHOP:
+- imsg_compose(ibuf, IMSG_CTL_SHOW_NEXTHOP, 0, 0, -1, NULL, 0);
++ imsg_compose(ibuf, IMSG_CTL_SHOW_NEXTHOP, res->rtableid, 0, -1,
++ NULL, 0);
+ show_nexthop_head();
+ break;
+ case SHOW_INTERFACE:
+@@ -192,7 +231,7 @@ main(int argc, char *argv[])
+ case SHOW_NEIGHBOR_TIMERS:
+ case SHOW_NEIGHBOR_TERSE:
+ neighbor.show_timers = (res->action == SHOW_NEIGHBOR_TIMERS);
+- if (res->peeraddr.af || res->peerdesc[0])
++ if (res->peeraddr.aid || res->peerdesc[0])
+ imsg_compose(ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1,
+ &neighbor, sizeof(neighbor));
+ else
+@@ -206,7 +245,7 @@ main(int argc, char *argv[])
+ memcpy(&ribreq.as, &res->as, sizeof(res->as));
+ type = IMSG_CTL_SHOW_RIB_AS;
+ }
+- if (res->addr.af) {
++ if (res->addr.aid) {
+ memcpy(&ribreq.prefix, &res->addr, sizeof(res->addr));
+ ribreq.prefixlen = res->prefixlen;
+ type = IMSG_CTL_SHOW_RIB_PREFIX;
+@@ -217,15 +256,35 @@ main(int argc, char *argv[])
+ sizeof(res->community));
+ type = IMSG_CTL_SHOW_RIB_COMMUNITY;
+ }
+- memcpy(&ribreq.neighbor, &neighbor,
+- sizeof(ribreq.neighbor));
++ memcpy(&ribreq.neighbor, &neighbor, sizeof(ribreq.neighbor));
+ strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib));
+- ribreq.af = res->af;
++ ribreq.aid = res->aid;
+ ribreq.flags = res->flags;
+ imsg_compose(ibuf, type, 0, 0, -1, &ribreq, sizeof(ribreq));
+ if (!(res->flags & F_CTL_DETAIL))
+ show_rib_summary_head();
+ break;
++ case SHOW_MRT:
++ close(fd);
++ bzero(&ribreq, sizeof(ribreq));
++ if (res->as.type != AS_NONE)
++ memcpy(&ribreq.as, &res->as, sizeof(res->as));
++ if (res->addr.aid) {
++ memcpy(&ribreq.prefix, &res->addr, sizeof(res->addr));
++ ribreq.prefixlen = res->prefixlen;
++ }
++ if (res->community.as != COMMUNITY_UNSET &&
++ res->community.type != COMMUNITY_UNSET)
++ memcpy(&ribreq.community, &res->community,
++ sizeof(res->community));
++ memcpy(&ribreq.neighbor, &neighbor, sizeof(ribreq.neighbor));
++ ribreq.aid = res->aid;
++ ribreq.flags = res->flags;
++ show_mrt.arg = &ribreq;
++ if (!(res->flags & F_CTL_DETAIL))
++ show_rib_summary_head();
++ mrt_parse(res->mrtfd, &show_mrt, 1);
++ exit(0);
+ case SHOW_RIB_MEM:
+ imsg_compose(ibuf, IMSG_CTL_SHOW_RIB_MEM, 0, 0, -1, NULL, 0);
+ break;
+@@ -237,12 +296,14 @@ main(int argc, char *argv[])
+ errx(1, "action==FIB");
+ break;
+ case FIB_COUPLE:
+- imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, 0, 0, -1, NULL, 0);
++ imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, res->rtableid, 0, -1,
++ NULL, 0);
+ printf("couple request sent.\n");
+ done = 1;
+ break;
+ case FIB_DECOUPLE:
+- imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, 0, 0, -1, NULL, 0);
++ imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, res->rtableid, 0, -1,
++ NULL, 0);
+ printf("decouple request sent.\n");
+ done = 1;
+ break;
+@@ -290,12 +351,40 @@ main(int argc, char *argv[])
+ break;
+ case NETWORK_SHOW:
+ bzero(&ribreq, sizeof(ribreq));
+- ribreq.af = res->af;
++ ribreq.aid = res->aid;
+ strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib));
+ imsg_compose(ibuf, IMSG_CTL_SHOW_NETWORK, 0, 0, -1,
+ &ribreq, sizeof(ribreq));
+ show_network_head();
+ break;
++ case NETWORK_MRT:
++ bzero(&ribreq, sizeof(ribreq));
++ if (res->as.type != AS_NONE)
++ memcpy(&ribreq.as, &res->as, sizeof(res->as));
++ if (res->addr.aid) {
++ memcpy(&ribreq.prefix, &res->addr, sizeof(res->addr));
++ ribreq.prefixlen = res->prefixlen;
++ }
++ if (res->community.as != COMMUNITY_UNSET &&
++ res->community.type != COMMUNITY_UNSET)
++ memcpy(&ribreq.community, &res->community,
++ sizeof(res->community));
++ memcpy(&ribreq.neighbor, &neighbor, sizeof(ribreq.neighbor));
++ ribreq.aid = res->aid;
++ ribreq.flags = res->flags;
++ net_mrt.arg = &ribreq;
++ mrt_parse(res->mrtfd, &net_mrt, 1);
++ done = 1;
++ break;
++ case LOG_VERBOSE:
++ verbose = 1;
++ /* FALLTHROUGH */
++ case LOG_BRIEF:
++ imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1,
++ &verbose, sizeof(verbose));
++ printf("logging request sent.\n");
++ done = 1;
++ break;
+ }
+
+ while (ibuf->w.queued)
+@@ -304,13 +393,13 @@ main(int argc, char *argv[])
+
+ while (!done) {
+ if ((n = imsg_read(ibuf)) == -1)
+- errx(1, "imsg_read error");
++ err(1, "imsg_read error");
+ if (n == 0)
+ errx(1, "pipe closed");
+
+ while (!done) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+- errx(1, "imsg_get error");
++ err(1, "imsg_get error");
+ if (n == 0)
+ break;
+
+@@ -329,6 +418,8 @@ main(int argc, char *argv[])
+ done = show_summary_terse_msg(&imsg, nodescr);
+ break;
+ case SHOW_FIB:
++ case SHOW_FIB_TABLES:
++ case NETWORK_SHOW:
+ done = show_fib_msg(&imsg);
+ break;
+ case SHOW_NEXTHOP:
+@@ -356,9 +447,6 @@ main(int argc, char *argv[])
+ case SHOW_RIB_MEM:
+ done = show_rib_memory_msg(&imsg);
+ break;
+- case NETWORK_SHOW:
+- done = show_fib_msg(&imsg);
+- break;
+ case NEIGHBOR:
+ case NEIGHBOR_UP:
+ case NEIGHBOR_DOWN:
+@@ -373,6 +461,10 @@ main(int argc, char *argv[])
+ case NETWORK_REMOVE:
+ case NETWORK_FLUSH:
+ case IRRFILTER:
++ case LOG_VERBOSE:
++ case LOG_BRIEF:
++ case SHOW_MRT:
++ case NETWORK_MRT:
+ break;
+ }
+ imsg_free(&imsg);
+@@ -398,8 +490,8 @@ fmt_peer(const char *descr, const struct
+ }
+
+ ip = log_addr(remote_addr);
+- if (masklen != -1 && ((remote_addr->af == AF_INET && masklen != 32) ||
+- (remote_addr->af == AF_INET6 && masklen != 128))) {
++ if (masklen != -1 && ((remote_addr->aid == AID_INET && masklen != 32) ||
++ (remote_addr->aid == AID_INET6 && masklen != 128))) {
+ if (asprintf(&p, "%s/%u", ip, masklen) == -1)
+ err(1, NULL);
+ } else {
+@@ -430,7 +522,7 @@ show_summary_msg(struct imsg *imsg, int
+ p->conf.remote_masklen, nodescr);
+ if (strlen(s) >= 20)
+ s[20] = 0;
+- printf("%-20s %8s %10llu %10llu %5u %-8s ",
++ printf("%-20s %8s %10" PRIu64 " %10" PRIu64 " %5u %-8s ",
+ s, log_as(p->conf.remote_as),
+ p->stats.msg_rcvd_open + p->stats.msg_rcvd_notification +
+ p->stats.msg_rcvd_update + p->stats.msg_rcvd_keepalive +
+@@ -492,8 +584,8 @@ show_neighbor_terse(struct imsg *imsg)
+ switch (imsg->hdr.type) {
+ case IMSG_CTL_SHOW_NEIGHBOR:
+ p = imsg->data;
+- printf("%llu %llu %llu %llu %llu %llu %llu "
+- "%llu %llu %llu %u %u %llu %llu %llu %llu\n",
++ printf("%" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " "
++ "%" PRIu64 " %" PRIu64 " %" PRIu64 " %u %u %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
+ p->stats.msg_sent_open, p->stats.msg_rcvd_open,
+ p->stats.msg_sent_notification,
+ p->stats.msg_rcvd_notification,
+@@ -521,13 +613,15 @@ show_neighbor_msg(struct imsg *imsg, enu
+ struct ctl_timer *t;
+ struct in_addr ina;
+ char buf[NI_MAXHOST], pbuf[NI_MAXSERV], *s;
++ int hascapamp = 0;
++ u_int8_t i;
+
+ switch (imsg->hdr.type) {
+ case IMSG_CTL_SHOW_NEIGHBOR:
+ p = imsg->data;
+- if ((p->conf.remote_addr.af == AF_INET &&
++ if ((p->conf.remote_addr.aid == AID_INET &&
+ p->conf.remote_masklen != 32) ||
+- (p->conf.remote_addr.af == AF_INET6 &&
++ (p->conf.remote_addr.aid == AID_INET6 &&
+ p->conf.remote_masklen != 128)) {
+ if (asprintf(&s, "%s/%u",
+ log_addr(&p->conf.remote_addr),
+@@ -549,9 +643,20 @@ show_neighbor_msg(struct imsg *imsg, enu
+ printf(", Template");
+ if (p->conf.cloned)
+ 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\n",
+ inet_ntoa(ina));
+ printf(" BGP state = %s", statenames[p->state]);
+@@ -563,22 +668,24 @@ show_neighbor_msg(struct imsg *imsg, enu
+ printf(" Last read %s, holdtime %us, keepalive interval %us\n",
+ fmt_timeframe(p->stats.last_read),
+ p->holdtime, p->holdtime/3);
+- if (p->capa.peer.mp_v4 || p->capa.peer.mp_v6 ||
+- p->capa.peer.refresh || p->capa.peer.restart ||
+- p->capa.peer.as4byte) {
++ 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 (p->capa.peer.mp_v4) {
+- printf(" Multiprotocol extensions: IPv4");
+- print_neighbor_capa_mp_safi(p->capa.peer.mp_v4);
+- }
+- if (p->capa.peer.mp_v6) {
+- printf(" Multiprotocol extensions: IPv6");
+- print_neighbor_capa_mp_safi(p->capa.peer.mp_v6);
++ 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.restart)
+- printf(" Graceful Restart\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");
+ }
+@@ -633,20 +740,38 @@ show_neighbor_msg(struct imsg *imsg, enu
+ }
+
+ void
+-print_neighbor_capa_mp_safi(u_int8_t safi)
++print_neighbor_capa_mp(struct peer *p)
+ {
+- switch (safi) {
+- case SAFI_UNICAST:
+- printf(" Unicast");
+- break;
+- case SAFI_MULTICAST:
+- printf(" Multicast");
+- break;
+- default:
+- printf(" unknown (%u)", safi);
+- break;
+- }
+- printf("\n");
++ int comma;
++ u_int8_t i;
++
++ for (i = 0, comma = 0; i < AID_MAX; i++)
++ if (p->capa.peer.mp[i]) {
++ printf("%s%s", comma ? ", " : "", aid2str(i));
++ comma = 1;
++ }
++}
++
++void
++print_neighbor_capa_restart(struct peer *p)
++{
++ int comma;
++ u_int8_t i;
++
++ if (p->capa.peer.grestart.timeout)
++ printf(": Timeout: %d, ", p->capa.peer.grestart.timeout);
++ for (i = 0, comma = 0; i < AID_MAX; i++)
++ if (p->capa.peer.grestart.flags[i] & CAPA_GR_PRESENT) {
++ if (!comma &&
++ p->capa.peer.grestart.flags[i] & CAPA_GR_RESTART)
++ printf("restarted, ");
++ if (comma)
++ printf(", ");
++ printf("%s", aid2str(i));
++ if (p->capa.peer.grestart.flags[i] & CAPA_GR_FORWARD)
++ printf(" (preserved)");
++ comma = 1;
++ }
+ }
+
+ void
+@@ -654,17 +779,17 @@ print_neighbor_msgstats(struct peer *p)
+ {
+ printf(" Message statistics:\n");
+ printf(" %-15s %-10s %-10s\n", "", "Sent", "Received");
+- printf(" %-15s %10llu %10llu\n", "Opens",
++ printf(" %-15s %10" PRIu64 " %10" PRIu64 "\n", "Opens",
+ p->stats.msg_sent_open, p->stats.msg_rcvd_open);
+- printf(" %-15s %10llu %10llu\n", "Notifications",
++ printf(" %-15s %10" PRIu64 " %10" PRIu64 "\n", "Notifications",
+ p->stats.msg_sent_notification, p->stats.msg_rcvd_notification);
+- printf(" %-15s %10llu %10llu\n", "Updates",
++ printf(" %-15s %10" PRIu64 " %10" PRIu64 "\n", "Updates",
+ p->stats.msg_sent_update, p->stats.msg_rcvd_update);
+- printf(" %-15s %10llu %10llu\n", "Keepalives",
++ printf(" %-15s %10" PRIu64 " %10" PRIu64 "\n", "Keepalives",
+ p->stats.msg_sent_keepalive, p->stats.msg_rcvd_keepalive);
+- printf(" %-15s %10llu %10llu\n", "Route Refresh",
++ printf(" %-15s %10" PRIu64 " %10" PRIu64 "\n", "Route Refresh",
+ p->stats.msg_sent_rrefresh, p->stats.msg_rcvd_rrefresh);
+- printf(" %-15s %10llu %10llu\n\n", "Total",
++ printf(" %-15s %10" PRIu64 " %10" PRIu64 "\n\n", "Total",
+ 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,
+@@ -673,14 +798,16 @@ print_neighbor_msgstats(struct peer *p)
+ p->stats.msg_rcvd_rrefresh);
+ printf(" Update statistics:\n");
+ printf(" %-15s %-10s %-10s\n", "", "Sent", "Received");
+- printf(" %-15s %10llu %10llu\n", "Updates",
++ printf(" %-15s %10" PRIu64 " %10" PRIu64 "\n", "Updates",
+ p->stats.prefix_sent_update, p->stats.prefix_rcvd_update);
+- printf(" %-15s %10llu %10llu\n", "Withdraws",
++ printf(" %-15s %10" PRIu64 " %10" PRIu64 "\n", "Withdraws",
+ p->stats.prefix_sent_withdraw, p->stats.prefix_rcvd_withdraw);
++ printf(" %-15s %10" PRIu64 " %10" PRIu64 "\n", "End-of-Rib",
++ p->stats.prefix_sent_eor, p->stats.prefix_rcvd_eor);
+ }
+
+ void
+-print_timer(const char *name, timer_t d)
++print_timer(const char *name, time_t d)
+ {
+ printf(" %-20s ", name);
+
+@@ -745,6 +872,12 @@ show_fib_head(void)
+ }
+
+ void
++show_fib_tables_head(void)
++{
++ printf("%-5s %-20s %-8s\n", "Table", "Description", "State");
++}
++
++void
+ show_network_head(void)
+ {
+ printf("flags: S = Static\n");
+@@ -788,56 +921,44 @@ show_fib_flags(u_int16_t flags)
+ int
+ show_fib_msg(struct imsg *imsg)
+ {
+- struct kroute *k;
+- struct kroute6 *k6;
++ struct kroute_full *kf;
++ struct ktable *kt;
+ char *p;
+
+ switch (imsg->hdr.type) {
+ case IMSG_CTL_KROUTE:
+ case IMSG_CTL_SHOW_NETWORK:
+- if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kroute))
++ if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(*kf))
+ errx(1, "wrong imsg len");
+- k = imsg->data;
++ kf = imsg->data;
+
+- show_fib_flags(k->flags);
++ show_fib_flags(kf->flags);
+
+- if (asprintf(&p, "%s/%u", inet_ntoa(k->prefix), k->prefixlen) ==
+- -1)
++ if (asprintf(&p, "%s/%u", log_addr(&kf->prefix),
++ kf->prefixlen) == -1)
+ err(1, NULL);
+- printf("%4i %-20s ", k->priority, p);
++ printf("%4i %-20s ", kf->priority, p);
+ free(p);
+
+- if (k->nexthop.s_addr)
+- printf("%s", inet_ntoa(k->nexthop));
+- else if (k->flags & F_CONNECTED)
+- printf("link#%u", k->ifindex);
++ if (kf->flags & F_CONNECTED)
++ printf("link#%u", kf->ifindex);
++ else
++ printf("%s", log_addr(&kf->nexthop));
+ printf("\n");
+
+ break;
+- case IMSG_CTL_KROUTE6:
+- case IMSG_CTL_SHOW_NETWORK6:
+- if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kroute6))
++ case IMSG_CTL_SHOW_FIB_TABLES:
++ if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(*kt))
+ errx(1, "wrong imsg len");
+- k6 = imsg->data;
+-
+- show_fib_flags(k6->flags);
++ kt = imsg->data;
+
+- if (asprintf(&p, "%s/%u", log_in6addr(&k6->prefix),
+- k6->prefixlen) == -1)
+- err(1, NULL);
+- printf("%4i %-20s ", k6->priority, p);
+- free(p);
+-
+- if (!IN6_IS_ADDR_UNSPECIFIED(&k6->nexthop))
+- printf("%s", log_in6addr(&k6->nexthop));
+- else if (k6->flags & F_CONNECTED)
+- printf("link#%u", k6->ifindex);
+- printf("\n");
++ printf("%5i %-20s %-8s%s\n", kt->rtableid, kt->descr,
++ kt->fib_sync ? "coupled" : "decoupled",
++ kt->fib_sync != kt->fib_conf ? "*" : "");
+
+ break;
+ case IMSG_CTL_END:
+ return (1);
+- break;
+ default:
+ break;
+ }
+@@ -848,35 +969,70 @@ show_fib_msg(struct imsg *imsg)
+ void
+ show_nexthop_head(void)
+ {
+- printf("%-20s %-10s\n", "Nexthop", "State");
++ printf("Flags: * = nexthop valid\n");
++ printf("\n %-15s %-19s%-4s %-15s %-20s\n", "Nexthop", "Route",
++ "Prio", "Gateway", "Iface");
+ }
+
+ int
+ show_nexthop_msg(struct imsg *imsg)
+ {
+ struct ctl_show_nexthop *p;
+- int ifms_type;
++ struct kroute *k;
++ struct kroute6 *k6;
++ char *s;
+
+ switch (imsg->hdr.type) {
+ case IMSG_CTL_SHOW_NEXTHOP:
+ p = imsg->data;
+- printf("%-20s %-10s", log_addr(&p->addr),
+- p->valid ? "valid" : "invalid");
++ printf("%s %-15s ", p->valid ? "*" : " ", log_addr(&p->addr));
++ if (!p->krvalid) {
++ printf("\n");
++ return (0);
++ }
++ switch (p->addr.aid) {
++ case AID_INET:
++ k = &p->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 = &p->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 (0);
++ }
+ if (p->kif.ifname[0]) {
+- printf("%-8s", p->kif.ifname);
+- if (p->kif.flags & IFF_UP) {
+- printf("UP");
+- ifms_type = ift2ifm(p->kif.media_type);
+- if (ifms_type != 0)
+- printf(", %s, %s",
+- get_media_descr(ifms_type),
+- get_linkstate(ifms_type,
+- p->kif.link_state));
+- if (p->kif.baudrate) {
+- printf(", ");
+- print_baudrate(p->kif.baudrate);
+- }
+- }
++ char *s1;
++ if (p->kif.baudrate) {
++ if (asprintf(&s1, ", %s",
++ get_baudrate(p->kif.baudrate,
++ "bps")) == -1)
++ err(1, NULL);
++ } else if (asprintf(&s1, ", %s", get_linkstate(
++ p->kif.media_type, p->kif.link_state)) == -1)
++ err(1, NULL);
++ if (asprintf(&s, "%s (%s%s)", p->kif.ifname,
++ p->kif.flags & IFF_UP ? "UP" : "DOWN", s1) == -1)
++ err(1, NULL);
++ printf("%-15s", s);
++ free(s1);
++ free(s);
+ }
+ printf("\n");
+ break;
+@@ -898,9 +1054,8 @@ show_interface_head(void)
+ "Link state");
+ }
+
+-const int ifm_status_valid_list[] = IFM_STATUS_VALID_LIST;
+-const struct ifmedia_status_description
+- ifm_status_descriptions[] = IFM_STATUS_DESCRIPTIONS;
++const struct if_status_description
++ if_status_descriptions[] = LINK_STATE_DESCRIPTIONS;
+ const struct ifmedia_description
+ ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS;
+
+@@ -936,36 +1091,36 @@ get_media_descr(int media_type)
+ const char *
+ get_linkstate(int media_type, int link_state)
+ {
+- const struct ifmedia_status_description *p;
+- int i;
+-
+- if (link_state == LINK_STATE_UNKNOWN)
+- return ("unknown");
+-
+- for (i = 0; ifm_status_valid_list[i] != 0; i++)
+- for (p = ifm_status_descriptions; p->ifms_valid != 0; p++) {
+- if (p->ifms_type != media_type ||
+- p->ifms_valid != ifm_status_valid_list[i])
+- continue;
+- if (LINK_STATE_IS_UP(link_state))
+- return (p->ifms_string[1]);
+- return (p->ifms_string[0]);
+- }
++ const struct if_status_description *p;
++ static char buf[8];
+
+- return ("unknown link state");
++ for (p = if_status_descriptions; p->ifs_string != NULL; p++) {
++ if (LINK_STATE_DESC_MATCH(p, media_type, link_state))
++ return (p->ifs_string);
++ }
++ snprintf(buf, sizeof(buf), "[#%d]", link_state);
++ return (buf);
+ }
+
+-void
+-print_baudrate(u_int64_t baudrate)
++const char *
++get_baudrate(u_int64_t baudrate, char *unit)
+ {
++ static char bbuf[16];
++
+ if (baudrate > IF_Gbps(1))
+- printf("%llu GBit/s", baudrate / IF_Gbps(1));
++ snprintf(bbuf, sizeof(bbuf), "%" PRIu64 " G%s",
++ baudrate / IF_Gbps(1), unit);
+ else if (baudrate > IF_Mbps(1))
+- printf("%llu MBit/s", baudrate / IF_Mbps(1));
++ snprintf(bbuf, sizeof(bbuf), "%" PRIu64 " M%s",
++ baudrate / IF_Mbps(1), unit);
+ else if (baudrate > IF_Kbps(1))
+- printf("%llu KBit/s", baudrate / IF_Kbps(1));
++ snprintf(bbuf, sizeof(bbuf), "%" PRIu64 " K%s",
++ baudrate / IF_Kbps(1), unit);
+ else
+- printf("%llu Bit/s", baudrate);
++ snprintf(bbuf, sizeof(bbuf), "%" PRIu64 " %s",
++ baudrate, unit);
++
++ return (bbuf);
+ }
+
+ int
+@@ -982,17 +1137,12 @@ show_interface_msg(struct imsg *imsg)
+ printf("%-15s", k->flags & IFF_UP ? "UP" : "");
+
+ if ((ifms_type = ift2ifm(k->media_type)) != 0)
+- printf("%s, %s", get_media_descr(ifms_type),
+- get_linkstate(ifms_type, k->link_state));
+- else if (k->link_state == LINK_STATE_UNKNOWN)
+- printf("unknown");
+- else
+- printf("link state %u", k->link_state);
++ printf("%s, ", get_media_descr(ifms_type));
+
+- if (k->link_state != LINK_STATE_DOWN && k->baudrate > 0) {
+- printf(", ");
+- print_baudrate(k->baudrate);
+- }
++ printf("%s", get_linkstate(k->media_type, k->link_state));
++
++ if (k->link_state != LINK_STATE_DOWN && k->baudrate > 0)
++ printf(", %s", get_baudrate(k->baudrate, "Bit/s"));
+ printf("\n");
+ break;
+ case IMSG_CTL_END:
+@@ -1008,10 +1158,10 @@ show_interface_msg(struct imsg *imsg)
+ void
+ show_rib_summary_head(void)
+ {
+- printf(
+- "flags: * = Valid, > = Selected, I = via IBGP, A = Announced\n");
++ printf("flags: * = Valid, > = Selected, I = via IBGP, A = Announced, "
++ "S = Stale\n");
+ printf("origin: i = IGP, e = EGP, ? = Incomplete\n\n");
+- printf("%-5s %-20s%-15s %5s %5s %s\n", "flags", "destination",
++ printf("%-5s %-20s %-15s %5s %5s %s\n", "flags", "destination",
+ "gateway", "lpref", "med", "aspath origin");
+ }
+
+@@ -1049,26 +1199,30 @@ print_flags(u_int8_t flags, int sum)
+ char *p = flagstr;
+
+ if (sum) {
+- if (flags & F_RIB_ANNOUNCE)
++ if (flags & F_PREF_ANNOUNCE)
+ *p++ = 'A';
+- if (flags & F_RIB_INTERNAL)
++ if (flags & F_PREF_INTERNAL)
+ *p++ = 'I';
+- if (flags & F_RIB_ELIGIBLE)
++ if (flags & F_PREF_STALE)
++ *p++ = 'S';
++ if (flags & F_PREF_ELIGIBLE)
+ *p++ = '*';
+- if (flags & F_RIB_ACTIVE)
++ if (flags & F_PREF_ACTIVE)
+ *p++ = '>';
+ *p = '\0';
+ printf("%-5s ", flagstr);
+ } else {
+- if (flags & F_RIB_INTERNAL)
++ if (flags & F_PREF_INTERNAL)
+ printf("internal");
+ else
+ printf("external");
+- if (flags & F_RIB_ELIGIBLE)
++ if (flags & F_PREF_STALE)
++ printf(", stale");
++ if (flags & F_PREF_ELIGIBLE)
+ printf(", valid");
+- if (flags & F_RIB_ACTIVE)
++ if (flags & F_PREF_ACTIVE)
+ printf(", best");
+- if (flags & F_RIB_ANNOUNCE)
++ if (flags & F_PREF_ANNOUNCE)
+ printf(", announced");
+ }
+ }
+@@ -1077,27 +1231,14 @@ int
+ show_rib_summary_msg(struct imsg *imsg)
+ {
+ struct ctl_show_rib rib;
+- char *aspath;
+ u_char *asdata;
+
+ switch (imsg->hdr.type) {
+ case IMSG_CTL_SHOW_RIB:
+ memcpy(&rib, imsg->data, sizeof(rib));
+-
+- print_prefix(&rib.prefix, rib.prefixlen, rib.flags);
+- printf("%-15s ", log_addr(&rib.exit_nexthop));
+-
+- printf(" %5u %5u ", rib.local_pref, rib.med);
+-
+ asdata = imsg->data;
+ asdata += sizeof(struct ctl_show_rib);
+- if (aspath_asprint(&aspath, asdata, rib.aspath_len) == -1)
+- err(1, NULL);
+- if (strlen(aspath) > 0)
+- printf("%s ", aspath);
+- free(aspath);
+-
+- printf("%s\n", print_origin(rib.origin, 1));
++ show_rib_brief(&rib, asdata);
+ break;
+ case IMSG_CTL_END:
+ return (1);
+@@ -1112,108 +1253,21 @@ int
+ show_rib_detail_msg(struct imsg *imsg, int nodescr)
+ {
+ struct ctl_show_rib rib;
+- struct in_addr id;
+- char *aspath, *s;
+- u_char *data;
+- u_int32_t as;
+- u_int16_t ilen, alen, ioff;
+- u_int8_t flags, type;
+- time_t now;
++ u_char *asdata;
++ u_int16_t ilen;
+
+ switch (imsg->hdr.type) {
+ case IMSG_CTL_SHOW_RIB:
+ memcpy(&rib, imsg->data, sizeof(rib));
+-
+- printf("\nBGP routing table entry for %s/%u\n",
+- log_addr(&rib.prefix), rib.prefixlen);
+-
+- data = imsg->data;
+- data += sizeof(struct ctl_show_rib);
+- if (aspath_asprint(&aspath, data, rib.aspath_len) == -1)
+- err(1, NULL);
+- if (strlen(aspath) > 0)
+- printf(" %s\n", aspath);
+- free(aspath);
+-
+- s = fmt_peer(rib.descr, &rib.remote_addr, -1, nodescr);
+- printf(" Nexthop %s ", log_addr(&rib.exit_nexthop));
+- printf("(via %s) from %s (", log_addr(&rib.true_nexthop), s);
+- free(s);
+- id.s_addr = htonl(rib.remote_id);
+- printf("%s)\n", inet_ntoa(id));
+-
+- printf(" Origin %s, metric %u, localpref %u, ",
+- print_origin(rib.origin, 0), rib.med, rib.local_pref);
+- print_flags(rib.flags, 0);
+-
+- now = time(NULL);
+- if (now > rib.lastchange)
+- now -= rib.lastchange;
+- else
+- now = 0;
+-
+- printf("\n Last update: %s ago\n",
+- fmt_timeframe_core(now));
++ asdata = imsg->data;
++ asdata += sizeof(struct ctl_show_rib);
++ show_rib_detail(&rib, asdata, nodescr);
+ break;
+ case IMSG_CTL_SHOW_RIB_ATTR:
+ ilen = imsg->hdr.len - IMSG_HEADER_SIZE;
+ if (ilen < 3)
+ errx(1, "bad IMSG_CTL_SHOW_RIB_ATTR received");
+- data = imsg->data;
+- flags = data[0];
+- type = data[1];
+-
+- /* get the attribute length */
+- if (flags & ATTR_EXTLEN) {
+- if (ilen < 4)
+- errx(1, "bad IMSG_CTL_SHOW_RIB_ATTR received");
+- memcpy(&alen, data+2, sizeof(u_int16_t));
+- alen = ntohs(alen);
+- data += 4;
+- ilen -= 4;
+- } else {
+- alen = data[2];
+- data += 3;
+- ilen -= 3;
+- }
+- /* bad imsg len how can that happen!? */
+- if (alen != ilen)
+- errx(1, "bad IMSG_CTL_SHOW_RIB_ATTR received");
+-
+- switch (type) {
+- case ATTR_COMMUNITIES:
+- printf(" Communities: ");
+- show_community(data, alen);
+- printf("\n");
+- break;
+- case ATTR_AGGREGATOR:
+- memcpy(&as, data, sizeof(as));
+- memcpy(&id, data + sizeof(as), sizeof(id));
+- printf(" Aggregator: %s [%s]\n",
+- log_as(htonl(as)), inet_ntoa(id));
+- break;
+- case ATTR_ORIGINATOR_ID:
+- memcpy(&id, data, sizeof(id));
+- printf(" Originator Id: %s\n", inet_ntoa(id));
+- break;
+- case ATTR_CLUSTER_LIST:
+- printf(" Cluster ID List:");
+- for (ioff = 0; ioff + sizeof(id) <= ilen;
+- ioff += sizeof(id)) {
+- memcpy(&id, data + ioff, sizeof(id));
+- printf(" %s", inet_ntoa(id));
+- }
+- printf("\n");
+- break;
+- case ATTR_EXT_COMMUNITIES:
+- printf(" Ext. communities: ");
+- show_ext_community(data, alen);
+- printf("\n");
+- break;
+- default:
+- /* ignore unknown attributes */
+- break;
+- }
++ show_attr(imsg->data, ilen);
+ break;
+ case IMSG_CTL_END:
+ printf("\n");
+@@ -1225,67 +1279,128 @@ show_rib_detail_msg(struct imsg *imsg, i
+ return (0);
+ }
+
+-char *
+-fmt_mem(int64_t num)
++void
++show_rib_brief(struct ctl_show_rib *r, u_char *asdata)
+ {
+- static char buf[16];
++ char *aspath;
+
+- if (fmt_scaled(num, buf) == -1)
+- snprintf(buf, sizeof(buf), "%lldB", (long long)num);
++ print_prefix(&r->prefix, r->prefixlen, r->flags);
++ printf(" %-15s ", log_addr(&r->exit_nexthop));
++ printf(" %5u %5u ", r->local_pref, r->med);
+
+- return (buf);
++ if (aspath_asprint(&aspath, asdata, r->aspath_len) == -1)
++ err(1, NULL);
++ if (strlen(aspath) > 0)
++ printf("%s ", aspath);
++ free(aspath);
++
++ printf("%s\n", print_origin(r->origin, 1));
+ }
+
+-int
+-show_rib_memory_msg(struct imsg *imsg)
++void
++show_rib_detail(struct ctl_show_rib *r, u_char *asdata, int nodescr)
+ {
+- struct rde_memstats stats;
++ struct in_addr id;
++ char *aspath, *s;
++ time_t now;
+
+- switch (imsg->hdr.type) {
+- case IMSG_CTL_SHOW_RIB_MEM:
+- memcpy(&stats, imsg->data, sizeof(stats));
+- printf("RDE memory statistics\n");
+- printf("%10lld IPv4 network entries using %s of memory\n",
+- (long long)stats.pt4_cnt, fmt_mem(stats.pt4_cnt *
+- sizeof(struct pt_entry4)));
+- if (stats.pt6_cnt != 0)
+- printf("%10lld IPv6 network entries using "
+- "%s of memory\n", (long long)stats.pt6_cnt,
+- fmt_mem(stats.pt6_cnt * sizeof(struct pt_entry6)));
+- printf("%10lld rib entries using %s of memory\n",
+- (long long)stats.rib_cnt, fmt_mem(stats.rib_cnt *
+- sizeof(struct rib_entry)));
+- printf("%10lld prefix entries using %s of memory\n",
+- (long long)stats.prefix_cnt, fmt_mem(stats.prefix_cnt *
+- sizeof(struct prefix)));
+- printf("%10lld BGP path attribute entries using %s of memory\n",
+- (long long)stats.path_cnt, fmt_mem(stats.path_cnt *
+- sizeof(struct rde_aspath)));
+- printf("%10lld BGP AS-PATH attribute entries using "
+- "%s of memory,\n\t and holding %lld references\n",
+- (long long)stats.aspath_cnt, fmt_mem(stats.aspath_size),
+- (long long)stats.aspath_refs);
+- printf("%10lld BGP attributes entries using %s of memory\n",
+- (long long)stats.attr_cnt, fmt_mem(stats.attr_cnt *
+- sizeof(struct attr)));
+- printf("\t and holding %lld references\n",
+- (long long)stats.attr_refs);
+- printf("%10lld BGP attributes using %s of memory\n",
+- (long long)stats.attr_dcnt, fmt_mem(stats.attr_data));
+- printf("RIB using %s of memory\n", fmt_mem(
+- stats.pt4_cnt * sizeof(struct pt_entry4) +
+- stats.pt6_cnt * sizeof(struct pt_entry6) +
+- 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("\nBGP routing table entry for %s/%u\n",
++ log_addr(&r->prefix), r->prefixlen);
++
++ if (aspath_asprint(&aspath, asdata, r->aspath_len) == -1)
++ err(1, NULL);
++ if (strlen(aspath) > 0)
++ printf(" %s\n", aspath);
++ free(aspath);
++
++ s = fmt_peer(r->descr, &r->remote_addr, -1, nodescr);
++ printf(" Nexthop %s ", log_addr(&r->exit_nexthop));
++ printf("(via %s) from %s (", log_addr(&r->true_nexthop), s);
++ free(s);
++ id.s_addr = htonl(r->remote_id);
++ printf("%s)\n", inet_ntoa(id));
++
++ printf(" Origin %s, metric %u, localpref %u, weight %u, ",
++ print_origin(r->origin, 0), r->med, r->local_pref, r->weight);
++ print_flags(r->flags, 0);
++
++ now = time(NULL);
++ if (now > r->lastchange)
++ now -= r->lastchange;
++ else
++ now = 0;
++
++ printf("\n Last update: %s ago\n", fmt_timeframe_core(now));
++}
++
++void
++show_attr(void *b, u_int16_t len)
++{
++ char *data = b;
++ struct in_addr id;
++ u_int32_t as;
++ u_int16_t alen, ioff;
++ u_int8_t flags, type;
++
++ data = b;
++ if (len < 3)
++ errx(1, "show_attr: too short bgp attr");
++
++ flags = data[0];
++ type = data[1];
++
++ /* get the attribute length */
++ if (flags & ATTR_EXTLEN) {
++ if (len < 4)
++ errx(1, "show_attr: too short bgp attr");
++ memcpy(&alen, data+2, sizeof(u_int16_t));
++ alen = ntohs(alen);
++ data += 4;
++ len -= 4;
++ } else {
++ alen = data[2];
++ data += 3;
++ len -= 3;
++ }
++
++ /* bad imsg len how can that happen!? */
++ if (alen > len)
++ errx(1, "show_attr: bad length");
++
++ switch (type) {
++ case ATTR_COMMUNITIES:
++ printf(" Communities: ");
++ show_community(data, alen);
++ printf("\n");
++ break;
++ case ATTR_AGGREGATOR:
++ memcpy(&as, data, sizeof(as));
++ memcpy(&id, data + sizeof(as), sizeof(id));
++ printf(" Aggregator: %s [%s]\n",
++ log_as(ntohl(as)), inet_ntoa(id));
++ break;
++ case ATTR_ORIGINATOR_ID:
++ memcpy(&id, data, sizeof(id));
++ printf(" Originator Id: %s\n", inet_ntoa(id));
++ break;
++ case ATTR_CLUSTER_LIST:
++ printf(" Cluster ID List:");
++ for (ioff = 0; ioff + sizeof(id) <= alen;
++ ioff += sizeof(id)) {
++ memcpy(&id, data + ioff, sizeof(id));
++ printf(" %s", inet_ntoa(id));
++ }
++ printf("\n");
++ break;
++ case ATTR_EXT_COMMUNITIES:
++ printf(" Ext. communities: ");
++ show_ext_community(data, alen);
++ printf("\n");
+ break;
+ default:
++ /* ignore unknown attributes */
+ break;
+ }
+-
+- return (1);
+ }
+
+ void
+@@ -1328,30 +1443,6 @@ show_community(u_char *data, u_int16_t l
+ }
+ }
+
+-const char *
+-get_ext_subtype(u_int8_t type)
+-{
+- static char etype[6];
+-
+- switch (type) {
+- case EXT_COMMUNITY_ROUTE_TGT:
+- return "rt"; /* route target */
+- case EXT_CUMMUNITY_ROUTE_ORIG:
+- return "soo"; /* source of origin */
+- case EXT_COMMUNITY_OSPF_DOM_ID:
+- return "odi"; /* ospf domain id */
+- case EXT_COMMUNITY_OSPF_RTR_TYPE:
+- return "ort"; /* ospf route type */
+- case EXT_COMMUNITY_OSPF_RTR_ID:
+- return "ori"; /* ospf router id */
+- case EXT_COMMUNITY_BGP_COLLECT:
+- return "bdc"; /* bgp data collection */
+- default:
+- snprintf(etype, sizeof(etype), "[%i]", (int)type);
+- return etype;
+- }
+-}
+-
+ void
+ show_ext_community(u_char *data, u_int16_t len)
+ {
+@@ -1372,34 +1463,101 @@ show_ext_community(u_char *data, u_int16
+ case EXT_COMMUNITY_TWO_AS:
+ memcpy(&as2, data + i + 2, sizeof(as2));
+ memcpy(&u32, data + i + 4, sizeof(u32));
+- printf("%s %hu:%u", get_ext_subtype(subtype), as2, u32);
++ printf("%s %s:%u", log_ext_subtype(subtype),
++ log_as(ntohs(as2)), ntohl(u32));
+ break;
+ case EXT_COMMUNITY_IPV4:
+ memcpy(&ip, data + i + 2, sizeof(ip));
+ memcpy(&u16, data + i + 6, sizeof(u16));
+- printf("%s %s:%hu", get_ext_subtype(subtype),
+- inet_ntoa(ip), u16);
++ printf("%s %s:%hu", log_ext_subtype(subtype),
++ inet_ntoa(ip), ntohs(u16));
+ break;
+ case EXT_COMMUNITY_FOUR_AS:
+ memcpy(&as4, data + i + 2, sizeof(as4));
+ memcpy(&u16, data + i + 6, sizeof(u16));
+- printf("%s %s:%hu", get_ext_subtype(subtype),
+- log_as(as4), u16);
++ printf("%s %s:%hu", log_ext_subtype(subtype),
++ log_as(ntohl(as4)), ntohs(u16));
+ break;
+ case EXT_COMMUNITY_OPAQUE:
+ memcpy(&ext, data + i, sizeof(ext));
+ ext = betoh64(ext) & 0xffffffffffffLL;
+- printf("%s 0x%llx", get_ext_subtype(subtype), ext);
++ printf("%s 0x%" PRIx64, log_ext_subtype(subtype), ext);
+ break;
+ default:
+ memcpy(&ext, data + i, sizeof(ext));
+- printf("0x%llx", betoh64(ext));
++ printf("0x%" PRIx64, betoh64(ext));
+ }
+ if (i + 8 < len)
+ printf(", ");
+ }
+ }
+
++char *
++fmt_mem(int64_t num)
++{
++ static char buf[16];
++
++ if (fmt_scaled(num, buf) == -1)
++ snprintf(buf, sizeof(buf), "%lldB", (long long)num);
++
++ return (buf);
++}
++
++size_t pt_sizes[AID_MAX] = AID_PTSIZE;
++
++int
++show_rib_memory_msg(struct imsg *imsg)
++{
++ struct rde_memstats stats;
++ size_t pts = 0;
++ int i;
++
++ switch (imsg->hdr.type) {
++ case IMSG_CTL_SHOW_RIB_MEM:
++ memcpy(&stats, imsg->data, sizeof(stats));
++ 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",
++ (long long)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",
++ (long long)stats.rib_cnt, fmt_mem(stats.rib_cnt *
++ sizeof(struct rib_entry)));
++ printf("%10lld prefix entries using %s of memory\n",
++ (long long)stats.prefix_cnt, fmt_mem(stats.prefix_cnt *
++ sizeof(struct prefix)));
++ printf("%10lld BGP path attribute entries using %s of memory\n",
++ (long long)stats.path_cnt, fmt_mem(stats.path_cnt *
++ sizeof(struct rde_aspath)));
++ printf("%10lld BGP AS-PATH attribute entries using "
++ "%s of memory,\n\t and holding %lld references\n",
++ (long long)stats.aspath_cnt, fmt_mem(stats.aspath_size),
++ (long long)stats.aspath_refs);
++ printf("%10lld BGP attributes entries using %s of memory\n",
++ (long long)stats.attr_cnt, fmt_mem(stats.attr_cnt *
++ sizeof(struct attr)));
++ printf("\t and holding %lld references\n",
++ (long long)stats.attr_refs);
++ printf("%10lld BGP attributes using %s of memory\n",
++ (long long)stats.attr_dcnt, fmt_mem(stats.attr_data));
++ 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));
++ break;
++ default:
++ break;
++ }
++
++ return (1);
++}
++
+ void
+ send_filterset(struct imsgbuf *i, struct filter_set_head *set)
+ {
+@@ -1469,6 +1627,183 @@ show_result(struct imsg *imsg)
+ return (1);
+ }
+
++void
++show_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg)
++{
++ struct ctl_show_rib ctl;
++ struct ctl_show_rib_request *req = arg;
++ struct mrt_rib_entry *mre;
++ u_int16_t i, j;
++
++ for (i = 0; i < mr->nentries; i++) {
++ mre = &mr->entries[i];
++ bzero(&ctl, sizeof(ctl));
++ mrt_to_bgpd_addr(&mr->prefix, &ctl.prefix);
++ ctl.prefixlen = mr->prefixlen;
++ ctl.lastchange = mre->originated;
++ mrt_to_bgpd_addr(&mre->nexthop, &ctl.true_nexthop);
++ mrt_to_bgpd_addr(&mre->nexthop, &ctl.exit_nexthop);
++ ctl.origin = mre->origin;
++ ctl.local_pref = mre->local_pref;
++ ctl.med = mre->med;
++ /* weight is not part of the mrt dump so it can't be set */
++ ctl.aspath_len = mre->aspath_len;
++
++ if (mre->peer_idx < mp->npeers) {
++ mrt_to_bgpd_addr(&mp->peers[mre->peer_idx].addr,
++ &ctl.remote_addr);
++ ctl.remote_id = mp->peers[mre->peer_idx].bgp_id;
++ }
++
++ /* filter by neighbor */
++ if (req->neighbor.addr.aid != AID_UNSPEC &&
++ memcmp(&req->neighbor.addr, &ctl.remote_addr,
++ sizeof(ctl.remote_addr)) != 0)
++ continue;
++ /* filter by AF */
++ if (req->aid && req->aid != ctl.prefix.aid)
++ return;
++ /* filter by prefix */
++ if (req->prefix.aid != AID_UNSPEC) {
++ if (!prefix_compare(&req->prefix, &ctl.prefix,
++ req->prefixlen)) {
++ if (req->flags & F_LONGER) {
++ if (req->prefixlen > ctl.prefixlen)
++ return;
++ } else if (req->prefixlen != ctl.prefixlen)
++ return;
++ } else
++ return;
++ }
++ /* filter by AS */
++ if (req->as.type != AS_NONE &&
++ !aspath_match(mre->aspath, mre->aspath_len,
++ req->as.type, req->as.as))
++ continue;
++
++ if (req->flags & F_CTL_DETAIL) {
++ show_rib_detail(&ctl, mre->aspath, 1);
++ for (j = 0; j < mre->nattrs; j++)
++ show_attr(mre->attrs[j].attr,
++ mre->attrs[j].attr_len);
++ } else
++ show_rib_brief(&ctl, mre->aspath);
++ }
++}
++
++void
++network_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg)
++{
++ struct ctl_show_rib ctl;
++ struct network_config net;
++ struct ctl_show_rib_request *req = arg;
++ struct mrt_rib_entry *mre;
++ struct ibuf *msg;
++ u_int16_t i, j;
++
++ for (i = 0; i < mr->nentries; i++) {
++ mre = &mr->entries[i];
++ bzero(&ctl, sizeof(ctl));
++ mrt_to_bgpd_addr(&mr->prefix, &ctl.prefix);
++ ctl.prefixlen = mr->prefixlen;
++ ctl.lastchange = mre->originated;
++ mrt_to_bgpd_addr(&mre->nexthop, &ctl.true_nexthop);
++ mrt_to_bgpd_addr(&mre->nexthop, &ctl.exit_nexthop);
++ ctl.origin = mre->origin;
++ ctl.local_pref = mre->local_pref;
++ ctl.med = mre->med;
++ ctl.aspath_len = mre->aspath_len;
++
++ if (mre->peer_idx < mp->npeers) {
++ mrt_to_bgpd_addr(&mp->peers[mre->peer_idx].addr,
++ &ctl.remote_addr);
++ ctl.remote_id = mp->peers[mre->peer_idx].bgp_id;
++ }
++
++ /* filter by neighbor */
++ if (req->neighbor.addr.aid != AID_UNSPEC &&
++ memcmp(&req->neighbor.addr, &ctl.remote_addr,
++ sizeof(ctl.remote_addr)) != 0)
++ continue;
++ /* filter by AF */
++ if (req->aid && req->aid != ctl.prefix.aid)
++ return;
++ /* filter by prefix */
++ if (req->prefix.aid != AID_UNSPEC) {
++ if (!prefix_compare(&req->prefix, &ctl.prefix,
++ req->prefixlen)) {
++ if (req->flags & F_LONGER) {
++ if (req->prefixlen > ctl.prefixlen)
++ return;
++ } else if (req->prefixlen != ctl.prefixlen)
++ return;
++ } else
++ return;
++ }
++ /* filter by AS */
++ if (req->as.type != AS_NONE &&
++ !aspath_match(mre->aspath, mre->aspath_len,
++ req->as.type, req->as.as))
++ continue;
++
++ bzero(&net, sizeof(net));
++ memcpy(&net.prefix, &ctl.prefix, sizeof(net.prefix));
++ net.prefixlen = ctl.prefixlen;
++ net.type = NETWORK_MRTCLONE;
++ /* XXX rtableid */
++
++ imsg_compose(ibuf, IMSG_NETWORK_ADD, 0, 0, -1,
++ &net, sizeof(net));
++ if ((msg = imsg_create(ibuf, IMSG_NETWORK_ASPATH,
++ 0, 0, sizeof(ctl) + mre->aspath_len)) == NULL)
++ errx(1, "imsg_create failure");
++ if (imsg_add(msg, &ctl, sizeof(ctl)) == -1 ||
++ imsg_add(msg, mre->aspath, mre->aspath_len) == -1)
++ errx(1, "imsg_add failure");
++ imsg_close(ibuf, msg);
++ for (j = 0; j < mre->nattrs; j++)
++ imsg_compose(ibuf, IMSG_NETWORK_ATTR, 0, 0, -1,
++ mre->attrs[j].attr, mre->attrs[j].attr_len);
++ imsg_compose(ibuf, IMSG_NETWORK_DONE, 0, 0, -1, NULL, 0);
++
++ while (ibuf->w.queued) {
++ if (msgbuf_write(&ibuf->w) < 0)
++ err(1, "write error");
++ }
++ }
++}
++
++void
++show_mrt_state(struct mrt_bgp_state *ms, void *arg)
++{
++ printf("show_mrt_state\n");
++}
++
++void
++show_mrt_msg(struct mrt_bgp_msg *mm, void *arg)
++{
++ printf("show_mrt_msg\n");
++}
++
++void
++mrt_to_bgpd_addr(union mrt_addr *ma, struct bgpd_addr *ba)
++{
++ switch (ma->sa.sa_family) {
++ case AF_INET:
++ case AF_INET6:
++ sa2addr(&ma->sa, ba);
++ break;
++ case AF_VPNv4:
++ bzero(ba, sizeof(*ba));
++ ba->aid = AID_VPN_IPv4;
++ ba->vpn4.rd = ma->svpn4.sv_rd;
++ ba->vpn4.addr.s_addr = ma->svpn4.sv_addr.s_addr;
++ memcpy(ba->vpn4.labelstack, ma->svpn4.sv_label,
++ sizeof(ba->vpn4.labelstack));
++ break;
++ }
++}
++
+ /* following functions are necessary for imsg framework */
+ void
+ log_warnx(const char *emsg, ...)
+@@ -1495,3 +1830,9 @@ fatal(const char *emsg)
+ {
+ err(1, emsg);
+ }
++
++void
++fatalx(const char *emsg)
++{
++ errx(1, emsg);
++}