Index: usr.sbin/ospfctl/output.c
===================================================================
RCS file: usr.sbin/ospfctl/output.c
diff -N usr.sbin/ospfctl/output.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ usr.sbin/ospfctl/output.c	15 May 2020 08:13:09 -0000
@@ -0,0 +1,654 @@
+/*
+ * Copyright (c) 2020 Richard Chivers <r.chivers@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);
+			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
+};
Index: usr.sbin/ospfctl/ospfctl.c
===================================================================
RCS file: /cvs/src/usr.sbin/ospfctl/ospfctl.c,v
retrieving revision 1.66
diff -u -r1.66 ospfctl.c
--- usr.sbin/ospfctl/ospfctl.c	1 Nov 2019 18:15:28 -0000	1.66
+++ usr.sbin/ospfctl/ospfctl.c	15 May 2020 08:13:09 -0000
@@ -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 @@
 		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 @@
 		    &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 @@
 		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 @@
 		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 @@
 			    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 @@
 		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");
+	/* no 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,93 @@
 }
 
 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 +361,6 @@
 	}
 }
 
-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)
 {
@@ -515,15 +374,6 @@
 #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)
 {
 	char		*buf;
@@ -598,108 +448,6 @@
 		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 +473,6 @@
 	}
 }
 
-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 +502,6 @@
 	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 +519,6 @@
 	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 +531,6 @@
 	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 +562,18 @@
 	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);
-}
Index: usr.sbin/ospfctl/ospfctl.h
===================================================================
RCS file: usr.sbin/ospfctl/ospfctl.h
diff -N usr.sbin/ospfctl/ospfctl.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ usr.sbin/ospfctl/ospfctl.h	15 May 2020 08:13:09 -0000
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
+ * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
+ * Copyright (c) 2003 Henning Brauer <henning@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);
Index: usr.sbin/ospfctl/Makefile
===================================================================
RCS file: /cvs/src/usr.sbin/ospfctl/Makefile,v
retrieving revision 1.5
diff -u -r1.5 Makefile
--- usr.sbin/ospfctl/Makefile	2 Sep 2016 14:02:48 -0000	1.5
+++ usr.sbin/ospfctl/Makefile	15 May 2020 08:13:09 -0000
@@ -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
