]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Sockets: Make dump sockets dump all sockets again
authorKaterina Kubecova <katerina.kubecova@nic.cz>
Thu, 3 Apr 2025 14:54:16 +0000 (16:54 +0200)
committerMaria Matejka <mq@ucw.cz>
Fri, 9 May 2025 14:30:35 +0000 (16:30 +0200)
Only sockets in main birdloop were dumped. Now, all sockets are dumped.
Because of serialization problems, socket dump is cached for each birdloop
and it is continuously updated. These cached dumps are then just
collected and written out without actually looking at the live data.

sysdep/unix/io-loop.c
sysdep/unix/io-loop.h
sysdep/unix/io.c

index 3be4a4ef6372fd16da6a929a47ba48a48f8dc817..8f3053fb4e66317d5601f1cb19a2278b18ef5fc4 100644 (file)
@@ -392,7 +392,7 @@ sockets_init(struct birdloop *loop)
 }
 
 void
-socket_changed(sock *s)
+socket_changed(struct birdsock *s, bool recalculate_sk_info)
 {
   struct birdloop *loop = s->loop;
   ASSERT_DIE(birdloop_inside(loop));
@@ -400,6 +400,38 @@ socket_changed(sock *s)
   LOOP_TRACE(loop, DL_SOCKETS, "socket %p changed", s);
   loop->sock_changed = 1;
   birdloop_ping(loop);
+
+  if (loop != &main_birdloop && recalculate_sk_info)
+  {
+    int size = loop->sock_num * sk_max_dump_len() + 17;
+    char *new_info = mb_alloc(loop->pool, size);
+
+    node *n;
+    buffer buf = {
+      .start = new_info,
+      .pos = new_info,
+      .end = new_info + size,
+    };
+
+    buffer_print(&buf, "%p ", s);
+
+    WALK_LIST(n, loop->sock_list)
+    {
+      SKIP_BACK_DECLARE(sock, s, n, n);
+      sk_dump_to_buffer(&buf, s);
+    }
+    buf.pos[0] = '\0';
+
+    char *old_info = NULL;
+    if (loop->sockets_info)
+      old_info = atomic_load_explicit(&loop->sockets_info, memory_order_relaxed);
+    atomic_store_explicit(&loop->sockets_info, new_info, memory_order_relaxed);
+
+    synchronize_rcu();
+
+    if (old_info)
+      mb_free(old_info);
+  }
 }
 
 void
@@ -415,7 +447,7 @@ birdloop_add_socket(struct birdloop *loop, sock *s)
   s->loop = loop;
   s->index = -1;
 
-  socket_changed(s);
+  socket_changed(s, true);
 }
 
 extern sock *stored_sock; /* mainloop hack */
@@ -443,7 +475,7 @@ birdloop_remove_socket(struct birdloop *loop, sock *s)
   rem_node(&s->n);
   loop->sock_num--;
 
-  socket_changed(s);
+  socket_changed(s, true);
 
   s->loop = NULL;
   s->index = -1;
@@ -467,7 +499,7 @@ sk_pause_rx(struct birdloop *loop, sock *s)
 {
   ASSERT_DIE(birdloop_inside(loop));
   s->rx_hook = NULL;
-  socket_changed(s);
+  socket_changed(s, false);
 }
 
 void
@@ -476,7 +508,7 @@ sk_resume_rx(struct birdloop *loop, sock *s, int (*hook)(sock *, uint))
   ASSERT_DIE(birdloop_inside(loop));
   ASSERT_DIE(hook);
   s->rx_hook = hook;
-  socket_changed(s);
+  socket_changed(s, false);
 }
 
 static inline uint sk_want_events(sock *s)
@@ -1511,7 +1543,6 @@ bird_thread_sync_all(struct bird_thread_syncer *sync,
   UNLOCK_DOMAIN(control, sync->lock);
 }
 
-
 struct bird_thread_show_data {
   struct bird_thread_syncer sync;
   cli *cli;
@@ -1671,6 +1702,111 @@ cmd_show_threads(int show_loops)
   bird_thread_sync_all(&tsd->sync, bird_thread_show, cmd_show_threads_done, "Show Threads");
 }
 
+struct bird_thread_show_socket {
+  struct bird_thread_syncer sync;
+  struct dump_request *dreq;
+};
+
+void
+sk_dump_all(struct dump_request *dreq)
+{
+  RDUMP("Open sockets:\n");
+  dreq->indent += 3;
+
+  node *n;
+  sock *s;
+
+  /* Dump sockets in main_birdloop */
+  WALK_LIST(n, main_birdloop.sock_list)
+  {
+    s = SKIP_BACK(sock, n, n);
+    RDUMP("%p ", s);
+    sk_dump(dreq, &s->r);
+  }
+
+  /* The rest of birdloops have the socket info cached */
+  WALK_TLIST(thread_group, gpub, &global_thread_group_list)
+    TG_LOCKED(gpub, group)
+      WALK_TLIST(thread, thr, &group->threads)
+        WALK_TLIST(birdloop, loop, &thr->loops)
+        {
+          rcu_read_lock();
+            char *info = atomic_load_explicit(&loop->sockets_info, memory_order_relaxed);
+          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){
+      rcu_read_lock();
+        char *info = atomic_load_explicit(&loop->sockets_info, memory_order_relaxed);
+      rcu_read_unlock();
+      if (info)
+        RDUMP(info);
+    }
+  }
+  dreq->indent -= 3;
+  RDUMP("\n");
+}
+
+static void
+_sk_dump_ao_for_thread(struct dump_request *dreq, list sock_list)
+{
+  WALK_LIST_(node, n, sock_list)
+  {
+    sock *s = SKIP_BACK(sock, n, n);
+
+    /* Skip non TCP-AO sockets / not supported */
+    if (sk_get_ao_info(s, &(struct ao_info){}) < 0)
+      continue;
+
+    RDUMP("\n%p", s);
+    sk_dump(dreq, &s->r);
+    sk_dump_ao_info(s, dreq);
+    sk_dump_ao_keys(s, dreq);
+  }
+}
+
+static void
+sk_dump_ao_for_thread(struct bird_thread_syncer *sync)
+{
+  SKIP_BACK_DECLARE(struct bird_thread_show_socket, tss, sync, sync);
+  struct dump_request *dreq = tss->dreq;
+
+  WALK_TLIST(birdloop, loop, &this_thread->loops)
+  {
+    birdloop_enter(loop);
+    _sk_dump_ao_for_thread(dreq, loop->sock_list);
+    birdloop_leave(loop);
+  }
+}
+
+void
+sk_dump_ao_all(struct dump_request *dreq)
+{
+  struct bird_thread_show_socket *tss = mb_allocz(&root_pool, sizeof(struct bird_thread_show_socket));
+  tss->dreq = dreq;
+
+  RDUMP("TCP-AO listening sockets:\n");
+  _sk_dump_ao_for_thread(dreq, main_birdloop.sock_list);
+
+  WALK_TLIST(thread_group, gpub, &global_thread_group_list)
+  TG_LOCKED(gpub, group)
+  {
+    WALK_TLIST(birdloop, loop, &group->loops)
+    {
+      birdloop_enter(loop);
+      _sk_dump_ao_for_thread(dreq, loop->sock_list);
+      birdloop_leave(loop);
+    }
+  }
+  bird_thread_sync_all(&tss->sync, sk_dump_ao_for_thread, NULL, "Show ao sockets");
+}
+
+
 bool task_still_in_limit(void)
 {
   static u64 main_counter = 0;
index 6681f4d6d591370a3606a3a3020887222dbf9dc7..7123456671437a7d2ddbf0f2a25677c45740c5a2 100644 (file)
@@ -21,13 +21,16 @@ struct pfd {
   BUFFER(struct birdloop *) loop;
 };
 
+uint sk_max_dump_len(void);
+void sk_dump_to_buffer(buffer *buf, sock *s);
 void sockets_prepare(struct birdloop *, struct pfd *);
-void socket_changed(struct birdsock *);
+void socket_changed(struct birdsock *, bool recalculate_sk_info);
 
 void pipe_new(struct pipe *);
 void pipe_pollin(struct pipe *, struct pfd *);
 void pipe_drain(struct pipe *);
 void pipe_kick(struct pipe *);
+void sk_dump(struct dump_request *dreq, resource *r);
 
 #define TIME_BY_SEC_SIZE       16
 
@@ -58,6 +61,7 @@ struct birdloop
   struct birdsock *sock_active;
   int sock_num;
   uint sock_changed:1;
+  char *_Atomic sockets_info;
 
   uint ping_pending;
 
index 5b9c2e0e636d8dcbbba93f00887f288cffb99b38..aa43256625eeb3546be9c9a6b369072f76410246 100644 (file)
@@ -348,6 +348,9 @@ dump_to_file_write(struct dump_request *dr, const char *fmt, ...)
       dump_to_file_flush(req);
   }
 
+  if (req->fd < 0)
+    return;
+
   bug("Too long dump call");
 }
 
@@ -1212,7 +1215,7 @@ sk_reallocate(sock *s)
   sk_alloc_bufs(s);
 }
 
-static void
+void
 sk_dump(struct dump_request *dreq, resource *r)
 {
   sock *s = (sock *) r;
@@ -1230,6 +1233,36 @@ sk_dump(struct dump_request *dreq, resource *r)
        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;
+}
+
+void
+sk_dump_to_buffer(buffer *buf, sock *s)
+{
+  static char *sk_type_names[] = { "TCP<", "TCP>", "TCP", "UDP", NULL, "IP", NULL, "MAGIC", "UNIX<", "UNIX", "SSH>", "SSH", "DEL!" };
+
+  buffer_print(buf, "(%s, ud=%p, sa=%I, sp=%d, da=%I, dp=%d, tos=%d, ttl=%d, if=%s)\n",
+       sk_type_names[s->type],
+       s->data,
+       s->saddr,
+       s->sport,
+       s->daddr,
+       s->dport,
+       s->tos,
+       s->ttl,
+       s->iface ? s->iface->name : "none");
+}
+
 static struct resclass sk_class = {
   "Socket",
   sizeof(sock),
@@ -2158,7 +2191,7 @@ sk_send(sock *s, unsigned len)
 
   int e = sk_maybe_write(s);
   if (e == 0) /* Trigger thread poll reload to poll this socket's write. */
-    socket_changed(s);
+    socket_changed(s, false);
 
   return e;
 }
@@ -2407,48 +2440,6 @@ sk_err(sock *s, int revents)
   tmp_flush();
 }
 
-
-/* FIXME: these two functions should actually call bird_thread_sync_all()
- * to get threads from all loops. Now they dump just mainloop. */
-
-void
-sk_dump_all(struct dump_request *dreq)
-{
-  node *n;
-  sock *s;
-
-  RDUMP("Open sockets:\n");
-  dreq->indent += 3;
-  WALK_LIST(n, main_birdloop.sock_list)
-  {
-    s = SKIP_BACK(sock, n, n);
-    RDUMP("%p ", s);
-    sk_dump(dreq, &s->r);
-  }
-  dreq->indent -= 3;
-  RDUMP("\n");
-}
-
-void
-sk_dump_ao_all(struct dump_request *dreq)
-{
-  RDUMP("TCP-AO listening sockets:\n");
-  WALK_LIST_(node, n, main_birdloop.sock_list)
-  {
-    sock *s = SKIP_BACK(sock, n, n);
-
-    /* Skip non TCP-AO sockets / not supported */
-    if (sk_get_ao_info(s, &(struct ao_info){}) < 0)
-      continue;
-
-    RDUMP("\n%p", s);
-    sk_dump(dreq, &s->r);
-    sk_dump_ao_info(s, dreq);
-    sk_dump_ao_keys(s, dreq);
-  }
-}
-
-
 /*
  *     Internal event log and watchdog
  */