From e640ac297d798a013847f089dc581ecd979731f0 Mon Sep 17 00:00:00 2001 From: snar Date: Tue, 8 Jan 2013 12:21:14 +0000 Subject: [PATCH] 0.1.18, JSON format. --- CHANGES | 3 +++ COPYRIGHT | 2 +- bgpq3.8 | 16 +++++++++------- bgpq3.c | 19 ++++++++++++++----- bgpq3.h | 3 ++- bgpq3.html | 31 +++++++++++++++++++++++++------ bgpq3.txt | 31 +++++++++++++++++++++++++------ bgpq3_printer.c | 44 +++++++++++++++++++++++++++++++++++++++++++- configure | 18 +++++++++--------- configure.in | 2 +- sx_prefix.c | 12 ++++++++++++ sx_prefix.h | 1 + 12 files changed, 145 insertions(+), 37 deletions(-) diff --git a/CHANGES b/CHANGES index 5a33ec8..075485a 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +0.1.18 (2013-01-08) + - JSON output format. Thanks to Job Snijders (Atrato Networks). + 0.1.17 (2012-10-25) - route-sets handling in command-line added. Thanks to Alexandr Turovsky for pointing out. diff --git a/COPYRIGHT b/COPYRIGHT index 9789901..ca85ca0 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2007-2012 Alexandre Snarskii + * Copyright (c) 2007-2013 Alexandre Snarskii * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/bgpq3.8 b/bgpq3.8 index 6555b96..f4c4902 100644 --- a/bgpq3.8 +++ b/bgpq3.8 @@ -21,7 +21,7 @@ .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. -.\" "$Id: bgpq3.8,v 1.8 2012/08/29 10:58:20 snar Exp $ +.\" "$Id: bgpq3.8,v 1.9 2013/01/08 12:21:14 snar Exp $ .\" .Dd Oct 27, 2008 .Dt BGPQ3 8 @@ -38,7 +38,7 @@ .Fl f Ar asn | .Fl G Ar asn .Oc -.Op Fl 36ADd +.Op Fl 36ADdJjX .Op Fl R Ar len .Op Fl m Ar max .Ar OBJECTS @@ -56,8 +56,8 @@ assume that your device is asn32-safe. .It Fl 6 generate IPv6 prefix/access-lists (IPv4 by default). .It Fl A -try to aggregate prefix-lists as much as possible (Cisco prefix-lists and -Juniper route-filters only supported). +try to aggregate prefix-lists as much as possible (not all output +formats supported). .It Fl d enable some debugging output. .It Fl D @@ -70,12 +70,14 @@ generate input as-path access-list. .It Fl G Ar number generate output as-path access-list. .It Fl h Ar host -host running IRRD database (default: whois.radb.net) +host running IRRD database (default: whois.radb.net). .It Fl J -generate config for Juniper (Cisco by default). +generate config for Juniper (default: Cisco). +.It Fl j +generate output in JSON format (default: Cisco). .It Fl m Ar len maximum prefix-length of accepted prefixes (default: 32 for IPv4 and -128 for IPv6) +128 for IPv6). .It Fl M Ar match extra match conditions for Juniper route-filters. .It Fl l Ar name diff --git a/bgpq3.c b/bgpq3.c index eab7f31..39667e9 100644 --- a/bgpq3.c +++ b/bgpq3.c @@ -24,7 +24,7 @@ int usage(int ecode) { printf("\nUsage: bgpq3 [-h host] [-S sources] [-P|E|G |f ]" - " [-36ADJXd] [-R len] ...\n"); + " [-36ADJjXd] [-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 Cisco prefix-lists or Juniper " @@ -38,6 +38,7 @@ usage(int ecode) printf(" -h host : host running IRRD software (whois.radb.net by " "default)\n"); printf(" -J : generate config for JunOS (Cisco IOS by default)\n"); + printf(" -j : generate JSON output (Cisco IOS by default)\n"); printf(" -M match : extra match conditions for JunOS route-filters\n"); printf(" -m len : maximum prefix length (default: 32 for IPv4, " "128 for IPv6)\n"); @@ -66,8 +67,8 @@ exclusive() void vendor_exclusive() { - fprintf(stderr, "-J (JunOS) and -X (IOS XR) options are mutually " - "exclusive\n"); + fprintf(stderr, "-J (JunOS), -j (JSON) and -X (IOS XR) options are mutually" + " exclusive\n"); exit(1); }; @@ -118,7 +119,7 @@ main(int argc, char* argv[]) bgpq_expander_init(&expander,af); expander.sources=getenv("IRRD_SOURCES"); - while((c=getopt(argc,argv,"36AdDES:Jf:l:m:M:W:PR:G:Th:X"))!=EOF) { + while((c=getopt(argc,argv,"36AdDES:jJf:l:m:M:W:PR:G:Th:X"))!=EOF) { switch(c) { case '3': expander.asn32=1; @@ -143,6 +144,9 @@ main(int argc, char* argv[]) case 'J': if(expander.vendor) vendor_exclusive(); expander.vendor=V_JUNIPER; break; + case 'j': if(expander.vendor) vendor_exclusive(); + expander.vendor=V_JSON; + break; case 'f': if(expander.generation) exclusive(); expander.generation=T_ASPATH; @@ -251,6 +255,10 @@ main(int argc, char* argv[]) if(expander.vendor==V_CISCO_XR && expander.generation!=T_PREFIXLIST) { sx_report(SX_FATAL, "Sorry, only prefix-sets supported for IOS XR\n"); }; + if(expander.vendor==V_JSON && expander.generation!=T_PREFIXLIST) { + sx_report(SX_FATAL, "Sorry, only prefix-lists supported for JSON " + "output\n"); + }; if(expander.asdot && expander.vendor!=V_CISCO) { sx_report(SX_FATAL,"asdot notation supported only for Cisco, Juniper" @@ -268,6 +276,7 @@ main(int argc, char* argv[]) " of prefix-lists (-P, default)\n"); exit(1); }; + if(aggregate && expander.generation128) || (expander.family==AF_INET && maxlen>32)) { @@ -311,7 +321,6 @@ main(int argc, char* argv[]) " yet.\n"); }; - if(!argv[0]) usage(1); while(argv[0]) { diff --git a/bgpq3.h b/bgpq3.h index 12304cb..2967e55 100644 --- a/bgpq3.h +++ b/bgpq3.h @@ -7,7 +7,8 @@ typedef enum { V_CISCO = 0, V_JUNIPER, - V_CISCO_XR + V_CISCO_XR, + V_JSON } bgpq_vendor_t; typedef enum { diff --git a/bgpq3.html b/bgpq3.html index fab83f7..9742c29 100644 --- a/bgpq3.html +++ b/bgpq3.html @@ -17,7 +17,7 @@ ul { list-style: none; }

SYNOPSIS

-
bgpq3 [-h host] [-S sources] [-EP] [-f asn | -G asn] [-36ADd] [-R len] [-m max] OBJECTS [...]
+
bgpq3 [-h host] [-S sources] [-EP] [-f asn | -G asn] [-36ADdJjX] [-R len] [-m max] OBJECTS [...]
 

DESCRIPTION

@@ -42,8 +42,8 @@ RADB data.

  • -A

    -

    try to aggregate generated filters as much as possible (Cisco - prefix-lists and Juniper route-filters only supported).

    +

    try to aggregate generated filters as much as possible (not all + output formats supported).

  • -d

    @@ -74,17 +74,22 @@ RADB data.

  • -h host

    -

    host running IRRD database (default: whois.radb.net)

    +

    host running IRRD database (default: whois.radb.net).

  • -J

    -

    generate config for Juniper (Cisco by default).

    +

    generate config for Juniper (default: Cisco).

    +
  • +
  • -j

    + +
    +

    generate output in JSON format (default: Cisco).

  • -m len

    -

    maximum length of accepted prefixes

    +

    maximum length of accepted prefixes (default: 32 for IPv4, 128 for IPv6).

  • -M match

    @@ -254,6 +259,19 @@ have been added to list if it were not present.

    exits with status == 0. In case of errors they are printed to stderr and program exits with non-zero status.

    +

    NOTES ON ULTRA-LARGE PREFIX-LISTS

    + +

    When using bgpq3 to expand extra-large AS-SETs, bgpq3 may stuck +due to lacking tcp buffer size. To avoid this, tune your OS. +FreeBSD can be tuned in the following way:

    + +
    sysctl -w net.inet.tcp.sendbuf_max=16777216
    +
    + +

    Please note that generated prefix-lists may not fit your router's +limitations. For example, JunOS supports only 85,325 prefixes in +each prefix-list 4.

    +

    SEE ALSO

      @@ -262,6 +280,7 @@ program exits with non-zero status.

      for information on 'asdot' and 'asplain' notations.
    1. Cisco documentation for information on Cisco implementation of ASN32.
    2. +
    3. JunOS prefix-lists limitation

    AUTHOR

    diff --git a/bgpq3.txt b/bgpq3.txt index 653b097..e5bbbcc 100644 --- a/bgpq3.txt +++ b/bgpq3.txt @@ -19,7 +19,7 @@ NAME SYNOPSIS -------- - bgpq3 [-h host] [-S sources] [-EP] [-f asn | -G asn] [-36ADd] [-R len] [-m max] OBJECTS [...] + bgpq3 [-h host] [-S sources] [-EP] [-f asn | -G asn] [-36ADdJjX] [-R len] [-m max] OBJECTS [...] DESCRIPTION ----------- @@ -40,8 +40,8 @@ The options are as follows: - -A - > try to aggregate generated filters as much as possible (Cisco - prefix-lists and Juniper route-filters only supported). + > try to aggregate generated filters as much as possible (not all + output formats supported). - -d @@ -66,15 +66,19 @@ The options are as follows: - -h host - > host running IRRD database (default: whois.radb.net) + > host running IRRD database (default: whois.radb.net). - -J - > generate config for Juniper (Cisco by default). + > generate config for Juniper (default: Cisco). + +- -j + + > generate output in JSON format (default: Cisco). - -m len - > maximum length of accepted prefixes + > maximum length of accepted prefixes (default: 32 for IPv4, 128 for IPv6). - -M match @@ -230,6 +234,20 @@ When everything is OK, `bgpq3` generates result to standard output and exits with status == 0. In case of errors they are printed to stderr and program exits with non-zero status. +NOTES ON ULTRA-LARGE PREFIX-LISTS +--------------------------------- + +When using `bgpq3` to expand extra-large AS-SETs, `bgpq3` may stuck +due to lacking tcp buffer size. To avoid this, tune your OS. +FreeBSD can be tuned in the following way: + + sysctl -w net.inet.tcp.sendbuf_max=16777216 + +Please note that generated prefix-lists may not fit your router's +limitations. For example, JunOS supports only 85,325 prefixes in +each prefix-list [4](http://www.juniper.net/techpubs/en_US/junos11.4/topics/reference/configuration-statement/prefix-list-edit-policy-options.html). + + SEE ALSO -------- @@ -238,6 +256,7 @@ SEE ALSO for information on 'asdot' and 'asplain' notations. 3. [Cisco documentation](http://www.cisco.com/en/US/prod/collateral/iosswrel/ps6537/ps6554/ps6599/data_sheet_C78-521821.html) for information on Cisco implementation of ASN32. +4. [JunOS prefix-lists limitation](http://www.juniper.net/techpubs/en_US/junos11.4/topics/reference/configuration-statement/prefix-list-edit-policy-options.html) AUTHOR ------ diff --git a/bgpq3_printer.c b/bgpq3_printer.c index 757ed13..d509d9b 100644 --- a/bgpq3_printer.c +++ b/bgpq3_printer.c @@ -239,6 +239,37 @@ bgpq3_print_jprefix(struct sx_radix_node* n, void* ff) fprintf(f," %s;\n",prefix); }; +static int needscomma=0; + +void +bgpq3_print_json_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_jsnprintf(&n->prefix, prefix, sizeof(prefix)); + if (!n->isAggregate) { + fprintf(f, "%s\n { \"prefix\": \"%s\", \"exact\": true }", + needscomma?",":"", prefix); + } else if (n->aggregateLow > n->prefix.masklen) { + fprintf(f, "%s\n { \"prefix\": \"%s\", \"exact\": false,\n " + "\"greater-equal\": %u, \"less-equal\": %u }", + needscomma?",":"", prefix, + n->aggregateLow, n->aggregateHi); + } else { + fprintf(f, "%s\n { \"prefix\": \"%s\", \"exact\": false, " + "\"less-equal\": %u }", + needscomma?",":"", prefix, n->aggregateHi); + }; + needscomma=1; +checkSon: + if(n->son) + bgpq3_print_json_prefix(n->son, ff); +}; + void bgpq3_print_jrfilter(struct sx_radix_node* n, void* ff) { @@ -264,7 +295,6 @@ checkSon: static char* bname=NULL; -static int needscomma=0; void bgpq3_print_cprefix(struct sx_radix_node* n, void* ff) @@ -439,6 +469,16 @@ bgpq3_print_ciscoxr_prefixlist(FILE* f, struct bgpq_expander* b) return 0; }; +int +bgpq3_print_json_prefixlist(FILE* f, struct bgpq_expander* b) +{ + fprintf(f,"{ \"%s\": [", + b->name?b->name:"NN"); + sx_radix_tree_foreach(b->tree,bgpq3_print_json_prefix,f); + fprintf(f,"\n] }\n"); + return 0; +}; + int bgpq3_print_cisco_eacl(FILE* f, struct bgpq_expander* b) { @@ -456,6 +496,7 @@ bgpq3_print_prefixlist(FILE* f, struct bgpq_expander* b) case V_JUNIPER: return bgpq3_print_juniper_prefixlist(f,b); case V_CISCO: return bgpq3_print_cisco_prefixlist(f,b); case V_CISCO_XR: return bgpq3_print_ciscoxr_prefixlist(f,b); + case V_JSON: return bgpq3_print_json_prefixlist(f,b); }; return 0; }; @@ -467,6 +508,7 @@ bgpq3_print_eacl(FILE* f, struct bgpq_expander* b) case V_JUNIPER: return bgpq3_print_juniper_routefilter(f,b); case V_CISCO: return bgpq3_print_cisco_eacl(f,b); case V_CISCO_XR: sx_report(SX_FATAL, "unreachable point\n"); + case V_JSON: sx_report(SX_FATAL, "unreachable point\n"); }; return 0; }; diff --git a/configure b/configure index 8f29f6d..f857c97 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.17. +# Generated by GNU Autoconf 2.69 for bgpq3 0.1.18. # # Report bugs to . # @@ -579,8 +579,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='bgpq3' PACKAGE_TARNAME='bgpq3' -PACKAGE_VERSION='0.1.17' -PACKAGE_STRING='bgpq3 0.1.17' +PACKAGE_VERSION='0.1.18' +PACKAGE_STRING='bgpq3 0.1.18' PACKAGE_BUGREPORT='snar@snar.spb.ru' PACKAGE_URL='' @@ -1186,7 +1186,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.17 to adapt to many kinds of systems. +\`configure' configures bgpq3 0.1.18 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1247,7 +1247,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of bgpq3 0.1.17:";; + short | recursive ) echo "Configuration of bgpq3 0.1.18:";; esac cat <<\_ACEOF @@ -1326,7 +1326,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -bgpq3 configure 0.1.17 +bgpq3 configure 0.1.18 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1494,7 +1494,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.17, which was +It was created by bgpq3 $as_me 0.1.18, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3368,7 +3368,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.17, which was +This file was extended by bgpq3 $as_me 0.1.18, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -3430,7 +3430,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.17 +bgpq3 config.status 0.1.18 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.in b/configure.in index 06245b9..12d9553 100644 --- a/configure.in +++ b/configure.in @@ -1,4 +1,4 @@ -AC_INIT(bgpq3,0.1.17,snar@snar.spb.ru) +AC_INIT(bgpq3,0.1.18,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 56f8bfd..d5f19fa 100644 --- a/sx_prefix.c +++ b/sx_prefix.c @@ -151,6 +151,18 @@ sx_prefix_snprintf(struct sx_prefix* p, char* rbuffer, int srb) return snprintf(rbuffer,srb,"%s/%i",buffer,p->masklen); }; +int +sx_prefix_jsnprintf(struct sx_prefix* p, char* rbuffer, int srb) +{ + char buffer[128]; + 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); +}; + struct sx_radix_tree* sx_radix_tree_new(int af) { diff --git a/sx_prefix.h b/sx_prefix.h index a17ce49..cc306fd 100644 --- a/sx_prefix.h +++ b/sx_prefix.h @@ -48,6 +48,7 @@ struct sx_prefix* sx_prefix_new(int af, char* text); int sx_prefix_parse(struct sx_prefix* p, int af, 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_jsnprintf(struct sx_prefix* p, char* rbuffer, int srb); struct sx_radix_tree* sx_radix_tree_new(int af); struct sx_radix_node* sx_radix_node_new(struct sx_prefix* prefix); struct sx_prefix* sx_prefix_overlay(struct sx_prefix* p, int n);