KRT: Fixes some minor bugs in kernel protocol
This commit is contained in:
parent
d217ba5111
commit
78a2cc289f
2 changed files with 71 additions and 41 deletions
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 .. */
|
||||
new = krt_export_net(p, n, &rt_free, &tmpa);
|
||||
|
||||
if (!new)
|
||||
verdict = (verdict == KRF_CREATE) ? KRF_IGNORE : KRF_DELETE;
|
||||
else
|
||||
tmpa = ea_append(tmpa, new->attrs->eattrs);
|
||||
}
|
||||
else
|
||||
{
|
||||
ea_list **x = &tmpa;
|
||||
while (*x)
|
||||
x = &((*x)->next);
|
||||
*x = new ? new->attrs->eattrs : NULL;
|
||||
}
|
||||
}
|
||||
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,6 +998,7 @@ 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().
|
||||
*/
|
||||
if (e == e->net->routes)
|
||||
e->net->n.flags &= ~KRF_INSTALLED;
|
||||
#endif
|
||||
return -1;
|
||||
|
|
Loading…
Reference in a new issue