Move some more output functions to output.c and convert some other
functions to a fmt_xyz() function that returns a string with the value
instead of doing a printf(). This is mostly mechanical but please test.

-- 
:wq Claudio

Index: bgpctl.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.c,v
retrieving revision 1.258
diff -u -p -r1.258 bgpctl.c
--- bgpctl.c    24 Jan 2020 05:46:00 -0000      1.258
+++ bgpctl.c    19 Mar 2020 17:36:18 -0000
@@ -46,11 +46,6 @@
 
 int             main(int, char *[]);
 int             show(struct imsg *, struct parse_result *);
-void            show_attr(void *, u_int16_t, int);
-void            show_communities(u_char *, size_t, int);
-void            show_community(u_char *, u_int16_t);
-void            show_large_community(u_char *, u_int16_t);
-void            show_ext_community(u_char *, u_int16_t);
 void            send_filterset(struct imsgbuf *, struct filter_set_head *);
 void            show_mrt_dump_neighbors(struct mrt_rib *, struct mrt_peer *,
                    void *);
@@ -425,7 +420,6 @@ show(struct imsg *imsg, struct parse_res
                if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(*kt))
                        errx(1, "wrong imsg len");
                kt = imsg->data;
-
                show_fib_table(kt);
                break;
        case IMSG_CTL_SHOW_RIB:
@@ -443,7 +437,7 @@ show(struct imsg *imsg, struct parse_res
                        warnx("bad IMSG_CTL_SHOW_RIB_COMMUNITIES received");
                        break;
                }
-               show_communities(imsg->data, ilen, res->flags);
+               show_communities(imsg->data, ilen, res);
                break;
        case IMSG_CTL_SHOW_RIB_ATTR:
                ilen = imsg->hdr.len - IMSG_HEADER_SIZE;
@@ -451,7 +445,7 @@ show(struct imsg *imsg, struct parse_res
                        warnx("bad IMSG_CTL_SHOW_RIB_ATTR received");
                        break;
                }
-               show_attr(imsg->data, ilen, res->flags);
+               show_attr(imsg->data, ilen, res);
                break;
        case IMSG_CTL_SHOW_RIB_MEM:
                memcpy(&stats, imsg->data, sizeof(stats));
@@ -506,7 +500,7 @@ fmt_peer(const char *descr, const struct
 }
 
 const char *
-print_auth_method(enum auth_method method)
+fmt_auth_method(enum auth_method method)
 {
        switch (method) {
        case AUTH_MD5SIG:
@@ -525,75 +519,6 @@ print_auth_method(enum auth_method metho
        }
 }
 
-void
-print_neighbor_capa_mp(struct peer *p)
-{
-       int             comma;
-       u_int8_t        i;
-
-       for (i = 0, comma = 0; i < AID_MAX; i++)
-               if (p->capa.peer.mp[i]) {
-                       printf("%s%s", comma ? ", " : "", aid2str(i));
-                       comma = 1;
-               }
-}
-
-void
-print_neighbor_capa_restart(struct peer *p)
-{
-       int             comma;
-       u_int8_t        i;
-
-       if (p->capa.peer.grestart.timeout)
-               printf(": Timeout: %d, ", p->capa.peer.grestart.timeout);
-       for (i = 0, comma = 0; i < AID_MAX; i++)
-               if (p->capa.peer.grestart.flags[i] & CAPA_GR_PRESENT) {
-                       if (!comma &&
-                           p->capa.peer.grestart.flags[i] & CAPA_GR_RESTART)
-                               printf("restarted, ");
-                       if (comma)
-                               printf(", ");
-                       printf("%s", aid2str(i));
-                       if (p->capa.peer.grestart.flags[i] & CAPA_GR_FORWARD)
-                               printf(" (preserved)");
-                       comma = 1;
-               }
-}
-
-void
-print_neighbor_msgstats(struct peer *p)
-{
-       printf("  Message statistics:\n");
-       printf("  %-15s %-10s %-10s\n", "", "Sent", "Received");
-       printf("  %-15s %10llu %10llu\n", "Opens",
-           p->stats.msg_sent_open, p->stats.msg_rcvd_open);
-       printf("  %-15s %10llu %10llu\n", "Notifications",
-           p->stats.msg_sent_notification, p->stats.msg_rcvd_notification);
-       printf("  %-15s %10llu %10llu\n", "Updates",
-           p->stats.msg_sent_update, p->stats.msg_rcvd_update);
-       printf("  %-15s %10llu %10llu\n", "Keepalives",
-           p->stats.msg_sent_keepalive, p->stats.msg_rcvd_keepalive);
-       printf("  %-15s %10llu %10llu\n", "Route Refresh",
-           p->stats.msg_sent_rrefresh, p->stats.msg_rcvd_rrefresh);
-       printf("  %-15s %10llu %10llu\n\n", "Total",
-           p->stats.msg_sent_open + p->stats.msg_sent_notification +
-           p->stats.msg_sent_update + p->stats.msg_sent_keepalive +
-           p->stats.msg_sent_rrefresh,
-           p->stats.msg_rcvd_open + p->stats.msg_rcvd_notification +
-           p->stats.msg_rcvd_update + p->stats.msg_rcvd_keepalive +
-           p->stats.msg_rcvd_rrefresh);
-       printf("  Update statistics:\n");
-       printf("  %-15s %-10s %-10s\n", "", "Sent", "Received");
-       printf("  %-15s %10u %10u\n", "Prefixes",
-           p->stats.prefix_out_cnt, p->stats.prefix_cnt);
-       printf("  %-15s %10llu %10llu\n", "Updates",
-           p->stats.prefix_sent_update, p->stats.prefix_rcvd_update);
-       printf("  %-15s %10llu %10llu\n", "Withdraws",
-           p->stats.prefix_sent_withdraw, p->stats.prefix_rcvd_withdraw);
-       printf("  %-15s %10llu %10llu\n", "End-of-Rib",
-           p->stats.prefix_sent_eor, p->stats.prefix_rcvd_eor);
-}
-
 #define TF_BUFS        8
 #define TF_LEN 9
 
@@ -646,58 +571,49 @@ fmt_monotime(time_t t)
        return (fmt_timeframe(ts.tv_sec - t));
 }
 
-void
-show_fib_flags(u_int16_t flags)
+const char *
+fmt_fib_flags(u_int16_t flags)
 {
+       static char buf[8];
+
        if (flags & F_DOWN)
-               printf(" ");
+               strlcpy(buf, " ", sizeof(buf));
        else
-               printf("*");
+               strlcpy(buf, "*", sizeof(buf));
 
        if (flags & F_BGPD_INSERTED)
-               printf("B");
+               strlcat(buf, "B", sizeof(buf));
        else if (flags & F_CONNECTED)
-               printf("C");
+               strlcat(buf, "C", sizeof(buf));
        else if (flags & F_STATIC)
-               printf("S");
+               strlcat(buf, "S", sizeof(buf));
        else if (flags & F_DYNAMIC)
-               printf("D");
+               strlcat(buf, "D", sizeof(buf));
        else
-               printf(" ");
+               strlcat(buf, " ", sizeof(buf));
 
        if (flags & F_NEXTHOP)
-               printf("N");
+               strlcat(buf, "N", sizeof(buf));
        else
-               printf(" ");
+               strlcat(buf, " ", sizeof(buf));
 
        if (flags & F_REJECT && flags & F_BLACKHOLE)
-               printf("f");
+               strlcat(buf, "f", sizeof(buf));
        else if (flags & F_REJECT)
-               printf("r");
+               strlcat(buf, "r", sizeof(buf));
        else if (flags & F_BLACKHOLE)
-               printf("b");
+               strlcat(buf, "b", sizeof(buf));
        else
-               printf(" ");
-
-       printf(" ");
-}
+               strlcat(buf, " ", sizeof(buf));
 
-void
-print_prefix(struct bgpd_addr *prefix, u_int8_t prefixlen, u_int8_t flags,
-    u_int8_t ovs)
-{
-       char                    *p;
+       if (strlcat(buf, " ", sizeof(buf)) >= sizeof(buf))
+               errx(1, "%s buffer too small", __func__);
 
-       print_flags(flags, 1);
-       printf("%3s ", print_ovs(ovs, 1));
-       if (asprintf(&p, "%s/%u", log_addr(prefix), prefixlen) == -1)
-               err(1, NULL);
-       printf("%-20s", p);
-       free(p);
+       return buf;
 }
 
 const char *
-print_origin(u_int8_t origin, int sum)
+fmt_origin(u_int8_t origin, int sum)
 {
        switch (origin) {
        case ORIGIN_IGP:
@@ -711,9 +627,10 @@ print_origin(u_int8_t origin, int sum)
        }
 }
 
-void
-print_flags(u_int8_t flags, int sum)
+const char *
+fmt_flags(u_int8_t flags, int sum)
 {
+       static char buf[80];
        char     flagstr[5];
        char    *p = flagstr;
 
@@ -731,25 +648,30 @@ print_flags(u_int8_t flags, int sum)
                if (flags & F_PREF_ACTIVE)
                        *p++ = '>';
                *p = '\0';
-               printf("%-5s ", flagstr);
+               snprintf(buf, sizeof(buf), "%-5s", flagstr);
        } else {
                if (flags & F_PREF_INTERNAL)
-                       printf("internal");
+                       strlcpy(buf, "internal", sizeof(buf));
                else
-                       printf("external");
+                       strlcpy(buf, "external", sizeof(buf));
+
                if (flags & F_PREF_STALE)
-                       printf(", stale");
+                       strlcat(buf, ", stale", sizeof(buf));
                if (flags & F_PREF_ELIGIBLE)
-                       printf(", valid");
+                       strlcat(buf, ", valid", sizeof(buf));
                if (flags & F_PREF_ACTIVE)
-                       printf(", best");
+                       strlcat(buf, ", best", sizeof(buf));
                if (flags & F_PREF_ANNOUNCE)
-                       printf(", announced");
+                       strlcat(buf, ", announced", sizeof(buf));
+               if (strlen(buf) >= sizeof(buf) - 1)
+                       errx(1, "%s buffer too small", __func__);
        }
+
+       return buf;
 }
 
 const char *
-print_ovs(u_int8_t validation_state, int sum)
+fmt_ovs(u_int8_t validation_state, int sum)
 {
        switch (validation_state) {
        case ROA_INVALID:
@@ -761,8 +683,86 @@ print_ovs(u_int8_t validation_state, int
        }
 }
 
-static const char *
-print_attr(u_int8_t type, u_int8_t flags)
+const char *
+fmt_mem(long long num)
+{
+       static char     buf[16];
+
+       if (fmt_scaled(num, buf) == -1)
+               snprintf(buf, sizeof(buf), "%lldB", num);
+
+       return (buf);
+}
+
+const char *
+fmt_errstr(u_int8_t errcode, u_int8_t subcode)
+{
+       static char      errbuf[256];
+       const char      *errstr = NULL;
+       const char      *suberr = NULL;
+       int              uk = 0;
+
+       if (errcode == 0)       /* no error */
+               return NULL;
+
+       if (errcode < sizeof(errnames)/sizeof(char *))
+               errstr = errnames[errcode];
+
+       switch (errcode) {
+       case ERR_HEADER:
+               if (subcode < sizeof(suberr_header_names)/sizeof(char *))
+                       suberr = suberr_header_names[subcode];
+               else
+                       uk = 1;
+               break;
+       case ERR_OPEN:
+               if (subcode < sizeof(suberr_open_names)/sizeof(char *))
+                       suberr = suberr_open_names[subcode];
+               else
+                       uk = 1;
+               break;
+       case ERR_UPDATE:
+               if (subcode < sizeof(suberr_update_names)/sizeof(char *))
+                       suberr = suberr_update_names[subcode];
+               else
+                       uk = 1;
+               break;
+       case ERR_HOLDTIMEREXPIRED:
+               if (subcode != 0)
+                       uk = 1;
+               break;
+       case ERR_FSM:
+               if (subcode < sizeof(suberr_fsm_names)/sizeof(char *))
+                       suberr = suberr_fsm_names[subcode];
+               else
+                       uk = 1;
+               break;
+       case ERR_CEASE:
+               if (subcode < sizeof(suberr_cease_names)/sizeof(char *))
+                       suberr = suberr_cease_names[subcode];
+               else
+                       uk = 1;
+               break;
+       default:
+               snprintf(errbuf, sizeof(errbuf),
+                   "unknown error code %u subcode %u", errcode, subcode);
+               return (errbuf);
+       }
+
+       if (uk)
+               snprintf(errbuf, sizeof(errbuf),
+                   "%s, unknown subcode %u", errstr, subcode);
+       else if (suberr == NULL)
+               return (errstr);
+       else
+               snprintf(errbuf, sizeof(errbuf),
+                   "%s, %s", errstr, suberr);
+
+       return (errbuf);
+}
+
+const char *
+fmt_attr(u_int8_t type, u_int8_t flags)
 {
 #define CHECK_FLAGS(s, t, m)   \
        if (((s) & ~(ATTR_DEFMASK | (m))) != (t)) pflags = 1
@@ -856,252 +856,46 @@ print_attr(u_int8_t type, u_int8_t flags
 #undef CHECK_FLAGS
 }
 
-void
-show_attr(void *b, u_int16_t len, int flag0)
+const char *
+fmt_community(u_int16_t a, u_int16_t v)
 {
-       u_char          *data = b, *path;
-       struct in_addr   id;
-       struct bgpd_addr prefix;
-       char            *aspath;
-       u_int32_t        as;
-       u_int16_t        alen, ioff, short_as, afi;
-       u_int8_t         flags, type, safi, aid, prefixlen;
-       int              i, pos, e2, e4;
-
-       if (len < 3)
-               errx(1, "show_attr: too short bgp attr");
-
-       flags = data[0];
-       type = data[1];
-
-       /* get the attribute length */
-       if (flags & ATTR_EXTLEN) {
-               if (len < 4)
-                       errx(1, "show_attr: too short bgp attr");
-               memcpy(&alen, data+2, sizeof(u_int16_t));
-               alen = ntohs(alen);
-               data += 4;
-               len -= 4;
-       } else {
-               alen = data[2];
-               data += 3;
-               len -= 3;
-       }
-
-       /* bad imsg len how can that happen!? */
-       if (alen > len)
-               errx(1, "show_attr: bad length");
-
-       printf("    %s: ", print_attr(type, flags));
+       static char buf[12];
 
-       switch (type) {
-       case ATTR_ORIGIN:
-               if (alen == 1)
-                       printf("%u", *data);
-               else
-                       printf("bad length");
-               break;
-       case ATTR_ASPATH:
-       case ATTR_AS4_PATH:
-               /* prefer 4-byte AS here */
-               e4 = aspath_verify(data, alen, 1);
-               e2 = aspath_verify(data, alen, 0);
-               if (e4 == 0 || e4 == AS_ERR_SOFT) {
-                       path = data;
-               } else if (e2 == 0 || e2 == AS_ERR_SOFT) {
-                       path = aspath_inflate(data, alen, &alen);
-                       if (path == NULL)
-                               errx(1, "aspath_inflate failed");
-               } else {
-                       printf("bad AS-Path");
-                       break;
-               }
-               if (aspath_asprint(&aspath, path, alen) == -1)
-                       err(1, NULL);
-               printf("%s", aspath);
-               free(aspath);
-               if (path != data)
-                       free(path);
-               break;
-       case ATTR_NEXTHOP:
-               if (alen == 4) {
-                       memcpy(&id, data, sizeof(id));
-                       printf("%s", inet_ntoa(id));
-               } else
-                       printf("bad length");
-               break;
-       case ATTR_MED:
-       case ATTR_LOCALPREF:
-               if (alen == 4) {
-                       u_int32_t val;
-                       memcpy(&val, data, sizeof(val));
-                       val = ntohl(val);
-                       printf("%u", val);
-               } else
-                       printf("bad length");
-               break;
-       case ATTR_AGGREGATOR:
-       case ATTR_AS4_AGGREGATOR:
-               if (alen == 8) {
-                       memcpy(&as, data, sizeof(as));
-                       memcpy(&id, data + sizeof(as), sizeof(id));
-                       as = ntohl(as);
-               } else if (alen == 6) {
-                       memcpy(&short_as, data, sizeof(short_as));
-                       memcpy(&id, data + sizeof(short_as), sizeof(id));
-                       as = ntohs(short_as);
-               } else {
-                       printf("bad length");
-                       break;
-               }
-               printf("%s [%s]", log_as(as), inet_ntoa(id));
-               break;
-       case ATTR_COMMUNITIES:
-               show_community(data, alen);
-               break;
-       case ATTR_ORIGINATOR_ID:
-               memcpy(&id, data, sizeof(id));
-               printf("%s", inet_ntoa(id));
-               break;
-       case ATTR_CLUSTER_LIST:
-               for (ioff = 0; ioff + sizeof(id) <= alen;
-                   ioff += sizeof(id)) {
-                       memcpy(&id, data + ioff, sizeof(id));
-                       printf(" %s", inet_ntoa(id));
-               }
-               break;
-       case ATTR_MP_REACH_NLRI:
-       case ATTR_MP_UNREACH_NLRI:
-               if (alen < 3) {
- bad_len:
-                       printf("bad length");
-                       break;
-               }
-               memcpy(&afi, data, 2);
-               data += 2;
-               alen -= 2;
-               afi = ntohs(afi);
-               safi = *data++;
-               alen--;
-
-               if (afi2aid(afi, safi, &aid) == -1) {
-                       printf("bad AFI/SAFI pair");
-                       break;
-               }
-               printf(" %s", aid2str(aid));
-
-               if (type == ATTR_MP_REACH_NLRI) {
-                       struct bgpd_addr nexthop;
-                       u_int8_t nhlen;
-                       if (len == 0)
-                               goto bad_len;
-                       nhlen = *data++;
-                       alen--;
-                       if (nhlen > len)
-                               goto bad_len;
-                       bzero(&nexthop, sizeof(nexthop));
-                       switch (aid) {
-                       case AID_INET6:
-                               nexthop.aid = aid;
-                               if (nhlen != 16 && nhlen != 32)
-                                       goto bad_len;
-                               memcpy(&nexthop.v6.s6_addr, data, 16);
-                               break;
-                       case AID_VPN_IPv4:
-                               if (nhlen != 12)
-                                       goto bad_len;
-                               nexthop.aid = AID_INET;
-                               memcpy(&nexthop.v4, data + sizeof(u_int64_t),
-                                   sizeof(nexthop.v4));
-                               break;
-                       default:
-                               printf("unhandled AID #%u", aid);
-                               goto done;
-                       }
-                       /* ignore reserved (old SNPA) field as per RFC4760 */
-                       data += nhlen + 1;
-                       alen -= nhlen + 1;
-
-                       printf(" nexthop: %s", log_addr(&nexthop));
-               }
-
-               while (alen > 0) {
-                       switch (aid) {
-                       case AID_INET6:
-                               pos = nlri_get_prefix6(data, alen, &prefix,
-                                   &prefixlen);
-                               break;
-                       case AID_VPN_IPv4:
-                               pos = nlri_get_vpn4(data, alen, &prefix,
-                                   &prefixlen, 1);
-                               break;
-                       default:
-                               printf("unhandled AID #%u", aid);
-                               goto done;
-                       }
-                       if (pos == -1) {
-                               printf("bad %s prefix", aid2str(aid));
-                               break;
-                       }
-                       printf(" %s/%u", log_addr(&prefix), prefixlen);
-                       data += pos;
-                       alen -= pos;
-               }
-               break;
-       case ATTR_EXT_COMMUNITIES:
-               show_ext_community(data, alen);
-               break;
-       case ATTR_LARGE_COMMUNITIES:
-               show_large_community(data, alen);
-               break;
-       case ATTR_ATOMIC_AGGREGATE:
-       default:
-               printf(" len %u", alen);
-               if (alen) {
-                       printf(":");
-                       for (i=0; i < alen; i++)
-                               printf(" %02x", *(data+i));
-               }
-               break;
-       }
- done:
-       printf("%c", EOL0(flag0));
-}
-
-static void
-print_community(u_int16_t a, u_int16_t v)
-{
        if (a == COMMUNITY_WELLKNOWN)
                switch (v) {
                case COMMUNITY_GRACEFUL_SHUTDOWN:
-                       printf("GRACEFUL_SHUTDOWN");
-                       break;
+                       return "GRACEFUL_SHUTDOWN";
                case COMMUNITY_NO_EXPORT:
-                       printf("NO_EXPORT");
-                       break;
+                       return "NO_EXPORT";
                case COMMUNITY_NO_ADVERTISE:
-                       printf("NO_ADVERTISE");
-                       break;
+                       return "NO_ADVERTISE";
                case COMMUNITY_NO_EXPSUBCONFED:
-                       printf("NO_EXPORT_SUBCONFED");
-                       break;
+                       return "NO_EXPORT_SUBCONFED";
                case COMMUNITY_NO_PEER:
-                       printf("NO_PEER");
-                       break;
+                       return "NO_PEER";
                case COMMUNITY_BLACKHOLE:
-                       printf("BLACKHOLE");
-                       break;
+                       return "BLACKHOLE";
                default:
-                       printf("%hu:%hu", a, v);
                        break;
                }
-       else
-               printf("%hu:%hu", a, v);
+
+       snprintf(buf, sizeof(buf), "%hu:%hu", a, v);
+       return buf;
 }
 
-static void
-print_ext_community(u_int8_t *data)
+const char *
+fmt_large_community(u_int32_t d1, u_int32_t d2, u_int32_t d3)
 {
+       static char buf[33];
+
+       snprintf(buf, sizeof(buf), "%u:%u:%u", d1, d2, d3);
+       return buf;
+}
+
+const char *
+fmt_ext_community(u_int8_t *data)
+{
+       static char     buf[32];
        u_int64_t       ext;
        struct in_addr  ip;
        u_int32_t       as4, u32;
@@ -1111,182 +905,68 @@ print_ext_community(u_int8_t *data)
        type = data[0];
        subtype = data[1];
 
-       printf("%s ", log_ext_subtype(type, subtype));
-
        switch (type) {
        case EXT_COMMUNITY_TRANS_TWO_AS:
                memcpy(&as2, data + 2, sizeof(as2));
                memcpy(&u32, data + 4, sizeof(u32));
-               printf("%s:%u", log_as(ntohs(as2)), ntohl(u32));
-               break;
+               snprintf(buf, sizeof(buf), "%s %s:%u",
+                   log_ext_subtype(type, subtype),
+                   log_as(ntohs(as2)), ntohl(u32));
+               return buf;
        case EXT_COMMUNITY_TRANS_IPV4:
                memcpy(&ip, data + 2, sizeof(ip));
                memcpy(&u16, data + 6, sizeof(u16));
-               printf("%s:%hu", inet_ntoa(ip), ntohs(u16));
-               break;
+               snprintf(buf, sizeof(buf), "%s %s:%hu",
+                   log_ext_subtype(type, subtype),
+                   inet_ntoa(ip), ntohs(u16));
+               return buf;
        case EXT_COMMUNITY_TRANS_FOUR_AS:
                memcpy(&as4, data + 2, sizeof(as4));
                memcpy(&u16, data + 6, sizeof(u16));
-               printf("%s:%hu", log_as(ntohl(as4)), ntohs(u16));
-               break;
+               snprintf(buf, sizeof(buf), "%s %s:%hu",
+                   log_ext_subtype(type, subtype),
+                   log_as(ntohl(as4)), ntohs(u16));
+               return buf;
        case EXT_COMMUNITY_TRANS_OPAQUE:
        case EXT_COMMUNITY_TRANS_EVPN:
                memcpy(&ext, data, sizeof(ext));
                ext = be64toh(ext) & 0xffffffffffffLL;
-               printf("0x%llx", (unsigned long long)ext);
-               break;
+               snprintf(buf, sizeof(buf), "%s 0x%llx",
+                   log_ext_subtype(type, subtype), (unsigned long long)ext);
+               return buf;
        case EXT_COMMUNITY_NON_TRANS_OPAQUE:
                memcpy(&ext, data, sizeof(ext));
                ext = be64toh(ext) & 0xffffffffffffLL;
                switch (ext) {
                case EXT_COMMUNITY_OVS_VALID:
-                       printf("valid ");
-                       break;
+                       snprintf(buf, sizeof(buf), "%s valid ",
+                           log_ext_subtype(type, subtype));
+                       return buf;
                case EXT_COMMUNITY_OVS_NOTFOUND:
-                       printf("not-found ");
-                       break;
+                       snprintf(buf, sizeof(buf), "%s not-found ",
+                           log_ext_subtype(type, subtype));
+                       return buf;
                case EXT_COMMUNITY_OVS_INVALID:
-                       printf("invalid ");
-                       break;
+                       snprintf(buf, sizeof(buf), "%s invalid ",
+                           log_ext_subtype(type, subtype));
+                       return buf;
                default:
-                       printf("0x%llx ", (unsigned long long)ext);
-                       break;
+                       snprintf(buf, sizeof(buf), "%s 0x%llx ",
+                           log_ext_subtype(type, subtype),
+                           (unsigned long long)ext);
+                       return buf;
                }
                break;
        default:
                memcpy(&ext, data, sizeof(ext));
-               printf("0x%llx", (unsigned long long)be64toh(ext));
+               snprintf(buf, sizeof(buf), "%s 0x%llx",
+                   log_ext_subtype(type, subtype),
+                   (unsigned long long)be64toh(ext));
+               return buf;
        }
 }
 
 void
-show_communities(u_char *data, size_t len, int flag0)
-{
-       struct community c;
-       size_t  i;
-       u_int64_t ext;
-       u_int8_t type = 0, nt;
-
-       if (len % sizeof(c))
-               return;
-
-       for (i = 0; i < len; i += sizeof(c)) {
-               memcpy(&c, data + i, sizeof(c));
-
-               nt = c.flags;
-               if (type != nt) {
-                       if (type != 0)
-                               printf("%c", EOL0(flag0));
-                       printf("    %s:", print_attr(nt,
-                           ATTR_OPTIONAL | ATTR_TRANSITIVE));
-                       type = nt;
-               }
-               printf(" ");
-
-               switch (nt) {
-               case COMMUNITY_TYPE_BASIC:
-                       print_community(c.data1, c.data2);
-                       break;
-               case COMMUNITY_TYPE_LARGE:
-                       printf("%u:%u:%u", c.data1, c.data2, c.data3);
-                       break;
-               case COMMUNITY_TYPE_EXT:
-                       ext = (u_int64_t)c.data3 << 48;
-                       switch (c.data3 >> 8) {
-                       case EXT_COMMUNITY_TRANS_TWO_AS:
-                       case EXT_COMMUNITY_TRANS_OPAQUE:
-                       case EXT_COMMUNITY_TRANS_EVPN:
-                       case EXT_COMMUNITY_NON_TRANS_OPAQUE:
-                               ext |= ((u_int64_t)c.data1 & 0xffff) << 32;
-                               ext |= (u_int64_t)c.data2;
-                               break;
-                       case EXT_COMMUNITY_TRANS_FOUR_AS:
-                       case EXT_COMMUNITY_TRANS_IPV4:
-                               ext |= (u_int64_t)c.data1 << 16;
-                               ext |= (u_int64_t)c.data2 & 0xffff;
-                               break;
-                       }
-                       ext = htobe64(ext);
-
-                       print_ext_community((void *)&ext);
-                       break;
-               }
-       }
-
-       printf("%c", EOL0(flag0));
-}
-
-void
-show_community(u_char *data, u_int16_t len)
-{
-       u_int16_t       a, v;
-       u_int16_t       i;
-
-       if (len & 0x3)
-               return;
-
-       for (i = 0; i < len; i += 4) {
-               memcpy(&a, data + i, sizeof(a));
-               memcpy(&v, data + i + 2, sizeof(v));
-               a = ntohs(a);
-               v = ntohs(v);
-               print_community(a, v);
-               if (i + 4 < len)
-                       printf(" ");
-       }
-}
-
-void
-show_large_community(u_char *data, u_int16_t len)
-{
-       u_int32_t       a, l1, l2;
-       u_int16_t       i;
-
-       if (len % 12)
-               return;
-
-       for (i = 0; i < len; i += 12) {
-               memcpy(&a, data + i, sizeof(a));
-               memcpy(&l1, data + i + 4, sizeof(l1));
-               memcpy(&l2, data + i + 8, sizeof(l2));
-               a = ntohl(a);
-               l1 = ntohl(l1);
-               l2 = ntohl(l2);
-               printf("%u:%u:%u", a, l1, l2);
-
-               if (i + 12 < len)
-                       printf(" ");
-       }
-}
-
-void
-show_ext_community(u_char *data, u_int16_t len)
-{
-       u_int16_t       i;
-
-       if (len & 0x7)
-               return;
-
-       for (i = 0; i < len; i += 8) {
-               print_ext_community(data + i);
-
-               if (i + 8 < len)
-                       printf(" ");
-       }
-}
-
-const char *
-fmt_mem(long long num)
-{
-       static char     buf[16];
-
-       if (fmt_scaled(num, buf) == -1)
-               snprintf(buf, sizeof(buf), "%lldB", num);
-
-       return (buf);
-}
-
-void
 send_filterset(struct imsgbuf *i, struct filter_set_head *set)
 {
        struct filter_set       *s;
@@ -1299,73 +979,6 @@ send_filterset(struct imsgbuf *i, struct
        }
 }
 
-const char *
-get_errstr(u_int8_t errcode, u_int8_t subcode)
-{
-       static char      errbuf[256];
-       const char      *errstr = NULL;
-       const char      *suberr = NULL;
-       int              uk = 0;
-
-       if (errcode == 0)       /* no error */
-               return NULL;
-
-       if (errcode < sizeof(errnames)/sizeof(char *))
-               errstr = errnames[errcode];
-
-       switch (errcode) {
-       case ERR_HEADER:
-               if (subcode < sizeof(suberr_header_names)/sizeof(char *))
-                       suberr = suberr_header_names[subcode];
-               else
-                       uk = 1;
-               break;
-       case ERR_OPEN:
-               if (subcode < sizeof(suberr_open_names)/sizeof(char *))
-                       suberr = suberr_open_names[subcode];
-               else
-                       uk = 1;
-               break;
-       case ERR_UPDATE:
-               if (subcode < sizeof(suberr_update_names)/sizeof(char *))
-                       suberr = suberr_update_names[subcode];
-               else
-                       uk = 1;
-               break;
-       case ERR_HOLDTIMEREXPIRED:
-               if (subcode != 0)
-                       uk = 1;
-               break;
-       case ERR_FSM:
-               if (subcode < sizeof(suberr_fsm_names)/sizeof(char *))
-                       suberr = suberr_fsm_names[subcode];
-               else
-                       uk = 1;
-               break;
-       case ERR_CEASE:
-               if (subcode < sizeof(suberr_cease_names)/sizeof(char *))
-                       suberr = suberr_cease_names[subcode];
-               else
-                       uk = 1;
-               break;
-       default:
-               snprintf(errbuf, sizeof(errbuf),
-                   "unknown error code %u subcode %u", errcode, subcode);
-               return (errbuf);
-       }
-
-       if (uk)
-               snprintf(errbuf, sizeof(errbuf),
-                   "%s, unknown subcode %u", errstr, subcode);
-       else if (suberr == NULL)
-               return (errstr);
-       else
-               snprintf(errbuf, sizeof(errbuf),
-                   "%s, %s", errstr, suberr);
-
-       return (errbuf);
-}
-
 void
 network_bulk(struct parse_result *res)
 {
@@ -1514,8 +1127,7 @@ show_mrt_dump(struct mrt_rib *mr, struct
                if (req->flags & F_CTL_DETAIL) {
                        for (j = 0; j < mre->nattrs; j++)
                                show_attr(mre->attrs[j].attr,
-                                   mre->attrs[j].attr_len,
-                                   req->flags);
+                                   mre->attrs[j].attr_len, &res);
                }
        }
 }
@@ -1603,7 +1215,7 @@ network_mrt_dump(struct mrt_rib *mr, str
 }
 
 static const char *
-print_time(struct timespec *t)
+fmt_time(struct timespec *t)
 {
        static char timebuf[32];
        static struct timespec prevtime;
@@ -1619,7 +1231,7 @@ print_time(struct timespec *t)
 void
 show_mrt_state(struct mrt_bgp_state *ms, void *arg)
 {
-       printf("%s %s[%u] -> ", print_time(&ms->time),
+       printf("%s %s[%u] -> ", fmt_time(&ms->time),
            log_addr(&ms->src), ms->src_as);
        printf("%s[%u]: %s -> %s\n", log_addr(&ms->dst), ms->dst_as,
            statenames[ms->old_state], statenames[ms->new_state]);
@@ -1998,7 +1610,7 @@ show_mrt_msg(struct mrt_bgp_msg *mm, voi
        u_int16_t len;
        u_int8_t type;
 
-       printf("%s %s[%u] -> ", print_time(&mm->time),
+       printf("%s %s[%u] -> ", fmt_time(&mm->time),
            log_addr(&mm->src), mm->src_as);
        printf("%s[%u]: size %u ", log_addr(&mm->dst), mm->dst_as, mm->msg_len);
        p = mm->msg;
Index: bgpctl.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.h,v
retrieving revision 1.3
diff -u -p -r1.3 bgpctl.h
--- bgpctl.h    9 Jan 2020 11:57:04 -0000       1.3
+++ bgpctl.h    19 Mar 2020 17:32:00 -0000
@@ -22,6 +22,8 @@ void  show_fib(struct kroute_full *);
 void   show_fib_table(struct ktable *);
 void   show_nexthop(struct ctl_show_nexthop *);
 void   show_interface(struct ctl_show_interface *);
+void   show_attr(u_char *, size_t, struct parse_result *);
+void   show_communities(u_char *, size_t, struct parse_result *);
 void   show_rib(struct ctl_show_rib *, u_char *, size_t,
            struct parse_result *);
 void   show_rib_hash(struct rde_hashstats *);
@@ -31,20 +33,18 @@ void        show_result(u_int);
 
 #define EOL0(flag)     ((flag & F_CTL_SSV) ? ';' : '\n')
 
-void            print_prefix(struct bgpd_addr *, u_int8_t, u_int8_t, u_int8_t);
-void            print_neighbor_capa_mp(struct peer *);
-void            print_neighbor_capa_restart(struct peer *);
-void            print_neighbor_msgstats(struct peer *);
-void            print_flags(u_int8_t, int);
-void            show_fib_flags(u_int16_t);
-
-const char     *print_ovs(u_int8_t, int);
-const char     *print_origin(u_int8_t, int);
-const char     *print_auth_method(enum auth_method);
-const char     *fmt_mem(long long);
-
+char           *fmt_peer(const char *, const struct bgpd_addr *, int);
 const char     *fmt_timeframe(time_t);
 const char     *fmt_monotime(time_t);
-char           *fmt_peer(const char *, const struct bgpd_addr *, int);
-const char     *get_errstr(u_int8_t, u_int8_t);
+const char     *fmt_fib_flags(u_int16_t);
+const char     *fmt_origin(u_int8_t, int);
+const char     *fmt_flags(u_int8_t, int);
+const char     *fmt_ovs(u_int8_t, int);
+const char     *fmt_auth_method(enum auth_method);
+const char     *fmt_mem(long long);
+const char     *fmt_errstr(u_int8_t, u_int8_t);
+const char     *fmt_attr(u_int8_t, u_int8_t);
+const char     *fmt_community(u_int16_t, u_int16_t);
+const char     *fmt_large_community(u_int32_t, u_int32_t, u_int32_t);
+const char     *fmt_ext_community(u_int8_t *);
 
Index: output.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/output.c,v
retrieving revision 1.5
diff -u -p -r1.5 output.c
--- output.c    24 Jan 2020 05:46:00 -0000      1.5
+++ output.c    19 Mar 2020 17:37:55 -0000
@@ -86,9 +86,9 @@ show_head(struct parse_result *res)
 static void
 show_summary(struct peer *p)
 {
-       char                    *s;
-       const char              *a;
-       size_t                  alen;
+       char            *s;
+       const char      *a;
+       size_t          alen;
 
        s = fmt_peer(p->conf.descr, &p->conf.remote_addr,
            p->conf.remote_masklen);
@@ -125,6 +125,79 @@ show_summary(struct peer *p)
 }
 
 static void
+show_neighbor_capa_mp(struct peer *p)
+{
+       int             comma;
+       u_int8_t        i;
+
+       printf("    Multiprotocol extensions: ");
+       for (i = 0, comma = 0; i < AID_MAX; i++)
+               if (p->capa.peer.mp[i]) {
+                       printf("%s%s", comma ? ", " : "", aid2str(i));
+                       comma = 1;
+               }
+       printf("\n");
+}
+
+static void
+show_neighbor_capa_restart(struct peer *p)
+{
+       int             comma;
+       u_int8_t        i;
+
+       printf("    Graceful Restart");
+       if (p->capa.peer.grestart.timeout)
+               printf(": Timeout: %d, ", p->capa.peer.grestart.timeout);
+       for (i = 0, comma = 0; i < AID_MAX; i++)
+               if (p->capa.peer.grestart.flags[i] & CAPA_GR_PRESENT) {
+                       if (!comma &&
+                           p->capa.peer.grestart.flags[i] & CAPA_GR_RESTART)
+                               printf("restarted, ");
+                       if (comma)
+                               printf(", ");
+                       printf("%s", aid2str(i));
+                       if (p->capa.peer.grestart.flags[i] & CAPA_GR_FORWARD)
+                               printf(" (preserved)");
+                       comma = 1;
+               }
+       printf("\n");
+}
+
+static void
+show_neighbor_msgstats(struct peer *p)
+{
+       printf("  Message statistics:\n");
+       printf("  %-15s %-10s %-10s\n", "", "Sent", "Received");
+       printf("  %-15s %10llu %10llu\n", "Opens",
+           p->stats.msg_sent_open, p->stats.msg_rcvd_open);
+       printf("  %-15s %10llu %10llu\n", "Notifications",
+           p->stats.msg_sent_notification, p->stats.msg_rcvd_notification);
+       printf("  %-15s %10llu %10llu\n", "Updates",
+           p->stats.msg_sent_update, p->stats.msg_rcvd_update);
+       printf("  %-15s %10llu %10llu\n", "Keepalives",
+           p->stats.msg_sent_keepalive, p->stats.msg_rcvd_keepalive);
+       printf("  %-15s %10llu %10llu\n", "Route Refresh",
+           p->stats.msg_sent_rrefresh, p->stats.msg_rcvd_rrefresh);
+       printf("  %-15s %10llu %10llu\n\n", "Total",
+           p->stats.msg_sent_open + p->stats.msg_sent_notification +
+           p->stats.msg_sent_update + p->stats.msg_sent_keepalive +
+           p->stats.msg_sent_rrefresh,
+           p->stats.msg_rcvd_open + p->stats.msg_rcvd_notification +
+           p->stats.msg_rcvd_update + p->stats.msg_rcvd_keepalive +
+           p->stats.msg_rcvd_rrefresh);
+       printf("  Update statistics:\n");
+       printf("  %-15s %-10s %-10s\n", "", "Sent", "Received");
+       printf("  %-15s %10u %10u\n", "Prefixes",
+           p->stats.prefix_out_cnt, p->stats.prefix_cnt);
+       printf("  %-15s %10llu %10llu\n", "Updates",
+           p->stats.prefix_sent_update, p->stats.prefix_rcvd_update);
+       printf("  %-15s %10llu %10llu\n", "Withdraws",
+           p->stats.prefix_sent_withdraw, p->stats.prefix_rcvd_withdraw);
+       printf("  %-15s %10llu %10llu\n", "End-of-Rib",
+           p->stats.prefix_sent_eor, p->stats.prefix_rcvd_eor);
+}
+
+static void
 show_neighbor_full(struct peer *p, struct parse_result *res)
 {
        struct in_addr           ina;
@@ -178,7 +251,7 @@ show_neighbor_full(struct peer *p, struc
 
        printf("  BGP version 4, remote router-id %s",
            inet_ntoa(ina));
-       printf("%s\n", print_auth_method(p->auth.method));
+       printf("%s\n", fmt_auth_method(p->auth.method));
        printf("  BGP state = %s", statenames[p->state]);
        if (p->conf.down) {
                printf(", marked down");
@@ -202,18 +275,12 @@ show_neighbor_full(struct peer *p, struc
        if (hascapamp || p->capa.peer.refresh ||
            p->capa.peer.grestart.restart || p->capa.peer.as4byte) {
                printf("  Neighbor capabilities:\n");
-               if (hascapamp) {
-                       printf("    Multiprotocol extensions: ");
-                       print_neighbor_capa_mp(p);
-                       printf("\n");
-               }
+               if (hascapamp)
+                       show_neighbor_capa_mp(p);
                if (p->capa.peer.refresh)
                        printf("    Route Refresh\n");
-               if (p->capa.peer.grestart.restart) {
-                       printf("    Graceful Restart");
-                       print_neighbor_capa_restart(p);
-                       printf("\n");
-               }
+               if (p->capa.peer.grestart.restart)
+                       show_neighbor_capa_restart(p);
                if (p->capa.peer.as4byte)
                        printf("    4-byte AS numbers\n");
        }
@@ -222,7 +289,7 @@ show_neighbor_full(struct peer *p, struc
        if (res->action == SHOW_NEIGHBOR_TIMERS)
                return;
 
-       print_neighbor_msgstats(p);
+       show_neighbor_msgstats(p);
        printf("\n");
        if (*(p->stats.last_shutcomm)) {
                printf("  Last received shutdown reason: \"%s\"\n",
@@ -231,11 +298,11 @@ show_neighbor_full(struct peer *p, struc
        if (p->state == STATE_IDLE) {
                const char *errstr;
 
-               errstr = get_errstr(p->stats.last_sent_errcode,
+               errstr = fmt_errstr(p->stats.last_sent_errcode,
                    p->stats.last_sent_suberr);
                if (errstr)
                        printf("  Last error sent: %s\n\n", errstr);
-               errstr = get_errstr(p->stats.last_rcvd_errcode,
+               errstr = fmt_errstr(p->stats.last_rcvd_errcode,
                    p->stats.last_rcvd_suberr);
                if (errstr)
                        printf("  Last error received: %s\n\n", errstr);
@@ -309,11 +376,9 @@ show_fib(struct kroute_full *kf)
 {
        char                    *p;
 
-       show_fib_flags(kf->flags);
-
        if (asprintf(&p, "%s/%u", log_addr(&kf->prefix), kf->prefixlen) == -1)
                err(1, NULL);
-       printf("%4i %-20s ", kf->priority, p);
+       printf("%s%4i %-20s ", fmt_fib_flags(kf->flags), kf->priority, p);
        free(p);
 
        if (kf->flags & F_CONNECTED)
@@ -397,14 +462,346 @@ show_interface(struct ctl_show_interface
        printf("\n");
 }
 
+void
+show_communities(u_char *data, size_t len, struct parse_result *res)
+{
+       struct community c;
+       size_t  i;
+       u_int64_t ext;
+       u_int8_t type = 0, nt;
+
+       if (len % sizeof(c))
+               return;
+
+       for (i = 0; i < len; i += sizeof(c)) {
+               memcpy(&c, data + i, sizeof(c));
+
+               nt = c.flags;
+               if (type != nt) {
+                       if (type != 0)
+                               printf("%c", EOL0(res->flags));
+                       printf("    %s:", fmt_attr(nt,
+                           ATTR_OPTIONAL | ATTR_TRANSITIVE));
+                       type = nt;
+               }
+
+               switch (nt) {
+               case COMMUNITY_TYPE_BASIC:
+                       printf(" %s", fmt_community(c.data1, c.data2));
+                       break;
+               case COMMUNITY_TYPE_LARGE:
+                       printf(" %s",
+                           fmt_large_community(c.data1, c.data2, c.data3));
+                       break;
+               case COMMUNITY_TYPE_EXT:
+                       ext = (u_int64_t)c.data3 << 48;
+                       switch (c.data3 >> 8) {
+                       case EXT_COMMUNITY_TRANS_TWO_AS:
+                       case EXT_COMMUNITY_TRANS_OPAQUE:
+                       case EXT_COMMUNITY_TRANS_EVPN:
+                       case EXT_COMMUNITY_NON_TRANS_OPAQUE:
+                               ext |= ((u_int64_t)c.data1 & 0xffff) << 32;
+                               ext |= (u_int64_t)c.data2;
+                               break;
+                       case EXT_COMMUNITY_TRANS_FOUR_AS:
+                       case EXT_COMMUNITY_TRANS_IPV4:
+                               ext |= (u_int64_t)c.data1 << 16;
+                               ext |= (u_int64_t)c.data2 & 0xffff;
+                               break;
+                       }
+                       ext = htobe64(ext);
+
+                       printf(" %s", fmt_ext_community((void *)&ext));
+                       break;
+               }
+       }
+
+       printf("%c", EOL0(res->flags));
+}
+
+static void
+show_community(u_char *data, u_int16_t len)
+{
+       u_int16_t       a, v;
+       u_int16_t       i;
+
+       if (len & 0x3)
+               return;
+
+       for (i = 0; i < len; i += 4) {
+               memcpy(&a, data + i, sizeof(a));
+               memcpy(&v, data + i + 2, sizeof(v));
+               a = ntohs(a);
+               v = ntohs(v);
+               printf("%s", fmt_community(a, v));
+
+               if (i + 4 < len)
+                       printf(" ");
+       }
+}
+
+static void
+show_large_community(u_char *data, u_int16_t len)
+{
+       u_int32_t       a, l1, l2;
+       u_int16_t       i;
+
+       if (len % 12)
+               return;
+
+       for (i = 0; i < len; i += 12) {
+               memcpy(&a, data + i, sizeof(a));
+               memcpy(&l1, data + i + 4, sizeof(l1));
+               memcpy(&l2, data + i + 8, sizeof(l2));
+               a = ntohl(a);
+               l1 = ntohl(l1);
+               l2 = ntohl(l2);
+                       printf("%s", fmt_large_community(a, l1, l2));
+
+               if (i + 12 < len)
+                       printf(" ");
+       }
+}
+
+static void
+show_ext_community(u_char *data, u_int16_t len)
+{
+       u_int16_t       i;
+
+       if (len & 0x7)
+               return;
+
+       for (i = 0; i < len; i += 8) {
+               printf("%s", fmt_ext_community(data + i));
+
+               if (i + 8 < len)
+                       printf(" ");
+       }
+}
+
+void
+show_attr(u_char *data, size_t len, struct parse_result *res)
+{
+       u_char          *path;
+       struct in_addr   id;
+       struct bgpd_addr prefix;
+       char            *aspath;
+       u_int32_t        as;
+       u_int16_t        alen, ioff, short_as, afi;
+       u_int8_t         flags, type, safi, aid, prefixlen;
+       int              i, pos, e2, e4;
+
+       if (len < 3)
+               errx(1, "show_attr: too short bgp attr");
+
+       flags = data[0];
+       type = data[1];
+
+       /* get the attribute length */
+       if (flags & ATTR_EXTLEN) {
+               if (len < 4)
+                       errx(1, "show_attr: too short bgp attr");
+               memcpy(&alen, data+2, sizeof(u_int16_t));
+               alen = ntohs(alen);
+               data += 4;
+               len -= 4;
+       } else {
+               alen = data[2];
+               data += 3;
+               len -= 3;
+       }
+
+       /* bad imsg len how can that happen!? */
+       if (alen > len)
+               errx(1, "show_attr: bad length");
+
+       printf("    %s: ", fmt_attr(type, flags));
+
+       switch (type) {
+       case ATTR_ORIGIN:
+               if (alen == 1)
+                       printf("%u", *data);
+               else
+                       printf("bad length");
+               break;
+       case ATTR_ASPATH:
+       case ATTR_AS4_PATH:
+               /* prefer 4-byte AS here */
+               e4 = aspath_verify(data, alen, 1);
+               e2 = aspath_verify(data, alen, 0);
+               if (e4 == 0 || e4 == AS_ERR_SOFT) {
+                       path = data;
+               } else if (e2 == 0 || e2 == AS_ERR_SOFT) {
+                       path = aspath_inflate(data, alen, &alen);
+                       if (path == NULL)
+                               errx(1, "aspath_inflate failed");
+               } else {
+                       printf("bad AS-Path");
+                       break;
+               }
+               if (aspath_asprint(&aspath, path, alen) == -1)
+                       err(1, NULL);
+               printf("%s", aspath);
+               free(aspath);
+               if (path != data)
+                       free(path);
+               break;
+       case ATTR_NEXTHOP:
+               if (alen == 4) {
+                       memcpy(&id, data, sizeof(id));
+                       printf("%s", inet_ntoa(id));
+               } else
+                       printf("bad length");
+               break;
+       case ATTR_MED:
+       case ATTR_LOCALPREF:
+               if (alen == 4) {
+                       u_int32_t val;
+                       memcpy(&val, data, sizeof(val));
+                       val = ntohl(val);
+                       printf("%u", val);
+               } else
+                       printf("bad length");
+               break;
+       case ATTR_AGGREGATOR:
+       case ATTR_AS4_AGGREGATOR:
+               if (alen == 8) {
+                       memcpy(&as, data, sizeof(as));
+                       memcpy(&id, data + sizeof(as), sizeof(id));
+                       as = ntohl(as);
+               } else if (alen == 6) {
+                       memcpy(&short_as, data, sizeof(short_as));
+                       memcpy(&id, data + sizeof(short_as), sizeof(id));
+                       as = ntohs(short_as);
+               } else {
+                       printf("bad length");
+                       break;
+               }
+               printf("%s [%s]", log_as(as), inet_ntoa(id));
+               break;
+       case ATTR_COMMUNITIES:
+               show_community(data, alen);
+               break;
+       case ATTR_ORIGINATOR_ID:
+               memcpy(&id, data, sizeof(id));
+               printf("%s", inet_ntoa(id));
+               break;
+       case ATTR_CLUSTER_LIST:
+               for (ioff = 0; ioff + sizeof(id) <= alen;
+                   ioff += sizeof(id)) {
+                       memcpy(&id, data + ioff, sizeof(id));
+                       printf(" %s", inet_ntoa(id));
+               }
+               break;
+       case ATTR_MP_REACH_NLRI:
+       case ATTR_MP_UNREACH_NLRI:
+               if (alen < 3) {
+ bad_len:
+                       printf("bad length");
+                       break;
+               }
+               memcpy(&afi, data, 2);
+               data += 2;
+               alen -= 2;
+               afi = ntohs(afi);
+               safi = *data++;
+               alen--;
+
+               if (afi2aid(afi, safi, &aid) == -1) {
+                       printf("bad AFI/SAFI pair");
+                       break;
+               }
+               printf(" %s", aid2str(aid));
+
+               if (type == ATTR_MP_REACH_NLRI) {
+                       struct bgpd_addr nexthop;
+                       u_int8_t nhlen;
+                       if (len == 0)
+                               goto bad_len;
+                       nhlen = *data++;
+                       alen--;
+                       if (nhlen > len)
+                               goto bad_len;
+                       bzero(&nexthop, sizeof(nexthop));
+                       switch (aid) {
+                       case AID_INET6:
+                               nexthop.aid = aid;
+                               if (nhlen != 16 && nhlen != 32)
+                                       goto bad_len;
+                               memcpy(&nexthop.v6.s6_addr, data, 16);
+                               break;
+                       case AID_VPN_IPv4:
+                               if (nhlen != 12)
+                                       goto bad_len;
+                               nexthop.aid = AID_INET;
+                               memcpy(&nexthop.v4, data + sizeof(u_int64_t),
+                                   sizeof(nexthop.v4));
+                               break;
+                       default:
+                               printf("unhandled AID #%u", aid);
+                               goto done;
+                       }
+                       /* ignore reserved (old SNPA) field as per RFC4760 */
+                       data += nhlen + 1;
+                       alen -= nhlen + 1;
+
+                       printf(" nexthop: %s", log_addr(&nexthop));
+               }
+
+               while (alen > 0) {
+                       switch (aid) {
+                       case AID_INET6:
+                               pos = nlri_get_prefix6(data, alen, &prefix,
+                                   &prefixlen);
+                               break;
+                       case AID_VPN_IPv4:
+                               pos = nlri_get_vpn4(data, alen, &prefix,
+                                   &prefixlen, 1);
+                               break;
+                       default:
+                               printf("unhandled AID #%u", aid);
+                               goto done;
+                       }
+                       if (pos == -1) {
+                               printf("bad %s prefix", aid2str(aid));
+                               break;
+                       }
+                       printf(" %s/%u", log_addr(&prefix), prefixlen);
+                       data += pos;
+                       alen -= pos;
+               }
+               break;
+       case ATTR_EXT_COMMUNITIES:
+               show_ext_community(data, alen);
+               break;
+       case ATTR_LARGE_COMMUNITIES:
+               show_large_community(data, alen);
+               break;
+       case ATTR_ATOMIC_AGGREGATE:
+       default:
+               printf(" len %u", alen);
+               if (alen) {
+                       printf(":");
+                       for (i=0; i < alen; i++)
+                               printf(" %02x", *(data+i));
+               }
+               break;
+       }
+ done:
+       printf("%c", EOL0(res->flags));
+}
+
 static void
 show_rib_brief(struct ctl_show_rib *r, u_char *asdata, size_t aslen)
 {
-       char                    *aspath;
+       char *p, *aspath;
 
-       print_prefix(&r->prefix, r->prefixlen, r->flags, r->validation_state);
-       printf(" %-15s ", log_addr(&r->exit_nexthop));
-       printf(" %5u %5u ", r->local_pref, r->med);
+       if (asprintf(&p, "%s/%u", log_addr(&r->prefix), r->prefixlen) == -1)
+               err(1, NULL);
+       printf("%s %3s %-20s %-15s %5u %5u ",
+           fmt_flags(r->flags, 1), fmt_ovs(r->validation_state, 1), p,
+           log_addr(&r->exit_nexthop), r->local_pref, r->med);
+       free(p);
 
        if (aspath_asprint(&aspath, asdata, aslen) == -1)
                err(1, NULL);
@@ -412,7 +809,7 @@ show_rib_brief(struct ctl_show_rib *r, u
                printf("%s ", aspath);
        free(aspath);
 
-       printf("%s\n", print_origin(r->origin, 1));
+       printf("%s\n", fmt_origin(r->origin, 1));
 }
 
 static void
@@ -440,9 +837,9 @@ show_rib_detail(struct ctl_show_rib *r, 
        printf("%s)%c", inet_ntoa(id), EOL0(flag0));
 
        printf("    Origin %s, metric %u, localpref %u, weight %u, ovs %s, ",
-           print_origin(r->origin, 0), r->med, r->local_pref, r->weight,
-           print_ovs(r->validation_state, 0));
-       print_flags(r->flags, 0);
+           fmt_origin(r->origin, 0), r->med, r->local_pref, r->weight,
+           fmt_ovs(r->validation_state, 0));
+       printf("%s", fmt_flags(r->flags, 0));
 
        printf("%c    Last update: %s ago%c", EOL0(flag0),
            fmt_timeframe(r->age), EOL0(flag0));

Reply via email to