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 @@ -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 #include #include #include +#if defined(__FreeBSD__) /* net/if_media.h */ +#include "if_media.h" +#else #include +#endif /* defined(__FreeBSD__) */ #include #include @@ -29,7 +37,11 @@ #include #include #include +#if defined(__FreeBSD__) /* util.h */ +#include "util.h" +#else #include +#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); +}