]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Filter language updates; new route attributes and datatype.
authorOndrej Zajicek <santiago@crfreenet.org>
Mon, 29 Mar 2010 17:29:03 +0000 (19:29 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Mon, 29 Mar 2010 17:29:03 +0000 (19:29 +0200)
 - 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
filter/config.Y
filter/filter.c
filter/filter.h
filter/test.conf
proto/bgp/config.Y
proto/ospf/config.Y
proto/ospf/ospf.c

index 6ad06909708f9364cdaf1d82e04bcf3accd99138..43f0c9c6249b3972748ad74dbaacd7f83e0b63e1 100644 (file)
@@ -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/&tilde;/ 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
 
index 1af5649c96661420900b4d8bc445ba97018024f1..7723658612c39daa8010986615521a8edeca56de 100644 (file)
@@ -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:
index de7a97bc625c9e732663071638bb08ac6c2b3365..ae3b03ab44de3d06fbaccb6c33845d41a796db4e 100644 (file)
@@ -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;
index 11e0623af8ad208784c9a3a6c529304568946a9b..46dc1a23fe00a18901c1cc693bce2e6a067b0752 100644 (file)
@@ -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
index 8eeb5c355426cbf4a37e2d1771fde3577f36919d..0483c3d90f985db6ebaa54f4d0ec3ef5ce774959 100644 (file)
@@ -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*";
index f882aaa50ea36275fc532f11c599b0c374e79b45..c4ed1032604acc3ac72c470482545795e848d95d 100644 (file)
@@ -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)
 
index aeb8a0dfe05091411c69a754c9100eccc850cf58..da7c97e2759490bf93961ee1c81a3ded37d748bb 100644 (file)
@@ -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)); };
index d345e49b98fedacb24940a1dbaad2ba2050e4fd8..5ed8abb10c9a41655afabc2c8d1b687dfe770d22 100644 (file)
@@ -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;
   }