summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/birdc.c4
-rw-r--r--client/birdcl.c5
-rw-r--r--client/client.c4
-rw-r--r--conf/cf-lex.l2
-rw-r--r--doc/bird.sgml142
-rw-r--r--filter/config.Y21
-rw-r--r--filter/filter.c291
-rw-r--r--filter/filter.h15
-rw-r--r--filter/test.conf21
-rw-r--r--filter/tree.c5
-rw-r--r--filter/trie.c2
-rw-r--r--lib/birdlib.h6
-rw-r--r--nest/a-path.c6
-rw-r--r--nest/attrs.h5
-rw-r--r--nest/config.Y2
-rw-r--r--nest/neighbor.c2
-rw-r--r--nest/proto.c32
-rw-r--r--nest/route.h4
-rw-r--r--nest/rt-attr.c3
-rw-r--r--nest/rt-dev.c3
-rw-r--r--nest/rt-table.c6
-rw-r--r--proto/bgp/attrs.c3
-rw-r--r--proto/bgp/bgp.h1
-rw-r--r--proto/bgp/config.Y4
-rw-r--r--proto/ospf/config.Y2
-rw-r--r--proto/ospf/hello.c21
-rw-r--r--proto/ospf/lsupd.c4
-rw-r--r--sysdep/bsd/krt-sock.c49
-rw-r--r--sysdep/cf/bsd-v6.h1
-rw-r--r--sysdep/cf/bsd.h1
-rw-r--r--sysdep/linux/netlink.c12
-rw-r--r--sysdep/unix/io.c9
-rw-r--r--sysdep/unix/krt.c12
-rw-r--r--sysdep/unix/main.c71
34 files changed, 499 insertions, 272 deletions
diff --git a/client/birdc.c b/client/birdc.c
index 9dd6d9b9..bbe18331 100644
--- a/client/birdc.c
+++ b/client/birdc.c
@@ -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;
diff --git a/client/birdcl.c b/client/birdcl.c
index c41b046c..2d5e1067 100644
--- a/client/birdcl.c
+++ b/client/birdcl.c
@@ -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
diff --git a/client/client.c b/client/client.c
index 61caf38b..a9d0096d 100644
--- a/client/client.c
+++ b/client/client.c
@@ -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;
}
diff --git a/conf/cf-lex.l b/conf/cf-lex.l
index 50f390e0..b1bbeae2 100644
--- a/conf/cf-lex.l
+++ b/conf/cf-lex.l
@@ -172,7 +172,7 @@ else: {
return ELSECOL;
}
-({ALPHA}{ALNUM}*|[']({ALNUM}|[-]|[\.])*[']) {
+({ALPHA}{ALNUM}*|[']({ALNUM}|[-]|[\.]|[:])*[']) {
if(*yytext == '\'') {
yytext[yyleng-1] = 0;
yytext++;
diff --git a/doc/bird.sgml b/doc/bird.sgml
index 3bc0e453..46d2e026 100644
--- a/doc/bird.sgml
+++ b/doc/bird.sgml
@@ -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
diff --git a/filter/config.Y b/filter/config.Y
index 66234050..04acfbab 100644
--- a/filter/config.Y
+++ b/filter/config.Y
@@ -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:
diff --git a/filter/filter.c b/filter/filter.c
index ff4000e8..e0451aa1 100644
--- a/filter/filter.c
+++ b/filter/filter.c
@@ -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;
diff --git a/filter/filter.h b/filter/filter.h
index 0cef9f36..07a4c9e4 100644
--- a/filter/filter.h
+++ b/filter/filter.h
@@ -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;
diff --git a/filter/test.conf b/filter/test.conf
index 3d35ed05..62c807b7 100644
--- a/filter/test.conf
+++ b/filter/test.conf
@@ -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);
diff --git a/filter/tree.c b/filter/tree.c
index 5e1d606a..ee9f448a 100644
--- a/filter/tree.c
+++ b/filter/tree.c
@@ -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
diff --git a/filter/trie.c b/filter/trie.c
index 52b1ed47..217d72c3 100644
--- a/filter/trie.c
+++ b/filter/trie.c
@@ -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 */
diff --git a/lib/birdlib.h b/lib/birdlib.h
index a5424958..b7a5a6a6 100644
--- a/lib/birdlib.h
+++ b/lib/birdlib.h
@@ -37,6 +37,12 @@
#define NULL ((void *) 0)
#endif
+#ifndef IPV6
+#define IP_VERSION 4
+#else
+#define IP_VERSION 6
+#endif
+
/* Macros for gcc attributes */
diff --git a/nest/a-path.c b/nest/a-path.c
index b1812981..dc36e653 100644
--- a/nest/a-path.c
+++ b/nest/a-path.c
@@ -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;
}
}
diff --git a/nest/attrs.h b/nest/attrs.h
index 44a23e18..b6e067cb 100644
--- a/nest/attrs.h
+++ b/nest/attrs.h
@@ -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; }
diff --git a/nest/config.Y b/nest/config.Y
index a6f13808..e9b8a21b 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -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)
diff --git a/nest/neighbor.c b/nest/neighbor.c
index 9dce8119..11a980b2 100644
--- a/nest/neighbor.c
+++ b/nest/neighbor.c
@@ -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;
diff --git a/nest/proto.c b/nest/proto.c
index c15247be..75ba10dd 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -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,
diff --git a/nest/route.h b/nest/route.h
index 35b5fa19..e0b88551 100644
--- a/nest/route.h
+++ b/nest/route.h
@@ -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_... */
diff --git a/nest/rt-attr.c b/nest/rt-attr.c
index 6aed318b..3f79ee59 100644
--- a/nest/rt-attr.c
+++ b/nest/rt-attr.c
@@ -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;
diff --git a/nest/rt-dev.c b/nest/rt-dev.c
index 54cb14ba..4fb5bddb 100644
--- a/nest/rt-dev.c
+++ b/nest/rt-dev.c
@@ -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;
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 16dd9bcd..fc554081 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -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);
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c
index c27a4988..8e25c4d2 100644
--- a/proto/bgp/attrs.c
+++ b/proto/bgp/attrs.c
@@ -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
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index 6da38949..d2a96bbb 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -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;
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index 0292c234..185b1bda 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -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); }
diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y
index f06dd311..68efa230 100644
--- a/proto/ospf/config.Y
+++ b/proto/ospf/config.Y
@@ -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)
diff --git a/proto/ospf/hello.c b/proto/ospf/hello.c
index bac2a589..b6b11004 100644
--- a/proto/ospf/hello.c
+++ b/proto/ospf/hello.c
@@ -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));
diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c
index a5da4251..b19f2619 100644
--- a/proto/ospf/lsupd.c
+++ b/proto/ospf/lsupd.c
@@ -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:
diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c
index 08dfccc8..0bc29458 100644
--- a/sysdep/bsd/krt-sock.c
+++ b/sysdep/bsd/krt-sock.c
@@ -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)
diff --git a/sysdep/cf/bsd-v6.h b/sysdep/cf/bsd-v6.h
index 3403299f..47a7c7ff 100644
--- a/sysdep/cf/bsd-v6.h
+++ b/sysdep/cf/bsd-v6.h
@@ -13,6 +13,7 @@
#define CONFIG_MULTIPLE_TABLES
#define CONFIG_SKIP_MC_BIND
+#define CONFIG_NO_IFACE_BIND
/*
Link: sysdep/unix
diff --git a/sysdep/cf/bsd.h b/sysdep/cf/bsd.h
index 1101b228..5e6d03e8 100644
--- a/sysdep/cf/bsd.h
+++ b/sysdep/cf/bsd.h
@@ -11,6 +11,7 @@
#define CONFIG_MULTIPLE_TABLES
#define CONFIG_SKIP_MC_BIND
+#define CONFIG_NO_IFACE_BIND
/*
Link: sysdep/unix
diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c
index f61e31a5..08dc11b6 100644
--- a/sysdep/linux/netlink.c
+++ b/sysdep/linux/netlink.c
@@ -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
diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c
index da8343f9..6e3f1e4d 100644
--- a/sysdep/unix/io.c
+++ b/sysdep/unix/io.c
@@ -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)
diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c
index 54297921..57cfe5a4 100644
--- a/sysdep/unix/krt.c
+++ b/sysdep/unix/krt.c
@@ -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
diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c
index ecf67b65..7a945826 100644
--- a/sysdep/unix/main.c
+++ b/sysdep/unix/main.c
@@ -474,6 +474,58 @@ cli_init_unix(uid_t use_uid, gid_t use_gid)
}
/*
+ * 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);