From 4e0b5b31b795815e853ec665e651743b280dfc9d Mon Sep 17 00:00:00 2001 From: Mark Stapp Date: Tue, 14 Apr 2020 10:45:09 -0400 Subject: [PATCH] lib,zebra: add a session id for zapi sessions Distinguish zapi sessions, for daemons who use more than one, by adding a session id. The tuple of proto + instance is not adequate to support clients who use multiple zapi sessions. Include the id in the client show output if it's present. Add a bit of info about this to the developer doc. Signed-off-by: Mark Stapp --- doc/developer/zebra.rst | 21 ++++++++++++++------- lib/zclient.c | 1 + lib/zclient.h | 3 +++ zebra/zapi_msg.c | 3 +++ zebra/zserv.c | 24 +++++++++++++++++++----- zebra/zserv.h | 21 ++++++++++++++++++++- 6 files changed, 60 insertions(+), 13 deletions(-) diff --git a/doc/developer/zebra.rst b/doc/developer/zebra.rst index e3526d1843..e2f887ef28 100644 --- a/doc/developer/zebra.rst +++ b/doc/developer/zebra.rst @@ -9,13 +9,20 @@ Zebra Overview of the Zebra Protocol ============================== -The Zebra protocol is used by protocol daemons to communicate with the -**zebra** daemon. - -Each protocol daemon may request and send information to and from the **zebra** -daemon such as interface states, routing state, nexthop-validation, and so on. -Protocol daemons may also install routes with **zebra**. The **zebra** daemon -manages which routes are installed into the forwarding table with the kernel. +The Zebra protocol (or ``ZAPI``) is used by protocol daemons to +communicate with the **zebra** daemon. + +Each protocol daemon may request and send information to and from the +**zebra** daemon such as interface states, routing state, +nexthop-validation, and so on. Protocol daemons may also install +routes with **zebra**. The **zebra** daemon manages which routes are +installed into the forwarding table with the kernel. Some daemons use +more than one ZAPI connection. This is supported: each ZAPI session is +identified by a tuple of: ``{protocol, instance, session_id}``. LDPD +is an example: it uses a second, synchronous ZAPI session to manage +label blocks. The default value for ``session_id`` is zero; daemons +who use multiple ZAPI sessions must assign unique values to the +sessions' ids. The Zebra protocol is a streaming protocol, with a common header. Version 0 lacks a version field and is implicitly versioned. Version 1 and all subsequent diff --git a/lib/zclient.c b/lib/zclient.c index 5402e9c3c5..be2c4e54a0 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -388,6 +388,7 @@ int zclient_send_hello(struct zclient *zclient) zclient_create_header(s, ZEBRA_HELLO, VRF_DEFAULT); stream_putc(s, zclient->redist_default); stream_putw(s, zclient->instance); + stream_putl(s, zclient->session_id); if (zclient->receive_notify) stream_putc(s, 1); else diff --git a/lib/zclient.h b/lib/zclient.h index 214226cf5f..6e8066381f 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -258,6 +258,9 @@ struct zclient { /* Is this a synchronous client? */ bool synchronous; + /* Session id (optional) to support clients with multiple sessions */ + uint32_t session_id; + /* Socket to zebra daemon. */ int sock; diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index a58df82698..d6f23de487 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1931,9 +1931,11 @@ static void zread_hello(ZAPI_HANDLER_ARGS) unsigned short instance; uint8_t notify; uint8_t synchronous; + uint32_t session_id; STREAM_GETC(msg, proto); STREAM_GETW(msg, instance); + STREAM_GETL(msg, session_id); STREAM_GETC(msg, notify); STREAM_GETC(msg, synchronous); if (notify) @@ -1953,6 +1955,7 @@ static void zread_hello(ZAPI_HANDLER_ARGS) client->proto = proto; client->instance = instance; + client->session_id = session_id; /* Graceful restart processing for client connect */ zebra_gr_client_reconnect(client); diff --git a/zebra/zserv.c b/zebra/zserv.c index 740e7c43c7..8a1ed115a7 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -889,6 +889,8 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client) vty_out(vty, "Client: %s", zebra_route_string(client->proto)); if (client->instance) vty_out(vty, " Instance: %u", client->instance); + if (client->session_id) + vty_out(vty, " [%u]", client->session_id); vty_out(vty, "\n"); vty_out(vty, "------------------------ \n"); @@ -995,11 +997,16 @@ static void zebra_show_stale_client_detail(struct vty *vty, time_t uptime; struct client_gr_info *info = NULL; struct zserv *s = NULL; - - if (client->instance) - vty_out(vty, " Instance: %d", client->instance); + bool first_p = true; TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) { + if (first_p) { + if (client->instance) + vty_out(vty, " Instance: %u", client->instance); + if (client->session_id) + vty_out(vty, " [%u]", client->session_id); + first_p = false; + } vty_out(vty, "VRF : %s\n", vrf_id_to_name(info->vrf_id)); vty_out(vty, "Capabilities : "); switch (info->capabilities) { @@ -1070,19 +1077,26 @@ static void zebra_show_client_brief(struct vty *vty, struct zserv *client) client->v6_route_del_cnt); } -struct zserv *zserv_find_client(uint8_t proto, unsigned short instance) +struct zserv *zserv_find_client_session(uint8_t proto, unsigned short instance, + uint32_t session_id) { struct listnode *node, *nnode; struct zserv *client; for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { - if (client->proto == proto && client->instance == instance) + if (client->proto == proto && client->instance == instance && + client->session_id == session_id) return client; } return NULL; } +struct zserv *zserv_find_client(uint8_t proto, unsigned short instance) +{ + return zserv_find_client_session(proto, instance, 0); +} + /* This command is for debugging purpose. */ DEFUN (show_zebra_client, show_zebra_client_cmd, diff --git a/zebra/zserv.h b/zebra/zserv.h index 08df664d56..5506c4299d 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -134,9 +134,10 @@ struct zserv { /* Indicates if client is synchronous. */ bool synchronous; - /* client's protocol */ + /* client's protocol and session info */ uint8_t proto; uint16_t instance; + uint32_t session_id; /* * Interested for MLAG Updates, and also stores the client @@ -286,6 +287,24 @@ extern int zserv_send_message(struct zserv *client, struct stream *msg); */ extern struct zserv *zserv_find_client(uint8_t proto, unsigned short instance); +/* + * Retrieve a client by its protocol, instance number, and session id. + * + * proto + * protocol number + * + * instance + * instance number + * + * session_id + * session id + * + * Returns: + * The Zebra API client. + */ +struct zserv *zserv_find_client_session(uint8_t proto, unsigned short instance, + uint32_t session_id); + /* * Close a client. * -- 2.39.5