0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-23 02:01:55 +00:00

proto.c: show protocol uses only proto id and attr table

This commit is contained in:
Katerina Kubecova 2024-05-31 12:27:59 +02:00
parent f715b3decc
commit b3e13eddb9
12 changed files with 319 additions and 12 deletions

View File

@ -650,6 +650,8 @@ mem_hash_mix_f_val(u64 *h, struct f_val *v)
case T_NEXTHOP_LIST: case T_NEXTHOP_LIST:
case T_HOSTENTRY: case T_HOSTENTRY:
case T_IFACE: case T_IFACE:
case T_ENUM_STATE:
case T_BTIME:
bug("Invalid type %s in f_val hashing", f_type_name(v->type)); bug("Invalid type %s in f_val hashing", f_type_name(v->type));
} }
} }

View File

@ -219,6 +219,7 @@ void lfjour_release(struct lfjour_recipient *r)
void void
lfjour_announce_now(struct lfjour *j) lfjour_announce_now(struct lfjour *j)
{ {
log("announce now %i", j);
ASSERT_DIE(birdloop_inside(j->loop)); ASSERT_DIE(birdloop_inside(j->loop));
settle_cancel(&j->announce_timer); settle_cancel(&j->announce_timer);
ev_postpone(&j->announce_kick_event); ev_postpone(&j->announce_kick_event);
@ -226,6 +227,7 @@ lfjour_announce_now(struct lfjour *j)
if (EMPTY_TLIST(lfjour_recipient, &j->recipients)) if (EMPTY_TLIST(lfjour_recipient, &j->recipients))
return lfjour_schedule_cleanup(j); return lfjour_schedule_cleanup(j);
log("walk recipient list");
WALK_TLIST(lfjour_recipient, r, &j->recipients) WALK_TLIST(lfjour_recipient, r, &j->recipients)
if (r->event) if (r->event)
ev_send(r->target, r->event); ev_send(r->target, r->event);

View File

@ -377,6 +377,8 @@ void ea_list_copy(ea_list *dest, ea_list *src, uint size);
#define EA_LITERAL_GENERIC(_id, _type, _flags, ...) \ #define EA_LITERAL_GENERIC(_id, _type, _flags, ...) \
((eattr) { .id = _id, .type = _type, .flags = _flags, __VA_ARGS__ }) ((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 * static inline eattr *
ea_set_attr(ea_list **to, eattr a) 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, extern struct ea_class ea_gen_mpls_label,
ea_gen_mpls_policy, ea_gen_mpls_class; 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. /* Source: An old method to devise the route source protocol and kind.
* To be superseded in a near future by something more informative. */ * To be superseded in a near future by something more informative. */

View File

@ -113,6 +113,10 @@ enum btype {
T_SET = 0x80, T_SET = 0x80,
T_PREFIX_SET = 0x84, T_PREFIX_SET = 0x84,
/* protocol */
T_ENUM_STATE = 0xd1,
T_BTIME = 0xd4,
} PACKED; } PACKED;
typedef enum btype btype; typedef enum btype btype;

View File

@ -65,9 +65,8 @@ xmalloc(uint size)
void * void *
xrealloc(void *ptr, uint size) xrealloc(void *ptr, uint size)
{ {
void *p = realloc(ptr, size);
MINFO(ptr, 0, 2); MINFO(ptr, 0, 2);
void *p = realloc(ptr, size);
MINFO(p, size, 3); MINFO(p, size, 3);
if (p) if (p)

View File

@ -28,6 +28,9 @@ static TLIST_LIST(proto) global_proto_list;
static list STATIC_LIST_INIT(protocol_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 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); }) #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" }; static char *c_states[] = { "DOWN", "START", "UP", "STOP", "RESTART" };
extern struct protocol proto_unix_iface; extern struct protocol proto_unix_iface;
struct proto_attrs *proto_attributes;
static void proto_rethink_goal(struct proto *p); static void proto_rethink_goal(struct proto *p);
static char *proto_state_name(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); rt_export_refeed(&c->out_req, rfr);
} }
void init_proto_journal(void);
static inline int proto_is_done(struct proto *p) static inline int proto_is_done(struct proto *p)
{ return (p->proto_state == PS_DOWN) && proto_is_inactive(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); struct proto *p = pr->init(c);
p->loop = &main_birdloop; p->loop = &main_birdloop;
int old_state = p->proto_state;
p->proto_state = PS_DOWN; p->proto_state = PS_DOWN;
p->last_state_change = current_time(); p->last_state_change = current_time();
p->vrf = c->vrf; p->vrf = c->vrf;
@ -1244,6 +1251,16 @@ proto_init(struct proto_config *c, struct proto *after)
PD(p, "Initializing%s", p->disabled ? " [disabled]" : ""); 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; return p;
} }
@ -1665,6 +1682,9 @@ proto_rethink_goal(struct proto *p)
struct proto_config *nc = p->cf_new; struct proto_config *nc = p->cf_new;
struct proto *after = p->n.prev; 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); DBG("%s has shut down for reconfiguration\n", p->name);
p->cf->proto = NULL; p->cf->proto = NULL;
config_del_obstacle(p->cf->global); 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"); proto_pool = rp_new(&root_pool, the_bird_domain.the_bird, "Protocols");
init_proto_journal();
create_dummy_recipient();
protos_build_gen(); protos_build_gen();
} }
@ -2254,8 +2276,14 @@ proto_notify_state(struct proto *p, uint state)
if (state == ps) if (state == ps)
return; return;
log("try to change state");
int old_state = p->proto_state;
p->proto_state = state; p->proto_state = state;
p->last_state_change = current_time(); 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) 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 static void
channel_show_stats(struct channel *c) 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", cli_msg(-2002, "%-10s %-10s %-10s %-6s %-12s %s",
"Name", "Proto", "Table", "State", "Since", "Info"); "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; buf[0] = 0;
if (p->proto->get_status) if (p->proto->get_status)
p->proto->get_status(p, buf); 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", cli_msg(-1002, "%-10s %-10s %-10s %-6s %-12s %s",
p->name, name,
p->proto->name, proto,
p->main_channel ? p->main_channel->table->name : "---", table,
proto_state_name(p), proto_state_name_from_int(state),
tbuf, tbuf,
buf); info);
if (verbose) if (verbose)
{ {
@ -2724,3 +2776,162 @@ proto_iterate_named(struct symbol *sym, struct protocol *proto, struct proto *ol
return NULL; 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();
}

View File

@ -172,6 +172,7 @@ struct proto {
btime last_state_change; /* Time of last state transition */ btime last_state_change; /* Time of last state transition */
char *last_state_name_announced; /* Last state name we've announced to the user */ char *last_state_name_announced; /* Last state name we've announced to the user */
char *message; /* State-change message, allocated from proto_pool */ char *message; /* State-change message, allocated from proto_pool */
u32 id; /* Id of the protocol indexing its position in proto_attributes */
/* /*
* General protocol hooks: * 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 * Debugging flags
*/ */

View File

@ -1765,6 +1765,52 @@ ea_show_list(struct cli *c, ea_list *eal)
ea_show(c, &n->attrs[i]); 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 * 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_policy);
ea_register_init(&ea_gen_mpls_class); ea_register_init(&ea_gen_mpls_class);
ea_register_init(&ea_gen_mpls_label); 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);
} }
/* /*

View 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); rt_export_change_state(r, BIT32_ALL(TES_DOWN), TES_FEEDING);
log("subscribe e=%p r=%p", e, r);
ASSERT_DIE(r->pool); ASSERT_DIE(r->pool);
rt_feeder_subscribe(e, &r->feeder); rt_feeder_subscribe(e, &r->feeder);
@ -357,6 +359,7 @@ rtex_export_subscribe(struct rt_exporter *e, struct rt_export_request *r)
void void
rtex_export_unsubscribe(struct rt_export_request *r) rtex_export_unsubscribe(struct rt_export_request *r)
{ {
log("unsubscribe r=%p", r);
rt_feeder_unsubscribe(&r->feeder); rt_feeder_unsubscribe(&r->feeder);
if (r->cur) if (r->cur)

View File

@ -1954,7 +1954,7 @@ bgp_tx_resend(struct bgp_proto *p, struct bgp_channel *bc)
*/ */
static void 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 * static struct rt_export_feed *

View File

@ -28,6 +28,7 @@ proto: mrt_proto ;
mrt_proto_start: proto_start MRT mrt_proto_start: proto_start MRT
{ {
this_proto = proto_config_new(&proto_mrt, $1); this_proto = proto_config_new(&proto_mrt, $1);
this_proto->loop_order = DOMAIN_ORDER(proto);
}; };
mrt_proto_item: mrt_proto_item:

View File

@ -271,7 +271,7 @@ mrt_open_file(struct mrt_table_dump_state *s)
return 0; 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) if (!s->file)
{ {
mrt_log(s, "Unable to open MRT file '%s': %m", name); 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 */ /* 0 is fake peer for non-BGP routes */
mrt_peer_table_entry(s, 0, 0, IPA_NONE); mrt_peer_table_entry(s, 0, 0, IPA_NONE);
#ifdef CONFIG_BGP /*#ifdef CONFIG_BGP
struct proto *P; struct proto *P;
WALK_LIST(P, proto_list) WALK_LIST(P, proto_list)
if ((P->proto == &proto_bgp) && (P->proto_state != PS_DOWN)) 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; struct bgp_proto *p = (void *) P;
mrt_peer_table_entry(s, p->remote_id, p->remote_as, p->remote_ip); mrt_peer_table_entry(s, p->remote_id, p->remote_as, p->remote_ip);
} }
#endif #endif*/
/* Fix Peer Count */ /* Fix Peer Count */
put_u16(s->buf.start + s->peer_count_offset, s->peer_count); put_u16(s->buf.start + s->peer_count_offset, s->peer_count);