[PATCH v6] Babel: Replace internal route selection by bird's nest

Daniel Gröber dxld at darkboxed.org
Tue Jan 6 12:23:33 CET 2026


Hi Lars,

Thanks for picking this up!

On Tue, Jan 06, 2026 at 04:43:41AM +0100, Lars Gierth via Bird-users wrote:
> Hi all,
> 
> happy new year and thanks for the fresh releases!
> 
> We have been successfully running the Babel route selection patch [1] with
> Bird 2.17 in our community mesh network with ~200 Babel nodes since Q3/2024.
> It has allowed us to really fine-tune a mix of all kinds of wire types
> connecting the locations: wifi at 60 / 5 / 2 GHz, tunnels over LTE or DSL,
> fiber in a datacenter, etc. etc. With Babel being a critical part of our
> network, the patch is running on a broad range of architectures: mips,
> ppc64, x86_64, and various arm and aarch64 types.
> 
> With dxld's consent I took his patch and rebased it on Bird 3.1, and we've
> been testing that for 2 months on the live network. Today I rebased it on
> 3.2 (thread-next branch), it applied cleanly but I haven't tested it yet.
> Nevertheless I decided to share it now, see attachment.
> 
> Kind regards,
> Lars
> Freifunk Berlin
> 
> [1] https://bird.network.cz/pipermail/bird-users/2023-February/016705.html

> From d2ee215ea7927fe5677990781bffe682b7e53719 Mon Sep 17 00:00:00 2001
> From: Packet Please <pktpls at systemli.org>
> Date: Sat, 8 Nov 2025 18:57:18 +0100
> Subject: [PATCH] Babel: Replace internal route selection by bird's nest
> MIME-Version: 1.0
> Content-Type: text/plain; charset=UTF-8
> Content-Transfer-Encoding: 8bit
> 
> This introduces the ability to filter routes from specific interfaces and
> neighbours. With the current internal route selection proto babel exports
> only up to one route and an admin cannot do fine-grained filtering.
> 
> To fix this we rip out the internal route selection entirely and export
> evey babel route as a distinct route into the bird's nest instead.
> 
> In the presence of esoteric route filters this change may be observable by
> users however we feel the additional filtering power is more important. A
> release note entry for this change is recommended.
> 
> Signed-off-by: Daniel GrM-CM-6ber <dxld at darkboxed.org>

Also add a Co-authored-by/Co-developed-by please. Also Is the encoding
broken?

https://www.kernel.org/doc/html/latest/process/submitting-patches.html#when-to-use-acked-by-cc-and-co-developed-by

> Signed-off-by: Lars Gierth <larsg at systemli.org>
> ---
>  proto/babel/babel.c | 306 ++++++++++++++++++++++----------------------
>  proto/babel/babel.h |   3 +
>  2 files changed, 154 insertions(+), 155 deletions(-)
> 
> diff --git a/proto/babel/babel.c b/proto/babel/babel.c
> index c7d47c01f..5f3e94fe1 100644

The patch doesn't apply. On thread-next (0b91feeda):

    $ git am < babel.patch
    Applying: Babel: Replace internal route selection by bird's nest
    error: patch failed: proto/babel/babel.c:251
    error: proto/babel/babel.c: patch does not apply
    error: patch failed: proto/babel/babel.h:25
    error: proto/babel/babel.h: patch does not apply
    Patch failed at 0001 Babel: Replace internal route selection by bird's nest
    hint: Use 'git am --show-current-patch=diff' to see the failed patch
    hint: When you have resolved this problem, run "git am --continue".
    hint: If you prefer to skip this patch, run "git am --skip" instead.
    hint: To restore the original branch and stop patching, run "git am --abort".
    hint: Disable this message with "git config advice.mergeConflict false"

Could you use git-send-email(1) please :>

  https://git-send-email.io

> --- a/proto/babel/babel.c
> +++ b/proto/babel/babel.c
> @@ -28,10 +28,12 @@
>   * possible routes for the prefix are tracked as &babel_route entries and the
>   * feasibility distance is maintained through &babel_source structures.
>   *
> - * The main route selection is done in babel_select_route(). This is called when
> - * an entry is updated by receiving updates from the network or when modified by
> - * internal timers. The function selects from feasible and reachable routes the
> - * one with the lowest metric to be announced to the core.
> + * The main route selection is done by bird's nest (heh). For each prefix we
> + * export all feasible routes to the core with a distinct source (rte_src) per
> + * neihbour so bird handles them as distinct routes. Nest will then notify us of
> + * one best route for each prefix, either our own (internal) or from another
> + * protocol, by calling babel_rt_notify. For internal best routes we remember
> + * which babel_route it selected in babel_entry.selected.
>   *
>   * Supported standards:
>   * RFC 8966 - The Babel Routing Protocol
> @@ -60,8 +62,8 @@ static inline int gt_mod64k(uint a, uint b)
>  { return ge_mod64k(a, b) && a != b; }
>  
>  static void babel_expire_requests(struct babel_proto *p, struct babel_entry *e);
> -static void babel_select_route(struct babel_proto *p, struct babel_entry *e, struct babel_route *mod);
> -static inline void babel_announce_retraction(struct babel_proto *p, struct babel_entry *e);
> +static void babel_announce_rte(struct babel_proto *p, struct babel_entry *e, struct babel_route *r);
> +static void babel_rte_update_unreachable(struct babel_proto *p, struct babel_entry *e, u8 announce);
>  static void babel_send_route_request(struct babel_proto *p, struct babel_entry *e, struct babel_neighbor *n);
>  static void babel_send_seqno_request(struct babel_proto *p, struct babel_entry *e, struct babel_seqno_request *sr, struct babel_neighbor *n);
>  static void babel_update_cost(struct babel_neighbor *n);
> @@ -181,9 +183,7 @@ static inline void
>  babel_retract_route(struct babel_proto *p, struct babel_route *r)
>  {
>    r->metric = r->advert_metric = BABEL_INFINITY;
> -
> -  if (r == r->e->selected)
> -    babel_select_route(p, r->e, r);
> +  babel_announce_rte(p, r->e, r);
>  }
>  
>  static void
> @@ -195,9 +195,6 @@ babel_flush_route(struct babel_proto *p UNUSED, struct babel_route *r)
>    rem_node(NODE r);
>    rem_node(&r->neigh_route);
>  
> -  if (r->e->selected == r)
> -    r->e->selected = NULL;
> -
>    sl_free(r);
>  }
>  
> @@ -213,6 +210,7 @@ babel_expire_route(struct babel_proto *p, struct babel_route *r)
>    {
>      r->metric = r->advert_metric = BABEL_INFINITY;
>      r->expires = current_time() + cf->hold_time;
> +    babel_announce_rte(p, r->e, r);
>    }
>    else
>    {
> @@ -242,8 +240,6 @@ babel_expire_routes_(struct babel_proto *p, struct fib *rtable)
>  loop:
>    FIB_ITERATE_START(rtable, &fit, struct babel_entry, e)
>    {
> -    int changed = 0;
> -
>      WALK_LIST_DELSAFE(r, rx, e->routes)
>      {
>        if (r->refresh_time && r->refresh_time <= now_)
> @@ -251,23 +247,12 @@ babel_expire_routes_(struct babel_proto *p, struct fib *rtable)
>  
>        if (r->expires && r->expires <= now_)
>        {
> -  changed = changed || (r == e->selected);
> +  FIB_ITERATE_PUT(&fit);
>    babel_expire_route(p, r);
> +  goto loop;
>        }
>      }
>  
> -    if (changed)
> -    {
> -      /*
> -       * We have to restart the iteration because there may be a cascade of
> -       * synchronous events babel_select_route() -> nest table change ->
> -       * babel_rt_notify() -> rtable change, invalidating hidden variables.
> -       */
> -      FIB_ITERATE_PUT(&fit);
> -      babel_select_route(p, e, NULL);
> -      goto loop;
> -    }
> -
>      /* Clean up stale entries */
>      if ((e->valid == BABEL_ENTRY_STALE) && ((e->updated + cf->hold_time) <= now_))
>        e->valid = BABEL_ENTRY_DUMMY;
> @@ -276,7 +261,7 @@ babel_expire_routes_(struct babel_proto *p, struct fib *rtable)
>      if (e->unreachable && (!e->valid || (e->router_id == p->router_id)))
>      {
>        FIB_ITERATE_PUT(&fit);
> -      babel_announce_retraction(p, e);
> +      babel_rte_update_unreachable(p, e, 0);
>        goto loop;
>      }
>  
> @@ -461,6 +446,8 @@ babel_get_neighbor(struct babel_iface *ifa, ip_addr addr)
>  
>    nbr = mb_allocz(ifa->pool, sizeof(struct babel_neighbor));
>    nbr->ifa = ifa;
> +  nbr->src = rt_get_source(&p->p, idm_alloc(&p->src_ids));
> +  rt_lock_source(nbr->src);
>    nbr->addr = addr;
>    nbr->rxcost = BABEL_INFINITY;
>    nbr->txcost = BABEL_INFINITY;
> @@ -488,6 +475,9 @@ babel_flush_neighbor(struct babel_proto *p, struct babel_neighbor *nbr)
>    }
>  
>    nbr->ifa = NULL;
> +
> +  rt_unlock_source(nbr->src);
> +  idm_free(&p->src_ids, nbr->src->private_id);
>    rem_node(NODE nbr);
>    mb_free(nbr);
>  }
> @@ -667,11 +657,60 @@ babel_update_cost(struct babel_neighbor *nbr)
>      WALK_LIST2(r, n, nbr->routes, neigh_route)
>      {
>        r->metric = babel_compute_metric(nbr, r->advert_metric);
> -      babel_select_route(p, r->e, r);
> +      babel_announce_rte(p, r->e, r);
>      }
>    }
>  }
>  
> +/**
> + * This function handles announcing the special unreachable route we insert for
> + * a prefix whenever we have no more feasible routes available as per RFC8966
> + * section 3.5.4 as well as retracting it when such routes are available
> + * again.
> + *
> + * We also remember if we inserted an unreachable route in e->unreachable in
> + * order to clean it up later in babel_expire_routes_.
> + */
> +static void
> +babel_rte_update_unreachable(struct babel_proto *p, struct babel_entry *e, u8 announce)
> +{
> +  struct channel *c = (e->n.addr->type == NET_IP4) ? p->ip4_channel : p->ip6_channel;
> +
> +  if (announce) {
> +    struct nexthop_adata nhad = NEXTHOP_DEST_LITERAL(RTD_UNREACHABLE);
> +    struct {
> +      ea_list l;
> +      eattr a[4];
> +    } eattrs = {
> +      .l.count = ARRAY_SIZE(eattrs.a),
> +      .a = {
> +  EA_LITERAL_EMBEDDED(&ea_gen_preference, 0, 1),
> +  EA_LITERAL_EMBEDDED(&ea_gen_source, 0, RTS_BABEL),
> +  EA_LITERAL_STORE_ADATA(&ea_gen_nexthop, 0, nhad.ad.data, nhad.ad.length),
> +  EA_LITERAL_EMBEDDED(&ea_babel_metric, 0, 1), // XXX this one is just for debugging
> +      }
> +    };
> +    rte e0 = {
> +      .attrs = &eattrs.l,
> +      .src = p->p.main_source,
> +    };
> +
> +    e->unreachable = 1;
> +    rte_update(c, e->n.addr, &e0, p->p.main_source);
> +  }
> +  else
> +  {
> +    e->unreachable = 0;
> +    rte_update(c, e->n.addr, NULL, p->p.main_source);
> +  }
> +
> +  /* Unlike the regular per-neighbour routes we only want one unreachable route
> +   * for each prefix. This is mainly due to the lifetime of the unreachable rte
> +   * exceeding that of the neighbour's rte_src ID as the babal neighbour may be
> +   * flushed before the unreachable route is retracted. */
> +  // rte_update(c, e->n.addr, rtee, p->p.main_source);
> +}
> +
>  /**
>   * babel_announce_rte - announce selected route to the core
>   * @p: Babel protocol instance
> @@ -682,12 +721,11 @@ babel_update_cost(struct babel_neighbor *nbr)
>   * the entry is valid and ours, the unreachable route is announced instead.
>   */
>  static void
> -babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
> +babel_announce_rte(struct babel_proto *p, struct babel_entry *e, struct babel_route *r)
>  {
> -  struct babel_route *r = e->selected;
>    struct channel *c = (e->n.addr->type == NET_IP4) ? p->ip4_channel : p->ip6_channel;
>  
> -  if (r)
> +  if (r->metric != BABEL_INFINITY && r->feasible)
>    {
>      struct nexthop_adata nhad = {
>        .nh = {
> @@ -706,7 +744,7 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
>       */
>      if (!neigh_find(&p->p, r->next_hop, r->neigh->ifa->iface, 0))
>        nhad.nh.flags = RNF_ONLINK;
> -    
> +
>      struct {
>        ea_list l;
>        eattr a[7];
> @@ -725,124 +763,25 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
>  
>      rte e0 = {
>        .attrs = &eattrs.l,
> -      .src = p->p.main_source,
> +      .src = r->neigh->src,
>      };
>  
> -    e->unreachable = 0;
> -    rte_update(c, e->n.addr, &e0, p->p.main_source);
> -  }
> -  else if (e->valid && (e->router_id != p->router_id))
> -  {
> -    /* Unreachable */
> -    ea_list *ea = NULL;
> -
> -    ea_set_attr_u32(&ea, &ea_gen_preference, 0, 1);
> -    ea_set_attr_u32(&ea, &ea_gen_source, 0, RTS_BABEL);
> -    ea_set_dest(&ea, 0, RTD_UNREACHABLE);
> -
> -    rte e0 = {
> -      .attrs = ea,
> -      .src = p->p.main_source,
> -    };
> -
> -    e->unreachable = 1;
> -    rte_update(c, e->n.addr, &e0, p->p.main_source);
> -  }
> -  else
> -  {
> -    /* Retraction */
> -    e->unreachable = 0;
> -    rte_update(c, e->n.addr, NULL, p->p.main_source);
> -  }
> -}
> -
> -/* Special case of babel_announce_rte() just for retraction */
> -static inline void
> -babel_announce_retraction(struct babel_proto *p, struct babel_entry *e)
> -{
> -  struct channel *c = (e->n.addr->type == NET_IP4) ? p->ip4_channel : p->ip6_channel;
> -  e->unreachable = 0;
> -  rte_update(c, e->n.addr, NULL, p->p.main_source);
> -}
> -
> -
> -/**
> - * babel_select_route - select best route for given route entry
> - * @p: Babel protocol instance
> - * @e: Babel entry to select the best route for
> - * @mod: Babel route that was modified or NULL if unspecified
> - *
> - * Select the best reachable and feasible route for a given prefix among the
> - * routes received from peers, and propagate it to the nest. This just selects
> - * the reachable and feasible route with the lowest metric, but keeps selected
> - * the old one in case of tie.
> - *
> - * If no feasible route is available for a prefix that previously had a route
> - * selected, a seqno request is sent to try to get a valid route. If the entry
> - * is valid and not owned by us, the unreachable route is announced to the nest
> - * (to blackhole packets going to it, as per section 2.8). It is later removed
> - * by babel_expire_routes(). Otherwise, the route is just removed from the nest.
> - *
> - * Argument @mod is used to optimize best route calculation. When specified, the
> - * function can assume that only the @mod route was modified to avoid full best
> - * route selection and announcement when non-best route was modified in minor
> - * way. The caller is advised to not call babel_select_route() when no change is
> - * done (e.g. periodic route updates) to avoid unnecessary announcements of the
> - * same best route. The caller is not required to call the function in case of a
> - * retraction of a non-best route.
> - *
> - * Note that the function does not active triggered updates. That is done by
> - * babel_rt_notify() when the change is propagated back to Babel.
> - */
> -static void
> -babel_select_route(struct babel_proto *p, struct babel_entry *e, struct babel_route *mod)
> -{
> -  struct babel_route *r, *best = e->selected;
> -
> -  /* Shortcut if only non-best was modified */
> -  if (mod && (mod != best))
> -  {
> -    /* Either select modified route, or keep old best route */
> -    if ((mod->metric < (best ? best->metric : BABEL_INFINITY)) && mod->feasible)
> -      best = mod;
> -    else
> -      return;
> +    rte_update(c, e->n.addr, &e0, r->neigh->src);
> +    if (e->unreachable)
> +      babel_rte_update_unreachable(p, e, 0);
>    }
>    else
>    {
> -    /* Selected route may be modified and no longer admissible */
> -    if (!best || (best->metric == BABEL_INFINITY) || !best->feasible)
> -      best = NULL;
> +    if (e->selected == r)
> +      /* We NULL e->selected here rather than wait for babel_rt_notify in order
> +       * to stay in a sync context. This is to be prepared for async rt_notify
> +       * in BIRD 3. This is critical as RFC8966 demands unfeasible or infinite
> +       * metric routes never being selected (see section 3.6 Route
> +       * Selection). */
> +      e->selected = NULL;
>  
> -    /* Find the best feasible route from all routes */
> -    WALK_LIST(r, e->routes)
> -      if ((r->metric < (best ? best->metric : BABEL_INFINITY)) && r->feasible)
> -  best = r;
> +    rte_update(c, e->n.addr, NULL, r->neigh->src);
>    }
> -
> -  if (best)
> -  {
> -    if (best != e->selected)
> -      TRACE(D_EVENTS, "Picked new route for prefix %N: router-id %lR metric %d",
> -      e->n.addr, best->router_id, best->metric);
> -  }
> -  else if (e->selected)
> -  {
> -    /*
> -     * We have lost all feasible routes. We have to broadcast seqno request
> -     * (Section 3.8.2.1) and keep unreachable route for a while (section 2.8).
> -     * The later is done automatically by babel_announce_rte().
> -     */
> -
> -    TRACE(D_EVENTS, "Lost feasible route for prefix %N", e->n.addr);
> -    if (e->valid && (e->selected->router_id == e->router_id))
> -      babel_add_seqno_request(p, e, e->selected->router_id, e->selected->seqno + 1, 0, NULL);
> -  }
> -  else
> -    return;
> -
> -  e->selected = best;
> -  babel_announce_rte(p, e);
>  }
>  
>  /*
> @@ -1414,7 +1353,12 @@ babel_handle_update(union babel_msg *m, struct babel_iface *ifa)
>    /*
>     * RFC 8966 3.8.2.2 - dealing with unfeasible updates. Generate a one-off
>     * (not retransmitted) unicast seqno request to the originator of this update.
> -   * Note: !feasible -> s exists, check for 's' is just for clarity / safety.
> +   *
> +   * Notes:
> +   *   - (!feasible) implies (s) is non-NULL, check for (s) is just for clarity
> +   *     and safety.
> +   *   - (!best) condition is not explicitly recommeded by RFCC8966 text but was
> +   *     in the old version, RFC6126.
>     */
>    if (!feasible && s && (metric != BABEL_INFINITY) &&
>        (!best || (r == best) || (metric < best->metric)))
> @@ -1448,7 +1392,7 @@ babel_handle_update(union babel_msg *m, struct babel_iface *ifa)
>      e->updated = current_time();
>    }
>  
> -  babel_select_route(p, e, r);
> +  babel_announce_rte(p, e, r);
>  }
>  
>  void
> @@ -2136,7 +2080,7 @@ static void
>  babel_dump_entry(struct dump_request *dreq, struct babel_entry *e)
>  {
>    struct babel_source *s;
> -  struct babel_route *r;
> +  struct babel_route *r, *best = e->selected;
>  
>    RDUMP("Babel: Entry %N:\n", e->n.addr);
>  
> @@ -2146,7 +2090,7 @@ babel_dump_entry(struct dump_request *dreq, struct babel_entry *e)
>    WALK_LIST(r,e->routes)
>    {
>      RDUMP(" ");
> -    if (r == e->selected) RDUMP("*");
> +    if (r == best) RDUMP("*");
>      babel_dump_route(dreq, r);
>    }
>  }
> @@ -2324,7 +2268,7 @@ babel_show_entries_(struct babel_proto *p, struct fib *rtable)
>  
>    FIB_WALK(rtable, struct babel_entry, e)
>    {
> -    struct babel_route *r = NULL;
> +    struct babel_route *r = NULL, *best = e->selected;
>      uint rts = 0, srcs = 0;
>      node *n;
>  
> @@ -2337,7 +2281,7 @@ babel_show_entries_(struct babel_proto *p, struct fib *rtable)
>      if (e->valid)
>        cli_msg(-1025, "%-*N %-23lR %6u %5u %7u %7u", width,
>          e->n.addr, e->router_id, e->metric, e->seqno, rts, srcs);
> -    else if (r = e->selected)
> +    else if (r = best)
>        cli_msg(-1025, "%-*N %-23lR %6u %5u %7u %7u", width,
>          e->n.addr, r->router_id, r->metric, r->seqno, rts, srcs);
>      else
> @@ -2374,10 +2318,10 @@ babel_show_routes_(struct babel_proto *p, struct fib *rtable)
>  
>    FIB_WALK(rtable, struct babel_entry, e)
>    {
> -    struct babel_route *r;
> +    struct babel_route *r, *best = e->selected;
>      WALK_LIST(r, e->routes)
>      {
> -      char c = (r == e->selected) ? '*' : (r->feasible ? '+' : ' ');
> +      char c = (r == best) ? '*' : (r->feasible ? '+' : ' ');
>        btime time = r->expires ? r->expires - current_time() : 0;
>        cli_msg(-1025, "%-*N %-25I %-10s %5u %c %5u %7t", width,
>          e->n.addr, r->next_hop, r->neigh->ifa->ifname,
> @@ -2466,8 +2410,9 @@ babel_entry_invalidate(struct babel_entry *e)
>  
>  
>  /*
> - * babel_rt_notify - core tells us about new route (possibly our own),
> - * so store it into our data structures.
> + * babel_rt_notify - BIRD core notifis us of changes in the selected optimal
> + * route. We can either get one of the routes back we exported or one from a
> + * different protocol.
>   */
>  static void
>  babel_rt_notify(struct proto *P, struct channel *c UNUSED, const net_addr *net,
> @@ -2475,6 +2420,8 @@ babel_rt_notify(struct proto *P, struct channel *c UNUSED, const net_addr *net,
>  {
>    struct babel_proto *p = (void *) P;
>    struct babel_entry *e;
> +  struct babel_iface *ifa;
> +  struct babel_neighbor *n;
>  
>    /* Ignore everything on shutdown */
>    if (SHUTTING_DOWN)
> @@ -2483,11 +2430,13 @@ babel_rt_notify(struct proto *P, struct channel *c UNUSED, const net_addr *net,
>    if (new)
>    {
>      /* Update */
> +    uint internal = new->src->owner == &P->sources;
>      uint rt_seqno;
>      uint rt_metric = ea_get_int(new->attrs, &ea_babel_metric, 0);
>      u64 rt_router_id = 0;
> +    struct babel_route *best;
>  
> -    if (new->src->owner == &P->sources)
> +    if (internal)
>      {
>        rt_seqno = ea_get_int(new->attrs, &ea_babel_seqno, 0);
>        eattr *e = ea_find(new->attrs, &ea_babel_router_id);
> @@ -2496,6 +2445,8 @@ babel_rt_notify(struct proto *P, struct channel *c UNUSED, const net_addr *net,
>      }
>      else
>      {
> +      /* If the selected route isn't one of ours we inject a new route into the
> +       * babel domain as per RFC8966 section 3.7 */
>        rt_seqno = p->update_seqno;
>        rt_router_id = p->router_id;
>      }
> @@ -2509,6 +2460,29 @@ babel_rt_notify(struct proto *P, struct channel *c UNUSED, const net_addr *net,
>  
>      e = babel_get_entry(p, net);
>  
> +    best = e->selected;
> +    if (internal) {
> +      eattr *ea = ea_find(new->attrs, &ea_gen_nexthop);
> +      struct nexthop_adata *nhad = (void *) ea->u.ptr;
> +      ifa = babel_find_iface(p, nhad->nh.iface);
> +      n = ifa ? babel_find_neighbor(ifa, ea_get_ip(new->attrs, &ea_gen_from, IPA_NONE)) : NULL;
> +      best = n ? babel_get_route(p, e, n) : NULL;
> +      ASSERT(best); /* Note: We think this can't happen but the lifetimes of the
> +         * involved objects are complicated so we're not yet
> +         * completely convinced. */
> +    }
> +    else
> +    {
> +      best = NULL;
> +    }
> +
> +    if (best && best != e->selected)
> +      TRACE(D_EVENTS,
> +      "Picked new route for prefix %N: router-id %lR metric %d",
> +      e->n.addr, best->router_id, best->metric);
> +
> +    e->selected = best;
> +
>      /* Activate triggered updates */
>      if (!(e->valid & BABEL_ENTRY_VALID) ||
>    (e->router_id != rt_router_id))
> @@ -2530,6 +2504,27 @@ babel_rt_notify(struct proto *P, struct channel *c UNUSED, const net_addr *net,
>      if (!e || e->valid != BABEL_ENTRY_VALID)
>        return;
>  
> +    if (e->selected) {
> +      TRACE(D_EVENTS, "Lost all feasible routes for prefix %N", e->n.addr);
> +      /* We had a feasible route, but now it's gone. We must send a seqno
> +       * request (Section 3.8.2.1). As allowed by RFC8966 we choose to always do
> +       * so even if we don't have any more unfeasible routes and we use the
> +       * simple unconditional multicast strategy.
> +       */
> +      if (e->valid && (e->selected->router_id == e->router_id))
> +  babel_add_seqno_request(
> +    p, e, e->selected->router_id, e->selected->seqno + 1, 0, NULL);
> +    }
> +
> +
> +    e->valid = BABEL_ENTRY_STALE;
> +    e->metric = BABEL_INFINITY;
> +    e->selected = NULL;
> +
> +    /* Install an unreachable route for prefix hold time as per RFC8966 section
> +     * 3.5.4. */
> +    babel_rte_update_unreachable(p, e, 1);
> +
>      babel_entry_invalidate(e);
>      babel_trigger_update(p);
>    }
> @@ -2626,6 +2621,7 @@ babel_start(struct proto *P)
>    p->source_slab = sl_new(P->pool, sizeof(struct babel_source));
>    p->msg_slab = sl_new(P->pool, sizeof(struct babel_msg_node));
>    p->seqno_slab = sl_new(P->pool, sizeof(struct babel_seqno_request));
> +  idm_init(&p->src_ids, P->pool, 8);
>  
>    p->log_pkt_tbf = (struct tbf){ .rate = 1, .burst = 5 };
>  
> diff --git a/proto/babel/babel.h b/proto/babel/babel.h
> index 146179cda..0699a2974 100644
> --- a/proto/babel/babel.h
> +++ b/proto/babel/babel.h
> @@ -25,6 +25,7 @@
>  #include "lib/socket.h"
>  #include "lib/string.h"
>  #include "lib/timer.h"
> +#include "lib/idm.h"
>  
>  #define BABEL_MAGIC    42
>  #define BABEL_VERSION    2
> @@ -193,6 +194,7 @@ struct babel_proto {
>    slab *source_slab;
>    slab *msg_slab;
>    slab *seqno_slab;
> +  struct idm src_ids;
>  
>    struct tbf log_pkt_tbf;    /* TBF for packet messages */
>  };
> @@ -235,6 +237,7 @@ struct babel_iface {
>  struct babel_neighbor {
>    node n;
>    struct babel_iface *ifa;
> +  struct rte_src *src;
>  
>    ip_addr addr;
>    u16 rxcost;        /* Sent in last IHU */

--Daniel


More information about the Bird-users mailing list