mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-04-28 15:36:25 +00:00
mgmtd: Add MGMT Frontend Interface Framework
This commit introduces the Frontend Interface which can be used by front-end management clients like Netconf server, Restconf Server and CLI to interact with new FRR Management daemon (MGMTd) to access and sometimes modify FRR management data. This commit includes the following functionalities in the changeset: 1. Add new Frontend server for clients connect to. 2. Add a C-based Frontend client library which can be used by Frontend clients to communicate with MGMTd via the Frontend interface. 3. Maintain a frontend adapter for each connection from an appropriate Frontend client to facilitate client requests and track one or more client sessions across it. 4. Define the protobuf message format for messages to be exchanged between MGMTd Frontend module and the Frontend client. 5. This changeset also introduces an instance of MGMT Frontend client embedded within the lib/vty module that can be leveraged by any FRR daemon to connect to MGMTd's Frontend interface. The same has been integrated with and initialized within the MGMTd daemon's process context to implement a bunch of 'set-config', 'commit-apply', 'get-config' and 'get-data' commands via VTYSH Co-authored-by: Pushpasis Sarkar <pushpasis@gmail.com> Co-authored-by: Abhinay Ramesh <rabhinay@vmware.com> Co-authored-by: Ujwal P <ujwalp@vmware.com> Signed-off-by: Yash Ranjan <ranjany@vmware.com>
This commit is contained in:
parent
1c84efe4fa
commit
ef43a6329b
@ -76,3 +76,8 @@ ForEachMacros:
|
||||
- FOREACH_SAFI
|
||||
# ospfd
|
||||
- LSDB_LOOP
|
||||
# mgmtd
|
||||
- FOREACH_MGMTD_DB_ID
|
||||
- FOREACH_ADAPTER_IN_LIST
|
||||
- FOREACH_SESSION_IN_LIST
|
||||
- FOREACH_SESSION_IN_LIST_SAFE
|
||||
|
@ -243,6 +243,9 @@ DEFUN_NOSH(end_config, end_config_cmd, "XFRR_end_configuration",
|
||||
|
||||
zlog_info("Configuration Read in Took: %s", readin_time_str);
|
||||
|
||||
if (vty_mgmt_fe_enabled())
|
||||
vty_mgmt_send_commit_config(vty, false, false);
|
||||
|
||||
if (callback.end_config)
|
||||
(*callback.end_config)();
|
||||
|
||||
|
345
lib/mgmt.proto
Normal file
345
lib/mgmt.proto
Normal file
@ -0,0 +1,345 @@
|
||||
// SPDX-License-Identifier: ISC
|
||||
//
|
||||
// mgmt.proto
|
||||
//
|
||||
// @copyright Copyright (C) 2021 Vmware, Inc.
|
||||
//
|
||||
// @author Pushpasis Sarkar <spushpasis@vmware.com>
|
||||
//
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
//
|
||||
// Protobuf definitions pertaining to the MGMTD component.
|
||||
//
|
||||
|
||||
package mgmtd;
|
||||
|
||||
//
|
||||
// Common Sub-Messages
|
||||
//
|
||||
|
||||
message YangDataXPath {
|
||||
required string xpath = 1;
|
||||
}
|
||||
|
||||
message YangDataValue {
|
||||
oneof value {
|
||||
//
|
||||
// NOTE: For now let's use stringized value ONLY.
|
||||
// We will enhance it later to pass native-format
|
||||
// if needed.
|
||||
//
|
||||
// bool bool_val = 2;
|
||||
// double double_val = 3;
|
||||
// float float_val = 4;
|
||||
// string string_val = 5;
|
||||
// bytes bytes_val = 6;
|
||||
// int32 int32_val = 7;
|
||||
// int64 int64_val = 8;
|
||||
// uint32 uint32_val = 9;
|
||||
// uint64 uint64_val = 10;
|
||||
// int32 int8_val = 11;
|
||||
// uint32 uint8_val = 12;
|
||||
// int32 int16_val = 13;
|
||||
// uint32 uint16_val = 14;
|
||||
string encoded_str_val = 100;
|
||||
}
|
||||
}
|
||||
|
||||
message YangData {
|
||||
required string xpath = 1;
|
||||
optional YangDataValue value = 2;
|
||||
}
|
||||
|
||||
enum CfgDataReqType {
|
||||
REQ_TYPE_NONE = 0;
|
||||
SET_DATA = 1;
|
||||
DELETE_DATA = 2;
|
||||
}
|
||||
|
||||
message YangCfgDataReq {
|
||||
required YangData data = 1;
|
||||
required CfgDataReqType req_type = 2;
|
||||
}
|
||||
|
||||
message YangGetDataReq {
|
||||
required YangData data = 1;
|
||||
required int64 next_indx = 2;
|
||||
}
|
||||
|
||||
//
|
||||
// Backend Interface Messages
|
||||
//
|
||||
message BeSubscribeReq {
|
||||
required string client_name = 1;
|
||||
required bool subscribe_xpaths = 2;
|
||||
repeated string xpath_reg = 3;
|
||||
}
|
||||
|
||||
message BeSubscribeReply {
|
||||
required bool success = 1;
|
||||
}
|
||||
|
||||
message BeTxnReq {
|
||||
required uint64 txn_id = 1;
|
||||
required bool create = 2;
|
||||
}
|
||||
|
||||
message BeTxnReply {
|
||||
required uint64 txn_id = 1;
|
||||
required bool create = 2;
|
||||
required bool success = 3;
|
||||
}
|
||||
|
||||
message BeCfgDataCreateReq {
|
||||
required uint64 txn_id = 1;
|
||||
required uint64 batch_id = 2;
|
||||
repeated YangCfgDataReq data_req = 3;
|
||||
required bool end_of_data = 4;
|
||||
}
|
||||
|
||||
message BeCfgDataCreateReply {
|
||||
required uint64 txn_id = 1;
|
||||
required uint64 batch_id = 2;
|
||||
required bool success = 3;
|
||||
optional string error_if_any = 4;
|
||||
}
|
||||
|
||||
message BeCfgDataValidateReq {
|
||||
required uint64 txn_id = 1;
|
||||
repeated uint64 batch_ids = 2;
|
||||
}
|
||||
|
||||
message BeCfgDataValidateReply {
|
||||
required uint64 txn_id = 1;
|
||||
repeated uint64 batch_ids = 2;
|
||||
required bool success = 3;
|
||||
optional string error_if_any = 4;
|
||||
}
|
||||
|
||||
message BeCfgDataApplyReq {
|
||||
required uint64 txn_id = 1;
|
||||
}
|
||||
|
||||
message BeCfgDataApplyReply {
|
||||
required uint64 txn_id = 1;
|
||||
repeated uint64 batch_ids = 2;
|
||||
required bool success = 3;
|
||||
optional string error_if_any = 4;
|
||||
}
|
||||
|
||||
message BeOperDataGetReq {
|
||||
required uint64 txn_id = 1;
|
||||
required uint64 batch_id = 2;
|
||||
repeated YangGetDataReq data = 3;
|
||||
}
|
||||
|
||||
message YangDataReply {
|
||||
repeated YangData data = 1;
|
||||
required int64 next_indx = 2;
|
||||
}
|
||||
|
||||
message BeOperDataGetReply {
|
||||
required uint64 txn_id = 1;
|
||||
required uint64 batch_id = 2;
|
||||
required bool success = 3;
|
||||
optional string error = 4;
|
||||
optional YangDataReply data = 5;
|
||||
}
|
||||
|
||||
message BeOperDataNotify {
|
||||
required YangDataReply data = 5;
|
||||
}
|
||||
|
||||
message BeConfigCmdReq {
|
||||
required string cmd = 1;
|
||||
}
|
||||
|
||||
message BeConfigCmdReply {
|
||||
required bool success = 1;
|
||||
required string error_if_any = 2;
|
||||
}
|
||||
|
||||
message BeShowCmdReq {
|
||||
required string cmd = 1;
|
||||
}
|
||||
|
||||
message BeShowCmdReply {
|
||||
required bool success = 1;
|
||||
required string cmd_ouput = 2;
|
||||
}
|
||||
|
||||
//
|
||||
// Any message on the MGMTD Backend Interface.
|
||||
//
|
||||
message BeMessage {
|
||||
oneof message {
|
||||
BeSubscribeReq subscr_req = 2;
|
||||
BeSubscribeReply subscr_reply = 3;
|
||||
BeTxnReq txn_req = 4;
|
||||
BeTxnReply txn_reply = 5;
|
||||
BeCfgDataCreateReq cfg_data_req = 6;
|
||||
BeCfgDataCreateReply cfg_data_reply = 7;
|
||||
BeCfgDataValidateReq cfg_validate_req = 8;
|
||||
BeCfgDataValidateReply cfg_validate_reply = 9;
|
||||
BeCfgDataApplyReq cfg_apply_req = 10;
|
||||
BeCfgDataApplyReply cfg_apply_reply = 11;
|
||||
BeOperDataGetReq get_req = 12;
|
||||
BeOperDataGetReply get_reply = 13;
|
||||
BeOperDataNotify notify_data = 14;
|
||||
BeConfigCmdReq cfg_cmd_req = 15;
|
||||
BeConfigCmdReply cfg_cmd_reply = 16;
|
||||
BeShowCmdReq show_cmd_req = 17;
|
||||
BeShowCmdReply show_cmd_reply = 18;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Frontend Interface Messages
|
||||
//
|
||||
|
||||
message FeRegisterReq {
|
||||
required string client_name = 1;
|
||||
}
|
||||
|
||||
message FeSessionReq {
|
||||
required bool create = 1;
|
||||
oneof id {
|
||||
uint64 client_conn_id = 2; // Applicable for create request only
|
||||
uint64 session_id = 3; // Applicable for delete request only
|
||||
}
|
||||
}
|
||||
|
||||
message FeSessionReply {
|
||||
required bool create = 1;
|
||||
required bool success = 2;
|
||||
optional uint64 client_conn_id = 3; // Applicable for create request only
|
||||
required uint64 session_id = 4;
|
||||
}
|
||||
|
||||
enum DatastoreId {
|
||||
DS_NONE = 0;
|
||||
RUNNING_DS = 1;
|
||||
CANDIDATE_DS = 2;
|
||||
OPERATIONAL_DS = 3;
|
||||
STARTUP_DS = 4;
|
||||
}
|
||||
|
||||
message FeLockDsReq {
|
||||
required uint64 session_id = 1;
|
||||
required uint64 req_id = 2;
|
||||
required DatastoreId ds_id = 3;
|
||||
required bool lock = 4;
|
||||
}
|
||||
|
||||
message FeLockDsReply {
|
||||
required uint64 session_id = 1;
|
||||
required uint64 req_id = 2;
|
||||
required DatastoreId ds_id = 3;
|
||||
required bool lock = 4;
|
||||
required bool success = 5;
|
||||
optional string error_if_any = 6;
|
||||
}
|
||||
|
||||
message FeSetConfigReq {
|
||||
required uint64 session_id = 1;
|
||||
required DatastoreId ds_id = 2;
|
||||
required uint64 req_id = 3;
|
||||
repeated YangCfgDataReq data = 4;
|
||||
required bool implicit_commit = 5;
|
||||
required DatastoreId commit_ds_id = 6;
|
||||
}
|
||||
|
||||
message FeSetConfigReply {
|
||||
required uint64 session_id = 1;
|
||||
required DatastoreId ds_id = 2;
|
||||
required uint64 req_id = 3;
|
||||
required bool success = 4;
|
||||
optional string error_if_any = 5;
|
||||
}
|
||||
|
||||
message FeCommitConfigReq {
|
||||
required uint64 session_id = 1;
|
||||
required DatastoreId src_ds_id = 2;
|
||||
required DatastoreId dst_ds_id = 3;
|
||||
required uint64 req_id = 4;
|
||||
required bool validate_only = 5;
|
||||
required bool abort = 6;
|
||||
}
|
||||
|
||||
message FeCommitConfigReply {
|
||||
required uint64 session_id = 1;
|
||||
required DatastoreId src_ds_id = 2;
|
||||
required DatastoreId dst_ds_id = 3;
|
||||
required uint64 req_id = 4;
|
||||
required bool validate_only = 5;
|
||||
required bool success = 6;
|
||||
required bool abort = 7;
|
||||
optional string error_if_any = 8;
|
||||
}
|
||||
|
||||
message FeGetConfigReq {
|
||||
required uint64 session_id = 1;
|
||||
required DatastoreId ds_id = 2;
|
||||
required uint64 req_id = 3;
|
||||
repeated YangGetDataReq data = 4;
|
||||
}
|
||||
|
||||
message FeGetConfigReply {
|
||||
required uint64 session_id = 1;
|
||||
required DatastoreId ds_id = 2;
|
||||
required uint64 req_id = 3;
|
||||
required bool success = 4;
|
||||
optional string error_if_any = 5;
|
||||
optional YangDataReply data = 6;
|
||||
}
|
||||
|
||||
message FeGetDataReq {
|
||||
required uint64 session_id = 1;
|
||||
required DatastoreId ds_id = 2;
|
||||
required uint64 req_id = 3;
|
||||
repeated YangGetDataReq data = 4;
|
||||
}
|
||||
|
||||
message FeGetDataReply {
|
||||
required uint64 session_id = 1;
|
||||
required DatastoreId ds_id = 2;
|
||||
required uint64 req_id = 3;
|
||||
required bool success = 4;
|
||||
optional string error_if_any = 5;
|
||||
optional YangDataReply data = 6;
|
||||
}
|
||||
|
||||
message FeNotifyDataReq {
|
||||
repeated YangData data = 1;
|
||||
}
|
||||
|
||||
message FeRegisterNotifyReq {
|
||||
required uint64 session_id = 1;
|
||||
required DatastoreId ds_id = 2;
|
||||
required bool register_req = 3;
|
||||
required uint64 req_id = 4;
|
||||
repeated YangDataXPath data_xpath = 5;
|
||||
}
|
||||
|
||||
message FeMessage {
|
||||
oneof message {
|
||||
FeRegisterReq register_req = 2;
|
||||
FeSessionReq session_req = 3;
|
||||
FeSessionReply session_reply = 4;
|
||||
FeLockDsReq lockds_req = 5;
|
||||
FeLockDsReply lockds_reply = 6;
|
||||
FeSetConfigReq setcfg_req = 7;
|
||||
FeSetConfigReply setcfg_reply = 8;
|
||||
FeCommitConfigReq commcfg_req = 9;
|
||||
FeCommitConfigReply commcfg_reply = 10;
|
||||
FeGetConfigReq getcfg_req = 11;
|
||||
FeGetConfigReply getcfg_reply = 12;
|
||||
FeGetDataReq getdata_req = 13;
|
||||
FeGetDataReply getdata_reply = 14;
|
||||
FeNotifyDataReq notify_data_req = 15;
|
||||
FeRegisterNotifyReq regnotify_req = 16;
|
||||
}
|
||||
}
|
1340
lib/mgmt_fe_client.c
Normal file
1340
lib/mgmt_fe_client.c
Normal file
File diff suppressed because it is too large
Load Diff
358
lib/mgmt_fe_client.h
Normal file
358
lib/mgmt_fe_client.h
Normal file
@ -0,0 +1,358 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* MGMTD Frontend Client Library api interfaces
|
||||
* Copyright (C) 2021 Vmware, Inc.
|
||||
* Pushpasis Sarkar <spushpasis@vmware.com>
|
||||
*/
|
||||
|
||||
#ifndef _FRR_MGMTD_FE_CLIENT_H_
|
||||
#define _FRR_MGMTD_FE_CLIENT_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "mgmtd/mgmt_defines.h"
|
||||
#include "mgmt_pb.h"
|
||||
|
||||
/***************************************************************
|
||||
* Macros
|
||||
***************************************************************/
|
||||
|
||||
/*
|
||||
* The server port MGMTD daemon is listening for Backend Client
|
||||
* connections.
|
||||
*/
|
||||
|
||||
#define MGMTD_FE_CLIENT_ERROR_STRING_MAX_LEN 32
|
||||
|
||||
#define MGMTD_FE_DEFAULT_CONN_RETRY_INTVL_SEC 5
|
||||
|
||||
#define MGMTD_FE_MSG_PROC_DELAY_USEC 10
|
||||
#define MGMTD_FE_MAX_NUM_MSG_PROC 500
|
||||
|
||||
#define MGMTD_FE_MSG_WRITE_DELAY_MSEC 1
|
||||
#define MGMTD_FE_MAX_NUM_MSG_WRITE 100
|
||||
|
||||
#define GMGD_FE_MAX_NUM_REQ_ITEMS 64
|
||||
|
||||
#define MGMTD_FE_MSG_MAX_LEN 9000
|
||||
|
||||
#define MGMTD_SOCKET_FE_SEND_BUF_SIZE 65535
|
||||
#define MGMTD_SOCKET_FE_RECV_BUF_SIZE MGMTD_SOCKET_FE_SEND_BUF_SIZE
|
||||
|
||||
/***************************************************************
|
||||
* Data-structures
|
||||
***************************************************************/
|
||||
|
||||
#define MGMTD_SESSION_ID_NONE 0
|
||||
|
||||
#define MGMTD_CLIENT_ID_NONE 0
|
||||
|
||||
#define MGMTD_DS_NONE MGMTD__DATASTORE_ID__DS_NONE
|
||||
#define MGMTD_DS_RUNNING MGMTD__DATASTORE_ID__RUNNING_DS
|
||||
#define MGMTD_DS_CANDIDATE MGMTD__DATASTORE_ID__CANDIDATE_DS
|
||||
#define MGMTD_DS_OPERATIONAL MGMTD__DATASTORE_ID__OPERATIONAL_DS
|
||||
#define MGMTD_DS_MAX_ID MGMTD_DS_OPERATIONAL + 1
|
||||
|
||||
struct mgmt_fe_msg_hdr {
|
||||
uint16_t marker;
|
||||
uint16_t len; /* Includes header */
|
||||
};
|
||||
#define MGMTD_FE_MSG_HDR_LEN sizeof(struct mgmt_fe_msg_hdr)
|
||||
#define MGMTD_FE_MSG_MARKER 0xdeaf
|
||||
|
||||
struct mgmt_fe_msg {
|
||||
struct mgmt_fe_msg_hdr hdr;
|
||||
uint8_t payload[];
|
||||
};
|
||||
|
||||
/*
|
||||
* All the client specific information this library needs to
|
||||
* initialize itself, setup connection with MGMTD FrontEnd interface
|
||||
* and carry on all required procedures appropriately.
|
||||
*
|
||||
* FrontEnd clients need to initialise a instance of this structure
|
||||
* with appropriate data and pass it while calling the API
|
||||
* to initialize the library (See mgmt_fe_client_lib_init for
|
||||
* more details).
|
||||
*/
|
||||
struct mgmt_fe_client_params {
|
||||
char name[MGMTD_CLIENT_NAME_MAX_LEN];
|
||||
uintptr_t user_data;
|
||||
unsigned long conn_retry_intvl_sec;
|
||||
|
||||
void (*client_connect_notify)(uintptr_t lib_hndl,
|
||||
uintptr_t user_data,
|
||||
bool connected);
|
||||
|
||||
void (*client_session_notify)(uintptr_t lib_hndl,
|
||||
uintptr_t user_data,
|
||||
uint64_t client_id,
|
||||
bool create, bool success,
|
||||
uintptr_t session_id,
|
||||
uintptr_t user_session_ctx);
|
||||
|
||||
void (*lock_ds_notify)(uintptr_t lib_hndl, uintptr_t user_data,
|
||||
uint64_t client_id, uintptr_t session_id,
|
||||
uintptr_t user_session_ctx, uint64_t req_id,
|
||||
bool lock_ds, bool success,
|
||||
Mgmtd__DatastoreId ds_id, char *errmsg_if_any);
|
||||
|
||||
void (*set_config_notify)(uintptr_t lib_hndl, uintptr_t user_data,
|
||||
uint64_t client_id, uintptr_t session_id,
|
||||
uintptr_t user_session_ctx, uint64_t req_id,
|
||||
bool success, Mgmtd__DatastoreId ds_id,
|
||||
char *errmsg_if_any);
|
||||
|
||||
void (*commit_config_notify)(
|
||||
uintptr_t lib_hndl, uintptr_t user_data, uint64_t client_id,
|
||||
uintptr_t session_id, uintptr_t user_session_ctx,
|
||||
uint64_t req_id, bool success, Mgmtd__DatastoreId src_ds_id,
|
||||
Mgmtd__DatastoreId dst_ds_id, bool validate_only,
|
||||
char *errmsg_if_any);
|
||||
|
||||
enum mgmt_result (*get_data_notify)(
|
||||
uintptr_t lib_hndl, uintptr_t user_data, uint64_t client_id,
|
||||
uintptr_t session_id, uintptr_t user_session_ctx,
|
||||
uint64_t req_id, bool success, Mgmtd__DatastoreId ds_id,
|
||||
Mgmtd__YangData **yang_data, size_t num_data, int next_key,
|
||||
char *errmsg_if_any);
|
||||
|
||||
enum mgmt_result (*data_notify)(
|
||||
uint64_t client_id, uint64_t session_id, uintptr_t user_data,
|
||||
uint64_t req_id, Mgmtd__DatastoreId ds_id,
|
||||
Mgmtd__YangData **yang_data, size_t num_data);
|
||||
};
|
||||
|
||||
/***************************************************************
|
||||
* API prototypes
|
||||
***************************************************************/
|
||||
|
||||
/*
|
||||
* Initialize library and try connecting with MGMTD FrontEnd interface.
|
||||
*
|
||||
* params
|
||||
* Frontend client parameters.
|
||||
*
|
||||
* master_thread
|
||||
* Thread master.
|
||||
*
|
||||
* Returns:
|
||||
* Frontend client lib handler (nothing but address of mgmt_fe_client_ctx)
|
||||
*/
|
||||
extern uintptr_t
|
||||
mgmt_fe_client_lib_init(struct mgmt_fe_client_params *params,
|
||||
struct thread_master *master_thread);
|
||||
|
||||
/*
|
||||
* Create a new Session for a Frontend Client connection.
|
||||
*
|
||||
* lib_hndl
|
||||
* Client library handler.
|
||||
*
|
||||
* client_id
|
||||
* Unique identifier of client.
|
||||
*
|
||||
* user_ctx
|
||||
* Client context.
|
||||
*
|
||||
* Returns:
|
||||
* MGMTD_SUCCESS on success, MGMTD_* otherwise.
|
||||
*/
|
||||
extern enum mgmt_result mgmt_fe_create_client_session(uintptr_t lib_hndl,
|
||||
uint64_t client_id,
|
||||
uintptr_t user_ctx);
|
||||
|
||||
/*
|
||||
* Delete an existing Session for a Frontend Client connection.
|
||||
*
|
||||
* lib_hndl
|
||||
* Client library handler.
|
||||
*
|
||||
* client_id
|
||||
* Unique identifier of client.
|
||||
*
|
||||
* Returns:
|
||||
* MGMTD_SUCCESS on success, MGMTD_* otherwise.
|
||||
*/
|
||||
extern enum mgmt_result mgmt_fe_destroy_client_session(uintptr_t lib_hndl,
|
||||
uint64_t client_id);
|
||||
|
||||
/*
|
||||
* Send UN/LOCK_DS_REQ to MGMTD for a specific Datastore DS.
|
||||
*
|
||||
* lib_hndl
|
||||
* Client library handler.
|
||||
*
|
||||
* session_id
|
||||
* Client session ID.
|
||||
*
|
||||
* req_id
|
||||
* Client request ID.
|
||||
*
|
||||
* ds_id
|
||||
* Datastore ID (Running/Candidate/Oper/Startup)
|
||||
*
|
||||
* lock_ds
|
||||
* TRUE for lock request, FALSE for unlock request.
|
||||
*
|
||||
* Returns:
|
||||
* MGMTD_SUCCESS on success, MGMTD_* otherwise.
|
||||
*/
|
||||
extern enum mgmt_result
|
||||
mgmt_fe_lock_ds(uintptr_t lib_hndl, uintptr_t session_id, uint64_t req_id,
|
||||
Mgmtd__DatastoreId ds_id, bool lock_ds);
|
||||
|
||||
/*
|
||||
* Send SET_CONFIG_REQ to MGMTD for one or more config data(s).
|
||||
*
|
||||
* lib_hndl
|
||||
* Client library handler.
|
||||
*
|
||||
* session_id
|
||||
* Client session ID.
|
||||
*
|
||||
* req_id
|
||||
* Client request ID.
|
||||
*
|
||||
* ds_id
|
||||
* Datastore ID (Running/Candidate/Oper/Startup)
|
||||
*
|
||||
* conf_req
|
||||
* Details regarding the SET_CONFIG_REQ.
|
||||
*
|
||||
* num_req
|
||||
* Number of config requests.
|
||||
*
|
||||
* implcit commit
|
||||
* TRUE for implicit commit, FALSE otherwise.
|
||||
*
|
||||
* dst_ds_id
|
||||
* Destination Datastore ID where data needs to be set.
|
||||
*
|
||||
* Returns:
|
||||
* MGMTD_SUCCESS on success, MGMTD_* otherwise.
|
||||
*/
|
||||
extern enum mgmt_result
|
||||
mgmt_fe_set_config_data(uintptr_t lib_hndl, uintptr_t session_id,
|
||||
uint64_t req_id, Mgmtd__DatastoreId ds_id,
|
||||
Mgmtd__YangCfgDataReq **config_req, int num_req,
|
||||
bool implicit_commit, Mgmtd__DatastoreId dst_ds_id);
|
||||
|
||||
/*
|
||||
* Send SET_COMMMIT_REQ to MGMTD for one or more config data(s).
|
||||
*
|
||||
* lib_hndl
|
||||
* Client library handler.
|
||||
*
|
||||
* session_id
|
||||
* Client session ID.
|
||||
*
|
||||
* req_id
|
||||
* Client request ID.
|
||||
*
|
||||
* src_ds_id
|
||||
* Source datastore ID from where data needs to be committed from.
|
||||
*
|
||||
* dst_ds_id
|
||||
* Destination datastore ID where data needs to be committed to.
|
||||
*
|
||||
* validate_only
|
||||
* TRUE if data needs to be validated only, FALSE otherwise.
|
||||
*
|
||||
* abort
|
||||
* TRUE if need to restore Src DS back to Dest DS, FALSE otherwise.
|
||||
*
|
||||
* Returns:
|
||||
* MGMTD_SUCCESS on success, MGMTD_* otherwise.
|
||||
*/
|
||||
extern enum mgmt_result
|
||||
mgmt_fe_commit_config_data(uintptr_t lib_hndl, uintptr_t session_id,
|
||||
uint64_t req_id, Mgmtd__DatastoreId src_ds_id,
|
||||
Mgmtd__DatastoreId dst_ds_id, bool validate_only,
|
||||
bool abort);
|
||||
|
||||
/*
|
||||
* Send GET_CONFIG_REQ to MGMTD for one or more config data item(s).
|
||||
*
|
||||
* lib_hndl
|
||||
* Client library handler.
|
||||
*
|
||||
* session_id
|
||||
* Client session ID.
|
||||
*
|
||||
* req_id
|
||||
* Client request ID.
|
||||
*
|
||||
* ds_id
|
||||
* Datastore ID (Running/Candidate)
|
||||
*
|
||||
* data_req
|
||||
* Get config requested.
|
||||
*
|
||||
* num_req
|
||||
* Number of get config requests.
|
||||
*
|
||||
* Returns:
|
||||
* MGMTD_SUCCESS on success, MGMTD_* otherwise.
|
||||
*/
|
||||
extern enum mgmt_result
|
||||
mgmt_fe_get_config_data(uintptr_t lib_hndl, uintptr_t session_id,
|
||||
uint64_t req_id, Mgmtd__DatastoreId ds_id,
|
||||
Mgmtd__YangGetDataReq **data_req, int num_reqs);
|
||||
|
||||
/*
|
||||
* Send GET_DATA_REQ to MGMTD for one or more data item(s).
|
||||
*
|
||||
* Similar to get config request but supports getting data
|
||||
* from operational ds aka backend clients directly.
|
||||
*/
|
||||
extern enum mgmt_result
|
||||
mgmt_fe_get_data(uintptr_t lib_hndl, uintptr_t session_id, uint64_t req_id,
|
||||
Mgmtd__DatastoreId ds_id, Mgmtd__YangGetDataReq **data_req,
|
||||
int num_reqs);
|
||||
|
||||
/*
|
||||
* Send NOTIFY_REGISTER_REQ to MGMTD daemon.
|
||||
*
|
||||
* lib_hndl
|
||||
* Client library handler.
|
||||
*
|
||||
* session_id
|
||||
* Client session ID.
|
||||
*
|
||||
* req_id
|
||||
* Client request ID.
|
||||
*
|
||||
* ds_id
|
||||
* Datastore ID.
|
||||
*
|
||||
* register_req
|
||||
* TRUE if registering, FALSE otherwise.
|
||||
*
|
||||
* data_req
|
||||
* Details of the YANG notification data.
|
||||
*
|
||||
* num_reqs
|
||||
* Number of data requests.
|
||||
*
|
||||
* Returns:
|
||||
* MGMTD_SUCCESS on success, MGMTD_* otherwise.
|
||||
*/
|
||||
extern enum mgmt_result
|
||||
mgmt_fe_register_yang_notify(uintptr_t lib_hndl, uintptr_t session_id,
|
||||
uint64_t req_id, Mgmtd__DatastoreId ds_id,
|
||||
bool register_req,
|
||||
Mgmtd__YangDataXPath **data_req, int num_reqs);
|
||||
|
||||
/*
|
||||
* Destroy library and cleanup everything.
|
||||
*/
|
||||
extern void mgmt_fe_client_lib_destroy(uintptr_t lib_hndl);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FRR_MGMTD_FE_CLIENT_H_ */
|
25
lib/mgmt_pb.h
Normal file
25
lib/mgmt_pb.h
Normal file
@ -0,0 +1,25 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* MGMTD protobuf main header file
|
||||
* Copyright (C) 2021 Vmware, Inc.
|
||||
* Pushpasis Sarkar <spushpasis@vmware.com>
|
||||
*/
|
||||
|
||||
#ifndef _FRR_MGMTD_PB_H_
|
||||
#define _FRR_MGMTD_PB_H_
|
||||
|
||||
#include "lib/mgmt.pb-c.h"
|
||||
|
||||
#define mgmt_yang_data_xpath_init(ptr) mgmtd__yang_data_xpath__init(ptr)
|
||||
|
||||
#define mgmt_yang_data_value_init(ptr) mgmtd__yang_data_value__init(ptr)
|
||||
|
||||
#define mgmt_yang_data_init(ptr) mgmtd__yang_data__init(ptr)
|
||||
|
||||
#define mgmt_yang_data_reply_init(ptr) mgmtd__yang_data_reply__init(ptr)
|
||||
|
||||
#define mgmt_yang_cfg_data_req_init(ptr) mgmtd__yang_cfg_data_req__init(ptr)
|
||||
|
||||
#define mgmt_yang_get_data_req_init(ptr) mgmtd__yang_get_data_req__init(ptr)
|
||||
|
||||
#endif /* _FRR_MGMTD_PB_H_ */
|
@ -68,6 +68,12 @@ enum nb_operation {
|
||||
NB_OP_RPC,
|
||||
};
|
||||
|
||||
struct nb_cfg_change {
|
||||
char xpath[XPATH_MAXLEN];
|
||||
enum nb_operation operation;
|
||||
const char *value;
|
||||
};
|
||||
|
||||
union nb_resource {
|
||||
int fd;
|
||||
void *ptr;
|
||||
|
@ -120,7 +120,7 @@ static int nb_cli_schedule_command(struct vty *vty)
|
||||
void nb_cli_enqueue_change(struct vty *vty, const char *xpath,
|
||||
enum nb_operation operation, const char *value)
|
||||
{
|
||||
struct vty_cfg_change *change;
|
||||
struct nb_cfg_change *change;
|
||||
|
||||
if (vty->num_cfg_changes == VTY_MAXCFGCHANGES) {
|
||||
/* Not expected to happen. */
|
||||
@ -149,7 +149,7 @@ static int nb_cli_apply_changes_internal(struct vty *vty,
|
||||
|
||||
/* Edit candidate configuration. */
|
||||
for (size_t i = 0; i < vty->num_cfg_changes; i++) {
|
||||
struct vty_cfg_change *change = &vty->cfg_changes[i];
|
||||
struct nb_cfg_change *change = &vty->cfg_changes[i];
|
||||
struct nb_node *nb_node;
|
||||
char xpath[XPATH_MAXLEN];
|
||||
struct yang_data *data;
|
||||
|
@ -64,6 +64,7 @@ lib_libfrr_la_SOURCES = \
|
||||
lib/log_vty.c \
|
||||
lib/md5.c \
|
||||
lib/memory.c \
|
||||
lib/mgmt_fe_client.c \
|
||||
lib/mlag.c \
|
||||
lib/module.c \
|
||||
lib/mpls.c \
|
||||
@ -146,6 +147,23 @@ nodist_lib_libfrr_la_SOURCES = \
|
||||
yang/frr-module-translator.yang.c \
|
||||
# end
|
||||
|
||||
# Add logic to build mgmt.proto
|
||||
lib_libfrr_la_LIBADD += $(PROTOBUF_C_LIBS)
|
||||
|
||||
BUILT_SOURCES += \
|
||||
lib/mgmt.pb-c.c \
|
||||
lib/mgmt.pb-c.h \
|
||||
# end
|
||||
|
||||
CLEANFILES += \
|
||||
lib/mgmt.pb-c.h \
|
||||
lib/mgmt.pb-c.c \
|
||||
# end
|
||||
|
||||
lib_libfrr_la_SOURCES += \
|
||||
lib/mgmt.pb-c.c \
|
||||
#end
|
||||
|
||||
if SQLITE3
|
||||
lib_libfrr_la_LIBADD += $(SQLITE3_LIBS)
|
||||
lib_libfrr_la_SOURCES += lib/db.c
|
||||
@ -222,6 +240,9 @@ pkginclude_HEADERS += \
|
||||
lib/log_vty.h \
|
||||
lib/md5.h \
|
||||
lib/memory.h \
|
||||
lib/mgmt.pb-c.h \
|
||||
lib/mgmt_fe_client.h \
|
||||
lib/mgmt_pb.h \
|
||||
lib/module.h \
|
||||
lib/monotime.h \
|
||||
lib/mpls.h \
|
||||
|
498
lib/vty.c
498
lib/vty.c
@ -65,6 +65,14 @@ enum vty_event {
|
||||
#endif /* VTYSH */
|
||||
};
|
||||
|
||||
struct nb_config *vty_mgmt_candidate_config;
|
||||
|
||||
static uintptr_t mgmt_lib_hndl;
|
||||
static bool mgmt_fe_connected;
|
||||
static bool mgmt_candidate_ds_wr_locked;
|
||||
static uint64_t mgmt_client_id_next;
|
||||
static uint64_t mgmt_last_req_id = UINT64_MAX;
|
||||
|
||||
PREDECL_DLIST(vtyservs);
|
||||
|
||||
struct vty_serv {
|
||||
@ -80,6 +88,7 @@ DECLARE_DLIST(vtyservs, struct vty_serv, itm);
|
||||
|
||||
static void vty_event_serv(enum vty_event event, struct vty_serv *);
|
||||
static void vty_event(enum vty_event, struct vty *);
|
||||
static int vtysh_flush(struct vty *vty);
|
||||
|
||||
/* Extern host structure from command.c */
|
||||
extern struct host host;
|
||||
@ -112,6 +121,36 @@ static char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG;
|
||||
static bool do_log_commands;
|
||||
static bool do_log_commands_perm;
|
||||
|
||||
static void vty_mgmt_resume_response(struct vty *vty, bool success)
|
||||
{
|
||||
uint8_t header[4] = {0, 0, 0, 0};
|
||||
int ret = CMD_SUCCESS;
|
||||
|
||||
if (!vty->mgmt_req_pending) {
|
||||
zlog_err(
|
||||
"vty response called without setting mgmt_req_pending");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!success)
|
||||
ret = CMD_WARNING_CONFIG_FAILED;
|
||||
|
||||
vty->mgmt_req_pending = false;
|
||||
header[3] = ret;
|
||||
buffer_put(vty->obuf, header, 4);
|
||||
|
||||
if (!vty->t_write && (vtysh_flush(vty) < 0))
|
||||
/* Try to flush results; exit if a write
|
||||
* error occurs.
|
||||
*/
|
||||
return;
|
||||
|
||||
if (vty->status == VTY_CLOSE)
|
||||
vty_close(vty);
|
||||
else
|
||||
vty_event(VTYSH_READ, vty);
|
||||
}
|
||||
|
||||
void vty_frame(struct vty *vty, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
@ -1586,6 +1625,17 @@ struct vty *vty_new(void)
|
||||
new->max = VTY_BUFSIZ;
|
||||
new->pass_fd = -1;
|
||||
|
||||
if (mgmt_lib_hndl) {
|
||||
new->mgmt_client_id = mgmt_client_id_next++;
|
||||
if (mgmt_fe_create_client_session(mgmt_lib_hndl,
|
||||
new->mgmt_client_id,
|
||||
(uintptr_t)new)
|
||||
!= MGMTD_SUCCESS)
|
||||
zlog_err(
|
||||
"Failed to open a MGMTD Frontend session for VTY session %p!!",
|
||||
new);
|
||||
}
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
@ -2201,6 +2251,12 @@ static void vtysh_read(struct thread *thread)
|
||||
if (ret == CMD_SUSPEND)
|
||||
break;
|
||||
|
||||
/* with new infra we need to stop response till
|
||||
* we get response through callback.
|
||||
*/
|
||||
if (vty->mgmt_req_pending)
|
||||
return;
|
||||
|
||||
/* warning: watchfrr hardcodes this result write
|
||||
*/
|
||||
header[3] = ret;
|
||||
@ -2257,6 +2313,12 @@ void vty_close(struct vty *vty)
|
||||
int i;
|
||||
bool was_stdio = false;
|
||||
|
||||
if (mgmt_lib_hndl) {
|
||||
mgmt_fe_destroy_client_session(mgmt_lib_hndl,
|
||||
vty->mgmt_client_id);
|
||||
vty->mgmt_session_id = 0;
|
||||
}
|
||||
|
||||
/* Drop out of configure / transaction if needed. */
|
||||
vty_config_exit(vty);
|
||||
|
||||
@ -2632,6 +2694,24 @@ int vty_config_enter(struct vty *vty, bool private_config, bool exclusive)
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (vty_mgmt_fe_enabled()) {
|
||||
if (!mgmt_candidate_ds_wr_locked) {
|
||||
if (vty_mgmt_send_lockds_req(vty, MGMTD_DS_CANDIDATE,
|
||||
true)
|
||||
!= 0) {
|
||||
vty_out(vty, "Not able to lock candidate DS\n");
|
||||
return CMD_WARNING;
|
||||
}
|
||||
} else {
|
||||
vty_out(vty,
|
||||
"Candidate DS already locked by different session\n");
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
vty->mgmt_locked_candidate_ds = true;
|
||||
mgmt_candidate_ds_wr_locked = true;
|
||||
}
|
||||
|
||||
vty->node = CONFIG_NODE;
|
||||
vty->config = true;
|
||||
vty->private_config = private_config;
|
||||
@ -2643,7 +2723,14 @@ int vty_config_enter(struct vty *vty, bool private_config, bool exclusive)
|
||||
vty_out(vty,
|
||||
"Warning: uncommitted changes will be discarded on exit.\n\n");
|
||||
} else {
|
||||
vty->candidate_config = vty_shared_candidate_config;
|
||||
/*
|
||||
* NOTE: On the MGMTD daemon we point the VTY candidate DS to
|
||||
* the global MGMTD candidate DS. Else we point to the VTY
|
||||
* Shared Candidate Config.
|
||||
*/
|
||||
vty->candidate_config = vty_mgmt_candidate_config
|
||||
? vty_mgmt_candidate_config
|
||||
: vty_shared_candidate_config;
|
||||
if (frr_get_cli_mode() == FRR_CLI_TRANSACTIONAL)
|
||||
vty->candidate_config_base =
|
||||
nb_config_dup(running_config);
|
||||
@ -2676,6 +2763,18 @@ int vty_config_node_exit(struct vty *vty)
|
||||
{
|
||||
vty->xpath_index = 0;
|
||||
|
||||
if (vty_mgmt_fe_enabled() && mgmt_candidate_ds_wr_locked
|
||||
&& vty->mgmt_locked_candidate_ds) {
|
||||
if (vty_mgmt_send_lockds_req(vty, MGMTD_DS_CANDIDATE, false)
|
||||
!= 0) {
|
||||
vty_out(vty, "Not able to unlock candidate DS\n");
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
vty->mgmt_locked_candidate_ds = false;
|
||||
mgmt_candidate_ds_wr_locked = false;
|
||||
}
|
||||
|
||||
/* Perform any pending commits. */
|
||||
(void)nb_cli_pending_commit_check(vty);
|
||||
|
||||
@ -3173,6 +3272,398 @@ void vty_init_vtysh(void)
|
||||
/* currently nothing to do, but likely to have future use */
|
||||
}
|
||||
|
||||
static void vty_mgmt_server_connected(uintptr_t lib_hndl, uintptr_t usr_data,
|
||||
bool connected)
|
||||
{
|
||||
zlog_err("%sGot %sconnected %s MGMTD Frontend Server",
|
||||
!connected ? "ERROR: " : "", !connected ? "dis: " : "",
|
||||
!connected ? "from" : "to");
|
||||
|
||||
mgmt_fe_connected = connected;
|
||||
|
||||
/*
|
||||
* TODO: Setup or teardown front-end sessions for existing
|
||||
* VTY connections.
|
||||
*/
|
||||
}
|
||||
|
||||
static void vty_mgmt_session_created(uintptr_t lib_hndl, uintptr_t usr_data,
|
||||
uint64_t client_id, bool create,
|
||||
bool success, uintptr_t session_id,
|
||||
uintptr_t session_ctx)
|
||||
{
|
||||
struct vty *vty;
|
||||
|
||||
vty = (struct vty *)session_ctx;
|
||||
|
||||
if (!success) {
|
||||
zlog_err("%s session for client %llu failed!",
|
||||
create ? "Creating" : "Destroying",
|
||||
(unsigned long long)client_id);
|
||||
return;
|
||||
}
|
||||
|
||||
zlog_err("%s session for client %llu successfully!",
|
||||
create ? "Created" : "Destroyed",
|
||||
(unsigned long long)client_id);
|
||||
if (create)
|
||||
vty->mgmt_session_id = session_id;
|
||||
}
|
||||
|
||||
static void vty_mgmt_ds_lock_notified(uintptr_t lib_hndl, uintptr_t usr_data,
|
||||
uint64_t client_id, uintptr_t session_id,
|
||||
uintptr_t session_ctx, uint64_t req_id,
|
||||
bool lock_ds, bool success,
|
||||
Mgmtd__DatastoreId ds_id,
|
||||
char *errmsg_if_any)
|
||||
{
|
||||
struct vty *vty;
|
||||
|
||||
vty = (struct vty *)session_ctx;
|
||||
|
||||
if (!success) {
|
||||
zlog_err("%socking for DS %u failed! Err: '%s'",
|
||||
lock_ds ? "L" : "Unl", ds_id, errmsg_if_any);
|
||||
vty_out(vty, "ERROR: %socking for DS %u failed! Err: '%s'\n",
|
||||
lock_ds ? "L" : "Unl", ds_id, errmsg_if_any);
|
||||
} else {
|
||||
zlog_err("%socked DS %u successfully!", lock_ds ? "L" : "Unl",
|
||||
ds_id);
|
||||
}
|
||||
|
||||
vty_mgmt_resume_response(vty, success);
|
||||
}
|
||||
|
||||
static void vty_mgmt_set_config_result_notified(
|
||||
uintptr_t lib_hndl, uintptr_t usr_data, uint64_t client_id,
|
||||
uintptr_t session_id, uintptr_t session_ctx, uint64_t req_id,
|
||||
bool success, Mgmtd__DatastoreId ds_id, char *errmsg_if_any)
|
||||
{
|
||||
struct vty *vty;
|
||||
|
||||
vty = (struct vty *)session_ctx;
|
||||
|
||||
if (!success) {
|
||||
zlog_err(
|
||||
"SET_CONFIG request for client 0x%llx failed! Error: '%s'",
|
||||
(unsigned long long)client_id,
|
||||
errmsg_if_any ? errmsg_if_any : "Unknown");
|
||||
vty_out(vty, "ERROR: SET_CONFIG request failed! Error: %s\n",
|
||||
errmsg_if_any ? errmsg_if_any : "Unknown");
|
||||
} else {
|
||||
zlog_err(
|
||||
"SET_CONFIG request for client 0x%llx req-id %llu was successfull!",
|
||||
(unsigned long long)client_id,
|
||||
(unsigned long long)req_id);
|
||||
}
|
||||
|
||||
vty_mgmt_resume_response(vty, success);
|
||||
}
|
||||
|
||||
static void vty_mgmt_commit_config_result_notified(
|
||||
uintptr_t lib_hndl, uintptr_t usr_data, uint64_t client_id,
|
||||
uintptr_t session_id, uintptr_t session_ctx, uint64_t req_id,
|
||||
bool success, Mgmtd__DatastoreId src_ds_id, Mgmtd__DatastoreId dst_ds_id,
|
||||
bool validate_only, char *errmsg_if_any)
|
||||
{
|
||||
struct vty *vty;
|
||||
|
||||
vty = (struct vty *)session_ctx;
|
||||
|
||||
if (!success) {
|
||||
zlog_err(
|
||||
"COMMIT_CONFIG request for client 0x%llx failed! Error: '%s'",
|
||||
(unsigned long long)client_id,
|
||||
errmsg_if_any ? errmsg_if_any : "Unknown");
|
||||
vty_out(vty, "ERROR: COMMIT_CONFIG request failed! Error: %s\n",
|
||||
errmsg_if_any ? errmsg_if_any : "Unknown");
|
||||
} else {
|
||||
zlog_err(
|
||||
"COMMIT_CONFIG request for client 0x%llx req-id %llu was successfull!",
|
||||
(unsigned long long)client_id,
|
||||
(unsigned long long)req_id);
|
||||
if (errmsg_if_any)
|
||||
vty_out(vty, "MGMTD: %s\n", errmsg_if_any);
|
||||
}
|
||||
|
||||
vty_mgmt_resume_response(vty, success);
|
||||
}
|
||||
|
||||
static enum mgmt_result vty_mgmt_get_data_result_notified(
|
||||
uintptr_t lib_hndl, uintptr_t usr_data, uint64_t client_id,
|
||||
uintptr_t session_id, uintptr_t session_ctx, uint64_t req_id,
|
||||
bool success, Mgmtd__DatastoreId ds_id, Mgmtd__YangData **yang_data,
|
||||
size_t num_data, int next_key, char *errmsg_if_any)
|
||||
{
|
||||
struct vty *vty;
|
||||
size_t indx;
|
||||
|
||||
vty = (struct vty *)session_ctx;
|
||||
|
||||
if (!success) {
|
||||
zlog_err(
|
||||
"GET_DATA request for client 0x%llx failed! Error: '%s'",
|
||||
(unsigned long long)client_id,
|
||||
errmsg_if_any ? errmsg_if_any : "Unknown");
|
||||
vty_out(vty, "ERROR: GET_DATA request failed! Error: %s\n",
|
||||
errmsg_if_any ? errmsg_if_any : "Unknown");
|
||||
vty_mgmt_resume_response(vty, success);
|
||||
return MGMTD_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
zlog_debug(
|
||||
"GET_DATA request for client 0x%llx req-id %llu was successfull!",
|
||||
(unsigned long long)client_id, (unsigned long long)req_id);
|
||||
|
||||
if (req_id != mgmt_last_req_id) {
|
||||
mgmt_last_req_id = req_id;
|
||||
vty_out(vty, "[\n");
|
||||
}
|
||||
|
||||
for (indx = 0; indx < num_data; indx++) {
|
||||
vty_out(vty, " \"%s\": \"%s\"\n", yang_data[indx]->xpath,
|
||||
yang_data[indx]->value->encoded_str_val);
|
||||
}
|
||||
if (next_key < 0) {
|
||||
vty_out(vty, "]\n");
|
||||
vty_mgmt_resume_response(vty, success);
|
||||
}
|
||||
|
||||
return MGMTD_SUCCESS;
|
||||
}
|
||||
|
||||
static struct mgmt_fe_client_params client_params = {
|
||||
.client_connect_notify = vty_mgmt_server_connected,
|
||||
.client_session_notify = vty_mgmt_session_created,
|
||||
.lock_ds_notify = vty_mgmt_ds_lock_notified,
|
||||
.set_config_notify =
|
||||
vty_mgmt_set_config_result_notified,
|
||||
.commit_config_notify =
|
||||
vty_mgmt_commit_config_result_notified,
|
||||
.get_data_notify = vty_mgmt_get_data_result_notified,
|
||||
};
|
||||
|
||||
void vty_init_mgmt_fe(void)
|
||||
{
|
||||
if (!vty_master) {
|
||||
zlog_err(
|
||||
"Always call vty_mgmt_init_fe() after vty_init()!!");
|
||||
return;
|
||||
}
|
||||
|
||||
assert(!mgmt_lib_hndl);
|
||||
snprintf(client_params.name, sizeof(client_params.name), "%s-%lld",
|
||||
frr_get_progname(), (long long)getpid());
|
||||
mgmt_lib_hndl = mgmt_fe_client_lib_init(&client_params, vty_master);
|
||||
assert(mgmt_lib_hndl);
|
||||
}
|
||||
|
||||
bool vty_mgmt_fe_enabled(void)
|
||||
{
|
||||
return mgmt_lib_hndl && mgmt_fe_connected ? true : false;
|
||||
}
|
||||
|
||||
int vty_mgmt_send_lockds_req(struct vty *vty, Mgmtd__DatastoreId ds_id,
|
||||
bool lock)
|
||||
{
|
||||
enum mgmt_result ret;
|
||||
|
||||
if (mgmt_lib_hndl && vty->mgmt_session_id) {
|
||||
vty->mgmt_req_id++;
|
||||
ret = mgmt_fe_lock_ds(mgmt_lib_hndl, vty->mgmt_session_id,
|
||||
vty->mgmt_req_id, ds_id, lock);
|
||||
if (ret != MGMTD_SUCCESS) {
|
||||
zlog_err(
|
||||
"Failed to send %sLOCK-DS-REQ to MGMTD for req-id %llu.",
|
||||
lock ? "" : "UN",
|
||||
(unsigned long long)vty->mgmt_req_id);
|
||||
vty_out(vty, "Failed to send %sLOCK-DS-REQ to MGMTD!",
|
||||
lock ? "" : "UN");
|
||||
return -1;
|
||||
}
|
||||
|
||||
vty->mgmt_req_pending = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vty_mgmt_send_config_data(struct vty *vty)
|
||||
{
|
||||
Mgmtd__YangDataValue value[VTY_MAXCFGCHANGES];
|
||||
Mgmtd__YangData cfg_data[VTY_MAXCFGCHANGES];
|
||||
Mgmtd__YangCfgDataReq cfg_req[VTY_MAXCFGCHANGES];
|
||||
Mgmtd__YangCfgDataReq * cfgreq[VTY_MAXCFGCHANGES] = {0};
|
||||
size_t indx;
|
||||
int cnt;
|
||||
|
||||
if (mgmt_lib_hndl && vty->mgmt_session_id) {
|
||||
cnt = 0;
|
||||
for (indx = 0; indx < vty->num_cfg_changes; indx++) {
|
||||
mgmt_yang_data_init(&cfg_data[cnt]);
|
||||
|
||||
if (vty->cfg_changes[indx].value) {
|
||||
mgmt_yang_data_value_init(&value[cnt]);
|
||||
value[cnt].encoded_str_val =
|
||||
(char *)vty->cfg_changes[indx].value;
|
||||
value[cnt].value_case =
|
||||
MGMTD__YANG_DATA_VALUE__VALUE_ENCODED_STR_VAL;
|
||||
cfg_data[cnt].value = &value[cnt];
|
||||
}
|
||||
|
||||
cfg_data[cnt].xpath = vty->cfg_changes[indx].xpath;
|
||||
|
||||
mgmt_yang_cfg_data_req_init(&cfg_req[cnt]);
|
||||
cfg_req[cnt].data = &cfg_data[cnt];
|
||||
switch (vty->cfg_changes[indx].operation) {
|
||||
case NB_OP_DESTROY:
|
||||
cfg_req[cnt].req_type =
|
||||
MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA;
|
||||
break;
|
||||
|
||||
case NB_OP_CREATE:
|
||||
case NB_OP_MODIFY:
|
||||
case NB_OP_MOVE:
|
||||
case NB_OP_PRE_VALIDATE:
|
||||
case NB_OP_APPLY_FINISH:
|
||||
cfg_req[cnt].req_type =
|
||||
MGMTD__CFG_DATA_REQ_TYPE__SET_DATA;
|
||||
break;
|
||||
case NB_OP_GET_ELEM:
|
||||
case NB_OP_GET_NEXT:
|
||||
case NB_OP_GET_KEYS:
|
||||
case NB_OP_LOOKUP_ENTRY:
|
||||
case NB_OP_RPC:
|
||||
assert(!"Invalid type of operation");
|
||||
break;
|
||||
default:
|
||||
assert(!"non-enum value, invalid");
|
||||
}
|
||||
|
||||
cfgreq[cnt] = &cfg_req[cnt];
|
||||
cnt++;
|
||||
}
|
||||
|
||||
vty->mgmt_req_id++;
|
||||
if (cnt
|
||||
&& mgmt_fe_set_config_data(
|
||||
mgmt_lib_hndl, vty->mgmt_session_id,
|
||||
vty->mgmt_req_id, MGMTD_DS_CANDIDATE, cfgreq,
|
||||
cnt,
|
||||
frr_get_cli_mode() == FRR_CLI_CLASSIC
|
||||
? ((vty->pending_allowed
|
||||
|| vty->no_implicit_commit)
|
||||
? false
|
||||
: true)
|
||||
: false,
|
||||
MGMTD_DS_RUNNING)
|
||||
!= MGMTD_SUCCESS) {
|
||||
zlog_err("Failed to send %d Config Xpaths to MGMTD!!",
|
||||
(int)indx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
vty->mgmt_req_pending = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vty_mgmt_send_commit_config(struct vty *vty, bool validate_only, bool abort)
|
||||
{
|
||||
enum mgmt_result ret;
|
||||
|
||||
if (mgmt_lib_hndl && vty->mgmt_session_id) {
|
||||
vty->mgmt_req_id++;
|
||||
ret = mgmt_fe_commit_config_data(
|
||||
mgmt_lib_hndl, vty->mgmt_session_id, vty->mgmt_req_id,
|
||||
MGMTD_DS_CANDIDATE, MGMTD_DS_RUNNING, validate_only,
|
||||
abort);
|
||||
if (ret != MGMTD_SUCCESS) {
|
||||
zlog_err(
|
||||
"Failed to send COMMIT-REQ to MGMTD for req-id %llu.",
|
||||
(unsigned long long)vty->mgmt_req_id);
|
||||
vty_out(vty, "Failed to send COMMIT-REQ to MGMTD!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
vty->mgmt_req_pending = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vty_mgmt_send_get_config(struct vty *vty, Mgmtd__DatastoreId datastore,
|
||||
const char **xpath_list, int num_req)
|
||||
{
|
||||
enum mgmt_result ret;
|
||||
Mgmtd__YangData yang_data[VTY_MAXCFGCHANGES];
|
||||
Mgmtd__YangGetDataReq get_req[VTY_MAXCFGCHANGES];
|
||||
Mgmtd__YangGetDataReq * getreq[VTY_MAXCFGCHANGES];
|
||||
int i;
|
||||
|
||||
vty->mgmt_req_id++;
|
||||
|
||||
for (i = 0; i < num_req; i++) {
|
||||
mgmt_yang_get_data_req_init(&get_req[i]);
|
||||
mgmt_yang_data_init(&yang_data[i]);
|
||||
|
||||
yang_data->xpath = (char *)xpath_list[i];
|
||||
|
||||
get_req[i].data = &yang_data[i];
|
||||
getreq[i] = &get_req[i];
|
||||
}
|
||||
ret = mgmt_fe_get_config_data(mgmt_lib_hndl, vty->mgmt_session_id,
|
||||
vty->mgmt_req_id, datastore, getreq,
|
||||
num_req);
|
||||
|
||||
if (ret != MGMTD_SUCCESS) {
|
||||
zlog_err("Failed to send GET-CONFIG to MGMTD for req-id %llu.",
|
||||
(unsigned long long)vty->mgmt_req_id);
|
||||
vty_out(vty, "Failed to send GET-CONFIG to MGMTD!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
vty->mgmt_req_pending = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vty_mgmt_send_get_data(struct vty *vty, Mgmtd__DatastoreId datastore,
|
||||
const char **xpath_list, int num_req)
|
||||
{
|
||||
enum mgmt_result ret;
|
||||
Mgmtd__YangData yang_data[VTY_MAXCFGCHANGES];
|
||||
Mgmtd__YangGetDataReq get_req[VTY_MAXCFGCHANGES];
|
||||
Mgmtd__YangGetDataReq * getreq[VTY_MAXCFGCHANGES];
|
||||
int i;
|
||||
|
||||
vty->mgmt_req_id++;
|
||||
|
||||
for (i = 0; i < num_req; i++) {
|
||||
mgmt_yang_get_data_req_init(&get_req[i]);
|
||||
mgmt_yang_data_init(&yang_data[i]);
|
||||
|
||||
yang_data->xpath = (char *)xpath_list[i];
|
||||
|
||||
get_req[i].data = &yang_data[i];
|
||||
getreq[i] = &get_req[i];
|
||||
}
|
||||
ret = mgmt_fe_get_data(mgmt_lib_hndl, vty->mgmt_session_id,
|
||||
vty->mgmt_req_id, datastore, getreq, num_req);
|
||||
|
||||
if (ret != MGMTD_SUCCESS) {
|
||||
zlog_err("Failed to send GET-DATA to MGMTD for req-id %llu.",
|
||||
(unsigned long long)vty->mgmt_req_id);
|
||||
vty_out(vty, "Failed to send GET-DATA to MGMTD!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
vty->mgmt_req_pending = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Install vty's own commands like `who' command. */
|
||||
void vty_init(struct thread_master *master_thread, bool do_command_logging)
|
||||
{
|
||||
@ -3220,6 +3711,11 @@ void vty_terminate(void)
|
||||
struct vty *vty;
|
||||
struct vty_serv *vtyserv;
|
||||
|
||||
if (mgmt_lib_hndl) {
|
||||
mgmt_fe_client_lib_destroy(mgmt_lib_hndl);
|
||||
mgmt_lib_hndl = 0;
|
||||
}
|
||||
|
||||
memset(vty_cwd, 0x00, sizeof(vty_cwd));
|
||||
|
||||
vty_reset();
|
||||
|
24
lib/vty.h
24
lib/vty.h
@ -25,6 +25,7 @@
|
||||
#include "compiler.h"
|
||||
#include "northbound.h"
|
||||
#include "zlog_live.h"
|
||||
#include "mgmt_fe_client.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -113,7 +114,7 @@ struct vty {
|
||||
|
||||
/* Changes enqueued to be applied in the candidate configuration. */
|
||||
size_t num_cfg_changes;
|
||||
struct vty_cfg_change cfg_changes[VTY_MAXCFGCHANGES];
|
||||
struct nb_cfg_change cfg_changes[VTY_MAXCFGCHANGES];
|
||||
|
||||
/* XPath of the current node */
|
||||
int xpath_index;
|
||||
@ -134,6 +135,7 @@ struct vty {
|
||||
/* Dynamic transaction information. */
|
||||
bool pending_allowed;
|
||||
bool pending_commit;
|
||||
bool no_implicit_commit;
|
||||
char *pending_cmds_buf;
|
||||
size_t pending_cmds_buflen;
|
||||
size_t pending_cmds_bufpos;
|
||||
@ -208,6 +210,12 @@ struct vty {
|
||||
* without any output. */
|
||||
size_t frame_pos;
|
||||
char frame[1024];
|
||||
|
||||
uintptr_t mgmt_session_id;
|
||||
uint64_t mgmt_client_id;
|
||||
uint64_t mgmt_req_id;
|
||||
bool mgmt_req_pending;
|
||||
bool mgmt_locked_candidate_ds;
|
||||
};
|
||||
|
||||
static inline void vty_push_context(struct vty *vty, int node, uint64_t id)
|
||||
@ -319,6 +327,8 @@ struct vty_arg {
|
||||
#define IS_DIRECTORY_SEP(c) ((c) == DIRECTORY_SEP)
|
||||
#endif
|
||||
|
||||
extern struct nb_config *vty_mgmt_candidate_config;
|
||||
|
||||
/* Prototypes. */
|
||||
extern void vty_init(struct thread_master *, bool do_command_logging);
|
||||
extern void vty_init_vtysh(void);
|
||||
@ -370,6 +380,18 @@ extern void vty_stdio_suspend(void);
|
||||
extern void vty_stdio_resume(void);
|
||||
extern void vty_stdio_close(void);
|
||||
|
||||
extern void vty_init_mgmt_fe(void);
|
||||
extern bool vty_mgmt_fe_enabled(void);
|
||||
extern int vty_mgmt_send_config_data(struct vty *vty);
|
||||
extern int vty_mgmt_send_commit_config(struct vty *vty, bool validate_only,
|
||||
bool abort);
|
||||
extern int vty_mgmt_send_get_config(struct vty *vty, Mgmtd__DatastoreId datastore,
|
||||
const char **xpath_list, int num_req);
|
||||
extern int vty_mgmt_send_get_data(struct vty *vty, Mgmtd__DatastoreId datastore,
|
||||
const char **xpath_list, int num_req);
|
||||
extern int vty_mgmt_send_lockds_req(struct vty *vty, Mgmtd__DatastoreId ds_id,
|
||||
bool lock);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
16
mgmtd/mgmt.c
16
mgmtd/mgmt.c
@ -8,6 +8,8 @@
|
||||
|
||||
#include <zebra.h>
|
||||
#include "mgmtd/mgmt.h"
|
||||
#include "mgmtd/mgmt_fe_server.h"
|
||||
#include "mgmtd/mgmt_fe_adapter.h"
|
||||
#include "mgmtd/mgmt_ds.h"
|
||||
#include "mgmtd/mgmt_memory.h"
|
||||
|
||||
@ -36,14 +38,28 @@ void mgmt_master_init(struct thread_master *master, const int buffer_size)
|
||||
void mgmt_init(void)
|
||||
{
|
||||
|
||||
/*
|
||||
* Allocates some vital data structures used by peer commands in
|
||||
* vty_init
|
||||
*/
|
||||
vty_init_mgmt_fe();
|
||||
|
||||
/* Initialize datastores */
|
||||
mgmt_ds_init(mm);
|
||||
|
||||
/* Initialize the MGMTD Frontend Adapter Module */
|
||||
mgmt_fe_adapter_init(mm->master, mm);
|
||||
|
||||
/* Start the MGMTD Frontend Server for clients to connect */
|
||||
mgmt_fe_server_init(mm->master);
|
||||
|
||||
/* MGMTD VTY commands installation. */
|
||||
mgmt_vty_init();
|
||||
}
|
||||
|
||||
void mgmt_terminate(void)
|
||||
{
|
||||
mgmt_fe_server_destroy();
|
||||
mgmt_fe_adapter_destroy();
|
||||
mgmt_ds_destroy();
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "vrf.h"
|
||||
|
||||
#include "defaults.h"
|
||||
#include "stream.h"
|
||||
|
||||
#include "mgmtd/mgmt_memory.h"
|
||||
#include "mgmtd/mgmt_ds.h"
|
||||
@ -44,6 +45,13 @@ struct mgmt_master {
|
||||
|
||||
extern struct mgmt_master *mm;
|
||||
|
||||
/* Inline functions */
|
||||
static inline unsigned long timeval_elapsed(struct timeval a, struct timeval b)
|
||||
{
|
||||
return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO)
|
||||
+ (a.tv_usec - b.tv_usec));
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove trailing separator from a string.
|
||||
*
|
||||
|
@ -17,4 +17,24 @@
|
||||
|
||||
#define MGMTD_MAX_YANG_VALUE_LEN YANG_VALUE_MAXLEN
|
||||
|
||||
enum mgmt_result {
|
||||
MGMTD_SUCCESS = 0,
|
||||
MGMTD_INVALID_PARAM,
|
||||
MGMTD_INTERNAL_ERROR,
|
||||
MGMTD_NO_CFG_CHANGES,
|
||||
MGMTD_DS_LOCK_FAILED,
|
||||
MGMTD_DS_UNLOCK_FAILED,
|
||||
MGMTD_UNKNOWN_FAILURE
|
||||
};
|
||||
|
||||
enum mgmt_fe_event {
|
||||
MGMTD_FE_SERVER = 1,
|
||||
MGMTD_FE_CONN_READ,
|
||||
MGMTD_FE_CONN_WRITE,
|
||||
MGMTD_FE_CONN_WRITES_ON,
|
||||
MGMTD_FE_PROC_MSG
|
||||
};
|
||||
|
||||
#define MGMTD_TXN_ID_NONE 0
|
||||
|
||||
#endif /* _FRR_MGMTD_DEFINES_H */
|
||||
|
@ -29,7 +29,7 @@
|
||||
#endif /* REDIRECT_DEBUG_TO_STDERR */
|
||||
|
||||
struct mgmt_ds_ctx {
|
||||
enum mgmt_datastore_id ds_id;
|
||||
Mgmtd__DatastoreId ds_id;
|
||||
int lock; /* 0 unlocked, >0 read locked < write locked */
|
||||
|
||||
bool config_ds;
|
||||
@ -212,11 +212,10 @@ 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)
|
||||
Mgmtd__DatastoreId ds_id)
|
||||
{
|
||||
switch (ds_id) {
|
||||
case MGMTD_DS_CANDIDATE:
|
||||
@ -226,8 +225,8 @@ struct mgmt_ds_ctx *mgmt_ds_get_ctx_by_id(struct mgmt_master *mm,
|
||||
case MGMTD_DS_OPERATIONAL:
|
||||
return (mm->oper_ds);
|
||||
case MGMTD_DS_NONE:
|
||||
case MGMTD_DS_MAX_ID:
|
||||
default:
|
||||
case MGMTD__DATASTORE_ID__STARTUP_DS:
|
||||
case _MGMTD__DATASTORE_ID_IS_INT_SIZE:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#ifndef _FRR_MGMTD_DS_H_
|
||||
#define _FRR_MGMTD_DS_H_
|
||||
|
||||
#include "mgmt_fe_client.h"
|
||||
#include "northbound.h"
|
||||
|
||||
#include "mgmtd/mgmt_defines.h"
|
||||
@ -40,18 +41,6 @@ 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);
|
||||
@ -71,7 +60,7 @@ extern const char *mgmt_ds_names[MGMTD_DS_MAX_ID + 1];
|
||||
* Returns:
|
||||
* Datastore name.
|
||||
*/
|
||||
static inline const char *mgmt_ds_id2name(enum mgmt_datastore_id id)
|
||||
static inline const char *mgmt_ds_id2name(Mgmtd__DatastoreId id)
|
||||
{
|
||||
if (id > MGMTD_DS_MAX_ID)
|
||||
id = MGMTD_DS_MAX_ID;
|
||||
@ -87,9 +76,9 @@ static inline const char *mgmt_ds_id2name(enum mgmt_datastore_id id)
|
||||
* Returns:
|
||||
* Datastore ID.
|
||||
*/
|
||||
static inline enum mgmt_datastore_id mgmt_ds_name2id(const char *name)
|
||||
static inline Mgmtd__DatastoreId mgmt_ds_name2id(const char *name)
|
||||
{
|
||||
enum mgmt_datastore_id id;
|
||||
Mgmtd__DatastoreId id;
|
||||
|
||||
FOREACH_MGMTD_DS_ID (id) {
|
||||
if (!strncmp(mgmt_ds_names[id], name, MGMTD_DS_NAME_MAX_LEN))
|
||||
@ -104,7 +93,7 @@ static inline enum mgmt_datastore_id mgmt_ds_name2id(const char *name)
|
||||
*
|
||||
* similar to above funtion.
|
||||
*/
|
||||
static inline enum mgmt_datastore_id mgmt_get_ds_id_by_name(const char *ds_name)
|
||||
static inline Mgmtd__DatastoreId mgmt_get_ds_id_by_name(const char *ds_name)
|
||||
{
|
||||
if (!strncmp(ds_name, "candidate", sizeof("candidate")))
|
||||
return MGMTD_DS_CANDIDATE;
|
||||
@ -191,7 +180,7 @@ extern void mgmt_ds_destroy(void);
|
||||
* 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);
|
||||
Mgmtd__DatastoreId ds_id);
|
||||
|
||||
/*
|
||||
* Check if a given datastore is config ds
|
||||
|
2147
mgmtd/mgmt_fe_adapter.c
Normal file
2147
mgmtd/mgmt_fe_adapter.c
Normal file
File diff suppressed because it is too large
Load Diff
189
mgmtd/mgmt_fe_adapter.h
Normal file
189
mgmtd/mgmt_fe_adapter.h
Normal file
@ -0,0 +1,189 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* MGMTD Frontend Client Connection Adapter
|
||||
*
|
||||
* Copyright (C) 2021 Vmware, Inc.
|
||||
* Pushpasis Sarkar <spushpasis@vmware.com>
|
||||
*/
|
||||
|
||||
#ifndef _FRR_MGMTD_FE_ADAPTER_H_
|
||||
#define _FRR_MGMTD_FE_ADAPTER_H_
|
||||
|
||||
struct mgmt_fe_client_adapter;
|
||||
struct mgmt_master;
|
||||
|
||||
struct mgmt_commit_stats {
|
||||
struct timeval last_start;
|
||||
#ifdef MGMTD_LOCAL_VALIDATIONS_ENABLED
|
||||
struct timeval validate_start;
|
||||
#endif
|
||||
struct timeval prep_cfg_start;
|
||||
struct timeval txn_create_start;
|
||||
struct timeval send_cfg_start;
|
||||
struct timeval apply_cfg_start;
|
||||
struct timeval apply_cfg_end;
|
||||
struct timeval txn_del_start;
|
||||
struct timeval last_end;
|
||||
unsigned long last_exec_tm;
|
||||
unsigned long max_tm;
|
||||
unsigned long min_tm;
|
||||
unsigned long last_batch_cnt;
|
||||
unsigned long last_num_cfgdata_reqs;
|
||||
unsigned long last_num_apply_reqs;
|
||||
unsigned long max_batch_cnt;
|
||||
unsigned long min_batch_cnt;
|
||||
unsigned long commit_cnt;
|
||||
};
|
||||
|
||||
struct mgmt_setcfg_stats {
|
||||
struct timeval last_start;
|
||||
struct timeval last_end;
|
||||
unsigned long last_exec_tm;
|
||||
unsigned long max_tm;
|
||||
unsigned long min_tm;
|
||||
unsigned long avg_tm;
|
||||
unsigned long set_cfg_count;
|
||||
};
|
||||
|
||||
PREDECL_LIST(mgmt_fe_sessions);
|
||||
|
||||
PREDECL_LIST(mgmt_fe_adapters);
|
||||
|
||||
struct mgmt_fe_client_adapter {
|
||||
int conn_fd;
|
||||
union sockunion conn_su;
|
||||
struct thread *conn_read_ev;
|
||||
struct thread *conn_write_ev;
|
||||
struct thread *conn_writes_on;
|
||||
struct thread *proc_msg_ev;
|
||||
uint32_t flags;
|
||||
|
||||
char name[MGMTD_CLIENT_NAME_MAX_LEN];
|
||||
|
||||
/* List of sessions created and being maintained for this client. */
|
||||
struct mgmt_fe_sessions_head fe_sessions;
|
||||
|
||||
/* IO streams for read and write */
|
||||
/* pthread_mutex_t ibuf_mtx; */
|
||||
struct stream_fifo *ibuf_fifo;
|
||||
/* pthread_mutex_t obuf_mtx; */
|
||||
struct stream_fifo *obuf_fifo;
|
||||
|
||||
/* Private I/O buffers */
|
||||
struct stream *ibuf_work;
|
||||
struct stream *obuf_work;
|
||||
|
||||
int refcount;
|
||||
uint32_t num_msg_tx;
|
||||
uint32_t num_msg_rx;
|
||||
struct mgmt_commit_stats cmt_stats;
|
||||
struct mgmt_setcfg_stats setcfg_stats;
|
||||
|
||||
struct mgmt_fe_adapters_item list_linkage;
|
||||
};
|
||||
|
||||
#define MGMTD_FE_ADAPTER_FLAGS_WRITES_OFF (1U << 0)
|
||||
|
||||
DECLARE_LIST(mgmt_fe_adapters, struct mgmt_fe_client_adapter, list_linkage);
|
||||
|
||||
/* Initialise frontend adapter module */
|
||||
extern int mgmt_fe_adapter_init(struct thread_master *tm,
|
||||
struct mgmt_master *cm);
|
||||
|
||||
/* Destroy frontend adapter module */
|
||||
extern void mgmt_fe_adapter_destroy(void);
|
||||
|
||||
/* Acquire lock for frontend adapter */
|
||||
extern void mgmt_fe_adapter_lock(struct mgmt_fe_client_adapter *adapter);
|
||||
|
||||
/* Remove lock from frontend adapter */
|
||||
extern void
|
||||
mgmt_fe_adapter_unlock(struct mgmt_fe_client_adapter **adapter);
|
||||
|
||||
/* Create frontend adapter */
|
||||
extern struct mgmt_fe_client_adapter *
|
||||
mgmt_fe_create_adapter(int conn_fd, union sockunion *su);
|
||||
|
||||
/* Fetch frontend adapter given a name */
|
||||
extern struct mgmt_fe_client_adapter *
|
||||
mgmt_fe_get_adapter(const char *name);
|
||||
|
||||
/*
|
||||
* Send set-config reply to the frontend client.
|
||||
*
|
||||
* session
|
||||
* Unique session identifier.
|
||||
*
|
||||
* txn_id
|
||||
* Unique transaction identifier.
|
||||
*
|
||||
* ds_id
|
||||
* Datastore ID.
|
||||
*
|
||||
* req_id
|
||||
* Config request ID.
|
||||
*
|
||||
* result
|
||||
* Config request result (MGMT_*).
|
||||
*
|
||||
* error_if_any
|
||||
* Buffer to store human-readable error message in case of error.
|
||||
*
|
||||
* implicit_commit
|
||||
* TRUE if the commit is implicit, FALSE otherwise.
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success, -1 on failures.
|
||||
*/
|
||||
extern int mgmt_fe_send_set_cfg_reply(uint64_t session_id, uint64_t txn_id,
|
||||
Mgmtd__DatastoreId ds_id,
|
||||
uint64_t req_id,
|
||||
enum mgmt_result result,
|
||||
const char *error_if_any,
|
||||
bool implcit_commit);
|
||||
|
||||
/*
|
||||
* Send commit-config reply to the frontend client.
|
||||
*/
|
||||
extern int mgmt_fe_send_commit_cfg_reply(
|
||||
uint64_t session_id, uint64_t txn_id, Mgmtd__DatastoreId src_ds_id,
|
||||
Mgmtd__DatastoreId dst_ds_id, uint64_t req_id, bool validate_only,
|
||||
enum mgmt_result result, const char *error_if_any);
|
||||
|
||||
/*
|
||||
* Send get-config reply to the frontend client.
|
||||
*/
|
||||
extern int mgmt_fe_send_get_cfg_reply(uint64_t session_id, uint64_t txn_id,
|
||||
Mgmtd__DatastoreId ds_id,
|
||||
uint64_t req_id,
|
||||
enum mgmt_result result,
|
||||
Mgmtd__YangDataReply *data_resp,
|
||||
const char *error_if_any);
|
||||
|
||||
/*
|
||||
* Send get-data reply to the frontend client.
|
||||
*/
|
||||
extern int mgmt_fe_send_get_data_reply(
|
||||
uint64_t session_id, uint64_t txn_id, Mgmtd__DatastoreId ds_id,
|
||||
uint64_t req_id, enum mgmt_result result,
|
||||
Mgmtd__YangDataReply *data_resp, const char *error_if_any);
|
||||
|
||||
/*
|
||||
* Send data notify to the frontend client.
|
||||
*/
|
||||
extern int mgmt_fe_send_data_notify(Mgmtd__DatastoreId ds_id,
|
||||
Mgmtd__YangData * data_resp[],
|
||||
int num_data);
|
||||
|
||||
/* Fetch frontend client session set-config stats */
|
||||
extern struct mgmt_setcfg_stats *
|
||||
mgmt_fe_get_session_setcfg_stats(uint64_t session_id);
|
||||
|
||||
/* Fetch frontend client session commit stats */
|
||||
extern struct mgmt_commit_stats *
|
||||
mgmt_fe_get_session_commit_stats(uint64_t session_id);
|
||||
|
||||
extern void mgmt_fe_adapter_status_write(struct vty *vty, bool detail);
|
||||
extern void mgmt_fe_adapter_perf_measurement(struct vty *vty, bool config);
|
||||
extern void mgmt_fe_adapter_reset_perf_stats(struct vty *vty);
|
||||
#endif /* _FRR_MGMTD_FE_ADAPTER_H_ */
|
160
mgmtd/mgmt_fe_server.c
Normal file
160
mgmtd/mgmt_fe_server.c
Normal file
@ -0,0 +1,160 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* MGMTD Frontend Server
|
||||
*
|
||||
* Copyright (C) 2021 Vmware, Inc.
|
||||
* Pushpasis Sarkar <spushpasis@vmware.com>
|
||||
*/
|
||||
|
||||
#include <zebra.h>
|
||||
#include "network.h"
|
||||
#include "libfrr.h"
|
||||
#include "mgmtd/mgmt.h"
|
||||
#include "mgmtd/mgmt_fe_server.h"
|
||||
#include "mgmtd/mgmt_fe_adapter.h"
|
||||
|
||||
#ifdef REDIRECT_DEBUG_TO_STDERR
|
||||
#define MGMTD_FE_SRVR_DBG(fmt, ...) \
|
||||
fprintf(stderr, "%s: " fmt "\n", __func__, ##__VA_ARGS__)
|
||||
#define MGMTD_FE_SRVR_ERR(fmt, ...) \
|
||||
fprintf(stderr, "%s: ERROR, " fmt "\n", __func__, ##__VA_ARGS__)
|
||||
#else /* REDIRECT_DEBUG_TO_STDERR */
|
||||
#define MGMTD_FE_SRVR_DBG(fmt, ...) \
|
||||
do { \
|
||||
if (mgmt_debug_fe) \
|
||||
zlog_debug("%s: " fmt, __func__, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#define MGMTD_FE_SRVR_ERR(fmt, ...) \
|
||||
zlog_err("%s: ERROR: " fmt, __func__, ##__VA_ARGS__)
|
||||
#endif /* REDIRECT_DEBUG_TO_STDERR */
|
||||
|
||||
static int mgmt_fe_listen_fd;
|
||||
static struct thread_master *mgmt_fe_listen_tm;
|
||||
static struct thread *mgmt_fe_listen_ev;
|
||||
static void mgmt_fe_server_register_event(enum mgmt_fe_event event);
|
||||
|
||||
static void mgmt_fe_conn_accept(struct thread *thread)
|
||||
{
|
||||
int client_conn_fd;
|
||||
union sockunion su;
|
||||
|
||||
if (mgmt_fe_listen_fd < 0)
|
||||
return;
|
||||
|
||||
/* We continue hearing server listen socket. */
|
||||
mgmt_fe_server_register_event(MGMTD_FE_SERVER);
|
||||
|
||||
memset(&su, 0, sizeof(union sockunion));
|
||||
|
||||
/* We can handle IPv4 or IPv6 socket. */
|
||||
client_conn_fd = sockunion_accept(mgmt_fe_listen_fd, &su);
|
||||
if (client_conn_fd < 0) {
|
||||
MGMTD_FE_SRVR_ERR(
|
||||
"Failed to accept MGMTD Frontend client connection : %s",
|
||||
safe_strerror(errno));
|
||||
return;
|
||||
}
|
||||
set_nonblocking(client_conn_fd);
|
||||
set_cloexec(client_conn_fd);
|
||||
|
||||
MGMTD_FE_SRVR_DBG("Got a new MGMTD Frontend connection");
|
||||
|
||||
mgmt_fe_create_adapter(client_conn_fd, &su);
|
||||
}
|
||||
|
||||
static void mgmt_fe_server_register_event(enum mgmt_fe_event event)
|
||||
{
|
||||
if (event == MGMTD_FE_SERVER) {
|
||||
thread_add_read(mgmt_fe_listen_tm, mgmt_fe_conn_accept,
|
||||
NULL, mgmt_fe_listen_fd,
|
||||
&mgmt_fe_listen_ev);
|
||||
assert(mgmt_fe_listen_ev);
|
||||
} else {
|
||||
assert(!"mgmt_fe_server_post_event() called incorrectly");
|
||||
}
|
||||
}
|
||||
|
||||
static void mgmt_fe_server_start(const char *hostname)
|
||||
{
|
||||
int ret;
|
||||
int sock;
|
||||
struct sockaddr_un addr;
|
||||
mode_t old_mask;
|
||||
|
||||
/* Set umask */
|
||||
old_mask = umask(0077);
|
||||
|
||||
sock = socket(AF_UNIX, SOCK_STREAM, PF_UNSPEC);
|
||||
if (sock < 0) {
|
||||
MGMTD_FE_SRVR_ERR("Failed to create server socket: %s",
|
||||
safe_strerror(errno));
|
||||
goto mgmt_fe_server_start_failed;
|
||||
}
|
||||
|
||||
addr.sun_family = AF_UNIX,
|
||||
strlcpy(addr.sun_path, MGMTD_FE_SERVER_PATH, sizeof(addr.sun_path));
|
||||
unlink(addr.sun_path);
|
||||
ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
|
||||
if (ret < 0) {
|
||||
MGMTD_FE_SRVR_ERR(
|
||||
"Failed to bind server socket to '%s'. Err: %s",
|
||||
addr.sun_path, safe_strerror(errno));
|
||||
goto mgmt_fe_server_start_failed;
|
||||
}
|
||||
|
||||
ret = listen(sock, MGMTD_FE_MAX_CONN);
|
||||
if (ret < 0) {
|
||||
MGMTD_FE_SRVR_ERR("Failed to listen on server socket: %s",
|
||||
safe_strerror(errno));
|
||||
goto mgmt_fe_server_start_failed;
|
||||
}
|
||||
|
||||
/* Restore umask */
|
||||
umask(old_mask);
|
||||
|
||||
mgmt_fe_listen_fd = sock;
|
||||
mgmt_fe_server_register_event(MGMTD_FE_SERVER);
|
||||
|
||||
MGMTD_FE_SRVR_DBG("Started MGMTD Frontend Server!");
|
||||
return;
|
||||
|
||||
mgmt_fe_server_start_failed:
|
||||
if (sock)
|
||||
close(sock);
|
||||
|
||||
mgmt_fe_listen_fd = -1;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
int mgmt_fe_server_init(struct thread_master *master)
|
||||
{
|
||||
if (mgmt_fe_listen_tm) {
|
||||
MGMTD_FE_SRVR_DBG("MGMTD Frontend Server already running!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
mgmt_fe_listen_tm = master;
|
||||
|
||||
mgmt_fe_server_start("localhost");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mgmt_fe_server_destroy(void)
|
||||
{
|
||||
if (mgmt_fe_listen_tm) {
|
||||
MGMTD_FE_SRVR_DBG("Closing MGMTD Frontend Server!");
|
||||
|
||||
if (mgmt_fe_listen_ev) {
|
||||
THREAD_OFF(mgmt_fe_listen_ev);
|
||||
mgmt_fe_listen_ev = NULL;
|
||||
}
|
||||
|
||||
if (mgmt_fe_listen_fd >= 0) {
|
||||
close(mgmt_fe_listen_fd);
|
||||
mgmt_fe_listen_fd = -1;
|
||||
}
|
||||
|
||||
mgmt_fe_listen_tm = NULL;
|
||||
}
|
||||
}
|
20
mgmtd/mgmt_fe_server.h
Normal file
20
mgmtd/mgmt_fe_server.h
Normal file
@ -0,0 +1,20 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* MGMTD Frontend Server
|
||||
*
|
||||
* Copyright (C) 2021 Vmware, Inc.
|
||||
* Pushpasis Sarkar <spushpasis@vmware.com>
|
||||
*/
|
||||
|
||||
#ifndef _FRR_MGMTD_FE_SERVER_H_
|
||||
#define _FRR_MGMTD_FE_SERVER_H_
|
||||
|
||||
#define MGMTD_FE_MAX_CONN 32
|
||||
|
||||
/* Initialise frontend server */
|
||||
extern int mgmt_fe_server_init(struct thread_master *master);
|
||||
|
||||
/* Destroy frontend server */
|
||||
extern void mgmt_fe_server_destroy(void);
|
||||
|
||||
#endif /* _FRR_MGMTD_FE_SERVER_H_ */
|
@ -97,26 +97,6 @@ static void sigusr1(void)
|
||||
zlog_rotate();
|
||||
}
|
||||
|
||||
static struct frr_signal_t mgmt_signals[] = {
|
||||
{
|
||||
.signal = SIGHUP,
|
||||
.handler = &sighup,
|
||||
},
|
||||
{
|
||||
.signal = SIGUSR1,
|
||||
.handler = &sigusr1,
|
||||
},
|
||||
{
|
||||
.signal = SIGINT,
|
||||
.handler = &sigint,
|
||||
},
|
||||
{
|
||||
.signal = SIGTERM,
|
||||
.handler = &sigint,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Try to free up allocations we know about so that diagnostic tools such as
|
||||
* valgrind are able to better illuminate leaks.
|
||||
@ -140,6 +120,25 @@ static __attribute__((__noreturn__)) void mgmt_exit(int status)
|
||||
exit(status);
|
||||
}
|
||||
|
||||
static struct frr_signal_t mgmt_signals[] = {
|
||||
{
|
||||
.signal = SIGHUP,
|
||||
.handler = &sighup,
|
||||
},
|
||||
{
|
||||
.signal = SIGUSR1,
|
||||
.handler = &sigusr1,
|
||||
},
|
||||
{
|
||||
.signal = SIGINT,
|
||||
.handler = &sigint,
|
||||
},
|
||||
{
|
||||
.signal = SIGTERM,
|
||||
.handler = &sigint,
|
||||
},
|
||||
};
|
||||
|
||||
static int mgmt_vrf_new(struct vrf *vrf)
|
||||
{
|
||||
zlog_debug("VRF Created: %s(%u)", vrf->name, vrf->vrf_id);
|
||||
|
@ -19,3 +19,5 @@
|
||||
|
||||
DEFINE_MGROUP(MGMTD, "mgmt");
|
||||
DEFINE_MTYPE(MGMTD, MGMTD, "MGMTD instance");
|
||||
DEFINE_MTYPE(MGMTD, MGMTD_FE_ADPATER, "MGMTD Frontend adapter");
|
||||
DEFINE_MTYPE(MGMTD, MGMTD_FE_SESSION, "MGMTD Frontend Client Session");
|
||||
|
@ -13,4 +13,6 @@
|
||||
|
||||
DECLARE_MGROUP(MGMTD);
|
||||
DECLARE_MTYPE(MGMTD);
|
||||
DECLARE_MTYPE(MGMTD_FE_ADPATER);
|
||||
DECLARE_MTYPE(MGMTD_FE_SESSION);
|
||||
#endif /* _FRR_MGMTD_MEMORY_H */
|
||||
|
@ -1,210 +0,0 @@
|
||||
#! /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
|
182
mgmtd/mgmt_vty.c
182
mgmtd/mgmt_vty.c
@ -11,11 +11,24 @@
|
||||
#include "command.h"
|
||||
#include "json.h"
|
||||
#include "mgmtd/mgmt.h"
|
||||
#include "mgmtd/mgmt_fe_server.h"
|
||||
#include "mgmtd/mgmt_fe_adapter.h"
|
||||
#include "mgmtd/mgmt_ds.h"
|
||||
|
||||
#ifndef VTYSH_EXTRACT_PL
|
||||
#include "mgmtd/mgmt_vty_clippy.c"
|
||||
#endif
|
||||
|
||||
DEFPY(show_mgmt_fe_adapter, show_mgmt_fe_adapter_cmd,
|
||||
"show mgmt frontend-adapter all [detail$detail]",
|
||||
SHOW_STR
|
||||
MGMTD_STR
|
||||
MGMTD_FE_ADAPTER_STR
|
||||
"Display all Frontend Adapters\n"
|
||||
"Display more details\n")
|
||||
{
|
||||
mgmt_fe_adapter_status_write(vty, !!detail);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY(show_mgmt_ds,
|
||||
show_mgmt_ds_cmd,
|
||||
@ -44,32 +57,124 @@ DEFPY(show_mgmt_ds,
|
||||
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 WORD$dsname [xpath WORD$path] [file WORD$filepath] <json|xml>$fmt",
|
||||
"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 | running | operational>\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|xml\n")
|
||||
"json output\n"
|
||||
"xml output\n")
|
||||
{
|
||||
enum mgmt_datastore_id datastore = MGMTD_DS_CANDIDATE;
|
||||
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;
|
||||
|
||||
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)
|
||||
datastore = mgmt_ds_name2id(dsname);
|
||||
|
||||
ds_ctx = mgmt_ds_get_ctx_by_id(mm, datastore);
|
||||
if (!ds_ctx) {
|
||||
@ -96,18 +201,16 @@ DEFPY(show_mgmt_dump_data,
|
||||
|
||||
DEFPY(mgmt_load_config,
|
||||
mgmt_load_config_cmd,
|
||||
"mgmt load-config file WORD$filepath <merge|replace>",
|
||||
"mgmt load-config WORD$filepath <merge|replace>$type",
|
||||
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;
|
||||
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,
|
||||
@ -121,17 +224,6 @@ DEFPY(mgmt_load_config,
|
||||
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",
|
||||
@ -141,33 +233,17 @@ DEFPY(mgmt_load_config,
|
||||
|
||||
DEFPY(mgmt_save_config,
|
||||
mgmt_save_config_cmd,
|
||||
"mgmt save-config datastore WORD$dsname file WORD$filepath",
|
||||
"mgmt save-config <candidate|running>$dsname WORD$filepath",
|
||||
MGMTD_STR
|
||||
"Save configuration from datastore\n"
|
||||
"Datastore keyword\n"
|
||||
"<candidate|running>\n"
|
||||
"Write the configuration to a file\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;
|
||||
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",
|
||||
@ -257,9 +333,15 @@ void mgmt_vty_init(void)
|
||||
{
|
||||
install_node(&debug_node);
|
||||
|
||||
install_element(VIEW_NODE, &show_mgmt_fe_adapter_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(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);
|
||||
|
||||
|
@ -18,6 +18,8 @@ noinst_LIBRARIES += mgmtd/libmgmtd.a
|
||||
mgmtd_libmgmtd_a_SOURCES = \
|
||||
mgmtd/mgmt.c \
|
||||
mgmtd/mgmt_ds.c \
|
||||
mgmtd/mgmt_fe_server.c \
|
||||
mgmtd/mgmt_fe_adapter.c \
|
||||
mgmtd/mgmt_memory.c \
|
||||
mgmtd/mgmt_vty.c \
|
||||
# end
|
||||
@ -30,6 +32,8 @@ mgmtdheader_HEADERS = \
|
||||
noinst_HEADERS += \
|
||||
mgmtd/mgmt.h \
|
||||
mgmtd/mgmt_ds.h \
|
||||
mgmtd/mgmt_fe_server.h \
|
||||
mgmtd/mgmt_fe_adapter.h \
|
||||
mgmtd/mgmt_memory.h \
|
||||
# end
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user