diff --git a/doc/user/sharp.rst b/doc/user/sharp.rst index 199685cdfb..dd0e67d4b7 100644 --- a/doc/user/sharp.rst +++ b/doc/user/sharp.rst @@ -103,3 +103,25 @@ keyword. At present, no sharp commands will be preserved in the config. nexthops are specified in nexthop-group ``NAME``. If ``prefix`` is specified, remove label bindings from the route of type ``TYPE`` also. + +.. index:: sharp send opaque +.. clicmd:: sharp send opaque type (1-255) (1-1000) + + Send opaque ZAPI messages with subtype ``type``. Sharpd will send + a stream of messages if the count is greater than one. + +.. index:: sharp send opaque unicast +.. clicmd:: sharp send opaque unicast type (1-255) $proto_str [{instance (0-1000) | session (1-1000)}] (1-1000) + + Send unicast opaque ZAPI messages with subtype ``type``. The + protocol, instance, and session_id identify a single target zapi + client. Sharpd will send a stream of messages if the count is + greater than one. + +.. index:: sharp send opaque reg unreg +.. clicmd:: sharp send opaque $proto_str [{instance (0-1000) | session (1-1000)}] type (1-1000) + + Send opaque ZAPI registration and unregistration messages for a + single subtype. The messages must specify a protocol daemon by + name, and can include optional zapi ``instance`` and ``session`` + values. diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index bad59d172f..72e9c22f17 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -557,7 +557,34 @@ DEFPY (send_opaque, "Type code to send\n" "Number of messages to send\n") { - sharp_opaque_send(type, count); + sharp_opaque_send(type, 0, 0, 0, count); + return CMD_SUCCESS; +} + +DEFPY (send_opaque_unicast, + send_opaque_unicast_cmd, + "sharp send opaque unicast type (1-255) \ + " FRR_IP_REDIST_STR_ZEBRA "$proto_str \ + [{instance (0-1000) | session (1-1000)}] (1-1000)$count", + SHARP_STR + "Send messages for testing\n" + "Send opaque messages\n" + "Send unicast messages\n" + "Type code to send\n" + "Type code to send\n" + FRR_IP_REDIST_HELP_STR_ZEBRA + "Daemon instance\n" + "Daemon instance\n" + "Session ID\n" + "Session ID\n" + "Number of messages to send\n") +{ + uint32_t proto; + + proto = proto_redistnum(AFI_IP, proto_str); + + sharp_opaque_send(type, proto, instance, session, count); + return CMD_SUCCESS; } @@ -600,6 +627,7 @@ void sharp_vty_init(void) install_element(ENABLE_NODE, &sharp_remove_lsp_prefix_v4_cmd); install_element(ENABLE_NODE, &logpump_cmd); install_element(ENABLE_NODE, &send_opaque_cmd); + install_element(ENABLE_NODE, &send_opaque_unicast_cmd); install_element(ENABLE_NODE, &send_opaque_reg_cmd); install_element(VIEW_NODE, &show_debugging_sharpd_cmd); diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index d94e272dd2..6ebc04b9eb 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -491,7 +491,8 @@ static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS) if (zclient_opaque_decode(s, &info) != 0) return -1; - zlog_debug("%s: received opaque type %u", __func__, info.type); + zlog_debug("%s: [%d] received opaque type %u", __func__, + zclient->session_id, info.type); return 0; } @@ -499,7 +500,8 @@ static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS) /* * Send OPAQUE messages, using subtype 'type'. */ -void sharp_opaque_send(uint32_t type, uint32_t count) +void sharp_opaque_send(uint32_t type, uint32_t proto, uint32_t instance, + uint32_t session_id, uint32_t count) { uint8_t buf[32]; int ret; @@ -513,9 +515,15 @@ void sharp_opaque_send(uint32_t type, uint32_t count) buf[i] = 255; } - /* Send some messages */ + /* Send some messages - broadcast and unicast are supported */ for (i = 0; i < count; i++) { - ret = zclient_send_opaque(zclient, type, buf, sizeof(buf)); + if (proto == 0) + ret = zclient_send_opaque(zclient, type, buf, + sizeof(buf)); + else + ret = zclient_send_opaque_unicast(zclient, type, proto, + instance, session_id, + buf, sizeof(buf)); if (ret < 0) { zlog_debug("%s: send_opaque() failed => %d", __func__, ret); diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h index 7c714b52d3..7604f4b0a4 100644 --- a/sharpd/sharp_zebra.h +++ b/sharpd/sharp_zebra.h @@ -46,7 +46,8 @@ int sharp_install_lsps_helper(bool install_p, const struct prefix *p, const struct nexthop_group *backup_nhg); /* Send OPAQUE messages, using subtype 'type'. */ -void sharp_opaque_send(uint32_t type, uint32_t count); +void sharp_opaque_send(uint32_t type, uint32_t proto, uint32_t instance, + uint32_t session_id, uint32_t count); /* Send OPAQUE registration messages, using subtype 'type'. */ void sharp_opaque_reg_send(bool is_reg, uint32_t proto, uint32_t instance, diff --git a/zebra/zebra_opaque.c b/zebra/zebra_opaque.c index 8fb02114d1..41e278f71b 100644 --- a/zebra/zebra_opaque.c +++ b/zebra/zebra_opaque.c @@ -394,9 +394,25 @@ static int dispatch_opq_messages(struct stream_fifo *msg_fifo) for (client = reg->clients; client; client = client->next) { dup = NULL; - /* Copy message if necessary */ - if (client->next) - dup = stream_dup(msg); + if (CHECK_FLAG(info.flags, ZAPI_OPAQUE_FLAG_UNICAST)) { + + if (client->proto != info.proto || + client->instance != info.instance || + client->session_id != info.session_id) + continue; + + if (IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: found matching unicast client %s", + __func__, + opq_client2str(buf, + sizeof(buf), + client)); + + } else { + /* Copy message if more clients */ + if (client->next) + dup = stream_dup(msg); + } /* * TODO -- this isn't ideal: we're going through an @@ -438,6 +454,10 @@ static int dispatch_opq_messages(struct stream_fifo *msg_fifo) if (dup) stream_free(dup); } + + /* If unicast, we're done */ + if (CHECK_FLAG(info.flags, ZAPI_OPAQUE_FLAG_UNICAST)) + break; } drop_it: diff --git a/zebra/zserv.c b/zebra/zserv.c index cb863b258c..99a85fd2ce 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -811,14 +811,6 @@ struct zserv *zserv_acquire_client(uint8_t proto, unsigned short instance, */ void zserv_release_client(struct zserv *client) { - bool cleanup_p = false; - const char *proto_str; - uint16_t instance; - - /* Capture some info for debugging */ - proto_str = zebra_route_string(client->proto); - instance = client->instance; - /* * Once we've decremented the client object's refcount, it's possible * for it to be deleted as soon as we release the lock, so we won't @@ -833,13 +825,10 @@ void zserv_release_client(struct zserv *client) * session is closed, schedule cleanup on the zebra * main pthread. */ - if (client->is_closed) { + if (client->is_closed) thread_add_event(zrouter.master, zserv_handle_client_fail, client, 0, &client->t_cleanup); - - cleanup_p = true; - } } } @@ -847,10 +836,6 @@ void zserv_release_client(struct zserv *client) * Cleanup must take place on the zebra main pthread, so we've * scheduled an event. */ - if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug("%s: %s clean-up for client '%s'[%u]", - __func__, (cleanup_p ? "scheduled" : "NO"), - proto_str, instance); } /*