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.
Cisco documentation
for information on Cisco implementation of ASN32.
+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);