KRT: Fixes some minor bugs in kernel protocol

This commit is contained in:
Ondrej Zajicek 2015-06-03 11:58:46 +02:00
parent d217ba5111
commit 78a2cc289f
2 changed files with 71 additions and 41 deletions

View file

@ -703,6 +703,11 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int new)
r.r.rtm_scope = RT_SCOPE_UNIVERSE; r.r.rtm_scope = RT_SCOPE_UNIVERSE;
nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net->n.prefix); nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net->n.prefix);
/* For route delete, we do not specify route attributes */
if (!new)
return nl_exchange(&r.h);
if (ea = ea_find(eattrs, EA_KRT_METRIC)) if (ea = ea_find(eattrs, EA_KRT_METRIC))
nl_add_attr_u32(&r.h, sizeof(r), RTA_PRIORITY, ea->u.data); nl_add_attr_u32(&r.h, sizeof(r), RTA_PRIORITY, ea->u.data);

View file

@ -592,6 +592,44 @@ krt_flush_routes(struct krt_proto *p)
FIB_WALK_END; FIB_WALK_END;
} }
static struct rte *
krt_export_net(struct krt_proto *p, net *net, rte **rt_free, ea_list **tmpa)
{
struct filter *filter = p->p.main_ahook->out_filter;
rte *rt;
rt = net->routes;
*rt_free = NULL;
if (!rte_is_valid(rt))
return NULL;
if (filter == FILTER_REJECT)
return NULL;
struct proto *src = rt->attrs->src->proto;
*tmpa = src->make_tmp_attrs ? src->make_tmp_attrs(rt, krt_filter_lp) : NULL;
/* We could run krt_import_control() here, but it is already handled by KRF_INSTALLED */
if (filter == FILTER_ACCEPT)
goto accept;
if (f_run(filter, &rt, tmpa, krt_filter_lp, FF_FORCE_TMPATTR) > F_ACCEPT)
goto reject;
accept:
if (rt != net->routes)
*rt_free = rt;
return rt;
reject:
if (rt != net->routes)
rte_free(rt);
return NULL;
}
static int static int
krt_same_dest(rte *k, rte *e) krt_same_dest(rte *k, rte *e)
{ {
@ -620,7 +658,6 @@ krt_same_dest(rte *k, rte *e)
void void
krt_got_route(struct krt_proto *p, rte *e) krt_got_route(struct krt_proto *p, rte *e)
{ {
rte *old;
net *net = e->net; net *net = e->net;
int verdict; int verdict;
@ -663,15 +700,26 @@ krt_got_route(struct krt_proto *p, rte *e)
goto sentenced; goto sentenced;
} }
old = net->routes; if (net->n.flags & KRF_INSTALLED)
if ((net->n.flags & KRF_INSTALLED) && rte_is_valid(old))
{ {
/* There may be changes in route attributes, we ignore that. rte *new, *rt_free;
Also, this does not work well if gw is changed in export filter */ ea_list *tmpa;
if ((net->n.flags & KRF_SYNC_ERROR) || ! krt_same_dest(e, old))
new = krt_export_net(p, net, &rt_free, &tmpa);
/* TODO: There also may be changes in route eattrs, we ignore that for now. */
if (!new)
verdict = KRF_DELETE;
else if ((net->n.flags & KRF_SYNC_ERROR) || !krt_same_dest(e, new))
verdict = KRF_UPDATE; verdict = KRF_UPDATE;
else else
verdict = KRF_SEEN; verdict = KRF_SEEN;
if (rt_free)
rte_free(rt_free);
lp_flush(krt_filter_lp);
} }
else else
verdict = KRF_DELETE; verdict = KRF_DELETE;
@ -692,25 +740,6 @@ krt_got_route(struct krt_proto *p, rte *e)
rte_free(e); rte_free(e);
} }
static inline int
krt_export_rte(struct krt_proto *p, rte **new, ea_list **tmpa)
{
struct filter *filter = p->p.main_ahook->out_filter;
if (! *new)
return 0;
if (filter == FILTER_REJECT)
return 0;
if (filter == FILTER_ACCEPT)
return 1;
struct proto *src = (*new)->attrs->src->proto;
*tmpa = src->make_tmp_attrs ? src->make_tmp_attrs(*new, krt_filter_lp) : NULL;
return f_run(filter, new, tmpa, krt_filter_lp, FF_FORCE_TMPATTR) <= F_ACCEPT;
}
static void static void
krt_prune(struct krt_proto *p) krt_prune(struct krt_proto *p)
{ {
@ -721,7 +750,7 @@ krt_prune(struct krt_proto *p)
{ {
net *n = (net *) f; net *n = (net *) f;
int verdict = f->flags & KRF_VERDICT_MASK; int verdict = f->flags & KRF_VERDICT_MASK;
rte *new, *new0, *old; rte *new, *old, *rt_free = NULL;
ea_list *tmpa = NULL; ea_list *tmpa = NULL;
if (verdict == KRF_UPDATE || verdict == KRF_DELETE) if (verdict == KRF_UPDATE || verdict == KRF_DELETE)
@ -733,23 +762,18 @@ krt_prune(struct krt_proto *p)
else else
old = NULL; old = NULL;
new = new0 = n->routes;
if (verdict == KRF_CREATE || verdict == KRF_UPDATE) if (verdict == KRF_CREATE || verdict == KRF_UPDATE)
{ {
/* We have to run export filter to get proper 'new' route */ /* We have to run export filter to get proper 'new' route */
if (! krt_export_rte(p, &new, &tmpa)) new = krt_export_net(p, n, &rt_free, &tmpa);
{
/* Route rejected, should not happen (KRF_INSTALLED) but to be sure .. */ if (!new)
verdict = (verdict == KRF_CREATE) ? KRF_IGNORE : KRF_DELETE; verdict = (verdict == KRF_CREATE) ? KRF_IGNORE : KRF_DELETE;
}
else else
{ tmpa = ea_append(tmpa, new->attrs->eattrs);
ea_list **x = &tmpa;
while (*x)
x = &((*x)->next);
*x = new ? new->attrs->eattrs : NULL;
}
} }
else
new = NULL;
switch (verdict) switch (verdict)
{ {
@ -778,8 +802,8 @@ krt_prune(struct krt_proto *p)
if (old) if (old)
rte_free(old); rte_free(old);
if (new != new0) if (rt_free)
rte_free(new); rte_free(rt_free);
lp_flush(krt_filter_lp); lp_flush(krt_filter_lp);
f->flags &= ~KRF_VERDICT_MASK; f->flags &= ~KRF_VERDICT_MASK;
} }
@ -974,7 +998,8 @@ krt_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *
* We will remove KRT_INSTALLED flag, which stops such withdraw to be * We will remove KRT_INSTALLED flag, which stops such withdraw to be
* processed in krt_rt_notify() and krt_replace_rte(). * processed in krt_rt_notify() and krt_replace_rte().
*/ */
e->net->n.flags &= ~KRF_INSTALLED; if (e == e->net->routes)
e->net->n.flags &= ~KRF_INSTALLED;
#endif #endif
return -1; return -1;
} }