]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
KRT: Fixes some minor bugs in kernel protocol
authorOndrej Zajicek <santiago@crfreenet.org>
Wed, 3 Jun 2015 09:58:46 +0000 (11:58 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Mon, 8 Jun 2015 00:24:08 +0000 (02:24 +0200)
sysdep/linux/netlink.c
sysdep/unix/krt.c

index c4d52255ca837586ddbaf66772a9afad891715f9..9f206e1cab863f675e4112dbf4673962c9b826a7 100644 (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);
 
index cfb623ce443f87918a3d798f59596627c1a9b7ac..d8d28c7c32bdb8d9b939722ca3e210d1ac7426fa 100644 (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;
   }