Bug fix for NTS YANGs. 22/5222/2
authorAlex Stancu <alexandru.stancu@highstreet-technologies.com>
Wed, 2 Dec 2020 17:17:24 +0000 (19:17 +0200)
committerAlex Stancu <alexandru.stancu@highstreet-technologies.com>
Wed, 2 Dec 2020 17:33:01 +0000 (19:33 +0200)
Issue-ID: SIM-50
Change-Id: I0409bf7137b4b663ccb3a82f29318d55d3bf9295
Signed-off-by: Alex Stancu <alexandru.stancu@highstreet-technologies.com>
24 files changed:
docs/overview.rst
docs/release-notes.rst
ntsimulator/deploy/base/build_ntsim-ng.sh
ntsimulator/deploy/base/yang/nts-common.yang
ntsimulator/deploy/base/yang/nts-network-function.yang
ntsimulator/deploy/nts-manager/ubuntu.Dockerfile
ntsimulator/deploy/nts-manager/yang/nts-manager.yang
ntsimulator/deploy/nts-manager/yang/nts-o-ran-pac.yang
ntsimulator/deploy/nts-manager/yang/nts-x-ran-pac.yang
ntsimulator/deploy/o-ran/ubuntu.Dockerfile
ntsimulator/deploy/x-ran/ubuntu.Dockerfile
ntsimulator/ntsim-ng/core/app/manager.c
ntsimulator/ntsim-ng/core/app/manager_operations.c
ntsimulator/ntsim-ng/core/app/network_function.c
ntsimulator/ntsim-ng/core/docker.c
ntsimulator/ntsim-ng/core/faults/faults_logic.c
ntsimulator/ntsim-ng/core/framework.c
ntsimulator/ntsim-ng/features/web_cut_through/web_cut_through.c [new file with mode: 0644]
ntsimulator/ntsim-ng/features/web_cut_through/web_cut_through.h [new file with mode: 0644]
ntsimulator/ntsim-ng/main.c
ntsimulator/ntsim-ng/utils/rand_utils.c
ntsimulator/ntsim-ng/utils/sys_utils.c
ntsimulator/ntsim-ng/utils/sys_utils.h
ntsimulator/regxstring/gen_regex.cpp

index b7203ba..17fd729 100644 (file)
 sim/o1-interface Overview
 ==========================
 
-The O1-interface simulator is based on the Network Topology Simulator (NTS). NTS is a framework that allows simulating devices that expose a management interface through a NETCONF/YANG interface. The NTS is loaded with the YANG files associated with the O-RAN O1 interface specifications.
+# Network Topology Simulator (NTS) | next generation
 
-The NETCONF/YANG management interface is simulated, and the O1 YANG models are loaded by the framework to be exposed. Random data is generated based on the specific models, such that each simulated device presents different data on its management interface.
+The Network Topology Simulator is a framework that allows simulating devices that expose a management interface through a NETCONF/YANG interface.
 
-The NTS Manager can be used to specify the simulation details and to manage the simulation environment at runtime.
+## Description
+
+### Overview
+
+The NETCONF/YANG management interface is simulated, and any YANG models can be loaded by the framework to be exposed. Random data is generated based on the specific models, such that each simulated device presents different data on its management interface.
 
 The NTS framework is based on several open-source projects:
+* [cJSON](https://github.com/DaveGamble/cJSON)
+* [libcurl](https://curl.haxx.se)
+* [libyang](https://github.com/CESNET/libyang)
+* [sysrepo](https://github.com/sysrepo/sysrepo)
+* [libnetconf2](https://github.com/CESNET/libnetconf2)
+* [Netopeer2](https://github.com/CESNET/Netopeer2) 
+
+The NTS Manager can be used to specify the simulation details and to manage the simulation environment at runtime.
+
+Each simulated device is represented as a docker container, where the NETCONF Server is running. The creation and deletion of docker containers associated with simulated devices is handled by the NTS Manager. The NTS Manager is also running as a docker container and exposes a NETCONF/YANG interface to control the simulation.
+
+### NTS Manager
+
+The purpose of the NTS Manager is to ease the utilization of the NTS framework. It enables the user to interact with the simulation framework through a NETCONF/YANG interface. The user has the ability to modify the simulation parameters at runtime and to see the status of the current state of the NTS. The NETCONF/YANG interface will be detailed below.
+
+```
+module: nts-manager
+  +--rw simulation
+     +--rw network-functions
+     |  +--rw network-function* [function-type]
+     |     +--rw function-type                    identityref
+     |     +--rw started-instances                uint16
+     |     +--rw mounted-instances                uint16
+     |     +--rw mount-point-addressing-method?   enumeration
+     |     +--rw docker-instance-name             string
+     |     +--rw docker-version-tag               string
+     |     +--rw docker-repository                string
+     |     +--rw fault-generation
+     |     |  +--rw fault-delay-list* [index]
+     |     |  |  +--rw index           uint16
+     |     |  |  +--rw delay-period?   uint16
+     |     |  +--ro fault-count {faults-status}?
+     |     |     +--ro normal?     uint32
+     |     |     +--ro warning?    uint32
+     |     |     +--ro minor?      uint32
+     |     |     +--ro major?      uint32
+     |     |     +--ro critical?   uint32
+     |     +--rw netconf
+     |     |  +--rw faults-enabled?   boolean
+     |     |  +--rw call-home?        boolean
+     |     +--rw ves
+     |     |  +--rw faults-enabled?     boolean
+     |     |  +--rw pnf-registration?   boolean
+     |     |  +--rw heartbeat-period?   uint16
+     |     +--ro instances
+     |        +--ro instance* [name]
+     |           +--ro mount-point-addressing-method?   enumeration
+     |           +--ro name                             string
+     |           +--ro networking
+     |              +--ro docker-ip?     inet:ip-address
+     |              +--ro docker-port*   inet:port-number
+     |              +--ro host-ip?       inet:ip-address
+     |              +--ro host-port*     inet:port-number
+     +--rw sdn-controller
+     |  +--rw controller-ip?                       inet:ip-address
+     |  +--rw controller-port?                     inet:port-number
+     |  +--rw controller-netconf-call-home-port?   inet:port-number
+     |  +--rw controller-username?                 string
+     |  +--rw controller-password?                 string
+     +--rw ves-endpoint
+     |  +--rw ves-endpoint-protocol?      enumeration
+     |  +--rw ves-endpoint-ip?            inet:ip-address
+     |  +--rw ves-endpoint-port?          inet:port-number
+     |  +--rw ves-endpoint-auth-method?   authentication-method-type
+     |  +--rw ves-endpoint-username?      string
+     |  +--rw ves-endpoint-password?      string
+     |  +--rw ves-endpoint-certificate?   string
+     +--ro base-port?           inet:port-number
+     +--ro ssh-connections?     uint8
+     +--ro tls-connections?     uint8
+     +--ro cpu-usage?           percent
+     +--ro mem-usage?           uint32
+```
+
+#### Detailed information about the YANG attributes
+
+Under **simulation** there are 3 configuration containers and a couple of statistics leafs:
+* **network-functions** - represents the simulation data, which will be best described below
+* **sdn-controller** - this container groups the configuration related to the ODL based SDN controller that the simulated devices can connect to
+    * **controller-ip** - the IP address of the ODL based SDN controller where the simulated devices can be mounted. Both IPv4 and IPv6 are supported
+    * **controller-port** - the port of the ODL based SDN controller
+    * **controller-netconf-call-home-port** - the NETCONF Call Home port of the ODL based SDN controller
+    * **controller-username** - the username to be used when connecting to the ODL based SDN controller
+    * **controller-password** - the password to be used when connecting to the ODL based SDN controller
+* **ves-endpoint** - this container groups the configuration related to the VES endpoint where the VES messages are targeted
+    * **ves-endpoint-protocol** - the protocol of the VES endpoint where VES messages are targeted
+    * **ves-endpoint-ip** - the IP address of the VES endpoint where VES messages are targeted
+    * **ves-endpoint-port** - the port address of the VES endpoint where VES messages are targeted
+    * **ves-endpoint-auth-method** - the authentication method to be used when sending the VES message to the VES endpoint. Possible values are:
+        + *no-auth* - no authentication
+        + *cert-only* - certificate only authentication in this case the certificate to be used for the communication must be configured
+        + *basic-auth* - classic username/password authentication in this case both the username and password need to be configured
+        + *cert-basic-auth* - authentication that uses both username/password and a certificate all three values need to be configured in this case
+    * **ves-endpoint-username** - the username to be used when authenticating to the VES endpoint
+    * **ves-endpoint-password** - the password to be used when authenticating to the VES endpoint
+    * **ves-endpoint-certificate** - the certificate to be used when authenticating to the VES endpoint
+* base-port - status node indicating the start port for mapping the simulated network functions; ports are assigned in an increasing order starting from this base port
+* ssh-connections - status node indicating the number of SSH Endpoints each network function instance exposes
+* tls-connections - status node indicating the number of TLS Endpoints each network function instance exposes
+* cpu-usage - status node indicating the **total** CPU usage of the simulation
+* mem-usage - status node indicating the **total** memory usage of the simulation
+
+Under the **network-functions** there is the **network-function** list. This list is automatically populated by the NTS Manager at start time with the available network functions. No changes at the actual list are allowed (adding or removing elements), only the changes of the properties of the elements have effect. The structure of an element of this list is described below:
+* **function-type** - the function type
+* **started-devices** - represents the number of simulated devices. The default value is 0, meaning that when the NTS is started, there are no simulated devices. When this value is increased to **n**, the NTS Manager starts docker containers in order to reach **n** simulated devices. If the value is decreased to **k**, the NTS Manager will remove docker containers in a LIFO manner, until the number of simulated devices reaches **k**
+* **mounted-devices** - represents the number of devices to be mounted to an ODL based SDN Controller. The same phylosophy as in the case of the previous leaf applies. If this number is increased, the number of ODL mountpoints increases. Else, the simulated devices are being unmounted from ODL. The number of mounted devices cannot exceed the number of started devices. The details about the ODL controller where to mount/unmount are given by the **sdn-controller** container
+* **mount-point-addressing-method** - addressing method of the mount point. Possible values are:
+    + *docker-mapping* - [default value] future started simulated devices will be mapped on the Docker container
+    + *host-mapping* - future started simulated devices will me mapped on the host's IP address and port based on *base-port*
+* **docker-instance-name** - the prefix for future simulated devices (to this name a dash and an increasing number is added)
+* **docker-version-tag** - a specific version tag for the Docker container to be ran. if empty, the latest version is ran
+* **docker-repository** - the prefix for containing the Docker repository information. if local repository is used, value can be either blank or *local*
+* **fault-generation** - container which groups the fault generation features, explained later
+* **netconf** - container with settings for enabling or disabling netconf features
+    * **faults-enabled** - enable or disable faults over netconf
+    * **call-home** - enable the NETCONF Call Home feature. If set to 'true', each simulated device, when booting up, will try to Call Home to the SDN Controller.
+* **ves** - container with settings for enabling or disabling VES features
+    * **faults-enabled** - enable or disable faults over VES
+    * **pnf-registration** - enable PNF registration on start
+    * **heartbeat-period** - the number of seconds between VES heartbeat messages
+    
+#### Manager datastore changes mode of operation
+
+Changing any value from **sdn-controller** or **ves-endpoint** containers will be propagated to all running simulated network functions, and all new ones will use the values here. In the same manner, triggering any changes to the **fault-generation**, **netconf** and **ves** settings in a network function element from the *network-function* list will automatically propagate to all running network functions of the same *function-type*. However, changing the *docker-\** leafs of the *network-function* won't propagate, as they're only used as settings for starting new network functions.
+
+### NTS network function 
+
+The NTS network function represents the actual simulated device.
+
+```
+module: nts-network-function
+  +--rw simulation
+     +--rw network-function
+     |  +--rw mount-point-addressing-method?   enumeration
+     |  +--rw fault-generation
+     |  |  +--rw fault-delay-list* [index]
+     |  |  |  +--rw index           uint16
+     |  |  |  +--rw delay-period?   uint16
+     |  |  +--ro fault-count {faults-status}?
+     |  |     +--ro normal?     uint32
+     |  |     +--ro warning?    uint32
+     |  |     +--ro minor?      uint32
+     |  |     +--ro major?      uint32
+     |  |     +--ro critical?   uint32
+     |  +--rw netconf
+     |  |  +--rw faults-enabled?   boolean
+     |  |  +--rw call-home?        boolean
+     |  +--rw ves
+     |     +--rw faults-enabled?     boolean
+     |     +--rw pnf-registration?   boolean
+     |     +--rw heartbeat-period?   uint16
+     +--rw sdn-controller
+     |  +--rw controller-ip?                       inet:ip-address
+     |  +--rw controller-port?                     inet:port-number
+     |  +--rw controller-netconf-call-home-port?   inet:port-number
+     |  +--rw controller-username?                 string
+     |  +--rw controller-password?                 string
+     +--rw ves-endpoint
+        +--rw ves-endpoint-protocol?      enumeration
+        +--rw ves-endpoint-ip?            inet:ip-address
+        +--rw ves-endpoint-port?          inet:port-number
+        +--rw ves-endpoint-auth-method?   authentication-method-type
+        +--rw ves-endpoint-username?      string
+        +--rw ves-endpoint-password?      string
+        +--rw ves-endpoint-certificate?   string
+
+  rpcs:
+    +---x datastore-random-populate
+    |  +--ro output
+    |     +--ro status    enumeration
+    +---x feature-control
+    |  +---w input
+    |  |  +---w features    ntsc:feature-type
+    |  +--ro output
+    |     +--ro status    enumeration
+    +---x invoke-notification
+    |  +---w input
+    |  |  +---w notification-format    enumeration
+    |  |  +---w notification-object    string
+    |  +--ro output
+    |     +--ro status    enumeration
+    +---x invoke-ves-pm-file-ready
+    |  +---w input
+    |  |  +---w file-location    string
+    |  +--ro output
+    |     +--ro status    enumeration
+    +---x clear-fault-counters
+       +--ro output
+          +--ro status    enumeration
+```
+
+#### Detailed information about the YANG attributes
+
+All de details and mechanisms of the **network-function** container are explained in the **NTS Manager** section. Besides this container, there are also a couple of RPCs defined:
+* **datastore-random-populate** - calling this will trigger the network function to populate all its datastore with random data, and based on the *config.json* defined rules
+* **feature-control** - calling this will enable selected features. currently available features are:
+    * **ves-file-ready** - enables VES file ready, and stats a FTP and a SFTP server on the network function
+    * **ves-heartbeat** - enabled VES heartbeat feature
+    * **ves-pnf-registration** - enables VES PNF registration
+    * **manual-notification-generation** - enables the manual notification generation feature
+    * **netconf-call-home** - enables NETCONF's Call Home feature
+    * **web-cut-through** - enables web cut through, adding the info to the ietf-system module
+* **invoke-notification** - this RPC is used for forcing a simulated device to send a NETCONF notification, as defined by the user. 
+    - The **input** needed by the RPC:
+        - **notification-format** - can be either *json* or *xml*
+        - **notification-object** - this is a string containing the notification object that we are trying to send from the simulated device, in JSON format. **Please note that the user has the responsibility to ensure that the JSON object is valid, according to the definition of the notification in the YANG module.** There is no possibility to see what was wrong when trying to send an incorrect notification. The RPC will only respond with an "ERROR" status in that case, without further information. E.g. of a JSON containing a notification object of type ***otdr-scan-result*** defined in the ***org-openroadm-device*** YANG module: ***{"org-openroadm-device:otdr-scan-result":{"status":"Successful","status-message":"Scan result was successful","result-file":"/home/result-file.txt"}}***. **Please note that the notification object contains also the name of the YANG model defning it, as a namespace, as seen in the example.**
+    - The **output** returned by the RPC:
+        - **status** - if the notification was send successfully by the simulated device, the RPC will return a **SUCCESS** value. Else, the RPC will return a **ERROR** value.
+* **invoke-ves-pm-file-ready** - as name impiles, it invokes a file ready VES request, with a specified *file-location*
+* **clear-fault-counters** - clears all counters for the fault generation system. see **Fault generation** below.
+
+#### Network function operation
+
+Under usual operation, the network functions are managed by the manager which will perform the operations listed below. However, if a user chooses to, it can manually start up a network function, and manage it via NETCONF (datastore and RPCs).
+1. Create and start Docker container
+2. Set the VES and SDN controller data via NETCONF
+3. Invoke **datastore-random-populate** RPC to populate the datastore
+4. Invoke **feature-control**, enabling **ALL** the features.
+
+#### Datastore random population
+
+The datastore will be populated with random values on each of its leafs. However, certain there is some control on the population itself, which can be found in *config.json*, which is commented. Please note that the nodes below should be main nodes in *config.json*:
+```
+"debug-max-string-size" : 50,       //max size of string. if not set, default is 255
+    
+"populate-rules" : {
+    "excluded-modules": [           //modules to be excluded from populating
+        "sysrepo",
+        "sysrepo-monitoring",
+        "ietf-yang-library",
+        "ietf-netconf-acm",
+        "ietf-netconf-monitoring",
+        "nc-notifications",
+        "ietf-keystore",
+        "ietf-truststore",
+        "ietf-system",
+        "ietf-netconf-server"
+    ],
+    
+    "default-list-instances": 1,    //default number of instances a list or a leaflist should be populated with
+    "custom-list-instances" : [     //custom number of list instances. instance is schema name, and should reflect a list or a leaflist
+        {"/ietf-interfaces:interfaces/interface": 2}, //2 instances of this. if 0, list will be excluded from populating
+    ],
+    "restrict-schema" : [           //restrictions to certain schema nodes to a set of values (so no random here)
+        {"/ietf-interfaces:interfaces/interface/type" : ["iana-if-type:ethernetCsmacd", "other-value"]},
+        {"/ietf-interfaces:interfaces/interface/name" : ["name1", "name2"]}
+    ]
+}
+```
+
+#### Fault generation
+
+Fault generation is controlled using a combination of JSON and YANG settings.
+From the JSON perspective, the settings are as below:
+```
+"alarm-rules" : {
+    "yang-notif-template" : "<xml ... %%severity%%  $$time$$  %%custom1%%>",
+    "choosing-method" : "random | linear",
+    "alarms" : [
+        {
+            //ves mandatory fields
+            "condition" : "",
+            "object"    : "",
+            "severity"  : "",
+            "date-time" : "$$time$$",
+            "specific-problem" : "",
+
+            //template custom fileds
+            "custom1" : "",
+            "custom2" : ""
+        }
+        ...
+        {
+            ...
+        }
+    ]
+}
+```
+* **alarm-rules** node should be a main node in *config.json* for the respective network function in order for the fault generation to be enabled
+    * **yang-notif-template** - template of the yang notification model in current network function. can be "" to disable notifications. must always be present
+    * **choosing-method** - method to choose the alarm. can be either *linear* or *random*, and must always be present
+    * **alarms** list of alarms to choose from by "choosing-method". it can contain any number of fields, custom ones, along with the mandatory VES fields presented below:
+        * **condition**
+        * **object**
+        * **severity** - should correspond to VES defined: NORMAL, WARNING, MINOR, MAJOR, CRITICAL (case sensitive)
+        * **date-time**
+        * **specific-problem**
+
+On the **yang-notif-template** and on any of the fields, there are two options for creating "dynamic" content (also see example above):
+* **variables** - any field put in between %% will be replaced with the field's value
+* **functions** - function names are put in between $$. Available functions are:
+    * **time** - returns current timestamp in a YANG date-time format
+    * **uint8_counter** - a unique 8-bit counter, starting from 0, each time this function is found, the counter is automatically increased; when going above the max value, it will reset from 0
+    * **uint16_counter** - a unique 16-bit counter, starting from 0, each time this function is found, the counter is automatically increased; when going above the max value, it will reset from 0
+    * **uint32_counter** - a unique 32-bit counter, starting from 0, each time this function is found, the counter is automatically increased; when going above the max value, it will reset from 0
+
+It is worth to mention that the replacement is done within any field, of any field. This means that it is possible to have nested fields and functions. See example for better understanding.
+
+From the YANG perspective, one can control whether faults are enabled or disabled independently via NETCONF and/or VES, through their respective containers described in the sections above. The YANG **fault-generation** container contains:
+* **fault-delay-list** - a list with elements which consists of *index* (unimportant, but needs to be unique) and *delay-period* which represents the number of seconds in between the current fault and the next fault. Please note that the fault is chosen from and based on the settings esablished in *config.json*
+* **fault-count** - the status of the faults encountered by the network function; it is not present in the manager's schema
+
+In order to clear the **fault-count** counters, on the **network-function** module there is a **clear-fault-counters** RPC which can be called via NETCONF.
+
+### NTS Application
+
+Either of the two main functionalities (*manager* and *network-function*) are implemented by the same binary application. Besides this functionality, the application can also do some utility functions, which can be used if the application is ran from the CLI (command line interface), along with some parameters.
+
+#### CLI paramters
+The paramers are described below:
+- --help - shows the help (also described here)
+- --docker-init - is automatically used by Docker when building the images to install modules and enable features. Described in the next chapter. **Do not run manually**
+- the two main modes:
+    - --manager - runs in manager mode
+    - --network-function - runs in network function mode
+- global settings, which can be used with **ANY** of the other operating modes:
+    - --operational-only - used in testing. do not use the RUNNING datastore, only do the population on OPERATIONAL datastore
+    - --fixed-rand - used in testing. specify a fixed value seed for the randomness
+    - --verbose - set the verbose level. can range from 0 to 2, default is 1
+    - --workspace - set the current working workspace. the workspace must contain the *config* and *log* folders    
+- test modes - do not use
+- utilitary functions:
+    - --ls - list all modules in the datastore with their attributes
+    - --schema - list the schema of an xpath given as parameter
+    - --populate - populate the datastore upon starting
+    - --enable-features - enable all features upon starting, after (if requested) the populating was done
+    - --nc-server-init - initialize netconf server
+    - --loop - after everything is done, run an endless loop
+
+#### Docker container initialization
+
+The NTS app is responsible for initializing the Docker container upon build. What it actually does is described below:
+1. Install modules located in the *deploy/yang/* folder recusively
+    - note that if a module requires startup data (mandatory data), this can be acheived by having an **XML** file with this data along the YANG file. For example, if, let's say *ietf-interfaces.yang* would require startup date, there must be a *ietf-interfaces.xml* located in the same folder.
+2. Enable all YANG features of the modules, unless specifically excluded
+
+If the initialization failes, the result is returned to the Docker builder, so the build will fail, and user can see the output. Docker initialization can be customized from the *config.json* file, as described below. The example is self-expainatory, and the *docker-rules* node needs to be a main node of *config.json*:
+
+```
+"docker-rules": {
+    "excluded-modules": [          //excluded modules from installing
+        "module1",
+        "module2"
+    ],
+    "excluded-features": [         //excluded features from installing
+        "feature1",
+        "feature2"
+    ]
+}
+```
+
+## Usage
+
+The NTS Manager can be used to start any type of simulated network function.
+
+### Building the images
+
+The `nts_build.sh` script should be used for building the docker images needed by the NTS to the local machine. This will create docker images for the Manager and for each type of simulated network function.
+
+The user can also directly use the already built docker images, that are pushed to the highstreet docker repository. This can be done by using the `nts_pull_highstreet_repo.sh` script, which will pull all the images locally.
+
+### Starting the NTS Manager
 
-* `Netopeer2 <https://github.com/CESNET/Netopeer2>`_
+The **nts-manager-ng** can be started using the docker-compose file in this repo. The file assumes that the docker images were pulled from the highstreet docker repository.
 
-* `libnetconf2 <https://github.com/CESNET/libnetconf2>`_
+```
+docker-compose up
+```
 
-* `libyang <https://github.com/CESNET/libyang>`_
+Before starting, the user should set the environment variables defined in the docker-compose file according to his needs:
+* **NETCONF_NTS_HOST_IP**: an IP address from the host, which should be used by systems outside the local machine to address the simulators;
+* **NETCONF_NTS_HOST_BASE_PORT**: the port from where the allocation for the simulated network functions should start;
+* **IPv6Enabled**: should be set to `true` if IPv6 is enabled in the docker daemon and the user wants to use IPv6 to address the simulated  network functions.
 
-* `sysrepo <https://github.com/sysrepo/sysrepo>`_ - all of these are used for the implementation of the NETCONF Server, both in the NTS Manager and in each simulated device
+When using the highstreet docker repository for the images, in each simulated network-function the **docker-repository** leaf must be set accordingly  (to the value: *10.20.6.10:30000/hightec*), because all the docker images that are being pulled from the docker repo have this prefix.
 
-* `cJSON <https://github.com/DaveGamble/cJSON>`_ - used to create the JSON payloads for talking with the simulation framework
+## Release notes
+### version 1.0.2
+- [fixed] bug that occured when trying to start a wrong instance (bad docker-repository or docker-tag)
+- [fixed] when populating the fault-delay-list, if the sum of all the faults was 0, the network funciton kept on generating faults and crashed
 
-* `pyang <https://github.com/mbj4668/pyang>`_ - used to create random data from the YANG models that are exposed
+### version 1.0.1
+- [feature-add] added web-cut-through feature
+- [fixed] mount-point-addressing-method was mistakenly changing after starting
 
-Each simulated device is represented as a docker container, where the NETCONF Server is running. The creation and deletion of docker containers associated with simulated devices is handled by the NTS Manager. The NTS Manager is also running as a docker container and exposes a NETCONF/YANG interface to control the simulation.
\ No newline at end of file
+### version 1.0.0
+Initial release.
index 516a823..0f33311 100644 (file)
@@ -21,6 +21,12 @@ Version history
 | **Date**           | **Ver.**           | **Author**         | **Comment**        |
 |                    |                    |                    |                    |
 +--------------------+--------------------+--------------------+--------------------+
+| 2020-12-02         | 1.0.3              |  Alex Stancu       | Cherry release     |
+|                    |                    |                    |                    |
++--------------------+--------------------+--------------------+--------------------+
+| 2020-11-11         | 1.0.0              |  Alex Stancu       | Cherry release     |
+|                    |                    |                    |                    |
++--------------------+--------------------+--------------------+--------------------+
 | 2020-06-08         | 0.6.1              |  Alex Stancu       | Bronze release     |
 |                    |                    |                    |                    |
 +--------------------+--------------------+--------------------+--------------------+
@@ -37,7 +43,25 @@ The O1 interface simulator is a framework that provides simulated devices with a
 
 Release Data
 ------------
-N/A
+version 1.0.3
+
+[fixed] fixed issues where ODL could not parse the correct versions for yang files
+
+
+version 1.0.2
+
+[fixed] bug that occured when trying to start a wrong instance (bad docker-repository or docker-tag)
+[fixed] when populating the fault-delay-list, if the sum of all the faults was 0, the network funciton kept on generating faults and crashed
+
+
+version 1.0.1
+
+[feature-add] added web-cut-through feature
+[fixed] mount-point-addressing-method was mistakenly changing after starting
+
+
+version 1.0.0
+Initial release.
 
 Feature Additions
 ^^^^^^^^^^^^^^^^^
@@ -63,8 +87,6 @@ The following docker containers are the resulting artefacts of the sim-o1-projec
 
 * **o-ran-sc/ntsim-o-ran-ru-fh** - this image contains a simulated device which exposes a management interface via NETCONF/YANG, implementing the O1 FH interface specifications;
 
-* **o-ran-sc/ntsim-o-ran-sc-o-ran-ru** - this image contains a simulated device which exposes a management interface via NETCONF/YANG, implementing the O-RAN-SC O-RU Management interface defined by the OAM project;
-
 * **o-ran-sc/ntsim-x-ran** - this image contains a simulated device which exposes a management interface via NETCONF/YANG, implementing the X-RAN Management interface.
 
 
index dbabaab..49cac32 100755 (executable)
@@ -45,8 +45,9 @@ files=(
     "features/ves_pnf_registration/ves_pnf_registration.c"
     "features/ves_heartbeat/ves_heartbeat.c"
     "features/ves_file_ready/ves_file_ready.c"
-    "features/netconf_call_home/netconf_call_home.c"
     "features/manual_notification/manual_notification.c"
+    "features/netconf_call_home/netconf_call_home.c"
+    "features/web_cut_through/web_cut_through.c"
     "main.c"
 )
 
index 0dd1472..ea7e60b 100644 (file)
@@ -18,6 +18,13 @@ module nts-common {
   description
     "This module contains common yang definitions YANG definitions for the Network Topology Simulator.";
 
+  revision 2020-11-20 {
+    description
+      "Add feature-type for the Web cut through feature.";
+    reference
+      "O-RAN-SC SIM project";
+  }
+
   revision 2020-10-22 {
     description
       "Add feature-type for the NETCONF Call Home feature.";
@@ -94,6 +101,11 @@ module nts-common {
             description
             "Controls the NETCONF Call Home feature.";
         }
+        bit web-cut-through {
+            position 5;
+            description
+            "Controls the Web Cut Through feature.";
+        }
     }
     description
     "Describes the features that can be enabled/disabled in the Network Function.";
index 5575d33..65fee7b 100644 (file)
@@ -5,7 +5,6 @@ module nts-network-function {
 
   import nts-common {
     prefix ntsc;
-    revision-date 2020-10-22;
   }
 
   organization
@@ -19,6 +18,13 @@ module nts-network-function {
   description
     "This module contains YANG definitions for the Network Topology Simulator - Network Functions";
 
+  revision 2020-11-30 {
+    description
+      "Cleared revision for nts-common import.";
+    reference
+      "O-RAN-SC SIM project";
+  }
+
   revision 2020-10-28 {
     description
       "Add RPC for clearing the fault counters.";
index 4978e0d..a119cce 100644 (file)
@@ -17,7 +17,7 @@
 #### DEVICE ####
 ################
 
-FROM nexus3.o-ran-sc.org:10004/o-ran-sc/nts-ng-base:latest
+FROM o-ran-sc/nts-ng-base:latest
 LABEL maintainer="alexandru.stancu@highstreet-technologies.com / adrian.lita@highstreet-technologies.com"
 
 # ntsim-ng configuration and deployment
index 36691b6..311a730 100644 (file)
@@ -9,7 +9,6 @@ module nts-manager {
 
   import nts-common {
     prefix ntsc;
-    revision-date 2020-10-22;
   }
 
   organization
@@ -23,6 +22,13 @@ module nts-manager {
   description
     "This module contains YANG definitions for the Network Topology Simulator - Manager.";
 
+  revision 2020-11-30 {
+    description
+      "Cleared revision for nts-common import.";
+    reference
+      "O-RAN-SC SIM project";
+  }
+
   revision 2020-10-06 {
     description
       "Initial revision for the Network Topology Simulator - Next Generation";
index 6e949c3..24313a7 100644 (file)
@@ -5,7 +5,6 @@ module nts-o-ran-pac {
 
   import nts-common {
       prefix ntsc;
-      revision-date 2020-10-22;
   }
 
   organization
@@ -19,6 +18,13 @@ module nts-o-ran-pac {
   description
     "This module contains YANG definitions for the Network Topology Simulator - O-RAN extensions.";
 
+  revision 2020-11-30 {
+    description
+      "Cleared revision for nts-common import.";
+    reference
+      "O-RAN implementation";
+  }
+
   revision 2020-10-26 {
     description
       "Initial revision for the Network Topology Simulator - Next Generation";
index ac9fea5..70b22d9 100644 (file)
@@ -5,7 +5,6 @@ module nts-x-ran-pac {
 
   import nts-common {
       prefix ntsc;
-      revision-date 2020-10-22;
   }
 
   organization
@@ -19,6 +18,13 @@ module nts-x-ran-pac {
   description
     "This module contains YANG definitions for the Network Topology Simulator - X-RAN extensions.";
 
+  revision 2020-11-30 {
+    description
+      "Cleared revision for nts-common import.";
+    reference
+      "X-RAN implementation";
+  }
+
   revision 2020-10-26 {
     description
       "Initial revision for the Network Topology Simulator - Next Generation";
index f5cdd80..329fa7f 100644 (file)
@@ -17,7 +17,7 @@
 #### DEVICE ####
 ################
 
-FROM nexus3.o-ran-sc.org:10004/o-ran-sc/nts-ng-base:latest
+FROM o-ran-sc/nts-ng-base:latest
 LABEL maintainer="alexandru.stancu@highstreet-technologies.com / adrian.lita@highstreet-technologies.com"
 
 # ntsim-ng configuration and deployment
index f5cdd80..329fa7f 100644 (file)
@@ -17,7 +17,7 @@
 #### DEVICE ####
 ################
 
-FROM nexus3.o-ran-sc.org:10004/o-ran-sc/nts-ng-base:latest
+FROM o-ran-sc/nts-ng-base:latest
 LABEL maintainer="alexandru.stancu@highstreet-technologies.com / adrian.lita@highstreet-technologies.com"
 
 # ntsim-ng configuration and deployment
index 60b8006..f20ea0e 100644 (file)
@@ -84,8 +84,8 @@ int manager_run(void) {
         manager_context[i].mounted_instances = 0;
         manager_context[i].mount_point_addressing_method = strdup("docker-mapping");
         manager_context[i].docker_instance_name = strdup(manager_context[i].function_type->name);
-        manager_context[i].docker_version_tag = strdup("");
-        manager_context[i].docker_repository = strdup("");
+        manager_context[i].docker_version_tag = strdup("latest");
+        manager_context[i].docker_repository = strdup("local");
     }
     free(found);
 
@@ -230,10 +230,12 @@ static int manager_populate_sysrepo_network_function_list(void) {
     char int_to_str[30];
 
     //setup sdn-controller defaults
-    rc = sr_set_item_str(session_running, NTS_SDN_CONTROLLER_CONFIG_XPATH"/controller-ip", (const char*)framework_environment.sdn_controller_ip, 0, 0);
-    if(rc != SR_ERR_OK) {
-        log_error("sr_set_item_str failed");
-        return NTS_ERR_FAILED;
+    if(strlen(framework_environment.sdn_controller_ip)) {
+        rc = sr_set_item_str(session_running, NTS_SDN_CONTROLLER_CONFIG_XPATH"/controller-ip", (const char*)framework_environment.sdn_controller_ip, 0, 0);
+        if(rc != SR_ERR_OK) {
+            log_error("sr_set_item_str failed");
+            return NTS_ERR_FAILED;
+        }
     }
 
     sprintf(int_to_str, "%d", framework_environment.sdn_controller_port);
@@ -250,29 +252,37 @@ static int manager_populate_sysrepo_network_function_list(void) {
         return NTS_ERR_FAILED;
     }
 
-    rc = sr_set_item_str(session_running, NTS_SDN_CONTROLLER_CONFIG_XPATH"/controller-username", (const char*)framework_environment.sdn_controller_username, 0, 0);
-    if(rc != SR_ERR_OK) {
-        log_error("sr_set_item_str failed");
-        return NTS_ERR_FAILED;
+    if(strlen(framework_environment.sdn_controller_username)) {
+        rc = sr_set_item_str(session_running, NTS_SDN_CONTROLLER_CONFIG_XPATH"/controller-username", (const char*)framework_environment.sdn_controller_username, 0, 0);
+        if(rc != SR_ERR_OK) {
+            log_error("sr_set_item_str failed");
+            return NTS_ERR_FAILED;
+        }
     }
 
-    rc = sr_set_item_str(session_running, NTS_SDN_CONTROLLER_CONFIG_XPATH"/controller-password", (const char*)framework_environment.sdn_controller_password, 0, 0);
-    if(rc != SR_ERR_OK) {
-        log_error("sr_set_item_str failed");
-        return NTS_ERR_FAILED;
+    if(strlen(framework_environment.sdn_controller_password)) {
+        rc = sr_set_item_str(session_running, NTS_SDN_CONTROLLER_CONFIG_XPATH"/controller-password", (const char*)framework_environment.sdn_controller_password, 0, 0);
+        if(rc != SR_ERR_OK) {
+            log_error("sr_set_item_str failed");
+            return NTS_ERR_FAILED;
+        }
     }
 
     //setup ves-endpoint details
-    rc = sr_set_item_str(session_running, NTS_VES_ENDPOINT_CONFIG_XPATH"/ves-endpoint-protocol", (const char*)framework_environment.ves_endpoint_protocol, 0, 0);
-    if(rc != SR_ERR_OK) {
-        log_error("sr_set_item_str failed");
-        return NTS_ERR_FAILED;
+    if(strlen(framework_environment.ves_endpoint_protocol)) {
+        rc = sr_set_item_str(session_running, NTS_VES_ENDPOINT_CONFIG_XPATH"/ves-endpoint-protocol", (const char*)framework_environment.ves_endpoint_protocol, 0, 0);
+        if(rc != SR_ERR_OK) {
+            log_error("sr_set_item_str failed");
+            return NTS_ERR_FAILED;
+        }
     }
 
-    rc = sr_set_item_str(session_running, NTS_VES_ENDPOINT_CONFIG_XPATH"/ves-endpoint-ip", (const char*)framework_environment.ves_endpoint_ip, 0, 0);
-    if(rc != SR_ERR_OK) {
-        log_error("sr_set_item_str failed");
-        return NTS_ERR_FAILED;
+    if(strlen(framework_environment.ves_endpoint_ip)) {
+        rc = sr_set_item_str(session_running, NTS_VES_ENDPOINT_CONFIG_XPATH"/ves-endpoint-ip", (const char*)framework_environment.ves_endpoint_ip, 0, 0);
+        if(rc != SR_ERR_OK) {
+            log_error("sr_set_item_str failed");
+            return NTS_ERR_FAILED;
+        }
     }
 
     sprintf(int_to_str, "%d", framework_environment.ves_endpoint_port);
@@ -282,34 +292,42 @@ static int manager_populate_sysrepo_network_function_list(void) {
         return NTS_ERR_FAILED;
     }
 
-    rc = sr_set_item_str(session_running, NTS_VES_ENDPOINT_CONFIG_XPATH"/ves-endpoint-auth-method", (const char*)framework_environment.ves_endpoint_auth_method, 0, 0);
-    if(rc != SR_ERR_OK) {
-        log_error("sr_set_item_str failed");
-        return NTS_ERR_FAILED;
+    if(strlen(framework_environment.ves_endpoint_auth_method)) {
+        rc = sr_set_item_str(session_running, NTS_VES_ENDPOINT_CONFIG_XPATH"/ves-endpoint-auth-method", (const char*)framework_environment.ves_endpoint_auth_method, 0, 0);
+        if(rc != SR_ERR_OK) {
+            log_error("sr_set_item_str failed");
+            return NTS_ERR_FAILED;
+        }
     }
 
-    rc = sr_set_item_str(session_running, NTS_VES_ENDPOINT_CONFIG_XPATH"/ves-endpoint-username", (const char*)framework_environment.ves_endpoint_username, 0, 0);
-    if(rc != SR_ERR_OK) {
-        log_error("sr_set_item_str failed");
-        return NTS_ERR_FAILED;
+    if(strlen(framework_environment.ves_endpoint_username)) {
+        rc = sr_set_item_str(session_running, NTS_VES_ENDPOINT_CONFIG_XPATH"/ves-endpoint-username", (const char*)framework_environment.ves_endpoint_username, 0, 0);
+        if(rc != SR_ERR_OK) {
+            log_error("sr_set_item_str failed");
+            return NTS_ERR_FAILED;
+        }
     }
 
-    rc = sr_set_item_str(session_running, NTS_VES_ENDPOINT_CONFIG_XPATH"/ves-endpoint-password", (const char*)framework_environment.ves_endpoint_password, 0, 0);
-    if(rc != SR_ERR_OK) {
-        log_error("sr_set_item_str failed");
-        return NTS_ERR_FAILED;
+    if(strlen(framework_environment.ves_endpoint_password)) {
+        rc = sr_set_item_str(session_running, NTS_VES_ENDPOINT_CONFIG_XPATH"/ves-endpoint-password", (const char*)framework_environment.ves_endpoint_password, 0, 0);
+        if(rc != SR_ERR_OK) {
+            log_error("sr_set_item_str failed");
+            return NTS_ERR_FAILED;
+        }
     }
 
-    rc = sr_set_item_str(session_running, NTS_VES_ENDPOINT_CONFIG_XPATH"/ves-endpoint-certificate", (const char*)framework_environment.ves_endpoint_certificate, 0, 0);
-    if(rc != SR_ERR_OK) {
-        log_error("sr_set_item_str failed");
-        return NTS_ERR_FAILED;
+    if(strlen(framework_environment.ves_endpoint_certificate)) {
+        rc = sr_set_item_str(session_running, NTS_VES_ENDPOINT_CONFIG_XPATH"/ves-endpoint-certificate", (const char*)framework_environment.ves_endpoint_certificate, 0, 0);
+        if(rc != SR_ERR_OK) {
+            log_error("sr_set_item_str failed");
+            return NTS_ERR_FAILED;
+        }
     }
 
     //apply all changes
     rc = sr_apply_changes(session_running, 0, 0);
     if(rc != SR_ERR_OK) {
-        log_error("sr_apply_changes failed");
+        log_error("sr_apply_changes failed: %s", sr_strerror(rc));
         return NTS_ERR_FAILED;
     }
 
@@ -368,11 +386,13 @@ static int manager_process_change(int context_index, manager_network_function_ty
     assert(context_index < manager_installed_function_types_count);
     assert(new_context);
 
+    int ret_code = NTS_ERR_OK;
+
     manager_network_function_type *current_context = &manager_context[context_index];
     int rc = 0;
 
     current_context->data_changed |= new_context->data_changed;
-    
+
     //process changes, and update data in current_context to resemble new_context
     if(new_context->docker_instance_name != 0) {
         free(current_context->docker_instance_name);
@@ -402,7 +422,9 @@ static int manager_process_change(int context_index, manager_network_function_ty
                 rc = manager_stop_instance(current_context);
                 if(rc != NTS_ERR_OK) {
                     log_error("manager_stop_instance failed");
-                    return NTS_ERR_FAILED;
+                    current_context->started_instances++;
+                    ret_code = NTS_ERR_FAILED;
+                    break;
                 }
             }
         }
@@ -413,7 +435,9 @@ static int manager_process_change(int context_index, manager_network_function_ty
                 rc = manager_start_instance(current_context);
                 if(rc != NTS_ERR_OK) {
                     log_error("manager_start_instance failed");
-                    return NTS_ERR_FAILED;
+                    current_context->started_instances--;
+                    ret_code = NTS_ERR_FAILED;
+                    break;
                 }
             }
         }
@@ -427,7 +451,9 @@ static int manager_process_change(int context_index, manager_network_function_ty
                 rc = manager_unmount_instance(current_context);
                 if(rc != NTS_ERR_OK) {
                     log_error("manager_unmount_instance failed");
-                    return NTS_ERR_FAILED;
+                    current_context->mounted_instances++;
+                    ret_code = NTS_ERR_FAILED;
+                    break;
                 }
             }
         }
@@ -438,13 +464,15 @@ static int manager_process_change(int context_index, manager_network_function_ty
                 rc = manager_mount_instance(current_context);
                 if(rc != NTS_ERR_OK) {
                     log_error("manager_mount_instance failed");
-                    return NTS_ERR_FAILED;
+                    current_context->mounted_instances--;
+                    ret_code = NTS_ERR_FAILED;
+                    break;
                 }
             }
         }
     }
 
-    return NTS_ERR_OK;
+    return ret_code;
 }
 
 static int manager_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) {
@@ -596,6 +624,7 @@ static int manager_instances_get_items_cb(sr_session_ctx_t *session, const char
 
     *parent = lyd_new_path(NULL, sr_get_context(sr_session_get_connection(session)), NTS_FUNCTION_LIST_SCHEMA_XPATH, 0, 0, 0);
     if(*parent == 0) {
+        log_error("lyd_new_path failed");
         return SR_ERR_OPERATION_FAILED;
     }
 
@@ -610,12 +639,14 @@ static int manager_instances_get_items_cb(sr_session_ctx_t *session, const char
 
             asprintf(&full_path, "%s/mount-point-addressing-method", instance_path);
             if(lyd_new_path(*parent, NULL, full_path, manager_context[i].instance[j].mount_point_addressing_method, 0, 0) == 0) {
+                log_error("lyd_new_path failed");
                 return SR_ERR_OPERATION_FAILED;
             }
             free(full_path);
 
             asprintf(&full_path, "%s/networking/docker-ip", instance_path);
             if(lyd_new_path(*parent, NULL, full_path, manager_context[i].instance[j].docker_ip, 0, 0) == 0) {
+                log_error("lyd_new_path failed");
                 return SR_ERR_OPERATION_FAILED;
             }
             free(full_path);
@@ -623,12 +654,14 @@ static int manager_instances_get_items_cb(sr_session_ctx_t *session, const char
             asprintf(&full_path, "%s/networking/docker-port", instance_path);
             sprintf(value, "%d", manager_context[i].instance[j].docker_port);
             if(lyd_new_path(*parent, NULL, full_path, value, 0, 0) == 0) {
+                log_error("lyd_new_path failed");
                 return SR_ERR_OPERATION_FAILED;
             }
             free(full_path);
 
             asprintf(&full_path, "%s/networking/host-ip", instance_path);
             if(lyd_new_path(*parent, NULL, full_path, manager_context[i].instance[j].host_ip, 0, 0) == 0) {
+                log_error("lyd_new_path failed");
                 return SR_ERR_OPERATION_FAILED;
             }
             free(full_path);
@@ -636,6 +669,7 @@ static int manager_instances_get_items_cb(sr_session_ctx_t *session, const char
             asprintf(&full_path, "%s/networking/host-port", instance_path);
             sprintf(value, "%d", manager_context[i].instance[j].host_port);
             if(lyd_new_path(*parent, NULL, full_path, value, 0, 0) == 0) {
+                log_error("lyd_new_path failed");
                 return SR_ERR_OPERATION_FAILED;
             }
             free(full_path);
@@ -649,7 +683,6 @@ static int manager_instances_get_items_cb(sr_session_ctx_t *session, const char
 }
 
 static int manager_stats_get_items_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 value[128];
 
     *parent = lyd_new_path(NULL, sr_get_context(sr_session_get_connection(session)), NTS_SIMULATION_SCHEMA_XPATH, 0, 0, 0);
@@ -669,5 +702,21 @@ static int manager_stats_get_items_cb(sr_session_ctx_t *session, const char *mod
         return SR_ERR_OPERATION_FAILED;
     }
 
+    //setup sdn-controller defaults
+    sprintf(value, "%d", framework_environment.host_base_port);
+    if(lyd_new_path(*parent, NULL, NTS_SIMULATION_SCHEMA_XPATH"/base-port", value, 0, 0) == 0) {
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    sprintf(value, "%d", framework_environment.ssh_connections);
+    if(lyd_new_path(*parent, NULL, NTS_SIMULATION_SCHEMA_XPATH"/ssh-connections", value, 0, 0) == 0) {
+        return SR_ERR_OPERATION_FAILED;
+    }
+
+    sprintf(value, "%d", framework_environment.tls_connections);
+    if(lyd_new_path(*parent, NULL, NTS_SIMULATION_SCHEMA_XPATH"/tls-connections", value, 0, 0) == 0) {
+        return SR_ERR_OPERATION_FAILED;
+    }
+
     return SR_ERR_OK;
 }
index 3d2245c..347c11d 100644 (file)
@@ -49,6 +49,7 @@ int manager_start_instance(manager_network_function_type *function_type) {
     function_type->instance = (manager_network_function_instance_t *)realloc(function_type->instance, sizeof(manager_network_function_instance_t) * function_type->started_instances);
     if(function_type->instance == 0) {
         log_error("realloc failed");
+        function_type->started_instances--;
         return NTS_ERR_FAILED;
     }
 
@@ -59,7 +60,6 @@ int manager_start_instance(manager_network_function_type *function_type) {
     asprintf(&instance->name, "%s-%d", function_type->docker_instance_name, function_type->started_instances - 1);
 
     instance->mount_point_addressing_method = strdup(function_type->mount_point_addressing_method);
-
     instance->docker_port = STANDARD_NETCONF_PORT;
     instance->host_ip = strdup(framework_environment.host_ip);
     instance->host_port = 0;
@@ -75,12 +75,19 @@ int manager_start_instance(manager_network_function_type *function_type) {
 
     if(instance->host_port == 0) {
         log_error("no ports available for operation");
+        free(instance->name);
+        free(instance->mount_point_addressing_method);
+        free(instance->host_ip);
         return NTS_ERR_FAILED;
     }
 
     int rc = docker_device_start(function_type, instance);
     if(rc != NTS_ERR_OK) {
         log_error("docker_device_start failed");
+        free(instance->name);
+        free(instance->mount_point_addressing_method);
+        free(instance->host_ip);
+        manager_port[instance->host_port] = 0;
         return NTS_ERR_FAILED;
     }
 
@@ -107,31 +114,34 @@ int manager_config_instance(manager_network_function_type *function_type, manage
     rc = lyd_utils_dup(session_running, "/nts-manager:simulation/ves-endpoint", "/nts-network-function:simulation/ves-endpoint", &local_tree);
     if(rc != NTS_ERR_OK) {
         log_error("lyd_utils_dup failed");
+        lyd_free_withsiblings(local_tree);
         return NTS_ERR_FAILED;
     }
 
     char *xpath_s = 0;
     asprintf(&xpath_s, "/nts-manager:simulation/network-functions/network-function[function-type='%s']", function_type->function_type_string);
     rc = lyd_utils_dup(session_running, xpath_s, "/nts-network-function:simulation/network-function", &local_tree);
+    free(xpath_s);
     if(rc != NTS_ERR_OK) {
         log_error("lyd_utils_dup failed");
+        lyd_free_withsiblings(local_tree);
         return NTS_ERR_FAILED;
-    }
-    free(xpath_s);
+    }    
 
     nc_client_t *nc_client = nc_client_ssh_connect(instance->docker_ip, instance->docker_port, "netconf", "netconf");
     if(nc_client == 0) {
         log_error("nc_client_ssh_connect");
+        lyd_free_withsiblings(local_tree);
         return NTS_ERR_FAILED;
     }
 
     rc += nc_client_edit_batch(nc_client, local_tree, 1000);
+    lyd_free_withsiblings(local_tree);
     if(rc != NTS_ERR_OK) {
         log_error("nc_client_edit_batch failed %d\n", rc);
+        nc_client_disconnect(nc_client);
         return NTS_ERR_FAILED;
     }
-    lyd_free_withsiblings(local_tree);
-
     
     if(instance->is_configured == false) {
         //run datastore-random-populate rpc
@@ -140,12 +150,15 @@ int manager_config_instance(manager_network_function_type *function_type, manage
         rpc_node = lyd_new_path(0, session_context, "/nts-network-function:datastore-random-populate", 0, 0, 0);
         if(rpc_node == 0) {
             log_error("failed to create rpc node");
+            nc_client_disconnect(nc_client);
             return NTS_ERR_FAILED;
         }
 
         rpcout = nc_client_send_rpc(nc_client, rpc_node, 5000);
         if(rpcout == 0) {
             log_error("datastore-random-populate rpc failed");
+            nc_client_disconnect(nc_client);
+            lyd_free_withsiblings(rpc_node);
             return NTS_ERR_FAILED;
         }
         else {
@@ -154,15 +167,18 @@ int manager_config_instance(manager_network_function_type *function_type, manage
         lyd_free_withsiblings(rpc_node);
 
         //run feature-control rpc
-        rpc_node = lyd_new_path(0, session_context, "/nts-network-function:feature-control/features", "ves-file-ready ves-heartbeat ves-pnf-registration manual-notification-generation netconf-call-home", 0, 0);
+        rpc_node = lyd_new_path(0, session_context, "/nts-network-function:feature-control/features", "ves-file-ready ves-heartbeat ves-pnf-registration manual-notification-generation netconf-call-home web-cut-through", 0, 0);
         if(rpc_node == 0) {
             log_error("failed to create rpc node");
+            nc_client_disconnect(nc_client);
             return NTS_ERR_FAILED;
         }
 
         rpcout = nc_client_send_rpc(nc_client, rpc_node, 1000);
         if(rpcout == 0) {
             log_error("feature-control rpc failed");
+            nc_client_disconnect(nc_client);
+            lyd_free_withsiblings(rpc_node);
             return NTS_ERR_FAILED;
         }
         else {
@@ -185,6 +201,7 @@ int manager_stop_instance(manager_network_function_type *function_type) {
 
     if(instance->is_mounted) {
         if(manager_unmount_instance(function_type) != NTS_ERR_OK) {
+            log_error("failed to unmount instance");
             return NTS_ERR_FAILED;
         }
     }
@@ -291,6 +308,10 @@ int manager_mount_instance(manager_network_function_type *function_type) {
         int rc = http_request(url, controller->username, controller->password, "PUT", json, 0, 0);
         if(rc != NTS_ERR_OK) {
             log_error("http_request failed");
+            free(url);
+            free(node_id);
+            free(json);
+            controller_details_free(controller);
             return NTS_ERR_FAILED;
         }
 
@@ -340,6 +361,9 @@ int manager_unmount_instance(manager_network_function_type *function_type) {
         int rc = http_request(url, controller->username, controller->password, "DELETE", "", 0, 0);
         if(rc != NTS_ERR_OK) {
             log_error("http_request failed");
+            free(url);
+            free(node_id);
+            controller_details_free(controller);
             return NTS_ERR_FAILED;
         }
 
index fbd2478..5b14ce2 100644 (file)
 #include "features/ves_file_ready/ves_file_ready.h"
 #include "features/manual_notification/manual_notification.h"
 #include "features/netconf_call_home/netconf_call_home.h"
+#include "features/web_cut_through/web_cut_through.h"
+
+#define NTS_NETWORK_FUNCTION_MODULE         "nts-network-function"
+#define NTS_NETWORK_FUNCTION_SCHEMA_XPATH   "/nts-network-function:simulation/network-function"
 
 #define POPULATE_RPC_SCHEMA_XPATH           "/nts-network-function:datastore-random-populate"
 #define FEATURE_CONTROL_SCHEMA_XPATH        "/nts-network-function:feature-control"
@@ -54,6 +58,8 @@ static int network_function_faults_clear_cb(sr_session_ctx_t *session, const cha
 static int network_function_faults_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 network_function_faults_count_get_items_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 network_function_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 faults_update_config(sr_session_ctx_t *session);                 //not protected by lock
 static void *faults_thread_routine(void *arg);
 
@@ -63,6 +69,10 @@ static char *nf_function_control_string = 0;
 static pthread_t faults_thread;
 static pthread_mutex_t faults_lock;
 
+static pthread_mutex_t mount_point_addressing_method_lock;
+static char *mount_point_addressing_method_default = 0;
+static char *mount_point_addressing_method_val = 0;
+
 int network_function_run(void) {
     assert_session();
 
@@ -88,13 +98,13 @@ int network_function_run(void) {
     }
 
     //faults
-    rc = sr_module_change_subscribe(session_running, "nts-network-function", FAULTS_LIST_SCHEMA_XPATH, network_function_faults_change_cb, NULL, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
+    rc = sr_module_change_subscribe(session_running, NTS_NETWORK_FUNCTION_MODULE, FAULTS_LIST_SCHEMA_XPATH, network_function_faults_change_cb, NULL, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
     if(rc != SR_ERR_OK) {
         log_error("could not subscribe to faults");
         return 0;
     }
 
-    rc = sr_oper_get_items_subscribe(session_running, "nts-network-function", FAULTS_COUNT_LIST_SCHEMA_XPATH, network_function_faults_count_get_items_cb, NULL, SR_SUBSCR_CTX_REUSE, &session_subscription);
+    rc = sr_oper_get_items_subscribe(session_running, NTS_NETWORK_FUNCTION_MODULE, FAULTS_COUNT_LIST_SCHEMA_XPATH, network_function_faults_count_get_items_cb, NULL, SR_SUBSCR_CTX_REUSE, &session_subscription);
     if(rc != SR_ERR_OK) {
         log_error("could not subscribe to oper faults: %s", sr_strerror(rc));
         return 0;
@@ -106,6 +116,13 @@ int network_function_run(void) {
         return NTS_ERR_FAILED;
     }
 
+    //subscribe to any changes on the main
+    rc = sr_module_change_subscribe(session_running, NTS_NETWORK_FUNCTION_MODULE, NTS_NETWORK_FUNCTION_SCHEMA_XPATH, network_function_change_cb, NULL, 0, SR_SUBSCR_CTX_REUSE, &session_subscription);
+    if(rc != SR_ERR_OK) {
+        log_error("could not subscribe to simulation changes");
+        return NTS_ERR_FAILED;
+    }
+
     rc = faults_init();
     if(rc != NTS_ERR_OK) {
         log_error("faults_init error", sr_strerror(rc));
@@ -122,7 +139,27 @@ int network_function_run(void) {
         return NTS_ERR_FAILED;
     }
 
+    if(pthread_mutex_init(&mount_point_addressing_method_lock, NULL) != 0) { 
+        log_error("mutex init has failed"); 
+        return NTS_ERR_FAILED; 
+    }
+
     while(!framework_sigint) {
+        pthread_mutex_lock(&mount_point_addressing_method_lock);
+        if(mount_point_addressing_method_val) {
+            rc = sr_set_item_str(session_running, NTS_NETWORK_FUNCTION_SCHEMA_XPATH"/mount-point-addressing-method", mount_point_addressing_method_val, 0, 0);
+            if(rc != SR_ERR_OK) {
+                log_error("sr_set_item_str failed");
+            }
+
+            rc = sr_apply_changes(session_running, 0, 0);
+            if(rc != SR_ERR_OK) {
+                log_error("sr_apply_changes failed");
+            }
+
+            mount_point_addressing_method_val = 0;
+        }
+        pthread_mutex_unlock(&mount_point_addressing_method_lock);
 
         pthread_mutex_lock(&nf_function_control_lock);
         if(nf_function_control_string) {
@@ -166,6 +203,14 @@ int network_function_run(void) {
                 }
             }
 
+            if(strstr(nf_function_control_string, "web-cut-through") != 0) {
+                // start feature for NETCONF Call Home
+                rc = web_cut_through_feature_start(session_running);
+                if(rc != 0) {
+                    log_error("web_cut_through_feature_start() failed");
+                }
+            }
+
             free(nf_function_control_string);
             nf_function_control_string = 0;
         }
@@ -450,3 +495,45 @@ static void *faults_thread_routine(void *arg) {
 
     return 0;
 }
+
+static int network_function_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) {
+    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;
+
+    static bool mount_point_addressing_method_set = false;
+
+    if(event == SR_EV_DONE) {
+        rc = sr_get_changes_iter(session, NTS_NETWORK_FUNCTION_SCHEMA_XPATH"//.", &it);
+        if(rc != SR_ERR_OK) {
+            log_error("sr_get_changes_iter failed");
+            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 && (strcmp(new_value->xpath, NTS_NETWORK_FUNCTION_SCHEMA_XPATH"/mount-point-addressing-method") == 0)) {
+                if(mount_point_addressing_method_set == false) {
+                    mount_point_addressing_method_set = true;
+                    mount_point_addressing_method_default = strdup(new_value->data.string_val);
+                }
+                else {
+                    //prevent changing mount_point_addressing_method
+                    if(strcmp(new_value->data.string_val, mount_point_addressing_method_default) != 0) {
+                        pthread_mutex_lock(&mount_point_addressing_method_lock);
+                        mount_point_addressing_method_val = mount_point_addressing_method_default;
+                        pthread_mutex_unlock(&mount_point_addressing_method_lock);
+                    }
+                }
+            }
+
+            sr_free_val(old_value);
+            sr_free_val(new_value);
+        }
+
+        sr_free_change_iter(it);
+    }
+
+    return SR_ERR_OK;
+}
index 40f2bff..7e8588d 100644 (file)
@@ -260,8 +260,8 @@ static void list_yangs(const char *path, struct installable_module **modules, in
 
 int docker_device_init(void) {
     char *response = 0;
-    char *url = 0;
-    asprintf(&url, "http://v%s/containers/%s/json", framework_environment.docker_engine_version, framework_environment.hostname);
+    char url[512];
+    sprintf(url, "http://v%s/containers/%s/json", framework_environment.docker_engine_version, framework_environment.hostname);
 
     int rc = http_socket_request(url, DOCKER_SOCK_FNAME, "GET", 0, 0, &response);
     if(rc != NTS_ERR_OK) {
@@ -280,12 +280,14 @@ int docker_device_init(void) {
     cJSON *hostConfig = cJSON_GetObjectItemCaseSensitive(json_response, "HostConfig");
     if(hostConfig == 0) {
         log_error("could not get HostConfig object");
+        cJSON_Delete(json_response);
         return NTS_ERR_FAILED;
     }
 
     cJSON *networkMode = cJSON_GetObjectItemCaseSensitive(hostConfig, "NetworkMode");
     if(networkMode == 0) {
         log_error("could not get NetworkMode object");
+        cJSON_Delete(json_response);
         return NTS_ERR_FAILED;
     }
 
@@ -299,6 +301,7 @@ int docker_device_init(void) {
     docker_environment_var = (environment_var_t *)malloc(sizeof(environment_var_t) * docker_environment_var_count);
     if(docker_environment_var == 0) {
         log_error("malloc failed");
+        cJSON_Delete(networkMode);
         return NTS_ERR_FAILED;
     }
     
@@ -322,21 +325,21 @@ int docker_device_start(const manager_network_function_type *function_type, mana
     assert(instance);
     assert(docker_network_info);
 
-    char *image = 0;
+    char image[512];
     if(function_type->docker_version_tag && (function_type->docker_version_tag[0] != 0)) {
-        if(function_type->docker_repository && (function_type->docker_repository[0] != 0)) {
-            asprintf(&image, "%s/%s:%s", function_type->docker_repository, function_type->docker_image_name, function_type->docker_version_tag);    
+        if(function_type->docker_repository && (function_type->docker_repository[0] != 0) && (strcmp(function_type->docker_repository, "local") != 0)) {
+            sprintf(image, "%s/%s:%s", function_type->docker_repository, function_type->docker_image_name, function_type->docker_version_tag);    
         }
         else {
-            asprintf(&image, "%s:%s", function_type->docker_image_name, function_type->docker_version_tag);
+            sprintf(image, "%s:%s", function_type->docker_image_name, function_type->docker_version_tag);
         }
     }
     else {
-        if(function_type->docker_repository && (function_type->docker_repository[0] != 0)) {
-            asprintf(&image, "%s/%s:latest", function_type->docker_repository, function_type->docker_image_name);    
+        if(function_type->docker_repository && (function_type->docker_repository[0] != 0) && (strcmp(function_type->docker_repository, "local") != 0)) {
+            sprintf(image, "%s/%s:latest", function_type->docker_repository, function_type->docker_image_name);    
         }
         else {
-            asprintf(&image, "%s:latest", function_type->docker_image_name);
+            sprintf(image, "%s:latest", function_type->docker_image_name);
         }
     }
 
@@ -345,17 +348,18 @@ int docker_device_start(const manager_network_function_type *function_type, mana
         log_error("docker_container_create failed");
         return NTS_ERR_FAILED;
     }
-    free(image);
 
     rc = docker_container_start(instance);
     if(rc != NTS_ERR_OK) {
         log_error("docker_container_start failed");
+        docker_device_stop(instance);
         return NTS_ERR_FAILED;
     }
 
     rc = docker_container_inspect(instance);
     if(rc != NTS_ERR_OK) {
         log_error("docker_container_inspect failed");
+        docker_device_stop(instance);
         return NTS_ERR_FAILED;
     }
 
@@ -367,11 +371,10 @@ int docker_device_start(const manager_network_function_type *function_type, mana
 int docker_device_stop(manager_network_function_instance_t *instance) {
     assert(instance);
 
-    char *url = 0;
-    asprintf(&url, "http://v%s/containers/%s?force=true", framework_environment.docker_engine_version, instance->docker_id);
+    char url[512];
+    sprintf(url, "http://v%s/containers/%s?force=true", framework_environment.docker_engine_version, instance->docker_id);
 
     int rc = http_socket_request(url, DOCKER_SOCK_FNAME, "DELETE", "", 0, 0);
-    free(url);
     if(rc != NTS_ERR_OK) {
         log_error("http_socket_request failed");
         return NTS_ERR_FAILED;
@@ -502,6 +505,7 @@ static char *docker_parse_json_message(const char *json_string) {
     message = cJSON_GetObjectItem(json_response, "message");
     if(message == 0) {
         log_error("json parsing failed");
+        cJSON_Delete(json_response);
         return 0;
     }
 
@@ -522,27 +526,39 @@ static int docker_container_create(const char *image, manager_network_function_i
 
     if(cJSON_AddStringToObject(postDataJson, "Hostname", instance->name) == 0) {
         log_error("could not create JSON object: Hostname");
+        cJSON_Delete(postDataJson);
         return NTS_ERR_FAILED;
     }    
 
     cJSON *hostConfig = cJSON_CreateObject();
     if(hostConfig == 0) {
         log_error("could not create JSON object: HostConfig");
+        cJSON_Delete(postDataJson);
+        return NTS_ERR_FAILED;
+    }
+    if(cJSON_AddItemToObject(postDataJson, "HostConfig", hostConfig) == 0) {
+        log_error("cJSON_AddItemToObject failed");
+        cJSON_Delete(postDataJson);
         return NTS_ERR_FAILED;
     }
-    cJSON_AddItemToObject(postDataJson, "HostConfig", hostConfig);
 
     cJSON *portBindings = cJSON_CreateObject();
     if(portBindings == 0) {
         printf("could not create JSON object: PortBindings");
+        cJSON_Delete(postDataJson);
+        return NTS_ERR_FAILED;
+    }
+    if(cJSON_AddItemToObject(hostConfig, "PortBindings", portBindings) == 0) {
+        log_error("cJSON_AddItemToObject failed");
+        cJSON_Delete(postDataJson);
         return NTS_ERR_FAILED;
     }
-    cJSON_AddItemToObject(hostConfig, "PortBindings", portBindings);
     
     for(int i = 0; i < (framework_environment.ssh_connections + framework_environment.tls_connections + framework_environment.ftp_connections + framework_environment.sftp_connections); ++i) {
         cJSON *port = cJSON_CreateArray();
         if(port == 0) {
             log_error("could not create JSON object: port");
+            cJSON_Delete(postDataJson);
             return NTS_ERR_FAILED;
         }
 
@@ -556,11 +572,16 @@ static int docker_container_create(const char *image, manager_network_function_i
         else if(i < (framework_environment.ssh_connections + framework_environment.tls_connections + framework_environment.ftp_connections + framework_environment.sftp_connections)) {
             sprintf(dockerContainerPort, "%d/tcp", STANDARD_SFTP_PORT);
         }
-        cJSON_AddItemToObject(portBindings, dockerContainerPort, port);
+        if(cJSON_AddItemToObject(portBindings, dockerContainerPort, port) == 0) {
+            log_error("cJSON_AddItemToObject failed");
+            cJSON_Delete(postDataJson);
+            return NTS_ERR_FAILED;
+        }
 
         cJSON *hostPort = cJSON_CreateObject();
         if(hostPort == 0) {
             log_error("could not create JSON object: HostPort");
+            cJSON_Delete(postDataJson);
             return NTS_ERR_FAILED;
         }
 
@@ -568,15 +589,21 @@ static int docker_container_create(const char *image, manager_network_function_i
         sprintf(dockerHostPort, "%d", instance->host_port + i);
         if(cJSON_AddStringToObject(hostPort, "HostPort", dockerHostPort) == 0) {
             log_error("could not create JSON object: HostPortString");
+            cJSON_Delete(postDataJson);
             return NTS_ERR_FAILED;
         }
 
         if(cJSON_AddStringToObject(hostPort, "HostIp", "0.0.0.0") == 0) {   //instance->host_ip
             log_error("could not create JSON object: HostIpString");
+            cJSON_Delete(postDataJson);
             return NTS_ERR_FAILED;
         }
 
-        cJSON_AddItemToArray(port, hostPort);
+        if(cJSON_AddItemToArray(port, hostPort) == 0) {
+            log_error("cJSON_AddItemToArray failed");
+            cJSON_Delete(postDataJson);
+            return NTS_ERR_FAILED;
+        }
     }
 
     
@@ -584,24 +611,26 @@ static int docker_container_create(const char *image, manager_network_function_i
     asprintf(&docker_environment_var[4].value, "%d", instance->host_port);
 
     cJSON *env_variables_array = cJSON_CreateArray();
-    if (env_variables_array == 0) {
+    if(env_variables_array == 0) {
         log_error("Could not create JSON object: Env array");
         return NTS_ERR_FAILED;
     }
     cJSON_AddItemToObject(postDataJson, "Env", env_variables_array);
 
     for(int i = 0; i < docker_environment_var_count; i++) {
-        char *environment_var = 0;
-        asprintf(&environment_var, "%s=%s", docker_environment_var[i].name, docker_environment_var[i].value);
+        if(docker_environment_var[i].value) {
+            char *environment_var = 0;
+            asprintf(&environment_var, "%s=%s", docker_environment_var[i].name, docker_environment_var[i].value);
+
+            cJSON *env_var_obj = cJSON_CreateString(environment_var);
+            if(env_var_obj == 0) {
+                log_error("could not create JSON object");
+                return NTS_ERR_FAILED;
+            }
+            cJSON_AddItemToArray(env_variables_array, env_var_obj);
 
-        cJSON *env_var_obj = cJSON_CreateString(environment_var);
-        if(env_var_obj == 0) {
-            log_error("could not create JSON object");
-            return NTS_ERR_FAILED;
+            free(environment_var);
         }
-        cJSON_AddItemToArray(env_variables_array, env_var_obj);
-
-        free(environment_var);
     }
 
     free(docker_environment_var[4].value);
@@ -615,17 +644,17 @@ static int docker_container_create(const char *image, manager_network_function_i
     post_data_string = cJSON_PrintUnformatted(postDataJson);
     cJSON_Delete(postDataJson);
 
-    char *url = 0;
-    asprintf(&url, "http:/v%s/containers/create?name=%s", framework_environment.docker_engine_version, instance->name);
+    char url[512];
+    sprintf(url, "http:/v%s/containers/create?name=%s", framework_environment.docker_engine_version, instance->name);
 
     char *response = 0;
     int response_code = 0;
     int rc = http_socket_request(url, DOCKER_SOCK_FNAME, "POST", post_data_string, &response_code, &response);
+    free(post_data_string);
     if(rc != NTS_ERR_OK) {
         log_error("http_socket_request failed");
         return NTS_ERR_FAILED;
     }
-    free(url);
 
     if(response_code != 201) {
         char *message = docker_parse_json_message(response);
@@ -661,13 +690,12 @@ static int docker_container_create(const char *image, manager_network_function_i
 static int docker_container_start(manager_network_function_instance_t *instance) {
     assert(instance);
 
-    char *url = 0;
-    asprintf(&url, "http://v%s/containers/%s/start", framework_environment.docker_engine_version, instance->docker_id);
+    char url[512];
+    sprintf(url, "http://v%s/containers/%s/start", framework_environment.docker_engine_version, instance->docker_id);
 
     char *response = 0;
     int response_code = 0;
     int rc = http_socket_request(url, DOCKER_SOCK_FNAME, "POST", "", &response_code, &response);
-    free(url);
     if(rc != NTS_ERR_OK) {
         log_error("http_socket_request failed");
         return NTS_ERR_FAILED;
@@ -694,12 +722,11 @@ static int docker_container_start(manager_network_function_instance_t *instance)
 static int docker_container_inspect(manager_network_function_instance_t *instance) {
     assert(instance);
 
-    char *url = 0;
-    asprintf(&url, "http://v%s/containers/%s/json", framework_environment.docker_engine_version, instance->docker_id);
+    char url[512];
+    sprintf(url, "http://v%s/containers/%s/json", framework_environment.docker_engine_version, instance->docker_id);
 
     char *response = 0;    
     int rc = http_socket_request(url, DOCKER_SOCK_FNAME, "GET", "", 0, &response);
-    free(url);
     if(rc != NTS_ERR_OK) {
         log_error("http_socket_request failed");
         return NTS_ERR_FAILED;
@@ -716,29 +743,26 @@ static int docker_container_inspect(manager_network_function_instance_t *instanc
     cJSON *main_node = cJSON_GetObjectItem(json_response, "NetworkSettings");
     if(main_node == 0) {
         log_error("json parsing failed");
+        cJSON_Delete(json_response);
         return NTS_ERR_FAILED;
     }
 
     cJSON *node = cJSON_GetObjectItem(main_node, "Networks");
     if(node == 0) {
         log_error("json parsing failed");
+        cJSON_Delete(json_response);
         return NTS_ERR_FAILED;
     }
         
     node = node->child;   //get info from the first in array
     if(node == 0) {
         log_error("json parsing failed");
+        cJSON_Delete(json_response);
         return NTS_ERR_FAILED;
     }
 
-    char *ipv6_env_var = getenv("IPv6_ENABLED");
-    if(ipv6_env_var == 0) {
-        log_error("could not get the IPv6 Enabled env variable");
-        return NTS_ERR_FAILED;
-    }
-
-    cJSON *element = cJSON_GetObjectItem(node, "IPAddress");
-    if(strcmp(ipv6_env_var, "true") == 0) {
+    cJSON *element;
+    if(framework_environment.ip_v6_enabled) {
         element = cJSON_GetObjectItem(node, "GlobalIPv6Address");
     }
     else {
@@ -747,8 +771,10 @@ static int docker_container_inspect(manager_network_function_instance_t *instanc
 
     if(element == 0) {
         log_error("json parsing failed");
+        cJSON_Delete(json_response);
         return NTS_ERR_FAILED;
     }
+
     instance->docker_ip = strdup(element->valuestring);
 
     cJSON_Delete(json_response);
index 3f1688e..879fb5a 100644 (file)
@@ -49,7 +49,16 @@ int faults_fault_list_add(uint16_t delay) {
 }
 
 bool faults_fault_list_not_empty(void) {
-    return (faults_fault_list_len != 0);
+    bool not_empty = (faults_fault_list_len != 0);
+    if(not_empty == true) {
+        int delay_sum = 0;
+        for(int i = 0; i < faults_fault_list_len; i++) {
+            delay_sum += faults_fault_list[i];
+        }
+
+        not_empty = (delay_sum != 0);
+    }
+    return not_empty;
 }
 
 uint16_t faults_fault_list_get_next(void) {
index 499f97d..471b72b 100644 (file)
@@ -36,7 +36,7 @@ framework_arguments_t framework_arguments;
 framework_config_t framework_config;
 framework_environment_t framework_environment;
 
-const char *argp_program_version = "ntsim-ng v0.0.1a";
+const char *argp_program_version = "ntsim-ng v1.0.0";
 const char *argp_program_bug_address = "<alexandru.stancu@highstreet-technologies.com> / <adrian.lita@highstreet-technologies.com>";
 static char doc[] = "ntsim - new generation";
 
@@ -480,7 +480,6 @@ void framework_free(void) {
     log_close();
     if(framework_arguments.container_init) {
         rename("log/log.txt", "log/install_log.txt");
-        rename("log/error.txt", "log/install_error.txt");
     }
 }
 
diff --git a/ntsimulator/ntsim-ng/features/web_cut_through/web_cut_through.c b/ntsimulator/ntsim-ng/features/web_cut_through/web_cut_through.c
new file mode 100644 (file)
index 0000000..8139b17
--- /dev/null
@@ -0,0 +1,78 @@
+/*************************************************************************
+*
+* 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 "web_cut_through.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 <stdio.h>
+#include <assert.h>
+
+#include "core/session.h"
+#include "core/framework.h"
+
+#define SYSTEM_NAME_SCHEMA_XPATH                "/ietf-system:system/onap-system:name"
+#define SYSTEM_WEB_UI_SCHEMA_XPATH              "/ietf-system:system/onap-system:web-ui"
+
+
+int web_cut_through_feature_start(sr_session_ctx_t *current_session) {
+    assert(current_session);
+    assert_session();
+
+    int rc = 0;
+
+    //update ietf-system details
+    rc = sr_set_item_str(current_session, SYSTEM_NAME_SCHEMA_XPATH, framework_environment.hostname, 0, 0);
+    if(rc != SR_ERR_OK) {
+        log_error("sr_set_item_str failed");
+        return NTS_ERR_FAILED;
+    }
+
+    controller_details_t *controller_details = controller_details_get(current_session);
+    if(controller_details == 0) {
+        log_error("controller_details_get failed");
+        return NTS_ERR_FAILED;
+    }
+
+    char *web_ui = 0;
+    asprintf(&web_ui, "%s/odlux/index.html#/about", controller_details->base_url);
+    controller_details_free(controller_details);
+
+    if(web_ui == 0) {
+        log_error("asprintf failed");
+        return NTS_ERR_FAILED;
+    }
+
+    rc = sr_set_item_str(current_session, SYSTEM_WEB_UI_SCHEMA_XPATH, web_ui, 0, 0);
+    free(web_ui);
+    if(rc != SR_ERR_OK) {
+        log_error("sr_set_item_str failed");
+        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;
+    }
+
+    return NTS_ERR_OK;
+}
diff --git a/ntsimulator/ntsim-ng/features/web_cut_through/web_cut_through.h b/ntsimulator/ntsim-ng/features/web_cut_through/web_cut_through.h
new file mode 100644 (file)
index 0000000..b3fb221
--- /dev/null
@@ -0,0 +1,22 @@
+/*************************************************************************
+*
+* 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.
+***************************************************************************/
+
+#pragma once
+
+#include <sysrepo.h>
+
+int web_cut_through_feature_start(sr_session_ctx_t *current_session);
index e967d7e..61fc129 100644 (file)
@@ -43,6 +43,7 @@
 #include "features/ves_file_ready/ves_file_ready.h"
 #include "features/manual_notification/manual_notification.h"
 #include "features/netconf_call_home/netconf_call_home.h"
+#include "features/web_cut_through/web_cut_through.h"
 
 int main(int argc, char **argv) {
     int return_code = EXIT_SUCCESS;
@@ -181,6 +182,14 @@ int main(int argc, char **argv) {
                     return_code = EXIT_FAILURE;
                     goto non_container_init_cleanup;
                 }
+
+                // start feature for web cut through
+                rc = web_cut_through_feature_start(session_running);
+                if(rc != 0) {
+                    log_error("web_cut_through_feature_start() failed");
+                    return_code = EXIT_FAILURE;
+                    goto non_container_init_cleanup;
+                }
             }
 
             if(framework_arguments.loop) {
index 28222e6..6b1fd6f 100644 (file)
@@ -472,27 +472,44 @@ char *rand_regex(const char *regexp) {
     char *cmd = 0;
     static int run_time = 0;
 
+    char *regexp64 = b64_encode((const unsigned char*)regexp, strlen(regexp));
+    if(regexp64 == 0) {
+        log_error("b64_encode failed");
+        return 0;
+    }
+
     if(framework_arguments.no_rand) {
         run_time++;
-        asprintf(&cmd, "regxstring %d '%s'", run_time, regexp);
+        asprintf(&cmd, "regxstring %d '%s'", run_time, regexp64);
     }
     else {
-        asprintf(&cmd, "regxstring '%s'", regexp);
+        asprintf(&cmd, "regxstring '%s'", regexp64);
     }
+    free(regexp64);
 
-    FILE* pipe = popen(cmd, "r");
-    free(cmd);
-
-    if (!pipe) {
-        log_error("popen() failed");
+    if(cmd == 0) {
+        log_error("asprintf failed");
         return 0;
     }
 
-    fgets(buffer, sizeof(buffer), pipe);
-    pclose(pipe);
-    
+    char last_char = ' ';
+    while(last_char == ' ') {
+        FILE* pipe = popen(cmd, "r");
+        if (!pipe) {
+            log_error("popen() failed");
+            free(cmd);
+            return 0;
+        }
+
+        fgets(buffer, sizeof(buffer), pipe);
+        pclose(pipe);
+
+        buffer[strlen(buffer) - 1] = 0;   //remove trailing \n
+        last_char = buffer[strlen(buffer) - 1];
+    }
+        
     char *ret = strdup(buffer);
-    ret[strlen(ret) - 1] = 0;   //remove trailing \n
+    free(cmd);
 
     return ret;
 }
index fc5c942..1007b62 100644 (file)
@@ -46,6 +46,8 @@ static char b64_encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
                                     'w', 'x', 'y', 'z', '0', '1', '2', '3',
                                     '4', '5', '6', '7', '8', '9', '+', '/'};
 
+static char b64_decoding_table[256] = {0};
+
 static int b64_mod_table[] = {0, 2, 1};
 
 bool dir_exists(const char *path) {
@@ -138,7 +140,7 @@ long int get_microseconds_since_epoch(void) {
     long int useconds;
 
     gettimeofday(&tv, 0);
-    useconds = t*1000 + tv.tv_usec; //add the microseconds to the seconds
+    useconds = t*1000000 + tv.tv_usec; //add the microseconds to the seconds
 
     return useconds;
 }
@@ -266,7 +268,7 @@ bool check_port_open(const char *host, uint16_t port) {
     return false;
 }
 
-char *b64_encode(const unsigned char *data, size_t input_length) {
+char *b64_encode(const uint8_t *data, size_t input_length) {
     assert(data);
     assert(input_length);
 
@@ -299,6 +301,60 @@ char *b64_encode(const unsigned char *data, size_t input_length) {
     return encoded_data;
 }
 
+uint8_t *b64_decode(const char *data, size_t input_length, size_t *output_length) {
+    assert(data);
+    assert(input_length);
+    assert(output_length);
+
+    int i, j;
+
+    //one time compute decoding table
+    if(b64_decoding_table['A'] == 0) {
+        for(i = 0; i < 64; i++) {
+            b64_decoding_table[(unsigned char)b64_encoding_table[i]] = i;
+        }
+    }
+
+    if(input_length % 4 != 0) {
+        return 0;
+    }
+
+    *output_length = input_length / 4 * 3;
+    if(data[input_length - 1] == '=') {
+        (*output_length )--;
+    }
+    if(data[input_length - 2] == '=') {
+        (*output_length )--;
+    }
+
+    uint8_t *decoded_data = (uint8_t*)malloc(*output_length + 1);
+    if(decoded_data == 0) {
+        return 0;
+    }
+
+    for(i = 0, j = 0; i < input_length;) {
+        uint32_t sextet_a = data[i] == '=' ? 0 & i++ : b64_decoding_table[(int)data[i++]];
+        uint32_t sextet_b = data[i] == '=' ? 0 & i++ : b64_decoding_table[(int)data[i++]];
+        uint32_t sextet_c = data[i] == '=' ? 0 & i++ : b64_decoding_table[(int)data[i++]];
+        uint32_t sextet_d = data[i] == '=' ? 0 & i++ : b64_decoding_table[(int)data[i++]];
+        uint32_t triple = ( sextet_a << 3 * 6 ) + ( sextet_b << 2 * 6 ) + ( sextet_c << 1 * 6 ) + ( sextet_d << 0 * 6 );
+
+        if(j < *output_length) {
+            decoded_data[j++] = (triple >> 2 * 8) & 0xFF;
+        }
+
+        if(j < *output_length) {
+            decoded_data[j++] = (triple >> 1 * 8) & 0xFF;
+        }
+
+        if(j < *output_length) {
+            decoded_data[j++] = (triple >> 0 * 8) & 0xFF;
+        }
+    }
+
+    return decoded_data;
+}
+
 char *str_replace(const char *orig, const char *rep, const char *with) {
     assert(orig);
     assert(rep);
index 9e7081b..2794ac5 100644 (file)
@@ -42,7 +42,8 @@ long int get_microseconds_since_epoch(void);
 bool get_local_ips(const char *ifname, char **ipv4, char **ipv6);
 bool check_port_open(const char *host, uint16_t port);
 
-char *b64_encode(const unsigned char *data, size_t input_length);
+char *b64_encode(const uint8_t *data, size_t input_length);
+uint8_t *b64_decode(const char *data, size_t input_length, size_t *output_length);
 char *str_replace(const char *orig, const char *rep, const char *with);
 
 char *read_key(const char *filename);
index e0a4953..42c0660 100644 (file)
 ***************************************************************************/\r
 \r
 #include <string>\r
+#include <cstring>\r
 #include <cstdlib>\r
 #include <iostream>\r
+#include <cstdio>\r
+#include <assert.h>\r
 \r
 #include "regxstring.h"\r
 \r
 using namespace std;\r
 \r
+static char b64_encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',\r
+                                    'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',\r
+                                    'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',\r
+                                    'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',\r
+                                    'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',\r
+                                    'o', 'p', 'q', 'r', 's', 't', 'u', 'v',\r
+                                    'w', 'x', 'y', 'z', '0', '1', '2', '3',\r
+                                    '4', '5', '6', '7', '8', '9', '+', '/'};\r
+\r
+static char b64_decoding_table[256] = {0};\r
+\r
+static int b64_mod_table[] = {0, 2, 1};\r
+\r
+\r
 static string trim(std::string str){\r
     size_t i = 0,e = str.length();\r
     for(;i < e && std::isspace(str[i]);++i);\r
@@ -54,15 +71,69 @@ static void rand_init(void) {
     srandom(seed);\r
 }\r
 \r
+static uint8_t *b64_decode(const char *data, size_t input_length, size_t *output_length) {\r
+    assert(data);\r
+    assert(input_length);\r
+    assert(output_length);\r
+\r
+    int i, j;\r
+\r
+    //one time compute decoding table\r
+    if(b64_decoding_table['A'] == 0) {\r
+        for(i = 0; i < 64; i++) {\r
+            b64_decoding_table[(unsigned char)b64_encoding_table[i]] = i;\r
+        }\r
+    }\r
+\r
+    if(input_length % 4 != 0) {\r
+        return 0;\r
+    }\r
+\r
+    *output_length = input_length / 4 * 3;\r
+    if(data[input_length - 1] == '=') {\r
+        (*output_length )--;\r
+    }\r
+    if(data[input_length - 2] == '=') {\r
+        (*output_length )--;\r
+    }\r
+\r
+    uint8_t *decoded_data = (uint8_t*)malloc(*output_length + 1);\r
+    if(decoded_data == 0) {\r
+        return 0;\r
+    }\r
+\r
+    for(i = 0, j = 0; i < input_length;) {\r
+        uint32_t sextet_a = data[i] == '=' ? 0 & i++ : b64_decoding_table[(int)data[i++]];\r
+        uint32_t sextet_b = data[i] == '=' ? 0 & i++ : b64_decoding_table[(int)data[i++]];\r
+        uint32_t sextet_c = data[i] == '=' ? 0 & i++ : b64_decoding_table[(int)data[i++]];\r
+        uint32_t sextet_d = data[i] == '=' ? 0 & i++ : b64_decoding_table[(int)data[i++]];\r
+        uint32_t triple = ( sextet_a << 3 * 6 ) + ( sextet_b << 2 * 6 ) + ( sextet_c << 1 * 6 ) + ( sextet_d << 0 * 6 );\r
+\r
+        if(j < *output_length) {\r
+            decoded_data[j++] = (triple >> 2 * 8) & 0xFF;\r
+        }\r
+\r
+        if(j < *output_length) {\r
+            decoded_data[j++] = (triple >> 1 * 8) & 0xFF;\r
+        }\r
+\r
+        if(j < *output_length) {\r
+            decoded_data[j++] = (triple >> 0 * 8) & 0xFF;\r
+        }\r
+    }\r
+\r
+    return decoded_data;\r
+}\r
+\r
 int main(int argc, const char ** argv)\r
 {\r
     CRegxString regxstr;\r
-    string regx = "";\r
+    string regx64 = "";\r
 \r
     switch(argc) {\r
         case 2:\r
             rand_init();\r
-            regx = argv[1];\r
+            regx64 = argv[1];\r
             break;\r
 \r
         case 3:\r
@@ -75,10 +146,17 @@ int main(int argc, const char ** argv)
             }\r
             srand(pseudo_seed);\r
             srandom(pseudo_seed);\r
-            regx = argv[2];\r
+            regx64 = argv[2];\r
             break;\r
     }\r
 \r
+    size_t ol;\r
+    char *x = (char *)b64_decode(regx64.c_str(), strlen(regx64.c_str()), &ol);\r
+    x[ol] = 0;\r
+\r
+    string regx = x;\r
+    free(x);\r
+\r
     regxstr.ParseRegx(pre_handle(regx).c_str());\r
     cout << regxstr.RandString() << endl;\r
     \r