$(AUTOMAKE_DUMMY)install-binPROGRAMS: install-libLTLIBRARIES
$(AUTOMAKE_DUMMY)install-sbinPROGRAMS: install-libLTLIBRARIES
+# Include default rules to compile protobuf message sources
+SUFFIXES += .proto .pb-c.c .pb-c.h
+
+# Rules
+
+AM_V_PROTOC_C = $(am__v_PROTOC_C_$(V))
+am__v_PROTOC_C_ = $(am__v_PROTOC_C_$(AM_DEFAULT_VERBOSITY))
+am__v_PROTOC_C_0 = @echo " PROTOC_C" $@;
+am__v_PROTOC_C_1 =
+
+.proto.pb-c.c:
+ $(AM_V_PROTOC_C)$(PROTOC_C) -I$(top_srcdir) --c_out=$(top_builddir) $^
+ $(AM_V_GEN)$(SED) -i -e '1i\
+ #include "config.h"' $@
+
+.pb-c.c.pb-c.h:
+ @echo " GEN " $@
+
include doc/subdir.am
include doc/user/subdir.am
include doc/manpages/subdir.am
include grpc/subdir.am
include tools/subdir.am
+include mgmtd/subdir.am
+
include bgpd/subdir.am
include bgpd/rfp-example/librfp/subdir.am
include bgpd/rfp-example/rfptest/subdir.am
pkgsrc/ripd.sh \
pkgsrc/ripngd.sh \
pkgsrc/zebra.sh \
+ pkgsrc/mgmtd.sh \
# end
endif
snapcraft/helpers \
snapcraft/snap \
babeld/Makefile \
+ mgmtd/Makefile \
bgpd/Makefile \
bgpd/rfp-example/librfp/Makefile \
bgpd/rfp-example/rfptest/Makefile \
$(MAKE) distclean CONFIG_CLEAN_FILES="$(filter-out $(EXTRA_DIST), $(CONFIG_CLEAN_FILES))"
indent:
- tools/indent.py `find sharpd bgpd eigrpd include isisd lib nhrpd ospf6d ospfd pimd qpb ripd vtysh zebra -name '*.[ch]' | grep -v include/linux`
+ tools/indent.py `find sharpd bgpd mgmtd eigrpd include isisd lib nhrpd ospf6d ospfd pimd qpb ripd vtysh zebra -name '*.[ch]' | grep -v include/linux`
if HAVE_GCOV
AS_HELP_STRING([--disable-zebra], [do not build zebra daemon]))
AC_ARG_ENABLE([bgpd],
AS_HELP_STRING([--disable-bgpd], [do not build bgpd]))
+AC_ARG_ENABLE([mgmtd],
+ AS_HELP_STRING([--disable-mgmtd], [do not build mgmtd]))
AC_ARG_ENABLE([ripd],
AS_HELP_STRING([--disable-ripd], [do not build ripd]))
AC_ARG_ENABLE([ripngd],
AC_DEFINE([KEEP_OLD_VPN_COMMANDS], [1], [Define for compiling with old vpn commands])
fi
-#
-# End of logic for protobuf support.
-#
-
AC_MSG_CHECKING([if zebra should be configurable to send Route Advertisements])
if test "$enable_rtadv" != "no"; then
AC_MSG_RESULT([yes])
# Logic for protobuf support.
#
PROTO3=false
-if test "$enable_protobuf" = "yes"; then
- # Check for protoc & protoc-c
+# Enable Protobuf by default at all times.
+# Check for protoc & protoc-c
+# protoc is not required, it's only for a "be nice" helper target
+AC_CHECK_PROGS([PROTOC], [protoc], [/bin/false])
- # protoc is not required, it's only for a "be nice" helper target
- AC_CHECK_PROGS([PROTOC], [protoc], [/bin/false])
-
- AC_CHECK_PROGS([PROTOC_C], [protoc-c], [/bin/false])
- if test "$PROTOC_C" = "/bin/false"; then
- AC_MSG_FAILURE([protobuf requested but protoc-c not found. Install protobuf-c.])
- fi
+AC_CHECK_PROGS([PROTOC_C], [protoc-c], [/bin/false])
+if test "$PROTOC_C" = "/bin/false"; then
+ AC_MSG_FAILURE([protobuf requested but protoc-c not found. Install protobuf-c.])
+fi
- PKG_CHECK_MODULES([PROTOBUF_C], [libprotobuf-c >= 0.14],, [
- AC_MSG_FAILURE([protobuf requested but libprotobuf-c not found. Install protobuf-c.])
- ])
+PKG_CHECK_MODULES([PROTOBUF_C], [libprotobuf-c >= 1.1.0],, [
+ AC_MSG_FAILURE([minimum version of libprotobuf-c not found. Install minimum required version of protobuf-c.])
+])
+if test "$enable_protobuf3" = "yes"; then
PROTO3=true
AC_CHECK_HEADER([google/protobuf-c/protobuf-c.h],
[AC_CHECK_DECLS(PROTOBUF_C_LABEL_NONE,
[1], [Have Protobuf version 3]),
[PROTO3=false],
[#include <google/protobuf-c/protobuf-c.h>])],
- [PROTO3=false && AC_MSG_FAILURE([protobuf requested but protobuf-c.h not found. Install protobuf-c.])])
-
- AC_DEFINE([HAVE_PROTOBUF], [1], [protobuf])
+ [PROTO3=false && AC_MSG_FAILURE([protobuf3 requested but protobuf-c.h not found. Install protobuf-c.])])
fi
+AC_DEFINE([HAVE_PROTOBUF], [1], [protobuf])
+#
+# End of logic for protobuf support.
+#
+
dnl ---------------------
dnl Integrated VTY option
AC_DEFINE([HAVE_BGPD], [1], [bgpd])
])
+AS_IF([test "$enable_mgmtd" != "no"], [
+ # Check for protoc & protoc-c
+
+ # protoc is not required, it's only for a "be nice" helper target
+ AC_CHECK_PROGS([PROTOC], [protoc], [/bin/false])
+
+ AC_CHECK_PROGS([PROTOC_C], [protoc-c], [/bin/false])
+ if test "$PROTOC_C" = "/bin/false"; then
+ AC_MSG_FAILURE([protobuf requested but protoc-c not found. Install protobuf-c.])
+ fi
+
+ PKG_CHECK_MODULES([PROTOBUF_C], [libprotobuf-c >= 1.1.0],, [
+ AC_MSG_FAILURE([minimum version of libprotobuf-c not found. Install minimum required version of protobuf-c.])
+ ])
+
+ AC_DEFINE([HAVE_MGMTD], [1], [mgmtd])
+])
+
AS_IF([test "$enable_ripd" != "no"], [
AC_DEFINE([HAVE_RIPD], [1], [ripd])
])
AC_DEFINE_UNQUOTED([ZEBRA_SERV_PATH], ["$frr_statedir%s%s/zserv.api"], [zebra api socket])
AC_DEFINE_UNQUOTED([BFDD_CONTROL_SOCKET], ["$frr_statedir%s%s/bfdd.sock"], [bfdd control socket])
AC_DEFINE_UNQUOTED([OSPFD_GR_STATE], ["$frr_statedir%s/ospfd-gr.json"], [ospfd GR state information])
+AC_DEFINE_UNQUOTED([MGMTD_FRNTND_SERVER_PATH], ["$frr_statedir/mgmtd_frntnd.sock"], [mgmtd frontend server socket])
+AC_DEFINE_UNQUOTED([MGMTD_BCKND_SERVER_PATH], ["$frr_statedir/mgmtd_bcknd.sock"], [mgmtd backend server socket])
AC_DEFINE_UNQUOTED([OSPF6D_GR_STATE], ["$frr_statedir/ospf6d-gr.json"], [ospf6d GR state information])
AC_DEFINE_UNQUOTED([OSPF6_AUTH_SEQ_NUM_FILE], ["$frr_statedir/ospf6d-at-seq-no.dat"], [ospf6d AT Sequence number information])
AC_DEFINE_UNQUOTED([DAEMON_VTY_DIR], ["$frr_statedir%s%s"], [daemon vty directory])
AM_CONDITIONAL([SNMP], [test "$SNMP_METHOD" = "agentx"])
AM_CONDITIONAL([IRDP], [$IRDP])
AM_CONDITIONAL([FPM], [test "$enable_fpm" = "yes"])
-AM_CONDITIONAL([HAVE_PROTOBUF], [test "$enable_protobuf" = "yes"])
+AM_CONDITIONAL([HAVE_PROTOBUF], [test "$enable_protobuf" != "no"])
AM_CONDITIONAL([HAVE_PROTOBUF3], [$PROTO3])
dnl PCEP plugin
AM_CONDITIONAL([VTYSH], [test "$VTYSH" = "vtysh"])
AM_CONDITIONAL([ZEBRA], [test "$enable_zebra" != "no"])
AM_CONDITIONAL([BGPD], [test "$enable_bgpd" != "no"])
+AM_CONDITIONAL([MGMTD], [test "$enable_mgmtd" != "no"])
AM_CONDITIONAL([RIPD], [test "$enable_ripd" != "no"])
AM_CONDITIONAL([OSPFD], [test "$enable_ospfd" != "no"])
AM_CONDITIONAL([LDPD], [test "$enable_ldpd" != "no"])
alpine/APKBUILD
snapcraft/snapcraft.yaml
lib/version.h
- tests/lib/cli/test_cli.refout
+ tests/lib/cli/test_cli.refout pkgsrc/mgmtd.sh
pkgsrc/bgpd.sh pkgsrc/ospf6d.sh pkgsrc/ospfd.sh
pkgsrc/ripd.sh pkgsrc/ripngd.sh pkgsrc/zebra.sh
pkgsrc/eigrpd.sh])
Suggests: frr-doc
Conflicts: pimd,
quagga,
+ quagga-mgmtd,
quagga-bgpd,
quagga-core,
quagga-isisd,
#define SHARP_STR "Sharp Routing Protocol\n"
#define OSPF_GR_STR \
"OSPF non-stop forwarding (NSF) also known as OSPF Graceful Restart\n"
+#define MGMTD_STR "Management Daemon (MGMTD) information\n"
+#define MGMTD_BCKND_ADPTR_STR "MGMTD Backend Adapter information\n"
+#define MGMTD_FRNTND_ADPTR_STR "MGMTD Frontend Adapter information\n"
+#define MGMTD_TRXN_STR "MGMTD Transaction information\n"
+#define MGMTD_DB_STR "MGMTD Database information\n"
#define CMD_VNI_RANGE "(1-16777215)"
#define CONF_BACKUP_EXT ".sav"
--- /dev/null
+all: ALWAYS
+ @$(MAKE) -s -C .. mgmtd/mgmtd
+%: ALWAYS
+ @$(MAKE) -s -C .. mgmtd/$@
+
+Makefile:
+ #nothing
+ALWAYS:
+.PHONY: ALWAYS makefiles
+.SUFFIXES:
--- /dev/null
+/* FRR Management Daemon (MGMTD) program
+ * Copyright (C) 2021 Vmware, Inc.
+ * Pushpasis Sarkar
+ *
+ * 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 "mgmtd/mgmt.h"
+#include "mgmtd/mgmt_vty.h"
+#include "mgmtd/mgmt_db.h"
+#include "mgmtd/mgmt_memory.h"
+
+bool mgmt_debug_bcknd;
+bool mgmt_debug_frntnd;
+bool mgmt_debug_db;
+bool mgmt_debug_trxn;
+
+/* MGMTD process wide configuration. */
+static struct mgmt_master mgmt_master;
+
+/* MGMTD process wide configuration pointer to export. */
+struct mgmt_master *mm;
+
+void mgmt_master_init(struct thread_master *master, const int buffer_size)
+{
+ memset(&mgmt_master, 0, sizeof(struct mgmt_master));
+
+ mm = &mgmt_master;
+ mm->master = master;
+ mm->terminating = false;
+ mm->socket_buffer = buffer_size;
+ mm->perf_stats_en = true;
+}
+
+void mgmt_init(void)
+{
+
+ /* Initialize databases */
+ mgmt_db_init(mm);
+
+ /* MGMTD VTY commands installation. */
+ mgmt_vty_init();
+}
+
+void mgmt_terminate(void)
+{
+ mgmt_db_destroy();
+}
--- /dev/null
+/* MGMTD message definition header.
+ * 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_H
+#define _FRR_MGMTD_H
+
+#include "vrf.h"
+
+#include "defaults.h"
+
+#include "mgmtd/mgmt_memory.h"
+#include "mgmtd/mgmt_db.h"
+
+#define MGMTD_VTY_PORT 2622
+#define MGMTD_SOCKET_BUF_SIZE 65535
+
+extern bool mgmt_debug_bcknd;
+extern bool mgmt_debug_frntnd;
+extern bool mgmt_debug_db;
+extern bool mgmt_debug_trxn;
+
+/*
+ * MGMTD master for system wide configurations and variables.
+ */
+struct mgmt_master {
+ struct thread_master *master;
+
+ /* How big should we set the socket buffer size */
+ uint32_t socket_buffer;
+
+ /* Databases */
+ struct mgmt_db_ctxt *running_db;
+ struct mgmt_db_ctxt *candidate_db;
+ struct mgmt_db_ctxt *oper_db;
+
+ bool terminating; /* global flag that sigint terminate seen */
+ bool perf_stats_en; /* to enable performance stats measurement */
+};
+
+extern struct mgmt_master *mm;
+
+/*
+ * Remove trailing separator from a string.
+ *
+ * str
+ * A null terminated string.
+ *
+ * sep
+ * Trailing character that needs to be removed.
+ */
+static inline void mgmt_remove_trailing_separator(char *str, char sep)
+{
+ size_t len;
+
+ len = strlen(str);
+ if (len && str[len - 1] == sep)
+ str[len - 1] = '\0';
+}
+
+/* Prototypes. */
+extern void mgmt_terminate(void);
+extern void mgmt_reset(void);
+extern time_t mgmt_clock(void);
+
+extern int mgmt_config_write(struct vty *vty);
+
+extern void mgmt_master_init(struct thread_master *master,
+ const int buffer_size);
+
+extern void mgmt_init(void);
+
+static inline char *mgmt_realtime_to_string(struct timeval *tv, char *buf,
+ size_t sz)
+{
+ char tmp[50];
+ struct tm *lm;
+
+ lm = localtime((const time_t *)&tv->tv_sec);
+ if (lm) {
+ strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S", lm);
+ snprintf(buf, sz, "%s.%06lu", tmp,
+ (unsigned long int)tv->tv_usec);
+ }
+
+ return buf;
+}
+
+#endif /* _FRR_MGMTD_H */
--- /dev/null
+/*
+ * MGMTD Databases
+ * 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 "md5.h"
+#include "mgmtd/mgmt.h"
+#include "mgmtd/mgmt_memory.h"
+#include "mgmtd/mgmt_db.h"
+#include "libyang/libyang.h"
+
+#ifdef REDIRECT_DEBUG_TO_STDERR
+#define MGMTD_DB_DBG(fmt, ...) \
+ fprintf(stderr, "%s: " fmt "\n", __func__, ##__VA_ARGS__)
+#define MGMTD_DB_ERR(fmt, ...) \
+ fprintf(stderr, "%s: ERROR, " fmt "\n", __func__, ##__VA_ARGS__)
+#else /* REDIRECT_DEBUG_TO_STDERR */
+#define MGMTD_DB_DBG(fmt, ...) \
+ do { \
+ if (mgmt_debug_db) \
+ zlog_debug("%s: " fmt, __func__, ##__VA_ARGS__); \
+ } while (0)
+#define MGMTD_DB_ERR(fmt, ...) \
+ zlog_err("%s: ERROR: " fmt, __func__, ##__VA_ARGS__)
+#endif /* REDIRECT_DEBUG_TO_STDERR */
+
+struct mgmt_db_ctxt {
+ enum mgmt_database_id db_id;
+ pthread_rwlock_t rw_lock;
+
+ bool config_db;
+
+ union {
+ struct nb_config *cfg_root;
+ struct lyd_node *dnode_root;
+ } root;
+};
+
+const char *mgmt_db_names[MGMTD_DB_MAX_ID + 1] = {
+ MGMTD_DB_NAME_NONE, /* MGMTD_DB_NONE */
+ MGMTD_DB_NAME_RUNNING, /* MGMTD_DB_RUNNING */
+ MGMTD_DB_NAME_CANDIDATE, /* MGMTD_DB_RUNNING */
+ MGMTD_DB_NAME_OPERATIONAL, /* MGMTD_DB_OPERATIONAL */
+ "Unknown/Invalid", /* MGMTD_DB_ID_MAX */
+};
+
+static struct mgmt_master *mgmt_db_mm;
+static struct mgmt_db_ctxt running, candidate, oper;
+
+/* Dump the data tree of the specified format in the file pointed by the path */
+static int mgmt_db_dump_in_memory(struct mgmt_db_ctxt *db_ctxt,
+ const char *base_xpath, LYD_FORMAT format,
+ struct ly_out *out)
+{
+ struct lyd_node *root;
+ uint32_t options = 0;
+
+ if (base_xpath[0] == '\0')
+ root = db_ctxt->config_db ? db_ctxt->root.cfg_root->dnode
+ : db_ctxt->root.dnode_root;
+ else
+ root = yang_dnode_get(db_ctxt->config_db
+ ? db_ctxt->root.cfg_root->dnode
+ : db_ctxt->root.dnode_root,
+ base_xpath);
+ if (!root)
+ return -1;
+
+ options = db_ctxt->config_db ? LYD_PRINT_WD_TRIM :
+ LYD_PRINT_WD_EXPLICIT;
+
+ if (base_xpath[0] == '\0')
+ lyd_print_all(out, root, format, options);
+ else
+ lyd_print_tree(out, root, format, options);
+
+ return 0;
+}
+
+static int mgmt_db_replace_dst_with_src_db(struct mgmt_db_ctxt *src,
+ struct mgmt_db_ctxt *dst)
+{
+ struct lyd_node *dst_dnode, *src_dnode;
+ struct ly_out *out;
+
+ if (!src || !dst)
+ return -1;
+ MGMTD_DB_DBG("Replacing %d with %d", dst->db_id, src->db_id);
+
+ src_dnode = src->config_db ? src->root.cfg_root->dnode
+ : dst->root.dnode_root;
+ dst_dnode = dst->config_db ? dst->root.cfg_root->dnode
+ : dst->root.dnode_root;
+
+ if (dst_dnode)
+ yang_dnode_free(dst_dnode);
+
+ /* Not using nb_config_replace as the oper db does not contain nb_config
+ */
+ dst_dnode = yang_dnode_dup(src_dnode);
+ if (dst->config_db)
+ dst->root.cfg_root->dnode = dst_dnode;
+ else
+ dst->root.dnode_root = dst_dnode;
+
+ if (dst->db_id == MGMTD_DB_RUNNING) {
+ if (ly_out_new_filepath(MGMTD_STARTUP_DB_FILE_PATH, &out)
+ == LY_SUCCESS)
+ mgmt_db_dump_in_memory(dst, "", LYD_JSON, out);
+ ly_out_free(out, NULL, 0);
+ }
+
+ /* TODO: Update the versions if nb_config present */
+
+ return 0;
+}
+
+static int mgmt_db_merge_src_with_dst_db(struct mgmt_db_ctxt *src,
+ struct mgmt_db_ctxt *dst)
+{
+ int ret;
+ struct lyd_node **dst_dnode, *src_dnode;
+ struct ly_out *out;
+
+ if (!src || !dst)
+ return -1;
+
+ MGMTD_DB_DBG("Merging DB %d with %d", dst->db_id, src->db_id);
+
+ src_dnode = src->config_db ? src->root.cfg_root->dnode
+ : dst->root.dnode_root;
+ dst_dnode = dst->config_db ? &dst->root.cfg_root->dnode
+ : &dst->root.dnode_root;
+ ret = lyd_merge_siblings(dst_dnode, src_dnode, 0);
+ if (ret != 0) {
+ MGMTD_DB_ERR("lyd_merge() failed with err %d", ret);
+ return ret;
+ }
+
+ if (dst->db_id == MGMTD_DB_RUNNING) {
+ if (ly_out_new_filepath(MGMTD_STARTUP_DB_FILE_PATH, &out)
+ == LY_SUCCESS)
+ mgmt_db_dump_in_memory(dst, "", LYD_JSON, out);
+ ly_out_free(out, NULL, 0);
+ }
+
+ return 0;
+}
+
+static int mgmt_db_load_cfg_from_file(const char *filepath,
+ struct lyd_node **dnode)
+{
+ LY_ERR ret;
+
+ *dnode = NULL;
+ ret = lyd_parse_data_path(ly_native_ctx, filepath, LYD_JSON,
+ LYD_PARSE_STRICT, 0, dnode);
+
+ if (ret != LY_SUCCESS) {
+ if (*dnode)
+ yang_dnode_free(*dnode);
+ return -1;
+ }
+
+ return 0;
+}
+
+int mgmt_db_init(struct mgmt_master *mm)
+{
+ struct lyd_node *root;
+
+ if (mgmt_db_mm || mm->running_db || mm->candidate_db || mm->oper_db)
+ assert(!"MGMTD: Call db_init only once!");
+
+ /* Use Running DB from NB module??? */
+ if (!running_config)
+ assert(!"MGMTD: Call db_init after frr_init only!");
+
+ if (mgmt_db_load_cfg_from_file(MGMTD_STARTUP_DB_FILE_PATH, &root)
+ == 0) {
+ nb_config_free(running_config);
+ running_config = nb_config_new(root);
+ }
+
+ running.root.cfg_root = running_config;
+ running.config_db = true;
+ running.db_id = MGMTD_DB_RUNNING;
+
+ candidate.root.cfg_root = nb_config_dup(running.root.cfg_root);
+ candidate.config_db = true;
+ candidate.db_id = MGMTD_DB_CANDIDATE;
+
+ oper.root.dnode_root = yang_dnode_new(ly_native_ctx, true);
+ oper.config_db = false;
+ oper.db_id = MGMTD_DB_OPERATIONAL;
+
+ mm->running_db = &running;
+ mm->candidate_db = &candidate;
+ mm->oper_db = &oper;
+ mgmt_db_mm = mm;
+
+ return 0;
+}
+
+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)
+{
+ switch (db_id) {
+ case MGMTD_DB_CANDIDATE:
+ return (mm->candidate_db);
+ case MGMTD_DB_RUNNING:
+ return (mm->running_db);
+ case MGMTD_DB_OPERATIONAL:
+ return (mm->oper_db);
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+bool mgmt_db_is_config(struct mgmt_db_ctxt *db_ctxt)
+{
+ if (!db_ctxt)
+ return false;
+
+ return db_ctxt->config_db;
+}
+
+int mgmt_db_read_lock(struct mgmt_db_ctxt *db_ctxt)
+{
+ int lock_status;
+
+ if (!db_ctxt)
+ return -1;
+
+ lock_status = pthread_rwlock_tryrdlock(&db_ctxt->rw_lock);
+ return lock_status;
+}
+
+int mgmt_db_write_lock(struct mgmt_db_ctxt *db_ctxt)
+{
+ int lock_status;
+
+ if (!db_ctxt)
+ return -1;
+
+ lock_status = pthread_rwlock_trywrlock(&db_ctxt->rw_lock);
+ return lock_status;
+}
+
+int mgmt_db_unlock(struct mgmt_db_ctxt *db_ctxt)
+{
+ int lock_status;
+
+ if (!db_ctxt)
+ return -1;
+
+ lock_status = pthread_rwlock_unlock(&db_ctxt->rw_lock);
+ return lock_status;
+}
+
+int mgmt_db_merge_dbs(struct mgmt_db_ctxt *src_db_ctxt,
+ struct mgmt_db_ctxt *dst_db_ctxt, bool updt_cmt_rec)
+{
+ if (mgmt_db_merge_src_with_dst_db(src_db_ctxt, dst_db_ctxt) != 0)
+ return -1;
+
+ return 0;
+}
+
+int mgmt_db_copy_dbs(struct mgmt_db_ctxt *src_db_ctxt,
+ struct mgmt_db_ctxt *dst_db_ctxt, bool updt_cmt_rec)
+{
+ if (mgmt_db_replace_dst_with_src_db(src_db_ctxt, dst_db_ctxt) != 0)
+ return -1;
+
+ return 0;
+}
+
+int mgmt_db_dump_db_to_file(char *file_name, struct mgmt_db_ctxt *db_ctxt)
+{
+ struct ly_out *out;
+ int ret = 0;
+
+ if (ly_out_new_filepath(file_name, &out) == LY_SUCCESS) {
+ ret = mgmt_db_dump_in_memory(db_ctxt, "", LYD_JSON, out);
+ ly_out_free(out, NULL, 0);
+ }
+
+ return ret;
+}
+
+struct nb_config *mgmt_db_get_nb_config(struct mgmt_db_ctxt *db_ctxt)
+{
+ if (!db_ctxt)
+ return NULL;
+
+ return db_ctxt->config_db ? db_ctxt->root.cfg_root : NULL;
+}
+
+static int mgmt_walk_db_nodes(
+ struct mgmt_db_ctxt *db_ctxt, char *base_xpath,
+ struct lyd_node *base_dnode,
+ void (*mgmt_db_node_iter_fn)(struct mgmt_db_ctxt *db_ctxt, char *xpath,
+ struct lyd_node *node,
+ struct nb_node *nb_node, void *ctxt),
+ void *ctxt, char *xpaths[], int *num_nodes, bool childs_as_well,
+ bool alloc_xp_copy)
+{
+ uint32_t indx;
+ char *xpath, *xpath_buf, *iter_xp;
+ int ret, num_left = 0, num_found = 0;
+ struct lyd_node *dnode;
+ struct nb_node *nbnode;
+ bool alloc_xp = false;
+
+ if (xpaths)
+ assert(num_nodes);
+
+ if (num_nodes && !*num_nodes)
+ return 0;
+
+ if (num_nodes) {
+ num_left = *num_nodes;
+ MGMTD_DB_DBG(" -- START: num_left:%d", num_left);
+ *num_nodes = 0;
+ }
+
+ MGMTD_DB_DBG(" -- START: Base: %s", base_xpath);
+
+ if (!base_dnode)
+ base_dnode = yang_dnode_get(
+ db_ctxt->config_db ? db_ctxt->root.cfg_root->dnode
+ : db_ctxt->root.dnode_root,
+ base_xpath);
+ if (!base_dnode)
+ return -1;
+
+ if (mgmt_db_node_iter_fn) {
+ /*
+ * In case the caller is interested in getting a copy
+ * of the xpath for themselves (by setting
+ * 'alloc_xp_copy' to 'true') we make a copy for the
+ * caller and pass it. Else we pass the original xpath
+ * buffer.
+ *
+ * NOTE: In such case caller will have to take care of
+ * the copy later.
+ */
+ iter_xp = alloc_xp_copy ? strdup(base_xpath) : base_xpath;
+
+ nbnode = (struct nb_node *)base_dnode->schema->priv;
+ (*mgmt_db_node_iter_fn)(db_ctxt, iter_xp, base_dnode, nbnode,
+ ctxt);
+ }
+
+ if (num_nodes) {
+ (*num_nodes)++;
+ num_left--;
+ }
+
+ /* If the base_xpath points to leaf node, we can skip the tree walk */
+ if (base_dnode->schema->nodetype & LYD_NODE_TERM)
+ return 0;
+
+ indx = 0;
+ LY_LIST_FOR (lyd_child(base_dnode), dnode) {
+ assert(dnode->schema && dnode->schema->priv);
+ nbnode = (struct nb_node *)dnode->schema->priv;
+
+ xpath = NULL;
+ if (xpaths) {
+ if (!xpaths[*num_nodes]) {
+ alloc_xp = true;
+ xpaths[*num_nodes] =
+ (char *)calloc(1, MGMTD_MAX_XPATH_LEN);
+ }
+ xpath = lyd_path(dnode, LYD_PATH_STD,
+ xpaths[*num_nodes],
+ MGMTD_MAX_XPATH_LEN);
+ } else {
+ alloc_xp = true;
+ xpath_buf = (char *)calloc(1, MGMTD_MAX_XPATH_LEN);
+ (void) lyd_path(dnode, LYD_PATH_STD, xpath_buf,
+ MGMTD_MAX_XPATH_LEN);
+ xpath = xpath_buf;
+ }
+
+ assert(xpath);
+ MGMTD_DB_DBG(" -- XPATH: %s", xpath);
+
+ if (!childs_as_well)
+ continue;
+
+ if (num_nodes)
+ num_found = num_left;
+
+ ret = mgmt_walk_db_nodes(db_ctxt, xpath, dnode,
+ mgmt_db_node_iter_fn, ctxt,
+ xpaths ? &xpaths[*num_nodes] : NULL,
+ num_nodes ? &num_found : NULL,
+ childs_as_well, alloc_xp_copy);
+
+ if (num_nodes) {
+ num_left -= num_found;
+ (*num_nodes) += num_found;
+ }
+
+ if (alloc_xp)
+ free(xpath);
+
+ if (ret != 0)
+ break;
+
+ indx++;
+ }
+
+
+ if (num_nodes) {
+ MGMTD_DB_DBG(" -- END: *num_nodes:%d, num_left:%d", *num_nodes,
+ num_left);
+ }
+
+ return 0;
+}
+
+int mgmt_db_lookup_data_nodes(struct mgmt_db_ctxt *db_ctxt, const char *xpath,
+ char *dxpaths[], int *num_nodes,
+ bool get_childs_as_well, bool alloc_xp_copy)
+{
+ char base_xpath[MGMTD_MAX_XPATH_LEN];
+
+ if (!db_ctxt || !num_nodes)
+ return -1;
+
+ if (xpath[0] == '.' && xpath[1] == '/')
+ xpath += 2;
+
+ strlcpy(base_xpath, xpath, sizeof(base_xpath));
+ mgmt_remove_trailing_separator(base_xpath, '/');
+
+ return (mgmt_walk_db_nodes(db_ctxt, base_xpath, NULL, NULL, NULL,
+ dxpaths, num_nodes, get_childs_as_well,
+ alloc_xp_copy));
+}
+
+struct lyd_node *mgmt_db_find_data_node_by_xpath(struct mgmt_db_ctxt *db_ctxt,
+ const char *xpath)
+{
+ if (!db_ctxt)
+ return NULL;
+
+ return yang_dnode_get(db_ctxt->config_db ? db_ctxt->root.cfg_root->dnode
+ : db_ctxt->root.dnode_root,
+ xpath);
+}
+
+int mgmt_db_delete_data_nodes(struct mgmt_db_ctxt *db_ctxt, const char *xpath)
+{
+ struct nb_node *nb_node;
+ struct lyd_node *dnode, *dep_dnode;
+ char dep_xpath[XPATH_MAXLEN];
+
+ if (!db_ctxt)
+ return -1;
+
+ nb_node = nb_node_find(xpath);
+
+ dnode = yang_dnode_get(db_ctxt->config_db
+ ? db_ctxt->root.cfg_root->dnode
+ : db_ctxt->root.dnode_root,
+ xpath);
+
+ if (!dnode)
+ /*
+ * Return a special error code so the caller can choose
+ * whether to ignore it or not.
+ */
+ return NB_ERR_NOT_FOUND;
+ /* destroy dependant */
+ if (nb_node->dep_cbs.get_dependant_xpath) {
+ nb_node->dep_cbs.get_dependant_xpath(dnode, dep_xpath);
+
+ dep_dnode = yang_dnode_get(
+ db_ctxt->config_db ? db_ctxt->root.cfg_root->dnode
+ : db_ctxt->root.dnode_root,
+ dep_xpath);
+ if (dep_dnode)
+ lyd_free_tree(dep_dnode);
+ }
+ lyd_free_tree(dnode);
+
+ return 0;
+}
+
+int mgmt_db_load_config_from_file(struct mgmt_db_ctxt *dst,
+ const char *file_path, bool merge)
+{
+ struct lyd_node *iter;
+ struct mgmt_db_ctxt parsed;
+
+ if (!dst)
+ return -1;
+
+ if (mgmt_db_load_cfg_from_file(file_path, &iter) != 0) {
+ MGMTD_DB_ERR("Failed to load config from the file %s",
+ file_path);
+ return -1;
+ }
+
+ parsed.root.cfg_root = nb_config_new(iter);
+ parsed.config_db = true;
+ parsed.db_id = dst->db_id;
+
+ if (merge)
+ mgmt_db_merge_src_with_dst_db(&parsed, dst);
+ else
+ mgmt_db_replace_dst_with_src_db(&parsed, dst);
+
+ nb_config_free(parsed.root.cfg_root);
+
+ return 0;
+}
+
+int mgmt_db_iter_data(struct mgmt_db_ctxt *db_ctxt, char *base_xpath,
+ void (*mgmt_db_node_iter_fn)(struct mgmt_db_ctxt *db_ctxt,
+ char *xpath,
+ struct lyd_node *node,
+ struct nb_node *nb_node,
+ void *ctxt),
+ void *ctxt, bool alloc_xp_copy)
+{
+ int ret;
+ char xpath[MGMTD_MAX_XPATH_LEN];
+ struct lyd_node *base_dnode = NULL;
+ struct lyd_node *node;
+
+ if (!db_ctxt)
+ return -1;
+
+ mgmt_remove_trailing_separator(base_xpath, '/');
+
+ strlcpy(xpath, base_xpath, sizeof(xpath));
+
+ MGMTD_DB_DBG(" -- START DB walk for DBid: %d", db_ctxt->db_id);
+
+ /* If the base_xpath is empty then crawl the sibblings */
+ if (xpath[0] == '\0') {
+ base_dnode = db_ctxt->config_db ? db_ctxt->root.cfg_root->dnode
+ : db_ctxt->root.dnode_root;
+
+ /* get first top-level sibling */
+ while (base_dnode->parent)
+ base_dnode = lyd_parent(base_dnode);
+
+ while (base_dnode->prev->next)
+ base_dnode = base_dnode->prev;
+
+ LY_LIST_FOR (base_dnode, node) {
+ ret = mgmt_walk_db_nodes(
+ db_ctxt, xpath, node, mgmt_db_node_iter_fn,
+ ctxt, NULL, NULL, true, alloc_xp_copy);
+ }
+ } else
+ ret = mgmt_walk_db_nodes(db_ctxt, xpath, base_dnode,
+ mgmt_db_node_iter_fn, ctxt, NULL, NULL,
+ true, alloc_xp_copy);
+
+ return ret;
+}
+
+void mgmt_db_dump_tree(struct vty *vty, struct mgmt_db_ctxt *db_ctxt,
+ const char *xpath, FILE *f, LYD_FORMAT format)
+{
+ struct ly_out *out;
+ char *str;
+ char base_xpath[MGMTD_MAX_XPATH_LEN] = {0};
+
+ if (!db_ctxt) {
+ vty_out(vty, " >>>>> Database Not Initialized!\n");
+ return;
+ }
+
+ if (xpath) {
+ strlcpy(base_xpath, xpath, MGMTD_MAX_XPATH_LEN);
+ mgmt_remove_trailing_separator(base_xpath, '/');
+ }
+
+ if (f)
+ ly_out_new_file(f, &out);
+ else
+ ly_out_new_memory(&str, 0, &out);
+
+ mgmt_db_dump_in_memory(db_ctxt, base_xpath, format, out);
+
+ if (!f)
+ vty_out(vty, "%s\n", str);
+
+ ly_out_free(out, NULL, 0);
+}
+
+void mgmt_db_status_write_one(struct vty *vty, struct mgmt_db_ctxt *db_ctxt)
+{
+ if (!db_ctxt) {
+ vty_out(vty, " >>>>> Database Not Initialized!\n");
+ return;
+ }
+
+ vty_out(vty, " DB: %s\n", mgmt_db_id2name(db_ctxt->db_id));
+ vty_out(vty, " DB-Hndl: \t\t\t%p\n", db_ctxt);
+ vty_out(vty, " Config: \t\t\t%s\n",
+ db_ctxt->config_db ? "True" : "False");
+}
+
+void mgmt_db_status_write(struct vty *vty)
+{
+ vty_out(vty, "MGMTD Databases\n");
+
+ mgmt_db_status_write_one(vty, mgmt_db_mm->running_db);
+
+ mgmt_db_status_write_one(vty, mgmt_db_mm->candidate_db);
+
+ mgmt_db_status_write_one(vty, mgmt_db_mm->oper_db);
+}
--- /dev/null
+/*
+ * MGMTD Databases
+ * 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_DB_H_
+#define _FRR_MGMTD_DB_H_
+
+#include "mgmtd/mgmt_defines.h"
+
+#define MGMTD_MAX_NUM_DBNODES_PER_BATCH 128
+
+#define MGMTD_DB_NAME_MAX_LEN 32
+#define MGMTD_DB_NAME_NONE "none"
+#define MGMTD_DB_NAME_RUNNING "running"
+#define MGMTD_DB_NAME_CANDIDATE "candidate"
+#define MGMTD_DB_NAME_OPERATIONAL "operational"
+
+#define MGMTD_STARTUP_DB_FILE_PATH "/etc/frr/frr_startup.json"
+
+#define FOREACH_MGMTD_DB_ID(id) \
+ for ((id) = MGMTD_DB_NONE; (id) < MGMTD_DB_MAX_ID; (id)++)
+
+#define MGMTD_MAX_COMMIT_LIST 10
+#define MGMTD_MD5_HASH_LEN 16
+#define MGMTD_MD5_HASH_STR_HEX_LEN 33
+
+#define MGMTD_MAX_COMMIT_FILE_PATH_LEN 55
+#define MGMTD_COMMIT_FILE_PATH "/etc/frr/commit-%s.json"
+#define MGMTD_COMMIT_INDEX_FILE_NAME "/etc/frr/commit-index.dat"
+#define MGMTD_COMMIT_TIME_STR_LEN 100
+
+struct mgmt_master;
+
+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);
+
+/***************************************************************
+ * Global data exported
+ ***************************************************************/
+
+extern const char *mgmt_db_names[MGMTD_DB_MAX_ID + 1];
+
+/*
+ * Convert database ID to database name.
+ *
+ * id
+ * Database ID.
+ *
+ * Returns:
+ * Database name.
+ */
+static inline const char *mgmt_db_id2name(enum mgmt_database_id id)
+{
+ if (id > MGMTD_DB_MAX_ID)
+ id = MGMTD_DB_MAX_ID;
+ return mgmt_db_names[id];
+}
+
+/*
+ * Convert database name to database ID.
+ *
+ * id
+ * Database name.
+ *
+ * Returns:
+ * Database ID.
+ */
+static inline enum mgmt_database_id mgmt_db_name2id(const char *name)
+{
+ enum mgmt_database_id id;
+
+ FOREACH_MGMTD_DB_ID (id) {
+ if (!strncmp(mgmt_db_names[id], name, MGMTD_DB_NAME_MAX_LEN))
+ return id;
+ }
+
+ return MGMTD_DB_NONE;
+}
+
+/*
+ * Convert database ID to database name.
+ *
+ * similar to above funtion.
+ */
+static inline enum mgmt_database_id mgmt_get_db_id_by_name(const char *db_name)
+{
+ if (!strncmp(db_name, "candidate", sizeof("candidate")))
+ return MGMTD_DB_CANDIDATE;
+ else if (!strncmp(db_name, "running", sizeof("running")))
+ return MGMTD_DB_RUNNING;
+ else if (!strncmp(db_name, "operational", sizeof("operational")))
+ return MGMTD_DB_OPERATIONAL;
+ return MGMTD_DB_NONE;
+}
+
+/*
+ * Appends trail wildcard '/' '*' to a given xpath.
+ *
+ * xpath
+ * YANG xpath.
+ *
+ * path_len
+ * xpath length.
+ */
+static inline void mgmt_xpath_append_trail_wildcard(char *xpath,
+ size_t *xpath_len)
+{
+ if (!xpath || !xpath_len)
+ return;
+
+ if (!*xpath_len)
+ *xpath_len = strlen(xpath);
+
+ if (*xpath_len > 2 && *xpath_len < MGMTD_MAX_XPATH_LEN - 2) {
+ if (xpath[*xpath_len - 1] == '/') {
+ xpath[*xpath_len] = '*';
+ xpath[*xpath_len + 1] = 0;
+ (*xpath_len)++;
+ } else if (xpath[*xpath_len - 1] != '*') {
+ xpath[*xpath_len] = '/';
+ xpath[*xpath_len + 1] = '*';
+ xpath[*xpath_len + 2] = 0;
+ (*xpath_len) += 2;
+ }
+ }
+}
+
+/*
+ * Removes trail wildcard '/' '*' from a given xpath.
+ *
+ * xpath
+ * YANG xpath.
+ *
+ * path_len
+ * xpath length.
+ */
+static inline void mgmt_xpath_remove_trail_wildcard(char *xpath,
+ size_t *xpath_len)
+{
+ if (!xpath || !xpath_len)
+ return;
+
+ if (!*xpath_len)
+ *xpath_len = strlen(xpath);
+
+ if (*xpath_len > 2 && xpath[*xpath_len - 2] == '/'
+ && xpath[*xpath_len - 1] == '*') {
+ xpath[*xpath_len - 2] = 0;
+ (*xpath_len) -= 2;
+ }
+}
+
+/* Initialise database */
+extern int mgmt_db_init(struct mgmt_master *cm);
+
+/* Destroy database */
+extern void mgmt_db_destroy(void);
+
+/*
+ * Get database handler by ID
+ *
+ * mm
+ * Management master structure.
+ *
+ * db_id
+ * Database ID.
+ *
+ * Returns:
+ * 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);
+
+/*
+ * Check if a given database is config db
+ */
+extern bool mgmt_db_is_config(struct mgmt_db_ctxt *db_ctxt);
+
+/*
+ * Acquire read lock to a db given a db_handle
+ */
+extern int mgmt_db_read_lock(struct mgmt_db_ctxt *db_ctxt);
+
+/*
+ * Acquire write lock to a db given a db_handle
+ */
+extern int mgmt_db_write_lock(struct mgmt_db_ctxt *db_ctxt);
+
+/*
+ * Remove a lock from db given a db_handle
+ */
+extern int mgmt_db_unlock(struct mgmt_db_ctxt *db_ctxt);
+
+/*
+ * Merge two databases.
+ *
+ * src_db
+ * Source database handle.
+ *
+ * dst_db
+ * Destination database handle.
+ *
+ * update_cmd_rec
+ * TRUE if need to update commit record, FALSE otherwise.
+ *
+ * Returns:
+ * 0 on success, -1 on failure.
+ */
+extern int mgmt_db_merge_dbs(struct mgmt_db_ctxt *src_db_ctxt,
+ struct mgmt_db_ctxt *dst_db_ctxt,
+ bool update_cmt_rec);
+
+/*
+ * Copy from source to destination database.
+ *
+ * src_db
+ * Source database handle (db to be copied from).
+ *
+ * dst_db
+ * Destination database handle (db to be copied to).
+ *
+ * update_cmd_rec
+ * TRUE if need to update commit record, FALSE otherwise.
+ *
+ * Returns:
+ * 0 on success, -1 on failure.
+ */
+extern int mgmt_db_copy_dbs(struct mgmt_db_ctxt *src_db_ctxt,
+ struct mgmt_db_ctxt *dst_db_ctxt,
+ bool update_cmt_rec);
+
+/*
+ * Fetch northbound configuration for a given database context.
+ */
+extern struct nb_config *mgmt_db_get_nb_config(struct mgmt_db_ctxt *db_ctxt);
+
+/*
+ * Lookup YANG data nodes.
+ *
+ * db_ctxt
+ * Database context.
+ *
+ * xpath
+ * YANG base xpath.
+ *
+ * dxpaths
+ * Out param - array of YANG data xpaths.
+ *
+ * num_nodes
+ * In-out param - number of YANG data xpaths.
+ * Note - Caller should init this to the size of the array
+ * provided in dxpaths.
+ * On return this will have the actual number of xpaths
+ * being returned.
+ *
+ * get_childs_as_well
+ * TRUE if child nodes needs to be fetched as well, FALSE otherwise.
+ *
+ * alloc_xp_copy
+ * TRUE if the caller is interested in getting a copy of the xpath.
+ *
+ * Returns:
+ * 0 on success, -1 on failure.
+ */
+extern int mgmt_db_lookup_data_nodes(struct mgmt_db_ctxt *db_ctxt,
+ const char *xpath, char *dxpaths[],
+ int *num_nodes, bool get_childs_as_well,
+ bool alloc_xp_copy);
+
+/*
+ * Find YANG data node given a database handle YANG xpath.
+ */
+extern struct lyd_node *
+mgmt_db_find_data_node_by_xpath(struct mgmt_db_ctxt *db_ctxt,
+ const char *xpath);
+
+/*
+ * Delete YANG data node given a database handle and YANG xpath.
+ */
+extern int mgmt_db_delete_data_nodes(struct mgmt_db_ctxt *db_ctxt,
+ const char *xpath);
+
+/*
+ * Iterate over database data.
+ *
+ * db_ctxt
+ * Database context.
+ *
+ * base_xpath
+ * Base YANG xpath from where needs to be iterated.
+ *
+ * iter_fn
+ * function that will be called during each iteration.
+ *
+ * ctxt
+ * User defined opaque value normally used to pass
+ * reference to some user private context that will
+ * be passed to the iterator function provided in
+ * 'iter_fn'.
+ *
+ * alloc_xp_copy
+ * TRUE if the caller is interested in getting a copy of the xpath.
+ *
+ * Returns:
+ * 0 on success, -1 on failure.
+ */
+extern int mgmt_db_iter_data(
+ struct mgmt_db_ctxt *db_ctxt, char *base_xpath,
+ void (*mgmt_db_node_iter_fn)(struct mgmt_db_ctxt *db_ctxt, char *xpath,
+ struct lyd_node *node,
+ struct nb_node *nb_node, void *ctxt),
+ void *ctxt, bool alloc_xp_copy);
+
+/*
+ * Load config to database from a file.
+ *
+ * db_ctxt
+ * Database context.
+ *
+ * file_path
+ * File path of the configuration file.
+ *
+ * merge
+ * TRUE if you want to merge with existing config,
+ * FALSE if you want to replace with existing config
+ *
+ * Returns:
+ * 0 on success, -1 on failure.
+ */
+extern int mgmt_db_load_config_from_file(struct mgmt_db_ctxt *db_ctxt,
+ const char *file_path, bool merge);
+
+/*
+ * Dump the data tree to a file with JSON/XML format.
+ *
+ * vty
+ * VTY context.
+ *
+ * db_ctxt
+ * Database context.
+ *
+ * xpath
+ * Base YANG xpath from where data needs to be dumped.
+ *
+ * f
+ * File pointer to where data to be dumped.
+ *
+ * format
+ * JSON/XML
+ */
+extern void mgmt_db_dump_tree(struct vty *vty, struct mgmt_db_ctxt *db_ctxt,
+ const char *xpath, FILE *f, LYD_FORMAT format);
+
+/*
+ * Dump the complete data tree to a file with JSON format.
+ *
+ * file_name
+ * File path to where data to be dumped.
+ *
+ * db
+ * Database context.
+ *
+ * Returns:
+ * 0 on success, -1 on failure.
+ */
+extern int mgmt_db_dump_db_to_file(char *file_name,
+ struct mgmt_db_ctxt *db_ctxt);
+
+/*
+ * Dump information about specific database.
+ */
+extern void mgmt_db_status_write_one(struct vty *vty,
+ struct mgmt_db_ctxt *db_ctxt);
+
+/*
+ * Dump information about all the databases.
+ */
+extern void mgmt_db_status_write(struct vty *vty);
+
+#endif /* _FRR_MGMTD_DB_H_ */
--- /dev/null
+/* MGMTD public defines.
+ * 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_DEFINES_H
+#define _FRR_MGMTD_DEFINES_H
+
+#define MGMTD_MAX_XPATH_LEN XPATH_MAXLEN
+
+#define MGMTD_MAX_YANG_VALUE_LEN YANG_VALUE_MAXLEN
+
+#endif /* _FRR_MGMTD_DEFINES_H */
--- /dev/null
+/*
+ * Main routine of mgmt.
+ * Copyright (C) 2021 Vmware, Inc.
+ * Pushpasis Sarkar
+ *
+ * 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 "lib/version.h"
+#include "routemap.h"
+#include "filter.h"
+#include "libfrr.h"
+#include "frr_pthread.h"
+#include "mgmtd/mgmt.h"
+#include "mgmtd/mgmt_db.h"
+#include "routing_nb.h"
+
+/*
+ * NOTE:
+ * For each Backend client migrated to MGMTD add the
+ * corresponding NB callback modules here.
+ */
+#include "staticd/static_nb.h"
+
+
+/* mgmt options, we use GNU getopt library. */
+static const struct option longopts[] = {
+ {"skip_runas", no_argument, NULL, 'S'},
+ {"no_zebra", no_argument, NULL, 'Z'},
+ {"socket_size", required_argument, NULL, 's'},
+ {0}
+};
+
+static void mgmt_exit(int);
+static void mgmt_vrf_terminate(void);
+
+/* privileges */
+static zebra_capabilities_t _caps_p[] = {ZCAP_BIND, ZCAP_NET_RAW,
+ ZCAP_NET_ADMIN, ZCAP_SYS_ADMIN};
+
+struct zebra_privs_t mgmt_privs = {
+#if defined(FRR_USER) && defined(FRR_GROUP)
+ .user = FRR_USER,
+ .group = FRR_GROUP,
+#endif
+#ifdef VTY_GROUP
+ .vty_group = VTY_GROUP,
+#endif
+ .caps_p = _caps_p,
+ .cap_num_p = array_size(_caps_p),
+ .cap_num_i = 0,
+};
+
+static struct frr_daemon_info mgmtd_di;
+
+/* SIGHUP handler. */
+static void sighup(void)
+{
+ zlog_info("SIGHUP received, ignoring");
+
+ return;
+
+ /*
+ * This is turned off for the moment. There is all
+ * sorts of config turned off by mgmt_terminate
+ * that is not setup properly again in mgmt_reset.
+ * I see no easy way to do this nor do I see that
+ * this is a desirable way to reload config
+ * given the yang work.
+ */
+ /* Terminate all thread. */
+ mgmt_terminate();
+
+ /*
+ * mgmt_reset();
+ */
+ zlog_info("MGMTD restarting!");
+
+ /*
+ * Reload config file.
+ * vty_read_config(NULL, mgmtd_di.config_file, config_default);
+ */
+ /* Try to return to normal operation. */
+}
+
+/* SIGINT handler. */
+static __attribute__((__noreturn__)) void sigint(void)
+{
+ zlog_notice("Terminating on signal");
+ assert(mm->terminating == false);
+ mm->terminating = true; /* global flag that shutting down */
+
+ mgmt_terminate();
+
+ mgmt_exit(0);
+
+ exit(0);
+}
+
+/* SIGUSR1 handler. */
+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.
+ *
+ * Zebra route removal and protocol teardown are not meant to be done here.
+ * For example, "retain_mode" may be set.
+ */
+static __attribute__((__noreturn__)) void mgmt_exit(int status)
+{
+ /* it only makes sense for this to be called on a clean exit */
+ assert(status == 0);
+
+ frr_early_fini();
+
+ /* stop pthreads (if any) */
+ frr_pthread_stop_all();
+
+ mgmt_vrf_terminate();
+
+ frr_fini();
+ exit(status);
+}
+
+static int mgmt_vrf_new(struct vrf *vrf)
+{
+ zlog_debug("VRF Created: %s(%u)", vrf->name, vrf->vrf_id);
+
+ return 0;
+}
+
+static int mgmt_vrf_delete(struct vrf *vrf)
+{
+ zlog_debug("VRF Deletion: %s(%u)", vrf->name, vrf->vrf_id);
+
+ return 0;
+}
+
+static int mgmt_vrf_enable(struct vrf *vrf)
+{
+ zlog_debug("VRF Enable: %s(%u)", vrf->name, vrf->vrf_id);
+
+ return 0;
+}
+
+static int mgmt_vrf_disable(struct vrf *vrf)
+{
+ zlog_debug("VRF Disable: %s(%u)", vrf->name, vrf->vrf_id);
+
+ /* Note: This is a callback, the VRF will be deleted by the caller. */
+ return 0;
+}
+
+static int mgmt_vrf_config_write(struct vty *vty)
+{
+ return 0;
+}
+
+static void mgmt_vrf_init(void)
+{
+ vrf_init(mgmt_vrf_new, mgmt_vrf_enable, mgmt_vrf_disable,
+ mgmt_vrf_delete);
+ vrf_cmd_init(mgmt_vrf_config_write);
+}
+
+static void mgmt_vrf_terminate(void)
+{
+ vrf_terminate();
+}
+
+/*
+ * List of YANG modules to be loaded in the process context of
+ * MGMTd.
+ *
+ * NOTE: In future this will also include the YANG modules of
+ * all individual Backend clients.
+ */
+static const struct frr_yang_module_info *const mgmt_yang_modules[] = {
+ &frr_filter_info, &frr_interface_info, &frr_route_map_info,
+ &frr_routing_info, &frr_vrf_info,
+};
+
+FRR_DAEMON_INFO(mgmtd, MGMTD, .vty_port = MGMTD_VTY_PORT,
+
+ .proghelp = "FRR Management Daemon.",
+
+ .signals = mgmt_signals, .n_signals = array_size(mgmt_signals),
+
+ .privs = &mgmt_privs, .yang_modules = mgmt_yang_modules,
+ .n_yang_modules = array_size(mgmt_yang_modules),
+);
+
+#define DEPRECATED_OPTIONS ""
+
+/* Main routine of mgmt. Treatment of argument and start mgmt finite
+ * state machine is handled at here.
+ */
+int main(int argc, char **argv)
+{
+ int opt;
+ int buffer_size = MGMTD_SOCKET_BUF_SIZE;
+
+ frr_preinit(&mgmtd_di, argc, argv);
+ frr_opt_add(
+ "s:" DEPRECATED_OPTIONS, longopts,
+ " -s, --socket_size Set MGMTD peer socket send buffer size\n");
+
+ /* Command line argument treatment. */
+ while (1) {
+ opt = frr_getopt(argc, argv, 0);
+
+ if (opt && opt < 128 && strchr(DEPRECATED_OPTIONS, opt)) {
+ fprintf(stderr,
+ "The -%c option no longer exists.\nPlease refer to the manual.\n",
+ opt);
+ continue;
+ }
+
+ if (opt == EOF)
+ break;
+
+ switch (opt) {
+ case 0:
+ break;
+ case 's':
+ buffer_size = atoi(optarg);
+ break;
+ default:
+ frr_help_exit(1);
+ break;
+ }
+ }
+
+ /* MGMTD master init. */
+ mgmt_master_init(frr_init(), buffer_size);
+
+ /* VRF Initializations. */
+ mgmt_vrf_init();
+
+ /* MGMTD related initialization. */
+ mgmt_init();
+
+ frr_config_fork();
+
+ frr_run(mm->master);
+
+ /* Not reached. */
+ return 0;
+}
--- /dev/null
+/* mgmt memory type definitions
+ * 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>
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mgmt_memory.h"
+
+/* this file is temporary in nature; definitions should be moved to the
+ * files they're used in
+ */
+
+DEFINE_MGROUP(MGMTD, "mgmt");
+DEFINE_MTYPE(MGMTD, MGMTD, "MGMTD instance");
--- /dev/null
+/* mgmt memory type declarations
+ * 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_MEMORY_H
+#define _FRR_MGMTD_MEMORY_H
+
+#include "memory.h"
+
+DECLARE_MGROUP(MGMTD);
+DECLARE_MTYPE(MGMTD);
+#endif /* _FRR_MGMTD_MEMORY_H */
--- /dev/null
+#! /bin/bash
+
+# mgmtd/mgmt_test_frntnd - temporary wrapper script for .libs/mgmt_test_frntnd
+# Generated by libtool (GNU libtool) 2.4.6 Debian-2.4.6-2
+#
+# The mgmtd/mgmt_test_frntnd program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='s|\([`"$\\]\)|\\\1|g'
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=""
+
+# This environment variable determines our operation mode.
+if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then
+ # install mode needs the following variables:
+ generated_by_libtool_version='2.4.6'
+ notinst_deplibs=' lib/libfrr.la'
+else
+ # When we are sourced in execute mode, $file and $ECHO are already set.
+ if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
+ file="$0"
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+ ECHO="printf %s\\n"
+ fi
+
+# Very basic option parsing. These options are (a) specific to
+# the libtool wrapper, (b) are identical between the wrapper
+# /script/ and the wrapper /executable/ that is used only on
+# windows platforms, and (c) all begin with the string --lt-
+# (application programs are unlikely to have options that match
+# this pattern).
+#
+# There are only two supported options: --lt-debug and
+# --lt-dump-script. There is, deliberately, no --lt-help.
+#
+# The first argument to this parsing function should be the
+# script's ./libtool value, followed by no.
+lt_option_debug=
+func_parse_lt_options ()
+{
+ lt_script_arg0=$0
+ shift
+ for lt_opt
+ do
+ case "$lt_opt" in
+ --lt-debug) lt_option_debug=1 ;;
+ --lt-dump-script)
+ lt_dump_D=`$ECHO "X$lt_script_arg0" | sed -e 's/^X//' -e 's%/[^/]*$%%'`
+ test "X$lt_dump_D" = "X$lt_script_arg0" && lt_dump_D=.
+ lt_dump_F=`$ECHO "X$lt_script_arg0" | sed -e 's/^X//' -e 's%^.*/%%'`
+ cat "$lt_dump_D/$lt_dump_F"
+ exit 0
+ ;;
+ --lt-*)
+ $ECHO "Unrecognized --lt- option: '$lt_opt'" 1>&2
+ exit 1
+ ;;
+ esac
+ done
+
+ # Print the debug banner immediately:
+ if test -n "$lt_option_debug"; then
+ echo "mgmt_test_frntnd:mgmtd/mgmt_test_frntnd:$LINENO: libtool wrapper (GNU libtool) 2.4.6 Debian-2.4.6-2" 1>&2
+ fi
+}
+
+# Used when --lt-debug. Prints its arguments to stdout
+# (redirection is the responsibility of the caller)
+func_lt_dump_args ()
+{
+ lt_dump_args_N=1;
+ for lt_arg
+ do
+ $ECHO "mgmt_test_frntnd:mgmtd/mgmt_test_frntnd:$LINENO: newargv[$lt_dump_args_N]: $lt_arg"
+ lt_dump_args_N=`expr $lt_dump_args_N + 1`
+ done
+}
+
+# Core function for launching the target application
+func_exec_program_core ()
+{
+
+ if test -n "$lt_option_debug"; then
+ $ECHO "mgmt_test_frntnd:mgmtd/mgmt_test_frntnd:$LINENO: newargv[0]: $progdir/$program" 1>&2
+ func_lt_dump_args ${1+"$@"} 1>&2
+ fi
+ exec "$progdir/$program" ${1+"$@"}
+
+ $ECHO "$0: cannot exec $program $*" 1>&2
+ exit 1
+}
+
+# A function to encapsulate launching the target application
+# Strips options in the --lt-* namespace from $@ and
+# launches target application with the remaining arguments.
+func_exec_program ()
+{
+ case " $* " in
+ *\ --lt-*)
+ for lt_wr_arg
+ do
+ case $lt_wr_arg in
+ --lt-*) ;;
+ *) set x "$@" "$lt_wr_arg"; shift;;
+ esac
+ shift
+ done ;;
+ esac
+ func_exec_program_core ${1+"$@"}
+}
+
+ # Parse options
+ func_parse_lt_options "$0" ${1+"$@"}
+
+ # Find the directory that this script lives in.
+ thisdir=`$ECHO "$file" | sed 's%/[^/]*$%%'`
+ test "x$thisdir" = "x$file" && thisdir=.
+
+ # Follow symbolic links until we get to the real thisdir.
+ file=`ls -ld "$file" | sed -n 's/.*-> //p'`
+ while test -n "$file"; do
+ destdir=`$ECHO "$file" | sed 's%/[^/]*$%%'`
+
+ # If there was a directory component, then change thisdir.
+ if test "x$destdir" != "x$file"; then
+ case "$destdir" in
+ [\\/]* | [A-Za-z]:[\\/]*) thisdir="$destdir" ;;
+ *) thisdir="$thisdir/$destdir" ;;
+ esac
+ fi
+
+ file=`$ECHO "$file" | sed 's%^.*/%%'`
+ file=`ls -ld "$thisdir/$file" | sed -n 's/.*-> //p'`
+ done
+
+ # Usually 'no', except on cygwin/mingw when embedded into
+ # the cwrapper.
+ WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=no
+ if test "$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR" = "yes"; then
+ # special case for '.'
+ if test "$thisdir" = "."; then
+ thisdir=`pwd`
+ fi
+ # remove .libs from thisdir
+ case "$thisdir" in
+ *[\\/].libs ) thisdir=`$ECHO "$thisdir" | sed 's%[\\/][^\\/]*$%%'` ;;
+ .libs ) thisdir=. ;;
+ esac
+ fi
+
+ # Try to get the absolute directory name.
+ absdir=`cd "$thisdir" && pwd`
+ test -n "$absdir" && thisdir="$absdir"
+
+ program='mgmt_test_frntnd'
+ progdir="$thisdir/.libs"
+
+
+ if test -f "$progdir/$program"; then
+ # Add our own library path to LD_LIBRARY_PATH
+ LD_LIBRARY_PATH="/root/upstream_p1/lib/.libs:$LD_LIBRARY_PATH"
+
+ # Some systems cannot cope with colon-terminated LD_LIBRARY_PATH
+ # The second colon is a workaround for a bug in BeOS R4 sed
+ LD_LIBRARY_PATH=`$ECHO "$LD_LIBRARY_PATH" | sed 's/::*$//'`
+
+ export LD_LIBRARY_PATH
+
+ if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
+ # Run the actual program with our arguments.
+ func_exec_program ${1+"$@"}
+ fi
+ else
+ # The program doesn't exist.
+ $ECHO "$0: error: '$progdir/$program' does not exist" 1>&2
+ $ECHO "This script is just a wrapper for $program." 1>&2
+ $ECHO "See the libtool documentation for more information." 1>&2
+ exit 1
+ fi
+fi
--- /dev/null
+/*
+ * MGMTD VTY Interface
+ * 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 "command.h"
+#include "json.h"
+#include "mgmtd/mgmt.h"
+#include "mgmtd/mgmt_vty.h"
+#include "mgmtd/mgmt_db.h"
+
+#ifndef VTYSH_EXTRACT_PL
+#include "mgmtd/mgmt_vty_clippy.c"
+#endif
+
+DEFPY(show_mgmt_db_all,
+ show_mgmt_db_all_cmd,
+ "show mgmt database all",
+ SHOW_STR
+ MGMTD_STR
+ MGMTD_DB_STR
+ "Display all Databases\n")
+{
+ mgmt_db_status_write(vty);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(show_mgmt_db_runn,
+ show_mgmt_db_runn_cmd,
+ "show mgmt database running",
+ SHOW_STR
+ MGMTD_STR
+ MGMTD_DB_STR
+ "Display Running Database\n")
+{
+ struct mgmt_db_ctxt *db_ctxt;
+
+ db_ctxt = mgmt_db_get_hndl_by_id(mm, MGMTD_DB_RUNNING);
+ if (!db_ctxt) {
+ vty_out(vty, "ERROR: Could not access running database!\n");
+ return CMD_ERR_NO_MATCH;
+ }
+
+ mgmt_db_status_write_one(vty, db_ctxt);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(show_mgmt_db_cand,
+ show_mgmt_db_cand_cmd,
+ "show mgmt database candidate",
+ SHOW_STR
+ MGMTD_STR
+ MGMTD_DB_STR
+ "Display Candidate Database\n")
+{
+ struct mgmt_db_ctxt *db_ctxt;
+
+ db_ctxt = mgmt_db_get_hndl_by_id(mm, MGMTD_DB_CANDIDATE);
+ if (!db_ctxt) {
+ vty_out(vty, "ERROR: Could not access candidate database!\n");
+ return CMD_ERR_NO_MATCH;
+ }
+
+ mgmt_db_status_write_one(vty, db_ctxt);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(show_mgmt_db_oper,
+ show_mgmt_db_oper_cmd,
+ "show mgmt database operational",
+ SHOW_STR
+ MGMTD_STR
+ MGMTD_DB_STR
+ "Display Operational Database\n")
+{
+ struct mgmt_db_ctxt *db_ctxt;
+
+ db_ctxt = mgmt_db_get_hndl_by_id(mm, MGMTD_DB_OPERATIONAL);
+ if (!db_ctxt) {
+ vty_out(vty, "ERROR: Could not access operational database!\n");
+ return CMD_ERR_NO_MATCH;
+ }
+
+ mgmt_db_status_write_one(vty, db_ctxt);
+
+ 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",
+ SHOW_STR
+ MGMTD_STR
+ "Get Database contents from a specific database\n"
+ "DB name\n"
+ "<candidate | running | operational>\n"
+ "XPath expression specifying the YANG data path\n"
+ "XPath string\n"
+ "Dump the contents to a file\n"
+ "Full path of the file\n"
+ "Format of the output\n"
+ "json|xml")
+{
+ enum mgmt_database_id database = MGMTD_DB_CANDIDATE;
+ struct mgmt_db_ctxt *db_ctxt;
+ LYD_FORMAT format = LYD_UNKNOWN;
+ FILE *f = NULL;
+
+ 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;
+ }
+
+ db_ctxt = mgmt_db_get_hndl_by_id(mm, database);
+ if (!db_ctxt) {
+ vty_out(vty, "ERROR: Could not access database!\n");
+ return CMD_ERR_NO_MATCH;
+ }
+
+ if (filepath) {
+ f = fopen(filepath, "w");
+ if (!f) {
+ vty_out(vty,
+ "Could not open file pointed by filepath %s\n",
+ filepath);
+ return CMD_SUCCESS;
+ }
+ }
+
+ format = mgmt_str2format(format_str);
+ if (format == LYD_UNKNOWN) {
+ vty_out(vty,
+ "String Format %s does not matches existing format\n",
+ format_str);
+ return CMD_SUCCESS;
+ }
+
+ mgmt_db_dump_tree(vty, db_ctxt, path, f, format);
+
+ if (f)
+ fclose(f);
+ return CMD_SUCCESS;
+}
+
+DEFPY(mgmt_load_config,
+ mgmt_load_config_cmd,
+ "mgmt load-config file WORD$filepath <merge|replace>",
+ MGMTD_STR
+ "Load configuration onto Candidate Database\n"
+ "Read the configuration from a file\n"
+ "Full path of the file\n"
+ "Merge configuration with contents of Candidate Database\n"
+ "Replace the existing contents of Candidate database")
+{
+ bool merge = false;
+ int idx_merge = 4;
+ int ret;
+ struct mgmt_db_ctxt *db_ctxt;
+
+ if (access(filepath, F_OK) == -1) {
+ vty_out(vty, "ERROR: File %s : %s\n", filepath,
+ strerror(errno));
+ return CMD_ERR_NO_FILE;
+ }
+
+ db_ctxt = mgmt_db_get_hndl_by_id(mm, MGMTD_DB_CANDIDATE);
+ if (!db_ctxt) {
+ vty_out(vty, "ERROR: Could not access Candidate database!\n");
+ return CMD_ERR_NO_MATCH;
+ }
+
+ if (strncmp(argv[idx_merge]->arg, "merge", sizeof("merge")) == 0)
+ merge = true;
+ else if (strncmp(argv[idx_merge]->arg, "replace", sizeof("replace"))
+ == 0)
+ merge = false;
+ else {
+ vty_out(vty, "Chosen option: %s not valid\n",
+ argv[idx_merge]->arg);
+ return CMD_SUCCESS;
+ }
+
+ ret = mgmt_db_load_config_from_file(db_ctxt, filepath, merge);
+ if (ret != 0)
+ vty_out(vty, "Error with parsing the file with error code %d\n",
+ ret);
+ return CMD_SUCCESS;
+}
+
+DEFPY(mgmt_save_config,
+ mgmt_save_config_cmd,
+ "mgmt save-config db-name WORD$dbname file WORD$filepath",
+ MGMTD_STR
+ "Save configuration from database\n"
+ "Name of the database\n"
+ "<candidate|running>"
+ "Write the configuration to a file\n"
+ "Full path of the file")
+{
+ struct mgmt_db_ctxt *db_ctxt;
+ enum mgmt_database_id database;
+ FILE *f;
+
+ 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;
+ }
+
+ if (database != MGMTD_DB_CANDIDATE && database != MGMTD_DB_RUNNING) {
+ vty_out(vty, "DB Name %s is not a configuration database\n",
+ dbname);
+ return CMD_SUCCESS;
+ }
+
+ db_ctxt = mgmt_db_get_hndl_by_id(mm, database);
+ if (!db_ctxt) {
+ vty_out(vty, "ERROR: Could not access the '%s' database!\n",
+ dbname);
+ return CMD_ERR_NO_MATCH;
+ }
+
+ if (!filepath) {
+ vty_out(vty, "ERROR: No file path mentioned!\n");
+ return CMD_ERR_NO_MATCH;
+ }
+
+ f = fopen(filepath, "w");
+ if (!f) {
+ vty_out(vty, "Could not open file pointed by filepath %s\n",
+ filepath);
+ return CMD_SUCCESS;
+ }
+
+ mgmt_db_dump_tree(vty, db_ctxt, "/", f, LYD_JSON);
+
+ fclose(f);
+
+ return CMD_SUCCESS;
+}
+
+static int config_write_mgmt_debug(struct vty *vty)
+{
+ if (mgmt_debug_bcknd && mgmt_debug_frntnd && mgmt_debug_db
+ && mgmt_debug_trxn) {
+ vty_out(vty, "debug mgmt all\n");
+ return 0;
+ }
+ if (mgmt_debug_bcknd)
+ vty_out(vty, "debug mgmt backend\n");
+ if (mgmt_debug_frntnd)
+ vty_out(vty, "debug mgmt frontend\n");
+ if (mgmt_debug_db)
+ vty_out(vty, "debug mgmt database\n");
+ if (mgmt_debug_trxn)
+ vty_out(vty, "debug mgmt transaction\n");
+
+ return 0;
+}
+static struct cmd_node debug_node = {
+ .name = "debug",
+ .node = DEBUG_NODE,
+ .prompt = "",
+ .config_write = config_write_mgmt_debug,
+};
+
+DEFPY(debug_mgmt_bcknd,
+ debug_mgmt_bcknd_cmd,
+ "[no$no] debug mgmt backend",
+ NO_STR
+ DEBUG_STR
+ MGMTD_STR
+ "Debug Backend Functionality")
+{
+ if (no)
+ mgmt_debug_bcknd = false;
+ else
+ mgmt_debug_bcknd = true;
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(debug_mgmt_frntnd,
+ debug_mgmt_frntnd_cmd,
+ "[no$no] debug mgmt frontend",
+ NO_STR
+ DEBUG_STR
+ MGMTD_STR
+ "Debug Frontend Functionality")
+{
+ if (no)
+ mgmt_debug_frntnd = false;
+ else
+ mgmt_debug_frntnd = true;
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(debug_mgmt_db,
+ debug_mgmt_db_cmd,
+ "[no$no] debug mgmt database",
+ NO_STR
+ DEBUG_STR
+ MGMTD_STR
+ "Debug Database Functionality")
+{
+ if (no)
+ mgmt_debug_db = false;
+ else
+ mgmt_debug_db = true;
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(debug_mgmt_trxn,
+ debug_mgmt_trxn_cmd,
+ "[no$no] debug mgmt transaction",
+ NO_STR
+ DEBUG_STR
+ MGMTD_STR
+ "Debug Transaction Functionality")
+{
+ if (no)
+ mgmt_debug_trxn = false;
+ else
+ mgmt_debug_trxn = true;
+
+ return CMD_SUCCESS;
+}
+DEFPY(debug_mgmt_all,
+ debug_mgmt_all_cmd,
+ "[no$no] debug mgmt all",
+ NO_STR
+ DEBUG_STR
+ MGMTD_STR
+ "Debug All Functionality")
+{
+ if (no) {
+ mgmt_debug_bcknd = false;
+ mgmt_debug_frntnd = false;
+ mgmt_debug_db = false;
+ mgmt_debug_trxn = false;
+ } else {
+ mgmt_debug_bcknd = true;
+ mgmt_debug_frntnd = true;
+ mgmt_debug_db = true;
+ mgmt_debug_trxn = true;
+ }
+
+ return CMD_SUCCESS;
+}
+
+void mgmt_vty_init(void)
+{
+ install_node(&debug_node);
+
+ 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_dump_data_cmd);
+
+ install_element(CONFIG_NODE, &mgmt_load_config_cmd);
+ install_element(CONFIG_NODE, &mgmt_save_config_cmd);
+
+ install_element(VIEW_NODE, &debug_mgmt_bcknd_cmd);
+ install_element(CONFIG_NODE, &debug_mgmt_bcknd_cmd);
+ install_element(VIEW_NODE, &debug_mgmt_frntnd_cmd);
+ install_element(CONFIG_NODE, &debug_mgmt_frntnd_cmd);
+ install_element(VIEW_NODE, &debug_mgmt_db_cmd);
+ install_element(CONFIG_NODE, &debug_mgmt_db_cmd);
+ install_element(VIEW_NODE, &debug_mgmt_trxn_cmd);
+ install_element(CONFIG_NODE, &debug_mgmt_trxn_cmd);
+ install_element(VIEW_NODE, &debug_mgmt_all_cmd);
+ install_element(CONFIG_NODE, &debug_mgmt_all_cmd);
+
+ /*
+ * TODO: Register and handlers for auto-completion here (if any).
+ */
+}
--- /dev/null
+/*
+ * MGMTD VTY interface.
+ * Copyright (C) 2021 Vmware, Inc.
+ * Pushpasis Sarkar
+ *
+ * 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 _MGMTD_VTY_H
+#define _MGMTD_VTY_H
+
+#include "lib/command.h"
+#include "northbound_cli.h"
+
+extern void mgmt_enqueue_vty_nb_command(struct vty *vty, const char *xpath,
+ enum nb_operation operation,
+ const char *value);
+extern int mgmt_apply_vty_nb_commands(struct vty *vty,
+ const char *xpath_base_fmt, ...);
+extern int mgmt_hndl_bknd_cmd(const struct cmd_element *cmd, struct vty *vty,
+ int argc, struct cmd_token *argv[]);
+
+static inline LYD_FORMAT mgmt_str2format(const char *format_str)
+{
+ if (!strncmp("json", format_str, sizeof("json")))
+ return LYD_JSON;
+ else if (!strncmp("xml", format_str, sizeof("xml")))
+ return LYD_XML;
+ return LYD_UNKNOWN;
+}
+
+extern void mgmt_vty_init(void);
+
+#endif /* _MGMTD_VTY_H */
--- /dev/null
+#
+# mgmtd -- Mangagement Daemon
+#
+
+# dist_examples_DATA += \
+ # end
+vtysh_scan += \
+ mgmtd/mgmt_vty.c \
+ # endif
+
+vtysh_daemons += mgmtd
+
+# man8 += $(MANBUILD)/frr-mgmtd.8
+# endif
+
+clippy_scan += \
+ mgmtd/mgmt_vty.c \
+ # end
+
+noinst_LIBRARIES += mgmtd/libmgmtd.a
+mgmtd_libmgmtd_a_SOURCES = \
+ mgmtd/mgmt.c \
+ mgmtd/mgmt_memory.c \
+ mgmtd/mgmt_db.c \
+ mgmtd/mgmt_vty.c \
+ # end
+
+mgmtdheaderdir = $(pkgincludedir)/mgmtd
+mgmtdheader_HEADERS = \
+ mgmtd/mgmt_defines.h \
+ # end
+
+noinst_HEADERS += \
+ mgmtd/mgmt.h \
+ mgmtd/mgmt_memory.h \
+ mgmtd/mgmt_db.h \
+ mgmtd/mgmt_vty.h \
+ # end
+
+sbin_PROGRAMS += mgmtd/mgmtd
+
+mgmtd_mgmtd_SOURCES = \
+ mgmtd/mgmt_main.c \
+ # end
+mgmtd_mgmtd_CFLAGS = $(AM_CFLAGS) -I ./
+mgmtd_mgmtd_LDADD = mgmtd/libmgmtd.a lib/libfrr.la $(LIBCAP) $(LIBM) $(LIBYANG_LIBS) $(UST_LIBS)
--- /dev/null
+#!/bin/sh
+#
+# mgmtd is part of the quagga routing beast
+#
+# PROVIDE: mgmtd
+# REQUIRE: none
+##
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin:@prefix@/sbin:@prefix@/bin
+export PATH
+
+if [ -f /etc/rc.subr ]
+then
+ . /etc/rc.subr
+fi
+
+name="mgmtd"
+rcvar=$name
+required_files="@sysconfdir@/${name}.conf"
+command="@prefix@/sbin/${name}"
+command_args="-d"
+
+start_precmd="zebra_precmd"
+socket_dir=@localstatedir@
+pidfile="${socket_dir}/${name}.pid"
+
+zebra_precmd()
+{
+ rc_flags="$(
+ set -- $rc_flags
+ while [ $# -ne 0 ]; do
+ if [ X"$1" = X-P -o X"$1" = X-A ]; then
+ break
+ fi
+ shift
+ done
+ if [ $# -eq 0 ]; then
+ echo "-P 0"
+ fi
+ ) $rc_flags"
+}
+
+load_rc_config $name
+run_rc_command "$1"
# end
EXTRA_DIST += qpb/qpb.proto
-SUFFIXES += .proto .pb-c.c .pb-c.h
-
-if HAVE_PROTOBUF
-
-# Rules
-.proto.pb.h:
- $(PROTOC) -I$(top_srcdir) --cpp_out=$(top_builddir) $^
-
-AM_V_PROTOC_C = $(am__v_PROTOC_C_$(V))
-am__v_PROTOC_C_ = $(am__v_PROTOC_C_$(AM_DEFAULT_VERBOSITY))
-am__v_PROTOC_C_0 = @echo " PROTOC_C" $@;
-am__v_PROTOC_C_1 =
-
-.proto.pb-c.c:
- $(AM_V_PROTOC_C)$(PROTOC_C) -I$(top_srcdir) --c_out=$(top_builddir) $^
- $(AM_V_GEN)$(SED) -e '1i#include "config.h"' -i $@
-.pb-c.c.pb-c.h:
- @/bin/true
-
-endif # HAVE_PROTOBUF
%{_sbindir}/ospfd
%{_sbindir}/ripd
%{_sbindir}/bgpd
+%{_sbindir}/mgmtd
%exclude %{_sbindir}/ssd
%if %{with_watchfrr}
%{_sbindir}/watchfrr
%{_libdir}/frr/modules/dplane_fpm_nl.so
%{_libdir}/frr/modules/zebra_irdp.so
%{_libdir}/frr/modules/bgpd_bmp.so
+%{_libdir}/libfrr_pb.so*
+%{_libdir}/libfrrfpm_pb.so*
+%{_libdir}/libmgmt_bcknd_nb.so*
%{_bindir}/*
%config(noreplace) %{configdir}/[!v]*.conf*
%config(noreplace) %attr(750,%{frr_user},%{frr_user}) %{configdir}/daemons
%{_libdir}/lib*.so
%dir %{_includedir}/%{name}
%{_includedir}/%{name}/*.h
+%dir %{_includedir}/%{name}/mgmtd
+%{_includedir}/%{name}/mgmtd/*.h
%dir %{_includedir}/%{name}/ospfd
%{_includedir}/%{name}/ospfd/*.h
%if %{with_bfdd}
%changelog
+* Tue Jan 11 2022 Pushpasis Sarkar <spushpasis@vmware.com> - %{version}
+- Added MGMTd Daemon to package.
+
* Tue Nov 4 2021 Martin Winter <mwinter@opensourcerouting.org> - %{version}
* Tue Feb 1 2022 Donatas Abraitis <donatas.abraitis@gmail.com> - 8.2
#
vtysh_enable=yes
zebra_options=" -A 127.0.0.1 -s 90000000"
+mgmtd_options=" -A 127.0.0.1"
bgpd_options=" -A 127.0.0.1"
ospfd_options=" -A 127.0.0.1"
ospf6d_options=" -A ::1"
# Local Daemon selection may be done by using /etc/frr/daemons.
# See /usr/share/doc/frr/README.Debian.gz for further information.
# Keep zebra first and do not list watchfrr!
-DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd vrrpd pathd"
+DAEMONS="mgmtd zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd vrrpd pathd"
MAX_INSTANCES=5
RELOAD_SCRIPT="$D_PATH/frr-reload.py"
# - keep zebra first
# - watchfrr does NOT belong in this list
-DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd vrrpd pathd"
+DAEMONS="zebra mgmtd bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd vrrpd pathd"
RELOAD_SCRIPT="$D_PATH/frr-reload.py"
#
for daemon in $DAEMONS; do
eval cfg=\$$daemon
eval inst=\$${daemon}_instances
- [ "$daemon" = zebra -o "$daemon" = staticd ] && cfg=yes
+ [ "$daemon" = zebra -o "$daemon" = staticd -o "$daemon" = mgmtd ] && cfg=yes
if [ -n "$cfg" -a "$cfg" != "no" -a "$cfg" != "0" ]; then
if ! daemon_prep "$daemon" "$inst"; then
continue
/* --- */
struct vtysh_client vtysh_client[] = {
+ {.name = "mgmtd", .flag = VTYSH_MGMTD},
{.name = "zebra", .flag = VTYSH_ZEBRA},
{.name = "ripd", .flag = VTYSH_RIPD},
{.name = "ripngd", .flag = VTYSH_RIPNGD},
#define VTYSH_VRRPD 0x40000
#define VTYSH_PATHD 0x80000
#define VTYSH_PIM6D 0x100000
+#define VTYSH_MGMTD 0x200000
#define VTYSH_WAS_ACTIVE (-2)
/* watchfrr is not in ALL since library CLI functions should not be
* run on it (logging & co. should stay in a fixed/frozen config, and
* things like prefix lists are not even initialised) */
-#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD|VTYSH_BFDD|VTYSH_FABRICD|VTYSH_VRRPD|VTYSH_PATHD
+#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD|VTYSH_BFDD|VTYSH_FABRICD|VTYSH_VRRPD|VTYSH_PATHD|VTYSH_MGMTD
#define VTYSH_ACL VTYSH_BFDD|VTYSH_BABELD|VTYSH_BGPD|VTYSH_EIGRPD|VTYSH_ISISD|VTYSH_FABRICD|VTYSH_LDPD|VTYSH_NHRPD|VTYSH_OSPF6D|VTYSH_OSPFD|VTYSH_PBRD|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_VRRPD|VTYSH_ZEBRA
#define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_EIGRPD|VTYSH_FABRICD
#define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_PBRD|VTYSH_FABRICD|VTYSH_VRRPD
-#define VTYSH_VRF VTYSH_INTERFACE|VTYSH_STATICD
+#define VTYSH_VRF VTYSH_INTERFACE|VTYSH_STATICD|VTYSH_MGMTD
#define VTYSH_KEYS VTYSH_RIPD | VTYSH_EIGRPD | VTYSH_OSPF6D
/* Daemons who can process nexthop-group configs */
#define VTYSH_NH_GROUP VTYSH_PBRD|VTYSH_SHARPD