]> git.puffer.fish Git - matthieu/frr.git/commitdiff
mgmtd: Add MGMT Frontend Interface Framework
authorYash Ranjan <ranjany@vmware.com>
Tue, 26 Oct 2021 14:10:11 +0000 (07:10 -0700)
committerChristian Hopps <chopps@labn.net>
Wed, 6 Apr 2022 01:41:23 +0000 (21:41 -0400)
This commit introduces the Frontend Interface which can be used
by front-end management clients like Netconf server, Restconf
Server and CLI to interact with new FRR Management daemon (MGMTd)
to access and sometimes modify FRR management data.

This commit includes the following functionalities in the changeset:
1. Add new Frontend server for clients connect to.
2. Add a C-based Frontend client library which can be used by Frontend
   clients to communicate with MGMTd via the Frontend interface.
3. Maintain a frontend adapter for each connection from an appropriate
   Frontend client to facilitate client requests and track one or more
   client sessions across it.
4. Define the protobuf message format for messages to be exchanged
   between MGMTd Frontend module and the Frontend client.
5. This changeset also introduces an instance of MGMT Frontend client
   embedded within the lib/vty module that can be leveraged by any FRR
   daemon to connect to MGMTd's Frontend interface. The same has been
   integrated with and initialized within the MGMTd daemon's process
   context to implement a bunch of 'set-config', 'commit-apply',
   'get-config' and 'get-data' commands via VTYSH

Co-authored-by: Pushpasis Sarkar <pushpasis@gmail.com>
Co-authored-by: Abhinay Ramesh <rabhinay@vmware.com>
Co-authored-by: Ujwal P <ujwalp@vmware.com>
Signed-off-by: Yash Ranjan <ranjany@vmware.com>
26 files changed:
.clang-format
lib/lib_vty.c
lib/mgmt.proto [new file with mode: 0644]
lib/mgmt_frntnd_client.c [new file with mode: 0644]
lib/mgmt_frntnd_client.h [new file with mode: 0644]
lib/mgmt_pb.h [new file with mode: 0644]
lib/northbound.h
lib/northbound_cli.c
lib/subdir.am
lib/vty.c
lib/vty.h
mgmtd/mgmt.c
mgmtd/mgmt.h
mgmtd/mgmt_db.c
mgmtd/mgmt_db.h
mgmtd/mgmt_defines.h
mgmtd/mgmt_frntnd_adapter.c [new file with mode: 0644]
mgmtd/mgmt_frntnd_adapter.h [new file with mode: 0644]
mgmtd/mgmt_frntnd_server.c [new file with mode: 0644]
mgmtd/mgmt_frntnd_server.h [new file with mode: 0644]
mgmtd/mgmt_main.c
mgmtd/mgmt_memory.c
mgmtd/mgmt_memory.h
mgmtd/mgmt_test_frntnd [deleted file]
mgmtd/mgmt_vty.c
mgmtd/subdir.am

index b01157b05183992cf06a51aa05450947758c3087..0aef994828f8c52c428cc09157d8d048e371e4e6 100644 (file)
@@ -76,3 +76,8 @@ ForEachMacros:
   - FOREACH_SAFI
   # ospfd
   - LSDB_LOOP
+  # mgmtd
+  - FOREACH_MGMTD_DB_ID
+  - FOREACH_ADPTR_IN_LIST
+  - FOREACH_SESSN_IN_LIST
+  - FOREACH_SESSN_IN_LIST_SAFE
index 85816c51230b2c568ccfb6296cd83d3c1c0b58d0..acf46b5254fc4f26e7fc7012c90cce7cd3d81bbd 100644 (file)
@@ -260,6 +260,9 @@ DEFUN_HIDDEN (end_config,
 
        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)();
 
diff --git a/lib/mgmt.proto b/lib/mgmt.proto
new file mode 100644 (file)
index 0000000..a8b1c71
--- /dev/null
@@ -0,0 +1,358 @@
+//
+// 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;
+  }
+}
diff --git a/lib/mgmt_frntnd_client.c b/lib/mgmt_frntnd_client.c
new file mode 100644 (file)
index 0000000..9662511
--- /dev/null
@@ -0,0 +1,1333 @@
+/*
+ * 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(&regntfy_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 = &regntfy_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);
+}
diff --git a/lib/mgmt_frntnd_client.h b/lib/mgmt_frntnd_client.h
new file mode 100644 (file)
index 0000000..51b4169
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ * 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_ */
diff --git a/lib/mgmt_pb.h b/lib/mgmt_pb.h
new file mode 100644 (file)
index 0000000..f2982d2
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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_ */
index a330bd1a30b0601ff4da5a7439e3a1eeb162bd7e..c59f96d2a93542a4d329b9b7807410e38bd4c619 100644 (file)
@@ -81,6 +81,12 @@ enum nb_operation {
        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;
index 56eac9dc32a30071f2a4d49929bfa72c752ff4fc..7b2f2f15d26b98e21b7cd8d61914fa8b4a4afc8d 100644 (file)
@@ -135,7 +135,7 @@ static int nb_cli_schedule_command(struct vty *vty)
 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. */
@@ -164,7 +164,7 @@ static int nb_cli_apply_changes_internal(struct vty *vty,
 
        /* 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;
index d1df9cb3d9e8c1937b9c0ce05c7f904ba3292117..23e16342e676f2c58f7a4e6403a6834326b4056c 100644 (file)
@@ -69,6 +69,7 @@ lib_libfrr_la_SOURCES = \
        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 \
@@ -137,6 +138,23 @@ nodist_lib_libfrr_la_SOURCES = \
        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 \
@@ -185,6 +203,9 @@ pkginclude_HEADERS += \
        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 \
index 619d51e1ce7dcb8fcc1ccbdd220fa404b04876fc..7343dad482e0380f71e0f8eba9047f96d2d9f9ac 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -77,6 +77,14 @@ enum vty_event {
 #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 {
@@ -92,6 +100,7 @@ DECLARE_DLIST(vtyservs, struct vty_serv, itm);
 
 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;
@@ -124,6 +133,36 @@ static char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG;
 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;
@@ -1564,6 +1603,17 @@ struct vty *vty_new(void)
        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;
 }
 
@@ -2179,6 +2229,12 @@ static void vtysh_read(struct thread *thread)
                                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;
@@ -2235,6 +2291,12 @@ void vty_close(struct vty *vty)
        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);
 
@@ -2610,6 +2672,24 @@ int vty_config_enter(struct vty *vty, bool private_config, bool exclusive)
                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;
@@ -2621,7 +2701,14 @@ int vty_config_enter(struct vty *vty, bool private_config, bool exclusive)
                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);
@@ -2654,6 +2741,18 @@ int vty_config_node_exit(struct vty *vty)
 {
        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);
 
@@ -3146,6 +3245,384 @@ void vty_init_vtysh(void)
        /* 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)
 {
@@ -3193,6 +3670,11 @@ void vty_terminate(void)
        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();
index e42a3b210fef4ea650621edd06cd49c82ed15a03..2fb29dfb4bee4c44ade5128a1119f92245f1f7e8 100644 (file)
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -35,6 +35,7 @@
 #include "compiler.h"
 #include "northbound.h"
 #include "zlog_live.h"
+#include "mgmt_frntnd_client.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -123,7 +124,7 @@ struct vty {
 
        /* 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;
@@ -144,6 +145,7 @@ struct vty {
        /* 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;
@@ -218,6 +220,12 @@ struct vty {
         * 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)
@@ -320,6 +328,8 @@ struct vty_arg {
 #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);
@@ -367,6 +377,18 @@ extern void vty_stdio_suspend(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
index 3ac3d8d3392e8cc9eacda31af8070bfa3b7fa2c2..9dbd01b13d335a8cd825c9c7d26a1c8217371ab9 100644 (file)
@@ -20,6 +20,8 @@
 #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"
 
@@ -48,14 +50,28 @@ void mgmt_master_init(struct thread_master *master, const int buffer_size)
 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();
 }
index 056d3cf15672e39012a86115cb1c6bcc8987d213..c694e6bb918f4445f8669c9d523cca58fe141c61 100644 (file)
@@ -23,6 +23,7 @@
 #include "vrf.h"
 
 #include "defaults.h"
+#include "stream.h"
 
 #include "mgmtd/mgmt_memory.h"
 #include "mgmtd/mgmt_db.h"
@@ -55,6 +56,13 @@ struct mgmt_master {
 
 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.
  *
index 354e5c2d3ab6f8f988d741819450ba5709570c90..39c916d102a7c839590cfe4c37e2db22377a5d6c 100644 (file)
@@ -41,7 +41,7 @@
 #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;
@@ -224,11 +224,10 @@ void mgmt_db_destroy(void)
        /*
         * 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:
@@ -237,7 +236,9 @@ struct mgmt_db_ctxt *mgmt_db_get_hndl_by_id(struct mgmt_master *mm,
                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;
        }
 
index ed5dd990ddcfa94fb5845cfefb94aeeafff0dcb4..9aec3aaca1a7cfac45d8505d5ec684591caa6cf0 100644 (file)
@@ -51,18 +51,6 @@ extern struct nb_config *running_config;
 
 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);
@@ -82,7 +70,7 @@ extern const char *mgmt_db_names[MGMTD_DB_MAX_ID + 1];
  * 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;
@@ -98,9 +86,9 @@ static inline const char *mgmt_db_id2name(enum mgmt_database_id 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))
@@ -115,7 +103,7 @@ static inline enum mgmt_database_id mgmt_db_name2id(const char *name)
  *
  * 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;
@@ -202,7 +190,7 @@ extern void mgmt_db_destroy(void);
  *    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
index 0d6dd774695ded62d1ffbb1cad5ffeaa4ae7b342..c07205736b59f41f5e96e1f3eb805c16871a2092 100644 (file)
 #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 */
diff --git a/mgmtd/mgmt_frntnd_adapter.c b/mgmtd/mgmt_frntnd_adapter.c
new file mode 100644 (file)
index 0000000..3c49b82
--- /dev/null
@@ -0,0 +1,2152 @@
+/*
+ * 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));
+               }
+       }
+}
diff --git a/mgmtd/mgmt_frntnd_adapter.h b/mgmtd/mgmt_frntnd_adapter.h
new file mode 100644 (file)
index 0000000..8c720cc
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * 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_ */
diff --git a/mgmtd/mgmt_frntnd_server.c b/mgmtd/mgmt_frntnd_server.c
new file mode 100644 (file)
index 0000000..3693e80
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * 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;
+       }
+}
diff --git a/mgmtd/mgmt_frntnd_server.h b/mgmtd/mgmt_frntnd_server.h
new file mode 100644 (file)
index 0000000..3e0c8e1
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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_ */
index 018b7d1051bf4982afe72ccb908713023fc150cf..3933838a26523015ef12a86655efe5c82b227b26 100644 (file)
@@ -116,26 +116,6 @@ static void sigusr1(void)
        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.
@@ -159,6 +139,25 @@ static __attribute__((__noreturn__)) void mgmt_exit(int status)
        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);
index a52d71c79712ce985fec0de890845f6f1f0f040b..3b98c60f872f8d83455575b30f3666b8c8185c7e 100644 (file)
@@ -30,3 +30,5 @@
 
 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");
index a8ef37665f5c9507dc265c7b7c83e758b12b5125..3b9575b325c57084295c86627e07d1229083d1a2 100644 (file)
@@ -24,4 +24,6 @@
 
 DECLARE_MGROUP(MGMTD);
 DECLARE_MTYPE(MGMTD);
+DECLARE_MTYPE(MGMTD_FRNTND_ADPATER);
+DECLARE_MTYPE(MGMTD_FRNTND_SESSN);
 #endif /* _FRR_MGMTD_MEMORY_H */
diff --git a/mgmtd/mgmt_test_frntnd b/mgmtd/mgmt_test_frntnd
deleted file mode 100755 (executable)
index 051336a..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-#! /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
index d2a23b4c12176f23dbe0e0f25765f4d61da5ffa4..5ea7a1624ab757f6dac3c30686274347057b2179 100644 (file)
 #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",
@@ -106,6 +135,143 @@ DEFPY(show_mgmt_db_oper,
        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",
@@ -121,7 +287,7 @@ DEFPY(show_mgmt_dump_data,
       "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;
@@ -222,7 +388,7 @@ DEFPY(mgmt_save_config,
       "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);
@@ -381,12 +547,21 @@ void mgmt_vty_init(void)
 {
        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);
 
index 91234eb0da66e91546fb011fe45e72e63b74e06d..66dd960c6a4f791295b04d6f37688901595be8df 100644 (file)
@@ -23,6 +23,8 @@ mgmtd_libmgmtd_a_SOURCES = \
        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
@@ -35,6 +37,8 @@ noinst_HEADERS += \
        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