*/
static void zserv_client_free(struct zserv *client)
{
+ if (client == NULL)
+ return;
+
hook_call(zserv_client_close, client);
/* Close file descriptor. */
nroutes = rib_score_proto(client->proto, client->instance);
zlog_notice(
- "client %d disconnected. %lu %s routes removed from the rib",
+ "client %d disconnected %lu %s routes removed from the rib",
client->sock, nroutes,
zebra_route_string(client->proto));
client->sock = -1;
pthread_mutex_init(&client->ibuf_mtx, NULL);
pthread_mutex_init(&client->obuf_mtx, NULL);
client->wb = buffer_new(0);
+ TAILQ_INIT(&(client->gr_info_queue));
atomic_store_explicit(&client->connect_time, (uint32_t) monotime(NULL),
memory_order_relaxed);
return buf;
}
+/* Display client info details */
static void zebra_show_client_detail(struct vty *vty, struct zserv *client)
{
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;
uint32_t last_read_cmd, last_write_cmd;
+ struct client_gr_info *info = NULL;
vty_out(vty, "Client: %s", zebra_route_string(client->proto));
if (client->instance)
vty_out(vty, "MAC-IP add notifications: %d\n", client->macipadd_cnt);
vty_out(vty, "MAC-IP delete notifications: %d\n", client->macipdel_cnt);
+ TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) {
+ vty_out(vty, "VRF : %s\n", vrf_id_to_name(info->vrf_id));
+ vty_out(vty, "Capabilities : ");
+ switch (info->capabilities) {
+ case ZEBRA_CLIENT_GR_CAPABILITIES:
+ vty_out(vty, "Graceful Restart\n");
+ break;
+ case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE:
+ case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING:
+ case ZEBRA_CLIENT_GR_DISABLE:
+ case ZEBRA_CLIENT_RIB_STALE_TIME:
+ vty_out(vty, "None\n");
+ break;
+ }
+ }
+
#if defined DEV_BUILD
vty_out(vty, "Input Fifo: %zu:%zu Output Fifo: %zu:%zu\n",
client->ibuf_fifo->count, client->ibuf_fifo->max_count,
client->obuf_fifo->count, client->obuf_fifo->max_count);
#endif
vty_out(vty, "\n");
+}
+
+/* Display stale client information */
+static void zebra_show_stale_client_detail(struct vty *vty,
+ struct zserv *client)
+{
+ char buf[PREFIX2STR_BUFFER];
+ struct tm *tm;
+ struct timeval tv;
+ time_t uptime;
+ struct client_gr_info *info = NULL;
+ struct zserv *s = NULL;
+
+ if (client->instance)
+ vty_out(vty, " Instance: %d", client->instance);
+
+ TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) {
+ vty_out(vty, "VRF : %s\n", vrf_id_to_name(info->vrf_id));
+ vty_out(vty, "Capabilities : ");
+ switch (info->capabilities) {
+ case ZEBRA_CLIENT_GR_CAPABILITIES:
+ vty_out(vty, "Graceful Restart\n");
+ break;
+ case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE:
+ case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING:
+ case ZEBRA_CLIENT_GR_DISABLE:
+ case ZEBRA_CLIENT_RIB_STALE_TIME:
+ vty_out(vty, "None\n");
+ break;
+ }
+
+ if (ZEBRA_CLIENT_GR_ENABLED(info->capabilities)) {
+ if (info->stale_client_ptr) {
+ s = (struct zserv *)(info->stale_client_ptr);
+ uptime = monotime(&tv);
+ uptime -= s->restart_time;
+ tm = gmtime(&uptime);
+ vty_out(vty, "Last restart time : ");
+ if (uptime < ONE_DAY_SECOND)
+ vty_out(vty, "%02d:%02d:%02d",
+ tm->tm_hour, tm->tm_min,
+ tm->tm_sec);
+ else if (uptime < ONE_WEEK_SECOND)
+ vty_out(vty, "%dd%02dh%02dm",
+ tm->tm_yday, tm->tm_hour,
+ tm->tm_min);
+ else
+ vty_out(vty, "%02dw%dd%02dh",
+ tm->tm_yday / 7,
+ tm->tm_yday - ((tm->tm_yday / 7)
+ * 7),
+ tm->tm_hour);
+ vty_out(vty, " ago\n");
+
+ vty_out(vty, "Stalepath removal time: %d sec\n",
+ info->stale_removal_time);
+ if (info->t_stale_removal) {
+ vty_out(vty,
+ "Stale delete timer: %ld sec\n",
+ thread_timer_remain_second(
+ info->t_stale_removal));
+ }
+ }
+ vty_out(vty, "Current AFI : %d\n", info->current_afi);
+ if (info->current_prefix) {
+ prefix2str(info->current_prefix, buf,
+ sizeof(buf));
+ vty_out(vty, "Current prefix : %s\n", buf);
+ }
+ }
+ }
+ vty_out(vty, "\n");
return;
}
struct listnode *node;
struct zserv *client;
- for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client))
+ for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) {
zebra_show_client_detail(vty, client);
+ vty_out(vty, "Stale Client Information\n");
+ vty_out(vty, "------------------------\n");
+ zebra_show_stale_client_detail(vty, client);
+ }
return CMD_SUCCESS;
}
{
/* Client list init. */
zrouter.client_list = list_new();
+ zrouter.stale_client_list = list_new();
/* Misc init. */
zsock = -1;
#define ZEBRA_RMAP_DEFAULT_UPDATE_TIMER 5 /* disabled by default */
+
+/* Stale route marker timer */
+#define ZEBRA_DEFAULT_STALE_UPDATE_DELAY 1
+
+/* Count of stale routes processed in timer context */
+#define ZEBRA_MAX_STALE_ROUTE_COUNT 50000
+
+/* Graceful Restart information */
+struct client_gr_info {
+ /* VRF for which GR enabled */
+ vrf_id_t vrf_id;
+
+ /* AFI */
+ afi_t current_afi;
+
+ /* Stale time and GR cap */
+ uint32_t stale_removal_time;
+ enum zserv_client_capabilities capabilities;
+
+ /* GR commands */
+ bool delete;
+ bool gr_enable;
+ bool stale_client;
+
+ /* Route sync and enable flags for AFI/SAFI */
+ bool af_enabled[AFI_MAX][SAFI_MAX];
+ bool route_sync[AFI_MAX][SAFI_MAX];
+
+ /* Book keeping */
+ struct prefix *current_prefix;
+ void *stale_client_ptr;
+ struct thread *t_stale_removal;
+
+ TAILQ_ENTRY(client_gr_info) gr_info;
+};
+
/* Client structure. */
struct zserv {
/* Client pthread */
_Atomic uint32_t last_read_cmd;
/* command code of last message written */
_Atomic uint32_t last_write_cmd;
+
+ /*
+ * Number of instances configured with
+ * graceful restart
+ */
+ uint32_t gr_instance_count;
+ time_t restart_time;
+
+ /*
+ * Graceful restart information for
+ * each instance
+ */
+ TAILQ_HEAD(info_list, client_gr_info) gr_info_queue;
};
#define ZAPI_HANDLER_ARGS \
*/
extern struct zserv *zserv_find_client(uint8_t proto, unsigned short instance);
-
/*
* Close a client.
*
*/
extern void zserv_close_client(struct zserv *client);
-
/*
* Log a ZAPI message hexdump.
*