diff --git a/CHANGES b/CHANGES index ac9bfd4..e2d739e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,4 @@ -untagged yet (2018-10-02) +untagged yet (2018-11-11) - initial support for Juniper route-filter-lists (JunOS 16.2+). - too large (>124bytes) sources list was not handled correctly. Reported by Pier Carlo Chiodi. @@ -14,6 +14,8 @@ untagged yet (2018-10-02) - cleanup OpenBGPd prefix-sets. Submitted by Claudio Jeker. - new flag -t: generate as-sets for OpenBGPD (OpenBSD 6.4+), BIRD and JSON formats. Based on submission by Claudio Jeker. + - new flag -n: support for Nokia SR OS MD-CLI. Based on examples + provided by Greg Hankins. 0.1.35-rc2 (2017-06-14) - OpenBSD need . Reported by Denis Fondras. diff --git a/README.md b/README.md index 7f7ff1e..9d2d4d9 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ SYNOPSIS -------- ``` - bgpq3 [-h host[:port]] [-S sources] [-EPz] [-f asn | -F fmt | -G asn | -t] [-2346ABbDdJjpsUX] [-a asn] [-r len] [-R len] [-m max] [-W len] OBJECTS [...] EXCEPT OBJECTS + bgpq3 [-h host[:port]] [-S sources] [-EPz] [-f asn | -F fmt | -G asn | -t] [-2346ABbDdJjNnpsUX] [-a asn] [-r len] [-R len] [-m max] [-W len] OBJECTS [...] EXCEPT OBJECTS ``` DESCRIPTION @@ -98,9 +98,13 @@ Maximum length of accepted prefixes (default: `32` for IPv4, `128` for IPv6). Extra match conditions for Juniper route-filters. See the examples section. +#### -n + +Generate config for Nokia SR OS (former Alcatel-Lucent) MD-CLI (default: Cisco) + #### -N -Generate config for Nokia SR OS (former Alcatel-Lucent) (default: Cisco) +Generate config for Nokia SR OS (former Alcatel-Lucent) classic CLI (default: Cisco) #### -l `name` diff --git a/bgpq3.8 b/bgpq3.8 index 0cfe80d..1301eb2 100644 --- a/bgpq3.8 +++ b/bgpq3.8 @@ -39,7 +39,7 @@ .Fl G Ar asn .Fl t .Oc -.Op Fl 2346ABbDdJjNsXU +.Op Fl 2346ABbDdJjNnsXU .Op Fl a Ar asn .Op Fl r Ar len .Op Fl R Ar len @@ -102,8 +102,10 @@ maximum prefix-length of accepted prefixes (default: 32 for IPv4 and 128 for IPv6). .It Fl M Ar match extra match conditions for Juniper route-filters. +.It Fl n +generate config for Nokia SR OS MD-CLI (Cisco IOS by default) .It Fl N -generate config for Nokia SR OS (Cisco IOS by default). +generate config for Nokia SR OS classic CLI (Cisco IOS by default). .It Fl p accept routes registered for private ASNs (default: disabled) .It Fl P diff --git a/bgpq3.c b/bgpq3.c index 0a9bd6e..f4010f9 100644 --- a/bgpq3.c +++ b/bgpq3.c @@ -27,14 +27,13 @@ int usage(int ecode) { printf("\nUsage: bgpq3 [-h host[:port]] [-S sources] [-P|E|G |f |t]" - " [-2346ABbDdJjwXz] [-R len] ...\n"); + " [-2346ABbDdJjNnwXz] [-R len] ...\n"); printf(" -2 : allow routes belonging to as23456 (transition-as) " "(default: false)\n"); printf(" -3 : assume that your device is asn32-safe\n"); printf(" -4 : generate IPv4 prefix-lists (default)\n"); printf(" -6 : generate IPv6 prefix-lists (IPv4 by default)\n"); - printf(" -A : try to aggregate Cisco prefix-lists or Juniper " - "route-filters\n as much as possible\n"); + printf(" -A : try to aggregate prefix-lists/route-filters\n"); printf(" -B : generate OpenBGPD output (Cisco IOS by default)\n"); printf(" -b : generate BIRD output (Cisco IOS by default)\n"); printf(" -D : use asdot notation in as-path (Cisco only)\n"); @@ -57,7 +56,10 @@ usage(int ecode) printf(" -L depth : limit recursion depth (default: unlimited)\n"), printf(" -l name : use specified name for generated access/prefix/.." " list\n"); - printf(" -N : generate config for Nokia SR OS (Cisco IOS by default)\n"); + printf(" -N : generate config for Nokia SR OS classic CLI " + "(Cisco IOS by default)\n"); + printf(" -n : generate config for Nokia SR OS MD-CLI (Cisco IOS " + "by default)\n"); printf(" -P : generate prefix-list (default, just for backward" " compatibility)\n"); printf(" -R len : allow more specific routes up to specified masklen\n"); @@ -91,8 +93,8 @@ void vendor_exclusive() { fprintf(stderr, "-b (BIRD), -B (OpenBGPD), -F (formatted), -J (JunOS), " - "-j (JSON), -N (NOKIA SR OS), -U (Huawei) and -X (IOS XR) options " - "are mutually exclusive\n"); + "-j (JSON), -N (Nokia SR OS classic), -n (Nokia SR OS MD-CLI), " + "-U (Huawei) and -X (IOS XR) options are mutually exclusive\n"); exit(1); }; @@ -144,7 +146,7 @@ main(int argc, char* argv[]) if (getenv("IRRD_SOURCES")) expander.sources=getenv("IRRD_SOURCES"); - while((c=getopt(argc,argv,"2346a:AbBdDEF:S:jJf:l:L:m:M:NW:Ppr:R:G:tTh:UwXsz")) + while((c=getopt(argc,argv,"2346a:AbBdDEF:S:jJf:l:L:m:M:NnW:Ppr:R:G:tTh:UwXsz")) !=EOF) { switch(c) { case '2': @@ -299,6 +301,9 @@ main(int argc, char* argv[]) case 'N': if(expander.vendor) vendor_exclusive(); expander.vendor=V_NOKIA; break; + case 'n': if(expander.vendor) vendor_exclusive(); + expander.vendor=V_NOKIA_MD; + break; case 't': if(expander.generation) exclusive(); expander.generation=T_ASSET; @@ -346,7 +351,7 @@ main(int argc, char* argv[]) expander.aswidth=8; } else if(expander.vendor==V_BIRD) { expander.aswidth=10; - } else if(expander.vendor==V_NOKIA) { + } else if(expander.vendor==V_NOKIA || expander.vendor==V_NOKIA_MD) { expander.aswidth=8; }; } else if(expander.generation==T_OASPATH) { @@ -356,7 +361,7 @@ main(int argc, char* argv[]) expander.aswidth=7; } else if(expander.vendor==V_JUNIPER) { expander.aswidth=8; - } else if(expander.vendor==V_NOKIA) { + } else if(expander.vendor==V_NOKIA || expander.vendor==V_NOKIA_MD) { expander.aswidth=8; }; }; @@ -430,7 +435,15 @@ main(int argc, char* argv[]) if(aggregate && expander.vendor==V_NOKIA) { sx_report(SX_FATAL, "Sorry, aggregation (-A) is not supported on " - "Nokia equipment (-N)\n"); + "Nokia classic CLI (-N)\n"); + exit(1); + }; + + if(aggregate && expander.vendor==V_NOKIA_MD && + expander.generation!=T_EACL) { + sx_report(SX_FATAL, "Sorry, aggregation (-A) is not supported with " + "match-lists on Nokia MD-CLI. You can try prefix-lists (-E) " + "instead\n"); exit(1); }; @@ -496,10 +509,10 @@ main(int argc, char* argv[]) if(expander.vendor==V_NOKIA) { if(refine) { sx_report(SX_FATAL, "Sorry, more-specific filters (-R %u) " - "not supported on Nokia (-N)\n", refine); + "not supported on Nokia classic CLI (-N)\n", refine); } else { sx_report(SX_FATAL, "Sorry, more-specific filters (-r %u) " - "not supported on Nokia (-N)\n", refineLow); + "not supported on Nokia classic CLI (-N)\n", refineLow); }; }; diff --git a/bgpq3.h b/bgpq3.h index 29185b3..b7d8af1 100644 --- a/bgpq3.h +++ b/bgpq3.h @@ -19,7 +19,8 @@ typedef enum { V_OPENBGPD, V_FORMAT, V_NOKIA, - V_HUAWEI + V_HUAWEI, + V_NOKIA_MD } bgpq_vendor_t; typedef enum { diff --git a/bgpq3_printer.c b/bgpq3_printer.c index 993b822..64089d6 100644 --- a/bgpq3_printer.c +++ b/bgpq3_printer.c @@ -370,6 +370,50 @@ bgpq3_print_nokia_aspath(FILE* f, struct bgpq_expander* b) return 0; }; +int +bgpq3_print_nokia_md_aspath(FILE* f, struct bgpq_expander* b) +{ + int nc=0, lineNo=1, i, j, k; + + fprintf(f,"/configure policy-options\ndelete as-path-group \"%s\"\n", + b->name ? b->name : "NN"); + fprintf(f,"as-path-group \"%s\" {\n", b->name ? b->name : "NN"); + + if(b->asn32s[b->asnumber/65536] && + b->asn32s[b->asnumber/65535][(b->asnumber%65536)/8]& + (0x80>>(b->asnumber%8))) { + fprintf(f," entry %u {\n expression \"%u+\"\n }\n", lineNo, + b->asnumber); + lineNo++; + }; + for(k=0;k<65536;k++) { + if(!b->asn32s[k]) continue; + for(i=0;i<8192;i++) { + for(j=0;j<8;j++) { + if(b->asn32s[k][i]&(0x80>>j)) { + if(k*65536+i*8+j==b->asnumber) continue; + if(!nc) { + fprintf(f," entry %u {\n expression \"%u.*[%u", + lineNo,b->asnumber,k*65536+i*8+j); + } else { + fprintf(f," %u",k*65536+i*8+j); + }; + nc++; + if(nc==b->aswidth) { + fprintf(f,"]\"\n }\n"); + nc=0; + lineNo++; + }; + }; + }; + }; + }; + if(nc) fprintf(f,"]\"\n }\n"); + fprintf(f, "}\n"); + return 0; +}; + + int bgpq3_print_huawei_aspath(FILE* f, struct bgpq_expander* b) { @@ -497,7 +541,50 @@ bgpq3_print_nokia_oaspath(FILE* f, struct bgpq_expander* b) }; }; if(nc) fprintf(f,"]\"\n"); - fprintf(f,"exit\ncommit\n"); + return 0; +}; + +int +bgpq3_print_nokia_md_oaspath(FILE* f, struct bgpq_expander* b) +{ + int nc=0, lineNo=1, i, j, k; + + fprintf(f,"/configure policy-options\ndelete as-path-group \"%s\"\n", + b->name ? b->name : "NN"); + fprintf(f,"as-path-group \"%s\" {\n", b->name ? b->name : "NN"); + + if(b->asn32s[b->asnumber/65536] && + b->asn32s[b->asnumber/65536][(b->asnumber%65536)/8]& + (0x80>>(b->asnumber%8))) { + fprintf(f," entry %u {\n expression \"%u+\"\n }\n", lineNo, + b->asnumber); + lineNo++; + }; + for(k=0;k<65536;k++) { + if(!b->asn32s[k]) continue; + + for(i=0;i<8192;i++) { + for(j=0;j<8;j++) { + if(b->asn32s[k][i]&(0x80>>j)) { + if(k*65536+i*8+j==b->asnumber) continue; + if(!nc) { + fprintf(f," entry %u {\n expression \".*[%u", + lineNo,k*65536+i*8+j); + } else { + fprintf(f," %u",k*65536+i*8+j); + } + nc++; + if(nc==b->aswidth) { + fprintf(f,"]\"\n }\n"); + nc=0; + lineNo++; + }; + }; + }; + }; + }; + if(nc) fprintf(f,"]\"\n }\n"); + fprintf(f, "}\n"); return 0; }; @@ -518,6 +605,8 @@ bgpq3_print_aspath(FILE* f, struct bgpq_expander* b) return bgpq3_print_openbgpd_aspath(f,b); } else if(b->vendor==V_NOKIA) { return bgpq3_print_nokia_aspath(f,b); + } else if(b->vendor==V_NOKIA_MD) { + return bgpq3_print_nokia_md_aspath(f,b); } else if(b->vendor==V_HUAWEI) { return bgpq3_print_huawei_aspath(f,b); } else { @@ -539,6 +628,8 @@ bgpq3_print_oaspath(FILE* f, struct bgpq_expander* b) return bgpq3_print_openbgpd_oaspath(f,b); } else if(b->vendor==V_NOKIA) { return bgpq3_print_nokia_oaspath(f,b); + } else if(b->vendor==V_NOKIA_MD) { + return bgpq3_print_nokia_md_oaspath(f,b); } else if(b->vendor==V_HUAWEI) { return bgpq3_print_huawei_oaspath(f,b); } else { @@ -555,6 +646,7 @@ bgpq3_print_asset(FILE* f, struct bgpq_expander* b) case V_CISCO: case V_CISCO_XR: case V_NOKIA: + case V_NOKIA_MD: case V_HUAWEI: case V_FORMAT: sx_report(SX_FATAL, "as-sets (-t) supported for JSON, OpenBGPD " @@ -974,6 +1066,20 @@ checkSon: bgpq3_print_nokia_ipfilter(n->son, ff); }; +void +bgpq3_print_nokia_md_ipfilter(struct sx_radix_node* n, void* ff) +{ + char prefix[128]; + FILE* f=(FILE*)ff; + if(n->isGlue) goto checkSon; + if(!f) f=stdout; + sx_prefix_snprintf(&n->prefix,prefix,sizeof(prefix)); + fprintf(f," prefix %s { }\n", prefix); +checkSon: + if(n->son) + bgpq3_print_nokia_md_ipfilter(n->son, ff); +}; + void bgpq3_print_nokia_prefix(struct sx_radix_node* n, void* ff) { @@ -999,6 +1105,33 @@ checkSon: }; +void +bgpq3_print_nokia_md_prefix(struct sx_radix_node* n, void* ff) +{ + char prefix[128]; + FILE* f=(FILE*)ff; + if(n->isGlue) goto checkSon; + if(!f) f=stdout; + sx_prefix_snprintf(&n->prefix,prefix,sizeof(prefix)); + if(!n->isAggregate) { + fprintf(f," prefix %s type exact {\n }\n", prefix); + } else { + if(n->aggregateLow>n->prefix.masklen) { + fprintf(f," prefix %s type range {\n start-length %u\n" + " end-length %u\n }\n", + prefix,n->aggregateLow,n->aggregateHi); + } else { + fprintf(f," prefix %s type through {\n " + "through-length %u\n }\n", + prefix, n->aggregateHi); + }; + }; +checkSon: + if(n->son) + bgpq3_print_nokia_md_prefix(n->son, ff); + +}; + int bgpq3_print_juniper_prefixlist(FILE* f, struct bgpq_expander* b) { @@ -1229,6 +1362,37 @@ bgpq3_print_nokia_ipprefixlist(FILE* f, struct bgpq_expander* b) return 0; }; +int +bgpq3_print_nokia_md_prefixlist(FILE* f, struct bgpq_expander* b) +{ + bname=b->name ? b->name : "NN"; + fprintf(f,"/configure filter match-list\ndelete %s-prefix-list \"%s\"\n", + b->tree->family==AF_INET?"ip":"ipv6", bname); + fprintf(f,"%s-prefix-list \"%s\" {\n", b->tree->family==AF_INET?"ip":"ipv6", + bname); + if (!sx_radix_tree_empty(b->tree)) { + sx_radix_tree_foreach(b->tree,bgpq3_print_nokia_md_ipfilter,f); + } else { + fprintf(f,"# generated %s-prefix-list %s is empty\n", + b->tree->family==AF_INET?"ip":"ipv6", bname); + }; + fprintf(f,"}\n"); + return 0; +}; + +int +bgpq3_print_nokia_md_ipprefixlist(FILE* f, struct bgpq_expander* b) +{ + bname=b->name ? b->name : "NN"; + fprintf(f,"/configure policy-options\ndelete prefix-list \"%s\"\n", bname); + fprintf(f,"prefix-list \"%s\" {\n", bname); + if (!sx_radix_tree_empty(b->tree)) { + sx_radix_tree_foreach(b->tree,bgpq3_print_nokia_md_prefix,f); + }; + fprintf(f,"}\n"); + return 0; +}; + int bgpq3_print_prefixlist(FILE* f, struct bgpq_expander* b) { @@ -1241,6 +1405,7 @@ bgpq3_print_prefixlist(FILE* f, struct bgpq_expander* b) case V_OPENBGPD: return bgpq3_print_openbgpd_prefixlist(f,b); case V_FORMAT: return bgpq3_print_format_prefixlist(f,b); case V_NOKIA: return bgpq3_print_nokia_prefixlist(f,b); + case V_NOKIA_MD: return bgpq3_print_nokia_md_prefixlist(f,b); case V_HUAWEI: return bgpq3_print_huawei_prefixlist(f,b); }; return 0; @@ -1258,6 +1423,7 @@ bgpq3_print_eacl(FILE* f, struct bgpq_expander* b) case V_OPENBGPD: return bgpq3_print_openbgpd_prefixset(f,b); case V_FORMAT: sx_report(SX_FATAL, "unreachable point\n"); case V_NOKIA: return bgpq3_print_nokia_ipprefixlist(f,b); + case V_NOKIA_MD: return bgpq3_print_nokia_md_ipprefixlist(f,b); case V_HUAWEI: return sx_report(SX_FATAL, "unreachable point\n"); }; return 0;