From b3e13eddb90edbd9b80ea157fbfdcfc27e004317 Mon Sep 17 00:00:00 2001 From: Katerina Kubecova Date: Fri, 31 May 2024 12:27:59 +0200 Subject: [PATCH] proto.c: show protocol uses only proto id and attr table --- filter/data.c | 2 + lib/lockfree.c | 2 + lib/route.h | 5 + lib/type.h | 4 + lib/xmalloc.c | 3 +- nest/proto.c | 223 +++++++++++++++++++++++++++++++++++++++++++-- nest/protocol.h | 23 +++++ nest/rt-attr.c | 57 ++++++++++++ nest/rt-export.c | 3 + proto/bgp/attrs.c | 2 +- proto/mrt/config.Y | 1 + proto/mrt/mrt.c | 6 +- 12 files changed, 319 insertions(+), 12 deletions(-) diff --git a/filter/data.c b/filter/data.c index 7b0f6750..660a8658 100644 --- a/filter/data.c +++ b/filter/data.c @@ -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)); } } diff --git a/lib/lockfree.c b/lib/lockfree.c index 6f8e66b9..e45f7185 100644 --- a/lib/lockfree.c +++ b/lib/lockfree.c @@ -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); diff --git a/lib/route.h b/lib/route.h index 0ef97f01..7087386d 100644 --- a/lib/route.h +++ b/lib/route.h @@ -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. */ diff --git a/lib/type.h b/lib/type.h index 2edaa2e4..97f021bd 100644 --- a/lib/type.h +++ b/lib/type.h @@ -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; diff --git a/lib/xmalloc.c b/lib/xmalloc.c index 38f6d0cf..74348d11 100644 --- a/lib/xmalloc.c +++ b/lib/xmalloc.c @@ -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) diff --git a/nest/proto.c b/nest/proto.c index 3493b239..43f61aec 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -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(); +} diff --git a/nest/protocol.h b/nest/protocol.h index ed36f418..06b0b2b5 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -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 */ diff --git a/nest/rt-attr.c b/nest/rt-attr.c index 4f44764c..0be51efb 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -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); } /* diff --git a/nest/rt-export.c b/nest/rt-export.c index 252c3d73..a237c666 100644 --- a/nest/rt-export.c +++ b/nest/rt-export.c @@ -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) diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index ec6cb508..9f9fac8c 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -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 * diff --git a/proto/mrt/config.Y b/proto/mrt/config.Y index d2136ed1..78a14dd9 100644 --- a/proto/mrt/config.Y +++ b/proto/mrt/config.Y @@ -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: diff --git a/proto/mrt/mrt.c b/proto/mrt/mrt.c index a1b53adf..49d38080 100644 --- a/proto/mrt/mrt.c +++ b/proto/mrt/mrt.c @@ -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);