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;
term_lns = tws.ws_row;
term_cls = tws.ws_col;
}
- else
- {
- term_lns = 25;
- term_cls = 80;
- }
}
void
}
input_init();
+
+ term_lns = (term_lns > 0) ? term_lns : 25;
+ term_cls = (term_cls > 0) ? term_cls : 80;
+
init = 0;
}
return ELSECOL;
}
-({ALPHA}{ALNUM}*|[']({ALNUM}|[-]|[\.])*[']) {
+({ALPHA}{ALNUM}*|[']({ALNUM}|[-]|[\.]|[:])*[']) {
if(*yytext == '\'') {
yytext[yyleng-1] = 0;
yytext++;
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).
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
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/=, !=, <, >, <=,
+ >=/), but you can't concatenate two strings. String literals are
+ written as <cf/"This is a string constant"/. Additionaly matching
+ <cf/˜/ 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
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,
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
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
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
<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
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,
}
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:
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)
{
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);
}
/**
* @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))
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:
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
}
}
-/*
- * 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)
{
* @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;
}
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);
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;
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" );
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" );
break;
default:
- bug( "Unknown type in set of static attribute" );
+ bug("Invalid static attribute access (%x)", res.type);
}
}
break;
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 ... */
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;
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);
#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;
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)))] );
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));
int set is;
pair set ps;
ec set ecs;
+ip set ips;
prefix set pxs;
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");
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;
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);
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
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 */
#define NULL ((void *) 0)
#endif
+#ifndef IPV6
+#define IP_VERSION 4
+#else
+#define IP_VERSION 6
+#endif
+
/* Macros for gcc attributes */
}
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)
for(i=0; i<n; i++)
{
if (get_as(p) == as)
- return 1;
+ if (++num == min)
+ return 1;
p += BS;
}
}
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);
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; }
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)
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;
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;
/* 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,
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_... */
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;
/* Empty list is automagically treated as "*" */
return;
+ if (ad->flags & IA_SECONDARY)
+ return;
+
if (ad->scope <= SCOPE_LINK)
return;
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;
{
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);
}
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);
}
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);
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
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;
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
| 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); }
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)
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))
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);
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));
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;
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:
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)
}
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);
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)
#define CONFIG_MULTIPLE_TABLES
#define CONFIG_SKIP_MC_BIND
+#define CONFIG_NO_IFACE_BIND
/*
Link: sysdep/unix
#define CONFIG_MULTIPLE_TABLES
#define CONFIG_SKIP_MC_BIND
+#define CONFIG_NO_IFACE_BIND
/*
Link: sysdep/unix
*/
#include <stdio.h>
+#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/uio.h>
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");
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);
}
/*
void
krt_sys_shutdown(struct krt_proto *p UNUSED)
{
+ nl_table_map[KRT_CF->sys.table_id] = NULL;
}
int
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)
/* 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)
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
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
*/
void
sysdep_shutdown_done(void)
{
+ unlink_pid_file();
unlink(path_control_socket);
log_msg(L_FATAL "Shutdown completed");
exit(0);
* 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);
}
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();
}
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);
if (parse_and_exit)
exit(0);
- if (!debug_flag)
+ if (!(debug_flag||run_in_foreground))
{
pid_t pid = fork();
if (pid < 0)
dup2(0, 2);
}
+ write_pid_file();
+
signal_init();
config_commit(conf, RECONFIG_HARD, 0);