| 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; }
;
*/
#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
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));
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
* 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)
" -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"
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;