- FOREACH_SAFI
# ospfd
- LSDB_LOOP
+ # mgmtd
+ - FOREACH_MGMTD_DB_ID
+ - FOREACH_ADPTR_IN_LIST
+ - FOREACH_SESSN_IN_LIST
+ - FOREACH_SESSN_IN_LIST_SAFE
zlog_info("Configuration Read in Took: %s", readin_time_str);
+ if (vty_mgmt_frntnd_enabled())
+ vty_mgmt_send_commit_config(vty, false, false);
+
if (callback.end_config)
(*callback.end_config)();
--- /dev/null
+//
+// mgmt.proto
+//
+// @copyright Copyright (C) 2021 Vmware, Inc.
+//
+// @author Pushpasis Sarkar <spushpasis@vmware.com>
+//
+// Permission to use, copy, modify, and/or distribute this software
+// for any purpose with or without fee is hereby granted, provided
+// that the above copyright notice and this permission notice appear
+// in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+// CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+// OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+// NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+//
+
+syntax = "proto2";
+
+//
+// Protobuf definitions pertaining to the MGMTD component.
+//
+
+package mgmtd;
+
+//
+// Common Sub-Messages
+//
+
+message YangDataXPath {
+ required string xpath = 1;
+}
+
+message YangDataValue {
+ oneof value {
+ //
+ // NOTE: For now let's use stringized value ONLY.
+ // We will enhance it later to pass native-format
+ // if needed.
+ //
+ // bool bool_val = 2;
+ // double double_val = 3;
+ // float float_val = 4;
+ // string string_val = 5;
+ // bytes bytes_val = 6;
+ // int32 int32_val = 7;
+ // int64 int64_val = 8;
+ // uint32 uint32_val = 9;
+ // uint64 uint64_val = 10;
+ // int32 int8_val = 11;
+ // uint32 uint8_val = 12;
+ // int32 int16_val = 13;
+ // uint32 uint16_val = 14;
+ string encoded_str_val = 100;
+ }
+}
+
+message YangData {
+ required string xpath = 1;
+ optional YangDataValue value = 2;
+}
+
+enum CfgDataReqType {
+ REQ_TYPE_NONE = 0;
+ SET_DATA = 1;
+ DELETE_DATA = 2;
+}
+
+message YangCfgDataReq {
+ required YangData data = 1;
+ required CfgDataReqType req_type = 2;
+}
+
+message YangGetDataReq {
+ required YangData data = 1;
+ required int64 next_indx = 2;
+}
+
+//
+// Backend Interface Messages
+//
+message BckndSubscribeReq {
+ required string client_name = 1;
+ required bool subscribe_xpaths = 2;
+ repeated string xpath_reg = 3;
+}
+
+message BckndSubscribeReply {
+ required bool success = 1;
+}
+
+message BckndTrxnReq {
+ required uint64 trxn_id = 1;
+ required bool create = 2;
+}
+
+message BckndTrxnReply {
+ required uint64 trxn_id = 1;
+ required bool create = 2;
+ required bool success = 3;
+}
+
+message BckndCfgDataCreateReq {
+ required uint64 trxn_id = 1;
+ required uint64 batch_id = 2;
+ repeated YangCfgDataReq data_req = 3;
+ required bool end_of_data = 4;
+}
+
+message BckndCfgDataCreateReply {
+ required uint64 trxn_id = 1;
+ required uint64 batch_id = 2;
+ required bool success = 3;
+ optional string error_if_any = 4;
+}
+
+message BckndCfgDataValidateReq {
+ required uint64 trxn_id = 1;
+ repeated uint64 batch_ids = 2;
+}
+
+message BckndCfgDataValidateReply {
+ required uint64 trxn_id = 1;
+ repeated uint64 batch_ids = 2;
+ required bool success = 3;
+ optional string error_if_any = 4;
+}
+
+message BckndCfgDataApplyReq {
+ required uint64 trxn_id = 1;
+}
+
+message BckndCfgDataApplyReply {
+ required uint64 trxn_id = 1;
+ repeated uint64 batch_ids = 2;
+ required bool success = 3;
+ optional string error_if_any = 4;
+}
+
+message BckndOperDataGetReq {
+ required uint64 trxn_id = 1;
+ required uint64 batch_id = 2;
+ repeated YangGetDataReq data = 3;
+}
+
+message YangDataReply {
+ repeated YangData data = 1;
+ required int64 next_indx = 2;
+}
+
+message BckndOperDataGetReply {
+ required uint64 trxn_id = 1;
+ required uint64 batch_id = 2;
+ required bool success = 3;
+ optional string error = 4;
+ optional YangDataReply data = 5;
+}
+
+message BckndOperDataNotify {
+ required YangDataReply data = 5;
+}
+
+message BckndConfigCmdReq {
+ required string cmd = 1;
+}
+
+message BckndConfigCmdReply {
+ required bool success = 1;
+ required string error_if_any = 2;
+}
+
+message BckndShowCmdReq {
+ required string cmd = 1;
+}
+
+message BckndShowCmdReply {
+ required bool success = 1;
+ required string cmd_ouput = 2;
+}
+
+//
+// Any message on the MGMTD Backend Interface.
+//
+message BckndMessage {
+ oneof message {
+ BckndSubscribeReq subscr_req = 2;
+ BckndSubscribeReply subscr_reply = 3;
+ BckndTrxnReq trxn_req = 4;
+ BckndTrxnReply trxn_reply = 5;
+ BckndCfgDataCreateReq cfg_data_req = 6;
+ BckndCfgDataCreateReply cfg_data_reply = 7;
+ BckndCfgDataValidateReq cfg_validate_req = 8;
+ BckndCfgDataValidateReply cfg_validate_reply = 9;
+ BckndCfgDataApplyReq cfg_apply_req = 10;
+ BckndCfgDataApplyReply cfg_apply_reply = 11;
+ BckndOperDataGetReq get_req = 12;
+ BckndOperDataGetReply get_reply = 13;
+ BckndOperDataNotify notify_data = 14;
+ BckndConfigCmdReq cfg_cmd_req = 15;
+ BckndConfigCmdReply cfg_cmd_reply = 16;
+ BckndShowCmdReq show_cmd_req = 17;
+ BckndShowCmdReply show_cmd_reply = 18;
+ }
+}
+
+
+//
+// Frontend Interface Messages
+//
+
+message FrntndRegisterReq {
+ required string client_name = 1;
+}
+
+message FrntndSessionReq {
+ required bool create = 1;
+ oneof id {
+ uint64 client_conn_id = 2; // Applicable for create request only
+ uint64 session_id = 3; // Applicable for delete request only
+ }
+}
+
+message FrntndSessionReply {
+ required bool create = 1;
+ required bool success = 2;
+ optional uint64 client_conn_id = 3; // Applicable for create request only
+ required uint64 session_id = 4;
+}
+
+enum DatabaseId {
+ DB_NONE = 0;
+ RUNNING_DB = 1;
+ CANDIDATE_DB = 2;
+ OPERATIONAL_DB = 3;
+ STARTUP_DB = 4;
+}
+
+message FrntndLockDbReq {
+ required uint64 session_id = 1;
+ required uint64 req_id = 2;
+ required DatabaseId db_id = 3;
+ required bool lock = 4;
+}
+
+message FrntndLockDbReply {
+ required uint64 session_id = 1;
+ required uint64 req_id = 2;
+ required DatabaseId db_id = 3;
+ required bool lock = 4;
+ required bool success = 5;
+ optional string error_if_any = 6;
+}
+
+message FrntndSetConfigReq {
+ required uint64 session_id = 1;
+ required DatabaseId db_id = 2;
+ required uint64 req_id = 3;
+ repeated YangCfgDataReq data = 4;
+ required bool implicit_commit = 5;
+ required DatabaseId commit_db_id = 6;
+}
+
+message FrntndSetConfigReply {
+ required uint64 session_id = 1;
+ required DatabaseId db_id = 2;
+ required uint64 req_id = 3;
+ required bool success = 4;
+ optional string error_if_any = 5;
+}
+
+message FrntndCommitConfigReq {
+ required uint64 session_id = 1;
+ required DatabaseId src_db_id = 2;
+ required DatabaseId dst_db_id = 3;
+ required uint64 req_id = 4;
+ required bool validate_only = 5;
+ required bool abort = 6;
+}
+
+message FrntndCommitConfigReply {
+ required uint64 session_id = 1;
+ required DatabaseId src_db_id = 2;
+ required DatabaseId dst_db_id = 3;
+ required uint64 req_id = 4;
+ required bool validate_only = 5;
+ required bool success = 6;
+ required bool abort = 7;
+ optional string error_if_any = 8;
+}
+
+message FrntndGetConfigReq {
+ required uint64 session_id = 1;
+ required DatabaseId db_id = 2;
+ required uint64 req_id = 3;
+ repeated YangGetDataReq data = 4;
+}
+
+message FrntndGetConfigReply {
+ required uint64 session_id = 1;
+ required DatabaseId db_id = 2;
+ required uint64 req_id = 3;
+ required bool success = 4;
+ optional string error_if_any = 5;
+ optional YangDataReply data = 6;
+}
+
+message FrntndGetDataReq {
+ required uint64 session_id = 1;
+ required DatabaseId db_id = 2;
+ required uint64 req_id = 3;
+ repeated YangGetDataReq data = 4;
+}
+
+message FrntndGetDataReply {
+ required uint64 session_id = 1;
+ required DatabaseId db_id = 2;
+ required uint64 req_id = 3;
+ required bool success = 4;
+ optional string error_if_any = 5;
+ optional YangDataReply data = 6;
+}
+
+message FrntndNotifyDataReq {
+ repeated YangData data = 1;
+}
+
+message FrntndRegisterNotifyReq {
+ required uint64 session_id = 1;
+ required DatabaseId db_id = 2;
+ required bool register_req = 3;
+ required uint64 req_id = 4;
+ repeated YangDataXPath data_xpath = 5;
+}
+
+message FrntndMessage {
+ oneof message {
+ FrntndRegisterReq register_req = 2;
+ FrntndSessionReq sessn_req = 3;
+ FrntndSessionReply sessn_reply = 4;
+ FrntndLockDbReq lockdb_req = 5;
+ FrntndLockDbReply lockdb_reply = 6;
+ FrntndSetConfigReq setcfg_req = 7;
+ FrntndSetConfigReply setcfg_reply = 8;
+ FrntndCommitConfigReq commcfg_req = 9;
+ FrntndCommitConfigReply commcfg_reply = 10;
+ FrntndGetConfigReq getcfg_req = 11;
+ FrntndGetConfigReply getcfg_reply = 12;
+ FrntndGetDataReq getdata_req = 13;
+ FrntndGetDataReply getdata_reply = 14;
+ FrntndNotifyDataReq notify_data_req = 15;
+ FrntndRegisterNotifyReq regnotify_req = 16;
+ }
+}
--- /dev/null
+/*
+ * MGMTD Frontend Client Library api interfaces
+ * Copyright (C) 2021 Vmware, Inc.
+ * Pushpasis Sarkar <spushpasis@vmware.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+#include "memory.h"
+#include "libfrr.h"
+#include "mgmt_frntnd_client.h"
+#include "mgmt_pb.h"
+#include "network.h"
+#include "stream.h"
+#include "sockopt.h"
+
+#ifdef REDIRECT_DEBUG_TO_STDERR
+#define MGMTD_FRNTND_CLNT_DBG(fmt, ...) \
+ fprintf(stderr, "%s: " fmt "\n", __func__, ##__VA_ARGS__)
+#define MGMTD_FRNTND_CLNT_ERR(fmt, ...) \
+ fprintf(stderr, "%s: ERROR, " fmt "\n", __func__, ##__VA_ARGS__)
+#else /* REDIRECT_DEBUG_TO_STDERR */
+#define MGMTD_FRNTND_CLNT_DBG(fmt, ...) \
+ do { \
+ if (mgmt_debug_frntnd_clnt) \
+ zlog_err("%s: " fmt, __func__, ##__VA_ARGS__); \
+ } while (0)
+#define MGMTD_FRNTND_CLNT_ERR(fmt, ...) \
+ zlog_err("%s: ERROR: " fmt, __func__, ##__VA_ARGS__)
+#endif /* REDIRECT_DEBUG_TO_STDERR */
+
+struct mgmt_frntnd_client_ctxt;
+
+PREDECL_LIST(mgmt_session_list);
+
+struct mgmt_frntnd_client_session {
+ uint64_t client_id;
+ uint64_t session_id;
+ struct mgmt_frntnd_client_ctxt *clnt_ctxt;
+ uintptr_t user_ctxt;
+
+ struct mgmt_session_list_item list_linkage;
+};
+
+DECLARE_LIST(mgmt_session_list, struct mgmt_frntnd_client_session,
+ list_linkage);
+
+DEFINE_MTYPE_STATIC(LIB, MGMTD_FRNTND_SESSION, "MGMTD Frontend session");
+
+struct mgmt_frntnd_client_ctxt {
+ int conn_fd;
+ struct thread_master *tm;
+ struct thread *conn_retry_tmr;
+ struct thread *conn_read_ev;
+ struct thread *conn_write_ev;
+ struct thread *conn_writes_on;
+ struct thread *msg_proc_ev;
+ uint32_t flags;
+ uint32_t num_msg_tx;
+ uint32_t num_msg_rx;
+
+ struct stream_fifo *ibuf_fifo;
+ struct stream *ibuf_work;
+ struct stream_fifo *obuf_fifo;
+ struct stream *obuf_work;
+
+ struct mgmt_frntnd_client_params client_params;
+
+ struct mgmt_session_list_head client_sessions;
+};
+
+#define MGMTD_FRNTND_CLNT_FLAGS_WRITES_OFF (1U << 0)
+
+#define FOREACH_SESSN_IN_LIST(clntctxt, sessn) \
+ frr_each_safe(mgmt_session_list, &(clntctxt)->client_sessions, (sessn))
+
+static bool mgmt_debug_frntnd_clnt;
+
+static struct mgmt_frntnd_client_ctxt mgmt_frntnd_clntctxt = {0};
+
+/* Forward declarations */
+static void
+mgmt_frntnd_client_register_event(struct mgmt_frntnd_client_ctxt *clnt_ctxt,
+ enum mgmt_frntnd_event event);
+static void mgmt_frntnd_client_schedule_conn_retry(
+ struct mgmt_frntnd_client_ctxt *clnt_ctxt, unsigned long intvl_secs);
+
+static struct mgmt_frntnd_client_session *
+mgmt_frntnd_find_session_by_client_id(struct mgmt_frntnd_client_ctxt *clnt_ctxt,
+ uint64_t client_id)
+{
+ struct mgmt_frntnd_client_session *sessn;
+
+ FOREACH_SESSN_IN_LIST (clnt_ctxt, sessn) {
+ if (sessn->client_id == client_id) {
+ MGMTD_FRNTND_CLNT_DBG(
+ "Found session %p for client-id %llu.", sessn,
+ (unsigned long long)client_id);
+ return sessn;
+ }
+ }
+
+ return NULL;
+}
+
+static struct mgmt_frntnd_client_session *
+mgmt_frntnd_find_session_by_sessn_id(struct mgmt_frntnd_client_ctxt *clnt_ctxt,
+ uint64_t sessn_id)
+{
+ struct mgmt_frntnd_client_session *sessn;
+
+ FOREACH_SESSN_IN_LIST (clnt_ctxt, sessn) {
+ if (sessn->session_id == sessn_id) {
+ MGMTD_FRNTND_CLNT_DBG(
+ "Found session %p for session-id %llu.", sessn,
+ (unsigned long long)sessn_id);
+ return sessn;
+ }
+ }
+
+ return NULL;
+}
+
+static void
+mgmt_frntnd_server_disconnect(struct mgmt_frntnd_client_ctxt *clnt_ctxt,
+ bool reconnect)
+{
+ if (clnt_ctxt->conn_fd) {
+ close(clnt_ctxt->conn_fd);
+ clnt_ctxt->conn_fd = 0;
+ }
+
+ if (reconnect)
+ mgmt_frntnd_client_schedule_conn_retry(
+ clnt_ctxt,
+ clnt_ctxt->client_params.conn_retry_intvl_sec);
+}
+
+static inline void
+mgmt_frntnd_client_sched_msg_write(struct mgmt_frntnd_client_ctxt *clnt_ctxt)
+{
+ if (!CHECK_FLAG(clnt_ctxt->flags, MGMTD_FRNTND_CLNT_FLAGS_WRITES_OFF))
+ mgmt_frntnd_client_register_event(clnt_ctxt,
+ MGMTD_FRNTND_CONN_WRITE);
+}
+
+static inline void
+mgmt_frntnd_client_writes_on(struct mgmt_frntnd_client_ctxt *clnt_ctxt)
+{
+ MGMTD_FRNTND_CLNT_DBG("Resume writing msgs");
+ UNSET_FLAG(clnt_ctxt->flags, MGMTD_FRNTND_CLNT_FLAGS_WRITES_OFF);
+ if (clnt_ctxt->obuf_work
+ || stream_fifo_count_safe(clnt_ctxt->obuf_fifo))
+ mgmt_frntnd_client_sched_msg_write(clnt_ctxt);
+}
+
+static inline void
+mgmt_frntnd_client_writes_off(struct mgmt_frntnd_client_ctxt *clnt_ctxt)
+{
+ SET_FLAG(clnt_ctxt->flags, MGMTD_FRNTND_CLNT_FLAGS_WRITES_OFF);
+ MGMTD_FRNTND_CLNT_DBG("Paused writing msgs");
+}
+
+static int
+mgmt_frntnd_client_send_msg(struct mgmt_frntnd_client_ctxt *clnt_ctxt,
+ Mgmtd__FrntndMessage *frntnd_msg)
+{
+ size_t msg_size;
+ uint8_t msg_buf[MGMTD_FRNTND_MSG_MAX_LEN];
+ struct mgmt_frntnd_msg *msg;
+
+ if (clnt_ctxt->conn_fd == 0)
+ return -1;
+
+ msg_size = mgmtd__frntnd_message__get_packed_size(frntnd_msg);
+ msg_size += MGMTD_FRNTND_MSG_HDR_LEN;
+ if (msg_size > sizeof(msg_buf)) {
+ MGMTD_FRNTND_CLNT_ERR(
+ "Message size %d more than max size'%d. Not sending!'",
+ (int)msg_size, (int)sizeof(msg_buf));
+ return -1;
+ }
+
+ msg = (struct mgmt_frntnd_msg *)msg_buf;
+ msg->hdr.marker = MGMTD_FRNTND_MSG_MARKER;
+ msg->hdr.len = (uint16_t)msg_size;
+ mgmtd__frntnd_message__pack(frntnd_msg, msg->payload);
+
+ if (!clnt_ctxt->obuf_work)
+ clnt_ctxt->obuf_work = stream_new(MGMTD_FRNTND_MSG_MAX_LEN);
+ if (STREAM_WRITEABLE(clnt_ctxt->obuf_work) < msg_size) {
+ stream_fifo_push(clnt_ctxt->obuf_fifo, clnt_ctxt->obuf_work);
+ clnt_ctxt->obuf_work = stream_new(MGMTD_FRNTND_MSG_MAX_LEN);
+ }
+ stream_write(clnt_ctxt->obuf_work, (void *)msg_buf, msg_size);
+
+ mgmt_frntnd_client_sched_msg_write(clnt_ctxt);
+ clnt_ctxt->num_msg_tx++;
+ return 0;
+}
+
+static void mgmt_frntnd_client_write(struct thread *thread)
+{
+ int bytes_written = 0;
+ int processed = 0;
+ int msg_size = 0;
+ struct stream *s = NULL;
+ struct stream *free = NULL;
+ struct mgmt_frntnd_client_ctxt *clnt_ctxt;
+
+ clnt_ctxt = (struct mgmt_frntnd_client_ctxt *)THREAD_ARG(thread);
+ assert(clnt_ctxt && clnt_ctxt->conn_fd);
+
+ /* Ensure pushing any pending write buffer to FIFO */
+ if (clnt_ctxt->obuf_work) {
+ stream_fifo_push(clnt_ctxt->obuf_fifo, clnt_ctxt->obuf_work);
+ clnt_ctxt->obuf_work = NULL;
+ }
+
+ for (s = stream_fifo_head(clnt_ctxt->obuf_fifo);
+ s && processed < MGMTD_FRNTND_MAX_NUM_MSG_WRITE;
+ s = stream_fifo_head(clnt_ctxt->obuf_fifo)) {
+ /* msg_size = (int)stream_get_size(s); */
+ msg_size = (int)STREAM_READABLE(s);
+ bytes_written = stream_flush(s, clnt_ctxt->conn_fd);
+ if (bytes_written == -1
+ && (errno == EAGAIN || errno == EWOULDBLOCK)) {
+ mgmt_frntnd_client_register_event(
+ clnt_ctxt, MGMTD_FRNTND_CONN_WRITE);
+ return;
+ } else if (bytes_written != msg_size) {
+ MGMTD_FRNTND_CLNT_ERR(
+ "Could not write all %d bytes (wrote: %d) to MGMTD Backend client socket. Err: '%s'",
+ msg_size, bytes_written, safe_strerror(errno));
+ if (bytes_written > 0) {
+ stream_forward_getp(s, (size_t)bytes_written);
+ stream_pulldown(s);
+ mgmt_frntnd_client_register_event(
+ clnt_ctxt, MGMTD_FRNTND_CONN_WRITE);
+ return;
+ }
+ mgmt_frntnd_server_disconnect(clnt_ctxt, true);
+ return;
+ }
+
+ free = stream_fifo_pop(clnt_ctxt->obuf_fifo);
+ stream_free(free);
+ MGMTD_FRNTND_CLNT_DBG(
+ "Wrote %d bytes of message to MGMTD Backend client socket.'",
+ bytes_written);
+ processed++;
+ }
+
+ if (s) {
+ mgmt_frntnd_client_writes_off(clnt_ctxt);
+ mgmt_frntnd_client_register_event(clnt_ctxt,
+ MGMTD_FRNTND_CONN_WRITES_ON);
+ }
+}
+
+static void mgmt_frntnd_client_resume_writes(struct thread *thread)
+{
+ struct mgmt_frntnd_client_ctxt *clnt_ctxt;
+
+ clnt_ctxt = (struct mgmt_frntnd_client_ctxt *)THREAD_ARG(thread);
+ assert(clnt_ctxt && clnt_ctxt->conn_fd);
+
+ mgmt_frntnd_client_writes_on(clnt_ctxt);
+}
+
+static int
+mgmt_frntnd_send_register_req(struct mgmt_frntnd_client_ctxt *clnt_ctxt)
+{
+ Mgmtd__FrntndMessage frntnd_msg;
+ Mgmtd__FrntndRegisterReq rgstr_req;
+
+ mgmtd__frntnd_register_req__init(&rgstr_req);
+ rgstr_req.client_name = clnt_ctxt->client_params.name;
+
+ mgmtd__frntnd_message__init(&frntnd_msg);
+ frntnd_msg.message_case = MGMTD__FRNTND_MESSAGE__MESSAGE_REGISTER_REQ;
+ frntnd_msg.register_req = &rgstr_req;
+
+ MGMTD_FRNTND_CLNT_DBG(
+ "Sending REGISTER_REQ message to MGMTD Frontend server");
+
+ return mgmt_frntnd_client_send_msg(clnt_ctxt, &frntnd_msg);
+}
+
+static int
+mgmt_frntnd_send_session_req(struct mgmt_frntnd_client_ctxt *clnt_ctxt,
+ struct mgmt_frntnd_client_session *sessn,
+ bool create)
+{
+ Mgmtd__FrntndMessage frntnd_msg;
+ Mgmtd__FrntndSessionReq sess_req;
+
+ mgmtd__frntnd_session_req__init(&sess_req);
+ sess_req.create = create;
+ if (create) {
+ sess_req.id_case = MGMTD__FRNTND_SESSION_REQ__ID_CLIENT_CONN_ID;
+ sess_req.client_conn_id = sessn->client_id;
+ } else {
+ sess_req.id_case = MGMTD__FRNTND_SESSION_REQ__ID_SESSION_ID;
+ sess_req.session_id = sessn->session_id;
+ }
+
+ mgmtd__frntnd_message__init(&frntnd_msg);
+ frntnd_msg.message_case = MGMTD__FRNTND_MESSAGE__MESSAGE_SESSN_REQ;
+ frntnd_msg.sessn_req = &sess_req;
+
+ MGMTD_FRNTND_CLNT_DBG(
+ "Sending SESSION_REQ message for %s session %llu to MGMTD Frontend server",
+ create ? "creating" : "destroying",
+ (unsigned long long)sessn->client_id);
+
+ return mgmt_frntnd_client_send_msg(clnt_ctxt, &frntnd_msg);
+}
+
+static int
+mgmt_frntnd_send_lockdb_req(struct mgmt_frntnd_client_ctxt *clnt_ctxt,
+ struct mgmt_frntnd_client_session *sessn, bool lock,
+ uint64_t req_id, Mgmtd__DatabaseId db_id)
+{
+ (void)req_id;
+ Mgmtd__FrntndMessage frntnd_msg;
+ Mgmtd__FrntndLockDbReq lockdb_req;
+
+ mgmtd__frntnd_lock_db_req__init(&lockdb_req);
+ lockdb_req.session_id = sessn->session_id;
+ lockdb_req.req_id = req_id;
+ lockdb_req.db_id = db_id;
+ lockdb_req.lock = lock;
+
+ mgmtd__frntnd_message__init(&frntnd_msg);
+ frntnd_msg.message_case = MGMTD__FRNTND_MESSAGE__MESSAGE_LOCKDB_REQ;
+ frntnd_msg.lockdb_req = &lockdb_req;
+
+ MGMTD_FRNTND_CLNT_DBG(
+ "Sending %sLOCK_REQ message for Db:%d session %llu to MGMTD Frontend server",
+ lock ? "" : "UN", db_id, (unsigned long long)sessn->client_id);
+
+ return mgmt_frntnd_client_send_msg(clnt_ctxt, &frntnd_msg);
+}
+
+static int
+mgmt_frntnd_send_setcfg_req(struct mgmt_frntnd_client_ctxt *clnt_ctxt,
+ struct mgmt_frntnd_client_session *sessn,
+ uint64_t req_id, Mgmtd__DatabaseId db_id,
+ Mgmtd__YangCfgDataReq **data_req, int num_data_reqs,
+ bool implicit_commit, Mgmtd__DatabaseId dst_db_id)
+{
+ (void)req_id;
+ Mgmtd__FrntndMessage frntnd_msg;
+ Mgmtd__FrntndSetConfigReq setcfg_req;
+
+ mgmtd__frntnd_set_config_req__init(&setcfg_req);
+ setcfg_req.session_id = sessn->session_id;
+ setcfg_req.db_id = db_id;
+ setcfg_req.req_id = req_id;
+ setcfg_req.data = data_req;
+ setcfg_req.n_data = (size_t)num_data_reqs;
+ setcfg_req.implicit_commit = implicit_commit;
+ setcfg_req.commit_db_id = dst_db_id;
+
+ mgmtd__frntnd_message__init(&frntnd_msg);
+ frntnd_msg.message_case = MGMTD__FRNTND_MESSAGE__MESSAGE_SETCFG_REQ;
+ frntnd_msg.setcfg_req = &setcfg_req;
+
+ MGMTD_FRNTND_CLNT_DBG(
+ "Sending SET_CONFIG_REQ message for Db:%d session %llu (#xpaths:%d) to MGMTD Frontend server",
+ db_id, (unsigned long long)sessn->client_id, num_data_reqs);
+
+ return mgmt_frntnd_client_send_msg(clnt_ctxt, &frntnd_msg);
+}
+
+static int
+mgmt_frntnd_send_commitcfg_req(struct mgmt_frntnd_client_ctxt *clnt_ctxt,
+ struct mgmt_frntnd_client_session *sessn,
+ uint64_t req_id, Mgmtd__DatabaseId src_db_id,
+ Mgmtd__DatabaseId dest_db_id, bool validate_only,
+ bool abort)
+{
+ (void)req_id;
+ Mgmtd__FrntndMessage frntnd_msg;
+ Mgmtd__FrntndCommitConfigReq commitcfg_req;
+
+ mgmtd__frntnd_commit_config_req__init(&commitcfg_req);
+ commitcfg_req.session_id = sessn->session_id;
+ commitcfg_req.src_db_id = src_db_id;
+ commitcfg_req.dst_db_id = dest_db_id;
+ commitcfg_req.req_id = req_id;
+ commitcfg_req.validate_only = validate_only;
+ commitcfg_req.abort = abort;
+
+ mgmtd__frntnd_message__init(&frntnd_msg);
+ frntnd_msg.message_case = MGMTD__FRNTND_MESSAGE__MESSAGE_COMMCFG_REQ;
+ frntnd_msg.commcfg_req = &commitcfg_req;
+
+ MGMTD_FRNTND_CLNT_DBG(
+ "Sending COMMIT_CONFIG_REQ message for Src-Db:%d, Dst-Db:%d session %llu to MGMTD Frontend server",
+ src_db_id, dest_db_id, (unsigned long long)sessn->client_id);
+
+ return mgmt_frntnd_client_send_msg(clnt_ctxt, &frntnd_msg);
+}
+
+static int
+mgmt_frntnd_send_getcfg_req(struct mgmt_frntnd_client_ctxt *clnt_ctxt,
+ struct mgmt_frntnd_client_session *sessn,
+ uint64_t req_id, Mgmtd__DatabaseId db_id,
+ Mgmtd__YangGetDataReq * data_req[],
+ int num_data_reqs)
+{
+ (void)req_id;
+ Mgmtd__FrntndMessage frntnd_msg;
+ Mgmtd__FrntndGetConfigReq getcfg_req;
+
+ mgmtd__frntnd_get_config_req__init(&getcfg_req);
+ getcfg_req.session_id = sessn->session_id;
+ getcfg_req.db_id = db_id;
+ getcfg_req.req_id = req_id;
+ getcfg_req.data = data_req;
+ getcfg_req.n_data = (size_t)num_data_reqs;
+
+ mgmtd__frntnd_message__init(&frntnd_msg);
+ frntnd_msg.message_case = MGMTD__FRNTND_MESSAGE__MESSAGE_GETCFG_REQ;
+ frntnd_msg.getcfg_req = &getcfg_req;
+
+ MGMTD_FRNTND_CLNT_DBG(
+ "Sending GET_CONFIG_REQ message for Db:%d session %llu (#xpaths:%d) to MGMTD Frontend server",
+ db_id, (unsigned long long)sessn->client_id, num_data_reqs);
+
+ return mgmt_frntnd_client_send_msg(clnt_ctxt, &frntnd_msg);
+}
+
+static int
+mgmt_frntnd_send_getdata_req(struct mgmt_frntnd_client_ctxt *clnt_ctxt,
+ struct mgmt_frntnd_client_session *sessn,
+ uint64_t req_id, Mgmtd__DatabaseId db_id,
+ Mgmtd__YangGetDataReq * data_req[],
+ int num_data_reqs)
+{
+ (void)req_id;
+ Mgmtd__FrntndMessage frntnd_msg;
+ Mgmtd__FrntndGetDataReq getdata_req;
+
+ mgmtd__frntnd_get_data_req__init(&getdata_req);
+ getdata_req.session_id = sessn->session_id;
+ getdata_req.db_id = db_id;
+ getdata_req.req_id = req_id;
+ getdata_req.data = data_req;
+ getdata_req.n_data = (size_t)num_data_reqs;
+
+ mgmtd__frntnd_message__init(&frntnd_msg);
+ frntnd_msg.message_case = MGMTD__FRNTND_MESSAGE__MESSAGE_GETDATA_REQ;
+ frntnd_msg.getdata_req = &getdata_req;
+
+ MGMTD_FRNTND_CLNT_DBG(
+ "Sending GET_CONFIG_REQ message for Db:%d session %llu (#xpaths:%d) to MGMTD Frontend server",
+ db_id, (unsigned long long)sessn->client_id, num_data_reqs);
+
+ return mgmt_frntnd_client_send_msg(clnt_ctxt, &frntnd_msg);
+}
+
+static int mgmt_frntnd_send_regnotify_req(
+ struct mgmt_frntnd_client_ctxt *clnt_ctxt,
+ struct mgmt_frntnd_client_session *sessn, uint64_t req_id,
+ Mgmtd__DatabaseId db_id, bool register_req,
+ Mgmtd__YangDataXPath * data_req[], int num_data_reqs)
+{
+ (void)req_id;
+ Mgmtd__FrntndMessage frntnd_msg;
+ Mgmtd__FrntndRegisterNotifyReq regntfy_req;
+
+ mgmtd__frntnd_register_notify_req__init(®ntfy_req);
+ regntfy_req.session_id = sessn->session_id;
+ regntfy_req.db_id = db_id;
+ regntfy_req.register_req = register_req;
+ regntfy_req.data_xpath = data_req;
+ regntfy_req.n_data_xpath = (size_t)num_data_reqs;
+
+ mgmtd__frntnd_message__init(&frntnd_msg);
+ frntnd_msg.message_case = MGMTD__FRNTND_MESSAGE__MESSAGE_REGNOTIFY_REQ;
+ frntnd_msg.regnotify_req = ®ntfy_req;
+
+ return mgmt_frntnd_client_send_msg(clnt_ctxt, &frntnd_msg);
+}
+
+static int
+mgmt_frntnd_client_handle_msg(struct mgmt_frntnd_client_ctxt *clnt_ctxt,
+ Mgmtd__FrntndMessage *frntnd_msg)
+{
+ struct mgmt_frntnd_client_session *sessn = NULL;
+
+ switch (frntnd_msg->message_case) {
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_SESSN_REPLY:
+ if (frntnd_msg->sessn_reply->create
+ && frntnd_msg->sessn_reply->has_client_conn_id) {
+ MGMTD_FRNTND_CLNT_DBG(
+ "Got Session Create Reply Msg for client-id %llu with session-id: %llu.",
+ (unsigned long long)
+ frntnd_msg->sessn_reply->client_conn_id,
+ (unsigned long long)
+ frntnd_msg->sessn_reply->session_id);
+
+ sessn = mgmt_frntnd_find_session_by_client_id(
+ clnt_ctxt,
+ frntnd_msg->sessn_reply->client_conn_id);
+
+ if (frntnd_msg->sessn_reply->success) {
+ MGMTD_FRNTND_CLNT_DBG(
+ "Session Create for client-id %llu successful.",
+ (unsigned long long)frntnd_msg
+ ->sessn_reply->client_conn_id);
+ sessn->session_id =
+ frntnd_msg->sessn_reply->session_id;
+ } else {
+ MGMTD_FRNTND_CLNT_ERR(
+ "Session Create for client-id %llu failed.",
+ (unsigned long long)frntnd_msg
+ ->sessn_reply->client_conn_id);
+ }
+ } else if (!frntnd_msg->sessn_reply->create) {
+ MGMTD_FRNTND_CLNT_DBG(
+ "Got Session Destroy Reply Msg for session-id %llu",
+ (unsigned long long)
+ frntnd_msg->sessn_reply->session_id);
+
+ sessn = mgmt_frntnd_find_session_by_sessn_id(
+ clnt_ctxt, frntnd_msg->sessn_req->session_id);
+ }
+
+ if (sessn && sessn->clnt_ctxt
+ && sessn->clnt_ctxt->client_params
+ .client_session_notify)
+ (*sessn->clnt_ctxt->client_params
+ .client_session_notify)(
+ (uintptr_t)clnt_ctxt,
+ clnt_ctxt->client_params.user_data,
+ sessn->client_id,
+ frntnd_msg->sessn_reply->create,
+ frntnd_msg->sessn_reply->success,
+ (uintptr_t)sessn, sessn->user_ctxt);
+ break;
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_LOCKDB_REPLY:
+ MGMTD_FRNTND_CLNT_DBG(
+ "Got LockDb Reply Msg for session-id %llu",
+ (unsigned long long)
+ frntnd_msg->lockdb_reply->session_id);
+ sessn = mgmt_frntnd_find_session_by_sessn_id(
+ clnt_ctxt, frntnd_msg->lockdb_reply->session_id);
+
+ if (sessn && sessn->clnt_ctxt
+ && sessn->clnt_ctxt->client_params
+ .lock_db_notify)
+ (*sessn->clnt_ctxt->client_params
+ .lock_db_notify)(
+ (uintptr_t)clnt_ctxt,
+ clnt_ctxt->client_params.user_data,
+ sessn->client_id, (uintptr_t)sessn,
+ sessn->user_ctxt,
+ frntnd_msg->lockdb_reply->req_id,
+ frntnd_msg->lockdb_reply->lock,
+ frntnd_msg->lockdb_reply->success,
+ frntnd_msg->lockdb_reply->db_id,
+ frntnd_msg->lockdb_reply->error_if_any);
+ break;
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_SETCFG_REPLY:
+ MGMTD_FRNTND_CLNT_DBG(
+ "Got Set Config Reply Msg for session-id %llu",
+ (unsigned long long)
+ frntnd_msg->setcfg_reply->session_id);
+
+ sessn = mgmt_frntnd_find_session_by_sessn_id(
+ clnt_ctxt, frntnd_msg->setcfg_reply->session_id);
+
+ if (sessn && sessn->clnt_ctxt
+ && sessn->clnt_ctxt->client_params
+ .set_config_notify)
+ (*sessn->clnt_ctxt->client_params
+ .set_config_notify)(
+ (uintptr_t)clnt_ctxt,
+ clnt_ctxt->client_params.user_data,
+ sessn->client_id, (uintptr_t)sessn,
+ sessn->user_ctxt,
+ frntnd_msg->setcfg_reply->req_id,
+ frntnd_msg->setcfg_reply->success,
+ frntnd_msg->setcfg_reply->db_id,
+ frntnd_msg->setcfg_reply->error_if_any);
+ break;
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_COMMCFG_REPLY:
+ MGMTD_FRNTND_CLNT_DBG(
+ "Got Commit Config Reply Msg for session-id %llu",
+ (unsigned long long)
+ frntnd_msg->commcfg_reply->session_id);
+
+ sessn = mgmt_frntnd_find_session_by_sessn_id(
+ clnt_ctxt, frntnd_msg->commcfg_reply->session_id);
+
+ if (sessn && sessn->clnt_ctxt
+ && sessn->clnt_ctxt->client_params
+ .commit_config_notify)
+ (*sessn->clnt_ctxt->client_params
+ .commit_config_notify)(
+ (uintptr_t)clnt_ctxt,
+ clnt_ctxt->client_params.user_data,
+ sessn->client_id, (uintptr_t)sessn,
+ sessn->user_ctxt,
+ frntnd_msg->commcfg_reply->req_id,
+ frntnd_msg->commcfg_reply->success,
+ frntnd_msg->commcfg_reply->src_db_id,
+ frntnd_msg->commcfg_reply->dst_db_id,
+ frntnd_msg->commcfg_reply->validate_only,
+ frntnd_msg->commcfg_reply->error_if_any);
+ break;
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_GETCFG_REPLY:
+ MGMTD_FRNTND_CLNT_DBG(
+ "Got Get Config Reply Msg for session-id %llu",
+ (unsigned long long)
+ frntnd_msg->getcfg_reply->session_id);
+
+ sessn = mgmt_frntnd_find_session_by_sessn_id(
+ clnt_ctxt, frntnd_msg->getcfg_reply->session_id);
+
+ if (sessn && sessn->clnt_ctxt
+ && sessn->clnt_ctxt->client_params
+ .get_data_notify)
+ (*sessn->clnt_ctxt->client_params
+ .get_data_notify)(
+ (uintptr_t)clnt_ctxt,
+ clnt_ctxt->client_params.user_data,
+ sessn->client_id, (uintptr_t)sessn,
+ sessn->user_ctxt,
+ frntnd_msg->getcfg_reply->req_id,
+ frntnd_msg->getcfg_reply->success,
+ frntnd_msg->getcfg_reply->db_id,
+ frntnd_msg->getcfg_reply->data
+ ? frntnd_msg->getcfg_reply->data->data
+ : NULL,
+ frntnd_msg->getcfg_reply->data
+ ? frntnd_msg->getcfg_reply->data->n_data
+ : 0,
+ frntnd_msg->getcfg_reply->data
+ ? frntnd_msg->getcfg_reply->data
+ ->next_indx
+ : 0,
+ frntnd_msg->getcfg_reply->error_if_any);
+ break;
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_GETDATA_REPLY:
+ MGMTD_FRNTND_CLNT_DBG(
+ "Got Get Data Reply Msg for session-id %llu",
+ (unsigned long long)
+ frntnd_msg->getdata_reply->session_id);
+
+ sessn = mgmt_frntnd_find_session_by_sessn_id(
+ clnt_ctxt, frntnd_msg->getdata_reply->session_id);
+
+ if (sessn && sessn->clnt_ctxt
+ && sessn->clnt_ctxt->client_params
+ .get_data_notify)
+ (*sessn->clnt_ctxt->client_params
+ .get_data_notify)(
+ (uintptr_t)clnt_ctxt,
+ clnt_ctxt->client_params.user_data,
+ sessn->client_id, (uintptr_t)sessn,
+ sessn->user_ctxt,
+ frntnd_msg->getdata_reply->req_id,
+ frntnd_msg->getdata_reply->success,
+ frntnd_msg->getdata_reply->db_id,
+ frntnd_msg->getdata_reply->data
+ ? frntnd_msg->getdata_reply->data->data
+ : NULL,
+ frntnd_msg->getdata_reply->data
+ ? frntnd_msg->getdata_reply->data
+ ->n_data
+ : 0,
+ frntnd_msg->getdata_reply->data
+ ? frntnd_msg->getdata_reply->data
+ ->next_indx
+ : 0,
+ frntnd_msg->getdata_reply->error_if_any);
+ break;
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_NOTIFY_DATA_REQ:
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_REGNOTIFY_REQ:
+ /*
+ * TODO: Add handling code in future.
+ */
+ break;
+ /*
+ * NOTE: The following messages are always sent from Frontend
+ * clients to MGMTd only and/or need not be handled here.
+ */
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_REGISTER_REQ:
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_SESSN_REQ:
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_LOCKDB_REQ:
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_SETCFG_REQ:
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_COMMCFG_REQ:
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_GETCFG_REQ:
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_GETDATA_REQ:
+ case MGMTD__FRNTND_MESSAGE__MESSAGE__NOT_SET:
+ default:
+ /*
+ * A 'default' case is being added contrary to the
+ * FRR code guidelines to take care of build
+ * failures on certain build systems (courtesy of
+ * the proto-c package).
+ */
+ break;
+ }
+
+ return 0;
+}
+
+static int
+mgmt_frntnd_client_process_msg(struct mgmt_frntnd_client_ctxt *clnt_ctxt,
+ uint8_t *msg_buf, int bytes_read)
+{
+ Mgmtd__FrntndMessage *frntnd_msg;
+ struct mgmt_frntnd_msg *msg;
+ uint16_t bytes_left;
+ uint16_t processed = 0;
+
+ MGMTD_FRNTND_CLNT_DBG(
+ "Have %u bytes of messages from MGMTD Frontend server to .",
+ bytes_read);
+
+ bytes_left = bytes_read;
+ for (; bytes_left > MGMTD_FRNTND_MSG_HDR_LEN;
+ bytes_left -= msg->hdr.len, msg_buf += msg->hdr.len) {
+ msg = (struct mgmt_frntnd_msg *)msg_buf;
+ if (msg->hdr.marker != MGMTD_FRNTND_MSG_MARKER) {
+ MGMTD_FRNTND_CLNT_DBG(
+ "Marker not found in message from MGMTD Frontend server.");
+ break;
+ }
+
+ if (bytes_left < msg->hdr.len) {
+ MGMTD_FRNTND_CLNT_DBG(
+ "Incomplete message of %d bytes (epxected: %u) from MGMTD Frontend server.",
+ bytes_left, msg->hdr.len);
+ break;
+ }
+
+ frntnd_msg = mgmtd__frntnd_message__unpack(
+ NULL, (size_t)(msg->hdr.len - MGMTD_FRNTND_MSG_HDR_LEN),
+ msg->payload);
+ if (!frntnd_msg) {
+ MGMTD_FRNTND_CLNT_DBG(
+ "Failed to decode %d bytes from MGMTD Frontend server.",
+ msg->hdr.len);
+ continue;
+ }
+
+ MGMTD_FRNTND_CLNT_DBG(
+ "Decoded %d bytes of message(msg: %u/%u) from MGMTD Frontend server",
+ msg->hdr.len, frntnd_msg->message_case,
+ frntnd_msg->message_case);
+
+ (void)mgmt_frntnd_client_handle_msg(clnt_ctxt, frntnd_msg);
+
+ mgmtd__frntnd_message__free_unpacked(frntnd_msg, NULL);
+ processed++;
+ clnt_ctxt->num_msg_rx++;
+ }
+
+ return processed;
+}
+
+static void mgmt_frntnd_client_proc_msgbufs(struct thread *thread)
+{
+ struct mgmt_frntnd_client_ctxt *clnt_ctxt;
+ struct stream *work;
+ int processed = 0;
+
+ clnt_ctxt = (struct mgmt_frntnd_client_ctxt *)THREAD_ARG(thread);
+ assert(clnt_ctxt && clnt_ctxt->conn_fd);
+
+ for (; processed < MGMTD_FRNTND_MAX_NUM_MSG_PROC;) {
+ work = stream_fifo_pop_safe(clnt_ctxt->ibuf_fifo);
+ if (!work)
+ break;
+
+ processed += mgmt_frntnd_client_process_msg(
+ clnt_ctxt, STREAM_DATA(work), stream_get_endp(work));
+
+ if (work != clnt_ctxt->ibuf_work) {
+ /* Free it up */
+ stream_free(work);
+ } else {
+ /* Reset stream buffer for next read */
+ stream_reset(work);
+ }
+ }
+
+ /*
+ * If we have more to process, reschedule for processing it.
+ */
+ if (stream_fifo_head(clnt_ctxt->ibuf_fifo))
+ mgmt_frntnd_client_register_event(clnt_ctxt,
+ MGMTD_FRNTND_PROC_MSG);
+}
+
+static void mgmt_frntnd_client_read(struct thread *thread)
+{
+ struct mgmt_frntnd_client_ctxt *clnt_ctxt;
+ int bytes_read, msg_cnt;
+ size_t total_bytes, bytes_left;
+ struct mgmt_frntnd_msg_hdr *msg_hdr;
+ bool incomplete = false;
+
+ clnt_ctxt = (struct mgmt_frntnd_client_ctxt *)THREAD_ARG(thread);
+ assert(clnt_ctxt && clnt_ctxt->conn_fd);
+
+ total_bytes = 0;
+ bytes_left = STREAM_SIZE(clnt_ctxt->ibuf_work)
+ - stream_get_endp(clnt_ctxt->ibuf_work);
+ for (; bytes_left > MGMTD_FRNTND_MSG_HDR_LEN;) {
+ bytes_read = stream_read_try(clnt_ctxt->ibuf_work,
+ clnt_ctxt->conn_fd, bytes_left);
+ MGMTD_FRNTND_CLNT_DBG(
+ "Got %d bytes of message from MGMTD Frontend server",
+ bytes_read);
+ if (bytes_read <= 0) {
+ if (bytes_read == -1
+ && (errno == EAGAIN || errno == EWOULDBLOCK)) {
+ mgmt_frntnd_client_register_event(
+ clnt_ctxt, MGMTD_FRNTND_CONN_READ);
+ return;
+ }
+
+ if (!bytes_read) {
+ /* Looks like connection closed */
+ MGMTD_FRNTND_CLNT_ERR(
+ "Got error (%d) while reading from MGMTD Frontend server. Err: '%s'",
+ bytes_read, safe_strerror(errno));
+ mgmt_frntnd_server_disconnect(clnt_ctxt, true);
+ return;
+ }
+ break;
+ }
+
+ total_bytes += bytes_read;
+ bytes_left -= bytes_read;
+ }
+
+ /*
+ * Check if we would have read incomplete messages or not.
+ */
+ stream_set_getp(clnt_ctxt->ibuf_work, 0);
+ total_bytes = 0;
+ msg_cnt = 0;
+ bytes_left = stream_get_endp(clnt_ctxt->ibuf_work);
+ for (; bytes_left > MGMTD_FRNTND_MSG_HDR_LEN;) {
+ msg_hdr = (struct mgmt_frntnd_msg_hdr
+ *)(STREAM_DATA(clnt_ctxt->ibuf_work)
+ + total_bytes);
+ if (msg_hdr->marker != MGMTD_FRNTND_MSG_MARKER) {
+ /* Corrupted buffer. Force disconnect?? */
+ MGMTD_FRNTND_CLNT_ERR(
+ "Received corrupted buffer from MGMTD frontend server.");
+ mgmt_frntnd_server_disconnect(clnt_ctxt, true);
+ return;
+ }
+ if (msg_hdr->len > bytes_left)
+ break;
+
+ total_bytes += msg_hdr->len;
+ bytes_left -= msg_hdr->len;
+ msg_cnt++;
+ }
+
+ if (bytes_left > 0)
+ incomplete = true;
+
+ /*
+ * We would have read one or several messages.
+ * Schedule processing them now.
+ */
+ msg_hdr =
+ (struct mgmt_frntnd_msg_hdr *)(STREAM_DATA(clnt_ctxt->ibuf_work)
+ + total_bytes);
+ stream_set_endp(clnt_ctxt->ibuf_work, total_bytes);
+ stream_fifo_push(clnt_ctxt->ibuf_fifo, clnt_ctxt->ibuf_work);
+ clnt_ctxt->ibuf_work = stream_new(MGMTD_FRNTND_MSG_MAX_LEN);
+ if (incomplete) {
+ stream_put(clnt_ctxt->ibuf_work, msg_hdr, bytes_left);
+ stream_set_endp(clnt_ctxt->ibuf_work, bytes_left);
+ }
+
+ if (msg_cnt)
+ mgmt_frntnd_client_register_event(clnt_ctxt,
+ MGMTD_FRNTND_PROC_MSG);
+
+ mgmt_frntnd_client_register_event(clnt_ctxt, MGMTD_FRNTND_CONN_READ);
+}
+
+static int mgmt_frntnd_server_connect(struct mgmt_frntnd_client_ctxt *clnt_ctxt)
+{
+ int ret, sock, len;
+ struct sockaddr_un addr;
+
+ MGMTD_FRNTND_CLNT_DBG(
+ "Trying to connect to MGMTD Frontend server at %s",
+ MGMTD_FRNTND_SERVER_PATH);
+
+ assert(!clnt_ctxt->conn_fd);
+
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0) {
+ MGMTD_FRNTND_CLNT_ERR("Failed to create socket");
+ goto mgmt_frntnd_server_connect_failed;
+ }
+
+ MGMTD_FRNTND_CLNT_DBG(
+ "Created MGMTD Frontend server socket successfully!");
+
+ memset(&addr, 0, sizeof(struct sockaddr_un));
+ addr.sun_family = AF_UNIX;
+ strlcpy(addr.sun_path, MGMTD_FRNTND_SERVER_PATH, sizeof(addr.sun_path));
+#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
+ len = addr.sun_len = SUN_LEN(&addr);
+#else
+ len = sizeof(addr.sun_family) + strlen(addr.sun_path);
+#endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */
+
+ ret = connect(sock, (struct sockaddr *)&addr, len);
+ if (ret < 0) {
+ MGMTD_FRNTND_CLNT_ERR(
+ "Failed to connect to MGMTD Frontend Server at %s. Err: %s",
+ addr.sun_path, safe_strerror(errno));
+ close(sock);
+ goto mgmt_frntnd_server_connect_failed;
+ }
+
+ MGMTD_FRNTND_CLNT_DBG(
+ "Connected to MGMTD Frontend Server at %s successfully!",
+ addr.sun_path);
+ clnt_ctxt->conn_fd = sock;
+
+ /* Make client socket non-blocking. */
+ set_nonblocking(sock);
+ setsockopt_so_sendbuf(clnt_ctxt->conn_fd,
+ MGMTD_SOCKET_FRNTND_SEND_BUF_SIZE);
+ setsockopt_so_recvbuf(clnt_ctxt->conn_fd,
+ MGMTD_SOCKET_FRNTND_RECV_BUF_SIZE);
+
+ thread_add_read(clnt_ctxt->tm, mgmt_frntnd_client_read,
+ (void *)&mgmt_frntnd_clntctxt, clnt_ctxt->conn_fd,
+ &clnt_ctxt->conn_read_ev);
+ assert(clnt_ctxt->conn_read_ev);
+
+ /* Send REGISTER_REQ message */
+ if (mgmt_frntnd_send_register_req(clnt_ctxt) != 0)
+ goto mgmt_frntnd_server_connect_failed;
+
+ /* Notify client through registered callback (if any) */
+ if (clnt_ctxt->client_params.client_connect_notify)
+ (void)(*clnt_ctxt->client_params.client_connect_notify)(
+ (uintptr_t)clnt_ctxt,
+ clnt_ctxt->client_params.user_data, true);
+
+ return 0;
+
+mgmt_frntnd_server_connect_failed:
+ if (sock && sock != clnt_ctxt->conn_fd)
+ close(sock);
+
+ mgmt_frntnd_server_disconnect(clnt_ctxt, true);
+ return -1;
+}
+
+static void mgmt_frntnd_client_conn_timeout(struct thread *thread)
+{
+ struct mgmt_frntnd_client_ctxt *clnt_ctxt;
+
+ clnt_ctxt = (struct mgmt_frntnd_client_ctxt *)THREAD_ARG(thread);
+ assert(clnt_ctxt);
+
+ mgmt_frntnd_server_connect(clnt_ctxt);
+}
+
+static void
+mgmt_frntnd_client_register_event(struct mgmt_frntnd_client_ctxt *clnt_ctxt,
+ enum mgmt_frntnd_event event)
+{
+ struct timeval tv = {0};
+
+ switch (event) {
+ case MGMTD_FRNTND_CONN_READ:
+ thread_add_read(clnt_ctxt->tm, mgmt_frntnd_client_read,
+ clnt_ctxt, clnt_ctxt->conn_fd,
+ &clnt_ctxt->conn_read_ev);
+ assert(clnt_ctxt->conn_read_ev);
+ break;
+ case MGMTD_FRNTND_CONN_WRITE:
+ thread_add_write(clnt_ctxt->tm, mgmt_frntnd_client_write,
+ clnt_ctxt, clnt_ctxt->conn_fd,
+ &clnt_ctxt->conn_write_ev);
+ assert(clnt_ctxt->conn_write_ev);
+ break;
+ case MGMTD_FRNTND_PROC_MSG:
+ tv.tv_usec = MGMTD_FRNTND_MSG_PROC_DELAY_USEC;
+ thread_add_timer_tv(clnt_ctxt->tm,
+ mgmt_frntnd_client_proc_msgbufs, clnt_ctxt,
+ &tv, &clnt_ctxt->msg_proc_ev);
+ assert(clnt_ctxt->msg_proc_ev);
+ break;
+ case MGMTD_FRNTND_CONN_WRITES_ON:
+ thread_add_timer_msec(
+ clnt_ctxt->tm, mgmt_frntnd_client_resume_writes,
+ clnt_ctxt, MGMTD_FRNTND_MSG_WRITE_DELAY_MSEC,
+ &clnt_ctxt->conn_writes_on);
+ assert(clnt_ctxt->conn_writes_on);
+ break;
+ case MGMTD_FRNTND_SERVER:
+ assert(!"mgmt_frntnd_clnt_ctxt_post_event called incorrectly");
+ break;
+ }
+}
+
+static void mgmt_frntnd_client_schedule_conn_retry(
+ struct mgmt_frntnd_client_ctxt *clnt_ctxt, unsigned long intvl_secs)
+{
+ MGMTD_FRNTND_CLNT_DBG(
+ "Scheduling MGMTD Frontend server connection retry after %lu seconds",
+ intvl_secs);
+ thread_add_timer(clnt_ctxt->tm, mgmt_frntnd_client_conn_timeout,
+ (void *)clnt_ctxt, intvl_secs,
+ &clnt_ctxt->conn_retry_tmr);
+}
+
+/*
+ * Initialize library and try connecting with MGMTD.
+ */
+uintptr_t mgmt_frntnd_client_lib_init(struct mgmt_frntnd_client_params *params,
+ struct thread_master *master_thread)
+{
+ assert(master_thread && params && strlen(params->name)
+ && !mgmt_frntnd_clntctxt.tm);
+
+ mgmt_frntnd_clntctxt.tm = master_thread;
+ memcpy(&mgmt_frntnd_clntctxt.client_params, params,
+ sizeof(mgmt_frntnd_clntctxt.client_params));
+ if (!mgmt_frntnd_clntctxt.client_params.conn_retry_intvl_sec)
+ mgmt_frntnd_clntctxt.client_params.conn_retry_intvl_sec =
+ MGMTD_FRNTND_DEFAULT_CONN_RETRY_INTVL_SEC;
+
+ assert(!mgmt_frntnd_clntctxt.ibuf_fifo
+ && !mgmt_frntnd_clntctxt.ibuf_work
+ && !mgmt_frntnd_clntctxt.obuf_fifo
+ && !mgmt_frntnd_clntctxt.obuf_work);
+
+ mgmt_frntnd_clntctxt.ibuf_fifo = stream_fifo_new();
+ mgmt_frntnd_clntctxt.ibuf_work = stream_new(MGMTD_FRNTND_MSG_MAX_LEN);
+ mgmt_frntnd_clntctxt.obuf_fifo = stream_fifo_new();
+
+ mgmt_frntnd_clntctxt.obuf_work = NULL;
+
+ mgmt_session_list_init(&mgmt_frntnd_clntctxt.client_sessions);
+
+ /* Start trying to connect to MGMTD frontend server immediately */
+ mgmt_frntnd_client_schedule_conn_retry(&mgmt_frntnd_clntctxt, 1);
+
+ MGMTD_FRNTND_CLNT_DBG("Initialized client '%s'", params->name);
+
+ return (uintptr_t)&mgmt_frntnd_clntctxt;
+}
+
+/*
+ * Create a new Session for a Frontend Client connection.
+ */
+enum mgmt_result mgmt_frntnd_create_client_session(uintptr_t lib_hndl,
+ uint64_t client_id,
+ uintptr_t user_ctxt)
+{
+ struct mgmt_frntnd_client_ctxt *clnt_ctxt;
+ struct mgmt_frntnd_client_session *sessn;
+
+ clnt_ctxt = (struct mgmt_frntnd_client_ctxt *)lib_hndl;
+ if (!clnt_ctxt)
+ return MGMTD_INVALID_PARAM;
+
+ sessn = XCALLOC(MTYPE_MGMTD_FRNTND_SESSION,
+ sizeof(struct mgmt_frntnd_client_session));
+ assert(sessn);
+ sessn->user_ctxt = user_ctxt;
+ sessn->client_id = client_id;
+ sessn->clnt_ctxt = clnt_ctxt;
+ sessn->session_id = 0;
+ mgmt_session_list_add_tail(&clnt_ctxt->client_sessions, sessn);
+
+ if (mgmt_frntnd_send_session_req(clnt_ctxt, sessn, true) != 0)
+ return MGMTD_INTERNAL_ERROR;
+
+ return MGMTD_SUCCESS;
+}
+
+/*
+ * Delete an existing Session for a Frontend Client connection.
+ */
+enum mgmt_result mgmt_frntnd_destroy_client_session(uintptr_t lib_hndl,
+ uintptr_t session_id)
+{
+ struct mgmt_frntnd_client_ctxt *clnt_ctxt;
+ struct mgmt_frntnd_client_session *sessn;
+
+ clnt_ctxt = (struct mgmt_frntnd_client_ctxt *)lib_hndl;
+ if (!clnt_ctxt)
+ return MGMTD_INVALID_PARAM;
+
+ sessn = (struct mgmt_frntnd_client_session *)session_id;
+ if (!sessn || sessn->clnt_ctxt != clnt_ctxt)
+ return MGMTD_INVALID_PARAM;
+
+ if (mgmt_frntnd_send_session_req(clnt_ctxt, sessn, false) != 0)
+ return MGMTD_INTERNAL_ERROR;
+
+ mgmt_session_list_del(&clnt_ctxt->client_sessions, sessn);
+ XFREE(MTYPE_MGMTD_FRNTND_SESSION, sessn);
+
+ return MGMTD_SUCCESS;
+}
+
+/*
+ * Send UN/LOCK_DB_REQ to MGMTD for a specific Datastore DB.
+ */
+enum mgmt_result mgmt_frntnd_lock_db(uintptr_t lib_hndl, uintptr_t session_id,
+ uint64_t req_id, Mgmtd__DatabaseId db_id,
+ bool lock_db)
+{
+ struct mgmt_frntnd_client_ctxt *clnt_ctxt;
+ struct mgmt_frntnd_client_session *sessn;
+
+ clnt_ctxt = (struct mgmt_frntnd_client_ctxt *)lib_hndl;
+ if (!clnt_ctxt)
+ return MGMTD_INVALID_PARAM;
+
+ sessn = (struct mgmt_frntnd_client_session *)session_id;
+ if (!sessn || sessn->clnt_ctxt != clnt_ctxt)
+ return MGMTD_INVALID_PARAM;
+
+ if (mgmt_frntnd_send_lockdb_req(clnt_ctxt, sessn, lock_db, req_id,
+ db_id)
+ != 0)
+ return MGMTD_INTERNAL_ERROR;
+
+ return MGMTD_SUCCESS;
+}
+
+/*
+ * Send SET_CONFIG_REQ to MGMTD for one or more config data(s).
+ */
+enum mgmt_result
+mgmt_frntnd_set_config_data(uintptr_t lib_hndl, uintptr_t session_id,
+ uint64_t req_id, Mgmtd__DatabaseId db_id,
+ Mgmtd__YangCfgDataReq **config_req, int num_reqs,
+ bool implicit_commit, Mgmtd__DatabaseId dst_db_id)
+{
+ struct mgmt_frntnd_client_ctxt *clnt_ctxt;
+ struct mgmt_frntnd_client_session *sessn;
+
+ clnt_ctxt = (struct mgmt_frntnd_client_ctxt *)lib_hndl;
+ if (!clnt_ctxt)
+ return MGMTD_INVALID_PARAM;
+
+ sessn = (struct mgmt_frntnd_client_session *)session_id;
+ if (!sessn || sessn->clnt_ctxt != clnt_ctxt)
+ return MGMTD_INVALID_PARAM;
+
+ if (mgmt_frntnd_send_setcfg_req(clnt_ctxt, sessn, req_id, db_id,
+ config_req, num_reqs, implicit_commit,
+ dst_db_id)
+ != 0)
+ return MGMTD_INTERNAL_ERROR;
+
+ return MGMTD_SUCCESS;
+}
+
+/*
+ * Send SET_CONFIG_REQ to MGMTD for one or more config data(s).
+ */
+enum mgmt_result mgmt_frntnd_commit_config_data(uintptr_t lib_hndl,
+ uintptr_t session_id,
+ uint64_t req_id,
+ Mgmtd__DatabaseId src_db_id,
+ Mgmtd__DatabaseId dst_db_id,
+ bool validate_only, bool abort)
+{
+ struct mgmt_frntnd_client_ctxt *clnt_ctxt;
+ struct mgmt_frntnd_client_session *sessn;
+
+ clnt_ctxt = (struct mgmt_frntnd_client_ctxt *)lib_hndl;
+ if (!clnt_ctxt)
+ return MGMTD_INVALID_PARAM;
+
+ sessn = (struct mgmt_frntnd_client_session *)session_id;
+ if (!sessn || sessn->clnt_ctxt != clnt_ctxt)
+ return MGMTD_INVALID_PARAM;
+
+ if (mgmt_frntnd_send_commitcfg_req(clnt_ctxt, sessn, req_id, src_db_id,
+ dst_db_id, validate_only, abort)
+ != 0)
+ return MGMTD_INTERNAL_ERROR;
+
+ return MGMTD_SUCCESS;
+}
+
+/*
+ * Send GET_CONFIG_REQ to MGMTD for one or more config data item(s).
+ */
+enum mgmt_result
+mgmt_frntnd_get_config_data(uintptr_t lib_hndl, uintptr_t session_id,
+ uint64_t req_id, Mgmtd__DatabaseId db_id,
+ Mgmtd__YangGetDataReq * data_req[], int num_reqs)
+{
+ struct mgmt_frntnd_client_ctxt *clnt_ctxt;
+ struct mgmt_frntnd_client_session *sessn;
+
+ clnt_ctxt = (struct mgmt_frntnd_client_ctxt *)lib_hndl;
+ if (!clnt_ctxt)
+ return MGMTD_INVALID_PARAM;
+
+ sessn = (struct mgmt_frntnd_client_session *)session_id;
+ if (!sessn || sessn->clnt_ctxt != clnt_ctxt)
+ return MGMTD_INVALID_PARAM;
+
+ if (mgmt_frntnd_send_getcfg_req(clnt_ctxt, sessn, req_id, db_id,
+ data_req, num_reqs)
+ != 0)
+ return MGMTD_INTERNAL_ERROR;
+
+ return MGMTD_SUCCESS;
+}
+
+/*
+ * Send GET_DATA_REQ to MGMTD for one or more config data item(s).
+ */
+enum mgmt_result mgmt_frntnd_get_data(uintptr_t lib_hndl, uintptr_t session_id,
+ uint64_t req_id, Mgmtd__DatabaseId db_id,
+ Mgmtd__YangGetDataReq * data_req[],
+ int num_reqs)
+{
+ struct mgmt_frntnd_client_ctxt *clnt_ctxt;
+ struct mgmt_frntnd_client_session *sessn;
+
+ clnt_ctxt = (struct mgmt_frntnd_client_ctxt *)lib_hndl;
+ if (!clnt_ctxt)
+ return MGMTD_INVALID_PARAM;
+
+ sessn = (struct mgmt_frntnd_client_session *)session_id;
+ if (!sessn || sessn->clnt_ctxt != clnt_ctxt)
+ return MGMTD_INVALID_PARAM;
+
+ if (mgmt_frntnd_send_getdata_req(clnt_ctxt, sessn, req_id, db_id,
+ data_req, num_reqs)
+ != 0)
+ return MGMTD_INTERNAL_ERROR;
+
+ return MGMTD_SUCCESS;
+}
+
+/*
+ * Send NOTIFY_REGISTER_REQ to MGMTD daemon.
+ */
+enum mgmt_result
+mgmt_frntnd_register_yang_notify(uintptr_t lib_hndl, uintptr_t session_id,
+ uint64_t req_id, Mgmtd__DatabaseId db_id,
+ bool register_req,
+ Mgmtd__YangDataXPath * data_req[],
+ int num_reqs)
+{
+ struct mgmt_frntnd_client_ctxt *clnt_ctxt;
+ struct mgmt_frntnd_client_session *sessn;
+
+ clnt_ctxt = (struct mgmt_frntnd_client_ctxt *)lib_hndl;
+ if (!clnt_ctxt)
+ return MGMTD_INVALID_PARAM;
+
+ sessn = (struct mgmt_frntnd_client_session *)session_id;
+ if (!sessn || sessn->clnt_ctxt != clnt_ctxt)
+ return MGMTD_INVALID_PARAM;
+
+ if (mgmt_frntnd_send_regnotify_req(clnt_ctxt, sessn, req_id, db_id,
+ register_req, data_req, num_reqs)
+ != 0)
+ return MGMTD_INTERNAL_ERROR;
+
+ return MGMTD_SUCCESS;
+}
+
+/*
+ * Destroy library and cleanup everything.
+ */
+void mgmt_frntnd_client_lib_destroy(uintptr_t lib_hndl)
+{
+ struct mgmt_frntnd_client_ctxt *clnt_ctxt;
+
+ clnt_ctxt = (struct mgmt_frntnd_client_ctxt *)lib_hndl;
+ assert(clnt_ctxt);
+
+ MGMTD_FRNTND_CLNT_DBG("Destroying MGMTD Frontend Client '%s'",
+ clnt_ctxt->client_params.name);
+
+ mgmt_frntnd_server_disconnect(clnt_ctxt, false);
+
+ assert(mgmt_frntnd_clntctxt.ibuf_fifo
+ && mgmt_frntnd_clntctxt.obuf_fifo);
+
+ THREAD_OFF(clnt_ctxt->conn_retry_tmr);
+ THREAD_OFF(clnt_ctxt->conn_read_ev);
+ THREAD_OFF(clnt_ctxt->conn_write_ev);
+ THREAD_OFF(clnt_ctxt->conn_writes_on);
+ THREAD_OFF(clnt_ctxt->msg_proc_ev);
+ stream_fifo_free(mgmt_frntnd_clntctxt.ibuf_fifo);
+ if (mgmt_frntnd_clntctxt.ibuf_work)
+ stream_free(mgmt_frntnd_clntctxt.ibuf_work);
+ stream_fifo_free(mgmt_frntnd_clntctxt.obuf_fifo);
+ if (mgmt_frntnd_clntctxt.obuf_work)
+ stream_free(mgmt_frntnd_clntctxt.obuf_work);
+}
--- /dev/null
+/*
+ * MGMTD Frontend Client Library api interfaces
+ * Copyright (C) 2021 Vmware, Inc.
+ * Pushpasis Sarkar <spushpasis@vmware.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _FRR_MGMTD_FRNTND_CLIENT_H_
+#define _FRR_MGMTD_FRNTND_CLIENT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mgmtd/mgmt_defines.h"
+#include "mgmt_pb.h"
+
+/***************************************************************
+ * Macros
+ ***************************************************************/
+
+/*
+ * The server port MGMTD daemon is listening for Backend Client
+ * connections.
+ */
+
+#define MGMTD_FRNTND_CLIENT_ERROR_STRING_MAX_LEN 32
+
+#define MGMTD_FRNTND_DEFAULT_CONN_RETRY_INTVL_SEC 5
+
+#define MGMTD_FRNTND_MSG_PROC_DELAY_USEC 10
+#define MGMTD_FRNTND_MAX_NUM_MSG_PROC 500
+
+#define MGMTD_FRNTND_MSG_WRITE_DELAY_MSEC 1
+#define MGMTD_FRNTND_MAX_NUM_MSG_WRITE 100
+
+#define GMGD_FRNTND_MAX_NUM_REQ_ITEMS 64
+
+#define MGMTD_FRNTND_MSG_MAX_LEN 9000
+
+#define MGMTD_SOCKET_FRNTND_SEND_BUF_SIZE 65535
+#define MGMTD_SOCKET_FRNTND_RECV_BUF_SIZE MGMTD_SOCKET_FRNTND_SEND_BUF_SIZE
+
+/***************************************************************
+ * Data-structures
+ ***************************************************************/
+
+#define MGMTD_SESSION_ID_NONE 0
+
+#define MGMTD_CLIENT_ID_NONE 0
+
+#define MGMTD_DB_NONE MGMTD__DATABASE_ID__DB_NONE
+#define MGMTD_DB_RUNNING MGMTD__DATABASE_ID__RUNNING_DB
+#define MGMTD_DB_CANDIDATE MGMTD__DATABASE_ID__CANDIDATE_DB
+#define MGMTD_DB_OPERATIONAL MGMTD__DATABASE_ID__OPERATIONAL_DB
+#define MGMTD_DB_MAX_ID MGMTD_DB_OPERATIONAL + 1
+
+struct mgmt_frntnd_msg_hdr {
+ uint16_t marker;
+ uint16_t len; /* Includes header */
+};
+#define MGMTD_FRNTND_MSG_HDR_LEN sizeof(struct mgmt_frntnd_msg_hdr)
+#define MGMTD_FRNTND_MSG_MARKER 0xdeaf
+
+struct mgmt_frntnd_msg {
+ struct mgmt_frntnd_msg_hdr hdr;
+ uint8_t payload[];
+};
+
+/*
+ * All the client specific information this library needs to
+ * initialize itself, setup connection with MGMTD FrontEnd interface
+ * and carry on all required procedures appropriately.
+ *
+ * FrontEnd clients need to initialise a instance of this structure
+ * with appropriate data and pass it while calling the API
+ * to initialize the library (See mgmt_frntnd_client_lib_init for
+ * more details).
+ */
+struct mgmt_frntnd_client_params {
+ char name[MGMTD_CLIENT_NAME_MAX_LEN];
+ uintptr_t user_data;
+ unsigned long conn_retry_intvl_sec;
+
+ void (*client_connect_notify)(uintptr_t lib_hndl,
+ uintptr_t user_data,
+ bool connected);
+
+ void (*client_session_notify)(uintptr_t lib_hndl,
+ uintptr_t user_data,
+ uint64_t client_id,
+ bool create, bool success,
+ uintptr_t session_id,
+ uintptr_t user_sessn_ctxt);
+
+ void (*lock_db_notify)(uintptr_t lib_hndl, uintptr_t user_data,
+ uint64_t client_id, uintptr_t session_id,
+ uintptr_t user_sessn_ctxt, uint64_t req_id,
+ bool lock_db, bool success,
+ Mgmtd__DatabaseId db_id, char *errmsg_if_any);
+
+ void (*set_config_notify)(uintptr_t lib_hndl, uintptr_t user_data,
+ uint64_t client_id, uintptr_t session_id,
+ uintptr_t user_sessn_ctxt, uint64_t req_id,
+ bool success, Mgmtd__DatabaseId db_id,
+ char *errmsg_if_any);
+
+ void (*commit_config_notify)(
+ uintptr_t lib_hndl, uintptr_t user_data, uint64_t client_id,
+ uintptr_t session_id, uintptr_t user_sessn_ctxt,
+ uint64_t req_id, bool success, Mgmtd__DatabaseId src_db_id,
+ Mgmtd__DatabaseId dst_db_id, bool validate_only,
+ char *errmsg_if_any);
+
+ enum mgmt_result (*get_data_notify)(
+ uintptr_t lib_hndl, uintptr_t user_data, uint64_t client_id,
+ uintptr_t session_id, uintptr_t user_sessn_ctxt,
+ uint64_t req_id, bool success, Mgmtd__DatabaseId db_id,
+ Mgmtd__YangData **yang_data, size_t num_data, int next_key,
+ char *errmsg_if_any);
+
+ enum mgmt_result (*data_notify)(
+ uint64_t client_id, uint64_t session_id, uintptr_t user_data,
+ uint64_t req_id, Mgmtd__DatabaseId db_id,
+ Mgmtd__YangData **yang_data, size_t num_data);
+};
+
+/***************************************************************
+ * API prototypes
+ ***************************************************************/
+
+/*
+ * Initialize library and try connecting with MGMTD FrontEnd interface.
+ *
+ * params
+ * Frontend client parameters.
+ *
+ * master_thread
+ * Thread master.
+ *
+ * Returns:
+ * Frontend client lib handler (nothing but address of mgmt_frntnd_clntctxt)
+ */
+extern uintptr_t
+mgmt_frntnd_client_lib_init(struct mgmt_frntnd_client_params *params,
+ struct thread_master *master_thread);
+
+/*
+ * Create a new Session for a Frontend Client connection.
+ *
+ * lib_hndl
+ * Client library handler.
+ *
+ * client_id
+ * Unique identifier of client.
+ *
+ * user_ctxt
+ * Client context.
+ *
+ * Returns:
+ * MGMTD_SUCCESS on success, MGMTD_* otherwise.
+ */
+extern enum mgmt_result mgmt_frntnd_create_client_session(uintptr_t lib_hndl,
+ uint64_t client_id,
+ uintptr_t user_ctxt);
+
+/*
+ * Delete an existing Session for a Frontend Client connection.
+ *
+ * lib_hndl
+ * Client library handler.
+ *
+ * session_id
+ * Client session ID.
+ *
+ * Returns:
+ * MGMTD_SUCCESS on success, MGMTD_* otherwise.
+ */
+extern enum mgmt_result
+mgmt_frntnd_destroy_client_session(uintptr_t lib_hndl, uintptr_t session_id);
+
+/*
+ * Send UN/LOCK_DB_REQ to MGMTD for a specific Datastore DB.
+ *
+ * lib_hndl
+ * Client library handler.
+ *
+ * session_id
+ * Client session ID.
+ *
+ * req_id
+ * Client request ID.
+ *
+ * db_id
+ * Database ID (Running/Candidate/Oper/Startup)
+ *
+ * lock_db
+ * TRUE for lock request, FALSE for unlock request.
+ *
+ * Returns:
+ * MGMTD_SUCCESS on success, MGMTD_* otherwise.
+ */
+extern enum mgmt_result
+mgmt_frntnd_lock_db(uintptr_t lib_hndl, uintptr_t session_id, uint64_t req_id,
+ Mgmtd__DatabaseId db_id, bool lock_db);
+
+/*
+ * Send SET_CONFIG_REQ to MGMTD for one or more config data(s).
+ *
+ * lib_hndl
+ * Client library handler.
+ *
+ * session_id
+ * Client session ID.
+ *
+ * req_id
+ * Client request ID.
+ *
+ * db_id
+ * Database ID (Running/Candidate/Oper/Startup)
+ *
+ * conf_req
+ * Details regarding the SET_CONFIG_REQ.
+ *
+ * num_req
+ * Number of config requests.
+ *
+ * implcit commit
+ * TRUE for implicit commit, FALSE otherwise.
+ *
+ * dst_db_id
+ * Destination Database ID where data needs to be set.
+ *
+ * Returns:
+ * MGMTD_SUCCESS on success, MGMTD_* otherwise.
+ */
+extern enum mgmt_result
+mgmt_frntnd_set_config_data(uintptr_t lib_hndl, uintptr_t session_id,
+ uint64_t req_id, Mgmtd__DatabaseId db_id,
+ Mgmtd__YangCfgDataReq **config_req, int num_req,
+ bool implicit_commit, Mgmtd__DatabaseId dst_db_id);
+
+/*
+ * Send SET_COMMMIT_REQ to MGMTD for one or more config data(s).
+ *
+ * lib_hndl
+ * Client library handler.
+ *
+ * session_id
+ * Client session ID.
+ *
+ * req_id
+ * Client request ID.
+ *
+ * src_db_id
+ * Source database ID from where data needs to be committed from.
+ *
+ * dst_db_id
+ * Destination database ID where data needs to be committed to.
+ *
+ * validate_only
+ * TRUE if data needs to be validated only, FALSE otherwise.
+ *
+ * abort
+ * TRUE if need to restore Src DB back to Dest DB, FALSE otherwise.
+ *
+ * Returns:
+ * MGMTD_SUCCESS on success, MGMTD_* otherwise.
+ */
+extern enum mgmt_result
+mgmt_frntnd_commit_config_data(uintptr_t lib_hndl, uintptr_t session_id,
+ uint64_t req_id, Mgmtd__DatabaseId src_db_id,
+ Mgmtd__DatabaseId dst_db_id, bool validate_only,
+ bool abort);
+
+/*
+ * Send GET_CONFIG_REQ to MGMTD for one or more config data item(s).
+ *
+ * lib_hndl
+ * Client library handler.
+ *
+ * session_id
+ * Client session ID.
+ *
+ * req_id
+ * Client request ID.
+ *
+ * db_id
+ * Database ID (Running/Candidate)
+ *
+ * data_req
+ * Get config requested.
+ *
+ * num_req
+ * Number of get config requests.
+ *
+ * Returns:
+ * MGMTD_SUCCESS on success, MGMTD_* otherwise.
+ */
+extern enum mgmt_result
+mgmt_frntnd_get_config_data(uintptr_t lib_hndl, uintptr_t session_id,
+ uint64_t req_id, Mgmtd__DatabaseId db_id,
+ Mgmtd__YangGetDataReq **data_req, int num_reqs);
+
+/*
+ * Send GET_DATA_REQ to MGMTD for one or more data item(s).
+ *
+ * Similar to get config request but supports getting data
+ * from operational db aka backend clients directly.
+ */
+extern enum mgmt_result
+mgmt_frntnd_get_data(uintptr_t lib_hndl, uintptr_t session_id, uint64_t req_id,
+ Mgmtd__DatabaseId db_id, Mgmtd__YangGetDataReq **data_req,
+ int num_reqs);
+
+/*
+ * Send NOTIFY_REGISTER_REQ to MGMTD daemon.
+ *
+ * lib_hndl
+ * Client library handler.
+ *
+ * session_id
+ * Client session ID.
+ *
+ * req_id
+ * Client request ID.
+ *
+ * db_id
+ * Database ID.
+ *
+ * register_req
+ * TRUE if registering, FALSE otherwise.
+ *
+ * data_req
+ * Details of the YANG notification data.
+ *
+ * num_reqs
+ * Number of data requests.
+ *
+ * Returns:
+ * MGMTD_SUCCESS on success, MGMTD_* otherwise.
+ */
+extern enum mgmt_result
+mgmt_frntnd_register_yang_notify(uintptr_t lib_hndl, uintptr_t session_id,
+ uint64_t req_id, Mgmtd__DatabaseId db_id,
+ bool register_req,
+ Mgmtd__YangDataXPath **data_req, int num_reqs);
+
+/*
+ * Destroy library and cleanup everything.
+ */
+extern void mgmt_frntnd_client_lib_destroy(uintptr_t lib_hndl);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FRR_MGMTD_FRNTND_CLIENT_H_ */
--- /dev/null
+/*
+ * MGMTD protobuf main header file
+ * Copyright (C) 2021 Vmware, Inc.
+ * Pushpasis Sarkar <spushpasis@vmware.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _FRR_MGMTD_PB_H_
+#define _FRR_MGMTD_PB_H_
+
+#include "lib/mgmt.pb-c.h"
+
+#define mgmt_yang_data_xpath_init(ptr) mgmtd__yang_data_xpath__init(ptr)
+
+#define mgmt_yang_data_value_init(ptr) mgmtd__yang_data_value__init(ptr)
+
+#define mgmt_yang_data_init(ptr) mgmtd__yang_data__init(ptr)
+
+#define mgmt_yang_data_reply_init(ptr) mgmtd__yang_data_reply__init(ptr)
+
+#define mgmt_yang_cfg_data_req_init(ptr) mgmtd__yang_cfg_data_req__init(ptr)
+
+#define mgmt_yang_get_data_req_init(ptr) mgmtd__yang_get_data_req__init(ptr)
+
+#endif /* _FRR_MGMTD_PB_H_ */
NB_OP_RPC,
};
+struct nb_cfg_change {
+ char xpath[XPATH_MAXLEN];
+ enum nb_operation operation;
+ const char *value;
+};
+
union nb_resource {
int fd;
void *ptr;
void nb_cli_enqueue_change(struct vty *vty, const char *xpath,
enum nb_operation operation, const char *value)
{
- struct vty_cfg_change *change;
+ struct nb_cfg_change *change;
if (vty->num_cfg_changes == VTY_MAXCFGCHANGES) {
/* Not expected to happen. */
/* Edit candidate configuration. */
for (size_t i = 0; i < vty->num_cfg_changes; i++) {
- struct vty_cfg_change *change = &vty->cfg_changes[i];
+ struct nb_cfg_change *change = &vty->cfg_changes[i];
struct nb_node *nb_node;
char xpath[XPATH_MAXLEN];
struct yang_data *data;
lib/northbound.c \
lib/northbound_cli.c \
lib/northbound_db.c \
+ lib/mgmt_frntnd_client.c \
lib/ntop.c \
lib/openbsd-tree.c \
lib/pid_output.c \
yang/frr-module-translator.yang.c \
# end
+# Add logic to build mgmt.proto
+lib_libfrr_la_LIBADD += $(PROTOBUF_C_LIBS)
+
+BUILT_SOURCES += \
+ lib/mgmt.pb-c.c \
+ lib/mgmt.pb-c.h \
+ # end
+
+CLEANFILES += \
+ lib/mgmt.pb-c.h \
+ lib/mgmt.pb-c.c \
+ # end
+
+lib_libfrr_la_SOURCES += \
+ lib/mgmt.pb-c.c \
+ #end
+
vtysh_scan += \
lib/distribute.c \
lib/filter.c \
lib/buffer.h \
lib/checksum.h \
lib/mlag.h \
+ lib/mgmt_frntnd_client.h \
+ lib/mgmt.pb-c.h \
+ lib/mgmt_pb.h \
lib/command.h \
lib/command_graph.h \
lib/command_match.h \
#endif /* VTYSH */
};
+struct nb_config *vty_mgmt_candidate_config;
+
+static uintptr_t mgmt_lib_hndl;
+static bool mgmt_frntnd_connected;
+static bool mgmt_candidate_db_wr_locked;
+static uint64_t mgmt_client_id_next;
+static uint64_t mgmt_last_req_id = UINT64_MAX;
+
PREDECL_DLIST(vtyservs);
struct vty_serv {
static void vty_event_serv(enum vty_event event, struct vty_serv *);
static void vty_event(enum vty_event, struct vty *);
+static int vtysh_flush(struct vty *vty);
/* Extern host structure from command.c */
extern struct host host;
static bool do_log_commands;
static bool do_log_commands_perm;
+static void vty_mgmt_resume_response(struct vty *vty, bool success)
+{
+ uint8_t header[4] = {0, 0, 0, 0};
+ int ret = CMD_SUCCESS;
+
+ if (!vty->mgmt_req_pending) {
+ zlog_err(
+ "vty response called without setting mgmt_req_pending");
+ return;
+ }
+
+ if (!success)
+ ret = CMD_WARNING_CONFIG_FAILED;
+
+ vty->mgmt_req_pending = false;
+ header[3] = ret;
+ buffer_put(vty->obuf, header, 4);
+
+ if (!vty->t_write && (vtysh_flush(vty) < 0))
+ /* Try to flush results; exit if a write
+ * error occurs.
+ */
+ return;
+
+ if (vty->status == VTY_CLOSE)
+ vty_close(vty);
+ else
+ vty_event(VTYSH_READ, vty);
+}
+
void vty_frame(struct vty *vty, const char *format, ...)
{
va_list args;
new->max = VTY_BUFSIZ;
new->pass_fd = -1;
+ if (mgmt_lib_hndl) {
+ new->mgmt_client_id = mgmt_client_id_next++;
+ if (mgmt_frntnd_create_client_session(mgmt_lib_hndl,
+ new->mgmt_client_id,
+ (uintptr_t)new)
+ != MGMTD_SUCCESS)
+ zlog_err(
+ "Failed to open a MGMTD Frontend session for VTY session %p!!",
+ new);
+ }
+
return new;
}
if (ret == CMD_SUSPEND)
break;
+ /* with new infra we need to stop response till
+ * we get response through callback.
+ */
+ if (vty->mgmt_req_pending)
+ return;
+
/* warning: watchfrr hardcodes this result write
*/
header[3] = ret;
int i;
bool was_stdio = false;
+ if (mgmt_lib_hndl) {
+ mgmt_frntnd_destroy_client_session(mgmt_lib_hndl,
+ vty->mgmt_session_id);
+ vty->mgmt_session_id = 0;
+ }
+
/* Drop out of configure / transaction if needed. */
vty_config_exit(vty);
return CMD_WARNING;
}
+ if (vty_mgmt_frntnd_enabled()) {
+ if (!mgmt_candidate_db_wr_locked) {
+ if (vty_mgmt_send_lockdb_req(vty, MGMTD_DB_CANDIDATE,
+ true)
+ != 0) {
+ vty_out(vty, "Not able to lock candidate DB\n");
+ return CMD_WARNING;
+ }
+ } else {
+ vty_out(vty,
+ "Candidate DB already locked by different session\n");
+ return CMD_WARNING;
+ }
+
+ vty->mgmt_locked_candidate_db = true;
+ mgmt_candidate_db_wr_locked = true;
+ }
+
vty->node = CONFIG_NODE;
vty->config = true;
vty->private_config = private_config;
vty_out(vty,
"Warning: uncommitted changes will be discarded on exit.\n\n");
} else {
- vty->candidate_config = vty_shared_candidate_config;
+ /*
+ * NOTE: On the MGMTD daemon we point the VTY candidate DB to
+ * the global MGMTD candidate DB. Else we point to the VTY
+ * Shared Candidate Config.
+ */
+ vty->candidate_config = vty_mgmt_candidate_config
+ ? vty_mgmt_candidate_config
+ : vty_shared_candidate_config;
if (frr_get_cli_mode() == FRR_CLI_TRANSACTIONAL)
vty->candidate_config_base =
nb_config_dup(running_config);
{
vty->xpath_index = 0;
+ if (vty_mgmt_frntnd_enabled() && mgmt_candidate_db_wr_locked
+ && vty->mgmt_locked_candidate_db) {
+ if (vty_mgmt_send_lockdb_req(vty, MGMTD_DB_CANDIDATE, false)
+ != 0) {
+ vty_out(vty, "Not able to unlock candidate DB\n");
+ return CMD_WARNING;
+ }
+
+ vty->mgmt_locked_candidate_db = false;
+ mgmt_candidate_db_wr_locked = false;
+ }
+
/* Perform any pending commits. */
(void)nb_cli_pending_commit_check(vty);
/* currently nothing to do, but likely to have future use */
}
+static void vty_mgmt_server_connected(uintptr_t lib_hndl, uintptr_t usr_data,
+ bool connected)
+{
+ zlog_err("%sGot %sconnected %s MGMTD Frontend Server",
+ !connected ? "ERROR: " : "", !connected ? "dis: " : "",
+ !connected ? "from" : "to");
+
+ mgmt_frntnd_connected = connected;
+
+ /*
+ * TODO: Setup or teardown front-end sessions for existing
+ * VTY connections.
+ */
+}
+
+static void vty_mgmt_session_created(uintptr_t lib_hndl, uintptr_t usr_data,
+ uint64_t client_id, bool create,
+ bool success, uintptr_t session_id,
+ uintptr_t sessn_ctxt)
+{
+ struct vty *vty;
+
+ vty = (struct vty *)sessn_ctxt;
+
+ if (!success) {
+ zlog_err("%s session for client %llu failed!",
+ create ? "Creating" : "Destroying",
+ (unsigned long long)client_id);
+ return;
+ }
+
+ zlog_err("%s session for client %llu successfully!",
+ create ? "Created" : "Destroyed",
+ (unsigned long long)client_id);
+ if (create)
+ vty->mgmt_session_id = session_id;
+}
+
+static void vty_mgmt_db_lock_notified(uintptr_t lib_hndl, uintptr_t usr_data,
+ uint64_t client_id, uintptr_t session_id,
+ uintptr_t sessn_ctxt, uint64_t req_id,
+ bool lock_db, bool success,
+ Mgmtd__DatabaseId db_id,
+ char *errmsg_if_any)
+{
+ struct vty *vty;
+
+ vty = (struct vty *)sessn_ctxt;
+
+ if (!success) {
+ zlog_err("%socking for DB %u failed! Err: '%s'",
+ lock_db ? "L" : "Unl", db_id, errmsg_if_any);
+ vty_out(vty, "ERROR: %socking for DB %u failed! Err: '%s'\n",
+ lock_db ? "L" : "Unl", db_id, errmsg_if_any);
+ } else {
+ zlog_err("%socked DB %u successfully!", lock_db ? "L" : "Unl",
+ db_id);
+ }
+
+ vty_mgmt_resume_response(vty, success);
+}
+
+static void vty_mgmt_set_config_result_notified(
+ uintptr_t lib_hndl, uintptr_t usr_data, uint64_t client_id,
+ uintptr_t session_id, uintptr_t sessn_ctxt, uint64_t req_id,
+ bool success, Mgmtd__DatabaseId db_id, char *errmsg_if_any)
+{
+ struct vty *vty;
+
+ vty = (struct vty *)sessn_ctxt;
+
+ if (!success) {
+ zlog_err(
+ "SET_CONFIG request for client 0x%llx failed! Error: '%s'",
+ (unsigned long long)client_id,
+ errmsg_if_any ? errmsg_if_any : "Unknown");
+ vty_out(vty, "ERROR: SET_CONFIG request failed! Error: %s\n",
+ errmsg_if_any ? errmsg_if_any : "Unknown");
+ } else {
+ zlog_err(
+ "SET_CONFIG request for client 0x%llx req-id %llu was successfull!",
+ (unsigned long long)client_id,
+ (unsigned long long)req_id);
+ }
+
+ vty_mgmt_resume_response(vty, success);
+}
+
+static void vty_mgmt_commit_config_result_notified(
+ uintptr_t lib_hndl, uintptr_t usr_data, uint64_t client_id,
+ uintptr_t session_id, uintptr_t sessn_ctxt, uint64_t req_id,
+ bool success, Mgmtd__DatabaseId src_db_id, Mgmtd__DatabaseId dst_db_id,
+ bool validate_only, char *errmsg_if_any)
+{
+ struct vty *vty;
+
+ vty = (struct vty *)sessn_ctxt;
+
+ if (!success) {
+ zlog_err(
+ "COMMIT_CONFIG request for client 0x%llx failed! Error: '%s'",
+ (unsigned long long)client_id,
+ errmsg_if_any ? errmsg_if_any : "Unknown");
+ vty_out(vty, "ERROR: COMMIT_CONFIG request failed! Error: %s\n",
+ errmsg_if_any ? errmsg_if_any : "Unknown");
+ } else {
+ zlog_err(
+ "COMMIT_CONFIG request for client 0x%llx req-id %llu was successfull!",
+ (unsigned long long)client_id,
+ (unsigned long long)req_id);
+ if (errmsg_if_any)
+ vty_out(vty, "MGMTD: %s\n", errmsg_if_any);
+ }
+
+ vty_mgmt_resume_response(vty, success);
+}
+
+static enum mgmt_result vty_mgmt_get_data_result_notified(
+ uintptr_t lib_hndl, uintptr_t usr_data, uint64_t client_id,
+ uintptr_t session_id, uintptr_t sessn_ctxt, uint64_t req_id,
+ bool success, Mgmtd__DatabaseId db_id, Mgmtd__YangData **yang_data,
+ size_t num_data, int next_key, char *errmsg_if_any)
+{
+ struct vty *vty;
+ size_t indx;
+
+ vty = (struct vty *)sessn_ctxt;
+
+ if (!success) {
+ zlog_err(
+ "GET_DATA request for client 0x%llx failed! Error: '%s'",
+ (unsigned long long)client_id,
+ errmsg_if_any ? errmsg_if_any : "Unknown");
+ vty_out(vty, "ERROR: GET_DATA request failed! Error: %s\n",
+ errmsg_if_any ? errmsg_if_any : "Unknown");
+ vty_mgmt_resume_response(vty, success);
+ return MGMTD_INTERNAL_ERROR;
+ }
+
+ zlog_debug(
+ "GET_DATA request for client 0x%llx req-id %llu was successfull!",
+ (unsigned long long)client_id, (unsigned long long)req_id);
+
+ if (req_id != mgmt_last_req_id) {
+ mgmt_last_req_id = req_id;
+ vty_out(vty, "[\n");
+ }
+
+ for (indx = 0; indx < num_data; indx++) {
+ vty_out(vty, " \"%s\": \"%s\"\n", yang_data[indx]->xpath,
+ yang_data[indx]->value->encoded_str_val);
+ }
+ if (next_key < 0) {
+ vty_out(vty, "]\n");
+ vty_mgmt_resume_response(vty, success);
+ }
+
+ return MGMTD_SUCCESS;
+}
+
+static struct mgmt_frntnd_client_params client_params = {
+ .client_connect_notify = vty_mgmt_server_connected,
+ .client_session_notify = vty_mgmt_session_created,
+ .lock_db_notify = vty_mgmt_db_lock_notified,
+ .set_config_notify =
+ vty_mgmt_set_config_result_notified,
+ .commit_config_notify =
+ vty_mgmt_commit_config_result_notified,
+ .get_data_notify = vty_mgmt_get_data_result_notified,
+};
+
+void vty_init_mgmt_frntnd(void)
+{
+ if (!vty_master) {
+ zlog_err(
+ "Always call vty_mgmt_init_frntnd() after vty_init()!!");
+ return;
+ }
+
+ assert(!mgmt_lib_hndl);
+ snprintf(client_params.name, sizeof(client_params.name), "%s-%lld",
+ frr_get_progname(), (long long)getpid());
+ mgmt_lib_hndl = mgmt_frntnd_client_lib_init(&client_params, vty_master);
+ assert(mgmt_lib_hndl);
+}
+
+bool vty_mgmt_frntnd_enabled(void)
+{
+ return mgmt_lib_hndl && mgmt_frntnd_connected ? true : false;
+}
+
+int vty_mgmt_send_lockdb_req(struct vty *vty, Mgmtd__DatabaseId db_id,
+ bool lock)
+{
+ enum mgmt_result ret;
+
+ if (mgmt_lib_hndl && vty->mgmt_session_id) {
+ vty->mgmt_req_id++;
+ ret = mgmt_frntnd_lock_db(mgmt_lib_hndl, vty->mgmt_session_id,
+ vty->mgmt_req_id, db_id, lock);
+ if (ret != MGMTD_SUCCESS) {
+ zlog_err(
+ "Failed to send %sLOCK-DB-REQ to MGMTD for req-id %llu.",
+ lock ? "" : "UN",
+ (unsigned long long)vty->mgmt_req_id);
+ vty_out(vty, "Failed to send %sLOCK-DB-REQ to MGMTD!",
+ lock ? "" : "UN");
+ return -1;
+ }
+
+ vty->mgmt_req_pending = true;
+ }
+
+ return 0;
+}
+
+int vty_mgmt_send_config_data(struct vty *vty)
+{
+ Mgmtd__YangDataValue value[VTY_MAXCFGCHANGES];
+ Mgmtd__YangData cfg_data[VTY_MAXCFGCHANGES];
+ Mgmtd__YangCfgDataReq cfg_req[VTY_MAXCFGCHANGES];
+ Mgmtd__YangCfgDataReq * cfgreq[VTY_MAXCFGCHANGES] = {0};
+ size_t indx;
+ int cnt;
+
+ if (mgmt_lib_hndl && vty->mgmt_session_id) {
+ cnt = 0;
+ for (indx = 0; indx < vty->num_cfg_changes; indx++) {
+ mgmt_yang_data_init(&cfg_data[cnt]);
+
+ if (vty->cfg_changes[indx].value) {
+ mgmt_yang_data_value_init(&value[cnt]);
+ value[cnt].encoded_str_val =
+ (char *)vty->cfg_changes[indx].value;
+ value[cnt].value_case =
+ MGMTD__YANG_DATA_VALUE__VALUE_ENCODED_STR_VAL;
+ cfg_data[cnt].value = &value[cnt];
+ }
+
+ cfg_data[cnt].xpath = vty->cfg_changes[indx].xpath;
+
+ mgmt_yang_cfg_data_req_init(&cfg_req[cnt]);
+ cfg_req[cnt].data = &cfg_data[cnt];
+ switch (vty->cfg_changes[indx].operation) {
+ case NB_OP_DESTROY:
+ cfg_req[cnt].req_type =
+ MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA;
+ break;
+ default:
+ cfg_req[cnt].req_type =
+ MGMTD__CFG_DATA_REQ_TYPE__SET_DATA;
+ break;
+ }
+
+ cfgreq[cnt] = &cfg_req[cnt];
+ cnt++;
+ }
+
+ vty->mgmt_req_id++;
+ if (cnt
+ && mgmt_frntnd_set_config_data(
+ mgmt_lib_hndl, vty->mgmt_session_id,
+ vty->mgmt_req_id, MGMTD_DB_CANDIDATE, cfgreq,
+ cnt,
+ frr_get_cli_mode() == FRR_CLI_CLASSIC
+ ? ((vty->pending_allowed
+ || vty->no_implicit_commit)
+ ? false
+ : true)
+ : false,
+ MGMTD_DB_RUNNING)
+ != MGMTD_SUCCESS) {
+ zlog_err("Failed to send %d Config Xpaths to MGMTD!!",
+ (int)indx);
+ return -1;
+ }
+
+ vty->mgmt_req_pending = true;
+ }
+
+ return 0;
+}
+
+int vty_mgmt_send_commit_config(struct vty *vty, bool validate_only, bool abort)
+{
+ enum mgmt_result ret;
+
+ if (mgmt_lib_hndl && vty->mgmt_session_id) {
+ vty->mgmt_req_id++;
+ ret = mgmt_frntnd_commit_config_data(
+ mgmt_lib_hndl, vty->mgmt_session_id, vty->mgmt_req_id,
+ MGMTD_DB_CANDIDATE, MGMTD_DB_RUNNING, validate_only,
+ abort);
+ if (ret != MGMTD_SUCCESS) {
+ zlog_err(
+ "Failed to send COMMIT-REQ to MGMTD for req-id %llu.",
+ (unsigned long long)vty->mgmt_req_id);
+ vty_out(vty, "Failed to send COMMIT-REQ to MGMTD!");
+ return -1;
+ }
+
+ vty->mgmt_req_pending = true;
+ }
+
+ return 0;
+}
+
+int vty_mgmt_send_get_config(struct vty *vty, Mgmtd__DatabaseId database,
+ const char **xpath_list, int num_req)
+{
+ enum mgmt_result ret;
+ Mgmtd__YangData yang_data[VTY_MAXCFGCHANGES];
+ Mgmtd__YangGetDataReq get_req[VTY_MAXCFGCHANGES];
+ Mgmtd__YangGetDataReq * getreq[VTY_MAXCFGCHANGES];
+ int i;
+
+ vty->mgmt_req_id++;
+
+ for (i = 0; i < num_req; i++) {
+ mgmt_yang_get_data_req_init(&get_req[i]);
+ mgmt_yang_data_init(&yang_data[i]);
+
+ yang_data->xpath = (char *)xpath_list[i];
+
+ get_req[i].data = &yang_data[i];
+ getreq[i] = &get_req[i];
+ }
+ ret = mgmt_frntnd_get_config_data(mgmt_lib_hndl, vty->mgmt_session_id,
+ vty->mgmt_req_id, database, getreq,
+ num_req);
+
+ if (ret != MGMTD_SUCCESS) {
+ zlog_err("Failed to send GET-CONFIG to MGMTD for req-id %llu.",
+ (unsigned long long)vty->mgmt_req_id);
+ vty_out(vty, "Failed to send GET-CONFIG to MGMTD!");
+ return -1;
+ }
+
+ vty->mgmt_req_pending = true;
+
+ return 0;
+}
+
+int vty_mgmt_send_get_data(struct vty *vty, Mgmtd__DatabaseId database,
+ const char **xpath_list, int num_req)
+{
+ enum mgmt_result ret;
+ Mgmtd__YangData yang_data[VTY_MAXCFGCHANGES];
+ Mgmtd__YangGetDataReq get_req[VTY_MAXCFGCHANGES];
+ Mgmtd__YangGetDataReq * getreq[VTY_MAXCFGCHANGES];
+ int i;
+
+ vty->mgmt_req_id++;
+
+ for (i = 0; i < num_req; i++) {
+ mgmt_yang_get_data_req_init(&get_req[i]);
+ mgmt_yang_data_init(&yang_data[i]);
+
+ yang_data->xpath = (char *)xpath_list[i];
+
+ get_req[i].data = &yang_data[i];
+ getreq[i] = &get_req[i];
+ }
+ ret = mgmt_frntnd_get_data(mgmt_lib_hndl, vty->mgmt_session_id,
+ vty->mgmt_req_id, database, getreq, num_req);
+
+ if (ret != MGMTD_SUCCESS) {
+ zlog_err("Failed to send GET-DATA to MGMTD for req-id %llu.",
+ (unsigned long long)vty->mgmt_req_id);
+ vty_out(vty, "Failed to send GET-DATA to MGMTD!");
+ return -1;
+ }
+
+ vty->mgmt_req_pending = true;
+
+ return 0;
+}
+
/* Install vty's own commands like `who' command. */
void vty_init(struct thread_master *master_thread, bool do_command_logging)
{
struct vty *vty;
struct vty_serv *vtyserv;
+ if (mgmt_lib_hndl) {
+ mgmt_frntnd_client_lib_destroy(mgmt_lib_hndl);
+ mgmt_lib_hndl = 0;
+ }
+
memset(vty_cwd, 0x00, sizeof(vty_cwd));
vty_reset();
#include "compiler.h"
#include "northbound.h"
#include "zlog_live.h"
+#include "mgmt_frntnd_client.h"
#ifdef __cplusplus
extern "C" {
/* Changes enqueued to be applied in the candidate configuration. */
size_t num_cfg_changes;
- struct vty_cfg_change cfg_changes[VTY_MAXCFGCHANGES];
+ struct nb_cfg_change cfg_changes[VTY_MAXCFGCHANGES];
/* XPath of the current node */
int xpath_index;
/* Dynamic transaction information. */
bool pending_allowed;
bool pending_commit;
+ bool no_implicit_commit;
char *pending_cmds_buf;
size_t pending_cmds_buflen;
size_t pending_cmds_bufpos;
* without any output. */
size_t frame_pos;
char frame[1024];
+
+ uintptr_t mgmt_session_id;
+ uint64_t mgmt_client_id;
+ uint64_t mgmt_req_id;
+ bool mgmt_req_pending;
+ bool mgmt_locked_candidate_db;
};
static inline void vty_push_context(struct vty *vty, int node, uint64_t id)
#define IS_DIRECTORY_SEP(c) ((c) == DIRECTORY_SEP)
#endif
+extern struct nb_config *vty_mgmt_candidate_config;
+
/* Prototypes. */
extern void vty_init(struct thread_master *, bool do_command_logging);
extern void vty_init_vtysh(void);
extern void vty_stdio_resume(void);
extern void vty_stdio_close(void);
+extern void vty_init_mgmt_frntnd(void);
+extern bool vty_mgmt_frntnd_enabled(void);
+extern int vty_mgmt_send_config_data(struct vty *vty);
+extern int vty_mgmt_send_commit_config(struct vty *vty, bool validate_only,
+ bool abort);
+extern int vty_mgmt_send_get_config(struct vty *vty, Mgmtd__DatabaseId database,
+ const char **xpath_list, int num_req);
+extern int vty_mgmt_send_get_data(struct vty *vty, Mgmtd__DatabaseId database,
+ const char **xpath_list, int num_req);
+extern int vty_mgmt_send_lockdb_req(struct vty *vty, Mgmtd__DatabaseId db_id,
+ bool lock);
+
#ifdef __cplusplus
}
#endif
#include <zebra.h>
#include "mgmtd/mgmt.h"
#include "mgmtd/mgmt_vty.h"
+#include "mgmtd/mgmt_frntnd_server.h"
+#include "mgmtd/mgmt_frntnd_adapter.h"
#include "mgmtd/mgmt_db.h"
#include "mgmtd/mgmt_memory.h"
void mgmt_init(void)
{
+ /*
+ * Allocates some vital data structures used by peer commands in
+ * vty_init
+ */
+ vty_init_mgmt_frntnd();
+
/* Initialize databases */
mgmt_db_init(mm);
+ /* Initialize the MGMTD Frontend Adapter Module */
+ mgmt_frntnd_adapter_init(mm->master, mm);
+
+ /* Start the MGMTD Frontend Server for clients to connect */
+ mgmt_frntnd_server_init(mm->master);
+
/* MGMTD VTY commands installation. */
mgmt_vty_init();
}
void mgmt_terminate(void)
{
+ mgmt_frntnd_server_destroy();
+ mgmt_frntnd_adapter_destroy();
mgmt_db_destroy();
}
#include "vrf.h"
#include "defaults.h"
+#include "stream.h"
#include "mgmtd/mgmt_memory.h"
#include "mgmtd/mgmt_db.h"
extern struct mgmt_master *mm;
+/* Inline functions */
+static inline unsigned long timeval_elapsed(struct timeval a, struct timeval b)
+{
+ return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO)
+ + (a.tv_usec - b.tv_usec));
+}
+
/*
* Remove trailing separator from a string.
*
#endif /* REDIRECT_DEBUG_TO_STDERR */
struct mgmt_db_ctxt {
- enum mgmt_database_id db_id;
+ Mgmtd__DatabaseId db_id;
pthread_rwlock_t rw_lock;
bool config_db;
/*
* TODO: Free the databases.
*/
-
}
struct mgmt_db_ctxt *mgmt_db_get_hndl_by_id(struct mgmt_master *mm,
- enum mgmt_database_id db_id)
+ Mgmtd__DatabaseId db_id)
{
switch (db_id) {
case MGMTD_DB_CANDIDATE:
return (mm->running_db);
case MGMTD_DB_OPERATIONAL:
return (mm->oper_db);
- default:
+ case MGMTD_DB_NONE:
+ case MGMTD__DATABASE_ID__STARTUP_DB:
+ case _MGMTD__DATABASE_ID_IS_INT_SIZE:
return 0;
}
struct mgmt_db_ctxt;
-/*
- * Database-Id: For now defined here. Eventually will be
- * defined as part of MGMTD Front-End interface.
- */
-enum mgmt_database_id {
- MGMTD_DB_NONE = 0,
- MGMTD_DB_RUNNING,
- MGMTD_DB_CANDIDATE,
- MGMTD_DB_OPERATIONAL,
- MGMTD_DB_MAX_ID
-};
-
typedef void (*mgmt_db_node_iter_fn)(uint64_t db_hndl, char *xpath,
struct lyd_node *node,
struct nb_node *nb_node, void *ctxt);
* Returns:
* Database name.
*/
-static inline const char *mgmt_db_id2name(enum mgmt_database_id id)
+static inline const char *mgmt_db_id2name(Mgmtd__DatabaseId id)
{
if (id > MGMTD_DB_MAX_ID)
id = MGMTD_DB_MAX_ID;
* Returns:
* Database ID.
*/
-static inline enum mgmt_database_id mgmt_db_name2id(const char *name)
+static inline Mgmtd__DatabaseId mgmt_db_name2id(const char *name)
{
- enum mgmt_database_id id;
+ Mgmtd__DatabaseId id;
FOREACH_MGMTD_DB_ID (id) {
if (!strncmp(mgmt_db_names[id], name, MGMTD_DB_NAME_MAX_LEN))
*
* similar to above funtion.
*/
-static inline enum mgmt_database_id mgmt_get_db_id_by_name(const char *db_name)
+static inline Mgmtd__DatabaseId mgmt_get_db_id_by_name(const char *db_name)
{
if (!strncmp(db_name, "candidate", sizeof("candidate")))
return MGMTD_DB_CANDIDATE;
* Database context (Holds info about ID, lock, root node etc).
*/
extern struct mgmt_db_ctxt *mgmt_db_get_hndl_by_id(struct mgmt_master *mm,
- enum mgmt_database_id db_id);
+ Mgmtd__DatabaseId db_id);
/*
* Check if a given database is config db
#ifndef _FRR_MGMTD_DEFINES_H
#define _FRR_MGMTD_DEFINES_H
+#include "lib/mgmt_pb.h"
+
+#define MGMTD_CLIENT_NAME_MAX_LEN 32
+
#define MGMTD_MAX_XPATH_LEN XPATH_MAXLEN
#define MGMTD_MAX_YANG_VALUE_LEN YANG_VALUE_MAXLEN
+enum mgmt_result {
+ MGMTD_SUCCESS = 0,
+ MGMTD_INVALID_PARAM,
+ MGMTD_INTERNAL_ERROR,
+ MGMTD_NO_CFG_CHANGES,
+ MGMTD_DB_LOCK_FAILED,
+ MGMTD_DB_UNLOCK_FAILED,
+ MGMTD_UNKNOWN_FAILURE
+};
+
+enum mgmt_frntnd_event {
+ MGMTD_FRNTND_SERVER = 1,
+ MGMTD_FRNTND_CONN_READ,
+ MGMTD_FRNTND_CONN_WRITE,
+ MGMTD_FRNTND_CONN_WRITES_ON,
+ MGMTD_FRNTND_PROC_MSG
+};
+
+#define MGMTD_TRXN_ID_NONE 0
+
#endif /* _FRR_MGMTD_DEFINES_H */
--- /dev/null
+/*
+ * MGMTD Frontend Client Connection Adapter
+ * Copyright (C) 2021 Vmware, Inc.
+ * Pushpasis Sarkar <spushpasis@vmware.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+#include "sockopt.h"
+#include "network.h"
+#include "libfrr.h"
+#include "mgmt_frntnd_client.h"
+#include "mgmt_pb.h"
+#include "hash.h"
+#include "jhash.h"
+#include "mgmtd/mgmt.h"
+#include "mgmtd/mgmt_memory.h"
+#include "mgmtd/mgmt_frntnd_adapter.h"
+
+#ifdef REDIRECT_DEBUG_TO_STDERR
+#define MGMTD_FRNTND_ADPTR_DBG(fmt, ...) \
+ fprintf(stderr, "%s: " fmt "\n", __func__, ##__VA_ARGS__)
+#define MGMTD_FRNTND_ADPTR_ERR(fmt, ...) \
+ fprintf(stderr, "%s: ERROR, " fmt "\n", __func__, ##__VA_ARGS__)
+#else /* REDIRECT_DEBUG_TO_STDERR */
+#define MGMTD_FRNTND_ADPTR_DBG(fmt, ...) \
+ do { \
+ if (mgmt_debug_frntnd) \
+ zlog_err("%s: " fmt, __func__, ##__VA_ARGS__); \
+ } while (0)
+#define MGMTD_FRNTND_ADPTR_ERR(fmt, ...) \
+ zlog_err("%s: ERROR: " fmt, __func__, ##__VA_ARGS__)
+#endif /* REDIRECT_DEBUG_TO_STDERR */
+
+#define FOREACH_ADPTR_IN_LIST(adptr) \
+ frr_each_safe(mgmt_frntnd_adptr_list, &mgmt_frntnd_adptrs, (adptr))
+
+enum mgmt_sessn_event {
+ MGMTD_FRNTND_SESSN_CFG_TRXN_CLNUP = 1,
+ MGMTD_FRNTND_SESSN_SHOW_TRXN_CLNUP,
+};
+
+struct mgmt_frntnd_sessn_ctxt {
+ struct mgmt_frntnd_client_adapter *adptr;
+ uint64_t session_id;
+ uint64_t client_id;
+ uint64_t trxn_id;
+ uint64_t cfg_trxn_id;
+ uint8_t db_write_locked[MGMTD_DB_MAX_ID];
+ uint8_t db_read_locked[MGMTD_DB_MAX_ID];
+ uint8_t db_locked_implict[MGMTD_DB_MAX_ID];
+ struct thread *proc_cfg_trxn_clnp;
+ struct thread *proc_show_trxn_clnp;
+
+ struct mgmt_frntnd_sessn_list_item list_linkage;
+};
+
+DECLARE_LIST(mgmt_frntnd_sessn_list, struct mgmt_frntnd_sessn_ctxt,
+ list_linkage);
+
+#define FOREACH_SESSN_IN_LIST(adptr, sessn) \
+ frr_each_safe(mgmt_frntnd_sessn_list, &(adptr)->frntnd_sessns, (sessn))
+
+static struct thread_master *mgmt_frntnd_adptr_tm;
+static struct mgmt_master *mgmt_frntnd_adptr_mm;
+
+static struct mgmt_frntnd_adptr_list_head mgmt_frntnd_adptrs;
+
+static struct hash *mgmt_frntnd_sessns;
+static uint64_t mgmt_frntnd_next_sessn_id;
+
+/* Forward declarations */
+static void
+mgmt_frntnd_adptr_register_event(struct mgmt_frntnd_client_adapter *adptr,
+ enum mgmt_frntnd_event event);
+static void
+mgmt_frntnd_adapter_disconnect(struct mgmt_frntnd_client_adapter *adptr);
+static void
+mgmt_frntnd_session_register_event(struct mgmt_frntnd_sessn_ctxt *sessn,
+ enum mgmt_sessn_event event);
+
+static int
+mgmt_frntnd_session_write_lock_db(Mgmtd__DatabaseId db_id,
+ struct mgmt_db_ctxt *db_ctxt,
+ struct mgmt_frntnd_sessn_ctxt *sessn)
+{
+ if (!sessn->db_write_locked[db_id]) {
+ if (mgmt_db_write_lock(db_ctxt) != 0) {
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Failed to lock the DB %u for Sessn: %p from %s!",
+ db_id, sessn, sessn->adptr->name);
+ return -1;
+ }
+
+ sessn->db_write_locked[db_id] = true;
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Write-Locked the DB %u for Sessn: %p from %s!", db_id,
+ sessn, sessn->adptr->name);
+ }
+
+ return 0;
+}
+
+static int
+mgmt_frntnd_session_read_lock_db(Mgmtd__DatabaseId db_id,
+ struct mgmt_db_ctxt *db_ctxt,
+ struct mgmt_frntnd_sessn_ctxt *sessn)
+{
+ if (!sessn->db_read_locked[db_id]) {
+ if (mgmt_db_read_lock(db_ctxt) != 0) {
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Failed to lock the DB %u for Sessn: %p from %s!",
+ db_id, sessn, sessn->adptr->name);
+ return -1;
+ }
+
+ sessn->db_read_locked[db_id] = true;
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Read-Locked the DB %u for Sessn: %p from %s!", db_id,
+ sessn, sessn->adptr->name);
+ }
+
+ return 0;
+}
+
+static int mgmt_frntnd_session_unlock_db(Mgmtd__DatabaseId db_id,
+ struct mgmt_db_ctxt *db_ctxt,
+ struct mgmt_frntnd_sessn_ctxt *sessn,
+ bool unlock_write, bool unlock_read)
+{
+ if (unlock_write && sessn->db_write_locked[db_id]) {
+ sessn->db_write_locked[db_id] = false;
+ sessn->db_locked_implict[db_id] = false;
+ if (mgmt_db_unlock(db_ctxt) != 0) {
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Failed to unlock the DB %u taken earlier by Sessn: %p from %s!",
+ db_id, sessn, sessn->adptr->name);
+ return -1;
+ }
+
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Unlocked DB %u write-locked earlier by Sessn: %p from %s",
+ db_id, sessn, sessn->adptr->name);
+ } else if (unlock_read && sessn->db_read_locked[db_id]) {
+ sessn->db_read_locked[db_id] = false;
+ sessn->db_locked_implict[db_id] = false;
+ if (mgmt_db_unlock(db_ctxt) != 0) {
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Failed to unlock the DB %u taken earlier by Sessn: %p from %s!",
+ db_id, sessn, sessn->adptr->name);
+ return -1;
+ }
+
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Unlocked DB %u read-locked earlier by Sessn: %p from %s",
+ db_id, sessn, sessn->adptr->name);
+ }
+
+ return 0;
+}
+
+static void
+mgmt_frntnd_sessn_cfg_trxn_cleanup(struct mgmt_frntnd_sessn_ctxt *sessn)
+{
+ Mgmtd__DatabaseId db_id;
+ struct mgmt_db_ctxt *db_ctxt;
+
+ /*
+ * Ensure any uncommitted changes in Candidate DB
+ * is discarded.
+ */
+ mgmt_db_copy_dbs(mm->running_db, mm->candidate_db, false);
+
+ for (db_id = 0; db_id < MGMTD_DB_MAX_ID; db_id++) {
+ db_ctxt = mgmt_db_get_hndl_by_id(mgmt_frntnd_adptr_mm, db_id);
+ if (db_ctxt) {
+ if (sessn->db_locked_implict[db_id])
+ mgmt_frntnd_session_unlock_db(
+ db_id, db_ctxt, sessn, true, false);
+ }
+ }
+
+ /* TODO: Destroy the actual transaction created earlier.
+ * if (sessn->cfg_trxn_id != MGMTD_TRXN_ID_NONE)
+ * mgmt_destroy_trxn(&sessn->cfg_trxn_id);
+ */
+}
+
+static void
+mgmt_frntnd_sessn_show_trxn_cleanup(struct mgmt_frntnd_sessn_ctxt *sessn)
+{
+ Mgmtd__DatabaseId db_id;
+ struct mgmt_db_ctxt *db_ctxt;
+
+ for (db_id = 0; db_id < MGMTD_DB_MAX_ID; db_id++) {
+ db_ctxt = mgmt_db_get_hndl_by_id(mgmt_frntnd_adptr_mm, db_id);
+ if (db_ctxt) {
+ mgmt_frntnd_session_unlock_db(db_id, db_ctxt, sessn,
+ false, true);
+ }
+ }
+
+ /* TODO: Destroy the transaction created recently.
+ * if (sessn->trxn_id != MGMTD_TRXN_ID_NONE)
+ * mgmt_destroy_trxn(&sessn->trxn_id);
+ */
+}
+
+static void
+mgmt_frntnd_adptr_compute_set_cfg_timers(struct mgmt_setcfg_stats *setcfg_stats)
+{
+ setcfg_stats->last_exec_tm = timeval_elapsed(setcfg_stats->last_end,
+ setcfg_stats->last_start);
+ if (setcfg_stats->last_exec_tm > setcfg_stats->max_tm)
+ setcfg_stats->max_tm = setcfg_stats->last_exec_tm;
+
+ if (setcfg_stats->last_exec_tm < setcfg_stats->min_tm)
+ setcfg_stats->min_tm = setcfg_stats->last_exec_tm;
+
+ setcfg_stats->avg_tm =
+ (((setcfg_stats->avg_tm * (setcfg_stats->set_cfg_count - 1))
+ + setcfg_stats->last_exec_tm)
+ / setcfg_stats->set_cfg_count);
+}
+
+static void
+mgmt_frntnd_sessn_compute_commit_timers(struct mgmt_commit_stats *cmt_stats)
+{
+ cmt_stats->last_exec_tm =
+ timeval_elapsed(cmt_stats->last_end, cmt_stats->last_start);
+ if (cmt_stats->last_exec_tm > cmt_stats->max_tm) {
+ cmt_stats->max_tm = cmt_stats->last_exec_tm;
+ cmt_stats->max_batch_cnt = cmt_stats->last_batch_cnt;
+ }
+
+ if (cmt_stats->last_exec_tm < cmt_stats->min_tm) {
+ cmt_stats->min_tm = cmt_stats->last_exec_tm;
+ cmt_stats->min_batch_cnt = cmt_stats->last_batch_cnt;
+ }
+}
+
+static void mgmt_frntnd_cleanup_session(struct mgmt_frntnd_sessn_ctxt **sessn)
+{
+ if ((*sessn)->adptr) {
+ mgmt_frntnd_sessn_cfg_trxn_cleanup((*sessn));
+ mgmt_frntnd_sessn_show_trxn_cleanup((*sessn));
+ mgmt_frntnd_session_unlock_db(
+ MGMTD_DB_CANDIDATE, mgmt_frntnd_adptr_mm->candidate_db,
+ *sessn, true, true);
+ mgmt_frntnd_session_unlock_db(MGMTD_DB_RUNNING,
+ mgmt_frntnd_adptr_mm->running_db,
+ *sessn, true, true);
+
+ mgmt_frntnd_sessn_list_del(&(*sessn)->adptr->frntnd_sessns,
+ *sessn);
+ mgmt_frntnd_adapter_unlock(&(*sessn)->adptr);
+ }
+
+ hash_release(mgmt_frntnd_sessns, *sessn);
+ XFREE(MTYPE_MGMTD_FRNTND_SESSN, *sessn);
+ *sessn = NULL;
+}
+
+static struct mgmt_frntnd_sessn_ctxt *
+mgmt_frntnd_find_session_by_client_id(struct mgmt_frntnd_client_adapter *adptr,
+ uint64_t client_id)
+{
+ struct mgmt_frntnd_sessn_ctxt *sessn;
+
+ FOREACH_SESSN_IN_LIST (adptr, sessn) {
+ if (sessn->client_id == client_id)
+ return sessn;
+ }
+
+ return NULL;
+}
+
+static unsigned int mgmt_frntnd_sessn_hash_key(const void *data)
+{
+ const struct mgmt_frntnd_sessn_ctxt *sessn = data;
+
+ return jhash2((uint32_t *) &sessn->session_id,
+ sizeof(sessn->session_id) / sizeof(uint32_t), 0);
+}
+
+static bool mgmt_frntnd_sessn_hash_cmp(const void *d1, const void *d2)
+{
+ const struct mgmt_frntnd_sessn_ctxt *sessn1 = d1;
+ const struct mgmt_frntnd_sessn_ctxt *sessn2 = d2;
+
+ return (sessn1->session_id == sessn2->session_id);
+}
+
+static void mgmt_frntnd_sessn_hash_free(void *data)
+{
+ struct mgmt_frntnd_sessn_ctxt *sessn = data;
+
+ mgmt_frntnd_cleanup_session(&sessn);
+}
+
+static void mgmt_frntnd_sessn_hash_destroy(void)
+{
+ if (mgmt_frntnd_sessns == NULL)
+ return;
+
+ hash_clean(mgmt_frntnd_sessns,
+ mgmt_frntnd_sessn_hash_free);
+ hash_free(mgmt_frntnd_sessns);
+ mgmt_frntnd_sessns = NULL;
+}
+
+static inline struct mgmt_frntnd_sessn_ctxt *
+mgmt_session_id2ctxt(uint64_t session_id)
+{
+ struct mgmt_frntnd_sessn_ctxt key = {0};
+ struct mgmt_frntnd_sessn_ctxt *sessn;
+
+ if (!mgmt_frntnd_sessns)
+ return NULL;
+
+ key.session_id = session_id;
+ sessn = hash_lookup(mgmt_frntnd_sessns, &key);
+
+ return sessn;
+}
+
+static struct mgmt_frntnd_sessn_ctxt *
+mgmt_frntnd_create_session(struct mgmt_frntnd_client_adapter *adptr,
+ uint64_t client_id)
+{
+ struct mgmt_frntnd_sessn_ctxt *sessn;
+
+ sessn = mgmt_frntnd_find_session_by_client_id(adptr, client_id);
+ if (sessn)
+ mgmt_frntnd_cleanup_session(&sessn);
+
+ sessn = XCALLOC(MTYPE_MGMTD_FRNTND_SESSN,
+ sizeof(struct mgmt_frntnd_sessn_ctxt));
+ assert(sessn);
+ sessn->client_id = client_id;
+ sessn->adptr = adptr;
+ sessn->trxn_id = MGMTD_TRXN_ID_NONE;
+ sessn->cfg_trxn_id = MGMTD_TRXN_ID_NONE;
+ mgmt_frntnd_adapter_lock(adptr);
+ mgmt_frntnd_sessn_list_add_tail(&adptr->frntnd_sessns, sessn);
+ if (!mgmt_frntnd_next_sessn_id)
+ mgmt_frntnd_next_sessn_id++;
+ sessn->session_id = mgmt_frntnd_next_sessn_id++;
+ hash_get(mgmt_frntnd_sessns, sessn, hash_alloc_intern);
+
+ return sessn;
+}
+
+static void
+mgmt_frntnd_cleanup_sessions(struct mgmt_frntnd_client_adapter *adptr)
+{
+ struct mgmt_frntnd_sessn_ctxt *sessn;
+
+ FOREACH_SESSN_IN_LIST (adptr, sessn)
+ mgmt_frntnd_cleanup_session(&sessn);
+}
+
+static inline void
+mgmt_frntnd_adapter_sched_msg_write(struct mgmt_frntnd_client_adapter *adptr)
+{
+ if (!CHECK_FLAG(adptr->flags, MGMTD_FRNTND_ADPTR_FLAGS_WRITES_OFF))
+ mgmt_frntnd_adptr_register_event(adptr,
+ MGMTD_FRNTND_CONN_WRITE);
+}
+
+static inline void
+mgmt_frntnd_adapter_writes_on(struct mgmt_frntnd_client_adapter *adptr)
+{
+ MGMTD_FRNTND_ADPTR_DBG("Resume writing msgs for '%s'", adptr->name);
+ UNSET_FLAG(adptr->flags, MGMTD_FRNTND_ADPTR_FLAGS_WRITES_OFF);
+ if (adptr->obuf_work || stream_fifo_count_safe(adptr->obuf_fifo))
+ mgmt_frntnd_adapter_sched_msg_write(adptr);
+}
+
+static inline void
+mgmt_frntnd_adapter_writes_off(struct mgmt_frntnd_client_adapter *adptr)
+{
+ SET_FLAG(adptr->flags, MGMTD_FRNTND_ADPTR_FLAGS_WRITES_OFF);
+ MGMTD_FRNTND_ADPTR_DBG("Paused writing msgs for '%s'", adptr->name);
+}
+
+static int
+mgmt_frntnd_adapter_send_msg(struct mgmt_frntnd_client_adapter *adptr,
+ Mgmtd__FrntndMessage *frntnd_msg)
+{
+ size_t msg_size;
+ uint8_t msg_buf[MGMTD_FRNTND_MSG_MAX_LEN];
+ struct mgmt_frntnd_msg *msg;
+
+ if (adptr->conn_fd == 0) {
+ MGMTD_FRNTND_ADPTR_ERR("Connection already reset");
+ return -1;
+ }
+
+ msg_size = mgmtd__frntnd_message__get_packed_size(frntnd_msg);
+ msg_size += MGMTD_FRNTND_MSG_HDR_LEN;
+ if (msg_size > sizeof(msg_buf)) {
+ MGMTD_FRNTND_ADPTR_ERR(
+ "Message size %d more than max size'%d. Not sending!'",
+ (int)msg_size, (int)sizeof(msg_buf));
+ return -1;
+ }
+
+ msg = (struct mgmt_frntnd_msg *)msg_buf;
+ msg->hdr.marker = MGMTD_FRNTND_MSG_MARKER;
+ msg->hdr.len = (uint16_t)msg_size;
+ mgmtd__frntnd_message__pack(frntnd_msg, msg->payload);
+
+ if (!adptr->obuf_work)
+ adptr->obuf_work = stream_new(MGMTD_FRNTND_MSG_MAX_LEN);
+ if (STREAM_WRITEABLE(adptr->obuf_work) < msg_size) {
+ stream_fifo_push(adptr->obuf_fifo, adptr->obuf_work);
+ adptr->obuf_work = stream_new(MGMTD_FRNTND_MSG_MAX_LEN);
+ }
+ stream_write(adptr->obuf_work, (void *)msg_buf, msg_size);
+
+ mgmt_frntnd_adapter_sched_msg_write(adptr);
+ adptr->num_msg_tx++;
+ return 0;
+}
+
+static int
+mgmt_frntnd_send_session_reply(struct mgmt_frntnd_client_adapter *adptr,
+ struct mgmt_frntnd_sessn_ctxt *sessn,
+ bool create, bool success)
+{
+ Mgmtd__FrntndMessage frntnd_msg;
+ Mgmtd__FrntndSessionReply sessn_reply;
+
+ mgmtd__frntnd_session_reply__init(&sessn_reply);
+ sessn_reply.create = create;
+ if (create) {
+ sessn_reply.has_client_conn_id = 1;
+ sessn_reply.client_conn_id = sessn->client_id;
+ }
+ sessn_reply.session_id = sessn->session_id;
+ sessn_reply.success = success;
+
+ mgmtd__frntnd_message__init(&frntnd_msg);
+ frntnd_msg.message_case = MGMTD__FRNTND_MESSAGE__MESSAGE_SESSN_REPLY;
+ frntnd_msg.sessn_reply = &sessn_reply;
+
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Sending SESSION_REPLY message to MGMTD Frontend client '%s'",
+ adptr->name);
+
+ return mgmt_frntnd_adapter_send_msg(adptr, &frntnd_msg);
+}
+
+static int mgmt_frntnd_send_lockdb_reply(struct mgmt_frntnd_sessn_ctxt *sessn,
+ Mgmtd__DatabaseId db_id,
+ uint64_t req_id, bool lock_db,
+ bool success, const char *error_if_any)
+{
+ Mgmtd__FrntndMessage frntnd_msg;
+ Mgmtd__FrntndLockDbReply lockdb_reply;
+
+ assert(sessn->adptr);
+
+ mgmtd__frntnd_lock_db_reply__init(&lockdb_reply);
+ lockdb_reply.session_id = sessn->session_id;
+ lockdb_reply.db_id = db_id;
+ lockdb_reply.req_id = req_id;
+ lockdb_reply.lock = lock_db;
+ lockdb_reply.success = success;
+ if (error_if_any)
+ lockdb_reply.error_if_any = (char *)error_if_any;
+
+ mgmtd__frntnd_message__init(&frntnd_msg);
+ frntnd_msg.message_case = MGMTD__FRNTND_MESSAGE__MESSAGE_LOCKDB_REPLY;
+ frntnd_msg.lockdb_reply = &lockdb_reply;
+
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Sending LOCK_DB_REPLY message to MGMTD Frontend client '%s'",
+ sessn->adptr->name);
+
+ return mgmt_frntnd_adapter_send_msg(sessn->adptr, &frntnd_msg);
+}
+
+static int mgmt_frntnd_send_setcfg_reply(struct mgmt_frntnd_sessn_ctxt *sessn,
+ Mgmtd__DatabaseId db_id,
+ uint64_t req_id, bool success,
+ const char *error_if_any,
+ bool implicit_commit)
+{
+ Mgmtd__FrntndMessage frntnd_msg;
+ Mgmtd__FrntndSetConfigReply setcfg_reply;
+
+ assert(sessn->adptr);
+
+ if (implicit_commit && sessn->cfg_trxn_id)
+ mgmt_frntnd_session_register_event(
+ sessn, MGMTD_FRNTND_SESSN_CFG_TRXN_CLNUP);
+
+ mgmtd__frntnd_set_config_reply__init(&setcfg_reply);
+ setcfg_reply.session_id = sessn->session_id;
+ setcfg_reply.db_id = db_id;
+ setcfg_reply.req_id = req_id;
+ setcfg_reply.success = success;
+ if (error_if_any)
+ setcfg_reply.error_if_any = (char *)error_if_any;
+
+ mgmtd__frntnd_message__init(&frntnd_msg);
+ frntnd_msg.message_case = MGMTD__FRNTND_MESSAGE__MESSAGE_SETCFG_REPLY;
+ frntnd_msg.setcfg_reply = &setcfg_reply;
+
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Sending SET_CONFIG_REPLY message to MGMTD Frontend client '%s'",
+ sessn->adptr->name);
+
+ if (implicit_commit) {
+ if (mm->perf_stats_en)
+ gettimeofday(&sessn->adptr->cmt_stats.last_end, NULL);
+ mgmt_frntnd_sessn_compute_commit_timers(
+ &sessn->adptr->cmt_stats);
+ }
+
+ if (mm->perf_stats_en)
+ gettimeofday(&sessn->adptr->setcfg_stats.last_end, NULL);
+ mgmt_frntnd_adptr_compute_set_cfg_timers(&sessn->adptr->setcfg_stats);
+
+ return mgmt_frntnd_adapter_send_msg(sessn->adptr, &frntnd_msg);
+}
+
+static int mgmt_frntnd_send_commitcfg_reply(
+ struct mgmt_frntnd_sessn_ctxt *sessn, Mgmtd__DatabaseId src_db_id,
+ Mgmtd__DatabaseId dst_db_id, uint64_t req_id, enum mgmt_result result,
+ bool validate_only, const char *error_if_any)
+{
+ Mgmtd__FrntndMessage frntnd_msg;
+ Mgmtd__FrntndCommitConfigReply commcfg_reply;
+
+ assert(sessn->adptr);
+
+ mgmtd__frntnd_commit_config_reply__init(&commcfg_reply);
+ commcfg_reply.session_id = sessn->session_id;
+ commcfg_reply.src_db_id = src_db_id;
+ commcfg_reply.dst_db_id = dst_db_id;
+ commcfg_reply.req_id = req_id;
+ commcfg_reply.success =
+ (result == MGMTD_SUCCESS || result == MGMTD_NO_CFG_CHANGES)
+ ? true
+ : false;
+ commcfg_reply.validate_only = validate_only;
+ if (error_if_any)
+ commcfg_reply.error_if_any = (char *)error_if_any;
+
+ mgmtd__frntnd_message__init(&frntnd_msg);
+ frntnd_msg.message_case = MGMTD__FRNTND_MESSAGE__MESSAGE_COMMCFG_REPLY;
+ frntnd_msg.commcfg_reply = &commcfg_reply;
+
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Sending COMMIT_CONFIG_REPLY message to MGMTD Frontend client '%s'",
+ sessn->adptr->name);
+
+ /*
+ * Cleanup the CONFIG transaction associated with this session.
+ */
+ if (sessn->cfg_trxn_id
+ && ((result == MGMTD_SUCCESS && !validate_only)
+ || (result == MGMTD_NO_CFG_CHANGES)))
+ mgmt_frntnd_session_register_event(
+ sessn, MGMTD_FRNTND_SESSN_CFG_TRXN_CLNUP);
+
+ if (mm->perf_stats_en)
+ gettimeofday(&sessn->adptr->cmt_stats.last_end, NULL);
+ mgmt_frntnd_sessn_compute_commit_timers(&sessn->adptr->cmt_stats);
+ return mgmt_frntnd_adapter_send_msg(sessn->adptr, &frntnd_msg);
+}
+
+static int mgmt_frntnd_send_getcfg_reply(struct mgmt_frntnd_sessn_ctxt *sessn,
+ Mgmtd__DatabaseId db_id,
+ uint64_t req_id, bool success,
+ Mgmtd__YangDataReply *data,
+ const char *error_if_any)
+{
+ Mgmtd__FrntndMessage frntnd_msg;
+ Mgmtd__FrntndGetConfigReply getcfg_reply;
+
+ assert(sessn->adptr);
+
+ mgmtd__frntnd_get_config_reply__init(&getcfg_reply);
+ getcfg_reply.session_id = sessn->session_id;
+ getcfg_reply.db_id = db_id;
+ getcfg_reply.req_id = req_id;
+ getcfg_reply.success = success;
+ getcfg_reply.data = data;
+ if (error_if_any)
+ getcfg_reply.error_if_any = (char *)error_if_any;
+
+ mgmtd__frntnd_message__init(&frntnd_msg);
+ frntnd_msg.message_case = MGMTD__FRNTND_MESSAGE__MESSAGE_GETCFG_REPLY;
+ frntnd_msg.getcfg_reply = &getcfg_reply;
+
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Sending GET_CONFIG_REPLY message to MGMTD Frontend client '%s'",
+ sessn->adptr->name);
+
+ /*
+ * Cleanup the SHOW transaction associated with this session.
+ */
+ if (sessn->trxn_id && (!success || (data && data->next_indx < 0)))
+ mgmt_frntnd_session_register_event(
+ sessn, MGMTD_FRNTND_SESSN_SHOW_TRXN_CLNUP);
+
+ return mgmt_frntnd_adapter_send_msg(sessn->adptr, &frntnd_msg);
+}
+
+static int mgmt_frntnd_send_getdata_reply(struct mgmt_frntnd_sessn_ctxt *sessn,
+ Mgmtd__DatabaseId db_id,
+ uint64_t req_id, bool success,
+ Mgmtd__YangDataReply *data,
+ const char *error_if_any)
+{
+ Mgmtd__FrntndMessage frntnd_msg;
+ Mgmtd__FrntndGetDataReply getdata_reply;
+
+ assert(sessn->adptr);
+
+ mgmtd__frntnd_get_data_reply__init(&getdata_reply);
+ getdata_reply.session_id = sessn->session_id;
+ getdata_reply.db_id = db_id;
+ getdata_reply.req_id = req_id;
+ getdata_reply.success = success;
+ getdata_reply.data = data;
+ if (error_if_any)
+ getdata_reply.error_if_any = (char *)error_if_any;
+
+ mgmtd__frntnd_message__init(&frntnd_msg);
+ frntnd_msg.message_case = MGMTD__FRNTND_MESSAGE__MESSAGE_GETDATA_REPLY;
+ frntnd_msg.getdata_reply = &getdata_reply;
+
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Sending GET_DATA_REPLY message to MGMTD Frontend client '%s'",
+ sessn->adptr->name);
+
+ /*
+ * Cleanup the SHOW transaction associated with this session.
+ */
+ if (sessn->trxn_id && (!success || (data && data->next_indx < 0)))
+ mgmt_frntnd_session_register_event(
+ sessn, MGMTD_FRNTND_SESSN_SHOW_TRXN_CLNUP);
+
+ return mgmt_frntnd_adapter_send_msg(sessn->adptr, &frntnd_msg);
+}
+
+static void mgmt_frntnd_session_cfg_trxn_clnup(struct thread *thread)
+{
+ struct mgmt_frntnd_sessn_ctxt *sessn;
+
+ sessn = (struct mgmt_frntnd_sessn_ctxt *)THREAD_ARG(thread);
+
+ mgmt_frntnd_sessn_cfg_trxn_cleanup(sessn);
+}
+
+static void mgmt_frntnd_session_show_trxn_clnup(struct thread *thread)
+{
+ struct mgmt_frntnd_sessn_ctxt *sessn;
+
+ sessn = (struct mgmt_frntnd_sessn_ctxt *)THREAD_ARG(thread);
+
+ mgmt_frntnd_sessn_show_trxn_cleanup(sessn);
+}
+
+static void
+mgmt_frntnd_session_register_event(struct mgmt_frntnd_sessn_ctxt *sessn,
+ enum mgmt_sessn_event event)
+{
+ struct timeval tv = {.tv_sec = 0,
+ .tv_usec = MGMTD_FRNTND_MSG_PROC_DELAY_USEC};
+
+ switch (event) {
+ case MGMTD_FRNTND_SESSN_CFG_TRXN_CLNUP:
+ thread_add_timer_tv(mgmt_frntnd_adptr_tm,
+ mgmt_frntnd_session_cfg_trxn_clnup, sessn,
+ &tv, &sessn->proc_cfg_trxn_clnp);
+ assert(sessn->proc_cfg_trxn_clnp);
+ break;
+ case MGMTD_FRNTND_SESSN_SHOW_TRXN_CLNUP:
+ thread_add_timer_tv(mgmt_frntnd_adptr_tm,
+ mgmt_frntnd_session_show_trxn_clnup, sessn,
+ &tv, &sessn->proc_show_trxn_clnp);
+ assert(sessn->proc_show_trxn_clnp);
+ break;
+ default:
+ assert(!"mgmt_frntnd_adptr_post_event() called incorrectly");
+ break;
+ }
+}
+
+static struct mgmt_frntnd_client_adapter *
+mgmt_frntnd_find_adapter_by_fd(int conn_fd)
+{
+ struct mgmt_frntnd_client_adapter *adptr;
+
+ FOREACH_ADPTR_IN_LIST (adptr) {
+ if (adptr->conn_fd == conn_fd)
+ return adptr;
+ }
+
+ return NULL;
+}
+
+static struct mgmt_frntnd_client_adapter *
+mgmt_frntnd_find_adapter_by_name(const char *name)
+{
+ struct mgmt_frntnd_client_adapter *adptr;
+
+ FOREACH_ADPTR_IN_LIST (adptr) {
+ if (!strncmp(adptr->name, name, sizeof(adptr->name)))
+ return adptr;
+ }
+
+ return NULL;
+}
+
+static void
+mgmt_frntnd_adapter_disconnect(struct mgmt_frntnd_client_adapter *adptr)
+{
+ if (adptr->conn_fd) {
+ close(adptr->conn_fd);
+ adptr->conn_fd = 0;
+ }
+
+ /* TODO: notify about client disconnect for appropriate cleanup */
+ mgmt_frntnd_cleanup_sessions(adptr);
+ mgmt_frntnd_sessn_list_fini(&adptr->frntnd_sessns);
+ mgmt_frntnd_adptr_list_del(&mgmt_frntnd_adptrs, adptr);
+
+ mgmt_frntnd_adapter_unlock(&adptr);
+}
+
+static void
+mgmt_frntnd_adapter_cleanup_old_conn(struct mgmt_frntnd_client_adapter *adptr)
+{
+ struct mgmt_frntnd_client_adapter *old;
+
+ FOREACH_ADPTR_IN_LIST (old) {
+ if (old != adptr
+ && !strncmp(adptr->name, old->name, sizeof(adptr->name))) {
+ /*
+ * We have a Zombie lingering around
+ */
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Client '%s' (FD:%d) seems to have reconnected. Removing old connection (FD:%d)!",
+ adptr->name, adptr->conn_fd, old->conn_fd);
+ mgmt_frntnd_adapter_disconnect(old);
+ }
+ }
+}
+
+static void
+mgmt_frntnd_cleanup_adapters(void)
+{
+ struct mgmt_frntnd_client_adapter *adptr;
+
+ FOREACH_ADPTR_IN_LIST (adptr) {
+ mgmt_frntnd_cleanup_sessions(adptr);
+ mgmt_frntnd_adapter_unlock(&adptr);
+ }
+}
+
+static int
+mgmt_frntnd_session_handle_lockdb_req_msg(struct mgmt_frntnd_sessn_ctxt *sessn,
+ Mgmtd__FrntndLockDbReq *lockdb_req)
+{
+ struct mgmt_db_ctxt *db_ctxt;
+
+ /*
+ * Next check first if the SET_CONFIG_REQ is for Candidate DB
+ * or not. Report failure if its not. MGMTD currently only
+ * supports editing the Candidate DB.
+ */
+ if (lockdb_req->db_id != MGMTD_DB_CANDIDATE) {
+ mgmt_frntnd_send_lockdb_reply(
+ sessn, lockdb_req->db_id, lockdb_req->req_id,
+ lockdb_req->lock, false,
+ "Lock/Unlock on databases other than Candidate DB not permitted!");
+ return -1;
+ }
+
+ db_ctxt =
+ mgmt_db_get_hndl_by_id(mgmt_frntnd_adptr_mm, lockdb_req->db_id);
+ if (!db_ctxt) {
+ mgmt_frntnd_send_lockdb_reply(
+ sessn, lockdb_req->db_id, lockdb_req->req_id,
+ lockdb_req->lock, false,
+ "Failed to retrieve handle for DB!");
+ return -1;
+ }
+
+ if (lockdb_req->lock) {
+ if (mgmt_frntnd_session_write_lock_db(lockdb_req->db_id,
+ db_ctxt, sessn)
+ != 0) {
+ mgmt_frntnd_send_lockdb_reply(
+ sessn, lockdb_req->db_id, lockdb_req->req_id,
+ lockdb_req->lock, false,
+ "Lock already taken on DB by another session!");
+ return -1;
+ }
+
+ sessn->db_locked_implict[lockdb_req->db_id] = false;
+ } else {
+ if (!sessn->db_write_locked[lockdb_req->db_id]) {
+ mgmt_frntnd_send_lockdb_reply(
+ sessn, lockdb_req->db_id, lockdb_req->req_id,
+ lockdb_req->lock, false,
+ "Lock on DB was not taken by this session!");
+ return 0;
+ }
+
+ (void)mgmt_frntnd_session_unlock_db(lockdb_req->db_id, db_ctxt,
+ sessn, true, false);
+ }
+
+ if (mgmt_frntnd_send_lockdb_reply(sessn, lockdb_req->db_id,
+ lockdb_req->req_id, lockdb_req->lock,
+ true, NULL)
+ != 0) {
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Failed to send LOCK_DB_REPLY for DB %u Sessn: %p from %s",
+ lockdb_req->db_id, sessn, sessn->adptr->name);
+ }
+
+ return 0;
+}
+
+static int
+mgmt_frntnd_session_handle_setcfg_req_msg(struct mgmt_frntnd_sessn_ctxt *sessn,
+ Mgmtd__FrntndSetConfigReq *setcfg_req)
+{
+ /* uint64_t cfg_sessn_id; */
+ struct mgmt_db_ctxt *db_ctxt, *dst_db_ctxt;
+
+ if (mm->perf_stats_en)
+ gettimeofday(&sessn->adptr->setcfg_stats.last_start, NULL);
+
+ /*
+ * Next check first if the SET_CONFIG_REQ is for Candidate DB
+ * or not. Report failure if its not. MGMTD currently only
+ * supports editing the Candidate DB.
+ */
+ if (setcfg_req->db_id != MGMTD_DB_CANDIDATE) {
+ mgmt_frntnd_send_setcfg_reply(
+ sessn, setcfg_req->db_id, setcfg_req->req_id, false,
+ "Set-Config on databases other than Candidate DB not permitted!",
+ setcfg_req->implicit_commit);
+ return 0;
+ }
+
+ /*
+ * Get the DB handle.
+ */
+ db_ctxt =
+ mgmt_db_get_hndl_by_id(mgmt_frntnd_adptr_mm, setcfg_req->db_id);
+ if (!db_ctxt) {
+ mgmt_frntnd_send_setcfg_reply(
+ sessn, setcfg_req->db_id, setcfg_req->req_id, false,
+ "No such DB exists!", setcfg_req->implicit_commit);
+ return 0;
+ }
+
+ if (sessn->cfg_trxn_id == MGMTD_TRXN_ID_NONE) {
+ /*
+ * TODO: Check first if the current session can run a CONFIG
+ * transaction or not. Report failure if a CONFIG transaction
+ * from another session is already in progress.
+ * cfg_sessn_id = mgmt_config_trxn_in_progress();
+ * if (cfg_sessn_id != MGMTD_SESSION_ID_NONE
+ * && cfg_sessn_id != sessn->session_id) {
+ * mgmt_frntnd_send_setcfg_reply(
+ * sessn, setcfg_req->db_id, setcfg_req->req_id,
+ * false,
+ * "Configuration already in-progress through a
+ *different user session!", setcfg_req->implicit_commit); goto
+ *mgmt_frntnd_sess_handle_setcfg_req_failed;
+ *}
+ */
+
+
+ /*
+ * Try taking write-lock on the requested DB (if not already).
+ */
+ if (!sessn->db_write_locked[setcfg_req->db_id]) {
+ if (mgmt_frntnd_session_write_lock_db(setcfg_req->db_id,
+ db_ctxt, sessn)
+ != 0) {
+ mgmt_frntnd_send_setcfg_reply(
+ sessn, setcfg_req->db_id,
+ setcfg_req->req_id, false,
+ "Failed to lock the DB!",
+ setcfg_req->implicit_commit);
+ goto mgmt_frntnd_sess_handle_setcfg_req_failed;
+ }
+
+ sessn->db_locked_implict[setcfg_req->db_id] = true;
+ }
+
+ /*
+ * TODO: Start a CONFIG Transaction (if not started already)
+ * sessn->cfg_trxn_id = mgmt_create_trxn(sessn->session_id,
+ * MGMTD_TRXN_TYPE_CONFIG);
+ * if (sessn->cfg_trxn_id == MGMTD_SESSION_ID_NONE) {
+ * mgmt_frntnd_send_setcfg_reply(
+ * sessn, setcfg_req->db_id, setcfg_req->req_id,
+ * false,
+ * "Failed to create a Configuration session!",
+ * setcfg_req->implicit_commit);
+ * goto mgmt_frntnd_sess_handle_setcfg_req_failed;
+ * }
+ */
+
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Created new Config Trxn 0x%llx for session %p",
+ (unsigned long long)sessn->cfg_trxn_id, sessn);
+ } else {
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Config Trxn 0x%llx for session %p already created",
+ (unsigned long long)sessn->cfg_trxn_id, sessn);
+
+ if (setcfg_req->implicit_commit) {
+ /*
+ * In this scenario need to skip cleanup of the trxn,
+ * so setting implicit commit to false.
+ */
+ mgmt_frntnd_send_setcfg_reply(
+ sessn, setcfg_req->db_id, setcfg_req->req_id,
+ false,
+ "A Configuration transaction is already in progress!",
+ false);
+ return 0;
+ }
+ }
+
+ dst_db_ctxt = 0;
+ if (setcfg_req->implicit_commit) {
+ dst_db_ctxt = mgmt_db_get_hndl_by_id(mgmt_frntnd_adptr_mm,
+ setcfg_req->commit_db_id);
+ if (!dst_db_ctxt) {
+ mgmt_frntnd_send_setcfg_reply(
+ sessn, setcfg_req->db_id, setcfg_req->req_id,
+ false, "No such commit DB exists!",
+ setcfg_req->implicit_commit);
+ return 0;
+ }
+ }
+
+ /* TODO: Create the SETConfig request under the transaction.
+ * if (mgmt_trxn_send_set_config_req(
+ * sessn->cfg_trxn_id, setcfg_req->req_id, setcfg_req->db_id,
+ * db_ctxt, setcfg_req->data, setcfg_req->n_data,
+ * setcfg_req->implicit_commit, setcfg_req->commit_db_id,
+ * dst_db_ctxt)
+ * != 0) {
+ * mgmt_frntnd_send_setcfg_reply(
+ * sessn, setcfg_req->db_id, setcfg_req->req_id, false,
+ * "Request processing for SET-CONFIG failed!",
+ * setcfg_req->implicit_commit);
+ * goto mgmt_frntnd_sess_handle_setcfg_req_failed;
+ * }
+ *
+ * For now send a failure reply.
+ */
+ mgmt_frntnd_send_setcfg_reply(
+ sessn, setcfg_req->db_id, setcfg_req->req_id, false,
+ "Request processing for SET-CONFIG failed!",
+ setcfg_req->implicit_commit);
+ goto mgmt_frntnd_sess_handle_setcfg_req_failed;
+
+ return 0;
+
+mgmt_frntnd_sess_handle_setcfg_req_failed:
+
+ /* TODO: Delete transaction created recently.
+ * if (sessn->cfg_trxn_id != MGMTD_TRXN_ID_NONE)
+ * mgmt_destroy_trxn(&sessn->cfg_trxn_id);
+ */
+ if (db_ctxt && sessn->db_write_locked[setcfg_req->db_id])
+ mgmt_frntnd_session_unlock_db(setcfg_req->db_id, db_ctxt, sessn,
+ true, false);
+
+ return 0;
+}
+
+static int
+mgmt_frntnd_session_handle_getcfg_req_msg(struct mgmt_frntnd_sessn_ctxt *sessn,
+ Mgmtd__FrntndGetConfigReq *getcfg_req)
+{
+ struct mgmt_db_ctxt *db_ctxt;
+
+ /*
+ * Get the DB handle.
+ */
+ db_ctxt =
+ mgmt_db_get_hndl_by_id(mgmt_frntnd_adptr_mm, getcfg_req->db_id);
+ if (!db_ctxt) {
+ mgmt_frntnd_send_getcfg_reply(sessn, getcfg_req->db_id,
+ getcfg_req->req_id, false, NULL,
+ "No such DB exists!");
+ return 0;
+ }
+
+ /*
+ * Next check first if the SET_CONFIG_REQ is for Candidate DB
+ * or not. Report failure if its not. MGMTD currently only
+ * supports editing the Candidate DB.
+ */
+ if (getcfg_req->db_id != MGMTD_DB_CANDIDATE
+ && getcfg_req->db_id != MGMTD_DB_RUNNING) {
+ mgmt_frntnd_send_getcfg_reply(
+ sessn, getcfg_req->db_id, getcfg_req->req_id, false,
+ NULL,
+ "Get-Config on databases other than Candidate or Running DB not permitted!");
+ return 0;
+ }
+
+ if (sessn->trxn_id == MGMTD_TRXN_ID_NONE) {
+ /*
+ * Try taking read-lock on the requested DB (if not already
+ * locked). If the DB has already been write-locked by a ongoing
+ * CONFIG transaction we may allow reading the contents of the
+ * same DB.
+ */
+ if (!sessn->db_read_locked[getcfg_req->db_id]
+ && !sessn->db_write_locked[getcfg_req->db_id]) {
+ if (mgmt_frntnd_session_read_lock_db(getcfg_req->db_id,
+ db_ctxt, sessn)
+ != 0) {
+ mgmt_frntnd_send_getcfg_reply(
+ sessn, getcfg_req->db_id,
+ getcfg_req->req_id, false, NULL,
+ "Failed to lock the DB! Another session might have locked it!");
+ goto mgmt_frntnd_sess_handle_getcfg_req_failed;
+ }
+
+ sessn->db_locked_implict[getcfg_req->db_id] = true;
+ }
+
+ /*
+ * TODO: Start a SHOW Transaction (if not started already)
+ * sessn->trxn_id = mgmt_create_trxn(sessn->session_id,
+ * MGMTD_TRXN_TYPE_SHOW);
+ * if (sessn->trxn_id == MGMTD_SESSION_ID_NONE) {
+ * mgmt_frntnd_send_getcfg_reply(
+ * sessn, getcfg_req->db_id, getcfg_req->req_id,
+ * false, NULL,
+ * "Failed to create a Show transaction!");
+ * goto mgmt_frntnd_sess_handle_getcfg_req_failed;
+ * }
+ */
+ mgmt_frntnd_send_getcfg_reply(
+ sessn, getcfg_req->db_id, getcfg_req->req_id, false,
+ NULL, "Failed to create a Show transaction!");
+ goto mgmt_frntnd_sess_handle_getcfg_req_failed;
+
+
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Created new Show Trxn 0x%llx for session %p",
+ (unsigned long long)sessn->trxn_id, sessn);
+ } else {
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Show Trxn 0x%llx for session %p already created",
+ (unsigned long long)sessn->trxn_id, sessn);
+ }
+
+ /* TODO: Create a GETConfig request under the transaction.
+ * if (mgmt_trxn_send_get_config_req(sessn->trxn_id, getcfg_req->req_id,
+ * getcfg_req->db_id, db_ctxt,
+ * getcfg_req->data, getcfg_req->n_data)
+ * != 0) {
+ * mgmt_frntnd_send_getcfg_reply(
+ * sessn, getcfg_req->db_id, getcfg_req->req_id, false,
+ * NULL, "Request processing for GET-CONFIG failed!");
+ * goto mgmt_frntnd_sess_handle_getcfg_req_failed;
+ * }
+ *
+ * For now send back a failure reply.
+ */
+ mgmt_frntnd_send_getcfg_reply(
+ sessn, getcfg_req->db_id, getcfg_req->req_id, false, NULL,
+ "Request processing for GET-CONFIG failed!");
+ goto mgmt_frntnd_sess_handle_getcfg_req_failed;
+
+ return 0;
+
+mgmt_frntnd_sess_handle_getcfg_req_failed:
+
+ /* TODO: Destroy the transaction created recently.
+ * if (sessn->trxn_id != MGMTD_TRXN_ID_NONE)
+ * mgmt_destroy_trxn(&sessn->trxn_id);
+ */
+ if (db_ctxt && sessn->db_read_locked[getcfg_req->db_id])
+ mgmt_frntnd_session_unlock_db(getcfg_req->db_id, db_ctxt, sessn,
+ false, true);
+
+ return -1;
+}
+
+static int
+mgmt_frntnd_session_handle_getdata_req_msg(struct mgmt_frntnd_sessn_ctxt *sessn,
+ Mgmtd__FrntndGetDataReq *getdata_req)
+{
+ struct mgmt_db_ctxt *db_ctxt;
+
+ /*
+ * Get the DB handle.
+ */
+ db_ctxt = mgmt_db_get_hndl_by_id(mgmt_frntnd_adptr_mm,
+ getdata_req->db_id);
+ if (!db_ctxt) {
+ mgmt_frntnd_send_getdata_reply(sessn, getdata_req->db_id,
+ getdata_req->req_id, false, NULL,
+ "No such DB exists!");
+ return 0;
+ }
+
+ if (sessn->trxn_id == MGMTD_TRXN_ID_NONE) {
+ /*
+ * Try taking read-lock on the requested DB (if not already
+ * locked). If the DB has already been write-locked by a ongoing
+ * CONFIG transaction we may allow reading the contents of the
+ * same DB.
+ */
+ if (!sessn->db_read_locked[getdata_req->db_id]
+ && !sessn->db_write_locked[getdata_req->db_id]) {
+ if (mgmt_frntnd_session_read_lock_db(getdata_req->db_id,
+ db_ctxt, sessn)
+ != 0) {
+ mgmt_frntnd_send_getdata_reply(
+ sessn, getdata_req->db_id,
+ getdata_req->req_id, false, NULL,
+ "Failed to lock the DB! Another session might have locked it!");
+ goto mgmt_frntnd_sess_handle_getdata_req_failed;
+ }
+
+ sessn->db_locked_implict[getdata_req->db_id] = true;
+ }
+
+ /*
+ * TODO: Start a SHOW Transaction (if not started already)
+ * sessn->trxn_id =
+ * mgmt_create_trxn(sessn->session_id,
+ * MGMTD_TRXN_TYPE_SHOW);
+ * if (sessn->trxn_id == MGMTD_SESSION_ID_NONE) {
+ * mgmt_frntnd_send_getdata_reply(
+ * sessn, getdata_req->db_id, getdata_req->req_id,
+ * false, NULL,
+ * "Failed to create a Show transaction!");
+ * goto mgmt_frntnd_sess_handle_getdata_req_failed;
+ * }
+ */
+ mgmt_frntnd_send_getdata_reply(
+ sessn, getdata_req->db_id, getdata_req->req_id, false,
+ NULL, "Failed to create a Show transaction!");
+ goto mgmt_frntnd_sess_handle_getdata_req_failed;
+
+
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Created new Show Trxn 0x%llx for session %p",
+ (unsigned long long)sessn->trxn_id, sessn);
+ } else {
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Show Trxn 0x%llx for session %p already created",
+ (unsigned long long)sessn->trxn_id, sessn);
+ }
+
+ /* TODO: Create a GETData request under the transaction.
+ * if (mgmt_trxn_send_get_data_req(sessn->trxn_id, getdata_req->req_id,
+ * getdata_req->db_id, db_ctxt,
+ * getdata_req->data, getdata_req->n_data)
+ * != 0) {
+ * mgmt_frntnd_send_getdata_reply(
+ * sessn, getdata_req->db_id, getdata_req->req_id, false,
+ * NULL, "Request processing for GET-CONFIG failed!");
+ * goto mgmt_frntnd_sess_handle_getdata_req_failed;
+ * }
+ *
+ * For now send back a failure reply.
+ */
+ mgmt_frntnd_send_getdata_reply(
+ sessn, getdata_req->db_id, getdata_req->req_id, false, NULL,
+ "Request processing for GET-CONFIG failed!");
+ goto mgmt_frntnd_sess_handle_getdata_req_failed;
+
+ return 0;
+
+mgmt_frntnd_sess_handle_getdata_req_failed:
+
+ /* TODO: Destroy the transaction created recently.
+ * if (sessn->trxn_id != MGMTD_TRXN_ID_NONE)
+ * mgmt_destroy_trxn(&sessn->trxn_id);
+ */
+
+ if (db_ctxt && sessn->db_read_locked[getdata_req->db_id])
+ mgmt_frntnd_session_unlock_db(getdata_req->db_id, db_ctxt,
+ sessn, false, true);
+
+ return -1;
+}
+
+static int mgmt_frntnd_session_handle_commit_config_req_msg(
+ struct mgmt_frntnd_sessn_ctxt *sessn,
+ Mgmtd__FrntndCommitConfigReq *commcfg_req)
+{
+ struct mgmt_db_ctxt *src_db_ctxt, *dst_db_ctxt;
+
+ if (mm->perf_stats_en)
+ gettimeofday(&sessn->adptr->cmt_stats.last_start, NULL);
+ sessn->adptr->cmt_stats.commit_cnt++;
+ /*
+ * Get the source DB handle.
+ */
+ src_db_ctxt = mgmt_db_get_hndl_by_id(mgmt_frntnd_adptr_mm,
+ commcfg_req->src_db_id);
+ if (!src_db_ctxt) {
+ mgmt_frntnd_send_commitcfg_reply(
+ sessn, commcfg_req->src_db_id, commcfg_req->dst_db_id,
+ commcfg_req->req_id, MGMTD_INTERNAL_ERROR,
+ commcfg_req->validate_only,
+ "No such source DB exists!");
+ return 0;
+ }
+
+ /*
+ * Get the destination DB handle.
+ */
+ dst_db_ctxt = mgmt_db_get_hndl_by_id(mgmt_frntnd_adptr_mm,
+ commcfg_req->dst_db_id);
+ if (!dst_db_ctxt) {
+ mgmt_frntnd_send_commitcfg_reply(
+ sessn, commcfg_req->src_db_id, commcfg_req->dst_db_id,
+ commcfg_req->req_id, MGMTD_INTERNAL_ERROR,
+ commcfg_req->validate_only,
+ "No such destination DB exists!");
+ return 0;
+ }
+
+ /*
+ * Next check first if the SET_CONFIG_REQ is for Candidate DB
+ * or not. Report failure if its not. MGMTD currently only
+ * supports editing the Candidate DB.
+ */
+ if (commcfg_req->dst_db_id != MGMTD_DB_RUNNING) {
+ mgmt_frntnd_send_commitcfg_reply(
+ sessn, commcfg_req->src_db_id, commcfg_req->dst_db_id,
+ commcfg_req->req_id, MGMTD_INTERNAL_ERROR,
+ commcfg_req->validate_only,
+ "Set-Config on databases other than Running DB not permitted!");
+ return 0;
+ }
+
+ if (sessn->cfg_trxn_id == MGMTD_TRXN_ID_NONE) {
+ /*
+ * TODO: Start a CONFIG Transaction (if not started already)
+ * sessn->cfg_trxn_id = mgmt_create_trxn(sessn->session_id,
+ * MGMTD_TRXN_TYPE_CONFIG);
+ * if (sessn->cfg_trxn_id == MGMTD_SESSION_ID_NONE) {
+ * mgmt_frntnd_send_commitcfg_reply(
+ * sessn, commcfg_req->src_db_id,
+ * commcfg_req->dst_db_id, commcfg_req->req_id,
+ * MGMTD_INTERNAL_ERROR,
+ * commcfg_req->validate_only,
+ * "Failed to create a Configuration session!");
+ * return 0;
+ * }
+ */
+ mgmt_frntnd_send_commitcfg_reply(
+ sessn, commcfg_req->src_db_id, commcfg_req->dst_db_id,
+ commcfg_req->req_id, MGMTD_INTERNAL_ERROR,
+ commcfg_req->validate_only,
+ "Failed to create a Configuration session!");
+ return 0;
+ }
+
+
+ /*
+ * Try taking write-lock on the destination DB (if not already).
+ */
+ if (!sessn->db_write_locked[commcfg_req->dst_db_id]) {
+ if (mgmt_frntnd_session_write_lock_db(commcfg_req->dst_db_id,
+ dst_db_ctxt, sessn)
+ != 0) {
+ mgmt_frntnd_send_commitcfg_reply(
+ sessn, commcfg_req->src_db_id,
+ commcfg_req->dst_db_id, commcfg_req->req_id,
+ MGMTD_DB_LOCK_FAILED,
+ commcfg_req->validate_only,
+ "Failed to lock the destination DB!");
+ return 0;
+ }
+
+ sessn->db_locked_implict[commcfg_req->dst_db_id] = true;
+ }
+
+ /* TODO: Create COMMITConfig request under the transaction
+ * if (mgmt_trxn_send_commit_config_req(
+ * sessn->cfg_trxn_id, commcfg_req->req_id,
+ * commcfg_req->src_db_id, src_db_ctxt, commcfg_req->dst_db_id,
+ * dst_db_ctxt, commcfg_req->validate_only, commcfg_req->abort,
+ * false)
+ * != 0) {
+ * mgmt_frntnd_send_commitcfg_reply(
+ * sessn, commcfg_req->src_db_id, commcfg_req->dst_db_id,
+ * commcfg_req->req_id, MGMTD_INTERNAL_ERROR,
+ * commcfg_req->validate_only,
+ * "Request processing for COMMIT-CONFIG failed!");
+ * return 0;
+ * }
+ *
+ * For now due to lack of trxn modules send a unsuccessfull reply.
+ */
+ mgmt_frntnd_send_commitcfg_reply(
+ sessn, commcfg_req->src_db_id, commcfg_req->dst_db_id,
+ commcfg_req->req_id, MGMTD_INTERNAL_ERROR,
+ commcfg_req->validate_only,
+ "Request processing for COMMIT-CONFIG failed!");
+
+ return 0;
+}
+
+static int
+mgmt_frntnd_adapter_handle_msg(struct mgmt_frntnd_client_adapter *adptr,
+ Mgmtd__FrntndMessage *frntnd_msg)
+{
+ struct mgmt_frntnd_sessn_ctxt *sessn;
+
+ switch (frntnd_msg->message_case) {
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_REGISTER_REQ:
+ MGMTD_FRNTND_ADPTR_DBG("Got Register Req Msg from '%s'",
+ frntnd_msg->register_req->client_name);
+
+ if (strlen(frntnd_msg->register_req->client_name)) {
+ strlcpy(adptr->name,
+ frntnd_msg->register_req->client_name,
+ sizeof(adptr->name));
+ mgmt_frntnd_adapter_cleanup_old_conn(adptr);
+ }
+ break;
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_SESSN_REQ:
+ if (frntnd_msg->sessn_req->create
+ && frntnd_msg->sessn_req->id_case
+ == MGMTD__FRNTND_SESSION_REQ__ID_CLIENT_CONN_ID) {
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Got Session Create Req Msg for client-id %llu from '%s'",
+ (unsigned long long)
+ frntnd_msg->sessn_req->client_conn_id,
+ adptr->name);
+
+ sessn = mgmt_frntnd_create_session(
+ adptr, frntnd_msg->sessn_req->client_conn_id);
+ mgmt_frntnd_send_session_reply(adptr, sessn, true,
+ sessn ? true : false);
+ } else if (
+ !frntnd_msg->sessn_req->create
+ && frntnd_msg->sessn_req->id_case
+ == MGMTD__FRNTND_SESSION_REQ__ID_SESSION_ID) {
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Got Session Destroy Req Msg for session-id %llu from '%s'",
+ (unsigned long long)
+ frntnd_msg->sessn_req->session_id,
+ adptr->name);
+
+ sessn = mgmt_session_id2ctxt(
+ frntnd_msg->sessn_req->session_id);
+ mgmt_frntnd_send_session_reply(adptr, sessn, false,
+ true);
+ mgmt_frntnd_cleanup_session(&sessn);
+ }
+ break;
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_LOCKDB_REQ:
+ sessn = mgmt_session_id2ctxt(
+ frntnd_msg->lockdb_req->session_id);
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Got %sockDB Req Msg for DB:%d for session-id %llx from '%s'",
+ frntnd_msg->lockdb_req->lock ? "L" : "Unl",
+ frntnd_msg->lockdb_req->db_id,
+ (unsigned long long)frntnd_msg->lockdb_req->session_id,
+ adptr->name);
+ mgmt_frntnd_session_handle_lockdb_req_msg(
+ sessn, frntnd_msg->lockdb_req);
+ break;
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_SETCFG_REQ:
+ sessn = mgmt_session_id2ctxt(
+ frntnd_msg->setcfg_req->session_id);
+ sessn->adptr->setcfg_stats.set_cfg_count++;
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Got Set Config Req Msg (%d Xpaths) on DB:%d for session-id %llu from '%s'",
+ (int)frntnd_msg->setcfg_req->n_data,
+ frntnd_msg->setcfg_req->db_id,
+ (unsigned long long)frntnd_msg->setcfg_req->session_id,
+ adptr->name);
+
+ mgmt_frntnd_session_handle_setcfg_req_msg(
+ sessn, frntnd_msg->setcfg_req);
+ break;
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_COMMCFG_REQ:
+ sessn = mgmt_session_id2ctxt(
+ frntnd_msg->commcfg_req->session_id);
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Got Commit Config Req Msg for src-DB:%d dst-DB:%d on session-id %llu from '%s'",
+ frntnd_msg->commcfg_req->src_db_id,
+ frntnd_msg->commcfg_req->dst_db_id,
+ (unsigned long long)frntnd_msg->commcfg_req->session_id,
+ adptr->name);
+ mgmt_frntnd_session_handle_commit_config_req_msg(
+ sessn, frntnd_msg->commcfg_req);
+ break;
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_GETCFG_REQ:
+ sessn = mgmt_session_id2ctxt(
+ frntnd_msg->getcfg_req->session_id);
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Got Get-Config Req Msg for DB:%d (xpaths: %d) on session-id %llu from '%s'",
+ frntnd_msg->getcfg_req->db_id,
+ (int)frntnd_msg->getcfg_req->n_data,
+ (unsigned long long)frntnd_msg->getcfg_req->session_id,
+ adptr->name);
+ mgmt_frntnd_session_handle_getcfg_req_msg(
+ sessn, frntnd_msg->getcfg_req);
+ break;
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_GETDATA_REQ:
+ sessn = mgmt_session_id2ctxt(
+ frntnd_msg->getdata_req->session_id);
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Got Get-Data Req Msg for DB:%d (xpaths: %d) on session-id %llu from '%s'",
+ frntnd_msg->getdata_req->db_id,
+ (int)frntnd_msg->getdata_req->n_data,
+ (unsigned long long)frntnd_msg->getdata_req->session_id,
+ adptr->name);
+ mgmt_frntnd_session_handle_getdata_req_msg(
+ sessn, frntnd_msg->getdata_req);
+ break;
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_NOTIFY_DATA_REQ:
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_REGNOTIFY_REQ:
+ /*
+ * TODO: Add handling code in future.
+ */
+ break;
+ /*
+ * NOTE: The following messages are always sent from MGMTD to
+ * Frontend clients only and/or need not be handled on MGMTd.
+ */
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_SESSN_REPLY:
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_LOCKDB_REPLY:
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_SETCFG_REPLY:
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_COMMCFG_REPLY:
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_GETCFG_REPLY:
+ case MGMTD__FRNTND_MESSAGE__MESSAGE_GETDATA_REPLY:
+ case MGMTD__FRNTND_MESSAGE__MESSAGE__NOT_SET:
+ default:
+ /*
+ * A 'default' case is being added contrary to the
+ * FRR code guidelines to take care of build
+ * failures on certain build systems (courtesy of
+ * the proto-c package).
+ */
+ break;
+ }
+
+ return 0;
+}
+
+static uint16_t
+mgmt_frntnd_adapter_process_msg(struct mgmt_frntnd_client_adapter *adptr,
+ uint8_t *msg_buf, uint16_t bytes_read)
+{
+ Mgmtd__FrntndMessage *frntnd_msg;
+ struct mgmt_frntnd_msg *msg;
+ uint16_t bytes_left;
+ uint16_t processed = 0;
+
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Have %u bytes of messages from client '%s' to process",
+ bytes_read, adptr->name);
+
+ bytes_left = bytes_read;
+ for (; bytes_left > MGMTD_FRNTND_MSG_HDR_LEN;
+ bytes_left -= msg->hdr.len, msg_buf += msg->hdr.len) {
+ msg = (struct mgmt_frntnd_msg *)msg_buf;
+ if (msg->hdr.marker != MGMTD_FRNTND_MSG_MARKER) {
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Marker not found in message from MGMTD Frontend adapter '%s'",
+ adptr->name);
+ break;
+ }
+
+ if (bytes_left < msg->hdr.len) {
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Incomplete message of %d bytes (epxected: %u) from MGMTD Frontend adapter '%s'",
+ bytes_left, msg->hdr.len, adptr->name);
+ break;
+ }
+
+ frntnd_msg = mgmtd__frntnd_message__unpack(
+ NULL, (size_t)(msg->hdr.len - MGMTD_FRNTND_MSG_HDR_LEN),
+ msg->payload);
+ if (!frntnd_msg) {
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Failed to decode %d bytes from MGMTD Frontend adapter '%s'",
+ msg->hdr.len, adptr->name);
+ continue;
+ }
+
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Decoded %d bytes of message(msg: %u/%u) from MGMTD Frontend adapter '%s'",
+ msg->hdr.len, frntnd_msg->message_case,
+ frntnd_msg->message_case, adptr->name);
+
+ (void)mgmt_frntnd_adapter_handle_msg(adptr, frntnd_msg);
+
+ mgmtd__frntnd_message__free_unpacked(frntnd_msg, NULL);
+ processed++;
+ adptr->num_msg_rx++;
+ }
+
+ return processed;
+}
+
+static void mgmt_frntnd_adapter_proc_msgbufs(struct thread *thread)
+{
+ struct mgmt_frntnd_client_adapter *adptr;
+ struct stream *work;
+ int processed = 0;
+
+ adptr = (struct mgmt_frntnd_client_adapter *)THREAD_ARG(thread);
+ assert(adptr && adptr->conn_fd);
+
+ MGMTD_FRNTND_ADPTR_DBG("Have %d ibufs for client '%s' to process",
+ (int)stream_fifo_count_safe(adptr->ibuf_fifo),
+ adptr->name);
+
+ for (; processed < MGMTD_FRNTND_MAX_NUM_MSG_PROC;) {
+ work = stream_fifo_pop_safe(adptr->ibuf_fifo);
+ if (!work)
+ break;
+
+ processed += mgmt_frntnd_adapter_process_msg(
+ adptr, STREAM_DATA(work), stream_get_endp(work));
+
+ if (work != adptr->ibuf_work) {
+ /* Free it up */
+ stream_free(work);
+ } else {
+ /* Reset stream buffer for next read */
+ stream_reset(work);
+ }
+ }
+
+ /*
+ * If we have more to process, reschedule for processing it.
+ */
+ if (stream_fifo_head(adptr->ibuf_fifo))
+ mgmt_frntnd_adptr_register_event(adptr, MGMTD_FRNTND_PROC_MSG);
+}
+
+static void mgmt_frntnd_adapter_read(struct thread *thread)
+{
+ struct mgmt_frntnd_client_adapter *adptr;
+ int bytes_read, msg_cnt;
+ size_t total_bytes, bytes_left;
+ struct mgmt_frntnd_msg_hdr *msg_hdr;
+ bool incomplete = false;
+
+ adptr = (struct mgmt_frntnd_client_adapter *)THREAD_ARG(thread);
+ assert(adptr && adptr->conn_fd);
+
+ total_bytes = 0;
+ bytes_left = STREAM_SIZE(adptr->ibuf_work)
+ - stream_get_endp(adptr->ibuf_work);
+ for (; bytes_left > MGMTD_FRNTND_MSG_HDR_LEN;) {
+ bytes_read = stream_read_try(adptr->ibuf_work, adptr->conn_fd,
+ bytes_left);
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Got %d bytes of message from MGMTD Frontend adapter '%s'",
+ bytes_read, adptr->name);
+ if (bytes_read <= 0) {
+ if (bytes_read == -1
+ && (errno == EAGAIN || errno == EWOULDBLOCK)) {
+ mgmt_frntnd_adptr_register_event(
+ adptr, MGMTD_FRNTND_CONN_READ);
+ return;
+ }
+
+ if (!bytes_read) {
+ /* Looks like connection closed */
+ MGMTD_FRNTND_ADPTR_ERR(
+ "Got error (%d) while reading from MGMTD Frontend adapter '%s'. Err: '%s'",
+ bytes_read, adptr->name,
+ safe_strerror(errno));
+ mgmt_frntnd_adapter_disconnect(adptr);
+ return;
+ }
+ break;
+ }
+
+ total_bytes += bytes_read;
+ bytes_left -= bytes_read;
+ }
+
+ /*
+ * Check if we would have read incomplete messages or not.
+ */
+ stream_set_getp(adptr->ibuf_work, 0);
+ total_bytes = 0;
+ msg_cnt = 0;
+ bytes_left = stream_get_endp(adptr->ibuf_work);
+ for (; bytes_left > MGMTD_FRNTND_MSG_HDR_LEN;) {
+ msg_hdr =
+ (struct mgmt_frntnd_msg_hdr *)(STREAM_DATA(
+ adptr->ibuf_work)
+ + total_bytes);
+ if (msg_hdr->marker != MGMTD_FRNTND_MSG_MARKER) {
+ /* Corrupted buffer. Force disconnect?? */
+ MGMTD_FRNTND_ADPTR_ERR(
+ "Received corrupted buffer from MGMTD frontend client.");
+ mgmt_frntnd_adapter_disconnect(adptr);
+ return;
+ }
+ if (msg_hdr->len > bytes_left)
+ break;
+
+ MGMTD_FRNTND_ADPTR_DBG("Got message (len: %u) from client '%s'",
+ msg_hdr->len, adptr->name);
+
+ total_bytes += msg_hdr->len;
+ bytes_left -= msg_hdr->len;
+ msg_cnt++;
+ }
+
+ if (bytes_left > 0)
+ incomplete = true;
+ /*
+ * We would have read one or several messages.
+ * Schedule processing them now.
+ */
+ msg_hdr = (struct mgmt_frntnd_msg_hdr *)(STREAM_DATA(adptr->ibuf_work)
+ + total_bytes);
+ stream_set_endp(adptr->ibuf_work, total_bytes);
+ stream_fifo_push(adptr->ibuf_fifo, adptr->ibuf_work);
+ adptr->ibuf_work = stream_new(MGMTD_FRNTND_MSG_MAX_LEN);
+ if (incomplete) {
+ stream_put(adptr->ibuf_work, msg_hdr, bytes_left);
+ stream_set_endp(adptr->ibuf_work, bytes_left);
+ }
+
+ if (msg_cnt)
+ mgmt_frntnd_adptr_register_event(adptr, MGMTD_FRNTND_PROC_MSG);
+
+ mgmt_frntnd_adptr_register_event(adptr, MGMTD_FRNTND_CONN_READ);
+}
+
+static void mgmt_frntnd_adapter_write(struct thread *thread)
+{
+ int bytes_written = 0;
+ int processed = 0;
+ int msg_size = 0;
+ struct stream *s = NULL;
+ struct stream *free = NULL;
+ struct mgmt_frntnd_client_adapter *adptr;
+
+ adptr = (struct mgmt_frntnd_client_adapter *)THREAD_ARG(thread);
+ assert(adptr && adptr->conn_fd);
+
+ /* Ensure pushing any pending write buffer to FIFO */
+ if (adptr->obuf_work) {
+ stream_fifo_push(adptr->obuf_fifo, adptr->obuf_work);
+ adptr->obuf_work = NULL;
+ }
+
+ for (s = stream_fifo_head(adptr->obuf_fifo);
+ s && processed < MGMTD_FRNTND_MAX_NUM_MSG_WRITE;
+ s = stream_fifo_head(adptr->obuf_fifo)) {
+ /* msg_size = (int)stream_get_size(s); */
+ msg_size = (int)STREAM_READABLE(s);
+ bytes_written = stream_flush(s, adptr->conn_fd);
+ if (bytes_written == -1
+ && (errno == EAGAIN || errno == EWOULDBLOCK)) {
+ mgmt_frntnd_adptr_register_event(
+ adptr, MGMTD_FRNTND_CONN_WRITE);
+ return;
+ } else if (bytes_written != msg_size) {
+ MGMTD_FRNTND_ADPTR_ERR(
+ "Could not write all %d bytes (wrote: %d) to MGMTD Frontend client socket. Err: '%s'",
+ msg_size, bytes_written, safe_strerror(errno));
+ if (bytes_written > 0) {
+ stream_forward_getp(s, (size_t)bytes_written);
+ stream_pulldown(s);
+ mgmt_frntnd_adptr_register_event(
+ adptr, MGMTD_FRNTND_CONN_WRITE);
+ return;
+ }
+ mgmt_frntnd_adapter_disconnect(adptr);
+ return;
+ }
+
+ free = stream_fifo_pop(adptr->obuf_fifo);
+ stream_free(free);
+ MGMTD_FRNTND_ADPTR_DBG(
+ "Wrote %d bytes of message to MGMTD Frontend client socket.'",
+ bytes_written);
+ processed++;
+ }
+
+ if (s) {
+ mgmt_frntnd_adapter_writes_off(adptr);
+ mgmt_frntnd_adptr_register_event(adptr,
+ MGMTD_FRNTND_CONN_WRITES_ON);
+ }
+}
+
+static void mgmt_frntnd_adapter_resume_writes(struct thread *thread)
+{
+ struct mgmt_frntnd_client_adapter *adptr;
+
+ adptr = (struct mgmt_frntnd_client_adapter *)THREAD_ARG(thread);
+ assert(adptr && adptr->conn_fd);
+
+ mgmt_frntnd_adapter_writes_on(adptr);
+}
+
+static void
+mgmt_frntnd_adptr_register_event(struct mgmt_frntnd_client_adapter *adptr,
+ enum mgmt_frntnd_event event)
+{
+ struct timeval tv = {0};
+
+ switch (event) {
+ case MGMTD_FRNTND_CONN_READ:
+ thread_add_read(mgmt_frntnd_adptr_tm, mgmt_frntnd_adapter_read,
+ adptr, adptr->conn_fd, &adptr->conn_read_ev);
+ assert(adptr->conn_read_ev);
+ break;
+ case MGMTD_FRNTND_CONN_WRITE:
+ thread_add_write(mgmt_frntnd_adptr_tm,
+ mgmt_frntnd_adapter_write, adptr,
+ adptr->conn_fd, &adptr->conn_write_ev);
+ assert(adptr->conn_write_ev);
+ break;
+ case MGMTD_FRNTND_PROC_MSG:
+ tv.tv_usec = MGMTD_FRNTND_MSG_PROC_DELAY_USEC;
+ thread_add_timer_tv(mgmt_frntnd_adptr_tm,
+ mgmt_frntnd_adapter_proc_msgbufs, adptr,
+ &tv, &adptr->proc_msg_ev);
+ assert(adptr->proc_msg_ev);
+ break;
+ case MGMTD_FRNTND_CONN_WRITES_ON:
+ thread_add_timer_msec(mgmt_frntnd_adptr_tm,
+ mgmt_frntnd_adapter_resume_writes, adptr,
+ MGMTD_FRNTND_MSG_WRITE_DELAY_MSEC,
+ &adptr->conn_writes_on);
+ assert(adptr->conn_writes_on);
+ break;
+ case MGMTD_FRNTND_SERVER:
+ assert(!"mgmt_frntnd_adptr_post_event() called incorrectly");
+ break;
+ }
+}
+
+void mgmt_frntnd_adapter_lock(struct mgmt_frntnd_client_adapter *adptr)
+{
+ adptr->refcount++;
+}
+
+extern void
+mgmt_frntnd_adapter_unlock(struct mgmt_frntnd_client_adapter **adptr)
+{
+ assert(*adptr && (*adptr)->refcount);
+
+ (*adptr)->refcount--;
+ if (!(*adptr)->refcount) {
+ mgmt_frntnd_adptr_list_del(&mgmt_frntnd_adptrs, *adptr);
+
+ stream_fifo_free((*adptr)->ibuf_fifo);
+ stream_free((*adptr)->ibuf_work);
+ stream_fifo_free((*adptr)->obuf_fifo);
+ stream_free((*adptr)->obuf_work);
+
+ THREAD_OFF((*adptr)->conn_read_ev);
+ THREAD_OFF((*adptr)->conn_write_ev);
+ THREAD_OFF((*adptr)->proc_msg_ev);
+ THREAD_OFF((*adptr)->conn_writes_on);
+ XFREE(MTYPE_MGMTD_FRNTND_ADPATER, *adptr);
+ }
+
+ *adptr = NULL;
+}
+
+int mgmt_frntnd_adapter_init(struct thread_master *tm, struct mgmt_master *mm)
+{
+ if (!mgmt_frntnd_adptr_tm) {
+ mgmt_frntnd_adptr_tm = tm;
+ mgmt_frntnd_adptr_mm = mm;
+ mgmt_frntnd_adptr_list_init(&mgmt_frntnd_adptrs);
+
+ assert(!mgmt_frntnd_sessns);
+ mgmt_frntnd_sessns =
+ hash_create(mgmt_frntnd_sessn_hash_key,
+ mgmt_frntnd_sessn_hash_cmp,
+ "MGMT Frontend Sessions");
+ }
+
+ return 0;
+}
+
+void mgmt_frntnd_adapter_destroy(void)
+{
+ mgmt_frntnd_cleanup_adapters();
+ mgmt_frntnd_sessn_hash_destroy();
+}
+
+struct mgmt_frntnd_client_adapter *
+mgmt_frntnd_create_adapter(int conn_fd, union sockunion *from)
+{
+ struct mgmt_frntnd_client_adapter *adptr = NULL;
+
+ adptr = mgmt_frntnd_find_adapter_by_fd(conn_fd);
+ if (!adptr) {
+ adptr = XCALLOC(MTYPE_MGMTD_FRNTND_ADPATER,
+ sizeof(struct mgmt_frntnd_client_adapter));
+ assert(adptr);
+
+ adptr->conn_fd = conn_fd;
+ memcpy(&adptr->conn_su, from, sizeof(adptr->conn_su));
+ snprintf(adptr->name, sizeof(adptr->name), "Unknown-FD-%d",
+ adptr->conn_fd);
+ mgmt_frntnd_sessn_list_init(&adptr->frntnd_sessns);
+ adptr->ibuf_fifo = stream_fifo_new();
+ adptr->ibuf_work = stream_new(MGMTD_FRNTND_MSG_MAX_LEN);
+ adptr->obuf_fifo = stream_fifo_new();
+ /* adptr->obuf_work = stream_new(MGMTD_FRNTND_MSG_MAX_LEN); */
+ adptr->obuf_work = NULL;
+ mgmt_frntnd_adapter_lock(adptr);
+
+ mgmt_frntnd_adptr_register_event(adptr, MGMTD_FRNTND_CONN_READ);
+ mgmt_frntnd_adptr_list_add_tail(&mgmt_frntnd_adptrs, adptr);
+
+ adptr->setcfg_stats.min_tm = ULONG_MAX;
+ adptr->cmt_stats.min_tm = ULONG_MAX;
+ MGMTD_FRNTND_ADPTR_DBG("Added new MGMTD Frontend adapter '%s'",
+ adptr->name);
+ }
+
+ /* Make client socket non-blocking. */
+ set_nonblocking(adptr->conn_fd);
+ setsockopt_so_sendbuf(adptr->conn_fd,
+ MGMTD_SOCKET_FRNTND_SEND_BUF_SIZE);
+ setsockopt_so_recvbuf(adptr->conn_fd,
+ MGMTD_SOCKET_FRNTND_RECV_BUF_SIZE);
+ return adptr;
+}
+
+struct mgmt_frntnd_client_adapter *mgmt_frntnd_get_adapter(const char *name)
+{
+ return mgmt_frntnd_find_adapter_by_name(name);
+}
+
+int mgmt_frntnd_send_set_cfg_reply(uint64_t session_id, uint64_t trxn_id,
+ Mgmtd__DatabaseId db_id, uint64_t req_id,
+ enum mgmt_result result,
+ const char *error_if_any,
+ bool implicit_commit)
+{
+ struct mgmt_frntnd_sessn_ctxt *sessn;
+
+ sessn = mgmt_session_id2ctxt(session_id);
+ if (!sessn || sessn->cfg_trxn_id != trxn_id) {
+ if (sessn)
+ MGMTD_FRNTND_ADPTR_ERR(
+ "Trxn_id doesnot match, session trxn is 0x%llx, current trxn 0x%llx",
+ (unsigned long long)sessn->cfg_trxn_id,
+ (unsigned long long)trxn_id);
+ return -1;
+ }
+
+ return mgmt_frntnd_send_setcfg_reply(
+ sessn, db_id, req_id, result == MGMTD_SUCCESS ? true : false,
+ error_if_any, implicit_commit);
+}
+
+int mgmt_frntnd_send_commit_cfg_reply(uint64_t session_id, uint64_t trxn_id,
+ Mgmtd__DatabaseId src_db_id,
+ Mgmtd__DatabaseId dst_db_id,
+ uint64_t req_id, bool validate_only,
+ enum mgmt_result result,
+ const char *error_if_any)
+{
+ struct mgmt_frntnd_sessn_ctxt *sessn;
+
+ sessn = mgmt_session_id2ctxt(session_id);
+ if (!sessn || sessn->cfg_trxn_id != trxn_id)
+ return -1;
+
+ return mgmt_frntnd_send_commitcfg_reply(sessn, src_db_id, dst_db_id,
+ req_id, result, validate_only,
+ error_if_any);
+}
+
+int mgmt_frntnd_send_get_cfg_reply(uint64_t session_id, uint64_t trxn_id,
+ Mgmtd__DatabaseId db_id, uint64_t req_id,
+ enum mgmt_result result,
+ Mgmtd__YangDataReply *data_resp,
+ const char *error_if_any)
+{
+ struct mgmt_frntnd_sessn_ctxt *sessn;
+
+ sessn = mgmt_session_id2ctxt(session_id);
+ if (!sessn || sessn->trxn_id != trxn_id)
+ return -1;
+
+ return mgmt_frntnd_send_getcfg_reply(sessn, db_id, req_id,
+ result == MGMTD_SUCCESS, data_resp,
+ error_if_any);
+}
+
+int mgmt_frntnd_send_get_data_reply(uint64_t session_id, uint64_t trxn_id,
+ Mgmtd__DatabaseId db_id, uint64_t req_id,
+ enum mgmt_result result,
+ Mgmtd__YangDataReply *data_resp,
+ const char *error_if_any)
+{
+ struct mgmt_frntnd_sessn_ctxt *sessn;
+
+ sessn = mgmt_session_id2ctxt(session_id);
+ if (!sessn || sessn->trxn_id != trxn_id)
+ return -1;
+
+ return mgmt_frntnd_send_getdata_reply(sessn, db_id, req_id,
+ result == MGMTD_SUCCESS,
+ data_resp, error_if_any);
+}
+
+int mgmt_frntnd_send_data_notify(Mgmtd__DatabaseId db_id,
+ Mgmtd__YangData * data_resp[], int num_data)
+{
+ /* struct mgmt_frntnd_sessn_ctxt *sessn; */
+
+ return 0;
+}
+
+struct mgmt_setcfg_stats *
+mgmt_frntnd_get_sessn_setcfg_stats(uint64_t session_id)
+{
+ struct mgmt_frntnd_sessn_ctxt *sessn;
+
+ sessn = mgmt_session_id2ctxt(session_id);
+ if (!sessn || !sessn->adptr)
+ return NULL;
+
+ return &sessn->adptr->setcfg_stats;
+}
+
+struct mgmt_commit_stats *
+mgmt_frntnd_get_sessn_commit_stats(uint64_t session_id)
+{
+ struct mgmt_frntnd_sessn_ctxt *sessn;
+
+ sessn = mgmt_session_id2ctxt(session_id);
+ if (!sessn || !sessn->adptr)
+ return NULL;
+
+ return &sessn->adptr->cmt_stats;
+}
+
+static void
+mgmt_frntnd_adapter_cmt_stats_write(struct vty *vty,
+ struct mgmt_frntnd_client_adapter *adptr)
+{
+ char buf[100] = {0};
+
+ if (!mm->perf_stats_en)
+ return;
+
+ vty_out(vty, " Num-Commits: \t\t\t%lu\n",
+ adptr->cmt_stats.commit_cnt);
+ if (adptr->cmt_stats.commit_cnt > 0) {
+ if (mm->perf_stats_en)
+ vty_out(vty, " Max-Commit-Duration: \t\t%lu uSecs\n",
+ adptr->cmt_stats.max_tm);
+ vty_out(vty, " Max-Commit-Batch-Size: \t\t%lu\n",
+ adptr->cmt_stats.max_batch_cnt);
+ if (mm->perf_stats_en)
+ vty_out(vty, " Min-Commit-Duration: \t\t%lu uSecs\n",
+ adptr->cmt_stats.min_tm);
+ vty_out(vty, " Min-Commit-Batch-Size: \t\t%lu\n",
+ adptr->cmt_stats.min_batch_cnt);
+ if (mm->perf_stats_en)
+ vty_out(vty,
+ " Last-Commit-Duration: \t\t%lu uSecs\n",
+ adptr->cmt_stats.last_exec_tm);
+ vty_out(vty, " Last-Commit-Batch-Size: \t\t%lu\n",
+ adptr->cmt_stats.last_batch_cnt);
+ vty_out(vty, " Last-Commit-CfgData-Reqs: \t\t%lu\n",
+ adptr->cmt_stats.last_num_cfgdata_reqs);
+ vty_out(vty, " Last-Commit-CfgApply-Reqs: \t\t%lu\n",
+ adptr->cmt_stats.last_num_apply_reqs);
+ if (mm->perf_stats_en) {
+ vty_out(vty, " Last-Commit-Details:\n");
+ vty_out(vty, " Commit Start: \t\t\t%s\n",
+ mgmt_realtime_to_string(
+ &adptr->cmt_stats.last_start, buf,
+ sizeof(buf)));
+ vty_out(vty, " Config-Validate Start: \t\t%s\n",
+ mgmt_realtime_to_string(
+ &adptr->cmt_stats.validate_start, buf,
+ sizeof(buf)));
+ vty_out(vty, " Prep-Config Start: \t\t%s\n",
+ mgmt_realtime_to_string(
+ &adptr->cmt_stats.prep_cfg_start, buf,
+ sizeof(buf)));
+ vty_out(vty, " Trxn-Create Start: \t\t%s\n",
+ mgmt_realtime_to_string(
+ &adptr->cmt_stats.trxn_create_start,
+ buf, sizeof(buf)));
+ vty_out(vty, " Send-Config Start: \t\t%s\n",
+ mgmt_realtime_to_string(
+ &adptr->cmt_stats.send_cfg_start, buf,
+ sizeof(buf)));
+ vty_out(vty, " Apply-Config Start: \t\t%s\n",
+ mgmt_realtime_to_string(
+ &adptr->cmt_stats.apply_cfg_start, buf,
+ sizeof(buf)));
+ vty_out(vty, " Apply-Config End: \t\t%s\n",
+ mgmt_realtime_to_string(
+ &adptr->cmt_stats.apply_cfg_end, buf,
+ sizeof(buf)));
+ vty_out(vty, " Trxn-Delete Start: \t\t%s\n",
+ mgmt_realtime_to_string(
+ &adptr->cmt_stats.trxn_del_start, buf,
+ sizeof(buf)));
+ vty_out(vty, " Commit End: \t\t\t%s\n",
+ mgmt_realtime_to_string(
+ &adptr->cmt_stats.last_end, buf,
+ sizeof(buf)));
+ }
+ }
+}
+
+static void
+mgmt_frntnd_adapter_setcfg_stats_write(struct vty *vty,
+ struct mgmt_frntnd_client_adapter *adptr)
+{
+ char buf[100] = {0};
+
+ if (!mm->perf_stats_en)
+ return;
+
+ vty_out(vty, " Num-Set-Cfg: \t\t\t%lu\n",
+ adptr->setcfg_stats.set_cfg_count);
+ if (mm->perf_stats_en && adptr->setcfg_stats.set_cfg_count > 0) {
+ vty_out(vty, " Max-Set-Cfg-Duration: \t\t%lu uSec\n",
+ adptr->setcfg_stats.max_tm);
+ vty_out(vty, " Min-Set-Cfg-Duration: \t\t%lu uSec\n",
+ adptr->setcfg_stats.min_tm);
+ vty_out(vty, " Avg-Set-Cfg-Duration: \t\t%lu uSec\n",
+ adptr->setcfg_stats.avg_tm);
+ vty_out(vty, " Last-Set-Cfg-Details:\n");
+ vty_out(vty, " Set-Cfg Start: \t\t\t%s\n",
+ mgmt_realtime_to_string(&adptr->setcfg_stats.last_start,
+ buf, sizeof(buf)));
+ vty_out(vty, " Set-Cfg End: \t\t\t%s\n",
+ mgmt_realtime_to_string(&adptr->setcfg_stats.last_end,
+ buf, sizeof(buf)));
+ }
+}
+
+void mgmt_frntnd_adapter_status_write(struct vty *vty, bool detail)
+{
+ struct mgmt_frntnd_client_adapter *adptr;
+ struct mgmt_frntnd_sessn_ctxt *sessn;
+ Mgmtd__DatabaseId db_id;
+ bool locked = false;
+
+ vty_out(vty, "MGMTD Frontend Adpaters\n");
+
+ FOREACH_ADPTR_IN_LIST (adptr) {
+ vty_out(vty, " Client: \t\t\t\t%s\n", adptr->name);
+ vty_out(vty, " Conn-FD: \t\t\t\t%d\n", adptr->conn_fd);
+ if (detail) {
+ mgmt_frntnd_adapter_setcfg_stats_write(vty, adptr);
+ mgmt_frntnd_adapter_cmt_stats_write(vty, adptr);
+ }
+ vty_out(vty, " Sessions\n");
+ FOREACH_SESSN_IN_LIST (adptr, sessn) {
+ vty_out(vty, " Session: \t\t\t\t%p\n", sessn);
+ vty_out(vty, " Client-Id: \t\t\t%llu\n",
+ (unsigned long long)sessn->client_id);
+ vty_out(vty, " Session-Id: \t\t\t%llx\n",
+ (unsigned long long)sessn->session_id);
+ vty_out(vty, " DB-Locks:\n");
+ FOREACH_MGMTD_DB_ID (db_id) {
+ if (sessn->db_write_locked[db_id]
+ || sessn->db_read_locked[db_id]) {
+ locked = true;
+ vty_out(vty,
+ " %s\t\t\t%s, %s\n",
+ mgmt_db_id2name(db_id),
+ sessn->db_write_locked[db_id]
+ ? "Write"
+ : "Read",
+ sessn->db_locked_implict[db_id]
+ ? "Implicit"
+ : "Explicit");
+ }
+ }
+ if (!locked)
+ vty_out(vty, " None\n");
+ }
+ vty_out(vty, " Total-Sessions: \t\t\t%d\n",
+ (int)mgmt_frntnd_sessn_list_count(
+ &adptr->frntnd_sessns));
+ vty_out(vty, " Msg-Sent: \t\t\t\t%u\n", adptr->num_msg_tx);
+ vty_out(vty, " Msg-Recvd: \t\t\t\t%u\n", adptr->num_msg_rx);
+ }
+ vty_out(vty, " Total: %d\n",
+ (int)mgmt_frntnd_adptr_list_count(&mgmt_frntnd_adptrs));
+}
+
+void mgmt_frntnd_adapter_perf_measurement(struct vty *vty, bool config)
+{
+ mm->perf_stats_en = config;
+}
+
+void mgmt_frntnd_adapter_reset_perf_stats(struct vty *vty)
+{
+ struct mgmt_frntnd_client_adapter *adptr;
+ struct mgmt_frntnd_sessn_ctxt *sessn;
+
+ FOREACH_ADPTR_IN_LIST (adptr) {
+ memset(&adptr->setcfg_stats, 0, sizeof(adptr->setcfg_stats));
+ FOREACH_SESSN_IN_LIST (adptr, sessn) {
+ memset(&adptr->cmt_stats, 0, sizeof(adptr->cmt_stats));
+ }
+ }
+}
--- /dev/null
+/*
+ * MGMTD Frontend Client Connection Adapter
+ * Copyright (C) 2021 Vmware, Inc.
+ * Pushpasis Sarkar <spushpasis@vmware.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _FRR_MGMTD_FRNTND_ADAPTER_H_
+#define _FRR_MGMTD_FRNTND_ADAPTER_H_
+
+struct mgmt_frntnd_client_adapter;
+struct mgmt_master;
+
+struct mgmt_commit_stats {
+ struct timeval last_start;
+ struct timeval validate_start;
+ struct timeval prep_cfg_start;
+ struct timeval trxn_create_start;
+ struct timeval send_cfg_start;
+ struct timeval apply_cfg_start;
+ struct timeval apply_cfg_end;
+ struct timeval trxn_del_start;
+ struct timeval last_end;
+ unsigned long last_exec_tm;
+ unsigned long max_tm;
+ unsigned long min_tm;
+ unsigned long last_batch_cnt;
+ unsigned long last_num_cfgdata_reqs;
+ unsigned long last_num_apply_reqs;
+ unsigned long max_batch_cnt;
+ unsigned long min_batch_cnt;
+ unsigned long commit_cnt;
+};
+
+struct mgmt_setcfg_stats {
+ struct timeval last_start;
+ struct timeval last_end;
+ unsigned long last_exec_tm;
+ unsigned long max_tm;
+ unsigned long min_tm;
+ unsigned long avg_tm;
+ unsigned long set_cfg_count;
+};
+
+PREDECL_LIST(mgmt_frntnd_sessn_list);
+
+PREDECL_LIST(mgmt_frntnd_adptr_list);
+
+struct mgmt_frntnd_client_adapter {
+ int conn_fd;
+ union sockunion conn_su;
+ struct thread *conn_read_ev;
+ struct thread *conn_write_ev;
+ struct thread *conn_writes_on;
+ struct thread *proc_msg_ev;
+ uint32_t flags;
+
+ char name[MGMTD_CLIENT_NAME_MAX_LEN];
+
+ /* List of sessions created and being maintained for this client. */
+ struct mgmt_frntnd_sessn_list_head frntnd_sessns;
+
+ /* IO streams for read and write */
+ /* pthread_mutex_t ibuf_mtx; */
+ struct stream_fifo *ibuf_fifo;
+ /* pthread_mutex_t obuf_mtx; */
+ struct stream_fifo *obuf_fifo;
+
+ /* Private I/O buffers */
+ struct stream *ibuf_work;
+ struct stream *obuf_work;
+
+ int refcount;
+ uint32_t num_msg_tx;
+ uint32_t num_msg_rx;
+ struct mgmt_commit_stats cmt_stats;
+ struct mgmt_setcfg_stats setcfg_stats;
+
+ struct mgmt_frntnd_adptr_list_item list_linkage;
+};
+
+#define MGMTD_FRNTND_ADPTR_FLAGS_WRITES_OFF (1U << 0)
+
+DECLARE_LIST(mgmt_frntnd_adptr_list, struct mgmt_frntnd_client_adapter,
+ list_linkage);
+
+/* Initialise frontend adapter module */
+extern int mgmt_frntnd_adapter_init(struct thread_master *tm,
+ struct mgmt_master *cm);
+
+/* Destroy frontend adapter module */
+extern void mgmt_frntnd_adapter_destroy(void);
+
+/* Acquire lock for frontend adapter */
+extern void mgmt_frntnd_adapter_lock(struct mgmt_frntnd_client_adapter *adptr);
+
+/* Remove lock from frontend adapter */
+extern void
+mgmt_frntnd_adapter_unlock(struct mgmt_frntnd_client_adapter **adptr);
+
+/* Create frontend adapter */
+extern struct mgmt_frntnd_client_adapter *
+mgmt_frntnd_create_adapter(int conn_fd, union sockunion *su);
+
+/* Fetch frontend adapter given a name */
+extern struct mgmt_frntnd_client_adapter *
+mgmt_frntnd_get_adapter(const char *name);
+
+/*
+ * Send set-config reply to the frontend client.
+ *
+ * session
+ * Unique session identifier.
+ *
+ * trxn_id
+ * Unique transaction identifier.
+ *
+ * db_id
+ * Database ID.
+ *
+ * req_id
+ * Config request ID.
+ *
+ * result
+ * Config request result (MGMT_*).
+ *
+ * error_if_any
+ * Buffer to store human-readable error message in case of error.
+ *
+ * implicit_commit
+ * TRUE if the commit is implicit, FALSE otherwise.
+ *
+ * Returns:
+ * 0 on success, -1 on failures.
+ */
+extern int mgmt_frntnd_send_set_cfg_reply(uint64_t session_id, uint64_t trxn_id,
+ Mgmtd__DatabaseId db_id,
+ uint64_t req_id,
+ enum mgmt_result result,
+ const char *error_if_any,
+ bool implcit_commit);
+
+/*
+ * Send commit-config reply to the frontend client.
+ */
+extern int mgmt_frntnd_send_commit_cfg_reply(
+ uint64_t session_id, uint64_t trxn_id, Mgmtd__DatabaseId src_db_id,
+ Mgmtd__DatabaseId dst_db_id, uint64_t req_id, bool validate_only,
+ enum mgmt_result result, const char *error_if_any);
+
+/*
+ * Send get-config reply to the frontend client.
+ */
+extern int mgmt_frntnd_send_get_cfg_reply(uint64_t session_id, uint64_t trxn_id,
+ Mgmtd__DatabaseId db_id,
+ uint64_t req_id,
+ enum mgmt_result result,
+ Mgmtd__YangDataReply *data_resp,
+ const char *error_if_any);
+
+/*
+ * Send get-data reply to the frontend client.
+ */
+extern int mgmt_frntnd_send_get_data_reply(
+ uint64_t session_id, uint64_t trxn_id, Mgmtd__DatabaseId db_id,
+ uint64_t req_id, enum mgmt_result result,
+ Mgmtd__YangDataReply *data_resp, const char *error_if_any);
+
+/*
+ * Send data notify to the frontend client.
+ */
+extern int mgmt_frntnd_send_data_notify(Mgmtd__DatabaseId db_id,
+ Mgmtd__YangData * data_resp[],
+ int num_data);
+
+/* Fetch frontend client session set-config stats */
+extern struct mgmt_setcfg_stats *
+mgmt_frntnd_get_sessn_setcfg_stats(uint64_t session_id);
+
+/* Fetch frontend client session commit stats */
+extern struct mgmt_commit_stats *
+mgmt_frntnd_get_sessn_commit_stats(uint64_t session_id);
+
+extern void mgmt_frntnd_adapter_status_write(struct vty *vty, bool detail);
+extern void mgmt_frntnd_adapter_perf_measurement(struct vty *vty, bool config);
+extern void mgmt_frntnd_adapter_reset_perf_stats(struct vty *vty);
+#endif /* _FRR_MGMTD_FRNTND_ADAPTER_H_ */
--- /dev/null
+/*
+ * MGMTD Frontend Server
+ * Copyright (C) 2021 Vmware, Inc.
+ * Pushpasis Sarkar <spushpasis@vmware.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+#include "network.h"
+#include "libfrr.h"
+#include "mgmtd/mgmt.h"
+#include "mgmtd/mgmt_frntnd_server.h"
+#include "mgmtd/mgmt_frntnd_adapter.h"
+
+#ifdef REDIRECT_DEBUG_TO_STDERR
+#define MGMTD_FRNTND_SRVR_DBG(fmt, ...) \
+ fprintf(stderr, "%s: " fmt "\n", __func__, ##__VA_ARGS__)
+#define MGMTD_FRNTND_SRVR_ERR(fmt, ...) \
+ fprintf(stderr, "%s: ERROR, " fmt "\n", __func__, ##__VA_ARGS__)
+#else /* REDIRECT_DEBUG_TO_STDERR */
+#define MGMTD_FRNTND_SRVR_DBG(fmt, ...) \
+ do { \
+ if (mgmt_debug_bcknd) \
+ zlog_err("%s: " fmt, __func__, ##__VA_ARGS__); \
+ } while (0)
+#define MGMTD_FRNTND_SRVR_ERR(fmt, ...) \
+ zlog_err("%s: ERROR: " fmt, __func__, ##__VA_ARGS__)
+#endif /* REDIRECT_DEBUG_TO_STDERR */
+
+static int mgmt_frntnd_listen_fd;
+static struct thread_master *mgmt_frntnd_listen_tm;
+static struct thread *mgmt_frntnd_listen_ev;
+static void mgmt_frntnd_server_register_event(enum mgmt_frntnd_event event);
+
+static void mgmt_frntnd_conn_accept(struct thread *thread)
+{
+ int client_conn_fd;
+ union sockunion su;
+
+ if (!mgmt_frntnd_listen_fd)
+ return;
+
+ /* We continue hearing server listen socket. */
+ mgmt_frntnd_server_register_event(MGMTD_FRNTND_SERVER);
+
+ memset(&su, 0, sizeof(union sockunion));
+
+ /* We can handle IPv4 or IPv6 socket. */
+ client_conn_fd = sockunion_accept(mgmt_frntnd_listen_fd, &su);
+ if (client_conn_fd < 0) {
+ MGMTD_FRNTND_SRVR_ERR(
+ "Failed to accept MGMTD Frontend client connection : %s",
+ safe_strerror(errno));
+ return;
+ }
+ set_nonblocking(client_conn_fd);
+ set_cloexec(client_conn_fd);
+
+ MGMTD_FRNTND_SRVR_DBG("Got a new MGMTD Frontend connection");
+
+ mgmt_frntnd_create_adapter(client_conn_fd, &su);
+}
+
+static void mgmt_frntnd_server_register_event(enum mgmt_frntnd_event event)
+{
+ if (event == MGMTD_FRNTND_SERVER) {
+ thread_add_read(mgmt_frntnd_listen_tm, mgmt_frntnd_conn_accept,
+ NULL, mgmt_frntnd_listen_fd,
+ &mgmt_frntnd_listen_ev);
+ assert(mgmt_frntnd_listen_ev);
+ } else {
+ assert(!"mgmt_frntnd_server_post_event() called incorrectly");
+ }
+}
+
+static void mgmt_frntnd_server_start(const char *hostname)
+{
+ int ret;
+ int sock;
+ struct sockaddr_un addr;
+ mode_t old_mask;
+
+ /* Set umask */
+ old_mask = umask(0077);
+
+ sock = socket(AF_UNIX, SOCK_STREAM, PF_UNSPEC);
+ if (sock < 0) {
+ MGMTD_FRNTND_SRVR_ERR("Failed to create server socket: %s",
+ safe_strerror(errno));
+ goto mgmt_frntnd_server_start_failed;
+ }
+
+ addr.sun_family = AF_UNIX,
+ strlcpy(addr.sun_path, MGMTD_FRNTND_SERVER_PATH, sizeof(addr.sun_path));
+ unlink(addr.sun_path);
+ ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
+ if (ret < 0) {
+ MGMTD_FRNTND_SRVR_ERR(
+ "Failed to bind server socket to '%s'. Err: %s",
+ addr.sun_path, safe_strerror(errno));
+ goto mgmt_frntnd_server_start_failed;
+ }
+
+ ret = listen(sock, MGMTD_FRNTND_MAX_CONN);
+ if (ret < 0) {
+ MGMTD_FRNTND_SRVR_ERR("Failed to listen on server socket: %s",
+ safe_strerror(errno));
+ goto mgmt_frntnd_server_start_failed;
+ }
+
+ /* Restore umask */
+ umask(old_mask);
+
+ mgmt_frntnd_listen_fd = sock;
+ mgmt_frntnd_server_register_event(MGMTD_FRNTND_SERVER);
+
+ MGMTD_FRNTND_SRVR_DBG("Started MGMTD Frontend Server!");
+ return;
+
+mgmt_frntnd_server_start_failed:
+ if (sock)
+ close(sock);
+
+ mgmt_frntnd_listen_fd = 0;
+ exit(-1);
+}
+
+int mgmt_frntnd_server_init(struct thread_master *master)
+{
+ if (mgmt_frntnd_listen_tm) {
+ MGMTD_FRNTND_SRVR_DBG("MGMTD Frontend Server already running!");
+ return 0;
+ }
+
+ mgmt_frntnd_listen_tm = master;
+
+ mgmt_frntnd_server_start("localhost");
+
+ return 0;
+}
+
+void mgmt_frntnd_server_destroy(void)
+{
+ if (mgmt_frntnd_listen_tm) {
+ MGMTD_FRNTND_SRVR_DBG("Closing MGMTD Frontend Server!");
+
+ if (mgmt_frntnd_listen_ev) {
+ THREAD_OFF(mgmt_frntnd_listen_ev);
+ mgmt_frntnd_listen_ev = NULL;
+ }
+
+ if (mgmt_frntnd_listen_fd) {
+ close(mgmt_frntnd_listen_fd);
+ mgmt_frntnd_listen_fd = 0;
+ }
+
+ mgmt_frntnd_listen_tm = NULL;
+ }
+}
--- /dev/null
+/*
+ * MGMTD Frontend Server
+ * Copyright (C) 2021 Vmware, Inc.
+ * Pushpasis Sarkar <spushpasis@vmware.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _FRR_MGMTD_FRNTND_SERVER_H_
+#define _FRR_MGMTD_FRNTND_SERVER_H_
+
+#define MGMTD_FRNTND_MAX_CONN 32
+
+/* Initialise frontend server */
+extern int mgmt_frntnd_server_init(struct thread_master *master);
+
+/* Destroy frontend server */
+extern void mgmt_frntnd_server_destroy(void);
+
+#endif /* _FRR_MGMTD_FRNTND_SERVER_H_ */
zlog_rotate();
}
-static struct frr_signal_t mgmt_signals[] = {
- {
- .signal = SIGHUP,
- .handler = &sighup,
- },
- {
- .signal = SIGUSR1,
- .handler = &sigusr1,
- },
- {
- .signal = SIGINT,
- .handler = &sigint,
- },
- {
- .signal = SIGTERM,
- .handler = &sigint,
- },
-};
-
-
/*
* Try to free up allocations we know about so that diagnostic tools such as
* valgrind are able to better illuminate leaks.
exit(status);
}
+static struct frr_signal_t mgmt_signals[] = {
+ {
+ .signal = SIGHUP,
+ .handler = &sighup,
+ },
+ {
+ .signal = SIGUSR1,
+ .handler = &sigusr1,
+ },
+ {
+ .signal = SIGINT,
+ .handler = &sigint,
+ },
+ {
+ .signal = SIGTERM,
+ .handler = &sigint,
+ },
+};
+
static int mgmt_vrf_new(struct vrf *vrf)
{
zlog_debug("VRF Created: %s(%u)", vrf->name, vrf->vrf_id);
DEFINE_MGROUP(MGMTD, "mgmt");
DEFINE_MTYPE(MGMTD, MGMTD, "MGMTD instance");
+DEFINE_MTYPE(MGMTD, MGMTD_FRNTND_ADPATER, "MGMTD Frontend adapter");
+DEFINE_MTYPE(MGMTD, MGMTD_FRNTND_SESSN, "MGMTD Frontend Client Session");
DECLARE_MGROUP(MGMTD);
DECLARE_MTYPE(MGMTD);
+DECLARE_MTYPE(MGMTD_FRNTND_ADPATER);
+DECLARE_MTYPE(MGMTD_FRNTND_SESSN);
#endif /* _FRR_MGMTD_MEMORY_H */
+++ /dev/null
-#! /bin/bash
-
-# mgmtd/mgmt_test_frntnd - temporary wrapper script for .libs/mgmt_test_frntnd
-# Generated by libtool (GNU libtool) 2.4.6 Debian-2.4.6-2
-#
-# The mgmtd/mgmt_test_frntnd program cannot be directly executed until all the libtool
-# libraries that it depends on are installed.
-#
-# This wrapper script should never be moved out of the build directory.
-# If it is, it will not operate correctly.
-
-# Sed substitution that helps us do robust quoting. It backslashifies
-# metacharacters that are still active within double-quoted strings.
-sed_quote_subst='s|\([`"$\\]\)|\\\1|g'
-
-# Be Bourne compatible
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
- emulate sh
- NULLCMD=:
- # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
- # is contrary to our usage. Disable this feature.
- alias -g '${1+"$@"}'='"$@"'
- setopt NO_GLOB_SUBST
-else
- case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
-fi
-BIN_SH=xpg4; export BIN_SH # for Tru64
-DUALCASE=1; export DUALCASE # for MKS sh
-
-# The HP-UX ksh and POSIX shell print the target directory to stdout
-# if CDPATH is set.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
-
-relink_command=""
-
-# This environment variable determines our operation mode.
-if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then
- # install mode needs the following variables:
- generated_by_libtool_version='2.4.6'
- notinst_deplibs=' lib/libfrr.la'
-else
- # When we are sourced in execute mode, $file and $ECHO are already set.
- if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
- file="$0"
-
-# A function that is used when there is no print builtin or printf.
-func_fallback_echo ()
-{
- eval 'cat <<_LTECHO_EOF
-$1
-_LTECHO_EOF'
-}
- ECHO="printf %s\\n"
- fi
-
-# Very basic option parsing. These options are (a) specific to
-# the libtool wrapper, (b) are identical between the wrapper
-# /script/ and the wrapper /executable/ that is used only on
-# windows platforms, and (c) all begin with the string --lt-
-# (application programs are unlikely to have options that match
-# this pattern).
-#
-# There are only two supported options: --lt-debug and
-# --lt-dump-script. There is, deliberately, no --lt-help.
-#
-# The first argument to this parsing function should be the
-# script's ./libtool value, followed by no.
-lt_option_debug=
-func_parse_lt_options ()
-{
- lt_script_arg0=$0
- shift
- for lt_opt
- do
- case "$lt_opt" in
- --lt-debug) lt_option_debug=1 ;;
- --lt-dump-script)
- lt_dump_D=`$ECHO "X$lt_script_arg0" | sed -e 's/^X//' -e 's%/[^/]*$%%'`
- test "X$lt_dump_D" = "X$lt_script_arg0" && lt_dump_D=.
- lt_dump_F=`$ECHO "X$lt_script_arg0" | sed -e 's/^X//' -e 's%^.*/%%'`
- cat "$lt_dump_D/$lt_dump_F"
- exit 0
- ;;
- --lt-*)
- $ECHO "Unrecognized --lt- option: '$lt_opt'" 1>&2
- exit 1
- ;;
- esac
- done
-
- # Print the debug banner immediately:
- if test -n "$lt_option_debug"; then
- echo "mgmt_test_frntnd:mgmtd/mgmt_test_frntnd:$LINENO: libtool wrapper (GNU libtool) 2.4.6 Debian-2.4.6-2" 1>&2
- fi
-}
-
-# Used when --lt-debug. Prints its arguments to stdout
-# (redirection is the responsibility of the caller)
-func_lt_dump_args ()
-{
- lt_dump_args_N=1;
- for lt_arg
- do
- $ECHO "mgmt_test_frntnd:mgmtd/mgmt_test_frntnd:$LINENO: newargv[$lt_dump_args_N]: $lt_arg"
- lt_dump_args_N=`expr $lt_dump_args_N + 1`
- done
-}
-
-# Core function for launching the target application
-func_exec_program_core ()
-{
-
- if test -n "$lt_option_debug"; then
- $ECHO "mgmt_test_frntnd:mgmtd/mgmt_test_frntnd:$LINENO: newargv[0]: $progdir/$program" 1>&2
- func_lt_dump_args ${1+"$@"} 1>&2
- fi
- exec "$progdir/$program" ${1+"$@"}
-
- $ECHO "$0: cannot exec $program $*" 1>&2
- exit 1
-}
-
-# A function to encapsulate launching the target application
-# Strips options in the --lt-* namespace from $@ and
-# launches target application with the remaining arguments.
-func_exec_program ()
-{
- case " $* " in
- *\ --lt-*)
- for lt_wr_arg
- do
- case $lt_wr_arg in
- --lt-*) ;;
- *) set x "$@" "$lt_wr_arg"; shift;;
- esac
- shift
- done ;;
- esac
- func_exec_program_core ${1+"$@"}
-}
-
- # Parse options
- func_parse_lt_options "$0" ${1+"$@"}
-
- # Find the directory that this script lives in.
- thisdir=`$ECHO "$file" | sed 's%/[^/]*$%%'`
- test "x$thisdir" = "x$file" && thisdir=.
-
- # Follow symbolic links until we get to the real thisdir.
- file=`ls -ld "$file" | sed -n 's/.*-> //p'`
- while test -n "$file"; do
- destdir=`$ECHO "$file" | sed 's%/[^/]*$%%'`
-
- # If there was a directory component, then change thisdir.
- if test "x$destdir" != "x$file"; then
- case "$destdir" in
- [\\/]* | [A-Za-z]:[\\/]*) thisdir="$destdir" ;;
- *) thisdir="$thisdir/$destdir" ;;
- esac
- fi
-
- file=`$ECHO "$file" | sed 's%^.*/%%'`
- file=`ls -ld "$thisdir/$file" | sed -n 's/.*-> //p'`
- done
-
- # Usually 'no', except on cygwin/mingw when embedded into
- # the cwrapper.
- WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=no
- if test "$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR" = "yes"; then
- # special case for '.'
- if test "$thisdir" = "."; then
- thisdir=`pwd`
- fi
- # remove .libs from thisdir
- case "$thisdir" in
- *[\\/].libs ) thisdir=`$ECHO "$thisdir" | sed 's%[\\/][^\\/]*$%%'` ;;
- .libs ) thisdir=. ;;
- esac
- fi
-
- # Try to get the absolute directory name.
- absdir=`cd "$thisdir" && pwd`
- test -n "$absdir" && thisdir="$absdir"
-
- program='mgmt_test_frntnd'
- progdir="$thisdir/.libs"
-
-
- if test -f "$progdir/$program"; then
- # Add our own library path to LD_LIBRARY_PATH
- LD_LIBRARY_PATH="/root/upstream_p1/lib/.libs:$LD_LIBRARY_PATH"
-
- # Some systems cannot cope with colon-terminated LD_LIBRARY_PATH
- # The second colon is a workaround for a bug in BeOS R4 sed
- LD_LIBRARY_PATH=`$ECHO "$LD_LIBRARY_PATH" | sed 's/::*$//'`
-
- export LD_LIBRARY_PATH
-
- if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
- # Run the actual program with our arguments.
- func_exec_program ${1+"$@"}
- fi
- else
- # The program doesn't exist.
- $ECHO "$0: error: '$progdir/$program' does not exist" 1>&2
- $ECHO "This script is just a wrapper for $program." 1>&2
- $ECHO "See the libtool documentation for more information." 1>&2
- exit 1
- fi
-fi
#include "json.h"
#include "mgmtd/mgmt.h"
#include "mgmtd/mgmt_vty.h"
+#include "mgmtd/mgmt_frntnd_server.h"
+#include "mgmtd/mgmt_frntnd_adapter.h"
#include "mgmtd/mgmt_db.h"
#ifndef VTYSH_EXTRACT_PL
#include "mgmtd/mgmt_vty_clippy.c"
#endif
+DEFPY(show_mgmt_frntnd_adapter,
+ show_mgmt_frntnd_adapter_cmd,
+ "show mgmt frontend-adapter all",
+ SHOW_STR
+ MGMTD_STR
+ MGMTD_FRNTND_ADPTR_STR
+ "Display all Frontend Adapters\n")
+{
+ mgmt_frntnd_adapter_status_write(vty, false);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(show_mgmt_frntnd_adapter_detail,
+ show_mgmt_frntnd_adapter_detail_cmd,
+ "show mgmt frontend-adapter all detail",
+ SHOW_STR
+ MGMTD_STR
+ MGMTD_FRNTND_ADPTR_STR
+ "Display all Frontend Adapters\n"
+ "Details of commit stats\n")
+{
+ mgmt_frntnd_adapter_status_write(vty, true);
+
+ return CMD_SUCCESS;
+}
+
DEFPY(show_mgmt_db_all,
show_mgmt_db_all_cmd,
"show mgmt database all",
return CMD_SUCCESS;
}
+DEFPY(mgmt_commit_apply,
+ mgmt_commit_apply_cmd,
+ "mgmt commit-apply",
+ MGMTD_STR
+ "Validate and apply the set of config commands\n")
+{
+ if (vty_mgmt_send_commit_config(vty, false, false) != 0)
+ return CMD_WARNING_CONFIG_FAILED;
+ return CMD_SUCCESS;
+}
+
+DEFPY(mgmt_commit_check,
+ mgmt_commit_check_cmd,
+ "mgmt commit-check",
+ MGMTD_STR
+ "Validate the set of config commands only\n")
+{
+ if (vty_mgmt_send_commit_config(vty, true, false) != 0)
+ return CMD_WARNING_CONFIG_FAILED;
+ return CMD_SUCCESS;
+}
+
+DEFPY(mgmt_commit_abort,
+ mgmt_commit_abort_cmd,
+ "mgmt commit-abort",
+ MGMTD_STR
+ "Abort and drop the set of config commands recently added\n")
+{
+ if (vty_mgmt_send_commit_config(vty, false, true) != 0)
+ return CMD_WARNING_CONFIG_FAILED;
+ return CMD_SUCCESS;
+}
+
+DEFPY(mgmt_set_config_data,
+ mgmt_set_config_data_cmd,
+ "mgmt set-config xpath WORD$path value WORD$val",
+ MGMTD_STR
+ "Set configuration data\n"
+ "XPath expression specifying the YANG data path\n"
+ "XPath string\n"
+ "Value of the data to set to\n"
+ "<value of the data>\n")
+{
+
+ strlcpy(vty->cfg_changes[0].xpath, path,
+ sizeof(vty->cfg_changes[0].xpath));
+ vty->cfg_changes[0].value = val;
+ vty->cfg_changes[0].operation = NB_OP_CREATE;
+ vty->num_cfg_changes = 1;
+
+ vty->no_implicit_commit = true;
+ vty_mgmt_send_config_data(vty);
+ vty->no_implicit_commit = false;
+ return CMD_SUCCESS;
+}
+
+DEFPY(mgmt_delete_config_data,
+ mgmt_delete_config_data_cmd,
+ "mgmt delete-config xpath WORD$path",
+ MGMTD_STR
+ "Delete configuration data\n"
+ "XPath expression specifying the YANG data path\n"
+ "XPath string\n")
+{
+
+ strlcpy(vty->cfg_changes[0].xpath, path,
+ sizeof(vty->cfg_changes[0].xpath));
+ vty->cfg_changes[0].value = NULL;
+ vty->cfg_changes[0].operation = NB_OP_DESTROY;
+ vty->num_cfg_changes = 1;
+
+ vty->no_implicit_commit = true;
+ vty_mgmt_send_config_data(vty);
+ vty->no_implicit_commit = false;
+ return CMD_SUCCESS;
+}
+
+DEFPY(show_mgmt_get_config,
+ show_mgmt_get_config_cmd,
+ "show mgmt get-config [db-name WORD$dbname] xpath WORD$path",
+ SHOW_STR
+ MGMTD_STR
+ "Get configuration data from a specific configuration database\n"
+ "DB name\n"
+ "<candidate running operational>\n"
+ "XPath expression specifying the YANG data path\n"
+ "XPath string\n")
+{
+ const char *xpath_list[VTY_MAXCFGCHANGES] = {0};
+ Mgmtd__DatabaseId database = MGMTD_DB_CANDIDATE;
+
+ if (dbname)
+ database = mgmt_db_name2id(dbname);
+
+ if (database == MGMTD_DB_NONE) {
+ vty_out(vty,
+ "DB Name %s does not matches any existing database\n",
+ dbname);
+ return CMD_SUCCESS;
+ }
+
+ xpath_list[0] = path;
+ vty_mgmt_send_get_config(vty, database, xpath_list, 1);
+ return CMD_SUCCESS;
+}
+
+DEFPY(show_mgmt_get_data,
+ show_mgmt_get_data_cmd,
+ "show mgmt get-data [db-name WORD$dbname] xpath WORD$path",
+ SHOW_STR
+ MGMTD_STR
+ "Get data from a specific database\n"
+ "DB name\n"
+ "<candidate running operational>\n"
+ "XPath expression specifying the YANG data path\n"
+ "XPath string\n")
+{
+ const char *xpath_list[VTY_MAXCFGCHANGES] = {0};
+ Mgmtd__DatabaseId database = MGMTD_DB_CANDIDATE;
+
+ if (dbname)
+ database = mgmt_db_name2id(dbname);
+
+ if (database == MGMTD_DB_NONE) {
+ vty_out(vty,
+ "DB Name %s does not matches any existing database\n",
+ dbname);
+ return CMD_SUCCESS;
+ }
+
+ xpath_list[0] = path;
+ vty_mgmt_send_get_data(vty, database, xpath_list, 1);
+ return CMD_SUCCESS;
+}
+
+
+
DEFPY(show_mgmt_dump_data,
show_mgmt_dump_data_cmd,
"show mgmt database-contents db-name WORD$dbname [xpath WORD$path] [file WORD$filepath] format WORD$format_str",
"Format of the output\n"
"json|xml")
{
- enum mgmt_database_id database = MGMTD_DB_CANDIDATE;
+ Mgmtd__DatabaseId database = MGMTD_DB_CANDIDATE;
struct mgmt_db_ctxt *db_ctxt;
LYD_FORMAT format = LYD_UNKNOWN;
FILE *f = NULL;
"Full path of the file")
{
struct mgmt_db_ctxt *db_ctxt;
- enum mgmt_database_id database;
+ Mgmtd__DatabaseId database;
FILE *f;
database = mgmt_db_name2id(dbname);
{
install_node(&debug_node);
+ install_element(VIEW_NODE, &show_mgmt_frntnd_adapter_cmd);
+ install_element(VIEW_NODE, &show_mgmt_frntnd_adapter_detail_cmd);
install_element(VIEW_NODE, &show_mgmt_db_all_cmd);
install_element(VIEW_NODE, &show_mgmt_db_runn_cmd);
install_element(VIEW_NODE, &show_mgmt_db_cand_cmd);
install_element(VIEW_NODE, &show_mgmt_db_oper_cmd);
+ install_element(VIEW_NODE, &show_mgmt_get_config_cmd);
+ install_element(VIEW_NODE, &show_mgmt_get_data_cmd);
install_element(VIEW_NODE, &show_mgmt_dump_data_cmd);
+ install_element(CONFIG_NODE, &mgmt_commit_apply_cmd);
+ install_element(CONFIG_NODE, &mgmt_commit_abort_cmd);
+ install_element(CONFIG_NODE, &mgmt_commit_check_cmd);
+ install_element(CONFIG_NODE, &mgmt_set_config_data_cmd);
+ install_element(CONFIG_NODE, &mgmt_delete_config_data_cmd);
install_element(CONFIG_NODE, &mgmt_load_config_cmd);
install_element(CONFIG_NODE, &mgmt_save_config_cmd);
mgmtd/mgmt_memory.c \
mgmtd/mgmt_db.c \
mgmtd/mgmt_vty.c \
+ mgmtd/mgmt_frntnd_server.c \
+ mgmtd/mgmt_frntnd_adapter.c \
# end
mgmtdheaderdir = $(pkgincludedir)/mgmtd
mgmtd/mgmt_memory.h \
mgmtd/mgmt_db.h \
mgmtd/mgmt_vty.h \
+ mgmtd/mgmt_frntnd_adapter.h \
+ mgmtd/mgmt_frntnd_server.h \
# end
sbin_PROGRAMS += mgmtd/mgmtd