diff options
author | sem <sem@FreeBSD.org> | 2012-01-26 23:17:58 +0800 |
---|---|---|
committer | sem <sem@FreeBSD.org> | 2012-01-26 23:17:58 +0800 |
commit | b11925f0f929eba1514c8d4a97d43d18860baa47 (patch) | |
tree | b58c337fc3548a2ca95c0b420cb12818a6612a3a /net/bird | |
parent | 48f1edc7fc96e2af8a0f0077515d2da9317ed37f (diff) | |
download | freebsd-ports-gnome-b11925f0f929eba1514c8d4a97d43d18860baa47.tar.gz freebsd-ports-gnome-b11925f0f929eba1514c8d4a97d43d18860baa47.tar.zst freebsd-ports-gnome-b11925f0f929eba1514c8d4a97d43d18860baa47.zip |
- Update to 1.3.6
- Add all current git patches
- for net/bird add beta firewall protocol support
Submitted by: mainteiner
Diffstat (limited to 'net/bird')
-rw-r--r-- | net/bird/Makefile | 10 | ||||
-rw-r--r-- | net/bird/distinfo | 4 | ||||
-rw-r--r-- | net/bird/files/firewall_support.patch | 982 | ||||
-rw-r--r-- | net/bird/files/patch-136-post.diff | 507 | ||||
-rw-r--r-- | net/bird/files/patch-protocoltemplates.diff | 1085 |
5 files changed, 1498 insertions, 1090 deletions
diff --git a/net/bird/Makefile b/net/bird/Makefile index 2aaffd3a170a..ded9c723c7c8 100644 --- a/net/bird/Makefile +++ b/net/bird/Makefile @@ -6,8 +6,7 @@ # PORTNAME= bird -PORTVERSION= 1.3.4 -PORTREVESION= 1 +PORTVERSION= 1.3.6 CATEGORIES= net MASTER_SITES= ftp://bird.network.cz/pub/bird/ @@ -18,7 +17,8 @@ USE_BISON= build USE_GMAKE= yes GNU_CONFIGURE= yes -OPTIONS= FIBS "Enable multiple fib support" Off +OPTIONS= FIBS "Enable multiple fib support" Off \ + FIREWALL "Enable firewall protocol" Off MAKE_JOBS_UNSAFE= yes @@ -30,6 +30,10 @@ USE_RC_SUBR= bird EXTRA_PATCHES+= ${FILESDIR}/fibs.diff .endif +.if defined(WITH_FIREWALL) +EXTRA_PATCHES+= ${FILESDIR}/firewall_support.patch +.endif + post-install: @if [ ! -f ${PREFIX}/etc/bird.conf ]; then \ ${CP} -p ${PREFIX}/etc/bird.conf.example ${PREFIX}/etc/bird.conf ; \ diff --git a/net/bird/distinfo b/net/bird/distinfo index 276df66fd0ac..9f46e07d9c67 100644 --- a/net/bird/distinfo +++ b/net/bird/distinfo @@ -1,2 +1,2 @@ -SHA256 (bird-1.3.4.tar.gz) = 0b97c7486515b3ec81b34935859c0b66d92e2cc3f1f001e640d5d38e10c61dc6 -SIZE (bird-1.3.4.tar.gz) = 759228 +SHA256 (bird-1.3.6.tar.gz) = 5d060256c179bceff861b7533831adc690eb64d27d14fb1ddfba407eb83d870a +SIZE (bird-1.3.6.tar.gz) = 864775 diff --git a/net/bird/files/firewall_support.patch b/net/bird/files/firewall_support.patch new file mode 100644 index 000000000000..de1275162523 --- /dev/null +++ b/net/bird/files/firewall_support.patch @@ -0,0 +1,982 @@ +From c99266ef16e66f94f22a2f78dcea82c795c4611f Mon Sep 17 00:00:00 2001 +From: Alexander V. Chernikov <melifaro@ipfw.ru> +Date: Fri, 23 Dec 2011 13:47:59 +0000 +Subject: [PATCH 1/1] * Add firewall support, v2 + +--- + configure.in | 6 +- + doc/bird.sgml | 34 ++++ + nest/proto.c | 3 + + nest/protocol.h | 2 +- + nest/route.h | 3 +- + proto/firewall/Doc | 1 + + proto/firewall/Makefile | 6 + + proto/firewall/config.Y | 77 +++++++++ + proto/firewall/firewall.c | 198 ++++++++++++++++++++++ + proto/firewall/firewall.h | 54 ++++++ + sysdep/autoconf.h.in | 5 + + sysdep/bsd/Modules | 1 + + sysdep/bsd/fw.c | 404 +++++++++++++++++++++++++++++++++++++++++++++ + 13 files changed, 791 insertions(+), 3 deletions(-) + create mode 100644 proto/firewall/Doc + create mode 100644 proto/firewall/Makefile + create mode 100644 proto/firewall/config.Y + create mode 100644 proto/firewall/firewall.c + create mode 100644 proto/firewall/firewall.h + create mode 100644 sysdep/bsd/fw.c + +diff --git configure.in configure.in +index 46a6ecd..bb5f445 100644 +--- configure.in ++++ configure.in +@@ -47,7 +47,7 @@ if test "$enable_ipv6" = yes ; then + else + ip=ipv4 + SUFFIX6="" +- all_protocols=bgp,ospf,pipe,rip,static ++ all_protocols=bgp,ospf,pipe,rip,static,firewall + fi + + if test "$with_protocols" = all ; then +@@ -126,10 +126,13 @@ else + ipv4:netbsd*) sysdesc=bsd + CPPFLAGS="$CPPFLAGS -I/usr/pkg/include" + LDFLAGS="$LDFLAGS -L/usr/pkg/lib -R/usr/pkg/lib" ++ AC_DEFINE(CONFIG_FIREWALL_PF, 1) + ;; + ipv6:freebsd*) sysdesc=bsd-v6 + ;; + ipv4:freebsd*) sysdesc=bsd ++ AC_DEFINE(CONFIG_FIREWALL_IPFW, 1) ++ AC_DEFINE(CONFIG_FIREWALL_PF, 1) + ;; + ipv6:kfreebsd*) sysdesc=bsd-v6 + ;; +@@ -138,6 +141,7 @@ else + ipv6:openbsd*) sysdesc=bsd-v6 + ;; + ipv4:openbsd*) sysdesc=bsd ++ AC_DEFINE(CONFIG_FIREWALL_PF, 1) + ;; + *) AC_MSG_ERROR([Cannot determine correct system configuration. Please use --with-sysconfig to set it manually.]) + ;; +--- configure.orig 2012-01-20 21:04:39.000000000 +0400 ++++ configure 2012-01-26 17:37:43.000000000 +0400 +@@ -2336,7 +2336,7 @@ + else + ip=ipv4 + SUFFIX6="" +- all_protocols=bgp,ospf,pipe,rip,static ++ all_protocols=bgp,ospf,pipe,rip,static,firewall + fi + + if test "$with_protocols" = all ; then +@@ -4372,10 +4372,13 @@ + ipv4:netbsd*) sysdesc=bsd + CPPFLAGS="$CPPFLAGS -I/usr/pkg/include" + LDFLAGS="$LDFLAGS -L/usr/pkg/lib -R/usr/pkg/lib" ++ $as_echo "#define CONFIG_FIREWALL_PF 1" >>confdefs.h + ;; + ipv6:freebsd*) sysdesc=bsd-v6 + ;; + ipv4:freebsd*) sysdesc=bsd ++ $as_echo "#define CONFIG_FIREWALL_IPFW 1" >>confdefs.h ++ $as_echo "#define CONFIG_FIREWALL_PF 1" >>confdefs.h + ;; + ipv6:kfreebsd*) sysdesc=bsd-v6 + ;; +@@ -4384,6 +4387,7 @@ + ipv6:openbsd*) sysdesc=bsd-v6 + ;; + ipv4:openbsd*) sysdesc=bsd ++ $as_echo "#define CONFIG_FIREWALL_PF 1" >>confdefs.h + ;; + *) as_fn_error $? "Cannot determine correct system configuration. Please use --with-sysconfig to set it manually." "$LINENO" 5 + ;;--- doc/bird.sgml ++++ doc/bird.sgml +@@ -2490,6 +2490,40 @@ protocol static { + } + </code> + ++<sect>Firewall ++ ++<p>Firewall protocol doesn't communicate with any network devices, ++but instead it allows you to add announced prefixes to given firewall table. ++At the moment IPFW and PF are supported. One can also specify special integer tag ++that can be passed as argument to IPFW table. Any number of instances can be configured. ++ ++<p>Firewall protocol does not have many configuration options. ++ ++<descrip> ++ <tag>fwtype pf|ipfw</tag> Select firewall type. ++ <tag>fwtable <m/name/</tag> Specifies firewall table name. ++ <tag>keep on startup|shutdown</tag>Do not flush table on protocol startup or shutdown. ++ <tag>keep always</tag>Do not flush table on protocol startup and shutdown. ++</descrip> ++ ++<p>Firewall defines single route attribute: ++ ++<descrip> ++ <tag>int <cf/fw_value/</tag> Value that can be passed with prefix. ++ Value is unsigned 4-byte integer. It can be set when importing routes from the other ++ protocols or on protocol export. ++</descrip> ++ ++<p>Example firewall config might look like this: ++ ++<p><code> ++protocol firewall { ++ table testable; # Connect to a non-default routing table ++ fwtype ipfw; # Use IPFW as backend ++ fwtable "2"; # Use table 2 ++ export filter { fw_value = 125; accept; }; # Set value 125 for all prefixes ++} ++</code> + <chapt>Conclusions + + <sect>Future work +diff --git nest/proto.c nest/proto.c +index d55c348..85bdb19 100644 +--- nest/proto.c ++++ nest/proto.c +@@ -632,6 +632,9 @@ protos_build(void) + #ifdef CONFIG_BGP + proto_build(&proto_bgp); + #endif ++#ifdef CONFIG_FIREWALL ++ proto_build(&proto_firewall); ++#endif + proto_pool = rp_new(&root_pool, "Protocols"); + proto_flush_event = ev_new(proto_pool); + proto_flush_event->hook = proto_flush_all; +diff --git nest/protocol.h nest/protocol.h +index a7518c2..d09a556 100644 +--- nest/protocol.h ++++ nest/protocol.h +@@ -73,7 +73,7 @@ void protos_dump_all(void); + + extern struct protocol + proto_device, proto_radv, proto_rip, proto_static, +- proto_ospf, proto_pipe, proto_bgp; ++ proto_ospf, proto_pipe, proto_bgp, proto_firewall; + + /* + * Routing Protocol Instance +diff --git nest/route.h nest/route.h +index a4c0154..e5f18dd 100644 +--- nest/route.h ++++ nest/route.h +@@ -349,7 +349,8 @@ typedef struct eattr { + #define EAP_RIP 2 /* RIP */ + #define EAP_OSPF 3 /* OSPF */ + #define EAP_KRT 4 /* Kernel route attributes */ +-#define EAP_MAX 5 ++#define EAP_FIREWALL 5 /* Abstact firewall interface */ ++#define EAP_MAX 6 + + #define EA_CODE(proto,id) (((proto) << 8) | (id)) + #define EA_PROTO(ea) ((ea) >> 8) +diff --git proto/firewall/Doc proto/firewall/Doc +new file mode 100644 +index 0000000..5779342 +--- /dev/null ++++ proto/firewall/Doc +@@ -0,0 +1 @@ ++S firewall.c +diff --git proto/firewall/Makefile proto/firewall/Makefile +new file mode 100644 +index 0000000..a322ab6 +--- /dev/null ++++ proto/firewall/Makefile +@@ -0,0 +1,6 @@ ++source=firewall.c ++root-rel=../../ ++dir-name=proto/firewall ++ ++include ../../Rules ++ +diff --git proto/firewall/config.Y proto/firewall/config.Y +new file mode 100644 +index 0000000..aefc606 +--- /dev/null ++++ proto/firewall/config.Y +@@ -0,0 +1,77 @@ ++/* ++ * BIRD -- Firewall Protocol Configuration ++ * ++ * (c) 2011 Alexander V. Chernikov <melifaro@FreeBSD.org> ++ * ++ * Can be freely distributed and used under the terms of the GNU GPL. ++ */ ++ ++CF_HDR ++ ++#include "proto/firewall/firewall.h" ++ ++CF_DEFINES ++ ++#define FIREWALL_CFG ((struct firewall_config *) this_proto) ++ ++CF_DECLS ++ ++CF_KEYWORDS(FIREWALL, FWTABLE, FWTYPE, FW_VALUE, IPFW, PF, IPSET, KEEP, ON, STARTUP, SHUTDOWN, ALWAYS) ++ ++%type <i> firewall_type ++CF_GRAMMAR ++ ++CF_ADDTO(proto, firewall_proto '}') ++ ++firewall_proto_start: proto_start FIREWALL { ++ this_proto = proto_config_new(&proto_firewall, sizeof(struct firewall_config), $1); ++ this_proto->preference = 0; ++ FIREWALL_CFG->flush_start = 1; ++ FIREWALL_CFG->flush_shutdown = 1; ++ } ++ ; ++ ++firewall_proto: ++ firewall_proto_start proto_name '{' ++ | firewall_proto proto_item ';' ++ | firewall_proto firewall_proto_item ';' ++ ; ++ ++firewall_proto_item: ++ FWTYPE firewall_type { ++ switch ($2) ++ { ++#ifdef CONFIG_FIREWALL_IPFW ++ case FWTYPE_IPFW: ++ break; ++#endif ++#ifdef CONFIG_FIREWALL_PF ++ case FWTYPE_PF: ++ break; ++#endif ++#ifdef CONFIG_FIREWALL_IPSET ++ case FWTYPE_IPSET: ++ break; ++#endif ++ default: ++ cf_error("firewall type is not supported by your OS/build"); ++ } ++ FIREWALL_CFG->fwtype = $2; ++ }; ++ | FWTABLE TEXT { FIREWALL_CFG->fwtable = $2; } ++ | KEEP ON STARTUP { FIREWALL_CFG->flush_start = 0; } ++ | KEEP ON SHUTDOWN { FIREWALL_CFG->flush_shutdown = 0; } ++ | KEEP ALWAYS { FIREWALL_CFG->flush_start = 0; FIREWALL_CFG->flush_shutdown = 0; } ++ ; ++ ++firewall_type: ++ IPFW { $$ = FWTYPE_IPFW; } ++ | PF { $$ = FWTYPE_PF; } ++ | IPSET { $$ = FWTYPE_IPSET; } ++ ; ++ ++CF_ADDTO(dynamic_attr, FW_VALUE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_FIREWALL_VALUE); }) ++ ++CF_CODE ++ ++CF_END +diff --git proto/firewall/firewall.c proto/firewall/firewall.c +new file mode 100644 +index 0000000..e447470 +--- /dev/null ++++ proto/firewall/firewall.c +@@ -0,0 +1,198 @@ ++/* ++ * BIRD -- Firewall Protocol Configuration ++ * ++ * (c) 2011 Alexander V. Chernikov <melifaro@FreeBSD.org> ++ * ++ * Can be freely distributed and used under the terms of the GNU GPL. ++ */ ++ ++/** ++ * DOC: Firewall ++ * ++ * Firewall protocol is very simple. It adds or removes exported routes to given firewall ++ * table with zero (or filter-specified) value. Table can be flushed on startup to ++ * avoid error messages on bird restart. ++ */ ++ ++#undef LOCAL_DEBUG ++ ++#include "nest/bird.h" ++#include "nest/iface.h" ++#include "nest/protocol.h" ++#include "nest/route.h" ++#include "conf/conf.h" ++#include "filter/filter.h" ++#include "lib/string.h" ++ ++#include "firewall.h" ++ ++static int init_done = 0; ++struct rate_limit rl_fw_err; ++ ++static void ++firewall_collect(void) ++{ ++ memset(&firewalls, 0, sizeof(firewalls)); ++ log(L_DEBUG "Initializing firewalls.."); ++#ifdef CONFIG_FIREWALL_IPFW ++ firewalls[FWTYPE_IPFW] = &fw_ipfw; ++ log(L_DEBUG "IPFW.."); ++#endif ++#ifdef CONFIG_FIREWALL_PF ++ firewalls[FWTYPE_PF] = &fw_pf; ++ log(L_DEBUG "PF.."); ++#endif ++#ifdef CONFIG_FIREWALL_IPSET ++ firewalls[FWTYPE_IPSET] = &fw_ipset; ++ log(L_DEBUG "IPSET.."); ++#endif ++} ++ ++static void ++firewall_rt_notify(struct proto *P, rtable *src_table, net *n, rte *new, rte *old, ea_list *attrs) ++{ ++ struct firewall_proto *p = (struct firewall_proto *) P; ++ u32 prefix_val; ++ char prefix_data[10]; ++ ++ if (!new && !old) ++ return; ++ ++ prefix_val = ea_get_int(attrs, EA_FIREWALL_VALUE, 0); ++ ++ if (prefix_val) ++ bsnprintf(prefix_data, sizeof(prefix_data), "%u", prefix_val); ++ else ++ prefix_data[0] = '\0'; ++ ++ DBG("Got prefix %I/%d with data '%s'\n", n->n.prefix, n->n.pxlen, prefix_data); ++ ++ if (old && new && p->fw->fw_replace) ++ { ++ p->fw->fw_replace(p->fwdata, n, prefix_data); ++ return; ++ } ++ ++ if (old) ++ p->fw->fw_del(p->fwdata, n); ++ ++ if (new) ++ p->fw->fw_add(p->fwdata, n, prefix_data); ++} ++ ++static int ++firewall_start(struct proto *P) ++{ ++ struct firewall_proto *p = (struct firewall_proto *) P; ++ struct firewall_config *c = (struct firewall_config *)P->cf; ++ void *fwdata; ++ ++ if ((fwdata = p->fw->fw_init(P, c->fwtable)) == NULL) ++ return PS_START; ++ ++ p->fwdata = fwdata; ++ ++ /* Flush table if needed */ ++ if ((c->flush_start) && (p->fw->fw_flush)) ++ if (!p->fw->fw_flush(fwdata)) ++ { ++ log(L_ERR "flush failed for table %s", c->fwtable); ++ return PS_START; ++ } ++ ++ return PS_UP; ++} ++ ++static int ++firewall_shutdown(struct proto *P) ++{ ++ struct firewall_proto *p = (struct firewall_proto *) P; ++ struct firewall_config *c = (struct firewall_config *)P->cf; ++ ++ log(L_DEBUG, "Shutdown requested"); ++ ++ /* Flush table if needed */ ++ if ((c->flush_shutdown) && (p->fw->fw_flush)) ++ if (!p->fw->fw_flush(p->fwdata)) ++ log(L_ERR "flush failed for table %s", c->fwtable); ++ ++ p->fw->fw_shutdown(p->fwdata); ++ ++ return PS_DOWN; ++} ++ ++static struct proto * ++firewall_init(struct proto_config *C) ++{ ++ struct firewall_config *c = (struct firewall_config *) C; ++ struct proto *P = proto_new(C, sizeof(struct firewall_proto)); ++ struct firewall_proto *p = (struct firewall_proto *) P; ++ ++ /* Configure firewalls */ ++ if (!init_done) ++ { ++ init_done = 1; ++ firewall_collect(); ++ } ++ ++ p->fwtype = c->fwtype; ++ p->fw = firewalls[p->fwtype]; ++ P->accept_ra_types = RA_OPTIMAL; ++ P->rt_notify = firewall_rt_notify; ++ ++ return P; ++} ++ ++static int ++firewall_reconfigure(struct proto *P, struct proto_config *new) ++{ ++ struct firewall_config *o = (struct firewall_config *) P->cf; ++ struct firewall_config *n = (struct firewall_config *) new; ++ ++ if ((o->fwtype != n->fwtype) || (strcmp(o->fwtable, n->fwtable))) ++ return 0; ++ ++ return 1; ++} ++ ++static void ++firewall_copy_config(struct proto_config *dest, struct proto_config *src) ++{ ++ /* Just a shallow copy, not many items here */ ++ proto_copy_rest(dest, src, sizeof(struct firewall_config)); ++} ++ ++static void ++firewall_get_status(struct proto *P, byte *buf) ++{ ++ struct firewall_config *c = (struct firewall_config *) P->cf; ++ ++ bsprintf(buf, "Table [%s]", c->fwtable); ++} ++ ++static int ++firewall_get_attr(eattr * a, byte * buf, int buflen UNUSED) ++{ ++ switch (a->id) ++ { ++ case EA_FIREWALL_VALUE: ++ bsprintf(buf, "fw_value"); ++ return GA_NAME; ++ default: ++ return GA_UNKNOWN; ++ } ++} ++ ++ ++struct protocol proto_firewall = { ++ name: "Firewall", ++ template: "fw%d", ++ attr_class: EAP_FIREWALL, ++ init: firewall_init, ++ start: firewall_start, ++ shutdown: firewall_shutdown, ++ reconfigure: firewall_reconfigure, ++ copy_config: firewall_copy_config, ++ get_status: firewall_get_status, ++ get_attr: firewall_get_attr, ++}; +diff --git proto/firewall/firewall.h proto/firewall/firewall.h +new file mode 100644 +index 0000000..c97ed38 +--- /dev/null ++++ proto/firewall/firewall.h +@@ -0,0 +1,54 @@ ++/* ++ * BIRD -- Firewall Protocol Configuration ++ * ++ * (c) 2011 Alexander V. Chernikov <melifaro@FreeBSD.org> ++ * ++ * Can be freely distributed and used under the terms of the GNU GPL. ++ */ ++ ++#ifndef _BIRD_FIREWALL_H_ ++#define _BIRD_FIREWALL_H_ ++ ++#define FWTYPE_IPFW 0 ++#define FWTYPE_PF 1 ++#define FWTYPE_IPSET 2 ++ ++#define FWTYPE_MAX 3 ++ ++#define EA_FIREWALL_VALUE EA_CODE(EAP_FIREWALL, 0) ++ ++struct firewall_config { ++ struct proto_config c; ++ int fwtype; /* Firewall type */ ++ char *fwtable; /* Firewall table to write to */ ++ int flush_start; /* Do table flush on startup? */ ++ int flush_shutdown; /* Do table flush on shutdown? */ ++}; ++ ++struct firewall_control { ++ int fwtype; /* Firewall type */ ++ char *description; /* Firewall description */ ++ void *(*fw_init)(struct proto *, char *); /* Init firewall instance */ ++ void (*fw_shutdown)(void *); /* Shutdown firewall instance */ ++ int (*fw_flush)(void *); /* Flush firewall table */ ++ int (*fw_add)(void *, net *, char *); /* Add record to table */ ++ int (*fw_del)(void *, net *); /* Remove record from table */ ++ int (*fw_replace)(void *, net *, char *); /* Replace record. Optional */ ++}; ++ ++struct firewall_control * firewalls[FWTYPE_MAX]; ++ ++struct firewall_proto { ++ struct proto p; ++ int fwtype; /* Firewall type */ ++ struct firewall_control *fw; /* Pointer to configured protocol type */ ++ void *fwdata; /* Firewall instance private data */ ++}; ++ ++extern struct protocol proto_firewall; ++ ++extern struct firewall_control fw_ipfw, fw_pf, fw_ipset; ++extern struct rate_limit rl_fw_err; ++#define FW_ERR(x, y...) log_rl(&rl_fw_err, L_ERR x, ##y) ++ ++#endif +diff --git sysdep/autoconf.h.in sysdep/autoconf.h.in +index d029e2a..c1fcdf7 100644 +--- sysdep/autoconf.h.in ++++ sysdep/autoconf.h.in +@@ -42,6 +42,11 @@ + #undef CONFIG_BGP + #undef CONFIG_OSPF + #undef CONFIG_PIPE ++#undef CONFIG_FIREWALL ++ ++#undef CONFIG_FIREWALL_IPFW ++#undef CONFIG_FIREWALL_PF ++#undef CONFIG_FIREWALL_IPSET + + /* We have <syslog.h> and syslog() */ + #undef HAVE_SYSLOG +diff --git sysdep/bsd/Modules sysdep/bsd/Modules +index 84abffd..77f26e3 100644 +--- sysdep/bsd/Modules ++++ sysdep/bsd/Modules +@@ -4,3 +4,4 @@ sysio.h + krt-set.h + krt-sock.c + krt-sock.h ++fw.c +diff --git sysdep/bsd/fw.c sysdep/bsd/fw.c +new file mode 100644 +index 0000000..e841e06 +--- /dev/null ++++ sysdep/bsd/fw.c +@@ -0,0 +1,404 @@ ++/* ++ * BIRD -- IPFW/PF manipulations ++ * ++ * (c) 2011 Alexander V. Chernikov <melifaro@FreeBSD.org> ++ * ++ * Can be freely distributed and used under the terms of the GNU GPL. ++ */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <limits.h> ++#include <ctype.h> ++#include <fcntl.h> ++#include <unistd.h> ++#include <sys/param.h> ++#include <sys/types.h> ++#include <sys/socket.h> ++#include <sys/sysctl.h> ++#include <sys/ioctl.h> ++#include <netinet/in.h> ++#include <errno.h> ++#include <err.h> ++#include <net/route.h> ++#include <net/if.h> ++#include <net/if_dl.h> ++ ++#undef LOCAL_DEBUG ++ ++#include "nest/bird.h" ++#include "nest/iface.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" ++#include "lib/socket.h" ++#ifdef CONFIG_FIREWALL ++#include "proto/firewall/firewall.h" ++#ifdef CONFIG_FIREWALL_IPFW ++#include "netinet/ip_fw.h" ++#endif ++#ifdef CONFIG_FIREWALL_PF ++#include "net/pfvar.h" ++#endif ++ ++#ifdef CONFIG_FIREWALL_IPFW ++ ++int ipfw_fd = -1; ++int ipfw_instance_count = 0; ++ ++struct ipfw_priv { ++ int table; /* Table number */ ++ pool *pool; /* Protocol pool */ ++}; ++ ++int ++ipfw_do_cmd(int optname, void *optval, uintptr_t optlen) ++{ ++ return setsockopt(ipfw_fd, IPPROTO_IP, optname, optval, optlen); ++} ++ ++void * ++ipfw_fw_init(struct proto *p, char *table) ++{ ++ pool *fwpool = p->pool; ++ int table_num = strtol(table, NULL, 10); ++ int tables_max; ++ size_t len = sizeof(tables_max); ++ ++ if (sysctlbyname("net.inet.ip.fw.tables_max", &tables_max, &len, NULL, 0) == -1) ++ { ++ log(L_ERR "Error getting maximum ipfw table count"); ++ tables_max = IPFW_TABLES_MAX; ++ } ++ DBG("ipfw maximum table count set to %d\n", tables_max); ++ ++ if ((table_num < 0) || (table_num >= tables_max)) ++ { ++ log(L_ERR "ipfw table %d is not within possible range (0..%d)", table_num, tables_max); ++ return NULL; ++ } ++ ++ if (ipfw_fd == -1) ++ { ++ if ((ipfw_fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) ++ { ++ log(L_ERR "ipfw: error opering raw socket: %m"); ++ return NULL; ++ } ++ DBG("Opened IPFW socked %d\n", ipfw_fd); ++ } ++ ++ struct ipfw_priv *priv = mb_alloc(fwpool, sizeof(struct ipfw_priv)); ++ ++ priv->table = table_num; ++ priv->pool = fwpool; ++ ++ ipfw_instance_count++; ++ ++ return priv; ++} ++ ++void ++ipfw_fw_shutdown(void *_priv UNUSED) ++{ ++ if (--ipfw_instance_count == 0) ++ { ++ DBG("Closing ipfw socket %d\n", ipfw_fd); ++ close(ipfw_fd); ++ ipfw_fd = -1; ++ } ++} ++ ++int ++ipfw_fw_flush(void *_priv) ++{ ++ struct ipfw_priv *priv = _priv; ++ ipfw_table_entry ent; ++ ++ memset(&ent, 0, sizeof(ent)); ++ ent.tbl = priv->table; ++ ++ log(L_DEBUG "Flushing ipfw table %d", priv->table); ++ ++ if (ipfw_do_cmd(IP_FW_TABLE_FLUSH, &ent.tbl, sizeof(ent.tbl)) == -1) ++ { ++ log(L_ERR "Error flushing ipfw table %d: %m", priv->table); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++int ++ipfw_fw_add(void *_priv, net *n, char *prefixdata) ++{ ++ struct ipfw_priv *priv = _priv; ++ ip_addr addr; ++ ipfw_table_entry ent; ++ ++ addr = n->n.prefix; ++ ipa_hton(addr); ++ ++ ent.masklen = n->n.pxlen; ++ memcpy(&ent.addr, &addr, sizeof(ip_addr)); ++ ent.value = strtol(prefixdata, NULL, 0); ++ ent.tbl = priv->table; ++ ++ DBG("Adding %I/%d to ipfw table %d with value %s\n", n->n.prefix, n->n.pxlen, priv->table, prefixdata); ++ ++ if (ipfw_do_cmd(IP_FW_TABLE_ADD, &ent, sizeof(ent)) == -1) ++ { ++ FW_ERR("Error adding %I/%d to ipfw table %d: %m", n->n.prefix, n->n.pxlen, priv->table); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++int ++ipfw_fw_del(void *_priv, net *n) ++{ ++ struct ipfw_priv *priv = _priv; ++ ip_addr addr; ++ ipfw_table_entry ent; ++ ++ addr = n->n.prefix; ++ ipa_hton(addr); ++ ++ ent.masklen = n->n.pxlen; ++ memcpy(&ent.addr, &addr, sizeof(ip_addr)); ++ ent.value = 0; ++ ent.tbl = priv->table; ++ ++ DBG("Removing %I/%d from ipfw table %d\n", n->n.prefix, n->n.pxlen, priv->table); ++ ++ if (ipfw_do_cmd(IP_FW_TABLE_DEL, &ent, sizeof(ent)) == -1) ++ { ++ FW_ERR("Error removing %I/%d from ipfw table %d: %m", n->n.prefix, n->n.pxlen, priv->table); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++struct firewall_control fw_ipfw = { ++ fwtype: FWTYPE_IPFW, ++ description: "IPFW", ++ fw_init: ipfw_fw_init, ++ fw_shutdown: ipfw_fw_shutdown, ++ fw_flush: ipfw_fw_flush, ++ fw_add: ipfw_fw_add, ++ fw_del: ipfw_fw_del, ++}; ++#endif ++ ++#ifdef CONFIG_FIREWALL_PF ++ ++#define PF_DEVNAME "/dev/pf" ++int pf_fd = -1; ++int pf_instance_count = 0; ++ ++struct pf_priv { ++ struct pfr_table table; /* PF table structure */ ++ pool *pool; /* Protocol pool */ ++}; ++ ++#define pf_tablename table.pfrt_name ++ ++int ++pf_do_cmd(struct pfr_table *tbl, unsigned long cmd, void *buffer, int esize, int items, int *nadd, int *ndel, int flags) ++{ ++ struct pfioc_table io; ++ ++ bzero(&io, sizeof(io)); ++ io.pfrio_flags = flags; ++ if (tbl) ++ io.pfrio_table = *tbl; ++ io.pfrio_buffer = buffer; ++ io.pfrio_esize = esize; ++ io.pfrio_size = items; ++ ++ /* DBG("Doing PF ioctl %X for table %s on fd %d\n", cmd, tbl ? tbl->pfrt_name : "NULL", pf_fd); */ ++ if (ioctl(pf_fd, cmd, &io)) ++ return 0; ++ ++ if (nadd) ++ *nadd = io.pfrio_nadd; ++ if (ndel) ++ *ndel = io.pfrio_ndel; ++ ++ return 1; ++} ++ ++void * ++pf_fw_init(struct proto *p, char *table) ++{ ++ pool *fwpool = p->pool; ++ struct pfr_table pf_table; ++ int nadd = 0; ++ ++ if (strlen(table) > PF_TABLE_NAME_SIZE) ++ { ++ log(L_ERR "PF table name too long, max %d", PF_TABLE_NAME_SIZE); ++ return NULL; ++ } ++ ++ memset(&pf_table, 0, sizeof(pf_table)); ++ ++ if (pf_fd == -1) ++ { ++ if ((pf_fd = open(PF_DEVNAME, O_RDWR)) == -1) ++ { ++ log(L_ERR "pf: error opening %s: %m", PF_DEVNAME); ++ return NULL; ++ } ++ ++ DBG("Opened PF socked %d\n", pf_fd); ++ } ++ ++ strcpy(pf_table.pfrt_name, table); ++ pf_table.pfrt_flags |= PFR_TFLAG_PERSIST; ++ if (!pf_do_cmd(NULL, DIOCRADDTABLES, &pf_table, sizeof(pf_table), 1, &nadd, NULL, 0)) ++ { ++ log(L_ERR "Error creating PF table %s: %m", table); ++ if (pf_instance_count == 0) ++ { ++ log(L_ERR "Closing PF socket"); ++ close(pf_fd); ++ pf_fd = -1; ++ } ++ return NULL; ++ } ++ DBG("PF table %s created\n", table); ++ /* Remove persistent flag */ ++ pf_table.pfrt_flags = 0; ++ ++ struct pf_priv *priv = mb_alloc(fwpool, sizeof(struct pf_priv)); ++ ++ priv->table = pf_table; ++ priv->pool = fwpool; ++ ++ pf_instance_count++; ++ ++ return priv; ++} ++ ++void ++pf_fw_shutdown(void *_priv UNUSED) ++{ ++ if (--pf_instance_count == 0) ++ { ++ DBG("Closing PF socket %d\n", pf_fd); ++ close(pf_fd); ++ pf_fd = -1; ++ } ++} ++ ++int ++pf_fw_flush(void *_priv) ++{ ++ struct pf_priv *priv = _priv; ++ int ndel; ++ ++ log(L_DEBUG "Flushing PF table %s", priv->pf_tablename); ++ ++ if (!pf_do_cmd(&priv->table, DIOCRCLRADDRS, NULL, 0, 0, NULL, &ndel, 0)) ++ { ++ log(L_ERR "Error flushing PF table %s: %m", priv->pf_tablename); ++ return 0; ++ } ++ ++ DBG("Flushed %d record(s) from PF table %s\n", ndel, priv->pf_tablename); ++ ++ return 1; ++} ++ ++static int ++pf_put_addr(struct pfr_addr *pf_addr, net *n) ++{ ++ int rt_family = AF_INET; ++ ip_addr addr; ++ ++ memset(pf_addr, 0, sizeof(struct pfr_addr)); ++ pf_addr->pfra_not = 0; ++ pf_addr->pfra_net = n->n.pxlen; ++ switch (rt_family) ++ { ++ case AF_INET: ++ addr = n->n.prefix; ++ ipa_hton(addr); ++ pf_addr->pfra_ip4addr.s_addr = addr; ++ pf_addr->pfra_af = rt_family; ++ break; ++ default: ++ log(L_ERR "Address family %d is not supported by pf, ignoring prefix", rt_family); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++int ++pf_fw_add(void *_priv, net *n, char *prefixdata) ++{ ++ struct pf_priv *priv = _priv; ++ struct pfr_addr pf_addr; ++ int nadd = 0; ++ ++ if (!pf_put_addr(&pf_addr, n)) ++ { ++ FW_ERR("Error adding %I/%d to PF table %s", n->n.prefix, n->n.pxlen, priv->pf_tablename); ++ return 0; ++ } ++ ++ DBG("Adding %I/%d to PF table %s with value %s\n", n->n.prefix, n->n.pxlen, priv->pf_tablename, prefixdata); ++ if (!pf_do_cmd(&priv->table, DIOCRADDADDRS, &pf_addr, sizeof(pf_addr), 1, &nadd, NULL, 0)) ++ { ++ FW_ERR("Error adding %I/%d to PF table %s: %m", n->n.prefix, n->n.pxlen, priv->pf_tablename); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++int ++pf_fw_del(void *_priv, net *n) ++{ ++ struct pf_priv *priv = _priv; ++ struct pfr_addr pf_addr; ++ int ndel = 0; ++ ++ if (!pf_put_addr(&pf_addr, n)) ++ { ++ FW_ERR("Error deleting %I/%d from PF table %s", n->n.prefix, n->n.pxlen, priv->pf_tablename); ++ return 0; ++ } ++ ++ DBG("Deleting %I/%d from PF table %s\n", n->n.prefix, n->n.pxlen, priv->pf_tablename); ++ if (!pf_do_cmd(&priv->table, DIOCRDELADDRS, &pf_addr, sizeof(pf_addr), 1, NULL, &ndel, 0)) ++ { ++ FW_ERR("Error deleting %I/%d from PF table %s: %m", n->n.prefix, n->n.pxlen, priv->pf_tablename); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++struct firewall_control fw_pf = { ++ fwtype: FWTYPE_PF, ++ description: "PF", ++ fw_init: pf_fw_init, ++ fw_shutdown: pf_fw_shutdown, ++ fw_flush: pf_fw_flush, ++ fw_add: pf_fw_add, ++ fw_del: pf_fw_del, ++}; ++#endif ++ ++ ++#endif ++ +-- +1.7.3.2 + diff --git a/net/bird/files/patch-136-post.diff b/net/bird/files/patch-136-post.diff new file mode 100644 index 000000000000..0bc99258965c --- /dev/null +++ b/net/bird/files/patch-136-post.diff @@ -0,0 +1,507 @@ +diff --git nest/config.Y nest/config.Y +index a6baf4e..3fcfa52 100644 +--- nest/config.Y ++++ nest/config.Y +@@ -219,7 +219,6 @@ CF_ADDTO(proto, dev_proto '}') + + dev_proto_start: proto_start DIRECT { + this_proto = proto_config_new(&proto_device, sizeof(struct rt_dev_config), $1); +- this_proto->preference = DEF_PREF_DIRECT; + init_list(&DIRECT_CFG->iface_list); + } + ; +diff --git nest/iface.c nest/iface.c +index b8b214e..eea3d3b 100644 +--- nest/iface.c ++++ nest/iface.c +@@ -253,6 +253,24 @@ if_change_flags(struct iface *i, unsigned flags) + } + + /** ++ * if_delete - remove interface ++ * @old: interface ++ * ++ * This function is called by the low-level platform dependent code ++ * whenever it notices an interface disappears. It is just a shorthand ++ * for if_update(). ++ */ ++ ++void ++if_delete(struct iface *old) ++{ ++ struct iface f = {}; ++ strncpy(f.name, old->name, sizeof(f.name)-1); ++ f.flags = IF_SHUTDOWN; ++ if_update(&f); ++} ++ ++/** + * if_update - update interface status + * @new: new interface status + * +@@ -288,13 +306,14 @@ if_update(struct iface *new) + new->addr = i->addr; + memcpy(&new->addrs, &i->addrs, sizeof(i->addrs)); + memcpy(i, new, sizeof(*i)); ++ i->flags &= ~IF_UP; /* IF_TMP_DOWN will be added later */ + goto newif; + } +- else if (c) +- { +- if_copy(i, new); +- if_notify_change(c, i); +- } ++ ++ if_copy(i, new); ++ if (c) ++ if_notify_change(c, i); ++ + i->flags |= IF_UPDATED; + return i; + } +@@ -400,7 +419,7 @@ if_find_by_index(unsigned idx) + struct iface *i; + + WALK_LIST(i, iface_list) +- if (i->index == idx) ++ if (i->index == idx && !(i->flags & IF_SHUTDOWN)) + return i; + return NULL; + } +diff --git nest/iface.h nest/iface.h +index d6d58ff..2416f82 100644 +--- nest/iface.h ++++ nest/iface.h +@@ -88,6 +88,7 @@ void ifa_dump(struct ifa *); + void if_show(void); + void if_show_summary(void); + struct iface *if_update(struct iface *); ++void if_delete(struct iface *old); + struct ifa *ifa_update(struct ifa *); + void ifa_delete(struct ifa *); + void if_start_update(void); +diff --git nest/proto.c nest/proto.c +index d55c348..0fc72ce 100644 +--- nest/proto.c ++++ nest/proto.c +@@ -200,6 +200,7 @@ proto_config_new(struct protocol *pr, unsigned size, int class) + c->global = new_config; + c->protocol = pr; + c->name = pr->name; ++ c->preference = pr->preference; + c->class = class; + c->out_filter = FILTER_REJECT; + c->table = c->global->master_rtc; +diff --git nest/protocol.h nest/protocol.h +index 3766e15..a83c4ff 100644 +--- nest/protocol.h ++++ nest/protocol.h +@@ -39,6 +39,7 @@ struct protocol { + char *template; /* Template for automatic generation of names */ + int name_counter; /* Counter for automatic name generation */ + int attr_class; /* Attribute class known to this protocol */ ++ unsigned preference; /* Default protocol preference */ + + void (*preconfig)(struct protocol *, struct config *); /* Just before configuring */ + void (*postconfig)(struct proto_config *); /* After configuring each instance */ +diff --git nest/rt-dev.c nest/rt-dev.c +index 497ee80..54cb14b 100644 +--- nest/rt-dev.c ++++ nest/rt-dev.c +@@ -109,6 +109,7 @@ dev_copy_config(struct proto_config *dest, struct proto_config *src) + struct protocol proto_device = { + name: "Direct", + template: "direct%d", ++ preference: DEF_PREF_DIRECT, + init: dev_init, + reconfigure: dev_reconfigure, + copy_config: dev_copy_config +diff --git proto/bgp/bgp.c proto/bgp/bgp.c +index 66fdc60..4d3c32f 100644 +--- proto/bgp/bgp.c ++++ proto/bgp/bgp.c +@@ -1178,6 +1178,7 @@ struct protocol proto_bgp = { + name: "BGP", + template: "bgp%d", + attr_class: EAP_BGP, ++ preference: DEF_PREF_BGP, + init: bgp_init, + start: bgp_start, + shutdown: bgp_shutdown, +diff --git proto/bgp/config.Y proto/bgp/config.Y +index 5fb6094..78ca52d 100644 +--- proto/bgp/config.Y ++++ proto/bgp/config.Y +@@ -33,7 +33,6 @@ CF_ADDTO(proto, bgp_proto '}' { bgp_check_config(BGP_CFG); } ) + + bgp_proto_start: proto_start BGP { + this_proto = proto_config_new(&proto_bgp, sizeof(struct bgp_config), $1); +- this_proto->preference = DEF_PREF_BGP; + BGP_CFG->hold_time = 240; + BGP_CFG->connect_retry_time = 120; + BGP_CFG->initial_hold_time = 240; +diff --git proto/ospf/config.Y proto/ospf/config.Y +index 4ada41e..24e125a 100644 +--- proto/ospf/config.Y ++++ proto/ospf/config.Y +@@ -129,7 +129,6 @@ CF_ADDTO(proto, ospf_proto '}' { ospf_proto_finish(); } ) + + ospf_proto_start: proto_start OSPF { + this_proto = proto_config_new(&proto_ospf, sizeof(struct ospf_config), $1); +- this_proto->preference = DEF_PREF_OSPF; + init_list(&OSPF_CFG->area_list); + init_list(&OSPF_CFG->vlink_list); + OSPF_CFG->rfc1583 = DEFAULT_RFC1583; +diff --git proto/ospf/ospf.c proto/ospf/ospf.c +index ce7ad37..73c06c2 100644 +--- proto/ospf/ospf.c ++++ proto/ospf/ospf.c +@@ -1542,6 +1542,7 @@ struct protocol proto_ospf = { + name: "OSPF", + template: "ospf%d", + attr_class: EAP_OSPF, ++ preference: DEF_PREF_OSPF, + init: ospf_init, + dump: ospf_dump, + start: ospf_start, +diff --git proto/ospf/ospf.h proto/ospf/ospf.h +index 60a34fb..d696151 100644 +--- proto/ospf/ospf.h ++++ proto/ospf/ospf.h +@@ -177,7 +177,7 @@ struct ospf_area_config + struct ospf_iface + { + node n; +- struct iface *iface; /* Nest's iface */ ++ struct iface *iface; /* Nest's iface, non-NULL (unless type OSPF_IT_VLINK) */ + struct ifa *addr; /* IP prefix associated with that OSPF iface */ + struct ospf_area *oa; + struct ospf_iface_patt *cf; +diff --git proto/ospf/packet.c proto/ospf/packet.c +index df67d5a..7a26967 100644 +--- proto/ospf/packet.c ++++ proto/ospf/packet.c +@@ -489,17 +489,17 @@ ospf_rx_hook(sock *sk, int size) + void + ospf_tx_hook(sock * sk) + { +-// struct ospf_iface *ifa= (struct ospf_iface *) (sk->data); ++ struct ospf_iface *ifa= (struct ospf_iface *) (sk->data); + // struct proto *p = (struct proto *) (ifa->oa->po); +- log(L_ERR "OSPF: TX_Hook called"); ++ log(L_ERR "OSPF: TX hook called on %s", ifa->iface->name); + } + + void + ospf_err_hook(sock * sk, int err) + { +-// struct ospf_iface *ifa= (struct ospf_iface *) (sk->data); ++ struct ospf_iface *ifa= (struct ospf_iface *) (sk->data); + // struct proto *p = (struct proto *) (ifa->oa->po); +- log(L_ERR "OSPF: Socket error: %M", err); ++ log(L_ERR "OSPF: Socket error on %s: %M", ifa->iface->name, err); + } + + void +diff --git proto/pipe/config.Y proto/pipe/config.Y +index 4478afe..4063755 100644 +--- proto/pipe/config.Y ++++ proto/pipe/config.Y +@@ -24,7 +24,6 @@ CF_ADDTO(proto, pipe_proto '}') + + pipe_proto_start: proto_start PIPE { + this_proto = proto_config_new(&proto_pipe, sizeof(struct pipe_config), $1); +- this_proto->preference = DEF_PREF_PIPE; + PIPE_CFG->mode = PIPE_TRANSPARENT; + } + ; +diff --git proto/pipe/pipe.c proto/pipe/pipe.c +index 420c5a9..fe8618b 100644 +--- proto/pipe/pipe.c ++++ proto/pipe/pipe.c +@@ -197,6 +197,7 @@ pipe_get_status(struct proto *P, byte *buf) + struct protocol proto_pipe = { + name: "Pipe", + template: "pipe%d", ++ preference: DEF_PREF_PIPE, + postconfig: pipe_postconfig, + init: pipe_init, + start: pipe_start, +diff --git proto/rip/rip.c proto/rip/rip.c +index 543aa30..f0a4134 100644 +--- proto/rip/rip.c ++++ proto/rip/rip.c +@@ -975,7 +975,6 @@ void + rip_init_config(struct rip_proto_config *c) + { + init_list(&c->iface_list); +- c->c.preference = DEF_PREF_RIP; + c->infinity = 16; + c->port = 520; + c->period = 30; +@@ -1032,6 +1031,7 @@ struct protocol proto_rip = { + name: "RIP", + template: "rip%d", + attr_class: EAP_RIP, ++ preference: DEF_PREF_RIP, + get_route_info: rip_get_route_info, + get_attr: rip_get_attr, + +diff --git proto/static/static.c proto/static/static.c +index f6c2a33..aaa9bfa 100644 +--- proto/static/static.c ++++ proto/static/static.c +@@ -353,7 +353,6 @@ static_if_notify(struct proto *p, unsigned flags, struct iface *i) + void + static_init_config(struct static_config *c) + { +- c->c.preference = DEF_PREF_STATIC; + init_list(&c->iface_routes); + init_list(&c->other_routes); + } +@@ -523,6 +522,7 @@ static_copy_config(struct proto_config *dest, struct proto_config *src) + struct protocol proto_static = { + name: "Static", + template: "static%d", ++ preference: DEF_PREF_STATIC, + init: static_init, + dump: static_dump, + start: static_start, +diff --git sysdep/bsd/krt-sock.c sysdep/bsd/krt-sock.c +index 4bf6600..4ee5495 100644 +--- sysdep/bsd/krt-sock.c ++++ sysdep/bsd/krt-sock.c +@@ -410,14 +410,42 @@ krt_read_rt(struct ks_msg *msg, struct krt_proto *p, int scan) + } + + static void ++krt_read_ifannounce(struct ks_msg *msg) ++{ ++ struct if_announcemsghdr *ifam = (struct if_announcemsghdr *)&msg->rtm; ++ ++ if (ifam->ifan_what == IFAN_ARRIVAL) ++ { ++ /* Not enough info to create the iface, so we just trigger iface scan */ ++ kif_request_scan(); ++ } ++ else if (ifam->ifan_what == IFAN_DEPARTURE) ++ { ++ struct iface *iface = if_find_by_index(ifam->ifan_index); ++ ++ /* Interface is destroyed */ ++ if (!iface) ++ { ++ DBG("KRT: unknown interface (%s, #%d) going down. Ignoring\n", ifam->ifan_name, ifam->ifan_index); ++ return; ++ } ++ ++ if_delete(iface); ++ } ++ ++ DBG("KRT: IFANNOUNCE what: %d index %d name %s\n", ifam->ifan_what, ifam->ifan_index, ifam->ifan_name); ++} ++ ++static void + krt_read_ifinfo(struct ks_msg *msg) + { + struct if_msghdr *ifm = (struct if_msghdr *)&msg->rtm; + void *body = (void *)(ifm + 1); + struct sockaddr_dl *dl = NULL; + unsigned int i; +- struct iface *iface = NULL, f; ++ struct iface *iface = NULL, f = {}; + int fl = ifm->ifm_flags; ++ int nlen = 0; + + for (i = 1; i<=RTA_IFP; i <<= 1) + { +@@ -432,31 +460,42 @@ krt_read_ifinfo(struct ks_msg *msg) + } + } + +- if(dl && (dl->sdl_family != AF_LINK)) ++ if (dl && (dl->sdl_family != AF_LINK)) + { +- log("Ignoring strange IFINFO"); ++ log(L_WARN "Ignoring strange IFINFO"); + return; + } + +- iface = if_find_by_index(ifm->ifm_index); ++ if (dl) ++ nlen = MIN(sizeof(f.name)-1, dl->sdl_nlen); + +- if(!iface) ++ /* Note that asynchronous IFINFO messages do not contain iface ++ name, so we have to found an existing iface by iface index */ ++ ++ iface = if_find_by_index(ifm->ifm_index); ++ if (!iface) + { + /* New interface */ +- if(!dl) return; /* No interface name, ignoring */ ++ if (!dl) ++ return; /* No interface name, ignoring */ + +- bzero(&f, sizeof(f)); +- f.index = ifm->ifm_index; +- memcpy(f.name, dl->sdl_data, MIN(sizeof(f.name)-1, dl->sdl_nlen)); +- DBG("New interface '%s' found", f.name); ++ memcpy(f.name, dl->sdl_data, nlen); ++ DBG("New interface '%s' found\n", f.name); ++ } ++ else if (dl && memcmp(iface->name, dl->sdl_data, nlen)) ++ { ++ /* Interface renamed */ ++ if_delete(iface); ++ memcpy(f.name, dl->sdl_data, nlen); + } + else + { +- memcpy(&f, iface, sizeof(struct iface)); ++ /* Old interface */ ++ memcpy(f.name, iface->name, sizeof(f.name)); + } + ++ f.index = ifm->ifm_index; + f.mtu = ifm->ifm_data.ifi_mtu; +- f.flags = 0; + + if (fl & IFF_UP) + f.flags |= IF_ADMIN_UP; +@@ -471,8 +510,7 @@ krt_read_ifinfo(struct ks_msg *msg) + else + f.flags |= IF_MULTIACCESS; /* NBMA */ + +- if((!iface) || memcmp(&f, iface, sizeof(struct iface))) +- if_update(&f); /* Just if something happens */ ++ if_update(&f); + } + + static void +@@ -588,6 +626,9 @@ krt_read_msg(struct proto *p, struct ks_msg *msg, int scan) + case RTM_DELETE: + krt_read_rt(msg, (struct krt_proto *)p, scan); + break; ++ case RTM_IFANNOUNCE: ++ krt_read_ifannounce(msg); ++ break; + case RTM_IFINFO: + krt_read_ifinfo(msg); + break; +diff --git sysdep/linux/netlink/netlink.c sysdep/linux/netlink/netlink.c +index cf80823..17c369e 100644 +--- sysdep/linux/netlink/netlink.c ++++ sysdep/linux/netlink/netlink.c +@@ -386,7 +386,7 @@ nl_parse_link(struct nlmsghdr *h, int scan) + struct ifinfomsg *i; + struct rtattr *a[IFLA_WIRELESS+1]; + int new = h->nlmsg_type == RTM_NEWLINK; +- struct iface f; ++ struct iface f = {}; + struct iface *ifi; + char *name; + u32 mtu; +@@ -408,26 +408,21 @@ nl_parse_link(struct nlmsghdr *h, int scan) + if (!new) + { + DBG("KIF: IF%d(%s) goes down\n", i->ifi_index, name); +- if (ifi && !scan) +- { +- memcpy(&f, ifi, sizeof(struct iface)); +- f.flags |= IF_SHUTDOWN; +- if_update(&f); +- } ++ if (!ifi) ++ return; ++ ++ if_delete(ifi); + } + else + { + DBG("KIF: IF%d(%s) goes up (mtu=%d,flg=%x)\n", i->ifi_index, name, mtu, i->ifi_flags); +- if (ifi) +- memcpy(&f, ifi, sizeof(f)); +- else +- { +- bzero(&f, sizeof(f)); +- f.index = i->ifi_index; +- } +- strncpy(f.name, RTA_DATA(a[IFLA_IFNAME]), sizeof(f.name)-1); ++ if (ifi && strncmp(ifi->name, name, sizeof(ifi->name)-1)) ++ if_delete(ifi); ++ ++ strncpy(f.name, name, sizeof(f.name)-1); ++ f.index = i->ifi_index; + f.mtu = mtu; +- f.flags = 0; ++ + fl = i->ifi_flags; + if (fl & IFF_UP) + f.flags |= IF_ADMIN_UP; +diff --git sysdep/unix/krt.Y sysdep/unix/krt.Y +index 8608196..18e1e52 100644 +--- sysdep/unix/krt.Y ++++ sysdep/unix/krt.Y +@@ -31,7 +31,6 @@ kern_proto_start: proto_start KERNEL { + cf_error("Kernel protocol already defined"); + #endif + cf_krt = this_proto = proto_config_new(&proto_unix_kernel, sizeof(struct krt_config), $1); +- this_proto->preference = DEF_PREF_INHERITED; + THIS_KRT->scan_time = 60; + THIS_KRT->learn = THIS_KRT->persist = 0; + krt_scan_construct(THIS_KRT); +@@ -67,7 +66,6 @@ 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_proto->preference = DEF_PREF_DIRECT; + THIS_KIF->scan_time = 60; + init_list(&THIS_KIF->primary); + krt_if_construct(THIS_KIF); +diff --git sysdep/unix/krt.c sysdep/unix/krt.c +index e5a8ce1..231c5fc 100644 +--- sysdep/unix/krt.c ++++ sysdep/unix/krt.c +@@ -104,6 +104,13 @@ kif_force_scan(void) + } + } + ++void ++kif_request_scan(void) ++{ ++ if (kif_proto && kif_scan_timer->expires > now) ++ tm_start(kif_scan_timer, 1); ++} ++ + static struct proto * + kif_init(struct proto_config *c) + { +@@ -236,6 +243,7 @@ kif_copy_config(struct proto_config *dest, struct proto_config *src) + struct protocol proto_unix_iface = { + name: "Device", + template: "device%d", ++ preference: DEF_PREF_DIRECT, + preconfig: kif_preconfig, + init: kif_init, + start: kif_start, +@@ -961,6 +969,7 @@ struct protocol proto_unix_kernel = { + name: "Kernel", + template: "kernel%d", + attr_class: EAP_KRT, ++ preference: DEF_PREF_INHERITED, + preconfig: krt_preconfig, + postconfig: krt_postconfig, + init: krt_init, +diff --git sysdep/unix/krt.h sysdep/unix/krt.h +index 7bb4fe7..b0c4dc5 100644 +--- sysdep/unix/krt.h ++++ sysdep/unix/krt.h +@@ -77,6 +77,7 @@ extern pool *krt_pool; + if (pr->p.debug & fl) \ + { log(L_TRACE "%s: " msg, pr->p.name , ## args); } } while(0) + ++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); + diff --git a/net/bird/files/patch-protocoltemplates.diff b/net/bird/files/patch-protocoltemplates.diff deleted file mode 100644 index d12a85f5fc19..000000000000 --- a/net/bird/files/patch-protocoltemplates.diff +++ /dev/null @@ -1,1085 +0,0 @@ -commit a7f23f581f5e3efe92ec97dfca7d01c66f31ab04 -Author: Ondrej Zajicek <santiago@crfreenet.org> -Date: Mon Nov 7 00:31:23 2011 +0100 - - Implements protocol templates. - - Based on the patch from Alexander V. Chernikov. - Extended to support almost all protocols. - Uses 'protocol bgp NAME from TEMPLATE { ... }' syntax. - -diff --git a/conf/cf-lex.l b/conf/cf-lex.l -index 02ba4b3..ddfe8c7 100644 ---- conf/cf-lex.l -+++ conf/cf-lex.l -@@ -533,6 +533,8 @@ cf_symbol_class_name(struct symbol *sym) - return "routing table"; - case SYM_IPA: - return "network address"; -+ case SYM_TEMPLATE: -+ return "protocol template"; - default: - return "unknown type"; - } -diff --git a/conf/conf.c b/conf/conf.c -index 5bdeece..4b605b3 100644 ---- conf/conf.c -+++ conf/conf.c -@@ -377,3 +377,18 @@ cfg_strdup(char *c) - memcpy(z, c, l); - return z; - } -+ -+ -+void -+cfg_copy_list(list *dest, list *src, unsigned node_size) -+{ -+ node *dn, *sn; -+ -+ init_list(dest); -+ WALK_LIST(sn, *src) -+ { -+ dn = cfg_alloc(node_size); -+ memcpy(dn, sn, node_size); -+ add_tail(dest, dn); -+ } -+} -diff --git a/conf/conf.h b/conf/conf.h -index 142c6ad..8753baf 100644 ---- conf/conf.h -+++ conf/conf.h -@@ -84,6 +84,7 @@ extern linpool *cfg_mem; - #define cfg_allocu(size) lp_allocu(cfg_mem, size) - #define cfg_allocz(size) lp_allocz(cfg_mem, size) - char *cfg_strdup(char *c); -+void cfg_copy_list(list *dest, list *src, unsigned node_size); - - /* Lexer */ - -@@ -108,6 +109,7 @@ struct symbol { - #define SYM_FILTER 4 - #define SYM_TABLE 5 - #define SYM_IPA 6 -+#define SYM_TEMPLATE 7 - - #define SYM_VARIABLE 0x100 /* 0x100-0x1ff are variable types */ - -diff --git a/doc/bird.conf.example b/doc/bird.conf.example -index 339898f..5e07ab5 100644 ---- doc/bird.conf.example -+++ doc/bird.conf.example -@@ -202,3 +202,16 @@ protocol static { - # reject; - # }; - #} -+# -+# Template usage example -+#template bgp rr_client { -+# disabled; -+# local as 65000; -+# multihop; -+# rr client; -+# rr cluster id 1.0.0.1; -+#} -+# -+#protocol bgp rr_abcd from rr_client { -+# neighbor 10.1.4.7 as 65000; -+#} -diff --git a/doc/bird.sgml b/doc/bird.sgml -index d454629..7f53f02 100644 ---- doc/bird.sgml -+++ doc/bird.sgml -@@ -296,10 +296,21 @@ protocol rip { - <tag>function <m/name/ (<m/parameters/) <m/local variables/ { <m/commands/ }</tag> Define a function. You can learn more - about functions in the following chapter. - -- <tag>protocol rip|ospf|bgp|... <m/[name]/ { <m>protocol options</m> }</tag> Define a protocol -- instance called <cf><m/name/</cf> (or with a name like "rip5" generated automatically if you don't specify any <cf><m/name/</cf>). You can learn more -- about configuring protocols in their own chapters. You can run more than one instance of -- most protocols (like RIP or BGP). By default, no instances are configured. -+ <tag>protocol rip|ospf|bgp|... [<m/name/ [from <m/name2/]] { <m>protocol options</m> }</tag> -+ Define a protocol instance called <cf><m/name/</cf> (or with a name like "rip5" generated -+ automatically if you don't specify any <cf><m/name/</cf>). You can learn more about -+ configuring protocols in their own chapters. When <cf>from <m/name2/</cf> expression is -+ used, initial protocol options are taken from protocol or template <cf><m/name2/</cf> -+ You can run more than one instance of most protocols (like RIP or BGP). By default, no -+ instances are configured. -+ -+ <tag>template rip|bgp|... [<m/name/ [from <m/name2/]] { <m>protocol options</m> }</tag> -+ Define a protocol template instance called <cf><m/name/</cf> (or with a name like "bgp1" -+ generated automatically if you don't specify any <cf><m/name/</cf>). Protocol templates can -+ be used to group common options when many similarly configured protocol instances are to be -+ defined. Protocol instances (and other templates) can use templates by using <cf/from/ -+ expression and the name of the template. At the moment templates (and <cf/from/ expression) -+ are not implemented for OSPF protocol. - - <tag>define <m/constant/ = (<m/expression/)|<m/number/|<m/IP address/</tag> - Define a constant. You can use it later in every place you could use a simple integer or an IP address. -diff --git a/nest/config.Y b/nest/config.Y -index dd4a9e0..a6baf4e 100644 ---- nest/config.Y -+++ nest/config.Y -@@ -26,7 +26,7 @@ static int password_id; - static inline void - reset_passwords(void) - { -- this_p_list = NULL; -+ this_p_list = NULL; - } - - static inline list * -@@ -37,10 +37,11 @@ get_passwords(void) - return rv; - } - -+#define DIRECT_CFG ((struct rt_dev_config *) this_proto) - - CF_DECLS - --CF_KEYWORDS(ROUTER, ID, PROTOCOL, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT) -+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(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES) - CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, GENERATE) -@@ -58,7 +59,7 @@ CF_ENUM(T_ENUM_RTD, RTD_, ROUTER, DEVICE, BLACKHOLE, UNREACHABLE, PROHIBIT, MULT - %type <r> rtable - %type <s> optsym - %type <ra> r_args --%type <i> echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_or_preexport -+%type <i> proto_start echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_or_preexport - %type <ps> proto_patt proto_patt2 - - CF_GRAMMAR -@@ -115,20 +116,30 @@ newtab: TABLE SYM { - - CF_ADDTO(conf, proto) - --proto_start: PROTOCOL -+proto_start: -+ PROTOCOL { $$ = SYM_PROTO; } -+ | TEMPLATE { $$ = SYM_TEMPLATE; } - ; - - proto_name: - /* EMPTY */ { - struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter); -- s->class = SYM_PROTO; -+ s->class = this_proto->class; - s->def = this_proto; - this_proto->name = s->name; - } - | SYM { -- cf_define_symbol($1, SYM_PROTO, this_proto); -+ cf_define_symbol($1, this_proto->class, this_proto); - this_proto->name = $1->name; - } -+ | SYM FROM SYM { -+ if (($3->class != SYM_TEMPLATE) && ($3->class != SYM_PROTO)) cf_error("Template or protocol name expected"); -+ -+ cf_define_symbol($1, this_proto->class, this_proto); -+ this_proto->name = $1->name; -+ -+ proto_copy_config(this_proto, $3->def); -+ } - ; - - proto_item: -@@ -207,10 +218,9 @@ iface_patt_list: - CF_ADDTO(proto, dev_proto '}') - - dev_proto_start: proto_start DIRECT { -- struct rt_dev_config *p = proto_config_new(&proto_device, sizeof(struct rt_dev_config)); -- this_proto = &p->c; -- p->c.preference = DEF_PREF_DIRECT; -- init_list(&p->iface_list); -+ this_proto = proto_config_new(&proto_device, sizeof(struct rt_dev_config), $1); -+ this_proto->preference = DEF_PREF_DIRECT; -+ init_list(&DIRECT_CFG->iface_list); - } - ; - -@@ -222,9 +232,8 @@ dev_proto: - - dev_iface_init: - /* EMPTY */ { -- struct rt_dev_config *p = (void *) this_proto; - this_ipatt = cfg_allocz(sizeof(struct iface_patt)); -- add_tail(&p->iface_list, NODE this_ipatt); -+ add_tail(&DIRECT_CFG->iface_list, NODE this_ipatt); - init_list(&this_ipatt->ipn_list); - } - ; -diff --git a/nest/proto.c b/nest/proto.c -index 4a154d5..d55c348 100644 ---- nest/proto.c -+++ nest/proto.c -@@ -175,6 +175,7 @@ proto_flush_hooks(struct proto *p) - * proto_config_new - create a new protocol configuration - * @pr: protocol the configuration will belong to - * @size: size of the structure including generic data -+ * @class: SYM_PROTO or SYM_TEMPLATE - * - * Whenever the configuration file says that a new instance - * of a routing protocol should be created, the parser calls -@@ -183,16 +184,23 @@ proto_flush_hooks(struct proto *p) - * containing all the generic items followed by protocol-specific - * ones). Also, the configuration entry gets added to the list - * of protocol instances kept in the configuration. -+ * -+ * The function is also used to create protocol templates (when class -+ * SYM_TEMPLATE is specified), the only difference is that templates -+ * are not added to the list of protocol instances and therefore not -+ * initialized during protos_commit()). - */ - void * --proto_config_new(struct protocol *pr, unsigned size) -+proto_config_new(struct protocol *pr, unsigned size, int class) - { - struct proto_config *c = cfg_allocz(size); - -- add_tail(&new_config->protos, &c->n); -+ if (class == SYM_PROTO) -+ add_tail(&new_config->protos, &c->n); - c->global = new_config; - c->protocol = pr; - c->name = pr->name; -+ c->class = class; - c->out_filter = FILTER_REJECT; - c->table = c->global->master_rtc; - c->debug = new_config->proto_default_debug; -@@ -201,6 +209,50 @@ proto_config_new(struct protocol *pr, unsigned size) - } - - /** -+ * proto_copy_config - copy a protocol configuration -+ * @dest: destination protocol configuration -+ * @src: source protocol configuration -+ * -+ * Whenever a new instance of a routing protocol is created from the -+ * template, proto_copy_config() is called to copy a content of -+ * the source protocol configuration to the new protocol configuration. -+ * Name, class and a node in protos list of @dest are kept intact. -+ * copy_config() protocol hook is used to copy protocol-specific data. -+ */ -+void -+proto_copy_config(struct proto_config *dest, struct proto_config *src) -+{ -+ node old_node; -+ int old_class; -+ char *old_name; -+ -+ if (dest->protocol != src->protocol) -+ cf_error("Can't copy configuration from a different protocol type"); -+ -+ if (dest->protocol->copy_config == NULL) -+ cf_error("Inheriting configuration for %s is not supported", src->protocol->name); -+ -+ DBG("Copying configuration from %s to %s\n", src->name, dest->name); -+ -+ /* -+ * Copy struct proto_config here. Keep original node, class and name. -+ * protocol-specific config copy is handled by protocol copy_config() hook -+ */ -+ -+ old_node = dest->n; -+ old_class = dest->class; -+ old_name = dest->name; -+ -+ memcpy(dest, src, sizeof(struct proto_config)); -+ -+ dest->n = old_node; -+ dest->class = old_class; -+ dest->name = old_name; -+ -+ dest->protocol->copy_config(dest, src); -+} -+ -+/** - * protos_preconfig - pre-configuration processing - * @c: new configuration - * -@@ -230,7 +282,8 @@ protos_preconfig(struct config *c) - * @c: new configuration - * - * This function calls the postconfig() hooks of all protocol -- * instances specified in configuration @c. -+ * instances specified in configuration @c. The hooks are not -+ * called for protocol templates. - */ - void - protos_postconfig(struct config *c) -@@ -366,14 +419,15 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty - { - struct proto_config *oc, *nc; - struct proto *p, *n; -+ struct symbol *sym; - - DBG("protos_commit:\n"); - if (old) - { - WALK_LIST(oc, old->protos) - { -- struct proto *p = oc->proto; -- struct symbol *sym = cf_find_symbol(oc->name); -+ p = oc->proto; -+ sym = cf_find_symbol(oc->name); - if (sym && sym->class == SYM_PROTO && !new->shutdown) - { - /* Found match, let's check if we can smoothly switch to new configuration */ -diff --git a/nest/protocol.h b/nest/protocol.h -index f95905a..a7518c2 100644 ---- nest/protocol.h -+++ nest/protocol.h -@@ -53,6 +53,7 @@ struct protocol { - void (*get_route_info)(struct rte *, byte *buf, struct ea_list *attrs); /* Get route information (for `show route' command) */ - int (*get_attr)(struct eattr *, byte *buf, int buflen); /* ASCIIfy dynamic attribute (returns GA_*) */ - void (*show_proto_info)(struct proto *); /* Show protocol info (for `show protocols all' command) */ -+ void (*copy_config)(struct proto_config *, struct proto_config *); /* Copy config from given protocol instance */ - }; - - void protos_build(void); -@@ -85,12 +86,15 @@ struct proto_config { - struct proto *proto; /* Instance we've created */ - char *name; - char *dsc; -+ int class; /* SYM_PROTO or SYM_TEMPLATE */ - u32 debug, mrtdump; /* Debugging bitfields, both use D_* constants */ - unsigned preference, disabled; /* Generic parameters */ - u32 router_id; /* Protocol specific router ID */ - struct rtable_config *table; /* Table we're attached to */ - struct filter *in_filter, *out_filter; /* Attached filters */ - -+ /* Check proto_reconfigure() and proto_copy_config() after changing struct proto_config */ -+ - /* Protocol-specific data follow... */ - }; - -@@ -203,9 +207,14 @@ struct proto_spec { - - - void *proto_new(struct proto_config *, unsigned size); --void *proto_config_new(struct protocol *, unsigned size); -+void *proto_config_new(struct protocol *, unsigned size, int class); -+void proto_copy_config(struct proto_config *dest, struct proto_config *src); - void proto_request_feeding(struct proto *p); - -+static inline void -+proto_copy_rest(struct proto_config *dest, struct proto_config *src, unsigned size) -+{ memcpy(dest + 1, src + 1, size - sizeof(struct proto_config)); } -+ - void proto_cmd_show(struct proto *, unsigned int, int); - void proto_cmd_disable(struct proto *, unsigned int, int); - void proto_cmd_enable(struct proto *, unsigned int, int); -diff --git a/nest/rt-dev.c b/nest/rt-dev.c -index 239bd26..497ee80 100644 ---- nest/rt-dev.c -+++ nest/rt-dev.c -@@ -92,9 +92,24 @@ dev_reconfigure(struct proto *p, struct proto_config *new) - return iface_patts_equal(&o->iface_list, &n->iface_list, NULL); - } - -+static void -+dev_copy_config(struct proto_config *dest, struct proto_config *src) -+{ -+ struct rt_dev_config *d = (struct rt_dev_config *) dest; -+ struct rt_dev_config *s = (struct rt_dev_config *) src; -+ -+ /* -+ * We copy iface_list as ifaces can be shared by more direct protocols. -+ * Copy suffices to be is shallow, because new nodes can be added, but -+ * old nodes cannot be modified (although they contain internal lists). -+ */ -+ cfg_copy_list(&d->iface_list, &s->iface_list, sizeof(struct iface_patt)); -+} -+ - struct protocol proto_device = { - name: "Direct", - template: "direct%d", - init: dev_init, -- reconfigure: dev_reconfigure -+ reconfigure: dev_reconfigure, -+ copy_config: dev_copy_config - }; -diff --git a/nest/rt-dev.h b/nest/rt-dev.h -index 64f2cd9..c36d074 100644 ---- nest/rt-dev.h -+++ nest/rt-dev.h -@@ -11,7 +11,7 @@ - - struct rt_dev_config { - struct proto_config c; -- list iface_list; -+ list iface_list; /* list of struct iface_patt */ - }; - - #endif -diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c -index 4e4ca9f..675342d 100644 ---- proto/bgp/bgp.c -+++ proto/bgp/bgp.c -@@ -919,6 +919,73 @@ bgp_init(struct proto_config *C) - return P; - } - -+ -+void -+bgp_check_config(struct bgp_config *c) -+{ -+ int internal = (c->local_as == c->remote_as); -+ -+ /* Do not check templates at all */ -+ if (c->c.class == SYM_TEMPLATE) -+ return; -+ -+ if (!c->local_as) -+ cf_error("Local AS number must be set"); -+ -+ if (!c->remote_as) -+ cf_error("Neighbor must be configured"); -+ -+ if (!(c->capabilities && c->enable_as4) && (c->remote_as > 0xFFFF)) -+ cf_error("Neighbor AS number out of range (AS4 not available)"); -+ -+ if (!internal && c->rr_client) -+ cf_error("Only internal neighbor can be RR client"); -+ -+ if (internal && c->rs_client) -+ cf_error("Only external neighbor can be RS client"); -+ -+ if (c->multihop && (c->gw_mode == GW_DIRECT)) -+ cf_error("Multihop BGP cannot use direct gateway mode"); -+ -+ /* Different default based on rs_client */ -+ if (!c->missing_lladdr) -+ c->missing_lladdr = c->rs_client ? MLL_IGNORE : MLL_SELF; -+ -+ /* Different default for gw_mode */ -+ if (!c->gw_mode) -+ c->gw_mode = (c->multihop || internal) ? GW_RECURSIVE : GW_DIRECT; -+} -+ -+static int -+bgp_reconfigure(struct proto *P, struct proto_config *C) -+{ -+ struct bgp_config *new = (struct bgp_config *) C; -+ struct bgp_proto *p = (struct bgp_proto *) P; -+ struct bgp_config *old = p->cf; -+ -+ int same = !memcmp(((byte *) old) + sizeof(struct proto_config), -+ ((byte *) new) + sizeof(struct proto_config), -+ // password item is last and must be checked separately -+ OFFSETOF(struct bgp_config, password) - sizeof(struct proto_config)) -+ && ((!old->password && !new->password) -+ || (old->password && new->password && !strcmp(old->password, new->password))) -+ && (get_igp_table(old) == get_igp_table(new)); -+ -+ /* We should update our copy of configuration ptr as old configuration will be freed */ -+ if (same) -+ p->cf = new; -+ -+ return same; -+} -+ -+static void -+bgp_copy_config(struct proto_config *dest, struct proto_config *src) -+{ -+ /* Just a shallow copy */ -+ proto_copy_rest(dest, src, sizeof(struct bgp_config)); -+} -+ -+ - /** - * bgp_error - report a protocol error - * @c: connection -@@ -983,38 +1050,6 @@ bgp_store_error(struct bgp_proto *p, struct bgp_conn *c, u8 class, u32 code) - p->last_error_code = code; - } - --void --bgp_check(struct bgp_config *c) --{ -- int internal = (c->local_as == c->remote_as); -- -- if (!c->local_as) -- cf_error("Local AS number must be set"); -- -- if (!c->remote_as) -- cf_error("Neighbor must be configured"); -- -- if (!(c->capabilities && c->enable_as4) && (c->remote_as > 0xFFFF)) -- cf_error("Neighbor AS number out of range (AS4 not available)"); -- -- if (!internal && c->rr_client) -- cf_error("Only internal neighbor can be RR client"); -- -- if (internal && c->rs_client) -- cf_error("Only external neighbor can be RS client"); -- -- if (c->multihop && (c->gw_mode == GW_DIRECT)) -- cf_error("Multihop BGP cannot use direct gateway mode"); -- -- /* Different default based on rs_client */ -- if (!c->missing_lladdr) -- c->missing_lladdr = c->rs_client ? MLL_IGNORE : MLL_SELF; -- -- /* Different default for gw_mode */ -- if (!c->gw_mode) -- c->gw_mode = (c->multihop || internal) ? GW_RECURSIVE : GW_DIRECT; --} -- - static char *bgp_state_names[] = { "Idle", "Connect", "Active", "OpenSent", "OpenConfirm", "Established", "Close" }; - static char *bgp_err_classes[] = { "", "Error: ", "Socket: ", "Received: ", "BGP Error: ", "Automatic shutdown: ", ""}; - static char *bgp_misc_errors[] = { "", "Neighbor lost", "Invalid next hop", "Kernel MD5 auth failed", "No listening socket" }; -@@ -1124,28 +1159,6 @@ bgp_show_proto_info(struct proto *P) - } - } - --static int --bgp_reconfigure(struct proto *P, struct proto_config *C) --{ -- struct bgp_config *new = (struct bgp_config *) C; -- struct bgp_proto *p = (struct bgp_proto *) P; -- struct bgp_config *old = p->cf; -- -- int same = !memcmp(((byte *) old) + sizeof(struct proto_config), -- ((byte *) new) + sizeof(struct proto_config), -- // password item is last and must be checked separately -- OFFSETOF(struct bgp_config, password) - sizeof(struct proto_config)) -- && ((!old->password && !new->password) -- || (old->password && new->password && !strcmp(old->password, new->password))) -- && (get_igp_table(old) == get_igp_table(new)); -- -- /* We should update our copy of configuration ptr as old configuration will be freed */ -- if (same) -- p->cf = new; -- -- return same; --} -- - struct protocol proto_bgp = { - name: "BGP", - template: "bgp%d", -@@ -1155,6 +1168,7 @@ struct protocol proto_bgp = { - shutdown: bgp_shutdown, - cleanup: bgp_cleanup, - reconfigure: bgp_reconfigure, -+ copy_config: bgp_copy_config, - get_status: bgp_get_status, - get_attr: bgp_get_attr, - get_route_info: bgp_get_route_info, -diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h -index 16e8ea8..437ba33 100644 ---- proto/bgp/bgp.h -+++ proto/bgp/bgp.h -@@ -141,7 +141,7 @@ extern struct linpool *bgp_linpool; - - - void bgp_start_timer(struct timer *t, int value); --void bgp_check(struct bgp_config *c); -+void bgp_check_config(struct bgp_config *c); - void bgp_error(struct bgp_conn *c, unsigned code, unsigned subcode, byte *data, int len); - void bgp_close_conn(struct bgp_conn *c); - void bgp_update_startup_delay(struct bgp_proto *p); -diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y -index 19d757a..03c233d 100644 ---- proto/bgp/config.Y -+++ proto/bgp/config.Y -@@ -29,10 +29,10 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, - - CF_GRAMMAR - --CF_ADDTO(proto, bgp_proto '}' { bgp_check(BGP_CFG); } ) -+CF_ADDTO(proto, bgp_proto '}' { bgp_check_config(BGP_CFG); } ) - - bgp_proto_start: proto_start BGP { -- this_proto = proto_config_new(&proto_bgp, sizeof(struct bgp_config)); -+ this_proto = proto_config_new(&proto_bgp, sizeof(struct bgp_config), $1); - this_proto->preference = DEF_PREF_BGP; - BGP_CFG->hold_time = 240; - BGP_CFG->connect_retry_time = 120; -diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y -index ec7da8e..4ada41e 100644 ---- proto/ospf/config.Y -+++ proto/ospf/config.Y -@@ -128,7 +128,7 @@ CF_GRAMMAR - CF_ADDTO(proto, ospf_proto '}' { ospf_proto_finish(); } ) - - ospf_proto_start: proto_start OSPF { -- this_proto = proto_config_new(&proto_ospf, sizeof(struct ospf_config)); -+ this_proto = proto_config_new(&proto_ospf, sizeof(struct ospf_config), $1); - this_proto->preference = DEF_PREF_OSPF; - init_list(&OSPF_CFG->area_list); - init_list(&OSPF_CFG->vlink_list); -diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h -index 2e99b0f..60a34fb 100644 ---- proto/ospf/ospf.h -+++ proto/ospf/ospf.h -@@ -85,8 +85,8 @@ struct ospf_config - byte rfc1583; - byte abr; - int ecmp; -- list area_list; -- list vlink_list; -+ list area_list; /* list of struct ospf_area_config */ -+ list vlink_list; /* list of struct ospf_iface_patt */ - }; - - struct nbma_node -diff --git a/proto/pipe/config.Y b/proto/pipe/config.Y -index e1c981b..4478afe 100644 ---- proto/pipe/config.Y -+++ proto/pipe/config.Y -@@ -23,7 +23,7 @@ CF_GRAMMAR - CF_ADDTO(proto, pipe_proto '}') - - pipe_proto_start: proto_start PIPE { -- this_proto = proto_config_new(&proto_pipe, sizeof(struct pipe_config)); -+ this_proto = proto_config_new(&proto_pipe, sizeof(struct pipe_config), $1); - this_proto->preference = DEF_PREF_PIPE; - PIPE_CFG->mode = PIPE_TRANSPARENT; - } -diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c -index e557097..420c5a9 100644 ---- proto/pipe/pipe.c -+++ proto/pipe/pipe.c -@@ -165,14 +165,6 @@ pipe_postconfig(struct proto_config *C) - cf_error("Primary table and peer table must be different"); - } - --static void --pipe_get_status(struct proto *P, byte *buf) --{ -- struct pipe_proto *p = (struct pipe_proto *) P; -- -- bsprintf(buf, "%c> %s", (p->mode == PIPE_OPAQUE) ? '-' : '=', p->peer->name); --} -- - static int - pipe_reconfigure(struct proto *P, struct proto_config *new) - { -@@ -186,6 +178,21 @@ pipe_reconfigure(struct proto *P, struct proto_config *new) - return 1; - } - -+static void -+pipe_copy_config(struct proto_config *dest, struct proto_config *src) -+{ -+ /* Just a shallow copy, not many items here */ -+ proto_copy_rest(dest, src, sizeof(struct pipe_config)); -+} -+ -+static void -+pipe_get_status(struct proto *P, byte *buf) -+{ -+ struct pipe_proto *p = (struct pipe_proto *) P; -+ -+ bsprintf(buf, "%c> %s", (p->mode == PIPE_OPAQUE) ? '-' : '=', p->peer->name); -+} -+ - - struct protocol proto_pipe = { - name: "Pipe", -@@ -195,5 +202,6 @@ struct protocol proto_pipe = { - start: pipe_start, - cleanup: pipe_cleanup, - reconfigure: pipe_reconfigure, -+ copy_config: pipe_copy_config, - get_status: pipe_get_status, - }; -diff --git a/proto/radv/radv.c b/proto/radv/radv.c -index 01cb689..42d4bff 100644 ---- proto/radv/radv.c -+++ proto/radv/radv.c -@@ -318,6 +318,19 @@ radv_reconfigure(struct proto *p, struct proto_config *c) - return 1; - } - -+static void -+radv_copy_config(struct proto_config *dest, struct proto_config *src) -+{ -+ struct radv_config *d = (struct radv_config *) dest; -+ struct radv_config *s = (struct radv_config *) src; -+ -+ /* We clean up patt_list, ifaces are non-sharable */ -+ init_list(&d->patt_list); -+ -+ /* We copy pref_list, shallow copy suffices */ -+ cfg_copy_list(&d->iface_list, &s->iface_list, sizeof(struct iface_patt)); -+} -+ - - struct protocol proto_radv = { - .name = "RAdv", -@@ -325,5 +338,6 @@ struct protocol proto_radv = { - .init = radv_init, - .start = radv_start, - .shutdown = radv_shutdown, -- .reconfigure = radv_reconfigure -+ .reconfigure = radv_reconfigure, -+ .copy_config = radv_copy_config - }; -diff --git a/proto/radv/radv.h b/proto/radv/radv.h -index fe121f2..12bfe42 100644 ---- proto/radv/radv.h -+++ proto/radv/radv.h -@@ -46,14 +46,14 @@ - struct radv_config - { - struct proto_config c; -- list patt_list; /* List of iface configs */ -- list pref_list; /* Global list of prefix configs */ -+ list patt_list; /* List of iface configs (struct radv_iface_config) */ -+ list pref_list; /* Global list of prefix configs (struct radv_prefix_config) */ - }; - - struct radv_iface_config - { - struct iface_patt i; -- list pref_list; /* Local list of prefix configs */ -+ list pref_list; /* Local list of prefix configs (struct radv_prefix_config) */ - - u32 min_ra_int; /* Standard options from RFC 4261 */ - u32 max_ra_int; -@@ -64,7 +64,7 @@ struct radv_iface_config - u32 link_mtu; - u32 reachable_time; - u32 retrans_timer; -- u32 current_hop_limit; -+ u32 current_hop_limit; - u32 default_lifetime; - }; - -diff --git a/proto/rip/config.Y b/proto/rip/config.Y -index 2df0c5c..cd4f30e 100644 ---- proto/rip/config.Y -+++ proto/rip/config.Y -@@ -37,7 +37,7 @@ CF_GRAMMAR - CF_ADDTO(proto, rip_cfg '}' { RIP_CFG->passwords = get_passwords(); } ) - - rip_cfg_start: proto_start RIP { -- this_proto = proto_config_new(&proto_rip, sizeof(struct rip_proto_config)); -+ this_proto = proto_config_new(&proto_rip, sizeof(struct rip_proto_config), $1); - rip_init_config(RIP_CFG); - } - ; -diff --git a/proto/rip/rip.c b/proto/rip/rip.c -index 1266380..543aa30 100644 ---- proto/rip/rip.c -+++ proto/rip/rip.c -@@ -1015,6 +1015,19 @@ rip_reconfigure(struct proto *p, struct proto_config *c) - sizeof(struct rip_proto_config) - generic); - } - -+static void -+rip_copy_config(struct proto_config *dest, struct proto_config *src) -+{ -+ /* Shallow copy of everything */ -+ proto_copy_rest(dest, src, sizeof(struct rip_proto_config)); -+ -+ /* We clean up iface_list, ifaces are non-sharable */ -+ init_list(&((struct rip_proto_config *) dest)->iface_list); -+ -+ /* Copy of passwords is OK, it just will be replaced in dest when used */ -+} -+ -+ - struct protocol proto_rip = { - name: "RIP", - template: "rip%d", -@@ -1026,4 +1039,5 @@ struct protocol proto_rip = { - dump: rip_dump, - start: rip_start, - reconfigure: rip_reconfigure, -+ copy_config: rip_copy_config - }; -diff --git a/proto/static/config.Y b/proto/static/config.Y -index 77d2419..621fdf9 100644 ---- proto/static/config.Y -+++ proto/static/config.Y -@@ -26,7 +26,7 @@ CF_GRAMMAR - CF_ADDTO(proto, static_proto '}') - - static_proto_start: proto_start STATIC { -- this_proto = proto_config_new(&proto_static, sizeof(struct static_config)); -+ this_proto = proto_config_new(&proto_static, sizeof(struct static_config), $1); - static_init_config((struct static_config *) this_proto); - } - ; -diff --git a/proto/static/static.c b/proto/static/static.c -index 2f33d81..e5b293c 100644 ---- proto/static/static.c -+++ proto/static/static.c -@@ -470,6 +470,58 @@ static_reconfigure(struct proto *p, struct proto_config *new) - return 1; - } - -+static void -+static_copy_routes(list *dlst, list *slst) -+{ -+ struct static_route *dr, *sr; -+ -+ init_list(dlst); -+ WALK_LIST(sr, *slst) -+ { -+ /* copy one route */ -+ dr = cfg_alloc(sizeof(struct static_route)); -+ memcpy(dr, sr, sizeof(struct static_route)); -+ -+ /* This fn is supposed to be called on fresh src routes, which have 'live' -+ fields (like .chain, .neigh or .installed) zero, so no need to zero them */ -+ -+ /* We need to copy multipath chain, because there are backptrs in 'if_name' */ -+ if (dr->dest == RTD_MULTIPATH) -+ { -+ struct static_route *md, *ms, **mp_last; -+ -+ mp_last = &(dr->mp_next); -+ for (ms = sr->mp_next; ms; ms = ms->mp_next) -+ { -+ md = cfg_alloc(sizeof(struct static_route)); -+ memcpy(md, ms, sizeof(struct static_route)); -+ md->if_name = (void *) dr; /* really */ -+ -+ *mp_last = md; -+ mp_last = &(md->mp_next); -+ } -+ *mp_last = NULL; -+ } -+ -+ add_tail(dlst, (node *) dr); -+ } -+} -+ -+static void -+static_copy_config(struct proto_config *dest, struct proto_config *src) -+{ -+ struct static_config *d = (struct static_config *) dest; -+ struct static_config *s = (struct static_config *) src; -+ -+ /* Shallow copy of everything */ -+ proto_copy_rest(dest, src, sizeof(struct static_config)); -+ -+ /* Copy route lists */ -+ static_copy_routes(&d->iface_routes, &s->iface_routes); -+ static_copy_routes(&d->other_routes, &s->other_routes); -+} -+ -+ - struct protocol proto_static = { - name: "Static", - template: "static%d", -@@ -479,6 +531,7 @@ struct protocol proto_static = { - shutdown: static_shutdown, - cleanup: static_cleanup, - reconfigure: static_reconfigure, -+ copy_config: static_copy_config - }; - - static void -diff --git a/sysdep/bsd/krt-iface.h b/sysdep/bsd/krt-iface.h -index 7d96fe8..7f0d52b 100644 ---- sysdep/bsd/krt-iface.h -+++ sysdep/bsd/krt-iface.h -@@ -12,6 +12,14 @@ - /* - * 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 -index 284df5e..19cd930 100644 ---- sysdep/bsd/krt-scan.h -+++ sysdep/bsd/krt-scan.h -@@ -17,5 +17,6 @@ struct krt_scan_status { - }; - - 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-sock.h b/sysdep/bsd/krt-sock.h -index d2a7efb..aab639c 100644 ---- sysdep/bsd/krt-sock.h -+++ sysdep/bsd/krt-sock.h -@@ -34,13 +34,9 @@ struct krt_set_params { - struct krt_set_status { - }; - --struct krt_if_params { --}; -- --struct krt_if_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/linux/netlink/krt-iface.h b/sysdep/linux/netlink/krt-iface.h -index f44ca27..770c6e2 100644 ---- sysdep/linux/netlink/krt-iface.h -+++ sysdep/linux/netlink/krt-iface.h -@@ -24,5 +24,6 @@ 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 -index 7885f07..9b5e075 100644 ---- sysdep/linux/netlink/krt-scan.h -+++ sysdep/linux/netlink/krt-scan.h -@@ -30,4 +30,7 @@ static inline int krt_scan_params_same(struct krt_scan_params *o, struct krt_sca - 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 -index 83d082d..4a08217 100644 ---- sysdep/linux/netlink/krt-set.h -+++ sysdep/linux/netlink/krt-set.h -@@ -23,5 +23,6 @@ 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/unix/krt-iface.h b/sysdep/unix/krt-iface.h -index 48075d6..9e12bcc 100644 ---- sysdep/unix/krt-iface.h -+++ sysdep/unix/krt-iface.h -@@ -17,6 +17,7 @@ struct krt_if_status { - - extern int if_scan_sock; - --static inline int kif_params_same(struct krt_if_params *old, struct krt_if_params *new) { return 1; } -+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.h b/sysdep/unix/krt-set.h -index 5d0b213..87cffcf 100644 ---- sysdep/unix/krt-set.h -+++ sysdep/unix/krt-set.h -@@ -16,5 +16,6 @@ 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 0375a13..8608196 100644 ---- sysdep/unix/krt.Y -+++ sysdep/unix/krt.Y -@@ -30,7 +30,7 @@ kern_proto_start: proto_start KERNEL { - if (cf_krt) - cf_error("Kernel protocol already defined"); - #endif -- cf_krt = this_proto = proto_config_new(&proto_unix_kernel, sizeof(struct krt_config)); -+ cf_krt = this_proto = proto_config_new(&proto_unix_kernel, sizeof(struct krt_config), $1); - this_proto->preference = DEF_PREF_INHERITED; - THIS_KRT->scan_time = 60; - THIS_KRT->learn = THIS_KRT->persist = 0; -@@ -66,7 +66,7 @@ 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)); -+ cf_kif = this_proto = proto_config_new(&proto_unix_iface, sizeof(struct kif_config), $1); - this_proto->preference = DEF_PREF_DIRECT; - THIS_KIF->scan_time = 60; - init_list(&THIS_KIF->primary); -diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c -index 7057070..e5a8ce1 100644 ---- sysdep/unix/krt.c -+++ sysdep/unix/krt.c -@@ -216,6 +216,23 @@ kif_reconfigure(struct proto *p, struct proto_config *new) - return 1; - } - -+static void -+kif_copy_config(struct proto_config *dest, struct proto_config *src) -+{ -+ struct kif_config *d = (struct kif_config *) dest; -+ 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)); -+ -+ /* 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); -+} -+ -+ - struct protocol proto_unix_iface = { - name: "Device", - template: "device%d", -@@ -224,6 +241,7 @@ struct protocol proto_unix_iface = { - start: kif_start, - shutdown: kif_shutdown, - reconfigure: kif_reconfigure, -+ copy_config: kif_copy_config - }; - - /* -@@ -908,6 +926,19 @@ krt_reconfigure(struct proto *p, struct proto_config *new) - ; - } - -+static void -+krt_copy_config(struct proto_config *dest, struct proto_config *src) -+{ -+ struct krt_config *d = (struct krt_config *) dest; -+ struct krt_config *s = (struct krt_config *) src; -+ -+ /* Shallow copy of everything */ -+ 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); -+} - - static int - krt_get_attr(eattr * a, byte * buf, int buflen UNUSED) -@@ -936,6 +967,7 @@ struct protocol proto_unix_kernel = { - start: krt_start, - shutdown: krt_shutdown, - reconfigure: krt_reconfigure, -+ copy_config: krt_copy_config, - get_attr: krt_get_attr, - #ifdef KRT_ALLOW_LEARN - dump: krt_dump, -diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h -index f83e6ee..7bb4fe7 100644 ---- sysdep/unix/krt.h -+++ sysdep/unix/krt.h -@@ -100,7 +100,7 @@ struct kif_config { - struct proto_config c; - struct krt_if_params iface; - int scan_time; /* How often we re-scan interfaces */ -- list primary; /* Preferences for primary addresses */ -+ list primary; /* Preferences for primary addresses (struct kif_primary_item) */ - }; - - struct kif_proto { |