0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-11-08 12:18:42 +00:00

Trie optimizer

This patch optimizes prefix sets like
  [ 10.0.0.0/24, 10.0.1.0/24, 10.0.2.0/24, 10.0.3.0/24 ]
into
  [ 10.0.0.0/22{24,24} ]

This should improve config loading speed with large config files.

Works only in config-check mode; the appropriate flag is -O.
Beware. The output is written directly on stdout.

This patch is not intended to be ever merged with mainline in this form.
Instead, we should fix bad lexer performance and also merge the
merge-able prefixes on-the-fly during trie creation. Ultimately,
we should have better possibility to feed database-like structures into
BIRD instead of config file.
This commit is contained in:
Jan Maria Matejka 2018-09-12 15:31:13 +02:00
parent abec20083a
commit dae0ea9b0e
5 changed files with 96 additions and 2 deletions

View File

@ -727,7 +727,13 @@ constant:
| fprefix_s {NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); $$->a1.p = val; *val = $1; }
| RTRID { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_QUAD; $$->a2.i = $1; }
| '[' set_items ']' { DBG( "We've got a set here..." ); $$ = f_new_inst(FI_CONSTANT); $$->aux = T_SET; $$->a2.p = build_tree($2); DBG( "ook\n" ); }
| '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_PREFIX_SET; $$->a2.p = $2; }
| '[' fprefix_set ']' {
$$ = f_new_inst(FI_CONSTANT);
$$->aux = T_PREFIX_SET;
$$->a2.p = $2;
if (trie_optimize_flag)
trie_optimize($$);
}
| ENUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; }
;

View File

@ -298,6 +298,8 @@ struct f_trie
struct f_trie_node root[0]; /* Root trie node follows */
};
void trie_optimize(struct f_inst *);
#define NEW_F_VAL struct f_val * val; val = cfg_alloc(sizeof(struct f_val));
#define FF_FORCE_TMPATTR 1 /* Force all attributes to be temporary */

View File

@ -70,10 +70,14 @@
*/
#include "nest/bird.h"
#include "lib/resource.h"
#include "lib/string.h"
#include "conf/conf.h"
#include "filter/filter.h"
#include <stdio.h>
#include <stdlib.h>
/**
* f_new_trie - allocates and returns a new empty trie
* @lp: linear pool to allocate items from
@ -181,6 +185,10 @@ trie_add_prefix(struct f_trie *t, ip_addr px, int plen, int l, int h)
return n;
}
/* All additional prefixes are already covered by this node. */
if (ipa_equal(ipa_and(n->accept, amask), amask))
return n;
/* Update accept mask part M2 and go deeper */
n->accept = ipa_or(n->accept, ipa_and(amask, n->mask));
@ -258,6 +266,77 @@ trie_node_same(struct f_trie_node *t1, struct f_trie_node *t2)
return trie_node_same(t1->c[0], t2->c[0]) && trie_node_same(t1->c[1], t2->c[1]);
}
static int
trie_node_optimize(struct f_trie_node *t)
{
int ret = 0;
if (t->c[0]) ret |= trie_node_optimize(t->c[0]);
if (t->c[1]) ret |= trie_node_optimize(t->c[1]);
if ((!t->c[0]) || (!t->c[1])) return ret;
if (t->c[0]->plen != t->plen + 1) return ret;
if (t->c[1]->plen != t->plen + 1) return ret;
ip_addr cmask = ipa_and(t->c[0]->accept, t->c[1]->accept);
if (ipa_zero(cmask)) return ret;
ip_addr lmask = ipa_xor(t->c[0]->accept, cmask);
ip_addr rmask = ipa_xor(t->c[1]->accept, cmask);
if (!ipa_zero(lmask) && !ipa_zero(rmask))
return ret;
t->c[0]->accept = lmask;
t->c[1]->accept = rmask;
t->accept = ipa_or(t->accept, cmask);
return 1;
}
static int
trie_node_count(struct f_trie_node *t)
{
int ret = 0;
if (t->c[0]) ret += trie_node_count(t->c[0]);
if (t->c[1]) ret += trie_node_count(t->c[1]);
for (
ip_addr amask = t->accept;
ipa_nonzero(amask);
ret++,
amask = ipa_xor(amask, ipa_bitrange(amask, NULL, NULL))
);
return ret;
}
void
trie_optimize(struct f_inst *what)
{
struct f_trie *t = what->a2.p;
if (!t || !t->root)
return;
if (!trie_node_optimize(t->root))
return;
int size = trie_node_count(t->root) * (STD_ADDRESS_P_LENGTH + 11);
char *buf = xmalloc(size);
buffer b = {
.start = buf,
.pos = buf,
.end = buf + size
};
printf("Prefix set in file %s at line %d: ", ifs->file_name, ifs->lino);
trie_format(t, &b);
buffer_puts(&b, "\n");
fputs(b.start, stdout);
xfree(buf);
}
/**
* trie_same
* @t1: first trie to be compared

View File

@ -619,12 +619,13 @@ signal_init(void)
* Parsing of command-line arguments
*/
static char *opt_list = "c:dD:ps:P:u:g:flRh";
static char *opt_list = "c:dD:pOs:P:u:g:flRh";
static int parse_and_exit;
char *bird_name;
static char *use_user;
static char *use_group;
static int run_in_foreground = 0;
int trie_optimize_flag = 0;
static void
display_usage(void)
@ -649,6 +650,7 @@ display_help(void)
" -h, --help Display this information\n"
" -l Look for a configuration file and a communication socket\n"
" file in the current working directory\n"
" -O Optimize prefix sets; implies -p\n"
" -p Test configuration file and exit without start\n"
" -P <pid-file> Create a PID file with given filename\n"
" -R Apply graceful restart recovery after start\n"
@ -758,6 +760,10 @@ parse_args(int argc, char **argv)
case 'p':
parse_and_exit = 1;
break;
case 'O':
parse_and_exit = 1;
trie_optimize_flag = 1;
break;
case 's':
path_control_socket = optarg;
socket_changed = 1;

View File

@ -18,6 +18,7 @@ struct birdsock;
/* main.c */
extern char *bird_name;
extern int trie_optimize_flag;
void async_config(void);
void async_dump(void);
void async_shutdown(void);