Hi, I have done the work to implement ospfctl json support, but as discussed i will provide it in two diffs.
This first one externalises the output aspect of ospfctl and there are some things like tail that are not needed specifically for straight standard output, but are required for json support. I also wasn't sure what to do with Copyright messages at the top of files, any advice appreciated. In terms of outstanding issues, not sure how big to make the array in print_baudrate, I guessed 32 would cover things? Many of the functions that return output fragments are called print, when they actually return strings. in bgpctl many of these seem to have been renamed to fmt_. I have left these as is for now to again reduce the size of the change. diff --git a/usr.sbin/ospfctl/Makefile b/usr.sbin/ospfctl/Makefile index cfd5e4ccb71..6560e0d5f89 100644 --- a/usr.sbin/ospfctl/Makefile +++ b/usr.sbin/ospfctl/Makefile @@ -3,7 +3,7 @@ .PATH: ${.CURDIR}/../ospfd PROG= ospfctl -SRCS= logmsg.c ospfctl.c parser.c +SRCS= logmsg.c ospfctl.c output.c parser.c CFLAGS+= -Wall CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual diff --git a/usr.sbin/ospfctl/ospfctl.c b/usr.sbin/ospfctl/ospfctl.c index 2d7189793d8..e04124853a1 100644 --- a/usr.sbin/ospfctl/ospfctl.c +++ b/usr.sbin/ospfctl/ospfctl.c @@ -35,42 +35,16 @@ #include "ospf.h" #include "ospfd.h" +#include "ospfctl.h" #include "ospfe.h" #include "parser.h" __dead void usage(void); -int show_summary_msg(struct imsg *); -uint64_t get_ifms_type(uint8_t); -int show_interface_msg(struct imsg *); -int show_interface_detail_msg(struct imsg *); -const char *print_link(int); -const char *fmt_timeframe(time_t t); -const char *fmt_timeframe_core(time_t t); -const char *log_id(u_int32_t ); -const char *log_adv_rtr(u_int32_t); -void show_database_head(struct in_addr, char *, u_int8_t); -int show_database_msg(struct imsg *); -char *print_ls_type(u_int8_t); -void show_db_hdr_msg_detail(struct lsa_hdr *); -char *print_rtr_link_type(u_int8_t); -const char *print_ospf_flags(u_int8_t); -int show_db_msg_detail(struct imsg *imsg); -int show_nbr_msg(struct imsg *); -const char *print_ospf_options(u_int8_t); -int show_nbr_detail_msg(struct imsg *); -int show_rib_msg(struct imsg *); -void show_rib_head(struct in_addr, u_int8_t, u_int8_t); -const char *print_ospf_rtr_flags(u_int8_t); -int show_rib_detail_msg(struct imsg *); -void show_fib_head(void); -int show_fib_msg(struct imsg *); -void show_interface_head(void); -const char * get_media_descr(uint64_t); -const char * get_linkstate(uint8_t, int); -void print_baudrate(u_int64_t); -int show_fib_interface_msg(struct imsg *); + +int show(struct imsg *imsg, struct parse_result *res); struct imsgbuf *ibuf; +const struct output *output = &show_output; __dead void usage(void) @@ -145,9 +119,6 @@ main(int argc, char *argv[]) imsg_compose(ibuf, IMSG_CTL_SHOW_SUM, 0, 0, -1, NULL, 0); break; case SHOW_IFACE: - printf("%-11s %-18s %-6s %-10s %-10s %-8s %3s %3s\n", - "Interface", "Address", "State", "HelloTimer", "Linkstate", - "Uptime", "nc", "ac"); /*FALLTHROUGH*/ case SHOW_IFACE_DTAIL: if (*res->ifname) { @@ -159,8 +130,6 @@ main(int argc, char *argv[]) &ifidx, sizeof(ifidx)); break; case SHOW_NBR: - printf("%-15s %-3s %-12s %-8s %-15s %-9s %s\n", "ID", "Pri", - "State", "DeadTime", "Address", "Iface","Uptime"); /*FALLTHROUGH*/ case SHOW_NBR_DTAIL: imsg_compose(ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0); @@ -194,8 +163,6 @@ main(int argc, char *argv[]) imsg_compose(ibuf, IMSG_CTL_SHOW_DB_OPAQ, 0, 0, -1, NULL, 0); break; case SHOW_RIB: - printf("%-20s %-17s %-12s %-9s %-7s %-8s\n", "Destination", - "Nexthop", "Path Type", "Type", "Cost", "Uptime"); /*FALLTHROUGH*/ case SHOW_RIB_DTAIL: imsg_compose(ibuf, IMSG_CTL_SHOW_RIB, 0, 0, -1, NULL, 0); @@ -207,7 +174,6 @@ main(int argc, char *argv[]) else imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, 0, 0, -1, &res->addr, sizeof(res->addr)); - show_fib_head(); break; case SHOW_FIB_IFACE: if (*res->ifname) @@ -215,7 +181,6 @@ main(int argc, char *argv[]) res->ifname, sizeof(res->ifname)); else imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1, NULL, 0); - show_interface_head(); break; case FIB: errx(1, "fib couple|decouple"); @@ -255,72 +220,30 @@ main(int argc, char *argv[]) if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) err(1, "write error"); - while (!done) { - if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) - errx(1, "imsg_read error"); - if (n == 0) - errx(1, "pipe closed"); + // Don't attempt output for certain commands such as log verbose + if(!done){ + output->head(res); while (!done) { - if ((n = imsg_get(ibuf, &imsg)) == -1) - errx(1, "imsg_get error"); + if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) + errx(1, "imsg_read error"); if (n == 0) - break; - switch (res->action) { - case SHOW: - case SHOW_SUM: - done = show_summary_msg(&imsg); - break; - case SHOW_IFACE: - done = show_interface_msg(&imsg); - break; - case SHOW_IFACE_DTAIL: - done = show_interface_detail_msg(&imsg); - break; - case SHOW_NBR: - done = show_nbr_msg(&imsg); - break; - case SHOW_NBR_DTAIL: - done = show_nbr_detail_msg(&imsg); - break; - case SHOW_DB: - case SHOW_DBBYAREA: - case SHOW_DBSELF: - done = show_database_msg(&imsg); - break; - case SHOW_DBEXT: - case SHOW_DBNET: - case SHOW_DBRTR: - case SHOW_DBSUM: - case SHOW_DBASBR: - case SHOW_DBOPAQ: - done = show_db_msg_detail(&imsg); - break; - case SHOW_RIB: - done = show_rib_msg(&imsg); - break; - case SHOW_RIB_DTAIL: - done = show_rib_detail_msg(&imsg); - break; - case SHOW_FIB: - done = show_fib_msg(&imsg); - break; - case SHOW_FIB_IFACE: - done = show_fib_interface_msg(&imsg); - break; - case NONE: - case FIB: - case FIB_COUPLE: - case FIB_DECOUPLE: - case FIB_RELOAD: - case LOG_VERBOSE: - case LOG_BRIEF: - case RELOAD: - break; + errx(1, "pipe closed"); + + while (!done) { + if ((n = imsg_get(ibuf, &imsg)) == -1) + errx(1, "imsg_get error"); + if (n == 0) + break; + + done = show(&imsg, res); + imsg_free(&imsg); } - imsg_free(&imsg); } + + output->tail(); } + close(ctl_sock); free(ibuf); @@ -328,45 +251,94 @@ main(int argc, char *argv[]) } int -show_summary_msg(struct imsg *imsg) +show(struct imsg *imsg, struct parse_result *res) { struct ctl_sum *sum; struct ctl_sum_area *sumarea; + struct ctl_iface *ctliface; + struct ctl_nbr *nbr; + struct ctl_rt *rt; + struct kroute *k; + struct kif *kif; + + static struct in_addr area_id; + struct area *area; + static u_int8_t lasttype; + static char ifname[IF_NAMESIZE]; + struct iface *iface; + struct lsa *lsa; + struct lsa_hdr *lsa_hdr; switch (imsg->hdr.type) { case IMSG_CTL_SHOW_SUM: sum = imsg->data; - printf("Router ID: %s\n", inet_ntoa(sum->rtr_id)); - printf("Uptime: %s\n", fmt_timeframe_core(sum->uptime)); - printf("RFC1583 compatibility flag is "); - if (sum->rfc1583compat) - printf("enabled\n"); - else - printf("disabled\n"); - - printf("SPF delay is %d msec(s), hold time between two SPFs " - "is %d msec(s)\n", sum->spf_delay, sum->spf_hold_time); - printf("Number of external LSA(s) %d (Checksum sum 0x%x)\n", - sum->num_ext_lsa, sum->ext_lsa_cksum); - printf("Number of areas attached to this router: %d\n", - sum->num_area); + output->summary(sum); break; case IMSG_CTL_SHOW_SUM_AREA: sumarea = imsg->data; - printf("\nArea ID: %s\n", inet_ntoa(sumarea->area)); - printf(" Number of interfaces in this area: %d\n", - sumarea->num_iface); - printf(" Number of fully adjacent neighbors in this " - "area: %d\n", sumarea->num_adj_nbr); - printf(" SPF algorithm executed %d time(s)\n", - sumarea->num_spf_calc); - printf(" Number LSA(s) %d (Checksum sum 0x%x)\n", - sumarea->num_lsa, sumarea->lsa_cksum); + output->summary_area(sumarea); + break; + case IMSG_CTL_SHOW_INTERFACE: + ctliface = imsg->data; + if(res->action == SHOW_IFACE_DTAIL) + output->interface(ctliface, 1); + else + output->interface(ctliface, 0); + break; + case IMSG_CTL_SHOW_NBR: + nbr = imsg->data; + if(res->action == SHOW_NBR_DTAIL) + output->neighbor(nbr, 1); + else + output->neighbor(nbr, 0); + break; + case IMSG_CTL_SHOW_RIB: + rt = imsg->data; + if(res->action == SHOW_RIB_DTAIL) + output->rib(rt, 1); + else + output->rib(rt, 0); + break; + case IMSG_CTL_KROUTE: + if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kroute)) + errx(1, "wrong imsg len"); + k = imsg->data; + output->fib(k); + break; + case IMSG_CTL_IFINFO: + kif = imsg->data; + output->fib_interface(kif); + break; + case IMSG_CTL_SHOW_DB_EXT: + case IMSG_CTL_SHOW_DB_NET: + case IMSG_CTL_SHOW_DB_RTR: + case IMSG_CTL_SHOW_DB_SUM: + case IMSG_CTL_SHOW_DB_ASBR: + case IMSG_CTL_SHOW_DB_OPAQ: + lsa = imsg->data; + output->db(lsa, area_id, lasttype, ifname); + lasttype = lsa->hdr.type; + break; + case IMSG_CTL_SHOW_DATABASE: + case IMSG_CTL_SHOW_DB_SELF: + lsa_hdr = imsg->data; + output->db_simple(lsa_hdr, area_id, lasttype, ifname); + lasttype = lsa_hdr->type; + break; + case IMSG_CTL_AREA: + area = imsg->data; + area_id = area->id; + lasttype = 0; + break; + case IMSG_CTL_IFACE: + iface = imsg->data; + strlcpy(ifname, iface->name, sizeof(ifname)); + lasttype = 0; break; case IMSG_CTL_END: - printf("\n"); return (1); default: + warnx("unknown imsg %d received", imsg->hdr.type); break; } @@ -390,118 +362,6 @@ get_ifms_type(uint8_t if_type) } } -int -show_interface_msg(struct imsg *imsg) -{ - struct ctl_iface *iface; - char *netid; - - switch (imsg->hdr.type) { - case IMSG_CTL_SHOW_INTERFACE: - iface = imsg->data; - - if (asprintf(&netid, "%s/%d", inet_ntoa(iface->addr), - mask2prefixlen(iface->mask.s_addr)) == -1) - err(1, NULL); - printf("%-11s %-18s %-6s %-10s %-10s %s %3d %3d\n", - iface->name, netid, if_state_name(iface->state), - iface->hello_timer.tv_sec < 0 ? "-" : - fmt_timeframe_core(iface->hello_timer.tv_sec), - get_linkstate(iface->if_type, iface->linkstate), - fmt_timeframe_core(iface->uptime), - iface->nbr_cnt, iface->adj_cnt); - free(netid); - break; - case IMSG_CTL_END: - printf("\n"); - return (1); - default: - break; - } - - return (0); -} - -int -show_interface_detail_msg(struct imsg *imsg) -{ - struct ctl_iface *iface; - - switch (imsg->hdr.type) { - case IMSG_CTL_SHOW_INTERFACE: - iface = imsg->data; - printf("\n"); - printf("Interface %s, line protocol is %s\n", - iface->name, print_link(iface->flags)); - printf(" Internet address %s/%d, ", - inet_ntoa(iface->addr), - mask2prefixlen(iface->mask.s_addr)); - printf("Area %s\n", inet_ntoa(iface->area)); - printf(" Linkstate %s,", - get_linkstate(iface->if_type, iface->linkstate)); - printf(" mtu %d\n", iface->mtu); - printf(" Router ID %s, network type %s, cost: %d\n", - inet_ntoa(iface->rtr_id), - if_type_name(iface->type), iface->metric); - printf(" Transmit delay is %d sec(s), state %s, priority %d\n", - iface->transmit_delay, if_state_name(iface->state), - iface->priority); - printf(" Designated Router (ID) %s, ", - inet_ntoa(iface->dr_id)); - printf("interface address %s\n", inet_ntoa(iface->dr_addr)); - printf(" Backup Designated Router (ID) %s, ", - inet_ntoa(iface->bdr_id)); - printf("interface address %s\n", inet_ntoa(iface->bdr_addr)); - if (iface->dead_interval == FAST_RTR_DEAD_TIME) { - printf(" Timer intervals configured, " - "hello %d msec, dead %d, wait %d, retransmit %d\n", - iface->fast_hello_interval, iface->dead_interval, - iface->dead_interval, iface->rxmt_interval); - - } else { - printf(" Timer intervals configured, " - "hello %d, dead %d, wait %d, retransmit %d\n", - iface->hello_interval, iface->dead_interval, - iface->dead_interval, iface->rxmt_interval); - } - if (iface->passive) - printf(" Passive interface (No Hellos)\n"); - else if (iface->hello_timer.tv_sec < 0) - printf(" Hello timer not running\n"); - else - printf(" Hello timer due in %s+%ldmsec\n", - fmt_timeframe_core(iface->hello_timer.tv_sec), - iface->hello_timer.tv_usec / 1000); - printf(" Uptime %s\n", fmt_timeframe_core(iface->uptime)); - printf(" Neighbor count is %d, adjacent neighbor count is " - "%d\n", iface->nbr_cnt, iface->adj_cnt); - if (iface->auth_type > 0) { - switch (iface->auth_type) { - case AUTH_SIMPLE: - printf(" Simple password authentication " - "enabled\n"); - break; - case AUTH_CRYPT: - printf(" Message digest authentication " - "enabled\n"); - printf(" Primary key id is %d\n", - iface->auth_keyid); - break; - default: - break; - } - } - break; - case IMSG_CTL_END: - printf("\n"); - return (1); - default: - break; - } - - return (0); -} - const char * print_link(int state) { @@ -514,15 +374,6 @@ print_link(int state) #define TF_BUFS 8 #define TF_LEN 9 -const char * -fmt_timeframe(time_t t) -{ - if (t == 0) - return ("Never"); - else - return (fmt_timeframe_core(time(NULL) - t)); -} - const char * fmt_timeframe_core(time_t t) { @@ -598,108 +449,6 @@ mask2prefixlen(in_addr_t ina) return (33 - ffs(ntohl(ina))); } -void -show_database_head(struct in_addr aid, char *ifname, u_int8_t type) -{ - char *header, *format; - int cleanup = 0; - - switch (type) { - case LSA_TYPE_ROUTER: - format = "Router Link States"; - break; - case LSA_TYPE_NETWORK: - format = "Net Link States"; - break; - case LSA_TYPE_SUM_NETWORK: - format = "Summary Net Link States"; - break; - case LSA_TYPE_SUM_ROUTER: - format = "Summary Router Link States"; - break; - case LSA_TYPE_EXTERNAL: - format = NULL; - if ((header = strdup("Type-5 AS External Link States")) == NULL) - err(1, NULL); - break; - case LSA_TYPE_LINK_OPAQ: - format = "Type-9 Link Local Opaque Link States"; - break; - case LSA_TYPE_AREA_OPAQ: - format = "Type-10 Area Local Opaque Link States"; - break; - case LSA_TYPE_AS_OPAQ: - format = NULL; - if ((header = strdup("Type-11 AS Wide Opaque Link States")) == - NULL) - err(1, NULL); - break; - default: - if (asprintf(&format, "LSA type %x", ntohs(type)) == -1) - err(1, NULL); - cleanup = 1; - break; - } - if (type == LSA_TYPE_LINK_OPAQ) { - if (asprintf(&header, "%s (Area %s Interface %s)", format, - inet_ntoa(aid), ifname) == -1) - err(1, NULL); - } else if (type != LSA_TYPE_EXTERNAL && type != LSA_TYPE_AS_OPAQ) - if (asprintf(&header, "%s (Area %s)", format, - inet_ntoa(aid)) == -1) - err(1, NULL); - - printf("\n%-15s %s\n\n", "", header); - free(header); - if (cleanup) - free(format); -} - -int -show_database_msg(struct imsg *imsg) -{ - static struct in_addr area_id; - static char ifname[IF_NAMESIZE]; - static u_int8_t lasttype; - struct area *area; - struct iface *iface; - struct lsa_hdr *lsa; - - switch (imsg->hdr.type) { - case IMSG_CTL_SHOW_DATABASE: - case IMSG_CTL_SHOW_DB_SELF: - lsa = imsg->data; - if (lsa->type != lasttype) { - show_database_head(area_id, ifname, lsa->type); - printf("%-15s %-15s %-4s %-10s %-8s\n", "Link ID", - "Adv Router", "Age", "Seq#", "Checksum"); - } - printf("%-15s %-15s %-4d 0x%08x 0x%04x\n", - log_id(lsa->ls_id), log_adv_rtr(lsa->adv_rtr), - ntohs(lsa->age), ntohl(lsa->seq_num), - ntohs(lsa->ls_chksum)); - lasttype = lsa->type; - break; - case IMSG_CTL_AREA: - area = imsg->data; - area_id = area->id; - lasttype = 0; - break; - case IMSG_CTL_IFACE: - iface = imsg->data; - strlcpy(ifname, iface->name, sizeof(ifname)); - lasttype = 0; - break; - case IMSG_CTL_END: - printf("\n"); - return (1); - default: - break; - } - - return (0); -} - char * print_ls_type(u_int8_t type) { @@ -725,47 +474,6 @@ print_ls_type(u_int8_t type) } } -void -show_db_hdr_msg_detail(struct lsa_hdr *lsa) -{ - printf("LS age: %d\n", ntohs(lsa->age)); - printf("Options: %s\n", print_ospf_options(lsa->opts)); - printf("LS Type: %s\n", print_ls_type(lsa->type)); - - switch (lsa->type) { - case LSA_TYPE_ROUTER: - printf("Link State ID: %s\n", log_id(lsa->ls_id)); - break; - case LSA_TYPE_NETWORK: - printf("Link State ID: %s (address of Designated Router)\n", - log_id(lsa->ls_id)); - break; - case LSA_TYPE_SUM_NETWORK: - printf("Link State ID: %s (Network ID)\n", log_id(lsa->ls_id)); - break; - case LSA_TYPE_SUM_ROUTER: - printf("Link State ID: %s (ASBR Router ID)\n", - log_id(lsa->ls_id)); - break; - case LSA_TYPE_EXTERNAL: - printf("Link State ID: %s (External Network Number)\n", - log_id(lsa->ls_id)); - break; - case LSA_TYPE_LINK_OPAQ: - case LSA_TYPE_AREA_OPAQ: - case LSA_TYPE_AS_OPAQ: - printf("Link State ID: %s Type %d ID %d\n", log_id(lsa->ls_id), - LSA_24_GETHI(ntohl(lsa->ls_id)), - LSA_24_GETLO(ntohl(lsa->ls_id))); - break; - } - - printf("Advertising Router: %s\n", log_adv_rtr(lsa->adv_rtr)); - printf("LS Seq Number: 0x%08x\n", ntohl(lsa->seq_num)); - printf("Checksum: 0x%04x\n", ntohs(lsa->ls_chksum)); - printf("Length: %d\n", ntohs(lsa->len)); -} - char * print_rtr_link_type(u_int8_t type) { @@ -795,190 +503,6 @@ print_ospf_flags(u_int8_t opts) return (optbuf); } -int -show_db_msg_detail(struct imsg *imsg) -{ - static struct in_addr area_id; - static char ifname[IF_NAMESIZE]; - static u_int8_t lasttype; - struct in_addr addr, data; - struct area *area; - struct iface *iface; - struct lsa *lsa; - struct lsa_rtr_link *rtr_link; - struct lsa_asext *asext; - u_int16_t i, nlinks, off; - - /* XXX sanity checks! */ - - switch (imsg->hdr.type) { - case IMSG_CTL_SHOW_DB_EXT: - lsa = imsg->data; - if (lsa->hdr.type != lasttype) - show_database_head(area_id, ifname, lsa->hdr.type); - show_db_hdr_msg_detail(&lsa->hdr); - addr.s_addr = lsa->data.asext.mask; - printf("Network Mask: %s\n", inet_ntoa(addr)); - - asext = (struct lsa_asext *)((char *)lsa + sizeof(lsa->hdr)); - - printf(" Metric type: "); - if (ntohl(lsa->data.asext.metric) & LSA_ASEXT_E_FLAG) - printf("2\n"); - else - printf("1\n"); - printf(" Metric: %d\n", ntohl(asext->metric) - & LSA_METRIC_MASK); - addr.s_addr = asext->fw_addr; - printf(" Forwarding Address: %s\n", inet_ntoa(addr)); - printf(" External Route Tag: %d\n\n", ntohl(asext->ext_tag)); - - lasttype = lsa->hdr.type; - break; - case IMSG_CTL_SHOW_DB_NET: - lsa = imsg->data; - if (lsa->hdr.type != lasttype) - show_database_head(area_id, ifname, lsa->hdr.type); - show_db_hdr_msg_detail(&lsa->hdr); - addr.s_addr = lsa->data.net.mask; - printf("Network Mask: %s\n", inet_ntoa(addr)); - - nlinks = (ntohs(lsa->hdr.len) - sizeof(struct lsa_hdr) - - sizeof(u_int32_t)) / sizeof(struct lsa_net_link); - off = sizeof(lsa->hdr) + sizeof(u_int32_t); - printf("Number of Routers: %d\n", nlinks); - - for (i = 0; i < nlinks; i++) { - addr.s_addr = lsa->data.net.att_rtr[i]; - printf(" Attached Router: %s\n", inet_ntoa(addr)); - } - - printf("\n"); - lasttype = lsa->hdr.type; - break; - case IMSG_CTL_SHOW_DB_RTR: - lsa = imsg->data; - if (lsa->hdr.type != lasttype) - show_database_head(area_id, ifname, lsa->hdr.type); - show_db_hdr_msg_detail(&lsa->hdr); - printf("Flags: %s\n", print_ospf_flags(lsa->data.rtr.flags)); - nlinks = ntohs(lsa->data.rtr.nlinks); - printf("Number of Links: %d\n\n", nlinks); - - off = sizeof(lsa->hdr) + sizeof(struct lsa_rtr); - - for (i = 0; i < nlinks; i++) { - rtr_link = (struct lsa_rtr_link *)((char *)lsa + off); - - printf(" Link connected to: %s\n", - print_rtr_link_type(rtr_link->type)); - - addr.s_addr = rtr_link->id; - data.s_addr = rtr_link->data; - - switch (rtr_link->type) { - case LINK_TYPE_POINTTOPOINT: - case LINK_TYPE_VIRTUAL: - printf(" Link ID (Neighbors Router ID):" - " %s\n", inet_ntoa(addr)); - printf(" Link Data (Router Interface " - "address): %s\n", inet_ntoa(data)); - break; - case LINK_TYPE_TRANSIT_NET: - printf(" Link ID (Designated Router " - "address): %s\n", inet_ntoa(addr)); - printf(" Link Data (Router Interface " - "address): %s\n", inet_ntoa(data)); - break; - case LINK_TYPE_STUB_NET: - printf(" Link ID (Network ID): %s\n", - inet_ntoa(addr)); - printf(" Link Data (Network Mask): %s\n", - inet_ntoa(data)); - break; - default: - printf(" Link ID (Unknown): %s\n", - inet_ntoa(addr)); - printf(" Link Data (Unknown): %s\n", - inet_ntoa(data)); - break; - } - - printf(" Metric: %d\n\n", ntohs(rtr_link->metric)); - - off += sizeof(struct lsa_rtr_link) + - rtr_link->num_tos * sizeof(u_int32_t); - } - - lasttype = lsa->hdr.type; - break; - case IMSG_CTL_SHOW_DB_SUM: - case IMSG_CTL_SHOW_DB_ASBR: - lsa = imsg->data; - if (lsa->hdr.type != lasttype) - show_database_head(area_id, ifname, lsa->hdr.type); - show_db_hdr_msg_detail(&lsa->hdr); - addr.s_addr = lsa->data.sum.mask; - printf("Network Mask: %s\n", inet_ntoa(addr)); - printf("Metric: %d\n\n", ntohl(lsa->data.sum.metric) & - LSA_METRIC_MASK); - lasttype = lsa->hdr.type; - break; - case IMSG_CTL_SHOW_DB_OPAQ: - lsa = imsg->data; - if (lsa->hdr.type != lasttype) - show_database_head(area_id, ifname, lsa->hdr.type); - show_db_hdr_msg_detail(&lsa->hdr); - /* XXX should we hexdump the data? */ - lasttype = lsa->hdr.type; - break; - case IMSG_CTL_AREA: - area = imsg->data; - area_id = area->id; - lasttype = 0; - break; - case IMSG_CTL_IFACE: - iface = imsg->data; - strlcpy(ifname, iface->name, sizeof(ifname)); - lasttype = 0; - break; - case IMSG_CTL_END: - return (1); - default: - break; - } - - return (0); -} - -int -show_nbr_msg(struct imsg *imsg) -{ - struct ctl_nbr *nbr; - char *state; - - switch (imsg->hdr.type) { - case IMSG_CTL_SHOW_NBR: - nbr = imsg->data; - if (asprintf(&state, "%s/%s", nbr_state_name(nbr->nbr_state), - if_state_name(nbr->iface_state)) == -1) - err(1, NULL); - printf("%-15s %-3d %-12s %-9s", inet_ntoa(nbr->id), - nbr->priority, state, fmt_timeframe_core(nbr->dead_timer)); - printf("%-15s %-9s %s\n", inet_ntoa(nbr->addr), nbr->name, - nbr->uptime == 0 ? "-" : fmt_timeframe_core(nbr->uptime)); - free(state); - break; - case IMSG_CTL_END: - printf("\n"); - return (1); - default: - break; - } - - return (0); -} - const char * print_ospf_options(u_int8_t opts) { @@ -996,128 +520,6 @@ print_ospf_options(u_int8_t opts) return (optbuf); } -int -show_nbr_detail_msg(struct imsg *imsg) -{ - struct ctl_nbr *nbr; - - switch (imsg->hdr.type) { - case IMSG_CTL_SHOW_NBR: - nbr = imsg->data; - printf("\nNeighbor %s, ", inet_ntoa(nbr->id)); - printf("interface address %s\n", inet_ntoa(nbr->addr)); - printf(" Area %s, interface %s\n", inet_ntoa(nbr->area), - nbr->name); - printf(" Neighbor priority is %d, " - "State is %s, %d state changes\n", - nbr->priority, nbr_state_name(nbr->nbr_state), - nbr->state_chng_cnt); - printf(" DR is %s, ", inet_ntoa(nbr->dr)); - printf("BDR is %s\n", inet_ntoa(nbr->bdr)); - printf(" Options %s\n", print_ospf_options(nbr->options)); - printf(" Dead timer due in %s\n", - fmt_timeframe_core(nbr->dead_timer)); - printf(" Uptime %s\n", fmt_timeframe_core(nbr->uptime)); - printf(" Database Summary List %d\n", nbr->db_sum_lst_cnt); - printf(" Link State Request List %d\n", nbr->ls_req_lst_cnt); - printf(" Link State Retransmission List %d\n", - nbr->ls_retrans_lst_cnt); - break; - case IMSG_CTL_END: - printf("\n"); - return (1); - default: - break; - } - - return (0); -} - -int -show_rib_msg(struct imsg *imsg) -{ - struct ctl_rt *rt; - char *dstnet; - - switch (imsg->hdr.type) { - case IMSG_CTL_SHOW_RIB: - rt = imsg->data; - switch (rt->d_type) { - case DT_NET: - if (asprintf(&dstnet, "%s/%d", inet_ntoa(rt->prefix), - rt->prefixlen) == -1) - err(1, NULL); - break; - case DT_RTR: - if (asprintf(&dstnet, "%s", - inet_ntoa(rt->prefix)) == -1) - err(1, NULL); - break; - default: - errx(1, "Invalid route type"); - } - - printf("%-20s %-16s%s %-12s %-9s %-7d %s\n", dstnet, - inet_ntoa(rt->nexthop), rt->connected ? "C" : " ", - path_type_name(rt->p_type), - dst_type_name(rt->d_type), rt->cost, - rt->uptime == 0 ? "-" : fmt_timeframe_core(rt->uptime)); - free(dstnet); - break; - case IMSG_CTL_END: - printf("\n"); - return (1); - default: - break; - } - - return (0); -} - -void -show_rib_head(struct in_addr aid, u_int8_t d_type, u_int8_t p_type) -{ - char *header, *format, *format2; - - switch (p_type) { - case PT_INTRA_AREA: - case PT_INTER_AREA: - switch (d_type) { - case DT_NET: - format = "Network Routing Table"; - format2 = ""; - break; - case DT_RTR: - format = "Router Routing Table"; - format2 = "Type"; - break; - default: - errx(1, "unknown route type"); - } - break; - case PT_TYPE1_EXT: - case PT_TYPE2_EXT: - format = NULL; - format2 = "Cost 2"; - if ((header = strdup("External Routing Table")) == NULL) - err(1, NULL); - break; - default: - errx(1, "unknown route type"); - } - - if (p_type != PT_TYPE1_EXT && p_type != PT_TYPE2_EXT) - if (asprintf(&header, "%s (Area %s)", format, - inet_ntoa(aid)) == -1) - err(1, NULL); - - printf("\n%-18s %s\n", "", header); - free(header); - - printf("\n%-18s %-15s %-15s %-12s %-7s %-7s\n", "Destination", - "Nexthop", "Adv Router", "Path type", "Cost", format2); -} - const char * print_ospf_rtr_flags(u_int8_t opts) { @@ -1130,155 +532,6 @@ print_ospf_rtr_flags(u_int8_t opts) return (optbuf); } -int -show_rib_detail_msg(struct imsg *imsg) -{ - static struct in_addr area_id; - struct ctl_rt *rt; - struct area *area; - char *dstnet; - static u_int8_t lasttype; - - switch (imsg->hdr.type) { - case IMSG_CTL_SHOW_RIB: - rt = imsg->data; - - switch (rt->p_type) { - case PT_INTRA_AREA: - case PT_INTER_AREA: - switch (rt->d_type) { - case DT_NET: - if (lasttype != RIB_NET) - show_rib_head(rt->area, rt->d_type, - rt->p_type); - if (asprintf(&dstnet, "%s/%d", - inet_ntoa(rt->prefix), rt->prefixlen) == -1) - err(1, NULL); - lasttype = RIB_NET; - break; - case DT_RTR: - if (lasttype != RIB_RTR) - show_rib_head(rt->area, rt->d_type, - rt->p_type); - if (asprintf(&dstnet, "%s", - inet_ntoa(rt->prefix)) == -1) - err(1, NULL); - lasttype = RIB_RTR; - break; - default: - errx(1, "unknown route type"); - } - printf("%-18s %-15s ", dstnet, inet_ntoa(rt->nexthop)); - printf("%-15s %-12s %-7d", inet_ntoa(rt->adv_rtr), - path_type_name(rt->p_type), rt->cost); - free(dstnet); - - if (rt->d_type == DT_RTR) - printf(" %-7s", - print_ospf_rtr_flags(rt->flags)); - - printf("\n"); - break; - case PT_TYPE1_EXT: - case PT_TYPE2_EXT: - if (lasttype != RIB_EXT) - show_rib_head(rt->area, rt->d_type, rt->p_type); - - if (asprintf(&dstnet, "%s/%d", - inet_ntoa(rt->prefix), rt->prefixlen) == -1) - err(1, NULL); - - printf("%-18s %-15s ", dstnet, inet_ntoa(rt->nexthop)); - printf("%-15s %-12s %-7d %-7d\n", - inet_ntoa(rt->adv_rtr), path_type_name(rt->p_type), - rt->cost, rt->cost2); - free(dstnet); - - lasttype = RIB_EXT; - break; - default: - errx(1, "unknown route type"); - } - break; - case IMSG_CTL_AREA: - area = imsg->data; - area_id = area->id; - break; - case IMSG_CTL_END: - printf("\n"); - return (1); - default: - break; - } - - return (0); -} - -void -show_fib_head(void) -{ - printf("flags: * = valid, O = OSPF, C = Connected, S = Static\n"); - printf("%-6s %-4s %-20s %-17s\n", "Flags", "Prio", "Destination", "Nexthop"); -} - -int -show_fib_msg(struct imsg *imsg) -{ - struct kroute *k; - char *p; - - switch (imsg->hdr.type) { - case IMSG_CTL_KROUTE: - if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kroute)) - errx(1, "wrong imsg len"); - k = imsg->data; - - if (k->flags & F_DOWN) - printf(" "); - else - printf("*"); - - if (!(k->flags & F_KERNEL)) - printf("O"); - else if (k->flags & F_CONNECTED) - printf("C"); - else if (k->flags & F_STATIC) - printf("S"); - else - printf(" "); - - printf(" "); - printf("%4d ", k->priority); - if (asprintf(&p, "%s/%u", inet_ntoa(k->prefix), k->prefixlen) == - -1) - err(1, NULL); - printf("%-20s ", 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); - printf("\n"); - - break; - case IMSG_CTL_END: - printf("\n"); - return (1); - default: - break; - } - - return (0); -} - -void -show_interface_head(void) -{ - printf("%-15s%-15s%s\n", "Interface", "Flags", - "Link state"); -} - const struct if_status_description if_status_descriptions[] = LINK_STATE_DESCRIPTIONS; const struct ifmedia_description @@ -1310,48 +563,18 @@ get_linkstate(uint8_t if_type, int link_state) return (buf); } -void +const char * print_baudrate(u_int64_t baudrate) { + static char buf[32]; if (baudrate > IF_Gbps(1)) - printf("%llu GBit/s", baudrate / IF_Gbps(1)); + snprintf(buf, sizeof(buf), "%llu GBit/s", baudrate / IF_Gbps(1)); else if (baudrate > IF_Mbps(1)) - printf("%llu MBit/s", baudrate / IF_Mbps(1)); + snprintf(buf, sizeof(buf), "%llu MBit/s", baudrate / IF_Mbps(1)); else if (baudrate > IF_Kbps(1)) - printf("%llu KBit/s", baudrate / IF_Kbps(1)); + snprintf(buf, sizeof(buf), "%llu KBit/s", baudrate / IF_Kbps(1)); else - printf("%llu Bit/s", baudrate); + snprintf(buf, sizeof(buf), "%llu Bit/s", baudrate); + return (buf); } -int -show_fib_interface_msg(struct imsg *imsg) -{ - struct kif *k; - uint64_t ifms_type; - - switch (imsg->hdr.type) { - case IMSG_CTL_IFINFO: - k = imsg->data; - printf("%-15s", k->ifname); - printf("%-15s", k->flags & IFF_UP ? "UP" : ""); - ifms_type = get_ifms_type(k->if_type); - if (ifms_type) - printf("%s, ", get_media_descr(ifms_type)); - - printf("%s", get_linkstate(k->if_type, k->link_state)); - - if (k->link_state != LINK_STATE_DOWN && k->baudrate > 0) { - printf(", "); - print_baudrate(k->baudrate); - } - printf("\n"); - break; - case IMSG_CTL_END: - printf("\n"); - return (1); - default: - break; - } - - return (0); -} diff --git a/usr.sbin/ospfctl/ospfctl.h b/usr.sbin/ospfctl/ospfctl.h new file mode 100644 index 00000000000..3077307cce6 --- /dev/null +++ b/usr.sbin/ospfctl/ospfctl.h @@ -0,0 +1,55 @@ +/* +* Copyright (c) 2005 Claudio Jeker <clau...@openbsd.org> + * Copyright (c) 2004, 2005 Esben Norby <no...@openbsd.org> + * Copyright (c) 2003 Henning Brauer <henn...@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +struct parse_result; + +struct output { + void (*head)(struct parse_result *); + void (*interface)(struct ctl_iface *, int); + void (*summary)(struct ctl_sum *); + void (*summary_area)(struct ctl_sum_area *); + void (*neighbor)(struct ctl_nbr *, int); + void (*rib)(struct ctl_rt *, int); + void (*fib)(struct kroute *); + void (*fib_interface)(struct kif *); + void (*db)(struct lsa *, struct in_addr, u_int8_t, + char ifname[IF_NAMESIZE]); + void (*db_simple)(struct lsa_hdr *, struct in_addr, u_int8_t, + char ifname[IF_NAMESIZE]); + void (*tail)(void); +}; + +extern const struct output show_output, json_output; + + + +#define EOL0(flag) ((flag & F_CTL_SSV) ? ';' : '\n') + +const char *fmt_timeframe_core(time_t); +const char *get_linkstate(uint8_t, int); +const char *print_ospf_rtr_flags(u_int8_t); +const char *print_ospf_options(u_int8_t); +uint64_t get_ifms_type(uint8_t); +const char *get_media_descr(uint64_t); +const char *print_baudrate(u_int64_t); +const char *print_link(int); +char *print_ls_type(u_int8_t); +const char *log_id(u_int32_t ); +const char *log_adv_rtr(u_int32_t); +const char *print_ospf_flags(u_int8_t); +char *print_rtr_link_type(u_int8_t); diff --git a/usr.sbin/ospfctl/output.c b/usr.sbin/ospfctl/output.c new file mode 100644 index 00000000000..f31eeb3c460 --- /dev/null +++ b/usr.sbin/ospfctl/output.c @@ -0,0 +1,650 @@ +/* + * Copyright (c) 2020 Richard Chivers <r.chiv...@zengenti.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <net/if_media.h> +#include <net/if_types.h> + +#include <err.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "ospf.h" +#include "ospfd.h" +#include "ospfctl.h" +#include "ospfe.h" +#include "parser.h" + +static void +show_head(struct parse_result *res) +{ + switch (res->action) { + case SHOW_IFACE: + printf("%-11s %-18s %-6s %-10s %-10s %-8s %3s %3s\n", + "Interface", "Address", "State", "HelloTimer", "Linkstate", + "Uptime", "nc", "ac"); + break; + case SHOW_FIB: + printf("flags: * = valid, O = OSPF, C = Connected, S = Static\n"); + printf("%-6s %-4s %-20s %-17s\n", "Flags", "Prio", "Destination", + "Nexthop"); + break; + case SHOW_FIB_IFACE: + printf("%-15s%-15s%s\n", "Interface", "Flags", "Link state"); + break; + case SHOW_NBR: + printf("%-15s %-3s %-12s %-8s %-15s %-9s %s\n", "ID", "Pri", + "State", "DeadTime", "Address", "Iface","Uptime"); + break; + case SHOW_RIB: + printf("%-20s %-17s %-12s %-9s %-7s %-8s\n", "Destination", + "Nexthop", "Path Type", "Type", "Cost", "Uptime"); + break; + default: + break; + } +} + +static void +show_summary(struct ctl_sum *sum) +{ + printf("Router ID: %s\n", inet_ntoa(sum->rtr_id)); + printf("Uptime: %s\n", fmt_timeframe_core(sum->uptime)); + printf("RFC1583 compatibility flag is "); + if (sum->rfc1583compat) + printf("enabled\n"); + else + printf("disabled\n"); + + printf("SPF delay is %d msec(s), hold time between two SPFs " + "is %d msec(s)\n", sum->spf_delay, sum->spf_hold_time); + printf("Number of external LSA(s) %d (Checksum sum 0x%x)\n", + sum->num_ext_lsa, sum->ext_lsa_cksum); + printf("Number of areas attached to this router: %d\n", + sum->num_area); +} + +static void +show_summary_area(struct ctl_sum_area *sumarea){ + printf("\nArea ID: %s\n", inet_ntoa(sumarea->area)); + printf(" Number of interfaces in this area: %d\n", + sumarea->num_iface); + printf(" Number of fully adjacent neighbors in this " + "area: %d\n", sumarea->num_adj_nbr); + printf(" SPF algorithm executed %d time(s)\n", + sumarea->num_spf_calc); + printf(" Number LSA(s) %d (Checksum sum 0x%x)\n", + sumarea->num_lsa, sumarea->lsa_cksum); +} + +static void +show_rib_head(struct in_addr aid, u_int8_t d_type, u_int8_t p_type) +{ + char *header, *format, *format2; + + switch (p_type) { + case PT_INTRA_AREA: + case PT_INTER_AREA: + switch (d_type) { + case DT_NET: + format = "Network Routing Table"; + format2 = ""; + break; + case DT_RTR: + format = "Router Routing Table"; + format2 = "Type"; + break; + default: + errx(1, "unknown route type"); + } + break; + case PT_TYPE1_EXT: + case PT_TYPE2_EXT: + format = NULL; + format2 = "Cost 2"; + if ((header = strdup("External Routing Table")) == NULL) + err(1, NULL); + break; + default: + errx(1, "unknown route type"); + } + + if (p_type != PT_TYPE1_EXT && p_type != PT_TYPE2_EXT) + if (asprintf(&header, "%s (Area %s)", format, + inet_ntoa(aid)) == -1) + err(1, NULL); + + printf("\n%-18s %s\n", "", header); + free(header); + + printf("\n%-18s %-15s %-15s %-12s %-7s %-7s\n", "Destination", + "Nexthop", "Adv Router", "Path type", "Cost", format2); +} + +static void +show_interface(struct ctl_iface *iface, int detail) +{ + char *netid; + + // This wasn't previously executed on detail call + if (asprintf(&netid, "%s/%d", inet_ntoa(iface->addr), + mask2prefixlen(iface->mask.s_addr)) == -1) + err(1, NULL); + + if(detail){ + printf("\n"); + printf("Interface %s, line protocol is %s\n", + iface->name, print_link(iface->flags)); + printf(" Internet address %s/%d, ", + inet_ntoa(iface->addr), + mask2prefixlen(iface->mask.s_addr)); + printf("Area %s\n", inet_ntoa(iface->area)); + printf(" Linkstate %s,", + get_linkstate(iface->if_type, iface->linkstate)); + printf(" mtu %d\n", iface->mtu); + printf(" Router ID %s, network type %s, cost: %d\n", + inet_ntoa(iface->rtr_id), + if_type_name(iface->type), iface->metric); + printf(" Transmit delay is %d sec(s), state %s, priority %d\n", + iface->transmit_delay, if_state_name(iface->state), + iface->priority); + printf(" Designated Router (ID) %s, ", + inet_ntoa(iface->dr_id)); + printf("interface address %s\n", inet_ntoa(iface->dr_addr)); + printf(" Backup Designated Router (ID) %s, ", + inet_ntoa(iface->bdr_id)); + printf("interface address %s\n", inet_ntoa(iface->bdr_addr)); + if (iface->dead_interval == FAST_RTR_DEAD_TIME) { + printf(" Timer intervals configured, " + "hello %d msec, dead %d, wait %d, retransmit %d\n", + iface->fast_hello_interval, iface->dead_interval, + iface->dead_interval, iface->rxmt_interval); + + } else { + printf(" Timer intervals configured, " + "hello %d, dead %d, wait %d, retransmit %d\n", + iface->hello_interval, iface->dead_interval, + iface->dead_interval, iface->rxmt_interval); + } + if (iface->passive) + printf(" Passive interface (No Hellos)\n"); + else if (iface->hello_timer.tv_sec < 0) + printf(" Hello timer not running\n"); + else + printf(" Hello timer due in %s+%ldmsec\n", + fmt_timeframe_core(iface->hello_timer.tv_sec), + iface->hello_timer.tv_usec / 1000); + printf(" Uptime %s\n", fmt_timeframe_core(iface->uptime)); + printf(" Neighbor count is %d, adjacent neighbor count is " + "%d\n", iface->nbr_cnt, iface->adj_cnt); + if (iface->auth_type > 0) { + switch (iface->auth_type) { + case AUTH_SIMPLE: + printf(" Simple password authentication " + "enabled\n"); + break; + case AUTH_CRYPT: + printf(" Message digest authentication " + "enabled\n"); + printf(" Primary key id is %d\n", + iface->auth_keyid); + break; + default: + break; + } + } + }else{ + printf("%-11s %-18s %-6s %-10s %-10s %s %3d %3d\n", + iface->name, netid, if_state_name(iface->state), + iface->hello_timer.tv_sec < 0 ? "-" : + fmt_timeframe_core(iface->hello_timer.tv_sec), + get_linkstate(iface->if_type, iface->linkstate), + fmt_timeframe_core(iface->uptime), + iface->nbr_cnt, iface->adj_cnt); + } + free(netid); +} + + +static void +show_neighbor(struct ctl_nbr *nbr, int detail) +{ + char *state; + if (asprintf(&state, "%s/%s", nbr_state_name(nbr->nbr_state), + if_state_name(nbr->iface_state)) == -1) + err(1, NULL); + + if(detail){ + printf("\nNeighbor %s, ", inet_ntoa(nbr->id)); + printf("interface address %s\n", inet_ntoa(nbr->addr)); + printf(" Area %s, interface %s\n", inet_ntoa(nbr->area), + nbr->name); + printf(" Neighbor priority is %d, " + "State is %s, %d state changes\n", + nbr->priority, nbr_state_name(nbr->nbr_state), + nbr->state_chng_cnt); + printf(" DR is %s, ", inet_ntoa(nbr->dr)); + printf("BDR is %s\n", inet_ntoa(nbr->bdr)); + printf(" Options %s\n", print_ospf_options(nbr->options)); + printf(" Dead timer due in %s\n", + fmt_timeframe_core(nbr->dead_timer)); + printf(" Uptime %s\n", fmt_timeframe_core(nbr->uptime)); + printf(" Database Summary List %d\n", nbr->db_sum_lst_cnt); + printf(" Link State Request List %d\n", nbr->ls_req_lst_cnt); + printf(" Link State Retransmission List %d\n", + nbr->ls_retrans_lst_cnt); + }else{ + printf("%-15s %-3d %-12s %-9s", inet_ntoa(nbr->id), + nbr->priority, state, fmt_timeframe_core(nbr->dead_timer)); + printf("%-15s %-9s %s\n", inet_ntoa(nbr->addr), nbr->name, + nbr->uptime == 0 ? "-" : fmt_timeframe_core(nbr->uptime)); + } + free(state); +} + +static void +show_rib(struct ctl_rt *rt, int detail) +{ + char *dstnet; + static u_int8_t lasttype; + if(detail){ + switch (rt->p_type) { + case PT_INTRA_AREA: + case PT_INTER_AREA: + switch (rt->d_type) { + case DT_NET: + if (lasttype != RIB_NET) + show_rib_head(rt->area, rt->d_type, + rt->p_type); + if (asprintf(&dstnet, "%s/%d", + inet_ntoa(rt->prefix), rt->prefixlen) == -1) + err(1, NULL); + lasttype = RIB_NET; + break; + case DT_RTR: + if (lasttype != RIB_RTR) + show_rib_head(rt->area, rt->d_type, + rt->p_type); + if (asprintf(&dstnet, "%s", + inet_ntoa(rt->prefix)) == -1) + err(1, NULL); + lasttype = RIB_RTR; + break; + default: + errx(1, "unknown route type"); + } + printf("%-18s %-15s ", dstnet, inet_ntoa(rt->nexthop)); + printf("%-15s %-12s %-7d", inet_ntoa(rt->adv_rtr), + path_type_name(rt->p_type), rt->cost); + free(dstnet); + + if (rt->d_type == DT_RTR) + printf(" %-7s", + print_ospf_rtr_flags(rt->flags)); + + printf("\n"); + break; + case PT_TYPE1_EXT: + case PT_TYPE2_EXT: + if (lasttype != RIB_EXT) + show_rib_head(rt->area, rt->d_type, rt->p_type); + + if (asprintf(&dstnet, "%s/%d", + inet_ntoa(rt->prefix), rt->prefixlen) == -1) + err(1, NULL); + + printf("%-18s %-15s ", dstnet, inet_ntoa(rt->nexthop)); + printf("%-15s %-12s %-7d %-7d\n", + inet_ntoa(rt->adv_rtr), path_type_name(rt->p_type), + rt->cost, rt->cost2); + free(dstnet); + + lasttype = RIB_EXT; + break; + default: + errx(1, "unknown route type"); + } + }else{ + switch (rt->d_type) { + case DT_NET: + if (asprintf(&dstnet, "%s/%d", inet_ntoa(rt->prefix), + rt->prefixlen) == -1) + err(1, NULL); + break; + case DT_RTR: + if (asprintf(&dstnet, "%s", + inet_ntoa(rt->prefix)) == -1) + err(1, NULL); + break; + default: + errx(1, "Invalid route type"); + } + + printf("%-20s %-16s%s %-12s %-9s %-7d %s\n", dstnet, + inet_ntoa(rt->nexthop), rt->connected ? "C" : " ", + path_type_name(rt->p_type), + dst_type_name(rt->d_type), rt->cost, + rt->uptime == 0 ? "-" : fmt_timeframe_core(rt->uptime)); + free(dstnet); + } +} + +static void +show_fib(struct kroute *k) +{ + char *p; + if (k->flags & F_DOWN) + printf(" "); + else + printf("*"); + + if (!(k->flags & F_KERNEL)) + printf("O"); + else if (k->flags & F_CONNECTED) + printf("C"); + else if (k->flags & F_STATIC) + printf("S"); + else + printf(" "); + + printf(" "); + printf("%4d ", k->priority); + if (asprintf(&p, "%s/%u", inet_ntoa(k->prefix), k->prefixlen) == + -1) + err(1, NULL); + printf("%-20s ", 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); + printf("\n"); +} + +static void +show_fib_interface(struct kif *k) +{ + uint64_t ifms_type; + printf("%-15s", k->ifname); + printf("%-15s", k->flags & IFF_UP ? "UP" : ""); + ifms_type = get_ifms_type(k->if_type); + if (ifms_type) + printf("%s, ", get_media_descr(ifms_type)); + + printf("%s", get_linkstate(k->if_type, k->link_state)); + + if (k->link_state != LINK_STATE_DOWN && k->baudrate > 0) { + printf(", "); + printf("%s", print_baudrate(k->baudrate)); + } + printf("\n"); +} + +static void +show_database_head(struct in_addr aid, char *ifname, u_int8_t type) +{ + char *header, *format; + int cleanup = 0; + + switch (type) { + case LSA_TYPE_ROUTER: + format = "Router Link States"; + break; + case LSA_TYPE_NETWORK: + format = "Net Link States"; + break; + case LSA_TYPE_SUM_NETWORK: + format = "Summary Net Link States"; + break; + case LSA_TYPE_SUM_ROUTER: + format = "Summary Router Link States"; + break; + case LSA_TYPE_EXTERNAL: + format = NULL; + if ((header = strdup("Type-5 AS External Link States")) == NULL) + err(1, NULL); + break; + case LSA_TYPE_LINK_OPAQ: + format = "Type-9 Link Local Opaque Link States"; + break; + case LSA_TYPE_AREA_OPAQ: + format = "Type-10 Area Local Opaque Link States"; + break; + case LSA_TYPE_AS_OPAQ: + format = NULL; + if ((header = strdup("Type-11 AS Wide Opaque Link States")) == + NULL) + err(1, NULL); + break; + default: + if (asprintf(&format, "LSA type %x", ntohs(type)) == -1) + err(1, NULL); + cleanup = 1; + break; + } + if (type == LSA_TYPE_LINK_OPAQ) { + if (asprintf(&header, "%s (Area %s Interface %s)", format, + inet_ntoa(aid), ifname) == -1) + err(1, NULL); + } else if (type != LSA_TYPE_EXTERNAL && type != LSA_TYPE_AS_OPAQ) + if (asprintf(&header, "%s (Area %s)", format, + inet_ntoa(aid)) == -1) + err(1, NULL); + + printf("\n%-15s %s\n\n", "", header); + free(header); + if (cleanup) + free(format); +} + +static void +show_db_hdr_msg_detail(struct lsa_hdr *lsa) +{ + printf("LS age: %d\n", ntohs(lsa->age)); + printf("Options: %s\n", print_ospf_options(lsa->opts)); + printf("LS Type: %s\n", print_ls_type(lsa->type)); + + switch (lsa->type) { + case LSA_TYPE_ROUTER: + printf("Link State ID: %s\n", log_id(lsa->ls_id)); + break; + case LSA_TYPE_NETWORK: + printf("Link State ID: %s (address of Designated Router)\n", + log_id(lsa->ls_id)); + break; + case LSA_TYPE_SUM_NETWORK: + printf("Link State ID: %s (Network ID)\n", log_id(lsa->ls_id)); + break; + case LSA_TYPE_SUM_ROUTER: + printf("Link State ID: %s (ASBR Router ID)\n", + log_id(lsa->ls_id)); + break; + case LSA_TYPE_EXTERNAL: + printf("Link State ID: %s (External Network Number)\n", + log_id(lsa->ls_id)); + break; + case LSA_TYPE_LINK_OPAQ: + case LSA_TYPE_AREA_OPAQ: + case LSA_TYPE_AS_OPAQ: + printf("Link State ID: %s Type %d ID %d\n", log_id(lsa->ls_id), + LSA_24_GETHI(ntohl(lsa->ls_id)), + LSA_24_GETLO(ntohl(lsa->ls_id))); + break; + } + + printf("Advertising Router: %s\n", log_adv_rtr(lsa->adv_rtr)); + printf("LS Seq Number: 0x%08x\n", ntohl(lsa->seq_num)); + printf("Checksum: 0x%04x\n", ntohs(lsa->ls_chksum)); + printf("Length: %d\n", ntohs(lsa->len)); +} + +static void +show_db_simple(struct lsa_hdr *lsa, struct in_addr area_id, u_int8_t lasttype, + char ifname[IF_NAMESIZE]) +{ + if (lsa->type != lasttype) { + show_database_head(area_id, ifname, lsa->type); + printf("%-15s %-15s %-4s %-10s %-8s\n", "Link ID", + "Adv Router", "Age", "Seq#", "Checksum"); + } + printf("%-15s %-15s %-4d 0x%08x 0x%04x\n", + log_id(lsa->ls_id), log_adv_rtr(lsa->adv_rtr), + ntohs(lsa->age), ntohl(lsa->seq_num), + ntohs(lsa->ls_chksum)); +} +static void +show_db(struct lsa *lsa, struct in_addr area_id, u_int8_t lasttype, + char ifname[IF_NAMESIZE]) +{ + struct in_addr addr, data; + struct lsa_asext *asext; + struct lsa_rtr_link *rtr_link; + u_int16_t i, nlinks, off; + if (lsa->hdr.type != lasttype) + show_database_head(area_id, ifname, lsa->hdr.type); + show_db_hdr_msg_detail(&lsa->hdr); + + switch (lsa->hdr.type) { + case LSA_TYPE_EXTERNAL: + addr.s_addr = lsa->data.asext.mask; + printf("Network Mask: %s\n", inet_ntoa(addr)); + + asext = (struct lsa_asext *)((char *)lsa + sizeof(lsa->hdr)); + + printf(" Metric type: "); + if (ntohl(lsa->data.asext.metric) & LSA_ASEXT_E_FLAG) + printf("2\n"); + else + printf("1\n"); + printf(" Metric: %d\n", ntohl(asext->metric) + & LSA_METRIC_MASK); + addr.s_addr = asext->fw_addr; + printf(" Forwarding Address: %s\n", inet_ntoa(addr)); + printf(" External Route Tag: %d\n\n", ntohl(asext->ext_tag)); + break; + case LSA_TYPE_NETWORK: + addr.s_addr = lsa->data.net.mask; + printf("Network Mask: %s\n", inet_ntoa(addr)); + + nlinks = (ntohs(lsa->hdr.len) - sizeof(struct lsa_hdr) + - sizeof(u_int32_t)) / sizeof(struct lsa_net_link); + off = sizeof(lsa->hdr) + sizeof(u_int32_t); + printf("Number of Routers: %d\n", nlinks); + + for (i = 0; i < nlinks; i++) { + addr.s_addr = lsa->data.net.att_rtr[i]; + printf(" Attached Router: %s\n", inet_ntoa(addr)); + } + + printf("\n"); + break; + case LSA_TYPE_ROUTER: + printf("Flags: %s\n", print_ospf_flags(lsa->data.rtr.flags)); + nlinks = ntohs(lsa->data.rtr.nlinks); + printf("Number of Links: %d\n\n", nlinks); + + off = sizeof(lsa->hdr) + sizeof(struct lsa_rtr); + + for (i = 0; i < nlinks; i++) { + rtr_link = (struct lsa_rtr_link *)((char *)lsa + off); + + printf(" Link connected to: %s\n", + print_rtr_link_type(rtr_link->type)); + + addr.s_addr = rtr_link->id; + data.s_addr = rtr_link->data; + + switch (rtr_link->type) { + case LINK_TYPE_POINTTOPOINT: + case LINK_TYPE_VIRTUAL: + printf(" Link ID (Neighbors Router ID):" + " %s\n", inet_ntoa(addr)); + printf(" Link Data (Router Interface " + "address): %s\n", inet_ntoa(data)); + break; + case LINK_TYPE_TRANSIT_NET: + printf(" Link ID (Designated Router " + "address): %s\n", inet_ntoa(addr)); + printf(" Link Data (Router Interface " + "address): %s\n", inet_ntoa(data)); + break; + case LINK_TYPE_STUB_NET: + printf(" Link ID (Network ID): %s\n", + inet_ntoa(addr)); + printf(" Link Data (Network Mask): %s\n", + inet_ntoa(data)); + break; + default: + printf(" Link ID (Unknown): %s\n", + inet_ntoa(addr)); + printf(" Link Data (Unknown): %s\n", + inet_ntoa(data)); + break; + } + + printf(" Metric: %d\n\n", ntohs(rtr_link->metric)); + + off += sizeof(struct lsa_rtr_link) + + rtr_link->num_tos * sizeof(u_int32_t); + } + break; + case LSA_TYPE_SUM_ROUTER: + if (lsa->hdr.type != lasttype) + show_database_head(area_id, ifname, lsa->hdr.type); + show_db_hdr_msg_detail(&lsa->hdr); + addr.s_addr = lsa->data.sum.mask; + printf("Network Mask: %s\n", inet_ntoa(addr)); + printf("Metric: %d\n\n", ntohl(lsa->data.sum.metric) & + LSA_METRIC_MASK); + break; + case LSA_TYPE_LINK_OPAQ: + case LSA_TYPE_AREA_OPAQ: + case LSA_TYPE_AS_OPAQ: + if (lsa->hdr.type != lasttype) + show_database_head(area_id, ifname, lsa->hdr.type); + show_db_hdr_msg_detail(&lsa->hdr); + /* XXX should we hexdump the data? */ + break; + } +} + +static void +show_tail(void) +{ + /* nothing */ +} + +const struct output show_output = { + .head = show_head, + .summary = show_summary, + .summary_area = show_summary_area, + .interface = show_interface, + .neighbor = show_neighbor, + .rib = show_rib, + .fib = show_fib, + .fib_interface = show_fib_interface, + .db = show_db, + .db_simple = show_db_simple, + .tail = show_tail +}; On Mon, May 11, 2020 at 1:52 PM Claudio Jeker <cje...@diehard.n-r-g.com> wrote: > > On Mon, May 11, 2020 at 12:38:38PM +0100, Richard Chivers wrote: > > Hi, > > > > I have done some work over the last few days to implement json support > > into ospfctl following the work done recently in bgpctl. > > > > I have some queries, hoping to get some help with. > > > > The change involves a refactor of ospfctl, but reuses the recent > > json.c written by Claudio, that is in the > > usr.sbin/bgpctl directory. At present no changes have been required at all. > > What is the best approach here, should/could this be centralised somewhere? > > At the moment just copy the files into ospfctl. We did the same thing with > other bits in the tree. My json API is super minimal and is for sure not > something that should be put into a common framework right now. The way > objects and arrays are opened and closed is a bit rough and does not > always work well. > > > In some cases there is room for change, for example ospfctl sh rib & > > ospfctl sh rib detail. > > > > In my view here, it makes sense to have a full list returned rather > > than splitting json into multiple lists of Router, Network and > > External. > > I looked for inspiration in the bgpctl, but couldn't find a similar > > pattern. The reason for a single list is that if consuming the json, > > I expect you will not want code that has to iterate over three > > separate arrays. Just looking for some feedback really. The original > > split > > made sense for screen use, just not so sure about machine readability. > > This issue also applies to ospfctl sh data, which returns 3 lists. > > A lot of this is depending on the imsgs used between ospfctl and ospfd. > IIRC ospfd sends all data in one batch so the multiple lists just happen > by ospfctl and indeed for json output it would be best to display the rib > as a single array of entries (which have a similar structure but probably > per LSA specific attributes). > > > When I am finished, should I just post the diff on here? Just > > conscious it is quite a big refactor, albeit much of the code is > > reused just moved into output.c as > > was done for bgpctl. > > Please split it up like I did it for bgpctl. I first did a lot of the > moving and cleanup and only later added the new input mode. This makes the > individual steps smaller to review. > > > I am testing each call individually against a set of openbsd 6.6 boxes > > we have running, which is great for ospfd. What is the normal > > practise for ospf6, is there a script run to replicate code changes or > > is it just a case of making very similar changes line by line? > > There is no script, you do it by hand it is quicker. > > > Just looking for the general thinking and approach I guess. I don't > > currently have ospf6 set-up so that would be some overhead. > > Happy to configure it though if needed/expected. > > Get ospfctl first, after that ospf6ctl can be done (and maybe somebody > else will take care of that). > > > Finally what was the driver under bgpctl for the json output, ours is > > for reading metrics to populate telemetry, just interested as the > > purpose other > > people have. Having this context will help in micro decisions when > > implementing the json structure. > > I'm doing this work to provide JSON payloads to external looking glasses. > I would not put the RIB into telemetry (that is just useless churn and > load on the telemetry system). In bgpctl the terse outputs are simple > space separated outputs for telemetry scripting but I guess people will > also use the JSON output for this. > > > As a final thought is this something that is actually wanted > > generally, I assumed it was as bgpctl has gone/is going in that > > direction, but just don't want to assume. > > I see no reason why not. At least I wont veto it. > > -- > :wq Claudio