#include "zebra/zapi_msg.h" /* for zserv_handle_commands */
#include "zebra/zebra_vrf.h" /* for zebra_vrf_lookup_by_id, zvrf */
#include "zebra/zserv.h" /* for zserv */
+#include "zebra/zebra_router.h"
#include "zebra/zebra_errors.h" /* for error messages */
/* clang-format on */
/* privileges */
extern struct zebra_privs_t zserv_privs;
+/* The listener socket for clients connecting to us */
+static int zsock;
+
/*
* Client thread events.
*
uint32_t p2p;
struct zmsghdr hdr;
- p2p_orig = atomic_load_explicit(&zebrad.packets_to_process,
+ p2p_orig = atomic_load_explicit(&zrouter.packets_to_process,
memory_order_relaxed);
cache = stream_fifo_new();
p2p = p2p_orig;
}
/* Debug packet information. */
- if (IS_ZEBRA_DEBUG_EVENT)
- zlog_debug("zebra message comes from socket [%d]",
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("zebra message[%s:%u:%u] comes from socket [%d]",
+ zserv_command_string(hdr.command),
+ hdr.vrf_id, hdr.length,
sock);
if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV)
}
if (IS_ZEBRA_DEBUG_PACKET)
- zlog_debug("Read %d packets", p2p_orig - p2p);
+ zlog_debug("Read %d packets from client: %s", p2p_orig - p2p,
+ zebra_route_string(client->proto));
/* Reschedule ourselves */
zserv_client_event(client, ZSERV_CLIENT_READ);
* with the message is executed. This proceeds until there are no more messages,
* an error occurs, or the processing limit is reached.
*
- * The client's I/O thread can push at most zebrad.packets_to_process messages
+ * The client's I/O thread can push at most zrouter.packets_to_process messages
* onto the input buffer before notifying us there are packets to read. As long
- * as we always process zebrad.packets_to_process messages here, then we can
+ * as we always process zrouter.packets_to_process messages here, then we can
* rely on the read thread to handle queuing this task enough times to process
* everything on the input queue.
*/
struct zserv *client = THREAD_ARG(thread);
struct stream *msg;
struct stream_fifo *cache = stream_fifo_new();
-
- uint32_t p2p = zebrad.packets_to_process;
+ uint32_t p2p = zrouter.packets_to_process;
+ bool need_resched = false;
pthread_mutex_lock(&client->ibuf_mtx);
{
}
msg = NULL;
+
+ /* Need to reschedule processing work if there are still
+ * packets in the fifo.
+ */
+ if (stream_fifo_head(client->ibuf_fifo))
+ need_resched = true;
}
pthread_mutex_unlock(&client->ibuf_mtx);
stream_fifo_free(cache);
+ /* Reschedule ourselves if necessary */
+ if (need_resched)
+ zserv_event(client, ZSERV_PROCESS_MESSAGES);
+
return 0;
}
pthread_mutex_destroy(&client->ibuf_mtx);
/* Free bitmaps. */
- for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++) {
for (int i = 0; i < ZEBRA_ROUTE_MAX; i++)
vrf_bitmap_free(client->redist[afi][i]);
- vrf_bitmap_free(client->redist_default);
- vrf_bitmap_free(client->ifinfo);
+ vrf_bitmap_free(client->redist_default[afi]);
+ }
vrf_bitmap_free(client->ridinfo);
XFREE(MTYPE_TMP, client);
zlog_debug("Closing client '%s'",
zebra_route_string(client->proto));
- thread_cancel_event(zebrad.master, client);
+ thread_cancel_event(zrouter.master, client);
THREAD_OFF(client->t_cleanup);
+ THREAD_OFF(client->t_process);
/* destroy pthread */
frr_pthread_destroy(client->pthread);
client->pthread = NULL;
/* remove from client list */
- listnode_delete(zebrad.client_list, client);
+ listnode_delete(zrouter.client_list, client);
/* delete client */
zserv_client_free(client);
client->wb = buffer_new(0);
/* Set table number. */
- client->rtm_table = zebrad.rtm_table_default;
+ client->rtm_table = zrouter.rtm_table_default;
atomic_store_explicit(&client->connect_time, (uint32_t) monotime(NULL),
memory_order_relaxed);
/* Initialize flags */
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (afi = AFI_IP; afi < AFI_MAX; afi++) {
for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
client->redist[afi][i] = vrf_bitmap_init();
- client->redist_default = vrf_bitmap_init();
- client->ifinfo = vrf_bitmap_init();
+ client->redist_default[afi] = vrf_bitmap_init();
+ }
client->ridinfo = vrf_bitmap_init();
/* by default, it's not a synchronous client */
client->is_synchronous = 0;
/* Add this client to linked list. */
- listnode_add(zebrad.client_list, client);
+ listnode_add(zrouter.client_list, client);
struct frr_pthread_attr zclient_pthr_attrs = {
.start = frr_pthread_attr_default.start,
frr_pthread_new(&zclient_pthr_attrs, "Zebra API client thread",
"zebra_apic");
- zebra_vrf_update_all(client);
-
/* start read loop */
zserv_client_event(client, ZSERV_CLIENT_READ);
return 0;
}
+void zserv_close(void)
+{
+ /*
+ * On shutdown, let's close the socket down
+ * so that long running processes of killing the
+ * routing table doesn't leave us in a bad
+ * state where a client tries to reconnect
+ */
+ close(zsock);
+ zsock = -1;
+}
+
void zserv_start(char *path)
{
int ret;
old_mask = umask(0077);
/* Make UNIX domain socket. */
- zebrad.sock = socket(sa.ss_family, SOCK_STREAM, 0);
- if (zebrad.sock < 0) {
+ zsock = socket(sa.ss_family, SOCK_STREAM, 0);
+ if (zsock < 0) {
flog_err_sys(EC_LIB_SOCKET, "Can't create zserv socket: %s",
safe_strerror(errno));
return;
}
if (sa.ss_family != AF_UNIX) {
- sockopt_reuseaddr(zebrad.sock);
- sockopt_reuseport(zebrad.sock);
+ sockopt_reuseaddr(zsock);
+ sockopt_reuseport(zsock);
} else {
struct sockaddr_un *suna = (struct sockaddr_un *)&sa;
if (suna->sun_path[0])
}
frr_elevate_privs(&zserv_privs) {
- setsockopt_so_recvbuf(zebrad.sock, 1048576);
- setsockopt_so_sendbuf(zebrad.sock, 1048576);
+ setsockopt_so_recvbuf(zsock, 1048576);
+ setsockopt_so_sendbuf(zsock, 1048576);
}
frr_elevate_privs((sa.ss_family != AF_UNIX) ? &zserv_privs : NULL) {
- ret = bind(zebrad.sock, (struct sockaddr *)&sa, sa_len);
+ ret = bind(zsock, (struct sockaddr *)&sa, sa_len);
}
if (ret < 0) {
flog_err_sys(EC_LIB_SOCKET, "Can't bind zserv socket on %s: %s",
path, safe_strerror(errno));
- close(zebrad.sock);
- zebrad.sock = -1;
+ close(zsock);
+ zsock = -1;
return;
}
- ret = listen(zebrad.sock, 5);
+ ret = listen(zsock, 5);
if (ret < 0) {
flog_err_sys(EC_LIB_SOCKET,
"Can't listen to zserv socket %s: %s", path,
safe_strerror(errno));
- close(zebrad.sock);
- zebrad.sock = -1;
+ close(zsock);
+ zsock = -1;
return;
}
{
switch (event) {
case ZSERV_ACCEPT:
- thread_add_read(zebrad.master, zserv_accept, NULL, zebrad.sock,
+ thread_add_read(zrouter.master, zserv_accept, NULL, zsock,
NULL);
break;
case ZSERV_PROCESS_MESSAGES:
- thread_add_event(zebrad.master, zserv_process_messages, client,
- 0, NULL);
+ thread_add_event(zrouter.master, zserv_process_messages, client,
+ 0, &client->t_process);
break;
case ZSERV_HANDLE_CLIENT_FAIL:
- thread_add_event(zebrad.master, zserv_handle_client_fail,
+ thread_add_event(zrouter.master, zserv_handle_client_fail,
client, 0, &client->t_cleanup);
}
}
char cbuf[ZEBRA_TIME_BUF], rbuf[ZEBRA_TIME_BUF];
char wbuf[ZEBRA_TIME_BUF], nhbuf[ZEBRA_TIME_BUF], mbuf[ZEBRA_TIME_BUF];
time_t connect_time, last_read_time, last_write_time;
- uint16_t last_read_cmd, last_write_cmd;
+ uint32_t last_read_cmd, last_write_cmd;
vty_out(vty, "Client: %s", zebra_route_string(client->proto));
if (client->instance)
client->ifdel_cnt);
vty_out(vty, "BFD peer %-12d%-12d%-12d\n", client->bfd_peer_add_cnt,
client->bfd_peer_upd8_cnt, client->bfd_peer_del_cnt);
+ vty_out(vty, "NHT v4 %-12d%-12d%-12d\n",
+ client->v4_nh_watch_add_cnt, 0, client->v4_nh_watch_rem_cnt);
+ vty_out(vty, "NHT v6 %-12d%-12d%-12d\n",
+ client->v6_nh_watch_add_cnt, 0, client->v6_nh_watch_rem_cnt);
vty_out(vty, "Interface Up Notifications: %d\n", client->ifup_cnt);
vty_out(vty, "Interface Down Notifications: %d\n", client->ifdown_cnt);
vty_out(vty, "VNI add notifications: %d\n", client->vniadd_cnt);
struct listnode *node, *nnode;
struct zserv *client;
- for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) {
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
if (client->proto == proto && client->instance == instance)
return client;
}
struct listnode *node;
struct zserv *client;
- for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client))
+ for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client))
zebra_show_client_detail(vty, client);
return CMD_SUCCESS;
vty_out(vty,
"--------------------------------------------------------------------------------\n");
- for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client))
+ for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client))
zebra_show_client_brief(vty, client);
vty_out(vty, "Routes column shows (added+updated)/deleted\n");
void zserv_init(void)
{
/* Client list init. */
- zebrad.client_list = list_new();
+ zrouter.client_list = list_new();
/* Misc init. */
- zebrad.sock = -1;
+ zsock = -1;
install_element(ENABLE_NODE, &show_zebra_client_cmd);
install_element(ENABLE_NODE, &show_zebra_client_summary_cmd);