From 126683feeda03ffb5a4ce23611e59a4598382d49 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Mon, 29 Mar 2010 19:29:03 +0200 Subject: Filter language updates; new route attributes and datatype. - Adds bgp_originator_id and bgp_cluster_list route attributes. - Adds dotted quad filter datatype (for router IDs, used by bgp_originator_id and ospf_router_id route attributes). - Fixes pair ~ pair set matching. - Documentation updates. --- doc/bird.sgml | 49 ++++++++++++++++++++++++----------- filter/config.Y | 9 +++++-- filter/filter.c | 74 +++++++++++++++++++++++++++++++++++++++++------------ filter/filter.h | 1 + filter/test.conf | 15 ++++++++++- proto/bgp/config.Y | 20 ++++++++++----- proto/ospf/config.Y | 2 +- proto/ospf/ospf.c | 10 ++++---- 8 files changed, 133 insertions(+), 47 deletions(-) diff --git a/doc/bird.sgml b/doc/bird.sgml index 6ad0690..43f0c9c 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -671,6 +671,11 @@ incompatible with each other (that is to prevent you from shooting in the foot). 65535. Literals of this type are written as 1.2.0.0/16.pxlen = 16 is true. - set int look like + but you can't modify them. Literals of type int set look like [ 1, 2, 5..7 ]. As you can see, both simple values and ranges are permitted in sets. @@ -756,15 +761,16 @@ incompatible with each other (that is to prevent you from shooting in the foot). and integer variables, for example [= * 4 (1+2) a =]. There is also old syntax that uses / .. / instead of [= .. =] and ? instead of *. - add( adds pair add( adds pair (or quad) delete( deletes pair delete( deletes pair (or quad) can be shortened to if Control structures @@ -818,6 +824,8 @@ if 1234 = i then printn "."; else { attributes just like it accesses variables. Attempts to access undefined attribute result in a runtime error; you can check if an attribute is defined by using the defined( attribute ) operator. +One notable exception to this rule are attributes of clist type, where +undefined value is regarded as empty clist for most purposes. @@ -1176,6 +1184,14 @@ with `quad This attribute is created by the + route reflector when reflecting the route and contains the router ID of the + originator of the route in the local AS. + + clist This attribute contains a list + of cluster IDs of route reflectors. Each route reflector prepends its + cluster ID when reflecting the route. Example @@ -1595,13 +1611,16 @@ External routes use Example diff --git a/filter/config.Y b/filter/config.Y index 1af5649..7723658 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -29,7 +29,7 @@ CF_DECLS CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, ACCEPT, REJECT, ERROR, QUITBIRD, - INT, BOOL, IP, PREFIX, PAIR, SET, STRING, BGPMASK, BGPPATH, CLIST, + INT, BOOL, IP, PREFIX, PAIR, QUAD, SET, STRING, BGPMASK, BGPPATH, CLIST, IF, THEN, ELSE, CASE, TRUE, FALSE, FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, PREFERENCE, @@ -75,6 +75,7 @@ type: | IP { $$ = T_IP; } | PREFIX { $$ = T_PREFIX; } | PAIR { $$ = T_PAIR; } + | QUAD { $$ = T_QUAD; } | STRING { $$ = T_STRING; } | BGPMASK { $$ = T_PATH_MASK; } | BGPPATH { $$ = T_PATH; } @@ -82,8 +83,9 @@ type: | type SET { switch ($1) { case T_INT: - case T_IP: case T_PAIR: + case T_QUAD: + case T_IP: $$ = T_SET; break; @@ -234,6 +236,7 @@ fipa: set_atom: NUM { $$.type = T_INT; $$.val.i = $1; } + | RTRID { $$.type = T_QUAD; $$.val.i = $1; } | cpair { $$.type = T_PAIR; $$.val.i = $1; } | fipa { $$ = $1; } | ENUM { $$.type = $1 >> 16; $$.val.i = $1 & 0xffff; } @@ -340,6 +343,7 @@ constant: | 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; } | fprefix_s {NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; } + | RTRID { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_QUAD; $$->a2.i = $1; } | '[' 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; } | ENUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; } @@ -396,6 +400,7 @@ symbol: case SYM_VARIABLE | T_BOOL: case SYM_VARIABLE | T_INT: case SYM_VARIABLE | T_PAIR: + case SYM_VARIABLE | T_QUAD: case SYM_VARIABLE | T_STRING: case SYM_VARIABLE | T_IP: case SYM_VARIABLE | T_PREFIX: diff --git a/filter/filter.c b/filter/filter.c index de7a97b..ae3b03a 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -65,6 +65,7 @@ pm_path_compare(struct f_path_mask *m1, struct f_path_mask *m2) if ((!m1) || (!m2)) return !((!m1) && (!m2)); + /* FIXME: buggy, should return -1, 0, 1; but it doesn't matter */ if ((m1->kind != m2->kind) || (m1->val != m2->val)) return 1; m1 = m1->next; m2 = m2->next; @@ -111,6 +112,13 @@ pm_format(struct f_path_mask *p, byte *buf, unsigned int size) *buf = 0; } +static inline int int_cmp(int i1, int i2) +{ + if (i1 == i2) return 0; + if (i1 < i2) return -1; + else return 1; +} + /** * val_compare - compare two values * @v1: first value @@ -133,6 +141,14 @@ val_compare(struct f_val v1, struct f_val v2) return 1; if (v1.type != v2.type) { +#ifndef IPV6 + /* IP->Quad implicit conversion */ + if ((v1.type == T_QUAD) && (v2.type == T_IP)) + return int_cmp(v1.val.i, ipa_to_u32(v2.val.px.ip)); + if ((v1.type == T_IP) && (v2.type == T_QUAD)) + return int_cmp(ipa_to_u32(v1.val.px.ip), v2.val.i); +#endif + debug( "Types do not match in val_compare\n" ); return CMP_ERROR; } @@ -141,9 +157,8 @@ val_compare(struct f_val v1, struct f_val v2) case T_INT: case T_BOOL: case T_PAIR: - if (v1.val.i == v2.val.i) return 0; - if (v1.val.i < v2.val.i) return -1; - return 1; + case T_QUAD: + return int_cmp(v1.val.i, v2.val.i); case T_IP: return ipa_compare(v1.val.px.ip, v2.val.px.ip); case T_PREFIX: @@ -196,8 +211,13 @@ val_simple_in_range(struct f_val v1, struct f_val v2) { if ((v1.type == T_PATH) && (v2.type == T_PATH_MASK)) return as_path_match(v1.val.ad, v2.val.path_mask); - if ((v1.type == T_PAIR) && (v2.type == T_CLIST)) + if (((v1.type == T_PAIR) || (v1.type == T_QUAD)) && (v2.type == T_CLIST)) return int_set_contains(v2.val.ad, v1.val.i); +#ifndef IPV6 + /* IP->Quad implicit conversion */ + if ((v1.type == T_IP) && (v2.type == T_CLIST)) + return int_set_contains(v2.val.ad, ipa_to_u32(v1.val.px.ip)); +#endif if ((v1.type == T_STRING) && (v2.type == T_STRING)) return patmatch(v2.val.s, v1.val.s); @@ -235,8 +255,9 @@ val_in_range(struct f_val v1, struct f_val v2) switch (v1.type) { case T_ENUM: case T_INT: + case T_PAIR: + case T_QUAD: case T_IP: - case T_PREFIX: { struct f_tree *n; n = find_tree(v2.val.t, v1); @@ -280,6 +301,7 @@ val_print(struct f_val v) case T_IP: PRINTF( "%I", v.val.px.ip ); break; case T_PREFIX: PRINTF( "%I/%d", v.val.px.ip, v.val.px.len ); break; case T_PAIR: PRINTF( "(%d,%d)", v.val.i >> 16, v.val.i & 0xffff ); break; + case T_QUAD: PRINTF( "%R", v.val.i ); break; case T_PREFIX_SET: trie_print(v.val.ti, buf, 2040); break; case T_SET: tree_print( v.val.t ); PRINTF( "\n" ); break; case T_ENUM: PRINTF( "(enum %x)%d", v.type, v.val.i ); break; @@ -355,7 +377,7 @@ static struct f_val interpret(struct f_inst *what) { struct symbol *sym; - struct f_val v1, v2, res; + struct f_val v1, v2, res, *vp; unsigned u1, u2; int i; u32 as; @@ -435,11 +457,11 @@ interpret(struct f_inst *what) /* Relational operators */ #define COMPARE(x) \ - TWOARGS_C; \ - res.type = T_BOOL; \ + TWOARGS; \ i = val_compare(v1, v2); \ if (i==CMP_ERROR) \ - runtime( "Error in comparison" ); \ + runtime( "Can't compare values of incompatible types" ); \ + res.type = T_BOOL; \ res.val.i = (x); \ break; @@ -473,10 +495,19 @@ interpret(struct f_inst *what) case 's': ARG(v2, a2.p); sym = what->a1.p; - if ((sym->class != (SYM_VARIABLE | v2.type)) && - (v2.type != T_VOID)) + vp = sym->def; + if ((sym->class != (SYM_VARIABLE | v2.type)) && (v2.type != T_VOID)) { +#ifndef IPV6 + /* IP->Quad implicit conversion */ + if ((sym->class == (SYM_VARIABLE | T_QUAD)) && (v2.type == T_IP)) { + vp->type = T_QUAD; + vp->val.i = ipa_to_u32(v2.val.px.ip); + break; + } +#endif runtime( "Assigning to variable of incompatible type" ); - * (struct f_val *) sym->def = v2; + } + *vp = v2; break; /* some constants have value in a2, some in *a1.p, strange. */ @@ -597,10 +628,13 @@ interpret(struct f_inst *what) switch (what->aux & EAF_TYPE_MASK) { case EAF_TYPE_INT: - case EAF_TYPE_ROUTER_ID: res.type = T_INT; res.val.i = e->u.data; break; + case EAF_TYPE_ROUTER_ID: + res.type = T_QUAD; + res.val.i = e->u.data; + break; case EAF_TYPE_OPAQUE: res.type = T_ENUM_EMPTY; res.val.i = 0; @@ -808,13 +842,21 @@ interpret(struct f_inst *what) v1.val.ad = adata_empty(f_pool); else if (v1.type != T_CLIST) runtime("Can't add/delete to non-clist"); - if (v2.type != T_PAIR) + + if ((v2.type == T_PAIR) || (v2.type == T_QUAD)) + i = v2.val.i; +#ifndef IPV6 + /* IP->Quad implicit conversion */ + else if (v2.type == T_IP) + i = ipa_to_u32(v2.val.px.ip); +#endif + else runtime("Can't add/delete non-pair"); res.type = T_CLIST; switch (what->aux) { - case 'a': res.val.ad = int_set_add(f_pool, v1.val.ad, v2.val.i); break; - case 'd': res.val.ad = int_set_del(f_pool, v1.val.ad, v2.val.i); break; + case 'a': res.val.ad = int_set_add(f_pool, v1.val.ad, i); break; + case 'd': res.val.ad = int_set_del(f_pool, v1.val.ad, i); break; default: bug("unknown Ca operation"); } break; diff --git a/filter/filter.h b/filter/filter.h index 11e0623..46dc1a2 100644 --- a/filter/filter.h +++ b/filter/filter.h @@ -115,6 +115,7 @@ void val_print(struct f_val v); #define T_INT 0x10 #define T_BOOL 0x11 #define T_PAIR 0x12 /* Notice that pair is stored as integer: first << 16 | second */ +#define T_QUAD 0x13 /* Put enumerational types in 0x30..0x3f range */ #define T_ENUM_LO 0x30 diff --git a/filter/test.conf b/filter/test.conf index 8eeb5c3..0483c3d 100644 --- a/filter/test.conf +++ b/filter/test.conf @@ -138,10 +138,12 @@ bool b; prefix px; ip p; pair pp; +quad qq; int set is; int set is1; int set is2; int set is3; +pair set ps; prefix set pxs; string s; { @@ -190,7 +192,18 @@ string s; pp = (1, 2); print "Testing pairs: (1,2) = ", (1,2), " = ", pp, " = ", (1,1+1), " = ", 'mkpair-a'(2); print " must be true: ", (1,2) = (1,1+1); - print "Testing enums: ", RTS_DUMMY, " ", RTS_STATIC; + print "Testing enums: ", RTS_DUMMY, " ", RTS_STATIC, " ", + ", true: ", RTS_STATIC ~ [RTS_STATIC, RTS_DEVICE], + ", false: ", RTS_BGP ~ [RTS_STATIC, RTS_DEVICE]; + + ps = [(1,2), (3,4)..(3,8)]; + print "Testing pair set (TTF):", pp ~ ps, " ", (3,5) ~ ps, " ", (3,9) ~ ps; + + qq = 1.2.3.4; + print "Testinq quad: 1.2.3.4 = ", qq, + ", true: ", qq = 1.2.3.4, " ", qq ~ [1.2.3.4, 5.6.7.8], + ", false: ", qq = 4.3.2.1, " ", qq ~ [1.2.1.1, 1.2.3.5]; + s = "Hello"; print "Testing string: ", s, " true: ", s ~ "Hell*", " false: ", s ~ "ell*"; diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index f882aaa..c4ed103 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -23,7 +23,8 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE, BGP_ATOMIC_AGGR, BGP_AGGREGATOR, BGP_COMMUNITY, SOURCE, ADDRESS, PASSWORD, RR, RS, CLIENT, CLUSTER, ID, AS4, ADVERTISE, IPV4, CAPABILITIES, LIMIT, PASSIVE, PREFER, OLDER, MISSING, LLADDR, - DROP, IGNORE, ROUTE, REFRESH, INTERPRET, COMMUNITIES) + DROP, IGNORE, ROUTE, REFRESH, INTERPRET, COMMUNITIES, + BGP_ORIGINATOR_ID, BGP_CLUSTER_LIST) CF_GRAMMAR @@ -90,22 +91,27 @@ bgp_proto: | bgp_proto INTERPRET COMMUNITIES bool ';' { BGP_CFG->interpret_communities = $4; } ; -CF_ADDTO(dynamic_attr, BGP_PATH - { $$ = f_new_dynamic_attr(EAF_TYPE_AS_PATH, T_PATH, EA_CODE(EAP_BGP, BA_AS_PATH)); }) -CF_ADDTO(dynamic_attr, BGP_LOCAL_PREF - { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(EAP_BGP, BA_LOCAL_PREF)); }) -CF_ADDTO(dynamic_attr, BGP_MED - { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(EAP_BGP, BA_MULTI_EXIT_DISC)); }) CF_ADDTO(dynamic_attr, BGP_ORIGIN { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_ENUM_BGP_ORIGIN, EA_CODE(EAP_BGP, BA_ORIGIN)); }) +CF_ADDTO(dynamic_attr, BGP_PATH + { $$ = f_new_dynamic_attr(EAF_TYPE_AS_PATH, T_PATH, EA_CODE(EAP_BGP, BA_AS_PATH)); }) CF_ADDTO(dynamic_attr, BGP_NEXT_HOP { $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, T_IP, EA_CODE(EAP_BGP, BA_NEXT_HOP)); }) +CF_ADDTO(dynamic_attr, BGP_MED + { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(EAP_BGP, BA_MULTI_EXIT_DISC)); }) +CF_ADDTO(dynamic_attr, BGP_LOCAL_PREF + { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(EAP_BGP, BA_LOCAL_PREF)); }) CF_ADDTO(dynamic_attr, BGP_ATOMIC_AGGR { $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, T_ENUM_EMPTY, EA_CODE(EAP_BGP, BA_ATOMIC_AGGR)); }) CF_ADDTO(dynamic_attr, BGP_AGGREGATOR { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(EAP_BGP, BA_AGGREGATOR)); }) CF_ADDTO(dynamic_attr, BGP_COMMUNITY { $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, T_CLIST, EA_CODE(EAP_BGP, BA_COMMUNITY)); }) +CF_ADDTO(dynamic_attr, BGP_ORIGINATOR_ID + { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, T_QUAD, EA_CODE(EAP_BGP, BA_ORIGINATOR_ID)); }) +CF_ADDTO(dynamic_attr, BGP_CLUSTER_LIST + { $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, T_CLIST, EA_CODE(EAP_BGP, BA_CLUSTER_LIST)); }) + CF_ENUM(T_ENUM_BGP_ORIGIN, ORIGIN_, IGP, EGP, INCOMPLETE) diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y index aeb8a0d..da7c97e 100644 --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@ -304,7 +304,7 @@ opttext: CF_ADDTO(dynamic_attr, OSPF_METRIC1 { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF_TEMP, T_INT, EA_OSPF_METRIC1); }) CF_ADDTO(dynamic_attr, OSPF_METRIC2 { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF_TEMP, T_INT, EA_OSPF_METRIC2); }) CF_ADDTO(dynamic_attr, OSPF_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF_TEMP, T_INT, EA_OSPF_TAG); }) -CF_ADDTO(dynamic_attr, OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF_TEMP, T_INT, EA_OSPF_ROUTER_ID); }) +CF_ADDTO(dynamic_attr, OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID | EAF_TEMP, T_QUAD, EA_OSPF_ROUTER_ID); }) CF_CLI(SHOW OSPF, optsym, [], [[Show information about OSPF protocol]]) { ospf_sh(proto_get_named($3, &proto_ospf)); }; diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index d345e49..5ed8abb 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -333,7 +333,7 @@ ospf_build_attrs(ea_list * next, struct linpool *pool, u32 m1, u32 m2, l->attrs[2].u.data = tag; l->attrs[3].id = EA_OSPF_ROUTER_ID; l->attrs[3].flags = 0; - l->attrs[3].type = EAF_TYPE_INT | EAF_TEMP; + l->attrs[3].type = EAF_TYPE_ROUTER_ID | EAF_TEMP; l->attrs[3].u.data = rid; return l; } @@ -598,11 +598,11 @@ ospf_get_attr(eattr * a, byte * buf, int buflen UNUSED) bsprintf(buf, "metric2"); return GA_NAME; case EA_OSPF_TAG: - bsprintf(buf, "tag: %08x (%u)", a->u.data, a->u.data); - return GA_FULL; - case EA_OSPF_ROUTER_ID: - bsprintf(buf, "router_id: %R (%u)", a->u.data, a->u.data); + bsprintf(buf, "tag: 0x%08x", a->u.data); return GA_FULL; + case EA_OSPF_ROUTER_ID: + bsprintf(buf, "router_id"); + return GA_NAME; default: return GA_UNKNOWN; } -- cgit v1.2.3