]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Merge commit 'origin/bfd'
authorOndrej Zajicek <santiago@crfreenet.org>
Fri, 22 Nov 2013 01:43:41 +0000 (02:43 +0100)
committerOndrej Zajicek <santiago@crfreenet.org>
Fri, 22 Nov 2013 01:48:44 +0000 (02:48 +0100)
34 files changed:
client/birdc.c
client/birdcl.c
client/client.c
conf/cf-lex.l
doc/bird.sgml
filter/config.Y
filter/filter.c
filter/filter.h
filter/test.conf
filter/tree.c
filter/trie.c
lib/birdlib.h
nest/a-path.c
nest/attrs.h
nest/config.Y
nest/neighbor.c
nest/proto.c
nest/route.h
nest/rt-attr.c
nest/rt-dev.c
nest/rt-table.c
proto/bgp/attrs.c
proto/bgp/bgp.h
proto/bgp/config.Y
proto/ospf/config.Y
proto/ospf/hello.c
proto/ospf/lsupd.c
sysdep/bsd/krt-sock.c
sysdep/cf/bsd-v6.h
sysdep/cf/bsd.h
sysdep/linux/netlink.c
sysdep/unix/io.c
sysdep/unix/krt.c
sysdep/unix/main.c

index 9dd6d9b9aef2be686baf4777e8a15edd3c495946..bbe18331bda8be1203aa0e7101a9072a8ff90aa9 100644 (file)
@@ -148,8 +148,8 @@ input_init(void)
   rl_callback_handler_install("bird> ", input_got_line);
 
   // rl_get_screen_size();
-  term_lns = LINES ? LINES : 25;
-  term_cls = COLS ? COLS : 80;
+  term_lns = LINES;
+  term_cls = COLS;
 
   prompt_active = 1;
 
index c41b046c012bb64b7cbfe59deb8ebbe8a600882b..2d5e10678cf9e0757ca8571b2b9c8a0a32527b33 100644 (file)
@@ -150,11 +150,6 @@ input_init(void)
       term_lns = tws.ws_row;
       term_cls = tws.ws_col;
     }
-  else
-    {
-       term_lns = 25;
-       term_cls = 80;
-    }
 }
 
 void
index 61caf38b0956080706eef3bcc4cab7166cce7aed..a9d0096d952f164a0b325e7f33768a6f3f0e9199 100644 (file)
@@ -178,6 +178,10 @@ init_commands(void)
     }
 
   input_init();
+
+  term_lns = (term_lns > 0) ? term_lns : 25;
+  term_cls = (term_cls > 0) ? term_cls : 80;
+
   init = 0;
 }
 
index 50f390e0a64a7c2a8382006509a6a5f6902071a0..b1bbeae2869249e62fce82e1ca666b4d92d93307 100644 (file)
@@ -172,7 +172,7 @@ else: {
   return ELSECOL;
 }
 
-({ALPHA}{ALNUM}*|[']({ALNUM}|[-]|[\.])*[']) {
+({ALPHA}{ALNUM}*|[']({ALNUM}|[-]|[\.]|[:])*[']) {
   if(*yytext == '\'') {
     yytext[yyleng-1] = 0;
     yytext++;
index 3bc0e4538876ee53fbc0b1ac569a56ac3a497e55..46d2e026fa566e03100fca56771e4ab185a1fcc1 100644 (file)
@@ -144,13 +144,19 @@ options. The most important ones are:
        nonzero if there are some errors.
 
        <tag>-s <m/name of communication socket/</tag>
-       use given filename for a  socket for communications with the client, default is <it/prefix/<file>/var/run/bird.ctl</file>.
+       use given filename for a socket for communications with the client, default is <it/prefix/<file>/var/run/bird.ctl</file>.
+
+       <tag>-P <m/name of PID file/</tag>
+       create a PID file with given filename</file>.
 
        <tag>-u <m/user/</tag>
        drop privileges and use that user ID, see the next section for details.
 
        <tag>-g <m/group/</tag>
        use that group ID, see the next section for details.
+
+       <tag>-f</tag>
+       run bird in foreground.
 </descrip>
 
 <p>BIRD writes messages about its work to log files or syslog (according to config).
@@ -477,7 +483,7 @@ to zero to disable it. An empty <cf><m/switch/</cf> is equivalent to <cf/on/
        using <cf/show route filtered/. Note that this option does not
        work for the pipe protocol. Default: off.
 
-       <tag>import limit [<m/number/ | off ] [action warn | block | restart | disable]</tag>
+       <tag><label id="import-limit">import limit [<m/number/ | off ] [action warn | block | restart | disable]</tag>
        Specify an import route limit (a maximum number of routes
        imported from the protocol) and optionally the action to be
        taken when the limit is hit. Warn action just prints warning
@@ -912,56 +918,63 @@ bird>
 incompatible with each other (that is to prevent you from shooting in the foot).
 
 <descrip>
-       <tag/bool/ This is a boolean type, it can have only two values, <cf/true/ and
-         <cf/false/. Boolean is the only type you can use in <cf/if/
-         statements.
-
-       <tag/int/ This is a general integer type, you can expect it to store signed values from -2000000000
-         to +2000000000. Overflows are not checked. You can use <cf/0x1234/ syntax to write hexadecimal values.
-
-       <tag/pair/ This is a pair of two short integers. Each component can have values from 0 to
-         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
-         are written as <cf/"This is a string constant"/.
-
-       <tag/ip/ 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 (<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/prefix/ This type can hold a network prefix consisting of IP address and prefix length. Prefix literals are written as
-         <cf><M>ipaddress</M>/<M>pxlen</M></cf>, or
+       <tag/bool/ This is a boolean type, it can have only two values,
+         <cf/true/ and <cf/false/. Boolean is the only type you can use in
+         <cf/if/ statements.
+
+       <tag/int/ This is a general integer type, you can expect it to store
+         signed values from -2000000000 to +2000000000. Overflows are not
+         checked. You can use <cf/0x1234/ syntax to write hexadecimal values.
+
+       <tag/pair/ This is a pair of two short integers. Each component can have
+         values from 0 to 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, use standard
+         string comparison operations (e.g. <cf/=, !=, &lt;, &gt;, &lt;=,
+         &gt;=/), but you can't concatenate two strings. String literals are
+         written as <cf/"This is a string constant"/. Additionaly matching
+         <cf/&tilde;/ operator could be used to match a string value against a
+         shell pattern (represented also as a string).
+
+       <tag/ip/ 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
+         (<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/prefix/ This type can hold a network prefix consisting of IP
+         address and prefix length. Prefix literals are written
+         as <cf><M>ipaddress</M>/<M>pxlen</M></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. So <cf>1.2.0.0/16.pxlen = 16</cf> is true.
-
-       <tag/ec/ This is a specialized type used to represent BGP
-         extended community values. It is essentially a 64bit value,
-         literals of this type are usually written as <cf>(<m/kind/,
-         <m/key/, <m/value/)</cf>, where <cf/kind/ is a kind of
-         extended community (e.g. <cf/rt/ / <cf/ro/ for a route
-         target / route origin communities), the format and possible
-         values of <cf/key/ and <cf/value/ are usually integers, but
+         operators on 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.pxlen = 16</cf> is true.
+
+       <tag/ec/ This is a specialized type used to represent BGP extended
+         community values. It is essentially a 64bit value, literals of this
+         type are usually written as <cf>(<m/kind/, <m/key/, <m/value/)</cf>,
+         where <cf/kind/ is a kind of extended community (e.g. <cf/rt/ /
+         <cf/ro/ for a route target / route origin communities), the format and
+         possible values of <cf/key/ and <cf/value/ are usually integers, but
          it depends on the used kind. Similarly to pairs, ECs can be
-         constructed using expressions for <cf/key/ and
-         <cf/value/ parts, (e.g. <cf/(ro, myas, 3*10)/, where
-         <cf/myas/ is an integer variable).
+         constructed using expressions for <cf/key/ and <cf/value/ parts,
+         (e.g. <cf/(ro, myas, 3*10)/, where <cf/myas/ is an integer variable).
  
-       <tag/int|pair|quad|ip|prefix|ec|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>int set</cf> look like <cf>
-         [ 1, 2, 5..7 ]</cf>. As you can see, both simple values and ranges are permitted in
-         sets.
+       <tag/int|pair|quad|ip|prefix|ec|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>int set</cf> look like <cf> [
+         1, 2, 5..7 ]</cf>. As you can see, both simple values and ranges are
+         permitted in sets.
 
          For pair sets, expressions like <cf/(123,*)/ can be used to denote ranges (in
          that case <cf/(123,0)..(123,65535)/). You can also use <cf/(123,5..100)/ for range
@@ -1071,6 +1084,8 @@ incompatible with each other (that is to prevent you from shooting in the foot).
          no literals of this type. There are three special operators on
          clists:
 
+         <cf><m/C/.len</cf> returns the length of clist <m/C/.
+
           <cf>add(<m/C/,<m/P/)</cf> adds pair (or quad) <m/P/ to clist
          <m/C/ and returns the result.  If item <m/P/ is already in
          clist <m/C/, it does nothing. <m/P/ may also be a clist,
@@ -1194,7 +1209,6 @@ undefined value is regarded as empty clist for most purposes.
        what protocol has told me about this route. Possible values: <cf/RTS_DUMMY/, <cf/RTS_STATIC/, <cf/RTS_INHERIT/, <cf/RTS_DEVICE/, <cf/RTS_STATIC_DEVICE/, <cf/RTS_REDIRECT/, <cf/RTS_RIP/, <cf/RTS_OSPF/, <cf/RTS_OSPF_IA/, <cf/RTS_OSPF_EXT1/, <cf/RTS_OSPF_EXT2/, <cf/RTS_BGP/, <cf/RTS_PIPE/.
 
        <tag><m/enum/ cast</tag>
-
        Route type (Currently <cf/RTC_UNICAST/ for normal routes,
        <cf/RTC_BROADCAST/, <cf/RTC_MULTICAST/, <cf/RTC_ANYCAST/ will
        be used in the future for broadcast, multicast and anycast
@@ -1212,6 +1226,19 @@ undefined value is regarded as empty clist for most purposes.
        only to <cf/RTD_BLACKHOLE/, <cf/RTD_UNREACHABLE/ or
        <cf/RTD_PROHIBIT/.
 
+       <tag><m/string/ ifname</tag>
+       Name of the outgoing interface. Sink routes (like blackhole,
+       unreachable or prohibit) and multipath routes have no interface
+       associated with them, so <cf/ifname/ returns an empty string for
+       such routes. Read-only.
+
+       <tag><m/int/ ifindex</tag>
+       Index of the outgoing interface. System wide index of the
+       interface. May be used for interface matching, however
+       indexes might change on interface creation/removal. Zero is
+       returned for routes with undefined outgoing
+       interfaces. Read-only.
+
        <tag><m/int/ igp_metric</tag>
        The optional attribute that can be used to specify a distance
        to the network for routes that do not have a native protocol
@@ -1643,6 +1670,16 @@ for each neighbor using the following configuration parameters:
        This option requires that the connected routing table is
        <ref id="dsc-sorted" name="sorted">. Default: off.
 
+       <tag>allow local as [<m/number/]</tag> 
+       BGP prevents routing loops by rejecting received routes with
+       the local AS number in the AS path. This option allows to
+       loose or disable the check. Optional <cf/number/ argument can
+       be used to specify the maximum number of local ASNs in the AS
+       path that is allowed for received routes. When the option is
+       used without the argument, the check is completely disabled
+       and you should ensure loop-free behavior by some other means.
+       Default: 0 (no local AS number allowed).
+
        <tag>enable route refresh <m/switch/</tag> When BGP speaker
        changes its import filter, it has to re-examine all routes
        received from its neighbor against the new filter. As these
@@ -1689,8 +1726,9 @@ for each neighbor using the following configuration parameters:
 
        <tag>route limit <m/number/</tag> The maximal number of routes
        that may be imported from the protocol. If the route limit is
-       exceeded, the connection is closed with error. Limit is currently implemented as
-       <cf/import limit number exceed restart/. Default: no limit.
+       exceeded, the connection is closed with an error. Limit is currently implemented as
+       <cf/import limit <m/number/ action restart/. This option is obsolete and it is
+        replaced by <ref id="import-limit" name="import limit option">.  Default: no limit.
 
        <tag>disable after error <m/switch/</tag> When an error is encountered (either
        locally or by the other side), disable the instance automatically
index 6623405078283f9a7cee031ab799790a49e23b46..04acfbabeee78df72c4a403aa4e48ade704ebbe3 100644 (file)
@@ -261,7 +261,8 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
        SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST,
        IF, THEN, ELSE, CASE,
        TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
-       FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, PREFERENCE,
+       FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, IFNAME, IFINDEX,
+       PREFERENCE,
        LEN,
        DEFINED,
        ADD, DELETE, CONTAINS, RESET,
@@ -680,14 +681,16 @@ symbol:
    }
 
 static_attr:
-   FROM    { $$ = f_new_inst(); $$->aux = T_IP;         $$->a2.i = OFFSETOF(struct rta, from);   $$->a1.i = 1; }
- | GW      { $$ = f_new_inst(); $$->aux = T_IP;         $$->a2.i = OFFSETOF(struct rta, gw);     $$->a1.i = 1; }
- | NET     { $$ = f_new_inst(); $$->aux = T_PREFIX;     $$->a2.i = 0x12345678; /* This is actually ok - T_PREFIX is special-cased. */ }
- | PROTO   { $$ = f_new_inst(); $$->aux = T_STRING;     $$->a2.i = 0x12345678; /* T_STRING is also special-cased. */ }
- | SOURCE  { $$ = f_new_inst(); $$->aux = T_ENUM_RTS;   $$->a2.i = OFFSETOF(struct rta, source); }
- | SCOPE   { $$ = f_new_inst(); $$->aux = T_ENUM_SCOPE; $$->a2.i = OFFSETOF(struct rta, scope);  $$->a1.i = 1; }
- | CAST    { $$ = f_new_inst(); $$->aux = T_ENUM_RTC;   $$->a2.i = OFFSETOF(struct rta, cast); }
- | DEST    { $$ = f_new_inst(); $$->aux = T_ENUM_RTD;   $$->a2.i = OFFSETOF(struct rta, dest);   $$->a1.i = 1; }
+   FROM    { $$ = f_new_inst(); $$->aux = T_IP;         $$->a2.i = SA_FROM;    $$->a1.i = 1; }
+ | GW      { $$ = f_new_inst(); $$->aux = T_IP;         $$->a2.i = SA_GW;      $$->a1.i = 1; }
+ | NET     { $$ = f_new_inst(); $$->aux = T_PREFIX;     $$->a2.i = SA_NET; }
+ | 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; }
  ;
 
 term:
index ff4000e83d7e031f3d64d37bb7e53c8b47d374f6..e0451aa157d6b98d1e6e82480d6ca8ff46b84199 100644 (file)
@@ -58,22 +58,6 @@ adata_empty(struct linpool *pool, int l)
   return res;
 }
 
-static int
-pm_path_compare(struct f_path_mask *m1, struct f_path_mask *m2)
-{
-  while (1) {
-    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;
-  }
-}
-
-u32 f_eval_asn(struct f_inst *expr);
-
 static void
 pm_format(struct f_path_mask *p, buffer *buf)
 {
@@ -106,25 +90,22 @@ pm_format(struct f_path_mask *p, buffer *buf)
   buffer_puts(buf, "=]");
 }
 
-static inline int int_cmp(int i1, int i2)
+static inline int
+int_cmp(int i1, int i2)
 {
-  if (i1 == i2) return 0;
-  if (i1 < i2) return -1;
-  else return 1;
+  return (i1 > i2) - (i1 < i2); 
 }
 
-static inline int uint_cmp(uint i1, uint i2)
+static inline int
+uint_cmp(uint i1, uint i2)
 {
-  if (i1 == i2) return 0;
-  if (i1 < i2) return -1;
-  else return 1;
+  return (int)(i1 > i2) - (int)(i1 < i2);
 }
 
-static inline int u64_cmp(u64 i1, u64 i2)
+static inline int
+u64_cmp(u64 i1, u64 i2)
 {
-  if (i1 == i2) return 0;
-  if (i1 < i2) return -1;
-  else return 1;
+  return (int)(i1 > i2) - (int)(i1 < i2);
 }
 
 /**
@@ -132,23 +113,21 @@ static inline int u64_cmp(u64 i1, u64 i2)
  * @v1: first value
  * @v2: second value
  *
- * Compares two values and returns -1, 0, 1 on <, =, > or 999 on error.
- * Tree module relies on this giving consistent results so that it can
- * build balanced trees.
+ * Compares two values and returns -1, 0, 1 on <, =, > or CMP_ERROR on
+ * error. Tree module relies on this giving consistent results so
+ * that it can be used for building balanced trees.
  */
 int
 val_compare(struct f_val v1, struct f_val v2)
 {
   int rc;
 
-  if ((v1.type == T_VOID) && (v2.type == T_VOID))
-    return 0;
-  if (v1.type == T_VOID)       /* Hack for else */
-    return -1;
-  if (v2.type == T_VOID)
-    return 1;
-
   if (v1.type != v2.type) {
+    if (v1.type == T_VOID)     /* Hack for else */
+      return -1;
+    if (v2.type == T_VOID)
+      return 1;
+
 #ifndef IPV6
     /* IP->Quad implicit conversion */
     if ((v1.type == T_QUAD) && (v2.type == T_IP))
@@ -160,7 +139,10 @@ val_compare(struct f_val v1, struct f_val v2)
     debug( "Types do not match in val_compare\n" );
     return CMP_ERROR;
   }
+
   switch (v1.type) {
+  case T_VOID:
+    return 0;
   case T_ENUM:
   case T_INT:
   case T_BOOL:
@@ -175,25 +157,63 @@ val_compare(struct f_val v1, struct f_val v2)
   case T_PREFIX:
     if (rc = ipa_compare(v1.val.px.ip, v2.val.px.ip))
       return rc;
-    if (v1.val.px.len < v2.val.px.len)
-      return -1;
-    if (v1.val.px.len > v2.val.px.len)
-      return 1;
-    return 0;
-  case T_PATH_MASK:
-    return pm_path_compare(v1.val.path_mask, v2.val.path_mask);
+    return int_cmp(v1.val.px.len, v2.val.px.len);
   case T_STRING:
     return strcmp(v1.val.s, v2.val.s);
   default:
-    debug( "Compare of unknown entities: %x\n", v1.type );
     return CMP_ERROR;
   }
 }
 
-int 
-tree_compare(const void *p1, const void *p2)
+static int
+pm_path_same(struct f_path_mask *m1, struct f_path_mask *m2)
+{
+  while (m1 && m2)
+  {
+    if ((m1->kind != m2->kind) || (m1->val != m2->val))
+      return 0;
+
+    m1 = m1->next;
+    m2 = m2->next;
+  }
+
+ return !m1 && !m2;
+}
+
+/**
+ * val_same - compare two values
+ * @v1: first value
+ * @v2: second value
+ *
+ * Compares two values and returns 1 if they are same and 0 if not.
+ * Comparison of values of different types is valid and returns 0.
+ */
+int
+val_same(struct f_val v1, struct f_val v2)
 {
-  return val_compare((* (struct f_tree **) p1)->from, (* (struct f_tree **) p2)->from);
+  int rc;
+
+  rc = val_compare(v1, v2);
+  if (rc != CMP_ERROR)
+    return !rc;
+
+  if (v1.type != v2.type)
+    return 0;
+
+  switch (v1.type) {
+  case T_PATH_MASK:
+    return pm_path_same(v1.val.path_mask, v2.val.path_mask);
+  case T_PATH:
+  case T_CLIST:
+  case T_ECLIST:
+    return adata_same(v1.val.ad, v2.val.ad);
+  case T_SET:
+    return same_tree(v1.val.t, v2.val.t);
+  case T_PREFIX_SET:
+    return trie_same(v1.val.ti, v2.val.ti);
+  default:
+    bug("Invalid type in val_same(): %x", v1.type);
+  }
 }
 
 void
@@ -214,39 +234,6 @@ fprefix_get_bounds(struct f_prefix *px, int *l, int *h)
     }
 }
 
-/*
- * val_simple_in_range - check if @v1 ~ @v2 for everything except sets
- */ 
-static int
-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_INT) && (v2.type == T_PATH))
-    return as_path_is_member(v2.val.ad, v1.val.i);
-
-  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_EC) && (v2.type == T_ECLIST))
-    return ec_set_contains(v2.val.ad, v1.val.ec);
-
-  if ((v1.type == T_STRING) && (v2.type == T_STRING))
-    return patmatch(v2.val.s, v1.val.s);
-
-  if ((v1.type == T_IP) && (v2.type == T_PREFIX))
-    return ipa_in_net(v1.val.px.ip, v2.val.px.ip, v2.val.px.len);
-
-  if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX))
-    return net_in_net(v1.val.px.ip, v1.val.px.len, v2.val.px.ip, v2.val.px.len);
-
-  return CMP_ERROR;
-}
-
 static int
 clist_set_type(struct f_tree *set, struct f_val *v)
 {
@@ -390,47 +377,57 @@ eclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int po
  * @v1: element
  * @v2: set
  *
- * Checks if @v1 is element (|~| operator) of @v2. Sets are internally represented as balanced trees, see
- * |tree.c| module (this is not limited to sets, but for non-set cases, val_simple_in_range() is called early).
+ * Checks if @v1 is element (|~| operator) of @v2.
  */
 static int
 val_in_range(struct f_val v1, struct f_val v2)
 {
-  int res;
+  if ((v1.type == T_PATH) && (v2.type == T_PATH_MASK))
+    return as_path_match(v1.val.ad, v2.val.path_mask);
 
-  res = val_simple_in_range(v1, v2);
+  if ((v1.type == T_INT) && (v2.type == T_PATH))
+    return as_path_contains(v2.val.ad, v1.val.i, 1);
+
+  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_EC) && (v2.type == T_ECLIST))
+    return ec_set_contains(v2.val.ad, v1.val.ec);
+
+  if ((v1.type == T_STRING) && (v2.type == T_STRING))
+    return patmatch(v2.val.s, v1.val.s);
+
+  if ((v1.type == T_IP) && (v2.type == T_PREFIX))
+    return ipa_in_net(v1.val.px.ip, v2.val.px.ip, v2.val.px.len);
+
+  if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX))
+    return net_in_net(v1.val.px.ip, v1.val.px.len, v2.val.px.ip, v2.val.px.len);
 
-  if (res != CMP_ERROR)
-    return res;
-  
   if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX_SET))
     return trie_match_fprefix(v2.val.ti, &v1.val.px);
 
-  if ((v1.type == T_CLIST) && (v2.type == T_SET))
+  if (v2.type != T_SET)
+    return CMP_ERROR;
+
+  /* With integrated Quad<->IP implicit conversion */
+  if ((v1.type == v2.val.t->from.type) ||
+      ((IP_VERSION == 4) && (v1.type == T_QUAD) && (v2.val.t->from.type == T_IP)))
+    return !!find_tree(v2.val.t, v1);
+
+  if (v1.type == T_CLIST)
     return clist_match_set(v1.val.ad, v2.val.t);
 
-  if ((v1.type == T_ECLIST) && (v2.type == T_SET))
+  if (v1.type == T_ECLIST)
     return eclist_match_set(v1.val.ad, v2.val.t);
 
-  if ((v1.type == T_PATH) && (v2.type == T_SET))
+  if (v1.type == T_PATH)
     return as_path_match_set(v1.val.ad, v2.val.t);
 
-  if (v2.type == T_SET)
-    switch (v1.type) {
-    case T_ENUM:
-    case T_INT:
-    case T_PAIR:
-    case T_QUAD:
-    case T_IP:
-    case T_EC:
-      {
-       struct f_tree *n;
-       n = find_tree(v2.val.t, v1);
-       if (!n)
-         return 0;
-       return !! (val_simple_in_range(v1, n->from));   /* We turn CMP_ERROR into compared ok, and that's fine */
-      }
-    }
   return CMP_ERROR;
 }
 
@@ -684,8 +681,15 @@ interpret(struct f_inst *what)
     res.val.i = (x); \
     break;
 
-  case P('!','='): COMPARE(i!=0);
-  case P('=','='): COMPARE(i==0);
+#define SAME(x) \
+    TWOARGS; \
+    i = val_same(v1, v2); \
+    res.type = T_BOOL; \
+    res.val.i = (x); \
+    break;
+
+  case P('!','='): SAME(!i);
+  case P('=','='): SAME(i);
   case '<': COMPARE(i==-1);
   case P('<','='): COMPARE(i!=1);
 
@@ -791,24 +795,23 @@ interpret(struct f_inst *what)
       ACCESS_RTE;
       struct rta *rta = (*f_rte)->attrs;
       res.type = what->aux;
-      switch(res.type) {
-      case T_IP:
-       res.val.px.ip = * (ip_addr *) ((char *) rta + what->a2.i);
-       break;
-      case T_ENUM:
-       res.val.i = * ((char *) rta + what->a2.i);
-       break;
-      case T_STRING:   /* Warning: this is a special case for proto attribute */
-       res.val.s = rta->proto->name;
-       break;
-      case T_PREFIX:   /* Warning: this works only for prefix of network */
-       {
-         res.val.px.ip = (*f_rte)->net->n.prefix;
-         res.val.px.len = (*f_rte)->net->n.pxlen;
-         break;
-       }
+
+      switch (what->a2.i)
+      {
+      case SA_FROM:    res.val.px.ip = rta->from; break;
+      case SA_GW:      res.val.px.ip = rta->gw; break;
+      case SA_NET:     res.val.px.ip = (*f_rte)->net->n.prefix;
+                       res.val.px.len = (*f_rte)->net->n.pxlen; break;
+      case SA_PROTO:   res.val.s = rta->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;
+
       default:
-       bug( "Invalid type for rta access (%x)", res.type );
+       bug("Invalid static attribute access (%x)", res.type);
       }
     }
     break;
@@ -817,19 +820,20 @@ interpret(struct f_inst *what)
     ONEARG;
     if (what->aux != v1.type)
       runtime( "Attempt to set static attribute to incompatible type" );
+
     f_rta_cow();
     {
       struct rta *rta = (*f_rte)->attrs;
-      ip_addr ip;
-
-      switch (what->aux) {
 
-      case T_IP:
-       ip = v1.val.px.ip;
+      switch (what->a2.i)
+      {
+      case SA_FROM:
+       rta->from = v1.val.px.ip;
+       break;
 
-       /* "gw" attribute? */
-       if (what->a2.i == OFFSETOF(struct rta, gw))
+      case SA_GW:
        {
+         ip_addr ip = v1.val.px.ip;
          neighbor *n = neigh_find(rta->proto, &ip, 0);
          if (!n || (n->scope == SCOPE_HOST))
            runtime( "Invalid gw address" );
@@ -840,16 +844,13 @@ interpret(struct f_inst *what)
          rta->nexthops = NULL;
          rta->hostentry = NULL;
        }
-       else /* or "from" attribute? */
-         rta->from = ip;
-
        break;
 
-      case T_ENUM_SCOPE:
+      case SA_SCOPE:
        rta->scope = v1.val.i;
        break;
 
-      case T_ENUM_RTD:
+      case SA_DEST:
        i = v1.val.i;
        if ((i != RTD_BLACKHOLE) && (i != RTD_UNREACHABLE) && (i != RTD_PROHIBIT))
          runtime( "Destination can be changed only to blackhole, unreachable or prohibit" );
@@ -862,7 +863,7 @@ interpret(struct f_inst *what)
        break;
 
       default:
-       bug( "Unknown type in set of static attribute" );
+       bug("Invalid static attribute access (%x)", res.type);
       }
     }
     break;
@@ -1033,7 +1034,9 @@ interpret(struct f_inst *what)
     switch(v1.type) {
     case T_PREFIX: res.val.i = v1.val.px.len; break;
     case T_PATH:   res.val.i = as_path_getlen(v1.val.ad); break;
-    default: runtime( "Prefix or path expected" );
+    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;
+    default: runtime( "Prefix, path, clist or eclist expected" );
     }
     break;
   case P('c','p'):     /* Convert prefix to ... */
@@ -1379,10 +1382,12 @@ i_same(struct f_inst *f1, struct f_inst *f2)
       A2_SAME;
     }
     break;
-  case 'C': 
-    if (val_compare(* (struct f_val *) f1->a1.p, * (struct f_val *) f2->a1.p))
+
+  case 'C':
+    if (!val_same(* (struct f_val *) f1->a1.p, * (struct f_val *) f2->a1.p))
       return 0;
     break;
+
   case 'V': 
     if (strcmp((char *) f1->a2.p, (char *) f2->a2.p))
       return 0;
index 0cef9f36e5aa7ec6257010028dd3563e509dab53..07a4c9e47ad3d5967ee291bf1463b09baaa480eb 100644 (file)
@@ -117,7 +117,7 @@ int filter_same(struct filter *new, struct filter *old);
 int i_same(struct f_inst *f1, struct f_inst *f2);
 
 int val_compare(struct f_val v1, struct f_val v2);
-int tree_compare(const void *p1, const void *p2);
+int val_same(struct f_val v1, struct f_val v2);
 
 void val_format(struct f_val v, buffer *buf);
 
@@ -174,6 +174,19 @@ void val_format(struct f_val v, buffer *buf);
 #define T_SET 0x80
 #define T_PREFIX_SET 0x81
 
+
+#define SA_FROM                 1    
+#define SA_GW           2      
+#define SA_NET          3     
+#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
+
+
 struct f_tree {
   struct f_tree *left, *right;
   struct f_val from, to;
index 3d35ed059fa5e2d35d376ab4b2e099c922966acf..62c807b731a242a2e50dc22ef61c71c1507fae4f 100644 (file)
@@ -142,10 +142,10 @@ eclist el2;
        l = add( l, (3,5) );
        l2 = filter( l, [(3,*)] );
        l = delete( l, [(3,2..4)] );
-       print "Community list (1,2) (3,1) (3,5) ", l;
+       print "Community list (1,2) (3,1) (3,5) ", l, " len: ", l.len;
        l = add( l, (3,2) );
        l = add( l, (4,5) );
-       print "Community list (1,2) (3,1) (3,2) (3,5) (4,5) ", l;
+       print "Community list (1,2) (3,1) (3,2) (3,5) (4,5) ", l, " len: ", l.len;
        print "Should be true: ", l ~ [(*,2)], " ", l ~ [(*,5)], " ", l ~ [(*, one)];
        print "Should be false: ", l ~ [(*,3)], " ", l ~ [(*,(one+6))], " ", l ~ [(*, (one+one+one))];
        l = delete( l, [(*,(one+onef(3)))] );
@@ -168,6 +168,7 @@ eclist el2;
        el = add(el, (ro, 11.21.31.41.mask(16), 200));
        print "EC list (rt, 10, 20) (ro, 10.20.30.40, 100) (ro, 11.21.0.0, 200):";
        print el;
+       print "EC len: ", el.len;
        el = delete(el, (rt, 10, 20));
        el = delete(el, (rt, 10, 30));
        el = add(el, (unknown 2, ten, 1));
@@ -264,6 +265,7 @@ ec cc;
 int set is;
 pair set ps;
 ec set ecs;
+ip set ips;
 prefix set pxs;
 string s;
 {
@@ -282,6 +284,12 @@ string s;
 #      if 1 <= 1 then printn "."; else { print "*** FAIL: test 3"; }
        if 1234 < 1234 then { print "*** FAIL: test 4"; quitbird; } else print "ok";
        is = [ 2, 3, 4, 7..11 ];
+
+       print "must be true:  ", 1 = 1, " ", 1 != (0,1), " ", 1 != "a", " ", +empty+ = +empty+, " ", -empty- = -empty-, " ", --empty-- = --empty-- ,
+                       " ", [1,4..10,20] = [1,4..10,20] , " ", [ 10.0.0.0/8{ 15 , 17 } ] = [ 10.0.0.0/8{ 15 , 17 } ];
+       print "must be false: ", 1 != 1, " ", 1 = (0,1), " ", 1 = "a", " ", +empty+ = -empty-, " ", -empty- = --empty--, " ", --empty-- = +empty+ ,
+                       " ", [1,2] = [1,3], " ", [ 10.0.0.0/8{ 15 , 17 } ] = [ 11.0.0.0/8{ 15 , 17 } ];
+
        print "  must be true: ", 1.2.0.0/16 ~ [ 1.0.0.0/8{ 15 , 17 } ];
        print "  data types; must be true: ", 1.2.3.4 = 1.2.3.4, ",", 1 ~ [1,2,3], ",", 5 ~ [1..20], ",", 10 ~ is, ",", 2 ~ [ 1, 2, 3 ], ",", 5 ~ [ 4 .. 7 ], ",", 1.2.3.4 ~ [ 1.2.3.3..1.2.3.5 ], ",", 1.2.3.4 ~ 1.0.0.0/8, ",", 1.0.0.0/8 ~ 1.0.0.0/8, ",", 1.0.0.0/8 ~ [ 1.0.0.0/8+ ];
        print "  must be true: ", true && true, ",", true || false, ",", ! false && ! false && true, ",", 1 < 2 && 1 != 3, ",", true && true && ! false, ",", true || 1+"a", ",", !(false && 1+"a");
@@ -353,6 +361,12 @@ string s;
         if ( b = true ) then print "Testing bool comparison b = true: ", b;
        else { print "*** FAIL: TRUE test failed" ; quitbird; }
        
+       ips = [ 1.1.1.0 .. 1.1.1.255, 1.2.2.2];
+       print "Testing IP sets: ";
+       print ips;
+       print "  must be true:  ",      1.1.1.0 ~ ips, ",", 1.1.1.100 ~ ips, ",", 1.2.2.2 ~ ips;
+       print "  must be false: ",      1.1.0.255 ~ ips, ",", 1.1.2.0  ~ ips, ",", 1.2.2.3 ~ ips, ",", 192.168.1.1 ~ ips;
+
        pxs = [ 1.2.0.0/16, 1.4.0.0/16+];
        print "Testing prefix sets: ";
        print pxs;
@@ -379,6 +393,9 @@ string s;
 
        print "1.2.3.4 = ", onetwo;
 
+       i = 4200000000;
+       print "4200000000 = ", i, "   false: ", i = 4200000000, " ", i > 4100000000, "   false: ", i > 4250000000;
+
        test_undef(2);
        test_undef(3);
        test_undef(2);
index 5e1d606a578a4eef8da30898119882ca02428282..ee9f448a11e3399284ccfded838fe396cbf471a5 100644 (file)
@@ -53,6 +53,11 @@ build_tree_rec(struct f_tree **buf, int l, int h)
   return n;
 }
 
+static int 
+tree_compare(const void *p1, const void *p2)
+{
+  return val_compare((* (struct f_tree **) p1)->from, (* (struct f_tree **) p2)->from);
+}
 
 /**
  * build_tree
index 52b1ed47d953ebc046915aa32b7ef831d616b814..217d72c3d749a4b9c99f75dbfe93c9dd00a77b42 100644 (file)
@@ -290,7 +290,7 @@ trie_format(struct f_trie *t, buffer *buf)
   buffer_puts(buf, "[");
 
   if (t->zero)
-    buffer_print(buf, "0.0.0.0/0, ");
+    buffer_print(buf, "%I/%d", IPA_NONE, 0);
   trie_node_format(&t->root, buf);
 
   /* Undo last separator */
index a542495899a4c11188f70fe2e2b753db9f5f3db3..b7a5a6a6352fcb48e9a53edb632e1cfaae4715a0 100644 (file)
 #define NULL ((void *) 0)
 #endif
 
+#ifndef IPV6
+#define IP_VERSION 4
+#else
+#define IP_VERSION 6
+#endif
+
 
 /* Macros for gcc attributes */
 
index b181298178896c4bfb889ca676c5fe3bad7008a8..dc36e6538951f1c3ca3401290b40e6663c4449ea 100644 (file)
@@ -244,10 +244,11 @@ as_path_get_first(struct adata *path, u32 *last_as)
 }
 
 int
-as_path_is_member(struct adata *path, u32 as)
+as_path_contains(struct adata *path, u32 as, int min)
 {
   u8 *p = path->data;
   u8 *q = p+path->length;
+  int num = 0;
   int i, n;
 
   while (p<q)
@@ -257,7 +258,8 @@ as_path_is_member(struct adata *path, u32 as)
       for(i=0; i<n; i++)
        {
          if (get_as(p) == as)
-           return 1;
+           if (++num == min)
+             return 1;
          p += BS;
        }
     }
index 44a23e18965927ddea09331b1d9387e65fe4dcf1..b6e067cb8c6fc144d2b69d4f1a936d6d02626e4f 100644 (file)
@@ -35,7 +35,7 @@ int as_path_getlen(struct adata *path);
 int as_path_getlen_int(struct adata *path, int bs);
 int as_path_get_first(struct adata *path, u32 *orig_as);
 int as_path_get_last(struct adata *path, u32 *last_as);
-int as_path_is_member(struct adata *path, u32 as);
+int as_path_contains(struct adata *path, u32 as, int min);
 int as_path_match_set(struct adata *path, struct f_tree *set);
 struct adata *as_path_filter(struct linpool *pool, struct adata *path, struct f_tree *set, u32 key, int pos);
 
@@ -69,6 +69,9 @@ int as_path_match(struct adata *path, struct f_path_mask *mask);
 static inline int int_set_get_size(struct adata *list)
 { return list->length / 4; }
 
+static inline int ec_set_get_size(struct adata *list)
+{ return list->length / 8; }
+
 static inline u32 *int_set_get_data(struct adata *list)
 { return (u32 *) list->data; }
 
index a6f13808b3bd6f61c9778a076c2f3e4802b3591c..e9b8a21ba4fdb5a1ddf9125c28b0b31006390b29 100644 (file)
@@ -46,7 +46,7 @@ CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OF
 CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILTERS)
 CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED)
 CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
-CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, GENERATE, ROA, MAX, FLUSH)
+CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, GENERATE, ROA, MAX, FLUSH, AS)
 CF_KEYWORDS(LISTEN, BGP, V6ONLY, DUAL, ADDRESS, PORT, PASSWORDS, DESCRIPTION, SORTED)
 CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, CLASS, DSCP)
 
index 9dce811941df9814d4f9db9193648a6895bdb3ab..11a980b25f9b3dafa9fccfe099c174b3bb624da3 100644 (file)
@@ -231,7 +231,7 @@ neigh_up(neighbor *n, struct iface *i, int scope)
 static void
 neigh_down(neighbor *n)
 {
-  DBG("Flushing neighbor %I on %s\n", n->addr, i->name);
+  DBG("Flushing neighbor %I on %s\n", n->addr, n->iface->name);
   rem_node(&n->if_n);
   if (! (n->flags & NEF_BIND))
     n->iface = NULL;
index c15247be9f2e7bc5cc6cafe27c5315104e88a681..75ba10dd9c8852bbb00b6b372d83adeefb4dbb2d 100644 (file)
@@ -376,6 +376,7 @@ int proto_reconfig_type;  /* Hack to propagate type info to pipe reconfigure hoo
 static int
 proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config *nc, int type)
 {
+  struct announce_hook *ah = p->main_ahook;
   /* If the protocol is DOWN, we just restart it */
   if (p->proto_state == PS_DOWN)
     return 0;
@@ -407,14 +408,31 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
 
   /* Update filters and limits in the main announce hook
      Note that this also resets limit state */
-  if (p->main_ahook)
+  if (ah)
     {
-      p->main_ahook->in_filter = nc->in_filter;
-      p->main_ahook->out_filter = nc->out_filter;
-      p->main_ahook->rx_limit = nc->rx_limit;
-      p->main_ahook->in_limit = nc->in_limit;
-      p->main_ahook->out_limit = nc->out_limit;
-      p->main_ahook->in_keep_filtered = nc->in_keep_filtered;
+      ah->in_filter = nc->in_filter;
+      ah->out_filter = nc->out_filter;
+      ah->rx_limit = nc->rx_limit;
+      ah->in_limit = nc->in_limit;
+      ah->out_limit = nc->out_limit;
+      ah->in_keep_filtered = nc->in_keep_filtered;
+
+      if (p->proto_state == PS_UP)     /* Recheck export/import/receive limit */
+        {
+          struct proto_stats *stats = ah->stats;
+          struct proto_limit *l = ah->in_limit;
+          u32 all_routes = stats->imp_routes + stats->filt_routes;
+
+          if (l && (stats->imp_routes >= l->limit)) proto_notify_limit(ah, l, PLD_IN, stats->imp_routes);
+
+          l = ah->rx_limit;
+
+          if (l && ( all_routes >= l->limit)) proto_notify_limit(ah, l, PLD_RX, all_routes );
+
+          l = ah->out_limit;
+
+          if (l && ( stats->exp_routes >= l->limit)) proto_notify_limit(ah, l, PLD_OUT, stats->exp_routes);
+        }
     }
 
   /* Update routes when filters changed. If the protocol in not UP,
index 35b5fa19335ff195ad09f04f3a7f787d646f3230..e0b88551545b4c0ea3ed74365f17169b7c358b63 100644 (file)
@@ -405,6 +405,10 @@ struct adata {
   byte data[0];
 };
 
+static inline int adata_same(struct adata *a, struct adata *b)
+{ return (a->length == b->length && !memcmp(a->data, b->data, a->length)); }
+
+
 typedef struct ea_list {
   struct ea_list *next;                        /* In case we have an override list */
   byte flags;                          /* Flags: EALF_... */
index 6aed318b1cf3ce41df2075ae852b86cb5d756cc2..3f79ee5949639a0a41723d67c14f56827ed7cc74 100644 (file)
@@ -366,8 +366,7 @@ ea_same(ea_list *x, ea_list *y)
       if (a->id != b->id ||
          a->flags != b->flags ||
          a->type != b->type ||
-         ((a->type & EAF_EMBEDDED) ? a->u.data != b->u.data :
-          (a->u.ptr->length != b->u.ptr->length || memcmp(a->u.ptr->data, b->u.ptr->data, a->u.ptr->length))))
+         ((a->type & EAF_EMBEDDED) ? a->u.data != b->u.data : !adata_same(a->u.ptr, b->u.ptr)))
        return 0;
     }
   return 1;
index 54cb14ba09a9f51e80b8d916a0755b37930d6672..4fb5bddbf2a54d16f31c187648f7fa794702fcd7 100644 (file)
@@ -34,6 +34,9 @@ dev_ifa_notify(struct proto *p, unsigned c, struct ifa *ad)
     /* Empty list is automagically treated as "*" */
     return;
 
+  if (ad->flags & IA_SECONDARY)
+    return;
+
   if (ad->scope <= SCOPE_LINK)
     return;
 
index 16dd9bcd63b0593d5859798a7e68c9c384cb483c..fc55408146d81fcf7a42079f7dea65112daee10a 100644 (file)
@@ -636,6 +636,7 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, str
   struct proto *p = ah->proto;
   struct rtable *table = ah->table;
   struct proto_stats *stats = ah->stats;
+  static struct rate_limit rl_pipe;
   rte *before_old = NULL;
   rte *old_best = net->routes;
   rte *old = NULL;
@@ -659,7 +660,7 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, str
            {
              if (new)
                {
-                 log(L_ERR "Pipe collision detected when sending %I/%d to table %s",
+                 log_rl(&rl_pipe, L_ERR "Pipe collision detected when sending %I/%d to table %s",
                      net->n.prefix, net->n.pxlen, table->name);
                  rte_free_quick(new);
                }
@@ -1271,6 +1272,7 @@ rt_init(void)
 static inline int
 rt_prune_step(rtable *tab, int step, int *max_feed)
 {
+  static struct rate_limit rl_flush;
   struct fib_iterator *fit = &tab->prune_fit;
 
   DBG("Pruning route table %s\n", tab->name);
@@ -1305,7 +1307,7 @@ again:
              }
 
            if (step)
-             log(L_WARN "Route %I/%d from %s still in %s after flush",
+             log_rl(&rl_flush, L_WARN "Route %I/%d from %s still in %s after flush",
                  n->n.prefix, n->n.pxlen, e->attrs->proto->name, tab->name);
 
            rte_discard(tab, e);
index c27a49880fe0840ca69267d8b8491da7893a4c1a..8e25c4d2413ee943d18250b4c1be391725f81ee0 100644 (file)
@@ -950,8 +950,9 @@ bgp_create_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *p
 static inline int
 bgp_as_path_loopy(struct bgp_proto *p, rta *a)
 {
+  int num = p->cf->allow_local_as + 1;
   eattr *e = ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
-  return (e && as_path_is_member(e->u.ptr, p->local_as));
+  return (e && (num > 0) && as_path_contains(e->u.ptr, p->local_as, num));
 }
 
 static inline int
index 6da38949418b5ef2d4bceddb9fa6d9a841ee5bd8..d2a96bbb67257800e50c3a51183228149c5f1e65 100644 (file)
@@ -45,6 +45,7 @@ struct bgp_config {
   int passive;                         /* Do not initiate outgoing connection */
   int interpret_communities;           /* Hardwired handling of well-known communities */
   int secondary;                       /* Accept also non-best routes (i.e. RA_ACCEPTED) */
+  int allow_local_as;                  /* Allow that number of local ASNs in incoming AS_PATHs */
   unsigned connect_retry_time;
   unsigned hold_time, initial_hold_time;
   unsigned keepalive_time;
index 0292c234536f8046a495cb5f5bccc4209970a7d3..185b1bda5189d3445f98c3f653c1ce3a70b43d9d 100644 (file)
@@ -26,7 +26,7 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY,
        PREFER, OLDER, MISSING, LLADDR, DROP, IGNORE, ROUTE, REFRESH,
        INTERPRET, COMMUNITIES, BGP_ORIGINATOR_ID, BGP_CLUSTER_LIST, IGP,
        TABLE, GATEWAY, DIRECT, RECURSIVE, MED, TTL, SECURITY, DETERMINISTIC,
-       SECONDARY, BFD)
+       SECONDARY, ALLOW, BFD)
 
 CF_GRAMMAR
 
@@ -108,6 +108,8 @@ bgp_proto:
  | bgp_proto PASSIVE bool ';' { BGP_CFG->passive = $3; }
  | bgp_proto INTERPRET COMMUNITIES bool ';' { BGP_CFG->interpret_communities = $4; }
  | bgp_proto SECONDARY bool ';' { BGP_CFG->secondary = $3; }
+ | bgp_proto ALLOW LOCAL AS ';' { BGP_CFG->allow_local_as = -1; }
+ | bgp_proto ALLOW LOCAL AS expr ';' { BGP_CFG->allow_local_as = $5; }
  | bgp_proto IGP TABLE rtable ';' { BGP_CFG->igp_table = $4; }
  | bgp_proto TTL SECURITY bool ';' { BGP_CFG->ttl_security = $4; }
  | bgp_proto BFD bool ';' { BGP_CFG->bfd = $3; cf_check_bfd($3); }
index f06dd31196f1ed62125e4d15cd9c65d95c75c39b..68efa23077e02bfe1684582ade302886af64450c 100644 (file)
@@ -125,7 +125,7 @@ CF_DECLS
 
 CF_KEYWORDS(OSPF, AREA, OSPF_METRIC1, OSPF_METRIC2, OSPF_TAG, OSPF_ROUTER_ID)
 CF_KEYWORDS(NEIGHBORS, RFC1583COMPAT, STUB, TICK, COST, COST2, RETRANSMIT)
-CF_KEYWORDS(HELLO, TRANSMIT, PRIORITY, DEAD, TYPE, BROADCAST, BCAST)
+CF_KEYWORDS(HELLO, TRANSMIT, PRIORITY, DEAD, TYPE, BROADCAST, BCAST, DEFAULT)
 CF_KEYWORDS(NONBROADCAST, NBMA, POINTOPOINT, PTP, POINTOMULTIPOINT, PTMP)
 CF_KEYWORDS(NONE, SIMPLE, AUTHENTICATION, STRICT, CRYPTOGRAPHIC, TTL, SECURITY)
 CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, CHECK, LINK, ONLY)
index bac2a58912e179d2ca4e720b44138b876dfabf52..b6b1100453443d8dd87dc7c879537bc143f2f540 100644 (file)
@@ -101,6 +101,17 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
     return;
   }
 
+#ifdef OSPFv2
+  if (n && (n->rid != ntohl(ps_i->routerid)))
+  {
+    OSPF_TRACE(D_EVENTS,
+       "Neighbor %I has changed router id from %R to %R.",
+            n->ip, n->rid, ntohl(ps_i->routerid));
+    ospf_neigh_remove(n);
+    n = NULL;
+  }
+#endif
+
   if (!n)
   {
     if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP))
@@ -132,7 +143,7 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
 
     n = ospf_neighbor_new(ifa);
 
-    n->rid = ntohl(((struct ospf_packet *) ps)->routerid);
+    n->rid = ntohl(ps_i->routerid);
     n->ip = faddr;
     n->dr = ntohl(ps->dr);
     n->bdr = ntohl(ps->bdr);
@@ -144,6 +155,14 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
     if (n->ifa->cf->bfd)
       ospf_neigh_update_bfd(n, n->ifa->bfd);
   }
+#ifdef OSPFv3  /* NOTE: this could also be relevant for OSPFv2 on PtP ifaces */
+  else if (!ipa_equal(faddr, n->ip))
+  {
+    OSPF_TRACE(D_EVENTS, "Neighbor address changed from %I to %I", n->ip, faddr);
+    n->ip = faddr;
+  }
+#endif
+
   ospf_neigh_sm(n, INM_HELLOREC);
 
   pnrid = (u32 *) ((struct ospf_hello_packet *) (ps + 1));
index a5da4251dae7ab7988ec60e3364f062c6db7c654..b19f2619f340649d8ef51329981eedb7fa08f75c 100644 (file)
@@ -205,7 +205,7 @@ ospf_lsupd_flood(struct proto_ospf *po,
            en->lsa_body = NULL;
            DBG("Removing from lsreq list for neigh %R\n", nn->rid);
            ospf_hash_delete(nn->lsrqh, en);
-           if (EMPTY_SLIST(nn->lsrql))
+           if ((EMPTY_SLIST(nn->lsrql)) && (nn->state == NEIGHBOR_LOADING))
              ospf_neigh_sm(nn, INM_LOADDONE);
            continue;
            break;
@@ -216,7 +216,7 @@ ospf_lsupd_flood(struct proto_ospf *po,
            en->lsa_body = NULL;
            DBG("Removing from lsreq list for neigh %R\n", nn->rid);
            ospf_hash_delete(nn->lsrqh, en);
-           if (EMPTY_SLIST(nn->lsrql))
+           if ((EMPTY_SLIST(nn->lsrql)) && (nn->state == NEIGHBOR_LOADING))
              ospf_neigh_sm(nn, INM_LOADDONE);
            break;
          default:
index 08dfccc81c4b2b6be2804b2dbf7d4ec194e9f3ec..0bc29458cc083e90d5bf584d40d3f1129576568e 100644 (file)
@@ -654,17 +654,25 @@ krt_read_addr(struct ks_msg *msg)
 
   if ((masklen = ipa_mklen(imask)) < 0)
   {
-    log("Invalid masklen");
+    log(L_ERR "KIF: Invalid masklen %I for %s", imask, iface->name);
     return;
   }
 
-  bzero(&ifa, sizeof(ifa));
+#ifdef IPV6
+  /* Clean up embedded interface ID returned in link-local address */
 
-  ifa.iface = iface;
+  if (ipa_has_link_scope(iaddr))
+    _I0(iaddr) = 0xfe800000;
+
+  if (ipa_has_link_scope(ibrd))
+    _I0(ibrd) = 0xfe800000;
+#endif
 
-  memcpy(&ifa.ip, &iaddr, sizeof(ip_addr));
+
+  bzero(&ifa, sizeof(ifa));
+  ifa.iface = iface;
+  ifa.ip = iaddr;
   ifa.pxlen = masklen;
-  memcpy(&ifa.brd, &ibrd, sizeof(ip_addr));
 
   scope = ipa_classify(ifa.ip);
   if (scope < 0)
@@ -674,24 +682,10 @@ krt_read_addr(struct ks_msg *msg)
   }
   ifa.scope = scope & IADDR_SCOPE_MASK;
 
-#ifdef IPV6
-  /* Clean up embedded interface ID returned in link-local address */
-  if (ipa_has_link_scope(ifa.ip))
-    _I0(ifa.ip) = 0xfe800000;
-#endif
-
-#ifdef IPV6
-  /* Why not the same check also for IPv4? */
-  if ((iface->flags & IF_MULTIACCESS) || (masklen != BITS_PER_IP_ADDRESS))
-#else
-  if (iface->flags & IF_MULTIACCESS)
-#endif
+  if (masklen < BITS_PER_IP_ADDRESS)
   {
     ifa.prefix = ipa_and(ifa.ip, ipa_mkmask(masklen));
 
-    if (masklen == BITS_PER_IP_ADDRESS)
-      ifa.flags |= IA_HOST;
-
     if (masklen == (BITS_PER_IP_ADDRESS - 1))
       ifa.opposite = ipa_opposite_m1(ifa.ip);
 
@@ -699,11 +693,22 @@ krt_read_addr(struct ks_msg *msg)
     if (masklen == (BITS_PER_IP_ADDRESS - 2))
       ifa.opposite = ipa_opposite_m2(ifa.ip);
 #endif
+
+    if (iface->flags & IF_BROADCAST)
+      ifa.brd = ibrd;
+
+    if (!(iface->flags & IF_MULTIACCESS))
+      ifa.opposite = ibrd;
   }
-  else         /* PtP iface */
+  else if (!(iface->flags & IF_MULTIACCESS) && ipa_nonzero(ibrd))
   {
+    ifa.prefix = ifa.opposite = ibrd;
     ifa.flags |= IA_PEER;
-    ifa.prefix = ifa.opposite = ifa.brd;
+  }
+  else
+  {
+    ifa.prefix = ifa.ip;
+    ifa.flags |= IA_HOST;
   }
 
   if (new)
index 3403299f698df7e6b2d563d91c9f1f25d3f6d8fa..47a7c7ff4e7b36242cb6c90cd3006940ecbcd268 100644 (file)
@@ -13,6 +13,7 @@
 #define CONFIG_MULTIPLE_TABLES
 
 #define CONFIG_SKIP_MC_BIND
+#define CONFIG_NO_IFACE_BIND
 
 /*
 Link: sysdep/unix
index 1101b228db0744d4eeb79f66287eeb1b05a0d4e5..5e6d03e8d4db5dde54f5ee1c3d09c09361efc743 100644 (file)
@@ -11,6 +11,7 @@
 #define CONFIG_MULTIPLE_TABLES
 
 #define CONFIG_SKIP_MC_BIND
+#define CONFIG_NO_IFACE_BIND
 
 /*
 Link: sysdep/unix
index f61e31a5069e67e5e890328c5d90417876a832a9..08dc11b6e1f3f3a78c3e50c41dcba662f4e059eb 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <stdio.h>
+#include <unistd.h>
 #include <fcntl.h>
 #include <sys/socket.h>
 #include <sys/uio.h>
@@ -1040,11 +1041,9 @@ nl_open_async(void)
   sock *sk;
   struct sockaddr_nl sa;
   int fd;
-  static int nl_open_tried = 0;
 
-  if (nl_open_tried)
+  if (nl_async_sk)
     return;
-  nl_open_tried = 1;
 
   DBG("KRT: Opening async netlink socket\n");
 
@@ -1065,18 +1064,18 @@ nl_open_async(void)
   if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0)
     {
       log(L_ERR "Unable to bind asynchronous rtnetlink socket: %m");
+      close(fd);
       return;
     }
 
+  nl_async_rx_buffer = xmalloc(NL_RX_SIZE);
+
   sk = nl_async_sk = sk_new(krt_pool);
   sk->type = SK_MAGIC;
   sk->rx_hook = nl_async_hook;
   sk->fd = fd;
   if (sk_open(sk))
     bug("Netlink: sk_open failed");
-
-  if (!nl_async_rx_buffer)
-    nl_async_rx_buffer = xmalloc(NL_RX_SIZE);
 }
 
 /*
@@ -1097,6 +1096,7 @@ krt_sys_start(struct krt_proto *p)
 void
 krt_sys_shutdown(struct krt_proto *p UNUSED)
 {
+  nl_table_map[KRT_CF->sys.table_id] = NULL;
 }
 
 int
index da8343f93118551f49cca5797d993de788ec7caf..6e3f1e4d90ea706a0bc717f68eee928ec2aa39c1 100644 (file)
@@ -1186,6 +1186,15 @@ sk_open(sock *s)
          port = s->sport;
          if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
            ERR("SO_REUSEADDR");
+       
+#ifdef CONFIG_NO_IFACE_BIND
+         /* Workaround missing ability to bind to an iface */
+         if ((type == SK_UDP) && s->iface && ipa_zero(s->saddr))
+         {
+           if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) < 0)
+             ERR("SO_REUSEPORT");
+         }
+#endif
        }
       fill_in_sockaddr(&sa, s->saddr, s->iface, port);
       if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0)
index 54297921c7c2dcad7d5f541014ca780a84dda962..57cfe5a48fd740e56728f4314548bdf4cac62bfd 100644 (file)
@@ -730,6 +730,13 @@ krt_prune(struct krt_proto *p)
              /* Route rejected, should not happen (KRF_INSTALLED) but to be sure .. */
              verdict = (verdict == KRF_CREATE) ? KRF_IGNORE : KRF_DELETE; 
            }
+         else
+           {
+             ea_list **x = &tmpa;
+             while (*x)
+               x = &((*x)->next);
+             *x = new ? new->attrs->eattrs : NULL;
+           }
        }
 
       switch (verdict)
@@ -839,12 +846,11 @@ static void
 krt_scan_timer_start(struct krt_proto *p)
 {
   if (!krt_scan_count)
-  {
     krt_scan_timer = tm_new_set(krt_pool, krt_scan, NULL, 0, KRT_CF->scan_time);
-    tm_start(krt_scan_timer, 0);
-  }
 
   krt_scan_count++;
+
+  tm_start(krt_scan_timer, 0);
 }
 
 static void
index ecf67b6539925aeaa9da7a4c55e0c48b70b338a7..7a945826298997d3c1050511326c6264c1e9e18a 100644 (file)
@@ -473,6 +473,58 @@ cli_init_unix(uid_t use_uid, gid_t use_gid)
     die("chmod: %m");
 }
 
+/*
+ *     PID file
+ */
+
+static char *pid_file;
+static int pid_fd;
+
+static inline void
+open_pid_file(void)
+{
+  if (!pid_file)
+    return;
+
+  pid_fd = open(pid_file, O_WRONLY|O_CREAT, 0664);
+  if (pid_fd < 0)
+    die("Cannot create PID file %s: %m", pid_file);
+}
+
+static inline void
+write_pid_file(void)
+{
+  int pl, rv;
+  char ps[24];
+
+  if (!pid_file)
+    return;
+
+  /* We don't use PID file for uniqueness, so no need for locking */
+
+  pl = bsnprintf(ps, sizeof(ps), "%ld\n", (long) getpid());
+  if (pl < 0)
+    bug("PID buffer too small");
+
+  rv = ftruncate(pid_fd, 0);
+  if (rv < 0)
+    die("fruncate: %m");
+    
+  rv = write(pid_fd, ps, pl);
+  if(rv < 0)
+    die("write: %m");
+
+  close(pid_fd);
+}
+
+static inline void
+unlink_pid_file(void)
+{
+  if (pid_file)
+    unlink(pid_file);
+}
+
+
 /*
  *     Shutdown
  */
@@ -497,6 +549,7 @@ async_shutdown(void)
 void
 sysdep_shutdown_done(void)
 {
+  unlink_pid_file();
   unlink(path_control_socket);
   log_msg(L_FATAL "Shutdown completed");
   exit(0);
@@ -549,16 +602,17 @@ signal_init(void)
  *     Parsing of command-line arguments
  */
 
-static char *opt_list = "c:dD:ps:u:g:";
+static char *opt_list = "c:dD:ps:P:u:g:f";
 static int parse_and_exit;
 char *bird_name;
 static char *use_user;
 static char *use_group;
+static int run_in_foreground = 0;
 
 static void
 usage(void)
 {
-  fprintf(stderr, "Usage: %s [-c <config-file>] [-d] [-D <debug-file>] [-p] [-s <control-socket>] [-u <user>] [-g <group>]\n", bird_name);
+  fprintf(stderr, "Usage: %s [-c <config-file>] [-d] [-D <debug-file>] [-p] [-s <control-socket>] [-P <pid-file>] [-u <user>] [-g <group>] [-f]\n", bird_name);
   exit(1);
 }
 
@@ -657,12 +711,18 @@ parse_args(int argc, char **argv)
       case 's':
        path_control_socket = optarg;
        break;
+      case 'P':
+       pid_file = optarg;
+       break;
       case 'u':
        use_user = optarg;
        break;
       case 'g':
        use_group = optarg;
        break;
+      case 'f':
+       run_in_foreground = 1;
+       break;
       default:
        usage();
       }
@@ -710,6 +770,9 @@ main(int argc, char **argv)
   if (use_uid)
     drop_uid(use_uid);
 
+  if (!parse_and_exit)
+    open_pid_file();
+
   protos_build();
   proto_build(&proto_unix_kernel);
   proto_build(&proto_unix_iface);
@@ -719,7 +782,7 @@ main(int argc, char **argv)
   if (parse_and_exit)
     exit(0);
 
-  if (!debug_flag)
+  if (!(debug_flag||run_in_foreground))
     {
       pid_t pid = fork();
       if (pid < 0)
@@ -734,6 +797,8 @@ main(int argc, char **argv)
       dup2(0, 2);
     }
 
+  write_pid_file();
+
   signal_init();
 
   config_commit(conf, RECONFIG_HARD, 0);