From 2152ecdb4303a43b90fbe9a2835c2606f17f7b3b Mon Sep 17 00:00:00 2001 From: Alexandre Snarskii Date: Fri, 10 Aug 2018 15:02:08 +0300 Subject: [PATCH] Huawei support, copyright year update. --- CHANGES | 4 +- COPYRIGHT | 2 +- README.md | 6 +- bgpq3.8 | 6 +- bgpq3.c | 45 +++++++++------ bgpq3.h | 4 +- bgpq3_printer.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++ configure | 18 +++--- configure.in | 2 +- sx_prefix.c | 11 +++- sx_prefix.h | 1 + 11 files changed, 205 insertions(+), 36 deletions(-) diff --git a/CHANGES b/CHANGES index 3b313ef..a836a2e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,7 +1,9 @@ -untagged yet (2017-09-08) +untagged yet (2018-08-10) - initial support for Juniper route-filter-lists (JunOS 16.2+). - too large (>124bytes) sources list was not handled correctly. Reported by Pier Carlo Chiodi. + - initial support for Huawei format (prefix-lists and as-path filters) + New flag -U. Requested by Alexander Wagberg. 0.1.35-rc2 (2017-06-14) - OpenBSD need . Reported by Denis Fondras. diff --git a/COPYRIGHT b/COPYRIGHT index a4324ef..5a11aae 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2007-2017 Alexandre Snarskii + * Copyright (c) 2007-2018 Alexandre Snarskii * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/README.md b/README.md index f2b4ce8..7cc55dc 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] [-2346ABbDdJjpsX] [-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] [-2346ABbDdJjpsUX] [-a asn] [-r len] [-R len] [-m max] [-W len] OBJECTS [...] EXCEPT OBJECTS ``` DESCRIPTION @@ -141,6 +141,10 @@ Use specified sources only (recommended: RADB,RIPE,APNIC). Disable pipelining. (not recommended) +#### -U + +Generate output in Huawei format (default: Cisco). + #### -W `length` Generate as-path strings of a given length maximum (0 for infinity). diff --git a/bgpq3.8 b/bgpq3.8 index 08bad2f..a9d7aa2 100644 --- a/bgpq3.8 +++ b/bgpq3.8 @@ -1,4 +1,4 @@ -.\" Copyright (c) 2007-2017 Alexandre Snarskii +.\" Copyright (c) 2007-2018 Alexandre Snarskii .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without @@ -38,7 +38,7 @@ .Fl F Ar fmt | .Fl G Ar asn .Oc -.Op Fl 2346ABbDdJjNsX +.Op Fl 2346ABbDdJjNsXU .Op Fl a Ar asn .Op Fl r Ar len .Op Fl R Ar len @@ -118,6 +118,8 @@ use specified sources only (recommended: RADB,RIPE,APNIC). disable pipelining. .It Fl W Ar len generate as-path strings of no more than len items (use 0 for inifinity). +.It Fl U +generate config for Huawei devices (Cisco IOS by default) .It Fl X generate config for Cisco IOS XR devices (plain IOS by default). .It Fl z diff --git a/bgpq3.c b/bgpq3.c index 540d5fa..c3abf1a 100644 --- a/bgpq3.c +++ b/bgpq3.c @@ -37,13 +37,13 @@ usage(int ecode) "route-filters\n as much as possible\n"); printf(" -B : generate OpenBGPD output (Cisco IOS by default)\n"); printf(" -b : generate BIRD output (Cisco IOS by default)\n"); - printf(" -d : generate some debugging output\n"); printf(" -D : use asdot notation in as-path (Cisco only)\n"); + printf(" -d : generate some debugging output\n"); printf(" -E : generate extended access-list(Cisco), " "route-filter(Juniper) or\n" " [ip|ipv6]-prefix-list (Nokia)\n"); - printf(" -f number : generate input as-path access-list\n"); printf(" -F fmt : generate output in user-defined format\n"); + printf(" -f number : generate input as-path access-list\n"); printf(" -G number : generate output as-path access-list\n"); printf(" -h host : host running IRRD software (whois.radb.net by " "default)\n" @@ -65,11 +65,12 @@ usage(int ecode) " RADB,RIPE,APNIC)\n"); printf(" -s : generate sequence numbers in prefix-lists (IOS only)\n"); printf(" -T : disable pipelining (experimental, faster mode)\n"); + printf(" -U : generate config for Huawei (Cisco IOS by default)\n"); printf(" -W len : specify max-entries on as-path line (use 0 for " "infinity)\n"); printf(" -X : generate config for IOS XR (Cisco IOS by default)\n"); printf("\n" PACKAGE_NAME " version: " PACKAGE_VERSION "\n"); - printf("Copyright(c) Alexandre Snarskii 2007-2017\n\n"); + printf("Copyright(c) Alexandre Snarskii 2007-2018\n\n"); exit(ecode); }; @@ -85,7 +86,8 @@ void vendor_exclusive() { fprintf(stderr, "-b (BIRD), -B (OpenBGPD), -F (formatted), -J (JunOS), " - "-j (JSON), -N (NOKIA SR OS) and -X (IOS XR) options are mutually exclusive\n"); + "-j (JSON), -N (NOKIA SR OS), -U (Huawei) and -X (IOS XR) options " + "are mutually exclusive\n"); exit(1); }; @@ -137,7 +139,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:Th:Xsz")) + while((c=getopt(argc,argv,"2346a:AbBdDEF:S:jJf:l:L:m:M:NW:Ppr:R:G:Th:UXsz")) !=EOF) { switch(c) { case '2': @@ -179,10 +181,10 @@ main(int argc, char* argv[]) expander.vendor=V_OPENBGPD; expander.asn32=1; break; - case 'd': debug_expander++; - break; case 'D': expander.asdot=1; break; + case 'd': debug_expander++; + break; case 'E': if(expander.generation) exclusive(); expander.generation=T_EACL; break; @@ -190,6 +192,16 @@ main(int argc, char* argv[]) expander.vendor=V_FORMAT; expander.format=optarg; break; + case 'f': + if(expander.generation) exclusive(); + expander.generation=T_ASPATH; + parseasnumber(&expander,optarg); + break; + case 'G': + if(expander.generation) exclusive(); + expander.generation=T_OASPATH; + parseasnumber(&expander,optarg); + break; case 'h': { char* d=strchr(optarg, ':'); expander.server=optarg; @@ -205,16 +217,6 @@ main(int argc, char* argv[]) case 'j': if(expander.vendor) vendor_exclusive(); expander.vendor=V_JSON; break; - case 'f': - if(expander.generation) exclusive(); - expander.generation=T_ASPATH; - parseasnumber(&expander,optarg); - break; - case 'G': - if(expander.generation) exclusive(); - expander.generation=T_OASPATH; - parseasnumber(&expander,optarg); - break; case 'p': expand_special_asn=1; break; @@ -298,6 +300,10 @@ main(int argc, char* argv[]) break; case 'S': expander.sources=optarg; break; + case 'U': + if(expander.vendor) exclusive(); + expander.vendor=V_HUAWEI; + break; case 'W': expander.aswidth=atoi(optarg); if(expander.aswidth<0) { sx_report(SX_FATAL,"Invalid as-width: %s\n", optarg); @@ -372,6 +378,11 @@ main(int argc, char* argv[]) "compatible with -R/-r options\n"); exit(1); }; + if(expander.vendor==V_HUAWEI && expander.generation!=T_ASPATH && + expander.generation!=T_OASPATH && expander.generation != T_PREFIXLIST) + sx_report(SX_FATAL, "Sorry, only as-paths and prefix-lists supported " + "for Huawei output\n"); + if(expander.generation==T_ROUTE_FILTER_LIST && expander.vendor!=V_JUNIPER) { sx_report(SX_FATAL, "Route-filter-lists (-z) supported for Juniper (-J)" " output only\n"); diff --git a/bgpq3.h b/bgpq3.h index a60d14c..9becd99 100644 --- a/bgpq3.h +++ b/bgpq3.h @@ -18,7 +18,8 @@ typedef enum { V_BIRD, V_OPENBGPD, V_FORMAT, - V_NOKIA + V_NOKIA, + V_HUAWEI } bgpq_vendor_t; typedef enum { @@ -90,4 +91,3 @@ size_t strlcpy(char* dst, const char* src, size_t size); #endif #endif - diff --git a/bgpq3_printer.c b/bgpq3_printer.c index 611981e..2bedb65 100644 --- a/bgpq3_printer.c +++ b/bgpq3_printer.c @@ -369,6 +369,94 @@ bgpq3_print_nokia_aspath(FILE* f, struct bgpq_expander* b) return 0; }; +int +bgpq3_print_huawei_aspath(FILE* f, struct bgpq_expander* b) +{ + int nc=0, i, j, k, empty=1; + + fprintf(f,"no ip as-path-filter %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,"ip as-path-filter %s permit ^%u(%u)*$\n", + b->name?b->name:"NN",b->asnumber,b->asnumber); + empty=0; + }; + 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,"ip as-path-filter %s permit ^%u([0-9]+)*" + "_(%u", + b->name?b->name:"NN",b->asnumber,k*65536+i*8+j); + empty=0; + } else { + fprintf(f,"|%u",k*65536+i*8+j); + }; + nc++; + if(nc==b->aswidth) { + fprintf(f,")\n"); + nc=0; + }; + }; + }; + }; + }; + if(nc) fprintf(f,")\n"); + if(empty) + fprintf(f,"ip as-path-filter %s deny .*\n", b->name?b->name:"NN"); + return 0; +}; + +int +bgpq3_print_huawei_oaspath(FILE* f, struct bgpq_expander* b) +{ + int nc=0, i, j, k, empty=1; + + fprintf(f,"no ip as-path-filter %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,"ip as-path-filter %s permit (_%u)*$\n", b->name?b->name:"NN", + b->asnumber); + empty=0; + }; + 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,"ip as-path-filter %s permit ^(_[0-9]+)*_(%u", + b->name?b->name:"NN",k*65536+i*8+j); + } else { + fprintf(f,"|%u",k*65536+i*8+j); + } + nc++; + empty=0; + if(nc==b->aswidth) { + fprintf(f,")\n"); + nc=0; + }; + }; + }; + }; + }; + if(nc) fprintf(f,")\n"); + if(empty) + fprintf(f, "ip as-path-filter %s deny .*\n", b->name?b->name:"NN"); + return 0; +}; + int bgpq3_print_nokia_oaspath(FILE* f, struct bgpq_expander* b) { @@ -429,6 +517,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_HUAWEI) { + return bgpq3_print_huawei_aspath(f,b); } else { sx_report(SX_FATAL,"Unknown vendor %i\n", b->vendor); }; @@ -448,6 +538,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_HUAWEI) { + return bgpq3_print_huawei_oaspath(f,b); } else { sx_report(SX_FATAL,"Unknown vendor %i\n", b->vendor); }; @@ -727,6 +819,36 @@ checkSon: bgpq3_print_cprefixxr(n->son,ff); }; +void +bgpq3_print_hprefix(struct sx_radix_node* n, void* ff) +{ + char prefix[128]; + FILE* f=(FILE*)ff; + if(!f) f=stdout; + if(n->isGlue) goto checkSon; + sx_prefix_snprintf_sep(&n->prefix,prefix,sizeof(prefix)," "); + if(n->isAggregate) { + if(n->aggregateLow>n->prefix.masklen) { + fprintf(f,"ip %s-prefix %s permit %s greater-equal %u " + "less-equal %u\n", + n->prefix.family==AF_INET?"ip":"ipv6",bname?bname:"NN", + prefix,n->aggregateLow,n->aggregateHi); + } else { + fprintf(f,"ip %s-prefix %s permit %s less-equal %u\n", + n->prefix.family==AF_INET?"ip":"ipv6",bname?bname:"NN", + prefix,n->aggregateHi); + }; + } else { + fprintf(f,"ip %s-prefix %s permit %s\n", + (n->prefix.family==AF_INET)?"ip":"ipv6",bname?bname:"NN", + prefix); + }; +checkSon: + if(n->son) + bgpq3_print_hprefix(n->son,ff); +}; + + void bgpq3_print_ceacl(struct sx_radix_node* n, void* ff) { @@ -957,6 +1079,24 @@ bgpq3_print_bird_prefixlist(FILE* f, struct bgpq_expander* b) return 0; }; +int +bgpq3_print_huawei_prefixlist(FILE* f, struct bgpq_expander* b) +{ + bname=b->name ? b->name : "NN"; + seq=b->sequence; + fprintf(f,"no ip %s-prefix %s\n", + (b->family==AF_INET)?"ip":"ipv6",bname); + if (!sx_radix_tree_empty(b->tree)) { + sx_radix_tree_foreach(b->tree,bgpq3_print_hprefix,f); + } else { + fprintf(f, "ip %s-prefix %s deny %s\n", + (b->family==AF_INET) ? "ip" : "ipv6", bname, + (b->family==AF_INET) ? "0.0.0.0/0" : "::/0"); + }; + return 0; +}; + + struct fpcbdata { FILE* f; struct bgpq_expander* b; @@ -1045,6 +1185,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_HUAWEI: return bgpq3_print_huawei_prefixlist(f,b); }; return 0; }; @@ -1061,6 +1202,7 @@ bgpq3_print_eacl(FILE* f, struct bgpq_expander* b) case V_OPENBGPD: return bgpq3_print_openbgpd_prefixlist(f,b); case V_FORMAT: sx_report(SX_FATAL, "unreachable point\n"); case V_NOKIA: return bgpq3_print_nokia_ipprefixlist(f,b); + case V_HUAWEI: return sx_report(SX_FATAL, "unreachable point\n"); }; return 0; }; diff --git a/configure b/configure index 9016baa..8f929f9 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for bgpq3 0.1.35-rc2. +# Generated by GNU Autoconf 2.69 for bgpq3 0.1.35-rc3. # # Report bugs to . # @@ -580,8 +580,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='bgpq3' PACKAGE_TARNAME='bgpq3' -PACKAGE_VERSION='0.1.35-rc2' -PACKAGE_STRING='bgpq3 0.1.35-rc2' +PACKAGE_VERSION='0.1.35-rc3' +PACKAGE_STRING='bgpq3 0.1.35-rc3' PACKAGE_BUGREPORT='snar@snar.spb.ru' PACKAGE_URL='' @@ -1228,7 +1228,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures bgpq3 0.1.35-rc2 to adapt to many kinds of systems. +\`configure' configures bgpq3 0.1.35-rc3 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1289,7 +1289,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of bgpq3 0.1.35-rc2:";; + short | recursive ) echo "Configuration of bgpq3 0.1.35-rc3:";; esac cat <<\_ACEOF @@ -1369,7 +1369,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -bgpq3 configure 0.1.35-rc2 +bgpq3 configure 0.1.35-rc3 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1738,7 +1738,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by bgpq3 $as_me 0.1.35-rc2, which was +It was created by bgpq3 $as_me 0.1.35-rc3, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -4102,7 +4102,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by bgpq3 $as_me 0.1.35-rc2, which was +This file was extended by bgpq3 $as_me 0.1.35-rc3, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -4164,7 +4164,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -bgpq3 config.status 0.1.35-rc2 +bgpq3 config.status 0.1.35-rc3 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.in b/configure.in index 5e7f46b..469eecf 100644 --- a/configure.in +++ b/configure.in @@ -1,4 +1,4 @@ -AC_INIT(bgpq3,0.1.35-rc2,snar@snar.spb.ru) +AC_INIT(bgpq3,0.1.35-rc3,snar@snar.spb.ru) AC_CONFIG_HEADER(config.h) AC_PROG_CC AC_PROG_INSTALL diff --git a/sx_prefix.c b/sx_prefix.c index f98c79b..50804eb 100644 --- a/sx_prefix.c +++ b/sx_prefix.c @@ -280,15 +280,22 @@ sx_prefix_fprint(FILE* f, struct sx_prefix* p) }; int -sx_prefix_snprintf(struct sx_prefix* p, char* rbuffer, int srb) +sx_prefix_snprintf_sep(struct sx_prefix* p, char* rbuffer, int srb, char* sep) { char buffer[128]; + if(!sep) sep="/"; if(!p) { snprintf(rbuffer,srb,"(null)"); return 0; }; inet_ntop(p->family,&p->addr,buffer,sizeof(buffer)); - return snprintf(rbuffer,srb,"%s/%i",buffer,p->masklen); + return snprintf(rbuffer,srb,"%s%s%i",buffer,sep,p->masklen); +}; + +int +sx_prefix_snprintf(struct sx_prefix* p, char* rbuffer, int srb) +{ + return sx_prefix_snprintf_sep(p, rbuffer, srb, "/"); }; int diff --git a/sx_prefix.h b/sx_prefix.h index 51278a4..a893057 100644 --- a/sx_prefix.h +++ b/sx_prefix.h @@ -49,6 +49,7 @@ int sx_prefix_parse(struct sx_prefix* p, int af, char* text); int sx_prefix_range_parse(struct sx_radix_tree* t, int af, int ml, char* text); int sx_prefix_fprint(FILE* f, struct sx_prefix* p); int sx_prefix_snprintf(struct sx_prefix* p, char* rbuffer, int srb); +int sx_prefix_snprintf_sep(struct sx_prefix* p, char* rbuffer, int srb, char*); int sx_prefix_snprintf_fmt(struct sx_prefix* p, char* rbuffer, int srb, const char* name, const char* fmt); int sx_prefix_jsnprintf(struct sx_prefix* p, char* rbuffer, int srb);