]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Merge branch 'master' into int-new-channels
authorJan Moskyto Matejka <mq@ucw.cz>
Fri, 8 Apr 2016 10:09:31 +0000 (12:09 +0200)
committerJan Moskyto Matejka <mq@ucw.cz>
Fri, 8 Apr 2016 10:28:33 +0000 (12:28 +0200)
18 files changed:
1  2 
filter/config.Y
filter/filter.c
lib/lists.h
lib/socket.h
nest/config.Y
nest/proto.c
nest/route.h
proto/bfd/bfd.c
proto/bgp/bgp.c
proto/ospf/iface.c
proto/ospf/neighbor.c
proto/ospf/topology.c
proto/rip/config.Y
sysdep/bsd/krt-sock.c
sysdep/linux/netlink.c
sysdep/unix/io.c
sysdep/unix/krt.c
sysdep/unix/main.c

diff --cc filter/config.Y
index 3bb00c13d0b1d617338aab8f166505dcc27d98b7,b94f5dfff0be4fe7abb22df66fd3b57111bed64e..3e70a63e5afbff44e5dd88f2f4309128c4b187af
@@@ -282,7 -283,8 +282,7 @@@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UN
        LEN,
        DEFINED,
        ADD, DELETE, CONTAINS, RESET,
-       PREPEND, FIRST, LAST, MATCH,
+       PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
 -      ROA_CHECK,
        EMPTY,
        FILTER, WHERE, EVAL)
  
diff --cc filter/filter.c
Simple merge
diff --cc lib/lists.h
Simple merge
diff --cc lib/socket.h
Simple merge
diff --cc nest/config.Y
index 6bb686c3b0d8e40468c94ee121bde7ef20169a7a,87827c10d52cbb397ec943ff241a1d45edbff14b..94a676705f518f6960575587733755a34c740e70
@@@ -109,10 -106,12 +109,10 @@@ idval
   | SYM {
       if ($1->class == (SYM_CONSTANT | T_INT) || $1->class == (SYM_CONSTANT | T_QUAD))
         $$ = SYM_VAL($1).i;
 -#ifndef IPV6
 -     else if ($1->class == (SYM_CONSTANT | T_IP))
 -       $$ = ipa_to_u32(SYM_VAL($1).px.ip);
 -#endif
 +     else if (($1->class == (SYM_CONSTANT | T_IP)) && ipa_is_ip4(SYM_VAL($1).ip))
 +       $$ = ipa_to_u32(SYM_VAL($1).ip);
       else
-        cf_error("Number of IPv4 address constant expected");
+        cf_error("Number or IPv4 address constant expected");
     }
   ;
  
diff --cc nest/proto.c
index f712fe5f4e7153743c3e9ee8d6116195fbe23bf0,436377f1b51ef6a44972f816f0efe9a625e6f803..df4952b736373eef2fd678738e9a943f47ef28e1
@@@ -78,297 -96,95 +78,298 @@@ proto_log_state_change(struct proto *p
  }
  
  
 -/**
 - * proto_new - create a new protocol instance
 - * @c: protocol configuration
 - * @size: size of protocol data structure (each protocol instance is represented by
 - * a structure starting with generic part [struct &proto] and continued
 - * with data specific to the protocol)
 - *
 - * When a new configuration has been read in, the core code starts
 - * initializing all the protocol instances configured by calling their
 - * init() hooks with the corresponding instance configuration. The initialization
 - * code of the protocol is expected to create a new instance according to the
 - * configuration by calling this function and then modifying the default settings
 - * to values wanted by the protocol.
 - */
 -void *
 -proto_new(struct proto_config *c, unsigned size)
 +struct channel_config *
 +proto_cf_find_channel(struct proto_config *pc, uint net_type)
  {
 -  struct protocol *pr = c->protocol;
 -  struct proto *p = mb_allocz(proto_pool, size);
 -
 -  p->cf = c;
 -  p->debug = c->debug;
 -  p->mrtdump = c->mrtdump;
 -  p->name = c->name;
 -  p->preference = c->preference;
 -  p->disabled = c->disabled;
 -  p->proto = pr;
 -  p->table = c->table->table;
 -  p->hash_key = random_u32();
 -  c->proto = p;
 -  return p;
 +  struct channel_config *cc;
 +
 +  WALK_LIST(cc, pc->channels)
 +    if (cc->net_type == net_type)
 +      return cc;
 +
 +  return NULL;
  }
  
 -static void
 -proto_init_instance(struct proto *p)
 +/**
 + * proto_find_channel_by_table - find channel connected to a routing table
 + * @p: protocol instance
 + * @t: routing table
 + *
 + * Returns pointer to channel or NULL
 + */
 +struct channel *
 +proto_find_channel_by_table(struct proto *p, struct rtable *t)
  {
 -  /* Here we cannot use p->cf->name since it won't survive reconfiguration */
 -  p->pool = rp_new(proto_pool, p->proto->name);
 -  p->attn = ev_new(p->pool);
 -  p->attn->data = p;
 +  struct channel *c;
  
 -  if (graceful_restart_state == GRS_INIT)
 -    p->gr_recovery = 1;
 +  WALK_LIST(c, p->channels)
 +    if (c->table == t)
 +      return c;
  
 -  if (! p->proto->multitable)
 -    rt_lock_table(p->table);
 +  return NULL;
  }
  
 -extern pool *rt_table_pool;
  /**
 - * proto_add_announce_hook - connect protocol to a routing table
 + * proto_add_channel - connect protocol to a routing table
   * @p: protocol instance
 - * @t: routing table to connect to
 - * @stats: per-table protocol statistics
 - *
 - * This function creates a connection between the protocol instance @p and the
 - * routing table @t, making the protocol hear all changes in the table.
 + * @cf: channel configuration
   *
 - * The announce hook is linked in the protocol ahook list. Announce hooks are
 - * allocated from the routing table resource pool and when protocol accepts
 - * routes also in the table ahook list. The are linked to the table ahook list
 - * and unlinked from it depending on export_state (in proto_want_export_up() and
 - * proto_want_export_down()) and they are automatically freed after the protocol
 - * is flushed (in proto_fell_down()).
 + * This function creates a channel between the protocol instance @p and the
 + * routing table specified in the configuration @cf, making the protocol hear
 + * all changes in the table and allowing the protocol to update routes in the
 + * table.
   *
 - * Unless you want to listen to multiple routing tables (as the Pipe protocol
 - * does), you needn't to worry about this function since the connection to the
 - * protocol's primary routing table is initialized automatically by the core
 - * code.
 + * The channel is linked in the protocol channel list and when active also in
 + * the table channel list. Channels are allocated from the global resource pool
 + * (@proto_pool) and they are automatically freed when the protocol is removed.
   */
 -struct announce_hook *
 -proto_add_announce_hook(struct proto *p, struct rtable *t, struct proto_stats *stats)
 +
 +struct channel *
 +proto_add_channel(struct proto *p, struct channel_config *cf)
 +{
 +  struct channel *c = mb_allocz(proto_pool, cf->channel->channel_size);
 +
 +  c->name = cf->name;
 +  c->channel = cf->channel;
 +  c->proto = p;
 +  c->table = cf->table->table;
 +
 +  c->in_filter = cf->in_filter;
 +  c->out_filter = cf->out_filter;
 +  c->rx_limit = cf->rx_limit;
 +  c->in_limit = cf->in_limit;
 +  c->out_limit = cf->out_limit;
 +
 +  c->net_type = cf->net_type;
 +  c->ra_mode = cf->ra_mode;
 +  c->preference = cf->preference;
 +  c->merge_limit = cf->merge_limit;
 +  c->in_keep_filtered = cf->in_keep_filtered;
 +
 +  c->channel_state = CS_DOWN;
 +  c->export_state = ES_DOWN;
 +  c->last_state_change = now;
 +  c->reloadable = 1;
 +
 +  CALL(c->channel->init, c, cf);
 +
 +  add_tail(&p->channels, &c->n);
 +
 +  PD(p, "Channel %s connected to table %s", c->name, c->table->name);
 +
 +  return c;
 +}
 +
 +void
 +proto_remove_channel(struct proto *p, struct channel *c)
 +{
 +  ASSERT(c->channel_state == CS_DOWN);
 +
 +  PD(p, "Channel %s removed", c->name);
 +
 +  rem_node(&c->n);
 +  mb_free(c);
 +}
 +
 +
 +static void
 +proto_start_channels(struct proto *p)
 +{
 +  struct channel *c;
 +  WALK_LIST(c, p->channels)
 +    if (!c->disabled)
 +      channel_set_state(c, CS_UP);
 +}
 +
 +static void
 +proto_pause_channels(struct proto *p)
 +{
 +  struct channel *c;
 +  WALK_LIST(c, p->channels)
 +    if (!c->disabled && channel_is_active(c))
 +      channel_set_state(c, CS_START);
 +}
 +
 +static void
 +proto_stop_channels(struct proto *p)
 +{
 +  struct channel *c;
 +  WALK_LIST(c, p->channels)
 +    if (!c->disabled && channel_is_active(c))
 +      channel_set_state(c, CS_FLUSHING);
 +}
 +
 +static void
 +proto_remove_channels(struct proto *p)
 +{
 +  struct channel *c;
 +  WALK_LIST_FIRST(c, p->channels)
 +    proto_remove_channel(p, c);
 +}
 +
 +static void
 +channel_schedule_feed(struct channel *c, int initial)
 +{
 +  // DBG("%s: Scheduling meal\n", p->name);
 +  ASSERT(c->channel_state == CS_UP);
 +
 +  c->export_state = ES_FEEDING;
 +  c->refeeding = !initial;
 +
 +  ev_schedule(c->feed_event);
 +}
 +
 +static void
 +channel_feed_loop(void *ptr)
 +{
 +  struct channel *c = ptr;
 +
 +  if (c->export_state != ES_FEEDING)
 +    return;
 +
 +  if (!c->feed_active)
 +    if (c->proto->feed_begin)
 +      c->proto->feed_begin(c, !c->refeeding);
 +
 +  // DBG("Feeding protocol %s continued\n", p->name);
 +  if (!rt_feed_channel(c))
 +  {
 +    ev_schedule(c->feed_event);
 +    return;
 +  }
 +
 +  // DBG("Feeding protocol %s finished\n", p->name);
 +  c->export_state = ES_READY;
 +  // proto_log_state_change(p);
 +
 +  if (c->proto->feed_end)
 +    c->proto->feed_end(c);
 +}
 +
 +
 +static void
 +channel_start_export(struct channel *c)
 +{
 +  ASSERT(c->channel_state == CS_UP);
 +  ASSERT(c->export_state == ES_DOWN);
 +
 +  channel_schedule_feed(c, 1);        /* Sets ES_FEEDING */
 +}
 +
 +static void
 +channel_stop_export(struct channel *c)
 +{
 +  /* Need to abort feeding */
 +  if (c->export_state == ES_FEEDING)
 +    rt_feed_channel_abort(c);
 +
 +  c->export_state = ES_DOWN;
++  c->stats.exp_routes = 0;
 +}
 +
 +static void
 +channel_do_start(struct channel *c)
  {
 -  struct announce_hook *h;
 +  rt_lock_table(c->table);
 +  add_tail(&c->table->channels, &c->table_node);
 +  c->proto->active_channels++;
 +
 +  c->feed_event = ev_new(c->proto->pool);
 +  c->feed_event->data = c;
 +  c->feed_event->hook = channel_feed_loop;
 +
 +  channel_reset_limit(&c->rx_limit);
 +  channel_reset_limit(&c->in_limit);
 +  channel_reset_limit(&c->out_limit);
 +
 +  CALL(c->channel->start, c);
 +}
 +
 +static void
 +channel_do_flush(struct channel *c)
 +{
 +  rt_schedule_prune(c->table);
 +
 +  c->gr_wait = 0;
 +  if (c->gr_lock)
 +    channel_graceful_restart_unlock(c);
 +
 +  CALL(c->channel->shutdown, c);
 +}
  
 -  DBG("Connecting protocol %s to table %s\n", p->name, t->name);
 -  PD(p, "Connected to table %s", t->name);
 +static void
 +channel_do_down(struct channel *c)
 +{
-   rem2_node(&c->table_node);
++  rem_node(&c->table_node);
 +  rt_unlock_table(c->table);
 +  c->proto->active_channels--;
  
 -  h = mb_allocz(rt_table_pool, sizeof(struct announce_hook));
 -  h->table = t;
 -  h->proto = p;
 -  h->stats = stats;
 +  if ((c->stats.imp_routes + c->stats.filt_routes) != 0)
 +    log(L_ERR "%s: Channel %s is down but still has some routes", c->proto->name, c->name);
  
 -  h->next = p->ahooks;
 -  p->ahooks = h;
 +  memset(&c->stats, 0, sizeof(struct proto_stats));
  
 -  if (p->rt_notify && (p->export_state != ES_DOWN))
 -    add_tail(&t->hooks, &h->n);
 -  return h;
 +  /* Schedule protocol shutddown */
 +  if (proto_is_done(c->proto))
 +    ev_schedule(c->proto->event);
 +}
 +
 +void
 +channel_set_state(struct channel *c, uint state)
 +{
 +  uint cs = c->channel_state;
 +  uint es = c->export_state;
 +
 +  DBG("%s reporting channel %s state transition %s -> %s\n", c->proto->name, c->name, cs_states[cs], cs_states[state]);
 +  if (state == cs)
 +    return;
 +
 +  c->channel_state = state;
 +  c->last_state_change = now;
 +
 +  switch (state)
 +  {
 +  case CS_START:
 +    ASSERT(cs == CS_DOWN || cs == CS_UP);
 +
 +    if (cs == CS_DOWN)
 +      channel_do_start(c);
 +
 +    if (es != ES_DOWN)
 +      channel_stop_export(c);
 +
 +    break;
 +
 +  case CS_UP:
 +    ASSERT(cs == CS_DOWN || cs == CS_START);
 +
 +    if (cs == CS_DOWN)
 +      channel_do_start(c);
 +
 +    if (!c->gr_wait && c->proto->rt_notify)
 +      channel_start_export(c);
 +
 +    break;
 +
 +  case CS_FLUSHING:
 +    ASSERT(cs == CS_START || cs == CS_UP);
 +
 +    if (es != ES_DOWN)
 +      channel_stop_export(c);
 +
 +    channel_do_flush(c);
 +    break;
 +
 +  case CS_DOWN:
 +    ASSERT(cs == CS_FLUSHING);
 +
 +    channel_do_down(c);
 +    break;
 +
 +  default:
 +    ASSERT(0);
 +  }
 +  // XXXX proto_log_state_change(c);
  }
  
  /**
diff --cc nest/route.h
Simple merge
diff --cc proto/bfd/bfd.c
Simple merge
diff --cc proto/bgp/bgp.c
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index cbfb47d5ddeda324be103812212ee81a1ad9234a,5955dbfef52fd8efbcfa3ccbc6d1fc292c8e9229..37e26c9b86aebd787418a32784befc3b8fe78284
@@@ -1416,9 -1402,7 +1402,6 @@@ sk_open(sock *s
    if (fd < 0)
      ERR("socket");
  
-   if (fd >= FD_SETSIZE)
-     ERR2("FD_SETSIZE limit reached");
 -  s->af = af;
    s->fd = fd;
  
    if (sk_setup(s) < 0)
index 6b3b4eee004b735c2fbff4ba3f309d15ccc73ac2,f5dee877575f6738f007404fe2b4d2f0398d3739..b0a966137de47df5a1c0fb073f789a470cd44073
@@@ -408,11 -412,18 +408,17 @@@ krt_learn_prune(struct krt_proto *p
  
    FIB_ITERATE_INIT(&fit, fib);
  again:
 -  FIB_ITERATE_START(fib, &fit, f)
 +  FIB_ITERATE_START(fib, &fit, net, n)
      {
 -      net *n = (net *) f;
        rte *e, **ee, *best, **pbest, *old_best;
  
-       old_best = n->routes;
+       /*
+        * 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().
+        * But in that case there is a new valid best route.
+        */
+       old_best = NULL;
        best = NULL;
        pbest = NULL;
        ee = &n->routes;
        {
          DBG("%I/%d: deleting\n", n->n.prefix, n->n.pxlen);
          if (old_best)
-           {
-             krt_learn_announce_delete(p, n);
-             n->n.flags &= ~KRF_INSTALLED;
-           }
+           krt_learn_announce_delete(p, n);
 -        FIB_ITERATE_PUT(&fit, f);
 -        fib_delete(fib, f);
 +        FIB_ITERATE_PUT(&fit);
 +        fib_delete(fib, n);
          goto again;
        }
+       best->u.krt.best = 1;
        *pbest = best->next;
        best->next = n->routes;
        n->routes = best;
Simple merge