1
0
mirror of https://github.com/bgp/bgpq4.git synced 2024-05-11 05:55:05 +00:00

feature: user-formatted output, -F <fmt>.

This commit is contained in:
Alexandre Snarskii
2015-07-01 20:03:41 +03:00
parent 2cf7024eac
commit c4d924ae6e
7 changed files with 137 additions and 6 deletions

View File

@ -1,6 +1,8 @@
0.1.32-rc3 (2015-07-01)
- feature: option -s can be used to generate sequence numbers in IOS
prefix-lists
- feature: option -F <fmt> can be used to generate output in user-defined
format. Only prefix-lists supported for now.
0.1.32-rc2 (2015-07-01)
- bugfix: when no sources provided in command line and via IRRD_SOURCES env,

View File

@ -7,7 +7,7 @@ SYNOPSIS
--------
```
bgpq3 [-h host] [-S sources] [-EP] [-f asn | -G asn] [-2346AbDdJjpsX] [-r len] [-R len] [-m max] [-W len] OBJECTS [...]
bgpq3 [-h host] [-S sources] [-EP] [-f asn | -G asn] [-2346AbDdJjpsX] [-F fmt] [-r len] [-R len] [-m max] [-W len] OBJECTS [...]
```
DESCRIPTION
@ -57,6 +57,10 @@ route-filters (Juniper).
Generate input as-path access-list for adjacent as `AS number`.
#### -F `fmt`
Generate output in user-defined format.
#### -G `number`
Generate output as-path access-list.
@ -244,6 +248,28 @@ and the result will be next:
`AS196611` is no more in the list, however, `AS23456` (transition AS) would
have been added to list if it were not present.
USER-DEFINED FORMAT
-------------------
If you want to generate configuration not for routers, but for some
other programs/systems, you may use user-defined formatting, like in
example below:
user@host:~>bgpq3 -F "ipfw add pass all from %n/%l to any\\n" as3254
ipfw add pass all from 62.244.0.0/18 to any
ipfw add pass all from 91.219.29.0/24 to any
ipfw add pass all from 91.219.30.0/24 to any
ipfw add pass all from 193.193.192.0/19 to any
Recognized format characters: '%n' - network, '%l' - mask length.
Recognized escape characters: '\n' - new line, '\t' - tabulation.
Please note that no new lines inserted automatically after each sentence,
you have to add them into format string manually, elsewhere output will
be in one line (sometimes it makes sense):
user@host:~>bgpq3 -6F "%n/%l; " as-eltel
2001:1b00::/32; 2620:4f:8000::/48; 2a04:bac0::/29; 2a05:3a80::/48;
DIAGNOSTICS
-----------

25
bgpq3.c
View File

@ -40,6 +40,7 @@ usage(int ecode)
printf(" -E : generate extended access-list(Cisco) or "
"route-filter(Juniper)\n");
printf(" -f number : generate input as-path access-list\n");
printf(" -F fmt : generate output in user-defined format\n");
printf(" -G number : generate output as-path access-list\n");
printf(" -h host : host running IRRD software (whois.radb.net by "
"default)\n");
@ -77,8 +78,8 @@ exclusive()
void
vendor_exclusive()
{
fprintf(stderr, "-b (BIRD), -J (JunOS), -j (JSON) and -X (IOS XR) options are "
"mutually exclusive\n");
fprintf(stderr, "-b (BIRD), -F (formatted), -J (JunOS), -j (JSON) "
"and -X (IOS XR) options are mutually exclusive\n");
exit(1);
};
@ -130,7 +131,7 @@ main(int argc, char* argv[])
if (getenv("IRRD_SOURCES"))
expander.sources=getenv("IRRD_SOURCES");
while((c=getopt(argc,argv,"2346AbdDES:jJf:l:m:M:W:Ppr:R:G:Th:Xs"))!=EOF) {
while((c=getopt(argc,argv,"2346AbdDEF:S:jJf:l:m:M:W:Ppr:R:G:Th:Xs"))!=EOF) {
switch(c) {
case '2':
expand_as23456=1;
@ -170,6 +171,10 @@ main(int argc, char* argv[])
case 'E': if(expander.generation) exclusive();
expander.generation=T_EACL;
break;
case 'F': if(expander.vendor) exclusive();
expander.vendor=V_FORMAT;
expander.format=optarg;
break;
case 'h': expander.server=optarg;
break;
case 'J': if(expander.vendor) vendor_exclusive();
@ -305,6 +310,14 @@ main(int argc, char* argv[])
sx_report(SX_FATAL, "Sorry, only prefix-lists and as-paths supported "
"for JSON output\n");
};
if(expander.vendor==V_FORMAT && expander.generation!=T_PREFIXLIST)
sx_report(SX_FATAL, "Sorry, only prefix-lists supported in formatted "
"output\n");
if(expander.vendor==V_FORMAT && (refine || refineLow)) {
sx_report(SX_FATAL, "Sorry, formatted output (-F <fmt>) in not "
"compatible with -R/-r options\n");
exit(1);
};
if(expander.asdot && expander.vendor!=V_CISCO) {
sx_report(SX_FATAL,"asdot notation supported only for Cisco, "
@ -323,6 +336,12 @@ main(int argc, char* argv[])
exit(1);
};
if(aggregate && expander.vendor==V_FORMAT) {
sx_report(SX_FATAL, "Sorry, aggregation (-A) is not compatible with "
"formatted output (-F <fmt>)\n");
exit(1);
};
if(aggregate && expander.generation<T_PREFIXLIST) {
sx_report(SX_FATAL, "Sorry, aggregation (-A) used only for prefix-"
"lists, extended access-lists and route-filters\n");

View File

@ -9,7 +9,8 @@ typedef enum {
V_JUNIPER,
V_CISCO_XR,
V_JSON,
V_BIRD
V_BIRD,
V_FORMAT
} bgpq_vendor_t;
typedef enum {
@ -47,6 +48,7 @@ struct bgpq_expander {
int piped;
char* match;
char* server;
char* format;
unsigned maxlen;
int socksize;
int qsize;

View File

@ -618,6 +618,38 @@ bgpq3_print_bird_prefixlist(FILE* f, struct bgpq_expander* b)
return 0;
};
struct fpcbdata {
FILE* f;
struct bgpq_expander* b;
};
void
bgpq3_print_format_prefix(struct sx_radix_node* n, void* ff)
{
char prefix[128];
struct fpcbdata* fpc=(struct fpcbdata*)ff;
FILE* f=fpc->f;
struct bgpq_expander* b=fpc->b;
if(n->isGlue)
return;
if(!f)
f=stdout;
memset(prefix, 0, sizeof(prefix));
sx_prefix_snprintf_fmt(&n->prefix, prefix, sizeof(prefix), b->format);
fprintf(f, "%s", prefix);
};
int
bgpq3_print_format_prefixlist(FILE* f, struct bgpq_expander* b)
{
struct fpcbdata ff = {.f=f, .b=b};
sx_radix_tree_foreach(b->tree,bgpq3_print_format_prefix,&ff);
if (strcmp(b->format+strlen(b->format-2), "\n"))
fprintf(f, "\n");
return 0;
};
int
bgpq3_print_cisco_eacl(FILE* f, struct bgpq_expander* b)
{
@ -642,6 +674,7 @@ bgpq3_print_prefixlist(FILE* f, struct bgpq_expander* b)
case V_CISCO_XR: return bgpq3_print_ciscoxr_prefixlist(f,b);
case V_JSON: return bgpq3_print_json_prefixlist(f,b);
case V_BIRD: return bgpq3_print_bird_prefixlist(f,b);
case V_FORMAT: return bgpq3_print_format_prefixlist(f,b);
};
return 0;
};
@ -655,6 +688,7 @@ bgpq3_print_eacl(FILE* f, struct bgpq_expander* b)
case V_CISCO_XR: sx_report(SX_FATAL, "unreachable point\n");
case V_JSON: sx_report(SX_FATAL, "unreachable point\n");
case V_BIRD: sx_report(SX_FATAL, "unreachable point\n");
case V_FORMAT: sx_report(SX_FATAL, "unreachable point\n");
};
return 0;
};

View File

@ -217,7 +217,7 @@ sx_prefix_range_parse(struct sx_radix_tree* tree, int af, int maxlen,
};
SX_DEBUG(debug_expander, "parsed prefix-range %s as %lu-%lu\n",
text, min, max);
if (max > maxlen)
if (max > maxlen)
max = maxlen;
sx_radix_tree_insert_specifics(tree, p, min, max);
return 1;
@ -264,6 +264,52 @@ sx_prefix_snprintf(struct sx_prefix* p, char* rbuffer, int srb)
return snprintf(rbuffer,srb,"%s/%i",buffer,p->masklen);
};
int
sx_prefix_snprintf_fmt(struct sx_prefix* p, char* buffer, int size,
const char* format)
{
unsigned off=0;
const char* c=format;
while(*c) {
if(*c=='%') {
switch(*(c+1)) {
case 'r':
case 'n':
inet_ntop(p->family,&p->addr,buffer+off,size-off);
off=strlen(buffer);
break;
case 'l':
off+=snprintf(buffer+off,size-off,"%i",p->masklen);
break;
case '%':
buffer[off++]='%';
break;
default :
sx_report(SX_ERROR, "Unknown format char '%c'\n", *(c+1));
return 0;
};
c+=2;
} else if (*c=='\\') {
switch(*(c+1)) {
case 'n':
buffer[off++]='\n'; break;
case 't':
buffer[off++]='\t'; break;
case '\\':
buffer[off++]='\\'; break;
default:
buffer[off++]=*(c+1);
break;
};
c+=2;
} else {
buffer[off++]=*c;
c++;
};
};
return strlen(buffer);
};
int
sx_prefix_jsnprintf(struct sx_prefix* p, char* rbuffer, int srb)
{

View File

@ -49,6 +49,8 @@ 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_fmt(struct sx_prefix* p, char* rbuffer, int srb,
const char* fmt);
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);