]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Merge branch 'mq-aggregator-for-v3' into thread-next
authorMaria Matejka <mq@ucw.cz>
Thu, 9 Nov 2023 15:53:34 +0000 (16:53 +0100)
committerMaria Matejka <mq@ucw.cz>
Thu, 9 Nov 2023 15:53:34 +0000 (16:53 +0100)
1  2 
nest/proto.c
nest/protocol.h
proto/bgp/bgp.c
proto/l3vpn/l3vpn.c

diff --cc nest/proto.c
index 50f302a92d6ce3236cc4baca9867afda6f65a722,88f4813ef572de5ca5a92cd360e4ca3dbf062815..4b8fef03ddc994ad508e7386f114b0202879158a
@@@ -46,27 -49,19 +46,26 @@@ static char *c_states[] = { "DOWN", "ST
  
  extern struct protocol proto_unix_iface;
  
--static void channel_request_reload(struct channel *c);
 -static void proto_shutdown_loop(timer *);
  static void proto_rethink_goal(struct proto *p);
  static char *proto_state_name(struct proto *p);
 -static void channel_verify_limits(struct channel *c);
 -static inline void channel_reset_limit(struct channel_limit *l);
 -
 +static void channel_init_limit(struct channel *c, struct limit *l, int dir, struct channel_limit *cf);
 +static void channel_update_limit(struct channel *c, struct limit *l, int dir, struct channel_limit *cf);
 +static void channel_reset_limit(struct channel *c, struct limit *l, int dir);
 +static int channel_refeed_prefilter(const struct rt_prefilter *p, const net_addr *n);
 +static int channel_import_prefilter(const struct rt_prefilter *p, const net_addr *n);
 +static void channel_feed_end(struct channel *c);
 +static void channel_stop_export(struct channel *c);
 +static void channel_export_stopped(struct rt_export_request *req);
 +static void channel_refeed_stopped(struct rt_export_request *req);
 +static void channel_check_stopped(struct channel *c);
 +static void channel_reload_in_done(struct channel_import_request *cir);
 +static void channel_request_partial_reload(struct channel *c, struct channel_import_request *cir);
  
  static inline int proto_is_done(struct proto *p)
 -{ return (p->proto_state == PS_DOWN) && (p->active_channels == 0); }
 +{ return (p->proto_state == PS_DOWN) && proto_is_inactive(p); }
  
  static inline int channel_is_active(struct channel *c)
 -{ return (c->channel_state == CS_START) || (c->channel_state == CS_UP); }
 +{ return (c->channel_state != CS_DOWN); }
  
  static inline int channel_reloadable(struct channel *c)
  { return c->proto->reload_routes && c->reloadable; }
@@@ -1232,15 -732,9 +1231,15 @@@ channel_stop_export(struct channel *c
  }
  
  static void
- static void
 +channel_import_request_done_dynamic(struct channel_import_request *req)
 +{
 +  mb_free(req);
 +}
 +
++void
  channel_request_reload(struct channel *c)
  {
 -  ASSERT(c->channel_state == CS_UP);
 +  ASSERT(c->in_req.hook);
    ASSERT(channel_reloadable(c));
  
    CD(c, "Reload requested");
diff --cc nest/protocol.h
index bcd54bdc259b68f214146020a2cc812fbd55f1c2,af2a5d6876e984cd5d258d24799e0296fd331606..f3bf6b4654527f072ccae690cb484fa000b18b88
@@@ -697,53 -641,25 +697,55 @@@ int channel_import_request_prefilter(st
  
  static inline void channel_init(struct channel *c) { channel_set_state(c, CS_START); }
  static inline void channel_open(struct channel *c) { channel_set_state(c, CS_UP); }
 -static inline void channel_close(struct channel *c) { channel_set_state(c, CS_FLUSHING); }
 +static inline void channel_close(struct channel *c) { channel_set_state(c, CS_STOP); }
 +
 +struct channel_feeding_request {
 +  struct channel_feeding_request *next;                       /* Next in request chain */
 +  void (*done)(struct channel_feeding_request *);     /* Called when refeed finishes */
 +  const struct f_trie *trie;                          /* Reload only matching nets */
 +  PACKED enum channel_feeding_request_type {
 +    CFRT_DIRECT = 1,                                  /* Refeed by export restart */
 +    CFRT_AUXILIARY,                                   /* Refeed by auxiliary request */
 +  } type;
 +  PACKED enum {
 +    CFRS_INACTIVE = 0,                                        /* Inactive request */
 +    CFRS_PENDING,                                     /* Request enqueued, do not touch */
 +    CFRS_RUNNING,                                     /* Request active, do not touch */
 +  } state;
 +};
  
 -void channel_request_feeding(struct channel *c);
 -void *channel_config_new(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
 -void *channel_config_get(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
 -int channel_reconfigure(struct channel *c, struct channel_config *cf);
 +struct channel *channel_from_export_request(struct rt_export_request *req);
 +void channel_request_feeding(struct channel *c, struct channel_feeding_request *);
 +void channel_request_feeding_dynamic(struct channel *c, enum channel_feeding_request_type);
  
 +static inline int channel_net_is_refeeding(struct channel *c, const net_addr *n)
 +{
 +  /* Not refeeding if not refeeding at all */
 +  if (!c->refeeding || !c->refeed_trie)
 +    return 0;
  
 -/* Moved from route.h to avoid dependency conflicts */
 -static inline void rte_update(struct proto *p, const net_addr *n, rte *new) { rte_update2(p->main_channel, n, new, p->main_source); }
 +  /* Not refeeding if already refed */
 +  if (trie_match_net(c->refeed_trie, n))
 +    return 0;
  
 -static inline void
 -rte_update3(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
 -{
 -  if (c->in_table && !rte_update_in(c, n, new, src))
 -    return;
 +  /* Refeeding if matching any request */
 +  for (struct channel_feeding_request *cfr = c->refeeding; cfr; cfr = cfr->next)
 +    if (!cfr->trie || trie_match_net(cfr->trie, n))
 +      return 1;
  
 -  rte_update2(c, n, new, src);
 +  /* Not matching any request */
 +  return 0;
  }
 +static inline void channel_net_mark_refed(struct channel *c, const net_addr *n)
 +{
 +  ASSERT_DIE(c->refeeding && c->refeed_trie);
 +  trie_add_prefix(c->refeed_trie, n, n->pxlen, n->pxlen);
 +}
 +
++void channel_request_reload(struct channel *c);
 +void *channel_config_new(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
 +void *channel_config_get(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
 +int channel_reconfigure(struct channel *c, struct channel_config *cf);
  
  #endif
diff --cc proto/bgp/bgp.c
index c93c553ff0171b7cc56cb05d2845d146126085ff,f8146bdf7e0e3cdac158535f2e0d1a9fa76977b5..24b952d9b070fbd112dcd5a3532a95097563ab96
@@@ -1592,24 -1414,26 +1592,36 @@@ bgp_reload_routes(struct channel *C, st
    struct bgp_proto *p = (void *) C->proto;
    struct bgp_channel *c = (void *) C;
  
 -      if ((c->desc->mpls) && (p->route_refresh || c->c.in_table))
 -      bgp_reload_routes(&c->c);
+   /* For MPLS channel, reload all MPLS-aware channels */
+   if (C == p->p.mpls_channel)
+   {
+     BGP_WALK_CHANNELS(p, c)
 -    return;
++      if ((c->desc->mpls) && (p->route_refresh || c->cf->import_table))
++      channel_request_reload(&c->c);
++    /* Ignoring CIR, reloading always everything */
++    cir->done(cir);
++    return 1;
+   }
    /* Ignore non-BGP channels */
 -  if (C->channel != &channel_bgp)
 -    return;
 +  if (C->class != &channel_bgp)
 +  {
 +    cir->done(cir);
 +    return 1;
 +  }
  
 -  ASSERT(p->conn && (p->route_refresh || c->c.in_table));
 +  if (cir->trie)
 +  {
 +    cir->done(cir);
 +    return 0;
 +  }
 +  /* We do not need cir anymore and later we will not be able to detect when to free it. */
 +  cir->done(cir);
  
 -  if (c->c.in_table)
 -    channel_schedule_reload(C);
 -  else
 -    bgp_schedule_packet(p->conn, c, PKT_ROUTE_REFRESH);
 +  ASSERT(p->conn && p->route_refresh);
 +  bgp_schedule_packet(p->conn, c, PKT_ROUTE_REFRESH);
 +  return 1;
  }
  
  static void
index 7b3d86d2a650b996bca20d0bb0d330fcdfe3e9ea,b7f60504f10aec41beaa66c01be583396138175d..eace62d0950b14fa405c6ec6f3146dfcd76d6027
@@@ -298,31 -296,17 +298,34 @@@ l3vpn_reload_routes(struct channel *C, 
      break;
  
    case NET_MPLS:
-     /* FIXME */
 -    channel_request_feeding(p->ip4_channel);
 -    channel_request_feeding(p->ip6_channel);
 -    break;
++    /* MPLS doesn't support partial refeed, always do a full one. */
++    channel_request_feeding_dynamic(p->ip4_channel, CFRT_DIRECT);
++    channel_request_feeding_dynamic(p->ip6_channel, CFRT_DIRECT);
++    cir->done(cir);
 +    return 1;
    }
 -}
  
 -static inline u32
 -l3vpn_metric(rte *e)
 -{
 -  u32 metric = ea_get_int(e->attrs->eattrs, EA_GEN_IGP_METRIC, e->attrs->igp_metric);
 -  return MIN(metric, IGP_METRIC_UNKNOWN);
 +  if (cir->trie)
 +  {
 +    struct import_to_export_reload *reload = lp_alloc(cir->trie->lp, sizeof *reload);
 +    *reload = (struct import_to_export_reload) {
 +      .cir = cir,
 +      .cfr = {
 +            .type = CFRT_AUXILIARY,
 +            .done = pipe_import_by_refeed_free,
 +            .trie = cir->trie,
 +          },
 +    };
 +    channel_request_feeding(feed, &reload->cfr);
 +  }
 +  else
 +  {
 +    /* Route reload on one channel is just refeed on the other */
 +    channel_request_feeding_dynamic(feed, CFRT_DIRECT);
 +    cir->done(cir);
 +  }
 +
 +  return 1;
  }
  
  static int