]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Trie optimizer mq-trie-opt
authorJan Maria Matejka <mq@ucw.cz>
Wed, 12 Sep 2018 13:31:13 +0000 (15:31 +0200)
committerJan Maria Matejka <mq@ucw.cz>
Wed, 12 Sep 2018 13:32:21 +0000 (15:32 +0200)
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.

filter/config.Y
filter/filter.h
filter/trie.c
sysdep/unix/main.c
sysdep/unix/unix.h

index 6328ba094c02bce9b1506c1747ce7b3cfc86c135..37d93f46dd98af012960356376bfe8d9dabba05b 100644 (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; }
  ;
 
index 572459d86b73b8e1b3fa569c593d4fdf071be0b1..046e5526ff76a96e80436d2caadf23ce0471dbb0 100644 (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 */
index 6477fbbfc41a2580b25f7d669400cb3144035348..2978cc3f42d876e419328c79c72bfcd18258bd6a 100644 (file)
  */
 
 #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
index 99cfab17e64fdff0c299d3c1fc9cccd1d96e5aff..8e60a7f1233d97ef9ac84f8ed9c1950348361252 100644 (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;
index 3ef2e3ef37a2827761adb9a01da1a7f81c75fc76..4acced584b6b88ec39d234d244a9948531b4b420 100644 (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);