diff options
-rw-r--r-- | doc/bird.sgml | 49 | ||||
-rw-r--r-- | filter/config.Y | 9 | ||||
-rw-r--r-- | filter/filter.c | 74 | ||||
-rw-r--r-- | filter/filter.h | 1 | ||||
-rw-r--r-- | filter/test.conf | 15 | ||||
-rw-r--r-- | proto/bgp/config.Y | 20 | ||||
-rw-r--r-- | proto/ospf/config.Y | 2 | ||||
-rw-r--r-- | proto/ospf/ospf.c | 10 |
8 files changed, 133 insertions, 47 deletions
diff --git a/doc/bird.sgml b/doc/bird.sgml index 6ad06909..43f0c9c6 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 <cf/(1234,5678)/. The same syntax can also be used to construct a pair from two arbitrary integer expressions (for example <cf/(1+2,a)/). + <tag/quad/ This is a dotted quad of numbers used to represent + router IDs (and others). Each component can have a value + from 0 to 255. Literals of this type are written like IPv4 + addresses. + <tag/string/ This is a string of characters. There are no ways to modify strings in filters. You can pass them between functions, assign them to variables of type <cf/string/, print such variables, but you can't concatenate two strings. String literals @@ -688,9 +693,9 @@ incompatible with each other (that is to prevent you from shooting in the foot). <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.pxlen = 16</cf> is true. - <tag/int|ip|prefix|pair|enum set/ + <tag/int|pair|quad|ip|prefix|enum set/ Filters recognize four types of sets. Sets are similar to strings: you can pass them around - but you can't modify them. Literals of type <cf>set int</cf> look like <cf> + but you can't modify them. Literals of type <cf>int set</cf> look like <cf> [ 1, 2, 5..7 ]</cf>. 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 <tt>[= * 4 (1+2) a =]</tt>. There is also old syntax that uses / .. / instead of [= .. =] and ? instead of *. - <tag/clist/ - Community list is similar to set of pairs, - except that unlike other sets, it can be modified. - There exist no literals of this type. - There are two special operators on clists: + <tag/clist/ + Clist is similar to a set, except that unlike other sets, it + can be modified. The type is used for community list (a set + of pairs) and for cluster list (a set of quads). There exist + no literals of this type. There are two special operators on + clists: - <cf>add(<m/C/,<m/P/)</cf> adds pair <m/P/ to clist <m/C/ and returns the result. + <cf>add(<m/C/,<m/P/)</cf> adds pair (or quad) <m/P/ to clist <m/C/ and returns the result. - <cf>delete(<m/C/,<m/P/)</cf> deletes pair <m/P/ from clist <m/C/ and returns the result. + <cf>delete(<m/C/,<m/P/)</cf> deletes pair (or quad) <m/P/ from clist <m/C/ and returns the result. Statement <cf><m/C/ = add(<m/C/, <m/P/);</cf> can be shortened to <cf><m/C/.add(<m/P/);</cf> if <m/C/ is appropriate route attribute @@ -779,7 +785,7 @@ incompatible with each other (that is to prevent you from shooting in the foot). Special operators include <cf/˜/ for "is element of a set" operation - it can be used on element and set of elements of the same type (returning true if element is contained in the given set), or on two strings (returning true if first string matches a shell-like pattern stored in second string) or on IP and prefix (returning true if IP is within the range defined by that prefix), or on -prefix and prefix (returning true if first prefix is more specific than second one) or on bgppath and bgpmask (returning true if the path matches the mask) or on pair and clist (returning true if the community is element of the community list). +prefix and prefix (returning true if first prefix is more specific than second one) or on bgppath and bgpmask (returning true if the path matches the mask) or on pair and clist (returning true if the pair (or quad) is element of the clist). <sect>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 <cf>defined( <m>attribute</m> )</cf> operator. +One notable exception to this rule are attributes of clist type, where +undefined value is regarded as empty clist for most purposes. <descrip> <tag><m/prefix/ net</tag> @@ -1176,6 +1184,14 @@ with `<tt/O/') are optional. policy information like "don't export to USA peers". As each AS can define its own routing policy, it also has a complete freedom about which community attributes it defines and what will their semantics be. + + <tag>quad <cf/bgp_originator_id/ [O]</tag> 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. + + <tag>clist <cf/bgp_cluster_list/ [O]</tag> This attribute contains a list + of cluster IDs of route reflectors. Each route reflector prepends its + cluster ID when reflecting the route. </descrip> <sect1>Example @@ -1595,13 +1611,16 @@ External routes use <cf/metric type 1/ or <cf/metric type 2/. A <cf/metric of type 1/ is comparable with internal <cf/metric/, a <cf/metric of type 2/ is always longer than any <cf/metric of type 1/ or any <cf/internal metric/. +<cf/Internal metric/ or <cf/metric of type 1/ is stored in attribute +<cf/ospf_metric1/, <cf/metric type 2/ is stored in attribute <cf/ospf_metric2/. If you specify both metrics only metric1 is used. -Each external route can also carry a <cf/tag/ which is a 32-bit -integer which is used when exporting routes to other protocols; + +Each external route can also carry attribute <cf/ospf_tag/ which is a +32-bit integer which is used when exporting routes to other protocols; otherwise, it doesn't affect routing inside the OSPF domain at all. -The fourth attribute is a <cf/router_id/ of the router advertising -that route/network. This attribute is read-only. -Default is <cf/metric of type 2 = 10000/ and <cf/tag = 0/. +The fourth attribute <cf/ospf_router_id/ is a router ID of the router +advertising that route/network. This attribute is read-only. Default +is <cf/ospf_metric2 = 10000/ and <cf/ospf_tag = 0/. <sect1>Example diff --git a/filter/config.Y b/filter/config.Y index 1af5649c..77236586 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 de7a97bc..ae3b03ab 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 11e0623a..46dc1a23 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 8eeb5c35..0483c3d9 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 f882aaa5..c4ed1032 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 aeb8a0df..da7c97e2 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, [<name>], [[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 d345e49b..5ed8abb1 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; } |