Commit 252c7e4d authored by Ondřej Zajíček's avatar Ondřej Zajíček

Refresh kernel protocol when interface disappears.

When an interface goes down, (Linux) kernel removes routes pointing to
that ifacem but does not send withdraws for them. We rescan the
kernel table to ensure synchronization.

Thanks to Alexander Demenshin for the bugreport.
parent b2f00837
......@@ -36,7 +36,7 @@
* 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_*
* 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.
*
......@@ -117,7 +117,7 @@ kif_request_scan(void)
static inline int
prefer_addr(struct ifa *a, struct ifa *b)
{
{
int sa = a->scope > SCOPE_LINK;
int sb = b->scope > SCOPE_LINK;
......@@ -737,7 +737,7 @@ krt_prune(struct krt_proto *p)
if (! krt_export_rte(p, &new, &tmpa))
{
/* Route rejected, should not happen (KRF_INSTALLED) but to be sure .. */
verdict = (verdict == KRF_CREATE) ? KRF_IGNORE : KRF_DELETE;
verdict = (verdict == KRF_CREATE) ? KRF_IGNORE : KRF_DELETE;
}
else
{
......@@ -910,7 +910,7 @@ krt_scan_timer_stop(struct krt_proto *p)
}
static void
krt_scan_timer_kick(struct krt_proto *p UNUSED)
krt_scan_timer_kick(struct krt_proto *p)
{
tm_start(p->scan_timer, 0);
}
......@@ -962,8 +962,8 @@ krt_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *
if (e->attrs->src->proto == P)
return -1;
if (!KRT_CF->devroutes &&
(e->attrs->dest == RTD_DEVICE) &&
if (!KRT_CF->devroutes &&
(e->attrs->dest == RTD_DEVICE) &&
(e->attrs->source != RTS_STATIC_DEVICE))
return -1;
......@@ -974,8 +974,8 @@ krt_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *
}
static void
krt_notify(struct proto *P, struct rtable *table UNUSED, net *net,
rte *new, rte *old, struct ea_list *eattrs)
krt_rt_notify(struct proto *P, struct rtable *table UNUSED, net *net,
rte *new, rte *old, struct ea_list *eattrs)
{
struct krt_proto *p = (struct krt_proto *) P;
......@@ -991,6 +991,36 @@ krt_notify(struct proto *P, struct rtable *table UNUSED, net *net,
krt_replace_rte(p, net, new, old, eattrs);
}
static void
krt_if_notify(struct proto *P, uint flags, struct iface *iface UNUSED)
{
struct krt_proto *p = (struct krt_proto *) P;
/*
* When interface went down, we should remove routes to it. In the ideal world,
* OS kernel would send us route removal notifications in such cases, but we
* cannot rely on it as it is often not true. E.g. Linux kernel removes related
* routes when an interface went down, but it does not notify userspace about
* that. To be sure, we just schedule a scan to ensure synchronization.
*/
if ((flags & IF_CHANGE_DOWN) && KRT_CF->learn)
krt_scan_timer_kick(p);
}
static int
krt_reload_routes(struct proto *P)
{
struct krt_proto *p = (struct krt_proto *) P;
/* Although we keep learned routes in krt_table, we rather schedule a scan */
if (KRT_CF->learn)
krt_scan_timer_kick(p);
return 1;
}
static void
krt_feed_done(struct proto *P)
{
......@@ -1022,7 +1052,9 @@ krt_init(struct proto_config *c)
p->p.accept_ra_types = RA_OPTIMAL;
p->p.import_control = krt_import_control;
p->p.rt_notify = krt_notify;
p->p.rt_notify = krt_rt_notify;
p->p.if_notify = krt_if_notify;
p->p.reload_routes = krt_reload_routes;
p->p.feed_done = krt_feed_done;
p->p.make_tmp_attrs = krt_make_tmp_attrs;
p->p.store_tmp_attrs = krt_store_tmp_attrs;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment