diff --git a/README.md b/README.md index 677492b..88f3bf4 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ \[**-f** *asn* | **-F** *fmt* | **-G** *asn* +**-H** *asn* **-t**] \[**-46ABbDdJjNnsXU**] \[**-a** *asn*] @@ -82,6 +83,10 @@ The options are as follows: > generate output as-path access-list. +**-H** *number* + +> generate output as-list for JunOS 21.3R1+ `as-path-origin` filter (JunOS only) + **-h** *host\[:port]* > host running IRRD database (default: rr.ntt.net). diff --git a/extern.h b/extern.h index 1172644..d75a76e 100644 --- a/extern.h +++ b/extern.h @@ -68,6 +68,7 @@ typedef enum { T_NONE = 0, T_ASPATH, T_OASPATH, + T_ASLIST, T_ASSET, T_PREFIXLIST, T_EACL, @@ -132,6 +133,7 @@ void bgpq4_print_eacl(FILE *f, struct bgpq_expander *b); void bgpq4_print_aspath(FILE *f, struct bgpq_expander *b); void bgpq4_print_asset(FILE *f, struct bgpq_expander *b); void bgpq4_print_oaspath(FILE *f, struct bgpq_expander *b); +void bgpq4_print_aslist(FILE *f, struct bgpq_expander *b); void bgpq4_print_route_filter_list(FILE *f, struct bgpq_expander *b); void sx_radix_node_freeall(struct sx_radix_node *n); diff --git a/main.c b/main.c index c1fd38d..9414478 100644 --- a/main.c +++ b/main.c @@ -50,7 +50,7 @@ extern int expand_special_asn; static int usage(int ecode) { - printf("\nUsage: bgpq4 [-h host[:port]] [-S sources] [-E|G " + printf("\nUsage: bgpq4 [-h host[:port]] [-S sources] [-E|G|H " "|f |t] [-46ABbdJjKNnwXz] [-R len] ... " "[EXCEPT ...]\n"); printf("\nVendor targets:\n"); @@ -87,6 +87,7 @@ usage(int ecode) "(OpenBGPD)\n"); printf(" -f number : generate input as-path access-list\n"); printf(" -G number : generate output as-path access-list\n"); + printf(" -H number : generate origin as-lists (JunOS only)\n"); printf(" -M match : extra match conditions for JunOS route-filters\n"); printf(" -l name : use specified name for generated access/prefix/.." " list\n"); @@ -96,7 +97,7 @@ usage(int ecode) printf(" -t : generate as-sets for OpenBGPD (OpenBGPD 6.4+), BIRD " "and JSON formats\n"); printf(" -z : generate route-filter-list (Junos only)\n"); - printf(" -W len : specify max-entries on as-path line (use 0 for " + printf(" -W len : specify max-entries on as-path/as-list line (use 0 for " "infinity)\n"); printf("\nUtility operations:\n"); @@ -196,7 +197,7 @@ main(int argc, char* argv[]) expander.sources=getenv("IRRD_SOURCES"); while ((c = getopt(argc, argv, - "46a:AbBdDEeF:S:jJKf:l:L:m:M:NnW:pr:R:G:tTh:UuwXsvz")) != EOF) { + "46a:AbBdDEeF:S:jJKf:l:L:m:M:NnW:pr:R:G:H:tTh:UuwXsvz")) != EOF) { switch (c) { case '4': /* do nothing, expander already configured for IPv4 */ @@ -267,6 +268,12 @@ main(int argc, char* argv[]) expander.generation = T_OASPATH; parseasnumber(&expander, optarg); break; + case 'H': + if (expander.generation) + exclusive(); + expander.generation = T_ASLIST; + parseasnumber(&expander, optarg); + break; case 'h': { char *d = strchr(optarg, ':'); @@ -475,6 +482,13 @@ main(int argc, char* argv[]) expander.aswidth = 8; break; } + } else if (expander.generation == T_ASLIST) { + int vendor = expander.vendor; + switch (vendor) { + case V_JUNIPER: + expander.aswidth = 8; + break; + } } } @@ -660,14 +674,18 @@ main(int argc, char* argv[]) "only with Juniper route-filters\n"); } - if ((expander.generation == T_ASPATH || expander.generation == T_OASPATH) + if ((expander.generation == T_ASPATH + || expander.generation == T_OASPATH + || expander.generation == T_ASLIST) && af != AF_INET && !expander.validate_asns) { - sx_report(SX_FATAL, "Sorry, -6 makes no sense with as-path (-f/-G) " + sx_report(SX_FATAL, "Sorry, -6 makes no sense with as-path (-f/-G) or as-list (-H) " "generation\n"); } - if (expander.validate_asns && expander.generation != T_ASPATH - && expander.generation != T_OASPATH) { + if (expander.validate_asns + && expander.generation != T_ASPATH + && expander.generation != T_OASPATH + && expander.generation != T_ASLIST) { sx_report(SX_FATAL, "Sorry, -w makes sense only for as-path " "(-f/-G) generation\n"); } @@ -738,6 +756,9 @@ main(int argc, char* argv[]) case T_OASPATH: bgpq4_print_oaspath(stdout, &expander); break; + case T_ASLIST: + bgpq4_print_aslist(stdout, &expander); + break; case T_ASSET: bgpq4_print_asset(stdout, &expander); break; diff --git a/printer.c b/printer.c index 17236bd..310527d 100644 --- a/printer.c +++ b/printer.c @@ -274,6 +274,45 @@ bgpq4_print_juniper_oaspath(FILE *f, struct bgpq_expander *b) fprintf(f, " }\n}\n"); } +static void +bgpq4_print_juniper_aslist(FILE *f, struct bgpq_expander *b) +{ + int nc = 0, lineNo = 0; + struct asn_entry *asne, find, *res; + + fprintf(f,"policy-options {\nreplace:\n as-list-group %s {\n", + b->name); + + find.asn = b->asnumber; + if ((res = RB_FIND(asn_tree, &b->asnlist, &find)) != NULL) { + fprintf(f, " as-list a0 members %u;\n", res->asn); + RB_REMOVE(asn_tree, &b->asnlist, res); + lineNo++; + } + + RB_FOREACH(asne, asn_tree, &b->asnlist) { + if (!nc) { + fprintf(f, " as-list a%u members [ %u", + lineNo, asne->asn); + } else { + fprintf(f," %u", asne->asn); + } + + nc++; + + if (nc == b->aswidth) { + fprintf(f, " ];\n"); + nc = 0; + lineNo++; + } + } + + if (nc) + fprintf(f, " ];\n"); + + fprintf(f, " }\n}\n"); +} + static void bgpq4_print_openbgpd_oaspath(FILE *f, struct bgpq_expander *b) { @@ -878,6 +917,18 @@ bgpq4_print_oaspath(FILE *f, struct bgpq_expander *b) } } +void +bgpq4_print_aslist(FILE *f, struct bgpq_expander *b) +{ + switch (b->vendor) { + case V_JUNIPER: + bgpq4_print_juniper_aslist(f, b); + break; + default: + sx_report(SX_FATAL,"Unknown vendor %i\n", b->vendor); + } +} + void bgpq4_print_asset(FILE *f, struct bgpq_expander *b) {