Add NETCONF CallHome via TLS feature. 20/6820/1
authorAlex Stancu <alexandru.stancu@highstreet-technologies.com>
Tue, 5 Oct 2021 14:22:44 +0000 (17:22 +0300)
committerAlex Stancu <alexandru.stancu@highstreet-technologies.com>
Tue, 5 Oct 2021 14:22:57 +0000 (17:22 +0300)
Issue-ID: SIM-80
Change-Id: I6ed024760eb430146fb2e94b244ab7c6241e75d4
Signed-off-by: Alex Stancu <alexandru.stancu@highstreet-technologies.com>
18 files changed:
ntsimulator/deploy/base/yang/nts-common.yang
ntsimulator/deploy/base/yang/nts-network-function.yang
ntsimulator/deploy/blank/container-tag.yaml
ntsimulator/deploy/nts-manager/container-tag.yaml
ntsimulator/deploy/nts-manager/yang/nts-manager.yang
ntsimulator/deploy/o-ran-du/container-tag.yaml
ntsimulator/deploy/o-ran-ru-fh/container-tag.yaml
ntsimulator/deploy/o-ran/container-tag.yaml
ntsimulator/deploy/x-ran/container-tag.yaml
ntsimulator/ntsim-ng/core/app/app_common.c
ntsimulator/ntsim-ng/core/app/manager.c
ntsimulator/ntsim-ng/core/app/manager_sysrepo.c
ntsimulator/ntsim-ng/core/app/network_function.c
ntsimulator/ntsim-ng/core/nc_config.c
ntsimulator/ntsim-ng/core/xpath.h
ntsimulator/ntsim-ng/features/netconf_call_home/netconf_call_home.c
ntsimulator/ntsim-ng/features/ves_pnf_registration/ves_pnf_registration.c
ntsimulator/ntsim-ng/utils/sys_utils.h

index 86d7b3e..960aea8 100644 (file)
@@ -18,6 +18,12 @@ module nts-common {
   description
     "This module contains common yang definitions YANG definitions for the Network Topology Simulator.";
 
+  revision 2021-06-08 {
+    description
+      "Moved NTS_PROTOCOL_TYPE_BASE identities from nts-manager.";
+    reference
+      "O-RAN-SC SIM project";
+  }
   revision 2021-03-26 {
     description
       "Added controller-protocol.";
@@ -55,6 +61,47 @@ module nts-common {
       "O-RAN-SC SIM project";
   }
 
+  identity NTS_PROTOCOL_TYPE_BASE {
+    description
+      "Base identity for protocol.";
+  }
+
+  identity NTS_PROTOCOL_TYPE_NETCONF_SSH {
+    base NTS_PROTOCOL_TYPE_BASE;
+    description
+      "Identity for NETCONF SSH protocol.";
+  }
+
+  identity NTS_PROTOCOL_TYPE_NETCONF_TLS {
+    base NTS_PROTOCOL_TYPE_BASE;
+    description
+      "Identity for NETCONF TLS protocol.";
+  }
+
+  identity NTS_PROTOCOL_TYPE_FTP {
+    base NTS_PROTOCOL_TYPE_BASE;
+    description
+      "Identity for FTP protocol.";
+  }
+
+  identity NTS_PROTOCOL_TYPE_SFTP {
+    base NTS_PROTOCOL_TYPE_BASE;
+    description
+      "Identity for SFTP protocol.";
+  }
+
+  identity NTS_PROTOCOL_TYPE_HTTP {
+    base NTS_PROTOCOL_TYPE_BASE;
+    description
+      "Identity for HTTP protocol.";
+  }
+
+  identity NTS_PROTOCOL_TYPE_HTTPS {
+    base NTS_PROTOCOL_TYPE_BASE;
+    description
+      "Identity for HTTPS protocol.";
+  }
+
   feature faults-status {
     description
       "This means that the server supports reporting back the number of faults that were generated";
@@ -281,7 +328,7 @@ module nts-common {
         "The protocol used for communication with the SDN Controller.";
     }
     leaf controller-ip {
-      type inet:ip-address;
+      type inet:host;
       description
         "The IP address of the SDN Controller.";
     }
@@ -326,7 +373,7 @@ module nts-common {
         "The protocol (HTTP / HTTPS) to be used to address the VES Collector.";
     }
     leaf ves-endpoint-ip {
-      type inet:ip-address;
+      type inet:host;
       description
         "The IP address of the VES Collector.";
     }
index 69c39fc..dbde984 100644 (file)
@@ -3,6 +3,9 @@ module nts-network-function {
   namespace "urn:o-ran-sc:params:xml:ns:yang:nts:network:function";
   prefix ntsnf;
 
+  import ietf-inet-types {
+    prefix inet;
+  }
   import nts-common {
     prefix ntsc;
   }
@@ -21,6 +24,24 @@ module nts-network-function {
   description
     "This module contains YANG definitions for the Network Topology Simulator - Network Functions";
 
+  revision 2021-06-18 {
+    description
+      "Added test-list for NETCONF hardware delay emulation.";
+    reference
+      "O-RAN-SC SIM project";
+  }
+  revision 2021-06-14 {
+    description
+      "Added total loss network emulation RPC and NETCONF write-delay emulation.";
+    reference
+      "O-RAN-SC SIM project";
+  }
+  revision 2021-06-08 {
+    description
+      "Added more info and NETCONF latency emulation.";
+    reference
+      "O-RAN-SC SIM project";
+  }
   revision 2021-05-17 {
     description
       "Added support for network emulation.";
@@ -153,6 +174,22 @@ module nts-network-function {
     }
   }
 
+  rpc emulate-total-loss {
+    description
+      "Operation to emulate 100% loss in network packets. Operation will resume after specified timeout.";
+    input {
+      leaf timeout {
+        type uint32;
+        units "miliseconds (ms)";
+        description
+          "Period after which loss will stop being 100%.";
+      }
+    }
+    output {
+      uses ntsc:rpc-status-g;
+    }
+  }
+
   container info {
     config false;
     description
@@ -172,6 +209,40 @@ module nts-network-function {
       description
         "A bit-wise list with currently started features.";
     }
+    leaf ssh-connections {
+      type uint8;
+      config false;
+      description
+        "The number of SSH Endpoints the network function instance exposes.";
+    }
+    leaf tls-connections {
+      type uint8;
+      config false;
+      description
+        "The number of TLS Endpoints the network function instance exposes.";
+    }
+    leaf hostname {
+      type string;
+      description
+        "Current network function hostname.";
+    }
+    list docker-ports {
+      key "port";
+      description
+        "The ports which are exposed inside the docker container implementing this network function instance.";
+      leaf port {
+        type inet:port-number;
+        description
+          "Port number.";
+      }
+      leaf protocol {
+        type identityref {
+          base ntsc:NTS_PROTOCOL_TYPE_BASE;
+        }
+        description
+          "Protocol attached to current port.";
+      }
+    }
   }
   container simulation {
     description
@@ -322,6 +393,54 @@ module nts-network-function {
           "Delay packets based on packet size.";
       }
     }
+    container hardware-emulation {
+      description
+        "Container which encompasses the details of hardware emulation.";
+      container netconf-delay {
+        description
+          "Emulates delay on an operational leaf.";
+        leaf delay {
+          type uint32;
+          units "miliseconds (ms)";
+          default "0";
+          description
+            "Delay time to be set for get operation on test leaf.";
+        }
+        leaf get-test {
+          type uint32;
+          units "miliseconds (ms)";
+          config false;
+          description
+            "Read to test. Value represents emulated delay.";
+        }
+        leaf edit-test {
+          type uint32;
+          units "miliseconds (ms)";
+          description
+            "Writing non-null value will emulate a write-delay.";
+        }
+        list get-test-list {
+          config false;
+          description
+            "Read to test. Returned values are saved from edit-test-list.";
+          leaf value {
+            type string;
+            description
+              "Values from edit-test-list.";
+          }
+        }
+        list edit-test-list {
+          key "value";
+          description
+            "Write to test.";
+          leaf value {
+            type string;
+            description
+              "Unique values for testing.";
+          }
+        }
+      }
+    }
     container sdn-controller {
       description
         "Groups details about the SDN Controller.";
index edd6735..b21c92a 100644 (file)
@@ -1,2 +1,2 @@
 ---
-tag: 1.3.4
\ No newline at end of file
+tag: 1.3.5
\ No newline at end of file
index edd6735..b21c92a 100644 (file)
@@ -1,2 +1,2 @@
 ---
-tag: 1.3.4
\ No newline at end of file
+tag: 1.3.5
\ No newline at end of file
index 5f7bc14..0ecdd9f 100644 (file)
@@ -21,6 +21,12 @@ module nts-manager {
   description
     "This module contains YANG definitions for the Network Topology Simulator - Manager.";
 
+  revision 2021-06-08 {
+    description
+      "Moved NTS_PROTOCOL_TYPE_BASE identities to nts-common.";
+    reference
+      "O-RAN-SC SIM project";
+  }
   revision 2021-03-26 {
     description
       "Added NTS_PROTOCOL_TYPE_BASE identities and changed instance/networking container; also added multi-base port support.";
@@ -52,47 +58,6 @@ module nts-manager {
       "O-RAN-SC SIM project";
   }
 
-  identity NTS_PROTOCOL_TYPE_BASE {
-    description
-      "Base identity for protocol.";
-  }
-
-  identity NTS_PROTOCOL_TYPE_NETCONF_SSH {
-    base NTS_PROTOCOL_TYPE_BASE;
-    description
-      "Identity for NETCONF SSH protocol.";
-  }
-
-  identity NTS_PROTOCOL_TYPE_NETCONF_TLS {
-    base NTS_PROTOCOL_TYPE_BASE;
-    description
-      "Identity for NETCONF TLS protocol.";
-  }
-
-  identity NTS_PROTOCOL_TYPE_FTP {
-    base NTS_PROTOCOL_TYPE_BASE;
-    description
-      "Identity for FTP protocol.";
-  }
-
-  identity NTS_PROTOCOL_TYPE_SFTP {
-    base NTS_PROTOCOL_TYPE_BASE;
-    description
-      "Identity for SFTP protocol.";
-  }
-
-  identity NTS_PROTOCOL_TYPE_HTTP {
-    base NTS_PROTOCOL_TYPE_BASE;
-    description
-      "Identity for HTTP protocol.";
-  }
-
-  identity NTS_PROTOCOL_TYPE_HTTPS {
-    base NTS_PROTOCOL_TYPE_BASE;
-    description
-      "Identity for HTTPS protocol.";
-  }
-
   typedef percent {
     type decimal64 {
       fraction-digits 2;
@@ -134,7 +99,7 @@ module nts-manager {
         }
         leaf protocol {
           type identityref {
-            base NTS_PROTOCOL_TYPE_BASE;
+            base ntsc:NTS_PROTOCOL_TYPE_BASE;
           }
           description
             "Protocol attached to current port.";
@@ -156,7 +121,7 @@ module nts-manager {
         }
         leaf protocol {
           type identityref {
-            base NTS_PROTOCOL_TYPE_BASE;
+            base ntsc:NTS_PROTOCOL_TYPE_BASE;
           }
           description
             "Protocol attached to current port.";
index edd6735..b21c92a 100644 (file)
@@ -1,2 +1,2 @@
 ---
-tag: 1.3.4
\ No newline at end of file
+tag: 1.3.5
\ No newline at end of file
index edd6735..b21c92a 100644 (file)
@@ -1,2 +1,2 @@
 ---
-tag: 1.3.4
\ No newline at end of file
+tag: 1.3.5
\ No newline at end of file
index edd6735..b21c92a 100644 (file)
@@ -1,2 +1,2 @@
 ---
-tag: 1.3.4
\ No newline at end of file
+tag: 1.3.5
\ No newline at end of file
index edd6735..b21c92a 100644 (file)
@@ -1,2 +1,2 @@
 ---
-tag: 1.3.4
\ No newline at end of file
+tag: 1.3.5
\ No newline at end of file
index e74b655..c4b6c1a 100644 (file)
 #include "core/xpath.h"
 #include "core/framework.h"
 
+#include <sysrepo.h>
+#include <sysrepo/values.h>
+
 static int app_common_populate_info(void);
+
 static int app_common_populate_network_emulation_info(void);
-static int app_common_populate_network_emulation_change_cb(sr_session_ctx_t *session, const char *module_name, const char *xpath, sr_event_t event, uint32_t request_id, void *private_data);
+static int app_common_network_emulation_change_cb(sr_session_ctx_t *session, const char *module_name, const char *xpath, sr_event_t event, uint32_t request_id, void *private_data);
+
+static int app_common_hardware_emulation_change_cb(sr_session_ctx_t *session, const char *module_name, const char *xpath, sr_event_t event, uint32_t request_id, void *private_data);
+static int app_common_hardware_emulation_netconf_delay_oper_cb(sr_session_ctx_t *session, const char *module_name, const char *xpath, const char *request_xpath, uint32_t request_id, struct lyd_node **parent, void *private_data);
+
+static int app_common_emulate_total_loss_cb(sr_session_ctx_t *session, const char *path, const sr_val_t *input, const size_t input_cnt, sr_event_t event, uint32_t request_id, sr_val_t **output, size_t *output_cnt, void *private_data);
+
+static uint32_t netconf_delay = 0;
 
 int app_common_init(void) {
     assert_session();
@@ -49,9 +60,28 @@ int app_common_init(void) {
         return NTS_ERR_FAILED;
     }
 
-    rc = sr_module_change_subscribe(session_running, NTS_NETWORK_FUNCTION_MODULE, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH, app_common_populate_network_emulation_change_cb, NULL, 0, SR_SUBSCR_CTX_REUSE | SR_SUBSCR_UPDATE, &session_subscription);
+    rc = sr_module_change_subscribe(session_running, NTS_NETWORK_FUNCTION_MODULE, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH, app_common_network_emulation_change_cb, NULL, 0, SR_SUBSCR_CTX_REUSE | SR_SUBSCR_UPDATE, &session_subscription);
+    if(rc != SR_ERR_OK) {
+        log_error("could not subscribe to network emulation\n");
+        return NTS_ERR_FAILED;
+    }
+
+
+    rc = sr_module_change_subscribe(session_running, NTS_NETWORK_FUNCTION_MODULE, NTS_NF_HARDWARE_EMULATION_SCHEMA_XPATH, app_common_hardware_emulation_change_cb, NULL, 2, SR_SUBSCR_CTX_REUSE | SR_SUBSCR_UPDATE, &session_subscription);
     if(rc != SR_ERR_OK) {
-        log_error("could not subscribe to faults");
+        log_error("could not subscribe to hardware emulation changes\n");
+        return NTS_ERR_FAILED;
+    }
+
+    rc = sr_oper_get_items_subscribe(session_running, NTS_NETWORK_FUNCTION_MODULE, NTS_NF_HE_NETCONF_DELAY_SCHEMA_XPATH, app_common_hardware_emulation_netconf_delay_oper_cb, 0, SR_SUBSCR_CTX_REUSE | SR_SUBSCR_OPER_MERGE, &session_subscription);
+    if(rc != SR_ERR_OK) {
+        log_error("error from sr_oper_get_items_subscribe: %s\n", sr_strerror(rc));
+        return 0;
+    }
+
+    rc = sr_rpc_subscribe(session_running, NTS_NF_RPC_EMULATE_TOTAL_LOSS_SCHEMA_XPATH, app_common_emulate_total_loss_cb, 0, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
+    if(rc != SR_ERR_OK) {
+        log_error("error from sr_rpc_subscribe: %s\n", sr_strerror(rc));
         return NTS_ERR_FAILED;
     }
 
@@ -60,18 +90,146 @@ int app_common_init(void) {
 
 static int app_common_populate_info(void) {
     int rc;
+    char aux[9];
+
+    struct lys_module *module = (struct lys_module *)ly_ctx_get_module(session_context, NTS_NETWORK_FUNCTION_MODULE, 0, 0);
+    if(module == 0) {
+        log_error("could not get module %s from context\n", NTS_NETWORK_FUNCTION_MODULE);
+        return NTS_ERR_FAILED;
+    }
+
+    struct lyd_node *info = lyd_new(0, module, "info");
+    if(info == 0) {
+        log_error("lyd_new failed\n");
+        return NTS_ERR_FAILED;
+    }
 
+    struct lyd_node *node;
     if (framework_environment.nts.build_time && strlen(framework_environment.nts.build_time) > 0) {
-        rc  = sr_set_item_str(session_operational, NTS_NF_INFO_SCHEMA_XPATH"/build-time", framework_environment.nts.build_time, 0, 0);
-        if(rc != SR_ERR_OK) {
-            log_error("sr_set_item_str failed\n");
+        node  = lyd_new_leaf(info, module, "build-time", framework_environment.nts.build_time);
+        if(node == 0) {
+            log_error("lyd_new_leaf failed\n");
             return NTS_ERR_FAILED;
         }
     }
 
-    rc = sr_set_item_str(session_operational, NTS_NF_INFO_SCHEMA_XPATH"/version", framework_environment.nts.version, 0, 0);
+    node  = lyd_new_leaf(info, module, "version", framework_environment.nts.version);
+    if(node == 0) {
+        log_error("lyd_new_leaf failed\n");
+        return NTS_ERR_FAILED;
+    }
+
+    sprintf(aux, "%d", framework_environment.settings.ssh_connections);
+    node  = lyd_new_leaf(info, module, "ssh-connections", aux);
+    if(node == 0) {
+        log_error("lyd_new_leaf failed\n");
+        return NTS_ERR_FAILED;
+    }
+
+    sprintf(aux, "%d", framework_environment.settings.tls_connections);
+    node  = lyd_new_leaf(info, module, "tls-connections", aux);
+    if(node == 0) {
+        log_error("lyd_new_leaf failed\n");
+        return NTS_ERR_FAILED;
+    }
+
+    node  = lyd_new_leaf(info, module, "hostname", framework_environment.settings.hostname);
+    if(node == 0) {
+        log_error("lyd_new_leaf failed\n");
+        return NTS_ERR_FAILED;
+    }
+
+    //netconf ssh ports
+    for(int k = 0; k < framework_environment.settings.ssh_connections; k++) {
+        char value[128];
+        
+        struct lyd_node *ports = lyd_new(info, module, "docker-ports");
+        if(ports == 0) {
+            log_error("lyd_new failed\n");
+            return NTS_ERR_FAILED;
+        }
+
+        sprintf(value, "%d", STANDARD_NETCONF_PORT + k);
+        if(lyd_new_leaf(ports, module, "port", value) == 0) {
+            log_error("lyd_new_leaf failed\n");
+            return NTS_ERR_FAILED;
+        }
+
+        if(lyd_new_leaf(ports, module, "protocol", "nts-common:NTS_PROTOCOL_TYPE_NETCONF_SSH") == 0) {
+            log_error("lyd_new_leaf failed\n");
+            return NTS_ERR_FAILED;
+        }
+    }
+
+    //netconf tls ports
+    for(int k = 0; k < framework_environment.settings.tls_connections; k++) {
+        char value[128];
+        
+        struct lyd_node *ports = lyd_new(info, module, "docker-ports");
+        if(ports == 0) {
+            log_error("lyd_new failed\n");
+            return NTS_ERR_FAILED;
+        }
+
+        sprintf(value, "%d", STANDARD_NETCONF_PORT + framework_environment.settings.ssh_connections + k);
+        if(lyd_new_leaf(ports, module, "port", value) == 0) {
+            log_error("lyd_new_leaf failed\n");
+            return NTS_ERR_FAILED;
+        }
+
+        if(lyd_new_leaf(ports, module, "protocol", "nts-common:NTS_PROTOCOL_TYPE_NETCONF_TLS") == 0) {
+            log_error("lyd_new_leaf failed\n");
+            return NTS_ERR_FAILED;
+        }
+    }
+
+    //ftp ports
+    for(int k = 0; k < framework_environment.settings.ftp_connections; k++) {
+        char value[128];
+        
+        struct lyd_node *ports = lyd_new(info, module, "docker-ports");
+        if(ports == 0) {
+            log_error("lyd_new failed\n");
+            return NTS_ERR_FAILED;
+        }
+
+        sprintf(value, "%d", STANDARD_FTP_PORT + k);
+        if(lyd_new_leaf(ports, module, "port", value) == 0) {
+            log_error("lyd_new_leaf failed\n");
+            return NTS_ERR_FAILED;
+        }
+
+        if(lyd_new_leaf(ports, module, "protocol", "nts-common:NTS_PROTOCOL_TYPE_FTP") == 0) {
+            log_error("lyd_new_leaf failed\n");
+            return NTS_ERR_FAILED;
+        }
+    }
+
+    //sftp ports
+    for(int k = 0; k < framework_environment.settings.sftp_connections; k++) {
+        char value[128];
+        
+        struct lyd_node *ports = lyd_new(info, module, "docker-ports");
+        if(ports == 0) {
+            log_error("lyd_new failed\n");
+            return NTS_ERR_FAILED;
+        }
+
+        sprintf(value, "%d", STANDARD_SFTP_PORT + k);
+        if(lyd_new_leaf(ports, module, "port", value) == 0) {
+            log_error("lyd_new_leaf failed\n");
+            return NTS_ERR_FAILED;
+        }
+
+        if(lyd_new_leaf(ports, module, "protocol", "nts-common:NTS_PROTOCOL_TYPE_SFTP") == 0) {
+            log_error("lyd_new_leaf failed\n");
+            return NTS_ERR_FAILED;
+        }
+    }
+
+    rc = sr_edit_batch(session_operational, info, "merge");
     if(rc != SR_ERR_OK) {
-        log_error("sr_set_item_str failed\n");
+        log_error("sr_edit_batch failed: %s\n", sr_strerror(rc));
         return NTS_ERR_FAILED;
     }
 
@@ -174,7 +332,7 @@ static int app_common_populate_network_emulation_info(void) {
     return NTS_ERR_OK;
 }
 
-static int app_common_populate_network_emulation_change_cb(sr_session_ctx_t *session, const char *module_name, const char *xpath, sr_event_t event, uint32_t request_id, void *private_data) {
+static int app_common_network_emulation_change_cb(sr_session_ctx_t *session, const char *module_name, const char *xpath, sr_event_t event, uint32_t request_id, void *private_data) {
     
     if(event == SR_EV_UPDATE) {
         sr_change_iter_t *it = 0;
@@ -293,3 +451,214 @@ static int app_common_populate_network_emulation_change_cb(sr_session_ctx_t *ses
 
     return SR_ERR_OK;
 }
+
+static int app_common_hardware_emulation_change_cb(sr_session_ctx_t *session, const char *module_name, const char *xpath, sr_event_t event, uint32_t request_id, void *private_data) {
+    bool delay = false;
+
+    if(event == SR_EV_UPDATE) {
+        sr_change_iter_t *it = 0;
+        int rc = SR_ERR_OK;
+        sr_change_oper_t oper;
+        sr_val_t *old_value = 0;
+        sr_val_t *new_value = 0;
+
+        rc = sr_get_changes_iter(session, NTS_NF_HARDWARE_EMULATION_SCHEMA_XPATH"//.", &it);
+        if(rc != SR_ERR_OK) {
+            log_error("sr_get_changes_iter failed\n");
+            return SR_ERR_VALIDATION_FAILED;
+        }
+
+        while((rc = sr_get_change_next(session, it, &oper, &old_value, &new_value)) == SR_ERR_OK) {
+            if(new_value->xpath && (strstr(new_value->xpath, "/netconf-delay/edit-test-list"))) {
+                delay = true;
+            }
+            else if(new_value->xpath && (strstr(new_value->xpath, "/netconf-delay/edit-test"))) {
+                rc = sr_set_item_str(session, NTS_NF_HARDWARE_EMULATION_SCHEMA_XPATH"/netconf-delay/edit-test", "0", 0, 0);
+                if(rc != SR_ERR_OK) {
+                    log_error("sr_set_item failed\n");
+                    return SR_ERR_VALIDATION_FAILED;
+                }
+                
+                delay = true;
+            }
+
+            sr_free_val(old_value);
+            sr_free_val(new_value);
+        }
+
+        if(delay) {
+            delay = false;
+
+            int32_t sec = netconf_delay / 1000;
+            uint32_t usec = (netconf_delay % 1000) * 1000;
+
+            usleep(usec);
+            if(sec > 0) {
+                sleep(sec);
+            }
+        }
+
+        sr_free_change_iter(it);
+    }
+
+    if(event == SR_EV_DONE) {
+        sr_val_t *values = NULL;
+        size_t count = 0;
+        
+        int rc = sr_get_items(session, NTS_NF_HARDWARE_EMULATION_SCHEMA_XPATH"//.", 0, 0, &values, &count);
+        if (rc != SR_ERR_OK) {
+            log_error("sr_get_items failed\n");
+            return rc;
+        }
+
+        for(size_t i = 0; i < count; i++) {
+            if(strstr(values[i].xpath, "/netconf-delay/delay")) {
+                netconf_delay = values[i].data.uint32_val;
+            }
+        }
+
+        sr_free_values(values, count);
+    }
+
+    return SR_ERR_OK;
+}
+
+static int app_common_hardware_emulation_netconf_delay_oper_cb(sr_session_ctx_t *session, const char *module_name, const char *xpath, const char *request_xpath, uint32_t request_id, struct lyd_node **parent, void *private_data) {
+
+    char aux[9];
+    sprintf(aux, "%d", netconf_delay);
+    struct lyd_node *container = lyd_new_path(0, session_context, NTS_NF_HE_NETCONF_DELAY_SCHEMA_XPATH, 0, 0, LYD_PATH_OPT_NOPARENTRET);
+    if(container == 0) {
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    //get test leaf
+    lyd_new_leaf(container, container->schema->module, "get-test", aux);
+
+    //get test list
+    sr_val_t *values = NULL;
+    size_t count = 0;
+    int rc = sr_get_items(session_running, NTS_NF_HE_NETCONF_DELAY_SCHEMA_XPATH"/edit-test-list/*", 0, 0, &values, &count);
+    if (rc != SR_ERR_OK) {
+        log_error("sr_get_items failed\n");
+        return rc;
+    }
+    for(size_t i = 0; i < count; i++) {
+        struct lyd_node *listitem = lyd_new(container, container->schema->module, "get-test-list");
+        if(listitem) {
+            lyd_new_leaf(listitem, container->schema->module, "value", values[i].data.string_val);
+        }
+    }
+
+    sr_free_values(values, count);
+
+
+
+    uint32_t sec = netconf_delay / 1000;
+    uint32_t usec = (netconf_delay % 1000) * 1000;
+
+    usleep(usec);
+    if(sec > 0) {
+        sleep(sec);
+    }
+
+    *parent = container;
+    return SR_ERR_OK;
+}
+
+static int app_common_emulate_total_loss_cb(sr_session_ctx_t *session, const char *path, const sr_val_t *input, const size_t input_cnt, sr_event_t event, uint32_t request_id, sr_val_t **output, size_t *output_cnt, void *private_data) {
+    int rc;
+
+    *output_cnt = 1;
+    rc = sr_new_values(*output_cnt, output);
+    if(SR_ERR_OK != rc) {
+        return rc;
+    }
+
+    rc = sr_val_set_xpath(output[0], NTS_NF_RPC_EMULATE_TOTAL_LOSS_SCHEMA_XPATH"/status");
+    if(SR_ERR_OK != rc) {
+        return rc;
+    }
+
+    sr_val_t *values = NULL;
+    size_t count = 0;
+    
+    rc = sr_get_items(session, NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH"//.", 0, 0, &values, &count);
+    if (rc != SR_ERR_OK) {
+        log_error("sr_get_items failed\n");
+        return rc;
+    }
+
+    network_emultation_settings_t s;
+    for(size_t i = 0; i < count; i++) {
+        if(strstr(values[i].xpath, "/limit")) {
+            s.limit = values[i].data.uint16_val;
+        }
+        else if(strstr(values[i].xpath, "/delay/time")) {
+            s.delay.time = values[i].data.uint16_val;
+        }
+        else if(strstr(values[i].xpath, "/delay/jitter")) {
+            s.delay.jitter = values[i].data.uint16_val;
+        }
+        else if(strstr(values[i].xpath, "/delay/correlation")) {
+            s.delay.correlation = values[i].data.uint16_val;
+        }
+        else if(strstr(values[i].xpath, "/delay/distribution")) {
+            s.delay.distribution = strdup(values[i].data.string_val);
+        }
+        else if(strstr(values[i].xpath, "/loss")) {
+            s.loss = values[i].data.uint16_val;
+        }
+        else if(strstr(values[i].xpath, "/corruption/percentage")) {
+            s.corruption.percentage = values[i].data.uint16_val;
+        }
+        else if(strstr(values[i].xpath, "/corruption/correlation")) {
+            s.corruption.correlation = values[i].data.uint16_val;
+        }
+        else if(strstr(values[i].xpath, "/duplication/percentage")) {
+            s.duplication.percentage = values[i].data.uint16_val;
+        }
+        else if(strstr(values[i].xpath, "/duplication/correlation")) {
+            s.duplication.correlation = values[i].data.uint16_val;
+        }
+        else if(strstr(values[i].xpath, "/reordering/percentage")) {
+            s.reordering.percentage = values[i].data.uint16_val;
+        }
+        else if(strstr(values[i].xpath, "/reordering/correlation")) {
+            s.reordering.correlation = values[i].data.uint16_val;
+        }
+        else if(strstr(values[i].xpath, "/rate")) {
+            s.rate = values[i].data.uint16_val;
+        }
+    }
+
+    uint16_t old_loss = s.loss;
+    s.loss = 100;   //100 percent loss
+
+    sr_free_values(values, count);
+    if(network_emulation_update(&s) != NTS_ERR_OK) {
+        log_error("network_emulation_update() failed\n");
+        free(s.delay.distribution);
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    int delay = input->data.uint32_val;
+    int32_t sec = delay / 1000;
+    uint32_t usec = (delay % 1000) * 1000;
+
+    usleep(usec);
+    if(sec > 0) {
+        sleep(sec);
+    }
+
+    s.loss = old_loss;
+    if(network_emulation_update(&s) != NTS_ERR_OK) {
+        log_error("network_emulation_update() failed\n");
+        free(s.delay.distribution);
+        return SR_ERR_OPERATION_FAILED;
+    }
+    free(s.delay.distribution);
+
+    rc = sr_val_build_str_data(output[0], SR_ENUM_T, "%s", "SUCCESS");
+    return rc;
+}
index f7ec705..179c7b6 100644 (file)
@@ -203,19 +203,21 @@ static int manager_change_cb(sr_session_ctx_t *session, const char *module_name,
                 char *leaf_path  = strdup(strstr(new_value->xpath, "']/") + 3);
                 if(strcmp(leaf_path, "started-instances") == 0) {
                     new_oper->started_instances = new_value->data.uint16_val;
-                    rc = sr_set_item(session, old_value->xpath, old_value, 0);
-                    if(rc != SR_ERR_OK) {
-                        log_error("sr_set_item failed\n");
-                        return SR_ERR_VALIDATION_FAILED;
-                    }
+                    // checkAL sysrepo v1.4.140 workaround
+                    // rc = sr_set_item(session, old_value->xpath, old_value, 0);
+                    // if(rc != SR_ERR_OK) {
+                    //     log_error("sr_set_item failed\n");
+                    //     return SR_ERR_VALIDATION_FAILED;
+                    // }
                 }
                 else if(strcmp(leaf_path, "mounted-instances") == 0) {
                     new_oper->mounted_instances = new_value->data.uint16_val;
-                    rc = sr_set_item(session, old_value->xpath, old_value, 0);
-                    if(rc != SR_ERR_OK) {
-                        log_error("sr_set_item failed\n");
-                        return SR_ERR_VALIDATION_FAILED;
-                    }
+                    // checkAL sysrepo v1.4.140 workaround
+                    // rc = sr_set_item(session, old_value->xpath, old_value, 0);
+                    // if(rc != SR_ERR_OK) {
+                    //     log_error("sr_set_item failed\n");
+                    //     return SR_ERR_VALIDATION_FAILED;
+                    // }
                 }
                 else if(strcmp(leaf_path, "docker-instance-name") == 0) {
                     new_oper->docker_instance_name = strdup(nv);
index d41ea56..b32f48c 100644 (file)
@@ -309,7 +309,7 @@ int manager_sr_populate_networking(struct lyd_node *parent, const manager_networ
             return NTS_ERR_FAILED;
         }
 
-        if(lyd_new_leaf(ports, ports->schema->module, "protocol", "NTS_PROTOCOL_TYPE_NETCONF_SSH") == 0) {
+        if(lyd_new_leaf(ports, ports->schema->module, "protocol", "nts-common:NTS_PROTOCOL_TYPE_NETCONF_SSH") == 0) {
             log_error("lyd_new_leaf failed\n");
             return NTS_ERR_FAILED;
         }
@@ -327,7 +327,7 @@ int manager_sr_populate_networking(struct lyd_node *parent, const manager_networ
             return NTS_ERR_FAILED;
         }
 
-        if(lyd_new_leaf(ports, ports->schema->module, "protocol", "NTS_PROTOCOL_TYPE_NETCONF_SSH") == 0) {
+        if(lyd_new_leaf(ports, ports->schema->module, "protocol", "nts-common:NTS_PROTOCOL_TYPE_NETCONF_SSH") == 0) {
             log_error("lyd_new_leaf failed\n");
             return NTS_ERR_FAILED;
         }
@@ -349,7 +349,7 @@ int manager_sr_populate_networking(struct lyd_node *parent, const manager_networ
             return NTS_ERR_FAILED;
         }
 
-        if(lyd_new_leaf(ports, ports->schema->module, "protocol", "NTS_PROTOCOL_TYPE_NETCONF_TLS") == 0) {
+        if(lyd_new_leaf(ports, ports->schema->module, "protocol", "nts-common:NTS_PROTOCOL_TYPE_NETCONF_TLS") == 0) {
             log_error("lyd_new_leaf failed\n");
             return NTS_ERR_FAILED;
         }
@@ -367,7 +367,7 @@ int manager_sr_populate_networking(struct lyd_node *parent, const manager_networ
             return NTS_ERR_FAILED;
         }
 
-        if(lyd_new_leaf(ports, ports->schema->module, "protocol", "NTS_PROTOCOL_TYPE_NETCONF_TLS") == 0) {
+        if(lyd_new_leaf(ports, ports->schema->module, "protocol", "nts-common:NTS_PROTOCOL_TYPE_NETCONF_TLS") == 0) {
             log_error("lyd_new_leaf failed\n");
             return NTS_ERR_FAILED;
         }
@@ -389,7 +389,7 @@ int manager_sr_populate_networking(struct lyd_node *parent, const manager_networ
             return NTS_ERR_FAILED;
         }
 
-        if(lyd_new_leaf(ports, ports->schema->module, "protocol", "NTS_PROTOCOL_TYPE_FTP") == 0) {
+        if(lyd_new_leaf(ports, ports->schema->module, "protocol", "nts-common:NTS_PROTOCOL_TYPE_FTP") == 0) {
             log_error("lyd_new_leaf failed\n");
             return NTS_ERR_FAILED;
         }
@@ -407,7 +407,7 @@ int manager_sr_populate_networking(struct lyd_node *parent, const manager_networ
             return NTS_ERR_FAILED;
         }
 
-        if(lyd_new_leaf(ports, ports->schema->module, "protocol", "NTS_PROTOCOL_TYPE_FTP") == 0) {
+        if(lyd_new_leaf(ports, ports->schema->module, "protocol", "nts-common:NTS_PROTOCOL_TYPE_FTP") == 0) {
             log_error("lyd_new_leaf failed\n");
             return NTS_ERR_FAILED;
         }
@@ -429,7 +429,7 @@ int manager_sr_populate_networking(struct lyd_node *parent, const manager_networ
             return NTS_ERR_FAILED;
         }
 
-        if(lyd_new_leaf(ports, ports->schema->module, "protocol", "NTS_PROTOCOL_TYPE_SFTP") == 0) {
+        if(lyd_new_leaf(ports, ports->schema->module, "protocol", "nts-common:NTS_PROTOCOL_TYPE_SFTP") == 0) {
             log_error("lyd_new_leaf failed\n");
             return NTS_ERR_FAILED;
         }
@@ -447,7 +447,7 @@ int manager_sr_populate_networking(struct lyd_node *parent, const manager_networ
             return NTS_ERR_FAILED;
         }
 
-        if(lyd_new_leaf(ports, ports->schema->module, "protocol", "NTS_PROTOCOL_TYPE_SFTP") == 0) {
+        if(lyd_new_leaf(ports, ports->schema->module, "protocol", "nts-common:NTS_PROTOCOL_TYPE_SFTP") == 0) {
             log_error("lyd_new_leaf failed\n");
             return NTS_ERR_FAILED;
         }
index 2a5ff0f..d7909c4 100644 (file)
@@ -99,14 +99,14 @@ int network_function_run(void) {
     }
 
     //ietf-netconf-monitoring schemas populate with modules and submodules (overwrite default Netopeer2 behaviour)
-    rc = sr_oper_get_items_subscribe(session_running, IETF_NETCONF_MONITORING_MODULE, IETF_NETCONF_MONITORING_STATE_SCHEMAS_SCHEMA_XPATH, netconf_monitoring_state_schemas_cb, 0, SR_SUBSCR_DEFAULT, &session_subscription);
+    rc = sr_oper_get_items_subscribe(session_running, IETF_NETCONF_MONITORING_MODULE, IETF_NETCONF_MONITORING_STATE_SCHEMAS_SCHEMA_XPATH, netconf_monitoring_state_schemas_cb, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
     if(rc != SR_ERR_OK) {
         log_error("error from sr_oper_get_items_subscribe: %s\n", sr_strerror(rc));
         return 0;
     }
 
     //nc-notifications overwrite
-    rc = sr_oper_get_items_subscribe(session_running, NC_NOTIFICATIONS_MODULE, NC_NOTIFICATIONS_STREAMS_SCHEMA_XPATH, notifications_streams_cb, 0, SR_SUBSCR_DEFAULT, &session_subscription);
+    rc = sr_oper_get_items_subscribe(session_running, NC_NOTIFICATIONS_MODULE, NC_NOTIFICATIONS_STREAMS_SCHEMA_XPATH, notifications_streams_cb, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
     if(rc != SR_ERR_OK) {
         log_error("error from sr_oper_get_items_subscribe: %s\n", sr_strerror(rc));
         return 0;
index 7700595..963133b 100644 (file)
 #include "core/framework.h"
 
 #define GEN_KEY_SCRIPT                              "/home/netconf/.ssh/generate-ssh-keys.sh"
-#define KS_CERT_NAME                                "melacon_server_cert"
 #define SERVER_PRIVATE_KEY_PATH                     "/home/netconf/.ssh/melacon.server.key"
 #define SERVER_PUBLIC_KEY_PATH                      "/home/netconf/.ssh/melacon.server.key.pub.pem"
-#define SERVER_CERT_PATH                            "/home/netconf/.ssh/melacon.server.crt"
 #define CA_CERT_PATH                                "/home/netconf/.ssh/ca.pem"
 
 static int nc_config_netconf_port = STANDARD_NETCONF_PORT;
@@ -635,12 +633,10 @@ static int configure_endpoints_connections(sr_session_ctx_t *session) {
         return NTS_ERR_FAILED;
     }
 
-    if (ssh_connections > 0) {
-        rc = create_ssh_listen_endpoints(netconf_node, ssh_connections);
-        if(rc != NTS_ERR_OK) {
-            log_error("could not create %d SSH Listen endpoints on the NETCONF Server\n", ssh_connections);
-            return NTS_ERR_FAILED;
-        }
+    rc = create_ssh_listen_endpoints(netconf_node, ssh_connections);
+    if(rc != NTS_ERR_OK) {
+        log_error("could not create %d SSH Listen endpoints on the NETCONF Server\n", ssh_connections);
+        return NTS_ERR_FAILED;
     }
 
     // create the TLS endpoints in ietf-netconf-server
index 3c57770..cf65ebc 100644 (file)
@@ -40,6 +40,8 @@
 #define NTS_NF_VES_HEARTBEAT_SCHEMA_XPATH                       "/nts-network-function:simulation/network-function/ves/heartbeat-period"
 #define NTS_NF_VES_PNF_REGISTRATION_SCHEMA_XPATH                "/nts-network-function:simulation/network-function/ves/pnf-registration"
 #define NTS_NF_NETWORK_EMULATION_SCHEMA_XPATH                   "/nts-network-function:simulation/network-emulation"
+#define NTS_NF_HARDWARE_EMULATION_SCHEMA_XPATH                  "/nts-network-function:simulation/hardware-emulation"
+#define NTS_NF_HE_NETCONF_DELAY_SCHEMA_XPATH                    "/nts-network-function:simulation/hardware-emulation/netconf-delay"
 #define NTS_NF_VES_ENDPOINT_CONFIG_XPATH                        "/nts-network-function:simulation/ves-endpoint"
 #define NTS_NF_SDN_CONTROLLER_CONFIG_XPATH                      "/nts-network-function:simulation/sdn-controller"
 
@@ -48,7 +50,7 @@
 #define NTS_NF_RPC_FAULTS_CLEAR_SCHEMA_XPATH                    "/nts-network-function:clear-fault-counters"
 #define NTS_NF_RPC_MANUAL_NOTIF_SCHEMA_XPATH                    "/nts-network-function:invoke-notification"
 #define NTS_NF_RPC_FILE_READY_SCHEMA_XPATH                      "/nts-network-function:invoke-ves-pm-file-ready"
-#define NTS_NF_RPC_SET_NETWORK_LATENCY_SCHEMA_XPATH             "/nts-network-function:set-network-latency"
+#define NTS_NF_RPC_EMULATE_TOTAL_LOSS_SCHEMA_XPATH              "/nts-network-function:emulate-total-loss"
 
 #define IETF_KEYSTORE_MODULE                                    "ietf-keystore"
 #define IETF_KEYSTORE_SCHEMA_XPATH                              "/ietf-keystore:keystore"
@@ -71,6 +73,9 @@
 #define IETF_NETCONF_SERVER_CH_SSH_TCP_CLIENT_SCHEMA_XPATH      "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='default-client']/endpoints/endpoint[name='callhome-ssh']/ssh/tcp-client-parameters"
 #define IETF_NETCONF_SERVER_CH_SSH_SERVER_PARAMS_SCEHMA_XPATH   "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='default-client']/endpoints/endpoint[name='callhome-ssh']/ssh/ssh-server-parameters"
 #define IETF_NETCONF_SERVER_CH_CONN_PERSISTENT_SCHEMA_XPATH     "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='default-client']/connection-type/persistent"
+#define IETF_NETCONF_SERVER_CH_TLS_TCP_CLIENT_SCHEMA_XPATH      "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='default-client']/endpoints/endpoint[name='callhome-tls']/tls/tcp-client-parameters"
+#define IETF_NETCONF_SERVER_CH_TLS_SERVER_PARAMS_SCEHMA_XPATH   "/ietf-netconf-server:netconf-server/call-home/netconf-client[name='default-client']/endpoints/endpoint[name='callhome-tls']/tls/tls-server-parameters"
+
 #define IETF_NETCONF_SERVER_SSH_TCP_SERVER_PARAM_SCHEMA_XPATH   "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/tcp-server-parameters"
 #define IETF_NETCONF_SERVER_SSH_SERVER_PARAM_SCHEMA_XPATH       "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters"
 #define IETF_NETCONF_SERVER_TLS_TCP_SERVER_PARAM_SCHEMA_XPATH   "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tcp-server-parameters"
index a56e45b..59b2e58 100644 (file)
 #include "core/framework.h"
 #include "core/xpath.h"
 
-#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 NETCONF_SSH_CALLHOME_CURL_SEND_PAYLOAD_FORMAT   "{\"odl-netconf-callhome-server:device\":[{\"odl-netconf-callhome-server:unique-id\":\"%s\", \"odl-netconf-callhome-server:ssh-client-params\": {\"odl-netconf-callhome-server:host-key\":\"%s\",\"odl-netconf-callhome-server:credentials\":{\"odl-netconf-callhome-server:username\":\"netconf\",\"odl-netconf-callhome-server:passwords\":[\"netconf!\"]}}}]}"
+#define NETCONF_TLS_CALLHOME_CURL_SEND_PAYLOAD_FORMAT   "{\"odl-netconf-callhome-server:device\":[{\"odl-netconf-callhome-server:unique-id\":\"%s\", \"odl-netconf-callhome-server:tls-client-params\": {\"odl-netconf-callhome-server:certificate-id\":\"%s\",\"odl-netconf-callhome-server:key-id\":\"%s\"}}]}"
+#define NETCONF_TRUSTED_CERTIFICATE_CURL_SEND_PAYLOAD_FORMAT   "{\"input\":{\"trusted-certificate\":[{\"name\":\"%s\",\"certificate\":\"%s\"}]}}"
 
 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);
+static int send_odl_add_trusted_certificate(sr_session_ctx_t *current_session);
+static int send_odl_callhome_configuration(sr_session_ctx_t *current_session, bool is_tls);
 
 static int netconf_call_home_status = 0;
 
@@ -73,17 +76,31 @@ int netconf_call_home_feature_start(sr_session_ctx_t *current_session) {
         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\n");
+    controller_details_t *controller = controller_details_get(current_session);
+    if(controller == 0) {
+        log_error("controller_details_get failed\n");
         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\n");
-        return NTS_ERR_FAILED;
+    if (controller->nc_callhome_port == 4335) {
+        // port is CallHome via TLS
+        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\n");
+            controller_details_free(controller);
+            return NTS_ERR_FAILED;
+        }
+    }
+    else {
+        // port is CallHome via SSH
+        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\n");
+            controller_details_free(controller);
+            return NTS_ERR_FAILED;
+        }
     }
+    controller_details_free(controller);
 
     rc = sr_edit_batch(current_session, netconf_node, "merge");
     if(rc != SR_ERR_OK) {
@@ -129,7 +146,6 @@ static int create_ssh_callhome_endpoint(sr_session_ctx_t *current_session, struc
         return NTS_ERR_FAILED;
     }
 
-    
     struct lyd_node *rcl = lyd_new_path(netconf_node, 0, IETF_NETCONF_SERVER_CH_SSH_TCP_CLIENT_SCHEMA_XPATH"/keepalives/idle-time", "1", 0, LYD_PATH_OPT_NOPARENTRET);
     if(rcl == 0) {
         log_error("could not created yang path\n");
@@ -202,7 +218,7 @@ static int create_ssh_callhome_endpoint(sr_session_ctx_t *current_session, struc
         return NTS_ERR_FAILED;
     }
 
-    int rc = send_odl_callhome_configuration(current_session);
+    int rc = send_odl_callhome_configuration(current_session, false);
     if(rc != NTS_ERR_OK) {
         log_add_verbose(2, "could not send ODL Call Home configuration.\n");
     }
@@ -214,30 +230,194 @@ static int create_tls_callhome_endpoint(sr_session_ctx_t *current_session, struc
     assert(current_session);
     assert(netconf_node);
 
-    // checkAS future usage, TLS endpoint yet supported in ODL
+    controller_details_t *controller = controller_details_get(current_session);
+    if(controller == 0) {
+        log_error("controller_details_get failed\n");
+        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\n");
+        return NTS_ERR_FAILED;
+    }
     
+    struct lyd_node *rcl = lyd_new_path(netconf_node, 0, IETF_NETCONF_SERVER_CH_TLS_TCP_CLIENT_SCHEMA_XPATH"/keepalives/idle-time", "1", 0, LYD_PATH_OPT_NOPARENTRET);
+    if(rcl == 0) {
+        log_error("could not created yang path\n");
+        free(controller_ip);
+        return NTS_ERR_FAILED;
+    }
+
+    rcl = lyd_new_path(netconf_node, 0, IETF_NETCONF_SERVER_CH_TLS_TCP_CLIENT_SCHEMA_XPATH"/keepalives/max-probes", "10", 0, LYD_PATH_OPT_NOPARENTRET);
+    if(rcl == 0) {
+        log_error("could not created yang path\n");
+        free(controller_ip);
+        return NTS_ERR_FAILED;
+    }
+
+    rcl = lyd_new_path(netconf_node, 0, IETF_NETCONF_SERVER_CH_TLS_TCP_CLIENT_SCHEMA_XPATH"/keepalives/probe-interval", "5", 0, LYD_PATH_OPT_NOPARENTRET);
+    if(rcl == 0) {
+        log_error("could not created yang path\n");
+        free(controller_ip);
+        return NTS_ERR_FAILED;
+    }
+
+    rcl = lyd_new_path(netconf_node, 0, IETF_NETCONF_SERVER_CH_TLS_TCP_CLIENT_SCHEMA_XPATH"/remote-address", controller_ip, 0, LYD_PATH_OPT_NOPARENTRET);
+    if(rcl == 0) {
+        log_error("could not created yang path\n");
+        free(controller_ip);
+        return NTS_ERR_FAILED;
+    }
+    free(controller_ip);
+
+    char port[20];
+    sprintf(port, "%d", controller_callhome_port);
+    rcl = lyd_new_path(netconf_node, 0, IETF_NETCONF_SERVER_CH_TLS_TCP_CLIENT_SCHEMA_XPATH"/remote-port", port, 0, LYD_PATH_OPT_NOPARENTRET);
+    if(rcl == 0) {
+        log_error("could not created yang path\n");
+        return NTS_ERR_FAILED;
+    }
+
+    rcl = lyd_new_path(netconf_node, 0, IETF_NETCONF_SERVER_CH_TLS_SERVER_PARAMS_SCEHMA_XPATH"/server-identity/keystore-reference/asymmetric-key", KS_KEY_NAME, 0, LYD_PATH_OPT_NOPARENTRET);
+    if(rcl == 0) {
+        log_error("could not created yang path\n");
+        return NTS_ERR_FAILED;
+    }
+
+    rcl = lyd_new_path(netconf_node, 0, IETF_NETCONF_SERVER_CH_TLS_SERVER_PARAMS_SCEHMA_XPATH"/server-identity/keystore-reference/certificate", KS_CERT_NAME, 0, LYD_PATH_OPT_NOPARENTRET);
+    if(rcl == 0) {
+        log_error("could not created yang path\n");
+        return NTS_ERR_FAILED;
+    }
+
+    rcl = lyd_new_path(netconf_node, 0, IETF_NETCONF_SERVER_CH_TLS_SERVER_PARAMS_SCEHMA_XPATH"/client-authentication/required", "", 0, LYD_PATH_OPT_NOPARENTRET);
+    if(rcl == 0) {
+        log_error("could not created yang path\n");
+        return NTS_ERR_FAILED;
+    }
+
+    rcl = lyd_new_path(netconf_node, 0, IETF_NETCONF_SERVER_CH_TLS_SERVER_PARAMS_SCEHMA_XPATH"/client-authentication/ca-certs", "cacerts", 0, LYD_PATH_OPT_NOPARENTRET);
+    if(rcl == 0) {
+        log_error("could not created yang path\n");
+        return NTS_ERR_FAILED;
+    }
+
+    rcl = lyd_new_path(netconf_node, 0, IETF_NETCONF_SERVER_CH_TLS_SERVER_PARAMS_SCEHMA_XPATH"/client-authentication/client-certs", "clientcerts", 0, LYD_PATH_OPT_NOPARENTRET);
+    if(rcl == 0) {
+        log_error("could not created yang path\n");
+        return NTS_ERR_FAILED;
+    }
+
+    rcl = lyd_new_path(netconf_node, 0, IETF_NETCONF_SERVER_CH_TLS_SERVER_PARAMS_SCEHMA_XPATH"/client-authentication/cert-maps/cert-to-name[id='1']/fingerprint", "02:E9:38:1F:F6:8B:62:DE:0A:0B:C5:03:81:A8:03:49:A0:00:7F:8B:F3", 0, LYD_PATH_OPT_NOPARENTRET);
+    if(rcl == 0) {
+        log_error("could not created yang path\n");
+        return NTS_ERR_FAILED;
+    }
+
+    rcl = lyd_new_path(netconf_node, session_context, IETF_NETCONF_SERVER_CH_TLS_SERVER_PARAMS_SCEHMA_XPATH"/client-authentication/cert-maps/cert-to-name[id='1']/map-type", "ietf-x509-cert-to-name:specified", 0, LYD_PATH_OPT_NOPARENTRET);
+    if(rcl == 0) {
+        log_error("could not created yang path\n");
+        return NTS_ERR_FAILED;
+    }
+
+    rcl = lyd_new_path(netconf_node, 0, IETF_NETCONF_SERVER_CH_TLS_SERVER_PARAMS_SCEHMA_XPATH"/client-authentication/cert-maps/cert-to-name[id='1']/name", "netconf", 0, LYD_PATH_OPT_NOPARENTRET);
+    if(rcl == 0) {
+        log_error("could not created yang path\n");
+        return NTS_ERR_FAILED;
+    }
+
+    rcl = lyd_new_path(netconf_node, 0, IETF_NETCONF_SERVER_CH_CONN_PERSISTENT_SCHEMA_XPATH, "", 0, LYD_PATH_OPT_NOPARENTRET);
+    if(rcl == 0) {
+        log_error("could not created yang path\n");
+        return NTS_ERR_FAILED;
+    }
+
+    int rc = send_odl_callhome_configuration(current_session, true);
+    if(rc != NTS_ERR_OK) {
+        log_add_verbose(2, "could not send ODL Call Home configuration.\n");
+    }
+
     return NTS_ERR_OK;
 }
 
 
-static int send_odl_callhome_configuration(sr_session_ctx_t *current_session) {
+static int send_odl_add_trusted_certificate(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\n", SERVER_PUBLIC_SSH_KEY_PATH);
+    char *server_cert = read_key(SERVER_CERT_PATH);
+    if(server_cert == 0) {
+        log_error("could not read the serevr certificate from file %s\n", SERVER_CERT_PATH);
         return NTS_ERR_FAILED;
     }
 
-    char *ssh_key_string;
-    ssh_key_string = strtok(public_ssh_key, " ");
-    ssh_key_string = strtok(NULL, " ");
-    ssh_key_string[strlen(ssh_key_string) - 1] = 0; // trim the newline character
+    char *odl_trusted_certificate_payload = 0;
+    asprintf(&odl_trusted_certificate_payload, NETCONF_TRUSTED_CERTIFICATE_CURL_SEND_PAYLOAD_FORMAT, framework_environment.settings.hostname, server_cert);
+    if(odl_trusted_certificate_payload == 0) {
+        log_error("bad asprintf\n");
+        return NTS_ERR_FAILED;
+    }
+    free(server_cert);
+
+    controller_details_t *controller = controller_details_get(current_session);
+    if(controller == 0) {
+        log_error("controller_details_get failed\n");
+        return NTS_ERR_FAILED;
+    }
+    
+    char *url = 0;
+    asprintf(&url, "%s/rests/operations/netconf-keystore:add-trusted-certificate", controller->base_url);
+    if(url == 0) {
+        log_error("bad asprintf\n");
+        controller_details_free(controller);
+        return NTS_ERR_FAILED;
+    }
+
+    int rc = http_request(url, controller->username, controller->password, "POST", odl_trusted_certificate_payload, 0, 0);
+    if(rc != NTS_ERR_OK) {
+        log_error("http_request failed\n");
+    }
+    
+    free(url);
+    controller_details_free(controller);
+    free(odl_trusted_certificate_payload);
+
+    return rc;
+}
+
+static int send_odl_callhome_configuration(sr_session_ctx_t *current_session, bool is_tls) {
+    assert(current_session);
 
-    // 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.settings.hostname, ssh_key_string);
-    free(public_ssh_key);
+    if (!is_tls) {
+        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\n", 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, " ");
+        ssh_key_string[strlen(ssh_key_string) - 1] = 0; // trim the newline character
+
+        // checkAS we have hardcoded here the username and password of the NETCONF Server
+        asprintf(&odl_callhome_payload, NETCONF_SSH_CALLHOME_CURL_SEND_PAYLOAD_FORMAT, framework_environment.settings.hostname, ssh_key_string);
+        free(public_ssh_key);
+    }
+    else {
+        int ret = send_odl_add_trusted_certificate(current_session);
+        if (ret != NTS_ERR_OK) {
+            log_error("Could not send trusted certificate to ODL.");
+            return NTS_ERR_FAILED;
+        }
+        // checkAS we have hardcoded here the private key of ODL
+        asprintf(&odl_callhome_payload, NETCONF_TLS_CALLHOME_CURL_SEND_PAYLOAD_FORMAT, framework_environment.settings.hostname, framework_environment.settings.hostname, "ODL_private_key_0");
+    }
+
     if(odl_callhome_payload == 0) {
         log_error("bad asprintf\n");
         return NTS_ERR_FAILED;
index 71d62aa..691a64d 100644 (file)
 #include "utils/nts_utils.h"
 #include <stdio.h>
 #include <assert.h>
+#include <pthread.h>
 
 #include "core/session.h"
 #include "core/framework.h"
 #include "core/xpath.h"
 
 static int ves_pnf_sequence_number = 0;
-
+static pthread_t ves_pnf_registration_thread;
+static void* ves_pnf_registration_thread_routine(void *arg);
 static int ves_pnf_registration_send(sr_session_ctx_t *current_session, const char *nf_ip_v4_address, const char *nf_ip_v6_address, int nf_port, nts_mount_point_addressing_method_t mp, bool is_tls);
 static cJSON* ves_create_pnf_registration_fields(const char *nf_ip_v4_address, const char *nf_ip_v6_address, int nf_port, bool is_tls);
 
@@ -49,19 +51,18 @@ int ves_pnf_registration_feature_start(sr_session_ctx_t *current_session) {
     sr_val_t *value = 0;
     int rc = NTS_ERR_OK;
     bool pnf_registration_enabled = false;
-    rc = sr_get_item(current_session, NTS_NF_VES_PNF_REGISTRATION_SCHEMA_XPATH, 0, &value);
-    if(rc == SR_ERR_OK) {
-        pnf_registration_enabled = value->data.bool_val;
-        sr_free_val(value);
-    }
-    else if(rc != SR_ERR_NOT_FOUND) {
-        log_error("sr_get_item failed\n");
-        return NTS_ERR_FAILED;
+    if(strlen(framework_environment.nts.nf_standalone_start_features)) {
+        pnf_registration_enabled = true;
     }
     else {
-        // if value is not set yet, feature enable means we want to start pnf-registration
-        if(strlen(framework_environment.nts.nf_standalone_start_features)) {
-            pnf_registration_enabled = true;
+        rc = sr_get_item(current_session, NTS_NF_VES_PNF_REGISTRATION_SCHEMA_XPATH, 0, &value);
+        if(rc == SR_ERR_OK) {
+            pnf_registration_enabled = value->data.bool_val;
+            sr_free_val(value);
+        }
+        else if(rc != SR_ERR_NOT_FOUND) {
+            log_error("sr_get_item failed\n");
+            return NTS_ERR_FAILED;
         }
     }
 
@@ -70,6 +71,17 @@ int ves_pnf_registration_feature_start(sr_session_ctx_t *current_session) {
         return NTS_ERR_OK;
     }
 
+    if(pthread_create(&ves_pnf_registration_thread, 0, ves_pnf_registration_thread_routine, current_session)) {
+        log_error("could not create thread for heartbeat\n");
+        return NTS_ERR_FAILED;
+    }
+
+    return NTS_ERR_OK;
+}
+
+static void* ves_pnf_registration_thread_routine(void *arg) {
+    sr_session_ctx_t *current_session = arg;
+
     int ssh_base_port = 0;
     int tls_base_port = 0;
     char nf_ip_v4_address[128];
@@ -81,7 +93,7 @@ int ves_pnf_registration_feature_start(sr_session_ctx_t *current_session) {
     nts_mount_point_addressing_method_t mp = nts_mount_point_addressing_method_get(current_session);
     if(mp == UNKNOWN_MAPPING) {
         log_error("mount-point-addressing-method failed\n");
-        return NTS_ERR_FAILED;
+        return (void*)NTS_ERR_FAILED;
     }
     else if(mp == DOCKER_MAPPING) {
         if (framework_environment.settings.ip_v4 != 0) {
@@ -106,40 +118,73 @@ int ves_pnf_registration_feature_start(sr_session_ctx_t *current_session) {
         tls_base_port = framework_environment.host.tls_base_port;
     }
 
+    uint32_t total_regs = 0;
+    struct regs_s {
+        bool sent;
+        uint16_t port;
+        bool is_tls;
+    } *regs;
+
+    regs = (struct regs_s *)malloc(sizeof(struct regs_s) * (1 + framework_environment.settings.ssh_connections + framework_environment.settings.tls_connections));
+    if(regs == 0) {
+        log_error("malloc failed\n");
+        return (void*)NTS_ERR_FAILED;
+    }
+
+
     if((framework_environment.settings.ssh_connections + framework_environment.settings.tls_connections) > 1) {
         for(int port = ssh_base_port; port < ssh_base_port + framework_environment.settings.ssh_connections; port++) {
-            int rc = ves_pnf_registration_send(current_session, nf_ip_v4_address, nf_ip_v6_address, port, mp, false);
-            if(rc != NTS_ERR_OK) {
-                log_error("could not send pnfRegistration message for IPv4=%s and IPv6=%s and port=%d and protocol SSH\n", nf_ip_v4_address, nf_ip_v6_address, port);
-            }
+            regs[total_regs].sent = false;
+            regs[total_regs].port = port;
+            regs[total_regs].is_tls = false;
+            total_regs++;
         }
 
         for(int port = tls_base_port; port < tls_base_port + framework_environment.settings.tls_connections; port++) {
-            int rc = ves_pnf_registration_send(current_session, nf_ip_v4_address, nf_ip_v6_address, port, mp, true);
-            if(rc != NTS_ERR_OK) {
-                log_error("could not send pnfRegistration message for IPv4=%s and IPv6=%s and port=%d and protocol TLS\n", nf_ip_v4_address, nf_ip_v6_address, port);
-            }
+            regs[total_regs].sent = false;
+            regs[total_regs].port = port;
+            regs[total_regs].is_tls = true;
+            total_regs++;
         }
     }
     else {
         bool tls;
-        int port;
         if(framework_environment.settings.tls_connections == 0) {
             tls = false;
-            port = ssh_base_port;
         }
         else {
             tls = true;
-            port = tls_base_port;
         }
 
-        int rc = ves_pnf_registration_send(current_session, nf_ip_v4_address, nf_ip_v6_address, 0, mp, tls);
-        if(rc != NTS_ERR_OK) {
-            log_error("could not send pnfRegistration message for IPv4=%s and IPv6=%s\n", nf_ip_v4_address, nf_ip_v6_address, port);
+        regs[total_regs].sent = false;
+        regs[total_regs].port = 0;
+        regs[total_regs].is_tls = tls;
+        total_regs++;
+    }
+
+    uint32_t remaining = total_regs;
+    while(remaining) {
+        for(int i = 0; i < total_regs; i++) {
+            if(regs[i].sent == false) {
+                uint16_t port = regs[i].port;
+                bool is_tls = regs[i].is_tls;
+                int rc = ves_pnf_registration_send(current_session, nf_ip_v4_address, nf_ip_v6_address, port, mp, is_tls);
+                if(rc == NTS_ERR_OK) {
+                    remaining--;
+                    regs[i].sent = true;
+                }
+                else {
+                    log_error("pnfRegistration failed for ipv4=%s ipv6=%s port=%d is_tls=%d\n", nf_ip_v4_address, nf_ip_v6_address, port, is_tls);
+                }
+            }
+        }
+        if(remaining) {
+            log_error("pnfRegistration could not register all ports; retrying in 5 seconds...\n");
+            sleep(5);
         }
     }
-
-    log_add_verbose(2, "PNF registration enabled\n");
+    free(regs);
+    log_add_verbose(2, "PNF registration finished\n");
     ves_pnf_registration_status = 1;
 
     return NTS_ERR_OK;
index f5c2cf2..eea514c 100644 (file)
@@ -26,7 +26,9 @@
 #define STANDARD_SFTP_PORT      22
 
 #define KS_KEY_NAME                                 "melacon_server_key"
+#define KS_CERT_NAME                                "melacon_server_cert"
 #define SERVER_PUBLIC_SSH_KEY_PATH                  "/home/netconf/.ssh/melacon.server.key.pub"
+#define SERVER_CERT_PATH                            "/home/netconf/.ssh/melacon.server.crt"
 
 //filesystem functions
 bool dir_exists(const char *path);