diff --git a/CHANGES b/CHANGES index 10a212d..bb418fb 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,8 @@ 0.1.3 (2008-05-20): - aggregation (-A) now supported for Cisco prefix-lists. + - pipelining now can be enabled for RIPE-style queries too (ipv6). + - more-specific routes (-R len) feature ported from bgpq + - pipelining now set by default. -T flag now disables pipelining. 0.1.2 (2008-05-19): - final support for asn32, now with correct syntax for Juniper. diff --git a/bgpq3.c b/bgpq3.c index 6ca980a..8a24196 100644 --- a/bgpq3.c +++ b/bgpq3.c @@ -23,8 +23,8 @@ extern int pipelining; int usage(int ecode) { - printf("\nUsage: bgpq3 [-h] [-S sources] [-P|G |f ] [-36A]" - " ...\n"); + printf("\nUsage: bgpq3 [-h] [-S sources] [-P|G |f ] [-36A]" + " [-R len] ...\n"); printf(" -3 : assume that your device is asn32-safe\n"); printf(" -6 : generate IPv6 prefix-lists (IPv4 by default)\n"); printf(" -A : try to aggregate prefix-lists as much as possible" @@ -37,9 +37,10 @@ usage(int ecode) printf(" -l : use specified name for generated access/prefix/.." " list\n"); printf(" -P : generate prefix-list (default)\n"); - printf(" -T : pipelining (experimental, faster mode)\n"); + printf(" -R len : allow specific routes up to masklen specified\n"); printf(" -S sources: use only specified sources (default:" " RADB,RIPE,APNIC)\n"); + printf(" -T : disable pipelining (experimental, faster mode)\n"); printf("\n" PACKAGE_NAME " version: " PACKAGE_VERSION "\n"); printf("Copyright(c) Alexandre Snarskii 2007, 2008\n\n"); exit(ecode); @@ -93,12 +94,12 @@ main(int argc, char* argv[]) int c; struct bgpq_expander expander; int af=AF_INET; - int widthSet=0, aggregate=0; + int widthSet=0, aggregate=0, refine=0; bgpq_expander_init(&expander,af); expander.sources=getenv("IRRD_SOURCES"); - while((c=getopt(argc,argv,"36AdhS:Jf:l:W:PG:T"))!=EOF) { + while((c=getopt(argc,argv,"36AdhS:Jf:l:W:PR:G:T"))!=EOF) { switch(c) { case '3': expander.asn32=1; @@ -129,6 +130,13 @@ main(int argc, char* argv[]) if(expander.generation) exclusive(); expander.generation=T_PREFIXLIST; break; + case 'R': + refine=strtoul(optarg,NULL,10); + if(!refine) { + sx_report(SX_FATAL,"Invalid refine length: %s\n", optarg); + exit(1); + }; + break; case 'l': expander.name=optarg; break; case 'T': pipelining=1; @@ -180,10 +188,34 @@ main(int argc, char* argv[]) }; if(aggregate && expander.vendor==V_JUNIPER) { - sx_report(SX_FATAL, "Sorry, aggregation (-A) does not work with" - " Juniper\n"); + sx_report(SX_FATAL, "Sorry, aggregation (-A) does not work in" + " Juniper prefix-lists\n"); exit(1); }; + if(aggregate && expander.generation128)) { + sx_report(SX_FATAL, "Invalid value for refinement: %u (1-128 for" + " IPv6)\n", refine); + } else if(expander.family==AF_INET && refine>32) { + sx_report(SX_FATAL, "Invalid value for refinement: %u (1-32 for" + " IPv4)\n", refine); + }; + if(expander.vendor==V_JUNIPER) { + sx_report(SX_FATAL, "Sorry, more-specific filter (-R %u) " + "is not supported for Juniper prefix-lists\n", refine); + }; + if(expander.generationfirstpipe) { + sx_report(SX_FATAL, "No piped requests\n"); + exit(1); + }; + while(fgets(buffer,sizeof(buffer),f)) { + if(buffer[0]=='\n') { + if(b->family==AF_INET && otype && !strcmp(otype,"route")) { + SX_DEBUG(debug_expander,"dequeuer(ripe): got route %s\n", + object); + if(b->firstpipe->callback) + b->firstpipe->callback(object,b->firstpipe->udata); + } else if(b->family==AF_INET6 && otype && !strcmp(otype,"route6")){ + SX_DEBUG(debug_expander,"dequeuer(ripe): got route6 %s\n", + object); + if(b->firstpipe->callback) + b->firstpipe->callback(object,b->firstpipe->udata); + }; + if(otype) free(otype); otype=NULL; + if(object) free(object); object=NULL; + sawNL++; + if(sawNL==2) { + /* end of object */ + struct bgpq_prequest* p=b->firstpipe; + b->firstpipe=b->firstpipe->next; + free(p); + b->piped--; + if(!b->piped) { + return 0; + }; + }; + } else { + sawNL=0; + if(!otype) { + char* c=strchr(buffer,':'); + if(c) { + *c=0; + otype=strdup(buffer); + c++; + while(isspace((int)*c)) c++; + object=strdup(c); + c=strchr(object,'\n'); + if(c) *c=0; + }; + }; + }; + }; + if(feof(f)) { + sx_report(SX_FATAL,"EOF from RADB\n"); + } else { + sx_report(SX_FATAL,"Error from RADB: %s\n", strerror(errno)); + }; + return 0; +}; + int bgpq_expand_ripe(FILE* f, int (*callback)(char*, void*), void* udata, char* fmt, ...) @@ -528,13 +593,23 @@ bgpq_expand(struct bgpq_expander* b) for(j=0;j<8;j++) { if(b->asn32s[k][i]&(0x80>>j)) { if(b->family==AF_INET6) { - if(k>0) - bgpq_expand_ripe(f,bgpq_expanded_v6prefix,b, - "-T route6 -i origin as%u.%u\r\n", k,i*8+j); - else - bgpq_expand_ripe(f,bgpq_expanded_v6prefix,b, - "-T route6 -i origin as%u\r\n", i*8+j); - + if(!pipelining) { + if(k>0) + bgpq_expand_ripe(f,bgpq_expanded_v6prefix,b, + "-T route6 -i origin as%u.%u\r\n", k, + i*8+j); + else + bgpq_expand_ripe(f,bgpq_expanded_v6prefix,b, + "-T route6 -i origin as%u\r\n", i*8+j); + } else { + if(k>0) + bgpq_pipeline(f,bgpq_expanded_v6prefix,b, + "-T route6 -i origin as%u.%u\r\n", k, + i*8+j); + else + bgpq_pipeline(f,bgpq_expanded_v6prefix,b, + "-T route6 -i origin as%u\r\n", i*8+j); + }; } else { if(!pipelining) { if(k>0) @@ -557,7 +632,11 @@ bgpq_expand(struct bgpq_expander* b) }; }; if(pipelining) { - bgpq_pipeline_dequeue(f,b); + if(b->family==AF_INET6) { + bgpq_pipeline_dequeue_ripe(f,b); + } else { + bgpq_pipeline_dequeue(f,b); + }; }; }; diff --git a/configure b/configure index 9855999..49f8ffb 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.59 for bgpq3 0.1.2. +# Generated by GNU Autoconf 2.59 for bgpq3 0.1.3. # # Report bugs to . # @@ -269,8 +269,8 @@ SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='bgpq3' PACKAGE_TARNAME='bgpq3' -PACKAGE_VERSION='0.1.2' -PACKAGE_STRING='bgpq3 0.1.2' +PACKAGE_VERSION='0.1.3' +PACKAGE_STRING='bgpq3 0.1.3' PACKAGE_BUGREPORT='snar@paranoia.ru' ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT LIBOBJS LTLIBOBJS' @@ -738,7 +738,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.2 to adapt to many kinds of systems. +\`configure' configures bgpq3 0.1.3 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -795,7 +795,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of bgpq3 0.1.2:";; + short | recursive ) echo "Configuration of bgpq3 0.1.3:";; esac cat <<\_ACEOF @@ -906,7 +906,7 @@ fi test -n "$ac_init_help" && exit 0 if $ac_init_version; then cat <<\_ACEOF -bgpq3 configure 0.1.2 +bgpq3 configure 0.1.3 generated by GNU Autoconf 2.59 Copyright (C) 2003 Free Software Foundation, Inc. @@ -920,7 +920,7 @@ cat >&5 <<_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.2, which was +It was created by bgpq3 $as_me 0.1.3, which was generated by GNU Autoconf 2.59. Invocation command line was $ $0 $@ @@ -2702,7 +2702,7 @@ _ASBOX } >&5 cat >&5 <<_CSEOF -This file was extended by bgpq3 $as_me 0.1.2, which was +This file was extended by bgpq3 $as_me 0.1.3, which was generated by GNU Autoconf 2.59. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -2762,7 +2762,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ -bgpq3 config.status 0.1.2 +bgpq3 config.status 0.1.3 configured by $0, generated by GNU Autoconf 2.59, with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" diff --git a/configure.in b/configure.in index 98da668..11244ae 100644 --- a/configure.in +++ b/configure.in @@ -1,4 +1,4 @@ -AC_INIT(bgpq3,0.1.2,snar@paranoia.ru) +AC_INIT(bgpq3,0.1.3,snar@paranoia.ru) AC_CONFIG_HEADER(config.h) AC_PROG_CC diff --git a/sx_prefix.c b/sx_prefix.c index 6a7c7d1..c9797cc 100644 --- a/sx_prefix.c +++ b/sx_prefix.c @@ -621,7 +621,47 @@ sx_radix_tree_aggregate(struct sx_radix_tree* tree) if(tree && tree->head) return sx_radix_node_aggregate(tree->head); return 0; }; + +static void +setGlue(struct sx_radix_node* node, void* udata) +{ + if(node) node->isGlue=1; +}; + +int +sx_radix_node_refine(struct sx_radix_node* node, unsigned refine) +{ + if(!node->isGlue && node->prefix.masklenisAggregate=1; + node->aggregateLow=node->prefix.masklen; + node->aggregateHi=refine; + if(node->l) sx_radix_node_foreach(node->l, setGlue, NULL); + if(node->r) sx_radix_node_foreach(node->r, setGlue, NULL); + } else if(!node->isGlue && node->prefix.masklen==refine) { + /* not setting aggregate in this case */ + if(node->l) sx_radix_node_foreach(node->l, setGlue, NULL); + if(node->r) sx_radix_node_foreach(node->r, setGlue, NULL); + } else if(node->isGlue) { + if(node->r) sx_radix_node_refine(node->r, refine); + if(node->l) sx_radix_node_refine(node->l, refine); + } else { + /* node->prefix.masklen > refine */ + /* do nothing, should pass specifics 'as is'. Also, do not + process any embedded routes, their masklen is bigger, too... + node->isGlue=1; + if(node->l) sx_radix_node_foreach(node->l, setGlue, NULL); + if(node->r) sx_radix_node_foreach(node->r, setGlue, NULL); + */ + }; + return 0; +}; +int +sx_radix_tree_refine(struct sx_radix_tree* tree, unsigned refine) +{ + if(tree && tree->head) return sx_radix_node_refine(tree->head, refine); + return 0; +}; diff --git a/sx_prefix.h b/sx_prefix.h index 82f7ed2..a17ce49 100644 --- a/sx_prefix.h +++ b/sx_prefix.h @@ -57,6 +57,7 @@ int sx_radix_node_foreach(struct sx_radix_node* node, int sx_radix_tree_foreach(struct sx_radix_tree* tree, void (*func)(struct sx_radix_node*, void*), void* udata); int sx_radix_tree_aggregate(struct sx_radix_tree* tree); +int sx_radix_tree_refine(struct sx_radix_tree* tree, unsigned refine); #endif