summaryrefslogtreecommitdiff
path: root/nest
diff options
context:
space:
mode:
Diffstat (limited to 'nest')
-rw-r--r--nest/route.h6
-rw-r--r--nest/rt-fib.c9
-rw-r--r--nest/rt-table.c71
3 files changed, 84 insertions, 2 deletions
diff --git a/nest/route.h b/nest/route.h
index c6e9cb41..1cce3c01 100644
--- a/nest/route.h
+++ b/nest/route.h
@@ -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 *);
diff --git a/nest/rt-fib.c b/nest/rt-fib.c
index 8bf67f8d..55387c5e 100644
--- a/nest/rt-fib.c
+++ b/nest/rt-fib.c
@@ -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
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 400b9d9c..f164ecd9 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -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)
{