Commit 78a2cc28 authored by Ondrej Zajicek's avatar Ondrej Zajicek
Browse files

KRT: Fixes some minor bugs in kernel protocol

parent d217ba51
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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);

+66 −41
Original line number Diff line number Diff line
@@ -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
	    {
	      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,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;