Commit 66dbdbd9 by Ondřej Zajíček

BGP: Support for large communities

Add support for large communities (draft-ietf-idr-large-community),
96bit alternative to RFC 1997 communities.

Thanks to Matt Griswold for the original patch.
parent f51b1f55
...@@ -36,6 +36,7 @@ f_valid_set_type(int type) ...@@ -36,6 +36,7 @@ f_valid_set_type(int type)
case T_ENUM: case T_ENUM:
case T_IP: case T_IP:
case T_EC: case T_EC:
case T_LC:
return 1; return 1;
default: default:
...@@ -148,6 +149,9 @@ f_generate_empty(struct f_inst *dyn) ...@@ -148,6 +149,9 @@ f_generate_empty(struct f_inst *dyn)
case EAF_TYPE_EC_SET: case EAF_TYPE_EC_SET:
e->aux = T_ECLIST; e->aux = T_ECLIST;
break; break;
case EAF_TYPE_LC_SET:
e->aux = T_LCLIST;
break;
default: default:
cf_error("Can't empty that attribute"); cf_error("Can't empty that attribute");
} }
...@@ -268,14 +272,44 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv) ...@@ -268,14 +272,44 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
return rv; return rv;
} }
static inline struct f_inst *
f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
{
struct f_inst *rv;
if ((t1->code == 'c') && (t2->code == 'c') && (t3->code == 'c')) {
if ((t1->aux != T_INT) || (t2->aux != T_INT) || (t3->aux != T_INT))
cf_error( "LC - Can't operate with value of non-integer type in tuple constructor");
rv = f_new_inst();
rv->code = 'C';
NEW_F_VAL;
rv->a1.p = val;
val->type = T_LC;
val->val.lc = (lcomm) { t1->a2.i, t2->a2.i, t3->a2.i };
}
else
{
rv = cfg_allocz(sizeof(struct f_inst3));
rv->lineno = ifs->lino;
rv->code = P('m','l');
rv->a1.p = t1;
rv->a2.p = t2;
INST3(rv).p = t3;
}
return rv;
}
CF_DECLS CF_DECLS
CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
ACCEPT, REJECT, ERROR, QUITBIRD, ACCEPT, REJECT, ERROR, QUITBIRD,
INT, BOOL, IP, PREFIX, PAIR, QUAD, EC, INT, BOOL, IP, PREFIX, PAIR, QUAD, EC, LC,
SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST,
IF, THEN, ELSE, CASE, IF, THEN, ELSE, CASE,
TRUE, FALSE, RT, RO, UNKNOWN, GENERIC, TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, IFNAME, IFINDEX, FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, IFNAME, IFINDEX,
...@@ -327,17 +361,20 @@ type: ...@@ -327,17 +361,20 @@ type:
| PAIR { $$ = T_PAIR; } | PAIR { $$ = T_PAIR; }
| QUAD { $$ = T_QUAD; } | QUAD { $$ = T_QUAD; }
| EC { $$ = T_EC; } | EC { $$ = T_EC; }
| LC { $$ = T_LC; }
| STRING { $$ = T_STRING; } | STRING { $$ = T_STRING; }
| BGPMASK { $$ = T_PATH_MASK; } | BGPMASK { $$ = T_PATH_MASK; }
| BGPPATH { $$ = T_PATH; } | BGPPATH { $$ = T_PATH; }
| CLIST { $$ = T_CLIST; } | CLIST { $$ = T_CLIST; }
| ECLIST { $$ = T_ECLIST; } | ECLIST { $$ = T_ECLIST; }
| LCLIST { $$ = T_LCLIST; }
| type SET { | type SET {
switch ($1) { switch ($1) {
case T_INT: case T_INT:
case T_PAIR: case T_PAIR:
case T_QUAD: case T_QUAD:
case T_EC: case T_EC:
case T_LC:
case T_IP: case T_IP:
$$ = T_SET; $$ = T_SET;
break; break;
...@@ -657,6 +694,7 @@ constant: ...@@ -657,6 +694,7 @@ constant:
constructor: constructor:
'(' term ',' term ')' { $$ = f_generate_dpair($2, $4); } '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); }
| '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); } | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); }
| '(' term ',' term ',' term ')' { $$ = f_generate_lc($2, $4, $6); }
; ;
...@@ -767,6 +805,7 @@ term: ...@@ -767,6 +805,7 @@ term:
| '+' EMPTY '+' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_PATH; } | '+' EMPTY '+' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_PATH; }
| '-' EMPTY '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_CLIST; } | '-' EMPTY '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_CLIST; }
| '-' '-' EMPTY '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_ECLIST; } | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_ECLIST; }
| '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_LCLIST; }
| PREPEND '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('A','p'); $$->a1.p = $3; $$->a2.p = $5; } | PREPEND '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('A','p'); $$->a1.p = $3; $$->a2.p = $5; }
| ADD '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; } | ADD '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; }
| DELETE '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; } | DELETE '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; }
......
...@@ -106,6 +106,18 @@ u64_cmp(u64 i1, u64 i2) ...@@ -106,6 +106,18 @@ u64_cmp(u64 i1, u64 i2)
return (int)(i1 > i2) - (int)(i1 < i2); return (int)(i1 > i2) - (int)(i1 < i2);
} }
static inline int
lcomm_cmp(lcomm v1, lcomm v2)
{
if (v1.asn != v2.asn)
return (v1.asn > v2.asn) ? 1 : -1;
if (v1.ldp1 != v2.ldp1)
return (v1.ldp1 > v2.ldp1) ? 1 : -1;
if (v1.ldp2 != v2.ldp2)
return (v1.ldp2 > v2.ldp2) ? 1 : -1;
return 0;
}
/** /**
* val_compare - compare two values * val_compare - compare two values
* @v1: first value * @v1: first value
...@@ -149,6 +161,8 @@ val_compare(struct f_val v1, struct f_val v2) ...@@ -149,6 +161,8 @@ val_compare(struct f_val v1, struct f_val v2)
return uint_cmp(v1.val.i, v2.val.i); return uint_cmp(v1.val.i, v2.val.i);
case T_EC: case T_EC:
return u64_cmp(v1.val.ec, v2.val.ec); return u64_cmp(v1.val.ec, v2.val.ec);
case T_LC:
return lcomm_cmp(v1.val.lc, v2.val.lc);
case T_IP: case T_IP:
return ipa_compare(v1.val.px.ip, v2.val.px.ip); return ipa_compare(v1.val.px.ip, v2.val.px.ip);
case T_PREFIX: case T_PREFIX:
...@@ -214,6 +228,7 @@ val_same(struct f_val v1, struct f_val v2) ...@@ -214,6 +228,7 @@ val_same(struct f_val v1, struct f_val v2)
case T_PATH: case T_PATH:
case T_CLIST: case T_CLIST:
case T_ECLIST: case T_ECLIST:
case T_LCLIST:
return adata_same(v1.val.ad, v2.val.ad); return adata_same(v1.val.ad, v2.val.ad);
case T_SET: case T_SET:
return same_tree(v1.val.t, v2.val.t); return same_tree(v1.val.t, v2.val.t);
...@@ -266,6 +281,10 @@ static inline int ...@@ -266,6 +281,10 @@ static inline int
eclist_set_type(struct f_tree *set) eclist_set_type(struct f_tree *set)
{ return set->from.type == T_EC; } { return set->from.type == T_EC; }
static inline int
lclist_set_type(struct f_tree *set)
{ return set->from.type == T_LC; }
static int static int
clist_match_set(struct adata *clist, struct f_tree *set) clist_match_set(struct adata *clist, struct f_tree *set)
{ {
...@@ -311,6 +330,30 @@ eclist_match_set(struct adata *list, struct f_tree *set) ...@@ -311,6 +330,30 @@ eclist_match_set(struct adata *list, struct f_tree *set)
return 0; return 0;
} }
static int
lclist_match_set(struct adata *list, struct f_tree *set)
{
if (!list)
return 0;
if (!lclist_set_type(set))
return CMP_ERROR;
struct f_val v;
u32 *l = int_set_get_data(list);
int len = int_set_get_size(list);
int i;
v.type = T_LC;
for (i = 0; i < len; i += 3) {
v.val.lc = lc_get(l, i);
if (find_tree(set, v))
return 1;
}
return 0;
}
static struct adata * static struct adata *
clist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos) clist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos)
{ {
...@@ -380,6 +423,38 @@ eclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int po ...@@ -380,6 +423,38 @@ eclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int po
return res; return res;
} }
static struct adata *
lclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos)
{
if (!list)
return NULL;
int tree = (set.type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
struct f_val v;
int len = int_set_get_size(list);
u32 *l = int_set_get_data(list);
u32 tmp[len];
u32 *k = tmp;
int i;
v.type = T_LC;
for (i = 0; i < len; i += 3) {
v.val.lc = lc_get(l, i);
/* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
if ((tree ? !!find_tree(set.val.t, v) : lc_set_contains(set.val.ad, v.val.lc)) == pos)
k = lc_copy(k, l+i);
}
int nl = (k - tmp) * 4;
if (nl == list->length)
return list;
struct adata *res = adata_empty(pool, nl);
memcpy(res->data, tmp, nl);
return res;
}
/** /**
* val_in_range - implement |~| operator * val_in_range - implement |~| operator
* @v1: element * @v1: element
...@@ -407,6 +482,9 @@ val_in_range(struct f_val v1, struct f_val v2) ...@@ -407,6 +482,9 @@ val_in_range(struct f_val v1, struct f_val v2)
if ((v1.type == T_EC) && (v2.type == T_ECLIST)) if ((v1.type == T_EC) && (v2.type == T_ECLIST))
return ec_set_contains(v2.val.ad, v1.val.ec); return ec_set_contains(v2.val.ad, v1.val.ec);
if ((v1.type == T_LC) && (v2.type == T_LCLIST))
return lc_set_contains(v2.val.ad, v1.val.lc);
if ((v1.type == T_STRING) && (v2.type == T_STRING)) if ((v1.type == T_STRING) && (v2.type == T_STRING))
return patmatch(v2.val.s, v1.val.s); return patmatch(v2.val.s, v1.val.s);
...@@ -433,6 +511,9 @@ val_in_range(struct f_val v1, struct f_val v2) ...@@ -433,6 +511,9 @@ val_in_range(struct f_val v1, struct f_val v2)
if (v1.type == T_ECLIST) if (v1.type == T_ECLIST)
return eclist_match_set(v1.val.ad, v2.val.t); return eclist_match_set(v1.val.ad, v2.val.t);
if (v1.type == T_LCLIST)
return lclist_match_set(v1.val.ad, v2.val.t);
if (v1.type == T_PATH) if (v1.type == T_PATH)
return as_path_match_set(v1.val.ad, v2.val.t); return as_path_match_set(v1.val.ad, v2.val.t);
...@@ -457,12 +538,14 @@ val_format(struct f_val v, buffer *buf) ...@@ -457,12 +538,14 @@ val_format(struct f_val v, buffer *buf)
case T_PAIR: buffer_print(buf, "(%u,%u)", v.val.i >> 16, v.val.i & 0xffff); return; case T_PAIR: buffer_print(buf, "(%u,%u)", v.val.i >> 16, v.val.i & 0xffff); return;
case T_QUAD: buffer_print(buf, "%R", v.val.i); return; 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_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_PREFIX_SET: trie_format(v.val.ti, buf); return; case T_PREFIX_SET: trie_format(v.val.ti, buf); return;
case T_SET: tree_format(v.val.t, 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; case T_ENUM: buffer_print(buf, "(enum %x)%u", v.type, v.val.i); return;
case T_PATH: as_path_format(v.val.ad, buf2, 1000); buffer_print(buf, "(path %s)", buf2); return; case T_PATH: as_path_format(v.val.ad, buf2, 1000); buffer_print(buf, "(path %s)", buf2); return;
case T_CLIST: int_set_format(v.val.ad, 1, -1, buf2, 1000); buffer_print(buf, "(clist %s)", buf2); return; case T_CLIST: int_set_format(v.val.ad, 1, -1, buf2, 1000); buffer_print(buf, "(clist %s)", buf2); return;
case T_ECLIST: ec_set_format(v.val.ad, -1, buf2, 1000); buffer_print(buf, "(eclist %s)", buf2); return; case T_ECLIST: ec_set_format(v.val.ad, -1, buf2, 1000); buffer_print(buf, "(eclist %s)", buf2); return;
case T_LCLIST: lc_set_format(v.val.ad, -1, buf2, 1000); buffer_print(buf, "(lclist %s)", buf2); return;
case T_PATH_MASK: pm_format(v.val.path_mask, buf); return; case T_PATH_MASK: pm_format(v.val.path_mask, buf); return;
default: buffer_print(buf, "[unknown type %x]", v.type); return; default: buffer_print(buf, "[unknown type %x]", v.type); return;
} }
...@@ -656,6 +739,7 @@ interpret(struct f_inst *what) ...@@ -656,6 +739,7 @@ interpret(struct f_inst *what)
runtime("Can't operate with value of non-integer type in EC constructor"); runtime("Can't operate with value of non-integer type in EC constructor");
val = v2.val.i; val = v2.val.i;
/* XXXX */
res.type = T_EC; res.type = T_EC;
if (what->aux == EC_GENERIC) { if (what->aux == EC_GENERIC) {
...@@ -677,6 +761,24 @@ interpret(struct f_inst *what) ...@@ -677,6 +761,24 @@ interpret(struct f_inst *what)
break; break;
} }
case P('m','l'):
{
TWOARGS;
/* Third argument hack */
struct f_val v3 = interpret(INST3(what).p);
if (v3.type & T_RETURN)
return v3;
if ((v1.type != T_INT) || (v2.type != T_INT) || (v3.type != T_INT))
runtime( "Can't operate with value of non-integer type in LC constructor" );
res.type = T_LC;
res.val.lc = (lcomm) { v1.val.i, v2.val.i, v3.val.i };
break;
}
/* Relational operators */ /* Relational operators */
#define COMPARE(x) \ #define COMPARE(x) \
...@@ -912,6 +1014,13 @@ interpret(struct f_inst *what) ...@@ -912,6 +1014,13 @@ interpret(struct f_inst *what)
break; break;
} }
/* The same special case for lc_set */
if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_LC_SET) {
res.type = T_LCLIST;
res.val.ad = adata_empty(f_pool, 0);
break;
}
/* Undefined value */ /* Undefined value */
res.type = T_VOID; res.type = T_VOID;
break; break;
...@@ -951,6 +1060,10 @@ interpret(struct f_inst *what) ...@@ -951,6 +1060,10 @@ interpret(struct f_inst *what)
res.type = T_ECLIST; res.type = T_ECLIST;
res.val.ad = e->u.ptr; res.val.ad = e->u.ptr;
break; break;
case EAF_TYPE_LC_SET:
res.type = T_LCLIST;
res.val.ad = e->u.ptr;
break;
case EAF_TYPE_UNDEF: case EAF_TYPE_UNDEF:
res.type = T_VOID; res.type = T_VOID;
break; break;
...@@ -1041,6 +1154,11 @@ interpret(struct f_inst *what) ...@@ -1041,6 +1154,11 @@ interpret(struct f_inst *what)
runtime( "Setting eclist attribute to non-eclist value" ); runtime( "Setting eclist attribute to non-eclist value" );
l->attrs[0].u.ptr = v1.val.ad; l->attrs[0].u.ptr = v1.val.ad;
break; break;
case EAF_TYPE_LC_SET:
if (v1.type != T_LCLIST)
runtime( "Setting lclist attribute to non-lclist value" );
l->attrs[0].u.ptr = v1.val.ad;
break;
case EAF_TYPE_UNDEF: case EAF_TYPE_UNDEF:
if (v1.type != T_VOID) if (v1.type != T_VOID)
runtime( "Setting void attribute to non-void value" ); runtime( "Setting void attribute to non-void value" );
...@@ -1082,6 +1200,7 @@ interpret(struct f_inst *what) ...@@ -1082,6 +1200,7 @@ interpret(struct f_inst *what)
case T_PATH: res.val.i = as_path_getlen(v1.val.ad); break; case T_PATH: res.val.i = as_path_getlen(v1.val.ad); break;
case T_CLIST: res.val.i = int_set_get_size(v1.val.ad); break; case T_CLIST: res.val.i = int_set_get_size(v1.val.ad); break;
case T_ECLIST: res.val.i = ec_set_get_size(v1.val.ad); break; case T_ECLIST: res.val.i = ec_set_get_size(v1.val.ad); break;
case T_LCLIST: res.val.i = lc_set_get_size(v1.val.ad); break;
default: runtime( "Prefix, path, clist or eclist expected" ); default: runtime( "Prefix, path, clist or eclist expected" );
} }
break; break;
...@@ -1277,7 +1396,7 @@ interpret(struct f_inst *what) ...@@ -1277,7 +1396,7 @@ interpret(struct f_inst *what)
else if (v2.type == T_ECLIST) else if (v2.type == T_ECLIST)
arg_set = 2; arg_set = 2;
else if (v2.type != T_EC) else if (v2.type != T_EC)
runtime("Can't add/delete non-pair"); runtime("Can't add/delete non-ec");
res.type = T_ECLIST; res.type = T_ECLIST;
switch (what->aux) switch (what->aux)
...@@ -1308,8 +1427,50 @@ interpret(struct f_inst *what) ...@@ -1308,8 +1427,50 @@ interpret(struct f_inst *what)
bug("unknown Ca operation"); bug("unknown Ca operation");
} }
} }
else if (v1.type == T_LCLIST)
{
/* Large community list */
int arg_set = 0;
/* v2.val is either LC or LC-set */
if ((v2.type == T_SET) && lclist_set_type(v2.val.t))
arg_set = 1;
else if (v2.type == T_LCLIST)
arg_set = 2;
else if (v2.type != T_LC)
runtime("Can't add/delete non-lc");
res.type = T_LCLIST;
switch (what->aux)
{
case 'a':
if (arg_set == 1)
runtime("Can't add set");
else if (!arg_set)
res.val.ad = lc_set_add(f_pool, v1.val.ad, v2.val.lc);
else
res.val.ad = lc_set_union(f_pool, v1.val.ad, v2.val.ad);
break;
case 'd':
if (!arg_set)
res.val.ad = lc_set_del(f_pool, v1.val.ad, v2.val.lc);
else
res.val.ad = lclist_filter(f_pool, v1.val.ad, v2, 0);
break;
case 'f':
if (!arg_set)
runtime("Can't filter lc");
res.val.ad = lclist_filter(f_pool, v1.val.ad, v2, 1);
break;
default:
bug("unknown Ca operation");
}
}
else else
runtime("Can't add/delete to non-(e)clist"); runtime("Can't add/delete to non-[e|l]clist");
break; break;
...@@ -1401,6 +1562,12 @@ i_same(struct f_inst *f1, struct f_inst *f2) ...@@ -1401,6 +1562,12 @@ i_same(struct f_inst *f1, struct f_inst *f2)
case '~': TWOARGS; break; case '~': TWOARGS; break;
case P('d','e'): ONEARG; break; case P('d','e'): ONEARG; break;
case P('m','l'):
TWOARGS;
if (!i_same(INST3(f1).p, INST3(f2).p))
return 0;
break;
case 's': case 's':
ARG(v2, a2.p); ARG(v2, a2.p);
{ {
......
...@@ -38,6 +38,17 @@ struct f_inst_roa_check { ...@@ -38,6 +38,17 @@ struct f_inst_roa_check {
struct roa_table_config *rtc; struct roa_table_config *rtc;
}; };
struct f_inst3 {
struct f_inst i;
union {
int i;
void *p;
} a3;
};
#define INST3(x) (((struct f_inst3 *) x)->a3)
struct f_prefix { struct f_prefix {
ip_addr ip; ip_addr ip;
int len; int len;
...@@ -53,6 +64,7 @@ struct f_val { ...@@ -53,6 +64,7 @@ struct f_val {
union { union {
uint i; uint i;
u64 ec; u64 ec;
lcomm lc;
/* ip_addr ip; Folded into prefix */ /* ip_addr ip; Folded into prefix */
struct f_prefix px; struct f_prefix px;
char *s; char *s;
...@@ -168,8 +180,10 @@ void val_format(struct f_val v, buffer *buf); ...@@ -168,8 +180,10 @@ void val_format(struct f_val v, buffer *buf);
#define T_PATH_MASK 0x23 /* mask for BGP path */ #define T_PATH_MASK 0x23 /* mask for BGP path */
#define T_PATH 0x24 /* BGP path */ #define T_PATH 0x24 /* BGP path */
#define T_CLIST 0x25 /* Community list */ #define T_CLIST 0x25 /* Community list */
#define T_ECLIST 0x26 /* Extended community list */ #define T_EC 0x26 /* Extended community value, u64 */
#define T_EC 0x27 /* Extended community value, u64 */ #define T_ECLIST 0x27 /* Extended community list */
#define T_LC 0x28 /* Large community value, lcomm */
#define T_LCLIST 0x29 /* Large community list */
#define T_RETURN 0x40 #define T_RETURN 0x40
#define T_SET 0x80 #define T_SET 0x80
......
...@@ -27,6 +27,11 @@ function 'mkpair-a'(int a) ...@@ -27,6 +27,11 @@ function 'mkpair-a'(int a)
return (1, a); return (1, a);
} }
function mktrip(int a)
{
return (a, 2*a, 3*a);
}
function mkpath(int a; int b) function mkpath(int a; int b)
{ {
return [= a b 3 2 1 =]; return [= a b 3 2 1 =];
...@@ -89,6 +94,7 @@ clist l; ...@@ -89,6 +94,7 @@ clist l;
clist l2; clist l2;
eclist el; eclist el;
eclist el2; eclist el2;
lclist ll;
{ {
print "Entering path test..."; print "Entering path test...";
pm1 = / 4 3 2 1 /; pm1 = / 4 3 2 1 /;
...@@ -203,6 +209,17 @@ eclist el2; ...@@ -203,6 +209,17 @@ eclist el2;
print "eclist A isect B: ", filter( el, el2 ); print "eclist A isect B: ", filter( el, el2 );
print "eclist A \ B: ", delete( el, el2 ); print "eclist A \ B: ", delete( el, el2 );
ll = --- empty ---;
ll = add(ll, (ten, 20, 30));
ll = add(ll, (1000, 2000, 3000));
ll = add(ll, mktrip(100000));
print "LC list (10, 20, 30) (1000, 2000, 3000) (100000, 200000, 300000):";
print ll;
print "LC len: ", el.len;
print "Should be true: ", mktrip(1000) ~ ll, " ", ll ~ [(5,10,15), (10,20,30)], " ", ll ~ [(10,15..25,*)], " ", ll ~ [(ten, *, *)];
print "Should be false: ", mktrip(100) ~ ll, " ", ll ~ [(5,10,15), (10,21,30)], " ", ll ~ [(10,21..25,*)], " ", ll ~ [(11, *, *)];
print "LC filtered: ", filter(ll, [(5..15, *, *), (100000, 500..500000, *)]);
# test_roa(); # test_roa();
} }
......
...@@ -116,7 +116,7 @@ int ...@@ -116,7 +116,7 @@ int
ec_set_format(struct adata *set, int from, byte *buf, uint size) ec_set_format(struct adata *set, int from, byte *buf, uint size)
{ {
u32 *z = int_set_get_data(set); u32 *z = int_set_get_data(set);
byte *end = buf + size - 24; byte *end = buf + size - 64;
int from2 = MAX(from, 0); int from2 = MAX(from, 0);
int to = int_set_get_size(set); int to = int_set_get_size(set);
int i; int i;
...@@ -142,6 +142,43 @@ ec_set_format(struct adata *set, int from, byte *buf, uint size) ...@@ -142,6 +142,43 @@ ec_set_format(struct adata *set, int from, byte *buf, uint size)
} }
int int
lc_format(byte *buf, lcomm lc)
{
return bsprintf(buf, "(%d, %d, %d)", lc.asn, lc.ldp1, lc.ldp2);
}
int
lc_set_format(struct adata *set, int from, byte *buf, uint bufsize)
{
u32 *d = (u32 *) set->data;
byte *end = buf + bufsize - 64;
int from2 = MAX(from, 0);
int to = set->length / 4;
int i;
for (i = from2; i < to; i += 3)
{
if (buf > end)
{
if (from < 0)
strcpy(buf, "...");
else
buf[-1] = 0;
return i;
}
buf += bsprintf(buf, "(%d, %d, %d)", d[i], d[i+1], d[i+2]);
*buf++ = ' ';
}
if (i != from2)
buf--;
*buf = 0;
return 0;
}
int
int_set_contains(struct adata *list, u32 val) int_set_contains(struct adata *list, u32 val)
{ {
if (!list) if (!list)
...@@ -177,6 +214,24 @@ ec_set_contains(struct adata *list, u64 val) ...@@ -177,6 +214,24 @@ ec_set_contains(struct adata *list, u64 val)
return 0; return 0;
} }
int
lc_set_contains(struct adata *list, lcomm val)
{
if (!list)
return 0;
u32 *l = int_set_get_data(list);
int len = int_set_get_size(list);
int i;
for (i = 0; i < len; i += 3)
if (lc_match(l, i, val))
return 1;
return 0;
}
struct adata * struct adata *
int_set_add(struct linpool *pool, struct adata *list, u32 val) int_set_add(struct linpool *pool, struct adata *list, u32 val)
{ {
...@@ -208,13 +263,30 @@ ec_set_add(struct linpool *pool, struct adata *list, u64 val) ...@@ -208,13 +263,30 @@ ec_set_add(struct linpool *pool, struct adata *list, u64 val)
if (list) if (list)
memcpy(res->data, list->data, list->length); memcpy(res->data, list->data, list->length);
u32 *l = (u32 *) (res->data + res->length - 8); u32 *l = (u32 *) (res->data + olen);
l[0] = ec_hi(val); l[0] = ec_hi(val);
l[1] = ec_lo(val); l[1] = ec_lo(val);
return res; return res;
} }
struct adata *
lc_set_add(struct linpool *pool, struct adata *list, lcomm val)
{
if (lc_set_contains(list, val))
return list;
int olen = list ? list->length : 0;