This diff implements 'bgpctl show flowspec' and on top of that also 'bgpctl flowspec flush'. bgpctl now uses both util.c and flowspec.c from bgpd. The code to print flowspec is stolen from printconf.c and I did not implement the json output yet because I have not decided on how to dump the NLRI there.
-- :wq Claudio Index: Makefile =================================================================== RCS file: /cvs/src/usr.sbin/bgpctl/Makefile,v retrieving revision 1.18 diff -u -p -r1.18 Makefile --- Makefile 17 Oct 2022 12:01:19 -0000 1.18 +++ Makefile 20 Apr 2023 12:55:28 -0000 @@ -4,7 +4,8 @@ PROG= bgpctl SRCS= bgpctl.c output.c output_json.c output_ometric.c parser.c \ - mrtparser.c util.c json.c ometric.c + mrtparser.c json.c ometric.c +SRCS+= util.c flowspec.c CFLAGS+= -Wall CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes CFLAGS+= -Wmissing-declarations Index: bgpctl.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.c,v retrieving revision 1.290 diff -u -p -r1.290 bgpctl.c --- bgpctl.c 13 Mar 2023 16:59:22 -0000 1.290 +++ bgpctl.c 20 Apr 2023 12:55:28 -0000 @@ -361,6 +361,22 @@ main(int argc, char *argv[]) mrt_parse(res->mrtfd, &net_mrt, 1); done = 1; break; + case FLOWSPEC_ADD: + case FLOWSPEC_REMOVE: + done = 1; + break; + case FLOWSPEC_FLUSH: + imsg_compose(ibuf, IMSG_FLOWSPEC_FLUSH, 0, 0, -1, NULL, 0); + printf("request sent.\n"); + done = 1; + break; + case FLOWSPEC_SHOW: + memset(&ribreq, 0, sizeof(ribreq)); + ribreq.aid = res->aid; + strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib)); + imsg_compose(ibuf, IMSG_CTL_SHOW_FLOWSPEC, 0, 0, -1, + &ribreq, sizeof(ribreq)); + break; case LOG_VERBOSE: verbose = 1; /* FALLTHROUGH */ @@ -424,6 +440,7 @@ show(struct imsg *imsg, struct parse_res struct ctl_show_rtr rtr; struct kroute_full *kf; struct ktable *kt; + struct flowspec *f; struct ctl_show_rib rib; struct rde_memstats stats; u_char *asdata; @@ -466,6 +483,14 @@ show(struct imsg *imsg, struct parse_res break; kf = imsg->data; output->fib(kf); + break; + case IMSG_CTL_SHOW_FLOWSPEC: + if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(*f)) + errx(1, "wrong imsg len"); + if (output->flowspec == NULL) + break; + f = imsg->data; + output->flowspec(f); break; case IMSG_CTL_SHOW_FIB_TABLES: if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(*kt)) Index: bgpctl.h =================================================================== RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.h,v retrieving revision 1.20 diff -u -p -r1.20 bgpctl.h --- bgpctl.h 28 Mar 2023 12:07:09 -0000 1.20 +++ bgpctl.h 20 Apr 2023 12:55:28 -0000 @@ -24,6 +24,7 @@ struct output { void (*timer)(struct ctl_timer *); void (*fib)(struct kroute_full *); void (*fib_table)(struct ktable *); + void (*flowspec)(struct flowspec *); void (*nexthop)(struct ctl_show_nexthop *); void (*interface)(struct ctl_show_interface *); void (*attr)(u_char *, size_t, int, int); Index: output.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpctl/output.c,v retrieving revision 1.38 diff -u -p -r1.38 output.c --- output.c 28 Mar 2023 12:07:09 -0000 1.38 +++ output.c 20 Apr 2023 12:55:28 -0000 @@ -85,6 +85,8 @@ show_head(struct parse_result *res) printf("%-5s %-4s %-32s %-32s\n", "flags", "prio", "destination", "gateway"); break; + case FLOWSPEC_SHOW: + printf("flags: S = Static\n"); default: break; } @@ -493,6 +495,108 @@ show_fib_table(struct ktable *kt) } static void +print_flowspec_list(struct flowspec *f, int type, int is_v6) +{ + const uint8_t *comp; + const char *fmt; + int complen, off = 0; + + if (flowspec_get_component(f->data, f->len, type, is_v6, + &comp, &complen) != 1) + return; + + printf("%s ", flowspec_fmt_label(type)); + fmt = flowspec_fmt_num_op(comp, complen, &off); + if (off == -1) { + printf("%s ", fmt); + } else { + printf("{ %s ", fmt); + do { + fmt = flowspec_fmt_num_op(comp, complen, &off); + printf("%s ", fmt); + } while (off != -1); + printf("} "); + } +} + +static void +print_flowspec_flags(struct flowspec *f, int type, int is_v6) +{ + const uint8_t *comp; + const char *fmt, *flags; + int complen, off = 0; + + if (flowspec_get_component(f->data, f->len, type, is_v6, + &comp, &complen) != 1) + return; + + printf("%s ", flowspec_fmt_label(type)); + + switch (type) { + case FLOWSPEC_TYPE_TCP_FLAGS: + flags = FLOWSPEC_TCP_FLAG_STRING; + break; + case FLOWSPEC_TYPE_FRAG: + if (!is_v6) + flags = FLOWSPEC_FRAG_STRING4; + else + flags = FLOWSPEC_FRAG_STRING6; + break; + } + + fmt = flowspec_fmt_bin_op(comp, complen, &off, flags); + if (off == -1) { + printf("%s ", fmt); + } else { + printf("{ %s ", fmt); + do { + fmt = flowspec_fmt_bin_op(comp, complen, &off, flags); + printf("%s ", fmt); + } while (off != -1); + printf("} "); + } +} + +static void +print_flowspec_addr(struct flowspec *f, int type, int is_v6) +{ + struct bgpd_addr addr; + uint8_t plen; + + flowspec_get_addr(f->data, f->len, type, is_v6, &addr, &plen, NULL); + if (plen == 0) + printf("%s any ", flowspec_fmt_label(type)); + else + printf("%s %s/%u ", flowspec_fmt_label(type), + log_addr(&addr), plen); +} + +static void +show_flowspec(struct flowspec *f) +{ + int is_v6 = (f->aid == AID_FLOWSPECv6); + + printf("%-5s ", fmt_fib_flags(f->flags)); + print_flowspec_list(f, FLOWSPEC_TYPE_PROTO, is_v6); + + print_flowspec_addr(f, FLOWSPEC_TYPE_SOURCE, is_v6); + print_flowspec_list(f, FLOWSPEC_TYPE_SRC_PORT, is_v6); + + print_flowspec_addr(f, FLOWSPEC_TYPE_DEST, is_v6); + print_flowspec_list(f, FLOWSPEC_TYPE_DST_PORT, is_v6); + + print_flowspec_list(f, FLOWSPEC_TYPE_DSCP, is_v6); + print_flowspec_list(f, FLOWSPEC_TYPE_PKT_LEN, is_v6); + print_flowspec_flags(f, FLOWSPEC_TYPE_TCP_FLAGS, is_v6); + print_flowspec_flags(f, FLOWSPEC_TYPE_FRAG, is_v6); + /* TODO: fixup the code handling to be like in the parser */ + print_flowspec_list(f, FLOWSPEC_TYPE_ICMP_TYPE, is_v6); + print_flowspec_list(f, FLOWSPEC_TYPE_ICMP_CODE, is_v6); + + printf("\n"); +} + +static void show_nexthop(struct ctl_show_nexthop *nh) { char *s; @@ -1117,6 +1221,7 @@ const struct output show_output = { .timer = show_timer, .fib = show_fib, .fib_table = show_fib_table, + .flowspec = show_flowspec, .nexthop = show_nexthop, .interface = show_interface, .communities = show_communities, Index: parser.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpctl/parser.c,v retrieving revision 1.129 diff -u -p -r1.129 parser.c --- parser.c 17 Apr 2023 13:48:31 -0000 1.129 +++ parser.c 20 Apr 2023 12:55:40 -0000 @@ -96,6 +96,7 @@ static const struct token t_show_mrt_as[ static const struct token t_show_prefix[]; static const struct token t_show_ip[]; static const struct token t_network[]; +static const struct token t_flowspec[]; static const struct token t_bulk[]; static const struct token t_network_show[]; static const struct token t_prefix[]; @@ -107,6 +108,7 @@ static const struct token t_communicatio static const struct token t_main[] = { { KEYWORD, "fib", FIB, t_fib}, + { KEYWORD, "flowspec", NONE, t_flowspec}, { KEYWORD, "log", NONE, t_log}, { KEYWORD, "neighbor", NEIGHBOR, t_neighbor}, { KEYWORD, "network", NONE, t_network}, @@ -118,6 +120,7 @@ static const struct token t_main[] = { static const struct token t_show[] = { { NOTOKEN, "", NONE, NULL}, { KEYWORD, "fib", SHOW_FIB, t_show_fib}, + { KEYWORD, "flowspec", FLOWSPEC_SHOW, t_network_show}, { KEYWORD, "interfaces", SHOW_INTERFACE, NULL}, { KEYWORD, "ip", NONE, t_show_ip}, { KEYWORD, "metrics", SHOW_METRICS, NULL}, @@ -326,6 +329,12 @@ static const struct token t_network[] = { KEYWORD, "flush", NETWORK_FLUSH, NULL}, { KEYWORD, "mrt", NETWORK_MRT, t_show_mrt}, { KEYWORD, "show", NETWORK_SHOW, t_network_show}, + { ENDTOKEN, "", NONE, NULL} +}; + +static const struct token t_flowspec[] = { + { KEYWORD, "flush", FLOWSPEC_FLUSH, NULL}, + { KEYWORD, "show", FLOWSPEC_SHOW, t_network_show}, { ENDTOKEN, "", NONE, NULL} }; Index: parser.h =================================================================== RCS file: /cvs/src/usr.sbin/bgpctl/parser.h,v retrieving revision 1.44 diff -u -p -r1.44 parser.h --- parser.h 17 Oct 2022 16:51:36 -0000 1.44 +++ parser.h 20 Apr 2023 12:55:28 -0000 @@ -56,7 +56,11 @@ enum actions { NETWORK_SHOW, NETWORK_MRT, NETWORK_BULK_ADD, - NETWORK_BULK_REMOVE + NETWORK_BULK_REMOVE, + FLOWSPEC_ADD, + FLOWSPEC_REMOVE, + FLOWSPEC_FLUSH, + FLOWSPEC_SHOW, }; struct parse_result {