diff --git a/bgpq4.8 b/bgpq4.8 index 90ff1d3..8604b90 100644 --- a/bgpq4.8 +++ b/bgpq4.8 @@ -74,6 +74,8 @@ generate output in BIRD format (default: Cisco). enable some debugging output. .It Fl e generate output in Arista EOS format (default: Cisco). +.It Fl Z +generate output in FRRouting format (default: Cisco). .It Fl E generate extended access-list (Cisco), policy-statement term using route-filters (Juniper), [ip|ipv6]-prefix-list (Nokia) or prefix-sets @@ -121,7 +123,7 @@ allow more specific routes starting with specified masklen too. .It Fl R Ar len allow more specific routes up to specified masklen too. .It Fl s -generate sequence numbers in IOS-style prefix-lists. +generate sequence numbers in prefix-lists (IOS, EOS and FRRouting only). .It Fl S Ar sources use specified sources only (recommended: RPKI,AFRINIC,APNIC,ARIN,LACNIC,RIPE). .It Fl t diff --git a/extern.h b/extern.h index 0f3179d..9ee02bd 100644 --- a/extern.h +++ b/extern.h @@ -64,6 +64,7 @@ typedef enum { V_NOKIA_MD, V_ARISTA, V_NOKIA_SRL, + V_FRR, } bgpq_vendor_t; typedef enum { diff --git a/main.c b/main.c index c427c04..41e8400 100644 --- a/main.c +++ b/main.c @@ -68,6 +68,7 @@ usage(int ecode) printf(" -n2 : Nokia SR Linux\n"); printf(" -B : OpenBSD OpenBGPD\n"); printf(" -e : Arista EOS\n"); + printf(" -Z : FRRouting\n"); printf(" -F fmt : User defined format (example: '-F %%n/%%l')\n"); printf("\nInput filters:\n"); @@ -97,7 +98,7 @@ usage(int ecode) printf(" -p : allow special ASNs like 23456 or in the private range\n"); printf(" -R len : allow more specific routes up to specified masklen\n"); printf(" -r len : allow more specific routes from masklen specified\n"); - printf(" -s : generate sequence numbers in prefix-lists (IOS only)\n"); + printf(" -s : generate sequence numbers in prefix-lists (IOS, EOS and FRRouting only)\n"); printf(" -t : generate as-sets for OpenBGPD (OpenBGPD 6.4+), BIRD " "and JSON formats\n"); printf(" -z : generate route-filter-list (Junos only)\n"); @@ -201,7 +202,7 @@ main(int argc, char* argv[]) expander.sources=getenv("IRRD_SOURCES"); while ((c = getopt(argc, argv, - "23467a:AbBdDEeF:S:jJKf:l:L:m:M:NnpW:r:R:G:H:tTh:UuwXsvz")) != EOF) { + "23467a:AbBdDEeF:S:jJKf:l:L:m:M:NnpW:r:R:G:H:tTh:UuwXsvZz")) != EOF) { switch (c) { case '2': if (expander.vendor != V_NOKIA_MD) { @@ -458,6 +459,11 @@ main(int argc, char* argv[]) exclusive(); expander.generation = T_ROUTE_FILTER_LIST; break; + case 'Z': + if (expander.vendor) + vendor_exclusive(); + expander.vendor = V_FRR; + break; default: usage(1); } @@ -613,9 +619,9 @@ main(int argc, char* argv[]) } if (expander.sequence - && (expander.vendor != V_CISCO && expander.vendor != V_ARISTA)) { + && (expander.vendor != V_CISCO && expander.vendor != V_ARISTA && expander.vendor != V_FRR)) { sx_report(SX_FATAL, "Sorry, prefix-lists sequencing (-s) supported" - " only for IOS and EOS\n"); + " only for IOS, EOS and FRRouting\n"); exit(1); } diff --git a/printer.c b/printer.c index fdf6e5a..54d748b 100644 --- a/printer.c +++ b/printer.c @@ -1184,6 +1184,42 @@ bgpq4_print_eprefix(struct sx_radix_node *n, void *ff) bgpq4_print_eprefix(n->son, ff); } +static void +bgpq4_print_frr_prefix(struct sx_radix_node *n, void *ff) +{ + char prefix[128], seqno[16] = ""; + FILE *f = (FILE*)ff; + + if (!f) + f = stdout; + + if (n->isGlue) + goto checkSon; + + sx_prefix_snprintf(n->prefix, prefix, sizeof(prefix)); + + if (seq) + snprintf(seqno, sizeof(seqno), " seq %i", seq++); + + if (n->isAggregate) { + if (n->aggregateLow > n->prefix->masklen) { + fprintf(f,"ip prefix-list %s%s permit %s ge %u le %u\n", + bname ? bname : "NN", seqno, prefix, + n->aggregateLow, n->aggregateHi); + } else { + fprintf(f,"ip prefix-list %s%s permit %s le %u\n", + bname?bname:"NN", seqno, prefix, n->aggregateHi); + } + } else { + fprintf(f,"ip prefix-list %s%s permit %s\n", + bname ? bname : "NN", seqno, prefix); + } + +checkSon: + if (n->son) + bgpq4_print_frr_prefix(n->son, ff); +} + static void bgpq4_print_ceacl(struct sx_radix_node *n, void *ff) { @@ -1900,6 +1936,19 @@ bgpq4_print_mikrotik_prefixlist(FILE *f, struct bgpq_expander *b) } } +static void +bgpq4_print_frr_prefixlist(FILE *f, struct bgpq_expander *b) +{ + bname = b->name ? b->name : "NN"; + seq = b->sequence; + + if (!sx_radix_tree_empty(b->tree)) { + sx_radix_tree_foreach(b->tree, bgpq4_print_frr_prefix, f); + } else { + fprintf(f, "# generated prefix-list %s is empty\n", bname); + } +} + void bgpq4_print_prefixlist(FILE *f, struct bgpq_expander *b) { @@ -1947,6 +1996,9 @@ bgpq4_print_prefixlist(FILE *f, struct bgpq_expander *b) case V_ARISTA: bgpq4_print_arista_prefixlist(f, b); break; + case V_FRR: + bgpq4_print_frr_prefixlist(f, b); + break; } }