forked from Mirror/frr
mgmtd: Bringup MGMTD daemon and datastore module support
Features added in this commit: 1. Bringup/shutdown new management daemon 'mgmtd' along with FRR. 2. Support for Startup, Candidate and Running DBs. 3. Lock/Unlock DS feature using pthread lock. 4. Load config from a JSON file onto candidate DS. 5. Save config to a JSON file from running/candidate DS. 6. Dump candidate or running DS contents on the terminal or a file in JSON/XML format. 7. Maintaining commit history (Full rollback support to be added in future commits). 8. Addition of debug commands. Co-authored-by: Yash Ranjan <ranjany@vmware.com> Co-authored-by: Abhinay Ramesh <rabhinay@vmware.com> Co-authored-by: Ujwal P <ujwalp@vmware.com> Signed-off-by: Pushpasis Sarkar <pushpasis@gmail.com>
This commit is contained in:
parent
ed851381b5
commit
1c84efe4fa
24
Makefile.am
24
Makefile.am
|
@ -155,6 +155,24 @@ $(AUTOMAKE_DUMMY)install-moduleLTLIBRARIES: install-libLTLIBRARIES
|
||||||
$(AUTOMAKE_DUMMY)install-binPROGRAMS: install-libLTLIBRARIES
|
$(AUTOMAKE_DUMMY)install-binPROGRAMS: install-libLTLIBRARIES
|
||||||
$(AUTOMAKE_DUMMY)install-sbinPROGRAMS: 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/subdir.am
|
||||||
include doc/user/subdir.am
|
include doc/user/subdir.am
|
||||||
include doc/manpages/subdir.am
|
include doc/manpages/subdir.am
|
||||||
|
@ -169,6 +187,8 @@ include fpm/subdir.am
|
||||||
include grpc/subdir.am
|
include grpc/subdir.am
|
||||||
include tools/subdir.am
|
include tools/subdir.am
|
||||||
|
|
||||||
|
include mgmtd/subdir.am
|
||||||
|
|
||||||
include bgpd/subdir.am
|
include bgpd/subdir.am
|
||||||
include bgpd/rfp-example/librfp/subdir.am
|
include bgpd/rfp-example/librfp/subdir.am
|
||||||
include bgpd/rfp-example/rfptest/subdir.am
|
include bgpd/rfp-example/rfptest/subdir.am
|
||||||
|
@ -207,6 +227,7 @@ rc_SCRIPTS = \
|
||||||
pkgsrc/ripd.sh \
|
pkgsrc/ripd.sh \
|
||||||
pkgsrc/ripngd.sh \
|
pkgsrc/ripngd.sh \
|
||||||
pkgsrc/zebra.sh \
|
pkgsrc/zebra.sh \
|
||||||
|
pkgsrc/mgmtd.sh \
|
||||||
# end
|
# end
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -244,6 +265,7 @@ EXTRA_DIST += \
|
||||||
snapcraft/helpers \
|
snapcraft/helpers \
|
||||||
snapcraft/snap \
|
snapcraft/snap \
|
||||||
babeld/Makefile \
|
babeld/Makefile \
|
||||||
|
mgmtd/Makefile \
|
||||||
bgpd/Makefile \
|
bgpd/Makefile \
|
||||||
bgpd/rfp-example/librfp/Makefile \
|
bgpd/rfp-example/librfp/Makefile \
|
||||||
bgpd/rfp-example/rfptest/Makefile \
|
bgpd/rfp-example/rfptest/Makefile \
|
||||||
|
@ -321,7 +343,7 @@ redistclean:
|
||||||
$(MAKE) distclean CONFIG_CLEAN_FILES="$(filter-out $(EXTRA_DIST), $(CONFIG_CLEAN_FILES))"
|
$(MAKE) distclean CONFIG_CLEAN_FILES="$(filter-out $(EXTRA_DIST), $(CONFIG_CLEAN_FILES))"
|
||||||
|
|
||||||
indent:
|
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
|
if HAVE_GCOV
|
||||||
|
|
||||||
|
|
51
configure.ac
51
configure.ac
|
@ -616,6 +616,8 @@ AC_ARG_ENABLE([zebra],
|
||||||
AS_HELP_STRING([--disable-zebra], [do not build zebra daemon]))
|
AS_HELP_STRING([--disable-zebra], [do not build zebra daemon]))
|
||||||
AC_ARG_ENABLE([bgpd],
|
AC_ARG_ENABLE([bgpd],
|
||||||
AS_HELP_STRING([--disable-bgpd], [do not build 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],
|
AC_ARG_ENABLE([ripd],
|
||||||
AS_HELP_STRING([--disable-ripd], [do not build ripd]))
|
AS_HELP_STRING([--disable-ripd], [do not build ripd]))
|
||||||
AC_ARG_ENABLE([ripngd],
|
AC_ARG_ENABLE([ripngd],
|
||||||
|
@ -890,10 +892,6 @@ if test "$enable_oldvpn_commands" = "yes"; then
|
||||||
AC_DEFINE([KEEP_OLD_VPN_COMMANDS], [1], [Define for compiling with old vpn commands])
|
AC_DEFINE([KEEP_OLD_VPN_COMMANDS], [1], [Define for compiling with old vpn commands])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#
|
|
||||||
# End of logic for protobuf support.
|
|
||||||
#
|
|
||||||
|
|
||||||
AC_MSG_CHECKING([if zebra should be configurable to send Route Advertisements])
|
AC_MSG_CHECKING([if zebra should be configurable to send Route Advertisements])
|
||||||
if test "$enable_rtadv" != "no"; then
|
if test "$enable_rtadv" != "no"; then
|
||||||
AC_MSG_RESULT([yes])
|
AC_MSG_RESULT([yes])
|
||||||
|
@ -1338,21 +1336,21 @@ dnl ##########################################################################
|
||||||
# Logic for protobuf support.
|
# Logic for protobuf support.
|
||||||
#
|
#
|
||||||
PROTO3=false
|
PROTO3=false
|
||||||
if test "$enable_protobuf" = "yes"; then
|
# Enable Protobuf by default at all times.
|
||||||
# Check for protoc & protoc-c
|
# 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_C], [protoc-c], [/bin/false])
|
||||||
AC_CHECK_PROGS([PROTOC], [protoc], [/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])
|
PKG_CHECK_MODULES([PROTOBUF_C], [libprotobuf-c >= 1.1.0],, [
|
||||||
if test "$PROTOC_C" = "/bin/false"; then
|
AC_MSG_FAILURE([minimum version (1.1.0) of libprotobuf-c not found. Install minimum required version of protobuf-c.])
|
||||||
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.])
|
|
||||||
])
|
|
||||||
|
|
||||||
|
if test "$enable_protobuf3" = "yes"; then
|
||||||
PROTO3=true
|
PROTO3=true
|
||||||
AC_CHECK_HEADER([google/protobuf-c/protobuf-c.h],
|
AC_CHECK_HEADER([google/protobuf-c/protobuf-c.h],
|
||||||
[AC_CHECK_DECLS(PROTOBUF_C_LABEL_NONE,
|
[AC_CHECK_DECLS(PROTOBUF_C_LABEL_NONE,
|
||||||
|
@ -1360,11 +1358,14 @@ if test "$enable_protobuf" = "yes"; then
|
||||||
[1], [Have Protobuf version 3]),
|
[1], [Have Protobuf version 3]),
|
||||||
[PROTO3=false],
|
[PROTO3=false],
|
||||||
[#include <google/protobuf-c/protobuf-c.h>])],
|
[#include <google/protobuf-c/protobuf-c.h>])],
|
||||||
[PROTO3=false && AC_MSG_FAILURE([protobuf requested but protobuf-c.h not found. Install protobuf-c.])])
|
[PROTO3=false && AC_MSG_FAILURE([protobuf3 requested but protobuf-c.h not found. Install protobuf-c.])])
|
||||||
|
|
||||||
AC_DEFINE([HAVE_PROTOBUF], [1], [protobuf])
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
AC_DEFINE([HAVE_PROTOBUF], [1], [protobuf])
|
||||||
|
#
|
||||||
|
# End of logic for protobuf support.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
dnl ---------------------
|
dnl ---------------------
|
||||||
dnl Integrated VTY option
|
dnl Integrated VTY option
|
||||||
|
@ -1728,6 +1729,11 @@ AS_IF([test "$enable_bgpd" != "no"], [
|
||||||
AC_DEFINE([HAVE_BGPD], [1], [bgpd])
|
AC_DEFINE([HAVE_BGPD], [1], [bgpd])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
AS_IF([test "$enable_mgmtd" != "no"], [
|
||||||
|
|
||||||
|
AC_DEFINE([HAVE_MGMTD], [1], [mgmtd])
|
||||||
|
])
|
||||||
|
|
||||||
AS_IF([test "$enable_ripd" != "no"], [
|
AS_IF([test "$enable_ripd" != "no"], [
|
||||||
AC_DEFINE([HAVE_RIPD], [1], [ripd])
|
AC_DEFINE([HAVE_RIPD], [1], [ripd])
|
||||||
])
|
])
|
||||||
|
@ -2658,6 +2664,8 @@ AC_DEFINE_UNQUOTED([LDPD_SOCKET], ["$frr_statedir%s%s/ldpd.sock"], [ldpd control
|
||||||
AC_DEFINE_UNQUOTED([ZEBRA_SERV_PATH], ["$frr_statedir%s%s/zserv.api"], [zebra api socket])
|
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([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([OSPFD_GR_STATE], ["$frr_statedir%s/ospfd-gr.json"], [ospfd GR state information])
|
||||||
|
AC_DEFINE_UNQUOTED([MGMTD_FE_SERVER_PATH], ["$frr_statedir/mgmtd_fe.sock"], [mgmtd frontend server socket])
|
||||||
|
AC_DEFINE_UNQUOTED([MGMTD_BE_SERVER_PATH], ["$frr_statedir/mgmtd_be.sock"], [mgmtd backend server socket])
|
||||||
AC_DEFINE_UNQUOTED([OSPF6D_GR_STATE], ["$frr_statedir/ospf6d-gr.json"], [ospf6d GR state information])
|
AC_DEFINE_UNQUOTED([OSPF6D_GR_STATE], ["$frr_statedir/ospf6d-gr.json"], [ospf6d GR state information])
|
||||||
AC_DEFINE_UNQUOTED([ISISD_RESTART], ["$frr_statedir%s/isid-restart.json"], [isisd restart information])
|
AC_DEFINE_UNQUOTED([ISISD_RESTART], ["$frr_statedir%s/isid-restart.json"], [isisd restart information])
|
||||||
AC_DEFINE_UNQUOTED([OSPF6_AUTH_SEQ_NUM_FILE], ["$frr_statedir/ospf6d-at-seq-no.dat"], [ospf6d AT Sequence number information])
|
AC_DEFINE_UNQUOTED([OSPF6_AUTH_SEQ_NUM_FILE], ["$frr_statedir/ospf6d-at-seq-no.dat"], [ospf6d AT Sequence number information])
|
||||||
|
@ -2716,7 +2724,7 @@ AM_CONDITIONAL([RPKI], [test "$RPKI" = "true"])
|
||||||
AM_CONDITIONAL([SNMP], [test "$SNMP_METHOD" = "agentx"])
|
AM_CONDITIONAL([SNMP], [test "$SNMP_METHOD" = "agentx"])
|
||||||
AM_CONDITIONAL([IRDP], [$IRDP])
|
AM_CONDITIONAL([IRDP], [$IRDP])
|
||||||
AM_CONDITIONAL([FPM], [test "$enable_fpm" = "yes"])
|
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])
|
AM_CONDITIONAL([HAVE_PROTOBUF3], [$PROTO3])
|
||||||
|
|
||||||
dnl PCEP plugin
|
dnl PCEP plugin
|
||||||
|
@ -2733,6 +2741,7 @@ dnl daemons
|
||||||
AM_CONDITIONAL([VTYSH], [test "$VTYSH" = "vtysh"])
|
AM_CONDITIONAL([VTYSH], [test "$VTYSH" = "vtysh"])
|
||||||
AM_CONDITIONAL([ZEBRA], [test "$enable_zebra" != "no"])
|
AM_CONDITIONAL([ZEBRA], [test "$enable_zebra" != "no"])
|
||||||
AM_CONDITIONAL([BGPD], [test "$enable_bgpd" != "no"])
|
AM_CONDITIONAL([BGPD], [test "$enable_bgpd" != "no"])
|
||||||
|
AM_CONDITIONAL([MGMTD], [test "$enable_mgmtd" != "no"])
|
||||||
AM_CONDITIONAL([RIPD], [test "$enable_ripd" != "no"])
|
AM_CONDITIONAL([RIPD], [test "$enable_ripd" != "no"])
|
||||||
AM_CONDITIONAL([OSPFD], [test "$enable_ospfd" != "no"])
|
AM_CONDITIONAL([OSPFD], [test "$enable_ospfd" != "no"])
|
||||||
AM_CONDITIONAL([LDPD], [test "$enable_ldpd" != "no"])
|
AM_CONDITIONAL([LDPD], [test "$enable_ldpd" != "no"])
|
||||||
|
@ -2770,7 +2779,7 @@ AC_CONFIG_FILES([
|
||||||
alpine/APKBUILD
|
alpine/APKBUILD
|
||||||
snapcraft/snapcraft.yaml
|
snapcraft/snapcraft.yaml
|
||||||
lib/version.h
|
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/bgpd.sh pkgsrc/ospf6d.sh pkgsrc/ospfd.sh
|
||||||
pkgsrc/ripd.sh pkgsrc/ripngd.sh pkgsrc/zebra.sh
|
pkgsrc/ripd.sh pkgsrc/ripngd.sh pkgsrc/zebra.sh
|
||||||
pkgsrc/eigrpd.sh])
|
pkgsrc/eigrpd.sh])
|
||||||
|
|
|
@ -429,6 +429,11 @@ struct cmd_node {
|
||||||
#define SHARP_STR "Sharp Routing Protocol\n"
|
#define SHARP_STR "Sharp Routing Protocol\n"
|
||||||
#define OSPF_GR_STR \
|
#define OSPF_GR_STR \
|
||||||
"OSPF non-stop forwarding (NSF) also known as OSPF Graceful Restart\n"
|
"OSPF non-stop forwarding (NSF) also known as OSPF Graceful Restart\n"
|
||||||
|
#define MGMTD_STR "Management Daemon (MGMTD) information\n"
|
||||||
|
#define MGMTD_BE_ADAPTER_STR "MGMTD Backend Adapter information\n"
|
||||||
|
#define MGMTD_FE_ADAPTER_STR "MGMTD Frontend Adapter information\n"
|
||||||
|
#define MGMTD_TXN_STR "MGMTD Transaction information\n"
|
||||||
|
#define MGMTD_DS_STR "MGMTD Datastore information\n"
|
||||||
|
|
||||||
#define CMD_VNI_RANGE "(1-16777215)"
|
#define CMD_VNI_RANGE "(1-16777215)"
|
||||||
#define CONF_BACKUP_EXT ".sav"
|
#define CONF_BACKUP_EXT ".sav"
|
||||||
|
|
|
@ -2389,6 +2389,8 @@ const char *nb_client_name(enum nb_client client)
|
||||||
return "gRPC";
|
return "gRPC";
|
||||||
case NB_CLIENT_PCEP:
|
case NB_CLIENT_PCEP:
|
||||||
return "Pcep";
|
return "Pcep";
|
||||||
|
case NB_CLIENT_MGMTD_SERVER:
|
||||||
|
return "MGMTD Server";
|
||||||
case NB_CLIENT_NONE:
|
case NB_CLIENT_NONE:
|
||||||
return "None";
|
return "None";
|
||||||
}
|
}
|
||||||
|
|
|
@ -613,6 +613,7 @@ enum nb_client {
|
||||||
NB_CLIENT_SYSREPO,
|
NB_CLIENT_SYSREPO,
|
||||||
NB_CLIENT_GRPC,
|
NB_CLIENT_GRPC,
|
||||||
NB_CLIENT_PCEP,
|
NB_CLIENT_PCEP,
|
||||||
|
NB_CLIENT_MGMTD_SERVER,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Northbound context. */
|
/* Northbound context. */
|
||||||
|
|
1
mgmtd/.gitignore
vendored
Normal file
1
mgmtd/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
mgmtd
|
10
mgmtd/Makefile
Normal file
10
mgmtd/Makefile
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
all: ALWAYS
|
||||||
|
@$(MAKE) -s -C .. mgmtd/mgmtd
|
||||||
|
%: ALWAYS
|
||||||
|
@$(MAKE) -s -C .. mgmtd/$@
|
||||||
|
|
||||||
|
Makefile:
|
||||||
|
#nothing
|
||||||
|
ALWAYS:
|
||||||
|
.PHONY: ALWAYS makefiles
|
||||||
|
.SUFFIXES:
|
49
mgmtd/mgmt.c
Normal file
49
mgmtd/mgmt.c
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
/*
|
||||||
|
* FRR Management Daemon (MGMTD) program
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Vmware, Inc.
|
||||||
|
* Pushpasis Sarkar
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zebra.h>
|
||||||
|
#include "mgmtd/mgmt.h"
|
||||||
|
#include "mgmtd/mgmt_ds.h"
|
||||||
|
#include "mgmtd/mgmt_memory.h"
|
||||||
|
|
||||||
|
bool mgmt_debug_be;
|
||||||
|
bool mgmt_debug_fe;
|
||||||
|
bool mgmt_debug_ds;
|
||||||
|
bool mgmt_debug_txn;
|
||||||
|
|
||||||
|
/* 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 datastores */
|
||||||
|
mgmt_ds_init(mm);
|
||||||
|
|
||||||
|
/* MGMTD VTY commands installation. */
|
||||||
|
mgmt_vty_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void mgmt_terminate(void)
|
||||||
|
{
|
||||||
|
mgmt_ds_destroy();
|
||||||
|
}
|
94
mgmtd/mgmt.h
Normal file
94
mgmtd/mgmt.h
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
/*
|
||||||
|
* MGMTD message definition header.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Vmware, Inc.
|
||||||
|
* Pushpasis Sarkar <spushpasis@vmware.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _FRR_MGMTD_H
|
||||||
|
#define _FRR_MGMTD_H
|
||||||
|
|
||||||
|
#include "vrf.h"
|
||||||
|
|
||||||
|
#include "defaults.h"
|
||||||
|
|
||||||
|
#include "mgmtd/mgmt_memory.h"
|
||||||
|
#include "mgmtd/mgmt_ds.h"
|
||||||
|
|
||||||
|
#define MGMTD_VTY_PORT 2622
|
||||||
|
#define MGMTD_SOCKET_BUF_SIZE 65535
|
||||||
|
|
||||||
|
extern bool mgmt_debug_be;
|
||||||
|
extern bool mgmt_debug_fe;
|
||||||
|
extern bool mgmt_debug_ds;
|
||||||
|
extern bool mgmt_debug_txn;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/* Datastores */
|
||||||
|
struct mgmt_ds_ctx *running_ds;
|
||||||
|
struct mgmt_ds_ctx *candidate_ds;
|
||||||
|
struct mgmt_ds_ctx *oper_ds;
|
||||||
|
|
||||||
|
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);
|
||||||
|
extern void mgmt_vty_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 */
|
20
mgmtd/mgmt_defines.h
Normal file
20
mgmtd/mgmt_defines.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
/*
|
||||||
|
* MGMTD public defines.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Vmware, Inc.
|
||||||
|
* Pushpasis Sarkar <spushpasis@vmware.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _FRR_MGMTD_DEFINES_H
|
||||||
|
#define _FRR_MGMTD_DEFINES_H
|
||||||
|
|
||||||
|
#include "yang.h"
|
||||||
|
|
||||||
|
#define MGMTD_CLIENT_NAME_MAX_LEN 32
|
||||||
|
|
||||||
|
#define MGMTD_MAX_XPATH_LEN XPATH_MAXLEN
|
||||||
|
|
||||||
|
#define MGMTD_MAX_YANG_VALUE_LEN YANG_VALUE_MAXLEN
|
||||||
|
|
||||||
|
#endif /* _FRR_MGMTD_DEFINES_H */
|
643
mgmtd/mgmt_ds.c
Normal file
643
mgmtd/mgmt_ds.c
Normal file
|
@ -0,0 +1,643 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
/*
|
||||||
|
* MGMTD Datastores
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Vmware, Inc.
|
||||||
|
* Pushpasis Sarkar <spushpasis@vmware.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zebra.h>
|
||||||
|
#include "md5.h"
|
||||||
|
#include "mgmtd/mgmt.h"
|
||||||
|
#include "mgmtd/mgmt_memory.h"
|
||||||
|
#include "mgmtd/mgmt_ds.h"
|
||||||
|
#include "libyang/libyang.h"
|
||||||
|
|
||||||
|
#ifdef REDIRECT_DEBUG_TO_STDERR
|
||||||
|
#define MGMTD_DS_DBG(fmt, ...) \
|
||||||
|
fprintf(stderr, "%s: " fmt "\n", __func__, ##__VA_ARGS__)
|
||||||
|
#define MGMTD_DS_ERR(fmt, ...) \
|
||||||
|
fprintf(stderr, "%s: ERROR, " fmt "\n", __func__, ##__VA_ARGS__)
|
||||||
|
#else /* REDIRECT_DEBUG_TO_STDERR */
|
||||||
|
#define MGMTD_DS_DBG(fmt, ...) \
|
||||||
|
do { \
|
||||||
|
if (mgmt_debug_ds) \
|
||||||
|
zlog_debug("%s: " fmt, __func__, ##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
#define MGMTD_DS_ERR(fmt, ...) \
|
||||||
|
zlog_err("%s: ERROR: " fmt, __func__, ##__VA_ARGS__)
|
||||||
|
#endif /* REDIRECT_DEBUG_TO_STDERR */
|
||||||
|
|
||||||
|
struct mgmt_ds_ctx {
|
||||||
|
enum mgmt_datastore_id ds_id;
|
||||||
|
int lock; /* 0 unlocked, >0 read locked < write locked */
|
||||||
|
|
||||||
|
bool config_ds;
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct nb_config *cfg_root;
|
||||||
|
struct lyd_node *dnode_root;
|
||||||
|
} root;
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *mgmt_ds_names[MGMTD_DS_MAX_ID + 1] = {
|
||||||
|
MGMTD_DS_NAME_NONE, /* MGMTD_DS_NONE */
|
||||||
|
MGMTD_DS_NAME_RUNNING, /* MGMTD_DS_RUNNING */
|
||||||
|
MGMTD_DS_NAME_CANDIDATE, /* MGMTD_DS_CANDIDATE */
|
||||||
|
MGMTD_DS_NAME_OPERATIONAL, /* MGMTD_DS_OPERATIONAL */
|
||||||
|
"Unknown/Invalid", /* MGMTD_DS_ID_MAX */
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct mgmt_master *mgmt_ds_mm;
|
||||||
|
static struct mgmt_ds_ctx running, candidate, oper;
|
||||||
|
|
||||||
|
/* Dump the data tree of the specified format in the file pointed by the path */
|
||||||
|
static int mgmt_ds_dump_in_memory(struct mgmt_ds_ctx *ds_ctx,
|
||||||
|
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 = ds_ctx->config_ds ? ds_ctx->root.cfg_root->dnode
|
||||||
|
: ds_ctx->root.dnode_root;
|
||||||
|
else
|
||||||
|
root = yang_dnode_get(ds_ctx->config_ds
|
||||||
|
? ds_ctx->root.cfg_root->dnode
|
||||||
|
: ds_ctx->root.dnode_root,
|
||||||
|
base_xpath);
|
||||||
|
if (!root)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
options = ds_ctx->config_ds ? 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_ds_replace_dst_with_src_ds(struct mgmt_ds_ctx *src,
|
||||||
|
struct mgmt_ds_ctx *dst)
|
||||||
|
{
|
||||||
|
struct lyd_node *dst_dnode, *src_dnode;
|
||||||
|
struct ly_out *out;
|
||||||
|
|
||||||
|
if (!src || !dst)
|
||||||
|
return -1;
|
||||||
|
MGMTD_DS_DBG("Replacing %d with %d", dst->ds_id, src->ds_id);
|
||||||
|
|
||||||
|
src_dnode = src->config_ds ? src->root.cfg_root->dnode
|
||||||
|
: dst->root.dnode_root;
|
||||||
|
dst_dnode = dst->config_ds ? 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 ds does not contain nb_config
|
||||||
|
*/
|
||||||
|
dst_dnode = yang_dnode_dup(src_dnode);
|
||||||
|
if (dst->config_ds)
|
||||||
|
dst->root.cfg_root->dnode = dst_dnode;
|
||||||
|
else
|
||||||
|
dst->root.dnode_root = dst_dnode;
|
||||||
|
|
||||||
|
if (dst->ds_id == MGMTD_DS_RUNNING) {
|
||||||
|
if (ly_out_new_filepath(MGMTD_STARTUP_DS_FILE_PATH, &out)
|
||||||
|
== LY_SUCCESS)
|
||||||
|
mgmt_ds_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_ds_merge_src_with_dst_ds(struct mgmt_ds_ctx *src,
|
||||||
|
struct mgmt_ds_ctx *dst)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct lyd_node **dst_dnode, *src_dnode;
|
||||||
|
struct ly_out *out;
|
||||||
|
|
||||||
|
if (!src || !dst)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
MGMTD_DS_DBG("Merging DS %d with %d", dst->ds_id, src->ds_id);
|
||||||
|
|
||||||
|
src_dnode = src->config_ds ? src->root.cfg_root->dnode
|
||||||
|
: dst->root.dnode_root;
|
||||||
|
dst_dnode = dst->config_ds ? &dst->root.cfg_root->dnode
|
||||||
|
: &dst->root.dnode_root;
|
||||||
|
ret = lyd_merge_siblings(dst_dnode, src_dnode, 0);
|
||||||
|
if (ret != 0) {
|
||||||
|
MGMTD_DS_ERR("lyd_merge() failed with err %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dst->ds_id == MGMTD_DS_RUNNING) {
|
||||||
|
if (ly_out_new_filepath(MGMTD_STARTUP_DS_FILE_PATH, &out)
|
||||||
|
== LY_SUCCESS)
|
||||||
|
mgmt_ds_dump_in_memory(dst, "", LYD_JSON, out);
|
||||||
|
ly_out_free(out, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mgmt_ds_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_ds_init(struct mgmt_master *mm)
|
||||||
|
{
|
||||||
|
struct lyd_node *root;
|
||||||
|
|
||||||
|
if (mgmt_ds_mm || mm->running_ds || mm->candidate_ds || mm->oper_ds)
|
||||||
|
assert(!"MGMTD: Call ds_init only once!");
|
||||||
|
|
||||||
|
/* Use Running DS from NB module??? */
|
||||||
|
if (!running_config)
|
||||||
|
assert(!"MGMTD: Call ds_init after frr_init only!");
|
||||||
|
|
||||||
|
if (mgmt_ds_load_cfg_from_file(MGMTD_STARTUP_DS_FILE_PATH, &root)
|
||||||
|
== 0) {
|
||||||
|
nb_config_free(running_config);
|
||||||
|
running_config = nb_config_new(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
running.root.cfg_root = running_config;
|
||||||
|
running.config_ds = true;
|
||||||
|
running.ds_id = MGMTD_DS_RUNNING;
|
||||||
|
|
||||||
|
candidate.root.cfg_root = nb_config_dup(running.root.cfg_root);
|
||||||
|
candidate.config_ds = true;
|
||||||
|
candidate.ds_id = MGMTD_DS_CANDIDATE;
|
||||||
|
|
||||||
|
oper.root.dnode_root = yang_dnode_new(ly_native_ctx, true);
|
||||||
|
oper.config_ds = false;
|
||||||
|
oper.ds_id = MGMTD_DS_OPERATIONAL;
|
||||||
|
|
||||||
|
mm->running_ds = &running;
|
||||||
|
mm->candidate_ds = &candidate;
|
||||||
|
mm->oper_ds = &oper;
|
||||||
|
mgmt_ds_mm = mm;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mgmt_ds_destroy(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Free the datastores.
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mgmt_ds_ctx *mgmt_ds_get_ctx_by_id(struct mgmt_master *mm,
|
||||||
|
enum mgmt_datastore_id ds_id)
|
||||||
|
{
|
||||||
|
switch (ds_id) {
|
||||||
|
case MGMTD_DS_CANDIDATE:
|
||||||
|
return (mm->candidate_ds);
|
||||||
|
case MGMTD_DS_RUNNING:
|
||||||
|
return (mm->running_ds);
|
||||||
|
case MGMTD_DS_OPERATIONAL:
|
||||||
|
return (mm->oper_ds);
|
||||||
|
case MGMTD_DS_NONE:
|
||||||
|
case MGMTD_DS_MAX_ID:
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mgmt_ds_is_config(struct mgmt_ds_ctx *ds_ctx)
|
||||||
|
{
|
||||||
|
if (!ds_ctx)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return ds_ctx->config_ds;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mgmt_ds_read_lock(struct mgmt_ds_ctx *ds_ctx)
|
||||||
|
{
|
||||||
|
if (!ds_ctx)
|
||||||
|
return EINVAL;
|
||||||
|
if (ds_ctx->lock < 0)
|
||||||
|
return EBUSY;
|
||||||
|
++ds_ctx->lock;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mgmt_ds_write_lock(struct mgmt_ds_ctx *ds_ctx)
|
||||||
|
{
|
||||||
|
if (!ds_ctx)
|
||||||
|
return EINVAL;
|
||||||
|
if (ds_ctx->lock != 0)
|
||||||
|
return EBUSY;
|
||||||
|
ds_ctx->lock = -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mgmt_ds_unlock(struct mgmt_ds_ctx *ds_ctx)
|
||||||
|
{
|
||||||
|
if (!ds_ctx)
|
||||||
|
return EINVAL;
|
||||||
|
if (ds_ctx->lock > 0)
|
||||||
|
--ds_ctx->lock;
|
||||||
|
else if (ds_ctx->lock < 0) {
|
||||||
|
assert(ds_ctx->lock == -1);
|
||||||
|
ds_ctx->lock = 0;
|
||||||
|
} else {
|
||||||
|
assert(ds_ctx->lock != 0);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mgmt_ds_merge_dss(struct mgmt_ds_ctx *src_ds_ctx,
|
||||||
|
struct mgmt_ds_ctx *dst_ds_ctx, bool updt_cmt_rec)
|
||||||
|
{
|
||||||
|
if (mgmt_ds_merge_src_with_dst_ds(src_ds_ctx, dst_ds_ctx) != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mgmt_ds_copy_dss(struct mgmt_ds_ctx *src_ds_ctx,
|
||||||
|
struct mgmt_ds_ctx *dst_ds_ctx, bool updt_cmt_rec)
|
||||||
|
{
|
||||||
|
if (mgmt_ds_replace_dst_with_src_ds(src_ds_ctx, dst_ds_ctx) != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mgmt_ds_dump_ds_to_file(char *file_name, struct mgmt_ds_ctx *ds_ctx)
|
||||||
|
{
|
||||||
|
struct ly_out *out;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (ly_out_new_filepath(file_name, &out) == LY_SUCCESS) {
|
||||||
|
ret = mgmt_ds_dump_in_memory(ds_ctx, "", LYD_JSON, out);
|
||||||
|
ly_out_free(out, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct nb_config *mgmt_ds_get_nb_config(struct mgmt_ds_ctx *ds_ctx)
|
||||||
|
{
|
||||||
|
if (!ds_ctx)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return ds_ctx->config_ds ? ds_ctx->root.cfg_root : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mgmt_walk_ds_nodes(
|
||||||
|
struct mgmt_ds_ctx *ds_ctx, char *base_xpath,
|
||||||
|
struct lyd_node *base_dnode,
|
||||||
|
void (*mgmt_ds_node_iter_fn)(struct mgmt_ds_ctx *ds_ctx, char *xpath,
|
||||||
|
struct lyd_node *node,
|
||||||
|
struct nb_node *nb_node, void *ctx),
|
||||||
|
void *ctx, 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_DS_DBG(" -- START: num_left:%d", num_left);
|
||||||
|
*num_nodes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MGMTD_DS_DBG(" -- START: Base: %s", base_xpath);
|
||||||
|
|
||||||
|
if (!base_dnode)
|
||||||
|
base_dnode = yang_dnode_get(
|
||||||
|
ds_ctx->config_ds ? ds_ctx->root.cfg_root->dnode
|
||||||
|
: ds_ctx->root.dnode_root,
|
||||||
|
base_xpath);
|
||||||
|
if (!base_dnode)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (mgmt_ds_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_ds_node_iter_fn)(ds_ctx, iter_xp, base_dnode, nbnode,
|
||||||
|
ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_DS_DBG(" -- XPATH: %s", xpath);
|
||||||
|
|
||||||
|
if (!childs_as_well)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (num_nodes)
|
||||||
|
num_found = num_left;
|
||||||
|
|
||||||
|
ret = mgmt_walk_ds_nodes(ds_ctx, xpath, dnode,
|
||||||
|
mgmt_ds_node_iter_fn, ctx,
|
||||||
|
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_DS_DBG(" -- END: *num_nodes:%d, num_left:%d", *num_nodes,
|
||||||
|
num_left);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mgmt_ds_lookup_data_nodes(struct mgmt_ds_ctx *ds_ctx, 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 (!ds_ctx || !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_ds_nodes(ds_ctx, base_xpath, NULL, NULL, NULL,
|
||||||
|
dxpaths, num_nodes, get_childs_as_well,
|
||||||
|
alloc_xp_copy));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lyd_node *mgmt_ds_find_data_node_by_xpath(struct mgmt_ds_ctx *ds_ctx,
|
||||||
|
const char *xpath)
|
||||||
|
{
|
||||||
|
if (!ds_ctx)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return yang_dnode_get(ds_ctx->config_ds ? ds_ctx->root.cfg_root->dnode
|
||||||
|
: ds_ctx->root.dnode_root,
|
||||||
|
xpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mgmt_ds_delete_data_nodes(struct mgmt_ds_ctx *ds_ctx, const char *xpath)
|
||||||
|
{
|
||||||
|
struct nb_node *nb_node;
|
||||||
|
struct lyd_node *dnode, *dep_dnode;
|
||||||
|
char dep_xpath[XPATH_MAXLEN];
|
||||||
|
|
||||||
|
if (!ds_ctx)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
nb_node = nb_node_find(xpath);
|
||||||
|
|
||||||
|
dnode = yang_dnode_get(ds_ctx->config_ds
|
||||||
|
? ds_ctx->root.cfg_root->dnode
|
||||||
|
: ds_ctx->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(
|
||||||
|
ds_ctx->config_ds ? ds_ctx->root.cfg_root->dnode
|
||||||
|
: ds_ctx->root.dnode_root,
|
||||||
|
dep_xpath);
|
||||||
|
if (dep_dnode)
|
||||||
|
lyd_free_tree(dep_dnode);
|
||||||
|
}
|
||||||
|
lyd_free_tree(dnode);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mgmt_ds_load_config_from_file(struct mgmt_ds_ctx *dst,
|
||||||
|
const char *file_path, bool merge)
|
||||||
|
{
|
||||||
|
struct lyd_node *iter;
|
||||||
|
struct mgmt_ds_ctx parsed;
|
||||||
|
|
||||||
|
if (!dst)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (mgmt_ds_load_cfg_from_file(file_path, &iter) != 0) {
|
||||||
|
MGMTD_DS_ERR("Failed to load config from the file %s",
|
||||||
|
file_path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
parsed.root.cfg_root = nb_config_new(iter);
|
||||||
|
parsed.config_ds = true;
|
||||||
|
parsed.ds_id = dst->ds_id;
|
||||||
|
|
||||||
|
if (merge)
|
||||||
|
mgmt_ds_merge_src_with_dst_ds(&parsed, dst);
|
||||||
|
else
|
||||||
|
mgmt_ds_replace_dst_with_src_ds(&parsed, dst);
|
||||||
|
|
||||||
|
nb_config_free(parsed.root.cfg_root);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mgmt_ds_iter_data(struct mgmt_ds_ctx *ds_ctx, char *base_xpath,
|
||||||
|
void (*mgmt_ds_node_iter_fn)(struct mgmt_ds_ctx *ds_ctx,
|
||||||
|
char *xpath,
|
||||||
|
struct lyd_node *node,
|
||||||
|
struct nb_node *nb_node,
|
||||||
|
void *ctx),
|
||||||
|
void *ctx, bool alloc_xp_copy)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
char xpath[MGMTD_MAX_XPATH_LEN];
|
||||||
|
struct lyd_node *base_dnode = NULL;
|
||||||
|
struct lyd_node *node;
|
||||||
|
|
||||||
|
if (!ds_ctx)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
mgmt_remove_trailing_separator(base_xpath, '/');
|
||||||
|
|
||||||
|
strlcpy(xpath, base_xpath, sizeof(xpath));
|
||||||
|
|
||||||
|
MGMTD_DS_DBG(" -- START DS walk for DSid: %d", ds_ctx->ds_id);
|
||||||
|
|
||||||
|
/* If the base_xpath is empty then crawl the sibblings */
|
||||||
|
if (xpath[0] == '\0') {
|
||||||
|
base_dnode = ds_ctx->config_ds ? ds_ctx->root.cfg_root->dnode
|
||||||
|
: ds_ctx->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_ds_nodes(
|
||||||
|
ds_ctx, xpath, node, mgmt_ds_node_iter_fn,
|
||||||
|
ctx, NULL, NULL, true, alloc_xp_copy);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
ret = mgmt_walk_ds_nodes(ds_ctx, xpath, base_dnode,
|
||||||
|
mgmt_ds_node_iter_fn, ctx, NULL, NULL,
|
||||||
|
true, alloc_xp_copy);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mgmt_ds_dump_tree(struct vty *vty, struct mgmt_ds_ctx *ds_ctx,
|
||||||
|
const char *xpath, FILE *f, LYD_FORMAT format)
|
||||||
|
{
|
||||||
|
struct ly_out *out;
|
||||||
|
char *str;
|
||||||
|
char base_xpath[MGMTD_MAX_XPATH_LEN] = {0};
|
||||||
|
|
||||||
|
if (!ds_ctx) {
|
||||||
|
vty_out(vty, " >>>>> Datastore 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_ds_dump_in_memory(ds_ctx, base_xpath, format, out);
|
||||||
|
|
||||||
|
if (!f)
|
||||||
|
vty_out(vty, "%s\n", str);
|
||||||
|
|
||||||
|
ly_out_free(out, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mgmt_ds_status_write_one(struct vty *vty, struct mgmt_ds_ctx *ds_ctx)
|
||||||
|
{
|
||||||
|
if (!ds_ctx) {
|
||||||
|
vty_out(vty, " >>>>> Datastore Not Initialized!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vty_out(vty, " DS: %s\n", mgmt_ds_id2name(ds_ctx->ds_id));
|
||||||
|
vty_out(vty, " DS-Hndl: \t\t\t%p\n", ds_ctx);
|
||||||
|
vty_out(vty, " Config: \t\t\t%s\n",
|
||||||
|
ds_ctx->config_ds ? "True" : "False");
|
||||||
|
}
|
||||||
|
|
||||||
|
void mgmt_ds_status_write(struct vty *vty)
|
||||||
|
{
|
||||||
|
vty_out(vty, "MGMTD Datastores\n");
|
||||||
|
|
||||||
|
mgmt_ds_status_write_one(vty, mgmt_ds_mm->running_ds);
|
||||||
|
|
||||||
|
mgmt_ds_status_write_one(vty, mgmt_ds_mm->candidate_ds);
|
||||||
|
|
||||||
|
mgmt_ds_status_write_one(vty, mgmt_ds_mm->oper_ds);
|
||||||
|
}
|
402
mgmtd/mgmt_ds.h
Normal file
402
mgmtd/mgmt_ds.h
Normal file
|
@ -0,0 +1,402 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
/*
|
||||||
|
* MGMTD Datastores
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Vmware, Inc.
|
||||||
|
* Pushpasis Sarkar <spushpasis@vmware.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _FRR_MGMTD_DS_H_
|
||||||
|
#define _FRR_MGMTD_DS_H_
|
||||||
|
|
||||||
|
#include "northbound.h"
|
||||||
|
|
||||||
|
#include "mgmtd/mgmt_defines.h"
|
||||||
|
|
||||||
|
#define MGMTD_MAX_NUM_DSNODES_PER_BATCH 128
|
||||||
|
|
||||||
|
#define MGMTD_DS_NAME_MAX_LEN 32
|
||||||
|
#define MGMTD_DS_NAME_NONE "none"
|
||||||
|
#define MGMTD_DS_NAME_RUNNING "running"
|
||||||
|
#define MGMTD_DS_NAME_CANDIDATE "candidate"
|
||||||
|
#define MGMTD_DS_NAME_OPERATIONAL "operational"
|
||||||
|
|
||||||
|
#define MGMTD_STARTUP_DS_FILE_PATH DAEMON_DB_DIR "/frr_startup.json"
|
||||||
|
|
||||||
|
#define FOREACH_MGMTD_DS_ID(id) \
|
||||||
|
for ((id) = MGMTD_DS_NONE; (id) < MGMTD_DS_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_COMMIT_FILE_PATH DAEMON_DB_DIR "/commit-%s.json"
|
||||||
|
#define MGMTD_COMMIT_INDEX_FILE_NAME DAEMON_DB_DIR "/commit-index.dat"
|
||||||
|
#define MGMTD_COMMIT_TIME_STR_LEN 100
|
||||||
|
|
||||||
|
struct mgmt_master;
|
||||||
|
|
||||||
|
extern struct nb_config *running_config;
|
||||||
|
|
||||||
|
struct mgmt_ds_ctx;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Datastore-Id: For now defined here. Eventually will be
|
||||||
|
* defined as part of MGMTD Front-End interface.
|
||||||
|
*/
|
||||||
|
enum mgmt_datastore_id {
|
||||||
|
MGMTD_DS_NONE = 0,
|
||||||
|
MGMTD_DS_RUNNING,
|
||||||
|
MGMTD_DS_CANDIDATE,
|
||||||
|
MGMTD_DS_OPERATIONAL,
|
||||||
|
MGMTD_DS_MAX_ID
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*mgmt_ds_node_iter_fn)(uint64_t ds_hndl, char *xpath,
|
||||||
|
struct lyd_node *node,
|
||||||
|
struct nb_node *nb_node, void *ctx);
|
||||||
|
|
||||||
|
/***************************************************************
|
||||||
|
* Global data exported
|
||||||
|
***************************************************************/
|
||||||
|
|
||||||
|
extern const char *mgmt_ds_names[MGMTD_DS_MAX_ID + 1];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert datastore ID to datastore name.
|
||||||
|
*
|
||||||
|
* id
|
||||||
|
* Datastore ID.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* Datastore name.
|
||||||
|
*/
|
||||||
|
static inline const char *mgmt_ds_id2name(enum mgmt_datastore_id id)
|
||||||
|
{
|
||||||
|
if (id > MGMTD_DS_MAX_ID)
|
||||||
|
id = MGMTD_DS_MAX_ID;
|
||||||
|
return mgmt_ds_names[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert datastore name to datastore ID.
|
||||||
|
*
|
||||||
|
* id
|
||||||
|
* Datastore name.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* Datastore ID.
|
||||||
|
*/
|
||||||
|
static inline enum mgmt_datastore_id mgmt_ds_name2id(const char *name)
|
||||||
|
{
|
||||||
|
enum mgmt_datastore_id id;
|
||||||
|
|
||||||
|
FOREACH_MGMTD_DS_ID (id) {
|
||||||
|
if (!strncmp(mgmt_ds_names[id], name, MGMTD_DS_NAME_MAX_LEN))
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MGMTD_DS_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert datastore ID to datastore name.
|
||||||
|
*
|
||||||
|
* similar to above funtion.
|
||||||
|
*/
|
||||||
|
static inline enum mgmt_datastore_id mgmt_get_ds_id_by_name(const char *ds_name)
|
||||||
|
{
|
||||||
|
if (!strncmp(ds_name, "candidate", sizeof("candidate")))
|
||||||
|
return MGMTD_DS_CANDIDATE;
|
||||||
|
else if (!strncmp(ds_name, "running", sizeof("running")))
|
||||||
|
return MGMTD_DS_RUNNING;
|
||||||
|
else if (!strncmp(ds_name, "operational", sizeof("operational")))
|
||||||
|
return MGMTD_DS_OPERATIONAL;
|
||||||
|
return MGMTD_DS_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 datastore */
|
||||||
|
extern int mgmt_ds_init(struct mgmt_master *cm);
|
||||||
|
|
||||||
|
/* Destroy datastore */
|
||||||
|
extern void mgmt_ds_destroy(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get datastore handler by ID
|
||||||
|
*
|
||||||
|
* mm
|
||||||
|
* Management master structure.
|
||||||
|
*
|
||||||
|
* ds_id
|
||||||
|
* Datastore ID.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* Datastore context (Holds info about ID, lock, root node etc).
|
||||||
|
*/
|
||||||
|
extern struct mgmt_ds_ctx *mgmt_ds_get_ctx_by_id(struct mgmt_master *mm,
|
||||||
|
enum mgmt_datastore_id ds_id);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if a given datastore is config ds
|
||||||
|
*/
|
||||||
|
extern bool mgmt_ds_is_config(struct mgmt_ds_ctx *ds_ctx);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Acquire read lock to a ds given a ds_handle
|
||||||
|
*/
|
||||||
|
extern int mgmt_ds_read_lock(struct mgmt_ds_ctx *ds_ctx);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Acquire write lock to a ds given a ds_handle
|
||||||
|
*/
|
||||||
|
extern int mgmt_ds_write_lock(struct mgmt_ds_ctx *ds_ctx);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove a lock from ds given a ds_handle
|
||||||
|
*/
|
||||||
|
extern int mgmt_ds_unlock(struct mgmt_ds_ctx *ds_ctx);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Merge two datastores.
|
||||||
|
*
|
||||||
|
* src_ds
|
||||||
|
* Source datastore handle.
|
||||||
|
*
|
||||||
|
* dst_ds
|
||||||
|
* Destination datastore handle.
|
||||||
|
*
|
||||||
|
* update_cmd_rec
|
||||||
|
* TRUE if need to update commit record, FALSE otherwise.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 on success, -1 on failure.
|
||||||
|
*/
|
||||||
|
extern int mgmt_ds_merge_dss(struct mgmt_ds_ctx *src_ds_ctx,
|
||||||
|
struct mgmt_ds_ctx *dst_ds_ctx,
|
||||||
|
bool update_cmt_rec);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy from source to destination datastore.
|
||||||
|
*
|
||||||
|
* src_ds
|
||||||
|
* Source datastore handle (ds to be copied from).
|
||||||
|
*
|
||||||
|
* dst_ds
|
||||||
|
* Destination datastore handle (ds 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_ds_copy_dss(struct mgmt_ds_ctx *src_ds_ctx,
|
||||||
|
struct mgmt_ds_ctx *dst_ds_ctx,
|
||||||
|
bool update_cmt_rec);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fetch northbound configuration for a given datastore context.
|
||||||
|
*/
|
||||||
|
extern struct nb_config *mgmt_ds_get_nb_config(struct mgmt_ds_ctx *ds_ctx);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lookup YANG data nodes.
|
||||||
|
*
|
||||||
|
* ds_ctx
|
||||||
|
* Datastore 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_ds_lookup_data_nodes(struct mgmt_ds_ctx *ds_ctx,
|
||||||
|
const char *xpath, char *dxpaths[],
|
||||||
|
int *num_nodes, bool get_childs_as_well,
|
||||||
|
bool alloc_xp_copy);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find YANG data node given a datastore handle YANG xpath.
|
||||||
|
*/
|
||||||
|
extern struct lyd_node *
|
||||||
|
mgmt_ds_find_data_node_by_xpath(struct mgmt_ds_ctx *ds_ctx,
|
||||||
|
const char *xpath);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Delete YANG data node given a datastore handle and YANG xpath.
|
||||||
|
*/
|
||||||
|
extern int mgmt_ds_delete_data_nodes(struct mgmt_ds_ctx *ds_ctx,
|
||||||
|
const char *xpath);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Iterate over datastore data.
|
||||||
|
*
|
||||||
|
* ds_ctx
|
||||||
|
* Datastore context.
|
||||||
|
*
|
||||||
|
* base_xpath
|
||||||
|
* Base YANG xpath from where needs to be iterated.
|
||||||
|
*
|
||||||
|
* iter_fn
|
||||||
|
* function that will be called during each iteration.
|
||||||
|
*
|
||||||
|
* ctx
|
||||||
|
* 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_ds_iter_data(
|
||||||
|
struct mgmt_ds_ctx *ds_ctx, char *base_xpath,
|
||||||
|
void (*mgmt_ds_node_iter_fn)(struct mgmt_ds_ctx *ds_ctx, char *xpath,
|
||||||
|
struct lyd_node *node,
|
||||||
|
struct nb_node *nb_node, void *ctx),
|
||||||
|
void *ctx, bool alloc_xp_copy);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load config to datastore from a file.
|
||||||
|
*
|
||||||
|
* ds_ctx
|
||||||
|
* Datastore 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_ds_load_config_from_file(struct mgmt_ds_ctx *ds_ctx,
|
||||||
|
const char *file_path, bool merge);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dump the data tree to a file with JSON/XML format.
|
||||||
|
*
|
||||||
|
* vty
|
||||||
|
* VTY context.
|
||||||
|
*
|
||||||
|
* ds_ctx
|
||||||
|
* Datastore 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_ds_dump_tree(struct vty *vty, struct mgmt_ds_ctx *ds_ctx,
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* ds
|
||||||
|
* Datastore context.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 on success, -1 on failure.
|
||||||
|
*/
|
||||||
|
extern int mgmt_ds_dump_ds_to_file(char *file_name,
|
||||||
|
struct mgmt_ds_ctx *ds_ctx);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dump information about specific datastore.
|
||||||
|
*/
|
||||||
|
extern void mgmt_ds_status_write_one(struct vty *vty,
|
||||||
|
struct mgmt_ds_ctx *ds_ctx);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dump information about all the datastores.
|
||||||
|
*/
|
||||||
|
extern void mgmt_ds_status_write(struct vty *vty);
|
||||||
|
|
||||||
|
#endif /* _FRR_MGMTD_DS_H_ */
|
271
mgmtd/mgmt_main.c
Normal file
271
mgmtd/mgmt_main.c
Normal file
|
@ -0,0 +1,271 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
/*
|
||||||
|
* Main routine of mgmt.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Vmware, Inc.
|
||||||
|
* Pushpasis Sarkar
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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_ds.h"
|
||||||
|
#include "routing_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;
|
||||||
|
char backup_config_file[256];
|
||||||
|
|
||||||
|
/* 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();
|
||||||
|
|
||||||
|
snprintf(backup_config_file, sizeof(backup_config_file),
|
||||||
|
"%s/zebra.conf", frr_sysconfdir);
|
||||||
|
mgmtd_di.backup_config_file = backup_config_file;
|
||||||
|
|
||||||
|
frr_config_fork();
|
||||||
|
|
||||||
|
frr_run(mm->master);
|
||||||
|
|
||||||
|
/* Not reached. */
|
||||||
|
return 0;
|
||||||
|
}
|
21
mgmtd/mgmt_memory.c
Normal file
21
mgmtd/mgmt_memory.c
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
/*
|
||||||
|
* mgmt memory type definitions
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Vmware, Inc.
|
||||||
|
* Pushpasis Sarkar <spushpasis@vmware.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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");
|
16
mgmtd/mgmt_memory.h
Normal file
16
mgmtd/mgmt_memory.h
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
/*
|
||||||
|
* mgmt memory type declarations
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Vmware, Inc.
|
||||||
|
* Pushpasis Sarkar <spushpasis@vmware.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _FRR_MGMTD_MEMORY_H
|
||||||
|
#define _FRR_MGMTD_MEMORY_H
|
||||||
|
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
|
DECLARE_MGROUP(MGMTD);
|
||||||
|
DECLARE_MTYPE(MGMTD);
|
||||||
|
#endif /* _FRR_MGMTD_MEMORY_H */
|
210
mgmtd/mgmt_test_fe
Executable file
210
mgmtd/mgmt_test_fe
Executable file
|
@ -0,0 +1,210 @@
|
||||||
|
#! /bin/bash
|
||||||
|
|
||||||
|
# mgmtd/mgmt_test_fe - temporary wrapper script for .libs/mgmt_test_fe
|
||||||
|
# Generated by libtool (GNU libtool) 2.4.6 Debian-2.4.6-2
|
||||||
|
#
|
||||||
|
# The mgmtd/mgmt_test_fe 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_fe:mgmtd/mgmt_test_fe:$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_fe:mgmtd/mgmt_test_fe:$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_fe:mgmtd/mgmt_test_fe:$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_fe'
|
||||||
|
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
|
272
mgmtd/mgmt_vty.c
Normal file
272
mgmtd/mgmt_vty.c
Normal file
|
@ -0,0 +1,272 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
/*
|
||||||
|
* MGMTD VTY Interface
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Vmware, Inc.
|
||||||
|
* Pushpasis Sarkar <spushpasis@vmware.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zebra.h>
|
||||||
|
|
||||||
|
#include "command.h"
|
||||||
|
#include "json.h"
|
||||||
|
#include "mgmtd/mgmt.h"
|
||||||
|
#include "mgmtd/mgmt_ds.h"
|
||||||
|
|
||||||
|
#ifndef VTYSH_EXTRACT_PL
|
||||||
|
#include "mgmtd/mgmt_vty_clippy.c"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DEFPY(show_mgmt_ds,
|
||||||
|
show_mgmt_ds_cmd,
|
||||||
|
"show mgmt datastore [all|candidate|operational|running]$dsname",
|
||||||
|
SHOW_STR
|
||||||
|
MGMTD_STR
|
||||||
|
MGMTD_DS_STR
|
||||||
|
"All datastores (default)\n"
|
||||||
|
"Candidate datastore\n"
|
||||||
|
"Operational datastore\n"
|
||||||
|
"Running datastore\n")
|
||||||
|
{
|
||||||
|
struct mgmt_ds_ctx *ds_ctx;
|
||||||
|
|
||||||
|
if (!dsname || dsname[0] == 'a') {
|
||||||
|
mgmt_ds_status_write(vty);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
ds_ctx = mgmt_ds_get_ctx_by_id(mm, mgmt_ds_name2id(dsname));
|
||||||
|
if (!ds_ctx) {
|
||||||
|
vty_out(vty, "ERROR: Could not access %s datastore!\n", dsname);
|
||||||
|
return CMD_ERR_NO_MATCH;
|
||||||
|
}
|
||||||
|
mgmt_ds_status_write_one(vty, ds_ctx);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY(show_mgmt_dump_data,
|
||||||
|
show_mgmt_dump_data_cmd,
|
||||||
|
"show mgmt datastore-contents WORD$dsname [xpath WORD$path] [file WORD$filepath] <json|xml>$fmt",
|
||||||
|
SHOW_STR
|
||||||
|
MGMTD_STR
|
||||||
|
"Get Datastore contents from a specific datastore\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"
|
||||||
|
"json|xml\n")
|
||||||
|
{
|
||||||
|
enum mgmt_datastore_id datastore = MGMTD_DS_CANDIDATE;
|
||||||
|
struct mgmt_ds_ctx *ds_ctx;
|
||||||
|
LYD_FORMAT format = fmt[0] == 'j' ? LYD_JSON : LYD_XML;
|
||||||
|
FILE *f = NULL;
|
||||||
|
|
||||||
|
datastore = mgmt_ds_name2id(dsname);
|
||||||
|
|
||||||
|
if (datastore == MGMTD_DS_NONE) {
|
||||||
|
vty_out(vty,
|
||||||
|
"DS Name %s does not matches any existing datastore\n",
|
||||||
|
dsname);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
ds_ctx = mgmt_ds_get_ctx_by_id(mm, datastore);
|
||||||
|
if (!ds_ctx) {
|
||||||
|
vty_out(vty, "ERROR: Could not access datastore!\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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mgmt_ds_dump_tree(vty, ds_ctx, 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 Datastore\n"
|
||||||
|
"Read the configuration from a file\n"
|
||||||
|
"Full path of the file\n"
|
||||||
|
"Merge configuration with contents of Candidate Datastore\n"
|
||||||
|
"Replace the existing contents of Candidate datastore\n")
|
||||||
|
{
|
||||||
|
bool merge = false;
|
||||||
|
int idx_merge = 4;
|
||||||
|
int ret;
|
||||||
|
struct mgmt_ds_ctx *ds_ctx;
|
||||||
|
|
||||||
|
if (access(filepath, F_OK) == -1) {
|
||||||
|
vty_out(vty, "ERROR: File %s : %s\n", filepath,
|
||||||
|
strerror(errno));
|
||||||
|
return CMD_ERR_NO_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ds_ctx = mgmt_ds_get_ctx_by_id(mm, MGMTD_DS_CANDIDATE);
|
||||||
|
if (!ds_ctx) {
|
||||||
|
vty_out(vty, "ERROR: Could not access Candidate datastore!\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_ds_load_config_from_file(ds_ctx, 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 datastore WORD$dsname file WORD$filepath",
|
||||||
|
MGMTD_STR
|
||||||
|
"Save configuration from datastore\n"
|
||||||
|
"Datastore keyword\n"
|
||||||
|
"<candidate|running>\n"
|
||||||
|
"Write the configuration to a file\n"
|
||||||
|
"Full path of the file\n")
|
||||||
|
{
|
||||||
|
struct mgmt_ds_ctx *ds_ctx;
|
||||||
|
enum mgmt_datastore_id datastore;
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
datastore = mgmt_ds_name2id(dsname);
|
||||||
|
|
||||||
|
if (datastore == MGMTD_DS_NONE) {
|
||||||
|
vty_out(vty,
|
||||||
|
"DS Name %s does not matches any existing datastore\n",
|
||||||
|
dsname);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (datastore != MGMTD_DS_CANDIDATE && datastore != MGMTD_DS_RUNNING) {
|
||||||
|
vty_out(vty, "DS Name %s is not a configuration datastore\n",
|
||||||
|
dsname);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
ds_ctx = mgmt_ds_get_ctx_by_id(mm, datastore);
|
||||||
|
if (!ds_ctx) {
|
||||||
|
vty_out(vty, "ERROR: Could not access the '%s' datastore!\n",
|
||||||
|
dsname);
|
||||||
|
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_ds_dump_tree(vty, ds_ctx, "/", f, LYD_JSON);
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int config_write_mgmt_debug(struct vty *vty)
|
||||||
|
{
|
||||||
|
int n = mgmt_debug_be + mgmt_debug_fe + mgmt_debug_ds + mgmt_debug_txn;
|
||||||
|
if (!n)
|
||||||
|
return 0;
|
||||||
|
if (n == 4) {
|
||||||
|
vty_out(vty, "debug mgmt all\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
vty_out(vty, "debug mgmt");
|
||||||
|
if (mgmt_debug_be)
|
||||||
|
vty_out(vty, " backend");
|
||||||
|
if (mgmt_debug_ds)
|
||||||
|
vty_out(vty, " datastore");
|
||||||
|
if (mgmt_debug_fe)
|
||||||
|
vty_out(vty, " frontend");
|
||||||
|
if (mgmt_debug_txn)
|
||||||
|
vty_out(vty, " transaction");
|
||||||
|
|
||||||
|
vty_out(vty, "\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static struct cmd_node debug_node = {
|
||||||
|
.name = "debug",
|
||||||
|
.node = DEBUG_NODE,
|
||||||
|
.prompt = "",
|
||||||
|
.config_write = config_write_mgmt_debug,
|
||||||
|
};
|
||||||
|
|
||||||
|
DEFPY(debug_mgmt,
|
||||||
|
debug_mgmt_cmd,
|
||||||
|
"[no$no] debug mgmt <all$all|{backend$be|datastore$ds|frontend$fe|transaction$txn}>",
|
||||||
|
NO_STR
|
||||||
|
DEBUG_STR
|
||||||
|
MGMTD_STR
|
||||||
|
"All debug\n"
|
||||||
|
"Back-end debug\n"
|
||||||
|
"Datastore debug\n"
|
||||||
|
"Front-end debug\n"
|
||||||
|
"Transaction debug\n")
|
||||||
|
{
|
||||||
|
bool set = !no;
|
||||||
|
if (all)
|
||||||
|
be = fe = ds = txn = set ? all : NULL;
|
||||||
|
|
||||||
|
if (be)
|
||||||
|
mgmt_debug_be = set;
|
||||||
|
if (ds)
|
||||||
|
mgmt_debug_ds = set;
|
||||||
|
if (fe)
|
||||||
|
mgmt_debug_fe = set;
|
||||||
|
if (txn)
|
||||||
|
mgmt_debug_txn = set;
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mgmt_vty_init(void)
|
||||||
|
{
|
||||||
|
install_node(&debug_node);
|
||||||
|
|
||||||
|
install_element(VIEW_NODE, &show_mgmt_ds_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_cmd);
|
||||||
|
install_element(CONFIG_NODE, &debug_mgmt_cmd);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Register and handlers for auto-completion here (if any).
|
||||||
|
*/
|
||||||
|
}
|
506
mgmtd/mgmt_vty.c.safe
Normal file
506
mgmtd/mgmt_vty.c.safe
Normal file
|
@ -0,0 +1,506 @@
|
||||||
|
/*
|
||||||
|
* 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_be_server.h"
|
||||||
|
#include "mgmtd/mgmt_be_adapter.h"
|
||||||
|
#include "mgmtd/mgmt_fe_server.h"
|
||||||
|
#include "mgmtd/mgmt_fe_adapter.h"
|
||||||
|
#include "mgmtd/mgmt_ds.h"
|
||||||
|
#include "mgmtd/mgmt_history.h"
|
||||||
|
|
||||||
|
#include "mgmtd/mgmt_vty_clippy.c"
|
||||||
|
|
||||||
|
DEFPY(show_mgmt_be_adapter,
|
||||||
|
show_mgmt_be_adapter_cmd,
|
||||||
|
"show mgmt backend-adapter all",
|
||||||
|
SHOW_STR
|
||||||
|
MGMTD_STR
|
||||||
|
MGMTD_BE_ADAPTER_STR
|
||||||
|
"Display all Backend Adapters\n")
|
||||||
|
{
|
||||||
|
mgmt_be_adapter_status_write(vty);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY(show_mgmt_be_xpath_reg,
|
||||||
|
show_mgmt_be_xpath_reg_cmd,
|
||||||
|
"show mgmt backend-yang-xpath-registry",
|
||||||
|
SHOW_STR
|
||||||
|
MGMTD_STR
|
||||||
|
"Backend Adapter YANG Xpath Registry\n")
|
||||||
|
{
|
||||||
|
mgmt_be_xpath_register_write(vty);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY(show_mgmt_fe_adapter,
|
||||||
|
show_mgmt_fe_adapter_cmd,
|
||||||
|
"show mgmt frontend-adapter all",
|
||||||
|
SHOW_STR MGMTD_STR MGMTD_FE_ADAPTER_STR "Display all Frontend Adapters\n")
|
||||||
|
{
|
||||||
|
mgmt_fe_adapter_status_write(vty, false);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY(show_mgmt_fe_adapter_detail, show_mgmt_fe_adapter_detail_cmd,
|
||||||
|
"show mgmt frontend-adapter all detail",
|
||||||
|
SHOW_STR MGMTD_STR MGMTD_FE_ADAPTER_STR
|
||||||
|
"Display all Frontend Adapters\n"
|
||||||
|
"Details of commit stats\n")
|
||||||
|
{
|
||||||
|
mgmt_fe_adapter_status_write(vty, true);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY_HIDDEN(mgmt_performance_measurement,
|
||||||
|
mgmt_performance_measurement_cmd,
|
||||||
|
"[no] mgmt performance-measurement",
|
||||||
|
NO_STR
|
||||||
|
MGMTD_STR
|
||||||
|
"Enable performance measurement\n")
|
||||||
|
{
|
||||||
|
if (no)
|
||||||
|
mgmt_fe_adapter_perf_measurement(vty, false);
|
||||||
|
else
|
||||||
|
mgmt_fe_adapter_perf_measurement(vty, true);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY(mgmt_reset_performance_stats,
|
||||||
|
mgmt_reset_performance_stats_cmd,
|
||||||
|
"mgmt reset-statistics",
|
||||||
|
MGMTD_STR
|
||||||
|
"Reset the Performance measurement statistics\n")
|
||||||
|
{
|
||||||
|
mgmt_fe_adapter_reset_perf_stats(vty);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY(show_mgmt_txn,
|
||||||
|
show_mgmt_txn_cmd,
|
||||||
|
"show mgmt transaction all",
|
||||||
|
SHOW_STR
|
||||||
|
MGMTD_STR
|
||||||
|
MGMTD_TXN_STR
|
||||||
|
"Display all Transactions\n")
|
||||||
|
{
|
||||||
|
mgmt_txn_status_write(vty);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY(show_mgmt_ds,
|
||||||
|
show_mgmt_ds_cmd,
|
||||||
|
"show mgmt datastore [all|candidate|operational|running]$dsname",
|
||||||
|
SHOW_STR
|
||||||
|
MGMTD_STR
|
||||||
|
MGMTD_DS_STR
|
||||||
|
"All datastores (default)\n"
|
||||||
|
"Candidate datastore\n"
|
||||||
|
"Operational datastore\n"
|
||||||
|
"Running datastore\n")
|
||||||
|
{
|
||||||
|
struct mgmt_ds_ctx *ds_ctx;
|
||||||
|
|
||||||
|
if (!dsname || dsname[0] == 'a') {
|
||||||
|
mgmt_ds_status_write(vty);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
ds_ctx = mgmt_ds_get_ctx_by_id(mm, mgmt_ds_name2id(dsname));
|
||||||
|
if (!ds_ctx) {
|
||||||
|
vty_out(vty, "ERROR: Could not access %s datastore!\n", dsname);
|
||||||
|
return CMD_ERR_NO_MATCH;
|
||||||
|
}
|
||||||
|
mgmt_ds_status_write_one(vty, ds_ctx);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY(mgmt_commit,
|
||||||
|
mgmt_commit_cmd,
|
||||||
|
"mgmt commit <check|apply|abort>$type",
|
||||||
|
MGMTD_STR
|
||||||
|
"Commit action\n"
|
||||||
|
"Validate the set of config commands\n"
|
||||||
|
"Validate and apply the set of config commands\n"
|
||||||
|
"Abort and drop the set of config commands recently added\n")
|
||||||
|
{
|
||||||
|
bool validate_only = type[0] == 'c';
|
||||||
|
bool abort = type[1] == 'b';
|
||||||
|
|
||||||
|
if (vty_mgmt_send_commit_config(vty, validate_only, abort) != 0)
|
||||||
|
return CMD_WARNING_CONFIG_FAILED;
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY(mgmt_set_config_data, mgmt_set_config_data_cmd,
|
||||||
|
"mgmt set-config WORD$path VALUE",
|
||||||
|
MGMTD_STR
|
||||||
|
"Set configuration data\n"
|
||||||
|
"XPath expression specifying the YANG data path\n"
|
||||||
|
"Value of the data to set\n")
|
||||||
|
{
|
||||||
|
strlcpy(vty->cfg_changes[0].xpath, path,
|
||||||
|
sizeof(vty->cfg_changes[0].xpath));
|
||||||
|
vty->cfg_changes[0].value = value;
|
||||||
|
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 WORD$path",
|
||||||
|
MGMTD_STR
|
||||||
|
"Delete configuration data\n"
|
||||||
|
"XPath expression specifying the YANG data path\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 [candidate|operational|running]$dsname WORD$path",
|
||||||
|
SHOW_STR MGMTD_STR
|
||||||
|
"Get configuration data from a specific configuration datastore\n"
|
||||||
|
"Candidate datastore (default)\n"
|
||||||
|
"Operational datastore\n"
|
||||||
|
"Running datastore\n"
|
||||||
|
"XPath expression specifying the YANG data path\n")
|
||||||
|
{
|
||||||
|
const char *xpath_list[VTY_MAXCFGCHANGES] = {0};
|
||||||
|
Mgmtd__DatastoreId datastore = MGMTD_DS_CANDIDATE;
|
||||||
|
|
||||||
|
if (dsname)
|
||||||
|
datastore = mgmt_ds_name2id(dsname);
|
||||||
|
|
||||||
|
xpath_list[0] = path;
|
||||||
|
vty_mgmt_send_get_config(vty, datastore, xpath_list, 1);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY(show_mgmt_get_data, show_mgmt_get_data_cmd,
|
||||||
|
"show mgmt get-data [candidate|operational|running]$dsname WORD$path",
|
||||||
|
SHOW_STR MGMTD_STR
|
||||||
|
"Get data from a specific datastore\n"
|
||||||
|
"Candidate datastore\n"
|
||||||
|
"Operational datastore (default)\n"
|
||||||
|
"Running datastore\n"
|
||||||
|
"XPath expression specifying the YANG data path\n")
|
||||||
|
{
|
||||||
|
const char *xpath_list[VTY_MAXCFGCHANGES] = {0};
|
||||||
|
Mgmtd__DatastoreId datastore = MGMTD_DS_OPERATIONAL;
|
||||||
|
|
||||||
|
if (dsname)
|
||||||
|
datastore = mgmt_ds_name2id(dsname);
|
||||||
|
|
||||||
|
xpath_list[0] = path;
|
||||||
|
vty_mgmt_send_get_data(vty, datastore, xpath_list, 1);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY(show_mgmt_dump_data,
|
||||||
|
show_mgmt_dump_data_cmd,
|
||||||
|
"show mgmt datastore-contents [candidate|operational|running]$dsname [xpath WORD$path] [file WORD$filepath] <json|xml>$fmt",
|
||||||
|
SHOW_STR
|
||||||
|
MGMTD_STR
|
||||||
|
"Get Datastore contents from a specific datastore\n"
|
||||||
|
"Candidate datastore (default)\n"
|
||||||
|
"Operational datastore\n"
|
||||||
|
"Running datastore\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"
|
||||||
|
"json output\n"
|
||||||
|
"xml output\n")
|
||||||
|
{
|
||||||
|
struct mgmt_ds_ctx *ds_ctx;
|
||||||
|
Mgmtd__DatastoreId datastore = MGMTD_DS_CANDIDATE;
|
||||||
|
LYD_FORMAT format = fmt[0] == 'j' ? LYD_JSON : LYD_XML;
|
||||||
|
FILE *f = NULL;
|
||||||
|
|
||||||
|
if (datastore)
|
||||||
|
datastore = mgmt_ds_name2id(dsname);
|
||||||
|
|
||||||
|
ds_ctx = mgmt_ds_get_ctx_by_id(mm, datastore);
|
||||||
|
if (!ds_ctx) {
|
||||||
|
vty_out(vty, "ERROR: Could not access datastore!\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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mgmt_ds_dump_tree(vty, ds_ctx, path, f, format);
|
||||||
|
|
||||||
|
if (f)
|
||||||
|
fclose(f);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY(show_mgmt_map_xpath,
|
||||||
|
show_mgmt_map_xpath_cmd,
|
||||||
|
"show mgmt yang-xpath-subscription WORD$path",
|
||||||
|
SHOW_STR
|
||||||
|
MGMTD_STR
|
||||||
|
"Get YANG Backend Subscription\n"
|
||||||
|
"XPath expression specifying the YANG data path\n")
|
||||||
|
{
|
||||||
|
mgmt_be_xpath_subscr_info_write(vty, path);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY(mgmt_load_config,
|
||||||
|
mgmt_load_config_cmd,
|
||||||
|
"mgmt load-config WORD$filepath <merge|replace>$type",
|
||||||
|
MGMTD_STR
|
||||||
|
"Load configuration onto Candidate Datastore\n"
|
||||||
|
"Full path of the file\n"
|
||||||
|
"Merge configuration with contents of Candidate Datastore\n"
|
||||||
|
"Replace the existing contents of Candidate datastore\n")
|
||||||
|
{
|
||||||
|
bool merge = type[0] == 'm' ? true : false;
|
||||||
|
struct mgmt_ds_ctx *ds_ctx;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (access(filepath, F_OK) == -1) {
|
||||||
|
vty_out(vty, "ERROR: File %s : %s\n", filepath,
|
||||||
|
strerror(errno));
|
||||||
|
return CMD_ERR_NO_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ds_ctx = mgmt_ds_get_ctx_by_id(mm, MGMTD_DS_CANDIDATE);
|
||||||
|
if (!ds_ctx) {
|
||||||
|
vty_out(vty, "ERROR: Could not access Candidate datastore!\n");
|
||||||
|
return CMD_ERR_NO_MATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = mgmt_ds_load_config_from_file(ds_ctx, 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 <candidate|running>$dsname WORD$filepath",
|
||||||
|
MGMTD_STR
|
||||||
|
"Save configuration from datastore\n"
|
||||||
|
"Candidate datastore\n"
|
||||||
|
"Running datastore\n"
|
||||||
|
"Full path of the file\n")
|
||||||
|
{
|
||||||
|
Mgmtd__DatastoreId datastore = mgmt_ds_name2id(dsname);
|
||||||
|
struct mgmt_ds_ctx *ds_ctx;
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
ds_ctx = mgmt_ds_get_ctx_by_id(mm, datastore);
|
||||||
|
if (!ds_ctx) {
|
||||||
|
vty_out(vty, "ERROR: Could not access the '%s' datastore!\n",
|
||||||
|
dsname);
|
||||||
|
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_ds_dump_tree(vty, ds_ctx, "/", f, LYD_JSON);
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY(show_mgmt_cmt_hist,
|
||||||
|
show_mgmt_cmt_hist_cmd,
|
||||||
|
"show mgmt commit-history",
|
||||||
|
SHOW_STR
|
||||||
|
MGMTD_STR
|
||||||
|
"Show commit history\n")
|
||||||
|
{
|
||||||
|
show_mgmt_cmt_history(vty);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY(mgmt_rollback,
|
||||||
|
mgmt_rollback_cmd,
|
||||||
|
"mgmt rollback <commit-id WORD$commit | last [(1-10)]$last>",
|
||||||
|
MGMTD_STR
|
||||||
|
"Rollback commits\n"
|
||||||
|
"Rollback to commit ID\n"
|
||||||
|
"Commit-ID\n"
|
||||||
|
"Rollbak n commits\n"
|
||||||
|
"Number of commits\n")
|
||||||
|
{
|
||||||
|
if (commit)
|
||||||
|
mgmt_history_rollback_by_id(vty, commit);
|
||||||
|
else
|
||||||
|
mgmt_history_rollback_n(vty, last);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int config_write_mgmt_debug(struct vty *vty);
|
||||||
|
static struct cmd_node debug_node = {
|
||||||
|
.name = "debug",
|
||||||
|
.node = DEBUG_NODE,
|
||||||
|
.prompt = "",
|
||||||
|
.config_write = config_write_mgmt_debug,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int config_write_mgmt_debug(struct vty *vty)
|
||||||
|
{
|
||||||
|
int n = mgmt_debug_be + mgmt_debug_fe + mgmt_debug_ds + mgmt_debug_txn;
|
||||||
|
if (!n)
|
||||||
|
return 0;
|
||||||
|
if (n == 4) {
|
||||||
|
vty_out(vty, "debug mgmt all\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
vty_out(vty, "debug mgmt");
|
||||||
|
if (mgmt_debug_be)
|
||||||
|
vty_out(vty, " backend");
|
||||||
|
if (mgmt_debug_ds)
|
||||||
|
vty_out(vty, " datastore");
|
||||||
|
if (mgmt_debug_fe)
|
||||||
|
vty_out(vty, " frontend");
|
||||||
|
if (mgmt_debug_txn)
|
||||||
|
vty_out(vty, " transaction");
|
||||||
|
|
||||||
|
vty_out(vty, "\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY(debug_mgmt,
|
||||||
|
debug_mgmt_cmd,
|
||||||
|
"[no$no] debug mgmt <all$all|{backend$be|datastore$ds|frontend$fe|transaction$txn}>",
|
||||||
|
NO_STR
|
||||||
|
DEBUG_STR
|
||||||
|
MGMTD_STR
|
||||||
|
"All debug\n"
|
||||||
|
"Back-end debug\n"
|
||||||
|
"Datastore debug\n"
|
||||||
|
"Front-end debug\n"
|
||||||
|
"Transaction debug\n")
|
||||||
|
{
|
||||||
|
bool set = !no;
|
||||||
|
if (all)
|
||||||
|
be = fe = ds = txn = set ? all : NULL;
|
||||||
|
|
||||||
|
if (be)
|
||||||
|
mgmt_debug_be = set;
|
||||||
|
if (ds)
|
||||||
|
mgmt_debug_ds = set;
|
||||||
|
if (fe)
|
||||||
|
mgmt_debug_fe = set;
|
||||||
|
if (txn)
|
||||||
|
mgmt_debug_txn = set;
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mgmt_vty_init(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Initialize command handling from VTYSH connection.
|
||||||
|
* Call command initialization routines defined by
|
||||||
|
* backend components that are moved to new MGMTD infra
|
||||||
|
* here one by one.
|
||||||
|
*/
|
||||||
|
#if HAVE_STATICD
|
||||||
|
extern void static_vty_init(void);
|
||||||
|
static_vty_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
install_node(&debug_node);
|
||||||
|
|
||||||
|
install_element(VIEW_NODE, &show_mgmt_be_adapter_cmd);
|
||||||
|
install_element(VIEW_NODE, &show_mgmt_be_xpath_reg_cmd);
|
||||||
|
install_element(VIEW_NODE, &show_mgmt_fe_adapter_cmd);
|
||||||
|
install_element(VIEW_NODE, &show_mgmt_fe_adapter_detail_cmd);
|
||||||
|
install_element(VIEW_NODE, &show_mgmt_txn_cmd);
|
||||||
|
install_element(VIEW_NODE, &show_mgmt_ds_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(VIEW_NODE, &show_mgmt_map_xpath_cmd);
|
||||||
|
install_element(VIEW_NODE, &show_mgmt_cmt_hist_cmd);
|
||||||
|
|
||||||
|
install_element(CONFIG_NODE, &mgmt_commit_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);
|
||||||
|
install_element(CONFIG_NODE, &mgmt_rollback_cmd);
|
||||||
|
|
||||||
|
install_element(VIEW_NODE, &debug_mgmt_cmd);
|
||||||
|
install_element(CONFIG_NODE, &debug_mgmt_cmd);
|
||||||
|
|
||||||
|
/* Enable view */
|
||||||
|
install_element(ENABLE_NODE, &mgmt_performance_measurement_cmd);
|
||||||
|
install_element(ENABLE_NODE, &mgmt_reset_performance_stats_cmd);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Register and handlers for auto-completion here.
|
||||||
|
*/
|
||||||
|
}
|
42
mgmtd/subdir.am
Normal file
42
mgmtd/subdir.am
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#
|
||||||
|
# mgmtd -- Mangagement Daemon
|
||||||
|
#
|
||||||
|
|
||||||
|
# dist_examples_DATA += \
|
||||||
|
# end
|
||||||
|
|
||||||
|
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_ds.c \
|
||||||
|
mgmtd/mgmt_memory.c \
|
||||||
|
mgmtd/mgmt_vty.c \
|
||||||
|
# end
|
||||||
|
|
||||||
|
mgmtdheaderdir = $(pkgincludedir)/mgmtd
|
||||||
|
mgmtdheader_HEADERS = \
|
||||||
|
mgmtd/mgmt_defines.h \
|
||||||
|
# end
|
||||||
|
|
||||||
|
noinst_HEADERS += \
|
||||||
|
mgmtd/mgmt.h \
|
||||||
|
mgmtd/mgmt_ds.h \
|
||||||
|
mgmtd/mgmt_memory.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)
|
44
pkgsrc/mgmtd.sh.in
Normal file
44
pkgsrc/mgmtd.sh.in
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#!/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"
|
|
@ -29,23 +29,3 @@ CLEANFILES += \
|
||||||
# end
|
# end
|
||||||
|
|
||||||
EXTRA_DIST += qpb/qpb.proto
|
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
|
|
||||||
|
|
|
@ -667,6 +667,7 @@ fi
|
||||||
%{_sbindir}/ospfd
|
%{_sbindir}/ospfd
|
||||||
%{_sbindir}/ripd
|
%{_sbindir}/ripd
|
||||||
%{_sbindir}/bgpd
|
%{_sbindir}/bgpd
|
||||||
|
%{_sbindir}/mgmtd
|
||||||
%exclude %{_sbindir}/ssd
|
%exclude %{_sbindir}/ssd
|
||||||
%if %{with_watchfrr}
|
%if %{with_watchfrr}
|
||||||
%{_sbindir}/watchfrr
|
%{_sbindir}/watchfrr
|
||||||
|
@ -716,6 +717,9 @@ fi
|
||||||
%{_libdir}/frr/modules/dplane_fpm_nl.so
|
%{_libdir}/frr/modules/dplane_fpm_nl.so
|
||||||
%{_libdir}/frr/modules/zebra_irdp.so
|
%{_libdir}/frr/modules/zebra_irdp.so
|
||||||
%{_libdir}/frr/modules/bgpd_bmp.so
|
%{_libdir}/frr/modules/bgpd_bmp.so
|
||||||
|
%{_libdir}/libfrr_pb.so*
|
||||||
|
%{_libdir}/libfrrfpm_pb.so*
|
||||||
|
%{_libdir}/libmgmt_be_nb.so*
|
||||||
%{_bindir}/*
|
%{_bindir}/*
|
||||||
%config(noreplace) %{configdir}/[!v]*.conf*
|
%config(noreplace) %{configdir}/[!v]*.conf*
|
||||||
%config(noreplace) %attr(750,%{frr_user},%{frr_user}) %{configdir}/daemons
|
%config(noreplace) %attr(750,%{frr_user},%{frr_user}) %{configdir}/daemons
|
||||||
|
@ -775,6 +779,8 @@ sed -i 's/ -M rpki//' %{_sysconfdir}/frr/daemons
|
||||||
%{_libdir}/lib*.so
|
%{_libdir}/lib*.so
|
||||||
%dir %{_includedir}/%{name}
|
%dir %{_includedir}/%{name}
|
||||||
%{_includedir}/%{name}/*.h
|
%{_includedir}/%{name}/*.h
|
||||||
|
%dir %{_includedir}/%{name}/mgmtd
|
||||||
|
%{_includedir}/%{name}/mgmtd/*.h
|
||||||
%dir %{_includedir}/%{name}/ospfd
|
%dir %{_includedir}/%{name}/ospfd
|
||||||
%{_includedir}/%{name}/ospfd/*.h
|
%{_includedir}/%{name}/ospfd/*.h
|
||||||
%if %{with_bfdd}
|
%if %{with_bfdd}
|
||||||
|
|
|
@ -40,6 +40,7 @@ pathd=no
|
||||||
#
|
#
|
||||||
vtysh_enable=yes
|
vtysh_enable=yes
|
||||||
zebra_options=" -A 127.0.0.1 -s 90000000"
|
zebra_options=" -A 127.0.0.1 -s 90000000"
|
||||||
|
mgmtd_options=" -A 127.0.0.1"
|
||||||
bgpd_options=" -A 127.0.0.1"
|
bgpd_options=" -A 127.0.0.1"
|
||||||
ospfd_options=" -A 127.0.0.1"
|
ospfd_options=" -A 127.0.0.1"
|
||||||
ospf6d_options=" -A ::1"
|
ospf6d_options=" -A ::1"
|
||||||
|
|
|
@ -27,7 +27,7 @@ FRR_DEFAULT_PROFILE="@DFLT_NAME@" # traditional / datacenter
|
||||||
# Local Daemon selection may be done by using /etc/frr/daemons.
|
# Local Daemon selection may be done by using /etc/frr/daemons.
|
||||||
# See /usr/share/doc/frr/README.Debian.gz for further information.
|
# See /usr/share/doc/frr/README.Debian.gz for further information.
|
||||||
# Keep zebra first and do not list watchfrr!
|
# Keep zebra first and do not list watchfrr!
|
||||||
DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd pim6d ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd vrrpd pathd"
|
DAEMONS="mgmtd zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd pim6d ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd vrrpd pathd"
|
||||||
MAX_INSTANCES=5
|
MAX_INSTANCES=5
|
||||||
RELOAD_SCRIPT="$D_PATH/frr-reload.py"
|
RELOAD_SCRIPT="$D_PATH/frr-reload.py"
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ FRR_DEFAULT_PROFILE="@DFLT_NAME@" # traditional / datacenter
|
||||||
# - keep zebra first
|
# - keep zebra first
|
||||||
# - watchfrr does NOT belong in this list
|
# - watchfrr does NOT belong in this list
|
||||||
|
|
||||||
DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd pim6d ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd vrrpd pathd"
|
DAEMONS="zebra mgmtd bgpd ripd ripngd ospfd ospf6d isisd babeld pimd pim6d ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd vrrpd pathd"
|
||||||
RELOAD_SCRIPT="$D_PATH/frr-reload.py"
|
RELOAD_SCRIPT="$D_PATH/frr-reload.py"
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -99,7 +99,7 @@ daemon_list() {
|
||||||
for daemon in $DAEMONS; do
|
for daemon in $DAEMONS; do
|
||||||
eval cfg=\$$daemon
|
eval cfg=\$$daemon
|
||||||
eval inst=\$${daemon}_instances
|
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 [ -n "$cfg" -a "$cfg" != "no" -a "$cfg" != "0" ]; then
|
||||||
if ! daemon_prep "$daemon" "$inst"; then
|
if ! daemon_prep "$daemon" "$inst"; then
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -120,6 +120,7 @@ static void vtysh_pager_envdef(bool fallback)
|
||||||
/* --- */
|
/* --- */
|
||||||
|
|
||||||
struct vtysh_client vtysh_client[] = {
|
struct vtysh_client vtysh_client[] = {
|
||||||
|
{.name = "mgmtd", .flag = VTYSH_MGMTD},
|
||||||
{.name = "zebra", .flag = VTYSH_ZEBRA},
|
{.name = "zebra", .flag = VTYSH_ZEBRA},
|
||||||
{.name = "ripd", .flag = VTYSH_RIPD},
|
{.name = "ripd", .flag = VTYSH_RIPD},
|
||||||
{.name = "ripngd", .flag = VTYSH_RIPNGD},
|
{.name = "ripngd", .flag = VTYSH_RIPNGD},
|
||||||
|
|
|
@ -34,6 +34,7 @@ extern struct thread_master *master;
|
||||||
#define VTYSH_VRRPD 0x40000
|
#define VTYSH_VRRPD 0x40000
|
||||||
#define VTYSH_PATHD 0x80000
|
#define VTYSH_PATHD 0x80000
|
||||||
#define VTYSH_PIM6D 0x100000
|
#define VTYSH_PIM6D 0x100000
|
||||||
|
#define VTYSH_MGMTD 0x200000
|
||||||
|
|
||||||
#define VTYSH_WAS_ACTIVE (-2)
|
#define VTYSH_WAS_ACTIVE (-2)
|
||||||
|
|
||||||
|
@ -42,7 +43,12 @@ extern struct thread_master *master;
|
||||||
/* watchfrr is not in ALL since library CLI functions should not be
|
/* 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
|
* run on it (logging & co. should stay in a fixed/frozen config, and
|
||||||
* things like prefix lists are not even initialised) */
|
* 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_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_AFFMAP VTYSH_ZEBRA | VTYSH_ISISD
|
#define VTYSH_AFFMAP VTYSH_ZEBRA | VTYSH_ISISD
|
||||||
#define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_FABRICD
|
#define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_FABRICD
|
||||||
|
@ -52,7 +58,7 @@ extern struct thread_master *master;
|
||||||
VTYSH_EIGRPD | VTYSH_BABELD | VTYSH_PBRD | VTYSH_FABRICD | \
|
VTYSH_EIGRPD | VTYSH_BABELD | VTYSH_PBRD | VTYSH_FABRICD | \
|
||||||
VTYSH_VRRPD
|
VTYSH_VRRPD
|
||||||
#define VTYSH_INTERFACE VTYSH_INTERFACE_SUBSET | VTYSH_BGPD
|
#define VTYSH_INTERFACE VTYSH_INTERFACE_SUBSET | VTYSH_BGPD
|
||||||
#define VTYSH_VRF VTYSH_INTERFACE_SUBSET | VTYSH_STATICD
|
#define VTYSH_VRF VTYSH_INTERFACE_SUBSET | VTYSH_STATICD | VTYSH_MGMTD
|
||||||
#define VTYSH_KEYS VTYSH_RIPD | VTYSH_EIGRPD | VTYSH_OSPF6D
|
#define VTYSH_KEYS VTYSH_RIPD | VTYSH_EIGRPD | VTYSH_OSPF6D
|
||||||
/* Daemons who can process nexthop-group configs */
|
/* Daemons who can process nexthop-group configs */
|
||||||
#define VTYSH_NH_GROUP VTYSH_PBRD|VTYSH_SHARPD
|
#define VTYSH_NH_GROUP VTYSH_PBRD|VTYSH_SHARPD
|
||||||
|
|
Loading…
Reference in a new issue