And just an idea. I've attached the patch as an example, although it
should be functional too. I mentioned that functions krt_learn_async()
and krt_learn_scan() are very similar and I thought that it may be
useful to join them into a single function. If I did not make a
mistake, all code pathes should be almost the same, with a couple of
minor exceptions:
1) old_best is set in the beginning, but was earlier only for async version
2) g = NULL after rte_free(g) in one of the branches, but it does not
affect anything and may be dropped

On Wed, Sep 21, 2022 at 6:00 PM Maria Matejka via Bird-users
<bird-users@network.cz> wrote:
>
> Hello!
>
> Thank you for finding and fixing. Will check and include.
>
> Maria
>
> On 9/21/22 17:15, Alexander Zubkov via Bird-users wrote:
> > I made a trivial patch for the case.
> >
> > On Tue, Sep 20, 2022 at 6:23 PM Alexander Zubkov <gr...@qrator.net> wrote:
> >>
> >> Hi,
> >>
> >> Bird from master branch ignores the default preference set in channel
> >> for a kernel protocol, like that:
> >>
> >> protocol kernel {
> >>          learn yes;
> >>          ipv4 {
> >>                  preference 200;
> >>                  import all;
> >>                  export none;
> >>          };
> >> }
> >>
> >> Version 2.0.10 seems ok. I suppose the change was introduced with this 
> >> commit:
> >>
> >> https://gitlab.nic.cz/labs/bird/-/commit/eb937358c087eaeb6f209660cc7ecfe6d6eff739
> >>
> >> It adds setting of the preference to the krt_learn_async() function.
> >> But as I understand when route is learned with netlink hook it is
> >> processed like this:
> >> nl_parse_route -> krt_got_route_async -> krt_learn_async
> >> But when it is learned from scan, it is processed like this:
> >> nl_parse_route -> krt_got_route -> krt_learn_scan
> >>
> >> And setting preference was not added to krt_learn_scan() function.
> >>
> >> I also saw that in my test - when I added a new route to the kernel
> >> while bird was running, it appeared in bird with correct preference.
> >> But some time after, the scan updated the route and it was replaced
> >> with the default preference.
diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c
index c4a3a4a8..e61efdfe 100644
--- a/sysdep/unix/krt.c
+++ b/sysdep/unix/krt.c
@@ -318,45 +318,6 @@ krt_learn_announce_delete(struct krt_proto *p, net *n)
   rte_update(&p->p, n->n.addr, NULL);
 }
 
-/* Called when alien route is discovered during scan */
-static void
-krt_learn_scan(struct krt_proto *p, rte *e)
-{
-  net *n0 = e->net;
-  net *n = net_get(p->krt_table, n0->n.addr);
-  rte *m, **mm;
-
-  e->attrs = rta_lookup(e->attrs);
-
-  for(mm=&n->routes; m = *mm; mm=&m->next)
-    if (krt_same_key(m, e))
-      break;
-  if (m)
-    {
-      if (krt_uptodate(m, e))
-	{
-	  krt_trace_in_rl(&rl_alien, p, e, "[alien] seen");
-	  rte_free(e);
-	  m->pflags |= KRT_REF_SEEN;
-	}
-      else
-	{
-	  krt_trace_in(p, e, "[alien] updated");
-	  *mm = m->next;
-	  rte_free(m);
-	  m = NULL;
-	}
-    }
-  else
-    krt_trace_in(p, e, "[alien] created");
-  if (!m)
-    {
-      e->next = n->routes;
-      n->routes = e;
-      e->pflags |= KRT_REF_SEEN;
-    }
-}
-
 static void
 krt_learn_prune(struct krt_proto *p)
 {
@@ -373,7 +334,7 @@ again:
 
       /*
        * Note that old_best may be NULL even if there was an old best route in
-       * the previous step, because it might be replaced in krt_learn_scan().
+       * the previous step, because it might be replaced in krt_learn_route().
        * But in that case there is a new valid best route.
        */
 
@@ -431,13 +392,17 @@ again:
   p->reload = 0;
 }
 
+/* sync = 0 : Called when alien route is discovered during scan */
 static void
-krt_learn_async(struct krt_proto *p, rte *e, int new)
+krt_learn_route(struct krt_proto *p, rte *e, int async, int new)
 {
   net *n0 = e->net;
   net *n = net_get(p->krt_table, n0->n.addr);
   rte *g, **gg, *best, **bestp, *old_best;
 
+  if (async)
+    new = 1;
+
   ASSERT(!e->attrs->cached);
   e->attrs->pref = p->p.main_channel->preference;
 
@@ -453,19 +418,35 @@ krt_learn_async(struct krt_proto *p, rte *e, int new)
 	{
 	  if (krt_uptodate(g, e))
 	    {
-	      krt_trace_in(p, e, "[alien async] same");
+	      if (async)
+		krt_trace_in(p, e, "[alien async] same");
+	      else
+		krt_trace_in_rl(&rl_alien, p, e, "[alien] seen");
 	      rte_free(e);
+	      if (!async)
+		g->pflags |= KRT_REF_SEEN;
 	      return;
 	    }
-	  krt_trace_in(p, e, "[alien async] updated");
+	  if (async)
+	    krt_trace_in(p, e, "[alien async] updated");
+	  else
+	    krt_trace_in(p, e, "[alien] updated");
 	  *gg = g->next;
 	  rte_free(g);
+	  g = NULL;
 	}
       else
-	krt_trace_in(p, e, "[alien async] created");
+	{
+	  if (async)
+	    krt_trace_in(p, e, "[alien async] created");
+	  else
+	    krt_trace_in(p, e, "[alien] created");
+	}
 
       e->next = n->routes;
       n->routes = e;
+      if (!async)
+	e->pflags |= KRT_REF_SEEN;
     }
   else if (!g)
     {
@@ -480,6 +461,10 @@ krt_learn_async(struct krt_proto *p, rte *e, int new)
       rte_free(e);
       rte_free(g);
     }
+
+  if (!async)
+    return;
+
   best = n->routes;
   bestp = &n->routes;
   for(gg=&n->routes; g=*gg; gg=&g->next)
@@ -503,7 +488,7 @@ krt_learn_async(struct krt_proto *p, rte *e, int new)
 
   if (best != old_best)
     {
-      DBG("krt_learn_async: distributing change\n");
+      DBG("krt_learn_route: distributing change\n");
       if (best)
 	krt_learn_announce_update(p, best);
       else
@@ -641,7 +626,7 @@ krt_got_route(struct krt_proto *p, rte *e, s8 src)
 
     case  KRT_SRC_ALIEN:
       if (KRT_CF->learn)
-	krt_learn_scan(p, e);
+	krt_learn_route(p, e, 0, 1);
       else
 	{
 	  krt_trace_in_rl(&rl_alien, p, e, "[alien] ignored");
@@ -777,7 +762,7 @@ krt_got_route_async(struct krt_proto *p, rte *e, int new, s8 src)
     case KRT_SRC_ALIEN:
       if (KRT_CF->learn)
 	{
-	  krt_learn_async(p, e, new);
+	  krt_learn_route(p, e, 1, new);
 	  return;
 	}
 #endif

Reply via email to