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;
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))
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;
}
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
krt_same_dest(rte *k, rte *e)
{
@ -620,7 +658,6 @@ krt_same_dest(rte *k, rte *e)
void
krt_got_route(struct krt_proto *p, rte *e)
{
rte *old;
net *net = e->net;
int verdict;
@ -663,15 +700,26 @@ krt_got_route(struct krt_proto *p, rte *e)
goto sentenced;
}
old = net->routes;
if ((net->n.flags & KRF_INSTALLED) && rte_is_valid(old))
if (net->n.flags & KRF_INSTALLED)
{
/* There may be changes in route attributes, we ignore that.
Also, this does not work well if gw is changed in export filter */
if ((net->n.flags & KRF_SYNC_ERROR) || ! krt_same_dest(e, old))
rte *new, *rt_free;
ea_list *tmpa;
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;
else
verdict = KRF_SEEN;
if (rt_free)
rte_free(rt_free);
lp_flush(krt_filter_lp);
}
else
verdict = KRF_DELETE;
@ -692,25 +740,6 @@ krt_got_route(struct krt_proto *p, rte *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
krt_prune(struct krt_proto *p)
{
@ -721,7 +750,7 @@ krt_prune(struct krt_proto *p)
{
net *n = (net *) f;
int verdict = f->flags & KRF_VERDICT_MASK;
rte *new, *new0, *old;
rte *new, *old, *rt_free = NULL;
ea_list *tmpa = NULL;
if (verdict == KRF_UPDATE || verdict == KRF_DELETE)
@ -733,23 +762,18 @@ krt_prune(struct krt_proto *p)
else
old = NULL;
new = new0 = n->routes;
if (verdict == KRF_CREATE || verdict == KRF_UPDATE)
{
/* We have to run export filter to get proper 'new' route */
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;
}
new = krt_export_net(p, n, &rt_free, &tmpa);
if (!new)
verdict = (verdict == KRF_CREATE) ? KRF_IGNORE : KRF_DELETE;
else
{
ea_list **x = &tmpa;
while (*x)
x = &((*x)->next);
*x = new ? new->attrs->eattrs : NULL;
}
tmpa = ea_append(tmpa, new->attrs->eattrs);
}
else
new = NULL;
switch (verdict)
{
@ -778,8 +802,8 @@ krt_prune(struct krt_proto *p)
if (old)
rte_free(old);
if (new != new0)
rte_free(new);
if (rt_free)
rte_free(rt_free);
lp_flush(krt_filter_lp);
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
* 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
return -1;
}