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.
This commit is contained in:
parent
b2f008378a
commit
252c7e4d0b
1 changed files with 41 additions and 9 deletions
|
@ -910,7 +910,7 @@ krt_scan_timer_stop(struct krt_proto *p)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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);
|
tm_start(p->scan_timer, 0);
|
||||||
}
|
}
|
||||||
|
@ -974,7 +974,7 @@ krt_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
krt_notify(struct proto *P, struct rtable *table UNUSED, net *net,
|
krt_rt_notify(struct proto *P, struct rtable *table UNUSED, net *net,
|
||||||
rte *new, rte *old, struct ea_list *eattrs)
|
rte *new, rte *old, struct ea_list *eattrs)
|
||||||
{
|
{
|
||||||
struct krt_proto *p = (struct krt_proto *) P;
|
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);
|
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
|
static void
|
||||||
krt_feed_done(struct proto *P)
|
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.accept_ra_types = RA_OPTIMAL;
|
||||||
p->p.import_control = krt_import_control;
|
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.feed_done = krt_feed_done;
|
||||||
p->p.make_tmp_attrs = krt_make_tmp_attrs;
|
p->p.make_tmp_attrs = krt_make_tmp_attrs;
|
||||||
p->p.store_tmp_attrs = krt_store_tmp_attrs;
|
p->p.store_tmp_attrs = krt_store_tmp_attrs;
|
||||||
|
|
Loading…
Reference in a new issue