X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=blobdiff_plain;f=ntsimulator%2Fntsim-ng%2Ffeatures%2Fnetconf_call_home%2Fnetconf_call_home.c;fp=ntsimulator%2Fntsim-ng%2Ffeatures%2Fnetconf_call_home%2Fnetconf_call_home.c;h=b3bacb0ba95f6269e14a9ab43092bbb4ae537aec;hb=f1d5c9198acde7a7ce296490087cad37e008f688;hp=0000000000000000000000000000000000000000;hpb=f2d8f1002fa93848c80a88e5658db4816cba3020;p=sim%2Fo1-interface.git diff --git a/ntsimulator/ntsim-ng/features/netconf_call_home/netconf_call_home.c b/ntsimulator/ntsim-ng/features/netconf_call_home/netconf_call_home.c new file mode 100644 index 0000000..b3bacb0 --- /dev/null +++ b/ntsimulator/ntsim-ng/features/netconf_call_home/netconf_call_home.c @@ -0,0 +1,284 @@ +/************************************************************************* +* +* Copyright 2020 highstreet technologies GmbH and others +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +***************************************************************************/ + +#define _GNU_SOURCE + +#include "netconf_call_home.h" +#include "utils/log_utils.h" +#include "utils/sys_utils.h" +#include "utils/rand_utils.h" +#include "utils/http_client.h" +#include "utils/nts_utils.h" +#include +#include + +#include "core/session.h" +#include "core/framework.h" + +#define NETCONF_CALLHOME_ENABLED_SCHEMA_PATH "/nts-network-function:simulation/network-function/netconf/call-home" +#define NETCONF_CALLHOME_CURL_SEND_PAYLOAD_FORMAT "{\"odl-netconf-callhome-server:device\":[{\"odl-netconf-callhome-server:unique-id\":\"%s\",\"odl-netconf-callhome-server:ssh-host-key\":\"%s\",\"odl-netconf-callhome-server:credentials\":{\"odl-netconf-callhome-server:username\":\"netconf\",\"odl-netconf-callhome-server:passwords\":[\"netconf\"]}}]}" +#define SDN_CONTROLLER_DETAILS_SCHEMA_PATH "/nts-network-function:simulation/sdn-controller" + +static int create_ssh_callhome_endpoint(sr_session_ctx_t *current_session, struct lyd_node *netconf_node); +static int create_tls_callhome_endpoint(sr_session_ctx_t *current_session, struct lyd_node *netconf_node); +static int send_odl_callhome_configuration(sr_session_ctx_t *current_session); + +int netconf_call_home_feature_start(sr_session_ctx_t *current_session) { + assert(current_session); + assert_session(); + + sr_val_t *value = 0; + + bool callhome_enabled = false; + int rc = sr_get_item(current_session, NETCONF_CALLHOME_ENABLED_SCHEMA_PATH, 0, &value); + if(rc == SR_ERR_OK) { + callhome_enabled = value->data.bool_val; + sr_free_val(value); + } + + if(callhome_enabled == false) { + log_message(2, "NETCONF CallHome is not enabled, not configuring NETCONF Server.\n"); + return NTS_ERR_OK; + } + + struct lyd_node *netconf_node = 0; + netconf_node = lyd_new_path(NULL, session_context, "/ietf-netconf-server:netconf-server", 0, 0, 0); + if(netconf_node == 0) { + log_error("could not create a new lyd_node"); + return NTS_ERR_FAILED; + } + + rc = create_ssh_callhome_endpoint(current_session, netconf_node); + if(rc != NTS_ERR_OK) { + log_error("could not create SSH CallHome endpoint on the NETCONF Server"); + return NTS_ERR_FAILED; + } + + rc = create_tls_callhome_endpoint(current_session, netconf_node); + if(rc != NTS_ERR_OK) { + log_error("could not create TLS CallHome endpoint on the NETCONF Server"); + return NTS_ERR_FAILED; + } + + rc = sr_edit_batch(current_session, netconf_node, "merge"); + if(rc != SR_ERR_OK) { + log_error("could not edit batch on datastore"); + return NTS_ERR_FAILED; + } + + rc = sr_validate(current_session, "ietf-netconf-server", 0); + if(rc != SR_ERR_OK) { + struct ly_err_item *err = ly_err_first(session_context); + log_error("sr_validate issues on STARTUP: %s", err->msg); + return NTS_ERR_FAILED; + } + + rc = sr_apply_changes(current_session, 0, 0); + if(rc != SR_ERR_OK) { + log_error("could not apply changes on datastore"); + return NTS_ERR_FAILED; + } + + lyd_free_withsiblings(netconf_node); + + return NTS_ERR_OK; +} + + +static int create_ssh_callhome_endpoint(sr_session_ctx_t *current_session, struct lyd_node *netconf_node) { + assert(current_session); + assert(netconf_node); + + sr_val_t *value = 0; + + bool callhome_enabled = false; + int rc = sr_get_item(current_session, NETCONF_CALLHOME_ENABLED_SCHEMA_PATH, 0, &value); + if(rc == SR_ERR_OK) { + callhome_enabled = value->data.bool_val; + sr_free_val(value); + } + + if(callhome_enabled == false) { + log_message(2, "NETCONF CallHome is not enabled, not configuring NETCONF Server.\n"); + return NTS_ERR_OK; + } + + controller_details_t *controller = controller_details_get(current_session); + if(controller == 0) { + log_error("controller_details_get failed"); + return NTS_ERR_FAILED; + } + + char *controller_ip = strdup(controller->ip); + uint16_t controller_callhome_port = controller->nc_callhome_port; + controller_details_free(controller); + + if(controller_ip == 0) { + log_error("strdup failed"); + return NTS_ERR_FAILED; + } + + char xpath[500]; + sprintf(xpath, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='default-client']/endpoints/endpoint[name='callhome-ssh']/ssh/tcp-client-parameters/keepalives/idle-time"); + struct lyd_node *rcl = lyd_new_path(netconf_node, 0, xpath, "1", 0, LYD_PATH_OPT_NOPARENTRET); + if(rcl == 0) { + log_error("could not created yang path"); + free(controller_ip); + return NTS_ERR_FAILED; + } + + sprintf(xpath, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='default-client']/endpoints/endpoint[name='callhome-ssh']/ssh/tcp-client-parameters/keepalives/max-probes"); + rcl = lyd_new_path(netconf_node, 0, xpath, "10", 0, LYD_PATH_OPT_NOPARENTRET); + if(rcl == 0) { + log_error("could not created yang path"); + free(controller_ip); + return NTS_ERR_FAILED; + } + + sprintf(xpath, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='default-client']/endpoints/endpoint[name='callhome-ssh']/ssh/tcp-client-parameters/keepalives/probe-interval"); + rcl = lyd_new_path(netconf_node, 0, xpath, "5", 0, LYD_PATH_OPT_NOPARENTRET); + if(rcl == 0) { + log_error("could not created yang path"); + free(controller_ip); + return NTS_ERR_FAILED; + } + + sprintf(xpath, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='default-client']/endpoints/endpoint[name='callhome-ssh']/ssh/tcp-client-parameters/remote-address"); + rcl = lyd_new_path(netconf_node, 0, xpath, controller_ip, 0, LYD_PATH_OPT_NOPARENTRET); + if(rcl == 0) { + log_error("could not created yang path"); + free(controller_ip); + return NTS_ERR_FAILED; + } + free(controller_ip); + + sprintf(xpath, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='default-client']/endpoints/endpoint[name='callhome-ssh']/ssh/tcp-client-parameters/remote-port"); + char port[20]; + sprintf(port, "%d", controller_callhome_port); + rcl = lyd_new_path(netconf_node, 0, xpath, port, 0, LYD_PATH_OPT_NOPARENTRET); + if(rcl == 0) { + log_error("could not created yang path"); + return NTS_ERR_FAILED; + } + + sprintf(xpath, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='default-client']/endpoints/endpoint[name='callhome-ssh']/ssh/ssh-server-parameters/server-identity/host-key[name='default-key']/public-key/keystore-reference"); + rcl = lyd_new_path(netconf_node, 0, xpath, KS_KEY_NAME, 0, LYD_PATH_OPT_NOPARENTRET); + if(rcl == 0) { + log_error("could not created yang path"); + return NTS_ERR_FAILED; + } + + sprintf(xpath, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='default-client']/endpoints/endpoint[name='callhome-ssh']/ssh/ssh-server-parameters/client-authentication/supported-authentication-methods/publickey"); + rcl = lyd_new_path(netconf_node, 0, xpath, "", 0, LYD_PATH_OPT_NOPARENTRET); + if(rcl == 0) { + log_error("could not created yang path"); + return NTS_ERR_FAILED; + } + + sprintf(xpath, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='default-client']/endpoints/endpoint[name='callhome-ssh']/ssh/ssh-server-parameters/client-authentication/supported-authentication-methods/passsword"); + rcl = lyd_new_path(netconf_node, 0, xpath, "", 0, LYD_PATH_OPT_NOPARENTRET); + if(rcl == 0) { + log_error("could not created yang path"); + return NTS_ERR_FAILED; + } + + sprintf(xpath, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='default-client']/endpoints/endpoint[name='callhome-ssh']/ssh/ssh-server-parameters/client-authentication/supported-authentication-methods/other"); + rcl = lyd_new_path(netconf_node, 0, xpath, "interactive", 0, LYD_PATH_OPT_NOPARENTRET); + if(rcl == 0) { + log_error("could not created yang path"); + return NTS_ERR_FAILED; + } + + sprintf(xpath, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='default-client']/endpoints/endpoint[name='callhome-ssh']/ssh/ssh-server-parameters/client-authentication/users"); + rcl = lyd_new_path(netconf_node, 0, xpath, "", 0, LYD_PATH_OPT_NOPARENTRET); + if(rcl == 0) { + log_error("could not created yang path"); + return NTS_ERR_FAILED; + } + + sprintf(xpath, "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='default-client']/connection-type/persistent"); + rcl = lyd_new_path(netconf_node, 0, xpath, "", 0, LYD_PATH_OPT_NOPARENTRET); + if(rcl == 0) { + log_error("could not created yang path"); + return NTS_ERR_FAILED; + } + + rc = send_odl_callhome_configuration(current_session); + if(rc != NTS_ERR_OK) { + log_message(2, "could not send ODL Call Home configuration.\n"); + } + + return NTS_ERR_OK; +} + +static int create_tls_callhome_endpoint(sr_session_ctx_t *current_session, struct lyd_node *netconf_node) { + assert(current_session); + assert(netconf_node); + + // checkAS future usage, TLS endpoint yet supported in ODL + + return NTS_ERR_OK; +} + + +static int send_odl_callhome_configuration(sr_session_ctx_t *current_session) { + assert(current_session); + + char *public_ssh_key = read_key(SERVER_PUBLIC_SSH_KEY_PATH); + if(public_ssh_key == 0) { + log_error("could not read the public ssh key from file %s", SERVER_PUBLIC_SSH_KEY_PATH); + return NTS_ERR_FAILED; + } + + char *ssh_key_string; + ssh_key_string = strtok(public_ssh_key, " "); + ssh_key_string = strtok(NULL, " "); + + // checkAS we have hardcoded here the username and password of the NETCONF Server + char *odl_callhome_payload = 0; + asprintf(&odl_callhome_payload, NETCONF_CALLHOME_CURL_SEND_PAYLOAD_FORMAT, framework_environment.hostname, ssh_key_string); + free(public_ssh_key); + if(odl_callhome_payload == 0) { + log_error("bad asprintf"); + return NTS_ERR_FAILED; + } + + controller_details_t *controller = controller_details_get(current_session); + if(controller == 0) { + log_error("controller_details_get failed"); + return NTS_ERR_FAILED; + } + + char *url = 0; + asprintf(&url, "%s/rests/data/odl-netconf-callhome-server:netconf-callhome-server/allowed-devices/device=%s", controller->base_url, framework_environment.hostname); + if(url == 0) { + log_error("bad asprintf"); + controller_details_free(controller); + return NTS_ERR_FAILED; + } + + int rc = http_request(url, controller->username, controller->password, "PUT", odl_callhome_payload, 0, 0); + if(rc != NTS_ERR_OK) { + log_error("http_request failed"); + } + + free(url); + controller_details_free(controller); + free(odl_callhome_payload); + + return rc; +}