summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--aclocal.m417
-rw-r--r--client/client.c12
-rw-r--r--configure.in60
-rw-r--r--doc/bird.sgml93
-rw-r--r--filter/config.Y2
-rw-r--r--filter/filter.c19
-rw-r--r--lib/ipv4.c2
-rw-r--r--lib/lists.h3
-rw-r--r--lib/resource.c2
-rw-r--r--nest/a-path.c1
-rw-r--r--nest/config.Y23
-rw-r--r--nest/proto.c175
-rw-r--r--nest/protocol.h69
-rw-r--r--nest/rt-table.c73
-rw-r--r--proto/bgp/bgp.c75
-rw-r--r--proto/bgp/bgp.h2
-rw-r--r--proto/bgp/config.Y6
-rw-r--r--proto/bgp/packets.c6
-rw-r--r--proto/ospf/config.Y26
-rw-r--r--proto/ospf/hello.c2
-rw-r--r--proto/ospf/iface.c44
-rw-r--r--proto/ospf/lsack.c8
-rw-r--r--proto/ospf/lsupd.c6
-rw-r--r--proto/ospf/ospf.c6
-rw-r--r--proto/ospf/ospf.h12
-rw-r--r--proto/ospf/packet.c5
-rw-r--r--proto/ospf/packet.h2
-rw-r--r--proto/ospf/topology.c6
-rw-r--r--proto/pipe/pipe.c45
-rw-r--r--proto/radv/config.Y126
-rw-r--r--proto/radv/packets.c181
-rw-r--r--proto/radv/radv.c4
-rw-r--r--proto/radv/radv.h31
-rw-r--r--proto/rip/rip.c5
-rw-r--r--sysdep/autoconf.h.in1
-rw-r--r--sysdep/bsd/Modules7
-rw-r--r--sysdep/bsd/krt-iface.h25
-rw-r--r--sysdep/bsd/krt-scan.h22
-rw-r--r--sysdep/bsd/krt-set.h17
-rw-r--r--sysdep/bsd/krt-sock.c137
-rw-r--r--sysdep/bsd/krt-sock.h42
-rw-r--r--sysdep/bsd/krt-sys.h49
-rw-r--r--sysdep/cf/README16
-rw-r--r--sysdep/cf/bsd-v6.h6
-rw-r--r--sysdep/cf/bsd.h7
-rw-r--r--sysdep/cf/linux-20.h26
-rw-r--r--sysdep/cf/linux-21.h26
-rw-r--r--sysdep/cf/linux-v6.h9
-rw-r--r--sysdep/cf/linux.h (renamed from sysdep/cf/linux-22.h)8
-rw-r--r--sysdep/config.h19
-rw-r--r--sysdep/linux/Modules7
-rw-r--r--sysdep/linux/krt-scan.c199
-rw-r--r--sysdep/linux/krt-scan.h21
-rw-r--r--sysdep/linux/krt-sys.h46
-rw-r--r--sysdep/linux/netlink.Y (renamed from sysdep/linux/netlink/netlink.Y)2
-rw-r--r--sysdep/linux/netlink.c (renamed from sysdep/linux/netlink/netlink.c)65
-rw-r--r--sysdep/linux/netlink/Modules5
-rw-r--r--sysdep/linux/netlink/krt-iface.h29
-rw-r--r--sysdep/linux/netlink/krt-scan.h36
-rw-r--r--sysdep/linux/netlink/krt-set.h28
-rw-r--r--sysdep/linux/sysio.h73
-rw-r--r--sysdep/unix/Modules10
-rw-r--r--sysdep/unix/io.c2
-rw-r--r--sysdep/unix/krt-iface.c233
-rw-r--r--sysdep/unix/krt-iface.h23
-rw-r--r--sysdep/unix/krt-set.c111
-rw-r--r--sysdep/unix/krt-set.h21
-rw-r--r--sysdep/unix/krt.Y21
-rw-r--r--sysdep/unix/krt.c317
-rw-r--r--sysdep/unix/krt.h62
-rw-r--r--sysdep/unix/main.c2
-rw-r--r--sysdep/unix/timer.h18
-rw-r--r--tools/Makefile.in16
73 files changed, 1398 insertions, 1515 deletions
diff --git a/aclocal.m4 b/aclocal.m4
index ee545252..75b3f92a 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -133,23 +133,6 @@ if test "$bird_cv_struct_ip_mreqn" = yes ; then
fi
])
-AC_DEFUN(BIRD_CHECK_LINUX_VERSION,
-[AC_CACHE_CHECK([Linux kernel version], bird_cv_sys_linux_version, [
-AC_REQUIRE_CPP()dnl
-cat > conftest.$ac_ext <<EOF
-[#]line __oline__ "configure"
-#include "confdefs.h"
-#include <linux/version.h>
-VERSION: UTS_RELEASE
-EOF
-bird_cv_sys_linux_version=`eval "$ac_cpp conftest.$ac_ext" 2>&AC_FD_CC | sed '/^VERSION/!d;s/^VERSION: "//;s/".*//'`
-rm -rf conftest*
-if test -z "$bird_cv_sys_linux_version" ; then
- AC_MSG_RESULT([unknown])
- AC_MSG_ERROR([Cannot determine kernel version])
-fi
-])])
-
AC_DEFUN(BIRD_CHECK_GCC_OPTIONS,
[AC_CACHE_VAL(bird_cv_c_option_no_pointer_sign, [
cat >conftest.c <<EOF
diff --git a/client/client.c b/client/client.c
index 7f9e0ef4..8711cf0a 100644
--- a/client/client.c
+++ b/client/client.c
@@ -135,6 +135,14 @@ submit_server_command(char *cmd)
num_lines = 2;
}
+static void
+add_history_dedup(char *cmd)
+{
+ /* Add history line if it differs from the last one */
+ HIST_ENTRY *he = history_get(history_length);
+ if (!he || strcmp(he->line, cmd))
+ add_history(cmd);
+}
static void
got_line(char *cmd_buffer)
@@ -151,7 +159,7 @@ got_line(char *cmd_buffer)
cmd = cmd_expand(cmd_buffer);
if (cmd)
{
- add_history(cmd);
+ add_history_dedup(cmd);
if (!handle_internal_command(cmd))
submit_server_command(cmd);
@@ -159,7 +167,7 @@ got_line(char *cmd_buffer)
free(cmd);
}
else
- add_history(cmd_buffer);
+ add_history_dedup(cmd_buffer);
}
free(cmd_buffer);
}
diff --git a/configure.in b/configure.in
index 46a6ecd9..dd57ab51 100644
--- a/configure.in
+++ b/configure.in
@@ -6,17 +6,20 @@ AC_REVISION($Id$)
AC_INIT(conf/confbase.Y)
AC_CONFIG_AUX_DIR(tools)
-AC_ARG_ENABLE(debug,[ --enable-debug enable internal debugging routines (default: disabled)],,enable_debug=no)
-AC_ARG_ENABLE(memcheck,[ --enable-memcheck check memory allocations when debugging (default: enabled)],,enable_memcheck=yes)
-AC_ARG_ENABLE(client,[ --enable-client enable building of BIRD client (default: enabled)],,enable_client=yes)
-AC_ARG_ENABLE(ipv6,[ --enable-ipv6 enable building of IPv6 version (default: disabled)],,enable_ipv6=no)
-AC_ARG_WITH(sysconfig,[ --with-sysconfig=FILE use specified BIRD system configuration file])
-AC_ARG_WITH(protocols,[ --with-protocols=LIST include specified routing protocols (default: all)],,[with_protocols="all"])
-AC_ARG_WITH(sysinclude,[ --with-sysinclude=PATH search for system includes on specified place])
-AC_ARG_WITH(iproutedir,[ --with-iproutedir=PATH path to iproute2 config files (default: /etc/iproute2)],[given_iproutedir="yes"])
-AC_ARG_VAR([FLEX], [location of the Flex program])
-AC_ARG_VAR([BISON], [location of the Bison program])
-AC_ARG_VAR([M4], [location of the M4 program])
+AC_ARG_ENABLE(debug, [ --enable-debug enable internal debugging routines (default: disabled)],,enable_debug=no)
+AC_ARG_ENABLE(memcheck, [ --enable-memcheck check memory allocations when debugging (default: enabled)],,enable_memcheck=yes)
+AC_ARG_ENABLE(client, [ --enable-client enable building of BIRD client (default: enabled)],,enable_client=yes)
+AC_ARG_ENABLE(ipv6, [ --enable-ipv6 enable building of IPv6 version (default: disabled)],,enable_ipv6=no)
+AC_ARG_WITH(suffix, [ --with-suffix=STRING use specified suffix for BIRD files (default: 6 for IPv6 version)],[given_suffix="yes"])
+AC_ARG_WITH(sysconfig, [ --with-sysconfig=FILE use specified BIRD system configuration file])
+AC_ARG_WITH(protocols, [ --with-protocols=LIST include specified routing protocols (default: all)],,[with_protocols="all"])
+AC_ARG_WITH(sysinclude, [ --with-sysinclude=PATH search for system includes on specified place])
+AC_ARG_WITH(runtimedir, [ --with-runtimedir=PATH path for runtime files (default: $(localstatedir)/run)],[runtimedir="$with_runtimedir"],[runtimedir="\$(localstatedir)/run"])
+AC_ARG_WITH(iproutedir, [ --with-iproutedir=PATH path to iproute2 config files (default: /etc/iproute2)],[given_iproutedir="yes"])
+AC_ARG_VAR([FLEX], [location of the Flex program])
+AC_ARG_VAR([BISON], [location of the Bison program])
+AC_ARG_VAR([M4], [location of the M4 program])
+
if test "$srcdir" = . ; then
# Building in current directory => create obj directory holding all objects
@@ -39,21 +42,37 @@ esac
AC_SUBST(objdir)
AC_SUBST(exedir)
AC_SUBST(srcdir_rel_mf)
+AC_SUBST(runtimedir)
if test "$enable_ipv6" = yes ; then
ip=ipv6
- SUFFIX6=6
+ SUFFIX=6
all_protocols=bgp,ospf,pipe,radv,rip,static
else
ip=ipv4
- SUFFIX6=""
+ SUFFIX=""
all_protocols=bgp,ospf,pipe,rip,static
fi
+if test "$given_suffix" = yes ; then
+ SUFFIX="$with_suffix"
+fi
+AC_SUBST(SUFFIX)
+
if test "$with_protocols" = all ; then
with_protocols="$all_protocols"
fi
+if test "$enable_debug" = yes ; then
+ CONFIG_FILE="bird$SUFFIX.conf"
+ CONTROL_SOCKET="bird$SUFFIX.ctl"
+else
+ CONFIG_FILE="\$(sysconfdir)/bird$SUFFIX.conf"
+ CONTROL_SOCKET="$runtimedir/bird$SUFFIX.ctl"
+fi
+AC_SUBST(CONFIG_FILE)
+AC_SUBST(CONTROL_SOCKET)
+
AC_SEARCH_LIBS(clock_gettime,[c rt posix4])
AC_CANONICAL_HOST
@@ -105,19 +124,11 @@ elif test -f sysconfig.h ; then
sysdesc=sysconfig
else
case "$ip:$host_os" in
- ipv4:linux*) BIRD_CHECK_LINUX_VERSION
+ ipv6:linux*) sysdesc=linux-v6
default_iproutedir="/etc/iproute2"
- case $bird_cv_sys_linux_version in
- 1.*|2.0.*) sysdesc=linux-20 ;;
- *) sysdesc=linux-22 ;;
- esac
;;
- ipv6:linux*) BIRD_CHECK_LINUX_VERSION
+ ipv4:linux*) sysdesc=linux
default_iproutedir="/etc/iproute2"
- case $bird_cv_sys_linux_version in
- 1.*|2.0.*) AC_MSG_ERROR([This version of Linux doesn't support IPv6.]) ;;
- *) sysdesc=linux-v6 ;;
- esac
;;
ipv6:netbsd*) sysdesc=bsd-v6
CPPFLAGS="$CPPFLAGS -I/usr/pkg/include"
@@ -180,7 +191,7 @@ AC_MSG_RESULT(ok)
AC_SUBST(protocols)
case $sysdesc in
- */linux-22*|*/linux-v6*)
+ */linux*|*/linux-v6*)
AC_CHECK_HEADER(linux/rtnetlink.h,,[AC_MSG_ERROR([Appropriate version of Linux kernel headers not found.])],[
#include <asm/types.h>
#include <sys/socket.h>
@@ -233,7 +244,6 @@ if test "$enable_client" = yes ; then
fi
AC_SUBST(CLIENT)
AC_SUBST(CLIENT_LIBS)
-AC_SUBST(SUFFIX6)
mkdir -p $objdir/sysdep
AC_CONFIG_HEADERS([$objdir/sysdep/autoconf.h:sysdep/autoconf.h.in])
diff --git a/doc/bird.sgml b/doc/bird.sgml
index 20738be3..087a4ebf 100644
--- a/doc/bird.sgml
+++ b/doc/bird.sgml
@@ -426,10 +426,37 @@ to zero to disable it. An empty <cf><m/switch/</cf> is equivalent to <cf/on/
uses global router id.
<tag>import all | none | filter <m/name/ | filter { <m/filter commands/ } | where <m/filter expression/</tag>
- Specify a filter to be used for filtering routes coming from the protocol to the routing table. <cf/all/ is shorthand for <cf/where true/ and <cf/none/ is shorthand for <cf/where false/. Default: <cf/all/.
-
- <tag>export <m/filter/</tag> This is similar to the <cf>import</cf> keyword, except that it
- works in the direction from the routing table to the protocol. Default: <cf/none/.
+ Specify a filter to be used for filtering routes coming from
+ the protocol to the routing table. <cf/all/ is shorthand for
+ <cf/where true/ and <cf/none/ is shorthand for
+ <cf/where false/. Default: <cf/all/.
+
+ <tag>export <m/filter/</tag>
+ This is similar to the <cf>import</cf> keyword, except that it
+ works in the direction from the routing table to the protocol.
+ Default: <cf/none/.
+
+ <tag>import limit <m/number/ [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
+ log message. Block action ignores new routes coming from the
+ protocol. Restart and disable actions shut the protocol down
+ like appropriate commands. Disable is the default action if an
+ action is not explicitly specified. Note that limits are reset
+ during protocol reconfigure, reload or restart.
+ Default: <cf/none/.
+
+ <tag>export limit <m/number/ [action warn | block | restart | disable]</tag>
+ Specify an export route limit, works similarly to
+ the <cf>import limit</cf> option, but for the routes exported
+ to the protocol. This option is experimental, there are some
+ problems in details of its behavior -- the number of exported
+ routes can temporarily exceed the limit without triggering it
+ during protocol reload, exported routes counter ignores route
+ blocking and block action also blocks route updates of alread
+ accepted routes -- and these details will probably change in
+ the future. Default: <cf/none/.
<tag>description "<m/text/"</tag> This is an optional
description of the protocol. It is displayed as a part of the
@@ -1045,7 +1072,16 @@ undefined value is regarded as empty clist for most purposes.
routes). Read-only.
<tag><m/enum/ dest</tag>
- Type of destination the packets should be sent to (<cf/RTD_ROUTER/ for forwarding to a neighboring router, <cf/RTD_DEVICE/ for routing to a directly-connected network, <cf/RTD_BLACKHOLE/ for packets to be silently discarded, <cf/RTD_UNREACHABLE/, <cf/RTD_PROHIBIT/ for packets that should be returned with ICMP host unreachable / ICMP administratively prohibited messages). Read-only.
+ Type of destination the packets should be sent to
+ (<cf/RTD_ROUTER/ for forwarding to a neighboring router,
+ <cf/RTD_DEVICE/ for routing to a directly-connected network,
+ <cf/RTD_MULTIPATH/ for multipath destinations,
+ <cf/RTD_BLACKHOLE/ for packets to be silently discarded,
+ <cf/RTD_UNREACHABLE/, <cf/RTD_PROHIBIT/ for packets that
+ should be returned with ICMP host unreachable / ICMP
+ administratively prohibited messages). Can be changed, but
+ only to <cf/RTD_BLACKHOLE/, <cf/RTD_UNREACHABLE/ or
+ <cf/RTD_PROHIBIT/.
<tag><m/int/ igp_metric</tag>
The optional attribute that can be used to specify a distance
@@ -1327,7 +1363,8 @@ 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. Default: no limit.
+ exceeded, the connection is closed with error. Limit is currently implemented as
+ <cf/import limit number exceed restart/. 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
@@ -1774,7 +1811,7 @@ protocol ospf &lt;name&gt; {
summary &lt;switch&gt;;
cost &lt;num&gt;;
}
- interface &lt;interface pattern&gt; {
+ interface &lt;interface pattern&gt; [instance &lt;num&gt;] {
cost &lt;num&gt;;
stub &lt;switch&gt;;
hello &lt;num&gt;;
@@ -1788,6 +1825,7 @@ protocol ospf &lt;name&gt; {
type [broadcast|bcast|pointopoint|ptp|
nonbroadcast|nbma|pointomultipoint|ptmp];
strict nonbroadcast &lt;switch&gt;;
+ real broadcast &lt;switch&gt;;
check link &lt;switch&gt;;
ecmp weight &lt;num&gt;;
authentication [none|simple|cryptographic];
@@ -1804,7 +1842,7 @@ protocol ospf &lt;name&gt; {
&lt;ip&gt; eligible;
};
};
- virtual link &lt;id&gt; {
+ virtual link &lt;id&gt; [instance &lt;num&gt;] {
hello &lt;num&gt;;
retransmit &lt;num&gt;;
wait &lt;num&gt;;
@@ -1924,14 +1962,19 @@ protocol ospf &lt;name&gt; {
subnetworks of given stub network are suppressed. This might
be used, for example, to aggregate generated stub networks.
- <tag>interface <M>pattern</M></tag>
+ <tag>interface <M>pattern</M> [instance <m/num/]</tag>
Defines that the specified interfaces belong to the area being defined.
See <ref id="dsc-iface" name="interface"> common option for detailed description.
+ In OSPFv3, you can specify instance ID for that interface
+ description, so it is possible to have several instances of
+ that interface with different options or even in different areas.
- <tag>virtual link <M>id</M></tag>
- Virtual link to router with the router id. Virtual link acts as a
- point-to-point interface belonging to backbone. The actual area is
- used as transport area. This item cannot be in the backbone.
+ <tag>virtual link <M>id</M> [instance <m/num/]</tag>
+ Virtual link to router with the router id. Virtual link acts
+ as a point-to-point interface belonging to backbone. The
+ actual area is used as transport area. This item cannot be in
+ the backbone. In OSPFv3, you could also use several virtual
+ links to one destination with different instance IDs.
<tag>cost <M>num</M></tag>
Specifies output cost (metric) of an interface. Default value is 10.
@@ -2016,6 +2059,16 @@ protocol ospf &lt;name&gt; {
If set, don't send hello to any undefined neighbor. This switch
is ignored on other than NBMA or PtMP networks. Default value is no.
+ <tag>real broadcast <m/switch/</tag>
+ In <cf/type broadcast/ or <cf/type ptp/ network
+ configuration, OSPF packets are sent as IP multicast
+ packets. This option changes the behavior to using
+ old-fashioned IP broadcast packets. This may be useful as a
+ workaround if IP multicast for some reason does not work or
+ does not work reliably. This is a non-standard option and
+ probably is not interoperable with other OSPF
+ implementations. Default value is no.
+
<tag>check link <M>switch</M></tag>
If set, a hardware link state (reported by OS) is taken into
consideration. When a link disappears (e.g. an ethernet cable is
@@ -2397,6 +2450,20 @@ protocol radv {
prefix 2001:0DB8:2000::/48 {
autonomous off; # Do not autoconfigure
};
+
+ rdnss 2001:0DB8:1234::10; # Short form of RDNSS
+
+ rdnss {
+ lifetime mult 10;
+ ns 2001:0DB8:1234::11;
+ ns 2001:0DB8:1234::12;
+ };
+
+ dnssl {
+ lifetime 3600;
+ domain "abc.com";
+ domain "xyz.com";
+ };
}
</code>
diff --git a/filter/config.Y b/filter/config.Y
index 2e8b522e..0eeb2ce1 100644
--- a/filter/config.Y
+++ b/filter/config.Y
@@ -703,7 +703,7 @@ static_attr:
| 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); }
+ | DEST { $$ = f_new_inst(); $$->aux = T_ENUM_RTD; $$->a2.i = OFFSETOF(struct rta, dest); $$->a1.i = 1; }
;
term:
diff --git a/filter/filter.c b/filter/filter.c
index acdcfd2b..49b67391 100644
--- a/filter/filter.c
+++ b/filter/filter.c
@@ -852,12 +852,25 @@ interpret(struct f_inst *what)
{
struct rta *rta = (*f_rte)->attrs;
switch (what->aux) {
- case T_ENUM:
- * ((char *) rta + what->a2.i) = v1.val.i;
- break;
+
case T_IP:
* (ip_addr *) ((char *) rta + what->a2.i) = v1.val.px.ip;
break;
+
+ case T_ENUM_SCOPE:
+ rta->scope = v1.val.i;
+ break;
+
+ case T_ENUM_RTD:
+ 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" );
+ rta->dest = i;
+ rta->gw = IPA_NONE;
+ rta->iface = NULL;
+ rta->nexthops = NULL;
+ break;
+
default:
bug( "Unknown type in set of static attribute" );
}
diff --git a/lib/ipv4.c b/lib/ipv4.c
index 8488a286..751351ca 100644
--- a/lib/ipv4.c
+++ b/lib/ipv4.c
@@ -60,7 +60,7 @@ ipv4_class_mask(u32 a)
if (a < 0x80000000)
m = 0xff000000;
- if (a < 0xc0000000)
+ else if (a < 0xc0000000)
m = 0xffff0000;
else
m = 0xffffff00;
diff --git a/lib/lists.h b/lib/lists.h
index 6fab12c4..0b0fdbe3 100644
--- a/lib/lists.h
+++ b/lib/lists.h
@@ -34,7 +34,8 @@ typedef struct list { /* In fact two overlayed nodes */
#define HEAD(list) ((void *)((list).head))
#define TAIL(list) ((void *)((list).tail))
#define NODE_NEXT(n) ((void *)((NODE (n))->next))
-#define WALK_LIST(n,list) for(n=HEAD(list);(NODE (n))->next; n=NODE_NEXT(n))
+#define NODE_VALID(n) ((NODE (n))->next)
+#define WALK_LIST(n,list) for(n=HEAD(list); NODE_VALID(n); n=NODE_NEXT(n))
#define WALK_LIST_DELSAFE(n,nxt,list) \
for(n=HEAD(list); nxt=NODE_NEXT(n); n=(void *) nxt)
/* WALK_LIST_FIRST supposes that called code removes each processed node */
diff --git a/lib/resource.c b/lib/resource.c
index 24164ec2..42243aa2 100644
--- a/lib/resource.c
+++ b/lib/resource.c
@@ -352,7 +352,7 @@ mb_alloc(pool *p, unsigned size)
* zeroes and creates a memory block resource representing this memory
* chunk in the pool @p.
*
- * Please note that mb_alloc() returns a pointer to the memory
+ * Please note that mb_allocz() returns a pointer to the memory
* chunk, not to the resource, hence you have to free it using
* mb_free(), not rfree().
*/
diff --git a/nest/a-path.c b/nest/a-path.c
index 058b4344..63ac402e 100644
--- a/nest/a-path.c
+++ b/nest/a-path.c
@@ -15,7 +15,6 @@
#include "lib/string.h"
#include "filter/filter.h"
-
// static inline void put_as(byte *data, u32 as) { put_u32(data, as); }
// static inline u32 get_as(byte *data) { return get_u32(data); }
diff --git a/nest/config.Y b/nest/config.Y
index 2bc5a4ab..a75dd0c3 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -44,6 +44,7 @@ CF_DECLS
CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILTERS)
+CF_KEYWORDS(LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE)
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(LISTEN, BGP, V6ONLY, DUAL, ADDRESS, PORT, PASSWORDS, DESCRIPTION, SORTED)
@@ -64,8 +65,9 @@ CF_ENUM(T_ENUM_ROA, ROA_, UNKNOWN, VALID, INVALID)
%type <ro> roa_args
%type <rot> roa_table_arg
%type <sd> sym_args
-%type <i> proto_start echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_or_preexport roa_mode tab_sorted
+%type <i> proto_start echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_or_preexport roa_mode limit_action tab_sorted
%type <ps> proto_patt proto_patt2
+%type <g> limit_spec
CF_GRAMMAR
@@ -183,6 +185,8 @@ proto_item:
| MRTDUMP mrtdump_mask { this_proto->mrtdump = $2; }
| IMPORT imexport { this_proto->in_filter = $2; }
| EXPORT imexport { this_proto->out_filter = $2; }
+ | IMPORT LIMIT limit_spec { this_proto->in_limit = $3; }
+ | EXPORT LIMIT limit_spec { this_proto->out_limit = $3; }
| TABLE rtable { this_proto->table = $2; }
| ROUTER ID idval { this_proto->router_id = $3; }
| DESCRIPTION TEXT { this_proto->dsc = $2; }
@@ -195,6 +199,23 @@ imexport:
| NONE { $$ = FILTER_REJECT; }
;
+limit_action:
+ /* default */ { $$ = PLA_DISABLE; }
+ | ACTION WARN { $$ = PLA_WARN; }
+ | ACTION BLOCK { $$ = PLA_BLOCK; }
+ | ACTION RESTART { $$ = PLA_RESTART; }
+ | ACTION DISABLE { $$ = PLA_DISABLE; }
+ ;
+
+limit_spec:
+ expr limit_action {
+ struct proto_limit *l = cfg_allocz(sizeof(struct proto_limit));
+ l->limit = $1;
+ l->action = $2;
+ $$ = l;
+ }
+ ;
+
rtable:
SYM {
if ($1->class != SYM_TABLE) cf_error("Table name expected");
diff --git a/nest/proto.c b/nest/proto.c
index 802d5238..887d3e5e 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -34,11 +34,13 @@ static list flush_proto_list;
static struct proto *initial_device_proto;
static event *proto_flush_event;
+static timer *proto_shutdown_timer;
static char *p_states[] = { "DOWN", "START", "UP", "STOP" };
static char *c_states[] = { "HUNGRY", "FEEDING", "HAPPY", "FLUSHING" };
static void proto_flush_loop(void *);
+static void proto_shutdown_loop(struct timer *);
static void proto_rethink_goal(struct proto *p);
static char *proto_state_name(struct proto *p);
@@ -134,8 +136,6 @@ extern pool *rt_table_pool;
* proto_add_announce_hook - connect protocol to a routing table
* @p: protocol instance
* @t: routing table to connect to
- * @in: input filter
- * @out: output filter
* @stats: per-table protocol statistics
*
* This function creates a connection between the protocol instance @p
@@ -155,8 +155,7 @@ extern pool *rt_table_pool;
* automatically by the core code.
*/
struct announce_hook *
-proto_add_announce_hook(struct proto *p, struct rtable *t, struct filter *in,
- struct filter *out, struct proto_stats *stats)
+proto_add_announce_hook(struct proto *p, struct rtable *t, struct proto_stats *stats)
{
struct announce_hook *h;
@@ -166,8 +165,6 @@ proto_add_announce_hook(struct proto *p, struct rtable *t, struct filter *in,
h = mb_allocz(rt_table_pool, sizeof(struct announce_hook));
h->table = t;
h->proto = p;
- h->in_filter = in;
- h->out_filter = out;
h->stats = stats;
h->next = p->ahooks;
@@ -409,11 +406,14 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
if (p->proto->multitable)
return 1;
- /* Update filters in the main announce hook */
+ /* Update filters and limits in the main announce hook
+ Note that this also resets limit state */
if (p->main_ahook)
{
p->main_ahook->in_filter = nc->in_filter;
p->main_ahook->out_filter = nc->out_filter;
+ p->main_ahook->in_limit = nc->in_limit;
+ p->main_ahook->out_limit = nc->out_limit;
}
/* Update routes when filters changed. If the protocol in not UP,
@@ -438,6 +438,7 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
and we have to do regular protocol restart. */
log(L_INFO "Restarting protocol %s", p->name);
p->disabled = 1;
+ p->down_code = PDC_CF_RESTART;
proto_rethink_goal(p);
p->disabled = 0;
proto_rethink_goal(p);
@@ -512,6 +513,7 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty
log(L_INFO "Disabling protocol %s", p->name);
PD(p, "Restarting");
+ p->down_code = nc->disabled ? PDC_CF_DISABLE : PDC_CF_RESTART;
p->cf_new = nc;
}
else
@@ -519,9 +521,11 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty
if (!shutting_down)
log(L_INFO "Removing protocol %s", p->name);
PD(p, "Unconfigured");
+ p->down_code = PDC_CF_REMOVE;
p->cf_new = NULL;
}
p->reconfiguring = 1;
+
config_add_obstacle(old);
proto_rethink_goal(p);
}
@@ -704,6 +708,8 @@ protos_build(void)
proto_pool = rp_new(&root_pool, "Protocols");
proto_flush_event = ev_new(proto_pool);
proto_flush_event->hook = proto_flush_loop;
+ proto_shutdown_timer = tm_new(proto_pool);
+ proto_shutdown_timer->hook = proto_shutdown_loop;
}
static void
@@ -769,14 +775,28 @@ proto_schedule_feed(struct proto *p, int initial)
p->core_state = FS_FEEDING;
p->refeeding = !initial;
- /* Hack: reset exp_routes during refeed, and do not decrease it later */
+ /* FIXME: This should be changed for better support of multitable protos */
if (!initial)
- p->stats.exp_routes = 0;
+ {
+ struct announce_hook *ah;
+ for (ah = p->ahooks; ah; ah = ah->next)
+ proto_reset_limit(ah->out_limit);
+
+ /* Hack: reset exp_routes during refeed, and do not decrease it later */
+ p->stats.exp_routes = 0;
+ }
/* Connect protocol to routing table */
if (initial && !p->proto->multitable)
- p->main_ahook = proto_add_announce_hook(p, p->table,
- p->cf->in_filter, p->cf->out_filter, &p->stats);
+ {
+ p->main_ahook = proto_add_announce_hook(p, p->table, &p->stats);
+ p->main_ahook->in_filter = p->cf->in_filter;
+ p->main_ahook->out_filter = p->cf->out_filter;
+ p->main_ahook->in_limit = p->cf->in_limit;
+ p->main_ahook->out_limit = p->cf->out_limit;
+ proto_reset_limit(p->main_ahook->in_limit);
+ proto_reset_limit(p->main_ahook->out_limit);
+ }
proto_relink(p);
p->attn->hook = initial ? proto_feed_initial : proto_feed_more;
@@ -860,6 +880,44 @@ proto_schedule_flush(struct proto *p)
proto_schedule_flush_loop();
}
+/* Temporary hack to propagate restart to BGP */
+int proto_restart;
+
+static void
+proto_shutdown_loop(struct timer *t UNUSED)
+{
+ struct proto *p, *p_next;
+
+ WALK_LIST_DELSAFE(p, p_next, active_proto_list)
+ if (p->down_sched)
+ {
+ proto_restart = (p->down_sched == PDS_RESTART);
+
+ p->disabled = 1;
+ proto_rethink_goal(p);
+ if (proto_restart)
+ {
+ p->disabled = 0;
+ proto_rethink_goal(p);
+ }
+ }
+}
+
+static inline void
+proto_schedule_down(struct proto *p, byte restart, byte code)
+{
+ /* Does not work for other states (even PS_START) */
+ ASSERT(p->proto_state == PS_UP);
+
+ /* Scheduled restart may change to shutdown, but not otherwise */
+ if (p->down_sched == PDS_DISABLE)
+ return;
+
+ p->down_sched = restart ? PDS_RESTART : PDS_DISABLE;
+ p->down_code = code;
+ tm_start_max(proto_shutdown_timer, restart ? 2 : 0);
+}
+
/**
* proto_request_feeding - request feeding routes to the protocol
@@ -890,6 +948,62 @@ proto_request_feeding(struct proto *p)
proto_schedule_feed(p, 0);
}
+static const char *
+proto_limit_name(struct proto_limit *l)
+{
+ const char *actions[] = {
+ [PLA_WARN] = "warn",
+ [PLA_BLOCK] = "block",
+ [PLA_RESTART] = "restart",
+ [PLA_DISABLE] = "disable",
+ };
+
+ return actions[l->action];
+}
+
+/**
+ * proto_notify_limit: notify about limit hit and take appropriate action
+ * @ah: announce hook
+ * @l: limit being hit
+ * @rt_count: the number of routes
+ *
+ * The function is called by the route processing core when limit @l
+ * is breached. It activates the limit and tooks appropriate action
+ * according to @l->action.
+ */
+void
+proto_notify_limit(struct announce_hook *ah, struct proto_limit *l, u32 rt_count)
+{
+ struct proto *p = ah->proto;
+ int dir = (ah->in_limit == l);
+
+ if (l->state == PLS_BLOCKED)
+ return;
+
+ /* For warning action, we want the log message every time we hit the limit */
+ if (!l->state || ((l->action == PLA_WARN) && (rt_count == l->limit)))
+ log(L_WARN "Protocol %s hits route %s limit (%d), action: %s",
+ p->name, dir ? "import" : "export", l->limit, proto_limit_name(l));
+
+ switch (l->action)
+ {
+ case PLA_WARN:
+ l->state = PLS_ACTIVE;
+ break;
+
+ case PLA_BLOCK:
+ l->state = PLS_BLOCKED;
+ break;
+
+ case PLA_RESTART:
+ case PLA_DISABLE:
+ l->state = PLS_BLOCKED;
+ proto_schedule_down(p, l->action == PLA_RESTART,
+ dir ? PDC_IN_LIMIT_HIT : PDC_OUT_LIMIT_HIT);
+ break;
+ }
+}
+
/**
* proto_notify_state - notify core about protocol state change
* @p: protocol the state of which has changed
@@ -919,6 +1033,8 @@ proto_notify_state(struct proto *p, unsigned ps)
switch (ps)
{
case PS_DOWN:
+ p->down_code = 0;
+ p->down_sched = 0;
if ((cs == FS_FEEDING) || (cs == FS_HAPPY))
proto_schedule_flush(p);
@@ -942,6 +1058,7 @@ proto_notify_state(struct proto *p, unsigned ps)
proto_schedule_feed(p, 1);
break;
case PS_STOP:
+ p->down_sched = 0;
if ((cs == FS_FEEDING) || (cs == FS_HAPPY))
proto_schedule_flush(p);
break;
@@ -994,6 +1111,16 @@ proto_show_stats(struct proto_stats *s)
}
void
+proto_show_limit(struct proto_limit *l, const char *dsc)
+{
+ if (!l)
+ return;
+
+ cli_msg(-1006, " %-16s%d%s", dsc, l->limit, l->state ? " [HIT]" : "");
+ cli_msg(-1006, " Action: %s", proto_limit_name(l));
+}
+
+void
proto_show_basic_info(struct proto *p)
{
// cli_msg(-1006, " Table: %s", p->table->name);
@@ -1001,6 +1128,9 @@ proto_show_basic_info(struct proto *p)
cli_msg(-1006, " Input filter: %s", filter_name(p->cf->in_filter));
cli_msg(-1006, " Output filter: %s", filter_name(p->cf->out_filter));
+ proto_show_limit(p->cf->in_limit, "Import limit:");
+ proto_show_limit(p->cf->out_limit, "Export limit:");
+
if (p->proto_state != PS_DOWN)
proto_show_stats(&p->stats);
}
@@ -1052,6 +1182,7 @@ proto_cmd_disable(struct proto *p, unsigned int arg UNUSED, int cnt UNUSED)
log(L_INFO "Disabling protocol %s", p->name);
p->disabled = 1;
+ p->down_code = PDC_CMD_DISABLE;
proto_rethink_goal(p);
cli_msg(-9, "%s: disabled", p->name);
}
@@ -1082,6 +1213,7 @@ proto_cmd_restart(struct proto *p, unsigned int arg UNUSED, int cnt UNUSED)
log(L_INFO "Restarting protocol %s", p->name);
p->disabled = 1;
+ p->down_code = PDC_CMD_RESTART;
proto_rethink_goal(p);
p->disabled = 0;
proto_rethink_goal(p);
@@ -1105,12 +1237,21 @@ proto_cmd_reload(struct proto *p, unsigned int dir, int cnt UNUSED)
/* re-importing routes */
if (dir != CMD_RELOAD_OUT)
- if (! (p->reload_routes && p->reload_routes(p)))
- {
- cli_msg(-8006, "%s: reload failed", p->name);
- return;
- }
-
+ {
+ if (! (p->reload_routes && p->reload_routes(p)))
+ {
+ cli_msg(-8006, "%s: reload failed", p->name);
+ return;
+ }
+
+ /*
+ * Should be done before reload_routes() hook?
+ * Perhaps, but these hooks work asynchronously.
+ */
+ if (!p->proto->multitable)
+ proto_reset_limit(p->main_ahook->in_limit);
+ }
+
/* re-exporting routes */
if (dir != CMD_RELOAD_IN)
proto_request_feeding(p);
diff --git a/nest/protocol.h b/nest/protocol.h
index 983ce75a..8a632715 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -94,13 +94,15 @@ struct proto_config {
u32 router_id; /* Protocol specific router ID */
struct rtable_config *table; /* Table we're attached to */
struct filter *in_filter, *out_filter; /* Attached filters */
+ struct proto_limit *in_limit; /* Limit for importing routes from protocol */
+ struct proto_limit *out_limit; /* Limit for exporting routes to protocol */
/* Check proto_reconfigure() and proto_copy_config() after changing struct proto_config */
/* Protocol-specific data follow... */
};
- /* Protocol statistics */
+/* Protocol statistics */
struct proto_stats {
/* Import - from protocol to core */
u32 imp_routes; /* Number of routes successfully imported to the (adjacent) routing table */
@@ -138,14 +140,16 @@ struct proto {
u32 debug; /* Debugging flags */
u32 mrtdump; /* MRTDump flags */
unsigned preference; /* Default route preference */
- unsigned accept_ra_types; /* Which types of route announcements are accepted (RA_OPTIMAL or RA_ANY) */
- unsigned disabled; /* Manually disabled */
- unsigned proto_state; /* Protocol state machine (see below) */
- unsigned core_state; /* Core state machine (see below) */
- unsigned core_goal; /* State we want to reach (see below) */
- unsigned reconfiguring; /* We're shutting down due to reconfiguration */
- unsigned refeeding; /* We are refeeding (valid only if core_state == FS_FEEDING) */
- unsigned flushing; /* Protocol is flushed in current flush loop round */
+ byte accept_ra_types; /* Which types of route announcements are accepted (RA_OPTIMAL or RA_ANY) */
+ byte disabled; /* Manually disabled */
+ byte proto_state; /* Protocol state machine (PS_*, see below) */
+ byte core_state; /* Core state machine (FS_*, see below) */
+ byte core_goal; /* State we want to reach (FS_*, see below) */
+ byte reconfiguring; /* We're shutting down due to reconfiguration */
+ byte refeeding; /* We are refeeding (valid only if core_state == FS_FEEDING) */
+ byte flushing; /* Protocol is flushed in current flush loop round */
+ byte down_sched; /* Shutdown is scheduled for later (PDS_*) */
+ byte down_code; /* Reason for shutdown (PDC_* codes) */
u32 hash_key; /* Random key used for hashing of neighbors */
bird_clock_t last_state_change; /* Time of last state transition */
char *last_state_name_announced; /* Last state name we've announced to the user */
@@ -210,6 +214,18 @@ struct proto_spec {
};
+#define PDS_DISABLE 1 /* Proto disable scheduled */
+#define PDS_RESTART 2 /* Proto restart scheduled */
+
+#define PDC_CF_REMOVE 0x01 /* Removed in new config */
+#define PDC_CF_DISABLE 0x02 /* Disabled in new config */
+#define PDC_CF_RESTART 0x03 /* Restart due to reconfiguration */
+#define PDC_CMD_DISABLE 0x11 /* Result of disable command */
+#define PDC_CMD_RESTART 0x12 /* Result of restart command */
+#define PDC_IN_LIMIT_HIT 0x21 /* Route import limit reached */
+#define PDC_OUT_LIMIT_HIT 0x22 /* Route export limit reached - not implemented */
+
+
void *proto_new(struct proto_config *, unsigned size);
void *proto_config_new(struct protocol *, unsigned size, int class);
void proto_copy_config(struct proto_config *dest, struct proto_config *src);
@@ -220,6 +236,7 @@ proto_copy_rest(struct proto_config *dest, struct proto_config *src, unsigned si
{ memcpy(dest + 1, src + 1, size - sizeof(struct proto_config)); }
+void proto_show_limit(struct proto_limit *l, const char *dsc);
void proto_show_basic_info(struct proto *p);
void proto_cmd_show(struct proto *, unsigned int, int);
@@ -348,6 +365,36 @@ void proto_notify_state(struct proto *p, unsigned state);
extern struct proto_config *cf_dev_proto;
+
+/*
+ * Protocol limits
+ */
+
+#define PLA_WARN 1 /* Issue log warning */
+#define PLA_BLOCK 2 /* Block new routes */
+#define PLA_RESTART 4 /* Force protocol restart */
+#define PLA_DISABLE 5 /* Shutdown and disable protocol */
+
+#define PLS_INITIAL 0 /* Initial limit state after protocol start */
+#define PLS_ACTIVE 1 /* Limit was hit */
+#define PLS_BLOCKED 2 /* Limit is active and blocking new routes */
+
+struct proto_limit {
+ u32 limit; /* Maximum number of prefixes */
+ byte action; /* Action to take (PLA_*) */
+ byte state; /* State of limit (PLS_*) */
+};
+
+void proto_notify_limit(struct announce_hook *ah, struct proto_limit *l, u32 rt_count);
+
+static inline void
+proto_reset_limit(struct proto_limit *l)
+{
+ if (l)
+ l->state = PLS_INITIAL;
+}
+
+
/*
* Route Announcement Hook
*/
@@ -358,11 +405,13 @@ struct announce_hook {
struct proto *proto;
struct filter *in_filter; /* Input filter */
struct filter *out_filter; /* Output filter */
+ struct proto_limit *in_limit; /* Input limit */
+ struct proto_limit *out_limit; /* Output limit */
struct proto_stats *stats; /* Per-table protocol statistics */
struct announce_hook *next; /* Next hook for the same protocol */
};
-struct announce_hook *proto_add_announce_hook(struct proto *, struct rtable *, struct filter *, struct filter *, struct proto_stats *);
+struct announce_hook *proto_add_announce_hook(struct proto *p, struct rtable *t, struct proto_stats *stats);
struct announce_hook *proto_find_announce_hook(struct proto *p, struct rtable *t);
#endif
diff --git a/nest/rt-table.c b/nest/rt-table.c
index eb8304f7..165f42bb 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -250,6 +250,53 @@ do_rt_notify(struct announce_hook *ah, net *net, rte *new, rte *old, ea_list *tm
struct proto *p = ah->proto;
struct proto_stats *stats = ah->stats;
+
+ /*
+ * First, apply export limit.
+ *
+ * Export route limits has several problems. Because exp_routes
+ * counter is reset before refeed, we don't really know whether
+ * limit is breached and whether the update is new or not. Therefore
+ * the number of really exported routes may exceed the limit
+ * temporarily (routes exported before and new routes in refeed).
+ *
+ * Minor advantage is that if the limit is decreased and refeed is
+ * requested, the number of exported routes really decrease.
+ *
+ * Second problem is that with export limits, we don't know whether
+ * old was really exported (it might be blocked by limit). When a
+ * withdraw is exported, we announce it even when the previous
+ * update was blocked. This is not a big issue, but the same problem
+ * is in updating exp_routes counter. Therefore, to be consistent in
+ * increases and decreases of exp_routes, we count exported routes
+ * regardless of blocking by limits.
+ *
+ * Similar problem is in handling updates - when a new route is
+ * received and blocking is active, the route would be blocked, but
+ * when an update for the route will be received later, the update
+ * would be propagated (as old != NULL). Therefore, we have to block
+ * also non-new updates (contrary to import blocking).
+ */
+
+ struct proto_limit *l = ah->out_limit;
+ if (l && new)
+ {
+ if ((!old || refeed) && (stats->exp_routes >= l->limit))
+ proto_notify_limit(ah, l, stats->exp_routes);
+
+ if (l->state == PLS_BLOCKED)
+ {
+ stats->exp_routes++; /* see note above */
+ stats->exp_updates_rejected++;
+ rte_trace_out(D_FILTERS, p, new, "rejected [limit]");
+ new = NULL;
+
+ if (!old)
+ return;
+ }
+ }
+
+
if (new)
stats->exp_updates_accepted++;
else
@@ -284,10 +331,8 @@ do_rt_notify(struct announce_hook *ah, net *net, rte *new, rte *old, ea_list *tm
}
else
p->rt_notify(p, ah->table, net, new, old, new->attrs->eattrs);
-
}
-
static void
rt_notify_basic(struct announce_hook *ah, net *net, rte *new, rte *old, ea_list *tmpa, int refeed)
{
@@ -632,6 +677,21 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, str
return;
}
+ struct proto_limit *l = ah->in_limit;
+ if (l && !old && new)
+ {
+ if (stats->imp_routes >= l->limit)
+ proto_notify_limit(ah, l, stats->imp_routes);
+
+ if (l->state == PLS_BLOCKED)
+ {
+ stats->imp_updates_ignored++;
+ rte_trace_in(D_FILTERS, p, new, "ignored [limit]");
+ rte_free_quick(new);
+ return;
+ }
+ }
+
if (new)
stats->imp_updates_accepted++;
else
@@ -911,10 +971,7 @@ void
rte_dump(rte *e)
{
net *n = e->net;
- if (n)
- debug("%-1I/%2d ", n->n.prefix, n->n.pxlen);
- else
- debug("??? ");
+ debug("%-1I/%2d ", n->n.prefix, n->n.pxlen);
debug("KF=%02x PF=%02x pref=%d lm=%d ", n->n.flags, e->pflags, e->pref, now-e->lastmod);
rta_dump(e->attrs);
if (e->attrs->proto->proto->dump_attrs)
@@ -1923,14 +1980,14 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
d->net_counter++;
for(e=n->routes; e; e=e->next)
{
- struct ea_list *tmpa, *old_tmpa;
+ struct ea_list *tmpa;
struct proto *p0 = e->attrs->proto;
struct proto *p1 = d->export_protocol;
struct proto *p2 = d->show_protocol;
d->rt_counter++;
ee = e;
rte_update_lock(); /* We use the update buffer for filtering */
- old_tmpa = tmpa = p0->make_tmp_attrs ? p0->make_tmp_attrs(e, rte_update_pool) : NULL;
+ tmpa = p0->make_tmp_attrs ? p0->make_tmp_attrs(e, rte_update_pool) : NULL;
ok = (d->filter == FILTER_ACCEPT || f_run(d->filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT);
if (p2 && p2 != p0) ok = 0;
if (ok && d->export_mode)
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index d59b4308..0b52dedc 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -542,22 +542,6 @@ bgp_active(struct bgp_proto *p)
bgp_start_timer(conn->connect_retry_timer, delay);
}
-int
-bgp_apply_limits(struct bgp_proto *p)
-{
- if (p->cf->route_limit && (p->p.stats.imp_routes > p->cf->route_limit))
- {
- log(L_WARN "%s: Route limit exceeded, shutting down", p->p.name);
- bgp_store_error(p, NULL, BE_AUTO_DOWN, BEA_ROUTE_LIMIT_EXCEEDED);
- bgp_update_startup_delay(p);
- bgp_stop(p, 1); // Errcode 6, 1 - max number of prefixes reached
- return -1;
- }
-
- return 0;
-}
-
-
/**
* bgp_connect - initiate an outgoing connection
* @p: BGP instance
@@ -864,28 +848,58 @@ bgp_start(struct proto *P)
return PS_START;
}
+extern int proto_restart;
+
static int
bgp_shutdown(struct proto *P)
{
struct bgp_proto *p = (struct bgp_proto *) P;
- unsigned subcode;
+ unsigned subcode = 0;
BGP_TRACE(D_EVENTS, "Shutdown requested");
- bgp_store_error(p, NULL, BE_MAN_DOWN, 0);
- if (P->reconfiguring)
+ switch (P->down_code)
{
- if (P->cf_new)
- subcode = 6; // Errcode 6, 6 - other configuration change
+ case PDC_CF_REMOVE:
+ case PDC_CF_DISABLE:
+ subcode = 3; // Errcode 6, 3 - peer de-configured
+ break;
+
+ case PDC_CF_RESTART:
+ subcode = 6; // Errcode 6, 6 - other configuration change
+ break;
+
+ case PDC_CMD_DISABLE:
+ subcode = 2; // Errcode 6, 2 - administrative shutdown
+ break;
+
+ case PDC_CMD_RESTART:
+ subcode = 4; // Errcode 6, 4 - administrative reset
+ break;
+
+ case PDC_IN_LIMIT_HIT:
+ subcode = 1; // Errcode 6, 1 - max number of prefixes reached
+ /* log message for compatibility */
+ log(L_WARN "%s: Route limit exceeded, shutting down", p->p.name);
+ goto limit;
+
+ case PDC_OUT_LIMIT_HIT:
+ subcode = proto_restart ? 4 : 2; // Administrative reset or shutdown
+
+ limit:
+ bgp_store_error(p, NULL, BE_AUTO_DOWN, BEA_ROUTE_LIMIT_EXCEEDED);
+ if (proto_restart)
+ bgp_update_startup_delay(p);
else
- subcode = 3; // Errcode 6, 3 - peer de-configured
+ p->startup_delay = 0;
+ goto done;
}
- else
- subcode = 2; // Errcode 6, 2 - administrative shutdown
+ bgp_store_error(p, NULL, BE_MAN_DOWN, 0);
p->startup_delay = 0;
- bgp_stop(p, subcode);
+ done:
+ bgp_stop(p, subcode);
return p->p.proto_state;
}
@@ -972,6 +986,10 @@ bgp_check_config(struct bgp_config *c)
if (!c->gw_mode)
c->gw_mode = (c->multihop || internal) ? GW_RECURSIVE : GW_DIRECT;
+ /* Disable after error incompatible with restart limit action */
+ if (c->c.in_limit && (c->c.in_limit->action == PLA_RESTART) && c->disable_after_error)
+ c->c.in_limit->action = PLA_DISABLE;
+
if ((c->gw_mode == GW_RECURSIVE) && c->c.table->sorted)
cf_error("BGP in recursive mode prohibits sorted table");
@@ -1128,9 +1146,6 @@ bgp_get_status(struct proto *P, byte *buf)
bsprintf(buf, "%-14s%s%s", bgp_state_dsc(p), err1, err2);
}
-static inline bird_clock_t tm_remains(timer *t)
-{ return t->expires ? t->expires - now : 0; }
-
static void
bgp_show_proto_info(struct proto *P)
{
@@ -1170,9 +1185,9 @@ bgp_show_proto_info(struct proto *P)
p->rs_client ? " route-server" : "",
p->as4_session ? " AS4" : "");
cli_msg(-1006, " Source address: %I", p->source_addr);
- if (p->cf->route_limit)
+ if (P->cf->in_limit)
cli_msg(-1006, " Route limit: %d/%d",
- p->p.stats.imp_routes, p->cf->route_limit);
+ p->p.stats.imp_routes, P->cf->in_limit->limit);
cli_msg(-1006, " Hold timer: %d/%d",
tm_remains(c->hold_timer), c->hold_time);
cli_msg(-1006, " Keepalive timer: %d/%d",
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index 87734425..c3adf254 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -40,7 +40,6 @@ struct bgp_config {
int rr_client; /* Whether neighbor is RR client of me */
int rs_client; /* Whether neighbor is RS client of me */
int advertise_ipv4; /* Whether we should add IPv4 capability advertisement to OPEN message */
- u32 route_limit; /* Number of routes that may be imported, 0 means disable limit */
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) */
@@ -153,7 +152,6 @@ void bgp_conn_enter_established_state(struct bgp_conn *conn);
void bgp_conn_enter_close_state(struct bgp_conn *conn);
void bgp_conn_enter_idle_state(struct bgp_conn *conn);
void bgp_store_error(struct bgp_proto *p, struct bgp_conn *c, u8 class, u32 code);
-int bgp_apply_limits(struct bgp_proto *p);
void bgp_stop(struct bgp_proto *p, unsigned subcode);
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index f9a5be65..8b80d7fd 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -99,7 +99,11 @@ bgp_proto:
| bgp_proto CAPABILITIES bool ';' { BGP_CFG->capabilities = $3; }
| bgp_proto ADVERTISE IPV4 bool ';' { BGP_CFG->advertise_ipv4 = $4; }
| bgp_proto PASSWORD TEXT ';' { BGP_CFG->password = $3; }
- | bgp_proto ROUTE LIMIT expr ';' { BGP_CFG->route_limit = $4; }
+ | bgp_proto ROUTE LIMIT expr ';' {
+ this_proto->in_limit = cfg_allocz(sizeof(struct proto_limit));
+ this_proto->in_limit->limit = $4;
+ this_proto->in_limit->action = PLA_RESTART;
+ }
| 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; }
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index d3e9b6a1..cfa37fb5 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -915,9 +915,6 @@ bgp_do_rx_update(struct bgp_conn *conn,
if (n = net_find(p->p.table, prefix, pxlen))
rte_update(p->p.table, n, &p->p, &p->p, NULL);
}
-
- if (bgp_apply_limits(p) < 0)
- goto done;
}
done:
@@ -1034,9 +1031,6 @@ bgp_do_rx_update(struct bgp_conn *conn,
if (n = net_find(p->p.table, prefix, pxlen))
rte_update(p->p.table, n, &p->p, &p->p, NULL);
}
-
- if (bgp_apply_limits(p) < 0)
- goto done;
}
}
diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y
index 38e59886..67b0785f 100644
--- a/proto/ospf/config.Y
+++ b/proto/ospf/config.Y
@@ -107,7 +107,17 @@ static inline void
check_defcost(int cost)
{
if ((cost <= 0) || (cost >= LSINFINITY))
- cf_error("Default cost must be in range 1-%d", LSINFINITY);
+ cf_error("Default cost must be in range 1-%d", LSINFINITY-1);
+}
+
+static inline void
+set_instance_id(unsigned id)
+{
+#ifdef OSPFv3
+ OSPF_PATT->instance_id = id;
+#else
+ cf_error("Instance ID requires OSPFv3");
+#endif
}
CF_DECLS
@@ -120,7 +130,7 @@ CF_KEYWORDS(NONE, SIMPLE, AUTHENTICATION, STRICT, CRYPTOGRAPHIC)
CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, CHECK, LINK)
CF_KEYWORDS(RX, BUFFER, LARGE, NORMAL, STUBNET, HIDDEN, SUMMARY, TAG, EXTERNAL)
CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT, NSSA, TRANSLATOR, STABILITY)
-CF_KEYWORDS(GLOBAL, LSID, ROUTER, SELF)
+CF_KEYWORDS(GLOBAL, LSID, ROUTER, SELF, INSTANCE, REAL)
%type <t> opttext
%type <ld> lsadb_args
@@ -218,8 +228,8 @@ ospf_stubnet_item:
;
ospf_vlink:
- ospf_vlink_start '{' ospf_vlink_opts '}' { ospf_iface_finish(); }
- | ospf_vlink_start { ospf_iface_finish(); }
+ ospf_vlink_start ospf_instance_id '{' ospf_vlink_opts '}' { ospf_iface_finish(); }
+ | ospf_vlink_start ospf_instance_id { ospf_iface_finish(); }
;
ospf_vlink_opts:
@@ -277,6 +287,7 @@ ospf_iface_item:
| TYPE PTP { OSPF_PATT->type = OSPF_IT_PTP ; }
| TYPE POINTOMULTIPOINT { OSPF_PATT->type = OSPF_IT_PTMP ; }
| TYPE PTMP { OSPF_PATT->type = OSPF_IT_PTMP ; }
+ | REAL BROADCAST bool { OSPF_PATT->real_bcast = $3; if (OSPF_VERSION != 2) cf_error("Real broadcast option requires OSPFv2"); }
| TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error("Transmit delay must be in range 1-65535"); }
| PRIORITY expr { OSPF_PATT->priority = $2 ; if (($2<0) || ($2>255)) cf_error("Priority must be in range 0-255"); }
| STRICT NONBROADCAST bool { OSPF_PATT->strictnbma = $3 ; }
@@ -364,6 +375,11 @@ ospf_iface_start:
}
;
+ospf_instance_id:
+ /* empty */
+ | INSTANCE expr { set_instance_id($2); }
+ ;
+
ospf_iface_opts:
/* empty */
| ospf_iface_opts ospf_iface_item ';'
@@ -375,7 +391,7 @@ ospf_iface_opt_list:
;
ospf_iface:
- ospf_iface_start iface_patt_list ospf_iface_opt_list { ospf_iface_finish(); }
+ ospf_iface_start iface_patt_list ospf_instance_id ospf_iface_opt_list { ospf_iface_finish(); }
;
opttext:
diff --git a/proto/ospf/hello.c b/proto/ospf/hello.c
index d04cb54c..f9ba28f6 100644
--- a/proto/ospf/hello.c
+++ b/proto/ospf/hello.c
@@ -303,7 +303,7 @@ ospf_hello_send(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn)
{
case OSPF_IT_BCAST:
case OSPF_IT_PTP:
- ospf_send_to(ifa, AllSPFRouters);
+ ospf_send_to_all(ifa);
break;
case OSPF_IT_NBMA:
diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c
index 405e49df..a6a0c6c1 100644
--- a/proto/ospf/iface.c
+++ b/proto/ospf/iface.c
@@ -120,13 +120,24 @@ ospf_sk_open(struct ospf_iface *ifa)
sk->saddr = ifa->addr->ip;
if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_PTP))
{
- sk->ttl = 1; /* Hack, this will affect just multicast packets */
+ if (ifa->cf->real_bcast)
+ {
+ ifa->all_routers = ifa->addr->brd;
+
+ if (sk_set_broadcast(sk, 1) < 0)
+ goto err;
+ }
+ else
+ {
+ ifa->all_routers = AllSPFRouters;
+ sk->ttl = 1; /* Hack, this will affect just multicast packets */
- if (sk_setup_multicast(sk) < 0)
- goto err;
+ if (sk_setup_multicast(sk) < 0)
+ goto err;
- if (sk_join_group(sk, AllSPFRouters) < 0)
- goto err;
+ if (sk_join_group(sk, ifa->all_routers) < 0)
+ goto err;
+ }
}
ifa->sk = sk;
@@ -265,7 +276,7 @@ ospf_iface_chstate(struct ospf_iface *ifa, u8 state)
OSPF_TRACE(D_EVENTS, "Changing state of iface %s from %s to %s",
ifa->iface->name, ospf_is[oldstate], ospf_is[state]);
- if ((ifa->type == OSPF_IT_BCAST) && ifa->sk)
+ if ((ifa->type == OSPF_IT_BCAST) && !ifa->cf->real_bcast && ifa->sk)
{
if ((state == OSPF_IS_BACKUP) || (state == OSPF_IS_DR))
ospf_sk_join_dr(ifa);
@@ -536,6 +547,7 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
/* Check validity of interface type */
int old_type = ifa->type;
+ u32 if_multi_flag = ip->real_bcast ? IF_BROADCAST : IF_MULTICAST;
#ifdef OSPFv2
if ((ifa->type == OSPF_IT_BCAST) && (addr->flags & IA_PEER))
@@ -545,10 +557,10 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
ifa->type = OSPF_IT_PTMP;
#endif
- if ((ifa->type == OSPF_IT_BCAST) && !(iface->flags & IF_MULTICAST))
+ if ((ifa->type == OSPF_IT_BCAST) && !(iface->flags & if_multi_flag))
ifa->type = OSPF_IT_NBMA;
- if ((ifa->type == OSPF_IT_PTP) && !(iface->flags & IF_MULTICAST))
+ if ((ifa->type == OSPF_IT_PTP) && !(iface->flags & if_multi_flag))
ifa->type = OSPF_IT_PTMP;
if (ifa->type != old_type)
@@ -628,6 +640,9 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
if (ifa->stub != new_stub)
return 0;
+ if (new->real_bcast != ifa->cf->real_bcast)
+ return 0;
+
ifa->cf = new;
ifa->marked = 0;
@@ -1099,11 +1114,15 @@ ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface)
void
ospf_iface_info(struct ospf_iface *ifa)
{
- char *strict = "";
+ char *more = "";
if (ifa->strictnbma &&
((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP)))
- strict = "(strict)";
+ more = " (strict)";
+
+ if (ifa->cf->real_bcast &&
+ ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_PTP)))
+ more = " (real)";
if (ifa->type == OSPF_IT_VLINK)
{
@@ -1124,11 +1143,10 @@ ospf_iface_info(struct ospf_iface *ifa)
#else /* OSPFv3 */
cli_msg(-1015, "Interface %s (IID %d)", ifa->iface->name, ifa->instance_id);
#endif
- cli_msg(-1015, "\tType: %s %s", ospf_it[ifa->type], strict);
+ cli_msg(-1015, "\tType: %s%s", ospf_it[ifa->type], more);
cli_msg(-1015, "\tArea: %R (%u)", ifa->oa->areaid, ifa->oa->areaid);
}
- cli_msg(-1015, "\tState: %s %s", ospf_is[ifa->state],
- ifa->stub ? "(stub)" : "");
+ cli_msg(-1015, "\tState: %s%s", ospf_is[ifa->state], ifa->stub ? " (stub)" : "");
cli_msg(-1015, "\tPriority: %u", ifa->priority);
cli_msg(-1015, "\tCost: %u", ifa->cost);
if (ifa->oa->po->ecmp)
diff --git a/proto/ospf/lsack.c b/proto/ospf/lsack.c
index 53422e53..00c50caf 100644
--- a/proto/ospf/lsack.c
+++ b/proto/ospf/lsack.c
@@ -97,7 +97,9 @@ ospf_lsack_send(struct ospf_neighbor *n, int queue)
if (ifa->type == OSPF_IT_BCAST)
{
if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
- ospf_send_to(ifa, AllSPFRouters);
+ ospf_send_to_all(ifa);
+ else if (ifa->cf->real_bcast)
+ ospf_send_to_bdr(ifa);
else
ospf_send_to(ifa, AllDRouters);
}
@@ -124,7 +126,9 @@ ospf_lsack_send(struct ospf_neighbor *n, int queue)
if (ifa->type == OSPF_IT_BCAST)
{
if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
- ospf_send_to(ifa, AllSPFRouters);
+ ospf_send_to_all(ifa);
+ else if (ifa->cf->real_bcast)
+ ospf_send_to_bdr(ifa);
else
ospf_send_to(ifa, AllDRouters);
}
diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c
index 325a8d00..f71c72d1 100644
--- a/proto/ospf/lsupd.c
+++ b/proto/ospf/lsupd.c
@@ -314,7 +314,9 @@ ospf_lsupd_flood(struct proto_ospf *po,
{
case OSPF_IT_BCAST:
if ((ifa->state == OSPF_IS_BACKUP) || (ifa->state == OSPF_IS_DR))
- ospf_send_to(ifa, AllSPFRouters);
+ ospf_send_to_all(ifa);
+ else if (ifa->cf->real_bcast)
+ ospf_send_to_bdr(ifa);
else
ospf_send_to(ifa, AllDRouters);
break;
@@ -327,7 +329,7 @@ ospf_lsupd_flood(struct proto_ospf *po,
break;
case OSPF_IT_PTP:
- ospf_send_to(ifa, AllSPFRouters);
+ ospf_send_to_all(ifa);
break;
case OSPF_IT_PTMP:
diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c
index 9872faf2..ef7b0363 100644
--- a/proto/ospf/ospf.c
+++ b/proto/ospf/ospf.c
@@ -1145,16 +1145,16 @@ show_lsa_sum_net(struct top_hash_entry *he)
static inline void
show_lsa_sum_rt(struct top_hash_entry *he)
{
- u32 dst_rid, options;
+ u32 dst_rid;
#ifdef OSPFv2
struct ospf_lsa_sum *ls = he->lsa_body;
dst_rid = he->lsa.id;
- options = 0;
+ // options = 0;
#else /* OSPFv3 */
struct ospf_lsa_sum_rt *ls = he->lsa_body;
dst_rid = ls->drid;
- options = ls->options & OPTIONS_MASK;
+ // options = ls->options & OPTIONS_MASK;
#endif
cli_msg(-1016, "\t\txrouter %R metric %u", dst_rid, ls->metric);
diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h
index 96da9aa7..3bffaf91 100644
--- a/proto/ospf/ospf.h
+++ b/proto/ospf/ospf.h
@@ -205,6 +205,7 @@ struct ospf_iface
bird_clock_t csn_use; /* Last time when packet with that CSN was sent */
#endif
+ ip_addr all_routers; /* */
ip_addr drip; /* Designated router */
ip_addr bdrip; /* Backup DR */
u32 drid;
@@ -790,22 +791,23 @@ struct ospf_iface_patt
u32 deadc;
u32 deadint;
u32 inftransdelay;
- u32 priority;
- u32 strictnbma;
list nbma_list;
+ u32 priority;
u32 voa;
u32 vid;
u16 rxbuf;
- u8 check_link;
- u8 ecmp_weight;
#define OSPF_RXBUF_NORMAL 0
#define OSPF_RXBUF_LARGE 1
#define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */
- u32 autype; /* Not really used in OSPFv3 */
+ u16 autype; /* Not really used in OSPFv3 */
#define OSPF_AUTH_NONE 0
#define OSPF_AUTH_SIMPLE 1
#define OSPF_AUTH_CRYPT 2
#define OSPF_AUTH_CRYPT_SIZE 16
+ u8 strictnbma;
+ u8 check_link;
+ u8 ecmp_weight;
+ u8 real_bcast; /* Not really used in OSPFv3 */
#ifdef OSPFv2
list *passwords;
diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c
index 7a26967f..241a58f7 100644
--- a/proto/ospf/packet.c
+++ b/proto/ospf/packet.c
@@ -273,7 +273,7 @@ ospf_rx_hook(sock *sk, int size)
int src_local, dst_local UNUSED, dst_mcast;
src_local = ipa_in_net(sk->faddr, ifa->addr->prefix, ifa->addr->pxlen);
dst_local = ipa_equal(sk->laddr, ifa->addr->ip);
- dst_mcast = ipa_equal(sk->laddr, AllSPFRouters) || ipa_equal(sk->laddr, AllDRouters);
+ dst_mcast = ipa_equal(sk->laddr, ifa->all_routers) || ipa_equal(sk->laddr, AllDRouters);
#ifdef OSPFv2
/* First, we eliminate packets with strange address combinations.
@@ -287,6 +287,9 @@ ospf_rx_hook(sock *sk, int size)
if (!dst_mcast && !dst_local)
return 1;
+ /* Ignore my own broadcast packets */
+ if (ifa->cf->real_bcast && ipa_equal(sk->faddr, ifa->addr->ip))
+ return 1;
#else /* OSPFv3 */
/* In OSPFv3, src_local and dst_local mean link-local.
diff --git a/proto/ospf/packet.h b/proto/ospf/packet.h
index c0185b9c..fbcb4288 100644
--- a/proto/ospf/packet.h
+++ b/proto/ospf/packet.h
@@ -19,6 +19,8 @@ void ospf_send_to_agt(struct ospf_iface *ifa, u8 state);
void ospf_send_to_bdr(struct ospf_iface *ifa);
void ospf_send_to(struct ospf_iface *ifa, ip_addr ip);
+static inline void ospf_send_to_all(struct ospf_iface *ifa) { ospf_send_to(ifa, ifa->all_routers); }
+
static inline void * ospf_tx_buffer(struct ospf_iface *ifa) { return ifa->sk->tbuf; }
static inline unsigned
diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c
index 604c8ea7..7e9bad50 100644
--- a/proto/ospf/topology.c
+++ b/proto/ospf/topology.c
@@ -798,7 +798,7 @@ originate_sum_net_lsa(struct ospf_area *oa, struct fib_node *fn, int metric)
body = originate_sum_net_lsa_body(po, &lsa.length, fn, metric);
lsasum_calculate(&lsa, body);
- en = lsa_install_new(po, &lsa, dom, body);
+ lsa_install_new(po, &lsa, dom, body);
ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1);
}
@@ -835,7 +835,7 @@ originate_sum_rt_lsa(struct ospf_area *oa, struct fib_node *fn, int metric, u32
body = originate_sum_rt_lsa_body(po, &lsa.length, lsa.id, metric, options);
lsasum_calculate(&lsa, body);
- en = lsa_install_new(po, &lsa, dom, body);
+ lsa_install_new(po, &lsa, dom, body);
ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1);
}
@@ -1117,7 +1117,7 @@ originate_ext_lsa(struct ospf_area *oa, struct fib_node *fn, int src,
if (src)
fn->x1 = src;
- en = lsa_install_new(po, &lsa, dom, body);
+ lsa_install_new(po, &lsa, dom, body);
ospf_lsupd_flood(po, NULL, NULL, &lsa, dom, 1);
if (po->ebit == 0)
diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c
index 36b06d43..6099d284 100644
--- a/proto/pipe/pipe.c
+++ b/proto/pipe/pipe.c
@@ -24,9 +24,10 @@
* rte_update(), an import filter in ahook 2 is called. When a new
* route is announced in the peer table, an export filter in ahook2
* and an import filter in ahook 1 are used. Oviously, there is no
- * need in filtering the same route twice, so both import filters
- * are set to accept, while user configured 'import' and 'export'
- * filters are used as export filters in ahooks 2 and 1.
+ * need in filtering the same route twice, so both import filters are
+ * set to accept, while user configured 'import' and 'export' filters
+ * are used as export filters in ahooks 2 and 1. Route limits are
+ * handled similarly, but on the import side of ahooks.
*/
#undef LOCAL_DEBUG
@@ -116,6 +117,8 @@ pipe_import_control(struct proto *P, rte **ee, ea_list **ea UNUSED, struct linpo
static int
pipe_reload_routes(struct proto *P)
{
+ struct pipe_proto *p = (struct pipe_proto *) P;
+
/*
* Because the pipe protocol feeds routes from both routing tables
* together, both directions are reloaded during refeed and 'reload
@@ -123,6 +126,10 @@ pipe_reload_routes(struct proto *P)
* request refeed when 'reload in' command is used.
*/
proto_request_feeding(P);
+
+ proto_reset_limit(P->main_ahook->in_limit);
+ proto_reset_limit(p->peer_ahook->in_limit);
+
return 1;
}
@@ -146,6 +153,7 @@ pipe_init(struct proto_config *C)
static int
pipe_start(struct proto *P)
{
+ struct pipe_config *cf = (struct pipe_config *) P->cf;
struct pipe_proto *p = (struct pipe_proto *) P;
/* Lock both tables, unlock is handled in pipe_cleanup() */
@@ -155,10 +163,15 @@ pipe_start(struct proto *P)
/* Going directly to PS_UP - prepare for feeding,
connect the protocol to both routing tables */
- P->main_ahook = proto_add_announce_hook(P, P->table,
- FILTER_ACCEPT, P->cf->out_filter, &P->stats);
- p->peer_ahook = proto_add_announce_hook(P, p->peer_table,
- FILTER_ACCEPT, P->cf->in_filter, &p->peer_stats);
+ P->main_ahook = proto_add_announce_hook(P, P->table, &P->stats);
+ P->main_ahook->out_filter = cf->c.out_filter;
+ P->main_ahook->in_limit = cf->c.in_limit;
+ proto_reset_limit(P->main_ahook->in_limit);
+
+ p->peer_ahook = proto_add_announce_hook(P, p->peer_table, &p->peer_stats);
+ p->peer_ahook->out_filter = cf->c.in_filter;
+ p->peer_ahook->in_limit = cf->c.out_limit;
+ proto_reset_limit(p->peer_ahook->in_limit);
return PS_UP;
}
@@ -204,10 +217,16 @@ pipe_reconfigure(struct proto *P, struct proto_config *new)
/* Update output filters in ahooks */
if (P->main_ahook)
- P->main_ahook->out_filter = new->out_filter;
+ {
+ P->main_ahook->out_filter = new->out_filter;
+ P->main_ahook->in_limit = new->in_limit;
+ }
if (p->peer_ahook)
- p->peer_ahook->out_filter = new->in_filter;
+ {
+ p->peer_ahook->out_filter = new->in_filter;
+ p->peer_ahook->in_limit = new->out_limit;
+ }
if ((P->proto_state != PS_UP) || (proto_reconfig_type == RECONFIG_SOFT))
return 1;
@@ -283,12 +302,16 @@ static void
pipe_show_proto_info(struct proto *P)
{
struct pipe_proto *p = (struct pipe_proto *) P;
+ struct pipe_config *cf = (struct pipe_config *) P->cf;
// cli_msg(-1006, " Table: %s", P->table->name);
// cli_msg(-1006, " Peer table: %s", p->peer_table->name);
cli_msg(-1006, " Preference: %d", P->preference);
- cli_msg(-1006, " Input filter: %s", filter_name(P->cf->in_filter));
- cli_msg(-1006, " Output filter: %s", filter_name(P->cf->out_filter));
+ cli_msg(-1006, " Input filter: %s", filter_name(cf->c.in_filter));
+ cli_msg(-1006, " Output filter: %s", filter_name(cf->c.out_filter));
+
+ proto_show_limit(cf->c.in_limit, "Import limit:");
+ proto_show_limit(cf->c.out_limit, "Export limit:");
if (P->proto_state != PS_DOWN)
pipe_show_stats(p);
diff --git a/proto/radv/config.Y b/proto/radv/config.Y
index 495d9a05..abccd2c7 100644
--- a/proto/radv/config.Y
+++ b/proto/radv/config.Y
@@ -14,32 +14,45 @@ CF_DEFINES
#define RADV_CFG ((struct radv_config *) this_proto)
#define RADV_IFACE ((struct radv_iface_config *) this_ipatt)
#define RADV_PREFIX this_radv_prefix
+#define RADV_RDNSS (&this_radv_rdnss)
+#define RADV_DNSSL (&this_radv_dnssl)
static struct radv_prefix_config *this_radv_prefix;
+static struct radv_rdnss_config this_radv_rdnss;
+static struct radv_dnssl_config this_radv_dnssl;
+static list radv_dns_list; /* Used by radv_rdnss and radv_dnssl */
+static u8 radv_mult_val; /* Used by radv_mult for second return value */
+
CF_DECLS
CF_KEYWORDS(RADV, PREFIX, INTERFACE, MIN, MAX, RA, DELAY, INTERVAL,
MANAGED, OTHER, CONFIG, LINK, MTU, REACHABLE, TIME, RETRANS,
- TIMER, CURRENT, HOP, LIMIT, DEFAULT, VALID, PREFERRED,
- LIFETIME, SKIP, ONLINK, AUTONOMOUS)
+ TIMER, CURRENT, HOP, LIMIT, DEFAULT, VALID, PREFERRED, MULT,
+ LIFETIME, SKIP, ONLINK, AUTONOMOUS, RDNSS, DNSSL, NS, DOMAIN,
+ LOCAL)
+%type<i> radv_mult
CF_GRAMMAR
-CF_ADDTO(proto, radv_proto '}')
+CF_ADDTO(proto, radv_proto)
radv_proto_start: proto_start RADV
{
this_proto = proto_config_new(&proto_radv, sizeof(struct radv_config), $1);
init_list(&RADV_CFG->patt_list);
init_list(&RADV_CFG->pref_list);
+ init_list(&RADV_CFG->rdnss_list);
+ init_list(&RADV_CFG->dnssl_list);
};
radv_proto_item:
proto_item
- | PREFIX radv_prefix { add_tail(&RADV_CFG->pref_list, NODE this_radv_prefix); }
| INTERFACE radv_iface
+ | PREFIX radv_prefix { add_tail(&RADV_CFG->pref_list, NODE this_radv_prefix); }
+ | RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_CFG->rdnss_list, &radv_dns_list); }
+ | DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_CFG->dnssl_list, &radv_dns_list); }
;
radv_proto_opts:
@@ -48,7 +61,7 @@ radv_proto_opts:
;
radv_proto:
- radv_proto_start proto_name '{' radv_proto_opts;
+ radv_proto_start proto_name '{' radv_proto_opts '}';
radv_iface_start:
@@ -57,6 +70,8 @@ radv_iface_start:
add_tail(&RADV_CFG->patt_list, NODE this_ipatt);
init_list(&this_ipatt->ipn_list);
init_list(&RADV_IFACE->pref_list);
+ init_list(&RADV_IFACE->rdnss_list);
+ init_list(&RADV_IFACE->dnssl_list);
RADV_IFACE->min_ra_int = -1; /* undefined */
RADV_IFACE->max_ra_int = DEFAULT_MAX_RA_INT;
@@ -77,6 +92,10 @@ radv_iface_item:
| CURRENT HOP LIMIT expr { RADV_IFACE->current_hop_limit = $4; if (($4 < 0) || ($4 > 255)) cf_error("Current hop limit must be in range 0-255"); }
| DEFAULT LIFETIME expr { RADV_IFACE->default_lifetime = $3; if (($3 < 0) || ($3 > 9000)) cf_error("Default lifetime must be in range 0-9000"); }
| PREFIX radv_prefix { add_tail(&RADV_IFACE->pref_list, NODE this_radv_prefix); }
+ | RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_IFACE->rdnss_list, &radv_dns_list); }
+ | DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_IFACE->dnssl_list, &radv_dns_list); }
+ | RDNSS LOCAL bool { RADV_IFACE->rdnss_local = $3; }
+ | DNSSL LOCAL bool { RADV_IFACE->dnssl_local = $3; }
;
radv_iface_finish:
@@ -152,6 +171,103 @@ radv_prefix:
radv_prefix_start radv_prefix_opt_list radv_prefix_finish;
+
+radv_rdnss_node: ipa
+{
+ struct radv_rdnss_config *cf = cfg_allocz(sizeof(struct radv_rdnss_config));
+ add_tail(&radv_dns_list, NODE cf);
+
+ cf->server = $1;
+ cf->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT;
+};
+
+radv_rdnss_start:
+{
+ RADV_RDNSS->lifetime = 0;
+ RADV_RDNSS->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT;
+};
+
+radv_rdnss_item:
+ | NS radv_rdnss_node
+ | LIFETIME radv_mult { RADV_RDNSS->lifetime = $2; RADV_RDNSS->lifetime_mult = radv_mult_val; }
+ ;
+
+radv_rdnss_finish:
+{
+ if (EMPTY_LIST(radv_dns_list))
+ cf_error("No nameserver in RDNSS section");
+
+ struct radv_rdnss_config *cf;
+ WALK_LIST(cf, radv_dns_list)
+ {
+ cf->lifetime = RADV_RDNSS->lifetime;
+ cf->lifetime_mult = RADV_RDNSS->lifetime_mult;
+ }
+};
+
+radv_rdnss_opts:
+ /* empty */
+ | radv_rdnss_opts radv_rdnss_item ';'
+ ;
+
+radv_rdnss:
+ radv_rdnss_node
+ | '{' radv_rdnss_start radv_rdnss_opts '}' radv_rdnss_finish
+ ;
+
+
+radv_dnssl_node: TEXT
+{
+ struct radv_dnssl_config *cf = cfg_allocz(sizeof(struct radv_dnssl_config));
+ add_tail(&radv_dns_list, NODE cf);
+
+ cf->domain = $1;
+ cf->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT;
+
+ if (radv_process_domain(cf) < 0)
+ cf_error("Invalid domain dame");
+};
+
+radv_dnssl_start:
+{
+ RADV_DNSSL->lifetime = 0;
+ RADV_DNSSL->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT;
+};
+
+radv_dnssl_item:
+ | DOMAIN radv_dnssl_node
+ | LIFETIME radv_mult { RADV_DNSSL->lifetime = $2; RADV_DNSSL->lifetime_mult = radv_mult_val; }
+ ;
+
+radv_dnssl_finish:
+{
+ if (EMPTY_LIST(radv_dns_list))
+ cf_error("No domain in DNSSL section");
+
+ struct radv_dnssl_config *cf;
+ WALK_LIST(cf, radv_dns_list)
+ {
+ cf->lifetime = RADV_DNSSL->lifetime;
+ cf->lifetime_mult = RADV_DNSSL->lifetime_mult;
+ }
+};
+
+radv_dnssl_opts:
+ /* empty */
+ | radv_dnssl_opts radv_dnssl_item ';'
+ ;
+
+radv_dnssl:
+ radv_dnssl_node
+ | '{' radv_dnssl_start radv_dnssl_opts '}' radv_dnssl_finish
+ ;
+
+
+radv_mult:
+ expr { $$ = $1; radv_mult_val = 0; }
+ | MULT expr { $$ = 0; radv_mult_val = $2; if (($2 < 1) || ($2 > 254)) cf_error("Multiplier must be in range 1-254"); }
+ ;
+
CF_CODE
CF_END
diff --git a/proto/radv/packets.c b/proto/radv/packets.c
index ac59ce94..6fdfcaa3 100644
--- a/proto/radv/packets.c
+++ b/proto/radv/packets.c
@@ -24,8 +24,10 @@ struct radv_ra_packet
#define OPT_RA_MANAGED 0x80
#define OPT_RA_OTHER_CFG 0x40
-#define OPT_PREFIX 3
-#define OPT_MTU 5
+#define OPT_PREFIX 3
+#define OPT_MTU 5
+#define OPT_RDNSS 25
+#define OPT_DNSSL 31
struct radv_opt_prefix
{
@@ -50,6 +52,25 @@ struct radv_opt_mtu
u32 mtu;
};
+struct radv_opt_rdnss
+{
+ u8 type;
+ u8 length;
+ u16 reserved;
+ u32 lifetime;
+ ip_addr servers[];
+};
+
+struct radv_opt_dnssl
+{
+ u8 type;
+ u8 length;
+ u16 reserved;
+ u32 lifetime;
+ char domain[];
+};
+
+
static struct radv_prefix_config default_prefix = {
.onlink = 1,
.autonomous = 1,
@@ -57,6 +78,7 @@ static struct radv_prefix_config default_prefix = {
.preferred_lifetime = DEFAULT_PREFERRED_LIFETIME
};
+
static struct radv_prefix_config *
radv_prefix_match(struct radv_iface *ifa, struct ifa *a)
{
@@ -78,10 +100,146 @@ radv_prefix_match(struct radv_iface *ifa, struct ifa *a)
return &default_prefix;
}
+static int
+radv_prepare_rdnss(struct radv_iface *ifa, list *rdnss_list, char **buf, char *bufend)
+{
+ struct radv_rdnss_config *rcf = HEAD(*rdnss_list);
+
+ while(NODE_VALID(rcf))
+ {
+ struct radv_rdnss_config *rcf_base = rcf;
+ struct radv_opt_rdnss *op = (void *) *buf;
+ int max_i = (bufend - *buf - sizeof(struct radv_opt_rdnss)) / sizeof(ip_addr);
+ int i = 0;
+
+ if (max_i < 1)
+ goto too_much;
+
+ op->type = OPT_RDNSS;
+ op->reserved = 0;
+
+ if (rcf->lifetime_mult)
+ op->lifetime = htonl(rcf->lifetime_mult * ifa->cf->max_ra_int);
+ else
+ op->lifetime = htonl(rcf->lifetime);
+
+ while(NODE_VALID(rcf) &&
+ (rcf->lifetime == rcf_base->lifetime) &&
+ (rcf->lifetime_mult == rcf_base->lifetime_mult))
+ {
+ if (i >= max_i)
+ goto too_much;
+
+ op->servers[i] = rcf->server;
+ ipa_hton(op->servers[i]);
+ i++;
+
+ rcf = NODE_NEXT(rcf);
+ }
+
+ op->length = 1+2*i;
+ *buf += 8 * op->length;
+ }
+
+ return 0;
+
+ too_much:
+ log(L_WARN "%s: Too many RA options on interface %s",
+ ifa->ra->p.name, ifa->iface->name);
+ return -1;
+}
+
+int
+radv_process_domain(struct radv_dnssl_config *cf)
+{
+ /* Format of domain in search list is <size> <label> <size> <label> ... 0 */
+
+ char *dom = cf->domain;
+ char *dom_end = dom; /* Just to */
+ u8 *dlen_save = &cf->dlen_first;
+ int len;
+
+ while (dom_end)
+ {
+ dom_end = strchr(dom, '.');
+ len = dom_end ? (dom_end - dom) : strlen(dom);
+
+ if (len < 1 || len > 63)
+ return -1;
+
+ *dlen_save = len;
+ dlen_save = (u8 *) dom_end;
+
+ dom += len + 1;
+ }
+
+ len = dom - cf->domain;
+ if (len > 254)
+ return -1;
+
+ cf->dlen_all = len;
+
+ return 0;
+}
+
+static int
+radv_prepare_dnssl(struct radv_iface *ifa, list *dnssl_list, char **buf, char *bufend)
+{
+ struct radv_dnssl_config *dcf = HEAD(*dnssl_list);
+
+ while(NODE_VALID(dcf))
+ {
+ struct radv_dnssl_config *dcf_base = dcf;
+ struct radv_opt_dnssl *op = (void *) *buf;
+ int bsize = bufend - *buf - sizeof(struct radv_opt_dnssl);
+ int bpos = 0;
+
+ if (bsize < 0)
+ goto too_much;
+
+ bsize = bsize & ~7; /* Round down to multiples of 8 */
+
+ op->type = OPT_DNSSL;
+ op->reserved = 0;
+
+ if (dcf->lifetime_mult)
+ op->lifetime = htonl(dcf->lifetime_mult * ifa->cf->max_ra_int);
+ else
+ op->lifetime = htonl(dcf->lifetime);
+
+ while(NODE_VALID(dcf) &&
+ (dcf->lifetime == dcf_base->lifetime) &&
+ (dcf->lifetime_mult == dcf_base->lifetime_mult))
+ {
+ if (bpos + dcf->dlen_all + 1 > bsize)
+ goto too_much;
+
+ op->domain[bpos++] = dcf->dlen_first;
+ memcpy(op->domain + bpos, dcf->domain, dcf->dlen_all);
+ bpos += dcf->dlen_all;
+
+ dcf = NODE_NEXT(dcf);
+ }
+
+ int blen = (bpos + 7) / 8;
+ bzero(op->domain + bpos, 8 * blen - bpos);
+ op->length = 1 + blen;
+ *buf += 8 * op->length;
+ }
+
+ return 0;
+
+ too_much:
+ log(L_WARN "%s: Too many RA options on interface %s",
+ ifa->ra->p.name, ifa->iface->name);
+ return -1;
+}
+
static void
radv_prepare_ra(struct radv_iface *ifa)
{
struct proto_radv *ra = ifa->ra;
+ struct radv_config *cf = (struct radv_config *) (ra->p.cf);
char *buf = ifa->sk->tbuf;
char *bufstart = buf;
@@ -121,7 +279,7 @@ radv_prepare_ra(struct radv_iface *ifa)
if (buf + sizeof(struct radv_opt_prefix) > bufend)
{
log(L_WARN "%s: Too many prefixes on interface %s", ra->p.name, ifa->iface->name);
- break;
+ goto done;
}
struct radv_opt_prefix *op = (void *) buf;
@@ -137,7 +295,22 @@ radv_prepare_ra(struct radv_iface *ifa)
ipa_hton(op->prefix);
buf += sizeof(*op);
}
-
+
+ if (! ifa->cf->rdnss_local)
+ if (radv_prepare_rdnss(ifa, &cf->rdnss_list, &buf, bufend) < 0)
+ goto done;
+
+ if (radv_prepare_rdnss(ifa, &ifa->cf->rdnss_list, &buf, bufend) < 0)
+ goto done;
+
+ if (! ifa->cf->dnssl_local)
+ if (radv_prepare_dnssl(ifa, &cf->dnssl_list, &buf, bufend) < 0)
+ goto done;
+
+ if (radv_prepare_dnssl(ifa, &ifa->cf->dnssl_list, &buf, bufend) < 0)
+ goto done;
+
+ done:
ifa->plen = buf - bufstart;
}
diff --git a/proto/radv/radv.c b/proto/radv/radv.c
index d6fc8da5..5e7296a3 100644
--- a/proto/radv/radv.c
+++ b/proto/radv/radv.c
@@ -29,6 +29,10 @@
* radv_iface_notify(), which processes asynchronous events (specified
* by RA_EV_* codes), and radv_timer(), which triggers sending RAs and
* computes the next timeout.
+ *
+ * Supported standards:
+ * - RFC 4861 - main RA standard
+ * - RFC 6106 - DNS extensions (RDDNS, DNSSL)
*/
static void
diff --git a/proto/radv/radv.h b/proto/radv/radv.h
index 12bfe42e..48af8c00 100644
--- a/proto/radv/radv.h
+++ b/proto/radv/radv.h
@@ -42,24 +42,33 @@
#define DEFAULT_VALID_LIFETIME 86400
#define DEFAULT_PREFERRED_LIFETIME 14400
+#define DEFAULT_DNS_LIFETIME_MULT 3
+
struct radv_config
{
struct proto_config c;
list patt_list; /* List of iface configs (struct radv_iface_config) */
list pref_list; /* Global list of prefix configs (struct radv_prefix_config) */
+ list rdnss_list; /* Global list of RDNSS configs (struct radv_rdnss_config) */
+ list dnssl_list; /* Global list of DNSSL configs (struct radv_dnssl_config) */
};
struct radv_iface_config
{
struct iface_patt i;
list pref_list; /* Local list of prefix configs (struct radv_prefix_config) */
+ list rdnss_list; /* Local list of RDNSS configs (struct radv_rdnss_config) */
+ list dnssl_list; /* Local list of DNSSL configs (struct radv_dnssl_config) */
u32 min_ra_int; /* Standard options from RFC 4261 */
u32 max_ra_int;
u32 min_delay;
- u8 managed;
+ u8 rdnss_local; /* Global list is not used for RDNSS */
+ u8 dnssl_local; /* Global list is not used for DNSSL */
+
+ u8 managed; /* Standard options from RFC 4261 */
u8 other_config;
u32 link_mtu;
u32 reachable_time;
@@ -81,6 +90,25 @@ struct radv_prefix_config
u32 preferred_lifetime;
};
+struct radv_rdnss_config
+{
+ node n;
+ u32 lifetime; /* Valid if lifetime_mult is 0 */
+ u16 lifetime_mult; /* Lifetime specified as multiple of max_ra_int */
+ ip_addr server; /* IP address of recursive DNS server */
+};
+
+struct radv_dnssl_config
+{
+ node n;
+ u32 lifetime; /* Valid if lifetime_mult is 0 */
+ u16 lifetime_mult; /* Lifetime specified as multiple of max_ra_int */
+ u8 dlen_first; /* Length of first label in domain */
+ u8 dlen_all; /* Both dlen_ filled in radv_process_domain() */
+ char *domain; /* Domain for DNS search list, in processed form */
+};
+
+
struct proto_radv
{
struct proto p;
@@ -123,6 +151,7 @@ struct radv_iface
void radv_iface_notify(struct radv_iface *ifa, int event);
/* packets.c */
+int radv_process_domain(struct radv_dnssl_config *cf);
void radv_send_ra(struct radv_iface *ifa, int shutdown);
int radv_sk_open(struct radv_iface *ifa);
diff --git a/proto/rip/rip.c b/proto/rip/rip.c
index b41c3f8d..281296a5 100644
--- a/proto/rip/rip.c
+++ b/proto/rip/rip.c
@@ -624,7 +624,6 @@ rip_dump(struct proto *p)
int i;
node *w;
struct rip_interface *rif;
- i = 0;
CHK_MAGIC;
WALK_LIST( w, P->connections ) {
@@ -995,8 +994,8 @@ static int
rip_get_attr(eattr *a, byte *buf, int buflen UNUSED)
{
switch (a->id) {
- case EA_RIP_METRIC: buf += bsprintf( buf, "metric: %d", a->u.data ); return GA_FULL;
- case EA_RIP_TAG: buf += bsprintf( buf, "tag: %d", a->u.data ); return GA_FULL;
+ case EA_RIP_METRIC: bsprintf( buf, "metric: %d", a->u.data ); return GA_FULL;
+ case EA_RIP_TAG: bsprintf( buf, "tag: %d", a->u.data ); return GA_FULL;
default: return GA_UNKNOWN;
}
}
diff --git a/sysdep/autoconf.h.in b/sysdep/autoconf.h.in
index d029e2a7..ac6f7a87 100644
--- a/sysdep/autoconf.h.in
+++ b/sysdep/autoconf.h.in
@@ -62,3 +62,4 @@
/* We have stdint.h */
#undef HAVE_STDINT_H
+#define CONFIG_PATH ?
diff --git a/sysdep/bsd/Modules b/sysdep/bsd/Modules
index 84abffdb..3729587d 100644
--- a/sysdep/bsd/Modules
+++ b/sysdep/bsd/Modules
@@ -1,6 +1,3 @@
-krt-scan.h
-krt-iface.h
-sysio.h
-krt-set.h
krt-sock.c
-krt-sock.h
+krt-sys.h
+sysio.h
diff --git a/sysdep/bsd/krt-iface.h b/sysdep/bsd/krt-iface.h
deleted file mode 100644
index 7f0d52bd..00000000
--- a/sysdep/bsd/krt-iface.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * BIRD -- Unix Kernel Socket Route Syncer -- Dummy Include File
- *
- * (c) 2004 Ondrej Filip <feela@network.cz>
- *
- * Can be freely distributed and used under the terms of the GNU GPL.
- */
-
-#ifndef _BIRD_KRT_IFACE_H_
-#define _BIRD_KRT_IFACE_H_
-
-/*
- * We don't have split iface/scan/set parts. See krt-sock.h.
- */
-
-struct krt_if_params {
-};
-
-struct krt_if_status {
-};
-
-static inline int kif_params_same(struct krt_if_params *old UNUSED, struct krt_if_params *new UNUSED) { return 1; }
-static inline void kif_copy_params(struct krt_if_params *dest UNUSED, struct krt_if_params *src UNUSED) { }
-
-#endif
diff --git a/sysdep/bsd/krt-scan.h b/sysdep/bsd/krt-scan.h
deleted file mode 100644
index 19cd930d..00000000
--- a/sysdep/bsd/krt-scan.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * BIRD -- *BSD Kernel Route Syncer -- Scanning
- *
- * (c) 2004 Ondrej Filip <feela@network.cz>
- *
- * Can be freely distributed and used under the terms of the GNU GPL.
- */
-
-#ifndef _BIRD_KRT_SCAN_H_
-#define _BIRD_KRT_SCAN_H_
-
-struct krt_scan_params {
-};
-
-struct krt_scan_status {
- list temp_ifs; /* Temporary interfaces */
-};
-
-static inline int krt_scan_params_same(struct krt_scan_params *o UNUSED, struct krt_scan_params *n UNUSED) { return 1; }
-static inline void krt_scan_copy_params(struct krt_scan_params *d UNUSED, struct krt_scan_params *s UNUSED) { }
-
-#endif
diff --git a/sysdep/bsd/krt-set.h b/sysdep/bsd/krt-set.h
deleted file mode 100644
index b5453d4b..00000000
--- a/sysdep/bsd/krt-set.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * BIRD -- Unix Kernel Socket Route Syncer -- Dummy Include File
- *
- * (c) 2004 Ondrej Filip <feela@network.cz>
- *
- * Can be freely distributed and used under the terms of the GNU GPL.
- */
-
-#ifndef _BIRD_KRT_SET_H_
-#define _BIRD_KRT_SET_H_
-
-/*
- * We don't have split iface/scan/set parts. See krt-sock.h.
- */
-#include "lib/krt-sock.h"
-
-#endif
diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c
index 9ca36d83..e970d6bd 100644
--- a/sysdep/bsd/krt-sock.c
+++ b/sysdep/bsd/krt-sock.c
@@ -33,7 +33,19 @@
#include "lib/string.h"
#include "lib/socket.h"
-int rt_sock = 0;
+
+#ifndef RTAX_MAX
+#define RTAX_MAX 8
+#endif
+
+struct ks_msg
+{
+ struct rt_msghdr rtm;
+ struct sockaddr_storage buf[RTAX_MAX];
+};
+
+
+static int rt_sock = 0;
int
krt_capable(rte *e)
@@ -189,8 +201,8 @@ krt_sock_send(int cmd, rte *e)
}
void
-krt_set_notify(struct krt_proto *p UNUSED, net *n, rte *new, rte *old,
- struct ea_list *eattrs UNUSED)
+krt_replace_rte(struct krt_proto *p UNUSED, net *n, rte *new, rte *old,
+ struct ea_list *eattrs UNUSED)
{
int err = 0;
@@ -206,45 +218,6 @@ krt_set_notify(struct krt_proto *p UNUSED, net *n, rte *new, rte *old,
n->n.flags &= ~KRF_SYNC_ERROR;
}
-static int
-krt_set_hook(sock *sk, int size UNUSED)
-{
- struct ks_msg msg;
- int l = read(sk->fd, (char *)&msg, sizeof(msg));
-
- if(l <= 0)
- log(L_ERR "krt-sock: read failed");
- else
- krt_read_msg((struct proto *)sk->data, &msg, 0);
-
- return 0;
-}
-
-void
-krt_set_start(struct krt_proto *x, int first UNUSED)
-{
- sock *sk_rt;
- static int ks_open_tried = 0;
-
- if (ks_open_tried)
- return;
-
- ks_open_tried = 1;
-
- DBG("KRT: Opening kernel socket\n");
-
- if( (rt_sock = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC)) < 0)
- die("Cannot open kernel socket for routes");
-
- sk_rt = sk_new(krt_pool);
- sk_rt->type = SK_MAGIC;
- sk_rt->rx_hook = krt_set_hook;
- sk_rt->fd = rt_sock;
- sk_rt->data = x;
- if (sk_open(sk_rt))
- bug("krt-sock: sk_open failed");
-}
-
#define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0)
static void
@@ -648,32 +621,6 @@ krt_read_msg(struct proto *p, struct ks_msg *msg, int scan)
}
}
-void
-krt_scan_construct(struct krt_config *c UNUSED)
-{
-}
-
-void
-krt_scan_preconfig(struct config *c UNUSED)
-{
-}
-
-void
-krt_scan_postconfig(struct krt_config *c UNUSED)
-{
-}
-
-void
-krt_scan_start(struct krt_proto *x, int first UNUSED)
-{
- init_list(&x->scan.temp_ifs);
-}
-
-void
-krt_scan_shutdown(struct krt_proto *x UNUSED, int last UNUSED)
-{
-}
-
static void
krt_sysctl_scan(struct proto *p, pool *pool, byte **buf, size_t *bl, int cmd)
{
@@ -732,13 +679,13 @@ static size_t krt_buflen = 32768;
static size_t kif_buflen = 4096;
void
-krt_scan_fire(struct krt_proto *p)
+krt_do_scan(struct krt_proto *p)
{
krt_sysctl_scan((struct proto *)p, p->krt_pool, &krt_buffer, &krt_buflen, NET_RT_DUMP);
}
void
-krt_if_scan(struct kif_proto *p)
+kif_do_scan(struct kif_proto *p)
{
struct proto *P = (struct proto *)p;
if_start_update();
@@ -746,14 +693,47 @@ krt_if_scan(struct kif_proto *p)
if_end_update();
}
+static int
+krt_sock_hook(sock *sk, int size UNUSED)
+{
+ struct ks_msg msg;
+ int l = read(sk->fd, (char *)&msg, sizeof(msg));
+
+ if(l <= 0)
+ log(L_ERR "krt-sock: read failed");
+ else
+ krt_read_msg((struct proto *)sk->data, &msg, 0);
+
+ return 0;
+}
void
-krt_set_construct(struct krt_config *c UNUSED)
+krt_sys_start(struct krt_proto *x, int first UNUSED)
{
+ sock *sk_rt;
+ static int ks_open_tried = 0;
+
+ if (ks_open_tried)
+ return;
+
+ ks_open_tried = 1;
+
+ DBG("KRT: Opening kernel socket\n");
+
+ if( (rt_sock = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC)) < 0)
+ die("Cannot open kernel socket for routes");
+
+ sk_rt = sk_new(krt_pool);
+ sk_rt->type = SK_MAGIC;
+ sk_rt->rx_hook = krt_sock_hook;
+ sk_rt->fd = rt_sock;
+ sk_rt->data = x;
+ if (sk_open(sk_rt))
+ bug("krt-sock: sk_open failed");
}
void
-krt_set_shutdown(struct krt_proto *x UNUSED, int last UNUSED)
+krt_sys_shutdown(struct krt_proto *x UNUSED, int last UNUSED)
{
if (!krt_buffer)
return;
@@ -762,23 +742,14 @@ krt_set_shutdown(struct krt_proto *x UNUSED, int last UNUSED)
krt_buffer = NULL;
}
-void
-krt_if_io_init(void)
-{
-}
-
-void
-krt_if_construct(struct kif_config *c UNUSED)
-{
-}
void
-krt_if_start(struct kif_proto *p UNUSED)
+kif_sys_start(struct kif_proto *p UNUSED)
{
}
void
-krt_if_shutdown(struct kif_proto *p UNUSED)
+kif_sys_shutdown(struct kif_proto *p UNUSED)
{
if (!kif_buffer)
return;
diff --git a/sysdep/bsd/krt-sock.h b/sysdep/bsd/krt-sock.h
deleted file mode 100644
index aab639c4..00000000
--- a/sysdep/bsd/krt-sock.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * BIRD -- Unix Kernel Route Syncer -- Setting
- *
- * (c) 2004 Ondrej Filip <feela@network.cz>
- *
- * Can be freely distributed and used under the terms of the GNU GPL.
- */
-
-#ifndef _BIRD_KRT_SOCK_H_
-#define _BIRD_KRT_SOCK_H_
-
-#include <sys/socket.h>
-#include <net/route.h>
-#include "lib/socket.h"
-
-#ifndef RTAX_MAX
-#define RTAX_MAX 8
-#endif
-
-
-struct ks_msg
-{
- struct rt_msghdr rtm;
- struct sockaddr_storage buf[RTAX_MAX];
-};
-
-
-
-extern int krt_set_sock;
-
-struct krt_set_params {
-};
-
-struct krt_set_status {
-};
-
-static inline int krt_set_params_same(struct krt_set_params *o UNUSED, struct krt_set_params *n UNUSED) { return 1; }
-static inline void krt_set_copy_params(struct krt_set_params *d UNUSED, struct krt_set_params *s UNUSED) { }
-
-void krt_read_msg(struct proto *p, struct ks_msg *msg, int scan);
-
-#endif
diff --git a/sysdep/bsd/krt-sys.h b/sysdep/bsd/krt-sys.h
new file mode 100644
index 00000000..88915dde
--- /dev/null
+++ b/sysdep/bsd/krt-sys.h
@@ -0,0 +1,49 @@
+/*
+ * BIRD -- *BSD Kernel Route Syncer
+ *
+ * (c) 2004 Ondrej Filip <feela@network.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifndef _BIRD_KRT_SYS_H_
+#define _BIRD_KRT_SYS_H_
+
+
+/* Kernel interfaces */
+
+struct kif_params {
+};
+
+struct kif_status {
+};
+
+
+static inline void kif_sys_init(struct kif_proto *p UNUSED) { }
+static inline int kif_sys_reconfigure(struct kif_proto *p UNUSED, struct kif_config *n UNUSED, struct kif_config *o UNUSED) { return 1; }
+
+static inline void kif_sys_preconfig(struct config *c UNUSED) { }
+static inline void kif_sys_postconfig(struct kif_config *c UNUSED) { }
+static inline void kif_sys_init_config(struct kif_config *c UNUSED) { }
+static inline void kif_sys_copy_config(struct kif_config *d UNUSED, struct kif_config *s UNUSED) { }
+
+
+/* Kernel routes */
+
+struct krt_params {
+};
+
+struct krt_status {
+};
+
+
+static inline void krt_sys_init(struct krt_proto *p UNUSED) { }
+static inline int krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n UNUSED, struct krt_config *o UNUSED) { return 1; }
+
+static inline void krt_sys_preconfig(struct config *c UNUSED) { }
+static inline void krt_sys_postconfig(struct krt_config *c UNUSED) { }
+static inline void krt_sys_init_config(struct krt_config *c UNUSED) { }
+static inline void krt_sys_copy_config(struct krt_config *d UNUSED, struct krt_config *s UNUSED) { }
+
+
+#endif
diff --git a/sysdep/cf/README b/sysdep/cf/README
index 3b5bcd4f..1c11edcf 100644
--- a/sysdep/cf/README
+++ b/sysdep/cf/README
@@ -5,19 +5,9 @@ CONFIG_AUTO_ROUTES Device routes are added automagically by the kernel
CONFIG_SELF_CONSCIOUS We're able to recognize whether route was installed by us
CONFIG_MULTIPLE_TABLES The kernel supports multiple routing tables
CONFIG_ALL_TABLES_AT_ONCE Kernel scanner wants to process all tables at once
-CONFIG_MC_PROPER_SRC Multicast packets have source address according to socket saddr field
-CONFIG_RESTRICTED_PRIVILEGES Implements restricted privileges using drop_uid()
-CONFIG_UNIX_IFACE Use Unix interface scanner
-CONFIG_UNIX_SET Use Unix route setting
-CONFIG_UNIX_DONTROUTE Use setsockopts DONTROUTE (undef for *BSD)
+CONFIG_MC_PROPER_SRC Multicast packets have source address according to socket saddr field
CONFIG_SKIP_MC_BIND Don't call bind on multicast socket (def for *BSD)
-CONFIG_LINUX_SCAN Use Linux /proc/net/route scanner
-
-CONFIG_ALL_MULTICAST krt-iface: All devices support multicasting (i.e., ignore IFF_MULTICAST)
-CONFIG_UNNUM_MULTICAST krt-iface: We support multicasts on unnumbered PtP devices
-
-CONFIG_LINUX_MC_MREQN Linux: Use struct mreqn for multicasting
-CONFIG_LINUX_MC_MREQ Linux: Use struct mreq
-CONFIG_LINUX_MC_MREQ_BIND Linux: Use struct mreq and SO_BINDTODEVICE
+CONFIG_UNIX_DONTROUTE Use setsockopts DONTROUTE (undef for *BSD)
+CONFIG_RESTRICTED_PRIVILEGES Implements restricted privileges using drop_uid()
diff --git a/sysdep/cf/bsd-v6.h b/sysdep/cf/bsd-v6.h
index 66985abf..b7f25f64 100644
--- a/sysdep/cf/bsd-v6.h
+++ b/sysdep/cf/bsd-v6.h
@@ -10,14 +10,8 @@
#define CONFIG_AUTO_ROUTES
#define CONFIG_SELF_CONSCIOUS
-#undef CONFIG_MULTIPLE_TABLES
-
-#undef CONFIG_UNIX_IFACE
-#undef CONFIG_UNIX_SET
#define CONFIG_SKIP_MC_BIND
-#define CONFIG_ALL_MULTICAST
-#define CONFIG_UNNUM_MULTICAST
/*
Link: sysdep/unix
diff --git a/sysdep/cf/bsd.h b/sysdep/cf/bsd.h
index acd1b58b..e7cc135f 100644
--- a/sysdep/cf/bsd.h
+++ b/sysdep/cf/bsd.h
@@ -8,15 +8,8 @@
#define CONFIG_AUTO_ROUTES
#define CONFIG_SELF_CONSCIOUS
-#undef CONFIG_MULTIPLE_TABLES
-
-#undef CONFIG_UNIX_IFACE
-#undef CONFIG_UNIX_SET
-#undef CONFIG_UNIX_DONTROUTE
#define CONFIG_SKIP_MC_BIND
-#define CONFIG_ALL_MULTICAST
-#define CONFIG_UNNUM_MULTICAST
/*
Link: sysdep/unix
diff --git a/sysdep/cf/linux-20.h b/sysdep/cf/linux-20.h
deleted file mode 100644
index e409706a..00000000
--- a/sysdep/cf/linux-20.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Configuration for Linux 2.0 based systems
- *
- * (c) 1998--1999 Martin Mares <mj@ucw.cz>
- *
- * Can be freely distributed and used under the terms of the GNU GPL.
- */
-
-#undef CONFIG_AUTO_ROUTES
-#undef CONFIG_SELF_CONSCIOUS
-#undef CONFIG_MULTIPLE_TABLES
-
-#define CONFIG_UNIX_IFACE
-#define CONFIG_UNIX_SET
-#define CONFIG_UNIX_DONTROUTE
-#undef CONFIG_SKIP_MC_BIND
-#define CONFIG_LINUX_SCAN
-
-#define CONFIG_LINUX_MC_MREQ_BIND
-#define CONFIG_ALL_MULTICAST
-#define CONFIG_UNNUM_MULTICAST
-
-/*
-Link: sysdep/linux
-Link: sysdep/unix
- */
diff --git a/sysdep/cf/linux-21.h b/sysdep/cf/linux-21.h
deleted file mode 100644
index 0fce7053..00000000
--- a/sysdep/cf/linux-21.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Configuration for Linux 2.1/2.2 based systems without Netlink
- *
- * (c) 1998--1999 Martin Mares <mj@ucw.cz>
- *
- * Can be freely distributed and used under the terms of the GNU GPL.
- */
-
-#define CONFIG_AUTO_ROUTES
-#undef CONFIG_SELF_CONSCIOUS
-#undef CONFIG_MULTIPLE_TABLES
-
-#define CONFIG_UNIX_IFACE
-#define CONFIG_UNIX_SET
-#define CONFIG_UNIX_DONTROUTE
-#undef CONFIG_SKIP_MC_BIND
-#define CONFIG_LINUX_SCAN
-
-#define CONFIG_LINUX_MC_MREQN
-#define CONFIG_ALL_MULTICAST
-#define CONFIG_UNNUM_MULTICAST
-
-/*
-Link: sysdep/linux
-Link: sysdep/unix
- */
diff --git a/sysdep/cf/linux-v6.h b/sysdep/cf/linux-v6.h
index 467d7728..09f60377 100644
--- a/sysdep/cf/linux-v6.h
+++ b/sysdep/cf/linux-v6.h
@@ -1,5 +1,5 @@
/*
- * Configuration for Linux 2.2 based systems running IPv6
+ * Configuration for Linux based systems running IPv6
*
* (c) 1998--1999 Martin Mares <mj@ucw.cz>
*
@@ -9,20 +9,13 @@
#define IPV6
#define CONFIG_AUTO_ROUTES
-#define CONFIG_ALL_MULTICAST
#define CONFIG_SELF_CONSCIOUS
-
-/*
- * Netlink supports multiple tables, but kernel IPv6 code doesn't, so we
- * treat it as a multiple table system with number of tables set to 1.
- */
#define CONFIG_MULTIPLE_TABLES
#define CONFIG_ALL_TABLES_AT_ONCE
#define CONFIG_RESTRICTED_PRIVILEGES
/*
-Link: sysdep/linux/netlink
Link: sysdep/linux
Link: sysdep/unix
*/
diff --git a/sysdep/cf/linux-22.h b/sysdep/cf/linux.h
index 51b339d1..9e34f869 100644
--- a/sysdep/cf/linux-22.h
+++ b/sysdep/cf/linux.h
@@ -1,5 +1,5 @@
/*
- * Configuration for Linux 2.2 based systems
+ * Configuration for Linux based systems
*
* (c) 1998--1999 Martin Mares <mj@ucw.cz>
*
@@ -10,17 +10,13 @@
#define CONFIG_SELF_CONSCIOUS
#define CONFIG_MULTIPLE_TABLES
#define CONFIG_ALL_TABLES_AT_ONCE
-#define CONFIG_MC_PROPER_SRC
-
-#undef CONFIG_SKIP_MC_BIND
-#define CONFIG_LINUX_MC_MREQN
+#define CONFIG_MC_PROPER_SRC
#define CONFIG_UNIX_DONTROUTE
#define CONFIG_RESTRICTED_PRIVILEGES
/*
-Link: sysdep/linux/netlink
Link: sysdep/linux
Link: sysdep/unix
*/
diff --git a/sysdep/config.h b/sysdep/config.h
index 7e6fad8b..8d93d381 100644
--- a/sysdep/config.h
+++ b/sysdep/config.h
@@ -37,23 +37,4 @@ typedef u16 word;
#endif
-/* Path to configuration file */
-#ifdef IPV6
-# ifdef DEBUGGING
-# define PATH_CONFIG "bird6.conf"
-# define PATH_CONTROL_SOCKET "bird6.ctl"
-# else
-# define PATH_CONFIG PATH_CONFIG_DIR "/bird6.conf"
-# define PATH_CONTROL_SOCKET PATH_CONTROL_SOCKET_DIR "/bird6.ctl"
-# endif
-#else
-# ifdef DEBUGGING
-# define PATH_CONFIG "bird.conf"
-# define PATH_CONTROL_SOCKET "bird.ctl"
-# else
-# define PATH_CONFIG PATH_CONFIG_DIR "/bird.conf"
-# define PATH_CONTROL_SOCKET PATH_CONTROL_SOCKET_DIR "/bird.ctl"
-# endif
-#endif
-
#endif
diff --git a/sysdep/linux/Modules b/sysdep/linux/Modules
index 09f4a470..940660b6 100644
--- a/sysdep/linux/Modules
+++ b/sysdep/linux/Modules
@@ -1,6 +1,5 @@
-#ifdef CONFIG_LINUX_SCAN
-krt-scan.c
-krt-scan.h
-#endif
+krt-sys.h
+netlink.c
+netlink.Y
sysio.h
syspriv.h
diff --git a/sysdep/linux/krt-scan.c b/sysdep/linux/krt-scan.c
deleted file mode 100644
index 8591607e..00000000
--- a/sysdep/linux/krt-scan.c
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * BIRD -- Linux Routing Table Scanning
- *
- * (c) 1998--2000 Martin Mares <mj@ucw.cz>
- *
- * Can be freely distributed and used under the terms of the GNU GPL.
- */
-
-#include <stdio.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <net/route.h>
-
-#undef LOCAL_DEBUG
-
-#include "nest/bird.h"
-#include "nest/route.h"
-#include "nest/protocol.h"
-#include "nest/iface.h"
-#include "lib/timer.h"
-#include "lib/unix.h"
-#include "lib/krt.h"
-#include "lib/string.h"
-
-static int krt_scan_fd = -1;
-
-struct iface *
-krt_temp_iface(struct krt_proto *p, char *name)
-{
- struct iface *i;
-
- WALK_LIST(i, p->scan.temp_ifs)
- if (!strcmp(i->name, name))
- return i;
- i = mb_allocz(p->p.pool, sizeof(struct iface));
- strcpy(i->name, name);
- add_tail(&p->scan.temp_ifs, &i->n);
- return i;
-}
-
-static void
-krt_parse_entry(byte *ent, struct krt_proto *p)
-{
- u32 dest0, gw0, mask0;
- ip_addr dest, gw, mask;
- unsigned int flags;
- int masklen;
- net *net;
- byte *iface = ent;
- rte *e;
-
- if (sscanf(ent, "%*s\t%x\t%x\t%x\t%*d\t%*d\t%*d\t%x\t", &dest0, &gw0, &flags, &mask0) != 4)
- {
- log(L_ERR "krt read: unable to parse `%s'", ent);
- return;
- }
- while (*ent != '\t')
- ent++;
- *ent = 0;
-
- dest = ipa_from_u32(dest0);
- ipa_ntoh(dest);
- gw = ipa_from_u32(gw0);
- ipa_ntoh(gw);
- mask = ipa_from_u32(mask0);
- ipa_ntoh(mask);
- if ((masklen = ipa_mklen(mask)) < 0)
- {
- log(L_ERR "krt read: invalid netmask %08x", mask0);
- return;
- }
- DBG("Got %I/%d via %I flags %x\n", dest, masklen, gw, flags);
-
- if (!(flags & RTF_UP))
- {
- DBG("Down.\n");
- return;
- }
- if (flags & RTF_HOST)
- masklen = 32;
- if (flags & (RTF_DYNAMIC | RTF_MODIFIED)) /* Redirect route */
- {
- log(L_WARN "krt: Ignoring redirect to %I/%d via %I", dest, masklen, gw);
- return;
- }
-
- net = net_get(p->p.table, dest, masklen);
-
- rta a = {
- .proto = &p->p,
- .source = RTS_INHERIT,
- .scope = SCOPE_UNIVERSE,
- .cast = RTC_UNICAST
- };
-
- if (flags & RTF_GATEWAY)
- {
- neighbor *ng = neigh_find(&p->p, &gw, 0);
- if (ng && ng->scope)
- a.iface = ng->iface;
- else
- {
- log(L_WARN "Kernel told us to use non-neighbor %I for %I/%d", gw, net->n.prefix, net->n.pxlen);
- return;
- }
- a.dest = RTD_ROUTER;
- a.gw = gw;
- }
- else if (flags & RTF_REJECT)
- {
- a.dest = RTD_UNREACHABLE;
- a.gw = IPA_NONE;
- }
- else if (isalpha(iface[0]))
- {
- a.dest = RTD_DEVICE;
- a.gw = IPA_NONE;
- a.iface = krt_temp_iface(p, iface);
- }
- else
- {
- log(L_WARN "Kernel reporting unknown route type to %I/%d", net->n.prefix, net->n.pxlen);
- return;
- }
-
- e = rte_get_temp(&a);
- e->net = net;
- e->u.krt.src = KRT_SRC_UNKNOWN;
- krt_got_route(p, e);
-}
-
-void
-krt_scan_fire(struct krt_proto *p)
-{
- byte buf[32768];
- int l, seen_hdr;
-
- if (krt_scan_fd < 0)
- {
- krt_scan_fd = open("/proc/net/route", O_RDONLY);
- if (krt_scan_fd < 0)
- die("/proc/net/route: %m");
- }
- else if (lseek(krt_scan_fd, 0, SEEK_SET) < 0)
- {
- log(L_ERR "krt seek: %m");
- return;
- }
- seen_hdr = 0;
- while ((l = read(krt_scan_fd, buf, sizeof(buf))) > 0)
- {
- byte *z = buf;
- if (l & 127)
- {
- log(L_ERR "krt read: misaligned entry: l=%d", l);
- return;
- }
- while (l >= 128)
- {
- if (seen_hdr++)
- krt_parse_entry(z, p);
- z += 128;
- l -= 128;
- }
- }
- if (l < 0)
- {
- log(L_ERR "krt read: %m");
- return;
- }
- DBG("KRT scan done, seen %d lines\n", seen_hdr);
-}
-
-void
-krt_scan_construct(struct krt_config *c)
-{
-}
-
-void
-krt_scan_preconfig(struct config *c)
-{
-}
-
-void
-krt_scan_postconfig(struct krt_config *c)
-{
-}
-
-void
-krt_scan_start(struct krt_proto *x, int first)
-{
- init_list(&x->scan.temp_ifs);
-}
-
-void
-krt_scan_shutdown(struct krt_proto *x, int last)
-{
-}
diff --git a/sysdep/linux/krt-scan.h b/sysdep/linux/krt-scan.h
deleted file mode 100644
index 6c7e440f..00000000
--- a/sysdep/linux/krt-scan.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * BIRD -- Linux Kernel Route Syncer -- Scanning
- *
- * (c) 1998--2000 Martin Mares <mj@ucw.cz>
- *
- * Can be freely distributed and used under the terms of the GNU GPL.
- */
-
-#ifndef _BIRD_KRT_SCAN_H_
-#define _BIRD_KRT_SCAN_H_
-
-struct krt_scan_params {
-};
-
-struct krt_scan_status {
- list temp_ifs; /* Temporary interfaces */
-};
-
-static inline int krt_scan_params_same(struct krt_scan_params *o, struct krt_scan_params *n) { return 1; }
-
-#endif
diff --git a/sysdep/linux/krt-sys.h b/sysdep/linux/krt-sys.h
new file mode 100644
index 00000000..cdee7fe3
--- /dev/null
+++ b/sysdep/linux/krt-sys.h
@@ -0,0 +1,46 @@
+/*
+ * BIRD -- Linux Kernel Netlink Route Syncer
+ *
+ * (c) 1998--2000 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifndef _BIRD_KRT_SYS_H_
+#define _BIRD_KRT_SYS_H_
+
+
+/* Kernel interfaces */
+
+struct kif_params {
+};
+
+struct kif_status {
+};
+
+
+static inline void kif_sys_init(struct kif_proto *p UNUSED) { }
+static inline int kif_sys_reconfigure(struct kif_proto *p UNUSED, struct kif_config *n UNUSED, struct kif_config *o UNUSED) { return 1; }
+
+static inline void kif_sys_preconfig(struct config *c UNUSED) { }
+static inline void kif_sys_postconfig(struct kif_config *c UNUSED) { }
+static inline void kif_sys_init_config(struct kif_config *c UNUSED) { }
+static inline void kif_sys_copy_config(struct kif_config *d UNUSED, struct kif_config *s UNUSED) { }
+
+
+/* Kernel routes */
+
+#define NL_NUM_TABLES 256
+
+struct krt_params {
+ int table_id; /* Kernel table ID we sync with */
+};
+
+struct krt_status {
+};
+
+
+static inline void krt_sys_init(struct krt_proto *p UNUSED) { }
+
+
+#endif
diff --git a/sysdep/linux/netlink/netlink.Y b/sysdep/linux/netlink.Y
index b00b0eee..51689ff9 100644
--- a/sysdep/linux/netlink/netlink.Y
+++ b/sysdep/linux/netlink.Y
@@ -20,7 +20,7 @@ nl_item:
KERNEL TABLE expr {
if ($3 <= 0 || $3 >= NL_NUM_TABLES)
cf_error("Kernel routing table number out of range");
- THIS_KRT->scan.table_id = $3;
+ THIS_KRT->sys.table_id = $3;
}
;
diff --git a/sysdep/linux/netlink/netlink.c b/sysdep/linux/netlink.c
index 182088a1..eaaf048e 100644
--- a/sysdep/linux/netlink/netlink.c
+++ b/sysdep/linux/netlink.c
@@ -548,7 +548,7 @@ nl_parse_addr(struct nlmsghdr *h)
}
void
-krt_if_scan(struct kif_proto *p UNUSED)
+kif_do_scan(struct kif_proto *p UNUSED)
{
struct nlmsghdr *h;
@@ -634,7 +634,7 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int new)
r.r.rtm_family = BIRD_AF;
r.r.rtm_dst_len = net->n.pxlen;
r.r.rtm_tos = 0;
- r.r.rtm_table = KRT_CF->scan.table_id;
+ r.r.rtm_table = KRT_CF->sys.table_id;
r.r.rtm_protocol = RTPROT_BIRD;
r.r.rtm_scope = RT_SCOPE_UNIVERSE;
nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net->n.prefix);
@@ -687,7 +687,7 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int new)
}
void
-krt_set_notify(struct krt_proto *p, net *n, rte *new, rte *old, struct ea_list *eattrs)
+krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old, struct ea_list *eattrs)
{
int err = 0;
@@ -940,7 +940,7 @@ nl_parse_route(struct nlmsghdr *h, int scan)
}
void
-krt_scan_fire(struct krt_proto *p UNUSED) /* CONFIG_ALL_TABLES_AT_ONCE => p is NULL */
+krt_do_scan(struct krt_proto *p UNUSED) /* CONFIG_ALL_TABLES_AT_ONCE => p is NULL */
{
struct nlmsghdr *h;
@@ -1084,15 +1084,38 @@ nl_open_async(void)
static u8 nl_cf_table[(NL_NUM_TABLES+7) / 8];
void
-krt_scan_preconfig(struct config *c UNUSED)
+krt_sys_start(struct krt_proto *p, int first)
+{
+ nl_table_map[KRT_CF->sys.table_id] = p;
+ if (first)
+ {
+ nl_open();
+ nl_open_async();
+ }
+}
+
+void
+krt_sys_shutdown(struct krt_proto *p UNUSED, int last UNUSED)
+{
+}
+
+int
+krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt_config *o)
+{
+ return n->sys.table_id == o->sys.table_id;
+}
+
+
+void
+krt_sys_preconfig(struct config *c UNUSED)
{
bzero(&nl_cf_table, sizeof(nl_cf_table));
}
void
-krt_scan_postconfig(struct krt_config *x)
+krt_sys_postconfig(struct krt_config *x)
{
- int id = x->scan.table_id;
+ int id = x->sys.table_id;
if (nl_cf_table[id/8] & (1 << (id%8)))
cf_error("Multiple kernel syncers defined for table #%d", id);
@@ -1100,35 +1123,27 @@ krt_scan_postconfig(struct krt_config *x)
}
void
-krt_scan_construct(struct krt_config *x)
+krt_sys_init_config(struct krt_config *cf)
{
-#ifndef IPV6
- x->scan.table_id = RT_TABLE_MAIN;
-#else
- x->scan.table_id = 254;
-#endif
+ cf->sys.table_id = RT_TABLE_MAIN;
}
void
-krt_scan_start(struct krt_proto *p, int first)
+krt_sys_copy_config(struct krt_config *d, struct krt_config *s)
{
- init_list(&p->scan.temp_ifs);
- nl_table_map[KRT_CF->scan.table_id] = p;
- if (first)
- {
- nl_open();
- nl_open_async();
- }
+ d->sys.table_id = s->sys.table_id;
}
+
+
void
-krt_scan_shutdown(struct krt_proto *p UNUSED, int last UNUSED)
+kif_sys_start(struct kif_proto *p UNUSED)
{
+ nl_open();
+ nl_open_async();
}
void
-krt_if_start(struct kif_proto *p UNUSED)
+kif_sys_shutdown(struct kif_proto *p UNUSED)
{
- nl_open();
- nl_open_async();
}
diff --git a/sysdep/linux/netlink/Modules b/sysdep/linux/netlink/Modules
deleted file mode 100644
index c26f7f72..00000000
--- a/sysdep/linux/netlink/Modules
+++ /dev/null
@@ -1,5 +0,0 @@
-krt-iface.h
-krt-set.h
-krt-scan.h
-netlink.c
-netlink.Y
diff --git a/sysdep/linux/netlink/krt-iface.h b/sysdep/linux/netlink/krt-iface.h
deleted file mode 100644
index 770c6e2e..00000000
--- a/sysdep/linux/netlink/krt-iface.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * BIRD -- Unix Kernel Netlink Interface Syncer -- Dummy Include File
- *
- * (c) 1998--1999 Martin Mares <mj@ucw.cz>
- *
- * Can be freely distributed and used under the terms of the GNU GPL.
- */
-
-#ifndef _BIRD_KRT_IFACE_H_
-#define _BIRD_KRT_IFACE_H_
-
-/*
- * We don't have split iface/scan/set parts. See krt-scan.h.
- */
-
-struct krt_if_params {
-};
-
-struct krt_if_status {
-};
-
-static inline void krt_if_construct(struct kif_config *c UNUSED) { };
-static inline void krt_if_shutdown(struct kif_proto *p UNUSED) { };
-static inline void krt_if_io_init(void) { };
-
-static inline int kif_params_same(struct krt_if_params *old UNUSED, struct krt_if_params *new UNUSED) { return 1; }
-static inline void kif_copy_params(struct krt_if_params *dest UNUSED, struct krt_if_params *src UNUSED) { }
-
-#endif
diff --git a/sysdep/linux/netlink/krt-scan.h b/sysdep/linux/netlink/krt-scan.h
deleted file mode 100644
index 9b5e075b..00000000
--- a/sysdep/linux/netlink/krt-scan.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * BIRD -- Linux Kernel Netlink Route Syncer -- Scanning
- *
- * (c) 1998--2000 Martin Mares <mj@ucw.cz>
- *
- * Can be freely distributed and used under the terms of the GNU GPL.
- */
-
-#ifndef _BIRD_KRT_SCAN_H_
-#define _BIRD_KRT_SCAN_H_
-
-/*
- * We don't have split iface/scan/set for Netlink. All options
- * and run-time parameters are declared here instead of splitting
- * to krt-set.h, krt-iface.h and this file.
- */
-
-#define NL_NUM_TABLES 256
-
-struct krt_scan_params {
- int table_id; /* Kernel table ID we sync with */
-};
-
-struct krt_scan_status {
- list temp_ifs; /* Temporary interfaces */
-};
-
-static inline int krt_scan_params_same(struct krt_scan_params *o, struct krt_scan_params *n)
-{
- return o->table_id == n->table_id;
-}
-
-static inline void krt_scan_copy_params(struct krt_scan_params *d UNUSED, struct krt_scan_params *s UNUSED) { }
-/* table_id copied in krt_copy_config() */
-
-#endif
diff --git a/sysdep/linux/netlink/krt-set.h b/sysdep/linux/netlink/krt-set.h
deleted file mode 100644
index 4a08217b..00000000
--- a/sysdep/linux/netlink/krt-set.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * BIRD -- Unix Kernel Netlink Route Syncer -- Dummy Include File
- *
- * (c) 1998--2000 Martin Mares <mj@ucw.cz>
- *
- * Can be freely distributed and used under the terms of the GNU GPL.
- */
-
-#ifndef _BIRD_KRT_SET_H_
-#define _BIRD_KRT_SET_H_
-
-/*
- * We don't have split iface/scan/set parts. See krt-scan.h.
- */
-
-struct krt_set_params {
-};
-
-struct krt_set_status {
-};
-
-static inline void krt_set_construct(struct krt_config *c UNUSED) { };
-static inline void krt_set_start(struct krt_proto *p UNUSED, int first UNUSED) { };
-static inline void krt_set_shutdown(struct krt_proto *p UNUSED, int last UNUSED) { };
-static inline int krt_set_params_same(struct krt_set_params *o UNUSED, struct krt_set_params *n UNUSED) { return 1; }
-static inline void krt_set_copy_params(struct krt_set_params *d UNUSED, struct krt_set_params *s UNUSED) { }
-
-#endif
diff --git a/sysdep/linux/sysio.h b/sysdep/linux/sysio.h
index bb522804..90b3ebd9 100644
--- a/sysdep/linux/sysio.h
+++ b/sysdep/linux/sysio.h
@@ -57,45 +57,6 @@ get_inaddr(ip_addr *a, struct in_addr *ia)
ipa_ntoh(*a);
}
-/*
- * Multicasting in Linux systems is a real mess. Not only different kernels
- * have different interfaces, but also different libc's export it in different
- * ways. Horrible.
- */
-
-
-#if defined(CONFIG_LINUX_MC_MREQ) || defined(CONFIG_LINUX_MC_MREQ_BIND)
-/*
- * Older kernels support only struct mreq which matches interfaces by their
- * addresses and thus fails on unnumbered devices. On newer 2.0 kernels
- * we can use SO_BINDTODEVICE to circumvent this problem.
- */
-
-#define MREQ_IFA struct in_addr
-#define MREQ_GRP struct ip_mreq
-static inline void fill_mreq_ifa(struct in_addr *m, struct iface *ifa UNUSED, ip_addr saddr, ip_addr maddr UNUSED)
-{
- set_inaddr(m, saddr);
-}
-
-static inline void fill_mreq_grp(struct ip_mreq *m, struct iface *ifa, ip_addr saddr, ip_addr maddr)
-{
- bzero(m, sizeof(*m));
-#ifdef CONFIG_LINUX_MC_MREQ_BIND
- m->imr_interface.s_addr = INADDR_ANY;
-#else
- set_inaddr(&m->imr_interface, saddr);
-#endif
- set_inaddr(&m->imr_multiaddr, maddr);
-}
-#endif
-
-
-#ifdef CONFIG_LINUX_MC_MREQN
-/*
- * 2.1 and newer kernels use struct mreqn which passes ifindex, so no
- * problems with unnumbered devices.
- */
#ifndef HAVE_STRUCT_IP_MREQN
/* Several versions of glibc don't define this structure, so we have to do it ourselves */
@@ -107,24 +68,19 @@ struct ip_mreqn
};
#endif
-#define MREQ_IFA struct ip_mreqn
-#define MREQ_GRP struct ip_mreqn
-#define fill_mreq_ifa fill_mreq
-#define fill_mreq_grp fill_mreq
-static inline void fill_mreq(struct ip_mreqn *m, struct iface *ifa, ip_addr saddr, ip_addr maddr)
+static inline void fill_mreqn(struct ip_mreqn *m, struct iface *ifa, ip_addr saddr, ip_addr maddr)
{
bzero(m, sizeof(*m));
m->imr_ifindex = ifa->index;
set_inaddr(&m->imr_address, saddr);
set_inaddr(&m->imr_multiaddr, maddr);
}
-#endif
static inline char *
sysio_setup_multicast(sock *s)
{
- MREQ_IFA m;
+ struct ip_mreqn m;
int zero = 0;
if (setsockopt(s->fd, SOL_IP, IP_MULTICAST_LOOP, &zero, sizeof(zero)) < 0)
@@ -134,18 +90,15 @@ sysio_setup_multicast(sock *s)
return "IP_MULTICAST_TTL";
/* This defines where should we send _outgoing_ multicasts */
- fill_mreq_ifa(&m, s->iface, s->saddr, IPA_NONE);
+ fill_mreqn(&m, s->iface, s->saddr, IPA_NONE);
if (setsockopt(s->fd, SOL_IP, IP_MULTICAST_IF, &m, sizeof(m)) < 0)
return "IP_MULTICAST_IF";
-#if defined(CONFIG_LINUX_MC_MREQ_BIND) || defined(CONFIG_LINUX_MC_MREQN)
- {
- struct ifreq ifr;
- strcpy(ifr.ifr_name, s->iface->name);
- if (setsockopt(s->fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0)
- return "SO_BINDTODEVICE";
- }
-#endif
+ /* Is this necessary? */
+ struct ifreq ifr;
+ strcpy(ifr.ifr_name, s->iface->name);
+ if (setsockopt(s->fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0)
+ return "SO_BINDTODEVICE";
return NULL;
}
@@ -153,10 +106,10 @@ sysio_setup_multicast(sock *s)
static inline char *
sysio_join_group(sock *s, ip_addr maddr)
{
- MREQ_GRP m;
+ struct ip_mreqn m;
/* And this one sets interface for _receiving_ multicasts from */
- fill_mreq_grp(&m, s->iface, s->saddr, maddr);
+ fill_mreqn(&m, s->iface, s->saddr, maddr);
if (setsockopt(s->fd, SOL_IP, IP_ADD_MEMBERSHIP, &m, sizeof(m)) < 0)
return "IP_ADD_MEMBERSHIP";
@@ -166,10 +119,10 @@ sysio_join_group(sock *s, ip_addr maddr)
static inline char *
sysio_leave_group(sock *s, ip_addr maddr)
{
- MREQ_GRP m;
+ struct ip_mreqn m;
/* And this one sets interface for _receiving_ multicasts from */
- fill_mreq_grp(&m, s->iface, s->saddr, maddr);
+ fill_mreqn(&m, s->iface, s->saddr, maddr);
if (setsockopt(s->fd, SOL_IP, IP_DROP_MEMBERSHIP, &m, sizeof(m)) < 0)
return "IP_DROP_MEMBERSHIP";
@@ -348,7 +301,7 @@ sk_set_min_ttl6(sock *s, int ttl)
if (errno == ENOPROTOOPT)
log(L_ERR "Kernel does not support IPv6 TTL security");
else
- log(L_ERR "sk_set_min_ttl4: setsockopt: %m");
+ log(L_ERR "sk_set_min_ttl6: setsockopt: %m");
return -1;
}
diff --git a/sysdep/unix/Modules b/sysdep/unix/Modules
index 2666f9d6..2c6514df 100644
--- a/sysdep/unix/Modules
+++ b/sysdep/unix/Modules
@@ -10,13 +10,3 @@ random.c
krt.c
krt.h
krt.Y
-
-#ifdef CONFIG_UNIX_IFACE
-krt-iface.c
-krt-iface.h
-#endif
-
-#ifdef CONFIG_UNIX_SET
-krt-set.c
-krt-set.h
-#endif
diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c
index 2dced67a..475d660c 100644
--- a/sysdep/unix/io.c
+++ b/sysdep/unix/io.c
@@ -950,7 +950,7 @@ int
sk_join_group(sock *s, ip_addr maddr)
{
struct ipv6_mreq mreq;
-
+
set_inaddr(&mreq.ipv6mr_multiaddr, maddr);
#ifdef CONFIG_IPV6_GLIBC_20
diff --git a/sysdep/unix/krt-iface.c b/sysdep/unix/krt-iface.c
deleted file mode 100644
index 69048ae8..00000000
--- a/sysdep/unix/krt-iface.c
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * BIRD -- Unix Interface Scanning and Syncing
- *
- * (c) 1998--2000 Martin Mares <mj@ucw.cz>
- * (c) 2004 Ondrej Filip <feela@network.cz>
- *
- * Can be freely distributed and used under the terms of the GNU GPL.
- */
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <net/if.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-
-#undef LOCAL_DEBUG
-
-#include "nest/bird.h"
-#include "nest/iface.h"
-#include "nest/route.h"
-#include "nest/protocol.h"
-#include "lib/timer.h"
-#include "lib/krt.h"
-#include "lib/string.h"
-
-#include "unix.h"
-
-int if_scan_sock = -1;
-
-static void
-scan_ifs(struct ifreq *r, int cnt)
-{
- struct iface i, *pi;
- struct ifa a;
- char *err, *colon;
- unsigned fl;
- ip_addr netmask;
- int l, scope;
- sockaddr *sa;
-
- if_start_update();
- for (cnt /= sizeof(struct ifreq); cnt; cnt--, r++)
- {
- int sec = 0;
- bzero(&i, sizeof(i));
- bzero(&a, sizeof(a));
- if (colon = strchr(r->ifr_name, ':'))
- {
- /* It's an alias -- let's interpret it as a secondary interface address */
- sec = 1;
- *colon = 0;
- }
- strncpy(i.name, r->ifr_name, sizeof(i.name) - 1);
-
- if(ioctl(if_scan_sock, SIOCGIFADDR,r)<0) continue;
-
- get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &a.ip, NULL, 1);
- if (ipa_nonzero(a.ip))
- {
- l = ipa_classify(a.ip);
- if (l < 0 || !(l & IADDR_HOST))
- {
- log(L_ERR "%s: Invalid interface address", i.name);
- a.ip = IPA_NONE;
- }
- else
- {
- a.scope = l & IADDR_SCOPE_MASK;
- if (a.scope == SCOPE_HOST)
- i.flags |= IF_LOOPBACK | IF_IGNORE;
- }
- }
-
- if (ioctl(if_scan_sock, SIOCGIFFLAGS, r) < 0)
- {
- err = "SIOCGIFFLAGS";
- faulty:
- log(L_ERR "%s(%s): %m", err, i.name);
- bad:
- i.flags = (i.flags & ~IF_ADMIN_UP) | IF_SHUTDOWN;
- continue;
- }
- fl = r->ifr_flags;
- if (fl & IFF_UP)
- i.flags |= IF_ADMIN_UP;
-
- if (ioctl(if_scan_sock, SIOCGIFNETMASK, r) < 0)
- { err = "SIOCGIFNETMASK"; goto faulty; }
- get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &netmask, NULL, 0);
- l = ipa_mklen(netmask);
- if (l < 0)
- {
- log(L_ERR "%s: Invalid netmask (%x)", i.name, netmask);
- goto bad;
- }
- a.pxlen = l;
-
- if (fl & IFF_POINTOPOINT)
- {
- a.flags |= IA_PEER;
- if (ioctl(if_scan_sock, SIOCGIFDSTADDR, r) < 0)
- { err = "SIOCGIFDSTADDR"; goto faulty; }
- get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &a.opposite, NULL, 1);
- a.prefix = a.opposite;
- a.pxlen = BITS_PER_IP_ADDRESS;
- }
- else
- a.prefix = ipa_and(a.ip, ipa_mkmask(a.pxlen));
- if (fl & IFF_LOOPBACK)
- i.flags |= IF_LOOPBACK | IF_IGNORE;
- if (1
-#ifndef CONFIG_ALL_MULTICAST
- && (fl & IFF_MULTICAST)
-#endif
-#ifndef CONFIG_UNNUM_MULTICAST
- && !(a.flags & IA_PEER)
-#endif
- )
- i.flags |= IF_MULTICAST;
-
- scope = ipa_classify(a.ip);
- if (scope < 0)
- {
- log(L_ERR "%s: Invalid address", i.name);
- goto bad;
- }
- a.scope = scope & IADDR_SCOPE_MASK;
-
- if (a.pxlen < 32)
- {
- a.brd = ipa_or(a.prefix, ipa_not(ipa_mkmask(a.pxlen)));
- if (ipa_equal(a.ip, a.prefix) || ipa_equal(a.ip, a.brd))
- {
- log(L_ERR "%s: Using network or broadcast address for interface", i.name);
- goto bad;
- }
- if (fl & IFF_BROADCAST)
- i.flags |= IF_BROADCAST;
- if (a.pxlen < 30)
- i.flags |= IF_MULTIACCESS;
- if (a.pxlen == 30)
- ifa.opposite = ipa_opposite_m2(ifa.ip);
- if (a.pxlen == 31)
- ifa.opposite = ipa_opposite_m1(ifa.ip);
- }
- else
- a.brd = a.opposite;
- a.scope = SCOPE_UNIVERSE;
-
- if (ioctl(if_scan_sock, SIOCGIFMTU, r) < 0)
- { err = "SIOCGIFMTU"; goto faulty; }
- i.mtu = r->ifr_mtu;
-
-#ifdef SIOCGIFINDEX
- if (ioctl(if_scan_sock, SIOCGIFINDEX, r) >= 0)
- i.index = r->ifr_ifindex;
- else if (errno != EINVAL)
- DBG("SIOCGIFINDEX failed: %m\n");
- else /* defined, but not supported by the kernel */
-#endif
- /*
- * The kernel doesn't give us real ifindices, but we still need them
- * at least for OSPF unnumbered links. So let's make them up ourselves.
- */
- if (pi = if_find_by_name(i.name))
- i.index = pi->index;
- else
- {
- static int if_index_counter = 1;
- i.index = if_index_counter++;
- }
-
- pi = NULL;
- if (sec)
- {
- a.flags |= IA_SECONDARY;
- pi = if_find_by_index(i.index);
- }
- if (!pi)
- pi = if_update(&i);
- a.iface = pi;
- ifa_update(&a);
- }
- if_end_update();
-}
-
-void
-krt_if_scan(struct kif_proto *p)
-{
- struct ifconf ic;
- static int last_ifbuf_size = 4*sizeof(struct ifreq);
- int res;
-
- for(;;)
- {
- ic.ifc_buf = alloca(last_ifbuf_size);
- ic.ifc_len = last_ifbuf_size;
- res = ioctl(if_scan_sock, SIOCGIFCONF, &ic);
- if (res < 0 && errno != EFAULT)
- die("SIOCCGIFCONF: %m");
- if (res >= 0 && ic.ifc_len <= last_ifbuf_size)
- break;
- last_ifbuf_size *= 2;
- DBG("Increased ifconf buffer size to %d\n", last_ifbuf_size);
- }
- scan_ifs(ic.ifc_req, ic.ifc_len);
-}
-
-void
-krt_if_construct(struct kif_config *c)
-{
-}
-
-void
-krt_if_start(struct kif_proto *p)
-{
-}
-
-void
-krt_if_shutdown(struct kif_proto *p)
-{
-}
-
-void
-krt_if_io_init(void)
-{
- if_scan_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
- DBG("Using socket %d for interface and route scanning\n", if_scan_sock);
- if (if_scan_sock < 0)
- die("Cannot create scanning socket: %m");
-}
-
diff --git a/sysdep/unix/krt-iface.h b/sysdep/unix/krt-iface.h
deleted file mode 100644
index 9e12bcc3..00000000
--- a/sysdep/unix/krt-iface.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * BIRD -- Unix Kernel Interface Syncer
- *
- * (c) 1998--2000 Martin Mares <mj@ucw.cz>
- *
- * Can be freely distributed and used under the terms of the GNU GPL.
- */
-
-#ifndef _BIRD_KRT_IFACE_H_
-#define _BIRD_KRT_IFACE_H_
-
-struct krt_if_params {
-};
-
-struct krt_if_status {
-};
-
-extern int if_scan_sock;
-
-static inline int kif_params_same(struct krt_if_params *old UNUSED, struct krt_if_params *new UNUSED) { return 1; }
-static inline void kif_copy_params(struct krt_if_params *dest UNUSED, struct krt_if_params *src UNUSED) { }
-
-#endif
diff --git a/sysdep/unix/krt-set.c b/sysdep/unix/krt-set.c
deleted file mode 100644
index 23cbe5c5..00000000
--- a/sysdep/unix/krt-set.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * BIRD -- Unix Routing Table Syncing
- *
- * (c) 1998--2000 Martin Mares <mj@ucw.cz>
- *
- * Can be freely distributed and used under the terms of the GNU GPL.
- */
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <sys/ioctl.h>
-#include <net/route.h>
-
-#undef LOCAL_DEBUG
-
-#include "nest/bird.h"
-#include "nest/iface.h"
-#include "nest/route.h"
-#include "nest/protocol.h"
-#include "lib/unix.h"
-#include "lib/krt.h"
-#include "lib/string.h"
-
-int
-krt_capable(rte *e)
-{
- rta *a = e->attrs;
-
-#ifdef CONFIG_AUTO_ROUTES
- if (a->source == RTS_DEVICE)
- return 0;
-#endif
- return
- a->cast == RTC_UNICAST &&
- (a->dest == RTD_ROUTER
- || a->dest == RTD_DEVICE
-#ifdef RTF_REJECT
- || a->dest == RTD_UNREACHABLE
-#endif
- );
-}
-
-static void
-krt_ioctl(int ioc, rte *e, char *name)
-{
- net *net = e->net;
- struct rtentry re;
- rta *a = e->attrs;
-
- bzero(&re, sizeof(re));
- fill_in_sockaddr((struct sockaddr_in *) &re.rt_dst, net->n.prefix, 0);
- fill_in_sockaddr((struct sockaddr_in *) &re.rt_genmask, ipa_mkmask(net->n.pxlen), 0);
- re.rt_flags = RTF_UP;
- if (net->n.pxlen == 32)
- re.rt_flags |= RTF_HOST;
- switch (a->dest)
- {
- case RTD_ROUTER:
- fill_in_sockaddr((struct sockaddr_in *) &re.rt_gateway, a->gw, 0);
- re.rt_flags |= RTF_GATEWAY;
- break;
- case RTD_DEVICE:
- if (!a->iface)
- return;
- re.rt_dev = a->iface->name;
- break;
-#ifdef RTF_REJECT
- case RTD_UNREACHABLE:
- re.rt_flags |= RTF_REJECT;
- break;
-#endif
- default:
- bug("krt set: unknown flags, but not filtered");
- }
-
- if (ioctl(if_scan_sock, ioc, &re) < 0)
- log(L_ERR "%s(%I/%d): %m", name, net->n.prefix, net->n.pxlen);
-}
-
-void
-krt_set_notify(struct krt_proto *p, net *net, rte *new, rte *old)
-{
- if (old)
- {
- DBG("krt_remove_route(%I/%d)\n", net->n.prefix, net->n.pxlen);
- krt_ioctl(SIOCDELRT, old, "SIOCDELRT");
- }
- if (new)
- {
- DBG("krt_add_route(%I/%d)\n", net->n.prefix, net->n.pxlen);
- krt_ioctl(SIOCADDRT, new, "SIOCADDRT");
- }
-}
-
-void
-krt_set_start(struct krt_proto *x, int first)
-{
- if (if_scan_sock < 0)
- bug("krt set: missing socket");
-}
-
-void
-krt_set_construct(struct krt_config *c)
-{
-}
-
-void
-krt_set_shutdown(struct krt_proto *x, int last)
-{
-}
diff --git a/sysdep/unix/krt-set.h b/sysdep/unix/krt-set.h
deleted file mode 100644
index 87cffcfc..00000000
--- a/sysdep/unix/krt-set.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * BIRD -- Unix Kernel Route Syncer -- Setting
- *
- * (c) 1998--2000 Martin Mares <mj@ucw.cz>
- *
- * Can be freely distributed and used under the terms of the GNU GPL.
- */
-
-#ifndef _BIRD_KRT_SET_H_
-#define _BIRD_KRT_SET_H_
-
-struct krt_set_params {
-};
-
-struct krt_set_status {
-};
-
-static inline int krt_set_params_same(struct krt_set_params *o UNUSED, struct krt_set_params *n UNUSED) { return 1; }
-static inline void krt_set_copy_params(struct krt_set_params *d UNUSED, struct krt_set_params *s UNUSED) { }
-
-#endif
diff --git a/sysdep/unix/krt.Y b/sysdep/unix/krt.Y
index c0141f57..469c136d 100644
--- a/sysdep/unix/krt.Y
+++ b/sysdep/unix/krt.Y
@@ -25,17 +25,7 @@ CF_GRAMMAR
CF_ADDTO(proto, kern_proto '}')
-kern_proto_start: proto_start KERNEL {
-#ifndef CONFIG_MULTIPLE_TABLES
- if (cf_krt)
- cf_error("Kernel protocol already defined");
-#endif
- cf_krt = this_proto = proto_config_new(&proto_unix_kernel, sizeof(struct krt_config), $1);
- THIS_KRT->scan_time = 60;
- THIS_KRT->learn = THIS_KRT->persist = 0;
- krt_scan_construct(THIS_KRT);
- krt_set_construct(THIS_KRT);
- }
+kern_proto_start: proto_start KERNEL { this_proto = krt_init_config($1); }
;
CF_ADDTO(kern_proto, kern_proto_start proto_name '{')
@@ -62,14 +52,7 @@ kern_item:
CF_ADDTO(proto, kif_proto '}')
-kif_proto_start: proto_start DEVICE {
- if (cf_kif)
- cf_error("Kernel device protocol already defined");
- cf_kif = this_proto = proto_config_new(&proto_unix_iface, sizeof(struct kif_config), $1);
- THIS_KIF->scan_time = 60;
- init_list(&THIS_KIF->primary);
- krt_if_construct(THIS_KIF);
- }
+kif_proto_start: proto_start DEVICE { this_proto = kif_init_config($1); }
;
CF_ADDTO(kif_proto, kif_proto_start proto_name '{')
diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c
index de97a092..2bd1bc44 100644
--- a/sysdep/unix/krt.c
+++ b/sysdep/unix/krt.c
@@ -23,7 +23,7 @@
* Either with a single routing table and single KRT protocol [traditional UNIX]
* or with many routing tables and separate KRT protocols for all of them
* or with many routing tables, but every scan including all tables, so we start
- * separate KRT protocols which cooperate with each other [Linux 2.2].
+ * separate KRT protocols which cooperate with each other [Linux].
* In this case, we keep only a single scan timer.
*
* We use FIB node flags in the routing table to keep track of route
@@ -34,6 +34,15 @@
* When starting up, we cheat by looking if there is another
* KRT instance to be initialized later and performing table scan
* only once for all the instances.
+ *
+ * The code uses OS-dependent parts for kernel updates and scans. These parts are
+ * in more specific sysdep directories (e.g. sysdep/linux) in functions krt_sys_*
+ * and kif_sys_* (and some others like krt_replace_rte()) and krt-sys.h header file.
+ * This is also used for platform specific protocol options and route attributes.
+ *
+ * There was also an old code that used traditional UNIX ioctls for these tasks.
+ * It was unmaintained and later removed. For reference, see sysdep/krt-* files
+ * in commit 396dfa9042305f62da1f56589c4b98fac57fc2f6
*/
/*
@@ -66,33 +75,25 @@ krt_io_init(void)
{
krt_pool = rp_new(&root_pool, "Kernel Syncer");
krt_filter_lp = lp_new(krt_pool, 4080);
- krt_if_io_init();
}
/*
* Interfaces
*/
-struct proto_config *cf_kif;
-
+static struct kif_config *kif_cf;
static struct kif_proto *kif_proto;
static timer *kif_scan_timer;
static bird_clock_t kif_last_shot;
static void
-kif_preconfig(struct protocol *P UNUSED, struct config *c UNUSED)
-{
- cf_kif = NULL;
-}
-
-static void
kif_scan(timer *t)
{
struct kif_proto *p = t->data;
KRT_TRACE(p, D_EVENTS, "Scanning interfaces");
kif_last_shot = now;
- krt_if_scan(p);
+ kif_do_scan(p);
}
static void
@@ -112,45 +113,6 @@ kif_request_scan(void)
tm_start(kif_scan_timer, 1);
}
-static struct proto *
-kif_init(struct proto_config *c)
-{
- struct kif_proto *p = proto_new(c, sizeof(struct kif_proto));
- return &p->p;
-}
-
-static int
-kif_start(struct proto *P)
-{
- struct kif_proto *p = (struct kif_proto *) P;
-
- kif_proto = p;
- krt_if_start(p);
-
- /* Start periodic interface scanning */
- kif_scan_timer = tm_new(P->pool);
- kif_scan_timer->hook = kif_scan;
- kif_scan_timer->data = p;
- kif_scan_timer->recurrent = KIF_CF->scan_time;
- kif_scan(kif_scan_timer);
- tm_start(kif_scan_timer, KIF_CF->scan_time);
-
- return PS_UP;
-}
-
-static int
-kif_shutdown(struct proto *P)
-{
- struct kif_proto *p = (struct kif_proto *) P;
-
- tm_stop(kif_scan_timer);
- krt_if_shutdown(p);
- kif_proto = NULL;
-
- return PS_DOWN;
-}
-
-
static inline int
prefer_scope(struct ifa *a, struct ifa *b)
{ return (a->scope > SCOPE_LINK) && (b->scope <= SCOPE_LINK); }
@@ -193,13 +155,53 @@ kif_choose_primary(struct iface *i)
}
+static struct proto *
+kif_init(struct proto_config *c)
+{
+ struct kif_proto *p = proto_new(c, sizeof(struct kif_proto));
+
+ kif_sys_init(p);
+ return &p->p;
+}
+
+static int
+kif_start(struct proto *P)
+{
+ struct kif_proto *p = (struct kif_proto *) P;
+
+ kif_proto = p;
+ kif_sys_start(p);
+
+ /* Start periodic interface scanning */
+ kif_scan_timer = tm_new(P->pool);
+ kif_scan_timer->hook = kif_scan;
+ kif_scan_timer->data = p;
+ kif_scan_timer->recurrent = KIF_CF->scan_time;
+ kif_scan(kif_scan_timer);
+ tm_start(kif_scan_timer, KIF_CF->scan_time);
+
+ return PS_UP;
+}
+
+static int
+kif_shutdown(struct proto *P)
+{
+ struct kif_proto *p = (struct kif_proto *) P;
+
+ tm_stop(kif_scan_timer);
+ kif_sys_shutdown(p);
+ kif_proto = NULL;
+
+ return PS_DOWN;
+}
+
static int
kif_reconfigure(struct proto *p, struct proto_config *new)
{
struct kif_config *o = (struct kif_config *) p->cf;
struct kif_config *n = (struct kif_config *) new;
- if (!kif_params_same(&o->iface, &n->iface))
+ if (!kif_sys_reconfigure((struct kif_proto *) p, n, o))
return 0;
if (o->scan_time != n->scan_time)
@@ -224,6 +226,28 @@ kif_reconfigure(struct proto *p, struct proto_config *new)
return 1;
}
+
+static void
+kif_preconfig(struct protocol *P UNUSED, struct config *c)
+{
+ kif_cf = NULL;
+ kif_sys_preconfig(c);
+}
+
+struct proto_config *
+kif_init_config(int class)
+{
+ if (kif_cf)
+ cf_error("Kernel device protocol already defined");
+
+ kif_cf = (struct kif_config *) proto_config_new(&proto_unix_iface, sizeof(struct kif_config), class);
+ kif_cf->scan_time = 60;
+ init_list(&kif_cf->primary);
+
+ kif_sys_init_config(kif_cf);
+ return (struct proto_config *) kif_cf;
+}
+
static void
kif_copy_config(struct proto_config *dest, struct proto_config *src)
{
@@ -231,13 +255,13 @@ kif_copy_config(struct proto_config *dest, struct proto_config *src)
struct kif_config *s = (struct kif_config *) src;
/* Shallow copy of everything (just scan_time currently) */
- proto_copy_rest(dest, src, sizeof(struct krt_config));
+ proto_copy_rest(dest, src, sizeof(struct kif_config));
/* Copy primary addr list */
cfg_copy_list(&d->primary, &s->primary, sizeof(struct kif_primary_item));
/* Fix sysdep parts */
- kif_copy_params(&d->iface, &s->iface);
+ kif_sys_copy_config(d, s);
}
@@ -551,16 +575,11 @@ krt_flush_routes(struct krt_proto *p)
{
net *n = (net *) f;
rte *e = n->routes;
- if (e)
+ if (e && (n->n.flags & KRF_INSTALLED))
{
- rta *a = e->attrs;
- if ((n->n.flags & KRF_INSTALLED) &&
- a->source != RTS_DEVICE && a->source != RTS_INHERIT)
- {
- /* FIXME: this does not work if gw is changed in export filter */
- krt_set_notify(p, e->net, NULL, e, NULL);
- n->n.flags &= ~KRF_INSTALLED;
- }
+ /* FIXME: this does not work if gw is changed in export filter */
+ krt_replace_rte(p, e->net, NULL, e, NULL);
+ n->n.flags &= ~KRF_INSTALLED;
}
}
FIB_WALK_END;
@@ -717,7 +736,7 @@ krt_prune(struct krt_proto *p)
if (new && (f->flags & KRF_INSTALLED))
{
krt_trace_in(p, new, "reinstalling");
- krt_set_notify(p, n, new, NULL, tmpa);
+ krt_replace_rte(p, n, new, NULL, tmpa);
}
break;
case KRF_SEEN:
@@ -726,11 +745,11 @@ krt_prune(struct krt_proto *p)
break;
case KRF_UPDATE:
krt_trace_in(p, new, "updating");
- krt_set_notify(p, n, new, old, tmpa);
+ krt_replace_rte(p, n, new, old, tmpa);
break;
case KRF_DELETE:
krt_trace_in(p, old, "deleting");
- krt_set_notify(p, n, NULL, old, NULL);
+ krt_replace_rte(p, n, NULL, old, NULL);
break;
default:
bug("krt_prune: invalid route status");
@@ -766,7 +785,7 @@ krt_got_route_async(struct krt_proto *p, rte *e, int new)
if (new)
{
krt_trace_in(p, e, "[redirect] deleting");
- krt_set_notify(p, net, NULL, e, NULL);
+ krt_replace_rte(p, net, NULL, e, NULL);
}
/* If !new, it is probably echo of our deletion */
break;
@@ -800,7 +819,7 @@ krt_scan(timer *t UNUSED)
p = SKIP_BACK(struct krt_proto, instance_node, HEAD(krt_instance_list));
if (p->instance_node.next)
KRT_TRACE(p, D_EVENTS, "Scanning routing table");
- krt_scan_fire(NULL);
+ krt_do_scan(NULL);
WALK_LIST(q, krt_instance_list)
{
p = SKIP_BACK(struct krt_proto, instance_node, q);
@@ -810,14 +829,45 @@ krt_scan(timer *t UNUSED)
#else
p = t->data;
KRT_TRACE(p, D_EVENTS, "Scanning routing table");
- krt_scan_fire(p);
+ krt_do_scan(p);
krt_prune(p);
#endif
}
+
/*
* Updates
*/
+
+static struct ea_list *
+krt_make_tmp_attrs(rte *rt, struct linpool *pool)
+{
+ struct ea_list *l = lp_alloc(pool, sizeof(struct ea_list) + 2 * sizeof(eattr));
+
+ l->next = NULL;
+ l->flags = EALF_SORTED;
+ l->count = 2;
+
+ l->attrs[0].id = EA_KRT_SOURCE;
+ l->attrs[0].flags = 0;
+ l->attrs[0].type = EAF_TYPE_INT | EAF_TEMP;
+ l->attrs[0].u.data = rt->u.krt.proto;
+
+ l->attrs[1].id = EA_KRT_METRIC;
+ l->attrs[1].flags = 0;
+ l->attrs[1].type = EAF_TYPE_INT | EAF_TEMP;
+ l->attrs[1].u.data = rt->u.krt.metric;
+
+ return l;
+}
+
+static void
+krt_store_tmp_attrs(rte *rt, struct ea_list *attrs)
+{
+ /* EA_KRT_SOURCE is read-only */
+ rt->u.krt.metric = ea_get_int(attrs, EA_KRT_METRIC, 0);
+}
+
static int
krt_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *pool)
{
@@ -853,37 +903,37 @@ krt_notify(struct proto *P, struct rtable *table UNUSED, net *net,
else
net->n.flags &= ~KRF_INSTALLED;
if (p->initialized) /* Before first scan we don't touch the routes */
- krt_set_notify(p, net, new, old, eattrs);
+ krt_replace_rte(p, net, new, old, eattrs);
}
+static int
+krt_rte_same(rte *a, rte *b)
+{
+ /* src is always KRT_SRC_ALIEN and type is irrelevant */
+ return (a->u.krt.proto == b->u.krt.proto) && (a->u.krt.metric == b->u.krt.metric);
+}
+
+
/*
* Protocol glue
*/
-struct proto_config *cf_krt;
-
-static void
-krt_preconfig(struct protocol *P UNUSED, struct config *c)
-{
- cf_krt = NULL;
- krt_scan_preconfig(c);
-}
+struct krt_config *krt_cf;
-static void
-krt_postconfig(struct proto_config *C)
+static struct proto *
+krt_init(struct proto_config *c)
{
- struct krt_config *c = (struct krt_config *) C;
+ struct krt_proto *p = proto_new(c, sizeof(struct krt_proto));
-#ifdef CONFIG_ALL_TABLES_AT_ONCE
- struct krt_config *first = (struct krt_config *) cf_krt;
- if (first->scan_time != c->scan_time)
- cf_error("All kernel syncers must use the same table scan interval");
-#endif
+ p->p.accept_ra_types = RA_OPTIMAL;
+ p->p.make_tmp_attrs = krt_make_tmp_attrs;
+ p->p.store_tmp_attrs = krt_store_tmp_attrs;
+ p->p.import_control = krt_import_control;
+ p->p.rt_notify = krt_notify;
+ p->p.rte_same = krt_rte_same;
- if (C->table->krt_attached)
- cf_error("Kernel syncer (%s) already attached to table %s", C->table->krt_attached->name, C->table->name);
- C->table->krt_attached = C;
- krt_scan_postconfig(c);
+ krt_sys_init(p);
+ return &p->p;
}
static timer *
@@ -920,8 +970,7 @@ krt_start(struct proto *P)
krt_learn_init(p);
#endif
- krt_scan_start(p, first);
- krt_set_start(p, first);
+ krt_sys_start(p, first);
/* Start periodic routing table scanning */
#ifdef CONFIG_ALL_TABLES_AT_ONCE
@@ -955,8 +1004,7 @@ krt_shutdown(struct proto *P)
if (p->initialized && !KRT_CF->persist)
krt_flush_routes(p);
- krt_set_shutdown(p, last);
- krt_scan_shutdown(p, last);
+ krt_sys_shutdown(p, last);
#ifdef CONFIG_ALL_TABLES_AT_ONCE
if (last)
@@ -966,69 +1014,55 @@ krt_shutdown(struct proto *P)
return PS_DOWN;
}
-static struct ea_list *
-krt_make_tmp_attrs(rte *rt, struct linpool *pool)
+static int
+krt_reconfigure(struct proto *p, struct proto_config *new)
{
- struct ea_list *l = lp_alloc(pool, sizeof(struct ea_list) + 2 * sizeof(eattr));
-
- l->next = NULL;
- l->flags = EALF_SORTED;
- l->count = 2;
-
- l->attrs[0].id = EA_KRT_SOURCE;
- l->attrs[0].flags = 0;
- l->attrs[0].type = EAF_TYPE_INT | EAF_TEMP;
- l->attrs[0].u.data = rt->u.krt.proto;
+ struct krt_config *o = (struct krt_config *) p->cf;
+ struct krt_config *n = (struct krt_config *) new;
- l->attrs[1].id = EA_KRT_METRIC;
- l->attrs[1].flags = 0;
- l->attrs[1].type = EAF_TYPE_INT | EAF_TEMP;
- l->attrs[1].u.data = rt->u.krt.metric;
+ if (!krt_sys_reconfigure((struct krt_proto *) p, n, o))
+ return 0;
- return l;
+ /* persist needn't be the same */
+ return o->scan_time == n->scan_time && o->learn == n->learn && o->devroutes == n->devroutes;
}
static void
-krt_store_tmp_attrs(rte *rt, struct ea_list *attrs)
-{
- /* EA_KRT_SOURCE is read-only */
- rt->u.krt.metric = ea_get_int(attrs, EA_KRT_METRIC, 0);
-}
-
-static int
-krt_rte_same(rte *a, rte *b)
+krt_preconfig(struct protocol *P UNUSED, struct config *c)
{
- /* src is always KRT_SRC_ALIEN and type is irrelevant */
- return (a->u.krt.proto == b->u.krt.proto) && (a->u.krt.metric == b->u.krt.metric);
+ krt_cf = NULL;
+ krt_sys_preconfig(c);
}
-static struct proto *
-krt_init(struct proto_config *c)
+static void
+krt_postconfig(struct proto_config *C)
{
- struct krt_proto *p = proto_new(c, sizeof(struct krt_proto));
+ struct krt_config *c = (struct krt_config *) C;
- p->p.accept_ra_types = RA_OPTIMAL;
- p->p.make_tmp_attrs = krt_make_tmp_attrs;
- p->p.store_tmp_attrs = krt_store_tmp_attrs;
- p->p.import_control = krt_import_control;
- p->p.rt_notify = krt_notify;
- p->p.rte_same = krt_rte_same;
+#ifdef CONFIG_ALL_TABLES_AT_ONCE
+ if (krt_cf->scan_time != c->scan_time)
+ cf_error("All kernel syncers must use the same table scan interval");
+#endif
- return &p->p;
+ if (C->table->krt_attached)
+ cf_error("Kernel syncer (%s) already attached to table %s", C->table->krt_attached->name, C->table->name);
+ C->table->krt_attached = C;
+ krt_sys_postconfig(c);
}
-static int
-krt_reconfigure(struct proto *p, struct proto_config *new)
+struct proto_config *
+krt_init_config(int class)
{
- struct krt_config *o = (struct krt_config *) p->cf;
- struct krt_config *n = (struct krt_config *) new;
+#ifndef CONFIG_MULTIPLE_TABLES
+ if (krt_cf)
+ cf_error("Kernel protocol already defined");
+#endif
+
+ krt_cf = (struct krt_config *) proto_config_new(&proto_unix_kernel, sizeof(struct krt_config), class);
+ krt_cf->scan_time = 60;
- return o->scan_time == n->scan_time
- && o->learn == n->learn /* persist needn't be the same */
- && o->devroutes == n->devroutes
- && krt_set_params_same(&o->set, &n->set)
- && krt_scan_params_same(&o->scan, &n->scan)
- ;
+ krt_sys_init_config(krt_cf);
+ return (struct proto_config *) krt_cf;
}
static void
@@ -1041,8 +1075,7 @@ krt_copy_config(struct proto_config *dest, struct proto_config *src)
proto_copy_rest(dest, src, sizeof(struct krt_config));
/* Fix sysdep parts */
- krt_set_copy_params(&d->set, &s->set);
- krt_scan_copy_params(&d->scan, &s->scan);
+ krt_sys_copy_config(d, s);
}
static int
diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h
index 19b69e49..d6fbf721 100644
--- a/sysdep/unix/krt.h
+++ b/sysdep/unix/krt.h
@@ -15,9 +15,7 @@ struct krt_proto;
struct kif_config;
struct kif_proto;
-#include "lib/krt-scan.h"
-#include "lib/krt-set.h"
-#include "lib/krt-iface.h"
+#include "lib/krt-sys.h"
/* Flags stored in net->n.flags, rest are in nest/route.h */
@@ -45,8 +43,7 @@ extern struct protocol proto_unix_kernel;
struct krt_config {
struct proto_config c;
- struct krt_set_params set;
- struct krt_scan_params scan;
+ struct krt_params sys; /* Sysdep params */
int persist; /* Keep routes when we exit */
int scan_time; /* How often we re-scan routes */
int learn; /* Learn routes from other sources */
@@ -55,9 +52,7 @@ struct krt_config {
struct krt_proto {
struct proto p;
- struct krt_set_status set;
- struct krt_scan_status scan;
- struct krt_if_status iface;
+ struct krt_status sys; /* Sysdep state */
#ifdef KRT_ALLOW_LEARN
struct rtable krt_table; /* Internal table of inherited routes */
#endif
@@ -69,7 +64,6 @@ struct krt_proto {
int initialized; /* First scan has already been finished */
};
-extern struct proto_config *cf_krt;
extern pool *krt_pool;
#define KRT_CF ((struct krt_config *)p->p.cf)
@@ -79,6 +73,7 @@ extern pool *krt_pool;
if (pr->p.debug & fl) \
{ log(L_TRACE "%s: " msg, pr->p.name , ## args); } } while(0)
+struct proto_config * kif_init_config(int class);
void kif_request_scan(void);
void krt_got_route(struct krt_proto *p, struct rte *e);
void krt_got_route_async(struct krt_proto *p, struct rte *e, int new);
@@ -101,46 +96,49 @@ struct kif_primary_item {
struct kif_config {
struct proto_config c;
- struct krt_if_params iface;
+ struct kif_params sys; /* Sysdep params */
int scan_time; /* How often we re-scan interfaces */
list primary; /* Preferences for primary addresses (struct kif_primary_item) */
};
struct kif_proto {
struct proto p;
- struct krt_if_status iface;
+ struct kif_status sys; /* Sysdep state */
};
-extern struct proto_config *cf_kif;
-
#define KIF_CF ((struct kif_config *)p->p.cf)
-/* krt-scan.c */
+struct proto_config * krt_init_config(int class);
+
+
+/* krt sysdep */
+
+void krt_sys_init(struct krt_proto *);
+void krt_sys_start(struct krt_proto *, int);
+void krt_sys_shutdown(struct krt_proto *, int);
+int krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt_config *o);
-void krt_scan_preconfig(struct config *);
-void krt_scan_postconfig(struct krt_config *);
-void krt_scan_construct(struct krt_config *);
-void krt_scan_start(struct krt_proto *, int);
-void krt_scan_shutdown(struct krt_proto *, int);
+void krt_sys_preconfig(struct config *);
+void krt_sys_postconfig(struct krt_config *);
+void krt_sys_init_config(struct krt_config *);
+void krt_sys_copy_config(struct krt_config *, struct krt_config *);
-void krt_scan_fire(struct krt_proto *);
+int krt_capable(rte *e);
+void krt_do_scan(struct krt_proto *);
+void krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old, struct ea_list *eattrs);
-/* krt-set.c */
-void krt_set_construct(struct krt_config *);
-void krt_set_start(struct krt_proto *, int);
-void krt_set_shutdown(struct krt_proto *, int);
+/* kif sysdep */
-int krt_capable(rte *e);
-void krt_set_notify(struct krt_proto *p, net *n, rte *new, rte *old, struct ea_list *eattrs);
+void kif_sys_init(struct kif_proto *);
+void kif_sys_start(struct kif_proto *);
+void kif_sys_shutdown(struct kif_proto *);
+int kif_sys_reconfigure(struct kif_proto *, struct kif_config *, struct kif_config *);
-/* krt-iface.c */
+void kif_sys_init_config(struct kif_config *);
+void kif_sys_copy_config(struct kif_config *, struct kif_config *);
-void krt_if_construct(struct kif_config *);
-void krt_if_start(struct kif_proto *);
-void krt_if_shutdown(struct kif_proto *);
+void kif_do_scan(struct kif_proto *);
-void krt_if_scan(struct kif_proto *);
-void krt_if_io_init(void);
#endif
diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c
index dfe0b89c..e0563aae 100644
--- a/sysdep/unix/main.c
+++ b/sysdep/unix/main.c
@@ -151,7 +151,7 @@ read_iproute_table(char *file, char *prefix, int max)
#endif // PATH_IPROUTE_DIR
-static char *config_name = PATH_CONFIG;
+static char *config_name = PATH_CONFIG_FILE;
static int
cf_read(byte *dest, unsigned int len, int fd)
diff --git a/sysdep/unix/timer.h b/sysdep/unix/timer.h
index a20df483..a788ae27 100644
--- a/sysdep/unix/timer.h
+++ b/sysdep/unix/timer.h
@@ -30,6 +30,22 @@ void tm_start(timer *, unsigned after);
void tm_stop(timer *);
void tm_dump_all(void);
+extern bird_clock_t now; /* Relative, monotonic time in seconds */
+extern bird_clock_t now_real; /* Time in seconds since fixed known epoch */
+
+static inline bird_clock_t
+tm_remains(timer *t)
+{
+ return t->expires ? t->expires - now : 0;
+}
+
+static inline void
+tm_start_max(timer *t, unsigned after)
+{
+ bird_clock_t rem = tm_remains(t);
+ tm_start(t, (rem > after) ? rem : after);
+}
+
static inline timer *
tm_new_set(pool *p, void (*hook)(struct timer *), void *data, unsigned rand, unsigned rec)
{
@@ -41,8 +57,6 @@ tm_new_set(pool *p, void (*hook)(struct timer *), void *data, unsigned rand, uns
return t;
}
-extern bird_clock_t now; /* Relative, monotonic time in seconds */
-extern bird_clock_t now_real; /* Time in seconds since fixed known epoch */
struct timeformat {
char *fmt1, *fmt2;
diff --git a/tools/Makefile.in b/tools/Makefile.in
index 556eba5f..728e5797 100644
--- a/tools/Makefile.in
+++ b/tools/Makefile.in
@@ -48,23 +48,23 @@ userdocs progdocs: .dir-stamp
sysdep/paths.h:
echo >sysdep/paths.h "/* Generated by Makefile, don't edit manually! */"
- echo >>sysdep/paths.h "#define PATH_CONFIG_DIR \"$(sysconfdir)\""
- echo >>sysdep/paths.h "#define PATH_CONTROL_SOCKET_DIR \"$(localstatedir)/run\""
+ echo >>sysdep/paths.h "#define PATH_CONFIG_FILE \"@CONFIG_FILE@\""
+ echo >>sysdep/paths.h "#define PATH_CONTROL_SOCKET \"@CONTROL_SOCKET@\""
if test -n "@iproutedir@" ; then echo >>sysdep/paths.h "#define PATH_IPROUTE_DIR \"@iproutedir@\"" ; fi
tags:
cd $(srcdir) ; etags -lc `find $(static-dirs) $(addprefix $(objdir)/,$(dynamic-dirs)) $(client-dirs) -name *.[chY]`
install: all
- $(INSTALL) -d $(DESTDIR)/$(sbindir) $(DESTDIR)/$(sysconfdir) $(DESTDIR)/$(localstatedir)/run
- $(INSTALL_PROGRAM) -s $(exedir)/bird $(DESTDIR)/$(sbindir)/bird@SUFFIX6@
+ $(INSTALL) -d $(DESTDIR)/$(sbindir) $(DESTDIR)/$(sysconfdir) $(DESTDIR)/@runtimedir@
+ $(INSTALL_PROGRAM) -s $(exedir)/bird $(DESTDIR)/$(sbindir)/bird@SUFFIX@
if test -n "@CLIENT@" ; then \
- $(INSTALL_PROGRAM) -s $(exedir)/birdc $(DESTDIR)/$(sbindir)/birdc@SUFFIX6@ ; \
+ $(INSTALL_PROGRAM) -s $(exedir)/birdc $(DESTDIR)/$(sbindir)/birdc@SUFFIX@ ; \
fi
- if ! test -f $(DESTDIR)/$(sysconfdir)/bird@SUFFIX6@.conf ; then \
- $(INSTALL_DATA) $(srcdir)/doc/bird.conf.example $(DESTDIR)/$(sysconfdir)/bird@SUFFIX6@.conf ; \
+ if ! test -f $(DESTDIR)/@CONFIG_FILE@ ; then \
+ $(INSTALL_DATA) $(srcdir)/doc/bird.conf.example $(DESTDIR)/@CONFIG_FILE@ ; \
else \
- echo "Not overwriting old bird@SUFFIX@.conf" ; \
+ echo "Not overwriting old bird@SUFFIX@.conf" ; \
fi
install-docs: