if (loop != &main_birdloop && recalculate_sk_info)
{
- int size = loop->sock_num * sk_max_dump_len() + 17;
+ int size = loop->sock_num * sk_max_dump_len + 17;
char *new_info = mb_alloc(loop->pool, size);
node *n;
old_info = atomic_load_explicit(&loop->sockets_info, memory_order_relaxed);
atomic_store_explicit(&loop->sockets_info, new_info, memory_order_relaxed);
- synchronize_rcu();
+ synchronize_rcu(); // We are about to free old_info, which might be in use in dumping right now
if (old_info)
mb_free(old_info);
bird_thread_sync_all(&tsd->sync, bird_thread_show, cmd_show_threads_done, "Show Threads");
}
+
+/*
+ sk_dump_all uses cached info, because we need the dupms quickly and locking
+ (especially for thread_group loops) would be too complicated and slow.
+
+ sk_dump_ao_all has a different approach - in each thread we send an event to each loop
+ and dump from the loops. We do this because ao dump changes much more often and caching
+ would be too frequent. This means ao dump is slower than basic socket dump
+ and the basic socket dump should be used for quick debugging.
+*/
+
void
sk_dump_all(struct dump_request *dreq)
{
WALK_TLIST(thread, thr, &group->threads)
WALK_TLIST(birdloop, loop, &thr->loops)
{
+ /* The socket_info might be about to change (and free previous version) right now */
rcu_read_lock();
char *info = atomic_load_explicit(&loop->sockets_info, memory_order_relaxed);
+
+ if (info)
+ RDUMP(info);
rcu_read_unlock();
- if (info)
- RDUMP(info);
}
WALK_TLIST_DELSAFE(thread_group, gpub, &global_thread_group_list)
TG_LOCKED(gpub, group)
{
- WALK_TLIST_DELSAFE(birdloop, loop, &group->loops){
+ WALK_TLIST_DELSAFE(birdloop, loop, &group->loops)
+ {
rcu_read_lock();
char *info = atomic_load_explicit(&loop->sockets_info, memory_order_relaxed);
rcu_read_unlock();
struct bird_show_ao_socket {
struct bird_thread_syncer sync;
struct dump_request *dreq;
- rw_spinlock lock;
+ DOMAIN(rtable) lock;
+ struct pool *pool;
+
_Atomic int dump_finished; // the dump is finished when reached zero
};
_sk_dump_ao_for_loop(struct bird_show_ao_socket *bsas, list sock_list)
{
struct dump_request *dreq = bsas->dreq;
- rws_write_lock(&bsas->lock);
+
WALK_LIST_(node, n, sock_list)
{
sock *s = SKIP_BACK(sock, n, n);
sk_dump_ao_keys(s, dreq);
}
- rws_write_unlock(&bsas->lock);
-
if (atomic_fetch_sub_explicit(&bsas->dump_finished, 1, memory_order_relaxed) == 1)
{
RDUMP("\n");
{
struct sk_dump_ao_event *sdae = (struct sk_dump_ao_event*) data;
_sk_dump_ao_for_loop(sdae->bsas, birdloop_current->sock_list);
- mb_free(sdae);
}
static void
{
WALK_TLIST(birdloop, loop, &this_thread->loops)
{
- birdloop_enter(loop);
- struct sk_dump_ao_event *sdae = mb_allocz(loop->pool, sizeof(struct sk_dump_ao_event));
+ struct sk_dump_ao_event *sdae = mb_allocz(bsas->pool, sizeof(struct sk_dump_ao_event));
sdae->event.hook = sk_dump_ao_for_loop;
sdae->event.data = sdae;
sdae->bsas = bsas;
ev_send_loop(loop, &sdae->event);
- birdloop_leave(loop);
}
}
sk_dump_ao_send_event(struct bird_thread_syncer *sync)
{
SKIP_BACK_DECLARE(struct bird_show_ao_socket, bsas, sync, sync);
+ LOCK_DOMAIN(rtable, bsas->lock);
_sk_dump_ao_send_event(bsas);
+ UNLOCK_DOMAIN(rtable, bsas->lock);
}
static void
{
struct dump_request *dreq = bsas->dreq;
RDUMP("\n");
- mb_free(bsas);
+ DOMAIN(rtable) lock = bsas->lock;
+ LOCK_DOMAIN(rtable, lock);
+ mb_free(bsas->pool);
+ UNLOCK_DOMAIN(rtable, lock);
}
}
void
sk_dump_ao_all(struct dump_request *dreq)
{
- struct bird_show_ao_socket *bsas = mb_allocz(&root_pool, sizeof(struct bird_show_ao_socket));
+ DOMAIN(rtable) lock = DOMAIN_NEW(rtable);
+ LOCK_DOMAIN(rtable, lock);
+
+ pool *pool = rp_new(&root_pool, lock.rtable, "Dump socket TCP-AO");
+
+ struct bird_show_ao_socket *bsas = mb_allocz(pool, sizeof(struct bird_show_ao_socket));
bsas->dreq = dreq;
- rws_init(&bsas->lock);
+ bsas->lock = lock;
+ bsas->pool = pool;
atomic_store_explicit(&bsas->dump_finished, 1, memory_order_relaxed);
RDUMP("TCP-AO listening sockets:\n");
_sk_dump_ao_send_event(bsas);
}
+ UNLOCK_DOMAIN(rtable, lock);
+
bird_thread_sync_all(&bsas->sync, sk_dump_ao_send_event, sk_dump_ao_thread_sync_done, "Show ao sockets");
}
s->iface ? s->iface->name : "none");
}
-uint
-sk_max_dump_len(void)
-{
- uint ret = strlen("(%s, ud=%p, sa=%I, sp=%d, da=%I, dp=%d, tos=%d, ttl=%d, if=%s)\n");
- ret += 3; // max sk_type_name = 5
- ret += 14; // looks like %p size is 16
- ret += (IP6_MAX_TEXT_LENGTH -2) * 2;
- ret += 14 * 4; // %d
- ret += IFNAMSIZ - 2;
- ret++; // terminating zero
- return ret;
-}
+int sk_max_dump_len = sizeof("(%s, ud=%p, sa=%I, sp=%d, da=%I, dp=%d, tos=%d, ttl=%d, if=%s)\n") \
+ + 3 /* max sk_type_name = 5 */ \
+ + 14 /* looks like %p size is 16 */ \
+ + (IP6_MAX_TEXT_LENGTH -2) * 2 \
+ + 14 * 4 /* %d lengths */ \
+ + IFNAMSIZ - 2;
void
sk_dump_to_buffer(buffer *buf, sock *s)