Commit ead7b8f4 authored by Jan Moskyto Matejka's avatar Jan Moskyto Matejka

Merge branch 'nexthop-merged' into int-new

parents da3cf9ea 61e501da
......@@ -123,6 +123,60 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
cf_include(start, end-start);
}
[02]:{DIGIT}+:{DIGIT}+ {
unsigned long int l, len1, len2;
char *e;
if (yytext[0] == '0')
{
cf_lval.i64 = 0;
len1 = 16;
len2 = 32;
}
else
{
cf_lval.i64 = 2ULL << 48;
len1 = 32;
len2 = 16;
}
errno = 0;
l = strtoul(yytext+2, &e, 10);
if (e && (*e != ':') || (errno == ERANGE) || (l >> len1))
cf_error("ASN out of range");
cf_lval.i64 |= ((u64) l) << len2;
errno = 0;
l = strtoul(e+1, &e, 10);
if (e && *e || (errno == ERANGE) || (l >> len2))
cf_error("Number out of range");
cf_lval.i64 |= l;
return VPN_RD;
}
1:{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+:{DIGIT}+ {
unsigned long int l;
ip4_addr ip4;
char *e;
cf_lval.i64 = 1ULL << 48;
e = strchr(yytext+2, ':');
*e++ = '\0';
if (!ip4_pton(yytext+2, &ip4))
cf_error("Invalid IPv4 address %s in Route Distinguisher", yytext+2);
cf_lval.i64 |= ((u64) ip4_to_u32(ip4)) << 16;
errno = 0;
l = strtoul(e, &e, 10);
if (e && *e || (errno == ERANGE) || (l >> 16))
cf_error("Number out of range");
cf_lval.i64 |= l;
return VPN_RD;
}
{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ {
if (!ip4_pton(yytext, &cf_lval.ip4))
cf_error("Invalid IPv4 address %s", yytext);
......
......@@ -38,6 +38,7 @@ CF_DECLS
%union {
int i;
u32 i32;
u64 i64;
ip_addr a;
ip4_addr ip4;
ip6_addr ip6;
......@@ -64,6 +65,7 @@ CF_DECLS
struct proto_spec ps;
struct channel_limit cl;
struct timeformat *tf;
mpls_label_stack *mls;
}
%token END CLI_MARKER INVALID_TOKEN ELSECOL DDOT
......@@ -72,6 +74,7 @@ CF_DECLS
%token <i> NUM ENUM
%token <ip4> IP4
%token <ip6> IP6
%token <i64> VPN_RD
%token <s> SYM
%token <t> TEXT
%type <iface> ipa_scope
......@@ -81,7 +84,8 @@ CF_DECLS
%type <time> datetime
%type <a> ipa
%type <net> net_ip4_ net_ip6_ net_ip6 net_ip_ net_ip net_or_ipa
%type <net_ptr> net_ net_any net_roa4_ net_roa6_ net_roa_
%type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_
%type <mls> label_stack_start label_stack
%type <t> text opttext
......@@ -93,7 +97,7 @@ CF_DECLS
%left '!'
%nonassoc '.'
CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT)
CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT, VPN)
CF_GRAMMAR
......@@ -196,6 +200,18 @@ net_ip6_: IP6 '/' NUM
cf_error("Invalid IPv6 prefix");
};
net_vpn4_: VPN_RD net_ip4_
{
$$ = cfg_alloc(sizeof(net_addr_vpn4));
net_fill_vpn4($$, net4_prefix(&$2), net4_pxlen(&$2), $1);
}
net_vpn6_: VPN_RD net_ip6_
{
$$ = cfg_alloc(sizeof(net_addr_vpn6));
net_fill_vpn6($$, net6_prefix(&$2), net6_pxlen(&$2), $1);
}
net_roa4_: net_ip4_ MAX NUM AS NUM
{
$$ = cfg_alloc(sizeof(net_addr_roa4));
......@@ -213,10 +229,12 @@ net_roa6_: net_ip6_ MAX NUM AS NUM
};
net_ip_: net_ip4_ | net_ip6_ ;
net_vpn_: net_vpn4_ | net_vpn6_ ;
net_roa_: net_roa4_ | net_roa6_ ;
net_:
net_ip_ { $$ = cfg_alloc($1.length); net_copy($$, &($1)); }
| net_vpn_
| net_roa_
| net_flow_
;
......@@ -254,6 +272,8 @@ net_any:
net_or_ipa:
net_ip4_
| net_ip6_
| net_vpn4_ { $$ = *$1; }
| net_vpn6_ { $$ = *$1; }
| IP4 { net_fill_ip4(&($$), $1, IP4_MAX_PREFIX_LENGTH); }
| IP6 { net_fill_ip6(&($$), $1, IP6_MAX_PREFIX_LENGTH); }
| SYM {
......@@ -266,6 +286,22 @@ net_or_ipa:
}
;
label_stack_start: NUM
{
$$ = cfg_allocz(sizeof(mpls_label_stack));
$$->len = 1;
$$->stack[0] = $1;
};
label_stack:
label_stack_start
| label_stack '/' NUM {
if ($1->len >= MPLS_MAX_LABEL_STACK)
cf_error("Too many labels in stack");
$1->stack[$1->len++] = $3;
$$ = $1;
}
;
datetime:
TEXT {
......
......@@ -57,6 +57,7 @@ if test "$ac_test_CFLAGS" != set ; then
bird_cflags_default=yes
fi
AC_PROG_CC
AC_PROG_CC_C99
if test -z "$GCC" ; then
AC_MSG_ERROR([This program requires the GNU C Compiler.])
......
......@@ -36,8 +36,8 @@ $(o)%.ps: $(o)%.dvi
dvips -D600 -ta4 -o $@ $<
$(o)%.pdf: $(o)%.tex
pdflatex -output-directory=$(dir $@) $<
pdflatex -output-directory=$(dir $@) $<
TEXINPUTS=$(TEXINPUTS):$(doc-srcdir)/tex pdflatex -output-directory=$(dir $@) $<
TEXINPUTS=$(TEXINPUTS):$(doc-srcdir)/tex pdflatex -output-directory=$(dir $@) $<
$(o)%.txt: $(o)%.sgml
cd $(dir $@) && $(sgml2)txt $(notdir $<)
......
......@@ -1186,20 +1186,41 @@ foot).
<tag><label id="type-ip">ip</tag>
This type can hold a single IP address. Depending on the compile-time
configuration of BIRD you are using, it is either an IPv4 or IPv6
address. IP addresses are written in the standard notation
address; this may be checked by <cf>.is_ip4</cf> which returns <cf/bool/.
IP addresses are written in the standard notation
(<cf/10.20.30.40/ or <cf/fec0:3:4::1/). You can apply special operator
<cf>.mask(<M>num</M>)</cf> on values of type ip. It masks out all but
first <cf><M>num</M></cf> bits from the IP address. So
<cf/1.2.3.4.mask(8) = 1.0.0.0/ is true.
<tag><label id="type-prefix">prefix</tag>
This type can hold a network prefix consisting of IP address and prefix
length. Prefix literals are written as <cf><m/ipaddress//<m/pxlen/</cf>,
This type can hold a network prefix consisting of IP address, prefix
length and several other values. This is the key in route tables.
Prefixes may be of several types, which can be determined by the special
operator <cf/.type/. The type may be:
<cf/NET_IP4/ and <cf/NET_IP6/ prefixes hold an IP prefix. The literals
are written as <cf><m/ipaddress//<m/pxlen/</cf>,
or <cf><m>ipaddress</m>/<m>netmask</m></cf>. There are two special
operators on prefixes: <cf/.ip/ which extracts the IP address from the
pair, and <cf/.len/, which separates prefix length from the pair.
operators on IP prefixes: <cf/.ip/ which extracts the IP address from
the pair, and <cf/.len/, which separates prefix length from the pair.
So <cf>1.2.0.0/16.len = 16</cf> is true.
<cf/NET_VPN4/ and <cf/NET_VPN6/ prefixes hold an IP prefix with VPN
Route Distinguisher (<rfc id="4364">). They support the same special
operators as IP prefixes, and also <cf/.rd/ which extracts the Route
Distinguisher. Their literals are written
as <cf><m/vpnrd/ <m/ipprefix/</cf>
<cf/NET_ROA4/ and <cf/NET_ROA6/ prefixes hold an IP prefix range
together with an ASN. They support the same special operators as IP
prefixes, and also <cf/.maxlen/ which extracts maximal prefix length,
and <cf/.asn/ which extracts the ASN.
<cf/NET_FLOW4/ and <cf/NET_FLOW6/ hold an IP prefix together with a
flowspec rule. Filters currently don't support flowspec parsing.
<tag><label id="type-ec">ec</tag>
This is a specialized type used to represent BGP extended community
values. It is essentially a 64bit value, literals of this type are
......@@ -4160,12 +4181,12 @@ return packets as undeliverable if they are in your IP block, you don't have any
specific destination for them and you don't want to send them out through the
default route to prevent routing loops).
<p>There are five types of static routes: `classical' routes telling to forward
packets to a neighboring router, multipath routes specifying several (possibly
weighted) neighboring routers, device routes specifying forwarding to hosts on a
directly connected network, recursive routes computing their nexthops by doing
route table lookups for a given IP, and special routes (sink, blackhole etc.)
which specify a special action to be done instead of forwarding the packet.
<p>There are four types of static routes: `classical' routes telling to forward
packets to a neighboring router (single path or multipath, possibly weighted),
device routes specifying forwarding to hosts on a directly connected network,
recursive routes computing their nexthops by doing route table lookups for a
given IP, and special routes (sink, blackhole etc.) which specify a special
action to be done instead of forwarding the packet.
<p>When the particular destination is not available (the interface is down or
the next hop of the route is not a neighbor at the moment), Static just
......@@ -4194,14 +4215,14 @@ definition of the protocol contains mainly a list of static routes.
<p>Route definitions (each may also contain a block of per-route options):
<descrip>
<tag><label id="static-route-via-ip">route <m/prefix/ via <m/ip/</tag>
Static route through a neighboring router. For link-local next hops,
<tag><label id="static-route-via-ip">route <m/prefix/ via <m/ip/ [mpls <m/num/[/<m/num/[/<m/num/[...]]]]</tag>
Static single path route through a neighboring router. For link-local next hops,
interface can be specified as a part of the address (e.g.,
<cf/via fe80::1234%eth0/).
<cf/via fe80::1234%eth0/). MPLS labels should be specified in outer-first order.
<tag><label id="static-route-via-mpath">route <m/prefix/ multipath via <m/ip/ [weight <m/num/] [bfd <m/switch/] [via <m/.../]</tag>
<tag><label id="static-route-via-mpath">route <m/prefix/ via <m/ip/ [mpls <m/num/[/<m/num/[/<m/num/[...]]]] [weight <m/num/] [bfd <m/switch/] [via ...]</tag>
Static multipath route. Contains several nexthops (gateways), possibly
with their weights.
with their weights and MPLS labels.
<tag><label id="static-route-via-iface">route <m/prefix/ via <m/"interface"/</tag>
Static device route through an interface to hosts on a directly
......
......@@ -393,13 +393,14 @@ CF_DECLS
CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
ACCEPT, REJECT, ERROR, QUITBIRD,
INT, BOOL, IP, PREFIX, PAIR, QUAD, EC, LC,
INT, BOOL, IP, TYPE, PREFIX, RD, PAIR, QUAD, EC, LC,
SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST,
IF, THEN, ELSE, CASE,
TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, IFNAME, IFINDEX,
FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX,
PREFERENCE,
ROA_CHECK, ASN,
IS_V4, IS_V6,
LEN, MAXLEN,
DEFINED,
ADD, DELETE, CONTAINS, RESET,
......@@ -460,6 +461,7 @@ type:
INT { $$ = T_INT; }
| BOOL { $$ = T_BOOL; }
| IP { $$ = T_IP; }
| RD { $$ = T_RD; }
| PREFIX { $$ = T_NET; }
| PAIR { $$ = T_PAIR; }
| QUAD { $$ = T_QUAD; }
......@@ -786,6 +788,7 @@ constant:
| FALSE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 0; }
| TEXT { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_STRING; $$->a2.p = $1; }
| fipa { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; }
| VPN_RD { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_RD; val->val.ec = $1; $$->a1.p = val; }
| net_ { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_NET; val->val.net = $1; $$->a1.p = val; }
| '[' set_items ']' { DBG( "We've got a set here..." ); $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_SET; $$->a2.p = build_tree($2); DBG( "ook\n" ); }
| '[' fprefix_set ']' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_PREFIX_SET; $$->a2.p = $2; }
......@@ -854,7 +857,6 @@ static_attr:
| PROTO { $$ = f_new_inst(); $$->aux = T_STRING; $$->a2.i = SA_PROTO; }
| SOURCE { $$ = f_new_inst(); $$->aux = T_ENUM_RTS; $$->a2.i = SA_SOURCE; }
| SCOPE { $$ = f_new_inst(); $$->aux = T_ENUM_SCOPE; $$->a2.i = SA_SCOPE; $$->a1.i = 1; }
| CAST { $$ = f_new_inst(); $$->aux = T_ENUM_RTC; $$->a2.i = SA_CAST; }
| DEST { $$ = f_new_inst(); $$->aux = T_ENUM_RTD; $$->a2.i = SA_DEST; $$->a1.i = 1; }
| IFNAME { $$ = f_new_inst(); $$->aux = T_STRING; $$->a2.i = SA_IFNAME; }
| IFINDEX { $$ = f_new_inst(); $$->aux = T_INT; $$->a2.i = SA_IFINDEX; }
......@@ -889,7 +891,10 @@ term:
| rtadot dynamic_attr { $$ = $2; $$->code = P('e','a'); }
| term '.' IS_V4 { $$ = f_new_inst(); $$->code = P('I','i'); $$->a1.p = $1; }
| term '.' TYPE { $$ = f_new_inst(); $$->code = 'T'; $$->a1.p = $1; }
| term '.' IP { $$ = f_new_inst(); $$->code = P('c','p'); $$->a1.p = $1; $$->aux = T_IP; }
| term '.' RD { $$ = f_new_inst(); $$->code = P('R','D'); $$->a1.p = $1; $$->aux = T_RD; }
| term '.' LEN { $$ = f_new_inst(); $$->code = 'L'; $$->a1.p = $1; }
| term '.' MAXLEN { $$ = f_new_inst(); $$->code = P('R','m'); $$->a1.p = $1; }
| term '.' ASN { $$ = f_new_inst(); $$->code = P('R','a'); $$->a1.p = $1; }
......
......@@ -151,6 +151,7 @@ val_compare(struct f_val v1, struct f_val v2)
case T_QUAD:
return uint_cmp(v1.val.i, v2.val.i);
case T_EC:
case T_RD:
return u64_cmp(v1.val.ec, v2.val.ec);
case T_LC:
return lcomm_cmp(v1.val.lc, v2.val.lc);
......@@ -515,6 +516,7 @@ val_format(struct f_val v, buffer *buf)
case T_QUAD: buffer_print(buf, "%R", v.val.i); return;
case T_EC: ec_format(buf2, v.val.ec); buffer_print(buf, "%s", buf2); return;
case T_LC: lc_format(buf2, v.val.lc); buffer_print(buf, "%s", buf2); return;
case T_RD: rd_format(v.val.ec, buf2, 1024); buffer_print(buf, "%s", buf2); return;
case T_PREFIX_SET: trie_format(v.val.ti, buf); return;
case T_SET: tree_format(v.val.t, buf); return;
case T_ENUM: buffer_print(buf, "(enum %x)%u", v.type, v.val.i); return;
......@@ -815,6 +817,25 @@ interpret(struct f_inst *what)
res.type = T_BOOL;
res.val.i = (v1.type != T_VOID);
break;
case 'T':
ONEARG;
switch (v1.type)
{
case T_NET:
res.type = T_ENUM_NETTYPE;
res.val.i = v1.val.net->type;
break;
default:
runtime( "Can't determine type of this item" );
}
break;
case P('I','i'):
ONEARG;
if (v1.type != T_IP)
runtime( "IP version check needs an IP address" );
res.type = T_BOOL;
res.val.i = ipa_is_ip4(v1.val.ip);
break;
/* Set to indirect value, a1 = variable, a2 = value */
case 's':
......@@ -900,15 +921,14 @@ interpret(struct f_inst *what)
switch (what->a2.i)
{
case SA_FROM: res.val.ip = rta->from; break;
case SA_GW: res.val.ip = rta->gw; break;
case SA_GW: res.val.ip = rta->nh.gw; break;
case SA_NET: res.val.net = (*f_rte)->net->n.addr; break;
case SA_PROTO: res.val.s = rta->src->proto->name; break;
case SA_SOURCE: res.val.i = rta->source; break;
case SA_SCOPE: res.val.i = rta->scope; break;
case SA_CAST: res.val.i = rta->cast; break;
case SA_DEST: res.val.i = rta->dest; break;
case SA_IFNAME: res.val.s = rta->iface ? rta->iface->name : ""; break;
case SA_IFINDEX: res.val.i = rta->iface ? rta->iface->index : 0; break;
case SA_IFNAME: res.val.s = rta->nh.iface ? rta->nh.iface->name : ""; break;
case SA_IFINDEX: res.val.i = rta->nh.iface ? rta->nh.iface->index : 0; break;
default:
bug("Invalid static attribute access (%x)", res.type);
......@@ -938,10 +958,10 @@ interpret(struct f_inst *what)
if (!n || (n->scope == SCOPE_HOST))
runtime( "Invalid gw address" );
rta->dest = RTD_ROUTER;
rta->gw = ip;
rta->iface = n->iface;
rta->nexthops = NULL;
rta->dest = RTD_UNICAST;
rta->nh.gw = ip;
rta->nh.iface = n->iface;
rta->nh.next = NULL;
rta->hostentry = NULL;
}
break;
......@@ -956,9 +976,9 @@ interpret(struct f_inst *what)
runtime( "Destination can be changed only to blackhole, unreachable or prohibit" );
rta->dest = i;
rta->gw = IPA_NONE;
rta->iface = NULL;
rta->nexthops = NULL;
rta->nh.gw = IPA_NONE;
rta->nh.iface = NULL;
rta->nh.next = NULL;
rta->hostentry = NULL;
break;
......@@ -1210,6 +1230,15 @@ interpret(struct f_inst *what)
res.type = T_IP;
res.val.ip = net_prefix(v1.val.net);
break;
case P('R','D'):
ONEARG;
if (v1.type != T_NET)
runtime( "Prefix expected" );
if (!net_is_vpn(v1.val.net))
runtime( "VPN address expected" );
res.type = T_RD;
res.val.ec = net_rd(v1.val.net);
break;
case P('a','f'): /* Get first ASN from AS PATH */
ONEARG;
if (v1.type != T_PATH)
......@@ -1582,6 +1611,8 @@ i_same(struct f_inst *f1, struct f_inst *f2)
case P('!', '~'):
case '~': TWOARGS; break;
case P('d','e'): ONEARG; break;
case 'T': ONEARG; break;
case P('n','T'): break;
case P('m','l'):
TWOARGS;
......@@ -1647,6 +1678,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
case 'r': ONEARG; break;
case P('c','p'): ONEARG; break;
case P('R','D'): ONEARG; break;
case P('c','a'): /* Call rewriting trickery to avoid exponential behaviour */
ONEARG;
if (!i_same(f1->a2.p, f2->a2.p))
......
......@@ -146,6 +146,8 @@ void val_format(struct f_val v, buffer *buf);
#define T_ENUM_RTC 0x33
#define T_ENUM_RTD 0x34
#define T_ENUM_ROA 0x35
#define T_ENUM_NETTYPE 0x36
/* new enums go here */
#define T_ENUM_EMPTY 0x3f /* Special hack for atomic_aggr */
......@@ -162,6 +164,7 @@ void val_format(struct f_val v, buffer *buf);
#define T_ECLIST 0x27 /* Extended community list */
#define T_LC 0x28 /* Large community value, lcomm */
#define T_LCLIST 0x29 /* Large community list */
#define T_RD 0x2a /* Route distinguisher for VPN addresses */
#define T_RETURN 0x40
#define T_SET 0x80
......@@ -174,10 +177,9 @@ void val_format(struct f_val v, buffer *buf);
#define SA_PROTO 4
#define SA_SOURCE 5
#define SA_SCOPE 6
#define SA_CAST 7
#define SA_DEST 8
#define SA_IFNAME 9
#define SA_IFINDEX 10
#define SA_DEST 7
#define SA_IFNAME 8
#define SA_IFINDEX 9
struct f_tree {
......
......@@ -312,15 +312,18 @@ function t_ip()
ip p;
{
p = 127.1.2.3;
bt_assert(p.is_v4);
bt_assert(p.mask(8) = 127.0.0.0);
bt_assert(1.2.3.4 = 1.2.3.4);
bt_assert(1.2.3.4 = onetwo);
bt_assert(format(p) = "127.1.2.3");
p = ::fffe:6:c0c:936d:88c7:35d3;
bt_assert(!p.is_v4);
bt_assert(format(p) = "::fffe:6:c0c:936d:88c7:35d3");
p = 1234:5678::;
bt_assert(!p.is_v4);
bt_assert(p.mask(24) = 1234:5600::);
}
......@@ -444,8 +447,8 @@ function test_pxset(prefix set pxs)
function t_prefix_set()
prefix set pxs;
{
pxs = [ 1.2.0.0/16, 1.4.0.0/16+];
bt_assert(format(pxs) = "[1.2.0.0/112{::0.1.0.0}, 1.4.0.0/112{::0.1.255.255}]");
pxs = [ 1.2.0.0/16, 1.4.0.0/16+, 44.66.88.64/30{24,28}, 12.34.56.0/24{8,16} ];
bt_assert(format(pxs) = "[1.2.0.0/112{::0.1.0.0}, 1.4.0.0/112{::0.1.255.255}, 12.34.0.0/112{::1.255.0.0}, 44.66.88.64/124{::1f0}]");
bt_assert(1.2.0.0/16 ~ pxs);
bt_assert(1.4.0.0/16 ~ pxs);
bt_assert(1.4.0.0/18 ~ pxs);
......@@ -1165,12 +1168,20 @@ int j;
accept "ok I take that";
}
filter roa_filter
{
if net ~ [ 10.0.0.0/8{16,24}, 2000::/3{16,96} ] then {
accept;
}
reject;
}
roa4 table r4;
roa6 table r6;
protocol static
{
roa4 { table r4; };
roa4 { table r4; import filter roa_filter; };
route 10.110.0.0/16 max 16 as 1000 blackhole;
route 10.120.0.0/16 max 24 as 1000 blackhole ;
route 10.130.0.0/16 max 24 as 2000 blackhole;
......@@ -1179,66 +1190,124 @@ protocol static
protocol static
{
roa6 { table r6; };
roa6 { table r6; import filter roa_filter; };
route 2001:0db8:85a3:8a2e::/64 max 96 as 1000 blackhole;
}
function test_roa_check()
prefix pfx;
{
# cannot be tested in __startup(), sorry
print "Should be true: ", roa_check(r4, 10.10.0.0/16, 1000) = ROA_UNKNOWN,
" ", roa_check(r4, 10.0.0.0/8, 1000) = ROA_UNKNOWN,
" ", roa_check(r4, 10.110.0.0/16, 1000) = ROA_VALID,
" ", roa_check(r4, 10.110.0.0/16, 2000) = ROA_INVALID,
" ", roa_check(r4, 10.110.32.0/20, 1000) = ROA_INVALID,
" ", roa_check(r4, 10.120.32.0/20, 1000) = ROA_VALID;
print "Should be true: ", roa_check(r4, 10.120.32.0/20, 2000) = ROA_INVALID,
" ", roa_check(r4, 10.120.32.32/28, 1000) = ROA_INVALID,
" ", roa_check(r4, 10.130.130.0/24, 1000) = ROA_INVALID,
" ", roa_check(r4, 10.130.130.0/24, 2000) = ROA_VALID,
" ", roa_check(r4, 10.130.30.0/24, 3000) = ROA_INVALID,
" ", roa_check(r4, 10.130.130.0/24, 3000) = ROA_VALID;
print "Should be true: ", roa_check(r6, 2001:0db8:85a3:8a2e:1234::/80, 1000) = ROA_VALID,
" ", roa_check(r6, 2001:0db8:85a3:8a2e:1234::/97, 1000) = ROA_INVALID,
" ", roa_check(r6, 2001:0db8:85a3:8a2e::/64, 1000) = ROA_VALID,
" ", roa_check(r6, 2001:0db8:85a3::/48, 1000) = ROA_UNKNOWN;
print "Should be true: ", roa_check(r4, 10.10.0.0/16, 1000) = ROA_UNKNOWN,
" ", roa_check(r4, 10.0.0.0/8, 1000) = ROA_UNKNOWN,
" ", roa_check(r4, 10.110.0.0/16, 1000) = ROA_VALID,
" ", roa_check(r4, 10.110.0.0/16, 2000) = ROA_INVALID,
" ", roa_check(r4, 10.110.32.0/20, 1000) = ROA_INVALID,
" ", roa_check(r4, 10.120.32.0/20, 1000) = ROA_VALID;
print "Should be true: ", roa_check(r6, 2001:0db8:85a3:8a2e:1234::/80, 1000) = ROA_VALID,
" ", roa_check(r6, 2001:0db8:85a3:8a2e:1234::/97, 1000) = ROA_INVALID,
" ", roa_check(r6, 2001:0db8:85a3:8a2e::/64, 1000) = ROA_VALID,
" ", roa_check(r6, 2001:0db8:85a3::/48, 1000) = ROA_UNKNOWN;
print "Should be true: ", roa_check(r4, 2001:0db8:85a3:8a2e:1234::/97, 1000) = ROA_INVALID ||
roa_check(r6, 2001:0db8:85a3:8a2e:1234::/97, 1000) = ROA_INVALID;
print "Should be false: ", roa_check(r4, 2001:0db8:85a3:8a2e:1234::/80, 1000) = ROA_INVALID ||
roa_check(r6, 2001:0db8:85a3:8a2e:1234::/80, 1000) = ROA_INVALID,
" ", roa_check(r4, 2001:0db8:85a3::/48, 1000) = ROA_INVALID ||
roa_check(r6, 2001:0db8:85a3::/48, 1000) = ROA_INVALID;
print "Should be true: ", 10.130.130.0/24 ~ 0.0.0.0/0,
" ", 2001:0db8:85a3:8a2e::/64 ~ ::/0;
print "Should be false: ", 10.130.130.0/24 ~ ::/0,
" ", 2001:0db8:85a3:8a2e::/64 ~ 0.0.0.0/0;
bt_assert(roa_check(r4, 10.10.0.0/16, 1000) = ROA_UNKNOWN);
bt_assert(roa_check(r4, 10.0.0.0/8, 1000) = ROA_UNKNOWN);
bt_assert(roa_check(r4, 10.110.0.0/16, 1000) = ROA_VALID);
bt_assert(roa_check(r4, 10.110.0.0/16, 2000) = ROA_INVALID);
bt_assert(roa_check(r4, 10.110.32.0/20, 1000) = ROA_INVALID);
bt_assert(roa_check(r4, 10.120.32.0/20, 1000) = ROA_VALID);
bt_assert(roa_check(r4, 10.120.32.0/20, 2000) = ROA_INVALID);
bt_assert(roa_check(r4, 10.120.32.32/28, 1000) = ROA_INVALID);
bt_assert(roa_check(r4, 10.130.130.0/24, 1000) = ROA_INVALID);
bt_assert(roa_check(r4, 10.130.130.0/24, 2000) = ROA_VALID);
bt_assert(roa_check(r4, 10.130.30.0/24, 3000) = ROA_INVALID);
bt_assert(roa_check(r4, 10.130.130.0/24, 3000) = ROA_VALID);
bt_assert(roa_check(r6, 2001:0db8:85a3:8a2e:1234::/80, 1000) = ROA_VALID);
bt_assert(roa_check(r6, 2001:0db8:85a3:8a2e:1234::/97, 1000) = ROA_INVALID);
bt_assert(roa_check(r6, 2001:0db8:85a3:8a2e::/64, 1000) = ROA_VALID);
bt_assert(roa_check(r6, 2001:0db8:85a3::/48, 1000) = ROA_UNKNOWN);
bt_assert(roa_check(r4, 10.10.0.0/16, 1000) = ROA_UNKNOWN);
bt_assert(roa_check(r4, 10.0.0.0/8, 1000) = ROA_UNKNOWN);
bt_assert(roa_check(r4, 10.110.0.0/16, 1000) = ROA_VALID);
bt_assert(roa_check(r4, 10.110.0.0/16, 2000) = ROA_INVALID);
bt_assert(roa_check(r4, 10.110.32.0/20, 1000) = ROA_INVALID);
bt_assert(roa_check(r4, 10.120.32.0/20, 1000) = ROA_VALID);
bt_assert(roa_check(r6, 2001:0db8:85a3:8a2e:1234::/80, 1000) = ROA_VALID);
bt_assert(roa_check(r6, 2001:0db8:85a3:8a2e:1234::/97, 1000) = ROA_INVALID);
bt_assert(roa_check(r6, 2001:0db8:85a3:8a2e::/64, 1000) = ROA_VALID);
bt_assert(roa_check(r6, 2001:0db8:85a3::/48, 1000) = ROA_UNKNOWN);
bt_assert(roa_check(r4, 2001:0db8:85a3:8a2e:1234::/97, 1000) = ROA_UNKNOWN);
bt_assert(roa_check(r6, 2001:0db8:85a3:8a2e:1234::/97, 1000) = ROA_INVALID);
bt_assert(roa_check(r4, 2001:0db8:85a3:8a2e:1234::/80, 1000) = ROA_UNKNOWN);
bt_assert(roa_check(r6, 2001:0db8:85a3:8a2e:1234::/80, 1000) = ROA_VALID);
bt_assert(roa_check(r4, 2001:0db8:85a3::/48, 1000) = ROA_UNKNOWN);
bt_assert(roa_check(r6, 2001:0db8:85a3::/48, 1000) = ROA_UNKNOWN);
bt_assert(10.130.130.0/24 ~ 0.0.0.0/0);
bt_assert(2001:0db8:85a3:8a2e::/64 ~ ::/0);
bt_assert(10.130.130.0/24 !~ ::/0);
bt_assert(2001:0db8:85a3:8a2e::/64 !~ 0.0.0.0/0);
pfx = 12.13.0.0/16 max 24 as 1234;
bt_assert(pfx.len = 16);
bt_assert(pfx.maxlen = 24);
bt_assert(pfx.asn = 1234);
pfx = 1000::/8 max 32 as 1234;
bt_assert(pfx.len = 8);
bt_assert(pfx.maxlen = 32);
bt_assert(pfx.asn = 1234);
}
function roa_operators_test()
prefix pfx;
bt_test_suite(test_roa_check, "Testing ROA");
/*
* Testing Mixed Net Types
* -----------------------
*/
function t_mixed_prefix()
prefix set pxs;
prefix set pxt;
{
print "Testing ROA prefix operators '.maxlen' and '.asn':";
pxs = [ 98.45.0.0/16, 128.128.0.0/12+, 2200::/42-, ::ffff:d000:0/100{98,102}];
bt_assert(format(pxs) = "[::/0, ::/2{c000::}, 98.45.0.0/112{::0.1.0.0}, 128.128.0.0/108{::0.31.255.255}, 208.0.0.0/100{::124.0.0.0}, 2200::/42{ffff:ffff:ffc0::}]");
bt_assert(::fe00:0:0/88 !~ pxs);
bt_assert(::fffe:0:0/95 !~ pxs);
bt_assert(::ffff:d800:0/101 ~ pxs);
bt_assert(216.0.0.0/5 ~ pxs);
bt_assert(212.0.0.0/6 ~ pxs);
bt_assert(212.0.0.0/7 !~ pxs);
bt_assert(::ffff:8080:8080/121 ~ pxs);
bt_assert(::/0 ~ pxs);
bt_assert(0.0.0.0/0 !~ pxs);
bt_assert(128.135.64.17/32 ~ pxs);
# pxt = [ 0:1:2 10.1.10.0/24, 0:5:10000 10.1.10.0/24 ];
# print pxt;
bt_assert(format(NET_IP4) = "(enum 36)1"); ## if (net.type = NET_IP4) ...
bt_assert(format(NET_VPN6) = "(enum 36)4");
bt_assert(format(0:1:2) = "0:1:2");
}
pfx = 12.13.0.0/16 max 24 as 1234;
print pfx;
print "Should be true: ", pfx.len = 16, " ", pfx.maxlen = 24, " ", pfx.asn = 1234;
bt_test_suite(t_mixed_prefix, "Testing mixed net types");
pfx = 1000::/8 max 32 as 1234;
print pfx;
print "Should be true: ", pfx.len = 8, " ", pfx.maxlen = 32, " ", pfx.asn = 1234;
filter vpn_filter
{
bt_assert(format(net) = "0:1:2 10.1.10.0/24");
bt_assert(net.type = NET_VPN4);
bt_assert(net.type != NET_IP4);
bt_assert(net.type != NET_IP6);
bt_assert(net.rd = 0:1:2);
case (net.type) {
NET_IP4: print "IPV4";
NET_IP6: print "IPV6";
}
accept;
}
vpn4 table v4;
vpn4 table v6;
protocol static
{
vpn4 { table v4; import filter vpn_filter; };
route 0:1:2 10.1.10.0/24 unreachable;
}
......@@ -15,4 +15,6 @@
#include <stdlib.h>
#endif
#define allocz(len) ({ void *_x = alloca(len); memset(_x, 0, len); _x; })
#endif
......@@ -14,7 +14,7 @@
#include "sysdep/config.h"
#define BUFFER(type) struct { type *data; uint used, size; }
#define BUFFER_TYPE(v) typeof(* (v).data)
#define BUFFER_SIZE(v) ((v).size * sizeof(* (v).data))
#define BUFFER_INIT(v,pool,isize) \
......@@ -46,6 +46,9 @@
#define BUFFER_FLUSH(v) ({ (v).used = 0; })
#define BUFFER_WALK(v,n) \
for (BUFFER_TYPE(v) *_n = (v).data, n; _n < ((v).data + (v).used) && (n = *_n, 1); _n++)
#define BUFFER_SHALLOW_COPY(dst, src) \
({ \
(dst).used = (src).used; \
......
......@@ -133,6 +133,25 @@ t_buffer_flush(void)
return 1;
}
static int
t_buffer_walk(void)
{
int i;
init_buffer();
fill_expected_array();
for (i = 0; i < MAX_NUM; i++)
BUFFER_PUSH(buf) = expected[i];
i = 0;
BUFFER_WALK(buf, v)