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:
2
CHANGES
2
CHANGES
@ -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,
|
||||
|
28
README.md
28
README.md
@ -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
25
bgpq3.c
@ -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");
|
||||
|
4
bgpq3.h
4
bgpq3.h
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
48
sx_prefix.c
48
sx_prefix.c
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
Reference in New Issue
Block a user