1*b3b12989Sclaudio /* $OpenBSD: bgpctl.c,v 1.314 2024/12/16 16:10:46 claudio Exp $ */ 2fd0978b9Shenning 3fd0978b9Shenning /* 4fd0978b9Shenning * Copyright (c) 2003 Henning Brauer <henning@openbsd.org> 56671ac0bSclaudio * Copyright (c) 2004-2019 Claudio Jeker <claudio@openbsd.org> 6280f24a4Sphessler * Copyright (c) 2016 Job Snijders <job@instituut.net> 7280f24a4Sphessler * Copyright (c) 2016 Peter Hessler <phessler@openbsd.org> 8fd0978b9Shenning * 9fd0978b9Shenning * Permission to use, copy, modify, and distribute this software for any 10fd0978b9Shenning * purpose with or without fee is hereby granted, provided that the above 11fd0978b9Shenning * copyright notice and this permission notice appear in all copies. 12fd0978b9Shenning * 13fd0978b9Shenning * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14fd0978b9Shenning * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15fd0978b9Shenning * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16fd0978b9Shenning * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17fd0978b9Shenning * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18fd0978b9Shenning * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19fd0978b9Shenning * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20fd0978b9Shenning */ 21fd0978b9Shenning 2289cb8daeSclaudio #include <sys/time.h> 23fd0978b9Shenning #include <sys/types.h> 24fd0978b9Shenning #include <sys/socket.h> 258d7b500cSbenno #include <sys/stat.h> 26fd0978b9Shenning #include <sys/un.h> 271b3c4f02Shenning 28bb4118bdSclaudio #include <endian.h> 29fd0978b9Shenning #include <err.h> 30c0dbf5cfSsthen #include <errno.h> 310ac5a32aSphessler #include <fcntl.h> 323afc9eb1Sclaudio #include <math.h> 33fd0978b9Shenning #include <stdio.h> 34fb57b3f9Shenning #include <stdlib.h> 35fd0978b9Shenning #include <string.h> 3685411ad9Sclaudio #include <time.h> 37fd0978b9Shenning #include <unistd.h> 386c34dfd1Sclaudio #include <util.h> 39fd0978b9Shenning 40fd0978b9Shenning #include "bgpd.h" 41a0f4a7e3Shenning #include "session.h" 427b6c56a0Sclaudio #include "rde.h" 433eb1af85Sjob #include "version.h" 446671ac0bSclaudio 456671ac0bSclaudio #include "bgpctl.h" 46acd8015aShenning #include "parser.h" 47a20554fdSclaudio #include "mrtparser.h" 48fde0bae3Shenning 49fd0978b9Shenning int main(int, char *[]); 50f084a78cSclaudio int show(struct imsg *, struct parse_result *); 519caec0aeSclaudio void send_filterset(struct imsgbuf *, struct filter_set_head *); 52b5cff06cSclaudio void show_mrt_dump_neighbors(struct mrt_rib *, struct mrt_peer *, 53b5cff06cSclaudio void *); 54a20554fdSclaudio void show_mrt_dump(struct mrt_rib *, struct mrt_peer *, void *); 55f486926aSclaudio void network_mrt_dump(struct mrt_rib *, struct mrt_peer *, void *); 56a20554fdSclaudio void show_mrt_state(struct mrt_bgp_state *, void *); 57a20554fdSclaudio void show_mrt_msg(struct mrt_bgp_msg *, void *); 5859154960Sclaudio const char *msg_type(uint8_t); 590ac5a32aSphessler void network_bulk(struct parse_result *); 6059154960Sclaudio int match_aspath(void *, uint16_t, struct filter_as *); 61e3925e28Sclaudio struct flowspec *res_to_flowspec(struct parse_result *); 620ac5a32aSphessler 6340466abfSclaudio struct imsgbuf *imsgbuf; 64a20554fdSclaudio struct mrt_parser show_mrt = { show_mrt_dump, show_mrt_state, show_mrt_msg }; 65f486926aSclaudio struct mrt_parser net_mrt = { network_mrt_dump, NULL, NULL }; 66d30a810dSclaudio const struct output *output = &show_output; 6747ffa64dSdenis int tableid; 68f084a78cSclaudio int nodescr; 69fd0978b9Shenning 70cbb557dbShenning __dead void 71a39dd3f0Shenning usage(void) 72a39dd3f0Shenning { 73a39dd3f0Shenning extern char *__progname; 74a39dd3f0Shenning 753123221bSclaudio fprintf(stderr, "usage: %s [-jnV] [-s socket] command [argument ...]\n", 7666761d00Ssobrado __progname); 77a39dd3f0Shenning exit(1); 78a39dd3f0Shenning } 79a39dd3f0Shenning 80fd0978b9Shenning int 81fd0978b9Shenning main(int argc, char *argv[]) 82fd0978b9Shenning { 83f0d589c3Sclaudio struct sockaddr_un sa_un; 8477a10e6fSclaudio int fd, n, done, numdone, ch, verbose = 0; 85fd0978b9Shenning struct imsg imsg; 86a4cb7d77Sclaudio struct network_config net; 87acd8015aShenning struct parse_result *res; 88fd71c51dShenning struct ctl_neighbor neighbor; 89ba099d61Sclaudio struct ctl_show_rib_request ribreq; 90e3925e28Sclaudio struct flowspec *f; 912302052bShenning char *sockname; 92ba099d61Sclaudio enum imsg_type type; 93acd8015aShenning 94445db22eSbenno if (pledge("stdio rpath wpath cpath unix inet dns", NULL) == -1) 95445db22eSbenno err(1, "pledge"); 96445db22eSbenno 9747ffa64dSdenis tableid = getrtable(); 9847ffa64dSdenis if (asprintf(&sockname, "%s.%d", SOCKET_NAME, tableid) == -1) 998d7b500cSbenno err(1, "asprintf"); 1008d7b500cSbenno 1013eb1af85Sjob while ((ch = getopt(argc, argv, "jns:V")) != -1) { 1022ec7f40eShenning switch (ch) { 1032ec7f40eShenning case 'n': 1042ec7f40eShenning if (++nodescr > 1) 1052ec7f40eShenning usage(); 1062ec7f40eShenning break; 10714178ff0Sclaudio case 'j': 10814178ff0Sclaudio output = &json_output; 10914178ff0Sclaudio break; 1108d594bb1Sclaudio case 's': 1118d594bb1Sclaudio sockname = optarg; 1128d594bb1Sclaudio break; 1133eb1af85Sjob case 'V': 1143eb1af85Sjob fprintf(stderr, "OpenBGPD %s\n", BGPD_VERSION); 1153eb1af85Sjob return 0; 1162ec7f40eShenning default: 1172ec7f40eShenning usage(); 1182ec7f40eShenning /* NOTREACHED */ 1192ec7f40eShenning } 1202ec7f40eShenning } 1214e9d3417Shenning argc -= optind; 1224e9d3417Shenning argv += optind; 1232ec7f40eShenning 124acd8015aShenning if ((res = parse(argc, argv)) == NULL) 125acd8015aShenning exit(1); 126fd0978b9Shenning 12730868731Sclaudio memcpy(&neighbor.addr, &res->peeraddr, sizeof(neighbor.addr)); 12830868731Sclaudio strlcpy(neighbor.descr, res->peerdesc, sizeof(neighbor.descr)); 129903de74aSclaudio neighbor.is_group = res->is_group; 130a78f83ceSderaadt strlcpy(neighbor.reason, res->reason, sizeof(neighbor.reason)); 13130868731Sclaudio 13230868731Sclaudio switch (res->action) { 13330868731Sclaudio case SHOW_MRT: 13430868731Sclaudio if (pledge("stdio", NULL) == -1) 13530868731Sclaudio err(1, "pledge"); 13630868731Sclaudio 1374a99c744Sclaudio memset(&ribreq, 0, sizeof(ribreq)); 1389efe3de0Sclaudio if (res->as.type != AS_UNDEF) 13930868731Sclaudio ribreq.as = res->as; 14030868731Sclaudio if (res->addr.aid) { 14130868731Sclaudio ribreq.prefix = res->addr; 14230868731Sclaudio ribreq.prefixlen = res->prefixlen; 14330868731Sclaudio } 144187619b8Sclaudio /* XXX currently no communities support */ 14530868731Sclaudio ribreq.neighbor = neighbor; 14630868731Sclaudio ribreq.aid = res->aid; 14730868731Sclaudio ribreq.flags = res->flags; 1482f429709Sjob ribreq.validation_state = res->validation_state; 14930868731Sclaudio show_mrt.arg = &ribreq; 150b5cff06cSclaudio if (res->flags & F_CTL_NEIGHBORS) 151b5cff06cSclaudio show_mrt.dump = show_mrt_dump_neighbors; 152f084a78cSclaudio else 153d30a810dSclaudio output->head(res); 15430868731Sclaudio mrt_parse(res->mrtfd, &show_mrt, 1); 15530868731Sclaudio exit(0); 15630868731Sclaudio default: 15730868731Sclaudio break; 158ec8f8491Sclaudio } 1593503d06eShenning 160e647dd64Sderaadt if (pledge("stdio unix", NULL) == -1) 161bf641d7bSbenno err(1, "pledge"); 162bf641d7bSbenno 1635dd784b9Shenning if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 164fd0978b9Shenning err(1, "control_init: socket"); 165fd0978b9Shenning 1664a99c744Sclaudio memset(&sa_un, 0, sizeof(sa_un)); 167f0d589c3Sclaudio sa_un.sun_family = AF_UNIX; 168f0d589c3Sclaudio if (strlcpy(sa_un.sun_path, sockname, sizeof(sa_un.sun_path)) >= 169f0d589c3Sclaudio sizeof(sa_un.sun_path)) 1708d594bb1Sclaudio errx(1, "socket name too long"); 171f0d589c3Sclaudio if (connect(fd, (struct sockaddr *)&sa_un, sizeof(sa_un)) == -1) 1728d594bb1Sclaudio err(1, "connect: %s", sockname); 173fd0978b9Shenning 17430868731Sclaudio if (pledge("stdio", NULL) == -1) 175bf641d7bSbenno err(1, "pledge"); 176bf641d7bSbenno 17740466abfSclaudio if ((imsgbuf = malloc(sizeof(struct imsgbuf))) == NULL) 17878d6515aSclaudio err(1, NULL); 1795bf6f543Sclaudio if (imsgbuf_init(imsgbuf, fd) == -1 || 1805bf6f543Sclaudio imsgbuf_set_maxsize(imsgbuf, MAX_BGPD_IMSGSIZE) == -1) 181f1b790a5Sclaudio err(1, NULL); 1823d6334e3Shenning done = 0; 183fd0978b9Shenning 184acd8015aShenning switch (res->action) { 185a7bd0fd3Shenning case NONE: 18630868731Sclaudio case SHOW_MRT: 187a7bd0fd3Shenning usage(); 1886d93a853Sclaudio /* NOTREACHED */ 189fde0bae3Shenning case SHOW: 190fde0bae3Shenning case SHOW_SUMMARY: 19140466abfSclaudio imsg_compose(imsgbuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1, 19240466abfSclaudio NULL, 0); 193fde0bae3Shenning break; 19416fcf8d2Shenning case SHOW_SUMMARY_TERSE: 19540466abfSclaudio imsg_compose(imsgbuf, IMSG_CTL_SHOW_TERSE, 0, 0, -1, NULL, 0); 19616fcf8d2Shenning break; 197fb57b3f9Shenning case SHOW_FIB: 198b26dd4adSclaudio if (!res->addr.aid) { 199ee979483Sclaudio struct ctl_kroute_req req = { 0 }; 200dd4f9aa8Shenning 201ee979483Sclaudio req.af = aid2af(res->aid); 202ee979483Sclaudio req.flags = res->flags; 203ee979483Sclaudio 204ee979483Sclaudio imsg_compose(imsgbuf, IMSG_CTL_KROUTE, res->rtableid, 205ee979483Sclaudio 0, -1, &req, sizeof(req)); 206dd4f9aa8Shenning } else 20740466abfSclaudio imsg_compose(imsgbuf, IMSG_CTL_KROUTE_ADDR, 20840466abfSclaudio res->rtableid, 0, -1, 20940466abfSclaudio &res->addr, sizeof(res->addr)); 210fb57b3f9Shenning break; 2117f410e5eSclaudio case SHOW_FIB_TABLES: 21240466abfSclaudio imsg_compose(imsgbuf, IMSG_CTL_SHOW_FIB_TABLES, 0, 0, -1, 2137f410e5eSclaudio NULL, 0); 214af7abb58Shenning break; 21540466abfSclaudio case SHOW_NEXTHOP: 21640466abfSclaudio imsg_compose(imsgbuf, IMSG_CTL_SHOW_NEXTHOP, res->rtableid, 21740466abfSclaudio 0, -1, NULL, 0); 21840466abfSclaudio break; 219a8b61ed1Shenning case SHOW_INTERFACE: 22040466abfSclaudio imsg_compose(imsgbuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1, 22140466abfSclaudio NULL, 0); 222a8b61ed1Shenning break; 223413f97b7Sclaudio case SHOW_SET: 22440466abfSclaudio imsg_compose(imsgbuf, IMSG_CTL_SHOW_SET, 0, 0, -1, NULL, 0); 225413f97b7Sclaudio break; 22669d2b5abSclaudio case SHOW_RTR: 22740466abfSclaudio imsg_compose(imsgbuf, IMSG_CTL_SHOW_RTR, 0, 0, -1, NULL, 0); 22869d2b5abSclaudio break; 229fde0bae3Shenning case SHOW_NEIGHBOR: 230ed99340cShenning case SHOW_NEIGHBOR_TIMERS: 2315901a216Sclaudio case SHOW_NEIGHBOR_TERSE: 2320d594c94Shenning neighbor.show_timers = (res->action == SHOW_NEIGHBOR_TIMERS); 233b26dd4adSclaudio if (res->peeraddr.aid || res->peerdesc[0]) 23440466abfSclaudio imsg_compose(imsgbuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1, 2354acf9b2eShenning &neighbor, sizeof(neighbor)); 236acd8015aShenning else 23740466abfSclaudio imsg_compose(imsgbuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1, 23809ad4f82Shenning NULL, 0); 239fde0bae3Shenning break; 2407b6c56a0Sclaudio case SHOW_RIB: 2414a99c744Sclaudio memset(&ribreq, 0, sizeof(ribreq)); 242ba099d61Sclaudio type = IMSG_CTL_SHOW_RIB; 243b26dd4adSclaudio if (res->addr.aid) { 24438500be7Sbenno ribreq.prefix = res->addr; 245ba099d61Sclaudio ribreq.prefixlen = res->prefixlen; 246ba099d61Sclaudio type = IMSG_CTL_SHOW_RIB_PREFIX; 247ba099d61Sclaudio } 248187619b8Sclaudio if (res->as.type != AS_UNDEF) 249187619b8Sclaudio ribreq.as = res->as; 2500ca99656Sclaudio if (res->community.flags != 0) 25138500be7Sbenno ribreq.community = res->community; 25238500be7Sbenno ribreq.neighbor = neighbor; 253a9a0337fSclaudio strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib)); 254536c61dcSclaudio ribreq.aid = res->aid; 25546daf8ccSclaudio ribreq.path_id = res->pathid; 256ba099d61Sclaudio ribreq.flags = res->flags; 25740466abfSclaudio imsg_compose(imsgbuf, type, 0, 0, -1, &ribreq, sizeof(ribreq)); 2587b6c56a0Sclaudio break; 2596c34dfd1Sclaudio case SHOW_RIB_MEM: 26040466abfSclaudio imsg_compose(imsgbuf, IMSG_CTL_SHOW_RIB_MEM, 0, 0, -1, NULL, 0); 2616c34dfd1Sclaudio break; 262cbe08412Sclaudio case SHOW_METRICS: 26377a10e6fSclaudio output = &ometric_output; 26477a10e6fSclaudio numdone = 2; 26540466abfSclaudio imsg_compose(imsgbuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1, 26640466abfSclaudio NULL, 0); 26740466abfSclaudio imsg_compose(imsgbuf, IMSG_CTL_SHOW_RIB_MEM, 0, 0, -1, NULL, 0); 26877a10e6fSclaudio break; 269fa8c3b18Shenning case RELOAD: 27040466abfSclaudio imsg_compose(imsgbuf, IMSG_CTL_RELOAD, 0, 0, -1, 271a78f83ceSderaadt res->reason, sizeof(res->reason)); 272a78f83ceSderaadt if (res->reason[0]) 273a78f83ceSderaadt printf("reload request sent: %s\n", res->reason); 274a78f83ceSderaadt else 275fa8c3b18Shenning printf("reload request sent.\n"); 2765b1876b6Shenning break; 2775b1876b6Shenning case FIB: 278acd8015aShenning errx(1, "action==FIB"); 2795b1876b6Shenning break; 2805b1876b6Shenning case FIB_COUPLE: 28140466abfSclaudio imsg_compose(imsgbuf, IMSG_CTL_FIB_COUPLE, res->rtableid, 0, -1, 2827f410e5eSclaudio NULL, 0); 2835b1876b6Shenning printf("couple request sent.\n"); 2845b1876b6Shenning done = 1; 2855b1876b6Shenning break; 2865b1876b6Shenning case FIB_DECOUPLE: 28740466abfSclaudio imsg_compose(imsgbuf, IMSG_CTL_FIB_DECOUPLE, res->rtableid, 28840466abfSclaudio 0, -1, NULL, 0); 2895b1876b6Shenning printf("decouple request sent.\n"); 2905b1876b6Shenning done = 1; 2915b1876b6Shenning break; 292ca112d92Shenning case NEIGHBOR: 293acd8015aShenning errx(1, "action==NEIGHBOR"); 294ca112d92Shenning break; 295ca112d92Shenning case NEIGHBOR_UP: 29640466abfSclaudio imsg_compose(imsgbuf, IMSG_CTL_NEIGHBOR_UP, 0, 0, -1, 297fd71c51dShenning &neighbor, sizeof(neighbor)); 298ca112d92Shenning break; 299ca112d92Shenning case NEIGHBOR_DOWN: 30040466abfSclaudio imsg_compose(imsgbuf, IMSG_CTL_NEIGHBOR_DOWN, 0, 0, -1, 301fd71c51dShenning &neighbor, sizeof(neighbor)); 302ca112d92Shenning break; 303e5f05614Shenning case NEIGHBOR_CLEAR: 30440466abfSclaudio imsg_compose(imsgbuf, IMSG_CTL_NEIGHBOR_CLEAR, 0, 0, -1, 305fd71c51dShenning &neighbor, sizeof(neighbor)); 306e5f05614Shenning break; 307846ad25aShenning case NEIGHBOR_RREFRESH: 30840466abfSclaudio imsg_compose(imsgbuf, IMSG_CTL_NEIGHBOR_RREFRESH, 0, 0, -1, 309846ad25aShenning &neighbor, sizeof(neighbor)); 310846ad25aShenning break; 31107820ff6Sclaudio case NEIGHBOR_DESTROY: 31240466abfSclaudio imsg_compose(imsgbuf, IMSG_CTL_NEIGHBOR_DESTROY, 0, 0, -1, 31307820ff6Sclaudio &neighbor, sizeof(neighbor)); 31407820ff6Sclaudio break; 3150ac5a32aSphessler case NETWORK_BULK_ADD: 3160ac5a32aSphessler case NETWORK_BULK_REMOVE: 3170ac5a32aSphessler network_bulk(res); 3180ac5a32aSphessler printf("requests sent.\n"); 3190ac5a32aSphessler done = 1; 3200ac5a32aSphessler break; 321a4cb7d77Sclaudio case NETWORK_ADD: 322a4cb7d77Sclaudio case NETWORK_REMOVE: 3234a99c744Sclaudio memset(&net, 0, sizeof(net)); 32438500be7Sbenno net.prefix = res->addr; 325a4cb7d77Sclaudio net.prefixlen = res->prefixlen; 326a73789d3Sclaudio net.rd = res->rd; 327a4cb7d77Sclaudio /* attribute sets are not supported */ 3286aa205c5Sclaudio if (res->action == NETWORK_ADD) { 32940466abfSclaudio imsg_compose(imsgbuf, IMSG_NETWORK_ADD, 0, 0, -1, 330a4cb7d77Sclaudio &net, sizeof(net)); 33140466abfSclaudio send_filterset(imsgbuf, &res->set); 33240466abfSclaudio imsg_compose(imsgbuf, IMSG_NETWORK_DONE, 0, 0, -1, 3336aa205c5Sclaudio NULL, 0); 3346aa205c5Sclaudio } else 33540466abfSclaudio imsg_compose(imsgbuf, IMSG_NETWORK_REMOVE, 0, 0, -1, 336a4cb7d77Sclaudio &net, sizeof(net)); 337a4cb7d77Sclaudio printf("request sent.\n"); 338a4cb7d77Sclaudio done = 1; 339a4cb7d77Sclaudio break; 340a4cb7d77Sclaudio case NETWORK_FLUSH: 34140466abfSclaudio imsg_compose(imsgbuf, IMSG_NETWORK_FLUSH, 0, 0, -1, NULL, 0); 342a4cb7d77Sclaudio printf("request sent.\n"); 343a4cb7d77Sclaudio done = 1; 344a4cb7d77Sclaudio break; 345a4cb7d77Sclaudio case NETWORK_SHOW: 3464a99c744Sclaudio memset(&ribreq, 0, sizeof(ribreq)); 347536c61dcSclaudio ribreq.aid = res->aid; 348a9a0337fSclaudio strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib)); 34940466abfSclaudio imsg_compose(imsgbuf, IMSG_CTL_SHOW_NETWORK, 0, 0, -1, 3505fe14a4bSclaudio &ribreq, sizeof(ribreq)); 351a4cb7d77Sclaudio break; 352f486926aSclaudio case NETWORK_MRT: 3534a99c744Sclaudio memset(&ribreq, 0, sizeof(ribreq)); 3549efe3de0Sclaudio if (res->as.type != AS_UNDEF) 35538500be7Sbenno ribreq.as = res->as; 356f486926aSclaudio if (res->addr.aid) { 35738500be7Sbenno ribreq.prefix = res->addr; 358f486926aSclaudio ribreq.prefixlen = res->prefixlen; 359f486926aSclaudio } 360187619b8Sclaudio /* XXX currently no community support */ 36138500be7Sbenno ribreq.neighbor = neighbor; 362f486926aSclaudio ribreq.aid = res->aid; 363f486926aSclaudio ribreq.flags = res->flags; 364f486926aSclaudio net_mrt.arg = &ribreq; 365f486926aSclaudio mrt_parse(res->mrtfd, &net_mrt, 1); 366f486926aSclaudio done = 1; 367f486926aSclaudio break; 3685fed6b04Sclaudio case FLOWSPEC_ADD: 3695fed6b04Sclaudio case FLOWSPEC_REMOVE: 370e3925e28Sclaudio f = res_to_flowspec(res); 371e3925e28Sclaudio /* attribute sets are not supported */ 372e3925e28Sclaudio if (res->action == FLOWSPEC_ADD) { 37340466abfSclaudio imsg_compose(imsgbuf, IMSG_FLOWSPEC_ADD, 0, 0, -1, 374e3925e28Sclaudio f, FLOWSPEC_SIZE + f->len); 37540466abfSclaudio send_filterset(imsgbuf, &res->set); 37640466abfSclaudio imsg_compose(imsgbuf, IMSG_FLOWSPEC_DONE, 0, 0, -1, 377e3925e28Sclaudio NULL, 0); 378e3925e28Sclaudio } else 37940466abfSclaudio imsg_compose(imsgbuf, IMSG_FLOWSPEC_REMOVE, 0, 0, -1, 380e3925e28Sclaudio f, FLOWSPEC_SIZE + f->len); 381e3925e28Sclaudio printf("request sent.\n"); 3825fed6b04Sclaudio done = 1; 3835fed6b04Sclaudio break; 3845fed6b04Sclaudio case FLOWSPEC_FLUSH: 38540466abfSclaudio imsg_compose(imsgbuf, IMSG_FLOWSPEC_FLUSH, 0, 0, -1, NULL, 0); 3865fed6b04Sclaudio printf("request sent.\n"); 3875fed6b04Sclaudio done = 1; 3885fed6b04Sclaudio break; 3895fed6b04Sclaudio case FLOWSPEC_SHOW: 3905fed6b04Sclaudio memset(&ribreq, 0, sizeof(ribreq)); 391890b8b5dSclaudio switch (res->aid) { 392890b8b5dSclaudio case AID_INET: 393890b8b5dSclaudio ribreq.aid = AID_FLOWSPECv4; 394890b8b5dSclaudio break; 395890b8b5dSclaudio case AID_INET6: 396890b8b5dSclaudio ribreq.aid = AID_FLOWSPECv6; 397890b8b5dSclaudio break; 398890b8b5dSclaudio case AID_UNSPEC: 3995fed6b04Sclaudio ribreq.aid = res->aid; 400890b8b5dSclaudio break; 401890b8b5dSclaudio default: 402890b8b5dSclaudio errx(1, "flowspec family %s currently not supported", 403890b8b5dSclaudio aid2str(res->aid)); 404890b8b5dSclaudio } 4055fed6b04Sclaudio strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib)); 40640466abfSclaudio imsg_compose(imsgbuf, IMSG_CTL_SHOW_FLOWSPEC, 0, 0, -1, 4075fed6b04Sclaudio &ribreq, sizeof(ribreq)); 4085fed6b04Sclaudio break; 409c3319070Sclaudio case LOG_VERBOSE: 410c3319070Sclaudio verbose = 1; 411c3319070Sclaudio /* FALLTHROUGH */ 412c3319070Sclaudio case LOG_BRIEF: 41340466abfSclaudio imsg_compose(imsgbuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1, 414c3319070Sclaudio &verbose, sizeof(verbose)); 415c3319070Sclaudio printf("logging request sent.\n"); 416c3319070Sclaudio done = 1; 417c3319070Sclaudio break; 418ba6ea253Shenning } 419ba6ea253Shenning 420d30a810dSclaudio output->head(res); 421f084a78cSclaudio 42277a10e6fSclaudio again: 423dd7efffeSclaudio if (imsgbuf_flush(imsgbuf) == -1) 42477a10e6fSclaudio err(1, "write error"); 425f0c28eecShenning 4263d6334e3Shenning while (!done) { 42777a10e6fSclaudio while (!done) { 42840466abfSclaudio if ((n = imsg_get(imsgbuf, &imsg)) == -1) 42909fbff4eSclaudio err(1, "imsg_get error"); 430b733d123Shenning if (n == 0) 431fd0978b9Shenning break; 432c2410a5fShenning 433f084a78cSclaudio done = show(&imsg, res); 434c2410a5fShenning imsg_free(&imsg); 435f084a78cSclaudio } 43677a10e6fSclaudio 43777a10e6fSclaudio if (done) 43877a10e6fSclaudio break; 43977a10e6fSclaudio 440dd7efffeSclaudio if ((n = imsgbuf_read(imsgbuf)) == -1) 441ef2e27a1Sclaudio err(1, "read error"); 44277a10e6fSclaudio if (n == 0) 44377a10e6fSclaudio errx(1, "pipe closed"); 44477a10e6fSclaudio 44577a10e6fSclaudio } 44677a10e6fSclaudio 447cbe08412Sclaudio if (res->action == SHOW_METRICS && --numdone > 0) { 44877a10e6fSclaudio done = 0; 44977a10e6fSclaudio goto again; 450f084a78cSclaudio } 451d30a810dSclaudio 452d30a810dSclaudio output->tail(); 453d30a810dSclaudio 454f084a78cSclaudio close(fd); 45540466abfSclaudio free(imsgbuf); 456f084a78cSclaudio 457f084a78cSclaudio exit(0); 458f084a78cSclaudio } 459f084a78cSclaudio 460f084a78cSclaudio int 461f084a78cSclaudio show(struct imsg *imsg, struct parse_result *res) 462f084a78cSclaudio { 463fbeb5293Sclaudio struct peer p; 46469d2b5abSclaudio struct ctl_timer t; 465fbeb5293Sclaudio struct ctl_show_interface iface; 466fbeb5293Sclaudio struct ctl_show_nexthop nh; 46769d2b5abSclaudio struct ctl_show_set set; 46869d2b5abSclaudio struct ctl_show_rtr rtr; 469fbeb5293Sclaudio struct kroute_full kf; 470fbeb5293Sclaudio struct ktable kt; 471fbeb5293Sclaudio struct flowspec f; 4723e9f8020Sclaudio struct ctl_show_rib rib; 4733e9f8020Sclaudio struct rde_memstats stats; 4744b4c1963Sclaudio struct ibuf ibuf; 475dd147aaaSclaudio u_int rescode; 476f084a78cSclaudio 477f084a78cSclaudio switch (imsg->hdr.type) { 4783e9f8020Sclaudio case IMSG_CTL_SHOW_NEIGHBOR: 47977a10e6fSclaudio if (output->neighbor == NULL) 48077a10e6fSclaudio break; 481fbeb5293Sclaudio if (imsg_get_data(imsg, &p, sizeof(p)) == -1) 482fbeb5293Sclaudio err(1, "imsg_get_data"); 483fbeb5293Sclaudio output->neighbor(&p, res); 4843e9f8020Sclaudio break; 4853e9f8020Sclaudio case IMSG_CTL_SHOW_TIMER: 48677a10e6fSclaudio if (output->timer == NULL) 48777a10e6fSclaudio break; 488fbeb5293Sclaudio if (imsg_get_data(imsg, &t, sizeof(t)) == -1) 489fbeb5293Sclaudio err(1, "imsg_get_data"); 49069d2b5abSclaudio if (t.type > 0 && t.type < Timer_Max) 49169d2b5abSclaudio output->timer(&t); 4923e9f8020Sclaudio break; 4933e9f8020Sclaudio case IMSG_CTL_SHOW_INTERFACE: 49477a10e6fSclaudio if (output->interface == NULL) 49577a10e6fSclaudio break; 496fbeb5293Sclaudio if (imsg_get_data(imsg, &iface, sizeof(iface)) == -1) 497fbeb5293Sclaudio err(1, "imsg_get_data"); 498fbeb5293Sclaudio output->interface(&iface); 4993e9f8020Sclaudio break; 5003e9f8020Sclaudio case IMSG_CTL_SHOW_NEXTHOP: 50177a10e6fSclaudio if (output->nexthop == NULL) 50277a10e6fSclaudio break; 503fbeb5293Sclaudio if (imsg_get_data(imsg, &nh, sizeof(nh)) == -1) 504fbeb5293Sclaudio err(1, "imsg_get_data"); 505fbeb5293Sclaudio output->nexthop(&nh); 5063e9f8020Sclaudio break; 5073e9f8020Sclaudio case IMSG_CTL_KROUTE: 5083e9f8020Sclaudio case IMSG_CTL_SHOW_NETWORK: 50977a10e6fSclaudio if (output->fib == NULL) 51077a10e6fSclaudio break; 511fbeb5293Sclaudio if (imsg_get_data(imsg, &kf, sizeof(kf)) == -1) 512fbeb5293Sclaudio err(1, "imsg_get_data"); 513fbeb5293Sclaudio output->fib(&kf); 5143e9f8020Sclaudio break; 5155fed6b04Sclaudio case IMSG_CTL_SHOW_FLOWSPEC: 5165fed6b04Sclaudio if (output->flowspec == NULL) 5175fed6b04Sclaudio break; 518fbeb5293Sclaudio if (imsg_get_data(imsg, &f, sizeof(f)) == -1) 519fbeb5293Sclaudio err(1, "imsg_get_data"); 520fbeb5293Sclaudio output->flowspec(&f); 5215fed6b04Sclaudio break; 5223e9f8020Sclaudio case IMSG_CTL_SHOW_FIB_TABLES: 52377a10e6fSclaudio if (output->fib_table == NULL) 52477a10e6fSclaudio break; 525fbeb5293Sclaudio if (imsg_get_data(imsg, &kt, sizeof(kt)) == -1) 526fbeb5293Sclaudio err(1, "imsg_get_data"); 527fbeb5293Sclaudio output->fib_table(&kt); 5283e9f8020Sclaudio break; 5293e9f8020Sclaudio case IMSG_CTL_SHOW_RIB: 53077a10e6fSclaudio if (output->rib == NULL) 53177a10e6fSclaudio break; 53246d5331aSclaudio if (imsg_get_ibuf(imsg, &ibuf) == -1) 53346d5331aSclaudio err(1, "imsg_get_ibuf"); 53446d5331aSclaudio if (ibuf_get(&ibuf, &rib, sizeof(rib)) == -1) 53546d5331aSclaudio err(1, "imsg_get_ibuf"); 53646d5331aSclaudio output->rib(&rib, &ibuf, res); 5373e9f8020Sclaudio break; 5383e9f8020Sclaudio case IMSG_CTL_SHOW_RIB_COMMUNITIES: 53977a10e6fSclaudio if (output->communities == NULL) 54077a10e6fSclaudio break; 5414b4c1963Sclaudio if (imsg_get_ibuf(imsg, &ibuf) == -1) 5424b4c1963Sclaudio err(1, "imsg_get_ibuf"); 5434b4c1963Sclaudio output->communities(&ibuf, res); 5443e9f8020Sclaudio break; 5453e9f8020Sclaudio case IMSG_CTL_SHOW_RIB_ATTR: 54677a10e6fSclaudio if (output->attr == NULL) 54777a10e6fSclaudio break; 548dd147aaaSclaudio if (imsg_get_ibuf(imsg, &ibuf) == -1) 549dd147aaaSclaudio err(1, "imsg_get_ibuf"); 550dd147aaaSclaudio output->attr(&ibuf, res->flags, 0); 5513e9f8020Sclaudio break; 5523e9f8020Sclaudio case IMSG_CTL_SHOW_RIB_MEM: 55377a10e6fSclaudio if (output->rib_mem == NULL) 55477a10e6fSclaudio break; 555fbeb5293Sclaudio if (imsg_get_data(imsg, &stats, sizeof(stats)) == -1) 556fbeb5293Sclaudio err(1, "imsg_get_data"); 557d30a810dSclaudio output->rib_mem(&stats); 558374adf67Sclaudio return (1); 559413f97b7Sclaudio case IMSG_CTL_SHOW_SET: 56077a10e6fSclaudio if (output->set == NULL) 56177a10e6fSclaudio break; 562fbeb5293Sclaudio if (imsg_get_data(imsg, &set, sizeof(set)) == -1) 563fbeb5293Sclaudio err(1, "imsg_get_data"); 56469d2b5abSclaudio output->set(&set); 56569d2b5abSclaudio break; 56669d2b5abSclaudio case IMSG_CTL_SHOW_RTR: 56777a10e6fSclaudio if (output->rtr == NULL) 56877a10e6fSclaudio break; 569fbeb5293Sclaudio if (imsg_get_data(imsg, &rtr, sizeof(rtr)) == -1) 570fbeb5293Sclaudio err(1, "imsg_get_data"); 57169d2b5abSclaudio output->rtr(&rtr); 572413f97b7Sclaudio break; 573f084a78cSclaudio case IMSG_CTL_RESULT: 57477a10e6fSclaudio if (output->result == NULL) 57577a10e6fSclaudio break; 576fbeb5293Sclaudio if (imsg_get_data(imsg, &rescode, sizeof(rescode)) == -1) 577fbeb5293Sclaudio err(1, "imsg_get_data"); 578d30a810dSclaudio output->result(rescode); 579f084a78cSclaudio return (1); 580f084a78cSclaudio case IMSG_CTL_END: 581f084a78cSclaudio return (1); 582f084a78cSclaudio default: 5833e9f8020Sclaudio warnx("unknown imsg %d received", imsg->hdr.type); 584f084a78cSclaudio break; 585c2410a5fShenning } 586c2410a5fShenning 5873e9f8020Sclaudio return (0); 588fd0978b9Shenning } 589f85ac724Shenning 590fd18fec4Sclaudio time_t 591fd18fec4Sclaudio get_monotime(time_t t) 592fd18fec4Sclaudio { 593fd18fec4Sclaudio struct timespec ts; 594fd18fec4Sclaudio 595fd18fec4Sclaudio if (t == 0) 596fd18fec4Sclaudio return -1; 597fd18fec4Sclaudio if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) 598fd18fec4Sclaudio err(1, "clock_gettime"); 599fd18fec4Sclaudio if (t > ts.tv_sec) /* time in the future is not possible */ 600fd18fec4Sclaudio t = ts.tv_sec; 601fd18fec4Sclaudio return (ts.tv_sec - t); 602fd18fec4Sclaudio } 603fd18fec4Sclaudio 6042ec7f40eShenning char * 6057e256512Sclaudio fmt_peer(const char *descr, const struct bgpd_addr *remote_addr, 606f084a78cSclaudio int masklen) 6072ec7f40eShenning { 6082ec7f40eShenning const char *ip; 6092ec7f40eShenning char *p; 6102ec7f40eShenning 6113e9f8020Sclaudio if (descr && descr[0] && !nodescr) { 6127e256512Sclaudio if ((p = strdup(descr)) == NULL) 61378d6515aSclaudio err(1, NULL); 6142ec7f40eShenning return (p); 6152ec7f40eShenning } 6162ec7f40eShenning 6177e256512Sclaudio ip = log_addr(remote_addr); 618b26dd4adSclaudio if (masklen != -1 && ((remote_addr->aid == AID_INET && masklen != 32) || 619b26dd4adSclaudio (remote_addr->aid == AID_INET6 && masklen != 128))) { 6207e256512Sclaudio if (asprintf(&p, "%s/%u", ip, masklen) == -1) 62178d6515aSclaudio err(1, NULL); 6222ec7f40eShenning } else { 6232ec7f40eShenning if ((p = strdup(ip)) == NULL) 62478d6515aSclaudio err(1, NULL); 6252ec7f40eShenning } 6262ec7f40eShenning 6272ec7f40eShenning return (p); 6282ec7f40eShenning } 6292ec7f40eShenning 6303d210dfcSphessler const char * 63104d0a88fSclaudio fmt_auth_method(enum auth_method method) 6323d210dfcSphessler { 6333d210dfcSphessler switch (method) { 6343d210dfcSphessler case AUTH_MD5SIG: 6353d210dfcSphessler return ", using md5sig"; 6363d210dfcSphessler case AUTH_IPSEC_MANUAL_ESP: 6373d210dfcSphessler return ", using ipsec manual esp"; 6383d210dfcSphessler case AUTH_IPSEC_MANUAL_AH: 6393d210dfcSphessler return ", using ipsec manual ah"; 6403d210dfcSphessler case AUTH_IPSEC_IKE_ESP: 6413d210dfcSphessler return ", using ipsec ike esp"; 6423d210dfcSphessler case AUTH_IPSEC_IKE_AH: 6433d210dfcSphessler return ", using ipsec ike ah"; 6443d210dfcSphessler case AUTH_NONE: /* FALLTHROUGH */ 6453d210dfcSphessler default: 6463d210dfcSphessler return ""; 6473d210dfcSphessler } 6483d210dfcSphessler } 6493d210dfcSphessler 65081dd5016Sclaudio #define TF_LEN 16 651c5b029bbShenning 652e67b1a58Sclaudio const char * 653e67b1a58Sclaudio fmt_timeframe(time_t t) 654ed99340cShenning { 65581dd5016Sclaudio static char buf[TF_LEN]; 656035b0708Sgilles unsigned int sec, min, hrs, day; 657035b0708Sgilles unsigned long long week; 658c5b029bbShenning 65981dd5016Sclaudio if (t < 0) 66081dd5016Sclaudio t = 0; 661ed99340cShenning week = t; 662c5b029bbShenning 663c5b029bbShenning sec = week % 60; 664c5b029bbShenning week /= 60; 665c5b029bbShenning min = week % 60; 666c5b029bbShenning week /= 60; 667c5b029bbShenning hrs = week % 24; 668c5b029bbShenning week /= 24; 669c5b029bbShenning day = week % 7; 670c5b029bbShenning week /= 7; 671c5b029bbShenning 67281dd5016Sclaudio if (week >= 1000) 67381dd5016Sclaudio snprintf(buf, TF_LEN, "%02lluw", week); 67481dd5016Sclaudio else if (week > 0) 675035b0708Sgilles snprintf(buf, TF_LEN, "%02lluw%01ud%02uh", week, day, hrs); 676c5b029bbShenning else if (day > 0) 677c5b029bbShenning snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min); 678c5b029bbShenning else 679c5b029bbShenning snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec); 680c5b029bbShenning 681c5b029bbShenning return (buf); 682c5b029bbShenning } 683b66d179dShenning 684da270b4dSclaudio const char * 685e67b1a58Sclaudio fmt_monotime(time_t t) 686da270b4dSclaudio { 687fd18fec4Sclaudio t = get_monotime(t); 688da270b4dSclaudio 689fd18fec4Sclaudio if (t == -1) 690da270b4dSclaudio return ("Never"); 691da270b4dSclaudio 692fd18fec4Sclaudio return (fmt_timeframe(t)); 693da270b4dSclaudio } 694da270b4dSclaudio 69504d0a88fSclaudio const char * 69659154960Sclaudio fmt_fib_flags(uint16_t flags) 697b5908c68Shenning { 69804d0a88fSclaudio static char buf[8]; 69904d0a88fSclaudio 700ef0c8610Sclaudio if (flags & F_BGPD) 7010d49b5f3Sclaudio strlcpy(buf, "B", sizeof(buf)); 702b5908c68Shenning else if (flags & F_CONNECTED) 7030d49b5f3Sclaudio strlcpy(buf, "C", sizeof(buf)); 704b5908c68Shenning else if (flags & F_STATIC) 7050d49b5f3Sclaudio strlcpy(buf, "S", sizeof(buf)); 706b5908c68Shenning else 7070d49b5f3Sclaudio strlcpy(buf, " ", sizeof(buf)); 708b5908c68Shenning 709b5908c68Shenning if (flags & F_NEXTHOP) 71004d0a88fSclaudio strlcat(buf, "N", sizeof(buf)); 711b5908c68Shenning else 71204d0a88fSclaudio strlcat(buf, " ", sizeof(buf)); 713b5908c68Shenning 714b5908c68Shenning if (flags & F_REJECT && flags & F_BLACKHOLE) 71504d0a88fSclaudio strlcat(buf, "f", sizeof(buf)); 716b5908c68Shenning else if (flags & F_REJECT) 71704d0a88fSclaudio strlcat(buf, "r", sizeof(buf)); 718b5908c68Shenning else if (flags & F_BLACKHOLE) 71904d0a88fSclaudio strlcat(buf, "b", sizeof(buf)); 720b5908c68Shenning else 72104d0a88fSclaudio strlcat(buf, " ", sizeof(buf)); 722b5908c68Shenning 72304d0a88fSclaudio return buf; 7247b6c56a0Sclaudio } 7257b6c56a0Sclaudio 7267b6c56a0Sclaudio const char * 72759154960Sclaudio fmt_origin(uint8_t origin, int sum) 7287b6c56a0Sclaudio { 7297b6c56a0Sclaudio switch (origin) { 7307b6c56a0Sclaudio case ORIGIN_IGP: 7317b6c56a0Sclaudio return (sum ? "i" : "IGP"); 7327b6c56a0Sclaudio case ORIGIN_EGP: 7337b6c56a0Sclaudio return (sum ? "e" : "EGP"); 7347b6c56a0Sclaudio case ORIGIN_INCOMPLETE: 7357b6c56a0Sclaudio return (sum ? "?" : "incomplete"); 7367b6c56a0Sclaudio default: 7377b6c56a0Sclaudio return (sum ? "X" : "bad origin"); 7387b6c56a0Sclaudio } 7397b6c56a0Sclaudio } 7407b6c56a0Sclaudio 74104d0a88fSclaudio const char * 7422953a2c1Sclaudio fmt_flags(uint32_t flags, int sum) 74373d4348fSclaudio { 74404d0a88fSclaudio static char buf[80]; 74573d4348fSclaudio char flagstr[5]; 74673d4348fSclaudio char *p = flagstr; 74773d4348fSclaudio 74873d4348fSclaudio if (sum) { 74909b2f24cSclaudio if (flags & F_PREF_FILTERED) 75009b2f24cSclaudio *p++ = 'F'; 75179dfb877Sclaudio if (flags & F_PREF_INVALID) 75279dfb877Sclaudio *p++ = 'E'; 75312abdda6Sclaudio if (flags & F_PREF_OTC_LEAK) 754135bf897Sclaudio *p++ = 'L'; 7557f410e5eSclaudio if (flags & F_PREF_ANNOUNCE) 75673d4348fSclaudio *p++ = 'A'; 7577f410e5eSclaudio if (flags & F_PREF_INTERNAL) 75873d4348fSclaudio *p++ = 'I'; 7596d93a853Sclaudio if (flags & F_PREF_STALE) 7606d93a853Sclaudio *p++ = 'S'; 7617f410e5eSclaudio if (flags & F_PREF_ELIGIBLE) 76273d4348fSclaudio *p++ = '*'; 7634ff57d1dSclaudio if (flags & F_PREF_BEST) 76473d4348fSclaudio *p++ = '>'; 7652953a2c1Sclaudio if (flags & F_PREF_ECMP) 7662953a2c1Sclaudio *p++ = 'm'; 7672953a2c1Sclaudio if (flags & F_PREF_AS_WIDE) 7682953a2c1Sclaudio *p++ = 'w'; 76973d4348fSclaudio *p = '\0'; 77004d0a88fSclaudio snprintf(buf, sizeof(buf), "%-5s", flagstr); 77173d4348fSclaudio } else { 7727f410e5eSclaudio if (flags & F_PREF_INTERNAL) 77304d0a88fSclaudio strlcpy(buf, "internal", sizeof(buf)); 77473d4348fSclaudio else 77504d0a88fSclaudio strlcpy(buf, "external", sizeof(buf)); 77604d0a88fSclaudio 77709b2f24cSclaudio if (flags & F_PREF_FILTERED) 77809b2f24cSclaudio strlcat(buf, ", filtered", sizeof(buf)); 779135bf897Sclaudio if (flags & F_PREF_INVALID) 780135bf897Sclaudio strlcat(buf, ", invalid", sizeof(buf)); 78112abdda6Sclaudio if (flags & F_PREF_OTC_LEAK) 78212abdda6Sclaudio strlcat(buf, ", otc leak", sizeof(buf)); 7836d93a853Sclaudio if (flags & F_PREF_STALE) 78404d0a88fSclaudio strlcat(buf, ", stale", sizeof(buf)); 7857f410e5eSclaudio if (flags & F_PREF_ELIGIBLE) 78604d0a88fSclaudio strlcat(buf, ", valid", sizeof(buf)); 7874ff57d1dSclaudio if (flags & F_PREF_BEST) 78804d0a88fSclaudio strlcat(buf, ", best", sizeof(buf)); 7892953a2c1Sclaudio if (flags & F_PREF_ECMP) 7902953a2c1Sclaudio strlcat(buf, ", ecmp", sizeof(buf)); 7912953a2c1Sclaudio if (flags & F_PREF_AS_WIDE) 7922953a2c1Sclaudio strlcat(buf, ", as-wide", sizeof(buf)); 7937f410e5eSclaudio if (flags & F_PREF_ANNOUNCE) 79404d0a88fSclaudio strlcat(buf, ", announced", sizeof(buf)); 79504d0a88fSclaudio if (strlen(buf) >= sizeof(buf) - 1) 79604d0a88fSclaudio errx(1, "%s buffer too small", __func__); 79773d4348fSclaudio } 79804d0a88fSclaudio 79904d0a88fSclaudio return buf; 80073d4348fSclaudio } 80173d4348fSclaudio 8022f429709Sjob const char * 80359154960Sclaudio fmt_ovs(uint8_t validation_state, int sum) 8042f429709Sjob { 8052f429709Sjob switch (validation_state) { 8062f429709Sjob case ROA_INVALID: 8072f429709Sjob return (sum ? "!" : "invalid"); 8082f429709Sjob case ROA_VALID: 8092f429709Sjob return (sum ? "V" : "valid"); 8102f429709Sjob default: 8112f429709Sjob return (sum ? "N" : "not-found"); 8122f429709Sjob } 8132f429709Sjob } 8142f429709Sjob 81504d0a88fSclaudio const char * 81650d35cacSclaudio fmt_avs(uint8_t validation_state, int sum) 81750d35cacSclaudio { 81850d35cacSclaudio switch (validation_state) { 81950d35cacSclaudio case ASPA_INVALID: 82050d35cacSclaudio return (sum ? "!" : "invalid"); 82150d35cacSclaudio case ASPA_VALID: 82250d35cacSclaudio return (sum ? "V" : "valid"); 82350d35cacSclaudio default: 82450d35cacSclaudio return (sum ? "?" : "unknown"); 82550d35cacSclaudio } 82650d35cacSclaudio } 82750d35cacSclaudio 82850d35cacSclaudio const char * 82904d0a88fSclaudio fmt_mem(long long num) 83004d0a88fSclaudio { 83104d0a88fSclaudio static char buf[16]; 83204d0a88fSclaudio 83304d0a88fSclaudio if (fmt_scaled(num, buf) == -1) 83404d0a88fSclaudio snprintf(buf, sizeof(buf), "%lldB", num); 83504d0a88fSclaudio 83604d0a88fSclaudio return (buf); 83704d0a88fSclaudio } 83804d0a88fSclaudio 83904d0a88fSclaudio const char * 84059154960Sclaudio fmt_errstr(uint8_t errcode, uint8_t subcode) 84104d0a88fSclaudio { 84204d0a88fSclaudio static char errbuf[256]; 84304d0a88fSclaudio const char *errstr = NULL; 84404d0a88fSclaudio const char *suberr = NULL; 84504d0a88fSclaudio int uk = 0; 84604d0a88fSclaudio 84704d0a88fSclaudio if (errcode == 0) /* no error */ 84804d0a88fSclaudio return NULL; 84904d0a88fSclaudio 85004d0a88fSclaudio if (errcode < sizeof(errnames)/sizeof(char *)) 85104d0a88fSclaudio errstr = errnames[errcode]; 85204d0a88fSclaudio 85304d0a88fSclaudio switch (errcode) { 85404d0a88fSclaudio case ERR_HEADER: 85504d0a88fSclaudio if (subcode < sizeof(suberr_header_names)/sizeof(char *)) 85604d0a88fSclaudio suberr = suberr_header_names[subcode]; 85704d0a88fSclaudio else 85804d0a88fSclaudio uk = 1; 85904d0a88fSclaudio break; 86004d0a88fSclaudio case ERR_OPEN: 86104d0a88fSclaudio if (subcode < sizeof(suberr_open_names)/sizeof(char *)) 86204d0a88fSclaudio suberr = suberr_open_names[subcode]; 86304d0a88fSclaudio else 86404d0a88fSclaudio uk = 1; 86504d0a88fSclaudio break; 86604d0a88fSclaudio case ERR_UPDATE: 86704d0a88fSclaudio if (subcode < sizeof(suberr_update_names)/sizeof(char *)) 86804d0a88fSclaudio suberr = suberr_update_names[subcode]; 86904d0a88fSclaudio else 87004d0a88fSclaudio uk = 1; 87104d0a88fSclaudio break; 87204d0a88fSclaudio case ERR_HOLDTIMEREXPIRED: 87304d0a88fSclaudio if (subcode != 0) 87404d0a88fSclaudio uk = 1; 87504d0a88fSclaudio break; 87604d0a88fSclaudio case ERR_FSM: 87704d0a88fSclaudio if (subcode < sizeof(suberr_fsm_names)/sizeof(char *)) 87804d0a88fSclaudio suberr = suberr_fsm_names[subcode]; 87904d0a88fSclaudio else 88004d0a88fSclaudio uk = 1; 88104d0a88fSclaudio break; 88204d0a88fSclaudio case ERR_CEASE: 88304d0a88fSclaudio if (subcode < sizeof(suberr_cease_names)/sizeof(char *)) 88404d0a88fSclaudio suberr = suberr_cease_names[subcode]; 88504d0a88fSclaudio else 88604d0a88fSclaudio uk = 1; 88704d0a88fSclaudio break; 88804d0a88fSclaudio default: 88904d0a88fSclaudio snprintf(errbuf, sizeof(errbuf), 89004d0a88fSclaudio "unknown error code %u subcode %u", errcode, subcode); 89104d0a88fSclaudio return (errbuf); 89204d0a88fSclaudio } 89304d0a88fSclaudio 89404d0a88fSclaudio if (uk) 89504d0a88fSclaudio snprintf(errbuf, sizeof(errbuf), 89604d0a88fSclaudio "%s, unknown subcode %u", errstr, subcode); 89704d0a88fSclaudio else if (suberr == NULL) 89804d0a88fSclaudio return (errstr); 89904d0a88fSclaudio else 90004d0a88fSclaudio snprintf(errbuf, sizeof(errbuf), 90104d0a88fSclaudio "%s, %s", errstr, suberr); 90204d0a88fSclaudio 90304d0a88fSclaudio return (errbuf); 90404d0a88fSclaudio } 90504d0a88fSclaudio 90604d0a88fSclaudio const char * 90759154960Sclaudio fmt_attr(uint8_t type, int flags) 90847c6720fSclaudio { 90947c6720fSclaudio #define CHECK_FLAGS(s, t, m) \ 91047c6720fSclaudio if (((s) & ~(ATTR_DEFMASK | (m))) != (t)) pflags = 1 91147c6720fSclaudio 91247c6720fSclaudio static char cstr[48]; 91347c6720fSclaudio int pflags = 0; 91447c6720fSclaudio 91547c6720fSclaudio switch (type) { 91647c6720fSclaudio case ATTR_ORIGIN: 91747c6720fSclaudio CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 91847c6720fSclaudio strlcpy(cstr, "Origin", sizeof(cstr)); 91947c6720fSclaudio break; 92047c6720fSclaudio case ATTR_ASPATH: 92147c6720fSclaudio CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 92247c6720fSclaudio strlcpy(cstr, "AS-Path", sizeof(cstr)); 92347c6720fSclaudio break; 92447c6720fSclaudio case ATTR_AS4_PATH: 92547c6720fSclaudio CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 92647c6720fSclaudio strlcpy(cstr, "AS4-Path", sizeof(cstr)); 92747c6720fSclaudio break; 92847c6720fSclaudio case ATTR_NEXTHOP: 92947c6720fSclaudio CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 93047c6720fSclaudio strlcpy(cstr, "Nexthop", sizeof(cstr)); 93147c6720fSclaudio break; 93247c6720fSclaudio case ATTR_MED: 93347c6720fSclaudio CHECK_FLAGS(flags, ATTR_OPTIONAL, 0); 93447c6720fSclaudio strlcpy(cstr, "Med", sizeof(cstr)); 93547c6720fSclaudio break; 93647c6720fSclaudio case ATTR_LOCALPREF: 93747c6720fSclaudio CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 93847c6720fSclaudio strlcpy(cstr, "Localpref", sizeof(cstr)); 93947c6720fSclaudio break; 94047c6720fSclaudio case ATTR_ATOMIC_AGGREGATE: 94147c6720fSclaudio CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0); 94247c6720fSclaudio strlcpy(cstr, "Atomic Aggregate", sizeof(cstr)); 94347c6720fSclaudio break; 94447c6720fSclaudio case ATTR_AGGREGATOR: 94547c6720fSclaudio CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL); 94647c6720fSclaudio strlcpy(cstr, "Aggregator", sizeof(cstr)); 94747c6720fSclaudio break; 94847c6720fSclaudio case ATTR_AS4_AGGREGATOR: 94947c6720fSclaudio CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL); 95047c6720fSclaudio strlcpy(cstr, "AS4-Aggregator", sizeof(cstr)); 95147c6720fSclaudio break; 95247c6720fSclaudio case ATTR_COMMUNITIES: 95347c6720fSclaudio CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL); 95447c6720fSclaudio strlcpy(cstr, "Communities", sizeof(cstr)); 95547c6720fSclaudio break; 95647c6720fSclaudio case ATTR_ORIGINATOR_ID: 95747c6720fSclaudio CHECK_FLAGS(flags, ATTR_OPTIONAL, 0); 95847c6720fSclaudio strlcpy(cstr, "Originator Id", sizeof(cstr)); 95947c6720fSclaudio break; 96047c6720fSclaudio case ATTR_CLUSTER_LIST: 96147c6720fSclaudio CHECK_FLAGS(flags, ATTR_OPTIONAL, 0); 96247c6720fSclaudio strlcpy(cstr, "Cluster Id List", sizeof(cstr)); 96347c6720fSclaudio break; 96447c6720fSclaudio case ATTR_MP_REACH_NLRI: 96547c6720fSclaudio CHECK_FLAGS(flags, ATTR_OPTIONAL, 0); 96647c6720fSclaudio strlcpy(cstr, "MP Reach NLRI", sizeof(cstr)); 96747c6720fSclaudio break; 96847c6720fSclaudio case ATTR_MP_UNREACH_NLRI: 96947c6720fSclaudio CHECK_FLAGS(flags, ATTR_OPTIONAL, 0); 97047c6720fSclaudio strlcpy(cstr, "MP Unreach NLRI", sizeof(cstr)); 97147c6720fSclaudio break; 97247c6720fSclaudio case ATTR_EXT_COMMUNITIES: 97347c6720fSclaudio CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL); 97447c6720fSclaudio strlcpy(cstr, "Ext. Communities", sizeof(cstr)); 97547c6720fSclaudio break; 97647c6720fSclaudio case ATTR_LARGE_COMMUNITIES: 97747c6720fSclaudio CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL); 97847c6720fSclaudio strlcpy(cstr, "Large Communities", sizeof(cstr)); 97947c6720fSclaudio break; 980135bf897Sclaudio case ATTR_OTC: 981135bf897Sclaudio CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL); 982135bf897Sclaudio strlcpy(cstr, "OTC", sizeof(cstr)); 983135bf897Sclaudio break; 98447c6720fSclaudio default: 98547c6720fSclaudio /* ignore unknown attributes */ 98647c6720fSclaudio snprintf(cstr, sizeof(cstr), "Unknown Attribute #%u", type); 98747c6720fSclaudio pflags = 1; 98847c6720fSclaudio break; 98947c6720fSclaudio } 990a47383e2Sclaudio if (flags != -1 && pflags) { 99147c6720fSclaudio strlcat(cstr, " flags [", sizeof(cstr)); 99247c6720fSclaudio if (flags & ATTR_OPTIONAL) 99347c6720fSclaudio strlcat(cstr, "O", sizeof(cstr)); 99447c6720fSclaudio if (flags & ATTR_TRANSITIVE) 99547c6720fSclaudio strlcat(cstr, "T", sizeof(cstr)); 99647c6720fSclaudio if (flags & ATTR_PARTIAL) 99747c6720fSclaudio strlcat(cstr, "P", sizeof(cstr)); 99847c6720fSclaudio strlcat(cstr, "]", sizeof(cstr)); 99947c6720fSclaudio } 100047c6720fSclaudio return (cstr); 100147c6720fSclaudio 100247c6720fSclaudio #undef CHECK_FLAGS 100347c6720fSclaudio } 100447c6720fSclaudio 100504d0a88fSclaudio const char * 100659154960Sclaudio fmt_community(uint16_t a, uint16_t v) 1007a20554fdSclaudio { 100804d0a88fSclaudio static char buf[12]; 1009a20554fdSclaudio 101073d4348fSclaudio if (a == COMMUNITY_WELLKNOWN) 101173d4348fSclaudio switch (v) { 101215406510Sphessler case COMMUNITY_GRACEFUL_SHUTDOWN: 101304d0a88fSclaudio return "GRACEFUL_SHUTDOWN"; 101473d4348fSclaudio case COMMUNITY_NO_EXPORT: 101504d0a88fSclaudio return "NO_EXPORT"; 101673d4348fSclaudio case COMMUNITY_NO_ADVERTISE: 101704d0a88fSclaudio return "NO_ADVERTISE"; 101873d4348fSclaudio case COMMUNITY_NO_EXPSUBCONFED: 101904d0a88fSclaudio return "NO_EXPORT_SUBCONFED"; 102073d4348fSclaudio case COMMUNITY_NO_PEER: 102104d0a88fSclaudio return "NO_PEER"; 102217c84f89Ssthen case COMMUNITY_BLACKHOLE: 102304d0a88fSclaudio return "BLACKHOLE"; 102473d4348fSclaudio default: 102573d4348fSclaudio break; 102673d4348fSclaudio } 102773d4348fSclaudio 102804d0a88fSclaudio snprintf(buf, sizeof(buf), "%hu:%hu", a, v); 102904d0a88fSclaudio return buf; 103004d0a88fSclaudio } 103104d0a88fSclaudio 103204d0a88fSclaudio const char * 103359154960Sclaudio fmt_large_community(uint32_t d1, uint32_t d2, uint32_t d3) 10340ca99656Sclaudio { 103504d0a88fSclaudio static char buf[33]; 103604d0a88fSclaudio 103704d0a88fSclaudio snprintf(buf, sizeof(buf), "%u:%u:%u", d1, d2, d3); 103804d0a88fSclaudio return buf; 103904d0a88fSclaudio } 104004d0a88fSclaudio 104104d0a88fSclaudio const char * 10424b4c1963Sclaudio fmt_ext_community(uint64_t ext) 104304d0a88fSclaudio { 104404d0a88fSclaudio static char buf[32]; 10450ca99656Sclaudio struct in_addr ip; 104659154960Sclaudio uint32_t as4, u32; 104759154960Sclaudio uint16_t as2, u16; 104859154960Sclaudio uint8_t type, subtype; 10490ca99656Sclaudio 10504b4c1963Sclaudio type = ext >> 56; 10514b4c1963Sclaudio subtype = ext >> 48; 10520ca99656Sclaudio 10530ca99656Sclaudio switch (type) { 10540ca99656Sclaudio case EXT_COMMUNITY_TRANS_TWO_AS: 1055c2371130Sclaudio case EXT_COMMUNITY_GEN_TWO_AS: 10564b4c1963Sclaudio as2 = ext >> 32; 10574b4c1963Sclaudio u32 = ext; 105804d0a88fSclaudio snprintf(buf, sizeof(buf), "%s %s:%u", 10594b4c1963Sclaudio log_ext_subtype(type, subtype), log_as(as2), u32); 106004d0a88fSclaudio return buf; 10610ca99656Sclaudio case EXT_COMMUNITY_TRANS_IPV4: 1062c2371130Sclaudio case EXT_COMMUNITY_GEN_IPV4: 10634b4c1963Sclaudio ip.s_addr = htonl(ext >> 16); 10644b4c1963Sclaudio u16 = ext; 106504d0a88fSclaudio snprintf(buf, sizeof(buf), "%s %s:%hu", 10664b4c1963Sclaudio log_ext_subtype(type, subtype), inet_ntoa(ip), u16); 106704d0a88fSclaudio return buf; 10680ca99656Sclaudio case EXT_COMMUNITY_TRANS_FOUR_AS: 1069c2371130Sclaudio case EXT_COMMUNITY_GEN_FOUR_AS: 10704b4c1963Sclaudio as4 = ext >> 16; 10714b4c1963Sclaudio u16 = ext; 107204d0a88fSclaudio snprintf(buf, sizeof(buf), "%s %s:%hu", 10734b4c1963Sclaudio log_ext_subtype(type, subtype), log_as(as4), u16); 107404d0a88fSclaudio return buf; 10750ca99656Sclaudio case EXT_COMMUNITY_TRANS_OPAQUE: 10760ca99656Sclaudio case EXT_COMMUNITY_TRANS_EVPN: 10774b4c1963Sclaudio ext &= 0xffffffffffffULL; 107804d0a88fSclaudio snprintf(buf, sizeof(buf), "%s 0x%llx", 107904d0a88fSclaudio log_ext_subtype(type, subtype), (unsigned long long)ext); 108004d0a88fSclaudio return buf; 10810ca99656Sclaudio case EXT_COMMUNITY_NON_TRANS_OPAQUE: 10824b4c1963Sclaudio ext &= 0xffffffffffffULL; 1083c2371130Sclaudio if (subtype == EXT_COMMUNITY_SUBTYPE_OVS) { 10840ca99656Sclaudio switch (ext) { 10850ca99656Sclaudio case EXT_COMMUNITY_OVS_VALID: 108604d0a88fSclaudio snprintf(buf, sizeof(buf), "%s valid", 108704d0a88fSclaudio log_ext_subtype(type, subtype)); 108804d0a88fSclaudio return buf; 10890ca99656Sclaudio case EXT_COMMUNITY_OVS_NOTFOUND: 109004d0a88fSclaudio snprintf(buf, sizeof(buf), "%s not-found", 109104d0a88fSclaudio log_ext_subtype(type, subtype)); 109204d0a88fSclaudio return buf; 10930ca99656Sclaudio case EXT_COMMUNITY_OVS_INVALID: 109404d0a88fSclaudio snprintf(buf, sizeof(buf), "%s invalid", 109504d0a88fSclaudio log_ext_subtype(type, subtype)); 109604d0a88fSclaudio return buf; 10970ca99656Sclaudio default: 109804d0a88fSclaudio snprintf(buf, sizeof(buf), "%s 0x%llx", 109904d0a88fSclaudio log_ext_subtype(type, subtype), 110004d0a88fSclaudio (unsigned long long)ext); 110104d0a88fSclaudio return buf; 11020ca99656Sclaudio } 1103c2371130Sclaudio } else { 1104c2371130Sclaudio snprintf(buf, sizeof(buf), "%s 0x%llx", 1105c2371130Sclaudio log_ext_subtype(type, subtype), 1106c2371130Sclaudio (unsigned long long)ext); 1107c2371130Sclaudio return buf; 1108c2371130Sclaudio } 11090ca99656Sclaudio break; 11100ca99656Sclaudio default: 11114b4c1963Sclaudio snprintf(buf, sizeof(buf), "0x%llx", (unsigned long long)ext); 111204d0a88fSclaudio return buf; 11130ca99656Sclaudio } 11140ca99656Sclaudio } 11150ca99656Sclaudio 1116413f97b7Sclaudio const char * 1117413f97b7Sclaudio fmt_set_type(struct ctl_show_set *set) 1118413f97b7Sclaudio { 1119413f97b7Sclaudio switch (set->type) { 1120c4f772fdSclaudio case ASPA_SET: 1121c4f772fdSclaudio return "ASPA"; 1122413f97b7Sclaudio case ROA_SET: 1123413f97b7Sclaudio return "ROA"; 1124413f97b7Sclaudio case PREFIX_SET: 1125413f97b7Sclaudio return "PREFIX"; 1126413f97b7Sclaudio case ORIGIN_SET: 1127413f97b7Sclaudio return "ORIGIN"; 1128413f97b7Sclaudio case ASNUM_SET: 1129413f97b7Sclaudio return "ASNUM"; 1130413f97b7Sclaudio default: 1131413f97b7Sclaudio return "BULA"; 1132413f97b7Sclaudio } 1133413f97b7Sclaudio } 1134413f97b7Sclaudio 11350ca99656Sclaudio void 11369caec0aeSclaudio send_filterset(struct imsgbuf *i, struct filter_set_head *set) 11379caec0aeSclaudio { 11389caec0aeSclaudio struct filter_set *s; 11399caec0aeSclaudio 114038cb626eSfgsch while ((s = TAILQ_FIRST(set)) != NULL) { 11419caec0aeSclaudio imsg_compose(i, IMSG_FILTER_SET, 0, 0, -1, s, 11429caec0aeSclaudio sizeof(struct filter_set)); 114338cb626eSfgsch TAILQ_REMOVE(set, s, entry); 11449caec0aeSclaudio free(s); 11459caec0aeSclaudio } 11469caec0aeSclaudio } 11479caec0aeSclaudio 1148a20554fdSclaudio void 11490ac5a32aSphessler network_bulk(struct parse_result *res) 11500ac5a32aSphessler { 11510ac5a32aSphessler struct network_config net; 11520ac5a32aSphessler struct filter_set *s = NULL; 11530ac5a32aSphessler struct bgpd_addr h; 11541ce75666Sclaudio char *line = NULL; 11551ce75666Sclaudio size_t linesize = 0; 11561ce75666Sclaudio ssize_t linelen; 115759154960Sclaudio uint8_t len; 11580ac5a32aSphessler FILE *f; 11590ac5a32aSphessler 11601ce75666Sclaudio if ((f = fdopen(STDIN_FILENO, "r")) == NULL) 11611ce75666Sclaudio err(1, "Failed to open stdin\n"); 11620ac5a32aSphessler 11631ce75666Sclaudio while ((linelen = getline(&line, &linesize, f)) != -1) { 11641ce75666Sclaudio char *b, *buf = line; 11651ce75666Sclaudio while ((b = strsep(&buf, " \t\n")) != NULL) { 11661ce75666Sclaudio if (*b == '\0') /* skip empty tokens */ 11671ce75666Sclaudio continue; 11681ce75666Sclaudio /* Stop processing after a comment */ 11691ce75666Sclaudio if (*b == '#') 11700ac5a32aSphessler break; 11714a99c744Sclaudio memset(&net, 0, sizeof(net)); 11721ce75666Sclaudio if (parse_prefix(b, strlen(b), &h, &len) != 1) 11731ce75666Sclaudio errx(1, "bad prefix: %s", b); 117438500be7Sbenno net.prefix = h; 11750ac5a32aSphessler net.prefixlen = len; 1176a73789d3Sclaudio net.rd = res->rd; 11770ac5a32aSphessler 11780ac5a32aSphessler if (res->action == NETWORK_BULK_ADD) { 117940466abfSclaudio imsg_compose(imsgbuf, IMSG_NETWORK_ADD, 11800ac5a32aSphessler 0, 0, -1, &net, sizeof(net)); 1181143a9790Sclaudio /* 1182143a9790Sclaudio * can't use send_filterset since that 1183143a9790Sclaudio * would free the set. 1184143a9790Sclaudio */ 11850ac5a32aSphessler TAILQ_FOREACH(s, &res->set, entry) { 118640466abfSclaudio imsg_compose(imsgbuf, 11870ac5a32aSphessler IMSG_FILTER_SET, 11880ac5a32aSphessler 0, 0, -1, s, sizeof(*s)); 11890ac5a32aSphessler } 119040466abfSclaudio imsg_compose(imsgbuf, IMSG_NETWORK_DONE, 11910ac5a32aSphessler 0, 0, -1, NULL, 0); 11920ac5a32aSphessler } else 119340466abfSclaudio imsg_compose(imsgbuf, IMSG_NETWORK_REMOVE, 11940ac5a32aSphessler 0, 0, -1, &net, sizeof(net)); 11950ac5a32aSphessler } 11960ac5a32aSphessler } 11971ce75666Sclaudio free(line); 11981ce75666Sclaudio if (ferror(f)) 11991ce75666Sclaudio err(1, "getline"); 12000ac5a32aSphessler fclose(f); 12010ac5a32aSphessler } 12020ac5a32aSphessler 12030ac5a32aSphessler void 1204b5cff06cSclaudio show_mrt_dump_neighbors(struct mrt_rib *mr, struct mrt_peer *mp, void *arg) 1205b5cff06cSclaudio { 1206b5cff06cSclaudio struct mrt_peer_entry *p; 1207b5cff06cSclaudio struct in_addr ina; 120859154960Sclaudio uint16_t i; 1209b5cff06cSclaudio 1210b5cff06cSclaudio ina.s_addr = htonl(mp->bgp_id); 1211b5cff06cSclaudio printf("view: %s BGP ID: %s Number of peers: %u\n\n", 1212b5cff06cSclaudio mp->view, inet_ntoa(ina), mp->npeers); 1213b5cff06cSclaudio printf("%-30s %8s %15s\n", "Neighbor", "AS", "BGP ID"); 1214b5cff06cSclaudio for (i = 0; i < mp->npeers; i++) { 1215b5cff06cSclaudio p = &mp->peers[i]; 1216b5cff06cSclaudio ina.s_addr = htonl(p->bgp_id); 1217b5cff06cSclaudio printf("%-30s %8u %15s\n", log_addr(&p->addr), p->asnum, 1218b5cff06cSclaudio inet_ntoa(ina)); 1219b5cff06cSclaudio } 1220b5cff06cSclaudio /* we only print the first message */ 1221b5cff06cSclaudio exit(0); 1222b5cff06cSclaudio } 1223b5cff06cSclaudio 1224b5cff06cSclaudio void 1225a20554fdSclaudio show_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg) 1226a20554fdSclaudio { 1227a20554fdSclaudio struct ctl_show_rib ctl; 1228a069aa25Sclaudio struct parse_result res; 1229a20554fdSclaudio struct ctl_show_rib_request *req = arg; 1230a20554fdSclaudio struct mrt_rib_entry *mre; 123146d5331aSclaudio struct ibuf ibuf; 1232e67b1a58Sclaudio time_t now; 123359154960Sclaudio uint16_t i, j; 1234a20554fdSclaudio 1235a069aa25Sclaudio memset(&res, 0, sizeof(res)); 1236a069aa25Sclaudio res.flags = req->flags; 1237e67b1a58Sclaudio now = time(NULL); 1238a069aa25Sclaudio 1239a20554fdSclaudio for (i = 0; i < mr->nentries; i++) { 1240a20554fdSclaudio mre = &mr->entries[i]; 12414a99c744Sclaudio memset(&ctl, 0, sizeof(ctl)); 1242000f4bc7Sclaudio ctl.prefix = mr->prefix; 1243a20554fdSclaudio ctl.prefixlen = mr->prefixlen; 1244e67b1a58Sclaudio if (mre->originated <= now) 1245e67b1a58Sclaudio ctl.age = now - mre->originated; 1246000f4bc7Sclaudio ctl.true_nexthop = mre->nexthop; 1247000f4bc7Sclaudio ctl.exit_nexthop = mre->nexthop; 1248a20554fdSclaudio ctl.origin = mre->origin; 1249a20554fdSclaudio ctl.local_pref = mre->local_pref; 1250a20554fdSclaudio ctl.med = mre->med; 125116f78093Sclaudio /* weight is not part of the mrt dump so it can't be set */ 12529e59dee7Sclaudio if (mr->add_path) { 12539e59dee7Sclaudio ctl.flags |= F_PREF_PATH_ID; 12549e59dee7Sclaudio ctl.path_id = mre->path_id; 12559e59dee7Sclaudio } 1256a20554fdSclaudio 1257a20554fdSclaudio if (mre->peer_idx < mp->npeers) { 1258000f4bc7Sclaudio ctl.remote_addr = mp->peers[mre->peer_idx].addr; 1259a20554fdSclaudio ctl.remote_id = mp->peers[mre->peer_idx].bgp_id; 1260a20554fdSclaudio } 1261a20554fdSclaudio 1262a20554fdSclaudio /* filter by neighbor */ 1263a20554fdSclaudio if (req->neighbor.addr.aid != AID_UNSPEC && 1264a20554fdSclaudio memcmp(&req->neighbor.addr, &ctl.remote_addr, 1265a20554fdSclaudio sizeof(ctl.remote_addr)) != 0) 1266a20554fdSclaudio continue; 1267a20554fdSclaudio /* filter by AF */ 1268a20554fdSclaudio if (req->aid && req->aid != ctl.prefix.aid) 1269a20554fdSclaudio return; 1270a20554fdSclaudio /* filter by prefix */ 1271a20554fdSclaudio if (req->prefix.aid != AID_UNSPEC) { 1272a20554fdSclaudio if (req->flags & F_LONGER) { 1273a20554fdSclaudio if (req->prefixlen > ctl.prefixlen) 1274a20554fdSclaudio return; 1275945d4f9bSclaudio if (prefix_compare(&req->prefix, &ctl.prefix, 1276945d4f9bSclaudio req->prefixlen)) 1277a20554fdSclaudio return; 1278945d4f9bSclaudio } else if (req->flags & F_SHORTER) { 1279945d4f9bSclaudio if (req->prefixlen < ctl.prefixlen) 1280a20554fdSclaudio return; 1281945d4f9bSclaudio if (prefix_compare(&req->prefix, &ctl.prefix, 1282945d4f9bSclaudio ctl.prefixlen)) 1283945d4f9bSclaudio return; 1284945d4f9bSclaudio } else { 1285945d4f9bSclaudio if (req->prefixlen != ctl.prefixlen) 1286945d4f9bSclaudio return; 1287945d4f9bSclaudio if (prefix_compare(&req->prefix, &ctl.prefix, 1288945d4f9bSclaudio req->prefixlen)) 1289945d4f9bSclaudio return; 1290945d4f9bSclaudio } 1291a20554fdSclaudio } 1292a20554fdSclaudio /* filter by AS */ 12939efe3de0Sclaudio if (req->as.type != AS_UNDEF && 1294291f32dfSclaudio !match_aspath(mre->aspath, mre->aspath_len, &req->as)) 1295f486926aSclaudio continue; 1296a20554fdSclaudio 129746d5331aSclaudio ibuf_from_buffer(&ibuf, mre->aspath, mre->aspath_len); 129846d5331aSclaudio output->rib(&ctl, &ibuf, &res); 1299a20554fdSclaudio if (req->flags & F_CTL_DETAIL) { 1300dd147aaaSclaudio for (j = 0; j < mre->nattrs; j++) { 1301dd147aaaSclaudio ibuf_from_buffer(&ibuf, mre->attrs[j].attr, 1302dd147aaaSclaudio mre->attrs[j].attr_len); 1303dd147aaaSclaudio output->attr(&ibuf, req->flags, 0); 1304dd147aaaSclaudio } 1305a069aa25Sclaudio } 1306a20554fdSclaudio } 1307a20554fdSclaudio } 1308a20554fdSclaudio 1309a20554fdSclaudio void 1310f486926aSclaudio network_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg) 1311f486926aSclaudio { 1312f486926aSclaudio struct ctl_show_rib ctl; 1313f486926aSclaudio struct network_config net; 1314f486926aSclaudio struct ctl_show_rib_request *req = arg; 1315f486926aSclaudio struct mrt_rib_entry *mre; 1316f486926aSclaudio struct ibuf *msg; 1317e67b1a58Sclaudio time_t now; 131859154960Sclaudio uint16_t i, j; 1319f486926aSclaudio 13209e59dee7Sclaudio /* can't announce more than one path so ignore add-path */ 13219e59dee7Sclaudio if (mr->add_path) 13229e59dee7Sclaudio return; 13239e59dee7Sclaudio 1324e67b1a58Sclaudio now = time(NULL); 1325f486926aSclaudio for (i = 0; i < mr->nentries; i++) { 1326f486926aSclaudio mre = &mr->entries[i]; 13274a99c744Sclaudio memset(&ctl, 0, sizeof(ctl)); 1328000f4bc7Sclaudio ctl.prefix = mr->prefix; 1329f486926aSclaudio ctl.prefixlen = mr->prefixlen; 1330e67b1a58Sclaudio if (mre->originated <= now) 1331e67b1a58Sclaudio ctl.age = now - mre->originated; 1332000f4bc7Sclaudio ctl.true_nexthop = mre->nexthop; 1333000f4bc7Sclaudio ctl.exit_nexthop = mre->nexthop; 1334f486926aSclaudio ctl.origin = mre->origin; 1335f486926aSclaudio ctl.local_pref = mre->local_pref; 1336f486926aSclaudio ctl.med = mre->med; 1337f486926aSclaudio 1338f486926aSclaudio if (mre->peer_idx < mp->npeers) { 1339000f4bc7Sclaudio ctl.remote_addr = mp->peers[mre->peer_idx].addr; 1340f486926aSclaudio ctl.remote_id = mp->peers[mre->peer_idx].bgp_id; 1341f486926aSclaudio } 1342f486926aSclaudio 1343f486926aSclaudio /* filter by neighbor */ 1344f486926aSclaudio if (req->neighbor.addr.aid != AID_UNSPEC && 1345f486926aSclaudio memcmp(&req->neighbor.addr, &ctl.remote_addr, 1346f486926aSclaudio sizeof(ctl.remote_addr)) != 0) 1347f486926aSclaudio continue; 1348f486926aSclaudio /* filter by AF */ 1349f486926aSclaudio if (req->aid && req->aid != ctl.prefix.aid) 1350f486926aSclaudio return; 1351f486926aSclaudio /* filter by prefix */ 1352f486926aSclaudio if (req->prefix.aid != AID_UNSPEC) { 1353f486926aSclaudio if (!prefix_compare(&req->prefix, &ctl.prefix, 1354f486926aSclaudio req->prefixlen)) { 1355f486926aSclaudio if (req->flags & F_LONGER) { 1356f486926aSclaudio if (req->prefixlen > ctl.prefixlen) 1357f486926aSclaudio return; 1358f486926aSclaudio } else if (req->prefixlen != ctl.prefixlen) 1359f486926aSclaudio return; 1360f486926aSclaudio } else 1361f486926aSclaudio return; 1362f486926aSclaudio } 1363f486926aSclaudio /* filter by AS */ 13649efe3de0Sclaudio if (req->as.type != AS_UNDEF && 1365291f32dfSclaudio !match_aspath(mre->aspath, mre->aspath_len, &req->as)) 1366f486926aSclaudio continue; 1367f486926aSclaudio 13684a99c744Sclaudio memset(&net, 0, sizeof(net)); 136938500be7Sbenno net.prefix = ctl.prefix; 1370f486926aSclaudio net.prefixlen = ctl.prefixlen; 1371f486926aSclaudio net.type = NETWORK_MRTCLONE; 1372a73789d3Sclaudio /* XXX rd can't be set and will be 0 */ 1373f486926aSclaudio 137440466abfSclaudio imsg_compose(imsgbuf, IMSG_NETWORK_ADD, 0, 0, -1, 1375f486926aSclaudio &net, sizeof(net)); 137640466abfSclaudio if ((msg = imsg_create(imsgbuf, IMSG_NETWORK_ASPATH, 1377f486926aSclaudio 0, 0, sizeof(ctl) + mre->aspath_len)) == NULL) 1378f486926aSclaudio errx(1, "imsg_create failure"); 1379f486926aSclaudio if (imsg_add(msg, &ctl, sizeof(ctl)) == -1 || 1380f486926aSclaudio imsg_add(msg, mre->aspath, mre->aspath_len) == -1) 1381f486926aSclaudio errx(1, "imsg_add failure"); 138240466abfSclaudio imsg_close(imsgbuf, msg); 1383f486926aSclaudio for (j = 0; j < mre->nattrs; j++) 138440466abfSclaudio imsg_compose(imsgbuf, IMSG_NETWORK_ATTR, 0, 0, -1, 1385f486926aSclaudio mre->attrs[j].attr, mre->attrs[j].attr_len); 138640466abfSclaudio imsg_compose(imsgbuf, IMSG_NETWORK_DONE, 0, 0, -1, NULL, 0); 1387f486926aSclaudio 1388dd7efffeSclaudio if (imsgbuf_flush(imsgbuf) == -1) 1389f486926aSclaudio err(1, "write error"); 1390f486926aSclaudio } 1391f486926aSclaudio } 1392f486926aSclaudio 139385411ad9Sclaudio static const char * 139404d0a88fSclaudio fmt_time(struct timespec *t) 139585411ad9Sclaudio { 139685411ad9Sclaudio static char timebuf[32]; 139785411ad9Sclaudio static struct timespec prevtime; 139885411ad9Sclaudio struct timespec temp; 139985411ad9Sclaudio 140085411ad9Sclaudio timespecsub(t, &prevtime, &temp); 140185411ad9Sclaudio snprintf(timebuf, sizeof(timebuf), "%lld.%06ld", 140285411ad9Sclaudio (long long)temp.tv_sec, temp.tv_nsec / 1000); 140385411ad9Sclaudio prevtime = *t; 140485411ad9Sclaudio return (timebuf); 140585411ad9Sclaudio } 140685411ad9Sclaudio 1407f486926aSclaudio void 1408a20554fdSclaudio show_mrt_state(struct mrt_bgp_state *ms, void *arg) 1409a20554fdSclaudio { 141004d0a88fSclaudio printf("%s %s[%u] -> ", fmt_time(&ms->time), 1411000f4bc7Sclaudio log_addr(&ms->src), ms->src_as); 1412000f4bc7Sclaudio printf("%s[%u]: %s -> %s\n", log_addr(&ms->dst), ms->dst_as, 1413e86c4bdeSclaudio statenames[ms->old_state], statenames[ms->new_state]); 1414a20554fdSclaudio } 1415a20554fdSclaudio 141647c6720fSclaudio static void 14176b941460Sclaudio print_afi(struct ibuf *b) 141847c6720fSclaudio { 141959154960Sclaudio uint16_t afi; 142059154960Sclaudio uint8_t safi, aid; 142147c6720fSclaudio 14226b941460Sclaudio if (ibuf_get_n16(b, &afi) == -1 || /* afi, 2 byte */ 14236b941460Sclaudio ibuf_skip(b, 1) == -1 || /* reserved, 1 byte */ 14246b941460Sclaudio ibuf_get_n8(b, &safi) == -1 || /* safi, 1 byte */ 14256b941460Sclaudio ibuf_size(b) != 0) { 142647c6720fSclaudio printf("bad length"); 142747c6720fSclaudio return; 142847c6720fSclaudio } 142947c6720fSclaudio 143047c6720fSclaudio if (afi2aid(afi, safi, &aid) == -1) 14319c5d31d7Sjob printf("unknown afi %u safi %u", afi, safi); 143247c6720fSclaudio else 143347c6720fSclaudio printf("%s", aid2str(aid)); 143447c6720fSclaudio } 143547c6720fSclaudio 143647c6720fSclaudio static void 14376b941460Sclaudio print_capability(uint8_t capa_code, struct ibuf *b) 143847c6720fSclaudio { 14396b941460Sclaudio uint32_t as; 14406b941460Sclaudio 144147c6720fSclaudio switch (capa_code) { 144247c6720fSclaudio case CAPA_MP: 144347c6720fSclaudio printf("multiprotocol capability: "); 14446b941460Sclaudio print_afi(b); 144547c6720fSclaudio break; 144647c6720fSclaudio case CAPA_REFRESH: 144747c6720fSclaudio printf("route refresh capability"); 144847c6720fSclaudio break; 144947c6720fSclaudio case CAPA_RESTART: 145047c6720fSclaudio printf("graceful restart capability"); 145147c6720fSclaudio /* XXX there is more needed here */ 145247c6720fSclaudio break; 145347c6720fSclaudio case CAPA_AS4BYTE: 145447c6720fSclaudio printf("4-byte AS num capability: "); 14556b941460Sclaudio if (ibuf_get_n32(b, &as) == -1 || 14566b941460Sclaudio ibuf_size(b) != 0) 145747c6720fSclaudio printf("bad length"); 14586b941460Sclaudio else 14596b941460Sclaudio printf("AS %u", as); 146047c6720fSclaudio break; 1461b6faf4c9Sclaudio case CAPA_ADD_PATH: 1462b6faf4c9Sclaudio printf("add-path capability"); 1463b6faf4c9Sclaudio /* XXX there is more needed here */ 1464b6faf4c9Sclaudio break; 1465b6faf4c9Sclaudio case CAPA_ENHANCED_RR: 1466b6faf4c9Sclaudio printf("enhanced route refresh capability"); 1467b6faf4c9Sclaudio break; 146882293aebSclaudio case CAPA_EXT_MSG: 146982293aebSclaudio printf("extended message capability"); 147082293aebSclaudio break; 147147c6720fSclaudio default: 14726b941460Sclaudio printf("unknown capability %u length %zu", 14736b941460Sclaudio capa_code, ibuf_size(b)); 147447c6720fSclaudio break; 147547c6720fSclaudio } 147647c6720fSclaudio } 147747c6720fSclaudio 147847c6720fSclaudio static void 147959154960Sclaudio print_notification(uint8_t errcode, uint8_t subcode) 148047c6720fSclaudio { 148147c6720fSclaudio const char *suberrname = NULL; 148247c6720fSclaudio int uk = 0; 148347c6720fSclaudio 148447c6720fSclaudio switch (errcode) { 148547c6720fSclaudio case ERR_HEADER: 148647c6720fSclaudio if (subcode >= sizeof(suberr_header_names)/sizeof(char *)) 148747c6720fSclaudio uk = 1; 148847c6720fSclaudio else 148947c6720fSclaudio suberrname = suberr_header_names[subcode]; 149047c6720fSclaudio break; 149147c6720fSclaudio case ERR_OPEN: 149247c6720fSclaudio if (subcode >= sizeof(suberr_open_names)/sizeof(char *)) 149347c6720fSclaudio uk = 1; 149447c6720fSclaudio else 149547c6720fSclaudio suberrname = suberr_open_names[subcode]; 149647c6720fSclaudio break; 149747c6720fSclaudio case ERR_UPDATE: 149847c6720fSclaudio if (subcode >= sizeof(suberr_update_names)/sizeof(char *)) 149947c6720fSclaudio uk = 1; 150047c6720fSclaudio else 150147c6720fSclaudio suberrname = suberr_update_names[subcode]; 150247c6720fSclaudio break; 150347c6720fSclaudio case ERR_CEASE: 150447c6720fSclaudio if (subcode >= sizeof(suberr_cease_names)/sizeof(char *)) 150547c6720fSclaudio uk = 1; 150647c6720fSclaudio else 150747c6720fSclaudio suberrname = suberr_cease_names[subcode]; 150847c6720fSclaudio break; 150947c6720fSclaudio case ERR_HOLDTIMEREXPIRED: 151047c6720fSclaudio if (subcode != 0) 151147c6720fSclaudio uk = 1; 151247c6720fSclaudio break; 151347c6720fSclaudio case ERR_FSM: 151447c6720fSclaudio if (subcode >= sizeof(suberr_fsm_names)/sizeof(char *)) 151547c6720fSclaudio uk = 1; 151647c6720fSclaudio else 151747c6720fSclaudio suberrname = suberr_fsm_names[subcode]; 151847c6720fSclaudio break; 151947c6720fSclaudio default: 152047c6720fSclaudio printf("unknown errcode %u, subcode %u", 152147c6720fSclaudio errcode, subcode); 152247c6720fSclaudio return; 152347c6720fSclaudio } 152447c6720fSclaudio 152547c6720fSclaudio if (uk) 152647c6720fSclaudio printf("%s, unknown subcode %u", errnames[errcode], subcode); 152747c6720fSclaudio else { 152847c6720fSclaudio if (suberrname == NULL) 152947c6720fSclaudio printf("%s", errnames[errcode]); 153047c6720fSclaudio else 153147c6720fSclaudio printf("%s, %s", errnames[errcode], suberrname); 153247c6720fSclaudio } 153347c6720fSclaudio } 153447c6720fSclaudio 153547c6720fSclaudio static int 15366b941460Sclaudio show_mrt_capabilities(struct ibuf *b) 153747c6720fSclaudio { 153859154960Sclaudio uint8_t capa_code, capa_len; 15396b941460Sclaudio struct ibuf cbuf; 154047c6720fSclaudio 15416b941460Sclaudio while (ibuf_size(b) > 0) { 15426b941460Sclaudio if (ibuf_get_n8(b, &capa_code) == -1 || 15436b941460Sclaudio ibuf_get_n8(b, &capa_len) == -1 || 15446b941460Sclaudio ibuf_get_ibuf(b, capa_len, &cbuf) == -1) { 15456b941460Sclaudio printf("truncated capabilities"); 154647c6720fSclaudio return (-1); 154747c6720fSclaudio } 154847c6720fSclaudio printf("\n "); 15496b941460Sclaudio print_capability(capa_code, &cbuf); 155047c6720fSclaudio } 15516b941460Sclaudio return (0); 155247c6720fSclaudio } 155347c6720fSclaudio 155447c6720fSclaudio static void 15556b941460Sclaudio show_mrt_open(struct ibuf *b) 155647c6720fSclaudio { 1557765bd20aSclaudio struct in_addr ina; 1558765bd20aSclaudio uint32_t bgpid; 155959154960Sclaudio uint16_t short_as, holdtime; 156059154960Sclaudio uint8_t version, optparamlen; 156147c6720fSclaudio 156247c6720fSclaudio /* length check up to optparamlen already happened */ 15636b941460Sclaudio if (ibuf_get_n8(b, &version) == -1 || 15646b941460Sclaudio ibuf_get_n16(b, &short_as) == -1 || 15656b941460Sclaudio ibuf_get_n16(b, &holdtime) == -1 || 1566765bd20aSclaudio ibuf_get_n32(b, &bgpid) == -1 || 15676b941460Sclaudio ibuf_get_n8(b, &optparamlen) == -1) { 15686b941460Sclaudio trunc: 15696b941460Sclaudio printf("truncated message"); 15706b941460Sclaudio return; 15716b941460Sclaudio } 157247c6720fSclaudio 157347c6720fSclaudio printf("\n "); 1574765bd20aSclaudio ina.s_addr = htonl(bgpid); 157547c6720fSclaudio printf("Version: %d AS: %u Holdtime: %u BGP Id: %s Paramlen: %u", 1576765bd20aSclaudio version, short_as, holdtime, inet_ntoa(ina), optparamlen); 15776b941460Sclaudio if (optparamlen != ibuf_size(b)) { 15786b941460Sclaudio /* XXX missing support for RFC9072 */ 157947c6720fSclaudio printf("optional parameter length mismatch"); 158047c6720fSclaudio return; 158147c6720fSclaudio } 15826b941460Sclaudio while (ibuf_size(b) > 0) { 158359154960Sclaudio uint8_t op_type, op_len; 158447c6720fSclaudio 15856b941460Sclaudio if (ibuf_get_n8(b, &op_type) == -1 || 15866b941460Sclaudio ibuf_get_n8(b, &op_len) == -1) 15876b941460Sclaudio goto trunc; 158847c6720fSclaudio 158947c6720fSclaudio printf("\n "); 159047c6720fSclaudio switch (op_type) { 159147c6720fSclaudio case OPT_PARAM_CAPABILITIES: 15926b941460Sclaudio printf("Capabilities: %u bytes", op_len); 15936b941460Sclaudio if (show_mrt_capabilities(b) == -1) 159447c6720fSclaudio return; 159547c6720fSclaudio break; 159647c6720fSclaudio case OPT_PARAM_AUTH: 159747c6720fSclaudio default: 159847c6720fSclaudio printf("unsupported optional parameter: type %u", 159947c6720fSclaudio op_type); 160047c6720fSclaudio return; 160147c6720fSclaudio } 160247c6720fSclaudio } 160347c6720fSclaudio } 160447c6720fSclaudio 160547c6720fSclaudio static void 16066b941460Sclaudio show_mrt_notification(struct ibuf *b) 160747c6720fSclaudio { 1608a78f83ceSderaadt char reason[REASON_LEN]; 16096b941460Sclaudio uint8_t errcode, subcode, reason_len, c; 16106b941460Sclaudio size_t i, len; 161147c6720fSclaudio 16126b941460Sclaudio if (ibuf_get_n8(b, &errcode) == -1 || 16136b941460Sclaudio ibuf_get_n8(b, &subcode) == -1) { 16146b941460Sclaudio trunc: 16156b941460Sclaudio printf("truncated message"); 16166b941460Sclaudio return; 16176b941460Sclaudio } 161847c6720fSclaudio 161947c6720fSclaudio printf("\n "); 162047c6720fSclaudio print_notification(errcode, subcode); 162147c6720fSclaudio 162247c6720fSclaudio if (errcode == ERR_CEASE && (subcode == ERR_CEASE_ADMIN_DOWN || 162347c6720fSclaudio subcode == ERR_CEASE_ADMIN_RESET)) { 16246b941460Sclaudio if (ibuf_size(b) > 1) { 16256b941460Sclaudio if (ibuf_get_n8(b, &reason_len) == -1) 16266b941460Sclaudio goto trunc; 16276b941460Sclaudio if (ibuf_get(b, reason, reason_len) == -1) 16286b941460Sclaudio goto trunc; 1629a78f83ceSderaadt reason[reason_len] = '\0'; 163047c6720fSclaudio printf("shutdown reason: \"%s\"", 1631a78f83ceSderaadt log_reason(reason)); 163247c6720fSclaudio } 163347c6720fSclaudio } 163447c6720fSclaudio if (errcode == ERR_OPEN && subcode == ERR_OPEN_CAPA) { 16356b941460Sclaudio if (show_mrt_capabilities(b) == -1) 163647c6720fSclaudio return; 163747c6720fSclaudio } 163847c6720fSclaudio 16396b941460Sclaudio if (ibuf_size(b) > 0) { 16406b941460Sclaudio len = ibuf_size(b); 16416b941460Sclaudio printf("\n additional data, %zu bytes", len); 164247c6720fSclaudio for (i = 0; i < len; i++) { 164347c6720fSclaudio if (i % 16 == 0) 164447c6720fSclaudio printf("\n "); 164547c6720fSclaudio if (i % 8 == 0) 164647c6720fSclaudio printf(" "); 16476b941460Sclaudio if (ibuf_get_n8(b, &c) == -1) 16486b941460Sclaudio goto trunc; 16496b941460Sclaudio printf(" %02X", c); 165047c6720fSclaudio } 165147c6720fSclaudio } 165247c6720fSclaudio } 165347c6720fSclaudio 1654d30a810dSclaudio /* XXX this function does not handle JSON output */ 165547c6720fSclaudio static void 16566b941460Sclaudio show_mrt_update(struct ibuf *b, int reqflags, int addpath) 165747c6720fSclaudio { 165847c6720fSclaudio struct bgpd_addr prefix; 16596b941460Sclaudio struct ibuf wbuf, abuf; 166059154960Sclaudio uint32_t pathid; 166159154960Sclaudio uint16_t wlen, alen; 166259154960Sclaudio uint8_t prefixlen; 166347c6720fSclaudio 16645ad4fcbaSclaudio if (ibuf_get_n16(b, &wlen) == -1 || 16655ad4fcbaSclaudio ibuf_get_ibuf(b, wlen, &wbuf) == -1) 16665ad4fcbaSclaudio goto trunc; 16676b941460Sclaudio 166847c6720fSclaudio if (wlen > 0) { 166947c6720fSclaudio printf("\n Withdrawn prefixes:"); 16705ad4fcbaSclaudio while (ibuf_size(&wbuf) > 0) { 16715ad4fcbaSclaudio if (addpath) 16725ad4fcbaSclaudio if (ibuf_get_n32(&wbuf, &pathid) == -1) 16735ad4fcbaSclaudio goto trunc; 16745ad4fcbaSclaudio if (nlri_get_prefix(&wbuf, &prefix, &prefixlen) == -1) 16755ad4fcbaSclaudio goto trunc; 16765ad4fcbaSclaudio 167747c6720fSclaudio printf(" %s/%u", log_addr(&prefix), prefixlen); 16789e59dee7Sclaudio if (addpath) 16799e59dee7Sclaudio printf(" path-id %u", pathid); 168047c6720fSclaudio } 168147c6720fSclaudio } 168247c6720fSclaudio 16835ad4fcbaSclaudio if (ibuf_get_n16(b, &alen) == -1 || 16845ad4fcbaSclaudio ibuf_get_ibuf(b, alen, &abuf) == -1) 16855ad4fcbaSclaudio goto trunc; 168647c6720fSclaudio 168747c6720fSclaudio printf("\n"); 168847c6720fSclaudio /* alen attributes here */ 16895ad4fcbaSclaudio while (ibuf_size(&abuf) > 0) { 16905ad4fcbaSclaudio struct ibuf attrbuf; 169159154960Sclaudio uint16_t attrlen; 16925ad4fcbaSclaudio uint8_t flags; 169347c6720fSclaudio 16945ad4fcbaSclaudio ibuf_from_ibuf(&abuf, &attrbuf); 16955ad4fcbaSclaudio if (ibuf_get_n8(&attrbuf, &flags) == -1 || 16965ad4fcbaSclaudio ibuf_skip(&attrbuf, 1) == -1) 16975ad4fcbaSclaudio goto trunc; 169847c6720fSclaudio 169947c6720fSclaudio /* get the attribute length */ 170047c6720fSclaudio if (flags & ATTR_EXTLEN) { 17015ad4fcbaSclaudio if (ibuf_get_n16(&attrbuf, &attrlen) == -1) 17025ad4fcbaSclaudio goto trunc; 170347c6720fSclaudio } else { 17045ad4fcbaSclaudio uint8_t tmp; 17055ad4fcbaSclaudio if (ibuf_get_n8(&attrbuf, &tmp) == -1) 17065ad4fcbaSclaudio goto trunc; 17075ad4fcbaSclaudio attrlen = tmp; 17085ad4fcbaSclaudio } 17095ad4fcbaSclaudio if (ibuf_truncate(&attrbuf, attrlen) == -1) 17105ad4fcbaSclaudio goto trunc; 17115ad4fcbaSclaudio ibuf_rewind(&attrbuf); 17125ad4fcbaSclaudio if (ibuf_skip(&abuf, ibuf_size(&attrbuf)) == -1) 17135ad4fcbaSclaudio goto trunc; 17145ad4fcbaSclaudio 1715dd147aaaSclaudio output->attr(&attrbuf, reqflags, addpath); 171647c6720fSclaudio } 171747c6720fSclaudio 17185ad4fcbaSclaudio if (ibuf_size(b) > 0) { 171947c6720fSclaudio printf(" NLRI prefixes:"); 17205ad4fcbaSclaudio while (ibuf_size(b) > 0) { 17215ad4fcbaSclaudio if (addpath) 17225ad4fcbaSclaudio if (ibuf_get_n32(b, &pathid) == -1) 17235ad4fcbaSclaudio goto trunc; 17245ad4fcbaSclaudio if (nlri_get_prefix(b, &prefix, &prefixlen) == -1) 17255ad4fcbaSclaudio goto trunc; 17265ad4fcbaSclaudio 172747c6720fSclaudio printf(" %s/%u", log_addr(&prefix), prefixlen); 17289e59dee7Sclaudio if (addpath) 17299e59dee7Sclaudio printf(" path-id %u", pathid); 173047c6720fSclaudio } 173147c6720fSclaudio } 17325ad4fcbaSclaudio return; 17335ad4fcbaSclaudio 17345ad4fcbaSclaudio trunc: 17355ad4fcbaSclaudio printf("truncated message"); 173647c6720fSclaudio } 173747c6720fSclaudio 1738a20554fdSclaudio void 1739a20554fdSclaudio show_mrt_msg(struct mrt_bgp_msg *mm, void *arg) 1740a20554fdSclaudio { 174159154960Sclaudio static const uint8_t marker[MSGSIZE_HEADER_MARKER] = { 174247c6720fSclaudio 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 174347c6720fSclaudio 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 17446b941460Sclaudio uint8_t m[MSGSIZE_HEADER_MARKER]; 17456b941460Sclaudio struct ibuf *b; 174659154960Sclaudio uint16_t len; 174759154960Sclaudio uint8_t type; 174852d49889Sclaudio struct ctl_show_rib_request *req = arg; 1749e86c4bdeSclaudio 175004d0a88fSclaudio printf("%s %s[%u] -> ", fmt_time(&mm->time), 1751000f4bc7Sclaudio log_addr(&mm->src), mm->src_as); 17526b941460Sclaudio printf("%s[%u]: size %zu%s ", log_addr(&mm->dst), mm->dst_as, 17536b941460Sclaudio ibuf_size(&mm->msg), mm->add_path ? " addpath" : ""); 17546b941460Sclaudio b = &mm->msg; 175547c6720fSclaudio 17566b941460Sclaudio if (ibuf_get(b, m, sizeof(m)) == -1) { 17576b941460Sclaudio printf("bad message: short header\n"); 175847c6720fSclaudio return; 175947c6720fSclaudio } 176047c6720fSclaudio 176147c6720fSclaudio /* parse BGP message header */ 17626b941460Sclaudio if (memcmp(m, marker, sizeof(marker))) { 176347c6720fSclaudio printf("incorrect marker in BGP message\n"); 176447c6720fSclaudio return; 176547c6720fSclaudio } 176647c6720fSclaudio 17676b941460Sclaudio if (ibuf_get_n16(b, &len) == -1 || 17686b941460Sclaudio ibuf_get_n8(b, &type) == -1) { 17696b941460Sclaudio printf("bad message: short header\n"); 17706b941460Sclaudio return; 17716b941460Sclaudio } 177247c6720fSclaudio 177347c6720fSclaudio if (len < MSGSIZE_HEADER || len > MAX_PKTSIZE) { 177447c6720fSclaudio printf("illegal header length: %u byte\n", len); 177547c6720fSclaudio return; 177647c6720fSclaudio } 177747c6720fSclaudio 177847c6720fSclaudio switch (type) { 1779*b3b12989Sclaudio case MSG_OPEN: 178047c6720fSclaudio printf("%s ", msgtypenames[type]); 178147c6720fSclaudio if (len < MSGSIZE_OPEN_MIN) { 17826b941460Sclaudio printf("bad length: %u bytes\n", len); 178347c6720fSclaudio return; 178447c6720fSclaudio } 17856b941460Sclaudio show_mrt_open(b); 178647c6720fSclaudio break; 1787*b3b12989Sclaudio case MSG_NOTIFICATION: 178847c6720fSclaudio printf("%s ", msgtypenames[type]); 178947c6720fSclaudio if (len < MSGSIZE_NOTIFICATION_MIN) { 17906b941460Sclaudio printf("bad length: %u bytes\n", len); 179147c6720fSclaudio return; 179247c6720fSclaudio } 17936b941460Sclaudio show_mrt_notification(b); 179447c6720fSclaudio break; 1795*b3b12989Sclaudio case MSG_UPDATE: 179647c6720fSclaudio printf("%s ", msgtypenames[type]); 179747c6720fSclaudio if (len < MSGSIZE_UPDATE_MIN) { 17986b941460Sclaudio printf("bad length: %u bytes\n", len); 179947c6720fSclaudio return; 180047c6720fSclaudio } 18016b941460Sclaudio show_mrt_update(b, req->flags, mm->add_path); 180247c6720fSclaudio break; 1803*b3b12989Sclaudio case MSG_KEEPALIVE: 180447c6720fSclaudio printf("%s ", msgtypenames[type]); 180547c6720fSclaudio if (len != MSGSIZE_KEEPALIVE) { 18066b941460Sclaudio printf("bad length: %u bytes\n", len); 180747c6720fSclaudio return; 180847c6720fSclaudio } 180947c6720fSclaudio /* nothing */ 181047c6720fSclaudio break; 1811*b3b12989Sclaudio case MSG_RREFRESH: 181247c6720fSclaudio printf("%s ", msgtypenames[type]); 181347c6720fSclaudio if (len != MSGSIZE_RREFRESH) { 18146b941460Sclaudio printf("bad length: %u bytes\n", len); 181547c6720fSclaudio return; 181647c6720fSclaudio } 18176b941460Sclaudio print_afi(b); 181847c6720fSclaudio break; 181947c6720fSclaudio default: 182047c6720fSclaudio printf("unknown type %u\n", type); 182147c6720fSclaudio return; 182247c6720fSclaudio } 182347c6720fSclaudio printf("\n"); 1824a20554fdSclaudio } 1825a20554fdSclaudio 1826e86c4bdeSclaudio const char * 182759154960Sclaudio msg_type(uint8_t type) 1828e86c4bdeSclaudio { 1829e86c4bdeSclaudio if (type >= sizeof(msgtypenames)/sizeof(msgtypenames[0])) 1830e86c4bdeSclaudio return "BAD"; 1831e86c4bdeSclaudio return (msgtypenames[type]); 1832e86c4bdeSclaudio } 1833ddebc6f6Sclaudio 1834722ee4e7Sclaudio int 183559154960Sclaudio match_aspath(void *data, uint16_t len, struct filter_as *f) 1836ddebc6f6Sclaudio { 183759154960Sclaudio uint8_t *seg; 1838291f32dfSclaudio int final; 183959154960Sclaudio uint16_t seg_size; 184059154960Sclaudio uint8_t i, seg_len; 184159154960Sclaudio uint32_t as = 0; 1842291f32dfSclaudio 1843291f32dfSclaudio if (f->type == AS_EMPTY) { 1844291f32dfSclaudio if (len == 0) 1845291f32dfSclaudio return (1); 1846291f32dfSclaudio else 1847291f32dfSclaudio return (0); 1848291f32dfSclaudio } 1849291f32dfSclaudio 1850291f32dfSclaudio seg = data; 1851291f32dfSclaudio 1852291f32dfSclaudio /* just check the leftmost AS */ 1853291f32dfSclaudio if (f->type == AS_PEER && len >= 6) { 1854291f32dfSclaudio as = aspath_extract(seg, 0); 1855291f32dfSclaudio if (f->as_min == as) 1856291f32dfSclaudio return (1); 1857291f32dfSclaudio else 1858291f32dfSclaudio return (0); 1859291f32dfSclaudio } 1860291f32dfSclaudio 1861291f32dfSclaudio for (; len >= 6; len -= seg_size, seg += seg_size) { 1862291f32dfSclaudio seg_len = seg[1]; 186359154960Sclaudio seg_size = 2 + sizeof(uint32_t) * seg_len; 1864291f32dfSclaudio 1865291f32dfSclaudio final = (len == seg_size); 1866291f32dfSclaudio 1867291f32dfSclaudio if (f->type == AS_SOURCE) { 1868291f32dfSclaudio /* 1869291f32dfSclaudio * Just extract the rightmost AS 1870291f32dfSclaudio * but if that segment is an AS_SET then the rightmost 1871291f32dfSclaudio * AS of a previous AS_SEQUENCE segment should be used. 1872291f32dfSclaudio * Because of that just look at AS_SEQUENCE segments. 1873291f32dfSclaudio */ 1874291f32dfSclaudio if (seg[0] == AS_SEQUENCE) 1875291f32dfSclaudio as = aspath_extract(seg, seg_len - 1); 1876291f32dfSclaudio /* not yet in the final segment */ 1877291f32dfSclaudio if (!final) 1878291f32dfSclaudio continue; 1879291f32dfSclaudio if (f->as_min == as) 1880291f32dfSclaudio return (1); 1881291f32dfSclaudio else 1882291f32dfSclaudio return (0); 1883291f32dfSclaudio } 1884291f32dfSclaudio /* AS_TRANSIT or AS_ALL */ 1885291f32dfSclaudio for (i = 0; i < seg_len; i++) { 1886291f32dfSclaudio /* 1887291f32dfSclaudio * the source (rightmost) AS is excluded from 1888291f32dfSclaudio * AS_TRANSIT matches. 1889291f32dfSclaudio */ 1890291f32dfSclaudio if (final && i == seg_len - 1 && f->type == AS_TRANSIT) 1891291f32dfSclaudio return (0); 1892291f32dfSclaudio as = aspath_extract(seg, i); 1893291f32dfSclaudio if (f->as_min == as) 1894291f32dfSclaudio return (1); 1895291f32dfSclaudio } 1896291f32dfSclaudio } 1897722ee4e7Sclaudio return (0); 1898ddebc6f6Sclaudio } 1899e3925e28Sclaudio 1900e3925e28Sclaudio static void 1901e3925e28Sclaudio component_finish(int type, uint8_t *data, int len) 1902e3925e28Sclaudio { 1903e3925e28Sclaudio uint8_t *last; 1904e3925e28Sclaudio int i; 1905e3925e28Sclaudio 1906e3925e28Sclaudio switch (type) { 1907e3925e28Sclaudio case FLOWSPEC_TYPE_DEST: 1908e3925e28Sclaudio case FLOWSPEC_TYPE_SOURCE: 1909e3925e28Sclaudio /* nothing todo */ 1910e3925e28Sclaudio return; 1911e3925e28Sclaudio default: 1912e3925e28Sclaudio break; 1913e3925e28Sclaudio } 1914e3925e28Sclaudio 1915e3925e28Sclaudio i = 0; 1916e3925e28Sclaudio do { 1917e3925e28Sclaudio last = data + i; 1918e3925e28Sclaudio i += FLOWSPEC_OP_LEN(*last) + 1; 1919e3925e28Sclaudio } while (i < len); 1920e3925e28Sclaudio *last |= FLOWSPEC_OP_EOL; 1921e3925e28Sclaudio } 1922e3925e28Sclaudio 1923e3925e28Sclaudio static void 1924e3925e28Sclaudio push_prefix(struct parse_result *r, int type, struct bgpd_addr *addr, 1925e3925e28Sclaudio uint8_t len) 1926e3925e28Sclaudio { 1927e3925e28Sclaudio void *data; 1928e3925e28Sclaudio uint8_t *comp; 1929e3925e28Sclaudio int complen, l; 1930e3925e28Sclaudio 1931e3925e28Sclaudio switch (addr->aid) { 1932e3925e28Sclaudio case AID_UNSPEC: 1933e3925e28Sclaudio return; 1934e3925e28Sclaudio case AID_INET: 1935e3925e28Sclaudio complen = PREFIX_SIZE(len); 1936e3925e28Sclaudio data = &addr->v4; 1937e3925e28Sclaudio break; 1938e3925e28Sclaudio case AID_INET6: 1939e3925e28Sclaudio /* IPv6 includes an offset byte */ 1940e3925e28Sclaudio complen = PREFIX_SIZE(len) + 1; 1941e3925e28Sclaudio data = &addr->v6; 1942e3925e28Sclaudio break; 19435cff40bcSclaudio default: 19445cff40bcSclaudio errx(1, "unsupported address family for flowspec address"); 1945e3925e28Sclaudio } 1946e3925e28Sclaudio comp = malloc(complen); 1947e3925e28Sclaudio if (comp == NULL) 1948e3925e28Sclaudio err(1, NULL); 1949e3925e28Sclaudio 1950e3925e28Sclaudio l = 0; 1951e3925e28Sclaudio comp[l++] = len; 1952e3925e28Sclaudio if (addr->aid == AID_INET6) 1953e3925e28Sclaudio comp[l++] = 0; 1954e3925e28Sclaudio memcpy(comp + l, data, complen - l); 1955e3925e28Sclaudio 1956e3925e28Sclaudio r->flow.complen[type] = complen; 1957e3925e28Sclaudio r->flow.components[type] = comp; 1958e3925e28Sclaudio } 1959e3925e28Sclaudio 1960e3925e28Sclaudio 1961e3925e28Sclaudio struct flowspec * 1962e3925e28Sclaudio res_to_flowspec(struct parse_result *r) 1963e3925e28Sclaudio { 1964e3925e28Sclaudio struct flowspec *f; 1965e3925e28Sclaudio int i, len = 0; 1966e3925e28Sclaudio uint8_t aid; 1967e3925e28Sclaudio 1968e3925e28Sclaudio switch (r->aid) { 1969e3925e28Sclaudio case AID_INET: 1970e3925e28Sclaudio aid = AID_FLOWSPECv4; 1971e3925e28Sclaudio break; 1972e3925e28Sclaudio case AID_INET6: 1973e3925e28Sclaudio aid = AID_FLOWSPECv6; 1974e3925e28Sclaudio break; 1975e3925e28Sclaudio default: 1976e3925e28Sclaudio errx(1, "unsupported AFI %s for flowspec rule", 1977e3925e28Sclaudio aid2str(r->aid)); 1978e3925e28Sclaudio } 1979e3925e28Sclaudio 1980e3925e28Sclaudio push_prefix(r, FLOWSPEC_TYPE_DEST, &r->flow.dst, r->flow.dstlen); 1981e3925e28Sclaudio push_prefix(r, FLOWSPEC_TYPE_SOURCE, &r->flow.src, r->flow.srclen); 1982e3925e28Sclaudio 1983e3925e28Sclaudio for (i = FLOWSPEC_TYPE_MIN; i < FLOWSPEC_TYPE_MAX; i++) 1984e3925e28Sclaudio if (r->flow.components[i] != NULL) 1985e3925e28Sclaudio len += r->flow.complen[i] + 1; 1986e3925e28Sclaudio 1987e3925e28Sclaudio if (len == 0) 1988e3925e28Sclaudio errx(1, "no flowspec rule defined"); 1989e3925e28Sclaudio 1990e3925e28Sclaudio f = malloc(FLOWSPEC_SIZE + len); 1991e3925e28Sclaudio if (f == NULL) 1992e3925e28Sclaudio err(1, NULL); 1993e3925e28Sclaudio memset(f, 0, FLOWSPEC_SIZE); 1994e3925e28Sclaudio 1995e3925e28Sclaudio f->aid = aid; 1996e3925e28Sclaudio f->len = len; 1997e3925e28Sclaudio 1998e3925e28Sclaudio len = 0; 1999e3925e28Sclaudio for (i = FLOWSPEC_TYPE_MIN; i < FLOWSPEC_TYPE_MAX; i++) 2000e3925e28Sclaudio if (r->flow.components[i] != NULL) { 2001e3925e28Sclaudio f->data[len++] = i; 2002e3925e28Sclaudio component_finish(i, r->flow.components[i], 2003e3925e28Sclaudio r->flow.complen[i]); 2004e3925e28Sclaudio memcpy(f->data + len, r->flow.components[i], 2005e3925e28Sclaudio r->flow.complen[i]); 2006e3925e28Sclaudio len += r->flow.complen[i]; 2007e3925e28Sclaudio } 2008e3925e28Sclaudio 2009e3925e28Sclaudio return f; 2010e3925e28Sclaudio } 2011