diff --git a/CHANGES b/CHANGES index 8dc5dc0..10a212d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,5 @@ +0.1.3 (2008-05-20): + - aggregation (-A) now supported for Cisco prefix-lists. 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 d4ac8fe..6ca980a 100644 --- a/bgpq3.c +++ b/bgpq3.c @@ -17,15 +17,18 @@ #include "sx_report.h" extern int debug_expander; +extern int debug_aggregation; extern int pipelining; int usage(int ecode) { - printf("\nUsage: bgpq3 [-h] [-S sources] [-P|G |f ] [-36]" + printf("\nUsage: bgpq3 [-h] [-S sources] [-P|G |f ] [-36A]" " ...\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" + " (Cisco only)\n"); printf(" -d : generate some debugging output\n"); printf(" -f number : generate input as-path access-list\n"); printf(" -G number : generate output as-path access-list\n"); @@ -90,12 +93,12 @@ main(int argc, char* argv[]) int c; struct bgpq_expander expander; int af=AF_INET; - int widthSet=0; + int widthSet=0, aggregate=0; bgpq_expander_init(&expander,af); expander.sources=getenv("IRRD_SOURCES"); - while((c=getopt(argc,argv,"36dhS:Jf:l:W:PG:T"))!=EOF) { + while((c=getopt(argc,argv,"36AdhS:Jf:l:W:PG:T"))!=EOF) { switch(c) { case '3': expander.asn32=1; @@ -104,6 +107,10 @@ main(int argc, char* argv[]) expander.family=AF_INET6; expander.tree->family=AF_INET6; break; + case 'A': + if(aggregate) debug_aggregation++; + aggregate=1; + break; case 'd': debug_expander++; break; case 'J': expander.vendor=V_JUNIPER; @@ -172,6 +179,12 @@ main(int argc, char* argv[]) expander.asnumber=23456; }; + if(aggregate && expander.vendor==V_JUNIPER) { + sx_report(SX_FATAL, "Sorry, aggregation (-A) does not work with" + " Juniper\n"); + exit(1); + }; + if(!argv[0]) usage(1); while(argv[0]) { @@ -195,6 +208,9 @@ main(int argc, char* argv[]) exit(1); }; + if(aggregate) + sx_radix_tree_aggregate(expander.tree); + switch(expander.generation) { case T_NONE: sx_report(SX_FATAL,"Unreachable point... call snar\n"); exit(1); diff --git a/bgpq3_printer.c b/bgpq3_printer.c index 90fd674..3694c0b 100644 --- a/bgpq3_printer.c +++ b/bgpq3_printer.c @@ -202,11 +202,26 @@ bgpq3_print_cprefix(struct sx_radix_node* n, void* ff) { char prefix[128]; FILE* f=(FILE*)ff; - if(n->isGlue) return; if(!f) f=stdout; + if(n->isGlue) goto checkSon; sx_prefix_snprintf(&n->prefix,prefix,sizeof(prefix)); - fprintf(f,"%s prefix-list %s permit %s\n", - (n->prefix.family==AF_INET)?"ip":"ipv6",bname?bname:"NN",prefix); + if(n->isAggregate) { + if(n->aggregateLow>n->prefix.masklen) { + fprintf(f,"%s prefix-list %s permit %s ge %u le %u\n", + n->prefix.family==AF_INET?"ip":"ipv6",bname?bname:"NN",prefix, + n->aggregateLow,n->aggregateHi); + } else { + fprintf(f,"%s prefix-list %s permit %s le %u\n", + n->prefix.family==AF_INET?"ip":"ipv6",bname?bname:"NN",prefix, + n->aggregateHi); + }; + } else { + fprintf(f,"%s prefix-list %s permit %s\n", + (n->prefix.family==AF_INET)?"ip":"ipv6",bname?bname:"NN",prefix); + }; +checkSon: + if(n->son) + bgpq3_print_cprefix(n->son,ff); }; int diff --git a/bgpq_expander.c b/bgpq_expander.c index 7eafc45..38fd3b7 100644 --- a/bgpq_expander.c +++ b/bgpq_expander.c @@ -506,6 +506,7 @@ bgpq_expand(struct bgpq_expander* b) snprintf(sources,sizeof(sources),"!s%s\n", b->sources); fseek(f,0,SEEK_END); fwrite(sources,strlen(sources),1,f); + fgets(sources,sizeof(sources),f); }; if(b->identify) { @@ -513,6 +514,7 @@ bgpq_expand(struct bgpq_expander* b) snprintf(ident,sizeof(ident),"!n" PACKAGE_STRING "\n"); fseek(f,0,SEEK_END); fwrite(ident,strlen(ident),1,f); + fgets(ident,sizeof(ident),f); }; for(mc=b->macroses;mc;mc=mc->next) { diff --git a/sx_prefix.c b/sx_prefix.c index 36e3c70..6a7c7d1 100644 --- a/sx_prefix.c +++ b/sx_prefix.c @@ -11,6 +11,8 @@ #include "sx_prefix.h" #include "sx_report.h" +int debug_aggregation=0; + struct sx_prefix* sx_prefix_alloc(struct sx_prefix* p) { @@ -451,6 +453,174 @@ sx_radix_tree_foreach(struct sx_radix_tree* tree, sx_radix_node_foreach(tree->head,func,udata); return 0; }; + +int +sx_radix_node_aggregate(struct sx_radix_node* node) +{ + if(node->l) + sx_radix_node_aggregate(node->l); + if(node->r) + sx_radix_node_aggregate(node->r); + + if(debug_aggregation) { + printf("Aggregating on node: "); + sx_prefix_fprint(stdout,&node->prefix); + printf(" %s%s%u,%u\n", node->isGlue?"Glue ":"", + node->isAggregate?"Aggregate ":"",node->aggregateLow, + node->aggregateHi); + if(node->r) { + printf("R-Tree: "); + sx_prefix_fprint(stdout,&node->r->prefix); + printf(" %s%s%u,%u\n", (node->r->isGlue)?"Glue ":"", + (node->r->isAggregate)?"Aggregate ":"", + node->r->aggregateLow,node->r->aggregateHi); + if(node->r->son) { + printf("R-Son: "); + sx_prefix_fprint(stdout,&node->r->son->prefix); + printf(" %s%s%u,%u\n",node->r->son->isGlue?"Glue ":"", + node->r->son->isAggregate?"Aggregate ":"", + node->r->son->aggregateLow,node->r->son->aggregateHi); + }; + }; + if(node->l) { + printf("L-Tree: "); + sx_prefix_fprint(stdout,&node->l->prefix); + printf(" %s%s%u,%u\n",node->l->isGlue?"Glue ":"", + node->l->isAggregate?"Aggregate ":"", + node->l->aggregateLow,node->l->aggregateHi); + if(node->l->son) { + printf("L-Son: "); + sx_prefix_fprint(stdout,&node->l->son->prefix); + printf(" %s%s%u,%u\n",node->l->son->isGlue?"Glue ":"", + node->l->son->isAggregate?"Aggregate ":"", + node->l->son->aggregateLow,node->l->son->aggregateHi); + }; + }; + }; + + if(node->r && node->l) { + if(!node->r->isAggregate && !node->l->isAggregate && + !node->r->isGlue && !node->l->isGlue && + node->r->prefix.masklen==node->l->prefix.masklen) { + if(node->r->prefix.masklen==node->prefix.masklen+1) { + node->isAggregate=1; + node->r->isGlue=1; + node->l->isGlue=1; + node->aggregateHi=node->r->prefix.masklen; + if(node->isGlue) { + node->isGlue=0; + node->aggregateLow=node->r->prefix.masklen; + } else { + node->aggregateLow=node->prefix.masklen; + }; + }; + if(node->r->son && node->l->son && + node->r->son->isAggregate && node->l->son->isAggregate && + node->r->son->aggregateHi==node->l->son->aggregateHi && + node->r->son->aggregateLow==node->l->son->aggregateLow) + { + node->son=sx_radix_node_new(&node->prefix); + node->son->isGlue=0; + node->son->isAggregate=1; + node->son->aggregateHi=node->r->son->aggregateHi; + node->son->aggregateLow=node->r->son->aggregateLow; + node->r->son->isGlue=1; + node->l->son->isGlue=1; + }; + } else if(node->r->isAggregate && node->l->isAggregate && + node->r->aggregateHi==node->l->aggregateHi && + node->r->aggregateLow==node->l->aggregateLow) { + if(node->r->prefix.masklen==node->prefix.masklen+1) { + if(node->isGlue) { + node->r->isGlue=1; + node->l->isGlue=1; + node->isAggregate=1; + node->isGlue=0; + node->aggregateHi=node->r->aggregateHi; + node->aggregateLow=node->r->aggregateLow; + } else if(node->r->prefix.masklen==node->r->aggregateLow) { + node->r->isGlue=1; + node->l->isGlue=1; + node->isAggregate=1; + node->aggregateHi=node->r->aggregateHi; + node->aggregateLow=node->prefix.masklen; + } else { + node->son=sx_radix_node_new(&node->prefix); + node->son->isGlue=0; + node->son->isAggregate=1; + node->son->aggregateHi=node->r->aggregateHi; + node->son->aggregateLow=node->r->aggregateLow; + node->r->isGlue=1; + node->l->isGlue=1; + if(node->r->son && node->l->son && + node->r->son->aggregateHi==node->l->son->aggregateHi && + node->r->son->aggregateLow==node->l->son->aggregateLow) + { + node->son->son=sx_radix_node_new(&node->prefix); + node->son->son->isGlue=0; + node->son->son->isAggregate=1; + node->son->son->aggregateHi=node->r->son->aggregateHi; + node->son->son->aggregateLow=node->r->son->aggregateLow; + node->r->son->isGlue=1; + node->l->son->isGlue=1; + }; + }; + }; + } else if(node->l->son && + node->r->isAggregate && node->l->son->isAggregate && + node->r->aggregateHi==node->l->son->aggregateHi && + node->r->aggregateLow==node->l->son->aggregateLow) { + if(node->r->prefix.masklen==node->prefix.masklen+1) { + if(node->isGlue) { + node->r->isGlue=1; + node->l->son->isGlue=1; + node->isAggregate=1; + node->isGlue=0; + node->aggregateHi=node->r->aggregateHi; + node->aggregateLow=node->r->aggregateLow; + } else { + node->son=sx_radix_node_new(&node->prefix); + node->son->isGlue=0; + node->son->isAggregate=1; + node->son->aggregateHi=node->r->aggregateHi; + node->son->aggregateLow=node->r->aggregateLow; + node->r->isGlue=1; + node->l->son->isGlue=1; + }; + }; + } else if(node->r->son && + node->l->isAggregate && node->r->son->isAggregate && + node->l->aggregateHi==node->r->son->aggregateHi && + node->l->aggregateLow==node->r->son->aggregateLow) { + if(node->l->prefix.masklen==node->prefix.masklen+1) { + if(node->isGlue) { + node->l->isGlue=1; + node->r->son->isGlue=1; + node->isAggregate=1; + node->isGlue=0; + node->aggregateHi=node->l->aggregateHi; + node->aggregateLow=node->l->aggregateLow; + } else { + node->son=sx_radix_node_new(&node->prefix); + node->son->isGlue=0; + node->son->isAggregate=1; + node->son->aggregateHi=node->l->aggregateHi; + node->son->aggregateLow=node->l->aggregateLow; + node->l->isGlue=1; + node->r->son->isGlue=1; + }; + }; + }; + }; + return 0; +}; + +int +sx_radix_tree_aggregate(struct sx_radix_tree* tree) +{ + if(tree && tree->head) return sx_radix_node_aggregate(tree->head); + return 0; +}; diff --git a/sx_prefix.h b/sx_prefix.h index 206a110..82f7ed2 100644 --- a/sx_prefix.h +++ b/sx_prefix.h @@ -17,9 +17,13 @@ typedef struct sx_prefix { } sx_prefix_t; typedef struct sx_radix_node { - struct sx_radix_node* parent, *l, *r; + struct sx_radix_node* parent, *l, *r, *son; void* payload; - int isGlue; + unsigned int isGlue:1; + unsigned int isAggregated:1; + unsigned int isAggregate:1; + unsigned int aggregateLow; + unsigned int aggregateHi; struct sx_prefix prefix; } sx_radix_node_t; @@ -52,5 +56,7 @@ int sx_radix_node_foreach(struct sx_radix_node* node, void (*func)(struct sx_radix_node*, void*), void* udata); 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); + #endif