summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2015-04-25 20:43:43 +0200
committerOndrej Zajicek <santiago@crfreenet.org>2015-04-25 20:43:43 +0200
commitc5ff44a703e4ab810a5bd45cf9140643a50fb3ec (patch)
tree9da170899ebd1d1afea30a358c031bc704c47d0d
parent90097f4fb924922b416247abf291fb21f39dc8e1 (diff)
KRT: Fixes learning of preferred kernel routes.
When a new route was imported from kernel and chosen as preferred, then the old best route was propagated as a withdraw to the kernel protocol. Under some circumstances such withdraw propagated to the BSD kernel could remove the new alien route and thus reverting the import.
-rw-r--r--sysdep/cf/README1
-rw-r--r--sysdep/cf/bsd-v6.h1
-rw-r--r--sysdep/cf/bsd.h1
-rw-r--r--sysdep/unix/krt.c14
4 files changed, 17 insertions, 0 deletions
diff --git a/sysdep/cf/README b/sysdep/cf/README
index 768a3727..e62c3481 100644
--- a/sysdep/cf/README
+++ b/sysdep/cf/README
@@ -5,6 +5,7 @@ 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_SINGLE_ROUTE There is only one route per network
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)
diff --git a/sysdep/cf/bsd-v6.h b/sysdep/cf/bsd-v6.h
index 47a7c7ff..745dfba3 100644
--- a/sysdep/cf/bsd-v6.h
+++ b/sysdep/cf/bsd-v6.h
@@ -11,6 +11,7 @@
#define CONFIG_AUTO_ROUTES
#define CONFIG_SELF_CONSCIOUS
#define CONFIG_MULTIPLE_TABLES
+#define CONFIG_SINGLE_ROUTE
#define CONFIG_SKIP_MC_BIND
#define CONFIG_NO_IFACE_BIND
diff --git a/sysdep/cf/bsd.h b/sysdep/cf/bsd.h
index df199199..51beb42b 100644
--- a/sysdep/cf/bsd.h
+++ b/sysdep/cf/bsd.h
@@ -9,6 +9,7 @@
#define CONFIG_AUTO_ROUTES
#define CONFIG_SELF_CONSCIOUS
#define CONFIG_MULTIPLE_TABLES
+#define CONFIG_SINGLE_ROUTE
#define CONFIG_SKIP_MC_BIND
#define CONFIG_NO_IFACE_BIND
diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c
index 0a223a4f..7cec28c8 100644
--- a/sysdep/unix/krt.c
+++ b/sysdep/unix/krt.c
@@ -961,7 +961,21 @@ krt_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *
rte *e = *new;
if (e->attrs->src->proto == P)
+ {
+#ifdef CONFIG_SINGLE_ROUTE
+ /*
+ * Implicit withdraw - when the imported kernel route becomes the best one,
+ * we know that the previous one exported to the kernel was already removed,
+ * but if we processed the update as usual, we would send withdraw to the
+ * kernel, which would remove the new imported route instead.
+ *
+ * We will remove KRT_INSTALLED flag, which stops such withdraw to be
+ * processed in krt_rt_notify() and krt_replace_rte().
+ */
+ e->net->n.flags &= ~KRF_INSTALLED;
+#endif
return -1;
+ }
if (!KRT_CF->devroutes &&
(e->attrs->dest == RTD_DEVICE) &&