]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
proto.c: show protocol uses only proto id and attr table
authorKaterina Kubecova <katerina.kubecova@nic.cz>
Fri, 31 May 2024 10:27:59 +0000 (12:27 +0200)
committerKaterina Kubecova <katerina.kubecova@nic.cz>
Mon, 24 Jun 2024 07:42:03 +0000 (09:42 +0200)
12 files changed:
filter/data.c
lib/lockfree.c
lib/route.h
lib/type.h
lib/xmalloc.c
nest/proto.c
nest/protocol.h
nest/rt-attr.c
nest/rt-export.c
proto/bgp/attrs.c
proto/mrt/config.Y
proto/mrt/mrt.c

index 7b0f6750172a36f414916874d2601088b64dd1fc..660a8658fe32ca02c86cbcb08dd2a0867c8b3eae 100644 (file)
@@ -650,6 +650,8 @@ mem_hash_mix_f_val(u64 *h, struct f_val *v)
     case T_NEXTHOP_LIST:
     case T_HOSTENTRY:
     case T_IFACE:
+    case T_ENUM_STATE:
+    case T_BTIME:
       bug("Invalid type %s in f_val hashing", f_type_name(v->type));
   }
 }
index 6f8e66b9dd713a34a5726077301dc018ade3db6d..e45f71851f4978788d906b14b72d71785158255f 100644 (file)
@@ -219,6 +219,7 @@ void lfjour_release(struct lfjour_recipient *r)
 void
 lfjour_announce_now(struct lfjour *j)
 {
+  log("announce now %i", j);
   ASSERT_DIE(birdloop_inside(j->loop));
   settle_cancel(&j->announce_timer);
   ev_postpone(&j->announce_kick_event);
@@ -226,6 +227,7 @@ lfjour_announce_now(struct lfjour *j)
   if (EMPTY_TLIST(lfjour_recipient, &j->recipients))
     return lfjour_schedule_cleanup(j);
 
+  log("walk recipient list");
   WALK_TLIST(lfjour_recipient, r, &j->recipients)
     if (r->event)
       ev_send(r->target, r->event);
index 0ef97f017f9bee66ce70ea8c142b93e4321c05c7..7087386da285c28048670ff50616deffe319d264 100644 (file)
@@ -377,6 +377,8 @@ void ea_list_copy(ea_list *dest, ea_list *src, uint size);
 #define EA_LITERAL_GENERIC(_id, _type, _flags, ...) \
   ((eattr) { .id = _id, .type = _type, .flags = _flags, __VA_ARGS__ })
 
+#define EA_LITERAL_STORE_STRING(_class, _flags, string) ({EA_LITERAL_STORE_ADATA(_class, _flags, string, strlen(string)+1);})
+
 static inline eattr *
 ea_set_attr(ea_list **to, eattr a)
 {
@@ -443,6 +445,9 @@ extern struct ea_class ea_gen_from;
 extern struct ea_class ea_gen_mpls_label,
        ea_gen_mpls_policy, ea_gen_mpls_class;
 
+extern struct ea_class ea_proto_name, ea_proto_protocol_name, ea_proto_table,
+       ea_proto_state, ea_proto_old_state, ea_proto_last_modified, ea_proto_info,
+       ea_proto_id, ea_proto_deleted;
 
 /* Source: An old method to devise the route source protocol and kind.
  * To be superseded in a near future by something more informative. */
index 2edaa2e4e179ca82e18f6d4e1633b6e642a89616..97f021bdbfffce1b2af2a16c6f2d8b1831e8e18a 100644 (file)
@@ -113,6 +113,10 @@ enum btype {
 
   T_SET = 0x80,
   T_PREFIX_SET = 0x84,
+
+/* protocol */
+  T_ENUM_STATE = 0xd1,
+  T_BTIME = 0xd4,
 } PACKED;
 
 typedef enum btype btype;
index 38f6d0cf868ad9e78fe5227a57cf46ce2a2d38f6..74348d11b2b831223bb0bfedb5d3cdc1e2c61881 100644 (file)
@@ -65,9 +65,8 @@ xmalloc(uint size)
 void *
 xrealloc(void *ptr, uint size)
 {
-  void *p = realloc(ptr, size);
-
   MINFO(ptr, 0, 2);
+  void *p = realloc(ptr, size);
   MINFO(p, size, 3);
 
   if (p)
index 3493b23926fe06f855ea7cde550302f4aba75db1..43f61aec2540bbe1a2d21a3cfd54bc0bcf05639e 100644 (file)
@@ -28,6 +28,9 @@ static TLIST_LIST(proto) global_proto_list;
 
 static list STATIC_LIST_INIT(protocol_list);
 
+struct lfjour *proto_journal;
+DOMAIN(rtable) proto_journal_domain;
+
 #define CD(c, msg, args...) ({ if (c->debug & D_STATES) log(L_TRACE "%s.%s: " msg, c->proto->name, c->name ?: "?", ## args); })
 #define PD(p, msg, args...) ({ if (p->debug & D_STATES) log(L_TRACE "%s: " msg, p->name, ## args); })
 
@@ -45,6 +48,7 @@ static char *p_states[] = { "DOWN", "START", "UP", "STOP" };
 static char *c_states[] = { "DOWN", "START", "UP", "STOP", "RESTART" };
 
 extern struct protocol proto_unix_iface;
+struct proto_attrs *proto_attributes;
 
 static void proto_rethink_goal(struct proto *p);
 static char *proto_state_name(struct proto *p);
@@ -64,6 +68,8 @@ static inline void channel_refeed(struct channel *c, struct rt_feeding_request *
   rt_export_refeed(&c->out_req, rfr);
 }
 
+void init_proto_journal(void);
+
 static inline int proto_is_done(struct proto *p)
 { return (p->proto_state == PS_DOWN) && proto_is_inactive(p); }
 
@@ -1235,6 +1241,7 @@ proto_init(struct proto_config *c, struct proto *after)
   struct proto *p = pr->init(c);
 
   p->loop = &main_birdloop;
+  int old_state = p->proto_state;
   p->proto_state = PS_DOWN;
   p->last_state_change = current_time();
   p->vrf = c->vrf;
@@ -1244,6 +1251,16 @@ proto_init(struct proto_config *c, struct proto *after)
 
   PD(p, "Initializing%s", p->disabled ? " [disabled]" : "");
 
+  log("try to change state");
+  p->id = hmap_first_zero(proto_attributes->proto_id_maker);
+  hmap_set(proto_attributes->proto_id_maker, p->id);
+  if (p->id >= proto_attributes->length)
+    protos_attr_field_grow();
+  ea_list *eal = proto_state_to_eattr(p, old_state, 0);
+  ea_list *old_eal = proto_attributes->attrs[p->id];
+  atomic_store(&proto_attributes->attrs[p->id], eal);
+  proto_journal_state_changed(eal, old_eal, p);
+
   return p;
 }
 
@@ -1665,6 +1682,9 @@ proto_rethink_goal(struct proto *p)
     struct proto_config *nc = p->cf_new;
     struct proto *after = p->n.prev;
 
+    hmap_clear(proto_attributes->proto_id_maker, p->id);
+    atomic_store(&proto_attributes->attrs[p->id], NULL);
+
     DBG("%s has shut down for reconfiguration\n", p->name);
     p->cf->proto = NULL;
     config_del_obstacle(p->cf->global);
@@ -1955,6 +1975,8 @@ protos_build(void)
 {
   proto_pool = rp_new(&root_pool, the_bird_domain.the_bird, "Protocols");
 
+  init_proto_journal();
+  create_dummy_recipient();
   protos_build_gen();
 }
 
@@ -2254,8 +2276,14 @@ proto_notify_state(struct proto *p, uint state)
   if (state == ps)
     return;
 
+  log("try to change state");
+  int old_state = p->proto_state;
   p->proto_state = state;
   p->last_state_change = current_time();
+  ea_list *eal = proto_state_to_eattr(p, old_state, 0);
+  ea_list *old_eal = proto_attributes->attrs[p->id];
+  atomic_store(&proto_attributes->attrs[p->id], eal);
+  proto_journal_state_changed(eal, old_eal, p);
 
   switch (state)
   {
@@ -2314,6 +2342,19 @@ proto_state_name(struct proto *p)
   }
 }
 
+static char *
+proto_state_name_from_int(int state)
+{
+  switch (state)
+  {
+  case PS_DOWN:                return "flush or down";
+  case PS_START:       return "start";
+  case PS_UP:          return "up";
+  case PS_STOP:                return "stop";
+  default:             return "???";
+  }
+}
+
 static void
 channel_show_stats(struct channel *c)
 {
@@ -2416,17 +2457,28 @@ proto_cmd_show(struct proto *p, uintptr_t verbose, int cnt)
     cli_msg(-2002, "%-10s %-10s %-10s %-6s %-12s  %s",
            "Name", "Proto", "Table", "State", "Since", "Info");
 
+  rcu_read_lock();
+  ea_list *eal = proto_attributes->attrs[p->id];
+  ea_free_later(ea_ref(eal));
+  rcu_read_unlock();
+
+  const char *name = ea_find(eal, &ea_proto_name)->u.ad->data;
+  const char *proto = ea_find(eal, &ea_proto_protocol_name)->u.ad->data;
+  const int state = ea_find(eal, &ea_proto_state)->u.i;
+  const char *table = ea_find(eal, &ea_proto_table)->u.ad->data;
+  const char *info = ea_find(eal, &ea_proto_info)->u.ad->data;
+  const btime *time = (btime*) ea_find(eal, &ea_proto_last_modified)->u.ad->data;
   buf[0] = 0;
   if (p->proto->get_status)
     p->proto->get_status(p, buf);
-  tm_format_time(tbuf, &config->tf_proto, p->last_state_change);
+  tm_format_time(tbuf, &config->tf_proto, *time);
   cli_msg(-1002, "%-10s %-10s %-10s %-6s %-12s  %s",
-         p->name,
-         p->proto->name,
-         p->main_channel ? p->main_channel->table->name : "---",
-         proto_state_name(p),
+         name,
+         proto,
+         table,
+         proto_state_name_from_int(state),
          tbuf,
-         buf);
+         info);
 
   if (verbose)
   {
@@ -2724,3 +2776,162 @@ proto_iterate_named(struct symbol *sym, struct protocol *proto, struct proto *ol
     return NULL;
   }
 }
+
+
+
+void
+protos_attr_field_init(void)
+{
+  proto_attributes = mb_allocz(&root_pool, sizeof(struct proto_attrs));
+  proto_attributes->attrs = mb_allocz(&root_pool, sizeof(ea_list *_Atomic)*16);
+  proto_attributes->length = 16;
+  proto_attributes->proto_id_maker = mb_allocz(&root_pool, sizeof(struct hmap));
+  hmap_init(proto_attributes->proto_id_maker, &root_pool, 16);
+  //TODO free? or have self pool?
+}
+
+void
+protos_attr_field_grow(void)
+{
+  ea_list *_Atomic * new_field = mb_allocz(&root_pool, sizeof(ea_list *_Atomic)*proto_attributes->length*2);
+  memcpy(new_field, proto_attributes->attrs, proto_attributes->length*(sizeof(ea_list* _Atomic)));
+  atomic_store(&proto_attributes->attrs, new_field);
+  atomic_store(&proto_attributes->length, (proto_attributes->length*2));
+}
+
+void
+cleanup_journal_item(struct lfjour * UNUSED, struct lfjour_item *i)
+{
+  log("clean item");
+  struct proto_pending_update *pupdate = SKIP_BACK(struct proto_pending_update, li, i);
+  ea_free_later(pupdate->old_attr);
+  eattr *new_ea = ea_find(pupdate->proto_attr, &ea_proto_deleted);
+  if (new_ea->u.i)
+    ea_free_later(pupdate->proto_attr);
+}
+
+void
+after_journal_birdloop_stop(void* UNUSED){}
+
+void
+init_proto_journal(void)
+{
+  protos_attr_field_init();
+  proto_journal = mb_allocz(&root_pool, sizeof(struct lfjour));
+  struct settle_config cf = {.min = 0, .max = 0};
+  proto_journal->item_done = cleanup_journal_item;
+  proto_journal->item_size = sizeof(struct proto_pending_update);
+  proto_journal->loop = birdloop_new(&root_pool, DOMAIN_ORDER(service), 1, "Protocol state journal");
+  proto_journal_domain = DOMAIN_NEW_RCU_SYNC(rtable);
+  proto_journal->domain = proto_journal_domain.rtable;
+
+  lfjour_init(proto_journal, &cf);
+}
+
+ea_list *
+proto_state_to_eattr(struct proto *p, int old_state, int proto_deleting)
+{
+  struct {
+       ea_list l;
+       eattr a[8];
+  } eattrs;
+
+  eattrs.l = (ea_list) {};
+
+  eattrs.a[eattrs.l.count++] = EA_LITERAL_STORE_STRING(&ea_proto_name, 0, p->name);
+  eattrs.a[eattrs.l.count++] = EA_LITERAL_STORE_STRING(&ea_proto_protocol_name, 0, p->proto->name);
+  eattrs.a[eattrs.l.count++] = EA_LITERAL_STORE_STRING(&ea_proto_table, 0, p->main_channel ? p->main_channel->table->name : "---");
+  eattrs.a[eattrs.l.count++] = EA_LITERAL_EMBEDDED(&ea_proto_state, 0, p->proto_state);
+  eattrs.a[eattrs.l.count++] = EA_LITERAL_EMBEDDED(&ea_proto_old_state, 0, old_state);
+  eattrs.a[eattrs.l.count++] = EA_LITERAL_STORE_ADATA(&ea_proto_last_modified, 0, &p->last_state_change, sizeof(btime));
+  eattrs.a[eattrs.l.count++] = EA_LITERAL_EMBEDDED(&ea_proto_id, 0, p->id);
+  eattrs.a[eattrs.l.count++] = EA_LITERAL_EMBEDDED(&ea_proto_deleted, 0, proto_deleting);
+  byte buf[256];
+  buf[0] = 0;
+  if (p->proto->get_status)
+    p->proto->get_status(p, buf);
+  eattrs.a[eattrs.l.count++] = EA_LITERAL_STORE_STRING(&ea_proto_info, 0, buf);
+  return ea_lookup_slow(&eattrs.l, 0, EALS_CUSTOM);
+}
+
+void
+proto_journal_state_changed(ea_list *attr, ea_list *old_attr, struct proto *p)
+{
+  LOCK_DOMAIN(rtable, proto_journal_domain);
+  struct proto_pending_update *pupdate = SKIP_BACK(struct proto_pending_update, li, lfjour_push_prepare(proto_journal));
+  if (!pupdate)
+  {
+    log("no recievers");
+    //if (free_add_data)
+    //  free_add_data(add_data);
+    log("returning");
+    UNLOCK_DOMAIN(rtable, proto_journal_domain);
+    return;
+  }
+  *pupdate = (struct proto_pending_update) {
+    .li = pupdate->li, /* Keep the item's internal state */
+    .proto_attr = attr,
+    .old_attr = old_attr,
+    .protocol = p
+  };
+  lfjour_push_commit(proto_journal);
+  log("in journal state change, proto %s, jfjour %i - pushed", p->name, proto_journal);
+  UNLOCK_DOMAIN(rtable, proto_journal_domain);
+}
+
+void dummy_log_proto_attr_list(void)
+{
+//debugging function
+  ea_list *eal;
+  for(u32 i = 0; i < proto_attributes->length; i++)
+  {
+    rcu_read_lock();
+    eal = proto_attributes->attrs[i];
+    if (eal)
+      ea_free_later(ea_ref(eal));
+    rcu_read_unlock();
+    if (eal)
+    {
+      const char *name = ea_find(eal, &ea_proto_name)->u.ad->data;
+      const char *type = ea_find(eal, &ea_proto_protocol_name)->u.ad->data;
+      const int state = ea_find(eal, &ea_proto_state)->u.i;
+      const char *table = ea_find(eal, &ea_proto_table)->u.ad->data;
+      const btime *time = (btime*) ea_find(eal, &ea_proto_last_modified)->u.ad->data;
+      log("protocol %s of type %s is in state %i (table %s, last modified %t)", name, type, state, table, time);
+    }
+  }
+}
+
+void
+fc_for_dummy_recipient(void *rec)
+{
+  struct lfjour_item *last_up;
+  struct proto_pending_update *pupdate;
+  while (last_up = lfjour_get((struct lfjour_recipient *)rec))
+  {
+    pupdate = SKIP_BACK(struct proto_pending_update, li, last_up);
+    eattr *name = ea_find(pupdate->proto_attr, &ea_proto_name);
+    eattr *state = ea_find(pupdate->proto_attr, &ea_proto_state);
+    if (name && state)
+      log("protocol %s changed state to %i", name->u.ad->data, state->u.i);
+    else
+      log("not found in %i", pupdate->proto_attr);
+    lfjour_release(rec);
+    dummy_log_proto_attr_list();
+  }
+}
+
+void
+create_dummy_recipient(void)
+{
+  struct lfjour_recipient *r = mb_allocz(&root_pool, sizeof(struct lfjour_recipient));
+  r->event = ev_new_init(&root_pool, fc_for_dummy_recipient, r);
+  struct birdloop *loop = birdloop_new(&root_pool, DOMAIN_ORDER(service), 1, "dummy recipient loop");
+  r->target = birdloop_event_list(loop);
+
+  LOCK_DOMAIN(rtable, proto_journal_domain);
+  lfjour_register(proto_journal, r);
+  UNLOCK_DOMAIN(rtable, proto_journal_domain);
+  log("recipient created r %i j %i", r, proto_journal);
+  dummy_log_proto_attr_list();
+}
index ed36f418788daee98536103bf74ff18053932bef..06b0b2b5746a1ca48b15ed4e4745c924f4b14a11 100644 (file)
@@ -172,6 +172,7 @@ struct proto {
   btime last_state_change;             /* Time of last state transition */
   char *last_state_name_announced;     /* Last state name we've announced to the user */
   char *message;                       /* State-change message, allocated from proto_pool */
+  u32 id;                   /* Id of the protocol indexing its position in proto_attributes */
 
   /*
    *   General protocol hooks:
@@ -392,6 +393,28 @@ static inline int proto_is_inactive(struct proto *p)
 }
 
 
+struct proto_attrs {
+  ea_list *_Atomic *attrs;
+  _Atomic u32 length;
+  struct hmap *proto_id_maker;
+};
+
+extern struct lfjour *proto_journal;
+extern struct proto_attrs *proto_attributes;
+
+struct proto_pending_update {
+  LFJOUR_ITEM_INHERIT(li);
+  ea_list *proto_attr;
+  ea_list *old_attr;
+  struct proto *protocol;
+};
+
+void proto_journal_state_changed(ea_list *attr, ea_list *old_attr, struct proto *p);
+ea_list *proto_state_to_eattr(struct proto *p, int old_state, int protocol_deleting);
+void create_dummy_recipient(void);
+void protos_attr_field_grow(void);
+
+
 /*
  *     Debugging flags
  */
index 4f44764c4a9be6708150093ae112b5ad0243bd7a..0be51efb03465921127344caf9d4828752d48dbb 100644 (file)
@@ -1765,6 +1765,52 @@ ea_show_list(struct cli *c, ea_list *eal)
     ea_show(c, &n->attrs[i]);
 }
 
+
+struct ea_class ea_proto_name = {
+  .name = "proto_name",
+  .type = T_STRING,
+};
+
+struct ea_class ea_proto_protocol_name = {
+  .name = "proto_protocol_name",
+  .type = T_STRING,
+};
+
+struct ea_class ea_proto_table = {
+  .name = "proto_table",
+  .type = T_STRING,
+};
+
+struct ea_class ea_proto_state = {
+  .name = "proto_state",
+  .type = T_ENUM_STATE,
+};
+
+struct ea_class ea_proto_old_state = {
+  .name = "proto_old_state",
+  .type = T_ENUM_STATE,
+};
+
+struct ea_class ea_proto_last_modified = {
+  .name = "proto_last_modified",
+  .type = T_BTIME,
+};
+
+struct ea_class ea_proto_info = {
+  .name = "proto_info",
+  .type = T_STRING,
+};
+
+struct ea_class ea_proto_deleted = {
+  .name = "proto_deleted",
+  .type = T_INT,
+};
+
+struct ea_class ea_proto_id = {
+  .name = "proto_id",
+  .type = T_INT,
+};
+
 /**
  * rta_init - initialize route attribute cache
  *
@@ -1809,6 +1855,17 @@ rta_init(void)
   ea_register_init(&ea_gen_mpls_policy);
   ea_register_init(&ea_gen_mpls_class);
   ea_register_init(&ea_gen_mpls_label);
+
+  /* Protocol attributes */
+  ea_register_init(&ea_proto_name);
+  ea_register_init(&ea_proto_protocol_name);
+  ea_register_init(&ea_proto_table);
+  ea_register_init(&ea_proto_state);
+  ea_register_init(&ea_proto_old_state);
+  ea_register_init(&ea_proto_last_modified);
+  ea_register_init(&ea_proto_info);
+  ea_register_init(&ea_proto_id);
+  ea_register_init(&ea_proto_deleted);
 }
 
 /*
index 252c3d73b748f1c6a611d546273074aa7f4ae1fc..a237c6668a47d29655df51d72d96ac61828a6693 100644 (file)
@@ -340,6 +340,8 @@ rtex_export_subscribe(struct rt_exporter *e, struct rt_export_request *r)
 {
   rt_export_change_state(r, BIT32_ALL(TES_DOWN), TES_FEEDING);
 
+  log("subscribe e=%p r=%p", e, r);
+
   ASSERT_DIE(r->pool);
 
   rt_feeder_subscribe(e, &r->feeder);
@@ -357,6 +359,7 @@ rtex_export_subscribe(struct rt_exporter *e, struct rt_export_request *r)
 void
 rtex_export_unsubscribe(struct rt_export_request *r)
 {
+  log("unsubscribe r=%p", r);
   rt_feeder_unsubscribe(&r->feeder);
 
   if (r->cur)
index ec6cb508795d3e99082de1cf8b03b4fc4b748b36..9f9fac8ca1c806bc904d2e4665df4a578a540f7b 100644 (file)
@@ -1954,7 +1954,7 @@ bgp_tx_resend(struct bgp_proto *p, struct bgp_channel *bc)
  */
 
 static void
-bgp_out_item_done(struct lfjour *j, struct lfjour_item *i)
+bgp_out_item_done(struct lfjour *j UNUSED, struct lfjour_item *i UNUSED)
 {}
 
 static struct rt_export_feed *
index d2136ed16f39bc7038660895174a27014615c689..78a14dd97abb1fff5b93769869c4a1572cdb510a 100644 (file)
@@ -28,6 +28,7 @@ proto: mrt_proto ;
 mrt_proto_start: proto_start MRT
 {
   this_proto = proto_config_new(&proto_mrt, $1);
+  this_proto->loop_order = DOMAIN_ORDER(proto);
 };
 
 mrt_proto_item:
index a1b53adfc0a420b77b7f5eb04661b7919dbc7844..49d38080fa2bebdb7e2a4f10e354f69108d256c6 100644 (file)
@@ -271,7 +271,7 @@ mrt_open_file(struct mrt_table_dump_state *s)
     return 0;
   }
 
-  s->file = rf_open(s->pool, name, "a");
+  s->file = rf_open(s->pool, name, RF_APPEND, -1); //TODO: is this correct? Do we want to limit appending file (or does it even make sence for append)? 
   if (!s->file)
   {
     mrt_log(s, "Unable to open MRT file '%s': %m", name);
@@ -359,7 +359,7 @@ mrt_peer_table_dump(struct mrt_table_dump_state *s)
   /* 0 is fake peer for non-BGP routes */
   mrt_peer_table_entry(s, 0, 0, IPA_NONE);
 
-#ifdef CONFIG_BGP
+/*#ifdef CONFIG_BGP
   struct proto *P;
   WALK_LIST(P, proto_list)
     if ((P->proto == &proto_bgp) && (P->proto_state != PS_DOWN))
@@ -367,7 +367,7 @@ mrt_peer_table_dump(struct mrt_table_dump_state *s)
       struct bgp_proto *p = (void *) P;
       mrt_peer_table_entry(s, p->remote_id, p->remote_as, p->remote_ip);
     }
-#endif
+#endif*/
 
   /* Fix Peer Count */
   put_u16(s->buf.start + s->peer_count_offset, s->peer_count);