]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Rewrite roa_check() for integrated BIRD
authorPavel Tvrdík <pawel.tvrdik@gmail.com>
Wed, 20 Jan 2016 14:38:37 +0000 (15:38 +0100)
committerPavel Tvrdík <pawel.tvrdik@gmail.com>
Wed, 20 Jan 2016 15:46:58 +0000 (16:46 +0100)
Thanks to Ondrej Zajicek for his support with writing this code.

filter/config.Y
filter/f-util.c
filter/filter.c
filter/filter.h
nest/route.h
nest/rt-fib.c
nest/rt-table.c

index 6efc14f5e0d22009450001155e6104eade025d18..3bb00c13d0b1d617338aab8f166505dcc27d98b7 100644 (file)
@@ -278,6 +278,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
        TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
        FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, IFNAME, IFINDEX,
        PREFERENCE,
+       ROA_CHECK,
        LEN,
        DEFINED,
        ADD, DELETE, CONTAINS, RESET,
@@ -759,10 +760,8 @@ term:
  | DELETE '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; }
  | FILTER '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; }
 
-/*
- | ROA_CHECK '(' SYM ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
- | ROA_CHECK '(' SYM ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }
-*/
+ | ROA_CHECK '(' rtable ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
+ | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }
 
 /* | term '.' LEN { $$->code = P('P','l'); } */
 
index 7311a56e6db094ef944376e4d770480263d68714..661941ecf40d9831bc60b0a1b1040b866c552126 100644 (file)
@@ -54,9 +54,8 @@ f_generate_complex(int operation, int operation_aux, struct f_inst *dyn, struct
   return set_dyn;
 }
 
-#if 0
 struct f_inst *
-f_generate_roa_check(struct symbol *sym, struct f_inst *prefix, struct f_inst *asn)
+f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn)
 {
   struct f_inst_roa_check *ret = cfg_allocz(sizeof(struct f_inst_roa_check));
   ret->i.code = P('R','C');
@@ -65,13 +64,12 @@ f_generate_roa_check(struct symbol *sym, struct f_inst *prefix, struct f_inst *a
   ret->i.arg2 = asn;
   /* prefix == NULL <-> asn == NULL */
 
-  if ((sym->class != SYM_ROA) || ! sym->def)
-    cf_error("%s is not a ROA table", sym->name);
-  ret->rtc = sym->def;
+  if (table->addr_type != NET_ROA4 && table->addr_type != NET_ROA6)
+    cf_error("%s is not a ROA table", table->name);
+  ret->rtc = table;
 
   return &ret->i;
 }
-#endif
 
 char *
 filter_name(struct filter *filter)
index 7a5ba5b9e5a2358c3aa74d18da5d1405030b083c..6ab0cc93cca4622a3fb148662efada6fb5117415 100644 (file)
@@ -39,6 +39,8 @@
 #include "lib/socket.h"
 #include "lib/string.h"
 #include "lib/unaligned.h"
+#include "lib/net.h"
+#include "lib/ip.h"
 #include "nest/route.h"
 #include "nest/protocol.h"
 #include "nest/iface.h"
@@ -1241,7 +1243,7 @@ interpret(struct f_inst *what)
 
     break;
 
-#if 0
+
   case P('R','C'):     /* ROA Check */
     if (what->arg1)
     {
@@ -1266,15 +1268,15 @@ interpret(struct f_inst *what)
       as_path_get_last(e->u.ptr, &as);
     }
 
-    struct roa_table_config *rtc = ((struct f_inst_roa_check *) what)->rtc;
-    if (!rtc->table)
+    struct rtable *table = ((struct f_inst_roa_check *) what)->rtc->table;
+    if (!table || table->addr_type != (v1.val.net->type == NET_IP4 ? NET_ROA4 : NET_ROA6))
       runtime("Missing ROA table");
 
     res.type = T_ENUM_ROA;
-    res.val.i = ROA_UNKNOWN;
-    // XXXX res.val.i = roa_check_net(rtc->table, &v1.val.net, as);
+    res.val.i = net_roa_check(table, v1.val.net, as);
+
     break;
-#endif
+
 
   default:
     bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff);
index 1875f314ffb6b121859f13180a5cb496697e1480..af4901210b6f6e11ef83a39df8fb1d6837dd8d23 100644 (file)
@@ -35,7 +35,7 @@ struct f_inst {               /* Instruction */
 /* Not enough fields in f_inst for three args used by roa_check() */
 struct f_inst_roa_check {
   struct f_inst i;
-  struct roa_table_config *rtc;        
+  struct rtable_config *rtc;
 };
 
 struct f_prefix {
@@ -67,7 +67,7 @@ struct f_inst *f_new_inst(void);
 struct f_inst *f_new_dynamic_attr(int type, int f_type, int code);     /* Type as core knows it, type as filters know it, and code of dynamic attribute */
 struct f_tree *f_new_tree(void);
 struct f_inst *f_generate_complex(int operation, int operation_aux, struct f_inst *dyn, struct f_inst *argument);
-// struct f_inst *f_generate_roa_check(struct symbol *sym, struct f_inst *prefix, struct f_inst *asn);
+struct f_inst *f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn);
 
 
 struct f_tree *build_tree(struct f_tree *);
index c6e9cb41cb12aa4d486f7b0f1231e6077486018b..1cce3c01e464f8da408f52c31644b7ef9fad80f9 100644 (file)
@@ -72,6 +72,7 @@ static inline struct fib_node * fib_user_to_node(struct fib *f, void *e)
 
 void fib_init(struct fib *f, pool *p, uint addr_type, uint node_size, uint node_offset, uint hash_order, fib_init_fn init);
 void *fib_find(struct fib *, const net_addr *);        /* Find or return NULL if doesn't exist */
+void *fib_get_chain(struct fib *f, const net_addr *a); /* Find first node in linked list from hash table */
 void *fib_get(struct fib *, const net_addr *);         /* Find or create new if nonexistent */
 void *fib_route(struct fib *, const net_addr *); /* Longest-match routing lookup */
 void fib_delete(struct fib *, void *); /* Remove fib entry */
@@ -273,8 +274,9 @@ void rt_commit(struct config *new, struct config *old);
 void rt_lock_table(rtable *);
 void rt_unlock_table(rtable *);
 void rt_setup(pool *, rtable *, char *, struct rtable_config *);
-static inline net *net_find(rtable *tab, net_addr *addr) { return (net *) fib_find(&tab->fib, addr); }
-static inline net *net_get(rtable *tab, net_addr *addr) { return (net *) fib_get(&tab->fib, addr); }
+static inline net *net_find(rtable *tab, const net_addr *addr) { return (net *) fib_find(&tab->fib, addr); }
+static inline net *net_get(rtable *tab, const net_addr *addr) { return (net *) fib_get(&tab->fib, addr); }
+byte net_roa_check(rtable *tab, const net_addr *n, u32 asn);
 
 rte *rte_find(net *net, struct rte_src *src);
 rte *rte_get_temp(struct rta *);
index 8bf67f8d64d8c088e27d7416e1265c09cace3ca0..55387c5e4944647f5902bcc46c74f458b42fd2bc 100644 (file)
@@ -195,6 +195,15 @@ fib_hash(struct fib *f, const net_addr *a)
   }
 }
 
+void *
+fib_get_chain(struct fib *f, const net_addr *a)
+{
+  ASSERT(f->addr_type == a->type);
+
+  struct fib_node *e = f->hash_table[fib_hash(f, a)];
+  return e;
+}
+
 /**
  * fib_find - search for FIB node by prefix
  * @f: FIB to search in
index 400b9d9c41dc1f1434c9923480b52c7dd167d031..f164ecd9987114b47c03aef65d63191bd575ec09 100644 (file)
@@ -100,6 +100,77 @@ net_route_ip6(struct fib *f, net_addr_ip6 *n)
   return r;
 }
 
+static byte
+net_roa4_check(rtable *tab, const net_addr_ip4 *px, u32 asn)
+{
+  struct net_addr_roa4 n = NET_ADDR_ROA4(px->prefix, px->pxlen, 0, 0);
+  byte anything = 0;
+
+  struct fib_node *fn;
+  while (1)
+  {
+    for (fn = fib_get_chain(&tab->fib, (net_addr *) &n); fn; fn = fn->next)
+    {
+      net *r = fib_node_to_user(&tab->fib, fn);
+      if (rte_is_valid(r->routes) && ipa_in_netX(ipa_from_ip4(px->prefix), r->n.addr))
+      {
+       net_addr_roa4 *roa = (void *) r->n.addr;
+       anything = 1;
+       if (asn && (roa->asn == asn) && (roa->max_pxlen >= px->pxlen))
+         return ROA_VALID;
+      }
+    }
+
+    if (n.pxlen == 0)
+      break;
+
+    n.pxlen--;
+    ip4_clrbit(&n.prefix, n.pxlen);
+  }
+
+  return anything ? ROA_INVALID : ROA_UNKNOWN;
+}
+
+static byte
+net_roa6_check(rtable *tab, const net_addr_ip6 *px, u32 asn)
+{
+  struct net_addr_roa6 n = NET_ADDR_ROA6(px->prefix, px->pxlen, 0, 0);
+  byte anything = 0;
+
+  struct fib_node *fn;
+  while (1)
+  {
+    for (fn = fib_get_chain(&tab->fib, (net_addr *) &n); fn; fn = fn->next)
+    {
+      net *r = fib_node_to_user(&tab->fib, fn);
+      if (rte_is_valid(r->routes) && ipa_in_netX(ipa_from_ip6(px->prefix), r->n.addr))
+      {
+       net_addr_roa6 *roa = (void *) r->n.addr;
+       anything = 1;
+       if (asn && (roa->asn == asn) && (roa->max_pxlen >= px->pxlen))
+         return ROA_VALID;
+      }
+    }
+
+    if (n.pxlen == 0)
+      break;
+
+    n.pxlen--;
+    ip6_clrbit(&n.prefix, n.pxlen);
+  }
+
+  return anything ? ROA_INVALID : ROA_UNKNOWN;
+}
+
+byte
+net_roa_check(rtable *tab, const net_addr *n, u32 asn)
+{
+  if (tab->addr_type == NET_ROA4)
+    return net_roa4_check(tab, (const net_addr_ip4 *) n, asn);
+  else
+    return net_roa6_check(tab, (const net_addr_ip6 *) n, asn);
+}
+
 void *
 net_route(rtable *tab, const net_addr *n)
 {