diff --git a/aclocal.m4 b/aclocal.m4
index ee5452526238cf93d926e7b61e89a30e085a6191..75b3f92a37eece597f53704688287bdca048e01b 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 7f9e0ef4b0077e06ec31637ffb2038b5610f8aa6..8711cf0ad349e280308f0f1633da541afa3cac0e 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 46a6ecd92f0f31dbf59288d9ca6f54d3d9543837..dd57ab513769a96fdb6b280abac6f68cc74d514e 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 a94fb9e14141ecb5e2ece960eaff11333f9e8e9a..3edd6e0e565947a65a742d23fe118c0d8152a541 100644
--- a/doc/bird.sgml
+++ b/doc/bird.sgml
@@ -1072,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
diff --git a/filter/config.Y b/filter/config.Y
index 2e8b522e39ec39f9369a1c8b5c550b64dd2153c4..0eeb2ce1748b77ad60f6495c38db245d579ed0e1 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 acdcfd2beece844f0c51341ac5f3330b4ba45715..49b67391a673552d5e48019a6543ab08b547d10a 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/nest/a-path.c b/nest/a-path.c
index 058b43442fd1aa5db183fb4c6c439c75ef018d3b..63ac402e472f7c36644c8b69824c48010cecf3fc 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/sysdep/autoconf.h.in b/sysdep/autoconf.h.in
index d029e2a7d40da06262f2868fa24de43c9271c221..ac6f7a8765b4cf48f0375eed8c273014fc16e67e 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 84abffdb9629b27113d0cd9a836b4e3b6a4782b1..3729587de4aa014c02f52e94be96eb323b4d2cd2 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 7f0d52bdcae3364e493642fa55fa19e43dec4df2..0000000000000000000000000000000000000000
--- 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 19cd930d602796cb4494b9d5245e783c75a6cac0..0000000000000000000000000000000000000000
--- 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 b5453d4b100b4b07202e4af96312115441ae1f19..0000000000000000000000000000000000000000
--- 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 9ca36d83a72603af6629cc9c8e7ce5a49329d431..e970d6bdff9682de80dd7cea3e8fa67d38d53294 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 aab639c4e6d054c1d3368dd6debad3c8da833001..0000000000000000000000000000000000000000
--- 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 0000000000000000000000000000000000000000..88915dde8b569b14702e45267d93ed5dd9662a88
--- /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 3b5bcd4f005583eacc77c8d38ac97c8aad13029a..1c11edcfa372684cc93624d1b213f8009c2c1ca7 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 66985abfc78e9ed292fbba70a739fbff419631da..b7f25f6471e20e4a54c1247d324fee91cec76d3c 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 acd1b58b722eb323d55ff327f022d7f0ece72ee7..e7cc135fbcc2fb3d1e6cf63796c71537f28c1f9d 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 e409706aba06cff71a4e3bc4854ba60095c68c12..0000000000000000000000000000000000000000
--- 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 0fce705329ebd0c96ade71e223648ad119e63759..0000000000000000000000000000000000000000
--- 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 467d7728a2006eaf48e23f02f65520385a9a678e..09f60377ded1a87963098c438cd75c99c65998ca 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
similarity index 75%
rename from sysdep/cf/linux-22.h
rename to sysdep/cf/linux.h
index 51b339d1bd28a6b363d7247dc9577be3f72f6b93..9e34f869f339f8bb2da4f3e6ba21340bb77382a2 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 7e6fad8b4621cd242fe89659654c59567494ac2e..8d93d3811ab492d669bf2bb6b09405ca8aa2fa02 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 09f4a47091119818a4348a5d20489f7107f5f09f..940660b6adf0f118975c673f862026abbe23c8d2 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 8591607e44f16e31429dcf328a9355e9203116ed..0000000000000000000000000000000000000000
--- 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 6c7e440fe321642b6ba749d6dd166fb89e773c83..0000000000000000000000000000000000000000
--- 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 0000000000000000000000000000000000000000..cdee7fe38467a47bbb1241134c38996307cae420
--- /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
similarity index 95%
rename from sysdep/linux/netlink/netlink.Y
rename to sysdep/linux/netlink.Y
index b00b0eee4918b6803ccbece441f4fc33937eebe5..51689ff92f1b8a3125b54302c14b8196d5978b57 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
similarity index 96%
rename from sysdep/linux/netlink/netlink.c
rename to sysdep/linux/netlink.c
index 182088a1a31380ffc3ef6c6af7afb7994798fe1a..eaaf048e1c41bfefce93ca21b2a2fa404da5d434 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 c26f7f729baae5f3654f1eada2b890eed22d0448..0000000000000000000000000000000000000000
--- 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 770c6e2efcec5444a020929668a195f6e72fa6ef..0000000000000000000000000000000000000000
--- 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 9b5e075b842cce704aada3a1b8fa06b1e064139e..0000000000000000000000000000000000000000
--- 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 4a08217ba6a9101e117baec8191acb0ac03b95e2..0000000000000000000000000000000000000000
--- 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 bb522804285016c247b1ffc74b811c529a10c7df..705a20ae9798863e11dfbfc232f0f4e0936f762f 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";
 
diff --git a/sysdep/unix/Modules b/sysdep/unix/Modules
index 2666f9d635fb5b231fed8a565f7ed78eb8a3a7ef..2c6514df4a06ee075fb8cfefaacf7677ffc31d45 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 2dced67a667c0cf84672cd92b4324d6694502e9d..475d660cdeb9ca87269fb79f2f25da975a6dc9d6 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 69048ae84ed56da3ee4394de192c7be6e1f812be..0000000000000000000000000000000000000000
--- 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 9e12bcc3d4b7eac983e1a187dadf99ebf6579d60..0000000000000000000000000000000000000000
--- 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 23cbe5c56007dcd1cdd15b2dd8ab520d2a523aad..0000000000000000000000000000000000000000
--- 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 87cffcfc6c1c015d22fbd6b57f60d83743a1eb50..0000000000000000000000000000000000000000
--- 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 c0141f574b629b2b209336b781e03bef1625357c..469c136d45d015585cdd9940954ff3e73522e517 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 de97a09222be8bda7e3eb393107c157ff58f99c3..2bd1bc446c6276dbcf354a47cfbac079cc8579bd 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,25 +75,17 @@ 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)
 {
@@ -92,7 +93,7 @@ kif_scan(timer *t)
 
   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 19b69e49a78c456954d2cb6dea6c2e451de9648e..d6fbf7213ac9d5163e346f7f158b5904e8611dd6 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 dfe0b89c1534ec071e73eae9719f91cec169cebd..e0563aaedd5a3d41de5f331a31fb228fbaa311c5 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/tools/Makefile.in b/tools/Makefile.in
index 556eba5fa2f863a005952940dc5b6afbbe711831..728e5797f2004166e655264199961cab8336fc9d 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: