From c5ff44a703e4ab810a5bd45cf9140643a50fb3ec Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sat, 25 Apr 2015 20:43:43 +0200 Subject: [PATCH] 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. --- sysdep/cf/README | 1 + sysdep/cf/bsd-v6.h | 1 + sysdep/cf/bsd.h | 1 + sysdep/unix/krt.c | 14 ++++++++++++++ 4 files changed, 17 insertions(+) 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) &&