Initial OpenECOMP Demo commit 41/541/1
authorplatania <platania@research.att.com>
Thu, 16 Feb 2017 16:20:22 +0000 (11:20 -0500)
committerplatania <platania@research.att.com>
Thu, 16 Feb 2017 16:20:47 +0000 (11:20 -0500)
Change-Id: Ibf8696196a7ac2c84ac8aa7cde1982c9c89fb64d
Signed-off-by: platania <platania@research.att.com>
215 files changed:
.gitreview [new file with mode: 0644]
LICENSE.TXT [new file with mode: 0644]
README.md [new file with mode: 0644]
boot/.DS_Store [new file with mode: 0644]
boot/.gitkeep [new file with mode: 0644]
boot/aaf_serv.sh [new file with mode: 0644]
boot/aaf_vm_init.sh [new file with mode: 0644]
boot/aai_serv.sh [new file with mode: 0644]
boot/aai_vm_init.sh [new file with mode: 0644]
boot/appc_serv.sh [new file with mode: 0644]
boot/appc_vm_init.sh [new file with mode: 0644]
boot/asdc_ext_volume_partitions.txt [new file with mode: 0644]
boot/asdc_serv.sh [new file with mode: 0644]
boot/asdc_vm_init.sh [new file with mode: 0644]
boot/db_openecomp_org [new file with mode: 0644]
boot/dcae_serv.sh [new file with mode: 0644]
boot/dcae_vm_init.sh [new file with mode: 0644]
boot/mr_serv.sh [new file with mode: 0644]
boot/mr_vm_init.sh [new file with mode: 0644]
boot/mso_serv.sh [new file with mode: 0644]
boot/mso_vm_init.sh [new file with mode: 0644]
boot/named.conf.local [new file with mode: 0644]
boot/named.conf.options [new file with mode: 0644]
boot/policy_serv.sh [new file with mode: 0644]
boot/policy_vm_init.sh [new file with mode: 0644]
boot/portal_serv.sh [new file with mode: 0644]
boot/portal_vm_init.sh [new file with mode: 0644]
boot/robot_serv.sh [new file with mode: 0644]
boot/robot_vm_init.sh [new file with mode: 0644]
boot/sdnc_serv.sh [new file with mode: 0644]
boot/sdnc_vm_init.sh [new file with mode: 0644]
boot/vid_serv.sh [new file with mode: 0644]
boot/vid_vm_init.sh [new file with mode: 0644]
deploy_scripts/.DS_Store [new file with mode: 0644]
deploy_scripts/deploy_boot.sh [new file with mode: 0755]
deploy_scripts/deploy_heat.sh [new file with mode: 0755]
deploy_scripts/deploy_vfw_scripts.sh [new file with mode: 0755]
deploy_scripts/deploy_vlb_scripts.sh [new file with mode: 0755]
deploy_scripts/repo_config.txt [new file with mode: 0644]
heat/.DS_Store [new file with mode: 0644]
heat/.gitkeep [new file with mode: 0644]
heat/LICENSE.TXT [new file with mode: 0644]
heat/OpenECOMP/.DS_Store [new file with mode: 0644]
heat/README.md [new file with mode: 0644]
heat/vFW/.DS_Store [new file with mode: 0644]
heat/vLB/.DS_Store [new file with mode: 0644]
vnfs/.DS_Store [new file with mode: 0644]
vnfs/.gitkeep [new file with mode: 0644]
vnfs/LICENSE.TXT [new file with mode: 0644]
vnfs/README.md [new file with mode: 0644]
vnfs/VES/.DS_Store [new file with mode: 0644]
vnfs/VES/LICENSE.md [new file with mode: 0644]
vnfs/VES/bldjobs/Doxyfile [new file with mode: 0644]
vnfs/VES/bldjobs/Makefile [new file with mode: 0644]
vnfs/VES/code/.DS_Store [new file with mode: 0644]
vnfs/VES/code/evel_library/double_list.c [new file with mode: 0644]
vnfs/VES/code/evel_library/double_list.h [new file with mode: 0644]
vnfs/VES/code/evel_library/evel.c [new file with mode: 0644]
vnfs/VES/code/evel_library/evel.h [new file with mode: 0644]
vnfs/VES/code/evel_library/evel_event.c [new file with mode: 0644]
vnfs/VES/code/evel_library/evel_event_mgr.c [new file with mode: 0644]
vnfs/VES/code/evel_library/evel_fault.c [new file with mode: 0644]
vnfs/VES/code/evel_library/evel_internal.h [new file with mode: 0644]
vnfs/VES/code/evel_library/evel_internal_event.c [new file with mode: 0644]
vnfs/VES/code/evel_library/evel_json_buffer.c [new file with mode: 0644]
vnfs/VES/code/evel_library/evel_logging.c [new file with mode: 0644]
vnfs/VES/code/evel_library/evel_mobile_flow.c [new file with mode: 0644]
vnfs/VES/code/evel_library/evel_option.c [new file with mode: 0644]
vnfs/VES/code/evel_library/evel_other.c [new file with mode: 0644]
vnfs/VES/code/evel_library/evel_reporting_measurement.c [new file with mode: 0644]
vnfs/VES/code/evel_library/evel_scaling_measurement.c [new file with mode: 0644]
vnfs/VES/code/evel_library/evel_service.c [new file with mode: 0644]
vnfs/VES/code/evel_library/evel_signaling.c [new file with mode: 0644]
vnfs/VES/code/evel_library/evel_state_change.c [new file with mode: 0644]
vnfs/VES/code/evel_library/evel_strings.c [new file with mode: 0644]
vnfs/VES/code/evel_library/evel_syslog.c [new file with mode: 0644]
vnfs/VES/code/evel_library/evel_throttle.c [new file with mode: 0644]
vnfs/VES/code/evel_library/evel_throttle.h [new file with mode: 0644]
vnfs/VES/code/evel_library/jsmn.c [new file with mode: 0644]
vnfs/VES/code/evel_library/jsmn.h [new file with mode: 0644]
vnfs/VES/code/evel_library/license.md [new file with mode: 0644]
vnfs/VES/code/evel_library/metadata.c [new file with mode: 0644]
vnfs/VES/code/evel_library/metadata.h [new file with mode: 0644]
vnfs/VES/code/evel_library/quickstart.md [new file with mode: 0644]
vnfs/VES/code/evel_library/readme.md [new file with mode: 0644]
vnfs/VES/code/evel_library/ring_buffer.c [new file with mode: 0644]
vnfs/VES/code/evel_library/ring_buffer.h [new file with mode: 0644]
vnfs/VES/code/evel_training/.DS_Store [new file with mode: 0644]
vnfs/VES/code/evel_training/.gitignore [new file with mode: 0644]
vnfs/VES/code/evel_unit/evel_unit.c [new file with mode: 0644]
vnfs/VES/dep.xml [new file with mode: 0644]
vnfs/VES/docs/source/evel/README [new file with mode: 0644]
vnfs/VES/libs/x86_64/README [new file with mode: 0644]
vnfs/VES/libs/x86_64/libevel.a [new file with mode: 0755]
vnfs/VES/output/.DS_Store [new file with mode: 0644]
vnfs/VES/output/x86_64/README [new file with mode: 0644]
vnfs/VES/pom.xml [new file with mode: 0644]
vnfs/VES/readme.md [new file with mode: 0644]
vnfs/VESreporting_vFW/LICENSE.TXT [new file with mode: 0644]
vnfs/VESreporting_vFW/Makefile [new file with mode: 0644]
vnfs/VESreporting_vFW/README.md [new file with mode: 0644]
vnfs/VESreporting_vFW/dep.xml [new file with mode: 0644]
vnfs/VESreporting_vFW/go-client.sh [new file with mode: 0755]
vnfs/VESreporting_vFW/pom.xml [new file with mode: 0644]
vnfs/VESreporting_vFW/vpp_measurement_reporter.c [new file with mode: 0644]
vnfs/VESreporting_vLB/LICENSE.TXT [new file with mode: 0644]
vnfs/VESreporting_vLB/Makefile [new file with mode: 0644]
vnfs/VESreporting_vLB/README.md [new file with mode: 0644]
vnfs/VESreporting_vLB/dep.xml [new file with mode: 0644]
vnfs/VESreporting_vLB/go-client.sh [new file with mode: 0755]
vnfs/VESreporting_vLB/pom.xml [new file with mode: 0644]
vnfs/VESreporting_vLB/vpp_measurement_reporter.c [new file with mode: 0644]
vnfs/honeycomb_plugin/.DS_Store [new file with mode: 0644]
vnfs/honeycomb_plugin/sample_plugin/.DS_Store [new file with mode: 0644]
vnfs/honeycomb_plugin/sample_plugin/LICENSE.TXT [new file with mode: 0644]
vnfs/honeycomb_plugin/sample_plugin/README.md [new file with mode: 0755]
vnfs/honeycomb_plugin/sample_plugin/parent-pom/pom.xml [new file with mode: 0644]
vnfs/honeycomb_plugin/sample_plugin/pom.xml [new file with mode: 0755]
vnfs/honeycomb_plugin/sample_plugin/sample-distribution/.DS_Store [new file with mode: 0644]
vnfs/honeycomb_plugin/sample_plugin/sample-distribution/pom.xml [new file with mode: 0755]
vnfs/honeycomb_plugin/sample_plugin/sample-distribution/src/.DS_Store [new file with mode: 0644]
vnfs/honeycomb_plugin/sample_plugin/sample-distribution/src/main/.DS_Store [new file with mode: 0644]
vnfs/honeycomb_plugin/sample_plugin/sample-distribution/src/main/java/.DS_Store [new file with mode: 0644]
vnfs/honeycomb_plugin/sample_plugin/sample-distribution/src/main/java/io/.DS_Store [new file with mode: 0644]
vnfs/honeycomb_plugin/sample_plugin/sample-distribution/src/main/java/io/fd/.DS_Store [new file with mode: 0644]
vnfs/honeycomb_plugin/sample_plugin/sample-distribution/src/main/java/io/fd/honeycomb/.DS_Store [new file with mode: 0644]
vnfs/honeycomb_plugin/sample_plugin/sample-distribution/src/main/java/io/fd/honeycomb/tutorial/Main.java [new file with mode: 0755]
vnfs/honeycomb_plugin/sample_plugin/sample-plugin-api/.DS_Store [new file with mode: 0644]
vnfs/honeycomb_plugin/sample_plugin/sample-plugin-api/pom.xml [new file with mode: 0755]
vnfs/honeycomb_plugin/sample_plugin/sample-plugin-api/src/.DS_Store [new file with mode: 0644]
vnfs/honeycomb_plugin/sample_plugin/sample-plugin-api/src/main/.DS_Store [new file with mode: 0644]
vnfs/honeycomb_plugin/sample_plugin/sample-plugin-api/src/main/yang/sample-plugin.yang [new file with mode: 0755]
vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/.DS_Store [new file with mode: 0644]
vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/Readme.adoc [new file with mode: 0755]
vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/pom.xml [new file with mode: 0755]
vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/src/main/java/io/fd/honeycomb/tutorial/Module.java [new file with mode: 0755]
vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/src/main/java/io/fd/honeycomb/tutorial/ModuleConfiguration.java [new file with mode: 0755]
vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/src/main/java/io/fd/honeycomb/tutorial/init/ConfigDataInitializer.java [new file with mode: 0755]
vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/src/main/java/io/fd/honeycomb/tutorial/notif/SampleNotificationProducer.java [new file with mode: 0755]
vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/src/main/java/io/fd/honeycomb/tutorial/write/ModuleWriterFactory.java [new file with mode: 0755]
vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/src/main/java/io/fd/honeycomb/tutorial/write/PgWriteCustomizer.java [new file with mode: 0755]
vnfs/honeycomb_plugin/sample_plugin/settings.xml [new file with mode: 0644]
vnfs/pom.xml [new file with mode: 0755]
vnfs/settings.xml [new file with mode: 0644]
vnfs/vFW/.DS_Store [new file with mode: 0644]
vnfs/vFW/pg_streams/.DS_Store [new file with mode: 0644]
vnfs/vFW/pg_streams/dep.xml [new file with mode: 0644]
vnfs/vFW/pg_streams/pom.xml [new file with mode: 0644]
vnfs/vFW/pg_streams/stream_fw_udp1 [new file with mode: 0644]
vnfs/vFW/pg_streams/stream_fw_udp10 [new file with mode: 0644]
vnfs/vFW/pg_streams/stream_fw_udp2 [new file with mode: 0644]
vnfs/vFW/pg_streams/stream_fw_udp3 [new file with mode: 0644]
vnfs/vFW/pg_streams/stream_fw_udp4 [new file with mode: 0644]
vnfs/vFW/pg_streams/stream_fw_udp5 [new file with mode: 0644]
vnfs/vFW/pg_streams/stream_fw_udp6 [new file with mode: 0644]
vnfs/vFW/pg_streams/stream_fw_udp7 [new file with mode: 0644]
vnfs/vFW/pg_streams/stream_fw_udp8 [new file with mode: 0644]
vnfs/vFW/pg_streams/stream_fw_udp9 [new file with mode: 0644]
vnfs/vFW/scripts/.DS_Store [new file with mode: 0644]
vnfs/vFW/scripts/run_traffic_fw_demo.sh [new file with mode: 0755]
vnfs/vFW/scripts/v_firewall_init.sh [new file with mode: 0644]
vnfs/vFW/scripts/v_packetgen_init.sh [new file with mode: 0644]
vnfs/vFW/scripts/v_sink_init.sh [new file with mode: 0644]
vnfs/vFW/scripts/vfirewall.sh [new file with mode: 0644]
vnfs/vFW/scripts/vpacketgen.sh [new file with mode: 0644]
vnfs/vFW/scripts/vsink.sh [new file with mode: 0644]
vnfs/vLB/.DS_Store [new file with mode: 0644]
vnfs/vLB/DNSClient/.DS_Store [new file with mode: 0644]
vnfs/vLB/DNSClient/LICENSE.TXT [new file with mode: 0644]
vnfs/vLB/DNSClient/README.txt [new file with mode: 0644]
vnfs/vLB/DNSClient/pom.xml [new file with mode: 0644]
vnfs/vLB/DNSClient/src/.DS_Store [new file with mode: 0644]
vnfs/vLB/DNSClient/src/main/.DS_Store [new file with mode: 0644]
vnfs/vLB/DNSClient/src/main/java/.DS_Store [new file with mode: 0644]
vnfs/vLB/DNSClient/src/main/java/DNSServer.java [new file with mode: 0644]
vnfs/vLB/DNSClient/src/main/java/FDClient.java [new file with mode: 0644]
vnfs/vLB/DNSManager/.DS_Store [new file with mode: 0644]
vnfs/vLB/DNSManager/LICENSE.TXT [new file with mode: 0644]
vnfs/vLB/DNSManager/README.txt [new file with mode: 0644]
vnfs/vLB/DNSManager/pom.xml [new file with mode: 0644]
vnfs/vLB/DNSManager/src/.DS_Store [new file with mode: 0644]
vnfs/vLB/DNSManager/src/main/.DS_Store [new file with mode: 0644]
vnfs/vLB/DNSManager/src/main/java/.DS_Store [new file with mode: 0644]
vnfs/vLB/DNSManager/src/main/java/DNSMembershipManager.java [new file with mode: 0644]
vnfs/vLB/DNSManager/src/main/java/FDServer.java [new file with mode: 0644]
vnfs/vLB/dns_streams/.DS_Store [new file with mode: 0644]
vnfs/vLB/dns_streams/dep.xml [new file with mode: 0644]
vnfs/vLB/dns_streams/pom.xml [new file with mode: 0644]
vnfs/vLB/dns_streams/stream_dns1 [new file with mode: 0644]
vnfs/vLB/dns_streams/stream_dns10 [new file with mode: 0644]
vnfs/vLB/dns_streams/stream_dns2 [new file with mode: 0644]
vnfs/vLB/dns_streams/stream_dns3 [new file with mode: 0644]
vnfs/vLB/dns_streams/stream_dns4 [new file with mode: 0644]
vnfs/vLB/dns_streams/stream_dns5 [new file with mode: 0644]
vnfs/vLB/dns_streams/stream_dns6 [new file with mode: 0644]
vnfs/vLB/dns_streams/stream_dns7 [new file with mode: 0644]
vnfs/vLB/dns_streams/stream_dns8 [new file with mode: 0644]
vnfs/vLB/dns_streams/stream_dns9 [new file with mode: 0644]
vnfs/vLB/scripts/.DS_Store [new file with mode: 0644]
vnfs/vLB/scripts/add_dns.sh [new file with mode: 0644]
vnfs/vLB/scripts/db_dnsdemo_openecomp_org [new file with mode: 0644]
vnfs/vLB/scripts/dnsclient.sh [new file with mode: 0644]
vnfs/vLB/scripts/dnsmembership.sh [new file with mode: 0644]
vnfs/vLB/scripts/named.conf.local [new file with mode: 0644]
vnfs/vLB/scripts/named.conf.options [new file with mode: 0644]
vnfs/vLB/scripts/remove_dns.sh [new file with mode: 0644]
vnfs/vLB/scripts/run_streams_dns.sh [new file with mode: 0755]
vnfs/vLB/scripts/set_gre_tunnel.sh [new file with mode: 0644]
vnfs/vLB/scripts/v_dns_init.sh [new file with mode: 0755]
vnfs/vLB/scripts/v_lb_init.sh [new file with mode: 0755]
vnfs/vLB/scripts/v_packetgen_for_dns_demo_init.sh [new file with mode: 0644]
vnfs/vLB/scripts/vdns.sh [new file with mode: 0644]
vnfs/vLB/scripts/vdnspacketgen_change_streams_ports.sh [new file with mode: 0644]
vnfs/vLB/scripts/vlb.sh [new file with mode: 0644]
vnfs/vLB/scripts/vpacketgenfordnsdemo.sh [new file with mode: 0644]

diff --git a/.gitreview b/.gitreview
new file mode 100644 (file)
index 0000000..ab3f054
--- /dev/null
@@ -0,0 +1,4 @@
+[gerrit]
+host=gerrit.openecomp.org
+port=29418
+project=demo.git
diff --git a/LICENSE.TXT b/LICENSE.TXT
new file mode 100644 (file)
index 0000000..5640474
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * ============LICENSE_START==========================================
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ===================================================================
+ * 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.
+ * ============LICENSE_END============================================
+ *
+ * ECOMP and OpenECOMP are trademarks 
+ * and service marks of AT&T Intellectual Property.
+ *
+ */
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..98b68a2
--- /dev/null
+++ b/README.md
@@ -0,0 +1,23 @@
+OpenECOMP Platform Instantiation and Demo Applications
+---
+
+This project contains the source code and scripts to instantiate OpenECOMP and the two demo applications, vFirewall and vLoadBalancer/vDNS. 
+
+This repository includes:
+
+- README.md: this file
+
+- LICENSE.TXT: the license file
+
+- The "boot" directory: the scripts to instantiate OpenECOMP. 
+
+- The "heat" directory: the heat templates to instantiate OpenECOMP and the demo applications. 
+
+- The "vnfs" directory: the scripts and source codes for running the two demo applications. 
+
+Usage
+---
+
+To instantiate OpenECOMP, please download and run the heat template and environment files in "heat/OpenECOMP". Please follow instructions in "heat/README.md" for further details. 
+
+
diff --git a/boot/.DS_Store b/boot/.DS_Store
new file mode 100644 (file)
index 0000000..5008ddf
Binary files /dev/null and b/boot/.DS_Store differ
diff --git a/boot/.gitkeep b/boot/.gitkeep
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/boot/aaf_serv.sh b/boot/aaf_serv.sh
new file mode 100644 (file)
index 0000000..73d22ad
--- /dev/null
@@ -0,0 +1,98 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides:
+# Required-Start:    $remote_fs $syslog
+# Required-Stop:     $remote_fs $syslog
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Start daemon at boot time
+# Description:       Enable service provided by daemon.
+### END INIT INFO
+
+dir="/opt"
+cmd="./aaf_vm_init.sh"
+user="root"
+
+name=`basename $0`
+pid_file="/var/run/$name.pid"
+stdout_log="/var/log/$name.log"
+stderr_log="/var/log/$name.err"
+
+get_pid() {
+    cat "$pid_file"
+}
+
+is_running() {
+    [ -f "$pid_file" ] && ps `get_pid` > /dev/null 2>&1
+}
+
+case "$1" in
+    start)
+    if is_running; then
+        echo "Already started"
+    else
+        echo "Starting $name"
+        cd "$dir"
+        if [ -z "$user" ]; then
+            sudo $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        else
+            sudo -u "$user" $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        fi
+        echo $! > "$pid_file"
+        if ! is_running; then
+            echo "Unable to start, see $stdout_log and $stderr_log"
+            exit 1
+        fi
+    fi
+    ;;
+    stop)
+    if is_running; then
+        echo -n "Stopping $name.."
+        kill `get_pid`
+        for i in {1..10}
+        do
+            if ! is_running; then
+                break
+            fi
+
+            echo -n "."
+            sleep 1
+        done
+        echo
+
+        if is_running; then
+            echo "Not stopped; may still be shutting down or shutdown may have failed"
+            exit 1
+        else
+            echo "Stopped"
+            if [ -f "$pid_file" ]; then
+                rm "$pid_file"
+            fi
+        fi
+    else
+        echo "Not running"
+    fi
+    ;;
+    restart)
+    $0 stop
+    if is_running; then
+        echo "Unable to stop, will not attempt to start"
+        exit 1
+    fi
+    $0 start
+    ;;
+    status)
+    if is_running; then
+        echo "Running"
+    else
+        echo "Stopped"
+        exit 1
+    fi
+    ;;
+    *)
+    echo "Usage: $0 {start|stop|restart|status}"
+    exit 1
+    ;;
+esac
+
+exit 0
diff --git a/boot/aaf_vm_init.sh b/boot/aaf_vm_init.sh
new file mode 100644 (file)
index 0000000..1f29429
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+cd dcae-startup-vm-aaf
+./deploy.sh
diff --git a/boot/aai_serv.sh b/boot/aai_serv.sh
new file mode 100644 (file)
index 0000000..2e0dbab
--- /dev/null
@@ -0,0 +1,98 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides:
+# Required-Start:    $remote_fs $syslog
+# Required-Stop:     $remote_fs $syslog
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Start daemon at boot time
+# Description:       Enable service provided by daemon.
+### END INIT INFO
+
+dir="/opt"
+cmd="./aai_vm_init.sh"
+user="root"
+
+name=`basename $0`
+pid_file="/var/run/$name.pid"
+stdout_log="/var/log/$name.log"
+stderr_log="/var/log/$name.err"
+
+get_pid() {
+    cat "$pid_file"
+}
+
+is_running() {
+    [ -f "$pid_file" ] && ps `get_pid` > /dev/null 2>&1
+}
+
+case "$1" in
+    start)
+    if is_running; then
+        echo "Already started"
+    else
+        echo "Starting $name"
+        cd "$dir"
+        if [ -z "$user" ]; then
+            sudo $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        else
+            sudo -u "$user" $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        fi
+        echo $! > "$pid_file"
+        if ! is_running; then
+            echo "Unable to start, see $stdout_log and $stderr_log"
+            exit 1
+        fi
+    fi
+    ;;
+    stop)
+    if is_running; then
+        echo -n "Stopping $name.."
+        kill `get_pid`
+        for i in {1..10}
+        do
+            if ! is_running; then
+                break
+            fi
+
+            echo -n "."
+            sleep 1
+        done
+        echo
+
+        if is_running; then
+            echo "Not stopped; may still be shutting down or shutdown may have failed"
+            exit 1
+        else
+            echo "Stopped"
+            if [ -f "$pid_file" ]; then
+                rm "$pid_file"
+            fi
+        fi
+    else
+        echo "Not running"
+    fi
+    ;;
+    restart)
+    $0 stop
+    if is_running; then
+        echo "Unable to stop, will not attempt to start"
+        exit 1
+    fi
+    $0 start
+    ;;
+    status)
+    if is_running; then
+        echo "Running"
+    else
+        echo "Stopped"
+        exit 1
+    fi
+    ;;
+    *)
+    echo "Usage: $0 {start|stop|restart|status}"
+    exit 1
+    ;;
+esac
+
+exit 0
diff --git a/boot/aai_vm_init.sh b/boot/aai_vm_init.sh
new file mode 100644 (file)
index 0000000..148fc58
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+NEXUS_USERNAME=$(cat /opt/config/nexus_username.txt)
+NEXUS_PASSWD=$(cat /opt/config/nexus_password.txt)
+NEXUS_DOCKER_REPO=$(cat /opt/config/nexus_docker_repo.txt)
+DMAAP_TOPIC=$(cat /opt/config/dmaap_topic.txt)
+GITLAB_CERTNAME=$(cat /opt/config/gitlab_certname.txt)
+GITLAB_USERNAME=$(cat /opt/config/gitlab_username.txt)
+GITLAB_PASSWD=$(cat /opt/config/gitlab_password.txt)
+
+docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO
+
+docker pull $NEXUS_DOCKER_REPO/ecomp/aai-hbase-1.2.3
+docker rm -f hbase-1.2.3
+docker run -d --net=host --name="hbase-1.2.3" $NEXUS_DOCKER_REPO/ecomp/aai-hbase-1.2.3
+
+# Wait 3 minutes before instantiating the A&AI container
+sleep 180
+
+docker pull $NEXUS_DOCKER_REPO/ecomp/ajsc-aai:latest
+docker rm -f aai-service
+docker run --name=aai-service --net=host -v /etc/ssl/certs/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt -it -e GITLAB_CERTNAME=$GITLAB_CERTNAME -e GITLAB_USERNAME=$GITLAB_USERNAME -e GITLAB_PASSWORD=$GITLAB_PASSWD -e AAI_REPO_PATH=OpenECOMP -e AAI_CHEF_ENV=simpledemo -d -e AAI_CHEF_LOC=/var/chef/aai-data/environments -e docker_gitbranch=develop $NEXUS_DOCKER_REPO/ecomp/ajsc-aai:latest
+
+docker pull $NEXUS_DOCKER_REPO/ecomp/model-loader:latest
+docker rm -f model-loader-service
+
+docker run --name=model-loader-service -it -d -e DISTR_CLIENT_ASDC_ADDRESS=c2.vm1.asdc.simpledemo.openecomp.org:8443 -e DISTR_CLIENT_ENVIRONMENT_NAME=$DMAAP_TOPIC -e DISTR_CLIENT_USER=aai -e DISTR_CLIENT_PASSWORD=OBF:1ks51l8d1o3i1pcc1r2r1e211r391kls1pyj1z7u1njf1lx51go21hnj1y0k1mli1sop1k8o1j651vu91mxw1vun1mze1vv11j8x1k5i1sp11mjc1y161hlr1gm41m111nkj1z781pw31kku1r4p1e391r571pbm1o741l4x1ksp -e APP_SERVER_BASE_URL=https://c1.vm1.aai.simpledemo.openecomp.org:8443 -e APP_SERVER_KEYSTORE_PASSWORD=OBF:1i9a1u2a1unz1lr61wn51wn11lss1unz1u301i6o -e APP_SERVER_AUTH_USER=ModelLoader -e APP_SERVER_AUTH_PASSWORD=OBF:1qvu1v2h1sov1sar1wfw1j7j1wg21saj1sov1v1x1qxw $NEXUS_DOCKER_REPO/ecomp/model-loader:latest
+
diff --git a/boot/appc_serv.sh b/boot/appc_serv.sh
new file mode 100644 (file)
index 0000000..a71db88
--- /dev/null
@@ -0,0 +1,98 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides:
+# Required-Start:    $remote_fs $syslog
+# Required-Stop:     $remote_fs $syslog
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Start daemon at boot time
+# Description:       Enable service provided by daemon.
+### END INIT INFO
+
+dir="/opt"
+cmd="./appc_vm_init.sh"
+user="root"
+
+name=`basename $0`
+pid_file="/var/run/$name.pid"
+stdout_log="/var/log/$name.log"
+stderr_log="/var/log/$name.err"
+
+get_pid() {
+    cat "$pid_file"
+}
+
+is_running() {
+    [ -f "$pid_file" ] && ps `get_pid` > /dev/null 2>&1
+}
+
+case "$1" in
+    start)
+    if is_running; then
+        echo "Already started"
+    else
+        echo "Starting $name"
+        cd "$dir"
+        if [ -z "$user" ]; then
+            sudo $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        else
+            sudo -u "$user" $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        fi
+        echo $! > "$pid_file"
+        if ! is_running; then
+            echo "Unable to start, see $stdout_log and $stderr_log"
+            exit 1
+        fi
+    fi
+    ;;
+    stop)
+    if is_running; then
+        echo -n "Stopping $name.."
+        kill `get_pid`
+        for i in {1..10}
+        do
+            if ! is_running; then
+                break
+            fi
+
+            echo -n "."
+            sleep 1
+        done
+        echo
+
+        if is_running; then
+            echo "Not stopped; may still be shutting down or shutdown may have failed"
+            exit 1
+        else
+            echo "Stopped"
+            if [ -f "$pid_file" ]; then
+                rm "$pid_file"
+            fi
+        fi
+    else
+        echo "Not running"
+    fi
+    ;;
+    restart)
+    $0 stop
+    if is_running; then
+        echo "Unable to stop, will not attempt to start"
+        exit 1
+    fi
+    $0 start
+    ;;
+    status)
+    if is_running; then
+        echo "Running"
+    else
+        echo "Stopped"
+        exit 1
+    fi
+    ;;
+    *)
+    echo "Usage: $0 {start|stop|restart|status}"
+    exit 1
+    ;;
+esac
+
+exit 0
diff --git a/boot/appc_vm_init.sh b/boot/appc_vm_init.sh
new file mode 100644 (file)
index 0000000..1692a07
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+NEXUS_USERNAME=$(cat /opt/config/nexus_username.txt)
+NEXUS_PASSWD=$(cat /opt/config/nexus_password.txt)
+NEXUS_DOCKER_REPO=$(cat /opt/config/nexus_docker_repo.txt)
+DMAAP_TOPIC=$(cat /opt/config/dmaap_topic.txt)
+
+cd /opt/appc
+
+sed -i "s/DMAAP_TOPIC_ENV=.*/DMAAP_TOPIC_ENV="$DMAAP_TOPIC"/g" /opt/appc/docker-compose.yml
+
+docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO
+/opt/docker/docker-compose pull
+/opt/docker/docker-compose up -d
diff --git a/boot/asdc_ext_volume_partitions.txt b/boot/asdc_ext_volume_partitions.txt
new file mode 100644 (file)
index 0000000..b00c6ae
--- /dev/null
@@ -0,0 +1,7 @@
+# partition table of /dev/xvdb
+unit: sectors
+
+/dev/xvdb1 : start=     2048, size=209713152, Id=83
+/dev/xvdb2 : start=        0, size=        0, Id= 0
+/dev/xvdb3 : start=        0, size=        0, Id= 0
+/dev/xvdb4 : start=        0, size=        0, Id= 0
diff --git a/boot/asdc_serv.sh b/boot/asdc_serv.sh
new file mode 100644 (file)
index 0000000..7d2539e
--- /dev/null
@@ -0,0 +1,98 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides:
+# Required-Start:    $remote_fs $syslog
+# Required-Stop:     $remote_fs $syslog
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Start daemon at boot time
+# Description:       Enable service provided by daemon.
+### END INIT INFO
+
+dir="/opt"
+cmd="./asdc_vm_init.sh"
+user="root"
+
+name=`basename $0`
+pid_file="/var/run/$name.pid"
+stdout_log="/var/log/$name.log"
+stderr_log="/var/log/$name.err"
+
+get_pid() {
+    cat "$pid_file"
+}
+
+is_running() {
+    [ -f "$pid_file" ] && ps `get_pid` > /dev/null 2>&1
+}
+
+case "$1" in
+    start)
+    if is_running; then
+        echo "Already started"
+    else
+        echo "Starting $name"
+        cd "$dir"
+        if [ -z "$user" ]; then
+            sudo $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        else
+            sudo -u "$user" $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        fi
+        echo $! > "$pid_file"
+        if ! is_running; then
+            echo "Unable to start, see $stdout_log and $stderr_log"
+            exit 1
+        fi
+    fi
+    ;;
+    stop)
+    if is_running; then
+        echo -n "Stopping $name.."
+        kill `get_pid`
+        for i in {1..10}
+        do
+            if ! is_running; then
+                break
+            fi
+
+            echo -n "."
+            sleep 1
+        done
+        echo
+
+        if is_running; then
+            echo "Not stopped; may still be shutting down or shutdown may have failed"
+            exit 1
+        else
+            echo "Stopped"
+            if [ -f "$pid_file" ]; then
+                rm "$pid_file"
+            fi
+        fi
+    else
+        echo "Not running"
+    fi
+    ;;
+    restart)
+    $0 stop
+    if is_running; then
+        echo "Unable to stop, will not attempt to start"
+        exit 1
+    fi
+    $0 start
+    ;;
+    status)
+    if is_running; then
+        echo "Running"
+    else
+        echo "Stopped"
+        exit 1
+    fi
+    ;;
+    *)
+    echo "Usage: $0 {start|stop|restart|status}"
+    exit 1
+    ;;
+esac
+
+exit 0
diff --git a/boot/asdc_vm_init.sh b/boot/asdc_vm_init.sh
new file mode 100644 (file)
index 0000000..f0777d5
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+NEXUS_USERNAME=$(cat /opt/config/nexus_username.txt)
+NEXUS_PASSWD=$(cat /opt/config/nexus_password.txt)
+NEXUS_DOCKER_REPO=$(cat /opt/config/nexus_docker_repo.txt)
+ENV_NAME=$(cat /opt/config/env_name.txt)
+
+docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO
+bash /data/scripts/docker_run.sh -e $ENV_NAME
diff --git a/boot/db_openecomp_org b/boot/db_openecomp_org
new file mode 100644 (file)
index 0000000..be42b60
--- /dev/null
@@ -0,0 +1,109 @@
+;
+; BIND data file for local loopback interface
+;
+$TTL    604800
+@       IN      SOA     openecomp.org. admin.openecomp.org. (
+                        20161202        ; Serial
+                         604800         ; Refresh
+                          86400         ; Retry
+                        2419200         ; Expire
+                         604800 )       ; Negative Cache TTL
+;
+; name servers - NS records
+    IN      NS      openecomp.org.
+
+; name servers - A records
+openecomp.org.          IN      A       10.0.0.1
+
+;
+vm1.aai.simpledemo.openecomp.org.       IN      A       10.0.1.1
+c1.vm1.aai.simpledemo.openecomp.org.    IN      A       10.0.1.1
+c2.vm1.aai.simpledemo.openecomp.org.    IN      A       10.0.1.1
+c3.vm1.aai.simpledemo.openecomp.org.    IN      A       10.0.1.1
+
+vm1.appc.simpledemo.openecomp.org.      IN      A       10.0.2.1
+c1.vm1.appc.simpledemo.openecomp.org.   IN      A       10.0.2.1
+c2.vm1.appc.simpledemo.openecomp.org.   IN      A       10.0.2.1
+
+vm1.asdc.simpledemo.openecomp.org.      IN      A       10.0.3.1
+c1.vm1.asdc.simpledemo.openecomp.org.   IN      A       10.0.3.1
+c2.vm1.asdc.simpledemo.openecomp.org.   IN      A       10.0.3.1
+c3.vm1.asdc.simpledemo.openecomp.org.   IN      A       10.0.3.1
+c4.vm1.asdc.simpledemo.openecomp.org.   IN      A       10.0.3.1
+
+vm1.dcae.simpledemo.openecomp.org.           IN      A       10.0.4.1
+c1.vm1.dcae.simpledemo.openecomp.org.        IN      A       10.0.4.1
+c2.vm1.dcae.simpledemo.openecomp.org.        IN      A       10.0.4.1
+c3.vm1.dcae.simpledemo.openecomp.org         IN      A       10.0.4.1
+
+vm1.mso.simpledemo.openecomp.org.       IN      A       10.0.5.1
+c1.vm1.mso.simpledemo.openecomp.org.    IN      A       10.0.5.1
+c1.vm1.mso.simpledemo.openecomp.org.    IN      A       10.0.5.1
+
+vm1.policy.simpledemo.openecomp.org.    IN      A       10.0.6.1
+c1.vm1.policy.simpledemo.openecomp.org. IN      A       10.0.6.1
+c2.vm1.policy.simpledemo.openecomp.org. IN      A       10.0.6.1
+c3.vm1.policy.simpledemo.openecomp.org. IN      A       10.0.6.1
+c4.vm1.policy.simpledemo.openecomp.org. IN      A       10.0.6.1
+c5.vm1.policy.simpledemo.openecomp.org. IN      A       10.0.6.1
+c6.vm1.policy.simpledemo.openecomp.org. IN      A       10.0.6.1
+c7.vm1.policy.simpledemo.openecomp.org. IN      A       10.0.6.1
+c8.vm1.policy.simpledemo.openecomp.org. IN      A       10.0.6.1
+
+vm1.sdnc.simpledemo.openecomp.org.      IN      A       10.0.7.1
+c1.vm1.sdnc.simpledemo.openecomp.org.   IN      A       10.0.7.1
+c2.vm1.sdnc.simpledemo.openecomp.org.   IN      A       10.0.7.1
+c3.vm1.sdnc.simpledemo.openecomp.org.   IN      A       10.0.7.1
+c4.vm1.sdnc.simpledemo.openecomp.org.   IN      A       10.0.7.1
+
+vm1.vid.simpledemo.openecomp.org.       IN      A       10.0.8.1
+c1.vm1.vid.simpledemo.openecomp.org.    IN      A       10.0.8.1
+c2.vm1.vid.simpledemo.openecomp.org.    IN      A       10.0.8.1
+
+vm1.portal.simpledemo.openecomp.org.           IN      A       10.0.9.1
+c1.vm1.portal.simpledemo.openecomp.org.        IN      A       10.0.9.1
+c2.vm1.portal.simpledemo.openecomp.org.        IN      A       10.0.9.1
+
+vm1.aaf.simpledemo.openecomp.org.      IN      A       10.0.12.1
+
+vm1.mr.simpledemo.openecomp.org.       IN      A       10.0.11.1       
+
+;CNAMES
+;A&AI
+aai.api.simpledemo.openecomp.org.      IN      CNAME   vm1.aai.simpledemo.openecomp.org.
+aai.hbase.simpledemo.openecomp.org.    IN      CNAME   vm1.aai.simpledemo.openecomp.org.
+
+;APPC
+appc.api.simpledemo.openecomp.org.     IN      CNAME   vm1.appc.simpledemo.openecomp.org.
+
+;ASDC
+asdc.api.simpledemo.openecomp.org.     IN      CNAME   vm1.asdc.simpledemo.openecomp.org.      
+
+;DCAE
+dcae.api.simpledemo.openecomp.org.     IN      CNAME   vm1.dcae.simpledemo.openecomp.org.
+
+;MSO
+mso.api.simpledemo.openecomp.org.      IN      CNAME   vm1.mso.simpledemo.openecomp.org.
+
+;Policy
+policy.api.simpledemo.openecomp.org.   IN      CNAME   vm1.policy.simpledemo.openecomp.org.
+
+;SDNC
+sdnc.api.simpledemo.openecomp.org.     IN      CNAME    vm1.sdnc.simpledemo.openecomp.org.
+
+;VID
+vid.api.simpledemo.openecomp.org.      IN      CNAME   vm1.vid.simpledemo.openecomp.org.       
+
+;PORTAL
+portal.api.simpledemo.openecomp.org.   IN      CNAME   vm1.portal.simpledemo.openecomp.org.
+
+;Message Router
+;mr.api.simpledemo.openecomp.org.      IN      CNAME   vm1.mr.simpledemo.openecomp.org.        
+ueb.api.simpledemo.openecomp.org.      IN      CNAME   vm1.mr.simpledemo.openecomp.org.
+mr.api.simpledemo.openecomp.org.        IN      A   10.0.4.102
+collector.api.simpledemo.openecomp.org. IN      A   10.0.4.102
+;dbc.api.simpledemo.openecomp.org.     IN      CNAME   vm1.mr.simpledemo.openecomp.org.
+;drprov.api.simpledemo.openecomp.org.  IN      CNAME   vm1.mr.simpledemo.openecomp.org.
+
+;AAF
+aaf.api.simpledemo.openecomp.org.      IN      CNAME   vm1.aaf.simpledemo.openecomp.org.
\ No newline at end of file
diff --git a/boot/dcae_serv.sh b/boot/dcae_serv.sh
new file mode 100644 (file)
index 0000000..f20a37b
--- /dev/null
@@ -0,0 +1,116 @@
+
+#############################################################################
+#
+# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+#
+# 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.
+#
+#############################################################################
+
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides:
+# Required-Start:    $remote_fs $syslog
+# Required-Stop:     $remote_fs $syslog
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Start daemon at boot time
+# Description:       Enable service provided by daemon.
+### END INIT INFO
+
+dir="/opt"
+cmd="./dcae_vm_init.sh"
+user="root"
+
+name=`basename $0`
+pid_file="/var/run/$name.pid"
+stdout_log="/var/log/$name.log"
+stderr_log="/var/log/$name.err"
+
+get_pid() {
+    cat "$pid_file"
+}
+
+is_running() {
+    [ -f "$pid_file" ] && ps `get_pid` > /dev/null 2>&1
+}
+
+case "$1" in
+    start)
+    if is_running; then
+        echo "Already started"
+    else
+        echo "Starting $name"
+        cd "$dir"
+        if [ -z "$user" ]; then
+            sudo $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        else
+            sudo -u "$user" $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        fi
+        echo $! > "$pid_file"
+        if ! is_running; then
+            echo "Unable to start, see $stdout_log and $stderr_log"
+            exit 1
+        fi
+    fi
+    ;;
+    stop)
+    if is_running; then
+        echo -n "Stopping $name.."
+        kill `get_pid`
+        for i in {1..10}
+        do
+            if ! is_running; then
+                break
+            fi
+
+            echo -n "."
+            sleep 1
+        done
+        echo
+
+        if is_running; then
+            echo "Not stopped; may still be shutting down or shutdown may have failed"
+            exit 1
+        else
+            echo "Stopped"
+            if [ -f "$pid_file" ]; then
+                rm "$pid_file"
+            fi
+        fi
+    else
+        echo "Not running"
+    fi
+    ;;
+    restart)
+    $0 stop
+    if is_running; then
+        echo "Unable to stop, will not attempt to start"
+        exit 1
+    fi
+    $0 start
+    ;;
+    status)
+    if is_running; then
+        echo "Running"
+    else
+        echo "Stopped"
+        exit 1
+    fi
+    ;;
+    *)
+    echo "Usage: $0 {start|stop|restart|status}"
+    exit 1
+    ;;
+esac
+
+exit 0
diff --git a/boot/dcae_vm_init.sh b/boot/dcae_vm_init.sh
new file mode 100644 (file)
index 0000000..1802ed4
--- /dev/null
@@ -0,0 +1,23 @@
+
+#############################################################################
+#
+# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+#
+# 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.
+#
+#############################################################################
+
+#!/bin/bash
+
+cd /opt/dcae-startup-vm-controller
+bash init.sh
+make up
diff --git a/boot/mr_serv.sh b/boot/mr_serv.sh
new file mode 100644 (file)
index 0000000..77f8639
--- /dev/null
@@ -0,0 +1,116 @@
+
+#############################################################################
+#
+# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+#
+# 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.
+#
+#############################################################################
+
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides:
+# Required-Start:    $remote_fs $syslog
+# Required-Stop:     $remote_fs $syslog
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Start daemon at boot time
+# Description:       Enable service provided by daemon.
+### END INIT INFO
+
+dir="/opt"
+cmd="./mr_vm_init.sh"
+user="root"
+
+name=`basename $0`
+pid_file="/var/run/$name.pid"
+stdout_log="/var/log/$name.log"
+stderr_log="/var/log/$name.err"
+
+get_pid() {
+    cat "$pid_file"
+}
+
+is_running() {
+    [ -f "$pid_file" ] && ps `get_pid` > /dev/null 2>&1
+}
+
+case "$1" in
+    start)
+    if is_running; then
+        echo "Already started"
+    else
+        echo "Starting $name"
+        cd "$dir"
+        if [ -z "$user" ]; then
+            sudo $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        else
+            sudo -u "$user" $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        fi
+        echo $! > "$pid_file"
+        if ! is_running; then
+            echo "Unable to start, see $stdout_log and $stderr_log"
+            exit 1
+        fi
+    fi
+    ;;
+    stop)
+    if is_running; then
+        echo -n "Stopping $name.."
+        kill `get_pid`
+        for i in {1..10}
+        do
+            if ! is_running; then
+                break
+            fi
+
+            echo -n "."
+            sleep 1
+        done
+        echo
+
+        if is_running; then
+            echo "Not stopped; may still be shutting down or shutdown may have failed"
+            exit 1
+        else
+            echo "Stopped"
+            if [ -f "$pid_file" ]; then
+                rm "$pid_file"
+            fi
+        fi
+    else
+        echo "Not running"
+    fi
+    ;;
+    restart)
+    $0 stop
+    if is_running; then
+        echo "Unable to stop, will not attempt to start"
+        exit 1
+    fi
+    $0 start
+    ;;
+    status)
+    if is_running; then
+        echo "Running"
+    else
+        echo "Stopped"
+        exit 1
+    fi
+    ;;
+    *)
+    echo "Usage: $0 {start|stop|restart|status}"
+    exit 1
+    ;;
+esac
+
+exit 0
diff --git a/boot/mr_vm_init.sh b/boot/mr_vm_init.sh
new file mode 100644 (file)
index 0000000..4cd6caf
--- /dev/null
@@ -0,0 +1,22 @@
+
+#############################################################################
+#
+# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+#
+# 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.
+#
+#############################################################################
+
+#!/bin/bash
+
+cd /opt/dcae-startup-vm-message-router
+bash deploy.sh
diff --git a/boot/mso_serv.sh b/boot/mso_serv.sh
new file mode 100644 (file)
index 0000000..00ee417
--- /dev/null
@@ -0,0 +1,98 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides:
+# Required-Start:    $remote_fs $syslog
+# Required-Stop:     $remote_fs $syslog
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Start daemon at boot time
+# Description:       Enable service provided by daemon.
+### END INIT INFO
+
+dir="/opt"
+cmd="./mso_vm_init.sh"
+user="root"
+
+name=`basename $0`
+pid_file="/var/run/$name.pid"
+stdout_log="/var/log/$name.log"
+stderr_log="/var/log/$name.err"
+
+get_pid() {
+    cat "$pid_file"
+}
+
+is_running() {
+    [ -f "$pid_file" ] && ps `get_pid` > /dev/null 2>&1
+}
+
+case "$1" in
+    start)
+    if is_running; then
+        echo "Already started"
+    else
+        echo "Starting $name"
+        cd "$dir"
+        if [ -z "$user" ]; then
+            sudo $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        else
+            sudo -u "$user" $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        fi
+        echo $! > "$pid_file"
+        if ! is_running; then
+            echo "Unable to start, see $stdout_log and $stderr_log"
+            exit 1
+        fi
+    fi
+    ;;
+    stop)
+    if is_running; then
+        echo -n "Stopping $name.."
+        kill `get_pid`
+        for i in {1..10}
+        do
+            if ! is_running; then
+                break
+            fi
+
+            echo -n "."
+            sleep 1
+        done
+        echo
+
+        if is_running; then
+            echo "Not stopped; may still be shutting down or shutdown may have failed"
+            exit 1
+        else
+            echo "Stopped"
+            if [ -f "$pid_file" ]; then
+                rm "$pid_file"
+            fi
+        fi
+    else
+        echo "Not running"
+    fi
+    ;;
+    restart)
+    $0 stop
+    if is_running; then
+        echo "Unable to stop, will not attempt to start"
+        exit 1
+    fi
+    $0 start
+    ;;
+    status)
+    if is_running; then
+        echo "Running"
+    else
+        echo "Stopped"
+        exit 1
+    fi
+    ;;
+    *)
+    echo "Usage: $0 {start|stop|restart|status}"
+    exit 1
+    ;;
+esac
+
+exit 0
diff --git a/boot/mso_vm_init.sh b/boot/mso_vm_init.sh
new file mode 100644 (file)
index 0000000..f878f53
--- /dev/null
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+NEXUS_USERNAME=$(cat /opt/config/nexus_username.txt)
+NEXUS_PASSWD=$(cat /opt/config/nexus_password.txt)
+NEXUS_DOCKER_REPO=$(cat /opt/config/nexus_docker_repo.txt)
+OPENSTACK_USERNAME=$(cat /opt/config/openstack_username.txt)
+OPENSTACK_APIKEY=$(cat /opt/config/api_key.txt)
+DMAAP_TOPIC=$(cat /opt/config/dmaap_topic.txt)
+export MSO_DOCKER_IMAGE_VERSION=1.0.0
+
+# Update the MSO configuration file.
+read -d '' MSO_CONFIG_UPDATES <<-EOF
+{
+"default_attributes":
+  {
+    "asdc-connections":
+      {
+           "asdc-controller1":
+           {
+               "environmentName": "$DMAAP_TOPIC"
+           }
+      },
+      "mso-po-adapter-config": 
+         {
+           "identity_services": 
+               [
+                   {"dcp_clli": "RAX_KEYSTONE", 
+                    "identity_url": "https://identity.api.rackspacecloud.com/v2.0", 
+                    "mso_id": "$OPENSTACK_USERNAME", 
+                    "mso_pass": "$OPENSTACK_APIKEY", 
+                    "admin_tenant": "service", 
+                    "member_role": "admin", 
+                    "tenant_metadata": "true",
+                    "identity_server_type": "KEYSTONE", 
+                    "identity_authentication_type": "RACKSPACE_APIKEY"
+                       
+                   }
+               ]
+         }
+  }
+}
+EOF
+export MSO_CONFIG_UPDATES
+
+
+# Deploy the environment
+cd /opt/test_lab
+chmod +x deploy.sh
+#This script takes in input 2 nexus repos (the first one for the MSO image, the second one for mariadb)
+./deploy.sh $NEXUS_DOCKER_REPO $NEXUS_USERNAME $NEXUS_PASSWD ecomp-nexus:51211 release sfWU3DFVdBr7GVxB85mTYgAW
diff --git a/boot/named.conf.local b/boot/named.conf.local
new file mode 100644 (file)
index 0000000..3cc9f0d
--- /dev/null
@@ -0,0 +1,12 @@
+//
+// Do any local configuration here
+//
+
+// Consider adding the 1918 zones here, if they are not used in your
+// organization
+//include "/etc/bind/zones.rfc1918";
+
+zone "openecomp.org" {
+    type master;
+    file "/etc/bind/zones/db.openecomp.org"; # zone file path
+};
diff --git a/boot/named.conf.options b/boot/named.conf.options
new file mode 100644 (file)
index 0000000..2b23f7e
--- /dev/null
@@ -0,0 +1,39 @@
+acl "trusted" {
+        #x.x.x.x;
+};
+options {
+        directory "/var/cache/bind";
+
+        #recursion no;                 # enables recursive queries
+        #allow-recursion { trusted; };  # allows recursive queries from "trusted” clients i.e. LB only
+        listen-on { 10.0.0.1; };   # ns1 IP address - listen on this address only
+        allow-transfer { none; };      # disable zone transfers by default
+
+        forwarders {
+                8.8.8.8;
+                8.8.4.4;
+        };
+
+        // If there is a firewall between you and nameservers you want
+        // to talk to, you may need to fix the firewall to allow multiple
+        // ports to talk.  See http://www.kb.cert.org/vuls/id/800113
+
+        // If your ISP provided one or more IP addresses for stable
+        // nameservers, you probably want to use them as forwarders.
+        // Uncomment the following block, and insert the addresses replacing
+        // the all-0's placeholder.
+
+        // forwarders {
+        //      0.0.0.0;
+        // };
+
+        //========================================================================
+        // If BIND logs error messages about the root key being expired,
+        // you will need to update your keys.  See https://www.isc.org/bind-keys
+        //========================================================================
+        dnssec-validation auto;
+
+        auth-nxdomain no;    # conform to RFC1035
+        listen-on-v6 { any; };
+};
+
diff --git a/boot/policy_serv.sh b/boot/policy_serv.sh
new file mode 100644 (file)
index 0000000..2e7195b
--- /dev/null
@@ -0,0 +1,98 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides:
+# Required-Start:    $remote_fs $syslog
+# Required-Stop:     $remote_fs $syslog
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Start daemon at boot time
+# Description:       Enable service provided by daemon.
+### END INIT INFO
+
+dir="/opt"
+cmd="./policy_vm_init.sh"
+user="root"
+
+name=`basename $0`
+pid_file="/var/run/$name.pid"
+stdout_log="/var/log/$name.log"
+stderr_log="/var/log/$name.err"
+
+get_pid() {
+    cat "$pid_file"
+}
+
+is_running() {
+    [ -f "$pid_file" ] && ps `get_pid` > /dev/null 2>&1
+}
+
+case "$1" in
+    start)
+    if is_running; then
+        echo "Already started"
+    else
+        echo "Starting $name"
+        cd "$dir"
+        if [ -z "$user" ]; then
+            sudo $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        else
+            sudo -u "$user" $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        fi
+        echo $! > "$pid_file"
+        if ! is_running; then
+            echo "Unable to start, see $stdout_log and $stderr_log"
+            exit 1
+        fi
+    fi
+    ;;
+    stop)
+    if is_running; then
+        echo -n "Stopping $name.."
+        kill `get_pid`
+        for i in {1..10}
+        do
+            if ! is_running; then
+                break
+            fi
+
+            echo -n "."
+            sleep 1
+        done
+        echo
+
+        if is_running; then
+            echo "Not stopped; may still be shutting down or shutdown may have failed"
+            exit 1
+        else
+            echo "Stopped"
+            if [ -f "$pid_file" ]; then
+                rm "$pid_file"
+            fi
+        fi
+    else
+        echo "Not running"
+    fi
+    ;;
+    restart)
+    $0 stop
+    if is_running; then
+        echo "Unable to stop, will not attempt to start"
+        exit 1
+    fi
+    $0 start
+    ;;
+    status)
+    if is_running; then
+        echo "Running"
+    else
+        echo "Stopped"
+        exit 1
+    fi
+    ;;
+    *)
+    echo "Usage: $0 {start|stop|restart|status}"
+    exit 1
+    ;;
+esac
+
+exit 0
diff --git a/boot/policy_vm_init.sh b/boot/policy_vm_init.sh
new file mode 100644 (file)
index 0000000..ad71cf0
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+NEXUS_USERNAME=$(cat /opt/config/nexus_username.txt)
+NEXUS_PASSWD=$(cat /opt/config/nexus_password.txt)
+NEXUS_DOCKER_REPO=$(cat /opt/config/nexus_docker_repo.txt)
+
+cd /opt/policy
+docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO
+/opt/docker/docker-compose up -d
diff --git a/boot/portal_serv.sh b/boot/portal_serv.sh
new file mode 100644 (file)
index 0000000..cf0c412
--- /dev/null
@@ -0,0 +1,98 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides:
+# Required-Start:    $remote_fs $syslog
+# Required-Stop:     $remote_fs $syslog
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Start daemon at boot time
+# Description:       Enable service provided by daemon.
+### END INIT INFO
+
+dir="/opt"
+cmd="./portal_vm_init.sh"
+user="root"
+
+name=`basename $0`
+pid_file="/var/run/$name.pid"
+stdout_log="/var/log/$name.log"
+stderr_log="/var/log/$name.err"
+
+get_pid() {
+    cat "$pid_file"
+}
+
+is_running() {
+    [ -f "$pid_file" ] && ps `get_pid` > /dev/null 2>&1
+}
+
+case "$1" in
+    start)
+    if is_running; then
+        echo "Already started"
+    else
+        echo "Starting $name"
+        cd "$dir"
+        if [ -z "$user" ]; then
+            sudo $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        else
+            sudo -u "$user" $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        fi
+        echo $! > "$pid_file"
+        if ! is_running; then
+            echo "Unable to start, see $stdout_log and $stderr_log"
+            exit 1
+        fi
+    fi
+    ;;
+    stop)
+    if is_running; then
+        echo -n "Stopping $name.."
+        kill `get_pid`
+        for i in {1..10}
+        do
+            if ! is_running; then
+                break
+            fi
+
+            echo -n "."
+            sleep 1
+        done
+        echo
+
+        if is_running; then
+            echo "Not stopped; may still be shutting down or shutdown may have failed"
+            exit 1
+        else
+            echo "Stopped"
+            if [ -f "$pid_file" ]; then
+                rm "$pid_file"
+            fi
+        fi
+    else
+        echo "Not running"
+    fi
+    ;;
+    restart)
+    $0 stop
+    if is_running; then
+        echo "Unable to stop, will not attempt to start"
+        exit 1
+    fi
+    $0 start
+    ;;
+    status)
+    if is_running; then
+        echo "Running"
+    else
+        echo "Stopped"
+        exit 1
+    fi
+    ;;
+    *)
+    echo "Usage: $0 {start|stop|restart|status}"
+    exit 1
+    ;;
+esac
+
+exit 0
diff --git a/boot/portal_vm_init.sh b/boot/portal_vm_init.sh
new file mode 100644 (file)
index 0000000..744c4fc
--- /dev/null
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+NEXUS_USERNAME=$(cat /opt/config/nexus_username.txt)
+NEXUS_PASSWD=$(cat /opt/config/nexus_password.txt)
+NEXUS_DOCKER_REPO=$(cat /opt/config/nexus_docker_repo.txt)
+
+docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO
+docker pull $NEXUS_DOCKER_REPO/ecomp/portaldb:1610.3
+docker pull $NEXUS_DOCKER_REPO/ecomp/portalapps:1610.3
+
+docker create --name data_vol_portal -v /var/lib/mysql mariadb
+
+docker tag 6ce6ea8c6e52 ecompdb:portal
+docker tag 925a8a953d4c ep:1610-1
+
+docker rm -f ecompdb_portal
+docker rm -f 1610-1
+
+./dbstart.sh
+./new_start.sh
+
+sleep 60
+
+if [ ! -e /opt/config/boot.txt ]
+then
+  IP_ADDRESS=$(ifconfig eth0 | grep "inet addr" | tr -s ' ' | cut -d' ' -f3 | cut -d':' -f2)
+  mysql -u root -p'Aa123456' -h $IP_ADDRESS < users.sql
+  echo "yes" > /opt/config/boot.txt
+fi
\ No newline at end of file
diff --git a/boot/robot_serv.sh b/boot/robot_serv.sh
new file mode 100644 (file)
index 0000000..7c4419d
--- /dev/null
@@ -0,0 +1,98 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides:
+# Required-Start:    $remote_fs $syslog
+# Required-Stop:     $remote_fs $syslog
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Start daemon at boot time
+# Description:       Enable service provided by daemon.
+### END INIT INFO
+
+dir="/opt"
+cmd="./robot_vm_init.sh"
+user="root"
+
+name=`basename $0`
+pid_file="/var/run/$name.pid"
+stdout_log="/var/log/$name.log"
+stderr_log="/var/log/$name.err"
+
+get_pid() {
+    cat "$pid_file"
+}
+
+is_running() {
+    [ -f "$pid_file" ] && ps `get_pid` > /dev/null 2>&1
+}
+
+case "$1" in
+    start)
+    if is_running; then
+        echo "Already started"
+    else
+        echo "Starting $name"
+        cd "$dir"
+        if [ -z "$user" ]; then
+            sudo $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        else
+            sudo -u "$user" $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        fi
+        echo $! > "$pid_file"
+        if ! is_running; then
+            echo "Unable to start, see $stdout_log and $stderr_log"
+            exit 1
+        fi
+    fi
+    ;;
+    stop)
+    if is_running; then
+        echo -n "Stopping $name.."
+        kill `get_pid`
+        for i in {1..10}
+        do
+            if ! is_running; then
+                break
+            fi
+
+            echo -n "."
+            sleep 1
+        done
+        echo
+
+        if is_running; then
+            echo "Not stopped; may still be shutting down or shutdown may have failed"
+            exit 1
+        else
+            echo "Stopped"
+            if [ -f "$pid_file" ]; then
+                rm "$pid_file"
+            fi
+        fi
+    else
+        echo "Not running"
+    fi
+    ;;
+    restart)
+    $0 stop
+    if is_running; then
+        echo "Unable to stop, will not attempt to start"
+        exit 1
+    fi
+    $0 start
+    ;;
+    status)
+    if is_running; then
+        echo "Running"
+    else
+        echo "Stopped"
+        exit 1
+    fi
+    ;;
+    *)
+    echo "Usage: $0 {start|stop|restart|status}"
+    exit 1
+    ;;
+esac
+
+exit 0
diff --git a/boot/robot_vm_init.sh b/boot/robot_vm_init.sh
new file mode 100644 (file)
index 0000000..582a3f2
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+NEXUS_USERNAME=$(cat /opt/config/nexus_username.txt)
+NEXUS_PASSWD=$(cat /opt/config/nexus_password.txt)
+NEXUS_DOCKER_REPO=$(cat /opt/config/nexus_docker_repo.txt)
+NEXUS_REPO=$(cat /opt/config/nexus_repo.txt)
+
+#
+# Deploy latest robot configuration 
+# 
+wget --user=$NEXUS_USERNAME --password=$NEXUS_PASSWD --no-check-certificate -O /opt/eteshare/config/robot_properties_ete.py  $NEXUS_REPO/org.openecomp.boot/robot_properties_ete.py
+wget --user=$NEXUS_USERNAME --password=$NEXUS_PASSWD --no-check-certificate -O /opt/eteshare/config/robot_preload_parameters.py  $NEXUS_REPO/org.openecomp.boot/robot_preload_parameters.py
+wget --user=$NEXUS_USERNAME --password=$NEXUS_PASSWD --no-check-certificate -O /opt/eteshare/config/vm_config2robot.sh  $NEXUS_REPO/org.openecomp.boot/vm_config2robot.sh
+/bin/bash /opt/eteshare/config/vm_config2robot.sh
+
+docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO
+docker pull $NEXUS_DOCKER_REPO/openecompete
+docker rm -f openecompete_container
+docker run -d --name openecompete_container -v /opt/eteshare:/share -p 88:88 $NEXUS_DOCKER_REPO/openecompete
diff --git a/boot/sdnc_serv.sh b/boot/sdnc_serv.sh
new file mode 100644 (file)
index 0000000..58f03f1
--- /dev/null
@@ -0,0 +1,98 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides:
+# Required-Start:    $remote_fs $syslog
+# Required-Stop:     $remote_fs $syslog
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Start daemon at boot time
+# Description:       Enable service provided by daemon.
+### END INIT INFO
+
+dir="/opt"
+cmd="./sdnc_vm_init.sh"
+user="root"
+
+name=`basename $0`
+pid_file="/var/run/$name.pid"
+stdout_log="/var/log/$name.log"
+stderr_log="/var/log/$name.err"
+
+get_pid() {
+    cat "$pid_file"
+}
+
+is_running() {
+    [ -f "$pid_file" ] && ps `get_pid` > /dev/null 2>&1
+}
+
+case "$1" in
+    start)
+    if is_running; then
+        echo "Already started"
+    else
+        echo "Starting $name"
+        cd "$dir"
+        if [ -z "$user" ]; then
+            sudo $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        else
+            sudo -u "$user" $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        fi
+        echo $! > "$pid_file"
+        if ! is_running; then
+            echo "Unable to start, see $stdout_log and $stderr_log"
+            exit 1
+        fi
+    fi
+    ;;
+    stop)
+    if is_running; then
+        echo -n "Stopping $name.."
+        kill `get_pid`
+        for i in {1..10}
+        do
+            if ! is_running; then
+                break
+            fi
+
+            echo -n "."
+            sleep 1
+        done
+        echo
+
+        if is_running; then
+            echo "Not stopped; may still be shutting down or shutdown may have failed"
+            exit 1
+        else
+            echo "Stopped"
+            if [ -f "$pid_file" ]; then
+                rm "$pid_file"
+            fi
+        fi
+    else
+        echo "Not running"
+    fi
+    ;;
+    restart)
+    $0 stop
+    if is_running; then
+        echo "Unable to stop, will not attempt to start"
+        exit 1
+    fi
+    $0 start
+    ;;
+    status)
+    if is_running; then
+        echo "Running"
+    else
+        echo "Stopped"
+        exit 1
+    fi
+    ;;
+    *)
+    echo "Usage: $0 {start|stop|restart|status}"
+    exit 1
+    ;;
+esac
+
+exit 0
diff --git a/boot/sdnc_vm_init.sh b/boot/sdnc_vm_init.sh
new file mode 100644 (file)
index 0000000..a642a53
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+NEXUS_USERNAME=$(cat /opt/config/nexus_username.txt)
+NEXUS_PASSWD=$(cat /opt/config/nexus_password.txt)
+NEXUS_DOCKER_REPO=$(cat /opt/config/nexus_docker_repo.txt)
+
+cd /opt/sdnc
+docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO
+/opt/docker/docker-compose up -d
diff --git a/boot/vid_serv.sh b/boot/vid_serv.sh
new file mode 100644 (file)
index 0000000..445196c
--- /dev/null
@@ -0,0 +1,98 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides:
+# Required-Start:    $remote_fs $syslog
+# Required-Stop:     $remote_fs $syslog
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Start daemon at boot time
+# Description:       Enable service provided by daemon.
+### END INIT INFO
+
+dir="/opt"
+cmd="./vid_vm_init.sh"
+user="root"
+
+name=`basename $0`
+pid_file="/var/run/$name.pid"
+stdout_log="/var/log/$name.log"
+stderr_log="/var/log/$name.err"
+
+get_pid() {
+    cat "$pid_file"
+}
+
+is_running() {
+    [ -f "$pid_file" ] && ps `get_pid` > /dev/null 2>&1
+}
+
+case "$1" in
+    start)
+    if is_running; then
+        echo "Already started"
+    else
+        echo "Starting $name"
+        cd "$dir"
+        if [ -z "$user" ]; then
+            sudo $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        else
+            sudo -u "$user" $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        fi
+        echo $! > "$pid_file"
+        if ! is_running; then
+            echo "Unable to start, see $stdout_log and $stderr_log"
+            exit 1
+        fi
+    fi
+    ;;
+    stop)
+    if is_running; then
+        echo -n "Stopping $name.."
+        kill `get_pid`
+        for i in {1..10}
+        do
+            if ! is_running; then
+                break
+            fi
+
+            echo -n "."
+            sleep 1
+        done
+        echo
+
+        if is_running; then
+            echo "Not stopped; may still be shutting down or shutdown may have failed"
+            exit 1
+        else
+            echo "Stopped"
+            if [ -f "$pid_file" ]; then
+                rm "$pid_file"
+            fi
+        fi
+    else
+        echo "Not running"
+    fi
+    ;;
+    restart)
+    $0 stop
+    if is_running; then
+        echo "Unable to stop, will not attempt to start"
+        exit 1
+    fi
+    $0 start
+    ;;
+    status)
+    if is_running; then
+        echo "Running"
+    else
+        echo "Stopped"
+        exit 1
+    fi
+    ;;
+    *)
+    echo "Usage: $0 {start|stop|restart|status}"
+    exit 1
+    ;;
+esac
+
+exit 0
diff --git a/boot/vid_vm_init.sh b/boot/vid_vm_init.sh
new file mode 100644 (file)
index 0000000..fa01976
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+NEXUS_USERNAME=$(cat /opt/config/nexus_username.txt)
+NEXUS_PASSWD=$(cat /opt/config/nexus_password.txt)
+NEXUS_DOCKER_REPO=$(cat /opt/config/nexus_docker_repo.txt)
+
+docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO
+docker pull $NEXUS_DOCKER_REPO/ecomp/vid:1.0.0
+
+docker rm -f vid-mariadb
+docker rm -f vid-server
+
+docker run --name vid-mariadb -e MYSQL_DATABASE=vid_openecomp -e MYSQL_USER=vidadmin -e MYSQL_PASSWORD=Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U -e MYSQL_ROOT_PASSWORD=LF+tp_1WqgSY -v /opt/vid-my.cnf:/etc/mysql/my.cnf -v /opt/vid-pre-init.sql:/docker-entrypoint-initdb.d/vid-pre-init.sql -v /var/lib/mysql -d mariadb:10
+
+docker run -e VID_MYSQL_DBNAME=vid_openecomp -e VID_MYSQL_PASS=Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U --name vid-server -p 8080:8080 --link vid-mariadb:vid-mariadb-docker-instance -d $NEXUS_DOCKER_REPO/ecomp/vid:1.0.0
diff --git a/deploy_scripts/.DS_Store b/deploy_scripts/.DS_Store
new file mode 100644 (file)
index 0000000..5008ddf
Binary files /dev/null and b/deploy_scripts/.DS_Store differ
diff --git a/deploy_scripts/deploy_boot.sh b/deploy_scripts/deploy_boot.sh
new file mode 100755 (executable)
index 0000000..fb25655
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+source repo_config.txt
+
+SOURCE_DIR=../boot
+GROUP_ID=org.openecomp.demo.boot
+VERSION=1.0.0
+
+cd $SOURCE_DIR
+ls | xargs -I{} curl -v -u $REPO_USERNAME:$REPO_PASSWORD --upload-file {} $REPO_URL/$GROUP_ID/$VERSION/{}
+
diff --git a/deploy_scripts/deploy_heat.sh b/deploy_scripts/deploy_heat.sh
new file mode 100755 (executable)
index 0000000..74a1620
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+source repo_config.txt
+
+SOURCE_DIR=../heat
+GROUP_ID=org.openecomp.demo.heat
+VERSION=1.0.0
+
+cd $SOURCE_DIR
+ls | xargs -I{} curl -v -u $REPO_USERNAME:$REPO_PASSWORD --upload-file {} $REPO_URL/$GROUP_ID/$VERSION/{}
+
diff --git a/deploy_scripts/deploy_vfw_scripts.sh b/deploy_scripts/deploy_vfw_scripts.sh
new file mode 100755 (executable)
index 0000000..49e7b01
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+source repo_config.txt
+
+SOURCE_DIR=../vnfs/vFW/scripts
+GROUP_ID=org.openecomp.demo.vnf.vfw
+VERSION=1.0.0
+
+cd $SOURCE_DIR
+ls | xargs -I{} curl -v -u $REPO_USERNAME:$REPO_PASSWORD --upload-file {} $REPO_URL/$GROUP_ID/$VERSION/{}
+
diff --git a/deploy_scripts/deploy_vlb_scripts.sh b/deploy_scripts/deploy_vlb_scripts.sh
new file mode 100755 (executable)
index 0000000..88c431f
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+source repo_config.txt
+
+SOURCE_DIR=../vnfs/vLB/scripts
+GROUP_ID=org.openecomp.demo.vnf.vlb
+VERSION=1.0.0
+
+cd $SOURCE_DIR
+ls | xargs -I{} curl -v -u $REPO_USERNAME:$REPO_PASSWORD --upload-file {} $REPO_URL/$GROUP_ID/$VERSION/{}
+
diff --git a/deploy_scripts/repo_config.txt b/deploy_scripts/repo_config.txt
new file mode 100644 (file)
index 0000000..8430dd4
--- /dev/null
@@ -0,0 +1,4 @@
+REPO_URL=https://ecomp-nexus:8443/repository/raw
+REPO_USERNAME=
+REPO_PASSWORD=
+
diff --git a/heat/.DS_Store b/heat/.DS_Store
new file mode 100644 (file)
index 0000000..1afff45
Binary files /dev/null and b/heat/.DS_Store differ
diff --git a/heat/.gitkeep b/heat/.gitkeep
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/heat/LICENSE.TXT b/heat/LICENSE.TXT
new file mode 100644 (file)
index 0000000..ae12da2
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * ============LICENSE_START==========================================
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ===================================================================
+ * 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.
+ * ============LICENSE_END============================================
+ *
+ * ECOMP and OpenECOMP are trademarks 
+ * and service marks of AT&T Intellectual Property.
+ *
+ */
diff --git a/heat/OpenECOMP/.DS_Store b/heat/OpenECOMP/.DS_Store
new file mode 100644 (file)
index 0000000..5008ddf
Binary files /dev/null and b/heat/OpenECOMP/.DS_Store differ
diff --git a/heat/README.md b/heat/README.md
new file mode 100644 (file)
index 0000000..3715a94
--- /dev/null
@@ -0,0 +1,120 @@
+Content
+---
+
+This repository contains all the HEAT templates for the instantiation of the OpenECOMP platform, and the vFirewall and vLoadBalancer/vDNS demo applications.
+
+The repository includes:
+ - README.md: this file
+ - LICENSE.TXT: the license text
+ - OpenECOMP: contains the HEAT template for the installation of the OpenECOMP platform (openecomp.yaml) and the environment file (openecomp.env)
+ - vFW: contains the HEAT template for the instantiation of the vFirewall VNF (base_vfw.yaml) and the environment file (base_vfw.env)
+ - vLB: contains the HEAT template for the instantiation of the vLoadBalancer/vDNS VNF (base_vlb.yaml) and the environment file (base_vlb.env). The folder also contains the HEAT template for the DNS scaling-up scenario (dnsscaling.yaml) with its environment file (dnsscaling.env), and the HEAT template for the vLB packet generator (packet_gen_vlb.yaml) and its environment file (packet_gen_vlb.env).
+
+
+OpenECOMP HEAT Template
+---
+
+The OpenECOMP HEAT template spins up the entire OpenECOMP platform. The template, openecomp.yaml, comes with an environment file, openecomp.env, in which all the default values are defined.
+
+The HEAT template is composed of two sections: (i) parameters, and (ii) resources. The parameter section contains the declaration and description of the parameters that will be used to spin up OpenECOMP, such as public network identifier, URLs of code and artifacts repositories, etc.
+The default values of these parameters can be found in the environment file. The resource section contains the definition of:
+ - OpenECOMP Private Management Network, which OpenECOMP components use to communicate with each other and with VNFs
+ - OpenECOMP Virtual Machines (VMs)
+ - Public/private key pair used to access OpenECOMP VMs
+ - Virtual interfaces towards the OpenECOMP Private Management Network
+ - Disk volumes. 
+
+Each VM specification includes Operating System image name, VM size (i.e. flavor), VM name, etc. Each VM has two virtual network interfaces: one towards the public network and one towards the OpenECOMP Private Management network, as described above. 
+Furthermore, each VM runs a post-instantiation script that downloads and installs software dependencies (e.g. Java JDK, gcc, make, Python, ...) and OpenECOMP software packages and docker containers from remote repositories.
+
+When the HEAT template is executed, the Openstack HEAT engine creates the resources defined in the HEAT template, based on the parameters values defined in the environment file.
+
+Before running HEAT, it is necessary to customize the environment file. Indeed, some parameters, namely public_net_id, pub_key, openstack_tenant_id, openstack_username, and openstack_api_key, need to be set depending on the user's environment:
+
+        public_net_id:       INSERT YOUR NETWORK ID/NAME HERE
+        pub_key:             INSERT YOUR PUBLIC KEY HERE
+        openstack_tenant_id: INSERT YOUR TENANT ID HERE
+        openstack_username:  INSERT YOUR USERNAME HERE
+        openstack_api_key:   INSERT YOUR API KEY HERE
+
+public_net_id is the unique identifier (UUID) or name of the public network of the cloud provider. Note that for Rackspace template, this value is already set to
+   
+        00000000-0000-0000-0000-000000000000
+
+
+pub_key is string value of the public key that will be installed in each OpenECOMP VM. To create a public/private key pair in Linux, execute the following instruction:
+   
+        user@ubuntu:~$ ssh-keygen -t rsa
+
+The following operations to create the public/private key pair occur:
+   
+        Generating public/private rsa key pair.
+        Enter file in which to save the key (/home/user/.ssh/id_rsa): 
+        Created directory '/home/user/.ssh'.
+        Enter passphrase (empty for no passphrase): 
+        Enter same passphrase again: 
+        Your identification has been saved in /home/user/.ssh/id_rsa.
+        Your public key has been saved in /home/user/.ssh/id_rsa.pub.
+
+openstack_username, openstack_tenant_id (password), and openstack_api_key are user's credentials to access the Openstack-based cloud. Note that in the Rackspace web interface, openstack_api_key can be found by clicking on the username and then "Account Settings".
+
+
+The OpenECOMP platform can be instantiated via Rackspace GUI or command line.
+
+Instantiation via Rackspace GUI:
+ - Login to Rackspace with your personal credentials
+ - Click "Stack Templates" from the "Orchestration" menu
+ - Click "Create Custom Template"
+ - Paste or manually upload the HEAT template (openecomp.yaml)
+ - Specify a name for your template in the "Template Name" form
+ - Click "Create Template and Launch Stack" at the bottom of the page
+ - In the "Create Stack" page, specify a name for your stack in the "Stack Name" form and select the Rackspace Region
+ - In the "Advanced Option" menu, insert the values of the parameters specified in the environment file (openecomp.env)
+ - Click "Create Stack"
+
+
+Instantiation via Command Line:
+ - Install the HEAT client on your machine, e.g. in Ubuntu (ref. http://docs.openstack.org/user-guide/common/cli-install-openstack-command-line-clients.html):
+
+        apt-get install python-dev python-pip
+        pip install python-heatclient        # Install heat client
+        pip install python-openstackclient   # Install the Openstack client to support multiple services
+ - Create a file (named i.e. ~/rackspace/openrc) that sets all the environmental variables required to access Rackspace:
+
+        export OS_AUTH_URL=https://identity.api.rackspacecloud.com/v2.0/
+        export OS_USERNAME=INSERT YOUR USERNAME HERE
+        export OS_TENANT_ID=INSERT YOUR TENANT ID HERE
+        export OS_REGION_NAME=INSERT THE RACKSPACE REGION ID [IAD | DFW | SYD | HKG]
+        export OS_PASSWORD=INSERT YOUR PASSWORD HERE
+        
+ - Run the script from command line:
+
+        source ~/rackspace/openrc
+        
+ - In order to install the OpenECOMP platform, type:
+
+        heat stack-create STACK_NAME -f PATH_TO_HEAT_TEMPLATE(YAML FILE) -e PATH_TO_ENV_FILE       # Old HEAT client, OR
+        openstack stack create -t PATH_TO_HEAT_TEMPLATE(YAML FILE) -e PATH_TO_ENV_FILE STACK_NAME  # New Openstack client
+
+
+VNFs HEAT Templates
+---
+
+The HEAT templates for the demo apps are stored in vFW and vLB directories. 
+
+vFW contains the HEAT template, base_vfw.yaml, and the environment file, base_vfw.env, that are used to instantiate a virtual firewall. The VNF is composed of three VMs:
+  - Packet generator
+  - Firewall
+  - Sink
+
+The packet generator generates traffic that passes through the firewall and reaches the sink. The firewall periodically reports the number of packets received in a unit of time to the DCAE collector. If the reported number of packets received on the firewall is above a high-water mark or below a low-water mark, OpenECOMP will enforce a configuration change on the packet generator, reducing or augmenting the quantity of traffic generated, respectively.
+
+vLB contains the HEAT template, base_vlb.yaml, and the environment file, base_vlb.env, that are used to spin up a virtual load balancer and a virtual DNS. vLB also contains the HEAT template, packet_gen_vlb.yaml, and the environment file packet_gen_vlb.env, of a packet generator that generates DNS queries.
+The load balancer periodically reports the number of DNS query packets received in a time unit to the DCAE collector. If the reported number of received packets crosses a threshold, then OpenECOMP will spin up a new DNS based on the dnsscaling.yaml HEAT template and dnsscaling.env to better balance the load of incoming DNS queries.
+
+The vFW and vLB HEAT templates and environment files are onboarded into OpenECOMP SDC and run automatically. The user is not required to run these templates manually.
+However, before onboarding the templates following the instructions in the OpenECOMP documentation, the user should set the following values in the environment files:
+
+        public_net_id:       INSERT YOUR NETWORK ID/NAME HERE
+        pub_key:             INSERT YOUR PUBLIC KEY HERE
\ No newline at end of file
diff --git a/heat/vFW/.DS_Store b/heat/vFW/.DS_Store
new file mode 100644 (file)
index 0000000..5008ddf
Binary files /dev/null and b/heat/vFW/.DS_Store differ
diff --git a/heat/vLB/.DS_Store b/heat/vLB/.DS_Store
new file mode 100644 (file)
index 0000000..5008ddf
Binary files /dev/null and b/heat/vLB/.DS_Store differ
diff --git a/vnfs/.DS_Store b/vnfs/.DS_Store
new file mode 100644 (file)
index 0000000..b1f0b35
Binary files /dev/null and b/vnfs/.DS_Store differ
diff --git a/vnfs/.gitkeep b/vnfs/.gitkeep
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/vnfs/LICENSE.TXT b/vnfs/LICENSE.TXT
new file mode 100644 (file)
index 0000000..ae12da2
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * ============LICENSE_START==========================================
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ===================================================================
+ * 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.
+ * ============LICENSE_END============================================
+ *
+ * ECOMP and OpenECOMP are trademarks 
+ * and service marks of AT&T Intellectual Property.
+ *
+ */
diff --git a/vnfs/README.md b/vnfs/README.md
new file mode 100644 (file)
index 0000000..6cbdf52
--- /dev/null
@@ -0,0 +1,118 @@
+OpenECOMP DEMO
+===
+
+This repository contains the source code and scripts to run the vFirewall and vLoadBalancer/vDNS demo applications for OpenECOMP.
+
+The repository includes:
+
+  - README.md: this file.
+
+  - LICENSE.TXT: the license text.
+
+  - honeycomb_plugin: Honeycomb plugin that allows upstream systems to change VNF configuration via RESTCONF or NETCONF protocols.
+
+  - VES: source code of the ECOMP Vendor Event Listener (VES) Library. The VES library used here has been cloned from the GitHub repository at https://github.com/att/evel-library on February 1, 2017.
+
+  - VESreporting_vFW: VES client for vFirewall demo application.
+
+  - VESreporting_vLB: VES client for vLoadBalancer/vDNS demo application.
+
+  - vFW: scripts that download, install and run packages for the vFirewall demo application.
+
+  - vLB: scripts that download, install and run packages for the vLoadBalancer/vDNS demo application.
+
+
+Usage
+===
+
+The content of this repository is downloaded and run automatically when the VNFs are instantiated. The user is not supposed to manually download and install the software contained in this repository.
+
+Two demo applications, vFirewall and vLoadBalancer/vDNS are included. 
+
+vFirewall
+---
+
+The vFirewall app contains 3 VMs: a firewall, a packet generator, and a packet sink. 
+
+The packet generator sends packets to the packet sink through the firewall. The firewall reports the volume of traffic from the packet generator to the sink to OpenECOMP DCAE’s collector. To check the traffic volume to the sink, you can access the link http://sink_IP:667 through your browser. You can see the traffic volume in the charts. 
+
+The packet generator includes a script that periodically generates different volumes of traffic. 
+
+The closedloop policy has been configured to re-adjust the traffic volume when it is needed.
+
+__Closedloop for vFirewall demo:__
+
+Through the OpenECOMP Portal’s Policy Portal, we can find the configuration and operation policies that is currently enabled for the vFirewall application. 
++ The configuration policy sets the thresholds for generating an onset event from DCAE to the Policy engine. Currently the threshold is set to below 300 packets or above 700 packets per 10 seconds. 
++ Once the threshold is crossed, the Policy engine executes the operational policy to request APP-C to change the configuration of the packet gen. 
++ APP-C sends a request to the packet generator to adjust the traffic volume to 500 packets per 10 seconds. 
++ The traffic volume can be observed through the link http://sink_IP:667.
+
+__Adjust packet generator:__
+
+The packet generator contains 10 streams: fw_udp1, fw_udp2, fw_udp3,...fw_udp10. Each stream generates 100 packets per 10 seconds. 
+
+To enable a stream, include *{"id":"fw_udp1", "is-enabled":"true"}* in the *pg-stream* bracket. 
+
+To adjust the traffic volume sending from the packet generator, run the following command that enable 5 streams in a shell with localhost or the correct packet generator IP address in the http argument:
+
+```
+curl -X PUT -H "Authorization: Basic YWRtaW46YWRtaW4=" -H "Content-Type: application/json" -H "Cache-Control: no-cache" -d '{"pg-streams":{"pg-stream": [{"id":"fw_udp1", "is-enabled":"true"},{"id":"fw_udp2", "is-enabled":"true"},{"id":"fw_udp3", "is-enabled":"true"},{"id":"fw_udp4", "is-enabled":"true"},{"id":"fw_udp5", "is-enabled":"true"}]}}' "http://PacketGen_IP:8183/restconf/config/sample-plugin:sample-plugin/pg-streams"
+```
+
+A script in /opt/run_traffic_fw_demo.sh on the packet generator VM starts automatically and alternate the volume of traffic every 10 minutes. 
+
+vLoadBalancer/vDNS
+---
+
+The vLoadBalancer/vDNS app contains 2 VMs in the base model: a load balancer and a DNS instance. When there are too many DNS queries, the Closedloop is triggered and a new DNS instance will be spun up. 
+
+To test the app, in the command prompt:
+
+``` 
+# nslookup host1.dnsdemo.openecomp.org *vLoadBalancer_IP*
+
+Server:     *vLoadBalancer_IP*
+Address:    *vLoadBalancer_IP*
+
+Name:     host1.dnsdemo.openecomp.org
+Address:  10.0.100.101
+
+```
+
+That means the load balancer has been set up correctly and has forwarded the DNS queries to the DNS instance. 
+
+__Closedloop for vLoadBalancer/vDNS:__
+
+Through the OpenECOMP Portal’s Policy Portal, we can find the configuration and operation policies that is currently enabled for the vLoadBalancer/vDNS application. 
++ The configuration policy sets the thresholds for generating an onset event from DCAE to the Policy engine. Currently the threshold is set to above 200 packets per 10 seconds. 
++ Once the threshold is crossed, the Policy engine executes the operational policy to query A&AI and send a request to MSO for spinning up a new DNS instance. 
++ A new DNS instance will be spun up after the threshold is crossed. It can take a few minutes for this to happen. 
+
+
+__Generate DNS queries:__
+
+To generate DNS queries to the vLoadBalancer/vDNS instance, a separate packet generator is prepared for this purpose. 
+
+1. Spin up the heat template in the repository: https://link_to_repo/demo/heat/vLB/packet_gen_vlb.yaml. 
+
+2. Log in to the packet generator instance through ssh.
+
+3. Change the IP address in the config file /opt/config/vlb_ipaddr.txt to the public IP address of the LoadBalancer instance. 
+
+4. Execute the script /opt/vdnspacketgen_change_streams_ports.sh to restart sending the DNS queries to the new LoadBalancer address. 
+
+5. To change the volume of queries, execute the following command in a command prompt with the updated vLoadBalancer_IP address or localhost in the http argument:
+```  
+curl -X PUT -H "Authorization: Basic YWRtaW46YWRtaW4=" -H "Content-Type: application/json" -H "Cache-Control: no-cache" -d '{"pg-streams":{"pg-stream": [{"id":"dns1", "is-enabled":"true"}]}}' "http://vLoadBalancer_IP:8183/restconf/config/sample-plugin:sample-plugin/pg-streams"  
+```  
++ *{"id":"dns1", "is-enabled":"true"}* shows the stream *dns1* is enabled. The packet gen sends requests in the rate of 100 packets per 10 seconds.  
+
++ To increase the amount of traffic, we can enable more streams. The packet gen has total 10 streams, *dns1*, *dns2*, *dns3* to *dns10*. Each of them produces 100 packets per 10 seconds. To enable the streams, includes *{"id":"dnsX", "is-enabled":"true"}* where *X* is the stream ID in the pg-stream bracket of the curl command.  
+For example, if we want to enable 3 streams, the curl command should be:
+
+```
+curl -X PUT -H "Authorization: Basic YWRtaW46YWRtaW4=" -H "Content-Type: application/json" -H "Cache-Control: no-cache" -d '{"pg-streams":{"pg-stream": [{"id":"dns1", "is-enabled":"true"}, {"id":"dns2", "is-enabled":"true"},{"id":"dns3", "is-enabled":"true"}]}}' "http://vLoadBalancer_IP:8183/restconf/config/sample-plugin:sample-plugin/pg-streams"
+```
+
diff --git a/vnfs/VES/.DS_Store b/vnfs/VES/.DS_Store
new file mode 100644 (file)
index 0000000..4b31f72
Binary files /dev/null and b/vnfs/VES/.DS_Store differ
diff --git a/vnfs/VES/LICENSE.md b/vnfs/VES/LICENSE.md
new file mode 100644 (file)
index 0000000..f131384
--- /dev/null
@@ -0,0 +1,27 @@
+BSD License
+
+Copyright (c) 2016, AT&T Intellectual Property.  All other rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted
+provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions
+   and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice, this list of
+   conditions and the following disclaimer in the documentation and/or other materials provided
+   with the distribution.
+3. All advertising materials mentioning features or use of this software must display the
+   following acknowledgement:  This product includes software developed by the AT&T.
+4. Neither the name of AT&T nor the names of its contributors may be used to endorse or
+   promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;  LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
diff --git a/vnfs/VES/bldjobs/Doxyfile b/vnfs/VES/bldjobs/Doxyfile
new file mode 100644 (file)
index 0000000..f96ead2
--- /dev/null
@@ -0,0 +1,1475 @@
+# Doxyfile 1.6.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = "AT&T ECOMP Vendor Event Listener library"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         = 0.1
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = ../docs/source/evel
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 2
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it parses.
+# With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this tag.
+# The format is ext=language, where ext is a file extension, and language is one of
+# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
+# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
+# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = NO
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
+# doxygen. The layout file controls the global structure of the generated output files
+# in an output format independent way. The create the layout file that represents
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name
+# of the layout file.
+
+LAYOUT_FILE            =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  = ../code/evel_library \
+                         ../code/evel_demo
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS          = *.h *.c *.md
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                = 
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            =
+
+# If the HTML_TIMESTAMP tag is set to YES then the generated HTML
+# documentation will contain the timesstamp.
+
+HTML_TIMESTAMP         = NO
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        =
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
+# are set, an additional index file will be generated that can be used as input for
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
+# HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
+# For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION           =
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP)
+# there is already a search function so this one should typically
+# be disabled.
+
+SEARCHENGINE           = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = YES
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME           = 
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES
diff --git a/vnfs/VES/bldjobs/Makefile b/vnfs/VES/bldjobs/Makefile
new file mode 100644 (file)
index 0000000..21d7a82
--- /dev/null
@@ -0,0 +1,338 @@
+#******************************************************************************
+# The ECOMP Vendor Event Listener (EVEL) API client library Makefile.
+#
+# Make the various targets associated with housekeeping functions as part of
+# Event Reporting library.
+#
+# NOTE: because Makefiles assign special meaning to the TAB character you
+#       will need to set tabstops to 2 characters for the layout to look OK.
+#
+# License
+# -------
+#
+# Copyright(c) <2016>, AT&T Intellectual Property.  All other rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+#    this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+#    this list of conditions and the following disclaimer in the documentation
+#    and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+#    must display the following acknowledgement:  This product includes
+#    software developed by the AT&T.
+# 4. Neither the name of AT&T nor the names of its contributors may be used to
+#    endorse or promote products derived from this software without specific
+#    prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#******************************************************************************
+
+ARCH=$(shell getconf LONG_BIT)
+CODE_ROOT=$(CURDIR)/..
+EVELLIB_ROOT=$(CODE_ROOT)/code/evel_library
+EVELDEMO_ROOT=$(CODE_ROOT)/code/evel_demo
+EVELUNIT_ROOT=$(CODE_ROOT)/code/evel_unit
+EVELTRAINING_ROOT=$(CODE_ROOT)/code/evel_training
+LIBS_DIR=$(CODE_ROOT)/libs/x86_$(ARCH)
+OUTPUT_DIR=$(CODE_ROOT)/output/x86_$(ARCH)
+DOCS_ROOT=$(CODE_ROOT)/docs
+CC=gcc
+SCP=scp
+SSH=ssh
+JAVA=java
+DOXYGEN=doxygen
+PLANTUML=/usr/local/bin/plantuml.jar
+PLANTFLAGS=-tsvg
+
+#******************************************************************************
+# Standard compiler flags.                                                    *
+#******************************************************************************
+CPPFLAGS=-I $(EVELLIB_ROOT)
+CFLAGS=-Wall -Wextra -m$(ARCH) -g -fPIC
+LIBCFLAGS=-Wall -Wextra -m$(ARCH) -g -shared -fPIC
+
+#******************************************************************************
+# The testbed is a VM instance where we can install the EVEL example under    *
+# CentOS.                                                                     *
+#******************************************************************************
+VNF_TESTBED_CENTOS=172.18.152.180
+VNF_TESTBED_CENTOS_USER=centos
+TESTBED_CENTOS_DOWNLOAD_PATH=/home/centos/download/evel_lib
+TESTBED_CENTOS_INSTALL_PATH=/home/centos/evel
+
+#******************************************************************************
+# The testbed is a VM instance where we can install the EVEL example under    *
+# Ubuntu.                                                                     *
+#******************************************************************************
+VNF_TESTBED_UBUNTU=172.18.152.179
+VNF_TESTBED_UBUNTU_USER=ubuntu
+TESTBED_UBUNTU_DOWNLOAD_PATH=/home/ubuntu/Downloads/evel_lib
+TESTBED_UBUNTU_INSTALL_PATH=/home/ubuntu/evel
+
+#******************************************************************************
+# The test-collector is where we can send events to be consumed and checked   *
+# during tests.                                                               *
+#******************************************************************************
+VNF_COLLECTOR_HOST=172.18.152.185
+VNF_COLLECTOR_PORT=30000
+
+#******************************************************************************
+# A documentation server used by the team where we can install documentation. *
+#******************************************************************************
+TEAM_DOCS_SERVER=covlx8
+DOCS_SERVER_PATH=/var/www/html/evel
+
+#******************************************************************************
+# Implicit rule to make dependency files.  Recipe copied from Gnu docs at:    *
+# https://www.gnu.org/software/make/manual/html_node/Automatic-Prerequisites.html                                      *
+#******************************************************************************
+%.d: %.c
+       @echo Making dependency file $(notdir $@) for $(notdir $<)
+       @set -e; rm -f $@; \
+         $(CC) -MM -MT $(<:.c=.o) $(CPPFLAGS) $< > $@.$$$$; \
+         sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+         rm -f $@.$$$$
+
+#******************************************************************************
+# Implicit rule to make object files.                                         *
+#******************************************************************************
+%.o: %.c
+       @echo Making $(notdir $@) from $(notdir $<)
+       @$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
+
+#******************************************************************************
+# Implicit rule to make diagram files using PlantUML.                         *
+#******************************************************************************
+%.svg : %.plantuml
+       @echo Making $(notdir $@)
+       $(JAVA) -jar $(PLANTUML) $(PLANTFLAGS) $<
+
+all:     api_library \
+         evel_library_training
+
+clean:   api_library_clean \
+         evel_unit_clean \
+         evel_library_training_clean \
+         docs_clean
+
+install: evel_install_centos evel_install_ubuntu
+
+test: evel_test_centos evel_test_ubuntu
+
+docs:    docs_clean doxygen_docs
+
+
+#******************************************************************************
+# Build the EVEL libraries.                                                   *
+#******************************************************************************
+API_SOURCES=$(EVELLIB_ROOT)/evel.c \
+            $(EVELLIB_ROOT)/metadata.c \
+            $(EVELLIB_ROOT)/ring_buffer.c \
+            $(EVELLIB_ROOT)/double_list.c \
+            $(EVELLIB_ROOT)/evel_event.c \
+            $(EVELLIB_ROOT)/evel_fault.c \
+            $(EVELLIB_ROOT)/evel_mobile_flow.c \
+            $(EVELLIB_ROOT)/evel_option.c \
+            $(EVELLIB_ROOT)/evel_other.c \
+            $(EVELLIB_ROOT)/evel_json_buffer.c \
+            $(EVELLIB_ROOT)/evel_reporting_measurement.c \
+            $(EVELLIB_ROOT)/evel_scaling_measurement.c \
+            $(EVELLIB_ROOT)/evel_state_change.c \
+            $(EVELLIB_ROOT)/evel_strings.c \
+            $(EVELLIB_ROOT)/evel_syslog.c \
+            $(EVELLIB_ROOT)/evel_throttle.c \
+            $(EVELLIB_ROOT)/evel_internal_event.c \
+            $(EVELLIB_ROOT)/evel_event_mgr.c \
+            $(EVELLIB_ROOT)/evel_logging.c \
+            $(EVELLIB_ROOT)/jsmn.c \
+            $(EVELLIB_ROOT)/evel_service.c \
+            $(EVELLIB_ROOT)/evel_signaling.c
+
+API_OBJECTS=$(API_SOURCES:.c=.o)
+-include $(API_SOURCES:.c=.d)
+
+api_library: $(LIBS_DIR)/libevel.so \
+             $(LIBS_DIR)/libevel.a
+
+$(LIBS_DIR)/libevel.a: $(API_OBJECTS)
+       @echo   Linking API Static Library
+       @$(CC) $(LIBCFLAGS) -o $@ $+
+
+$(LIBS_DIR)/libevel.so: $(API_OBJECTS)
+       @echo   Linking API Shared Library
+       @$(CC) $(LIBCFLAGS) -L $(QLIBCLIBSDIR) -lqlibc -o $@ $+
+
+api_library_clean:
+       @echo   Cleaning API Library
+       @$(RM) $(LIBS_DIR)/libevel.so
+       @$(RM) $(API_OBJECTS)
+       @$(RM) $(EVELLIB_ROOT)/*.d
+
+#******************************************************************************
+# Build the EVEL library unit test.                                           *
+#******************************************************************************
+UNIT_SOURCES=$(EVELUNIT_ROOT)/evel_unit.c
+UNIT_OBJECTS=$(UNIT_SOURCES:.c=.o)
+-include $(UNIT_SOURCES:.c=.d)
+
+evel_unit: api_library \
+           $(OUTPUT_DIR)/evel_unit
+
+$(OUTPUT_DIR)/evel_unit: $(UNIT_OBJECTS)
+       @echo   Linking EVEL unit test
+       $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ \
+                          -L $(LIBS_DIR) \
+                          $(UNIT_OBJECTS) \
+                          -level \
+                          -lpthread \
+                          -lcurl
+
+evel_unit_clean:
+       @echo   Cleaning EVEL unit test
+       @$(RM) $(OUTPUT_DIR)/evel_unit
+       @$(RM) $(API_OBJECTS)
+       @$(RM) $(UNIT_OBJECTS)
+       @$(RM) $(EVELLIB_ROOT)/*.d
+       @$(RM) $(EVELUNIT_ROOT)/*.d
+
+#******************************************************************************
+# Build the EVEL library training files.                                      *
+#******************************************************************************
+evel_library_training:
+       @echo   Making EVEL training
+       @$(MAKE) -s -C $(EVELTRAINING_ROOT)/VESreporting
+
+evel_library_training_clean:
+       @echo   Cleaning EVEL training
+       @$(RM) $(EVELTRAINING_ROOT)/VESreporting/vpp_measurement_reporter
+
+#******************************************************************************
+# Copy the EVEL demo onto the CentOS testbed as a package and build it.       *
+#******************************************************************************
+evel_install_centos: delivery
+       @echo Installing EVEL library on CentOS testbed...
+       @$(SSH) $(VNF_TESTBED_CENTOS_USER)@$(VNF_TESTBED_CENTOS) \
+          rm -rf $(TESTBED_CENTOS_DOWNLOAD_PATH) \; \
+          mkdir -p $(TESTBED_CENTOS_DOWNLOAD_PATH) \; \
+          mkdir -p $(TESTBED_CENTOS_INSTALL_PATH)
+       @$(SCP) -r $(CODE_ROOT)/output/evel-library-package.tgz \
+           $(VNF_TESTBED_CENTOS_USER)@$(VNF_TESTBED_CENTOS):$(TESTBED_CENTOS_DOWNLOAD_PATH)
+       @$(SSH) $(VNF_TESTBED_CENTOS_USER)@$(VNF_TESTBED_CENTOS) \
+          tar zx --directory $(TESTBED_CENTOS_INSTALL_PATH) \
+                 --file $(TESTBED_CENTOS_DOWNLOAD_PATH)/evel-library-package.tgz
+       @echo Making EVEL library on testbed...
+       @$(SSH) $(VNF_TESTBED_CENTOS_USER)@$(VNF_TESTBED_CENTOS) \
+           cd $(TESTBED_CENTOS_INSTALL_PATH)/bldjobs \; \
+           make clean all
+
+#******************************************************************************
+# Copy the EVEL demo onto the Ubuntu testbed as a package and build it.       *
+#******************************************************************************
+evel_install_ubuntu: delivery
+       @echo Installing EVEL library on Ubuntu testbed...
+       @$(SSH) $(VNF_TESTBED_UBUNTU_USER)@$(VNF_TESTBED_UBUNTU) \
+          rm -rf $(TESTBED_UBUNTU_DOWNLOAD_PATH) \; \
+          mkdir -p $(TESTBED_UBUNTU_DOWNLOAD_PATH) \; \
+          mkdir -p $(TESTBED_UBUNTU_INSTALL_PATH)
+       @$(SCP) -r $(CODE_ROOT)/output/evel-library-package.tgz \
+           $(VNF_TESTBED_UBUNTU_USER)@$(VNF_TESTBED_UBUNTU):$(TESTBED_UBUNTU_DOWNLOAD_PATH)
+       @$(SSH) $(VNF_TESTBED_UBUNTU_USER)@$(VNF_TESTBED_UBUNTU) \
+          tar zx --directory $(TESTBED_UBUNTU_INSTALL_PATH) \
+                 --file $(TESTBED_UBUNTU_DOWNLOAD_PATH)/evel-library-package.tgz
+       @echo Making EVEL library on testbed...
+       @$(SSH) $(VNF_TESTBED_UBUNTU_USER)@$(VNF_TESTBED_UBUNTU) \
+           cd $(TESTBED_UBUNTU_INSTALL_PATH)/bldjobs \; \
+           make clean all
+
+#******************************************************************************
+# Make sure that the Centos platform is up to date and then run the software  *
+# against a test collector.  Validating correct operation is not presently    *
+# automated.                                                                  *
+#******************************************************************************
+evel_test_centos: evel_install_centos
+       @echo Testing EVEL Demo application on CentOS...
+       @$(SSH) $(VNF_TESTBED_CENTOS_USER)@$(VNF_TESTBED_CENTOS) \
+           source .bash_profile \; \
+           $(TESTBED_CENTOS_INSTALL_PATH)/output/x86_$(ARCH)/evel_demo \
+                                                 --fqdn $(VNF_COLLECTOR_HOST) \
+                                                 --port $(VNF_COLLECTOR_PORT) \
+                                                 --verbose
+
+#******************************************************************************
+# Make sure that the Ubuntu platform is up to date and then run the software  *
+# against a test collector.  Validating correct operation is not presently    *
+# automated.                                                                  *
+#******************************************************************************
+evel_test_ubuntu: evel_install_ubuntu
+       @echo Testing EVEL Demo application on Ubuntu...
+       @$(SSH) $(VNF_TESTBED_UBUNTU_USER)@$(VNF_TESTBED_UBUNTU) \
+           source .profile \; \
+           $(TESTBED_UBUNTU_INSTALL_PATH)/output/x86_$(ARCH)/evel_demo \
+                                                 --fqdn $(VNF_COLLECTOR_HOST) \
+                                                 --port $(VNF_COLLECTOR_PORT) \
+                                                 --verbose
+
+#******************************************************************************
+# Making a clean delivery has some very specific dependencies which are order *
+# dependent, so we recursively make a series of targets to do a clean  build  *
+# of all of the required deliverables and then finally zipping up.            *
+#******************************************************************************
+delivery:
+       @$(MAKE) -s delivery_baseline
+       @$(MAKE) -s package
+
+delivery_baseline:     docs
+
+#******************************************************************************
+# Package the software for delivery.                                          *
+#******************************************************************************
+package: api_library_clean \
+         evel_unit_clean \
+         evel_library_demo_clean \
+         evel_library_training_clean \
+         docs
+       @echo Packaging the software for delivery
+       @cd $(CODE_ROOT) && tar cfz output/evel-library-package.tgz  bldjobs \
+                                                      code \
+                                                      docs \
+                                                      libs/x86_64/README \
+                                                      output/x86_64/README \
+                                                      readme.md
+
+package_clean:
+       @echo Clean delivery packages
+       @$(RM) $(OUTPUTDIR)/*.tgz
+
+#******************************************************************************
+# Create project documentation.                                               *
+#******************************************************************************
+doxygen_docs:
+       @echo Making Doxygen documentation
+       @$(DOXYGEN) Doxyfile
+
+pdf_docs: doxygen_docs  # This target is slightly broken.  Run manually.
+       @echo   Making PDF...
+       @$(MAKE) -C $(DOCS_ROOT)/source/evel/latex
+
+docs_clean:
+       @echo Cleaning docs...
+       @$(RM) $(DOCS_ROOT)/*.svg
+       @$(RM) -r $(DOCS_ROOT)/source/evel/html \
+                 $(DOCS_ROOT)/source/evel/latex
+
+docs_install: docs
+       @echo Copying docs to team web-server...
+       @$(SCP) -r $(DOCS_ROOT)/source/evel/html/* \
+                 root@$(TEAM_DOCS_SERVER):$(DOCS_SERVER_PATH)
diff --git a/vnfs/VES/code/.DS_Store b/vnfs/VES/code/.DS_Store
new file mode 100644 (file)
index 0000000..a9cc98d
Binary files /dev/null and b/vnfs/VES/code/.DS_Store differ
diff --git a/vnfs/VES/code/evel_library/double_list.c b/vnfs/VES/code/evel_library/double_list.c
new file mode 100644 (file)
index 0000000..a480acc
--- /dev/null
@@ -0,0 +1,194 @@
+/**************************************************************************//**
+ * @file
+ * A simple double-linked list.
+ *
+ * @note  No thread protection so you will need to use appropriate
+ * synchronization if use spans multiple threads.
+ *
+ * License
+ * -------
+ *
+ * Copyright(c) <2016>, AT&T Intellectual Property.  All other rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:  This product includes
+ *    software developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <assert.h>
+#include <malloc.h>
+
+#include "double_list.h"
+#include "evel.h"
+
+/**************************************************************************//**
+ * List initialization.
+ *
+ * Initialize the list supplied to be empty.
+ *
+ * @param   list    Pointer to the list to be initialized.
+
+ * @returns Nothing
+******************************************************************************/
+void dlist_initialize(DLIST * list)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check assumptions.                                                      */
+  /***************************************************************************/
+  assert(list != NULL);
+
+  /***************************************************************************/
+  /* Initialize the list as empty.                                           */
+  /***************************************************************************/
+  list->head = NULL;
+  list->tail = NULL;
+
+  EVEL_EXIT();
+}
+
+void * dlist_pop_last(DLIST * list)
+{
+  void *item = NULL;
+  DLIST_ITEM *current_tail = NULL;
+  DLIST_ITEM *new_tail = NULL;
+
+  assert(list != NULL);
+
+  current_tail = list->tail;
+  if (current_tail != NULL)
+  {
+    item = current_tail->item;
+    new_tail = current_tail->previous;
+    if (new_tail == NULL)
+    {
+      list->head = NULL;
+      list->tail = NULL;
+    }
+    else
+    {
+      new_tail->next = NULL;
+      list->tail = new_tail;
+    }
+    free(current_tail);
+  }
+
+  return item;
+}
+
+void dlist_push_first(DLIST * list, void * item)
+{
+  DLIST_ITEM * new_element = NULL;
+  DLIST_ITEM * current_head = NULL;
+
+  /***************************************************************************/
+  /* Check assumptions.  Note that we do allow putting NULL pointers into    */
+  /* the list - not sure you'd want to, but let it happen.                   */
+  /***************************************************************************/
+  assert(list != NULL);
+
+  current_head = list->head;
+
+  new_element = malloc(sizeof(DLIST_ITEM));
+  assert(new_element != NULL);
+  new_element->next = current_head;
+  new_element->previous = NULL;
+  new_element->item = item;
+  list->head = new_element;
+
+  if (current_head != NULL)
+  {
+    current_head->previous = new_element;
+  }
+  else
+  {
+    list->tail = new_element;
+  }
+}
+
+void dlist_push_last(DLIST * list, void * item)
+{
+  DLIST_ITEM * new_element = NULL;
+  DLIST_ITEM * current_tail = NULL;
+
+  /***************************************************************************/
+  /* Check assumptions.  Note that we do allow putting NULL pointers into    */
+  /* the list - not sure you'd want to, but let it happen.                   */
+  /***************************************************************************/
+  assert(list != NULL);
+
+  current_tail = list->tail;
+
+  new_element = malloc(sizeof(DLIST_ITEM));
+  assert(new_element != NULL);
+  new_element->next = NULL;
+  new_element->previous = current_tail;
+  new_element->item = item;
+  list->tail = new_element;
+
+  if (current_tail != NULL)
+  {
+    current_tail->next = new_element;
+  }
+  else
+  {
+    list->head = new_element;
+  }
+}
+
+DLIST_ITEM * dlist_get_first(DLIST * list)
+{
+  return list->head;
+}
+
+DLIST_ITEM * dlist_get_last(DLIST * list)
+{
+  return list->tail;
+}
+
+DLIST_ITEM * dlist_get_next(DLIST_ITEM * item)
+{
+  return item->next;
+}
+
+int dlist_is_empty(DLIST * list)
+{
+  return (list->head == NULL);
+}
+
+int dlist_count(DLIST * list)
+{
+  int count = 0;
+  DLIST_ITEM * item = list->head;
+
+  while (item != NULL)
+  {
+    count++;
+    item = item->next;
+  }
+
+  return count;
+}
diff --git a/vnfs/VES/code/evel_library/double_list.h b/vnfs/VES/code/evel_library/double_list.h
new file mode 100644 (file)
index 0000000..e8bdd74
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef DOUBLE_LIST_INCLUDED
+#define DOUBLE_LIST_INCLUDED
+
+/**************************************************************************//**
+ * @file
+ * A simple double-linked list.
+ *
+ * @note  No thread protection so you will need to use appropriate
+ * synchronization if use spans multiple threads.
+ *
+ * License
+ * -------
+ *
+ * Copyright(c) <2016>, AT&T Intellectual Property.  All other rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:  This product includes
+ *    software developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+typedef struct dlist_item
+{
+  struct dlist_item * previous;
+  struct dlist_item * next;
+  void * item;
+} DLIST_ITEM;
+
+/**************************************************************************//**
+ * Double-linked list structure
+ *****************************************************************************/
+typedef struct dlist
+{
+  DLIST_ITEM * head;
+  DLIST_ITEM * tail;
+} DLIST;
+
+
+void dlist_initialize(DLIST * list);
+void * dlist_pop_last(DLIST * list);
+void dlist_push_first(DLIST * list, void * item);
+void dlist_push_last(DLIST * list, void * item);
+DLIST_ITEM * dlist_get_first(DLIST * list);
+DLIST_ITEM * dlist_get_last(DLIST * list);
+DLIST_ITEM * dlist_get_next(DLIST_ITEM * item);
+int dlist_is_empty(DLIST * list);
+int dlist_count(DLIST * list);
+
+#endif
diff --git a/vnfs/VES/code/evel_library/evel.c b/vnfs/VES/code/evel_library/evel.c
new file mode 100644 (file)
index 0000000..3380cac
--- /dev/null
@@ -0,0 +1,395 @@
+/**************************************************************************//**
+ * @file
+ * Source module isolating the ECOMP Vendor Event Listener (EVEL) API.
+ *
+ * This file implements the EVEL library which is intended to provide a
+ * simple wrapper around the complexity of AT&T's Vendor Event Listener API so
+ * that VNFs can use it without worrying about details of:
+ *
+ *  *   The API's encoding into JSON.
+ *  *   The API's transport over HTTP/HTTPS.
+ *
+ * License
+ * -------
+ *
+ * Copyright(c) <2016>, AT&T Intellectual Property.  All other rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:  This product includes
+ *    software developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <curl/curl.h>
+
+#include "evel.h"
+#include "evel_internal.h"
+#include "evel_throttle.h"
+#include "metadata.h"
+
+/**************************************************************************//**
+ * The type of equipment represented by this VNF.
+ *****************************************************************************/
+EVEL_SOURCE_TYPES event_source_type = EVEL_SOURCE_OTHER;
+
+/**************************************************************************//**
+ * The Functional Role of the equipment represented by this VNF.
+ *****************************************************************************/
+char *functional_role = NULL;
+
+/**************************************************************************//**
+ * Library initialization.
+ *
+ * Initialize the EVEL library.
+ *
+ * @note  This function initializes the cURL library.  Applications making use
+ *        of libcurl may need to pull the initialization out of here.  Note
+ *        also that this function is not threadsafe as a result - refer to
+ *        libcurl's API documentation for relevant warnings.
+ *
+ * @sa  Matching Term function.
+ *
+ * @param   fqdn    The API's FQDN or IP address.
+ * @param   port    The API's port.
+ * @param   path    The optional path (may be NULL).
+ * @param   topic   The optional topic part of the URL (may be NULL).
+ * @param   secure  Whether to use HTTPS (0=HTTP, 1=HTTPS)
+ * @param   username  Username for Basic Authentication of requests.
+ * @param   password  Password for Basic Authentication of requests.
+ * @param   source_type The kind of node we represent.
+ * @param   role    The role this node undertakes.
+ * @param   verbosity  0 for normal operation, positive values for chattier
+ *                        logs.
+ *
+ * @returns Status code
+ * @retval  EVEL_SUCCESS      On success
+ * @retval  ::EVEL_ERR_CODES  On failure.
+ *****************************************************************************/
+EVEL_ERR_CODES evel_initialize(const char * const fqdn,
+                               int port,
+                               const char * const path,
+                               const char * const topic,
+                               int secure,
+                               const char * const username,
+                               const char * const password,
+                               EVEL_SOURCE_TYPES source_type,
+                               const char * const role,
+                               int verbosity
+                               )
+{
+  EVEL_ERR_CODES rc = EVEL_SUCCESS;
+  char base_api_url[EVEL_MAX_URL_LEN + 1] = {0};
+  char event_api_url[EVEL_MAX_URL_LEN + 1] = {0};
+  char throt_api_url[EVEL_MAX_URL_LEN + 1] = {0};
+  char path_url[EVEL_MAX_URL_LEN + 1] = {0};
+  char topic_url[EVEL_MAX_URL_LEN + 1] = {0};
+  char version_string[10] = {0};
+  int offset;
+
+  /***************************************************************************/
+  /* Check assumptions.                                                      */
+  /***************************************************************************/
+  assert(fqdn != NULL);
+  assert(port > 0 && port <= 65535);
+  assert(source_type < EVEL_MAX_SOURCE_TYPES);
+  assert(role != NULL);
+
+  /***************************************************************************/
+  /* Start logging so we can report on progress.                             */
+  /***************************************************************************/
+  log_initialize(verbosity == 0 ? EVEL_LOG_INFO : EVEL_LOG_DEBUG, "EVEL");
+  EVEL_INFO("EVEL started");
+  EVEL_INFO("API server is: %s", fqdn);
+  EVEL_INFO("API port is: %d", port);
+
+  if (path != NULL)
+  {
+    EVEL_INFO("API path is: %s", path);
+  }
+  else
+  {
+    EVEL_INFO("No API path");
+  }
+
+  if (topic != NULL)
+  {
+    EVEL_INFO("API topic is: %s", topic);
+  }
+  else
+  {
+    EVEL_INFO("No API topic");
+  }
+
+  EVEL_INFO("API transport is: %s", secure ? "HTTPS" : "HTTP");
+  EVEL_INFO("Event Source Type is: %d", source_type);
+  EVEL_INFO("Functional Role is: %s", role);
+  EVEL_INFO("Log verbosity is: %d", verbosity);
+
+  /***************************************************************************/
+  /* Initialize event throttling to the default state.                       */
+  /***************************************************************************/
+  evel_throttle_initialize();
+
+  /***************************************************************************/
+  /* Save values we will need during operation.                              */
+  /***************************************************************************/
+  event_source_type = source_type;
+  functional_role = strdup(role);
+
+  /***************************************************************************/
+  /* Ensure there are no trailing zeroes and unnecessary decimal points in   */
+  /* the version.                                                            */
+  /***************************************************************************/
+  offset = sprintf(version_string, "%d", EVEL_API_MAJOR_VERSION);
+
+  if (EVEL_API_MINOR_VERSION != 0)
+  {
+    sprintf(version_string + offset, ".%d", EVEL_API_MINOR_VERSION);
+  }
+
+  /***************************************************************************/
+  /* Build a common base of the API URLs.                                    */
+  /***************************************************************************/
+  strcpy(path_url, "/");
+  snprintf(base_api_url,
+           EVEL_MAX_URL_LEN,
+           "%s://%s:%d%s/eventListener/v%s",
+           secure ? "https" : "http",
+           fqdn,
+           port,
+           (((path != NULL) && (strlen(path) > 0)) ?
+            strncat(path_url, path, EVEL_MAX_URL_LEN) : ""),
+           version_string);
+
+  /***************************************************************************/
+  /* Build the URL to the event API.                                         */
+  /***************************************************************************/
+  strcpy(topic_url, "/");
+  snprintf(event_api_url,
+           EVEL_MAX_URL_LEN,
+           "%s%s",
+           base_api_url,
+           (((topic != NULL) && (strlen(topic) > 0)) ?
+            strncat(topic_url, topic, EVEL_MAX_URL_LEN) : ""));
+  EVEL_INFO("Vendor Event Listener API is located at: %s", event_api_url);
+
+  /***************************************************************************/
+  /* Build the URL to the throttling API.                                    */
+  /***************************************************************************/
+  snprintf(throt_api_url,
+           EVEL_MAX_URL_LEN,
+           "%s/clientThrottlingState",
+           base_api_url);
+  EVEL_INFO("Vendor Event Throttling API is located at: %s", throt_api_url);
+
+  /***************************************************************************/
+  /* Spin-up the event-handler, which gets cURL readied for use.             */
+  /***************************************************************************/
+  rc = event_handler_initialize(event_api_url,
+                                throt_api_url,
+                                username,
+                                password,
+                                verbosity);
+  if (rc != EVEL_SUCCESS)
+  {
+    log_error_state("Failed to initialize event handler (including cURL)");
+    goto exit_label;
+  }
+
+  /***************************************************************************/
+  /* Extract the metadata from OpenStack. If we fail to extract it, we       */
+  /* record that in the logs, but carry on, assuming we're in a test         */
+  /* without a metadata service.                                             */
+  /***************************************************************************/
+  rc = openstack_metadata(verbosity);
+  if (rc != EVEL_SUCCESS)
+  {
+    EVEL_INFO("Failed to load OpenStack metadata - assuming test environment");
+    rc = EVEL_SUCCESS;
+  }
+
+  /***************************************************************************/
+  /* Start the event handler thread.                                         */
+  /***************************************************************************/
+  rc = event_handler_run();
+  if (rc != EVEL_SUCCESS)
+  {
+    log_error_state("Failed to start event handler thread. "
+                    "Error code=%d", rc);
+    goto exit_label;
+  }
+
+exit_label:
+  return(rc);
+}
+
+/**************************************************************************//**
+ * Clean up the EVEL library.
+ *
+ * @note that at present don't expect Init/Term cycling not to leak memory!
+ *
+ * @returns Status code
+ * @retval  EVEL_SUCCESS On success
+ * @retval  "One of ::EVEL_ERR_CODES" On failure.
+ *****************************************************************************/
+EVEL_ERR_CODES evel_terminate(void)
+{
+  int rc = EVEL_SUCCESS;
+
+  /***************************************************************************/
+  /* First terminate any pending transactions in the event-posting thread.   */
+  /***************************************************************************/
+  rc = event_handler_terminate();
+  if (rc != EVEL_SUCCESS)
+  {
+    log_error_state("Failed to terminate EVEL library cleanly!");
+  }
+
+  /***************************************************************************/
+  /* Shut down the Event Handler library in a tidy manner.                   */
+  /***************************************************************************/
+  curl_global_cleanup();
+
+  /***************************************************************************/
+  /* Clean up allocated memory.                                              */
+  /***************************************************************************/
+  free(functional_role);
+
+  /***************************************************************************/
+  /* Clean up event throttling.                                              */
+  /***************************************************************************/
+  evel_throttle_terminate();
+
+  EVEL_INFO("EVEL stopped");
+  return(rc);
+}
+
+/**************************************************************************//**
+ * Free an event.
+ *
+ * Free off the event supplied.  Will free all the contained allocated memory.
+ *
+ * @note  It is safe to free a NULL pointer.
+ *****************************************************************************/
+void evel_free_event(void * event)
+{
+  EVENT_HEADER * evt_ptr = event;
+  EVEL_ENTER();
+
+  if (event != NULL)
+  {
+    /*************************************************************************/
+    /* Work out what kind of event we're dealing with so we can cast it      */
+    /* appropriately.                                                        */
+    /*************************************************************************/
+    switch (evt_ptr->event_domain)
+    {
+    case EVEL_DOMAIN_INTERNAL:
+      EVEL_DEBUG("Event is an Internal event at %lp", evt_ptr);
+      evel_free_internal_event((EVENT_INTERNAL *) evt_ptr);
+      memset(evt_ptr, 0, sizeof(EVENT_INTERNAL));
+      free(evt_ptr);
+      break;
+
+    case EVEL_DOMAIN_HEARTBEAT:
+      EVEL_DEBUG("Event is a Heartbeat at %lp", evt_ptr);
+      evel_free_header(evt_ptr);
+      memset(evt_ptr, 0, sizeof(EVENT_HEADER));
+      free(evt_ptr);
+      break;
+
+    case EVEL_DOMAIN_FAULT:
+      EVEL_DEBUG("Event is a Fault at %lp", evt_ptr);
+      evel_free_fault((EVENT_FAULT *)evt_ptr);
+      memset(evt_ptr, 0, sizeof(EVENT_FAULT));
+      free(evt_ptr);
+      break;
+
+    case EVEL_DOMAIN_MEASUREMENT:
+      EVEL_DEBUG("Event is a Measurement at %lp", evt_ptr);
+      evel_free_measurement((EVENT_MEASUREMENT *)evt_ptr);
+      memset(evt_ptr, 0, sizeof(EVENT_MEASUREMENT));
+      free(evt_ptr);
+      break;
+
+    case EVEL_DOMAIN_MOBILE_FLOW:
+      EVEL_DEBUG("Event is a Mobile Flow at %lp", evt_ptr);
+      evel_free_mobile_flow((EVENT_MOBILE_FLOW *)evt_ptr);
+      memset(evt_ptr, 0, sizeof(EVENT_MOBILE_FLOW));
+      free(evt_ptr);
+      break;
+
+    case EVEL_DOMAIN_REPORT:
+      EVEL_DEBUG("Event is a Report at %lp", evt_ptr);
+      evel_free_report((EVENT_REPORT *)evt_ptr);
+      memset(evt_ptr, 0, sizeof(EVENT_REPORT));
+      free(evt_ptr);
+      break;
+
+    case EVEL_DOMAIN_SERVICE:
+      EVEL_DEBUG("Event is a Service Event at %lp", evt_ptr);
+      evel_free_service((EVENT_SERVICE *)evt_ptr);
+      memset(evt_ptr, 0, sizeof(EVENT_SERVICE));
+      free(evt_ptr);
+      break;
+
+    case EVEL_DOMAIN_SIGNALING:
+      EVEL_DEBUG("Event is a Signaling at %lp", evt_ptr);
+      evel_free_signaling((EVENT_SIGNALING *)evt_ptr);
+      memset(evt_ptr, 0, sizeof(EVENT_SIGNALING));
+      free(evt_ptr);
+      break;
+
+    case EVEL_DOMAIN_STATE_CHANGE:
+      EVEL_DEBUG("Event is a State Change at %lp", evt_ptr);
+      evel_free_state_change((EVENT_STATE_CHANGE *)evt_ptr);
+      memset(evt_ptr, 0, sizeof(EVENT_STATE_CHANGE));
+      free(evt_ptr);
+      break;
+
+    case EVEL_DOMAIN_SYSLOG:
+      EVEL_DEBUG("Event is a Syslog at %lp", evt_ptr);
+      evel_free_syslog((EVENT_SYSLOG *)evt_ptr);
+      memset(evt_ptr, 0, sizeof(EVENT_SYSLOG));
+      free(evt_ptr);
+      break;
+
+    case EVEL_DOMAIN_OTHER:
+      EVEL_DEBUG("Event is an Other at %lp", evt_ptr);
+      evel_free_other((EVENT_OTHER *)evt_ptr);
+      memset(evt_ptr, 0, sizeof(EVENT_OTHER));
+      free(evt_ptr);
+      break;
+
+    default:
+      EVEL_ERROR("Unexpected event domain (%d)", evt_ptr->event_domain);
+      assert(0);
+    }
+  }
+  EVEL_EXIT();
+}
diff --git a/vnfs/VES/code/evel_library/evel.h b/vnfs/VES/code/evel_library/evel.h
new file mode 100644 (file)
index 0000000..a97dadc
--- /dev/null
@@ -0,0 +1,3677 @@
+#ifndef EVEL_INCLUDED
+#define EVEL_INCLUDED
+/**************************************************************************//**
+ * @file
+ * Header for EVEL library
+ *
+ * This file implements the EVEL library which is intended to provide a
+ * simple wrapper around the complexity of AT&T's Vendor Event Listener API so
+ * that VNFs can use it without worrying about details of the API transport.
+ *
+ * Zero return value is success (::EVEL_SUCCESS), non-zero is failure and will
+ * be one of ::EVEL_ERR_CODES.
+ *
+ * License
+ * -------
+ *
+ * Copyright(c) <2016>, AT&T Intellectual Property.  All other rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:  This product includes
+ *    software developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <time.h>
+
+#include "double_list.h"
+
+/*****************************************************************************/
+/* Supported API version.                                                    */
+/*****************************************************************************/
+#define EVEL_API_MAJOR_VERSION 3
+#define EVEL_API_MINOR_VERSION 0
+
+/**************************************************************************//**
+ * Error codes
+ *
+ * Error codes for EVEL low level interface
+ *****************************************************************************/
+typedef enum {
+  EVEL_SUCCESS,                   /** The operation was successful.          */
+  EVEL_ERR_GEN_FAIL,              /** Non-specific failure.                  */
+  EVEL_CURL_LIBRARY_FAIL,         /** A cURL library operation failed.       */
+  EVEL_PTHREAD_LIBRARY_FAIL,      /** A Posix threads operation failed.      */
+  EVEL_OUT_OF_MEMORY,             /** A memory allocation failure occurred.  */
+  EVEL_EVENT_BUFFER_FULL,         /** Too many events in the ring-buffer.    */
+  EVEL_EVENT_HANDLER_INACTIVE,    /** Attempt to raise event when inactive.  */
+  EVEL_NO_METADATA,               /** Failed to retrieve OpenStack metadata. */
+  EVEL_BAD_METADATA,              /** OpenStack metadata invalid format.     */
+  EVEL_BAD_JSON_FORMAT,           /** JSON failed to parse correctly.        */
+  EVEL_JSON_KEY_NOT_FOUND,        /** Failed to find the specified JSON key. */
+  EVEL_MAX_ERROR_CODES            /** Maximum number of valid error codes.   */
+} EVEL_ERR_CODES;
+
+/**************************************************************************//**
+ * Logging levels
+ *
+ * Variable levels of verbosity in the logging functions.
+ *****************************************************************************/
+typedef enum {
+  EVEL_LOG_MIN               = 0,
+  EVEL_LOG_SPAMMY            = 30,
+  EVEL_LOG_DEBUG             = 40,
+  EVEL_LOG_INFO              = 50,
+  EVEL_LOG_ERROR             = 60,
+  EVEL_LOG_MAX               = 101
+} EVEL_LOG_LEVELS;
+
+/*****************************************************************************/
+/* Maximum string lengths.                                                   */
+/*****************************************************************************/
+#define EVEL_MAX_STRING_LEN          4096
+#define EVEL_MAX_JSON_BODY           16000
+#define EVEL_MAX_ERROR_STRING_LEN    255
+#define EVEL_MAX_URL_LEN             511
+
+/**************************************************************************//**
+ * This value represents there being no restriction on the reporting interval.
+ *****************************************************************************/
+static const int EVEL_MEASUREMENT_INTERVAL_UKNOWN = 0;
+
+/**************************************************************************//**
+ * How many events can be backed-up before we start dropping events on the
+ * floor.
+ *
+ * @note  This value should be tuned in accordance with expected burstiness of
+ *        the event load and the expected response time of the ECOMP event
+ *        listener so that the probability of the buffer filling is suitably
+ *        low.
+ *****************************************************************************/
+static const int EVEL_EVENT_BUFFER_DEPTH = 100;
+
+/*****************************************************************************/
+/* How many different IP Types-of-Service are supported.                     */
+/*****************************************************************************/
+#define EVEL_TOS_SUPPORTED      256
+
+/**************************************************************************//**
+ * Event domains for the various events we support.
+ * JSON equivalent field: domain
+ *****************************************************************************/
+typedef enum {
+  EVEL_DOMAIN_INTERNAL,       /** Internal event, not for external routing.  */
+  EVEL_DOMAIN_HEARTBEAT,      /** A Heartbeat event (event header only).     */
+  EVEL_DOMAIN_FAULT,          /** A Fault event.                             */
+  EVEL_DOMAIN_MEASUREMENT,    /** A Measurement for VF Scaling event.        */
+  EVEL_DOMAIN_MOBILE_FLOW,    /** A Mobile Flow event.                       */
+  EVEL_DOMAIN_REPORT,         /** A Measurement for VF Reporting event.      */
+  EVEL_DOMAIN_SERVICE,        /** A Service event.                           */
+  EVEL_DOMAIN_SIGNALING,      /** A Signaling event.                         */
+  EVEL_DOMAIN_STATE_CHANGE,   /** A State Change event.                      */
+  EVEL_DOMAIN_SYSLOG,         /** A Syslog event.                            */
+  EVEL_DOMAIN_OTHER,          /** Another event.                             */
+  EVEL_MAX_DOMAINS            /** Maximum number of recognized Event types.  */
+} EVEL_EVENT_DOMAINS;
+
+/**************************************************************************//**
+ * Event priorities.
+ * JSON equivalent field: priority
+ *****************************************************************************/
+typedef enum {
+  EVEL_PRIORITY_HIGH,
+  EVEL_PRIORITY_MEDIUM,
+  EVEL_PRIORITY_NORMAL,
+  EVEL_PRIORITY_LOW,
+  EVEL_MAX_PRIORITIES
+} EVEL_EVENT_PRIORITIES;
+
+/**************************************************************************//**
+ * Fault / Threshold severities.
+ * JSON equivalent field: eventSeverity
+ *****************************************************************************/
+typedef enum {
+  EVEL_SEVERITY_CRITICAL,
+  EVEL_SEVERITY_MAJOR,
+  EVEL_SEVERITY_MINOR,
+  EVEL_SEVERITY_WARNING,
+  EVEL_SEVERITY_NORMAL,
+  EVEL_MAX_SEVERITIES
+} EVEL_SEVERITIES;
+
+/**************************************************************************//**
+ * Fault source types.
+ * JSON equivalent field: eventSourceType
+ *****************************************************************************/
+typedef enum {
+  EVEL_SOURCE_OTHER,
+  EVEL_SOURCE_ROUTER,
+  EVEL_SOURCE_SWITCH,
+  EVEL_SOURCE_HOST,
+  EVEL_SOURCE_CARD,
+  EVEL_SOURCE_PORT,
+  EVEL_SOURCE_SLOT_THRESHOLD,
+  EVEL_SOURCE_PORT_THRESHOLD,
+  EVEL_SOURCE_VIRTUAL_MACHINE,
+  EVEL_SOURCE_VIRTUAL_NETWORK_FUNCTION,
+  /***************************************************************************/
+  /* START OF VENDOR-SPECIFIC VALUES                                         */
+  /*                                                                         */
+  /* Vendor-specific values should be added here, and handled appropriately  */
+  /* in evel_event.c.                                                        */
+  /***************************************************************************/
+
+  /***************************************************************************/
+  /* END OF VENDOR-SPECIFIC VALUES                                           */
+  /***************************************************************************/
+  EVEL_MAX_SOURCE_TYPES
+} EVEL_SOURCE_TYPES;
+
+/**************************************************************************//**
+ * Fault VNF Status.
+ * JSON equivalent field: vfStatus
+ *****************************************************************************/
+typedef enum {
+  EVEL_VF_STATUS_ACTIVE,
+  EVEL_VF_STATUS_IDLE,
+  EVEL_VF_STATUS_PREP_TERMINATE,
+  EVEL_VF_STATUS_READY_TERMINATE,
+  EVEL_VF_STATUS_REQ_TERMINATE,
+  EVEL_MAX_VF_STATUSES
+} EVEL_VF_STATUSES;
+
+/**************************************************************************//**
+ * Counter criticalities.
+ * JSON equivalent field: criticality
+ *****************************************************************************/
+typedef enum {
+  EVEL_COUNTER_CRITICALITY_CRIT,
+  EVEL_COUNTER_CRITICALITY_MAJ,
+  EVEL_MAX_COUNTER_CRITICALITIES
+} EVEL_COUNTER_CRITICALITIES;
+
+/**************************************************************************//**
+ * Alert actions.
+ * JSON equivalent field: alertAction
+ *****************************************************************************/
+typedef enum {
+  EVEL_ALERT_ACTION_CLEAR,
+  EVEL_ALERT_ACTION_CONT,
+  EVEL_ALERT_ACTION_SET,
+  EVEL_MAX_ALERT_ACTIONS
+} EVEL_ALERT_ACTIONS;
+
+/**************************************************************************//**
+ * Alert types.
+ * JSON equivalent field: alertType
+ *****************************************************************************/
+typedef enum {
+  EVEL_ALERT_TYPE_CARD,
+  EVEL_ALERT_TYPE_ELEMENT,
+  EVEL_ALERT_TYPE_INTERFACE,
+  EVEL_ALERT_TYPE_SERVICE,
+  EVEL_MAX_ALERT_TYPES
+} EVEL_ALERT_TYPES;
+
+/**************************************************************************//**
+ * Alert types.
+ * JSON equivalent fields: newState, oldState
+ *****************************************************************************/
+typedef enum {
+  EVEL_ENTITY_STATE_IN_SERVICE,
+  EVEL_ENTITY_STATE_MAINTENANCE,
+  EVEL_ENTITY_STATE_OUT_OF_SERVICE,
+  EVEL_MAX_ENTITY_STATES
+} EVEL_ENTITY_STATE;
+
+/**************************************************************************//**
+ * Syslog facilities.
+ * JSON equivalent field: syslogFacility
+ *****************************************************************************/
+typedef enum {
+  EVEL_SYSLOG_FACILITY_KERNEL,
+  EVEL_SYSLOG_FACILITY_USER,
+  EVEL_SYSLOG_FACILITY_MAIL,
+  EVEL_SYSLOG_FACILITY_SYSTEM_DAEMON,
+  EVEL_SYSLOG_FACILITY_SECURITY_AUTH,
+  EVEL_SYSLOG_FACILITY_INTERNAL,
+  EVEL_SYSLOG_FACILITY_LINE_PRINTER,
+  EVEL_SYSLOG_FACILITY_NETWORK_NEWS,
+  EVEL_SYSLOG_FACILITY_UUCP,
+  EVEL_SYSLOG_FACILITY_CLOCK_DAEMON,
+  EVEL_SYSLOG_FACILITY_SECURITY_AUTH2,
+  EVEL_SYSLOG_FACILITY_FTP_DAEMON,
+  EVEL_SYSLOG_FACILITY_NTP,
+  EVEL_SYSLOG_FACILITY_LOG_AUDIT,
+  EVEL_SYSLOG_FACILITY_LOG_ALERT,
+  EVEL_SYSLOG_FACILITY_CLOCK_DAEMON2,
+  EVEL_SYSLOG_FACILITY_LOCAL0,
+  EVEL_SYSLOG_FACILITY_LOCAL1,
+  EVEL_SYSLOG_FACILITY_LOCAL2,
+  EVEL_SYSLOG_FACILITY_LOCAL3,
+  EVEL_SYSLOG_FACILITY_LOCAL4,
+  EVEL_SYSLOG_FACILITY_LOCAL5,
+  EVEL_SYSLOG_FACILITY_LOCAL6,
+  EVEL_SYSLOG_FACILITY_LOCAL7,
+  EVEL_MAX_SYSLOG_FACILITIES
+} EVEL_SYSLOG_FACILITIES;
+
+/**************************************************************************//**
+ * TCP flags.
+ * JSON equivalent fields: tcpFlagCountList, tcpFlagList
+ *****************************************************************************/
+typedef enum {
+  EVEL_TCP_NS,
+  EVEL_TCP_CWR,
+  EVEL_TCP_ECE,
+  EVEL_TCP_URG,
+  EVEL_TCP_ACK,
+  EVEL_TCP_PSH,
+  EVEL_TCP_RST,
+  EVEL_TCP_SYN,
+  EVEL_TCP_FIN,
+  EVEL_MAX_TCP_FLAGS
+} EVEL_TCP_FLAGS;
+
+/**************************************************************************//**
+ * Mobile QCI Classes of Service.
+ * JSON equivalent fields: mobileQciCosCountList, mobileQciCosList
+ *****************************************************************************/
+typedef enum {
+
+  /***************************************************************************/
+  /* UMTS Classes of Service.                                                */
+  /***************************************************************************/
+  EVEL_QCI_COS_UMTS_CONVERSATIONAL,
+  EVEL_QCI_COS_UMTS_STREAMING,
+  EVEL_QCI_COS_UMTS_INTERACTIVE,
+  EVEL_QCI_COS_UMTS_BACKGROUND,
+
+  /***************************************************************************/
+  /* LTE Classes of Service.                                                 */
+  /***************************************************************************/
+  EVEL_QCI_COS_LTE_1,
+  EVEL_QCI_COS_LTE_2,
+  EVEL_QCI_COS_LTE_3,
+  EVEL_QCI_COS_LTE_4,
+  EVEL_QCI_COS_LTE_65,
+  EVEL_QCI_COS_LTE_66,
+  EVEL_QCI_COS_LTE_5,
+  EVEL_QCI_COS_LTE_6,
+  EVEL_QCI_COS_LTE_7,
+  EVEL_QCI_COS_LTE_8,
+  EVEL_QCI_COS_LTE_9,
+  EVEL_QCI_COS_LTE_69,
+  EVEL_QCI_COS_LTE_70,
+  EVEL_MAX_QCI_COS_TYPES
+} EVEL_QCI_COS_TYPES;
+
+/**************************************************************************//**
+ * Service Event endpoint description
+ * JSON equivalent field: endpointDesc
+ *****************************************************************************/
+typedef enum {
+  EVEL_SERVICE_ENDPOINT_CALLEE,
+  EVEL_SERVICE_ENDPOINT_CALLER,
+  EVEL_MAX_SERVICE_ENDPOINT_DESC
+} EVEL_SERVICE_ENDPOINT_DESC;
+
+/**************************************************************************//**
+ * Boolean type for EVEL library.
+ *****************************************************************************/
+typedef enum {
+  EVEL_FALSE,
+  EVEL_TRUE
+} EVEL_BOOLEAN;
+
+/**************************************************************************//**
+ * Optional parameter holder for double.
+ *****************************************************************************/
+typedef struct evel_option_double
+{
+  double value;
+  EVEL_BOOLEAN is_set;
+} EVEL_OPTION_DOUBLE;
+
+/**************************************************************************//**
+ * Optional parameter holder for string.
+ *****************************************************************************/
+typedef struct evel_option_string
+{
+  char * value;
+  EVEL_BOOLEAN is_set;
+} EVEL_OPTION_STRING;
+
+/**************************************************************************//**
+ * Optional parameter holder for int.
+ *****************************************************************************/
+typedef struct evel_option_int
+{
+  int value;
+  EVEL_BOOLEAN is_set;
+} EVEL_OPTION_INT;
+
+/**************************************************************************//**
+ * Optional parameter holder for unsigned long long.
+ *****************************************************************************/
+typedef struct evel_option_ull
+{
+  unsigned long long value;
+  EVEL_BOOLEAN is_set;
+} EVEL_OPTION_ULL;
+
+/**************************************************************************//**
+ * Optional parameter holder for time_t.
+ *****************************************************************************/
+typedef struct evel_option_time
+{
+  time_t value;
+  EVEL_BOOLEAN is_set;
+} EVEL_OPTION_TIME;
+
+/*****************************************************************************/
+/* Supported Common Event Header version.                                    */
+/*****************************************************************************/
+#define EVEL_HEADER_MAJOR_VERSION 1
+#define EVEL_HEADER_MINOR_VERSION 2
+
+/**************************************************************************//**
+ * Event header.
+ * JSON equivalent field: commonEventHeader
+ *****************************************************************************/
+typedef struct event_header {
+  /***************************************************************************/
+  /* Version                                                                 */
+  /***************************************************************************/
+  int major_version;
+  int minor_version;
+
+  /***************************************************************************/
+  /* Mandatory fields                                                        */
+  /***************************************************************************/
+  EVEL_EVENT_DOMAINS event_domain;
+  char * event_id;
+  char * source_name;
+  char * functional_role;
+  char * reporting_entity_name;
+  EVEL_EVENT_PRIORITIES priority;
+  unsigned long long start_epoch_microsec;
+  unsigned long long last_epoch_microsec;
+  int sequence;
+
+  /***************************************************************************/
+  /* Optional fields                                                         */
+  /***************************************************************************/
+  EVEL_OPTION_STRING event_type;
+  EVEL_OPTION_STRING source_id;
+  EVEL_OPTION_STRING reporting_entity_id;
+
+} EVENT_HEADER;
+
+/*****************************************************************************/
+/* Supported Fault version.                                                  */
+/*****************************************************************************/
+#define EVEL_FAULT_MAJOR_VERSION 1
+#define EVEL_FAULT_MINOR_VERSION 1
+
+/**************************************************************************//**
+ * Fault.
+ * JSON equivalent field: faultFields
+ *****************************************************************************/
+typedef struct event_fault {
+  /***************************************************************************/
+  /* Header and version                                                      */
+  /***************************************************************************/
+  EVENT_HEADER header;
+  int major_version;
+  int minor_version;
+
+  /***************************************************************************/
+  /* Mandatory fields                                                        */
+  /***************************************************************************/
+  EVEL_SEVERITIES event_severity;
+  EVEL_SOURCE_TYPES event_source_type;
+  char * alarm_condition;
+  char * specific_problem;
+  EVEL_VF_STATUSES vf_status;
+
+  /***************************************************************************/
+  /* Optional fields                                                         */
+  /***************************************************************************/
+  EVEL_OPTION_STRING alarm_interface_a;
+  DLIST additional_info;
+
+} EVENT_FAULT;
+
+/**************************************************************************//**
+ * Fault Additional Info.
+ * JSON equivalent field: alarmAdditionalInformation
+ *****************************************************************************/
+typedef struct fault_additional_info {
+  char * name;
+  char * value;
+} FAULT_ADDL_INFO;
+
+/*****************************************************************************/
+/* Supported Measurement version.                                            */
+/*****************************************************************************/
+#define EVEL_MEASUREMENT_MAJOR_VERSION 1
+#define EVEL_MEASUREMENT_MINOR_VERSION 1
+
+/**************************************************************************//**
+ * Errors.
+ * JSON equivalent field: errors
+ *****************************************************************************/
+typedef struct measurement_errors {
+  int receive_discards;
+  int receive_errors;
+  int transmit_discards;
+  int transmit_errors;
+} MEASUREMENT_ERRORS;
+
+/**************************************************************************//**
+ * Measurement.
+ * JSON equivalent field: measurementsForVfScalingFields
+ *****************************************************************************/
+typedef struct event_measurement {
+  /***************************************************************************/
+  /* Header and version                                                      */
+  /***************************************************************************/
+  EVENT_HEADER header;
+  int major_version;
+  int minor_version;
+
+  /***************************************************************************/
+  /* Mandatory fields                                                        */
+  /***************************************************************************/
+  double measurement_interval;
+
+  /***************************************************************************/
+  /* Optional fields                                                         */
+  /***************************************************************************/
+  DLIST additional_measurements;
+  EVEL_OPTION_DOUBLE aggregate_cpu_usage;
+  DLIST codec_usage;
+  EVEL_OPTION_INT concurrent_sessions;
+  EVEL_OPTION_INT configured_entities;
+  DLIST cpu_usage;
+  MEASUREMENT_ERRORS * errors;
+  DLIST feature_usage;
+  DLIST filesystem_usage;
+  DLIST latency_distribution;
+  EVEL_OPTION_DOUBLE mean_request_latency;
+  EVEL_OPTION_DOUBLE memory_configured;
+  EVEL_OPTION_DOUBLE memory_used;
+  EVEL_OPTION_INT media_ports_in_use;
+  EVEL_OPTION_INT request_rate;
+  EVEL_OPTION_DOUBLE vnfc_scaling_metric;
+  DLIST vnic_usage;
+
+} EVENT_MEASUREMENT;
+
+/**************************************************************************//**
+ * CPU Usage.
+ * JSON equivalent field: cpuUsage
+ *****************************************************************************/
+typedef struct measurement_cpu_use {
+  char * id;
+  double usage;
+} MEASUREMENT_CPU_USE;
+
+/**************************************************************************//**
+ * Filesystem Usage.
+ * JSON equivalent field: filesystemUsage
+ *****************************************************************************/
+typedef struct measurement_fsys_use {
+  char * filesystem_name;
+  double block_configured;
+  int block_iops;
+  double block_used;
+  double ephemeral_configured;
+  int ephemeral_iops;
+  double ephemeral_used;
+} MEASUREMENT_FSYS_USE;
+
+/**************************************************************************//**
+ * Latency Bucket.
+ * JSON equivalent field: latencyBucketMeasure
+ *****************************************************************************/
+typedef struct measurement_latency_bucket {
+  int count;
+
+  /***************************************************************************/
+  /* Optional fields                                                         */
+  /***************************************************************************/
+  EVEL_OPTION_DOUBLE high_end;
+  EVEL_OPTION_DOUBLE low_end;
+
+} MEASUREMENT_LATENCY_BUCKET;
+
+/**************************************************************************//**
+ * Virtual NIC usage.
+ * JSON equivalent field: vNicUsage
+ *****************************************************************************/
+typedef struct measurement_vnic_use {
+  int bytes_in;
+  int bytes_out;
+  int packets_in;
+  int packets_out;
+  char * vnic_id;
+
+  /***************************************************************************/
+  /* Optional fields                                                         */
+  /***************************************************************************/
+  EVEL_OPTION_INT broadcast_packets_in;
+  EVEL_OPTION_INT broadcast_packets_out;
+  EVEL_OPTION_INT multicast_packets_in;
+  EVEL_OPTION_INT multicast_packets_out;
+  EVEL_OPTION_INT unicast_packets_in;
+  EVEL_OPTION_INT unicast_packets_out;
+
+} MEASUREMENT_VNIC_USE;
+
+/**************************************************************************//**
+ * Codec Usage.
+ * JSON equivalent field: codecsInUse
+ *****************************************************************************/
+typedef struct measurement_codec_use {
+  char * codec_id;
+  int number_in_use;
+} MEASUREMENT_CODEC_USE;
+
+/**************************************************************************//**
+ * Feature Usage.
+ * JSON equivalent field: featuresInUse
+ *****************************************************************************/
+typedef struct measurement_feature_use {
+  char * feature_id;
+  int feature_utilization;
+} MEASUREMENT_FEATURE_USE;
+
+/**************************************************************************//**
+ * Measurement Group.
+ * JSON equivalent field: additionalMeasurements
+ *****************************************************************************/
+typedef struct measurement_group {
+  char * name;
+  DLIST measurements;
+} MEASUREMENT_GROUP;
+
+/**************************************************************************//**
+ * Custom Defined Measurement.
+ * JSON equivalent field: measurements
+ *****************************************************************************/
+typedef struct custom_measurement {
+  char * name;
+  char * value;
+} CUSTOM_MEASUREMENT;
+
+/*****************************************************************************/
+/* Supported Report version.                                                 */
+/*****************************************************************************/
+#define EVEL_REPORT_MAJOR_VERSION 1
+#define EVEL_REPORT_MINOR_VERSION 1
+
+/**************************************************************************//**
+ * Report.
+ * JSON equivalent field: measurementsForVfReportingFields
+ *
+ * @note  This is an experimental event type and is not currently a formal part
+ *        of AT&T's specification.
+ *****************************************************************************/
+typedef struct event_report {
+  /***************************************************************************/
+  /* Header and version                                                      */
+  /***************************************************************************/
+  EVENT_HEADER header;
+  int major_version;
+  int minor_version;
+
+  /***************************************************************************/
+  /* Mandatory fields                                                        */
+  /***************************************************************************/
+  double measurement_interval;
+
+  /***************************************************************************/
+  /* Optional fields                                                         */
+  /***************************************************************************/
+  DLIST feature_usage;
+  DLIST measurement_groups;
+
+} EVENT_REPORT;
+
+/**************************************************************************//**
+ * Mobile GTP Per Flow Metrics.
+ * JSON equivalent field: gtpPerFlowMetrics
+ *****************************************************************************/
+typedef struct mobile_gtp_per_flow_metrics {
+  double avg_bit_error_rate;
+  double avg_packet_delay_variation;
+  int avg_packet_latency;
+  int avg_receive_throughput;
+  int avg_transmit_throughput;
+  int flow_activation_epoch;
+  int flow_activation_microsec;
+  int flow_deactivation_epoch;
+  int flow_deactivation_microsec;
+  time_t flow_deactivation_time;
+  char * flow_status;
+  int max_packet_delay_variation;
+  int num_activation_failures;
+  int num_bit_errors;
+  int num_bytes_received;
+  int num_bytes_transmitted;
+  int num_dropped_packets;
+  int num_l7_bytes_received;
+  int num_l7_bytes_transmitted;
+  int num_lost_packets;
+  int num_out_of_order_packets;
+  int num_packet_errors;
+  int num_packets_received_excl_retrans;
+  int num_packets_received_incl_retrans;
+  int num_packets_transmitted_incl_retrans;
+  int num_retries;
+  int num_timeouts;
+  int num_tunneled_l7_bytes_received;
+  int round_trip_time;
+  int time_to_first_byte;
+
+  /***************************************************************************/
+  /* Optional fields                                                         */
+  /***************************************************************************/
+  EVEL_OPTION_INT ip_tos_counts[EVEL_TOS_SUPPORTED];
+  EVEL_OPTION_INT tcp_flag_counts[EVEL_MAX_TCP_FLAGS];
+  EVEL_OPTION_INT qci_cos_counts[EVEL_MAX_QCI_COS_TYPES];
+  EVEL_OPTION_INT dur_connection_failed_status;
+  EVEL_OPTION_INT dur_tunnel_failed_status;
+  EVEL_OPTION_STRING flow_activated_by;
+  EVEL_OPTION_TIME flow_activation_time;
+  EVEL_OPTION_STRING flow_deactivated_by;
+  EVEL_OPTION_STRING gtp_connection_status;
+  EVEL_OPTION_STRING gtp_tunnel_status;
+  EVEL_OPTION_INT large_packet_rtt;
+  EVEL_OPTION_DOUBLE large_packet_threshold;
+  EVEL_OPTION_INT max_receive_bit_rate;
+  EVEL_OPTION_INT max_transmit_bit_rate;
+  EVEL_OPTION_INT num_gtp_echo_failures;
+  EVEL_OPTION_INT num_gtp_tunnel_errors;
+  EVEL_OPTION_INT num_http_errors;
+
+} MOBILE_GTP_PER_FLOW_METRICS;
+
+/*****************************************************************************/
+/* Supported Mobile Flow version.                                            */
+/*****************************************************************************/
+#define EVEL_MOBILE_FLOW_MAJOR_VERSION 1
+#define EVEL_MOBILE_FLOW_MINOR_VERSION 1
+
+/**************************************************************************//**
+ * Mobile Flow.
+ * JSON equivalent field: mobileFlow
+ *****************************************************************************/
+typedef struct event_mobile_flow {
+  /***************************************************************************/
+  /* Header and version                                                      */
+  /***************************************************************************/
+  EVENT_HEADER header;
+  int major_version;
+  int minor_version;
+
+  /***************************************************************************/
+  /* Mandatory fields                                                        */
+  /***************************************************************************/
+  char * flow_direction;
+  MOBILE_GTP_PER_FLOW_METRICS * gtp_per_flow_metrics;
+  char * ip_protocol_type;
+  char * ip_version;
+  char * other_endpoint_ip_address;
+  int other_endpoint_port;
+  char * reporting_endpoint_ip_addr;
+  int reporting_endpoint_port;
+
+  /***************************************************************************/
+  /* Optional fields                                                         */
+  /***************************************************************************/
+  EVEL_OPTION_STRING application_type;
+  EVEL_OPTION_STRING app_protocol_type;
+  EVEL_OPTION_STRING app_protocol_version;
+  EVEL_OPTION_STRING cid;
+  EVEL_OPTION_STRING connection_type;
+  EVEL_OPTION_STRING ecgi;
+  EVEL_OPTION_STRING gtp_protocol_type;
+  EVEL_OPTION_STRING gtp_version;
+  EVEL_OPTION_STRING http_header;
+  EVEL_OPTION_STRING imei;
+  EVEL_OPTION_STRING imsi;
+  EVEL_OPTION_STRING lac;
+  EVEL_OPTION_STRING mcc;
+  EVEL_OPTION_STRING mnc;
+  EVEL_OPTION_STRING msisdn;
+  EVEL_OPTION_STRING other_functional_role;
+  EVEL_OPTION_STRING rac;
+  EVEL_OPTION_STRING radio_access_technology;
+  EVEL_OPTION_STRING sac;
+  EVEL_OPTION_INT sampling_algorithm;
+  EVEL_OPTION_STRING tac;
+  EVEL_OPTION_STRING tunnel_id;
+  EVEL_OPTION_STRING vlan_id;
+
+} EVENT_MOBILE_FLOW;
+
+/**************************************************************************//**
+ * Other.
+ * JSON equivalent field: otherFields
+ *****************************************************************************/
+typedef struct event_other {
+  EVENT_HEADER header;
+  DLIST other_fields;
+
+} EVENT_OTHER;
+
+/**************************************************************************//**
+ * Other Field.
+ * JSON equivalent field: otherFields
+ *****************************************************************************/
+typedef struct other_field {
+  char * name;
+  char * value;
+} OTHER_FIELD;
+
+/**************************************************************************//**
+ * Event Instance Identifier
+ * JSON equivalent field: eventInstanceIdentifier
+ *****************************************************************************/
+typedef struct evel_event_instance_id {
+
+  /***************************************************************************/
+  /* Mandatory fields                                                        */
+  /***************************************************************************/
+  char * vendor_id;                                        /* JSON: vendorId */
+  char * event_id;                                          /* JSON: eventId */
+
+  /***************************************************************************/
+  /* Optional fields                                                         */
+  /***************************************************************************/
+  EVEL_OPTION_STRING product_id;                          /* JSON: productId */
+  EVEL_OPTION_STRING subsystem_id;                      /* JSON: subsystemId */
+  EVEL_OPTION_STRING event_friendly_name;         /* JSON: eventFriendlyName */
+
+} EVEL_EVENT_INSTANCE_ID;
+
+/*****************************************************************************/
+/* Supported Service Events version.                                         */
+/*****************************************************************************/
+#define EVEL_SERVICE_MAJOR_VERSION 1
+#define EVEL_SERVICE_MINOR_VERSION 1
+
+/**************************************************************************//**
+ * Service Events.
+ * JSON equivalent field: serviceEventsFields
+ *****************************************************************************/
+typedef struct event_service {
+  /***************************************************************************/
+  /* Header and version                                                      */
+  /***************************************************************************/
+  EVENT_HEADER header;
+  int major_version;
+  int minor_version;
+
+  /***************************************************************************/
+  /* Mandatory fields                                                        */
+  /***************************************************************************/
+  EVEL_EVENT_INSTANCE_ID instance_id;       /* JSON: eventInstanceIdentifier */
+
+  /***************************************************************************/
+  /* Optional fields.                                                        */
+  /***************************************************************************/
+  EVEL_OPTION_STRING correlator;                         /* JSON: correlator */
+  DLIST additional_fields;                         /* JSON: additionalFields */
+
+  /***************************************************************************/
+  /* Optional fields within JSON equivalent object: codecSelected            */
+  /***************************************************************************/
+  EVEL_OPTION_STRING codec;                                   /* JSON: codec */
+
+  /***************************************************************************/
+  /* Optional fields within JSON equivalent object: codecSelectedTranscoding */
+  /***************************************************************************/
+  EVEL_OPTION_STRING callee_side_codec;             /* JSON: calleeSideCodec */
+  EVEL_OPTION_STRING caller_side_codec;             /* JSON: callerSideCodec */
+
+  /***************************************************************************/
+  /* Optional fields within JSON equivalent object: midCallRtcp              */
+  /***************************************************************************/
+  EVEL_OPTION_STRING rtcp_data;                            /* JSON: rtcpData */
+
+  /***************************************************************************/
+  /* Optional fields within JSON equivalent object: endOfCallVqmSummaries    */
+  /***************************************************************************/
+  EVEL_OPTION_STRING adjacency_name;                  /* JSON: adjacencyName */
+  EVEL_OPTION_STRING endpoint_description;      /* JSON: endpointDescription */
+  EVEL_OPTION_INT endpoint_jitter;                   /* JSON: endpointJitter */
+  EVEL_OPTION_INT endpoint_rtp_oct_disc; /* JSON: endpointRtpOctetsDiscarded */
+  EVEL_OPTION_INT endpoint_rtp_oct_recv;  /* JSON: endpointRtpOctetsReceived */
+  EVEL_OPTION_INT endpoint_rtp_oct_sent;      /* JSON: endpointRtpOctetsSent */
+  EVEL_OPTION_INT endpoint_rtp_pkt_disc;/* JSON: endpointRtpPacketsDiscarded */
+  EVEL_OPTION_INT endpoint_rtp_pkt_recv; /* JSON: endpointRtpPacketsReceived */
+  EVEL_OPTION_INT endpoint_rtp_pkt_sent;     /* JSON: endpointRtpPacketsSent */
+  EVEL_OPTION_INT local_jitter;                         /* JSON: localJitter */
+  EVEL_OPTION_INT local_rtp_oct_disc;       /* JSON: localRtpOctetsDiscarded */
+  EVEL_OPTION_INT local_rtp_oct_recv;        /* JSON: localRtpOctetsReceived */
+  EVEL_OPTION_INT local_rtp_oct_sent;            /* JSON: localRtpOctetsSent */
+  EVEL_OPTION_INT local_rtp_pkt_disc;      /* JSON: localRtpPacketsDiscarded */
+  EVEL_OPTION_INT local_rtp_pkt_recv;       /* JSON: localRtpPacketsReceived */
+  EVEL_OPTION_INT local_rtp_pkt_sent;           /* JSON: localRtpPacketsSent */
+  EVEL_OPTION_DOUBLE mos_cqe;                                /* JSON: mosCqe */
+  EVEL_OPTION_INT packets_lost;                         /* JSON: packetsLost */
+  EVEL_OPTION_DOUBLE packet_loss_percent;         /* JSON: packetLossPercent */
+  EVEL_OPTION_INT r_factor;                                 /* JSON: rFactor */
+  EVEL_OPTION_INT round_trip_delay;                  /* JSON: roundTripDelay */
+
+  /***************************************************************************/
+  /* Optional fields within JSON equivalent object: marker                   */
+  /***************************************************************************/
+  EVEL_OPTION_STRING phone_number;                      /* JSON: phoneNumber */
+
+} EVENT_SERVICE;
+
+/*****************************************************************************/
+/* Supported Signaling version.                                              */
+/*****************************************************************************/
+#define EVEL_SIGNALING_MAJOR_VERSION 1
+#define EVEL_SIGNALING_MINOR_VERSION 1
+
+/**************************************************************************//**
+ * Signaling.
+ * JSON equivalent field: signalingFields
+ *****************************************************************************/
+typedef struct event_signaling {
+  /***************************************************************************/
+  /* Header and version                                                      */
+  /***************************************************************************/
+  EVENT_HEADER header;
+  int major_version;
+  int minor_version;
+
+  /***************************************************************************/
+  /* Mandatory fields                                                        */
+  /***************************************************************************/
+  EVEL_EVENT_INSTANCE_ID instance_id;       /* JSON: eventInstanceIdentifier */
+
+  /***************************************************************************/
+  /* Optional fields                                                         */
+  /***************************************************************************/
+  EVEL_OPTION_STRING correlator;                         /* JSON: correlator */
+  EVEL_OPTION_STRING local_ip_address;               /* JSON: localIpAddress */
+  EVEL_OPTION_STRING local_port;                          /* JSON: localPort */
+  EVEL_OPTION_STRING remote_ip_address;             /* JSON: remoteIpAddress */
+  EVEL_OPTION_STRING remote_port;                        /* JSON: remotePort */
+  EVEL_OPTION_STRING compressed_sip;                  /* JSON: compressedSip */
+  EVEL_OPTION_STRING summary_sip;                        /* JSON: summarySip */
+
+} EVENT_SIGNALING;
+
+/*****************************************************************************/
+/* Supported State Change version.                                           */
+/*****************************************************************************/
+#define EVEL_STATE_CHANGE_MAJOR_VERSION 1
+#define EVEL_STATE_CHANGE_MINOR_VERSION 1
+
+/**************************************************************************//**
+ * State Change.
+ * JSON equivalent field: stateChangeFields
+ *****************************************************************************/
+typedef struct event_state_change {
+  /***************************************************************************/
+  /* Header and version                                                      */
+  /***************************************************************************/
+  EVENT_HEADER header;
+  int major_version;
+  int minor_version;
+
+  /***************************************************************************/
+  /* Mandatory fields                                                        */
+  /***************************************************************************/
+  EVEL_ENTITY_STATE new_state;
+  EVEL_ENTITY_STATE old_state;
+  char * state_interface;
+
+  /***************************************************************************/
+  /* Optional fields                                                         */
+  /***************************************************************************/
+  DLIST additional_fields;
+
+} EVENT_STATE_CHANGE;
+
+/**************************************************************************//**
+ * State Change Additional Field.
+ * JSON equivalent field: additionalFields
+ *****************************************************************************/
+typedef struct state_change_additional_field {
+  char * name;
+  char * value;
+} STATE_CHANGE_ADDL_FIELD;
+
+/*****************************************************************************/
+/* Supported Syslog version.                                                 */
+/*****************************************************************************/
+#define EVEL_SYSLOG_MAJOR_VERSION 1
+#define EVEL_SYSLOG_MINOR_VERSION 1
+
+/**************************************************************************//**
+ * Syslog.
+ * JSON equivalent field: syslogFields
+ *****************************************************************************/
+typedef struct event_syslog {
+  /***************************************************************************/
+  /* Header and version                                                      */
+  /***************************************************************************/
+  EVENT_HEADER header;
+  int major_version;
+  int minor_version;
+
+  /***************************************************************************/
+  /* Mandatory fields                                                        */
+  /***************************************************************************/
+  EVEL_SOURCE_TYPES event_source_type;
+  char * syslog_msg;
+  char * syslog_tag;
+
+  /***************************************************************************/
+  /* Optional fields                                                         */
+  /***************************************************************************/
+  DLIST additional_fields;
+  EVEL_OPTION_STRING event_source_host;
+  EVEL_OPTION_INT syslog_facility;
+  EVEL_OPTION_STRING syslog_proc;
+  EVEL_OPTION_INT syslog_proc_id;
+  EVEL_OPTION_STRING syslog_s_data;
+  EVEL_OPTION_INT syslog_ver;
+
+} EVENT_SYSLOG;
+
+/**************************************************************************//**
+ * Syslog Additional Field.
+ * JSON equivalent field: additionalFields
+ *****************************************************************************/
+typedef struct syslog_additional_field {
+  char * name;
+  char * value;
+} SYSLOG_ADDL_FIELD;
+
+/**************************************************************************//**
+ * Copyright.
+ * JSON equivalent object: attCopyrightNotice
+ *****************************************************************************/
+typedef struct copyright {
+  char * useAndRedistribution;
+  char * condition1;
+  char * condition2;
+  char * condition3;
+  char * condition4;
+  char * disclaimerLine1;
+  char * disclaimerLine2;
+  char * disclaimerLine3;
+  char * disclaimerLine4;
+} COPYRIGHT;
+
+/**************************************************************************//**
+ * Library initialization.
+ *
+ * Initialize the EVEL library.
+ *
+ * @note  This function initializes the cURL library.  Applications making use
+ *        of libcurl may need to pull the initialization out of here.  Note
+ *        also that this function is not threadsafe as a result - refer to
+ *        libcurl's API documentation for relevant warnings.
+ *
+ * @sa  Matching Term function.
+ *
+ * @param   fqdn    The API's FQDN or IP address.
+ * @param   port    The API's port.
+ * @param   path    The optional path (may be NULL).
+ * @param   topic   The optional topic part of the URL (may be NULL).
+ * @param   secure  Whether to use HTTPS (0=HTTP, 1=HTTPS).
+ * @param   username  Username for Basic Authentication of requests.
+ * @param   password  Password for Basic Authentication of requests.
+ * @param   source_type The kind of node we represent.
+ * @param   role    The role this node undertakes.
+ * @param   verbosity  0 for normal operation, positive values for chattier
+ *                     logs.
+ *
+ * @returns Status code
+ * @retval  EVEL_SUCCESS      On success
+ * @retval  ::EVEL_ERR_CODES  On failure.
+ *****************************************************************************/
+EVEL_ERR_CODES evel_initialize(const char * const fqdn,
+                               int port,
+                               const char * const path,
+                               const char * const topic,
+                               int secure,
+                               const char * const username,
+                               const char * const password,
+                               EVEL_SOURCE_TYPES source_type,
+                               const char * const role,
+                               int verbosity
+                               );
+
+/**************************************************************************//**
+ * Clean up the EVEL library.
+ *
+ * @note that at present don't expect Init/Term cycling not to leak memory!
+ *
+ * @returns Status code
+ * @retval  EVEL_SUCCESS On success
+ * @retval  "One of ::EVEL_ERR_CODES" On failure.
+ *****************************************************************************/
+EVEL_ERR_CODES evel_terminate(void);
+
+EVEL_ERR_CODES evel_post_event(EVENT_HEADER * event);
+const char * evel_error_string(void);
+
+
+/**************************************************************************//**
+ * Free an event.
+ *
+ * Free off the event supplied.  Will free all the contained allocated memory.
+ *
+ * @note  It is safe to free a NULL pointer.
+ *****************************************************************************/
+void evel_free_event(void * event);
+
+/**************************************************************************//**
+ * Encode the event as a JSON event object according to AT&T's schema.
+ *
+ * @param json      Pointer to where to store the JSON encoded data.
+ * @param max_size  Size of storage available in json_body.
+ * @param event     Pointer to the ::EVENT_HEADER to encode.
+ * @returns Number of bytes actually written.
+ *****************************************************************************/
+int evel_json_encode_event(char * json,
+                           int max_size,
+                           EVENT_HEADER * event);
+
+/**************************************************************************//**
+ * Callback function to provide returned data.
+ *
+ * Copy data into the supplied buffer, write_callback::ptr, checking size
+ * limits.
+ *
+ * @returns   Number of bytes placed into write_callback::ptr. 0 for EOF.
+ *****************************************************************************/
+size_t evel_write_callback(void *contents,
+                           size_t size,
+                           size_t nmemb,
+                           void *userp);
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*                                                                           */
+/*   HEARTBEAT - (includes common header, too)                               */
+/*                                                                           */
+/*****************************************************************************/
+/*****************************************************************************/
+
+/**************************************************************************//**
+ * Create a new heartbeat event.
+ *
+ * @note that the heartbeat is just a "naked" commonEventHeader!
+ *
+ * @returns pointer to the newly manufactured ::EVENT_HEADER.  If the event is
+ *          not used it must be released using ::evel_free_event
+ * @retval  NULL  Failed to create the event.
+ *****************************************************************************/
+EVENT_HEADER * evel_new_heartbeat(void);
+
+/**************************************************************************//**
+ * Free an event header.
+ *
+ * Free off the event header supplied.  Will free all the contained allocated
+ * memory.
+ *
+ * @note It does not free the header itself, since that may be part of a
+ * larger structure.
+ *****************************************************************************/
+void evel_free_header(EVENT_HEADER * const event);
+
+/**************************************************************************//**
+ * Initialize a newly created event header.
+ *
+ * @param header  Pointer to the header being initialized.
+ *****************************************************************************/
+void evel_init_header(EVENT_HEADER * const header);
+
+/**************************************************************************//**
+ * Set the Event Type property of the event header.
+ *
+ * @param header        Pointer to the ::EVENT_HEADER.
+ * @param type          The Event Type to be set. ASCIIZ string. The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_header_type_set(EVENT_HEADER * const header,
+                          const char * const type);
+
+/**************************************************************************//**
+ * Set the Start Epoch property of the event header.
+ *
+ * @note The Start Epoch defaults to the time of event creation.
+ *
+ * @param header        Pointer to the ::EVENT_HEADER.
+ * @param start_epoch_microsec
+ *                      The start epoch to set, in microseconds.
+ *****************************************************************************/
+void evel_start_epoch_set(EVENT_HEADER * const header,
+                          const unsigned long long start_epoch_microsec);
+
+/**************************************************************************//**
+ * Set the Last Epoch property of the event header.
+ *
+ * @note The Last Epoch defaults to the time of event creation.
+ *
+ * @param header        Pointer to the ::EVENT_HEADER.
+ * @param last_epoch_microsec
+ *                      The last epoch to set, in microseconds.
+ *****************************************************************************/
+void evel_last_epoch_set(EVENT_HEADER * const header,
+                         const unsigned long long last_epoch_microsec);
+
+/**************************************************************************//**
+ * Set the Reporting Entity Name property of the event header.
+ *
+ * @note The Reporting Entity Name defaults to the OpenStack VM Name.
+ *
+ * @param header        Pointer to the ::EVENT_HEADER.
+ * @param entity_name   The entity name to set.
+ *****************************************************************************/
+void evel_reporting_entity_name_set(EVENT_HEADER * const header,
+                                    const char * const entity_name);
+
+/**************************************************************************//**
+ * Set the Reporting Entity Id property of the event header.
+ *
+ * @note The Reporting Entity Id defaults to the OpenStack VM UUID.
+ *
+ * @param header        Pointer to the ::EVENT_HEADER.
+ * @param entity_id     The entity id to set.
+ *****************************************************************************/
+void evel_reporting_entity_id_set(EVENT_HEADER * const header,
+                                  const char * const entity_id);
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*                                                                           */
+/*   FAULT                                                                   */
+/*                                                                           */
+/*****************************************************************************/
+/*****************************************************************************/
+
+/**************************************************************************//**
+ * Create a new fault event.
+ *
+ *
+ * @returns pointer to the newly manufactured ::EVENT_FAULT.  If the event is
+ *          not used it must be released using ::evel_free_fault
+ * @retval  NULL  Failed to create the event.
+ *****************************************************************************/
+EVENT_FAULT * evel_new_fault(const char * const condition,
+                             const char * const specific_problem,
+                             EVEL_EVENT_PRIORITIES priority,
+                             EVEL_SEVERITIES severity);
+
+/**************************************************************************//**
+ * Free a Fault.
+ *
+ * Free off the Fault supplied.  Will free all the contained allocated memory.
+ *
+ * @note It does not free the Fault itself, since that may be part of a
+ * larger structure.
+ *****************************************************************************/
+void evel_free_fault(EVENT_FAULT * event);
+
+
+/**************************************************************************//**
+ * Set the Alarm Interface A property of the Fault.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param fault      Pointer to the fault.
+ * @param interface  The Alarm Interface A to be set. ASCIIZ string. The caller
+ *                   does not need to preserve the value once the function
+ *                   returns.
+ *****************************************************************************/
+void evel_fault_interface_set(EVENT_FAULT * fault,
+                              const char * const interface);
+
+/**************************************************************************//**
+ * Add an additional value name/value pair to the Fault.
+ *
+ * The name and value are null delimited ASCII strings.  The library takes
+ * a copy so the caller does not have to preserve values after the function
+ * returns.
+ *
+ * @param fault     Pointer to the fault.
+ * @param name      ASCIIZ string with the attribute's name.
+ * @param value     ASCIIZ string with the attribute's value.
+ *****************************************************************************/
+void evel_fault_addl_info_add(EVENT_FAULT * fault, char * name, char * value);
+
+/**************************************************************************//**
+ * Set the Event Type property of the Fault.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param fault      Pointer to the fault.
+ * @param type       The Event Type to be set. ASCIIZ string. The caller
+ *                   does not need to preserve the value once the function
+ *                   returns.
+ *****************************************************************************/
+void evel_fault_type_set(EVENT_FAULT * fault, const char * const type);
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*                                                                           */
+/*   MEASUREMENT                                                             */
+/*                                                                           */
+/*****************************************************************************/
+/*****************************************************************************/
+
+/**************************************************************************//**
+ * Create a new Measurement event.
+ *
+ * @note    The mandatory fields on the Measurement must be supplied to this
+ *          factory function and are immutable once set.  Optional fields have
+ *          explicit setter functions, but again values may only be set once so
+ *          that the Measurement has immutable properties.
+ *
+ * @param   measurement_interval
+ *
+ * @returns pointer to the newly manufactured ::EVENT_MEASUREMENT.  If the
+ *          event is not used (i.e. posted) it must be released using
+ *          ::evel_free_event.
+ * @retval  NULL  Failed to create the event.
+ *****************************************************************************/
+EVENT_MEASUREMENT * evel_new_measurement(double measurement_interval);
+
+/**************************************************************************//**
+ * Free a Measurement.
+ *
+ * Free off the Measurement supplied.  Will free all the contained allocated
+ * memory.
+ *
+ * @note It does not free the Measurement itself, since that may be part of a
+ * larger structure.
+ *****************************************************************************/
+void evel_free_measurement(EVENT_MEASUREMENT * event);
+
+/**************************************************************************//**
+ * Set the Event Type property of the Measurement.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param measurement Pointer to the Measurement.
+ * @param type        The Event Type to be set. ASCIIZ string. The caller
+ *                    does not need to preserve the value once the function
+ *                    returns.
+ *****************************************************************************/
+void evel_measurement_type_set(EVENT_MEASUREMENT * measurement,
+                               const char * const type);
+
+/**************************************************************************//**
+ * Set the Concurrent Sessions property of the Measurement.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param measurement         Pointer to the Measurement.
+ * @param concurrent_sessions The Concurrent Sessions to be set.
+ *****************************************************************************/
+void evel_measurement_conc_sess_set(EVENT_MEASUREMENT * measurement,
+                                    int concurrent_sessions);
+
+/**************************************************************************//**
+ * Set the Configured Entities property of the Measurement.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param measurement         Pointer to the Measurement.
+ * @param configured_entities The Configured Entities to be set.
+ *****************************************************************************/
+void evel_measurement_cfg_ents_set(EVENT_MEASUREMENT * measurement,
+                                   int configured_entities);
+
+/**************************************************************************//**
+ * Add an additional set of Errors to the Measurement.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param measurement       Pointer to the measurement.
+ * @param receive_discards  The number of receive discards.
+ * @param receive_errors    The number of receive errors.
+ * @param transmit_discards The number of transmit discards.
+ * @param transmit_errors   The number of transmit errors.
+ *****************************************************************************/
+void evel_measurement_errors_set(EVENT_MEASUREMENT * measurement,
+                                 int receive_discards,
+                                 int receive_errors,
+                                 int transmit_discards,
+                                 int transmit_errors);
+
+/**************************************************************************//**
+ * Set the Mean Request Latency property of the Measurement.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param measurement          Pointer to the Measurement.
+ * @param mean_request_latency The Mean Request Latency to be set.
+ *****************************************************************************/
+void evel_measurement_mean_req_lat_set(EVENT_MEASUREMENT * measurement,
+                                       double mean_request_latency);
+
+/**************************************************************************//**
+ * Set the Memory Configured property of the Measurement.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param measurement       Pointer to the Measurement.
+ * @param memory_configured The Memory Configured to be set.
+ *****************************************************************************/
+void evel_measurement_mem_cfg_set(EVENT_MEASUREMENT * measurement,
+                                  double memory_configured);
+
+/**************************************************************************//**
+ * Set the Memory Used property of the Measurement.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param measurement       Pointer to the Measurement.
+ * @param memory_used The Memory Used to be set.
+ *****************************************************************************/
+void evel_measurement_mem_used_set(EVENT_MEASUREMENT * measurement,
+                                   double memory_used);
+
+/**************************************************************************//**
+ * Set the Request Rate property of the Measurement.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param measurement  Pointer to the Measurement.
+ * @param request_rate The Request Rate to be set.
+ *****************************************************************************/
+void evel_measurement_request_rate_set(EVENT_MEASUREMENT * measurement,
+                                       int request_rate);
+
+/**************************************************************************//**
+ * Add an additional CPU usage value name/value pair to the Measurement.
+ *
+ * The name and value are null delimited ASCII strings.  The library takes
+ * a copy so the caller does not have to preserve values after the function
+ * returns.
+ *
+ * @param measurement   Pointer to the measurement.
+ * @param id            ASCIIZ string with the CPU's identifier.
+ * @param usage         CPU utilization.
+ *****************************************************************************/
+void evel_measurement_cpu_use_add(EVENT_MEASUREMENT * measurement,
+                                  char * id, double usage);
+
+/**************************************************************************//**
+ * Add an additional File System usage value name/value pair to the
+ * Measurement.
+ *
+ * The filesystem_name is null delimited ASCII string.  The library takes a
+ * copy so the caller does not have to preserve values after the function
+ * returns.
+ *
+ * @param measurement     Pointer to the measurement.
+ * @param filesystem_name   ASCIIZ string with the file-system's UUID.
+ * @param block_configured  Block storage configured.
+ * @param block_used        Block storage in use.
+ * @param block_iops        Block storage IOPS.
+ * @param ephemeral_configured  Ephemeral storage configured.
+ * @param ephemeral_used        Ephemeral storage in use.
+ * @param ephemeral_iops        Ephemeral storage IOPS.
+ *****************************************************************************/
+void evel_measurement_fsys_use_add(EVENT_MEASUREMENT * measurement,
+                                   char * filesystem_name,
+                                   double block_configured,
+                                   double block_used,
+                                   int block_iops,
+                                   double ephemeral_configured,
+                                   double ephemeral_used,
+                                   int ephemeral_iops);
+
+/**************************************************************************//**
+ * Add a Feature usage value name/value pair to the Measurement.
+ *
+ * The name is null delimited ASCII string.  The library takes
+ * a copy so the caller does not have to preserve values after the function
+ * returns.
+ *
+ * @param measurement     Pointer to the measurement.
+ * @param feature         ASCIIZ string with the feature's name.
+ * @param utilization     Utilization of the feature.
+ *****************************************************************************/
+void evel_measurement_feature_use_add(EVENT_MEASUREMENT * measurement,
+                                      char * feature,
+                                      int utilization);
+
+/**************************************************************************//**
+ * Add a Additional Measurement value name/value pair to the Measurement.
+ *
+ * The name is null delimited ASCII string.  The library takes
+ * a copy so the caller does not have to preserve values after the function
+ * returns.
+ *
+ * @param measurement   Pointer to the Measurement.
+ * @param group    ASCIIZ string with the measurement group's name.
+ * @param name     ASCIIZ string containing the measurement's name.
+ * @param name     ASCIIZ string containing the measurement's value.
+ *****************************************************************************/
+void evel_measurement_custom_measurement_add(EVENT_MEASUREMENT * measurement,
+                                             const char * const group,
+                                             const char * const name,
+                                             const char * const value);
+
+/**************************************************************************//**
+ * Add a Codec usage value name/value pair to the Measurement.
+ *
+ * The name is null delimited ASCII string.  The library takes
+ * a copy so the caller does not have to preserve values after the function
+ * returns.
+ *
+ * @param measurement     Pointer to the measurement.
+ * @param codec           ASCIIZ string with the codec's name.
+ * @param utilization     Utilization of the feature.
+ *****************************************************************************/
+void evel_measurement_codec_use_add(EVENT_MEASUREMENT * measurement,
+                                    char * codec,
+                                    int utilization);
+
+/**************************************************************************//**
+}
+ * Set the Aggregate CPU Use property of the Measurement.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param measurement   Pointer to the measurement.
+ * @param cpu_use       The CPU use to set.
+ *****************************************************************************/
+void evel_measurement_agg_cpu_use_set(EVENT_MEASUREMENT * measurement,
+                                      double cpu_use);
+
+/**************************************************************************//**
+ * Set the Media Ports in Use property of the Measurement.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param measurement         Pointer to the measurement.
+ * @param media_ports_in_use  The media port usage to set.
+ *****************************************************************************/
+void evel_measurement_media_port_use_set(EVENT_MEASUREMENT * measurement,
+                                         int media_ports_in_use);
+
+/**************************************************************************//**
+ * Set the VNFC Scaling Metric property of the Measurement.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param measurement     Pointer to the measurement.
+ * @param scaling_metric  The scaling metric to set.
+ *****************************************************************************/
+void evel_measurement_vnfc_scaling_metric_set(EVENT_MEASUREMENT * measurement,
+                                              double scaling_metric);
+
+/**************************************************************************//**
+ * Create a new Latency Bucket to be added to a Measurement event.
+ *
+ * @note    The mandatory fields on the ::MEASUREMENT_LATENCY_BUCKET must be
+ *          supplied to this factory function and are immutable once set.
+ *          Optional fields have explicit setter functions, but again values
+ *          may only be set once so that the ::MEASUREMENT_LATENCY_BUCKET has
+ *          immutable properties.
+ *
+ * @param count         Count of events in this bucket.
+ *
+ * @returns pointer to the newly manufactured ::MEASUREMENT_LATENCY_BUCKET.
+ * @retval  NULL  Failed to create the Latency Bucket.
+ *****************************************************************************/
+MEASUREMENT_LATENCY_BUCKET * evel_new_meas_latency_bucket(const int count);
+
+/**************************************************************************//**
+ * Set the High End property of the Measurement Latency Bucket.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param bucket        Pointer to the Measurement Latency Bucket.
+ * @param high_end      High end of the bucket's range.
+ *****************************************************************************/
+void evel_meas_latency_bucket_high_end_set(
+                                     MEASUREMENT_LATENCY_BUCKET * const bucket,
+                                     const double high_end);
+
+/**************************************************************************//**
+ * Set the Low End property of the Measurement Latency Bucket.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param bucket        Pointer to the Measurement Latency Bucket.
+ * @param low_end       Low end of the bucket's range.
+ *****************************************************************************/
+void evel_meas_latency_bucket_low_end_set(
+                                     MEASUREMENT_LATENCY_BUCKET * const bucket,
+                                     const double low_end);
+
+/**************************************************************************//**
+ * Add an additional Measurement Latency Bucket to the specified event.
+ *
+ * @param measurement   Pointer to the Measurement event.
+ * @param bucket        Pointer to the Measurement Latency Bucket to add.
+ *****************************************************************************/
+void evel_meas_latency_bucket_add(EVENT_MEASUREMENT * const measurement,
+                                  MEASUREMENT_LATENCY_BUCKET * const bucket);
+
+/**************************************************************************//**
+ * Add an additional Latency Distribution bucket to the Measurement.
+ *
+ * This function implements the previous API, purely for convenience.
+ *
+ * @param measurement   Pointer to the measurement.
+ * @param low_end       Low end of the bucket's range.
+ * @param high_end      High end of the bucket's range.
+ * @param count         Count of events in this bucket.
+ *****************************************************************************/
+void evel_measurement_latency_add(EVENT_MEASUREMENT * const measurement,
+                                  const double low_end,
+                                  const double high_end,
+                                  const int count);
+
+/**************************************************************************//**
+ * Create a new vNIC Use to be added to a Measurement event.
+ *
+ * @note    The mandatory fields on the ::MEASUREMENT_VNIC_USE must be supplied
+ *          to this factory function and are immutable once set. Optional
+ *          fields have explicit setter functions, but again values may only be
+ *          set once so that the ::MEASUREMENT_VNIC_USE has immutable
+ *          properties.
+ *
+ * @param vnic_id               ASCIIZ string with the vNIC's ID.
+ * @param packets_in            Total packets received.
+ * @param packets_out           Total packets transmitted.
+ * @param bytes_in              Total bytes received.
+ * @param bytes_out             Total bytes transmitted.
+ *
+ * @returns pointer to the newly manufactured ::MEASUREMENT_VNIC_USE.
+ *          If the structure is not used it must be released using
+ *          ::evel_free_measurement_vnic_use.
+ * @retval  NULL  Failed to create the vNIC Use.
+ *****************************************************************************/
+MEASUREMENT_VNIC_USE * evel_new_measurement_vnic_use(char * const vnic_id,
+                                                     const int packets_in,
+                                                     const int packets_out,
+                                                     const int bytes_in,
+                                                     const int bytes_out);
+
+/**************************************************************************//**
+ * Free a vNIC Use.
+ *
+ * Free off the ::MEASUREMENT_VNIC_USE supplied.  Will free all the contained
+ * allocated memory.
+ *
+ * @note It does not free the vNIC Use itself, since that may be part of a
+ * larger structure.
+ *****************************************************************************/
+void evel_free_measurement_vnic_use(MEASUREMENT_VNIC_USE * const vnic_use);
+
+/**************************************************************************//**
+ * Set the Broadcast Packets Received property of the vNIC Use.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param vnic_use      Pointer to the vNIC Use.
+ * @param broadcast_packets_in
+ *                      Broadcast packets received.
+ *****************************************************************************/
+void evel_vnic_use_bcast_pkt_in_set(MEASUREMENT_VNIC_USE * const vnic_use,
+                                    const int broadcast_packets_in);
+
+/**************************************************************************//**
+ * Set the Broadcast Packets Transmitted property of the vNIC Use.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param vnic_use      Pointer to the vNIC Use.
+ * @param broadcast_packets_out
+ *                      Broadcast packets transmitted.
+ *****************************************************************************/
+void evel_vnic_use_bcast_pkt_out_set(MEASUREMENT_VNIC_USE * const vnic_use,
+                                     const int broadcast_packets_out);
+
+/**************************************************************************//**
+ * Set the Multicast Packets Received property of the vNIC Use.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param vnic_use      Pointer to the vNIC Use.
+ * @param multicast_packets_in
+ *                      Multicast packets received.
+ *****************************************************************************/
+void evel_vnic_use_mcast_pkt_in_set(MEASUREMENT_VNIC_USE * const vnic_use,
+                                    const int multicast_packets_in);
+
+/**************************************************************************//**
+ * Set the Multicast Packets Transmitted property of the vNIC Use.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param vnic_use      Pointer to the vNIC Use.
+ * @param multicast_packets_out
+ *                      Multicast packets transmitted.
+ *****************************************************************************/
+void evel_vnic_use_mcast_pkt_out_set(MEASUREMENT_VNIC_USE * const vnic_use,
+                                     const int multicast_packets_out);
+
+/**************************************************************************//**
+ * Set the Unicast Packets Received property of the vNIC Use.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param vnic_use      Pointer to the vNIC Use.
+ * @param unicast_packets_in
+ *                      Unicast packets received.
+ *****************************************************************************/
+void evel_vnic_use_ucast_pkt_in_set(MEASUREMENT_VNIC_USE * const vnic_use,
+                                    const int unicast_packets_in);
+
+/**************************************************************************//**
+ * Set the Unicast Packets Transmitted property of the vNIC Use.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param vnic_use      Pointer to the vNIC Use.
+ * @param unicast_packets_out
+ *                      Unicast packets transmitted.
+ *****************************************************************************/
+void evel_vnic_use_ucast_pkt_out_set(MEASUREMENT_VNIC_USE * const vnic_use,
+                                     const int unicast_packets_out);
+
+/**************************************************************************//**
+ * Add an additional vNIC Use to the specified Measurement event.
+ *
+ * @param measurement   Pointer to the measurement.
+ * @param vnic_use      Pointer to the vNIC Use to add.
+ *****************************************************************************/
+void evel_meas_vnic_use_add(EVENT_MEASUREMENT * const measurement,
+                            MEASUREMENT_VNIC_USE * const vnic_use);
+
+/**************************************************************************//**
+ * Add an additional vNIC usage record Measurement.
+ *
+ * This function implements the previous API, purely for convenience.
+ *
+ * The ID is null delimited ASCII string.  The library takes a copy so the
+ * caller does not have to preserve values after the function returns.
+ *
+ * @param measurement           Pointer to the measurement.
+ * @param vnic_id               ASCIIZ string with the vNIC's ID.
+ * @param packets_in            Total packets received.
+ * @param packets_out           Total packets transmitted.
+ * @param broadcast_packets_in  Broadcast packets received.
+ * @param broadcast_packets_out Broadcast packets transmitted.
+ * @param bytes_in              Total bytes received.
+ * @param bytes_out             Total bytes transmitted.
+ * @param multicast_packets_in  Multicast packets received.
+ * @param multicast_packets_out Multicast packets transmitted.
+ * @param unicast_packets_in    Unicast packets received.
+ * @param unicast_packets_out   Unicast packets transmitted.
+ *****************************************************************************/
+void evel_measurement_vnic_use_add(EVENT_MEASUREMENT * const measurement,
+                                   char * const vnic_id,
+                                   const int packets_in,
+                                   const int packets_out,
+                                   const int broadcast_packets_in,
+                                   const int broadcast_packets_out,
+                                   const int bytes_in,
+                                   const int bytes_out,
+                                   const int multicast_packets_in,
+                                   const int multicast_packets_out,
+                                   const int unicast_packets_in,
+                                   const int unicast_packets_out);
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*                                                                           */
+/*   REPORT                                                                  */
+/*                                                                           */
+/*****************************************************************************/
+/*****************************************************************************/
+
+/**************************************************************************//**
+ * Create a new Report event.
+ *
+ * @note    The mandatory fields on the Report must be supplied to this
+ *          factory function and are immutable once set.  Optional fields have
+ *          explicit setter functions, but again values may only be set once so
+ *          that the Report has immutable properties.
+ *
+ * @param   measurement_interval
+ *
+ * @returns pointer to the newly manufactured ::EVENT_REPORT.  If the event is
+ *          not used (i.e. posted) it must be released using
+ *          ::evel_free_report.
+ * @retval  NULL  Failed to create the event.
+ *****************************************************************************/
+EVENT_REPORT * evel_new_report(double measurement_interval);
+
+/**************************************************************************//**
+ * Free a Report.
+ *
+ * Free off the Report supplied.  Will free all the contained allocated memory.
+ *
+ * @note It does not free the Report itself, since that may be part of a
+ * larger structure.
+ *****************************************************************************/
+void evel_free_report(EVENT_REPORT * event);
+
+/**************************************************************************//**
+ * Set the Event Type property of the Report.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param report Pointer to the Report.
+ * @param type        The Event Type to be set. ASCIIZ string. The caller
+ *                    does not need to preserve the value once the function
+ *                    returns.
+ *****************************************************************************/
+void evel_report_type_set(EVENT_REPORT * report, const char * const type);
+
+/**************************************************************************//**
+ * Add a Feature usage value name/value pair to the Report.
+ *
+ * The name is null delimited ASCII string.  The library takes
+ * a copy so the caller does not have to preserve values after the function
+ * returns.
+ *
+ * @param report          Pointer to the report.
+ * @param feature         ASCIIZ string with the feature's name.
+ * @param utilization     Utilization of the feature.
+ *****************************************************************************/
+void evel_report_feature_use_add(EVENT_REPORT * report,
+                                 char * feature,
+                                 int utilization);
+
+/**************************************************************************//**
+ * Add a Additional Measurement value name/value pair to the Report.
+ *
+ * The name is null delimited ASCII string.  The library takes
+ * a copy so the caller does not have to preserve values after the function
+ * returns.
+ *
+ * @param report   Pointer to the report.
+ * @param group    ASCIIZ string with the measurement group's name.
+ * @param name     ASCIIZ string containing the measurement's name.
+ * @param value    ASCIIZ string containing the measurement's value.
+ *****************************************************************************/
+void evel_report_custom_measurement_add(EVENT_REPORT * report,
+                                        const char * const group,
+                                        const char * const name,
+                                        const char * const value);
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*                                                                           */
+/*   MOBILE_FLOW                                                             */
+/*                                                                           */
+/*****************************************************************************/
+/*****************************************************************************/
+
+/**************************************************************************//**
+ * Create a new Mobile Flow event.
+ *
+ * @note    The mandatory fields on the Mobile Flow must be supplied to this
+ *          factory function and are immutable once set.  Optional fields have
+ *          explicit setter functions, but again values may only be set once so
+ *          that the Mobile Flow has immutable properties.
+ *
+ * @param   flow_direction
+ * @param   gtp_per_flow_metrics
+ * @param   ip_protocol_type
+ * @param   ip_version
+ * @param   other_endpoint_ip_address
+ * @param   other_endpoint_port
+ * @param   reporting_endpoint_ip_addr
+ * @param   reporting_endpoint_port
+ *
+ * @returns pointer to the newly manufactured ::EVENT_MOBILE_FLOW.  If the
+ *          event is not used (i.e. posted) it must be released using
+ *          ::evel_free_mobile_flow.
+ * @retval  NULL  Failed to create the event.
+ *****************************************************************************/
+EVENT_MOBILE_FLOW * evel_new_mobile_flow(
+                      const char * const flow_direction,
+                      MOBILE_GTP_PER_FLOW_METRICS * gtp_per_flow_metrics,
+                      const char * const ip_protocol_type,
+                      const char * const ip_version,
+                      const char * const other_endpoint_ip_address,
+                      int other_endpoint_port,
+                      const char * const reporting_endpoint_ip_addr,
+                      int reporting_endpoint_port);
+
+/**************************************************************************//**
+ * Free a Mobile Flow.
+ *
+ * Free off the Mobile Flow supplied.  Will free all the contained allocated
+ * memory.
+ *
+ * @note It does not free the Mobile Flow itself, since that may be part of a
+ * larger structure.
+ *****************************************************************************/
+void evel_free_mobile_flow(EVENT_MOBILE_FLOW * event);
+
+/**************************************************************************//**
+ * Set the Event Type property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param type        The Event Type to be set. ASCIIZ string. The caller
+ *                    does not need to preserve the value once the function
+ *                    returns.
+ *****************************************************************************/
+void evel_mobile_flow_type_set(EVENT_MOBILE_FLOW * mobile_flow,
+                               const char * const type);
+
+/**************************************************************************//**
+ * Set the Application Type property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param type        The Application Type to be set. ASCIIZ string. The caller
+ *                    does not need to preserve the value once the function
+ *                    returns.
+ *****************************************************************************/
+void evel_mobile_flow_app_type_set(EVENT_MOBILE_FLOW * mobile_flow,
+                                   const char * const type);
+
+/**************************************************************************//**
+ * Set the Application Protocol Type property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param type        The Application Protocol Type to be set. ASCIIZ string.
+ *                    The caller does not need to preserve the value once the
+ *                    function returns.
+ *****************************************************************************/
+void evel_mobile_flow_app_prot_type_set(EVENT_MOBILE_FLOW * mobile_flow,
+                                        const char * const type);
+
+/**************************************************************************//**
+ * Set the Application Protocol Version property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param version     The Application Protocol Version to be set. ASCIIZ
+ *                    string.  The caller does not need to preserve the value
+ *                    once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_app_prot_ver_set(EVENT_MOBILE_FLOW * mobile_flow,
+                                       const char * const version);
+
+/**************************************************************************//**
+ * Set the CID property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param cid         The CID to be set. ASCIIZ string.  The caller does not
+ *                    need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_cid_set(EVENT_MOBILE_FLOW * mobile_flow,
+                              const char * const cid);
+
+/**************************************************************************//**
+ * Set the Connection Type property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param type        The Connection Type to be set. ASCIIZ string. The caller
+ *                    does not need to preserve the value once the function
+ *                    returns.
+ *****************************************************************************/
+void evel_mobile_flow_con_type_set(EVENT_MOBILE_FLOW * mobile_flow,
+                                   const char * const type);
+
+/**************************************************************************//**
+ * Set the ECGI property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param ecgi        The ECGI to be set. ASCIIZ string.  The caller does not
+ *                    need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_ecgi_set(EVENT_MOBILE_FLOW * mobile_flow,
+                               const char * const ecgi);
+
+/**************************************************************************//**
+ * Set the GTP Protocol Type property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param type        The GTP Protocol Type to be set. ASCIIZ string.  The
+ *                    caller does not need to preserve the value once the
+ *                    function returns.
+ *****************************************************************************/
+void evel_mobile_flow_gtp_prot_type_set(EVENT_MOBILE_FLOW * mobile_flow,
+                                        const char * const type);
+
+/**************************************************************************//**
+ * Set the GTP Protocol Version property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param version     The GTP Protocol Version to be set. ASCIIZ string.  The
+ *                    caller does not need to preserve the value once the
+ *                    function returns.
+ *****************************************************************************/
+void evel_mobile_flow_gtp_prot_ver_set(EVENT_MOBILE_FLOW * mobile_flow,
+                                       const char * const version);
+
+/**************************************************************************//**
+ * Set the HTTP Header property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param header      The HTTP header to be set. ASCIIZ string. The caller does
+ *                    not need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_http_header_set(EVENT_MOBILE_FLOW * mobile_flow,
+                                      const char * const header);
+
+/**************************************************************************//**
+ * Set the IMEI property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param imei        The IMEI to be set. ASCIIZ string.  The caller does not
+ *                    need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_imei_set(EVENT_MOBILE_FLOW * mobile_flow,
+                               const char * const imei);
+
+/**************************************************************************//**
+ * Set the IMSI property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param imsi        The IMSI to be set. ASCIIZ string.  The caller does not
+ *                    need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_imsi_set(EVENT_MOBILE_FLOW * mobile_flow,
+                               const char * const imsi);
+
+/**************************************************************************//**
+ * Set the LAC property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param lac         The LAC to be set. ASCIIZ string.  The caller does not
+ *                    need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_lac_set(EVENT_MOBILE_FLOW * mobile_flow,
+                              const char * const lac);
+
+/**************************************************************************//**
+ * Set the MCC property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param mcc         The MCC to be set. ASCIIZ string.  The caller does not
+ *                    need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_mcc_set(EVENT_MOBILE_FLOW * mobile_flow,
+                              const char * const mcc);
+
+/**************************************************************************//**
+ * Set the MNC property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param mnc         The MNC to be set. ASCIIZ string.  The caller does not
+ *                    need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_mnc_set(EVENT_MOBILE_FLOW * mobile_flow,
+                              const char * const mnc);
+
+/**************************************************************************//**
+ * Set the MSISDN property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param msisdn      The MSISDN to be set. ASCIIZ string.  The caller does not
+ *                    need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_msisdn_set(EVENT_MOBILE_FLOW * mobile_flow,
+                                 const char * const msisdn);
+
+/**************************************************************************//**
+ * Set the Other Functional Role property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param role        The Other Functional Role to be set. ASCIIZ string. The
+ *                    caller does not need to preserve the value once the
+ *                    function returns.
+ *****************************************************************************/
+void evel_mobile_flow_other_func_role_set(EVENT_MOBILE_FLOW * mobile_flow,
+                                          const char * const role);
+
+/**************************************************************************//**
+ * Set the RAC property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param rac         The RAC to be set. ASCIIZ string.  The caller does not
+ *                    need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_rac_set(EVENT_MOBILE_FLOW * mobile_flow,
+                              const char * const rac);
+
+/**************************************************************************//**
+ * Set the Radio Access Technology property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param tech        The Radio Access Technology to be set. ASCIIZ string. The
+ *                    caller does not need to preserve the value once the
+ *                    function returns.
+ *****************************************************************************/
+void evel_mobile_flow_radio_acc_tech_set(EVENT_MOBILE_FLOW * mobile_flow,
+                                         const char * const tech);
+
+/**************************************************************************//**
+ * Set the SAC property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param sac         The SAC to be set. ASCIIZ string.  The caller does not
+ *                    need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_sac_set(EVENT_MOBILE_FLOW * mobile_flow,
+                              const char * const sac);
+
+/**************************************************************************//**
+ * Set the Sampling Algorithm property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param algorithm   The Sampling Algorithm to be set.
+ *****************************************************************************/
+void evel_mobile_flow_samp_alg_set(EVENT_MOBILE_FLOW * mobile_flow,
+                                   int algorithm);
+
+/**************************************************************************//**
+ * Set the TAC property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param tac         The TAC to be set. ASCIIZ string.  The caller does not
+ *                    need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_tac_set(EVENT_MOBILE_FLOW * mobile_flow,
+                              const char * const tac);
+
+/**************************************************************************//**
+ * Set the Tunnel ID property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param tunnel_id   The Tunnel ID to be set. ASCIIZ string.  The caller does
+ *                    not need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_tunnel_id_set(EVENT_MOBILE_FLOW * mobile_flow,
+                                    const char * const tunnel_id);
+
+/**************************************************************************//**
+ * Set the VLAN ID property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param vlan_id     The VLAN ID to be set. ASCIIZ string.  The caller does
+ *                    not need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_vlan_id_set(EVENT_MOBILE_FLOW * mobile_flow,
+                                  const char * const vlan_id);
+
+/**************************************************************************//**
+ * Create a new Mobile GTP Per Flow Metrics.
+ *
+ * @note    The mandatory fields on the Mobile GTP Per Flow Metrics must be
+ *          supplied to this factory function and are immutable once set.
+ *          Optional fields have explicit setter functions, but again values
+ *          may only be set once so that the Mobile GTP Per Flow Metrics has
+ *          immutable properties.
+ *
+ * @param   avg_bit_error_rate
+ * @param   avg_packet_delay_variation
+ * @param   avg_packet_latency
+ * @param   avg_receive_throughput
+ * @param   avg_transmit_throughput
+ * @param   flow_activation_epoch
+ * @param   flow_activation_microsec
+ * @param   flow_deactivation_epoch
+ * @param   flow_deactivation_microsec
+ * @param   flow_deactivation_time
+ * @param   flow_status
+ * @param   max_packet_delay_variation
+ * @param   num_activation_failures
+ * @param   num_bit_errors
+ * @param   num_bytes_received
+ * @param   num_bytes_transmitted
+ * @param   num_dropped_packets
+ * @param   num_l7_bytes_received
+ * @param   num_l7_bytes_transmitted
+ * @param   num_lost_packets
+ * @param   num_out_of_order_packets
+ * @param   num_packet_errors
+ * @param   num_packets_received_excl_retrans
+ * @param   num_packets_received_incl_retrans
+ * @param   num_packets_transmitted_incl_retrans
+ * @param   num_retries
+ * @param   num_timeouts
+ * @param   num_tunneled_l7_bytes_received
+ * @param   round_trip_time
+ * @param   time_to_first_byte
+ *
+ * @returns pointer to the newly manufactured ::MOBILE_GTP_PER_FLOW_METRICS.
+ *          If the structure is not used it must be released using
+ *          ::evel_free_mobile_gtp_flow_metrics.
+ * @retval  NULL  Failed to create the event.
+ *****************************************************************************/
+MOBILE_GTP_PER_FLOW_METRICS * evel_new_mobile_gtp_flow_metrics(
+                                      double avg_bit_error_rate,
+                                      double avg_packet_delay_variation,
+                                      int avg_packet_latency,
+                                      int avg_receive_throughput,
+                                      int avg_transmit_throughput,
+                                      int flow_activation_epoch,
+                                      int flow_activation_microsec,
+                                      int flow_deactivation_epoch,
+                                      int flow_deactivation_microsec,
+                                      time_t flow_deactivation_time,
+                                      const char * const flow_status,
+                                      int max_packet_delay_variation,
+                                      int num_activation_failures,
+                                      int num_bit_errors,
+                                      int num_bytes_received,
+                                      int num_bytes_transmitted,
+                                      int num_dropped_packets,
+                                      int num_l7_bytes_received,
+                                      int num_l7_bytes_transmitted,
+                                      int num_lost_packets,
+                                      int num_out_of_order_packets,
+                                      int num_packet_errors,
+                                      int num_packets_received_excl_retrans,
+                                      int num_packets_received_incl_retrans,
+                                      int num_packets_transmitted_incl_retrans,
+                                      int num_retries,
+                                      int num_timeouts,
+                                      int num_tunneled_l7_bytes_received,
+                                      int round_trip_time,
+                                      int time_to_first_byte);
+
+/**************************************************************************//**
+ * Free a Mobile GTP Per Flow Metrics.
+ *
+ * Free off the Mobile GTP Per Flow Metrics supplied.  Will free all the
+ * contained allocated memory.
+ *
+ * @note It does not free the Mobile GTP Per Flow Metrics itself, since that
+ * may be part of a larger structure.
+ *****************************************************************************/
+void evel_free_mobile_gtp_flow_metrics(MOBILE_GTP_PER_FLOW_METRICS * metrics);
+
+/**************************************************************************//**
+ * Set the Duration of Connection Failed Status property of the Mobile GTP Per
+ * Flow Metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param duration    The Duration of Connection Failed Status to be set.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_dur_con_fail_set(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         int duration);
+
+/**************************************************************************//**
+ * Set the Duration of Tunnel Failed Status property of the Mobile GTP Per Flow
+ * Metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param duration    The Duration of Tunnel Failed Status to be set.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_dur_tun_fail_set(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         int duration);
+
+/**************************************************************************//**
+ * Set the Activated By property of the Mobile GTP Per Flow metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param act_by      The Activated By to be set.  ASCIIZ string. The caller
+ *                    does not need to preserve the value once the function
+ *                    returns.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_act_by_set(MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                        const char * const act_by);
+
+/**************************************************************************//**
+ * Set the Activation Time property of the Mobile GTP Per Flow metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param act_time    The Activation Time to be set.  ASCIIZ string. The caller
+ *                    does not need to preserve the value once the function
+ *                    returns.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_act_time_set(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         time_t act_time);
+
+/**************************************************************************//**
+ * Set the Deactivated By property of the Mobile GTP Per Flow metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param deact_by    The Deactivated By to be set.  ASCIIZ string. The caller
+ *                    does not need to preserve the value once the function
+ *                    returns.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_deact_by_set(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         const char * const deact_by);
+
+/**************************************************************************//**
+ * Set the GTP Connection Status property of the Mobile GTP Per Flow metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param status      The GTP Connection Status to be set.  ASCIIZ string. The
+ *                    caller does not need to preserve the value once the
+ *                    function returns.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_con_status_set(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         const char * const status);
+
+/**************************************************************************//**
+ * Set the GTP Tunnel Status property of the Mobile GTP Per Flow metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param status      The GTP Tunnel Status to be set.  ASCIIZ string. The
+ *                    caller does not need to preserve the value once the
+ *                    function returns.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_tun_status_set(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         const char * const status);
+
+/**************************************************************************//**
+ * Set an IP Type-of-Service count property of the Mobile GTP Per Flow metrics.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param index       The index of the IP Type-of-Service.
+ * @param count       The count.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_iptos_set(MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                       int index,
+                                       int count);
+
+/**************************************************************************//**
+ * Set the Large Packet Round-Trip Time property of the Mobile GTP Per Flow
+ * Metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param rtt         The Large Packet Round-Trip Time to be set.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_large_pkt_rtt_set(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         int rtt);
+
+/**************************************************************************//**
+ * Set the Large Packet Threshold property of the Mobile GTP Per Flow Metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param threshold   The Large Packet Threshold to be set.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_large_pkt_thresh_set(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         double threshold);
+
+/**************************************************************************//**
+ * Set the Max Receive Bit Rate property of the Mobile GTP Per Flow Metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param rate        The Max Receive Bit Rate to be set.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_max_rcv_bit_rate_set(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         int rate);
+
+/**************************************************************************//**
+ * Set the Max Transmit Bit Rate property of the Mobile GTP Per Flow Metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param rate        The Max Transmit Bit Rate to be set.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_max_trx_bit_rate_set(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         int rate);
+
+/**************************************************************************//**
+ * Set the Number of GTP Echo Failures property of the Mobile GTP Per Flow
+ * Metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param num         The Number of GTP Echo Failures to be set.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_num_echo_fail_set(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         int num);
+
+/**************************************************************************//**
+ * Set the Number of GTP Tunnel Errors property of the Mobile GTP Per Flow
+ * Metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param num         The Number of GTP Tunnel Errors to be set.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_num_tun_fail_set(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         int num);
+
+/**************************************************************************//**
+ * Set the Number of HTTP Errors property of the Mobile GTP Per Flow Metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param num         The Number of HTTP Errors to be set.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_num_http_errors_set(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         int num);
+
+/**************************************************************************//**
+ * Add a TCP flag count to the metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics       Pointer to the Mobile GTP Per Flow Metrics.
+ * @param tcp_flag      The TCP flag count to be updated.
+ * @param count         The associated flag count.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_tcp_flag_count_add(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         const EVEL_TCP_FLAGS tcp_flag,
+                                         const int count);
+
+/**************************************************************************//**
+ * Add a QCI COS count to the metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics       Pointer to the Mobile GTP Per Flow Metrics.
+ * @param qci_cos       The QCI COS count to be updated.
+ * @param count         The associated QCI COS count.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_qci_cos_count_add(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         const EVEL_QCI_COS_TYPES qci_cos,
+                                         const int count);
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*                                                                           */
+/*   SERVICE EVENTS                                                          */
+/*                                                                           */
+/*****************************************************************************/
+/*****************************************************************************/
+
+/**************************************************************************//**
+ * Create a new Service event.
+ *
+ * @note    The mandatory fields on the Service must be supplied to
+ *          this factory function and are immutable once set.  Optional fields
+ *          have explicit setter functions, but again values may only be set
+ *          once so that the event has immutable properties.
+ * @param vendor_id     The vendor id to encode in the event instance id.
+ * @param event_id      The vendor event id to encode in the event instance id.
+ * @returns pointer to the newly manufactured ::EVENT_SERVICE.  If the event
+ *          is not used (i.e. posted) it must be released using
+ *          ::evel_free_service.
+ * @retval  NULL  Failed to create the event.
+ *****************************************************************************/
+EVENT_SERVICE * evel_new_service(const char * const vendor_id,
+                                 const char * const event_id);
+
+/**************************************************************************//**
+ * Free a Service Events event.
+ *
+ * Free off the event supplied.  Will free all the contained allocated memory.
+ *
+ * @note It does not free the event itself, since that may be part of a larger
+ * structure.
+ *****************************************************************************/
+void evel_free_service(EVENT_SERVICE * const event);
+
+/**************************************************************************//**
+ * Set the Event Type property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param type          The Event Type to be set. ASCIIZ string. The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_service_type_set(EVENT_SERVICE * const event,
+                           const char * const type);
+
+/**************************************************************************//**
+ * Set the Product Id property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param product_id    The vendor product id to be set. ASCIIZ string. The
+ *                      caller does not need to preserve the value once the
+ *                      function returns.
+ *****************************************************************************/
+void evel_service_product_id_set(EVENT_SERVICE * const event,
+                                 const char * const product_id);
+
+/**************************************************************************//**
+ * Set the Subsystem Id property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param subsystem_id  The vendor subsystem id to be set. ASCIIZ string. The
+ *                      caller does not need to preserve the value once the
+ *                      function returns.
+ *****************************************************************************/
+void evel_service_subsystem_id_set(EVENT_SERVICE * const event,
+                                   const char * const subsystem_id);
+
+/**************************************************************************//**
+ * Set the Friendly Name property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param friendly_name The vendor friendly name to be set. ASCIIZ string. The
+ *                      caller does not need to preserve the value once the
+ *                      function returns.
+ *****************************************************************************/
+void evel_service_friendly_name_set(EVENT_SERVICE * const event,
+                                    const char * const friendly_name);
+
+/**************************************************************************//**
+ * Set the correlator property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param correlator    The correlator to be set. ASCIIZ string. The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_service_correlator_set(EVENT_SERVICE * const event,
+                                 const char * const correlator);
+
+/**************************************************************************//**
+ * Set the Codec property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param codec         The codec to be set. ASCIIZ string. The caller does not
+ *                      need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_service_codec_set(EVENT_SERVICE * const event,
+                            const char * const codec);
+
+/**************************************************************************//**
+ * Set the Callee Side Codec property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param codec         The codec to be set. ASCIIZ string. The caller does not
+ *                      need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_service_callee_codec_set(EVENT_SERVICE * const event,
+                                   const char * const codec);
+
+/**************************************************************************//**
+ * Set the Caller Side Codec property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param codec         The codec to be set. ASCIIZ string. The caller does not
+ *                      need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_service_caller_codec_set(EVENT_SERVICE * const event,
+                                   const char * const codec);
+
+/**************************************************************************//**
+ * Set the RTCP Data property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param rtcp_data     The RTCP Data to be set. ASCIIZ string. The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_service_rtcp_data_set(EVENT_SERVICE * const event,
+                                const char * const rtcp_data);
+
+/**************************************************************************//**
+ * Set the Adjacency Name property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param adjacency_name
+ *                      The adjacency name to be set. ASCIIZ string. The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_service_adjacency_name_set(EVENT_SERVICE * const event,
+                                     const char * const adjacency_name);
+
+/**************************************************************************//**
+ * Set the Endpoint Descriptor property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param endpoint_desc The endpoint descriptor to be set.
+ *****************************************************************************/
+void evel_service_endpoint_desc_set(
+                                EVENT_SERVICE * const event,
+                                const EVEL_SERVICE_ENDPOINT_DESC endpoint_desc);
+
+/**************************************************************************//**
+ * Set the Endpoint Jitter property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param jitter        The jitter to be set.
+ *****************************************************************************/
+void evel_service_endpoint_jitter_set(EVENT_SERVICE * const event,
+                                      const int jitter);
+
+/**************************************************************************//**
+ * Set the Endpoint Rtp Octets Discarded property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param rtp_oct_disc  The discard count.
+ *****************************************************************************/
+void evel_service_endpoint_rtp_oct_disc_set(EVENT_SERVICE * const event,
+                                            const int rtp_oct_disc);
+
+/**************************************************************************//**
+ * Set the Endpoint Rtp Octets Received property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param rtp_oct_recv  The receive count.
+ *****************************************************************************/
+void evel_service_endpoint_rtp_oct_recv_set(EVENT_SERVICE * const event,
+                                            const int rtp_oct_recv);
+
+/**************************************************************************//**
+ * Set the Endpoint Rtp Octets Sent property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param rtp_oct_sent  The send count.
+ *****************************************************************************/
+void evel_service_endpoint_rtp_oct_sent_set(EVENT_SERVICE * const event,
+                                            const int rtp_oct_sent);
+
+/**************************************************************************//**
+ * Set the Endpoint Rtp Packets Discarded property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param rtp_pkt_disc  The discard count.
+ *****************************************************************************/
+void evel_service_endpoint_rtp_pkt_disc_set(EVENT_SERVICE * const event,
+                                            const int rtp_pkt_disc);
+
+/**************************************************************************//**
+ * Set the Endpoint Rtp Packets Received property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param rtp_pkt_recv  The receive count.
+ *****************************************************************************/
+void evel_service_endpoint_rtp_pkt_recv_set(EVENT_SERVICE * const event,
+                                            const int rtp_pkt_recv);
+
+/**************************************************************************//**
+ * Set the Endpoint Rtp Packets Sent property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param rtp_pkt_sent  The send count.
+ *****************************************************************************/
+void evel_service_endpoint_rtp_pkt_sent_set(EVENT_SERVICE * const event,
+                                            const int rtp_pkt_sent);
+
+/**************************************************************************//**
+ * Set the Local Jitter property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param jitter        The jitter to be set.
+ *****************************************************************************/
+void evel_service_local_jitter_set(EVENT_SERVICE * const event,
+                                   const int jitter);
+
+/**************************************************************************//**
+ * Set the Local Rtp Octets Discarded property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param rtp_oct_disc  The discard count.
+ *****************************************************************************/
+void evel_service_local_rtp_oct_disc_set(EVENT_SERVICE * const event,
+                                         const int rtp_oct_disc);
+
+/**************************************************************************//**
+ * Set the Local Rtp Octets Received property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param rtp_oct_recv  The receive count.
+ *****************************************************************************/
+void evel_service_local_rtp_oct_recv_set(EVENT_SERVICE * const event,
+                                         const int rtp_oct_recv);
+
+/**************************************************************************//**
+ * Set the Local Rtp Octets Sent property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param rtp_oct_sent  The send count.
+ *****************************************************************************/
+void evel_service_local_rtp_oct_sent_set(EVENT_SERVICE * const event,
+                                         const int rtp_oct_sent);
+
+/**************************************************************************//**
+ * Set the Local Rtp Packets Discarded property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param rtp_pkt_disc  The discard count.
+ *****************************************************************************/
+void evel_service_local_rtp_pkt_disc_set(EVENT_SERVICE * const event,
+                                         const int rtp_pkt_disc);
+
+/**************************************************************************//**
+ * Set the Local Rtp Packets Received property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param rtp_pkt_recv  The receive count.
+ *****************************************************************************/
+void evel_service_local_rtp_pkt_recv_set(EVENT_SERVICE * const event,
+                                         const int rtp_pkt_recv);
+
+/**************************************************************************//**
+ * Set the Local Rtp Packets Sent property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param rtp_pkt_sent  The send count.
+ *****************************************************************************/
+void evel_service_local_rtp_pkt_sent_set(EVENT_SERVICE * const event,
+                                         const int rtp_pkt_sent);
+
+/**************************************************************************//**
+ * Set the Mos Cqe property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param mos_cqe       The mosCqe to be set.
+ *****************************************************************************/
+void evel_service_mos_cqe_set(EVENT_SERVICE * const event,
+                              const double mos_cqe);
+
+/**************************************************************************//**
+ * Set the Packets Lost property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param packets_lost  The number of packets lost to be set.
+ *****************************************************************************/
+void evel_service_packets_lost_set(EVENT_SERVICE * const event,
+                                   const int packets_lost);
+
+/**************************************************************************//**
+ * Set the packet Loss Percent property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param packet_loss_percent
+ *                      The packet loss in percent.
+ *****************************************************************************/
+void evel_service_packet_loss_percent_set(EVENT_SERVICE * const event,
+                                          const double packet_loss_percent);
+
+/**************************************************************************//**
+ * Set the R Factor property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param r_factor      The R Factor to be set.
+ *****************************************************************************/
+void evel_service_r_factor_set(EVENT_SERVICE * const event,
+                               const int r_factor);
+
+/**************************************************************************//**
+ * Set the Round Trip Delay property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param round_trip_delay
+ *                      The Round trip delay to be set.
+ *****************************************************************************/
+void evel_service_round_trip_delay_set(EVENT_SERVICE * const event,
+                                       const int round_trip_delay);
+
+/**************************************************************************//**
+ * Set the Phone Number property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param phone_number  The Phone Number to be set. ASCIIZ string. The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_service_phone_number_set(EVENT_SERVICE * const event,
+                                   const char * const phone_number);
+
+/**************************************************************************//**
+ * Add a name/value pair to the Service, under the additionalFields array.
+ *
+ * The name and value are null delimited ASCII strings.  The library takes
+ * a copy so the caller does not have to preserve values after the function
+ * returns.
+ *
+ * @param event     Pointer to the Service event.
+ * @param name      ASCIIZ string with the field's name.  The caller does not
+ *                  need to preserve the value once the function returns.
+ * @param value     ASCIIZ string with the field's value.  The caller does not
+ *                  need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_service_addl_field_add(EVENT_SERVICE * const event,
+                                 const char * const name,
+                                 const char * const value);
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*                                                                           */
+/*   SIGNALING                                                               */
+/*                                                                           */
+/*****************************************************************************/
+/*****************************************************************************/
+
+/**************************************************************************//**
+ * Create a new Signaling event.
+ *
+ * @note    The mandatory fields on the Signaling must be supplied to
+ *          this factory function and are immutable once set.  Optional fields
+ *          have explicit setter functions, but again values may only be set
+ *          once so that the event has immutable properties.
+ * @param vendor_id     The vendor id to encode in the event instance id.
+ * @param event_id      The vendor event id to encode in the event instance id.
+ * @returns pointer to the newly manufactured ::EVENT_SIGNALING.  If the event
+ *          is not used (i.e. posted) it must be released using
+ *          ::evel_free_signaling.
+ * @retval  NULL  Failed to create the event.
+ *****************************************************************************/
+EVENT_SIGNALING * evel_new_signaling(const char * const vendor_id,
+                                     const char * const event_id);
+
+/**************************************************************************//**
+ * Free a Signaling event.
+ *
+ * Free off the event supplied.  Will free all the contained allocated memory.
+ *
+ * @note It does not free the event itself, since that may be part of a larger
+ * structure.
+ *****************************************************************************/
+void evel_free_signaling(EVENT_SIGNALING * const event);
+
+/**************************************************************************//**
+ * Set the Event Type property of the Signaling event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Signaling event.
+ * @param type          The Event Type to be set. ASCIIZ string. The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_signaling_type_set(EVENT_SIGNALING * const event,
+                             const char * const type);
+
+/**************************************************************************//**
+ * Set the Product Id property of the Signaling event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Signaling event.
+ * @param product_id    The vendor product id to be set. ASCIIZ string. The
+ *                      caller does not need to preserve the value once the
+ *                      function returns.
+ *****************************************************************************/
+void evel_signaling_product_id_set(EVENT_SIGNALING * const event,
+                                   const char * const product_id);
+
+/**************************************************************************//**
+ * Set the Subsystem Id property of the Signaling event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Signaling event.
+ * @param subsystem_id  The vendor subsystem id to be set. ASCIIZ string. The
+ *                      caller does not need to preserve the value once the
+ *                      function returns.
+ *****************************************************************************/
+void evel_signaling_subsystem_id_set(EVENT_SIGNALING * const event,
+                                     const char * const subsystem_id);
+
+/**************************************************************************//**
+ * Set the Friendly Name property of the Signaling event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Signaling event.
+ * @param friendly_name The vendor friendly name to be set. ASCIIZ string. The
+ *                      caller does not need to preserve the value once the
+ *                      function returns.
+ *****************************************************************************/
+void evel_signaling_friendly_name_set(EVENT_SIGNALING * const event,
+                                      const char * const friendly_name);
+
+/**************************************************************************//**
+ * Set the Correlator property of the Signaling event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Signaling event.
+ * @param correlator    The correlator to be set. ASCIIZ string. The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_signaling_correlator_set(EVENT_SIGNALING * const event,
+                                   const char * const correlator);
+
+/**************************************************************************//**
+ * Set the Local Ip Address property of the Signaling event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Signaling event.
+ * @param local_ip_address
+ *                      The Local Ip Address to be set. ASCIIZ string. The
+ *                      caller does not need to preserve the value once the
+ *                      function returns.
+ *****************************************************************************/
+void evel_signaling_local_ip_address_set(EVENT_SIGNALING * const event,
+                                         const char * const local_ip_address);
+
+/**************************************************************************//**
+ * Set the Local Port property of the Signaling event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Signaling event.
+ * @param local_port    The Local Port to be set. ASCIIZ string. The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_signaling_local_port_set(EVENT_SIGNALING * const event,
+                                   const char * const local_port);
+
+/**************************************************************************//**
+ * Set the Remote Ip Address property of the Signaling event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Signaling event.
+ * @param remote_ip_address
+ *                      The Remote Ip Address to be set. ASCIIZ string. The
+ *                      caller does not need to preserve the value once the
+ *                      function returns.
+ *****************************************************************************/
+void evel_signaling_remote_ip_address_set(EVENT_SIGNALING * const event,
+                                         const char * const remote_ip_address);
+
+/**************************************************************************//**
+ * Set the Remote Port property of the Signaling event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Signaling event.
+ * @param remote_port   The Remote Port to be set. ASCIIZ string. The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_signaling_remote_port_set(EVENT_SIGNALING * const event,
+                                    const char * const remote_port);
+
+/**************************************************************************//**
+ * Set the Compressed SIP property of the Signaling event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Signaling event.
+ * @param compressed_sip
+ *                      The Compressed SIP to be set. ASCIIZ string. The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_signaling_compressed_sip_set(EVENT_SIGNALING * const event,
+                                       const char * const compressed_sip);
+
+/**************************************************************************//**
+ * Set the Summary SIP property of the Signaling event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Signaling event.
+ * @param summary_sip   The Summary SIP to be set. ASCIIZ string. The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_signaling_summary_sip_set(EVENT_SIGNALING * const event,
+                                    const char * const summary_sip);
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*                                                                           */
+/*   STATE CHANGE                                                            */
+/*                                                                           */
+/*****************************************************************************/
+/*****************************************************************************/
+
+/**************************************************************************//**
+ * Create a new State Change event.
+ *
+ * @note    The mandatory fields on the Syslog must be supplied to this factory
+ *          function and are immutable once set.  Optional fields have explicit
+ *          setter functions, but again values may only be set once so that the
+ *          Syslog has immutable properties.
+ *
+ * @param new_state     The new state of the reporting entity.
+ * @param old_state     The old state of the reporting entity.
+ * @param interface     The card or port name of the reporting entity.
+ *
+ * @returns pointer to the newly manufactured ::EVENT_STATE_CHANGE.  If the
+ *          event is not used it must be released using
+ *          ::evel_free_state_change
+ * @retval  NULL  Failed to create the event.
+ *****************************************************************************/
+EVENT_STATE_CHANGE * evel_new_state_change(const EVEL_ENTITY_STATE new_state,
+                                           const EVEL_ENTITY_STATE old_state,
+                                           const char * const interface);
+
+/**************************************************************************//**
+ * Free a State Change.
+ *
+ * Free off the State Change supplied.  Will free all the contained allocated
+ * memory.
+ *
+ * @note It does not free the State Change itself, since that may be part of a
+ * larger structure.
+ *****************************************************************************/
+void evel_free_state_change(EVENT_STATE_CHANGE * const state_change);
+
+/**************************************************************************//**
+ * Set the Event Type property of the State Change.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param state_change  Pointer to the ::EVENT_STATE_CHANGE.
+ * @param type          The Event Type to be set. ASCIIZ string. The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_state_change_type_set(EVENT_STATE_CHANGE * const state_change,
+                                const char * const type);
+
+/**************************************************************************//**
+ * Add an additional field name/value pair to the State Change.
+ *
+ * The name and value are null delimited ASCII strings.  The library takes
+ * a copy so the caller does not have to preserve values after the function
+ * returns.
+ *
+ * @param state_change  Pointer to the ::EVENT_STATE_CHANGE.
+ * @param name          ASCIIZ string with the attribute's name.  The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ * @param value         ASCIIZ string with the attribute's value.  The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_state_change_addl_field_add(EVENT_STATE_CHANGE * const state_change,
+                                      const char * const name,
+                                      const char * const value);
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*                                                                           */
+/*   SYSLOG                                                                  */
+/*                                                                           */
+/*****************************************************************************/
+/*****************************************************************************/
+
+/**************************************************************************//**
+ * Create a new syslog event.
+ *
+ * @note    The mandatory fields on the Syslog must be supplied to this factory
+ *          function and are immutable once set.  Optional fields have explicit
+ *          setter functions, but again values may only be set once so that the
+ *          Syslog has immutable properties.
+ *
+ * @param   event_source_type
+ * @param   syslog_msg
+ * @param   syslog_tag
+ *
+ * @returns pointer to the newly manufactured ::EVENT_SYSLOG.  If the event is
+ *          not used it must be released using ::evel_free_syslog
+ * @retval  NULL  Failed to create the event.
+ *****************************************************************************/
+EVENT_SYSLOG * evel_new_syslog(EVEL_SOURCE_TYPES event_source_type,
+                               const char * const syslog_msg,
+                               const char * const syslog_tag);
+
+/**************************************************************************//**
+ * Set the Event Type property of the Syslog.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param syslog      Pointer to the syslog.
+ * @param type        The Event Type to be set. ASCIIZ string. The caller
+ *                    does not need to preserve the value once the function
+ *                    returns.
+ *****************************************************************************/
+void evel_syslog_type_set(EVENT_SYSLOG * syslog,
+                          const char * const type);
+
+/**************************************************************************//**
+ * Free a Syslog.
+ *
+ * Free off the Syslog supplied.  Will free all the contained allocated memory.
+ *
+ * @note It does not free the Syslog itself, since that may be part of a
+ * larger structure.
+ *****************************************************************************/
+void evel_free_syslog(EVENT_SYSLOG * event);
+
+/**************************************************************************//**
+ * Add an additional field name/value pair to the Syslog.
+ *
+ * The name and value are null delimited ASCII strings.  The library takes
+ * a copy so the caller does not have to preserve values after the function
+ * returns.
+ *
+ * @param syslog    Pointer to the syslog.
+ * @param name      ASCIIZ string with the attribute's name.  The caller
+ *                  does not need to preserve the value once the function
+ *                  returns.
+ * @param value     ASCIIZ string with the attribute's value.  The caller
+ *                  does not need to preserve the value once the function
+ *                  returns.
+ *****************************************************************************/
+void evel_syslog_addl_field_add(EVENT_SYSLOG * syslog,
+                                char * name,
+                                char * value);
+
+/**************************************************************************//**
+ * Set the Event Source Host property of the Syslog.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param syslog      Pointer to the Syslog.
+ * @param host        The Event Source Host to be set.  ASCIIZ string. The
+ *                    caller does not need to preserve the value once the
+ *                    function returns.
+ *****************************************************************************/
+void evel_syslog_event_source_host_set(EVENT_SYSLOG * syslog,
+                                       const char * const host);
+
+/**************************************************************************//**
+ * Set the Syslog Facility property of the Syslog.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param syslog      Pointer to the Syslog.
+ * @param facility    The Syslog Facility to be set.  ASCIIZ string. The caller
+ *                    does not need to preserve the value once the function
+ *                    returns.
+ *****************************************************************************/
+void evel_syslog_facility_set(EVENT_SYSLOG * syslog,
+                              EVEL_SYSLOG_FACILITIES facility);
+
+/**************************************************************************//**
+ * Set the Process property of the Syslog.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param syslog      Pointer to the Syslog.
+ * @param proc        The Process to be set.  ASCIIZ string. The caller does
+ *                    not need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_syslog_proc_set(EVENT_SYSLOG * syslog, const char * const proc);
+
+/**************************************************************************//**
+ * Set the Process ID property of the Syslog.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param syslog      Pointer to the Syslog.
+ * @param proc_id     The Process ID to be set.
+ *****************************************************************************/
+void evel_syslog_proc_id_set(EVENT_SYSLOG * syslog, int proc_id);
+
+/**************************************************************************//**
+ * Set the Version property of the Syslog.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param syslog      Pointer to the Syslog.
+ * @param version     The Version to be set.
+ *****************************************************************************/
+void evel_syslog_version_set(EVENT_SYSLOG * syslog, int version);
+
+/**************************************************************************//**
+ * Set the Structured Data property of the Syslog.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param syslog      Pointer to the Syslog.
+ * @param s_data      The Structured Data to be set.  ASCIIZ string. The caller
+ *                    does not need to preserve the value once the function
+ *                    returns.
+ *****************************************************************************/
+void evel_syslog_s_data_set(EVENT_SYSLOG * syslog, const char * const s_data);
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*                                                                           */
+/*   OTHER                                                                   */
+/*                                                                           */
+/*****************************************************************************/
+/*****************************************************************************/
+
+/**************************************************************************//**
+ * Create a new other event.
+ *
+ *
+ * @returns pointer to the newly manufactured ::EVENT_OTHER.  If the event is
+ *          not used it must be released using ::evel_free_other.
+ * @retval  NULL  Failed to create the event.
+ *****************************************************************************/
+EVENT_OTHER * evel_new_other(void);
+
+/**************************************************************************//**
+ * Free an Other.
+ *
+ * Free off the Other supplied.  Will free all the contained allocated memory.
+ *
+ * @note It does not free the Other itself, since that may be part of a
+ * larger structure.
+ *****************************************************************************/
+void evel_free_other(EVENT_OTHER * event);
+
+/**************************************************************************//**
+ * Set the Event Type property of the Other.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param other       Pointer to the Other.
+ * @param type        The Event Type to be set. ASCIIZ string. The caller
+ *                    does not need to preserve the value once the function
+ *                    returns.
+ *****************************************************************************/
+void evel_other_type_set(EVENT_OTHER * other,
+                         const char * const type);
+
+/**************************************************************************//**
+ * Add a value name/value pair to the Other.
+ *
+ * The name and value are null delimited ASCII strings.  The library takes
+ * a copy so the caller does not have to preserve values after the function
+ * returns.
+ *
+ * @param other     Pointer to the Other.
+ * @param name      ASCIIZ string with the attribute's name.
+ * @param value     ASCIIZ string with the attribute's value.
+ *****************************************************************************/
+void evel_other_field_add(EVENT_OTHER * other,
+                          char * name,
+                          char * value);
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*                                                                           */
+/*   THROTTLING                                                              */
+/*                                                                           */
+/*****************************************************************************/
+/*****************************************************************************/
+
+/**************************************************************************//**
+ * Return the current measurement interval provided by the Event Listener.
+ *
+ * @returns The current measurement interval
+ * @retval  EVEL_MEASUREMENT_INTERVAL_UKNOWN (0) - interval has not been
+ *          specified
+ *****************************************************************************/
+int evel_get_measurement_interval();
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*                                                                           */
+/*   LOGGING                                                                 */
+/*                                                                           */
+/*****************************************************************************/
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Debug macros.                                                             */
+/*****************************************************************************/
+#define EVEL_DEBUG(FMT, ...)   log_debug(EVEL_LOG_DEBUG, (FMT), ##__VA_ARGS__)
+#define EVEL_INFO(FMT, ...)    log_debug(EVEL_LOG_INFO, (FMT), ##__VA_ARGS__)
+#define EVEL_SPAMMY(FMT, ...)  log_debug(EVEL_LOG_SPAMMY, (FMT), ##__VA_ARGS__)
+#define EVEL_ERROR(FMT, ...)   log_debug(EVEL_LOG_ERROR, "ERROR: " FMT, \
+                                         ##__VA_ARGS__)
+#define EVEL_ENTER()                                                          \
+        {                                                                     \
+          log_debug(EVEL_LOG_DEBUG, "Enter %s {", __FUNCTION__);              \
+          debug_indent += 2;                                                  \
+        }
+#define EVEL_EXIT()                                                           \
+        {                                                                     \
+          debug_indent -= 2;                                                  \
+          log_debug(EVEL_LOG_DEBUG, "Exit %s }", __FUNCTION__);               \
+        }
+
+#define INDENT_SEPARATORS                                                     \
+        "| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | "
+
+extern EVEL_LOG_LEVELS debug_level;
+extern int debug_indent;
+extern FILE * fout;
+
+#define EVEL_DEBUG_ON() ((debug_level) >= EVEL_LOG_DEBUG)
+
+/**************************************************************************//**
+ * Initialize logging
+ *
+ * @param[in] level  The debugging level - one of ::EVEL_LOG_LEVELS.
+ * @param[in] ident  The identifier for our logs.
+ *****************************************************************************/
+void log_initialize(EVEL_LOG_LEVELS level, const char * ident);
+
+/**************************************************************************//**
+ * Log debug information
+ *
+ * Logs debugging information in a platform independent manner.
+ *
+ * @param[in] level   The debugging level - one of ::EVEL_LOG_LEVELS.
+ * @param[in] format  Log formatting string in printf format.
+ * @param[in] ...     Variable argument list.
+ *****************************************************************************/
+void log_debug(EVEL_LOG_LEVELS level, char * format, ...);
+
+/***************************************************************************//*
+ * Store the formatted string into the static error string and log the error.
+ *
+ * @param format  Error string in standard printf format.
+ * @param ...     Variable parameters to be substituted into the format string.
+ *****************************************************************************/
+void log_error_state(char * format, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/vnfs/VES/code/evel_library/evel_event.c b/vnfs/VES/code/evel_library/evel_event.c
new file mode 100644 (file)
index 0000000..2e49870
--- /dev/null
@@ -0,0 +1,568 @@
+/**************************************************************************//**
+ * @file
+ * Implementation of EVEL functions relating to Event Headers - since
+ * Heartbeats only contain the Event Header, the Heartbeat factory function is
+ * here too.
+ *
+ * License
+ * -------
+ *
+ * Copyright(c) <2016>, AT&T Intellectual Property.  All other rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:  This product includes
+ *    software developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+#include "evel.h"
+#include "evel_internal.h"
+#include "evel_throttle.h"
+#include "metadata.h"
+
+/**************************************************************************//**
+ * Unique sequence number for events from this VNF.
+ *****************************************************************************/
+static int event_sequence = 1;
+
+/**************************************************************************//**
+ * Set the next event_sequence to use.
+ *
+ * @param sequence      The next sequence number to use.
+ *****************************************************************************/
+void evel_set_next_event_sequence(const int sequence)
+{
+  EVEL_ENTER();
+
+  EVEL_INFO("Setting event sequence to %d, was %d ", sequence, event_sequence);
+  event_sequence = sequence;
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Create a new heartbeat event.
+ *
+ * @note that the heartbeat is just a "naked" commonEventHeader!
+ *
+ * @returns pointer to the newly manufactured ::EVENT_HEADER.  If the event is
+ *          not used it must be released using ::evel_free_event
+ * @retval  NULL  Failed to create the event.
+ *****************************************************************************/
+EVENT_HEADER * evel_new_heartbeat()
+{
+  EVENT_HEADER * heartbeat = NULL;
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Allocate the header.                                                    */
+  /***************************************************************************/
+  heartbeat = malloc(sizeof(EVENT_HEADER));
+  if (heartbeat == NULL)
+  {
+    log_error_state("Out of memory");
+    goto exit_label;
+  }
+  memset(heartbeat, 0, sizeof(EVENT_HEADER));
+
+  /***************************************************************************/
+  /* Initialize the header.  Get a new event sequence number.  Note that if  */
+  /* any memory allocation fails in here we will fail gracefully because     */
+  /* everything downstream can cope with NULLs.                              */
+  /***************************************************************************/
+  evel_init_header(heartbeat);
+  evel_force_option_string(&heartbeat->event_type, "Autonomous heartbeat");
+
+exit_label:
+  EVEL_EXIT();
+  return heartbeat;
+}
+
+/**************************************************************************//**
+ * Initialize a newly created event header.
+ *
+ * @param header  Pointer to the header being initialized.
+ *****************************************************************************/
+void evel_init_header(EVENT_HEADER * const header)
+{
+  char scratchpad[EVEL_MAX_STRING_LEN + 1] = {0};
+  struct timeval tv;
+
+  EVEL_ENTER();
+
+  assert(header != NULL);
+
+  gettimeofday(&tv, NULL);
+
+  /***************************************************************************/
+  /* Initialize the header.  Get a new event sequence number.  Note that if  */
+  /* any memory allocation fails in here we will fail gracefully because     */
+  /* everything downstream can cope with NULLs.                              */
+  /***************************************************************************/
+  header->event_domain = EVEL_DOMAIN_HEARTBEAT;
+  snprintf(scratchpad, EVEL_MAX_STRING_LEN, "%d", event_sequence);
+  header->event_id = strdup(scratchpad);
+  header->functional_role = strdup(functional_role);
+  header->last_epoch_microsec = tv.tv_usec + 1000000 * tv.tv_sec;
+  header->priority = EVEL_PRIORITY_NORMAL;
+  header->reporting_entity_name = strdup(openstack_vm_name());
+  header->source_name = strdup(openstack_vm_name());
+  header->sequence = event_sequence;
+  header->start_epoch_microsec = header->last_epoch_microsec;
+  header->major_version = EVEL_HEADER_MAJOR_VERSION;
+  header->minor_version = EVEL_HEADER_MINOR_VERSION;
+  event_sequence++;
+
+  /***************************************************************************/
+  /* Optional parameters.                                                    */
+  /***************************************************************************/
+  evel_init_option_string(&header->event_type);
+  evel_force_option_string(&header->reporting_entity_id, openstack_vm_uuid());
+  evel_force_option_string(&header->source_id, openstack_vm_uuid());
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Event Type property of the event header.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param header        Pointer to the ::EVENT_HEADER.
+ * @param type          The Event Type to be set. ASCIIZ string. The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_header_type_set(EVENT_HEADER * const header,
+                          const char * const type)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(header != NULL);
+  assert(type != NULL);
+
+  evel_set_option_string(&header->event_type, type, "Event Type");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Start Epoch property of the event header.
+ *
+ * @note The Start Epoch defaults to the time of event creation.
+ *
+ * @param header        Pointer to the ::EVENT_HEADER.
+ * @param start_epoch_microsec
+ *                      The start epoch to set, in microseconds.
+ *****************************************************************************/
+void evel_start_epoch_set(EVENT_HEADER * const header,
+                          const unsigned long long start_epoch_microsec)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and assign the new value.                           */
+  /***************************************************************************/
+  assert(header != NULL);
+  header->start_epoch_microsec = start_epoch_microsec;
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Last Epoch property of the event header.
+ *
+ * @note The Last Epoch defaults to the time of event creation.
+ *
+ * @param header        Pointer to the ::EVENT_HEADER.
+ * @param last_epoch_microsec
+ *                      The last epoch to set, in microseconds.
+ *****************************************************************************/
+void evel_last_epoch_set(EVENT_HEADER * const header,
+                         const unsigned long long last_epoch_microsec)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and assign the new value.                           */
+  /***************************************************************************/
+  assert(header != NULL);
+  header->last_epoch_microsec = last_epoch_microsec;
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Reporting Entity Name property of the event header.
+ *
+ * @note The Reporting Entity Name defaults to the OpenStack VM Name.
+ *
+ * @param header        Pointer to the ::EVENT_HEADER.
+ * @param entity_name   The entity name to set.
+ *****************************************************************************/
+void evel_reporting_entity_name_set(EVENT_HEADER * const header,
+                                    const char * const entity_name)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and assign the new value.                           */
+  /***************************************************************************/
+  assert(header != NULL);
+  assert(entity_name != NULL);
+  assert(header->reporting_entity_name != NULL);
+
+  /***************************************************************************/
+  /* Free the previously allocated memory and replace it with a copy of the  */
+  /* provided one.                                                           */
+  /***************************************************************************/
+  free(header->reporting_entity_name);
+  header->reporting_entity_name = strdup(entity_name);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Reporting Entity Id property of the event header.
+ *
+ * @note The Reporting Entity Id defaults to the OpenStack VM UUID.
+ *
+ * @param header        Pointer to the ::EVENT_HEADER.
+ * @param entity_id     The entity id to set.
+ *****************************************************************************/
+void evel_reporting_entity_id_set(EVENT_HEADER * const header,
+                                  const char * const entity_id)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and assign the new value.                           */
+  /***************************************************************************/
+  assert(header != NULL);
+  assert(entity_id != NULL);
+
+  /***************************************************************************/
+  /* Free the previously allocated memory and replace it with a copy of the  */
+  /* provided one.  Note that evel_force_option_string strdups entity_id.    */
+  /***************************************************************************/
+  evel_free_option_string(&header->reporting_entity_id);
+  evel_force_option_string(&header->reporting_entity_id, entity_id);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Encode the event as a JSON event object according to AT&T's schema.
+ *
+ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
+ * @param event         Pointer to the ::EVENT_HEADER to encode.
+ *****************************************************************************/
+void evel_json_encode_header(EVEL_JSON_BUFFER * jbuf,
+                             EVENT_HEADER * event)
+{
+  char * domain;
+  char * priority;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(jbuf != NULL);
+  assert(jbuf->json != NULL);
+  assert(jbuf->max_size > 0);
+  assert(event != NULL);
+
+  domain = evel_event_domain(event->event_domain);
+  priority = evel_event_priority(event->priority);
+  evel_json_open_named_object(jbuf, "commonEventHeader");
+
+  /***************************************************************************/
+  /* Mandatory fields.                                                       */
+  /***************************************************************************/
+  evel_enc_kv_string(jbuf, "domain", domain);
+  evel_enc_kv_string(jbuf, "eventId", event->event_id);
+  evel_enc_kv_string(jbuf, "functionalRole", event->functional_role);
+  evel_enc_kv_ull(jbuf, "lastEpochMicrosec", event->last_epoch_microsec);
+  evel_enc_kv_string(jbuf, "priority", priority);
+  evel_enc_kv_string(
+    jbuf, "reportingEntityName", event->reporting_entity_name);
+  evel_enc_kv_int(jbuf, "sequence", event->sequence);
+  evel_enc_kv_string(jbuf, "sourceName", event->source_name);
+  evel_enc_kv_ull(jbuf, "startEpochMicrosec", event->start_epoch_microsec);
+  evel_enc_version(
+    jbuf, "version", event->major_version, event->minor_version);
+
+  /***************************************************************************/
+  /* Optional fields.                                                        */
+  /***************************************************************************/
+  evel_enc_kv_opt_string(jbuf, "eventType", &event->event_type);
+  evel_enc_kv_opt_string(
+    jbuf, "reportingEntityId", &event->reporting_entity_id);
+  evel_enc_kv_opt_string(jbuf, "sourceId", &event->source_id);
+
+  evel_json_close_object(jbuf);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Free an event header.
+ *
+ * Free off the event header supplied.  Will free all the contained allocated
+ * memory.
+ *
+ * @note It does not free the header itself, since that may be part of a
+ * larger structure.
+ *****************************************************************************/
+void evel_free_header(EVENT_HEADER * const event)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.  As an internal API we don't allow freeing NULL    */
+  /* events as we do on the public API.                                      */
+  /***************************************************************************/
+  assert(event != NULL);
+
+  /***************************************************************************/
+  /* Free all internal strings.                                              */
+  /***************************************************************************/
+  free(event->event_id);
+  evel_free_option_string(&event->event_type);
+  free(event->functional_role);
+  evel_free_option_string(&event->reporting_entity_id);
+  free(event->reporting_entity_name);
+  evel_free_option_string(&event->source_id);
+  free(event->source_name);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Encode the event as a JSON event object according to AT&T's schema.
+ *
+ * @param json      Pointer to where to store the JSON encoded data.
+ * @param max_size  Size of storage available in json_body.
+ * @param event     Pointer to the ::EVENT_HEADER to encode.
+ * @returns Number of bytes actually written.
+ *****************************************************************************/
+int evel_json_encode_event(char * json,
+                           int max_size,
+                           EVENT_HEADER * event)
+{
+  EVEL_JSON_BUFFER json_buffer;
+  EVEL_JSON_BUFFER * jbuf = &json_buffer;
+  EVEL_THROTTLE_SPEC * throttle_spec;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Get the latest throttle specification for the domain.                   */
+  /***************************************************************************/
+  throttle_spec = evel_get_throttle_spec(event->event_domain);
+
+  /***************************************************************************/
+  /* Initialize the JSON_BUFFER and open the top-level objects.              */
+  /***************************************************************************/
+  evel_json_buffer_init(jbuf, json, max_size, throttle_spec);
+  evel_json_open_object(jbuf);
+  evel_json_open_named_object(jbuf, "event");
+
+  switch (event->event_domain)
+  {
+    case EVEL_DOMAIN_HEARTBEAT:
+      evel_json_encode_header(jbuf, event);
+      break;
+
+    case EVEL_DOMAIN_FAULT:
+      evel_json_encode_fault(jbuf, (EVENT_FAULT *)event);
+      break;
+
+    case EVEL_DOMAIN_MEASUREMENT:
+      evel_json_encode_measurement(jbuf, (EVENT_MEASUREMENT *)event);
+      break;
+
+    case EVEL_DOMAIN_MOBILE_FLOW:
+      evel_json_encode_mobile_flow(jbuf, (EVENT_MOBILE_FLOW *)event);
+      break;
+
+    case EVEL_DOMAIN_REPORT:
+      evel_json_encode_report(jbuf, (EVENT_REPORT *)event);
+      break;
+
+    case EVEL_DOMAIN_SERVICE:
+      evel_json_encode_service(jbuf, (EVENT_SERVICE *)event);
+      break;
+
+    case EVEL_DOMAIN_SIGNALING:
+      evel_json_encode_signaling(jbuf, (EVENT_SIGNALING *)event);
+      break;
+
+    case EVEL_DOMAIN_STATE_CHANGE:
+      evel_json_encode_state_change(jbuf, (EVENT_STATE_CHANGE *)event);
+      break;
+
+    case EVEL_DOMAIN_SYSLOG:
+      evel_json_encode_syslog(jbuf, (EVENT_SYSLOG *)event);
+      break;
+
+    case EVEL_DOMAIN_OTHER:
+      evel_json_encode_other(jbuf, (EVENT_OTHER *)event);
+      break;
+
+    case EVEL_DOMAIN_INTERNAL:
+    default:
+      EVEL_ERROR("Unexpected domain %d", event->event_domain);
+      assert(0);
+  }
+
+  evel_json_close_object(jbuf);
+  evel_json_close_object(jbuf);
+
+  /***************************************************************************/
+  /* Sanity check.                                                           */
+  /***************************************************************************/
+  assert(jbuf->depth == 0);
+
+  EVEL_EXIT();
+
+  return jbuf->offset;
+}
+
+/**************************************************************************//**
+ * Initialize an event instance id.
+ *
+ * @param instance_id   Pointer to the event instance id being initialized.
+ * @param vendor_id     The vendor id to encode in the event instance id.
+ * @param event_id      The event id to encode in the event instance id.
+ *****************************************************************************/
+void evel_init_event_instance_id(EVEL_EVENT_INSTANCE_ID * const instance_id,
+                                 const char * const vendor_id,
+                                 const char * const event_id)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(instance_id != NULL);
+  assert(vendor_id != NULL);
+  assert(event_id != NULL);
+
+  /***************************************************************************/
+  /* Store the mandatory parts.                                              */
+  /***************************************************************************/
+  instance_id->vendor_id = strdup(vendor_id);
+  instance_id->event_id = strdup(event_id);
+
+  /***************************************************************************/
+  /* Initialize the optional parts.                                          */
+  /***************************************************************************/
+  evel_init_option_string(&instance_id->product_id);
+  evel_init_option_string(&instance_id->subsystem_id);
+  evel_init_option_string(&instance_id->event_friendly_name);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Free an event instance id.
+ *
+ * @param instance_id   Pointer to the event instance id being initialized.
+ *****************************************************************************/
+void evel_free_event_instance_id(EVEL_EVENT_INSTANCE_ID * const instance_id)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(instance_id != NULL);
+  assert(instance_id->vendor_id != NULL);
+  assert(instance_id->event_id != NULL);
+
+  /***************************************************************************/
+  /* Free everything.                                                        */
+  /***************************************************************************/
+  free(instance_id->vendor_id);
+  free(instance_id->event_id);
+  evel_free_option_string(&instance_id->product_id);
+  evel_free_option_string(&instance_id->subsystem_id);
+  evel_free_option_string(&instance_id->event_friendly_name);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Encode the instance id as a JSON object according to AT&T's schema.
+ *
+ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
+ * @param instance_id   Pointer to the ::EVEL_EVENT_INSTANCE_ID to encode.
+ *****************************************************************************/
+void evel_json_encode_instance_id(EVEL_JSON_BUFFER * jbuf,
+                                  EVEL_EVENT_INSTANCE_ID * instance_id)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(jbuf != NULL);
+  assert(jbuf->json != NULL);
+  assert(jbuf->max_size > 0);
+  assert(instance_id != NULL);
+  assert(instance_id->vendor_id != NULL);
+  assert(instance_id->event_id != NULL);
+
+  evel_json_open_named_object(jbuf, "eventInstanceIdentifier");
+
+  /***************************************************************************/
+  /* Mandatory fields.                                                       */
+  /***************************************************************************/
+  evel_enc_kv_string(jbuf, "vendorId", instance_id->vendor_id);
+  evel_enc_kv_string(jbuf, "eventId", instance_id->event_id);
+
+  /***************************************************************************/
+  /* Optional fields.                                                        */
+  /***************************************************************************/
+  evel_enc_kv_opt_string(jbuf, "productId", &instance_id->product_id);
+  evel_enc_kv_opt_string(jbuf, "subsystemId", &instance_id->subsystem_id);
+  evel_enc_kv_opt_string(
+    jbuf, "eventFriendlyName", &instance_id->event_friendly_name);
+
+  evel_json_close_object(jbuf);
+
+  EVEL_EXIT();
+}
diff --git a/vnfs/VES/code/evel_library/evel_event_mgr.c b/vnfs/VES/code/evel_library/evel_event_mgr.c
new file mode 100644 (file)
index 0000000..0cc049f
--- /dev/null
@@ -0,0 +1,1053 @@
+/**************************************************************************//**
+ * @file
+ * Event Manager
+ *
+ * Simple event manager that is responsible for taking events (Heartbeats,
+ * Faults and Measurements) from the ring-buffer and posting them to the API.
+ *
+ * License
+ * -------
+ *
+ * Copyright(c) <2016>, AT&T Intellectual Property.  All other rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:  This product includes
+ *    software developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#include <curl/curl.h>
+
+#include "evel.h"
+#include "evel_internal.h"
+#include "ring_buffer.h"
+#include "evel_throttle.h"
+
+/**************************************************************************//**
+ * How long we're prepared to wait for the API service to respond in
+ * seconds.
+ *****************************************************************************/
+static const int EVEL_API_TIMEOUT = 5;
+
+/*****************************************************************************/
+/* Prototypes of locally scoped functions.                                   */
+/*****************************************************************************/
+static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp);
+static void * event_handler(void *arg);
+static bool evel_handle_response_tokens(const MEMORY_CHUNK * const chunk,
+                                        const jsmntok_t * const json_tokens,
+                                        const int num_tokens,
+                                        MEMORY_CHUNK * const post);
+static bool evel_tokens_match_command_list(const MEMORY_CHUNK * const chunk,
+                                           const jsmntok_t * const json_token,
+                                           const int num_tokens);
+static bool evel_token_equals_string(const MEMORY_CHUNK * const chunk,
+                                     const jsmntok_t * const json_token,
+                                     const char * check_string);
+
+/**************************************************************************//**
+ * Buffers for error strings from libcurl.
+ *****************************************************************************/
+static char curl_err_string[CURL_ERROR_SIZE] = "<NULL>";
+
+/**************************************************************************//**
+ * Handle for the API into libcurl.
+ *****************************************************************************/
+static CURL * curl_handle = NULL;
+
+/**************************************************************************//**
+ * Special headers that we send.
+ *****************************************************************************/
+static struct curl_slist * hdr_chunk = NULL;
+
+/**************************************************************************//**
+ * Message queue for sending events to the API.
+ *****************************************************************************/
+static ring_buffer event_buffer;
+
+/**************************************************************************//**
+ * Single pending priority post, which can be generated as a result of a
+ * response to an event.  Currently only used to respond to a commandList.
+ *****************************************************************************/
+static MEMORY_CHUNK priority_post;
+
+/**************************************************************************//**
+ * The thread which is responsible for handling events off of the ring-buffer
+ * and posting them to the Event Handler API.
+ *****************************************************************************/
+static pthread_t evt_handler_thread;
+
+/**************************************************************************//**
+ * Variable to convey to the event handler thread what the foreground wants it
+ * to do.
+ *****************************************************************************/
+static EVT_HANDLER_STATE evt_handler_state = EVT_HANDLER_UNINITIALIZED;
+
+/**************************************************************************//**
+ * The configured API URL for event and throttling.
+ *****************************************************************************/
+static char * evel_event_api_url;
+static char * evel_throt_api_url;
+
+/**************************************************************************//**
+ * Initialize the event handler.
+ *
+ * Primarily responsible for getting CURL ready for use.
+ *
+ * @param[in] event_api_url
+ *                      The URL where the Vendor Event Listener API is expected
+ *                      to be.
+ * @param[in] throt_api_url
+ *                      The URL where the Throttling API is expected to be.
+ * @param[in] username  The username for the Basic Authentication of requests.
+ * @param[in] password  The password for the Basic Authentication of requests.
+ * @param     verbosity 0 for normal operation, positive values for chattier
+ *                        logs.
+ *****************************************************************************/
+EVEL_ERR_CODES event_handler_initialize(const char * const event_api_url,
+                                        const char * const throt_api_url,
+                                        const char * const username,
+                                        const char * const password,
+                                        int verbosity)
+{
+  int rc = EVEL_SUCCESS;
+  CURLcode curl_rc = CURLE_OK;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check assumptions.                                                      */
+  /***************************************************************************/
+  assert(event_api_url != NULL);
+  assert(throt_api_url != NULL);
+  assert(username != NULL);
+  assert(password != NULL);
+
+  /***************************************************************************/
+  /* Store the API URLs.                                                     */
+  /***************************************************************************/
+  evel_event_api_url = strdup(event_api_url);
+  assert(evel_event_api_url != NULL);
+  evel_throt_api_url = strdup(throt_api_url);
+  assert(evel_throt_api_url != NULL);
+
+  /***************************************************************************/
+  /* Start the CURL library. Note that this initialization is not threadsafe */
+  /* which imposes a constraint that the EVEL library is initialized before  */
+  /* any threads are started.                                                */
+  /***************************************************************************/
+  curl_rc = curl_global_init(CURL_GLOBAL_SSL);
+  if (curl_rc != CURLE_OK)
+  {
+    rc = EVEL_CURL_LIBRARY_FAIL;
+    log_error_state("Failed to initialize libCURL. Error code=%d", curl_rc);
+    goto exit_label;
+  }
+
+  /***************************************************************************/
+  /* Get a curl handle which we'll use for all of our output.                */
+  /***************************************************************************/
+  curl_handle = curl_easy_init();
+  if (curl_handle == NULL)
+  {
+    rc = EVEL_CURL_LIBRARY_FAIL;
+    log_error_state("Failed to get libCURL handle");
+    goto exit_label;
+  }
+
+  /***************************************************************************/
+  /* Prime the library to give friendly error codes.                         */
+  /***************************************************************************/
+  curl_rc = curl_easy_setopt(curl_handle,
+                             CURLOPT_ERRORBUFFER,
+                             curl_err_string);
+  if (curl_rc != CURLE_OK)
+  {
+    rc = EVEL_CURL_LIBRARY_FAIL;
+    log_error_state("Failed to initialize libCURL to provide friendly errors. "
+                    "Error code=%d", curl_rc);
+    goto exit_label;
+  }
+
+  /***************************************************************************/
+  /* If running in verbose mode generate more output.                        */
+  /***************************************************************************/
+  if (verbosity > 0)
+  {
+    curl_rc = curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
+    if (curl_rc != CURLE_OK)
+    {
+      rc = EVEL_CURL_LIBRARY_FAIL;
+      log_error_state("Failed to initialize libCURL to be verbose. "
+                      "Error code=%d", curl_rc);
+      goto exit_label;
+    }
+  }
+
+  /***************************************************************************/
+  /* Set the URL for the API.                                                */
+  /***************************************************************************/
+  curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, event_api_url);
+  if (curl_rc != CURLE_OK)
+  {
+    rc = EVEL_CURL_LIBRARY_FAIL;
+    log_error_state("Failed to initialize libCURL with the API URL. "
+                    "Error code=%d (%s)", curl_rc, curl_err_string);
+    goto exit_label;
+  }
+  EVEL_INFO("Initializing CURL to send events to: %s", event_api_url);
+
+  /***************************************************************************/
+  /* send all data to this function.                                         */
+  /***************************************************************************/
+  curl_rc = curl_easy_setopt(curl_handle,
+                             CURLOPT_WRITEFUNCTION,
+                             evel_write_callback);
+  if (curl_rc != CURLE_OK)
+  {
+    rc = EVEL_CURL_LIBRARY_FAIL;
+    log_error_state("Failed to initialize libCURL with the write callback. "
+                    "Error code=%d (%s)", curl_rc, curl_err_string);
+    goto exit_label;
+  }
+
+  /***************************************************************************/
+  /* some servers don't like requests that are made without a user-agent     */
+  /* field, so we provide one.                                               */
+  /***************************************************************************/
+  curl_rc = curl_easy_setopt(curl_handle,
+                             CURLOPT_USERAGENT,
+                             "libcurl-agent/1.0");
+  if (curl_rc != CURLE_OK)
+  {
+    rc = EVEL_CURL_LIBRARY_FAIL;
+    log_error_state("Failed to initialize libCURL to upload. "
+                    "Error code=%d (%s)", curl_rc, curl_err_string);
+    goto exit_label;
+  }
+
+  /***************************************************************************/
+  /* Specify that we are going to POST data.                                 */
+  /***************************************************************************/
+  curl_rc = curl_easy_setopt(curl_handle, CURLOPT_POST, 1L);
+  if (curl_rc != CURLE_OK)
+  {
+    rc = EVEL_CURL_LIBRARY_FAIL;
+    log_error_state("Failed to initialize libCURL to upload. "
+                    "Error code=%d (%s)", curl_rc, curl_err_string);
+    goto exit_label;
+  }
+
+  /***************************************************************************/
+  /* we want to use our own read function.                                   */
+  /***************************************************************************/
+  curl_rc = curl_easy_setopt(curl_handle, CURLOPT_READFUNCTION, read_callback);
+  if (curl_rc != CURLE_OK)
+  {
+    rc = EVEL_CURL_LIBRARY_FAIL;
+    log_error_state("Failed to initialize libCURL to upload using read "
+                    "function. Error code=%d (%s)", curl_rc, curl_err_string);
+    goto exit_label;
+  }
+
+  /***************************************************************************/
+  /* All of our events are JSON encoded.  We also suppress the               */
+  /* Expect: 100-continue   header that we would otherwise get since it      */
+  /* confuses some servers.                                                  */
+  /*                                                                         */
+  /* @TODO: do AT&T want this behavior?                                      */
+  /***************************************************************************/
+  hdr_chunk = curl_slist_append(hdr_chunk, "Content-type: application/json");
+  hdr_chunk = curl_slist_append(hdr_chunk, "Expect:");
+
+  /***************************************************************************/
+  /* set our custom set of headers.                                         */
+  /***************************************************************************/
+  curl_rc = curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, hdr_chunk);
+  if (curl_rc != CURLE_OK)
+  {
+    rc = EVEL_CURL_LIBRARY_FAIL;
+    log_error_state("Failed to initialize libCURL to use custom headers. "
+                    "Error code=%d (%s)", curl_rc, curl_err_string);
+    goto exit_label;
+  }
+
+  /***************************************************************************/
+  /* Set the timeout for the operation.                                      */
+  /***************************************************************************/
+  curl_rc = curl_easy_setopt(curl_handle,
+                             CURLOPT_TIMEOUT,
+                             EVEL_API_TIMEOUT);
+  if (curl_rc != CURLE_OK)
+  {
+    rc = EVEL_CURL_LIBRARY_FAIL;
+    log_error_state("Failed to initialize libCURL for API timeout. "
+                    "Error code=%d (%s)", curl_rc, curl_err_string);
+    goto exit_label;
+  }
+
+  /***************************************************************************/
+  /* Set that we want Basic authentication with username:password Base-64    */
+  /* encoded for the operation.                                              */
+  /***************************************************************************/
+  curl_rc = curl_easy_setopt(curl_handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
+  if (curl_rc != CURLE_OK)
+  {
+    rc = EVEL_CURL_LIBRARY_FAIL;
+    log_error_state("Failed to initialize libCURL for Basic Authentication. "
+                    "Error code=%d (%s)", curl_rc, curl_err_string);
+    goto exit_label;
+  }
+  curl_rc = curl_easy_setopt(curl_handle, CURLOPT_USERNAME, username);
+  if (curl_rc != CURLE_OK)
+  {
+    rc = EVEL_CURL_LIBRARY_FAIL;
+    log_error_state("Failed to initialize libCURL with username. "
+                    "Error code=%d (%s)", curl_rc, curl_err_string);
+    goto exit_label;
+  }
+  curl_rc = curl_easy_setopt(curl_handle, CURLOPT_PASSWORD, password);
+  if (curl_rc != CURLE_OK)
+  {
+    rc = EVEL_CURL_LIBRARY_FAIL;
+    log_error_state("Failed to initialize libCURL with password. "
+                    "Error code=%d (%s)", curl_rc, curl_err_string);
+    goto exit_label;
+  }
+
+  /***************************************************************************/
+  /* Initialize a message ring-buffer to be used between the foreground and  */
+  /* the thread which sends the messages.  This can't fail.                  */
+  /***************************************************************************/
+  ring_buffer_initialize(&event_buffer, EVEL_EVENT_BUFFER_DEPTH);
+
+  /***************************************************************************/
+  /* Initialize the priority post buffer to empty.                           */
+  /***************************************************************************/
+  priority_post.memory = NULL;
+
+exit_label:
+  EVEL_EXIT();
+
+  return(rc);
+}
+
+/**************************************************************************//**
+ * Run the event handler.
+ *
+ * Spawns the thread responsible for handling events and sending them to the
+ * API.
+ *
+ *  @return Status code.
+ *  @retval ::EVEL_SUCCESS if everything OK.
+ *  @retval One of ::EVEL_ERR_CODES if there was a problem.
+ *****************************************************************************/
+EVEL_ERR_CODES event_handler_run()
+{
+  EVEL_ERR_CODES rc = EVEL_SUCCESS;
+  int pthread_rc = 0;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Start the event handler thread.                                         */
+  /***************************************************************************/
+  evt_handler_state = EVT_HANDLER_INACTIVE;
+  pthread_rc = pthread_create(&evt_handler_thread, NULL, event_handler, NULL);
+  if (pthread_rc != 0)
+  {
+    rc = EVEL_PTHREAD_LIBRARY_FAIL;
+    log_error_state("Failed to start event handler thread. "
+                    "Error code=%d", pthread_rc);
+  }
+
+  EVEL_EXIT()
+  return rc;
+}
+
+/**************************************************************************//**
+ * Terminate the event handler.
+ *
+ * Shuts down the event handler thread in as clean a way as possible. Sets the
+ * global exit flag and then signals the thread to interrupt it since it's
+ * most likely waiting on the ring-buffer.
+ *
+ * Having achieved an orderly shutdown of the event handler thread, clean up
+ * the cURL library's resources cleanly.
+ *
+ *  @return Status code.
+ *  @retval ::EVEL_SUCCESS if everything OK.
+ *  @retval One of ::EVEL_ERR_CODES if there was a problem.
+ *****************************************************************************/
+EVEL_ERR_CODES event_handler_terminate()
+{
+  EVEL_ERR_CODES rc = EVEL_SUCCESS;
+
+  EVEL_ENTER();
+  EVENT_INTERNAL *event = NULL;
+
+  /***************************************************************************/
+  /* Make sure that we were initialized before trying to terminate the       */
+  /* event handler thread.                                                   */
+  /***************************************************************************/
+  if (evt_handler_state != EVT_HANDLER_UNINITIALIZED)
+  {
+    /*************************************************************************/
+    /* Make sure that the event handler knows it's time to die.              */
+    /*************************************************************************/
+    event = evel_new_internal_event(EVT_CMD_TERMINATE);
+    if (event == NULL)
+    {
+      /***********************************************************************/
+      /* We failed to get an event, but we don't bail out - we will just     */
+      /* clean up what we can and continue on our way, since we're exiting   */
+      /* anyway.                                                             */
+      /***********************************************************************/
+      EVEL_ERROR("Failed to get internal event - perform dirty exit instead!");
+    }
+    else
+    {
+      /***********************************************************************/
+      /* Post the event then wait for the Event Handler to exit.  Set the    */
+      /* global command, too, in case the ring-buffer is full.               */
+      /***********************************************************************/
+      EVEL_DEBUG("Sending event to Event Hander to request it to exit.");
+      evt_handler_state = EVT_HANDLER_REQUEST_TERMINATE;
+      evel_post_event((EVENT_HEADER *) event);
+      pthread_join(evt_handler_thread, NULL);
+      EVEL_DEBUG("Event Handler thread has exited.");
+    }
+  }
+  else
+  {
+    EVEL_DEBUG("Event handler was not initialized, so no need to kill it");
+  }
+
+  /***************************************************************************/
+  /* Clean-up the cURL library.                                              */
+  /***************************************************************************/
+  if (curl_handle != NULL)
+  {
+    curl_easy_cleanup(curl_handle);
+    curl_handle = NULL;
+  }
+  if (hdr_chunk != NULL)
+  {
+    curl_slist_free_all(hdr_chunk);
+    hdr_chunk = NULL;
+  }
+
+  /***************************************************************************/
+  /* Free off the stored API URL strings.                                    */
+  /***************************************************************************/
+  if (evel_event_api_url != NULL)
+  {
+    free(evel_event_api_url);
+    evel_event_api_url = NULL;
+  }
+  if (evel_throt_api_url != NULL)
+  {
+    free(evel_throt_api_url);
+    evel_throt_api_url = NULL;
+  }
+
+  EVEL_EXIT();
+  return rc;
+}
+
+/**************************************************************************//**
+ * Post an event.
+ *
+ * @note  So far as the caller is concerned, successfully posting the event
+ * relinquishes all responsibility for the event - the library will take care
+ * of freeing the event in due course.
+
+ * @param event   The event to be posted.
+ *
+ * @returns Status code
+ * @retval  EVEL_SUCCESS On success
+ * @retval  "One of ::EVEL_ERR_CODES" On failure.
+ *****************************************************************************/
+EVEL_ERR_CODES evel_post_event(EVENT_HEADER * event)
+{
+  int rc = EVEL_SUCCESS;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(event != NULL);
+
+  /***************************************************************************/
+  /* We need to make sure that we are either initializing or running         */
+  /* normally before writing the event into the buffer so that we can        */
+  /* guarantee that the ring-buffer empties  properly on exit.               */
+  /***************************************************************************/
+  if ((evt_handler_state == EVT_HANDLER_ACTIVE) ||
+      (evt_handler_state == EVT_HANDLER_INACTIVE) ||
+      (evt_handler_state == EVT_HANDLER_REQUEST_TERMINATE))
+  {
+    if (ring_buffer_write(&event_buffer, event) == 0)
+    {
+      log_error_state("Failed to write event to buffer - event dropped!");
+      rc = EVEL_EVENT_BUFFER_FULL;
+      evel_free_event(event);
+    }
+  }
+  else
+  {
+    /*************************************************************************/
+    /* System is not in active operation, so reject the event.               */
+    /*************************************************************************/
+    log_error_state("Event Handler system not active - event dropped!");
+    rc = EVEL_EVENT_HANDLER_INACTIVE;
+    evel_free_event(event);
+  }
+
+  EVEL_EXIT();
+  return (rc);
+}
+
+/**************************************************************************//**
+ * Post an event to the Vendor Event Listener API.
+ *
+ * @returns Status code
+ * @retval  EVEL_SUCCESS On success
+ * @retval  "One of ::EVEL_ERR_CODES" On failure.
+ *****************************************************************************/
+static EVEL_ERR_CODES evel_post_api(char * msg, size_t size)
+{
+  int rc = EVEL_SUCCESS;
+  CURLcode curl_rc = CURLE_OK;
+  MEMORY_CHUNK rx_chunk;
+  MEMORY_CHUNK tx_chunk;
+  int http_response_code = 0;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Create the memory chunk to be used for the response to the post.  The   */
+  /* will be realloced.                                                      */
+  /***************************************************************************/
+  rx_chunk.memory = malloc(1);
+  assert(rx_chunk.memory != NULL);
+  rx_chunk.size = 0;
+
+  /***************************************************************************/
+  /* Create the memory chunk to be sent as the body of the post.             */
+  /***************************************************************************/
+  tx_chunk.memory = msg;
+  tx_chunk.size = size;
+  EVEL_DEBUG("Sending chunk of size %d", tx_chunk.size);
+
+  /***************************************************************************/
+  /* Point to the data to be received.                                       */
+  /***************************************************************************/
+  curl_rc = curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &rx_chunk);
+  if (curl_rc != CURLE_OK)
+  {
+    rc = EVEL_CURL_LIBRARY_FAIL;
+    log_error_state("Failed to initialize libCURL to upload. "
+                    "Error code=%d (%s)", curl_rc, curl_err_string);
+    goto exit_label;
+  }
+  EVEL_DEBUG("Initialized data to receive");
+
+  /***************************************************************************/
+  /* Pointer to pass to our read function                                    */
+  /***************************************************************************/
+  curl_rc = curl_easy_setopt(curl_handle, CURLOPT_READDATA, &tx_chunk);
+  if (curl_rc != CURLE_OK)
+  {
+    rc = EVEL_CURL_LIBRARY_FAIL;
+    log_error_state("Failed to set upload data for libCURL to upload. "
+                    "Error code=%d (%s)", curl_rc, curl_err_string);
+    goto exit_label;
+  }
+  EVEL_DEBUG("Initialized data to send");
+
+  /***************************************************************************/
+  /* Size of the data to transmit.                                           */
+  /***************************************************************************/
+  curl_rc = curl_easy_setopt(curl_handle,
+                             CURLOPT_POSTFIELDSIZE,
+                             tx_chunk.size);
+  if (curl_rc != CURLE_OK)
+  {
+    rc = EVEL_CURL_LIBRARY_FAIL;
+    log_error_state("Failed to set length of upload data for libCURL to "
+                    "upload.  Error code=%d (%s)", curl_rc, curl_err_string);
+    goto exit_label;
+  }
+  EVEL_DEBUG("Initialized length of data to send");
+
+  /***************************************************************************/
+  /* Now run off and do what you've been told!                               */
+  /***************************************************************************/
+  curl_rc = curl_easy_perform(curl_handle);
+  if (curl_rc != CURLE_OK)
+  {
+    rc = EVEL_CURL_LIBRARY_FAIL;
+    log_error_state("Failed to transfer an event to Vendor Event Listener! "
+                    "Error code=%d (%s)", curl_rc, curl_err_string);
+    EVEL_ERROR("Dropped event: %s", msg);
+    goto exit_label;
+  }
+
+  /***************************************************************************/
+  /* See what response we got - any 2XX response is good.                    */
+  /***************************************************************************/
+  curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &http_response_code);
+  EVEL_DEBUG("HTTP response code: %d", http_response_code);
+  if ((http_response_code / 100) == 2)
+  {
+    /*************************************************************************/
+    /* If the server responded with data it may be interesting but not a     */
+    /* problem.                                                              */
+    /*************************************************************************/
+    if ((rx_chunk.size > 0) && (rx_chunk.memory != NULL))
+    {
+      EVEL_DEBUG("Server returned data = %d (%s)",
+                 rx_chunk.size,
+                 rx_chunk.memory);
+
+      /***********************************************************************/
+      /* If this is a response to priority post, then we're not interested.  */
+      /***********************************************************************/
+      if (priority_post.memory != NULL)
+      {
+        EVEL_ERROR("Ignoring priority post response");
+      }
+      else
+      {
+        evel_handle_event_response(&rx_chunk, &priority_post);
+      }
+    }
+  }
+  else
+  {
+    EVEL_ERROR("Unexpected HTTP response code: %d with data size %d (%s)",
+                http_response_code,
+                rx_chunk.size,
+                rx_chunk.size > 0 ? rx_chunk.memory : "NONE");
+    EVEL_ERROR("Potentially dropped event: %s", msg);
+  }
+
+exit_label:
+  free(rx_chunk.memory);
+  EVEL_EXIT();
+  return(rc);
+}
+
+/**************************************************************************//**
+ * Callback function to provide data to send.
+ *
+ * Copy data into the supplied buffer, read_callback::ptr, checking size
+ * limits.
+ *
+ * @returns   Number of bytes placed into read_callback::ptr. 0 for EOF.
+ *****************************************************************************/
+static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp)
+{
+  size_t rtn = 0;
+  size_t bytes_to_write = 0;
+  MEMORY_CHUNK *tx_chunk = (MEMORY_CHUNK *)userp;
+
+  EVEL_ENTER();
+
+  bytes_to_write = min(size*nmemb, tx_chunk->size);
+
+  if (bytes_to_write > 0)
+  {
+    EVEL_DEBUG("Going to try to write %d bytes", bytes_to_write);
+    strncpy((char *)ptr, tx_chunk->memory, bytes_to_write);
+    tx_chunk->memory += bytes_to_write;
+    tx_chunk->size -= bytes_to_write;
+    rtn = bytes_to_write;
+  }
+  else
+  {
+    EVEL_DEBUG("Reached EOF");
+  }
+
+  EVEL_EXIT();
+  return rtn;
+}
+
+/**************************************************************************//**
+ * Callback function to provide returned data.
+ *
+ * Copy data into the supplied buffer, write_callback::ptr, checking size
+ * limits.
+ *
+ * @returns   Number of bytes placed into write_callback::ptr. 0 for EOF.
+ *****************************************************************************/
+size_t evel_write_callback(void *contents,
+                             size_t size,
+                             size_t nmemb,
+                             void *userp)
+{
+  size_t realsize = size * nmemb;
+  MEMORY_CHUNK * rx_chunk = (MEMORY_CHUNK *)userp;
+
+  EVEL_ENTER();
+
+  EVEL_DEBUG("Called with %d chunks of %d size = %d", nmemb, size, realsize);
+  EVEL_DEBUG("rx chunk size is %d", rx_chunk->size);
+
+  rx_chunk->memory = realloc(rx_chunk->memory, rx_chunk->size + realsize + 1);
+  if(rx_chunk->memory == NULL) {
+    /* out of memory! */
+    printf("not enough memory (realloc returned NULL)\n");
+    return 0;
+  }
+
+  memcpy(&(rx_chunk->memory[rx_chunk->size]), contents, realsize);
+  rx_chunk->size += realsize;
+  rx_chunk->memory[rx_chunk->size] = 0;
+
+  EVEL_DEBUG("Rx data: %s", rx_chunk->memory);
+  EVEL_DEBUG("Returning: %d", realsize);
+
+  EVEL_EXIT();
+  return realsize;
+}
+
+/**************************************************************************//**
+ * Event Handler.
+ *
+ * Watch for messages coming on the internal queue and send them to the
+ * listener.
+ *
+ * param[in]  arg  Argument - unused.
+ *****************************************************************************/
+static void * event_handler(void * arg __attribute__ ((unused)))
+{
+  int old_type = 0;
+  EVENT_HEADER * msg = NULL;
+  EVENT_INTERNAL * internal_msg = NULL;
+  int json_size = 0;
+  char json_body[EVEL_MAX_JSON_BODY];
+  int rc = EVEL_SUCCESS;
+  CURLcode curl_rc;
+
+  EVEL_INFO("Event handler thread started");
+
+  /***************************************************************************/
+  /* Set this thread to be cancellable immediately.                          */
+  /***************************************************************************/
+  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old_type);
+
+  /***************************************************************************/
+  /* Set the handler as active, defending against weird situations like      */
+  /* immediately shutting down after initializing the library so the         */
+  /* handler never gets started up properly.                                 */
+  /***************************************************************************/
+  if (evt_handler_state == EVT_HANDLER_INACTIVE)
+  {
+    evt_handler_state = EVT_HANDLER_ACTIVE;
+  }
+  else
+  {
+    EVEL_ERROR("Event Handler State was not INACTIVE at start-up - "
+               "Handler will exit immediately!");
+  }
+
+  while (evt_handler_state == EVT_HANDLER_ACTIVE)
+  {
+    /*************************************************************************/
+    /* Wait for a message to be received.                                    */
+    /*************************************************************************/
+    EVEL_DEBUG("Event handler getting any messages");
+    msg = ring_buffer_read(&event_buffer);
+
+    /*************************************************************************/
+    /* Internal events get special treatment while regular events get posted */
+    /* to the far side.                                                      */
+    /*************************************************************************/
+    if (msg->event_domain != EVEL_DOMAIN_INTERNAL)
+    {
+      EVEL_DEBUG("External event received");
+
+      /***********************************************************************/
+      /* Encode the event in JSON.                                           */
+      /***********************************************************************/
+      json_size = evel_json_encode_event(json_body, EVEL_MAX_JSON_BODY, msg);
+
+      /***********************************************************************/
+      /* Send the JSON across the API.                                       */
+      /***********************************************************************/
+      EVEL_DEBUG("Sending JSON of size %d is: %s", json_size, json_body);
+      rc = evel_post_api(json_body, json_size);
+      if (rc != EVEL_SUCCESS)
+      {
+        EVEL_ERROR("Failed to transfer the data. Error code=%d", rc);
+      }
+    }
+    else
+    {
+      EVEL_DEBUG("Internal event received");
+      internal_msg = (EVENT_INTERNAL *) msg;
+      assert(internal_msg->command == EVT_CMD_TERMINATE);
+      evt_handler_state = EVT_HANDLER_TERMINATING;
+    }
+
+    /*************************************************************************/
+    /* We are responsible for freeing the memory.                            */
+    /*************************************************************************/
+    evel_free_event(msg);
+    msg = NULL;
+
+    /*************************************************************************/
+    /* There may be a single priority post to be sent.                       */
+    /*************************************************************************/
+    if (priority_post.memory != NULL)
+    {
+      EVEL_DEBUG("Priority Post");
+
+      /***********************************************************************/
+      /* Set the URL for the throttling API.                                 */
+      /***********************************************************************/
+      curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, evel_throt_api_url);
+      if (curl_rc != CURLE_OK)
+      {
+        /*********************************************************************/
+        /* This is only likely to happen with CURLE_OUT_OF_MEMORY, in which  */
+        /* case we carry on regardless.                                      */
+        /*********************************************************************/
+        EVEL_ERROR("Failed to set throttling URL. Error code=%d", rc);
+      }
+      else
+      {
+        rc = evel_post_api(priority_post.memory, priority_post.size);
+        if (rc != EVEL_SUCCESS)
+        {
+          EVEL_ERROR("Failed to transfer priority post. Error code=%d", rc);
+        }
+      }
+
+      /***********************************************************************/
+      /* Reinstate the URL for the event API.                                */
+      /***********************************************************************/
+      curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, evel_event_api_url);
+      if (curl_rc != CURLE_OK)
+      {
+        /*********************************************************************/
+        /* This is only likely to happen with CURLE_OUT_OF_MEMORY, in which  */
+        /* case we carry on regardless.                                      */
+        /*********************************************************************/
+        EVEL_ERROR("Failed to reinstate events URL. Error code=%d", rc);
+      }
+
+      /***********************************************************************/
+      /* We are responsible for freeing the memory.                          */
+      /***********************************************************************/
+      free(priority_post.memory);
+      priority_post.memory = NULL;
+    }
+  }
+
+  /***************************************************************************/
+  /* The event handler is now exiting. The ring-buffer could contain events  */
+  /* which have not been processed, so deplete those.  Because we've been    */
+  /* asked to exit we can be confident that the foreground will have stopped */
+  /* sending events in so we know that this process will conclude!           */
+  /***************************************************************************/
+  evt_handler_state = EVT_HANDLER_TERMINATING;
+  while (!ring_buffer_is_empty(&event_buffer))
+  {
+    EVEL_DEBUG("Reading event from buffer");
+    msg = ring_buffer_read(&event_buffer);
+    evel_free_event(msg);
+  }
+  evt_handler_state = EVT_HANDLER_TERMINATED;
+  EVEL_INFO("Event handler thread stopped");
+
+  return (NULL);
+}
+
+/**************************************************************************//**
+ * Handle a JSON response from the listener, contained in a ::MEMORY_CHUNK.
+ *
+ * Tokenize the response, and decode any tokens found.
+ *
+ * @param chunk         The memory chunk containing the response.
+ * @param post          The memory chunk in which to place any resulting POST.
+ *****************************************************************************/
+void evel_handle_event_response(const MEMORY_CHUNK * const chunk,
+                                MEMORY_CHUNK * const post)
+{
+  jsmn_parser json_parser;
+  jsmntok_t json_tokens[EVEL_MAX_RESPONSE_TOKENS];
+  int num_tokens = 0;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(chunk != NULL);
+  assert(priority_post.memory == NULL);
+
+  EVEL_DEBUG("Response size = %d", chunk->size);
+  EVEL_DEBUG("Response = %s", chunk->memory);
+
+  /***************************************************************************/
+  /* Initialize the parser and tokenize the response.                        */
+  /***************************************************************************/
+  jsmn_init(&json_parser);
+  num_tokens = jsmn_parse(&json_parser,
+                          chunk->memory,
+                          chunk->size,
+                          json_tokens,
+                          EVEL_MAX_RESPONSE_TOKENS);
+
+  if (num_tokens < 0)
+  {
+    EVEL_ERROR("Failed to parse JSON response.  "
+               "Error code=%d", num_tokens);
+  }
+  else if (num_tokens == 0)
+  {
+    EVEL_DEBUG("No tokens found in JSON response");
+  }
+  else
+  {
+    EVEL_DEBUG("Decode JSON response tokens");
+    if (!evel_handle_response_tokens(chunk, json_tokens, num_tokens, post))
+    {
+      EVEL_ERROR("Failed to handle JSON response.");
+    }
+  }
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Handle a JSON response from the listener, as a list of tokens from JSMN.
+ *
+ * @param chunk         Memory chunk containing the JSON buffer.
+ * @param json_tokens   Array of tokens to handle.
+ * @param num_tokens    The number of tokens to handle.
+ * @param post          The memory chunk in which to place any resulting POST.
+ * @return true if we handled the response, false otherwise.
+ *****************************************************************************/
+bool evel_handle_response_tokens(const MEMORY_CHUNK * const chunk,
+                                 const jsmntok_t * const json_tokens,
+                                 const int num_tokens,
+                                 MEMORY_CHUNK * const post)
+{
+  bool json_ok = false;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(chunk != NULL);
+  assert(json_tokens != NULL);
+  assert(num_tokens < EVEL_MAX_RESPONSE_TOKENS);
+
+  /***************************************************************************/
+  /* Peek at the tokens to decide what the response it, then call the        */
+  /* appropriate handler to handle it.  There is only one handler at this    */
+  /* point.                                                                  */
+  /***************************************************************************/
+  if (evel_tokens_match_command_list(chunk, json_tokens, num_tokens))
+  {
+    json_ok = evel_handle_command_list(chunk, json_tokens, num_tokens, post);
+  }
+
+  EVEL_EXIT();
+
+  return json_ok;
+}
+
+/**************************************************************************//**
+ * Determine whether a list of tokens looks like a "commandList" response.
+ *
+ * @param chunk         Memory chunk containing the JSON buffer.
+ * @param json_tokens   Token to check.
+ * @param num_tokens    The number of tokens to handle.
+ * @return true if the tokens look like a "commandList" match, or false.
+ *****************************************************************************/
+bool evel_tokens_match_command_list(const MEMORY_CHUNK * const chunk,
+                                    const jsmntok_t * const json_tokens,
+                                    const int num_tokens)
+{
+  bool result = false;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Make some checks on the basic layout of the commandList.                */
+  /***************************************************************************/
+  if ((num_tokens > 3) &&
+      (json_tokens[0].type == JSMN_OBJECT) &&
+      (json_tokens[1].type == JSMN_STRING) &&
+      (json_tokens[2].type == JSMN_ARRAY) &&
+      (evel_token_equals_string(chunk, &json_tokens[1], "commandList")))
+  {
+    result = true;
+  }
+
+  EVEL_EXIT();
+
+  return result;
+}
+
+/**************************************************************************//**
+ * Check that a string token matches a given input string.
+ *
+ * @param chunk         Memory chunk containing the JSON buffer.
+ * @param json_token    Token to check.
+ * @param check_string  String to check it against.
+ * @return true if the strings match, or false.
+ *****************************************************************************/
+bool evel_token_equals_string(const MEMORY_CHUNK * const chunk,
+                              const jsmntok_t * json_token,
+                              const char * check_string)
+{
+  bool result = false;
+
+  EVEL_ENTER();
+
+  const int token_length = json_token->end - json_token->start;
+  const char * const token_string = chunk->memory + json_token->start;
+
+  if (token_length == (int)strlen(check_string))
+  {
+    result = (strncmp(token_string, check_string, token_length) == 0);
+  }
+
+  EVEL_EXIT();
+
+  return result;
+}
diff --git a/vnfs/VES/code/evel_library/evel_fault.c b/vnfs/VES/code/evel_library/evel_fault.c
new file mode 100644 (file)
index 0000000..cbb80d7
--- /dev/null
@@ -0,0 +1,337 @@
+/**************************************************************************//**
+ * @file
+ * Implementation of EVEL functions relating to the Fault.
+ *
+ * License
+ * -------
+ *
+ * Copyright(c) <2016>, AT&T Intellectual Property.  All other rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:  This product includes
+ *    software developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "evel.h"
+#include "evel_internal.h"
+#include "evel_throttle.h"
+
+/**************************************************************************//**
+ * Create a new fault event.
+ *
+ * @note    The mandatory fields on the Fault must be supplied to this factory
+ *          function and are immutable once set.  Optional fields have explicit
+ *          setter functions, but again values may only be set once so that the
+ *          Fault has immutable properties.
+ * @param   condition   The condition indicated by the Fault.
+ * @param   specific_problem  The specific problem triggering the fault.
+ * @param   priority    The priority of the event.
+ * @param   severity    The severity of the Fault.
+ * @returns pointer to the newly manufactured ::EVENT_FAULT.  If the event is
+ *          not used (i.e. posted) it must be released using ::evel_free_fault.
+ * @retval  NULL  Failed to create the event.
+ *****************************************************************************/
+EVENT_FAULT * evel_new_fault(const char * const condition,
+                             const char * const specific_problem,
+                             EVEL_EVENT_PRIORITIES priority,
+                             EVEL_SEVERITIES severity)
+{
+  EVENT_FAULT * fault = NULL;
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(condition != NULL);
+  assert(specific_problem != NULL);
+  assert(priority < EVEL_MAX_PRIORITIES);
+  assert(severity < EVEL_MAX_SEVERITIES);
+
+  /***************************************************************************/
+  /* Allocate the fault.                                                     */
+  /***************************************************************************/
+  fault = malloc(sizeof(EVENT_FAULT));
+  if (fault == NULL)
+  {
+    log_error_state("Out of memory");
+    goto exit_label;
+  }
+  memset(fault, 0, sizeof(EVENT_FAULT));
+  EVEL_DEBUG("New fault is at %lp", fault);
+
+  /***************************************************************************/
+  /* Initialize the header & the fault fields.  Optional string values are   */
+  /* uninitialized (NULL).                                                   */
+  /***************************************************************************/
+  evel_init_header(&fault->header);
+  fault->header.event_domain = EVEL_DOMAIN_FAULT;
+  fault->header.priority = priority;
+  fault->major_version = EVEL_FAULT_MAJOR_VERSION;
+  fault->minor_version = EVEL_FAULT_MINOR_VERSION;
+  fault->event_severity = severity;
+  fault->event_source_type = event_source_type;
+  fault->vf_status = EVEL_VF_STATUS_ACTIVE;
+  fault->alarm_condition = strdup(condition);
+  fault->specific_problem = strdup(specific_problem);
+  evel_init_option_string(&fault->alarm_interface_a);
+  dlist_initialize(&fault->additional_info);
+
+exit_label:
+  EVEL_EXIT();
+  return fault;
+}
+
+/**************************************************************************//**
+ * Add an additional value name/value pair to the Fault.
+ *
+ * The name and value are null delimited ASCII strings.  The library takes
+ * a copy so the caller does not have to preserve values after the function
+ * returns.
+ *
+ * @param fault     Pointer to the fault.
+ * @param name      ASCIIZ string with the attribute's name.  The caller
+ *                  does not need to preserve the value once the function
+ *                  returns.
+ * @param value     ASCIIZ string with the attribute's value.  The caller
+ *                  does not need to preserve the value once the function
+ *                  returns.
+ *****************************************************************************/
+void evel_fault_addl_info_add(EVENT_FAULT * fault, char * name, char * value)
+{
+  FAULT_ADDL_INFO * addl_info = NULL;
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(fault != NULL);
+  assert(fault->header.event_domain == EVEL_DOMAIN_FAULT);
+  assert(name != NULL);
+  assert(value != NULL);
+
+  EVEL_DEBUG("Adding name=%s value=%s", name, value);
+  addl_info = malloc(sizeof(FAULT_ADDL_INFO));
+  assert(addl_info != NULL);
+  memset(addl_info, 0, sizeof(FAULT_ADDL_INFO));
+  addl_info->name = strdup(name);
+  addl_info->value = strdup(value);
+  assert(addl_info->name != NULL);
+  assert(addl_info->value != NULL);
+
+  dlist_push_last(&fault->additional_info, addl_info);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Alarm Interface A property of the Fault.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param fault      Pointer to the fault.
+ * @param interface  The Alarm Interface A to be set. ASCIIZ string. The caller
+ *                   does not need to preserve the value once the function
+ *                   returns.
+ *****************************************************************************/
+void evel_fault_interface_set(EVENT_FAULT * fault,
+                              const char * const interface)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(fault != NULL);
+  assert(fault->header.event_domain == EVEL_DOMAIN_FAULT);
+  assert(interface != NULL);
+
+  evel_set_option_string(&fault->alarm_interface_a,
+                         interface,
+                         "Alarm Interface A");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Event Type property of the Fault.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param fault      Pointer to the fault.
+ * @param type       The Event Type to be set. ASCIIZ string. The caller
+ *                   does not need to preserve the value once the function
+ *                   returns.
+ *****************************************************************************/
+void evel_fault_type_set(EVENT_FAULT * fault, const char * const type)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_header_type_set.                      */
+  /***************************************************************************/
+  assert(fault != NULL);
+  assert(fault->header.event_domain == EVEL_DOMAIN_FAULT);
+  evel_header_type_set(&fault->header, type);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Encode the fault in JSON according to AT&T's schema for the fault type.
+ *
+ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
+ * @param event         Pointer to the ::EVENT_HEADER to encode.
+ *****************************************************************************/
+void evel_json_encode_fault(EVEL_JSON_BUFFER * jbuf,
+                            EVENT_FAULT * event)
+{
+  FAULT_ADDL_INFO * addl_info = NULL;
+  DLIST_ITEM * addl_info_item = NULL;
+  char * fault_severity;
+  char * fault_source_type;
+  char * fault_vf_status;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_FAULT);
+
+  fault_severity = evel_severity(event->event_severity);
+  fault_source_type = evel_source_type(event->event_source_type);
+  fault_vf_status = evel_vf_status(event->vf_status);
+
+  evel_json_encode_header(jbuf, &event->header);
+  evel_json_open_named_object(jbuf, "faultFields");
+
+  /***************************************************************************/
+  /* Mandatory fields.                                                       */
+  /***************************************************************************/
+  evel_enc_kv_string(jbuf, "alarmCondition", event->alarm_condition);
+  evel_enc_kv_string(jbuf, "eventSeverity", fault_severity);
+  evel_enc_kv_string(jbuf, "eventSourceType", fault_source_type);
+  evel_enc_kv_string(jbuf, "specificProblem", event->specific_problem);
+  evel_enc_kv_string(jbuf, "vfStatus", fault_vf_status);
+  evel_enc_version(
+    jbuf, "faultFieldsVersion", event->major_version, event->minor_version);
+
+  /***************************************************************************/
+  /* Optional fields.                                                        */
+  /***************************************************************************/
+
+  /***************************************************************************/
+  /* Checkpoint, so that we can wind back if all fields are suppressed.      */
+  /***************************************************************************/
+  evel_json_checkpoint(jbuf);
+  if (evel_json_open_opt_named_list(jbuf, "alarmAdditionalInformation"))
+  {
+    bool item_added = false;
+
+    addl_info_item = dlist_get_first(&event->additional_info);
+    while (addl_info_item != NULL)
+    {
+      addl_info = (FAULT_ADDL_INFO*) addl_info_item->item;
+      assert(addl_info != NULL);
+
+      if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec,
+                                          "alarmAdditionalInformation",
+                                          addl_info->name))
+      {
+        evel_json_open_object(jbuf);
+        evel_enc_kv_string(jbuf, "name", addl_info->name);
+        evel_enc_kv_string(jbuf, "value", addl_info->value);
+        evel_json_close_object(jbuf);
+        item_added = true;
+      }
+      addl_info_item = dlist_get_next(addl_info_item);
+    }
+    evel_json_close_list(jbuf);
+
+    /*************************************************************************/
+    /* If we've not written anything, rewind to before we opened the list.   */
+    /*************************************************************************/
+    if (!item_added)
+    {
+      evel_json_rewind(jbuf);
+    }
+  }
+  evel_enc_kv_opt_string(jbuf, "alarmInterfaceA", &event->alarm_interface_a);
+
+  evel_json_close_object(jbuf);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Free a Fault.
+ *
+ * Free off the Fault supplied.  Will free all the contained allocated memory.
+ *
+ * @note It does not free the Fault itself, since that may be part of a
+ * larger structure.
+ *****************************************************************************/
+void evel_free_fault(EVENT_FAULT * event)
+{
+  FAULT_ADDL_INFO * addl_info = NULL;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.  As an internal API we don't allow freeing NULL    */
+  /* events as we do on the public API.                                      */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_FAULT);
+
+  /***************************************************************************/
+  /* Free all internal strings then the header itself.                       */
+  /***************************************************************************/
+  addl_info = dlist_pop_last(&event->additional_info);
+  while (addl_info != NULL)
+  {
+    EVEL_DEBUG("Freeing Additional Info (%s, %s)",
+               addl_info->name,
+               addl_info->value);
+    free(addl_info->name);
+    free(addl_info->value);
+    free(addl_info);
+    addl_info = dlist_pop_last(&event->additional_info);
+  }
+  free(event->alarm_condition);
+  evel_free_option_string(&event->alarm_interface_a);
+  free(event->specific_problem);
+  evel_free_header(&event->header);
+
+  EVEL_EXIT();
+}
diff --git a/vnfs/VES/code/evel_library/evel_internal.h b/vnfs/VES/code/evel_library/evel_internal.h
new file mode 100644 (file)
index 0000000..fc887c9
--- /dev/null
@@ -0,0 +1,867 @@
+#ifndef EVEL_INTERNAL_INCLUDED
+#define EVEL_INTERNAL_INCLUDED
+
+/**************************************************************************//**
+ * @file
+ * EVEL internal definitions.
+ *
+ * These are internal definitions which need to be shared between modules
+ * within the library but are not intended for external consumption.
+ *
+ * License
+ * -------
+ *
+ * Copyright(c) <2016>, AT&T Intellectual Property.  All other rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:  This product includes
+ *    software developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "evel.h"
+
+/*****************************************************************************/
+/* Define some type-safe min/max macros.                                     */
+/*****************************************************************************/
+#define max(a,b) \
+   ({ __typeof__ (a) _a = (a); \
+       __typeof__ (b) _b = (b); \
+     _a > _b ? _a : _b; })
+
+#define min(a,b) \
+   ({ __typeof__ (a) _a = (a); \
+       __typeof__ (b) _b = (b); \
+     _a < _b ? _a : _b; })
+
+
+/**************************************************************************//**
+ * Compile-time assertion.
+ *****************************************************************************/
+#define EVEL_CT_ASSERT(X) switch (0) {case 0: case (X):;}
+
+/**************************************************************************//**
+ * The Functional Role of the equipment represented by this VNF.
+ *****************************************************************************/
+extern char * functional_role;
+
+/**************************************************************************//**
+ * The type of equipment represented by this VNF.
+ *****************************************************************************/
+extern EVEL_SOURCE_TYPES event_source_type;
+
+/**************************************************************************//**
+ * A chunk of memory used in the cURL functions.
+ *****************************************************************************/
+typedef struct memory_chunk {
+  char * memory;
+  size_t size;
+} MEMORY_CHUNK;
+
+/**************************************************************************//**
+ * Global commands that may be sent to the Event Handler thread.
+ *****************************************************************************/
+typedef enum {
+  EVT_CMD_TERMINATE,
+  EVT_CMD_MAX_COMMANDS
+} EVT_HANDLER_COMMAND;
+
+/**************************************************************************//**
+ * State of the Event Handler thread.
+ *****************************************************************************/
+typedef enum {
+  EVT_HANDLER_UNINITIALIZED,      /** The library cannot handle events.      */
+  EVT_HANDLER_INACTIVE,           /** The event handler thread not started.  */
+  EVT_HANDLER_ACTIVE,             /** The event handler thread is started.   */
+  EVT_HANDLER_REQUEST_TERMINATE,  /** Initial stages of shutdown.            */
+  EVT_HANDLER_TERMINATING,        /** The ring-buffer is being depleted.     */
+  EVT_HANDLER_TERMINATED,         /** The library is exited.                 */
+  EVT_HANDLER_MAX_STATES          /** Maximum number of valid states.        */
+} EVT_HANDLER_STATE;
+
+/**************************************************************************//**
+ * Internal event.
+ * Pseudo-event used for routing internal commands.
+ *****************************************************************************/
+typedef struct event_internal {
+  EVENT_HEADER header;
+  EVT_HANDLER_COMMAND command;
+} EVENT_INTERNAL;
+
+/**************************************************************************//**
+ * Suppressed NV pairs list entry.
+ * JSON equivalent field: suppressedNvPairs
+ *****************************************************************************/
+typedef struct evel_suppressed_nv_pairs {
+
+  /***************************************************************************/
+  /* Mandatory fields                                                        */
+  /* JSON equivalent field: nvPairFieldName                                  */
+  /***************************************************************************/
+  char * nv_pair_field_name;
+
+  /***************************************************************************/
+  /* Optional fields                                                         */
+  /* JSON equivalent field: suppressedNvPairNames                            */
+  /* Type of each list entry: char *                                         */
+  /***************************************************************************/
+  DLIST suppressed_nv_pair_names;
+
+  /***************************************************************************/
+  /* Hash table containing suppressed_nv_pair_names as keys.                 */
+  /***************************************************************************/
+  struct hsearch_data * hash_nv_pair_names;
+
+} EVEL_SUPPRESSED_NV_PAIRS;
+
+/**************************************************************************//**
+ * Event Throttling Specification for a domain which is in a throttled state.
+ * JSON equivalent object: eventThrottlingState
+ *****************************************************************************/
+typedef struct evel_throttle_spec {
+
+  /***************************************************************************/
+  /* List of field names to be suppressed.                                   */
+  /* JSON equivalent field: suppressedFieldNames                             */
+  /* Type of each list entry: char *                                         */
+  /***************************************************************************/
+  DLIST suppressed_field_names;
+
+  /***************************************************************************/
+  /* List of name-value pairs to be suppressed.                              */
+  /* JSON equivalent field: suppressedNvPairsList                            */
+  /* Type of each list entry: EVEL_SUPPRESSED_NV_PAIRS *                     */
+  /***************************************************************************/
+  DLIST suppressed_nv_pairs_list;
+
+  /***************************************************************************/
+  /* Hash table containing suppressed_nv_pair_names as keys.                 */
+  /***************************************************************************/
+  struct hsearch_data * hash_field_names;
+
+  /***************************************************************************/
+  /* Hash table containing nv_pair_field_name as keys, and                   */
+  /* suppressed_nv_pairs_list as values.                                     */
+  /***************************************************************************/
+  struct hsearch_data * hash_nv_pairs_list;
+
+} EVEL_THROTTLE_SPEC;
+
+/*****************************************************************************/
+/* RFC2822 format string for strftime.                                       */
+/*****************************************************************************/
+#define EVEL_RFC2822_STRFTIME_FORMAT "%a, %d %b %Y %T %z"
+
+/*****************************************************************************/
+/* EVEL_JSON_BUFFER depth at which we throttle fields.                       */
+/*****************************************************************************/
+#define EVEL_THROTTLE_FIELD_DEPTH 3
+
+/**************************************************************************//**
+ * Initialize the event handler.
+ *
+ * Primarily responsible for getting cURL ready for use.
+ *
+ * @param[in] event_api_url
+ *                      The URL where the Vendor Event Listener API is expected
+ *                      to be.
+ * @param[in] throt_api_url
+ *                      The URL where the Throttling API is expected to be.
+ * @param[in] username  The username for the Basic Authentication of requests.
+ * @param[in] password  The password for the Basic Authentication of requests.
+ * @param     verbosity 0 for normal operation, positive values for chattier
+ *                        logs.
+ *****************************************************************************/
+EVEL_ERR_CODES event_handler_initialize(const char * const event_api_url,
+                                        const char * const throt_api_url,
+                                        const char * const username,
+                                        const char * const password,
+                                        int verbosity);
+
+/**************************************************************************//**
+ * Terminate the event handler.
+ *
+ * Shuts down the event handler thread in as clean a way as possible. Sets the
+ * global exit flag and then signals the thread to interrupt it since it's
+ * most likely waiting on the ring-buffer.
+ *
+ * Having achieved an orderly shutdown of the event handler thread, clean up
+ * the cURL library's resources cleanly.
+ *
+ *  @return Status code.
+ *  @retval ::EVEL_SUCCESS if everything OK.
+ *  @retval One of ::EVEL_ERR_CODES if there was a problem.
+ *****************************************************************************/
+EVEL_ERR_CODES event_handler_terminate();
+
+/**************************************************************************//**
+ * Run the event handler.
+ *
+ * Spawns the thread responsible for handling events and sending them to the
+ * API.
+ *
+ *  @return Status code.
+ *  @retval ::EVEL_SUCCESS if everything OK.
+ *  @retval One of ::EVEL_ERR_CODES if there was a problem.
+ *****************************************************************************/
+EVEL_ERR_CODES event_handler_run();
+
+/**************************************************************************//**
+ * Create a new internal event.
+ *
+ * @note    The mandatory fields on the Fault must be supplied to this factory
+ *          function and are immutable once set.  Optional fields have explicit
+ *          setter functions, but again values may only be set once so that the
+ *          Fault has immutable properties.
+ * @param   command   The condition indicated by the event.
+ * @returns pointer to the newly manufactured ::EVENT_INTERNAL.  If the event
+ *          is not used (i.e. posted) it must be released using
+ *          ::evel_free_event.
+ * @retval  NULL  Failed to create the event.
+ *****************************************************************************/
+EVENT_INTERNAL * evel_new_internal_event(EVT_HANDLER_COMMAND command);
+
+/**************************************************************************//**
+ * Free an internal event.
+ *
+ * Free off the event supplied.  Will free all the contained* allocated memory.
+ *
+ * @note It does not free the internal event itself, since that may be part of
+ * a larger structure.
+ *****************************************************************************/
+void evel_free_internal_event(EVENT_INTERNAL * event);
+
+/**************************************************************************//**
+ * Initialize an event instance id, typically embedded in an event.
+ *
+ * @param instance_id   Pointer to the event instance id being initialized.
+ * @param vendor_id     The vendor id to encode in the event instance id.
+ * @param event_id      The event id to encode in the event instance id.
+ *****************************************************************************/
+void evel_init_event_instance_id(EVEL_EVENT_INSTANCE_ID * const instance_id,
+                                 const char * const vendor_id,
+                                 const char * const event_id);
+
+/**************************************************************************//**
+ * Free an event instance id.
+ *
+ * @param instance_id   Pointer to the event instance id being initialized.
+ *****************************************************************************/
+void evel_free_event_instance_id(EVEL_EVENT_INSTANCE_ID * const instance_id);
+
+/*****************************************************************************/
+/* Structure to hold JSON buffer and associated tracking, as it is written.  */
+/*****************************************************************************/
+typedef struct evel_json_buffer
+{
+  char * json;
+  int offset;
+  int max_size;
+
+  /***************************************************************************/
+  /* The working throttle specification, which can be NULL.                  */
+  /***************************************************************************/
+  EVEL_THROTTLE_SPEC * throttle_spec;
+
+  /***************************************************************************/
+  /* Current object/list nesting depth.                                      */
+  /***************************************************************************/
+  int depth;
+
+  /***************************************************************************/
+  /* The checkpoint.                                                         */
+  /***************************************************************************/
+  int checkpoint;
+
+} EVEL_JSON_BUFFER;
+
+/**************************************************************************//**
+ * Encode the event as a JSON event object according to AT&T's schema.
+ *
+ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
+ * @param event         Pointer to the ::EVENT_HEADER to encode.
+ *****************************************************************************/
+void evel_json_encode_header(EVEL_JSON_BUFFER * jbuf,
+                             EVENT_HEADER * event);
+
+/**************************************************************************//**
+ * Encode the instance id as a JSON object according to AT&T's schema.
+ *
+ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
+ * @param instance_id   Pointer to the ::EVEL_EVENT_INSTANCE_ID to encode.
+ *****************************************************************************/
+void evel_json_encode_instance_id(EVEL_JSON_BUFFER * jbuf,
+                                  EVEL_EVENT_INSTANCE_ID * instance_id);
+
+/**************************************************************************//**
+ * Encode the fault in JSON according to AT&T's schema for the fault type.
+ *
+ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
+ * @param event         Pointer to the ::EVENT_HEADER to encode.
+ *****************************************************************************/
+void evel_json_encode_fault(EVEL_JSON_BUFFER * jbuf,
+                            EVENT_FAULT * event);
+
+/**************************************************************************//**
+ * Encode the measurement as a JSON measurement.
+ *
+ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
+ * @param event         Pointer to the ::EVENT_HEADER to encode.
+ *****************************************************************************/
+void evel_json_encode_measurement(EVEL_JSON_BUFFER * jbuf,
+                                  EVENT_MEASUREMENT * event);
+
+/**************************************************************************//**
+ * Encode the Mobile Flow in JSON according to AT&T's schema for the event
+ * type.
+ *
+ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
+ * @param event         Pointer to the ::EVENT_HEADER to encode.
+ *****************************************************************************/
+void evel_json_encode_mobile_flow(EVEL_JSON_BUFFER * jbuf,
+                                  EVENT_MOBILE_FLOW * event);
+
+/**************************************************************************//**
+ * Encode the report as a JSON report.
+ *
+ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
+ * @param event         Pointer to the ::EVENT_HEADER to encode.
+ *****************************************************************************/
+void evel_json_encode_report(EVEL_JSON_BUFFER * jbuf,
+                             EVENT_REPORT * event);
+
+/**************************************************************************//**
+ * Encode the Service Event in JSON according to AT&T's schema for the event
+ * type.
+ *
+ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
+ * @param event         Pointer to the ::EVENT_HEADER to encode.
+ *****************************************************************************/
+void evel_json_encode_service(EVEL_JSON_BUFFER * const jbuf,
+                              EVENT_SERVICE * const event);
+
+/**************************************************************************//**
+ * Encode the Signaling in JSON according to AT&T's schema for the event type.
+ *
+ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
+ * @param event         Pointer to the ::EVENT_HEADER to encode.
+ *****************************************************************************/
+void evel_json_encode_signaling(EVEL_JSON_BUFFER * const jbuf,
+                                EVENT_SIGNALING * const event);
+
+/**************************************************************************//**
+ * Encode the state change as a JSON state change.
+ *
+ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
+ * @param state_change  Pointer to the ::EVENT_STATE_CHANGE to encode.
+ *****************************************************************************/
+void evel_json_encode_state_change(EVEL_JSON_BUFFER * jbuf,
+                                   EVENT_STATE_CHANGE * state_change);
+
+/**************************************************************************//**
+ * Encode the Syslog in JSON according to AT&T's schema for the event type.
+ *
+ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
+ * @param event         Pointer to the ::EVENT_HEADER to encode.
+ *****************************************************************************/
+void evel_json_encode_syslog(EVEL_JSON_BUFFER * jbuf,
+                             EVENT_SYSLOG * event);
+
+/**************************************************************************//**
+ * Encode the Other in JSON according to AT&T's schema for the event type.
+ *
+ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
+ * @param event         Pointer to the ::EVENT_HEADER to encode.
+ *****************************************************************************/
+void evel_json_encode_other(EVEL_JSON_BUFFER * jbuf,
+                            EVENT_OTHER * event);
+
+/**************************************************************************//**
+ * Set the next event_sequence to use.
+ *
+ * @param sequence      The next sequence number to use.
+ *****************************************************************************/
+void evel_set_next_event_sequence(const int sequence);
+
+/**************************************************************************//**
+ * Handle a JSON response from the listener, contained in a ::MEMORY_CHUNK.
+ *
+ * Tokenize the response, and decode any tokens found.
+ *
+ * @param chunk         The memory chunk containing the response.
+ * @param post          The memory chunk in which to place any resulting POST.
+ *****************************************************************************/
+void evel_handle_event_response(const MEMORY_CHUNK * const chunk,
+                                MEMORY_CHUNK * const post);
+
+/**************************************************************************//**
+ * Initialize a ::EVEL_JSON_BUFFER.
+ *
+ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to initialise.
+ * @param json          Pointer to the underlying working buffer to use.
+ * @param max_size      Size of storage available in the JSON buffer.
+ * @param throttle_spec Pointer to throttle specification. Can be NULL.
+ *****************************************************************************/
+void evel_json_buffer_init(EVEL_JSON_BUFFER * jbuf,
+                           char * const json,
+                           const int max_size,
+                           EVEL_THROTTLE_SPEC * throttle_spec);
+
+/**************************************************************************//**
+ * Encode a string key and string value to a ::EVEL_JSON_BUFFER.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ * @param option        Pointer to holder of the corresponding value to encode.
+ * @return true if the key, value was added, false if it was suppressed.
+ *****************************************************************************/
+bool evel_enc_kv_opt_string(EVEL_JSON_BUFFER * jbuf,
+                            const char * const key,
+                            const EVEL_OPTION_STRING * const option);
+
+/**************************************************************************//**
+ * Encode a string key and string value to a ::EVEL_JSON_BUFFER.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ * @param value         Pointer to the corresponding value to encode.
+ *****************************************************************************/
+void evel_enc_kv_string(EVEL_JSON_BUFFER * jbuf,
+                        const char * const key,
+                        const char * const value);
+
+/**************************************************************************//**
+ * Encode a string key and integer value to a ::EVEL_JSON_BUFFER.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ * @param option        Pointer to holder of the corresponding value to encode.
+ * @return true if the key, value was added, false if it was suppressed.
+ *****************************************************************************/
+bool evel_enc_kv_opt_int(EVEL_JSON_BUFFER * jbuf,
+                         const char * const key,
+                         const EVEL_OPTION_INT * const option);
+
+/**************************************************************************//**
+ * Encode a string key and integer value to a ::EVEL_JSON_BUFFER.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ * @param value         The corresponding value to encode.
+ *****************************************************************************/
+void evel_enc_kv_int(EVEL_JSON_BUFFER * jbuf,
+                     const char * const key,
+                     const int value);
+
+/**************************************************************************//**
+ * Encode a string key and double value to a ::EVEL_JSON_BUFFER.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ * @param option        Pointer to holder of the corresponding value to encode.
+ * @return true if the key, value was added, false if it was suppressed.
+ *****************************************************************************/
+bool evel_enc_kv_opt_double(EVEL_JSON_BUFFER * jbuf,
+                            const char * const key,
+                            const EVEL_OPTION_DOUBLE * const option);
+
+/**************************************************************************//**
+ * Encode a string key and double value to a ::EVEL_JSON_BUFFER.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ * @param value         The corresponding value to encode.
+ *****************************************************************************/
+void evel_enc_kv_double(EVEL_JSON_BUFFER * jbuf,
+                        const char * const key,
+                        const double value);
+
+/**************************************************************************//**
+ * Encode a string key and unsigned long long value to a ::EVEL_JSON_BUFFER.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ * @param option        Pointer to holder of the corresponding value to encode.
+ * @return true if the key, value was added, false if it was suppressed.
+ *****************************************************************************/
+bool evel_enc_kv_opt_ull(EVEL_JSON_BUFFER * jbuf,
+                         const char * const key,
+                         const EVEL_OPTION_ULL * const option);
+
+/**************************************************************************//**
+ * Encode a string key and unsigned long long value to a ::EVEL_JSON_BUFFER.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ * @param value         The corresponding value to encode.
+ *****************************************************************************/
+void evel_enc_kv_ull(EVEL_JSON_BUFFER * jbuf,
+                     const char * const key,
+                     const unsigned long long value);
+
+/**************************************************************************//**
+ * Encode a string key and time value to a ::EVEL_JSON_BUFFER.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ * @param option        Pointer to holder of the corresponding value to encode.
+ * @return true if the key, value was added, false if it was suppressed.
+ *****************************************************************************/
+bool evel_enc_kv_opt_time(EVEL_JSON_BUFFER * jbuf,
+                          const char * const key,
+                          const EVEL_OPTION_TIME * const option);
+
+/**************************************************************************//**
+ * Encode a string key and time value to a ::EVEL_JSON_BUFFER.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ * @param time          Pointer to the time to encode.
+ *****************************************************************************/
+void evel_enc_kv_time(EVEL_JSON_BUFFER * jbuf,
+                      const char * const key,
+                      const time_t * time);
+
+/**************************************************************************//**
+ * Encode a key and version.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ * @param major_version The major version to encode.
+ * @param minor_version The minor version to encode.
+ *****************************************************************************/
+void evel_enc_version(EVEL_JSON_BUFFER * jbuf,
+                      const char * const key,
+                      const int major_version,
+                      const int minor_version);
+
+/**************************************************************************//**
+ * Add the key and opening bracket of an optional named list to a JSON buffer.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ * @return true if the list was opened, false if it was suppressed.
+ *****************************************************************************/
+bool evel_json_open_opt_named_list(EVEL_JSON_BUFFER * jbuf,
+                                   const char * const key);
+
+/**************************************************************************//**
+ * Add the key and opening bracket of a named list to a JSON buffer.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ *****************************************************************************/
+void evel_json_open_named_list(EVEL_JSON_BUFFER * jbuf,
+                               const char * const key);
+
+/**************************************************************************//**
+ * Add the closing bracket of a list to a JSON buffer.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ *****************************************************************************/
+void evel_json_close_list(EVEL_JSON_BUFFER * jbuf);
+
+/**************************************************************************//**
+ * Encode a list item with format and param list to a ::EVEL_JSON_BUFFER.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param format        Format string in standard printf format.
+ * @param ...           Variable parameters for format string.
+ *****************************************************************************/
+void evel_enc_list_item(EVEL_JSON_BUFFER * jbuf,
+                        const char * const format,
+                        ...);
+
+/**************************************************************************//**
+ * Add the opening bracket of an optional named object to a JSON buffer.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ *****************************************************************************/
+bool evel_json_open_opt_named_object(EVEL_JSON_BUFFER * jbuf,
+                                     const char * const key);
+
+/**************************************************************************//**
+ * Add the opening bracket of an object to a JSON buffer.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ * @return true if the object was opened, false if it was suppressed.
+ *****************************************************************************/
+void evel_json_open_named_object(EVEL_JSON_BUFFER * jbuf,
+                                 const char * const key);
+
+/**************************************************************************//**
+ * Add the opening bracket of an object to a JSON buffer.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ *****************************************************************************/
+void evel_json_open_object(EVEL_JSON_BUFFER * jbuf);
+
+/**************************************************************************//**
+ * Add the closing bracket of an object to a JSON buffer.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ *****************************************************************************/
+void evel_json_close_object(EVEL_JSON_BUFFER * jbuf);
+
+/**************************************************************************//**
+ * Add a checkpoint - a stake in the ground to which we can rewind.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ *****************************************************************************/
+void evel_json_checkpoint(EVEL_JSON_BUFFER * jbuf);
+
+/**************************************************************************//**
+ * Rewind to the latest checkoint.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ *****************************************************************************/
+void evel_json_rewind(EVEL_JSON_BUFFER * jbuf);
+
+/**************************************************************************//**
+ * Free the underlying resources of an ::EVEL_OPTION_STRING.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_STRING.
+ *****************************************************************************/
+void evel_free_option_string(EVEL_OPTION_STRING * const option);
+
+/**************************************************************************//**
+ * Initialize an ::EVEL_OPTION_STRING to a not-set state.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_STRING.
+ *****************************************************************************/
+void evel_init_option_string(EVEL_OPTION_STRING * const option);
+
+/**************************************************************************//**
+ * Set the value of an ::EVEL_OPTION_STRING.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_STRING.
+ * @param value         The value to set.
+ * @param description   Description to be used in logging.
+ *****************************************************************************/
+void evel_set_option_string(EVEL_OPTION_STRING * const option,
+                            const char * const value,
+                            const char * const description);
+
+/**************************************************************************//**
+ * Force the value of an ::EVEL_OPTION_STRING.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_STRING.
+ * @param value         The value to set.
+ *****************************************************************************/
+void evel_force_option_string(EVEL_OPTION_STRING * const option,
+                              const char * const value);
+
+/**************************************************************************//**
+ * Initialize an ::EVEL_OPTION_INT to a not-set state.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_INT.
+ *****************************************************************************/
+void evel_init_option_int(EVEL_OPTION_INT * const option);
+
+/**************************************************************************//**
+ * Force the value of an ::EVEL_OPTION_INT.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_INT.
+ * @param value         The value to set.
+ *****************************************************************************/
+void evel_force_option_int(EVEL_OPTION_INT * const option,
+                           const int value);
+
+/**************************************************************************//**
+ * Set the value of an ::EVEL_OPTION_INT.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_INT.
+ * @param value         The value to set.
+ * @param description   Description to be used in logging.
+ *****************************************************************************/
+void evel_set_option_int(EVEL_OPTION_INT * const option,
+                         const int value,
+                         const char * const description);
+
+/**************************************************************************//**
+ * Initialize an ::EVEL_OPTION_DOUBLE to a not-set state.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_DOUBLE.
+ *****************************************************************************/
+void evel_init_option_double(EVEL_OPTION_DOUBLE * const option);
+
+/**************************************************************************//**
+ * Force the value of an ::EVEL_OPTION_DOUBLE.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_DOUBLE.
+ * @param value         The value to set.
+ *****************************************************************************/
+void evel_force_option_double(EVEL_OPTION_DOUBLE * const option,
+                              const double value);
+
+/**************************************************************************//**
+ * Set the value of an ::EVEL_OPTION_DOUBLE.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_DOUBLE.
+ * @param value         The value to set.
+ * @param description   Description to be used in logging.
+ *****************************************************************************/
+void evel_set_option_double(EVEL_OPTION_DOUBLE * const option,
+                            const double value,
+                            const char * const description);
+
+/**************************************************************************//**
+ * Initialize an ::EVEL_OPTION_ULL to a not-set state.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_ULL.
+ *****************************************************************************/
+void evel_init_option_ull(EVEL_OPTION_ULL * const option);
+
+/**************************************************************************//**
+ * Force the value of an ::EVEL_OPTION_ULL.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_ULL.
+ * @param value         The value to set.
+ *****************************************************************************/
+void evel_force_option_ull(EVEL_OPTION_ULL * const option,
+                           const unsigned long long value);
+
+/**************************************************************************//**
+ * Set the value of an ::EVEL_OPTION_ULL.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_ULL.
+ * @param value         The value to set.
+ * @param description   Description to be used in logging.
+ *****************************************************************************/
+void evel_set_option_ull(EVEL_OPTION_ULL * const option,
+                         const unsigned long long value,
+                         const char * const description);
+
+/**************************************************************************//**
+ * Initialize an ::EVEL_OPTION_TIME to a not-set state.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_TIME.
+ *****************************************************************************/
+void evel_init_option_time(EVEL_OPTION_TIME * const option);
+
+/**************************************************************************//**
+ * Force the value of an ::EVEL_OPTION_TIME.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_TIME.
+ * @param value         The value to set.
+ *****************************************************************************/
+void evel_force_option_time(EVEL_OPTION_TIME * const option,
+                            const time_t value);
+
+/**************************************************************************//**
+ * Set the value of an ::EVEL_OPTION_TIME.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_TIME.
+ * @param value         The value to set.
+ * @param description   Description to be used in logging.
+ *****************************************************************************/
+void evel_set_option_time(EVEL_OPTION_TIME * const option,
+                          const time_t value,
+                          const char * const description);
+
+/**************************************************************************//**
+ * Map an ::EVEL_COUNTER_CRITICALITIES enum value to the equivalent string.
+ *
+ * @param criticality   The criticality to convert.
+ * @returns The equivalent string.
+ *****************************************************************************/
+char * evel_criticality(const EVEL_COUNTER_CRITICALITIES criticality);
+
+/**************************************************************************//**
+ * Map an ::EVEL_SEVERITIES enum value to the equivalent string.
+ *
+ * @param severity      The severity to convert.
+ * @returns The equivalent string.
+ *****************************************************************************/
+char * evel_severity(const EVEL_SEVERITIES severity);
+
+/**************************************************************************//**
+ * Map an ::EVEL_ALERT_ACTIONS enum value to the equivalent string.
+ *
+ * @param alert_action  The alert_action to convert.
+ * @returns The equivalent string.
+ *****************************************************************************/
+char * evel_alert_action(const EVEL_ALERT_ACTIONS alert_action);
+
+/**************************************************************************//**
+ * Map an ::EVEL_ALERT_TYPES enum value to the equivalent string.
+ *
+ * @param alert_type    The alert_type to convert.
+ * @returns The equivalent string.
+ *****************************************************************************/
+char * evel_alert_type(const EVEL_ALERT_TYPES alert_type);
+
+/**************************************************************************//**
+ * Map an ::EVEL_EVENT_DOMAINS enum value to the equivalent string.
+ *
+ * @param domain        The domain to convert.
+ * @returns The equivalent string.
+ *****************************************************************************/
+char * evel_event_domain(const EVEL_EVENT_DOMAINS domain);
+
+/**************************************************************************//**
+ * Map an ::EVEL_EVENT_PRIORITIES enum value to the equivalent string.
+ *
+ * @param priority      The priority to convert.
+ * @returns The equivalent string.
+ *****************************************************************************/
+char * evel_event_priority(const EVEL_EVENT_PRIORITIES priority);
+
+/**************************************************************************//**
+ * Map an ::EVEL_SOURCE_TYPES enum value to the equivalent string.
+ *
+ * @param source_type   The source type to convert.
+ * @returns The equivalent string.
+ *****************************************************************************/
+char * evel_source_type(const EVEL_SOURCE_TYPES source_type);
+
+/**************************************************************************//**
+ * Map an ::EVEL_VF_STATUSES enum value to the equivalent string.
+ *
+ * @param vf_status     The vf_status to convert.
+ * @returns The equivalent string.
+ *****************************************************************************/
+char * evel_vf_status(const EVEL_VF_STATUSES vf_status);
+
+/**************************************************************************//**
+ * Convert a ::EVEL_ENTITY_STATE to it's string form for JSON encoding.
+ *
+ * @param state         The entity state to encode.
+ *
+ * @returns the corresponding string
+ *****************************************************************************/
+char * evel_entity_state(const EVEL_ENTITY_STATE state);
+
+/**************************************************************************//**
+ * Convert a ::EVEL_SERVICE_ENDPOINT_DESC to string form for JSON encoding.
+ *
+ * @param endpoint_desc endpoint description to encode.
+ *
+ * @returns the corresponding string
+ *****************************************************************************/
+char * evel_service_endpoint_desc(const EVEL_ENTITY_STATE endpoint_desc);
+
+#endif
diff --git a/vnfs/VES/code/evel_library/evel_internal_event.c b/vnfs/VES/code/evel_library/evel_internal_event.c
new file mode 100644 (file)
index 0000000..03a3d14
--- /dev/null
@@ -0,0 +1,124 @@
+/**************************************************************************//**
+ * @file
+ * Implementation of EVEL functions relating to the internal events.
+ *
+ * Internal events are never expected to be sent to the JSON API but comply
+ * with interfaces for regular event types.  The primary use-case is to enable
+ * the foreground processing to communicate with the background event handling
+ * processing in an orderly fashion.  At present the only use is to initiate an
+ * orderly shutdown of the Event Handler thread.
+ *
+ * License
+ * -------
+ *
+ * Copyright(c) <2016>, AT&T Intellectual Property.  All other rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:  This product includes
+ *    software developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "evel.h"
+#include "evel_internal.h"
+
+
+/**************************************************************************//**
+ * Create a new internal event.
+ *
+ * @note    The mandatory fields on the Fault must be supplied to this factory
+ *          function and are immutable once set.  Optional fields have explicit
+ *          setter functions, but again values may only be set once so that the
+ *          Fault has immutable properties.
+ * @param   command   The condition indicated by the event.
+ * @returns pointer to the newly manufactured ::EVENT_INTERNAL.  If the event
+ *          is not used (i.e. posted) it must be released using
+ *          ::evel_free_event.
+ * @retval  NULL  Failed to create the event.
+ *****************************************************************************/
+EVENT_INTERNAL * evel_new_internal_event(EVT_HANDLER_COMMAND command)
+{
+  EVENT_INTERNAL * event = NULL;
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(command < EVT_CMD_MAX_COMMANDS);
+
+  /***************************************************************************/
+  /* Allocate the fault.                                                     */
+  /***************************************************************************/
+  event = malloc(sizeof(EVENT_INTERNAL));
+  if (event == NULL)
+  {
+    log_error_state("Out of memory");
+    goto exit_label;
+  }
+  memset(event, 0, sizeof(EVENT_INTERNAL));
+  EVEL_DEBUG("New internal event is at %lp", event);
+
+  /***************************************************************************/
+  /* Initialize the header & the event fields.                               */
+  /***************************************************************************/
+  evel_init_header(&event->header);
+  event->header.event_domain = EVEL_DOMAIN_INTERNAL;
+  event->command = command;
+
+exit_label:
+  EVEL_EXIT();
+  return event;
+}
+
+/**************************************************************************//**
+ * Free an internal event.
+ *
+ * Free off the event supplied.  Will free all the contained allocated memory.
+ *
+ * @note It does not free the internal event itself, since that may be part of
+ * a larger structure.
+ *****************************************************************************/
+void evel_free_internal_event(EVENT_INTERNAL * event)
+{
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.  As an internal API we don't allow freeing NULL    */
+  /* events as we do on the public API.                                      */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_INTERNAL);
+
+  /***************************************************************************/
+  /* Free the header itself.                                                 */
+  /***************************************************************************/
+  evel_free_header(&event->header);
+
+  EVEL_EXIT();
+}
\ No newline at end of file
diff --git a/vnfs/VES/code/evel_library/evel_json_buffer.c b/vnfs/VES/code/evel_library/evel_json_buffer.c
new file mode 100644 (file)
index 0000000..7ae3453
--- /dev/null
@@ -0,0 +1,853 @@
+/**************************************************************************//**
+ * @file
+ * Source module relating to internal EVEL_JSON_BUFFER manipulation functions.
+ *
+ * License
+ * -------
+ *
+ * Copyright(c) <2016>, AT&T Intellectual Property.  All other rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:  This product includes
+ *    software developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <assert.h>
+#include <string.h>
+
+#include "evel_throttle.h"
+
+/*****************************************************************************/
+/* Local prototypes.                                                         */
+/*****************************************************************************/
+static char * evel_json_kv_comma(EVEL_JSON_BUFFER * jbuf);
+
+/**************************************************************************//**
+ * Initialize a ::EVEL_JSON_BUFFER.
+ *
+ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to initialise.
+ * @param json          Pointer to the underlying working buffer to use.
+ * @param max_size      Size of storage available in the JSON buffer.
+ * @param throttle_spec Pointer to throttle specification. Can be NULL.
+ *****************************************************************************/
+void evel_json_buffer_init(EVEL_JSON_BUFFER * jbuf,
+                           char * const json,
+                           const int max_size,
+                           EVEL_THROTTLE_SPEC * throttle_spec)
+{
+  EVEL_ENTER();
+
+  assert(jbuf != NULL);
+  assert(json != NULL);
+  jbuf->json = json;
+  jbuf->max_size = max_size;
+  jbuf->offset = 0;
+  jbuf->throttle_spec = throttle_spec;
+  jbuf->depth = 0;
+  jbuf->checkpoint = -1;
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Encode an integer value to a JSON buffer.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param value         The integer to add to it.
+ *****************************************************************************/
+void evel_enc_int(EVEL_JSON_BUFFER * jbuf,
+                  const int value)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(jbuf != NULL);
+
+  jbuf->offset += snprintf(jbuf->json + jbuf->offset,
+                           jbuf->max_size - jbuf->offset,
+                           "%d", value);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Encode a string key and string value to a ::EVEL_JSON_BUFFER.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ * @param option        Pointer to holder of the corresponding value to encode.
+ * @return true if the key, value was added, false if it was suppressed.
+ *****************************************************************************/
+bool evel_enc_kv_opt_string(EVEL_JSON_BUFFER * jbuf,
+                            const char * const key,
+                            const EVEL_OPTION_STRING * const option)
+{
+  bool added = false;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(option != NULL);
+
+  if (option->is_set)
+  {
+    if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
+        (jbuf->throttle_spec != NULL) &&
+        evel_throttle_suppress_field(jbuf->throttle_spec, key))
+    {
+      EVEL_INFO("Suppressed: %s, %s", key, option->value);
+    }
+    else
+    {
+      EVEL_DEBUG("Encoded: %s, %s", key, option->value);
+      evel_enc_kv_string(jbuf, key, option->value);
+      added = true;
+    }
+  }
+
+  EVEL_EXIT();
+
+  return added;
+}
+
+/**************************************************************************//**
+ * Encode a string key and string value to a ::EVEL_JSON_BUFFER.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ * @param value         Pointer to the corresponding value to encode.
+ *****************************************************************************/
+void evel_enc_kv_string(EVEL_JSON_BUFFER * jbuf,
+                        const char * const key,
+                        const char * const value)
+{
+  int index;
+  int length;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(jbuf != NULL);
+  assert(key != NULL);
+
+  jbuf->offset += snprintf(jbuf->json + jbuf->offset,
+                           jbuf->max_size - jbuf->offset,
+                           "%s\"%s\": \"",
+                           evel_json_kv_comma(jbuf),
+                           key);
+
+  /***************************************************************************/
+  /* We need to escape quotation marks and backslashes in the value.         */
+  /***************************************************************************/
+  length = strlen(value);
+
+  for (index = 0; index < length; index++)
+  {
+    /*************************************************************************/
+    /* Drop out if no more space.                                            */
+    /*************************************************************************/
+    if (jbuf->max_size - jbuf->offset < 2)
+    {
+      break;
+    }
+
+    /*************************************************************************/
+    /* Add an escape character if necessary, then write the character        */
+    /* itself.                                                               */
+    /*************************************************************************/
+    if ((value[index] == '\"') || (value[index] == '\\'))
+    {
+      jbuf->json[jbuf->offset] = '\\';
+      jbuf->offset++;
+    }
+
+    jbuf->json[jbuf->offset] = value[index];
+    jbuf->offset++;
+  }
+
+  jbuf->offset += snprintf(jbuf->json + jbuf->offset,
+                           jbuf->max_size - jbuf->offset,
+                           "\"");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Encode a string key and integer value to a ::EVEL_JSON_BUFFER.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ * @param option        Pointer to holder of the corresponding value to encode.
+ * @return true if the key, value was added, false if it was suppressed.
+ *****************************************************************************/
+bool evel_enc_kv_opt_int(EVEL_JSON_BUFFER * jbuf,
+                         const char * const key,
+                         const EVEL_OPTION_INT * const option)
+{
+  bool added = false;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(option != NULL);
+
+  if (option->is_set)
+  {
+    if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
+        (jbuf->throttle_spec != NULL) &&
+        evel_throttle_suppress_field(jbuf->throttle_spec, key))
+    {
+      EVEL_INFO("Suppressed: %s, %d", key, option->value);
+    }
+    else
+    {
+      EVEL_DEBUG("Encoded: %s, %d", key, option->value);
+      evel_enc_kv_int(jbuf, key, option->value);
+      added = true;
+    }
+  }
+
+  EVEL_EXIT();
+
+  return added;
+}
+
+/**************************************************************************//**
+ * Encode a string key and integer value to a ::EVEL_JSON_BUFFER.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ * @param value         The corresponding value to encode.
+ *****************************************************************************/
+void evel_enc_kv_int(EVEL_JSON_BUFFER * jbuf,
+                     const char * const key,
+                     const int value)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(jbuf != NULL);
+  assert(key != NULL);
+
+  jbuf->offset += snprintf(jbuf->json + jbuf->offset,
+                           jbuf->max_size - jbuf->offset,
+                           "%s\"%s\": %d",
+                           evel_json_kv_comma(jbuf),
+                           key,
+                           value);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Encode a string key and double value to a ::EVEL_JSON_BUFFER.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ * @param option        Pointer to holder of the corresponding value to encode.
+ * @return true if the key, value was added, false if it was suppressed.
+ *****************************************************************************/
+bool evel_enc_kv_opt_double(EVEL_JSON_BUFFER * jbuf,
+                            const char * const key,
+                            const EVEL_OPTION_DOUBLE * const option)
+{
+  bool added = false;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(option != NULL);
+
+  if (option->is_set)
+  {
+    if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
+        (jbuf->throttle_spec != NULL) &&
+        evel_throttle_suppress_field(jbuf->throttle_spec, key))
+    {
+      EVEL_INFO("Suppressed: %s, %1f", key, option->value);
+    }
+    else
+    {
+      EVEL_DEBUG("Encoded: %s, %1f", key, option->value);
+      evel_enc_kv_double(jbuf, key, option->value);
+      added = true;
+    }
+  }
+
+  EVEL_EXIT();
+
+  return added;
+}
+
+/**************************************************************************//**
+ * Encode a string key and double value to a ::EVEL_JSON_BUFFER.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ * @param value         The corresponding value to encode.
+ *****************************************************************************/
+void evel_enc_kv_double(EVEL_JSON_BUFFER * jbuf,
+                        const char * const key,
+                        const double value)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(jbuf != NULL);
+  assert(key != NULL);
+
+  jbuf->offset += snprintf(jbuf->json + jbuf->offset,
+                           jbuf->max_size - jbuf->offset,
+                           "%s\"%s\": %1f",
+                           evel_json_kv_comma(jbuf),
+                           key,
+                           value);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Encode a string key and unsigned long long value to a ::EVEL_JSON_BUFFER.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ * @param option        Pointer to holder of the corresponding value to encode.
+ * @return true if the key, value was added, false if it was suppressed.
+ *****************************************************************************/
+bool evel_enc_kv_opt_ull(EVEL_JSON_BUFFER * jbuf,
+                         const char * const key,
+                         const EVEL_OPTION_ULL * const option)
+{
+  bool added = false;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(option != NULL);
+
+  if (option->is_set)
+  {
+    if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
+        (jbuf->throttle_spec != NULL) &&
+        evel_throttle_suppress_field(jbuf->throttle_spec, key))
+    {
+      EVEL_INFO("Suppressed: %s, %1lu", key, option->value);
+    }
+    else
+    {
+      EVEL_DEBUG("Encoded: %s, %1lu", key, option->value);
+      evel_enc_kv_ull(jbuf, key, option->value);
+      added = true;
+    }
+  }
+
+  EVEL_EXIT();
+
+  return added;
+}
+
+/**************************************************************************//**
+ * Encode a string key and unsigned long long value to a ::EVEL_JSON_BUFFER.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ * @param value         The corresponding value to encode.
+ *****************************************************************************/
+void evel_enc_kv_ull(EVEL_JSON_BUFFER * jbuf,
+                     const char * const key,
+                     const unsigned long long value)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(jbuf != NULL);
+  assert(key != NULL);
+
+  jbuf->offset += snprintf(jbuf->json + jbuf->offset,
+                           jbuf->max_size - jbuf->offset,
+                           "%s\"%s\": %llu",
+                           evel_json_kv_comma(jbuf),
+                           key,
+                           value);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Encode a string key and time value to a ::EVEL_JSON_BUFFER.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ * @param option        Pointer to holder of the corresponding value to encode.
+ * @return true if the key, value was added, false if it was suppressed.
+ *****************************************************************************/
+bool evel_enc_kv_opt_time(EVEL_JSON_BUFFER * jbuf,
+                          const char * const key,
+                          const EVEL_OPTION_TIME * const option)
+{
+  bool added = false;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(option != NULL);
+
+  if (option->is_set)
+  {
+    if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
+        (jbuf->throttle_spec != NULL) &&
+        evel_throttle_suppress_field(jbuf->throttle_spec, key))
+    {
+      EVEL_INFO("Suppressed time: %s", key);
+    }
+    else
+    {
+      EVEL_DEBUG("Encoded time: %s", key);
+      evel_enc_kv_time(jbuf, key, &option->value);
+      added = true;
+    }
+  }
+
+  EVEL_EXIT();
+
+  return added;
+}
+
+/**************************************************************************//**
+ * Encode a string key and time value to a ::EVEL_JSON_BUFFER.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ * @param time          Pointer to the time to encode.
+ *****************************************************************************/
+void evel_enc_kv_time(EVEL_JSON_BUFFER * jbuf,
+                      const char * const key,
+                      const time_t * time)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(jbuf != NULL);
+  assert(key != NULL);
+  assert(time != NULL);
+
+  jbuf->offset += snprintf(jbuf->json + jbuf->offset,
+                           jbuf->max_size - jbuf->offset,
+                           "%s\"%s\": \"",
+                           evel_json_kv_comma(jbuf),
+                           key);
+  jbuf->offset += strftime(jbuf->json + jbuf->offset,
+                           jbuf->max_size - jbuf->offset,
+                           EVEL_RFC2822_STRFTIME_FORMAT,
+                           localtime(time));
+  jbuf->offset += snprintf(jbuf->json + jbuf->offset,
+                           jbuf->max_size - jbuf->offset,
+                           "\"");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Encode a key and version.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ * @param major_version The major version to encode.
+ * @param minor_version The minor version to encode.
+ *****************************************************************************/
+void evel_enc_version(EVEL_JSON_BUFFER * jbuf,
+                      const char * const key,
+                      const int major_version,
+                      const int minor_version)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(jbuf != NULL);
+  assert(key != NULL);
+
+  evel_enc_kv_int(jbuf, key, major_version);
+  if (minor_version != 0)
+  {
+    jbuf->offset += snprintf(jbuf->json + jbuf->offset,
+                             jbuf->max_size - jbuf->offset,
+                             ".%d",
+                             minor_version);
+  }
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Add the key and opening bracket of an optional named list to a JSON buffer.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ * @return true if the list was opened, false if it was suppressed.
+ *****************************************************************************/
+bool evel_json_open_opt_named_list(EVEL_JSON_BUFFER * jbuf,
+                                   const char * const key)
+{
+  bool opened = false;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(jbuf != NULL);
+  assert(key != NULL);
+
+  if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
+      (jbuf->throttle_spec != NULL) &&
+      evel_throttle_suppress_field(jbuf->throttle_spec, key))
+  {
+    EVEL_INFO("Suppressed: %s", key);
+    opened = false;
+  }
+  else
+  {
+    evel_json_open_named_list(jbuf, key);
+    opened = true;
+  }
+
+  EVEL_EXIT();
+
+  return opened;
+}
+
+/**************************************************************************//**
+ * Add the key and opening bracket of a named list to a JSON buffer.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ *****************************************************************************/
+void evel_json_open_named_list(EVEL_JSON_BUFFER * jbuf,
+                               const char * const key)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(jbuf != NULL);
+  assert(key != NULL);
+
+  jbuf->offset += snprintf(jbuf->json + jbuf->offset,
+                           jbuf->max_size - jbuf->offset,
+                           "%s\"%s\": [",
+                           evel_json_kv_comma(jbuf),
+                           key);
+  jbuf->depth++;
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Add the closing bracket of a list to a JSON buffer.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ *****************************************************************************/
+void evel_json_close_list(EVEL_JSON_BUFFER * jbuf)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(jbuf != NULL);
+
+  jbuf->offset += snprintf(jbuf->json + jbuf->offset,
+                           jbuf->max_size - jbuf->offset,
+                           "]");
+  jbuf->depth--;
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Encode a list item with format and param list to a ::EVEL_JSON_BUFFER.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param format        Format string in standard printf format.
+ * @param ...           Variable parameters for format string.
+ *****************************************************************************/
+void evel_enc_list_item(EVEL_JSON_BUFFER * jbuf,
+                        const char * const format,
+                        ...)
+{
+  va_list largs;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(jbuf != NULL);
+  assert(format != NULL);
+
+  /***************************************************************************/
+  /* Add a comma unless we're at the start of the list.                      */
+  /***************************************************************************/
+  if (jbuf->json[jbuf->offset - 1] != '[')
+  {
+    jbuf->offset += snprintf(jbuf->json + jbuf->offset,
+                             jbuf->max_size - jbuf->offset,
+                             ", ");
+  }
+
+  va_start(largs, format);
+  jbuf->offset += vsnprintf(jbuf->json + jbuf->offset,
+                            jbuf->max_size - jbuf->offset,
+                            format,
+                            largs);
+  va_end(largs);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Add the opening bracket of an optional named object to a JSON buffer.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ *****************************************************************************/
+bool evel_json_open_opt_named_object(EVEL_JSON_BUFFER * jbuf,
+                                     const char * const key)
+{
+  bool opened = false;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(jbuf != NULL);
+  assert(key != NULL);
+
+  if ((jbuf->depth == EVEL_THROTTLE_FIELD_DEPTH) &&
+      (jbuf->throttle_spec != NULL) &&
+      evel_throttle_suppress_field(jbuf->throttle_spec, key))
+  {
+    EVEL_INFO("Suppressed: %s", key);
+    opened = false;
+  }
+  else
+  {
+    evel_json_open_named_object(jbuf, key);
+    opened = true;
+  }
+
+  EVEL_EXIT();
+
+  return opened;
+}
+
+/**************************************************************************//**
+ * Add the opening bracket of an object to a JSON buffer.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param key           Pointer to the key to encode.
+ * @return true if the object was opened, false if it was suppressed.
+ *****************************************************************************/
+void evel_json_open_named_object(EVEL_JSON_BUFFER * jbuf,
+                                 const char * const key)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(jbuf != NULL);
+  assert(key != NULL);
+
+  jbuf->offset += snprintf(jbuf->json + jbuf->offset,
+                           jbuf->max_size - jbuf->offset,
+                           "%s\"%s\": {",
+                           evel_json_kv_comma(jbuf),
+                           key);
+  jbuf->depth++;
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Add the opening bracket of an object to a JSON buffer.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ *****************************************************************************/
+void evel_json_open_object(EVEL_JSON_BUFFER * jbuf)
+{
+  char * comma;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(jbuf != NULL);
+
+  if ((jbuf->offset != 0) && (jbuf->json[jbuf->offset-1] == '}'))
+  {
+    comma = ", ";
+  }
+  else
+  {
+    comma = "";
+  }
+
+  jbuf->offset += snprintf(jbuf->json + jbuf->offset,
+                           jbuf->max_size - jbuf->offset,
+                           "%s{",
+                           comma);
+  jbuf->depth++;
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Add the closing bracket of an object to a JSON buffer.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ *****************************************************************************/
+void evel_json_close_object(EVEL_JSON_BUFFER * jbuf)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(jbuf != NULL);
+
+  jbuf->offset += snprintf(jbuf->json + jbuf->offset,
+                           jbuf->max_size - jbuf->offset,
+                           "}");
+  jbuf->depth--;
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Determine whether to add a comma when adding a key-value pair.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @returns A string containing the comma if it is required.
+ *****************************************************************************/
+char * evel_json_kv_comma(EVEL_JSON_BUFFER * jbuf)
+{
+  char * result;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(jbuf != NULL);
+
+  if ((jbuf->offset == 0) ||
+      (jbuf->json[jbuf->offset-1] == '{') ||
+      (jbuf->json[jbuf->offset-1] == '['))
+  {
+    result = "";
+  }
+  else
+  {
+    result = ", ";
+  }
+
+  EVEL_EXIT();
+
+  return result;
+}
+
+/**************************************************************************//**
+ * Add a checkpoint - a stake in the ground to which we can rewind.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ *****************************************************************************/
+void evel_json_checkpoint(EVEL_JSON_BUFFER * jbuf)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(jbuf != NULL);
+
+  /***************************************************************************/
+  /* Store the current offset.                                               */
+  /***************************************************************************/
+  jbuf->checkpoint = jbuf->offset;
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Rewind to the latest checkoint.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ *****************************************************************************/
+void evel_json_rewind(EVEL_JSON_BUFFER * jbuf)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(jbuf != NULL);
+  assert(jbuf->checkpoint >= 0);
+  assert(jbuf->checkpoint <= jbuf->offset);
+
+  /***************************************************************************/
+  /* Reinstate the offset from the last checkpoint.                          */
+  /***************************************************************************/
+  jbuf->offset = jbuf->checkpoint;
+  jbuf->checkpoint = -1;
+
+  EVEL_EXIT();
+}
diff --git a/vnfs/VES/code/evel_library/evel_logging.c b/vnfs/VES/code/evel_library/evel_logging.c
new file mode 100644 (file)
index 0000000..6dabc63
--- /dev/null
@@ -0,0 +1,181 @@
+/**************************************************************************//**
+ * @file
+ * Wrapper for event logging built on syslog.
+ *
+ * License
+ * -------
+ *
+ * Copyright(c) <2016>, AT&T Intellectual Property.  All other rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:  This product includes
+ *    software developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <string.h>
+#include <assert.h>
+#include <syslog.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+#include <curl/curl.h>
+
+#include "evel.h"
+
+
+/*****************************************************************************/
+/* Debug settings.  Logging is done through macros so these need to be       */
+/* externally visible.                                                       */
+/*****************************************************************************/
+EVEL_LOG_LEVELS debug_level = EVEL_LOG_DEBUG;
+//static char *syslog_ident = "evel";
+int debug_indent = 0;
+
+/*****************************************************************************/
+/* Buffers for error strings from this library.                              */
+/*****************************************************************************/
+static char evel_err_string[EVEL_MAX_ERROR_STRING_LEN] = "<NULL>";
+
+
+/**************************************************************************//**
+ * Initialize logging
+ *
+ * @param[in] level  The debugging level - one of ::EVEL_LOG_LEVELS.
+ * @param[in] ident  The identifier for our logs.
+ *****************************************************************************/
+void log_initialize(EVEL_LOG_LEVELS level, const char * ident)
+{
+  assert(level < EVEL_LOG_MAX);
+  assert(ident != NULL);
+
+  debug_level = level;
+  openlog(ident, LOG_PID, LOG_USER);
+}
+
+/**************************************************************************//**
+ * Descriptive text for library errors.
+ *
+ * Return a text error string that relates to the last failure.  May be
+ * "<null>" but will never be NULL.
+ *
+ * @returns   Text error string.
+ *
+ * @note      Must not be freed!
+ *****************************************************************************/
+const char * evel_error_string(void)
+{
+  return(evel_err_string);
+}
+
+/***************************************************************************//*
+ * Store the formatted string into the static error string and log the error.
+ *
+ * @param format  Error string in standard printf format.
+ * @param ...     Variable parameters to be substituted into the format string.
+ *****************************************************************************/
+void log_error_state(char * format, ...)
+{
+  va_list largs;
+
+  assert(format != NULL);
+  va_start(largs, format);
+  vsnprintf(evel_err_string, EVEL_MAX_ERROR_STRING_LEN, format, largs);
+  va_end(largs);
+  EVEL_ERROR("%s", evel_err_string);
+}
+
+
+/**************************************************************************//**
+ *  Generate a debug log.
+ *
+ *  Provides an interface to syslog with formatting of the nesting level
+ *  so that it's easier to see function entry/exit.
+ *
+ *  @param[in]  level   The debug level - see ::EVEL_LOG_LEVELS.
+ *  @param[in]  format  The output formatting in printf style.
+ *  @param[in]  ...     Variable arguments as specified in the format string.
+ *****************************************************************************/
+void log_debug(EVEL_LOG_LEVELS level, char * format, ...)
+{
+  va_list largs;
+  int priority;
+  char indent_fmt[1024];
+  char *syslog_fmt = NULL;
+
+  /***************************************************************************/
+  /* Test assumptions.                                                       */
+  /***************************************************************************/
+  assert(format != NULL);
+  assert(level <= EVEL_LOG_MAX);
+
+  if (level >= debug_level)
+  {
+    if ((debug_level == EVEL_LOG_INFO) || (debug_indent == 0))
+    {
+      /***********************************************************************/
+      /* Just use the format as is.                                          */
+      /***********************************************************************/
+      syslog_fmt = format;
+    }
+    else
+    {
+      /***********************************************************************/
+      /* Combine the format with a preceding number of indent markers.       */
+      /***********************************************************************/
+      sprintf(indent_fmt, "%.*s%s",
+              debug_indent,
+              INDENT_SEPARATORS,
+              format);
+      syslog_fmt = indent_fmt;
+    }
+
+    /*************************************************************************/
+    /* Work out the syslog priority value.                                   */
+    /*************************************************************************/
+    switch (level)
+    {
+    case EVEL_LOG_ERROR:
+      priority = LOG_ERR;
+      break;
+
+    case EVEL_LOG_INFO:
+      priority = LOG_INFO;
+      break;
+
+    case EVEL_LOG_DEBUG:
+    case EVEL_LOG_SPAMMY:
+    default:
+      priority = LOG_DEBUG;
+      break;
+    }
+
+    /*************************************************************************/
+    /* Write the log to the file next, which requires the var args list.     */
+    /*************************************************************************/
+    va_start(largs, format);
+    vsyslog(priority, syslog_fmt, largs);
+    va_end(largs);
+  }
+}
\ No newline at end of file
diff --git a/vnfs/VES/code/evel_library/evel_mobile_flow.c b/vnfs/VES/code/evel_library/evel_mobile_flow.c
new file mode 100644 (file)
index 0000000..45f22ea
--- /dev/null
@@ -0,0 +1,2036 @@
+/**************************************************************************//**
+ * @file
+ * Implementation of EVEL functions relating to the Mobile Flow.
+ *
+ * License
+ * -------
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:  This product includes
+ *    software developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "evel.h"
+#include "evel_internal.h"
+
+/*****************************************************************************/
+/* Array of strings to use when encoding TCP flags.                          */
+/*****************************************************************************/
+static char * evel_tcp_flag_strings[EVEL_MAX_TCP_FLAGS] = {
+  "NS",
+  "CWR",
+  "ECE",
+  "URG",
+  "ACK",
+  "PSH",
+  "RST",
+  "SYN",
+  "FIN"
+};
+
+/*****************************************************************************/
+/* Array of strings to use when encoding QCI COS.                            */
+/*****************************************************************************/
+static char * evel_qci_cos_strings[EVEL_MAX_QCI_COS_TYPES] = {
+  "conversational",
+  "streaming",
+  "interactive",
+  "background",
+  "1",
+  "2",
+  "3",
+  "4",
+  "65",
+  "66",
+  "5",
+  "6",
+  "7",
+  "8",
+  "9",
+  "69",
+  "70"
+};
+
+/*****************************************************************************/
+/* Local prototypes                                                          */
+/*****************************************************************************/
+void evel_json_encode_mobile_flow_gtp_flow_metrics(
+                                        EVEL_JSON_BUFFER * jbuf,
+                                        MOBILE_GTP_PER_FLOW_METRICS * metrics);
+
+/**************************************************************************//**
+ * Create a new Mobile Flow event.
+ *
+ * @note    The mandatory fields on the Mobile Flow must be supplied to this
+ *          factory function and are immutable once set.  Optional fields have
+ *          explicit setter functions, but again values may only be set once so
+ *          that the Mobile Flow has immutable properties.
+ * @param   flow_direction              Flow direction.
+ * @param   gtp_per_flow_metrics        GTP per-flow metrics.
+ * @param   ip_protocol_type            IP protocol type.
+ * @param   ip_version                  IP protocol version.
+ * @param   other_endpoint_ip_address   IP address of the other endpoint.
+ * @param   other_endpoint_port         IP port of the other endpoint.
+ * @param   reporting_endpoint_ip_addr  IP address of the reporting endpoint.
+ * @param   reporting_endpoint_port     IP port of the reporting endpoint.
+ * @returns pointer to the newly manufactured ::EVENT_MOBILE_FLOW.  If the
+ *          event is not used (i.e. posted) it must be released using
+ *          ::evel_free_mobile_flow.
+ * @retval  NULL  Failed to create the event.
+ *****************************************************************************/
+EVENT_MOBILE_FLOW * evel_new_mobile_flow(
+                            const char * const flow_direction,
+                            MOBILE_GTP_PER_FLOW_METRICS * gtp_per_flow_metrics,
+                            const char * const ip_protocol_type,
+                            const char * const ip_version,
+                            const char * const other_endpoint_ip_address,
+                            int other_endpoint_port,
+                            const char * const reporting_endpoint_ip_addr,
+                            int reporting_endpoint_port)
+{
+  EVENT_MOBILE_FLOW * mobile_flow = NULL;
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(flow_direction != NULL);
+  assert(gtp_per_flow_metrics != NULL);
+  assert(ip_protocol_type != NULL);
+  assert(ip_version != NULL);
+  assert(other_endpoint_ip_address != NULL);
+  assert(other_endpoint_port > 0);
+  assert(reporting_endpoint_ip_addr != NULL);
+  assert(reporting_endpoint_port > 0);
+
+  /***************************************************************************/
+  /* Allocate the Mobile Flow.                                               */
+  /***************************************************************************/
+  mobile_flow = malloc(sizeof(EVENT_MOBILE_FLOW));
+  if (mobile_flow == NULL)
+  {
+    log_error_state("Out of memory");
+    goto exit_label;
+  }
+  memset(mobile_flow, 0, sizeof(EVENT_MOBILE_FLOW));
+  EVEL_DEBUG("New Mobile Flow is at %lp", mobile_flow);
+
+  /***************************************************************************/
+  /* Initialize the header & the Mobile Flow fields.  Optional string values */
+  /* are uninitialized (NULL).                                               */
+  /***************************************************************************/
+  evel_init_header(&mobile_flow->header);
+  mobile_flow->header.event_domain = EVEL_DOMAIN_MOBILE_FLOW;
+  mobile_flow->major_version = EVEL_MOBILE_FLOW_MAJOR_VERSION;
+  mobile_flow->minor_version = EVEL_MOBILE_FLOW_MINOR_VERSION;
+  mobile_flow->flow_direction = strdup(flow_direction);
+  mobile_flow->gtp_per_flow_metrics = gtp_per_flow_metrics;
+  mobile_flow->ip_protocol_type = strdup(ip_protocol_type);
+  mobile_flow->ip_version = strdup(ip_version);
+  mobile_flow->other_endpoint_ip_address = strdup(other_endpoint_ip_address);
+  mobile_flow->other_endpoint_port = other_endpoint_port;
+  mobile_flow->reporting_endpoint_ip_addr = strdup(reporting_endpoint_ip_addr);
+  mobile_flow->reporting_endpoint_port = reporting_endpoint_port;
+  evel_init_option_string(&mobile_flow->application_type);
+  evel_init_option_string(&mobile_flow->app_protocol_type);
+  evel_init_option_string(&mobile_flow->app_protocol_version);
+  evel_init_option_string(&mobile_flow->cid);
+  evel_init_option_string(&mobile_flow->connection_type);
+  evel_init_option_string(&mobile_flow->ecgi);
+  evel_init_option_string(&mobile_flow->gtp_protocol_type);
+  evel_init_option_string(&mobile_flow->gtp_version);
+  evel_init_option_string(&mobile_flow->http_header);
+  evel_init_option_string(&mobile_flow->imei);
+  evel_init_option_string(&mobile_flow->imsi);
+  evel_init_option_string(&mobile_flow->lac);
+  evel_init_option_string(&mobile_flow->mcc);
+  evel_init_option_string(&mobile_flow->mnc);
+  evel_init_option_string(&mobile_flow->msisdn);
+  evel_init_option_string(&mobile_flow->other_functional_role);
+  evel_init_option_string(&mobile_flow->rac);
+  evel_init_option_string(&mobile_flow->radio_access_technology);
+  evel_init_option_string(&mobile_flow->sac);
+  evel_init_option_int(&mobile_flow->sampling_algorithm);
+  evel_init_option_string(&mobile_flow->tac);
+  evel_init_option_string(&mobile_flow->tunnel_id);
+  evel_init_option_string(&mobile_flow->vlan_id);
+
+exit_label:
+  EVEL_EXIT();
+  return mobile_flow;
+}
+
+/**************************************************************************//**
+ * Set the Event Type property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param type        The Event Type to be set. ASCIIZ string. The caller
+ *                    does not need to preserve the value once the function
+ *                    returns.
+ *****************************************************************************/
+void evel_mobile_flow_type_set(EVENT_MOBILE_FLOW * mobile_flow,
+                               const char * const type)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_header_type_set.                      */
+  /***************************************************************************/
+  assert(mobile_flow != NULL);
+  assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW);
+  evel_header_type_set(&mobile_flow->header, type);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Application Type property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param type        The Application Type to be set. ASCIIZ string. The caller
+ *                    does not need to preserve the value once the function
+ *                    returns.
+ *****************************************************************************/
+void evel_mobile_flow_app_type_set(EVENT_MOBILE_FLOW * mobile_flow,
+                                   const char * const type)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(mobile_flow != NULL);
+  assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW);
+  assert(type != NULL);
+
+  evel_set_option_string(&mobile_flow->application_type,
+                         type,
+                         "Application Type");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Application Protocol Type property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param type        The Application Protocol Type to be set. ASCIIZ string.
+ *                    The caller does not need to preserve the value once the
+ *                    function returns.
+ *****************************************************************************/
+void evel_mobile_flow_app_prot_type_set(EVENT_MOBILE_FLOW * mobile_flow,
+                                        const char * const type)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(mobile_flow != NULL);
+  assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW);
+  assert(type != NULL);
+
+  evel_set_option_string(&mobile_flow->app_protocol_type,
+                         type,
+                         "Application Protocol Type");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Application Protocol Version property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param version     The Application Protocol Version to be set. ASCIIZ
+ *                    string.  The caller does not need to preserve the value
+ *                    once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_app_prot_ver_set(EVENT_MOBILE_FLOW * mobile_flow,
+                                       const char * const version)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(mobile_flow != NULL);
+  assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW);
+  assert(version != NULL);
+
+  evel_set_option_string(&mobile_flow->app_protocol_version,
+                         version,
+                         "Application Protocol Version");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the CID property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param cid         The CID to be set. ASCIIZ string.  The caller does not
+ *                    need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_cid_set(EVENT_MOBILE_FLOW * mobile_flow,
+                              const char * const cid)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(mobile_flow != NULL);
+  assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW);
+  assert(cid != NULL);
+
+  evel_set_option_string(&mobile_flow->cid,
+                         cid,
+                         "CID");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Connection Type property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param type        The Connection Type to be set. ASCIIZ string. The caller
+ *                    does not need to preserve the value once the function
+ *                    returns.
+ *****************************************************************************/
+void evel_mobile_flow_con_type_set(EVENT_MOBILE_FLOW * mobile_flow,
+                                   const char * const type)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(mobile_flow != NULL);
+  assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW);
+  assert(type != NULL);
+
+  evel_set_option_string(&mobile_flow->connection_type,
+                         type,
+                         "Connection Type");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the ECGI property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param ecgi        The ECGI to be set. ASCIIZ string.  The caller does not
+ *                    need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_ecgi_set(EVENT_MOBILE_FLOW * mobile_flow,
+                               const char * const ecgi)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(mobile_flow != NULL);
+  assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW);
+  assert(ecgi != NULL);
+
+  evel_set_option_string(&mobile_flow->ecgi,
+                         ecgi,
+                         "ECGI");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the GTP Protocol Type property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param type        The GTP Protocol Type to be set. ASCIIZ string.  The
+ *                    caller does not need to preserve the value once the
+ *                    function returns.
+ *****************************************************************************/
+void evel_mobile_flow_gtp_prot_type_set(EVENT_MOBILE_FLOW * mobile_flow,
+                                        const char * const type)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(mobile_flow != NULL);
+  assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW);
+  assert(type != NULL);
+
+  evel_set_option_string(&mobile_flow->gtp_protocol_type,
+                         type,
+                         "GTP Protocol Type");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the GTP Protocol Version property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param version     The GTP Protocol Version to be set. ASCIIZ string.  The
+ *                    caller does not need to preserve the value once the
+ *                    function returns.
+ *****************************************************************************/
+void evel_mobile_flow_gtp_prot_ver_set(EVENT_MOBILE_FLOW * mobile_flow,
+                                       const char * const version)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(mobile_flow != NULL);
+  assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW);
+  assert(version != NULL);
+
+  evel_set_option_string(&mobile_flow->gtp_version,
+                         version,
+                         "GTP Protocol Version");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the HTTP Header property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param header      The HTTP header to be set. ASCIIZ string. The caller does
+ *                    not need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_http_header_set(EVENT_MOBILE_FLOW * mobile_flow,
+                                      const char * const header)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(mobile_flow != NULL);
+  assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW);
+  assert(header != NULL);
+
+  evel_set_option_string(&mobile_flow->http_header,
+                         header,
+                         "HTTP Header");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the IMEI property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param imei        The IMEI to be set. ASCIIZ string.  The caller does not
+ *                    need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_imei_set(EVENT_MOBILE_FLOW * mobile_flow,
+                               const char * const imei)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(mobile_flow != NULL);
+  assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW);
+  assert(imei != NULL);
+
+  evel_set_option_string(&mobile_flow->imei,
+                         imei,
+                         "IMEI");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the IMSI property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param imsi        The IMSI to be set. ASCIIZ string.  The caller does not
+ *                    need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_imsi_set(EVENT_MOBILE_FLOW * mobile_flow,
+                               const char * const imsi)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(mobile_flow != NULL);
+  assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW);
+  assert(imsi != NULL);
+
+  evel_set_option_string(&mobile_flow->imsi,
+                         imsi,
+                         "IMSI");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the LAC property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param lac         The LAC to be set. ASCIIZ string.  The caller does not
+ *                    need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_lac_set(EVENT_MOBILE_FLOW * mobile_flow,
+                              const char * const lac)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(mobile_flow != NULL);
+  assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW);
+  assert(lac != NULL);
+
+  evel_set_option_string(&mobile_flow->lac,
+                         lac,
+                         "LAC");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the MCC property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param mcc         The MCC to be set. ASCIIZ string.  The caller does not
+ *                    need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_mcc_set(EVENT_MOBILE_FLOW * mobile_flow,
+                              const char * const mcc)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(mobile_flow != NULL);
+  assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW);
+  assert(mcc != NULL);
+
+  evel_set_option_string(&mobile_flow->mcc,
+                         mcc,
+                         "MCC");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the MNC property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param mnc         The MNC to be set. ASCIIZ string.  The caller does not
+ *                    need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_mnc_set(EVENT_MOBILE_FLOW * mobile_flow,
+                              const char * const mnc)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(mobile_flow != NULL);
+  assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW);
+  assert(mnc != NULL);
+
+  evel_set_option_string(&mobile_flow->mnc,
+                         mnc,
+                         "MNC");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the MSISDN property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param msisdn      The MSISDN to be set. ASCIIZ string.  The caller does not
+ *                    need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_msisdn_set(EVENT_MOBILE_FLOW * mobile_flow,
+                                 const char * const msisdn)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(mobile_flow != NULL);
+  assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW);
+  assert(msisdn != NULL);
+
+  evel_set_option_string(&mobile_flow->msisdn,
+                         msisdn,
+                         "MSISDN");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Other Functional Role property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param role        The Other Functional Role to be set. ASCIIZ string. The
+ *                    caller does not need to preserve the value once the
+ *                    function returns.
+ *****************************************************************************/
+void evel_mobile_flow_other_func_role_set(EVENT_MOBILE_FLOW * mobile_flow,
+                                          const char * const role)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(mobile_flow != NULL);
+  assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW);
+  assert(role != NULL);
+
+  evel_set_option_string(&mobile_flow->other_functional_role,
+                         role,
+                         "Other Functional Role");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the RAC property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param rac         The RAC to be set. ASCIIZ string.  The caller does not
+ *                    need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_rac_set(EVENT_MOBILE_FLOW * mobile_flow,
+                              const char * const rac)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(mobile_flow != NULL);
+  assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW);
+  assert(rac != NULL);
+
+  evel_set_option_string(&mobile_flow->rac,
+                         rac,
+                         "RAC");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Radio Access Technology property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param tech        The Radio Access Technology to be set. ASCIIZ string. The
+ *                    caller does not need to preserve the value once the
+ *                    function returns.
+ *****************************************************************************/
+void evel_mobile_flow_radio_acc_tech_set(EVENT_MOBILE_FLOW * mobile_flow,
+                                         const char * const tech)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(mobile_flow != NULL);
+  assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW);
+  assert(tech != NULL);
+
+  evel_set_option_string(&mobile_flow->radio_access_technology,
+                         tech,
+                         "Radio Access Technology");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the SAC property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param sac         The SAC to be set. ASCIIZ string.  The caller does not
+ *                    need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_sac_set(EVENT_MOBILE_FLOW * mobile_flow,
+                              const char * const sac)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(mobile_flow != NULL);
+  assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW);
+  assert(sac != NULL);
+
+  evel_set_option_string(&mobile_flow->sac,
+                         sac,
+                         "SAC");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Sampling Algorithm property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param algorithm   The Sampling Algorithm to be set.
+ *****************************************************************************/
+void evel_mobile_flow_samp_alg_set(EVENT_MOBILE_FLOW * mobile_flow,
+                                   int algorithm)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(mobile_flow != NULL);
+  assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW);
+  assert(algorithm >= 0);
+
+  evel_set_option_int(&mobile_flow->sampling_algorithm,
+                      algorithm,
+                      "Sampling Algorithm");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the TAC property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param tac         The TAC to be set. ASCIIZ string.  The caller does not
+ *                    need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_tac_set(EVENT_MOBILE_FLOW * mobile_flow,
+                              const char * const tac)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(mobile_flow != NULL);
+  assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW);
+  assert(tac != NULL);
+
+  evel_set_option_string(&mobile_flow->tac,
+                         tac,
+                         "TAC");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Tunnel ID property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param tunnel_id   The Tunnel ID to be set. ASCIIZ string.  The caller does
+ *                    not need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_tunnel_id_set(EVENT_MOBILE_FLOW * mobile_flow,
+                                    const char * const tunnel_id)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(mobile_flow != NULL);
+  assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW);
+  assert(tunnel_id != NULL);
+
+  evel_set_option_string(&mobile_flow->tunnel_id,
+                         tunnel_id,
+                         "Tunnel ID");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the VLAN ID property of the Mobile Flow.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param mobile_flow Pointer to the Mobile Flow.
+ * @param vlan_id     The VLAN ID to be set. ASCIIZ string.  The caller does
+ *                    not need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_mobile_flow_vlan_id_set(EVENT_MOBILE_FLOW * mobile_flow,
+                                  const char * const vlan_id)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(mobile_flow != NULL);
+  assert(mobile_flow->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW);
+  assert(vlan_id != NULL);
+
+  evel_set_option_string(&mobile_flow->vlan_id,
+                         vlan_id,
+                         "VLAN ID");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Encode the Mobile Flow in JSON according to AT&T's schema for the event
+ * type.
+ *
+ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
+ * @param event         Pointer to the ::EVENT_HEADER to encode.
+ *****************************************************************************/
+void evel_json_encode_mobile_flow(EVEL_JSON_BUFFER * jbuf,
+                                  EVENT_MOBILE_FLOW * event)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW);
+
+  evel_json_encode_header(jbuf, &event->header);
+  evel_json_open_named_object(jbuf, "mobileFlowFields");
+
+  /***************************************************************************/
+  /* Mandatory parameters.                                                   */
+  /***************************************************************************/
+  evel_enc_kv_string(jbuf, "flowDirection", event->flow_direction);
+  evel_json_encode_mobile_flow_gtp_flow_metrics(
+    jbuf, event->gtp_per_flow_metrics);
+  evel_enc_kv_string(jbuf, "ipProtocolType", event->ip_protocol_type);
+  evel_enc_kv_string(jbuf, "ipVersion", event->ip_version);
+  evel_enc_kv_string(
+    jbuf, "otherEndpointIpAddress", event->other_endpoint_ip_address);
+  evel_enc_kv_int(jbuf, "otherEndpointPort", event->other_endpoint_port);
+  evel_enc_kv_string(
+    jbuf, "reportingEndpointIpAddr", event->reporting_endpoint_ip_addr);
+  evel_enc_kv_int(
+    jbuf, "reportingEndpointPort", event->reporting_endpoint_port);
+
+  /***************************************************************************/
+  /* Optional parameters.                                                    */
+  /***************************************************************************/
+  evel_enc_kv_opt_string(jbuf, "applicationType", &event->application_type);
+  evel_enc_kv_opt_string(jbuf, "appProtocolType", &event->app_protocol_type);
+  evel_enc_kv_opt_string(
+    jbuf, "appProtocolVersion", &event->app_protocol_version);
+  evel_enc_kv_opt_string(jbuf, "cid", &event->cid);
+  evel_enc_kv_opt_string(jbuf, "connectionType", &event->connection_type);
+  evel_enc_kv_opt_string(jbuf, "ecgi", &event->ecgi);
+  evel_enc_kv_opt_string(jbuf, "gtpProtocolType", &event->gtp_protocol_type);
+  evel_enc_kv_opt_string(jbuf, "gtpVersion", &event->gtp_version);
+  evel_enc_kv_opt_string(jbuf, "httpHeader", &event->http_header);
+  evel_enc_kv_opt_string(jbuf, "imei", &event->imei);
+  evel_enc_kv_opt_string(jbuf, "imsi", &event->imsi);
+  evel_enc_kv_opt_string(jbuf, "lac", &event->lac);
+  evel_enc_kv_opt_string(jbuf, "mcc", &event->mcc);
+  evel_enc_kv_opt_string(jbuf, "mnc", &event->mnc);
+  evel_enc_kv_opt_string(jbuf, "msisdn", &event->msisdn);
+  evel_enc_kv_opt_string(
+    jbuf, "otherFunctionalRole", &event->other_functional_role);
+  evel_enc_kv_opt_string(jbuf, "rac", &event->rac);
+  evel_enc_kv_opt_string(
+    jbuf, "radioAccessTechnology", &event->radio_access_technology);
+  evel_enc_kv_opt_string(jbuf, "sac", &event->sac);
+  evel_enc_kv_opt_int(jbuf, "samplingAlgorithm", &event->sampling_algorithm);
+  evel_enc_kv_opt_string(jbuf, "tac", &event->tac);
+  evel_enc_kv_opt_string(jbuf, "tunnelId", &event->tunnel_id);
+  evel_enc_kv_opt_string(jbuf, "vlanId", &event->vlan_id);
+#if 0
+  /***************************************************************************/
+  /* Not in schema.                                                          */
+  /***************************************************************************/
+  evel_enc_version(jbuf,
+                   "mobileFlowFieldsVersion",
+                   event->major_version,
+                   event->minor_version);
+#endif
+  evel_json_close_object(jbuf);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Free a Mobile Flow.
+ *
+ * Free off the Mobile Flow supplied.  Will free all the contained allocated
+ * memory.
+ *
+ * @note It does not free the Mobile Flow itself, since that may be part of a
+ * larger structure.
+ *****************************************************************************/
+void evel_free_mobile_flow(EVENT_MOBILE_FLOW * event)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.  As an internal API we don't allow freeing NULL    */
+  /* events as we do on the public API.                                      */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_MOBILE_FLOW);
+
+  /***************************************************************************/
+  /* Free all internal strings then the header itself.                       */
+  /***************************************************************************/
+  free(event->flow_direction);
+
+  evel_free_mobile_gtp_flow_metrics(event->gtp_per_flow_metrics);
+  free(event->gtp_per_flow_metrics);
+  free(event->ip_protocol_type);
+  free(event->ip_version);
+  free(event->other_endpoint_ip_address);
+  free(event->reporting_endpoint_ip_addr);
+  evel_free_option_string(&event->application_type);
+  evel_free_option_string(&event->app_protocol_type);
+  evel_free_option_string(&event->app_protocol_version);
+  evel_free_option_string(&event->cid);
+  evel_free_option_string(&event->connection_type);
+  evel_free_option_string(&event->ecgi);
+  evel_free_option_string(&event->gtp_protocol_type);
+  evel_free_option_string(&event->gtp_version);
+  evel_free_option_string(&event->http_header);
+  evel_free_option_string(&event->imei);
+  evel_free_option_string(&event->imsi);
+  evel_free_option_string(&event->lac);
+  evel_free_option_string(&event->mcc);
+  evel_free_option_string(&event->mnc);
+  evel_free_option_string(&event->msisdn);
+  evel_free_option_string(&event->other_functional_role);
+  evel_free_option_string(&event->rac);
+  evel_free_option_string(&event->radio_access_technology);
+  evel_free_option_string(&event->sac);
+  evel_free_option_string(&event->tac);
+  evel_free_option_string(&event->tunnel_id);
+  evel_free_option_string(&event->vlan_id);
+
+  evel_free_header(&event->header);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Create a new Mobile GTP Per Flow Metrics.
+ *
+ * @note    The mandatory fields on the Mobile GTP Per Flow Metrics must be
+ *          supplied to this factory function and are immutable once set.
+ *          Optional fields have explicit setter functions, but again values
+ *          may only be set once so that the Mobile GTP Per Flow Metrics has
+ *          immutable properties.
+ *
+ * @param   avg_bit_error_rate          Average bit error rate.
+ * @param   avg_packet_delay_variation  Average delay or jitter in ms.
+ * @param   avg_packet_latency          Average delivery latency.
+ * @param   avg_receive_throughput      Average receive throughput.
+ * @param   avg_transmit_throughput     Average transmit throughput.
+ * @param   flow_activation_epoch       Time the connection is activated.
+ * @param   flow_activation_microsec    Microseconds for the start of the flow
+ *                                      connection.
+ * @param   flow_deactivation_epoch     Time for the end of the connection.
+ * @param   flow_deactivation_microsec  Microseconds for the end of the flow
+ *                                      connection.
+ * @param   flow_deactivation_time      Transmission time of the first packet.
+ * @param   flow_status                 Connection status.
+ * @param   max_packet_delay_variation  Maximum packet delay or jitter in ms.
+ * @param   num_activation_failures     Number of failed activation requests.
+ * @param   num_bit_errors              Number of errored bits.
+ * @param   num_bytes_received          Number of bytes received.
+ * @param   num_bytes_transmitted       Number of bytes transmitted.
+ * @param   num_dropped_packets         Number of received packets dropped.
+ * @param   num_l7_bytes_received       Number of tunneled Layer 7 bytes
+ *                                      received.
+ * @param   num_l7_bytes_transmitted    Number of tunneled Layer 7 bytes
+ *                                      transmitted.
+ * @param   num_lost_packets            Number of lost packets.
+ * @param   num_out_of_order_packets    Number of out-of-order packets.
+ * @param   num_packet_errors           Number of errored packets.
+ * @param   num_packets_received_excl_retrans  Number of packets received,
+ *                                             excluding retransmits.
+ * @param   num_packets_received_incl_retrans  Number of packets received.
+ * @param   num_packets_transmitted_incl_retrans  Number of packets
+ *                                                transmitted.
+ * @param   num_retries                 Number of packet retries.
+ * @param   num_timeouts                Number of packet timeouts.
+ * @param   num_tunneled_l7_bytes_received  Number of tunneled Layer 7 bytes
+ *                                          received, excluding retransmits.
+ * @param   round_trip_time             Round trip time.
+ * @param   time_to_first_byte          Time in ms between connection
+ *                                      activation and first byte received.
+ *
+ * @returns pointer to the newly manufactured ::MOBILE_GTP_PER_FLOW_METRICS.
+ *          If the structure is not used it must be released using
+ *          ::evel_free_mobile_gtp_flow_metrics.
+ * @retval  NULL  Failed to create the event.
+ *****************************************************************************/
+MOBILE_GTP_PER_FLOW_METRICS * evel_new_mobile_gtp_flow_metrics(
+                                      double avg_bit_error_rate,
+                                      double avg_packet_delay_variation,
+                                      int avg_packet_latency,
+                                      int avg_receive_throughput,
+                                      int avg_transmit_throughput,
+                                      int flow_activation_epoch,
+                                      int flow_activation_microsec,
+                                      int flow_deactivation_epoch,
+                                      int flow_deactivation_microsec,
+                                      time_t flow_deactivation_time,
+                                      const char * const flow_status,
+                                      int max_packet_delay_variation,
+                                      int num_activation_failures,
+                                      int num_bit_errors,
+                                      int num_bytes_received,
+                                      int num_bytes_transmitted,
+                                      int num_dropped_packets,
+                                      int num_l7_bytes_received,
+                                      int num_l7_bytes_transmitted,
+                                      int num_lost_packets,
+                                      int num_out_of_order_packets,
+                                      int num_packet_errors,
+                                      int num_packets_received_excl_retrans,
+                                      int num_packets_received_incl_retrans,
+                                      int num_packets_transmitted_incl_retrans,
+                                      int num_retries,
+                                      int num_timeouts,
+                                      int num_tunneled_l7_bytes_received,
+                                      int round_trip_time,
+                                      int time_to_first_byte)
+{
+  MOBILE_GTP_PER_FLOW_METRICS * metrics = NULL;
+  int ii;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(avg_bit_error_rate >= 0.0);
+  assert(avg_packet_delay_variation >= 0.0);
+  assert(avg_packet_latency >= 0);
+  assert(avg_receive_throughput >= 0);
+  assert(avg_transmit_throughput >= 0);
+  assert(flow_activation_epoch > 0);
+  assert(flow_activation_microsec >= 0);
+  assert(flow_deactivation_epoch > 0);
+  assert(flow_deactivation_microsec >= 0);
+  assert(flow_status != NULL);
+  assert(max_packet_delay_variation >= 0);
+  assert(num_activation_failures >= 0);
+  assert(num_bit_errors >= 0);
+  assert(num_bytes_received >= 0);
+  assert(num_bytes_transmitted >= 0);
+  assert(num_dropped_packets >= 0);
+  assert(num_l7_bytes_received >= 0);
+  assert(num_l7_bytes_transmitted >= 0);
+  assert(num_lost_packets >= 0);
+  assert(num_out_of_order_packets >= 0);
+  assert(num_packet_errors >= 0);
+  assert(num_packets_received_excl_retrans >= 0);
+  assert(num_packets_received_incl_retrans >= 0);
+  assert(num_packets_transmitted_incl_retrans >= 0);
+  assert(num_retries >= 0);
+  assert(num_timeouts >= 0);
+  assert(num_tunneled_l7_bytes_received >= 0);
+  assert(round_trip_time >= 0);
+  assert(time_to_first_byte >= 0);
+
+  /***************************************************************************/
+  /* Allocate the Mobile Flow GTP Per Flow Metrics.                          */
+  /***************************************************************************/
+  metrics = malloc(sizeof(MOBILE_GTP_PER_FLOW_METRICS));
+  if (metrics == NULL)
+  {
+    log_error_state("Out of memory");
+    goto exit_label;
+  }
+  memset(metrics, 0, sizeof(MOBILE_GTP_PER_FLOW_METRICS));
+  EVEL_DEBUG("New Mobile Flow GTP Per Flow Metrics is at %lp", metrics);
+
+  /***************************************************************************/
+  /* Initialize the Mobile Flow GTP Per Flow Metrics fields.  Optional       */
+  /* string values are uninitialized (NULL).                                 */
+  /***************************************************************************/
+  metrics->avg_bit_error_rate = avg_bit_error_rate;
+  metrics->avg_packet_delay_variation = avg_packet_delay_variation;
+  metrics->avg_packet_latency = avg_packet_latency;
+  metrics->avg_receive_throughput = avg_receive_throughput;
+  metrics->avg_transmit_throughput = avg_transmit_throughput;
+  metrics->flow_activation_epoch = flow_activation_epoch;
+  metrics->flow_activation_microsec = flow_activation_microsec;
+  metrics->flow_deactivation_epoch = flow_deactivation_epoch;
+  metrics->flow_deactivation_microsec = flow_deactivation_microsec;
+  metrics->flow_deactivation_time = flow_deactivation_time;
+  metrics->flow_status = strdup(flow_status);
+  metrics->max_packet_delay_variation = max_packet_delay_variation;
+  metrics->num_activation_failures = num_activation_failures;
+  metrics->num_bit_errors = num_bit_errors;
+  metrics->num_bytes_received = num_bytes_received;
+  metrics->num_bytes_transmitted = num_bytes_transmitted;
+  metrics->num_dropped_packets = num_dropped_packets;
+  metrics->num_l7_bytes_received = num_l7_bytes_received;
+  metrics->num_l7_bytes_transmitted = num_l7_bytes_transmitted;
+  metrics->num_lost_packets = num_lost_packets;
+  metrics->num_out_of_order_packets = num_out_of_order_packets;
+  metrics->num_packet_errors = num_packet_errors;
+  metrics->num_packets_received_excl_retrans =
+                                             num_packets_received_excl_retrans;
+  metrics->num_packets_received_incl_retrans =
+                                             num_packets_received_incl_retrans;
+  metrics->num_packets_transmitted_incl_retrans =
+                                          num_packets_transmitted_incl_retrans;
+  metrics->num_retries = num_retries;
+  metrics->num_timeouts = num_timeouts;
+  metrics->num_tunneled_l7_bytes_received = num_tunneled_l7_bytes_received;
+  metrics->round_trip_time = round_trip_time;
+  metrics->time_to_first_byte = time_to_first_byte;
+  for (ii = 0; ii < EVEL_TOS_SUPPORTED; ii++)
+  {
+    evel_init_option_int(&metrics->ip_tos_counts[ii]);
+  }
+  for (ii = 0; ii < EVEL_MAX_TCP_FLAGS; ii++)
+  {
+    evel_init_option_int(&metrics->tcp_flag_counts[ii]);
+  }
+  for (ii = 0; ii < EVEL_MAX_QCI_COS_TYPES; ii++)
+  {
+    evel_init_option_int(&metrics->qci_cos_counts[ii]);
+  }
+  evel_init_option_int(&metrics->dur_connection_failed_status);
+  evel_init_option_int(&metrics->dur_tunnel_failed_status);
+  evel_init_option_string(&metrics->flow_activated_by);
+  evel_init_option_time(&metrics->flow_activation_time);
+  evel_init_option_string(&metrics->flow_deactivated_by);
+  evel_init_option_string(&metrics->gtp_connection_status);
+  evel_init_option_string(&metrics->gtp_tunnel_status);
+  evel_init_option_int(&metrics->large_packet_rtt);
+  evel_init_option_double(&metrics->large_packet_threshold);
+  evel_init_option_int(&metrics->max_receive_bit_rate);
+  evel_init_option_int(&metrics->max_transmit_bit_rate);
+  evel_init_option_int(&metrics->num_gtp_echo_failures);
+  evel_init_option_int(&metrics->num_gtp_tunnel_errors);
+  evel_init_option_int(&metrics->num_http_errors);
+
+exit_label:
+  EVEL_EXIT();
+  return metrics;
+}
+
+/**************************************************************************//**
+ * Set the Duration of Connection Failed Status property of the Mobile GTP Per
+ * Flow Metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param duration    The Duration of Connection Failed Status to be set.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_dur_con_fail_set(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         int duration)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(metrics != NULL);
+  assert(duration >= 0);
+
+  evel_set_option_int(&metrics->dur_connection_failed_status,
+                      duration,
+                      "Duration of Connection Failed Status");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Duration of Tunnel Failed Status property of the Mobile GTP Per Flow
+ * Metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param duration    The Duration of Tunnel Failed Status to be set.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_dur_tun_fail_set(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         int duration)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(metrics != NULL);
+  assert(duration >= 0);
+
+  evel_set_option_int(&metrics->dur_tunnel_failed_status,
+                      duration,
+                      "Duration of Tunnel Failed Status");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Activated By property of the Mobile GTP Per Flow metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param act_by      The Activated By to be set.  ASCIIZ string. The caller
+ *                    does not need to preserve the value once the function
+ *                    returns.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_act_by_set(MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                        const char * const act_by)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(metrics != NULL);
+  assert(act_by != NULL);
+
+  evel_set_option_string(&metrics->flow_activated_by,
+                         act_by,
+                         "Activated By");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Activation Time property of the Mobile GTP Per Flow metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param act_time    The Activation Time to be set.  ASCIIZ string. The caller
+ *                    does not need to preserve the value once the function
+ *                    returns.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_act_time_set(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         time_t act_time)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(metrics != NULL);
+  assert(act_time > 0);
+
+  evel_set_option_time(&metrics->flow_activation_time,
+                       act_time,
+                       "Activation Time");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Deactivated By property of the Mobile GTP Per Flow metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param deact_by    The Deactivated By to be set.  ASCIIZ string. The caller
+ *                    does not need to preserve the value once the function
+ *                    returns.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_deact_by_set(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         const char * const deact_by)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(metrics != NULL);
+  assert(deact_by != NULL);
+
+  evel_set_option_string(&metrics->flow_deactivated_by,
+                         deact_by,
+                         "Deactivated By");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the GTP Connection Status property of the Mobile GTP Per Flow metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param status      The GTP Connection Status to be set.  ASCIIZ string. The
+ *                    caller does not need to preserve the value once the
+ *                    function returns.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_con_status_set(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         const char * const status)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(metrics != NULL);
+  assert(status != NULL);
+
+  evel_set_option_string(&metrics->gtp_connection_status,
+                         status,
+                         "GTP Connection Status");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the GTP Tunnel Status property of the Mobile GTP Per Flow metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param status      The GTP Tunnel Status to be set.  ASCIIZ string. The
+ *                    caller does not need to preserve the value once the
+ *                    function returns.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_tun_status_set(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         const char * const status)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(metrics != NULL);
+  assert(status != NULL);
+
+  evel_set_option_string(&metrics->gtp_tunnel_status,
+                         status,
+                         "GTP Tunnel Status");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set an IP Type-of-Service count property of the Mobile GTP Per Flow metrics.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param index       The index of the IP Type-of-Service.
+ * @param count       The count.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_iptos_set(MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                       int index,
+                                       int count)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(metrics != NULL);
+  assert(index >= 0);
+  assert(index < EVEL_TOS_SUPPORTED);
+  assert(count >= 0);
+  assert(count <= 255);
+
+  EVEL_DEBUG("IP Type-of-Service %d", index);
+  evel_set_option_int(&metrics->ip_tos_counts[index],
+                      count,
+                      "IP Type-of-Service");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Large Packet Round-Trip Time property of the Mobile GTP Per Flow
+ * Metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param rtt         The Large Packet Round-Trip Time to be set.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_large_pkt_rtt_set(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         int rtt)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(metrics != NULL);
+  assert(rtt >= 0);
+
+  evel_set_option_int(&metrics->large_packet_rtt,
+                      rtt,
+                      "Large Packet Round-Trip Time");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Large Packet Threshold property of the Mobile GTP Per Flow Metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param threshold   The Large Packet Threshold to be set.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_large_pkt_thresh_set(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         double threshold)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(metrics != NULL);
+  assert(threshold >= 0.0);
+
+  evel_set_option_double(&metrics->large_packet_threshold,
+                         threshold,
+                         "Large Packet Threshold");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Max Receive Bit Rate property of the Mobile GTP Per Flow Metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param rate        The Max Receive Bit Rate to be set.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_max_rcv_bit_rate_set(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         int rate)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(metrics != NULL);
+  assert(rate >= 0);
+
+  evel_set_option_int(&metrics->max_receive_bit_rate,
+                      rate,
+                      "Max Receive Bit Rate");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Max Transmit Bit Rate property of the Mobile GTP Per Flow Metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param rate        The Max Transmit Bit Rate to be set.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_max_trx_bit_rate_set(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         int rate)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(metrics != NULL);
+  assert(rate >= 0);
+
+  evel_set_option_int(&metrics->max_transmit_bit_rate,
+                      rate,
+                      "Max Transmit Bit Rate");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Number of GTP Echo Failures property of the Mobile GTP Per Flow
+ * Metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param num         The Number of GTP Echo Failures to be set.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_num_echo_fail_set(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         int num)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(metrics != NULL);
+  assert(num >= 0);
+
+  evel_set_option_int(&metrics->num_gtp_echo_failures,
+                      num,
+                      "Number of GTP Echo Failures");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Number of GTP Tunnel Errors property of the Mobile GTP Per Flow
+ * Metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param num         The Number of GTP Tunnel Errors to be set.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_num_tun_fail_set(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         int num)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(metrics != NULL);
+  assert(num >= 0);
+
+  evel_set_option_int(&metrics->num_gtp_tunnel_errors,
+                      num,
+                      "Number of GTP Tunnel Errors");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Number of HTTP Errors property of the Mobile GTP Per Flow Metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics     Pointer to the Mobile GTP Per Flow Metrics.
+ * @param num         The Number of HTTP Errors to be set.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_num_http_errors_set(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         int num)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(metrics != NULL);
+  assert(num >= 0);
+
+  evel_set_option_int(&metrics->num_http_errors,
+                      num,
+                      "Number of HTTP Errors");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Add a TCP flag count to the metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics       Pointer to the Mobile GTP Per Flow Metrics.
+ * @param tcp_flag      The TCP flag to be updated.
+ * @param count         The associated flag count, which must be nonzero.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_tcp_flag_count_add(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         const EVEL_TCP_FLAGS tcp_flag,
+                                         const int count)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(metrics != NULL);
+  assert(tcp_flag >= 0);
+  assert(tcp_flag < EVEL_MAX_TCP_FLAGS);
+  assert(count >= 0);
+
+  EVEL_DEBUG("TCP Flag: %d", tcp_flag);
+  evel_set_option_int(&metrics->tcp_flag_counts[tcp_flag],
+                      count,
+                      "TCP flag");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Add a QCI COS count to the metrics.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param metrics       Pointer to the Mobile GTP Per Flow Metrics.
+ * @param qci_cos       The QCI COS count to be updated.
+ * @param count         The associated QCI COS count.
+ *****************************************************************************/
+void evel_mobile_gtp_metrics_qci_cos_count_add(
+                                         MOBILE_GTP_PER_FLOW_METRICS * metrics,
+                                         const EVEL_QCI_COS_TYPES qci_cos,
+                                         const int count)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(metrics != NULL);
+  assert(qci_cos >= 0);
+  assert(qci_cos < EVEL_MAX_QCI_COS_TYPES);
+  assert(count >= 0);
+
+  EVEL_DEBUG("QCI COS: %d", qci_cos);
+  evel_set_option_int(&metrics->qci_cos_counts[qci_cos],
+                      count,
+                      "QCI COS");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Encode the Mobile Flow GTP Per Flow Metrics as a JSON object.
+ *
+ * @param jbuf          Pointer to working ::EVEL_JSON_BUFFER.
+ * @param metrics       Pointer to the ::EVENT_MOBILE_FLOW to encode.
+ * @returns Number of bytes actually written.
+ *****************************************************************************/
+void evel_json_encode_mobile_flow_gtp_flow_metrics(
+                                        EVEL_JSON_BUFFER * jbuf,
+                                        MOBILE_GTP_PER_FLOW_METRICS * metrics)
+{
+  int index;
+  bool found_ip_tos;
+  bool found_tcp_flag;
+  bool found_qci_cos;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(jbuf != NULL);
+  assert(metrics != NULL);
+
+  evel_json_open_named_object(jbuf, "gtpPerFlowMetrics");
+
+  /***************************************************************************/
+  /* Mandatory parameters.                                                   */
+  /***************************************************************************/
+  evel_enc_kv_double(jbuf, "avgBitErrorRate", metrics->avg_bit_error_rate);
+  evel_enc_kv_double(
+    jbuf, "avgPacketDelayVariation", metrics->avg_packet_delay_variation);
+  evel_enc_kv_int(jbuf, "avgPacketLatency", metrics->avg_packet_latency);
+  evel_enc_kv_int(
+    jbuf, "avgReceiveThroughput", metrics->avg_receive_throughput);
+  evel_enc_kv_int(
+    jbuf, "avgTransmitThroughput", metrics->avg_transmit_throughput);
+  evel_enc_kv_int(jbuf, "flowActivationEpoch", metrics->flow_activation_epoch);
+  evel_enc_kv_int(
+    jbuf, "flowActivationMicrosec", metrics->flow_activation_microsec);
+  evel_enc_kv_int(
+    jbuf, "flowDeactivationEpoch", metrics->flow_deactivation_epoch);
+  evel_enc_kv_int(
+    jbuf, "flowDeactivationMicrosec", metrics->flow_deactivation_microsec);
+  evel_enc_kv_time(
+    jbuf, "flowDeactivationTime", &metrics->flow_deactivation_time);
+  evel_enc_kv_string(jbuf, "flowStatus", metrics->flow_status);
+  evel_enc_kv_int(
+    jbuf, "maxPacketDelayVariation", metrics->max_packet_delay_variation);
+  evel_enc_kv_int(
+    jbuf, "numActivationFailures", metrics->num_activation_failures);
+  evel_enc_kv_int(jbuf, "numBitErrors", metrics->num_bit_errors);
+  evel_enc_kv_int(jbuf, "numBytesReceived", metrics->num_bytes_received);
+  evel_enc_kv_int(jbuf, "numBytesTransmitted", metrics->num_bytes_transmitted);
+  evel_enc_kv_int(jbuf, "numDroppedPackets", metrics->num_dropped_packets);
+  evel_enc_kv_int(jbuf, "numL7BytesReceived", metrics->num_l7_bytes_received);
+  evel_enc_kv_int(
+    jbuf, "numL7BytesTransmitted", metrics->num_l7_bytes_transmitted);
+  evel_enc_kv_int(jbuf, "numLostPackets", metrics->num_lost_packets);
+  evel_enc_kv_int(
+    jbuf, "numOutOfOrderPackets", metrics->num_out_of_order_packets);
+  evel_enc_kv_int(jbuf, "numPacketErrors", metrics->num_packet_errors);
+  evel_enc_kv_int(jbuf,
+                  "numPacketsReceivedExclRetrans",
+                  metrics->num_packets_received_excl_retrans);
+  evel_enc_kv_int(jbuf,
+                  "numPacketsReceivedInclRetrans",
+                  metrics->num_packets_received_incl_retrans);
+  evel_enc_kv_int(jbuf,
+                  "numPacketsTransmittedInclRetrans",
+                  metrics->num_packets_transmitted_incl_retrans);
+  evel_enc_kv_int(jbuf, "numRetries", metrics->num_retries);
+  evel_enc_kv_int(jbuf, "numTimeouts", metrics->num_timeouts);
+  evel_enc_kv_int(jbuf,
+                  "numTunneledL7BytesReceived",
+                  metrics->num_tunneled_l7_bytes_received);
+  evel_enc_kv_int(jbuf, "roundTripTime", metrics->round_trip_time);
+  evel_enc_kv_int(jbuf, "timeToFirstByte", metrics->time_to_first_byte);
+
+  /***************************************************************************/
+  /* Optional parameters.                                                    */
+  /***************************************************************************/
+  found_ip_tos = false;
+  for (index = 0; index < EVEL_TOS_SUPPORTED; index++)
+  {
+    if (metrics->ip_tos_counts[index].is_set)
+    {
+      found_ip_tos = true;
+      break;
+    }
+  }
+
+  if (found_ip_tos)
+  {
+    evel_json_open_named_list(jbuf, "ipTosCountList");
+    for (index = 0; index < EVEL_TOS_SUPPORTED; index++)
+    {
+      if (metrics->ip_tos_counts[index].is_set)
+      {
+        evel_enc_list_item(jbuf,
+                           "[\"%d\", %d]",
+                           index,
+                           metrics->ip_tos_counts[index].value);
+      }
+    }
+    evel_json_close_list(jbuf);
+  }
+
+  if (found_ip_tos)
+  {
+    evel_json_open_named_list(jbuf, "ipTosList");
+    for (index = 0; index < EVEL_TOS_SUPPORTED; index++)
+    {
+      if (metrics->ip_tos_counts[index].is_set)
+      {
+        evel_enc_list_item(jbuf, "\"%d\"", index);
+      }
+    }
+    evel_json_close_list(jbuf);
+  }
+
+  /***************************************************************************/
+  /* Make some compile-time assertions about EVEL_TCP_FLAGS.  If you update  */
+  /* these, make sure you update evel_tcp_flag_strings to match the enum.    */
+  /***************************************************************************/
+  EVEL_CT_ASSERT(EVEL_TCP_NS == 0);
+  EVEL_CT_ASSERT(EVEL_TCP_CWR == 1);
+  EVEL_CT_ASSERT(EVEL_TCP_ECE == 2);
+  EVEL_CT_ASSERT(EVEL_TCP_URG == 3);
+  EVEL_CT_ASSERT(EVEL_TCP_ACK == 4);
+  EVEL_CT_ASSERT(EVEL_TCP_PSH == 5);
+  EVEL_CT_ASSERT(EVEL_TCP_RST == 6);
+  EVEL_CT_ASSERT(EVEL_TCP_SYN == 7);
+  EVEL_CT_ASSERT(EVEL_TCP_FIN == 8);
+  EVEL_CT_ASSERT(EVEL_MAX_TCP_FLAGS == 9);
+
+  found_tcp_flag = false;
+  for (index = 0; index < EVEL_MAX_TCP_FLAGS; index++)
+  {
+    if (metrics->tcp_flag_counts[index].is_set)
+    {
+      found_tcp_flag = true;
+      break;
+    }
+  }
+
+  if (found_tcp_flag)
+  {
+    evel_json_open_named_list(jbuf, "tcpFlagList");
+    for (index = 0; index < EVEL_MAX_TCP_FLAGS; index++)
+    {
+      if (metrics->tcp_flag_counts[index].is_set)
+      {
+        evel_enc_list_item(jbuf,
+                           "\"%s\"",
+                           evel_tcp_flag_strings[index]);
+      }
+    }
+    evel_json_close_list(jbuf);
+  }
+
+  if (found_tcp_flag)
+  {
+    evel_json_open_named_list(jbuf, "tcpFlagCountList");
+    for (index = 0; index < EVEL_MAX_TCP_FLAGS; index++)
+    {
+      if (metrics->tcp_flag_counts[index].is_set)
+      {
+        evel_enc_list_item(jbuf,
+                           "[\"%s\", %d]",
+                           evel_tcp_flag_strings[index],
+                           metrics->tcp_flag_counts[index].value);
+      }
+    }
+    evel_json_close_list(jbuf);
+  }
+
+  /***************************************************************************/
+  /* Make some compile-time assertions about EVEL_QCI_COS_TYPES.  If you     */
+  /* update these, make sure you update evel_qci_cos_strings to match the    */
+  /* enum.                                                                   */
+  /***************************************************************************/
+  EVEL_CT_ASSERT(EVEL_QCI_COS_UMTS_CONVERSATIONAL ==0);
+  EVEL_CT_ASSERT(EVEL_QCI_COS_UMTS_STREAMING == 1);
+  EVEL_CT_ASSERT(EVEL_QCI_COS_UMTS_INTERACTIVE == 2);
+  EVEL_CT_ASSERT(EVEL_QCI_COS_UMTS_BACKGROUND == 3);
+  EVEL_CT_ASSERT(EVEL_QCI_COS_LTE_1 == 4);
+  EVEL_CT_ASSERT(EVEL_QCI_COS_LTE_2 == 5);
+  EVEL_CT_ASSERT(EVEL_QCI_COS_LTE_3 == 6);
+  EVEL_CT_ASSERT(EVEL_QCI_COS_LTE_4 == 7);
+  EVEL_CT_ASSERT(EVEL_QCI_COS_LTE_65 == 8);
+  EVEL_CT_ASSERT(EVEL_QCI_COS_LTE_66 == 9);
+  EVEL_CT_ASSERT(EVEL_QCI_COS_LTE_5 == 10);
+  EVEL_CT_ASSERT(EVEL_QCI_COS_LTE_6 == 11);
+  EVEL_CT_ASSERT(EVEL_QCI_COS_LTE_7 == 12);
+  EVEL_CT_ASSERT(EVEL_QCI_COS_LTE_8 == 13);
+  EVEL_CT_ASSERT(EVEL_QCI_COS_LTE_9 == 14);
+  EVEL_CT_ASSERT(EVEL_QCI_COS_LTE_69 == 15);
+  EVEL_CT_ASSERT(EVEL_QCI_COS_LTE_70 == 16);
+  EVEL_CT_ASSERT(EVEL_MAX_QCI_COS_TYPES == 17);
+
+  found_qci_cos = false;
+  for (index = 0; index < EVEL_MAX_QCI_COS_TYPES; index++)
+  {
+    if (metrics->qci_cos_counts[index].is_set)
+    {
+      found_qci_cos = true;
+      break;
+    }
+  }
+
+  if (found_qci_cos)
+  {
+    evel_json_open_named_list(jbuf, "mobileQciCosList");
+    for (index = 0; index < EVEL_MAX_QCI_COS_TYPES; index++)
+    {
+      if (metrics->qci_cos_counts[index].is_set)
+      {
+        evel_enc_list_item(jbuf,
+                           "\"%s\"",
+                           evel_qci_cos_strings[index]);
+      }
+    }
+    evel_json_close_list(jbuf);
+  }
+
+  if (found_qci_cos)
+  {
+    evel_json_open_named_list(jbuf, "mobileQciCosCountList");
+    for (index = 0; index < EVEL_MAX_QCI_COS_TYPES; index++)
+    {
+      if (metrics->qci_cos_counts[index].is_set)
+      {
+        evel_enc_list_item(jbuf,
+                           "[\"%s\", %d]",
+                           evel_qci_cos_strings[index],
+                           metrics->qci_cos_counts[index].value);
+      }
+    }
+    evel_json_close_list(jbuf);
+  }
+
+  evel_enc_kv_opt_int(
+    jbuf, "durConnectionFailedStatus", &metrics->dur_connection_failed_status);
+  evel_enc_kv_opt_int(
+    jbuf, "durTunnelFailedStatus", &metrics->dur_tunnel_failed_status);
+  evel_enc_kv_opt_string(jbuf, "flowActivatedBy", &metrics->flow_activated_by);
+  evel_enc_kv_opt_time(
+    jbuf, "flowActivationTime", &metrics->flow_activation_time);
+  evel_enc_kv_opt_string(
+    jbuf, "flowDeactivatedBy", &metrics->flow_deactivated_by);
+  evel_enc_kv_opt_string(
+    jbuf, "gtpConnectionStatus", &metrics->gtp_connection_status);
+  evel_enc_kv_opt_string(jbuf, "gtpTunnelStatus", &metrics->gtp_tunnel_status);
+  evel_enc_kv_opt_int(jbuf, "largePacketRtt", &metrics->large_packet_rtt);
+  evel_enc_kv_opt_double(
+    jbuf, "largePacketThreshold", &metrics->large_packet_threshold);
+  evel_enc_kv_opt_int(
+    jbuf, "maxReceiveBitRate", &metrics->max_receive_bit_rate);
+  evel_enc_kv_opt_int(
+    jbuf, "maxTransmitBitRate", &metrics->max_transmit_bit_rate);
+  evel_enc_kv_opt_int(
+    jbuf, "numGtpEchoFailures", &metrics->num_gtp_echo_failures);
+  evel_enc_kv_opt_int(
+    jbuf, "numGtpTunnelErrors", &metrics->num_gtp_tunnel_errors);
+  evel_enc_kv_opt_int(jbuf, "numHttpErrors", &metrics->num_http_errors);
+
+  evel_json_close_object(jbuf);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Free a Mobile GTP Per Flow Metrics.
+ *
+ * Free off the Mobile GTP Per Flow Metrics supplied.  Will free all the
+ * contained allocated memory.
+ *
+ * @note It does not free the Mobile GTP Per Flow Metrics itself, since that
+ * may be part of a larger structure.
+ *****************************************************************************/
+void evel_free_mobile_gtp_flow_metrics(MOBILE_GTP_PER_FLOW_METRICS * metrics)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(metrics != NULL);
+
+  /***************************************************************************/
+  /* Free all internal strings.                                              */
+  /***************************************************************************/
+  free(metrics->flow_status);
+
+  evel_free_option_string(&metrics->flow_activated_by);
+  evel_free_option_string(&metrics->flow_deactivated_by);
+  evel_free_option_string(&metrics->gtp_connection_status);
+  evel_free_option_string(&metrics->gtp_tunnel_status);
+
+  EVEL_EXIT();
+}
\ No newline at end of file
diff --git a/vnfs/VES/code/evel_library/evel_option.c b/vnfs/VES/code/evel_library/evel_option.c
new file mode 100644 (file)
index 0000000..fe714b5
--- /dev/null
@@ -0,0 +1,442 @@
+/**************************************************************************//**
+ * @file
+ * Source module relating to EVEL_OPTION_ types.
+ *
+ * License
+ * -------
+ *
+ * Copyright(c) <2016>, AT&T Intellectual Property.  All other rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:  This product includes
+ *    software developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "evel_internal.h"
+
+/**************************************************************************//**
+ * Free the underlying resources of an ::EVEL_OPTION_STRING.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_STRING.
+ *****************************************************************************/
+void evel_free_option_string(EVEL_OPTION_STRING * const option)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(option != NULL);
+
+  if (option->is_set)
+  {
+    free(option->value);
+    option->value = NULL;
+    option->is_set = EVEL_FALSE;
+  }
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Initialize an ::EVEL_OPTION_STRING to a not-set state.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_STRING.
+ *****************************************************************************/
+void evel_init_option_string(EVEL_OPTION_STRING * const option)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(option != NULL);
+
+  option->value = NULL;
+  option->is_set = EVEL_FALSE;
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the value of an ::EVEL_OPTION_STRING.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_STRING.
+ * @param value         The value to set.
+ * @param description   Description to be used in logging.
+ *****************************************************************************/
+void evel_set_option_string(EVEL_OPTION_STRING * const option,
+                            const char * const value,
+                            const char * const description)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(option != NULL);
+  assert(value != NULL);
+  assert(description != NULL);
+
+  if (option->is_set)
+  {
+    EVEL_ERROR("Ignoring attempt to update %s to %s. %s already set to %s",
+               description, value, description, option->value);
+  }
+  else
+  {
+    EVEL_DEBUG("Setting %s to %s", description, value);
+    option->value = strdup(value);
+    option->is_set = EVEL_TRUE;
+  }
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Force the value of an ::EVEL_OPTION_STRING.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_STRING.
+ * @param value         The value to set.
+ *****************************************************************************/
+void evel_force_option_string(EVEL_OPTION_STRING * const option,
+                              const char * const value)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(option != NULL);
+  assert(option->is_set == EVEL_FALSE);
+  assert(option->value == NULL);
+
+  option->value = strdup(value);
+  option->is_set = EVEL_TRUE;
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Initialize an ::EVEL_OPTION_INT to a not-set state.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_INT.
+ *****************************************************************************/
+void evel_init_option_int(EVEL_OPTION_INT * const option)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(option != NULL);
+
+  option->value = 0;
+  option->is_set = EVEL_FALSE;
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Force the value of an ::EVEL_OPTION_INT.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_INT.
+ * @param value         The value to set.
+ *****************************************************************************/
+void evel_force_option_int(EVEL_OPTION_INT * const option,
+                           const int value)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(option != NULL);
+
+  option->value = value;
+  option->is_set = EVEL_TRUE;
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the value of an ::EVEL_OPTION_INT.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_INT.
+ * @param value         The value to set.
+ * @param description   Description to be used in logging.
+ *****************************************************************************/
+void evel_set_option_int(EVEL_OPTION_INT * const option,
+                         const int value,
+                         const char * const description)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(option != NULL);
+  assert(description != NULL);
+
+  if (option->is_set)
+  {
+    EVEL_ERROR("Ignoring attempt to update %s to %d. %s already set to %d",
+               description, value, description, option->value);
+  }
+  else
+  {
+    EVEL_DEBUG("Setting %s to %d", description, value);
+    option->value = value;
+    option->is_set = EVEL_TRUE;
+  }
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Initialize an ::EVEL_OPTION_DOUBLE to a not-set state.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_DOUBLE.
+ *****************************************************************************/
+void evel_init_option_double(EVEL_OPTION_DOUBLE * const option)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(option != NULL);
+
+  option->value = 0.0;
+  option->is_set = EVEL_FALSE;
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Force the value of an ::EVEL_OPTION_DOUBLE.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_DOUBLE.
+ * @param value         The value to set.
+ *****************************************************************************/
+void evel_force_option_double(EVEL_OPTION_DOUBLE * const option,
+                              const double value)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(option != NULL);
+
+  option->value = value;
+  option->is_set = EVEL_TRUE;
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the value of an ::EVEL_OPTION_DOUBLE.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_DOUBLE.
+ * @param value         The value to set.
+ * @param description   Description to be used in logging.
+ *****************************************************************************/
+void evel_set_option_double(EVEL_OPTION_DOUBLE * const option,
+                            const double value,
+                            const char * const description)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(option != NULL);
+  assert(description != NULL);
+
+  if (option->is_set)
+  {
+    EVEL_ERROR("Ignoring attempt to update %s to %lf. %s already set to %lf",
+               description, value, description, option->value);
+  }
+  else
+  {
+    EVEL_DEBUG("Setting %s to %lf", description, value);
+    option->value = value;
+    option->is_set = EVEL_TRUE;
+  }
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Initialize an ::EVEL_OPTION_ULL to a not-set state.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_ULL.
+ *****************************************************************************/
+void evel_init_option_ull(EVEL_OPTION_ULL * const option)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(option != NULL);
+  option->value = 0;
+  option->is_set = EVEL_FALSE;
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Force the value of an ::EVEL_OPTION_ULL.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_ULL.
+ * @param value         The value to set.
+ *****************************************************************************/
+void evel_force_option_ull(EVEL_OPTION_ULL * const option,
+                           const unsigned long long value)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(option != NULL);
+
+  option->value = value;
+  option->is_set = EVEL_TRUE;
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the value of an ::EVEL_OPTION_ULL.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_ULL.
+ * @param value         The value to set.
+ * @param description   Description to be used in logging.
+ *****************************************************************************/
+void evel_set_option_ull(EVEL_OPTION_ULL * const option,
+                         const unsigned long long value,
+                         const char * const description)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(option != NULL);
+  assert(description != NULL);
+
+  if (option->is_set)
+  {
+    EVEL_ERROR("Ignoring attempt to update %s to %llu. %s already set to %llu",
+               description, value, description, option->value);
+  }
+  else
+  {
+    EVEL_DEBUG("Setting %s to %llu", description, value);
+    option->value = value;
+    option->is_set = EVEL_TRUE;
+  }
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Initialize an ::EVEL_OPTION_TIME to a not-set state.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_TIME.
+ *****************************************************************************/
+void evel_init_option_time(EVEL_OPTION_TIME * const option)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(option != NULL);
+  option->value = 0;
+  option->is_set = EVEL_FALSE;
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Force the value of an ::EVEL_OPTION_TIME.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_TIME.
+ * @param value         The value to set.
+ *****************************************************************************/
+void evel_force_option_time(EVEL_OPTION_TIME * const option,
+                            const time_t value)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(option != NULL);
+
+  option->value = value;
+  option->is_set = EVEL_TRUE;
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the value of an ::EVEL_OPTION_TIME.
+ *
+ * @param option        Pointer to the ::EVEL_OPTION_TIME.
+ * @param value         The value to set.
+ * @param description   Description to be used in logging.
+ *****************************************************************************/
+void evel_set_option_time(EVEL_OPTION_TIME * const option,
+                          const time_t value,
+                          const char * const description)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(option != NULL);
+  assert(description != NULL);
+
+  if (option->is_set)
+  {
+    EVEL_ERROR("Ignoring attempt to update %s to %d. %s already set to %d",
+               description, value, description, option->value);
+  }
+  else
+  {
+    EVEL_DEBUG("Setting %s to %d", description, value);
+    option->value = value;
+    option->is_set = EVEL_TRUE;
+  }
+  EVEL_EXIT();
+}
diff --git a/vnfs/VES/code/evel_library/evel_other.c b/vnfs/VES/code/evel_library/evel_other.c
new file mode 100644 (file)
index 0000000..f63a091
--- /dev/null
@@ -0,0 +1,231 @@
+/**************************************************************************//**
+ * @file
+ * Implementation of EVEL functions relating to Other.
+ *
+ * License
+ * -------
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:  This product includes
+ *    software developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "evel.h"
+#include "evel_internal.h"
+
+/**************************************************************************//**
+ * Create a new Other event.
+ *
+ * @note    The mandatory fields on the Other must be supplied to this factory
+ *          function and are immutable once set.  Optional fields have explicit
+ *          setter functions, but again values may only be set once so that the
+ *          Other has immutable properties.
+ * @returns pointer to the newly manufactured ::EVENT_OTHER.  If the event is
+ *          not used (i.e. posted) it must be released using ::evel_free_other.
+ * @retval  NULL  Failed to create the event.
+ *****************************************************************************/
+EVENT_OTHER * evel_new_other()
+{
+  EVENT_OTHER * other = NULL;
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+
+  /***************************************************************************/
+  /* Allocate the Other.                                                     */
+  /***************************************************************************/
+  other = malloc(sizeof(EVENT_OTHER));
+  if (other == NULL)
+  {
+    log_error_state("Out of memory");
+    goto exit_label;
+  }
+  memset(other, 0, sizeof(EVENT_OTHER));
+  EVEL_DEBUG("New Other is at %lp", other);
+
+  /***************************************************************************/
+  /* Initialize the header & the Other fields.  Optional string values are   */
+  /* uninitialized (NULL).                                                   */
+  /***************************************************************************/
+  evel_init_header(&other->header);
+  other->header.event_domain = EVEL_DOMAIN_OTHER;
+  dlist_initialize(&other->other_fields);
+
+exit_label:
+  EVEL_EXIT();
+  return other;
+}
+
+/**************************************************************************//**
+ * Set the Event Type property of the Other.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param other       Pointer to the Other.
+ * @param type        The Event Type to be set. ASCIIZ string. The caller
+ *                    does not need to preserve the value once the function
+ *                    returns.
+ *****************************************************************************/
+void evel_other_type_set(EVENT_OTHER * other,
+                         const char * const type)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_header_type_set.                      */
+  /***************************************************************************/
+  assert(other != NULL);
+  assert(other->header.event_domain == EVEL_DOMAIN_OTHER);
+  evel_header_type_set(&other->header, type);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Add a field name/value pair to the Other.
+ *
+ * The name and value are null delimited ASCII strings.  The library takes
+ * a copy so the caller does not have to preserve values after the function
+ * returns.
+ *
+ * @param other     Pointer to the Other.
+ * @param name      ASCIIZ string with the field's name.  The caller does not
+ *                  need to preserve the value once the function returns.
+ * @param value     ASCIIZ string with the field's value.  The caller does not
+ *                  need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_other_field_add(EVENT_OTHER * other, char * name, char * value)
+{
+  OTHER_FIELD * other_field = NULL;
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(other != NULL);
+  assert(other->header.event_domain == EVEL_DOMAIN_OTHER);
+  assert(name != NULL);
+  assert(value != NULL);
+
+  EVEL_DEBUG("Adding name=%s value=%s", name, value);
+  other_field = malloc(sizeof(OTHER_FIELD));
+  assert(other_field != NULL);
+  memset(other_field, 0, sizeof(OTHER_FIELD));
+  other_field->name = strdup(name);
+  other_field->value = strdup(value);
+  assert(other_field->name != NULL);
+  assert(other_field->value != NULL);
+
+  dlist_push_last(&other->other_fields, other_field);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Encode the Other in JSON according to AT&T's schema for the event type.
+ *
+ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
+ * @param event         Pointer to the ::EVENT_HEADER to encode.
+ *****************************************************************************/
+void evel_json_encode_other(EVEL_JSON_BUFFER * jbuf,
+                            EVENT_OTHER * event)
+{
+  OTHER_FIELD * other_field = NULL;
+  DLIST_ITEM * other_field_item = NULL;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_OTHER);
+
+  evel_json_encode_header(jbuf, &event->header);
+  evel_json_open_named_list(jbuf, "otherFields");
+  other_field_item = dlist_get_first(&event->other_fields);
+  while (other_field_item != NULL)
+  {
+    other_field = (OTHER_FIELD *) other_field_item->item;
+    assert(other_field != NULL);
+
+    evel_json_open_object(jbuf);
+    evel_enc_kv_string(jbuf, "name", other_field->name);
+    evel_enc_kv_string(jbuf, "value", other_field->value);
+    evel_json_close_object(jbuf);
+    other_field_item = dlist_get_next(other_field_item);
+  }
+  evel_json_close_list(jbuf);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Free an Other.
+ *
+ * Free off the Other supplied.  Will free all the contained allocated memory.
+ *
+ * @note It does not free the Other itself, since that may be part of a
+ * larger structure.
+ *****************************************************************************/
+void evel_free_other(EVENT_OTHER * event)
+{
+  OTHER_FIELD * other_field = NULL;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.  As an internal API we don't allow freeing NULL    */
+  /* events as we do on the public API.                                      */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_OTHER);
+
+  /***************************************************************************/
+  /* Free all internal strings then the header itself.                       */
+  /***************************************************************************/
+  other_field = dlist_pop_last(&event->other_fields);
+  while (other_field != NULL)
+  {
+    EVEL_DEBUG("Freeing Other Field (%s, %s)",
+               other_field->name,
+               other_field->value);
+    free(other_field->name);
+    free(other_field->value);
+    free(other_field);
+    other_field = dlist_pop_last(&event->other_fields);
+  }
+  evel_free_header(&event->header);
+
+  EVEL_EXIT();
+}
\ No newline at end of file
diff --git a/vnfs/VES/code/evel_library/evel_reporting_measurement.c b/vnfs/VES/code/evel_library/evel_reporting_measurement.c
new file mode 100644 (file)
index 0000000..8455293
--- /dev/null
@@ -0,0 +1,450 @@
+/**************************************************************************//**
+ * @file
+ * Implementation of EVEL functions relating to the Measurement for VF
+ * Reporting event.
+ *
+ * @note  This is an experimental event tytpe and does not form part of the
+ *        currently approved AT&T event schema.  It is intended to allow a
+ *        less-onerous event reporting mechanism because it avoids having to
+ *        return all the platform statistics which are mandatory in the
+ *        **measurementsForVfScaling** event.
+ *
+ * License
+ * -------
+ *
+ * Copyright(c) <2016>, AT&T Intellectual Property.  All other rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:  This product includes
+ *    software developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "evel.h"
+#include "evel_internal.h"
+#include "evel_throttle.h"
+
+/**************************************************************************//**
+ * Create a new Report event.
+ *
+ * @note    The mandatory fields on the Report must be supplied to this
+ *          factory function and are immutable once set.  Optional fields have
+ *          explicit setter functions, but again values may only be set once so
+ *          that the Report has immutable properties.
+ *
+ * @param   measurement_interval
+
+ * @returns pointer to the newly manufactured ::EVENT_REPORT.  If the event is
+ *          not used (i.e. posted) it must be released using ::evel_free_event.
+ * @retval  NULL  Failed to create the event.
+ *****************************************************************************/
+EVENT_REPORT * evel_new_report(double measurement_interval)
+{
+  EVENT_REPORT * report = NULL;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(measurement_interval >= 0.0);
+
+  /***************************************************************************/
+  /* Allocate the report.                                                    */
+  /***************************************************************************/
+  report = malloc(sizeof(EVENT_REPORT));
+  if (report == NULL)
+  {
+    log_error_state("Out of memory for Report");
+    goto exit_label;
+  }
+  memset(report, 0, sizeof(EVENT_REPORT));
+  EVEL_DEBUG("New report is at %lp", report);
+
+  /***************************************************************************/
+  /* Initialize the header & the report fields.                              */
+  /***************************************************************************/
+  evel_init_header(&report->header);
+  report->header.event_domain = EVEL_DOMAIN_REPORT;
+  report->measurement_interval = measurement_interval;
+
+  dlist_initialize(&report->feature_usage);
+  dlist_initialize(&report->measurement_groups);
+  report->major_version = EVEL_REPORT_MAJOR_VERSION;
+  report->minor_version = EVEL_REPORT_MINOR_VERSION;
+
+exit_label:
+  EVEL_EXIT();
+  return report;
+}
+
+/**************************************************************************//**
+ * Set the Event Type property of the Report.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param report Pointer to the Report.
+ * @param type        The Event Type to be set. ASCIIZ string. The caller
+ *                    does not need to preserve the value once the function
+ *                    returns.
+ *****************************************************************************/
+void evel_report_type_set(EVENT_REPORT * report,
+                          const char * const type)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_header_type_set.                      */
+  /***************************************************************************/
+  assert(report != NULL);
+  assert(report->header.event_domain == EVEL_DOMAIN_REPORT);
+  evel_header_type_set(&report->header, type);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Add a Feature usage value name/value pair to the Report.
+ *
+ * The name is null delimited ASCII string.  The library takes
+ * a copy so the caller does not have to preserve values after the function
+ * returns.
+ *
+ * @param report          Pointer to the report.
+ * @param feature         ASCIIZ string with the feature's name.
+ * @param utilization     Utilization of the feature.
+ *****************************************************************************/
+void evel_report_feature_use_add(EVENT_REPORT * report,
+                                 char * feature,
+                                 int utilization)
+{
+  MEASUREMENT_FEATURE_USE * feature_use = NULL;
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check assumptions.                                                      */
+  /***************************************************************************/
+  assert(report != NULL);
+  assert(report->header.event_domain == EVEL_DOMAIN_REPORT);
+  assert(feature != NULL);
+  assert(utilization >= 0);
+
+  /***************************************************************************/
+  /* Allocate a container for the value and push onto the list.              */
+  /***************************************************************************/
+  EVEL_DEBUG("Adding Feature=%s Use=%d", feature, utilization);
+  feature_use = malloc(sizeof(MEASUREMENT_FEATURE_USE));
+  assert(feature_use != NULL);
+  memset(feature_use, 0, sizeof(MEASUREMENT_FEATURE_USE));
+  feature_use->feature_id = strdup(feature);
+  assert(feature_use->feature_id != NULL);
+  feature_use->feature_utilization = utilization;
+
+  dlist_push_last(&report->feature_usage, feature_use);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Add a Additional Measurement value name/value pair to the Report.
+ *
+ * The name is null delimited ASCII string.  The library takes
+ * a copy so the caller does not have to preserve values after the function
+ * returns.
+ *
+ * @param report   Pointer to the report.
+ * @param group    ASCIIZ string with the measurement group's name.
+ * @param name     ASCIIZ string containing the measurement's name.
+ * @param value    ASCIIZ string containing the measurement's value.
+ *****************************************************************************/
+void evel_report_custom_measurement_add(EVENT_REPORT * report,
+                                        const char * const group,
+                                        const char * const name,
+                                        const char * const value)
+{
+  MEASUREMENT_GROUP * measurement_group = NULL;
+  CUSTOM_MEASUREMENT * measurement = NULL;
+  DLIST_ITEM * item = NULL;
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check assumptions.                                                      */
+  /***************************************************************************/
+  assert(report != NULL);
+  assert(report->header.event_domain == EVEL_DOMAIN_REPORT);
+  assert(group != NULL);
+  assert(name != NULL);
+  assert(value != NULL);
+
+  /***************************************************************************/
+  /* Allocate a container for the name/value pair.                           */
+  /***************************************************************************/
+  EVEL_DEBUG("Adding Measurement Group=%s Name=%s Value=%s",
+              group, name, value);
+  measurement = malloc(sizeof(CUSTOM_MEASUREMENT));
+  assert(measurement != NULL);
+  memset(measurement, 0, sizeof(CUSTOM_MEASUREMENT));
+  measurement->name = strdup(name);
+  assert(measurement->name != NULL);
+  measurement->value = strdup(value);
+  assert(measurement->value != NULL);
+
+  /***************************************************************************/
+  /* See if we have that group already.                                      */
+  /***************************************************************************/
+  item = dlist_get_first(&report->measurement_groups);
+  while (item != NULL)
+  {
+    measurement_group = (MEASUREMENT_GROUP *) item->item;
+    assert(measurement_group != NULL);
+
+    EVEL_DEBUG("Got measurement group %s", measurement_group->name);
+    if (strcmp(group, measurement_group->name) == 0)
+    {
+      EVEL_DEBUG("Found existing Measurement Group");
+      break;
+    }
+    item = dlist_get_next(item);
+  }
+
+  /***************************************************************************/
+  /* If we didn't have the group already, create it.                         */
+  /***************************************************************************/
+  if (item == NULL)
+  {
+    EVEL_DEBUG("Creating new Measurement Group");
+    measurement_group = malloc(sizeof(MEASUREMENT_GROUP));
+    assert(measurement_group != NULL);
+    memset(measurement_group, 0, sizeof(MEASUREMENT_GROUP));
+    measurement_group->name = strdup(group);
+    assert(measurement_group->name != NULL);
+    dlist_initialize(&measurement_group->measurements);
+    dlist_push_last(&report->measurement_groups, measurement_group);
+  }
+
+  /***************************************************************************/
+  /* If we didn't have the group already, create it.                         */
+  /***************************************************************************/
+  dlist_push_last(&measurement_group->measurements, measurement);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Encode the report as a JSON report.
+ *
+ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
+ * @param event         Pointer to the ::EVENT_HEADER to encode.
+ *****************************************************************************/
+void evel_json_encode_report(EVEL_JSON_BUFFER * jbuf,
+                             EVENT_REPORT * event)
+{
+  MEASUREMENT_FEATURE_USE * feature_use = NULL;
+  MEASUREMENT_GROUP * measurement_group = NULL;
+  CUSTOM_MEASUREMENT * custom_measurement = NULL;
+  DLIST_ITEM * item = NULL;
+  DLIST_ITEM * nested_item = NULL;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_REPORT);
+
+  evel_json_encode_header(jbuf, &event->header);
+  evel_json_open_named_object(jbuf, "measurementsForVfReportingFields");
+  evel_enc_kv_double(jbuf, "measurementInterval", event->measurement_interval);
+
+  /***************************************************************************/
+  /* Feature Utilization list.                                               */
+  /***************************************************************************/
+  evel_json_checkpoint(jbuf);
+  if (evel_json_open_opt_named_list(jbuf, "featureUsageArray"))
+  {
+    bool item_added = false;
+
+    item = dlist_get_first(&event->feature_usage);
+    while (item != NULL)
+    {
+      feature_use = (MEASUREMENT_FEATURE_USE*) item->item;
+      assert(feature_use != NULL);
+
+      if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec,
+                                          "featureUsageArray",
+                                          feature_use->feature_id))
+      {
+        evel_json_open_object(jbuf);
+        evel_enc_kv_string(jbuf, "featureIdentifier", feature_use->feature_id);
+        evel_enc_kv_int(
+          jbuf, "featureUtilization", feature_use->feature_utilization);
+        evel_json_close_object(jbuf);
+        item_added = true;
+      }
+      item = dlist_get_next(item);
+    }
+    evel_json_close_list(jbuf);
+
+    /*************************************************************************/
+    /* If we've not written anything, rewind to before we opened the list.   */
+    /*************************************************************************/
+    if (!item_added)
+    {
+      evel_json_rewind(jbuf);
+    }
+  }
+
+  /***************************************************************************/
+  /* Additional Measurement Groups list.                                     */
+  /***************************************************************************/
+  evel_json_checkpoint(jbuf);
+  if (evel_json_open_opt_named_list(jbuf, "additionalMeasurements"))
+  {
+    bool item_added = false;
+
+    item = dlist_get_first(&event->measurement_groups);
+    while (item != NULL)
+    {
+      measurement_group = (MEASUREMENT_GROUP *) item->item;
+      assert(measurement_group != NULL);
+
+      if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec,
+                                          "additionalMeasurements",
+                                          measurement_group->name))
+      {
+        evel_json_open_object(jbuf);
+        evel_enc_kv_string(jbuf, "name", measurement_group->name);
+        evel_json_open_named_list(jbuf, "measurements");
+
+        /*********************************************************************/
+        /* Measurements list.                                                */
+        /*********************************************************************/
+        nested_item = dlist_get_first(&measurement_group->measurements);
+        while (nested_item != NULL)
+        {
+          custom_measurement = (CUSTOM_MEASUREMENT *) nested_item->item;
+          assert(custom_measurement != NULL);
+
+          evel_json_open_object(jbuf);
+          evel_enc_kv_string(jbuf, "name", custom_measurement->name);
+          evel_enc_kv_string(jbuf, "value", custom_measurement->value);
+          evel_json_close_object(jbuf);
+          nested_item = dlist_get_next(nested_item);
+        }
+        evel_json_close_list(jbuf);
+        evel_json_close_object(jbuf);
+        item_added = true;
+      }
+      item = dlist_get_next(item);
+    }
+    evel_json_close_list(jbuf);
+
+    /*************************************************************************/
+    /* If we've not written anything, rewind to before we opened the list.   */
+    /*************************************************************************/
+    if (!item_added)
+    {
+      evel_json_rewind(jbuf);
+    }
+  }
+
+  /***************************************************************************/
+  /* Although optional, we always generate the version.  Note that this      */
+  /* closes the object, too.                                                 */
+  /***************************************************************************/
+  evel_enc_version(jbuf,
+                   "measurementFieldsVersion",
+                   event->major_version,
+                   event->major_version);
+  evel_json_close_object(jbuf);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Free a Report.
+ *
+ * Free off the Report supplied.  Will free all the contained allocated memory.
+ *
+ * @note It does not free the Report itself, since that may be part of a
+ * larger structure.
+ *****************************************************************************/
+void evel_free_report(EVENT_REPORT * event)
+{
+  MEASUREMENT_FEATURE_USE * feature_use = NULL;
+  MEASUREMENT_GROUP * measurement_group = NULL;
+  CUSTOM_MEASUREMENT * custom_measurement = NULL;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.  As an internal API we don't allow freeing NULL    */
+  /* events as we do on the public API.                                      */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_REPORT);
+
+  /***************************************************************************/
+  /* Free all internal strings then the header itself.                       */
+  /***************************************************************************/
+  feature_use = dlist_pop_last(&event->feature_usage);
+  while (feature_use != NULL)
+  {
+    EVEL_DEBUG("Freeing Feature use Info (%s)", feature_use->feature_id);
+    free(feature_use->feature_id);
+    free(feature_use);
+    feature_use = dlist_pop_last(&event->feature_usage);
+  }
+  measurement_group = dlist_pop_last(&event->measurement_groups);
+  while (measurement_group != NULL)
+  {
+    EVEL_DEBUG("Freeing Measurement Group (%s)", measurement_group->name);
+
+    custom_measurement = dlist_pop_last(&measurement_group->measurements);
+    while (custom_measurement != NULL)
+    {
+      EVEL_DEBUG("Freeing mesaurement (%s)", custom_measurement->name);
+
+      free(custom_measurement->name);
+      free(custom_measurement->value);
+      free(custom_measurement);
+      custom_measurement = dlist_pop_last(&measurement_group->measurements);
+    }
+
+    free(measurement_group->name);
+    free(measurement_group);
+    measurement_group = dlist_pop_last(&event->measurement_groups);
+  }
+
+  evel_free_header(&event->header);
+
+  EVEL_EXIT();
+}
diff --git a/vnfs/VES/code/evel_library/evel_scaling_measurement.c b/vnfs/VES/code/evel_library/evel_scaling_measurement.c
new file mode 100644 (file)
index 0000000..ec8f32a
--- /dev/null
@@ -0,0 +1,1711 @@
+/**************************************************************************//**
+ * @file
+ * Implementation of EVEL functions relating to the Measurement.
+ *
+ * License
+ * -------
+ *
+ * Copyright(c) <2016>, AT&T Intellectual Property.  All other rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:  This product includes
+ *    software developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "evel.h"
+#include "evel_internal.h"
+#include "evel_throttle.h"
+
+/**************************************************************************//**
+ * Create a new Measurement event.
+ *
+ * @note    The mandatory fields on the Measurement must be supplied to this
+ *          factory function and are immutable once set.  Optional fields have
+ *          explicit setter functions, but again values may only be set once so
+ *          that the Measurement has immutable properties.
+ *
+ * @param   measurement_interval
+ *
+ * @returns pointer to the newly manufactured ::EVENT_MEASUREMENT.  If the
+ *          event is not used (i.e. posted) it must be released using
+ *          ::evel_free_event.
+ * @retval  NULL  Failed to create the event.
+ *****************************************************************************/
+EVENT_MEASUREMENT * evel_new_measurement(double measurement_interval)
+{
+  EVENT_MEASUREMENT * measurement = NULL;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(measurement_interval >= 0.0);
+
+  /***************************************************************************/
+  /* Allocate the measurement.                                               */
+  /***************************************************************************/
+  measurement = malloc(sizeof(EVENT_MEASUREMENT));
+  if (measurement == NULL)
+  {
+    log_error_state("Out of memory for Measurement");
+    goto exit_label;
+  }
+  memset(measurement, 0, sizeof(EVENT_MEASUREMENT));
+  EVEL_DEBUG("New measurement is at %lp", measurement);
+
+  /***************************************************************************/
+  /* Initialize the header & the measurement fields.                         */
+  /***************************************************************************/
+  evel_init_header(&measurement->header);
+  measurement->header.event_domain = EVEL_DOMAIN_MEASUREMENT;
+  measurement->measurement_interval = measurement_interval;
+  dlist_initialize(&measurement->cpu_usage);
+  dlist_initialize(&measurement->filesystem_usage);
+  dlist_initialize(&measurement->latency_distribution);
+  dlist_initialize(&measurement->vnic_usage);
+  dlist_initialize(&measurement->codec_usage);
+  dlist_initialize(&measurement->feature_usage);
+  dlist_initialize(&measurement->additional_measurements);
+  evel_init_option_double(&measurement->aggregate_cpu_usage);
+  evel_init_option_double(&measurement->mean_request_latency);
+  evel_init_option_double(&measurement->memory_configured);
+  evel_init_option_double(&measurement->memory_used);
+  evel_init_option_double(&measurement->vnfc_scaling_metric);
+  evel_init_option_int(&measurement->concurrent_sessions);
+  evel_init_option_int(&measurement->configured_entities);
+  evel_init_option_int(&measurement->media_ports_in_use);
+  evel_init_option_int(&measurement->request_rate);
+  measurement->major_version = EVEL_MEASUREMENT_MAJOR_VERSION;
+  measurement->minor_version = EVEL_MEASUREMENT_MINOR_VERSION;
+
+exit_label:
+  EVEL_EXIT();
+  return measurement;
+}
+
+/**************************************************************************//**
+ * Set the Event Type property of the Measurement.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param measurement Pointer to the Measurement.
+ * @param type        The Event Type to be set. ASCIIZ string. The caller
+ *                    does not need to preserve the value once the function
+ *                    returns.
+ *****************************************************************************/
+void evel_measurement_type_set(EVENT_MEASUREMENT * measurement,
+                               const char * const type)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_header_type_set.                      */
+  /***************************************************************************/
+  assert(measurement != NULL);
+  assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT);
+  evel_header_type_set(&measurement->header, type);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Concurrent Sessions property of the Measurement.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param measurement         Pointer to the Measurement.
+ * @param concurrent_sessions The Concurrent Sessions to be set.
+ *****************************************************************************/
+void evel_measurement_conc_sess_set(EVENT_MEASUREMENT * measurement,
+                                    int concurrent_sessions)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(measurement != NULL);
+  assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT);
+  assert(concurrent_sessions >= 0);
+
+  evel_set_option_int(&measurement->concurrent_sessions,
+                      concurrent_sessions,
+                      "Concurrent Sessions");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Configured Entities property of the Measurement.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param measurement         Pointer to the Measurement.
+ * @param configured_entities The Configured Entities to be set.
+ *****************************************************************************/
+void evel_measurement_cfg_ents_set(EVENT_MEASUREMENT * measurement,
+                                   int configured_entities)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(measurement != NULL);
+  assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT);
+  assert(configured_entities >= 0);
+
+  evel_set_option_int(&measurement->configured_entities,
+                      configured_entities,
+                      "Configured Entities");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Add an additional set of Errors to the Measurement.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param measurement       Pointer to the measurement.
+ * @param receive_discards  The number of receive discards.
+ * @param receive_errors    The number of receive errors.
+ * @param transmit_discards The number of transmit discards.
+ * @param transmit_errors   The number of transmit errors.
+ *****************************************************************************/
+void evel_measurement_errors_set(EVENT_MEASUREMENT * measurement,
+                                 int receive_discards,
+                                 int receive_errors,
+                                 int transmit_discards,
+                                 int transmit_errors)
+{
+  MEASUREMENT_ERRORS * errors = NULL;
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                      */
+  /***************************************************************************/
+  assert(measurement != NULL);
+  assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT);
+  assert(receive_discards >= 0);
+  assert(receive_errors >= 0);
+  assert(transmit_discards >= 0);
+  assert(transmit_errors >= 0);
+
+  if (measurement->errors == NULL)
+  {
+    EVEL_DEBUG("Adding Errors: %d, %d; %d, %d",
+               receive_discards,
+               receive_errors,
+               transmit_discards,
+               transmit_errors);
+    errors = malloc(sizeof(MEASUREMENT_ERRORS));
+    assert(errors != NULL);
+    memset(errors, 0, sizeof(MEASUREMENT_ERRORS));
+    errors->receive_discards = receive_discards;
+    errors->receive_errors = receive_errors;
+    errors->transmit_discards = transmit_discards;
+    errors->transmit_errors = transmit_errors;
+    measurement->errors = errors;
+  }
+  else
+  {
+    errors = measurement->errors;
+    EVEL_DEBUG("Ignoring attempt to add Errors: %d, %d; %d, %d\n"
+               "Errors already set: %d, %d; %d, %d",
+               receive_discards,
+               receive_errors,
+               transmit_discards,
+               transmit_errors,
+               errors->receive_discards,
+               errors->receive_errors,
+               errors->transmit_discards,
+               errors->transmit_errors);
+  }
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Mean Request Latency property of the Measurement.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param measurement          Pointer to the Measurement.
+ * @param mean_request_latency The Mean Request Latency to be set.
+ *****************************************************************************/
+void evel_measurement_mean_req_lat_set(EVENT_MEASUREMENT * measurement,
+                                       double mean_request_latency)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(measurement != NULL);
+  assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT);
+  assert(mean_request_latency >= 0.0);
+
+  evel_set_option_double(&measurement->mean_request_latency,
+                         mean_request_latency,
+                         "Mean Request Latency");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Memory Configured property of the Measurement.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param measurement       Pointer to the Measurement.
+ * @param memory_configured The Memory Configured to be set.
+ *****************************************************************************/
+void evel_measurement_mem_cfg_set(EVENT_MEASUREMENT * measurement,
+                                  double memory_configured)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(measurement != NULL);
+  assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT);
+  assert(memory_configured >= 0.0);
+
+  evel_set_option_double(&measurement->memory_configured,
+                         memory_configured,
+                         "Memory Configured");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Memory Used property of the Measurement.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param measurement Pointer to the Measurement.
+ * @param memory_used The Memory Used to be set.
+ *****************************************************************************/
+void evel_measurement_mem_used_set(EVENT_MEASUREMENT * measurement,
+                                   double memory_used)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(measurement != NULL);
+  assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT);
+  assert(memory_used >= 0.0);
+
+  evel_set_option_double(&measurement->memory_used,
+                         memory_used,
+                         "Memory Used");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Request Rate property of the Measurement.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param measurement  Pointer to the Measurement.
+ * @param request_rate The Request Rate to be set.
+ *****************************************************************************/
+void evel_measurement_request_rate_set(EVENT_MEASUREMENT * measurement,
+                                       int request_rate)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(measurement != NULL);
+  assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT);
+  assert(request_rate >= 0);
+
+  evel_set_option_int(&measurement->request_rate,
+                      request_rate,
+                      "Request Rate");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Add an additional CPU usage value name/value pair to the Measurement.
+ *
+ * The name and value are null delimited ASCII strings.  The library takes
+ * a copy so the caller does not have to preserve values after the function
+ * returns.
+ *
+ * @param measurement   Pointer to the measurement.
+ * @param id            ASCIIZ string with the CPU's identifier.
+ * @param usage         CPU utilization.
+ *****************************************************************************/
+void evel_measurement_cpu_use_add(EVENT_MEASUREMENT * measurement,
+                                 char * id, double usage)
+{
+  MEASUREMENT_CPU_USE * cpu_use = NULL;
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check assumptions.                                                      */
+  /***************************************************************************/
+  assert(measurement != NULL);
+  assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT);
+  assert(id != NULL);
+  assert(usage >= 0.0);
+
+  /***************************************************************************/
+  /* Allocate a container for the value and push onto the list.              */
+  /***************************************************************************/
+  EVEL_DEBUG("Adding id=%s usage=%lf", id, usage);
+  cpu_use = malloc(sizeof(MEASUREMENT_CPU_USE));
+  assert(cpu_use != NULL);
+  memset(cpu_use, 0, sizeof(MEASUREMENT_CPU_USE));
+  cpu_use->id = strdup(id);
+  cpu_use->usage = usage;
+  assert(cpu_use->id != NULL);
+
+  dlist_push_last(&measurement->cpu_usage, cpu_use);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Add an additional File System usage value name/value pair to the
+ * Measurement.
+ *
+ * The filesystem_name is null delimited ASCII string.  The library takes a
+ * copy so the caller does not have to preserve values after the function
+ * returns.
+ *
+ * @param measurement     Pointer to the measurement.
+ * @param filesystem_name   ASCIIZ string with the file-system's UUID.
+ * @param block_configured  Block storage configured.
+ * @param block_used        Block storage in use.
+ * @param block_iops        Block storage IOPS.
+ * @param ephemeral_configured  Ephemeral storage configured.
+ * @param ephemeral_used        Ephemeral storage in use.
+ * @param ephemeral_iops        Ephemeral storage IOPS.
+ *****************************************************************************/
+void evel_measurement_fsys_use_add(EVENT_MEASUREMENT * measurement,
+                                   char * filesystem_name,
+                                   double block_configured,
+                                   double block_used,
+                                   int block_iops,
+                                   double ephemeral_configured,
+                                   double ephemeral_used,
+                                   int ephemeral_iops)
+{
+  MEASUREMENT_FSYS_USE * fsys_use = NULL;
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check assumptions.                                                      */
+  /***************************************************************************/
+  assert(measurement != NULL);
+  assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT);
+  assert(filesystem_name != NULL);
+  assert(block_configured >= 0.0);
+  assert(block_used >= 0.0);
+  assert(block_iops >= 0);
+  assert(ephemeral_configured >= 0.0);
+  assert(ephemeral_used >= 0.0);
+  assert(ephemeral_iops >= 0);
+
+  /***************************************************************************/
+  /* Allocate a container for the value and push onto the list.              */
+  /***************************************************************************/
+  EVEL_DEBUG("Adding filesystem_name=%s", filesystem_name);
+  fsys_use = malloc(sizeof(MEASUREMENT_FSYS_USE));
+  assert(fsys_use != NULL);
+  memset(fsys_use, 0, sizeof(MEASUREMENT_FSYS_USE));
+  fsys_use->filesystem_name = strdup(filesystem_name);
+  fsys_use->block_configured = block_configured;
+  fsys_use->block_used = block_used;
+  fsys_use->block_iops = block_iops;
+  fsys_use->ephemeral_configured = block_configured;
+  fsys_use->ephemeral_used = ephemeral_used;
+  fsys_use->ephemeral_iops = ephemeral_iops;
+
+  dlist_push_last(&measurement->filesystem_usage, fsys_use);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Add a Feature usage value name/value pair to the Measurement.
+ *
+ * The name is null delimited ASCII string.  The library takes
+ * a copy so the caller does not have to preserve values after the function
+ * returns.
+ *
+ * @param measurement     Pointer to the measurement.
+ * @param feature         ASCIIZ string with the feature's name.
+ * @param utilization     Utilization of the feature.
+ *****************************************************************************/
+void evel_measurement_feature_use_add(EVENT_MEASUREMENT * measurement,
+                                      char * feature,
+                                      int utilization)
+{
+  MEASUREMENT_FEATURE_USE * feature_use = NULL;
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check assumptions.                                                      */
+  /***************************************************************************/
+  assert(measurement != NULL);
+  assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT);
+  assert(feature != NULL);
+  assert(utilization >= 0);
+
+  /***************************************************************************/
+  /* Allocate a container for the value and push onto the list.              */
+  /***************************************************************************/
+  EVEL_DEBUG("Adding Feature=%s Use=%d", feature, utilization);
+  feature_use = malloc(sizeof(MEASUREMENT_FEATURE_USE));
+  assert(feature_use != NULL);
+  memset(feature_use, 0, sizeof(MEASUREMENT_FEATURE_USE));
+  feature_use->feature_id = strdup(feature);
+  assert(feature_use->feature_id != NULL);
+  feature_use->feature_utilization = utilization;
+
+  dlist_push_last(&measurement->feature_usage, feature_use);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Add a Additional Measurement value name/value pair to the Report.
+ *
+ * The name is null delimited ASCII string.  The library takes
+ * a copy so the caller does not have to preserve values after the function
+ * returns.
+ *
+ * @param measurement   Pointer to the Measaurement.
+ * @param group    ASCIIZ string with the measurement group's name.
+ * @param name     ASCIIZ string containing the measurement's name.
+ * @param value    ASCIIZ string containing the measurement's value.
+ *****************************************************************************/
+void evel_measurement_custom_measurement_add(EVENT_MEASUREMENT * measurement,
+                                             const char * const group,
+                                             const char * const name,
+                                             const char * const value)
+{
+  MEASUREMENT_GROUP * measurement_group = NULL;
+  CUSTOM_MEASUREMENT * custom_measurement = NULL;
+  DLIST_ITEM * item = NULL;
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check assumptions.                                                      */
+  /***************************************************************************/
+  assert(measurement != NULL);
+  assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT);
+  assert(group != NULL);
+  assert(name != NULL);
+  assert(value != NULL);
+
+  /***************************************************************************/
+  /* Allocate a container for the name/value pair.                           */
+  /***************************************************************************/
+  EVEL_DEBUG("Adding Measurement Group=%s Name=%s Value=%s",
+              group, name, value);
+  custom_measurement = malloc(sizeof(CUSTOM_MEASUREMENT));
+  assert(custom_measurement != NULL);
+  memset(custom_measurement, 0, sizeof(CUSTOM_MEASUREMENT));
+  custom_measurement->name = strdup(name);
+  assert(custom_measurement->name != NULL);
+  custom_measurement->value = strdup(value);
+  assert(custom_measurement->value != NULL);
+
+  /***************************************************************************/
+  /* See if we have that group already.                                      */
+  /***************************************************************************/
+  item = dlist_get_first(&measurement->additional_measurements);
+  while (item != NULL)
+  {
+    measurement_group = (MEASUREMENT_GROUP *) item->item;
+    assert(measurement_group != NULL);
+
+    EVEL_DEBUG("Got measurement group %s", measurement_group->name);
+    if (strcmp(group, measurement_group->name) == 0)
+    {
+      EVEL_DEBUG("Found existing Measurement Group");
+      break;
+    }
+    item = dlist_get_next(item);
+  }
+
+  /***************************************************************************/
+  /* If we didn't have the group already, create it.                         */
+  /***************************************************************************/
+  if (item == NULL)
+  {
+    EVEL_DEBUG("Creating new Measurement Group");
+    measurement_group = malloc(sizeof(MEASUREMENT_GROUP));
+    assert(measurement_group != NULL);
+    memset(measurement_group, 0, sizeof(MEASUREMENT_GROUP));
+    measurement_group->name = strdup(group);
+    assert(measurement_group->name != NULL);
+    dlist_initialize(&measurement_group->measurements);
+    dlist_push_last(&measurement->additional_measurements, measurement_group);
+  }
+
+  /***************************************************************************/
+  /* If we didn't have the group already, create it.                         */
+  /***************************************************************************/
+  dlist_push_last(&measurement_group->measurements, custom_measurement);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Add a Codec usage value name/value pair to the Measurement.
+ *
+ * The name is null delimited ASCII string.  The library takes
+ * a copy so the caller does not have to preserve values after the function
+ * returns.
+ *
+ * @param measurement     Pointer to the measurement.
+ * @param codec           ASCIIZ string with the codec's name.
+ * @param utilization     Number of codecs in use.
+ *****************************************************************************/
+void evel_measurement_codec_use_add(EVENT_MEASUREMENT * measurement,
+                                    char * codec,
+                                    int utilization)
+{
+  MEASUREMENT_CODEC_USE * codec_use = NULL;
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check assumptions.                                                      */
+  /***************************************************************************/
+  assert(measurement != NULL);
+  assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT);
+  assert(codec != NULL);
+  assert(utilization >= 0.0);
+
+  /***************************************************************************/
+  /* Allocate a container for the value and push onto the list.              */
+  /***************************************************************************/
+  EVEL_DEBUG("Adding Codec=%s Use=%d", codec, utilization);
+  codec_use = malloc(sizeof(MEASUREMENT_CODEC_USE));
+  assert(codec_use != NULL);
+  memset(codec_use, 0, sizeof(MEASUREMENT_CODEC_USE));
+  codec_use->codec_id = strdup(codec);
+  assert(codec_use->codec_id != NULL);
+  codec_use->number_in_use = utilization;
+
+  dlist_push_last(&measurement->codec_usage, codec_use);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Aggregate CPU Use property of the Measurement.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param measurement   Pointer to the measurement.
+ * @param cpu_use       The CPU use to set.
+ *****************************************************************************/
+void evel_measurement_agg_cpu_use_set(EVENT_MEASUREMENT * measurement,
+                                      double cpu_use)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(measurement != NULL);
+  assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT);
+  assert(cpu_use >= 0.0);
+
+  evel_set_option_double(&measurement->aggregate_cpu_usage,
+                         cpu_use,
+                         "CPU Use");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Media Ports in Use property of the Measurement.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param measurement         Pointer to the measurement.
+ * @param media_ports_in_use  The media port usage to set.
+ *****************************************************************************/
+void evel_measurement_media_port_use_set(EVENT_MEASUREMENT * measurement,
+                                         int media_ports_in_use)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(measurement != NULL);
+  assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT);
+  assert(media_ports_in_use >= 0);
+
+  evel_set_option_int(&measurement->media_ports_in_use,
+                      media_ports_in_use,
+                      "Media Ports In Use");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the VNFC Scaling Metric property of the Measurement.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param measurement     Pointer to the measurement.
+ * @param scaling_metric  The scaling metric to set.
+ *****************************************************************************/
+void evel_measurement_vnfc_scaling_metric_set(EVENT_MEASUREMENT * measurement,
+                                              double scaling_metric)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(measurement != NULL);
+  assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT);
+  assert(scaling_metric >= 0.0);
+
+  evel_set_option_double(&measurement->vnfc_scaling_metric,
+                         scaling_metric,
+                         "VNFC Scaling Metric");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Create a new Latency Bucket to be added to a Measurement event.
+ *
+ * @note    The mandatory fields on the ::MEASUREMENT_LATENCY_BUCKET must be
+ *          supplied to this factory function and are immutable once set.
+ *          Optional fields have explicit setter functions, but again values
+ *          may only be set once so that the ::MEASUREMENT_LATENCY_BUCKET has
+ *          immutable properties.
+ *
+ * @param count         Count of events in this bucket.
+ *
+ * @returns pointer to the newly manufactured ::MEASUREMENT_LATENCY_BUCKET.
+ *          If the structure is not used it must be released using free.
+ * @retval  NULL  Failed to create the Latency Bucket.
+ *****************************************************************************/
+MEASUREMENT_LATENCY_BUCKET * evel_new_meas_latency_bucket(const int count)
+{
+  MEASUREMENT_LATENCY_BUCKET * bucket;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(count >= 0);
+
+  /***************************************************************************/
+  /* Allocate, then set Mandatory Parameters.                                */
+  /***************************************************************************/
+  EVEL_DEBUG("Creating bucket, count = %d", count);
+  bucket = malloc(sizeof(MEASUREMENT_LATENCY_BUCKET));
+  assert(bucket != NULL);
+
+  /***************************************************************************/
+  /* Set Mandatory Parameters.                                               */
+  /***************************************************************************/
+  bucket->count = count;
+
+  /***************************************************************************/
+  /* Initialize Optional Parameters.                                         */
+  /***************************************************************************/
+  evel_init_option_double(&bucket->high_end);
+  evel_init_option_double(&bucket->low_end);
+
+  EVEL_EXIT();
+
+  return bucket;
+}
+
+/**************************************************************************//**
+ * Set the High End property of the Measurement Latency Bucket.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param bucket        Pointer to the Measurement Latency Bucket.
+ * @param high_end      High end of the bucket's range.
+ *****************************************************************************/
+void evel_meas_latency_bucket_high_end_set(
+                                     MEASUREMENT_LATENCY_BUCKET * const bucket,
+                                     const double high_end)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(high_end >= 0.0);
+  evel_set_option_double(&bucket->high_end, high_end, "High End");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Low End property of the Measurement Latency Bucket.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param bucket        Pointer to the Measurement Latency Bucket.
+ * @param low_end       Low end of the bucket's range.
+ *****************************************************************************/
+void evel_meas_latency_bucket_low_end_set(
+                                     MEASUREMENT_LATENCY_BUCKET * const bucket,
+                                     const double low_end)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(low_end >= 0.0);
+  evel_set_option_double(&bucket->low_end, low_end, "Low End");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Add an additional Measurement Latency Bucket to the specified event.
+ *
+ * @param measurement   Pointer to the Measurement event.
+ * @param bucket        Pointer to the Measurement Latency Bucket to add.
+ *****************************************************************************/
+void evel_meas_latency_bucket_add(EVENT_MEASUREMENT * const measurement,
+                                  MEASUREMENT_LATENCY_BUCKET * const bucket)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(measurement != NULL);
+  assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT);
+  assert(bucket != NULL);
+  dlist_push_last(&measurement->latency_distribution, bucket);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Add an additional Latency Distribution bucket to the Measurement.
+ *
+ * This function implements the previous API, purely for convenience.
+ *
+ * @param measurement   Pointer to the measurement.
+ * @param low_end       Low end of the bucket's range.
+ * @param high_end      High end of the bucket's range.
+ * @param count         Count of events in this bucket.
+ *****************************************************************************/
+void evel_measurement_latency_add(EVENT_MEASUREMENT * const measurement,
+                                  const double low_end,
+                                  const double high_end,
+                                  const int count)
+{
+  MEASUREMENT_LATENCY_BUCKET * bucket = NULL;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Trust the assertions in the underlying methods.                         */
+  /***************************************************************************/
+  bucket = evel_new_meas_latency_bucket(count);
+  evel_meas_latency_bucket_low_end_set(bucket, low_end);
+  evel_meas_latency_bucket_high_end_set(bucket, high_end);
+  evel_meas_latency_bucket_add(measurement, bucket);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Create a new vNIC Use to be added to a Measurement event.
+ *
+ * @note    The mandatory fields on the ::MEASUREMENT_VNIC_USE must be supplied
+ *          to this factory function and are immutable once set. Optional
+ *          fields have explicit setter functions, but again values may only be
+ *          set once so that the ::MEASUREMENT_VNIC_USE has immutable
+ *          properties.
+ *
+ * @param vnic_id               ASCIIZ string with the vNIC's ID.
+ * @param packets_in            Total packets received.
+ * @param packets_out           Total packets transmitted.
+ * @param bytes_in              Total bytes received.
+ * @param bytes_out             Total bytes transmitted.
+ *
+ * @returns pointer to the newly manufactured ::MEASUREMENT_VNIC_USE.
+ *          If the structure is not used it must be released using
+ *          ::evel_free_measurement_vnic_use.
+ * @retval  NULL  Failed to create the vNIC Use.
+ *****************************************************************************/
+MEASUREMENT_VNIC_USE * evel_new_measurement_vnic_use(char * const vnic_id,
+                                                     const int packets_in,
+                                                     const int packets_out,
+                                                     const int bytes_in,
+                                                     const int bytes_out)
+{
+  MEASUREMENT_VNIC_USE * vnic_use;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(vnic_id != NULL);
+  assert(packets_in >= 0);
+  assert(packets_out >= 0);
+  assert(bytes_in >= 0);
+  assert(bytes_out >= 0);
+
+  /***************************************************************************/
+  /* Allocate, then set Mandatory Parameters.                                */
+  /***************************************************************************/
+  EVEL_DEBUG("Adding VNIC ID=%s", vnic_id);
+  vnic_use = malloc(sizeof(MEASUREMENT_VNIC_USE));
+  assert(vnic_use != NULL);
+  vnic_use->vnic_id = strdup(vnic_id);
+  vnic_use->packets_in = packets_in;
+  vnic_use->packets_out = packets_out;
+  vnic_use->bytes_in = bytes_in;
+  vnic_use->bytes_out = bytes_out;
+
+  /***************************************************************************/
+  /* Initialize Optional Parameters.                                         */
+  /***************************************************************************/
+  evel_init_option_int(&vnic_use->broadcast_packets_in);
+  evel_init_option_int(&vnic_use->broadcast_packets_out);
+  evel_init_option_int(&vnic_use->multicast_packets_in);
+  evel_init_option_int(&vnic_use->multicast_packets_out);
+  evel_init_option_int(&vnic_use->unicast_packets_in);
+  evel_init_option_int(&vnic_use->unicast_packets_out);
+
+  EVEL_EXIT();
+
+  return vnic_use;
+}
+
+/**************************************************************************//**
+ * Free a vNIC Use.
+ *
+ * Free off the ::MEASUREMENT_VNIC_USE supplied.  Will free all the contained
+ * allocated memory.
+ *
+ * @note It does not free the vNIC Use itself, since that may be part of a
+ * larger structure.
+ *****************************************************************************/
+void evel_free_measurement_vnic_use(MEASUREMENT_VNIC_USE * const vnic_use)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(vnic_use != NULL);
+  assert(vnic_use->vnic_id != NULL);
+
+  /***************************************************************************/
+  /* Free the duplicated string.                                             */
+  /***************************************************************************/
+  free(vnic_use->vnic_id);
+  vnic_use->vnic_id = NULL;
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Broadcast Packets Received property of the vNIC Use.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param vnic_use      Pointer to the vNIC Use.
+ * @param broadcast_packets_in
+ *                      Broadcast packets received.
+ *****************************************************************************/
+void evel_vnic_use_bcast_pkt_in_set(MEASUREMENT_VNIC_USE * const vnic_use,
+                                    const int broadcast_packets_in)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(broadcast_packets_in >= 0);
+
+  evel_set_option_int(&vnic_use->broadcast_packets_in,
+                      broadcast_packets_in,
+                      "Broadcast Packets Received");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Broadcast Packets Transmitted property of the vNIC Use.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param vnic_use      Pointer to the vNIC Use.
+ * @param broadcast_packets_out
+ *                      Broadcast packets transmitted.
+ *****************************************************************************/
+void evel_vnic_use_bcast_pkt_out_set(MEASUREMENT_VNIC_USE * const vnic_use,
+                                     const int broadcast_packets_out)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(broadcast_packets_out >= 0);
+
+  evel_set_option_int(&vnic_use->broadcast_packets_out,
+                      broadcast_packets_out,
+                      "Broadcast Packets Transmitted");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Multicast Packets Received property of the vNIC Use.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param vnic_use      Pointer to the vNIC Use.
+ * @param multicast_packets_in
+ *                      Multicast packets received.
+ *****************************************************************************/
+void evel_vnic_use_mcast_pkt_in_set(MEASUREMENT_VNIC_USE * const vnic_use,
+                                    const int multicast_packets_in)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(multicast_packets_in >= 0);
+
+  evel_set_option_int(&vnic_use->multicast_packets_in,
+                      multicast_packets_in,
+                      "Multicast Packets Received");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Multicast Packets Transmitted property of the vNIC Use.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param vnic_use      Pointer to the vNIC Use.
+ * @param multicast_packets_out
+ *                      Multicast packets transmitted.
+ *****************************************************************************/
+void evel_vnic_use_mcast_pkt_out_set(MEASUREMENT_VNIC_USE * const vnic_use,
+                                     const int multicast_packets_out)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(multicast_packets_out >= 0);
+
+  evel_set_option_int(&vnic_use->multicast_packets_out,
+                      multicast_packets_out,
+                      "Multicast Packets Transmitted");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Unicast Packets Received property of the vNIC Use.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param vnic_use      Pointer to the vNIC Use.
+ * @param unicast_packets_in
+ *                      Unicast packets received.
+ *****************************************************************************/
+void evel_vnic_use_ucast_pkt_in_set(MEASUREMENT_VNIC_USE * const vnic_use,
+                                    const int unicast_packets_in)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(unicast_packets_in >= 0);
+
+  evel_set_option_int(&vnic_use->unicast_packets_in,
+                      unicast_packets_in,
+                      "Unicast Packets Received");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Unicast Packets Transmitted property of the vNIC Use.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param vnic_use      Pointer to the vNIC Use.
+ * @param unicast_packets_out
+ *                      Unicast packets transmitted.
+ *****************************************************************************/
+void evel_vnic_use_ucast_pkt_out_set(MEASUREMENT_VNIC_USE * const vnic_use,
+                                     const int unicast_packets_out)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(unicast_packets_out >= 0);
+
+  evel_set_option_int(&vnic_use->unicast_packets_out,
+                      unicast_packets_out,
+                      "Unicast Packets Transmitted");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Add an additional vNIC Use to the specified Measurement event.
+ *
+ * @param measurement   Pointer to the measurement.
+ * @param vnic_use      Pointer to the vNIC Use to add.
+ *****************************************************************************/
+void evel_meas_vnic_use_add(EVENT_MEASUREMENT * const measurement,
+                            MEASUREMENT_VNIC_USE * const vnic_use)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(measurement != NULL);
+  assert(measurement->header.event_domain == EVEL_DOMAIN_MEASUREMENT);
+  assert(vnic_use != NULL);
+
+  dlist_push_last(&measurement->vnic_usage, vnic_use);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Add an additional vNIC usage record Measurement.
+ *
+ * This function implements the previous API, purely for convenience.
+ *
+ * The ID is null delimited ASCII string.  The library takes a copy so the
+ * caller does not have to preserve values after the function returns.
+ *
+ * @param measurement           Pointer to the measurement.
+ * @param vnic_id               ASCIIZ string with the vNIC's ID.
+ * @param packets_in            Total packets received.
+ * @param packets_out           Total packets transmitted.
+ * @param broadcast_packets_in  Broadcast packets received.
+ * @param broadcast_packets_out Broadcast packets transmitted.
+ * @param bytes_in              Total bytes received.
+ * @param bytes_out             Total bytes transmitted.
+ * @param multicast_packets_in  Multicast packets received.
+ * @param multicast_packets_out Multicast packets transmitted.
+ * @param unicast_packets_in    Unicast packets received.
+ * @param unicast_packets_out   Unicast packets transmitted.
+ *****************************************************************************/
+void evel_measurement_vnic_use_add(EVENT_MEASUREMENT * const measurement,
+                                   char * const vnic_id,
+                                   const int packets_in,
+                                   const int packets_out,
+                                   const int broadcast_packets_in,
+                                   const int broadcast_packets_out,
+                                   const int bytes_in,
+                                   const int bytes_out,
+                                   const int multicast_packets_in,
+                                   const int multicast_packets_out,
+                                   const int unicast_packets_in,
+                                   const int unicast_packets_out)
+{
+  MEASUREMENT_VNIC_USE * vnic_use = NULL;
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Trust the assertions in the underlying methods.                         */
+  /***************************************************************************/
+  vnic_use = evel_new_measurement_vnic_use(vnic_id,
+                                           packets_in,
+                                           packets_out,
+                                           bytes_in,
+                                           bytes_out);
+  evel_vnic_use_bcast_pkt_in_set(vnic_use, broadcast_packets_in);
+  evel_vnic_use_bcast_pkt_out_set(vnic_use, broadcast_packets_out);
+  evel_vnic_use_mcast_pkt_in_set(vnic_use, multicast_packets_in);
+  evel_vnic_use_mcast_pkt_out_set(vnic_use, multicast_packets_out);
+  evel_vnic_use_ucast_pkt_in_set(vnic_use, unicast_packets_in);
+  evel_vnic_use_ucast_pkt_out_set(vnic_use, unicast_packets_out);
+  evel_meas_vnic_use_add(measurement, vnic_use);
+}
+
+/**************************************************************************//**
+ * Encode the measurement as a JSON measurement.
+ *
+ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
+ * @param event         Pointer to the ::EVENT_HEADER to encode.
+ *****************************************************************************/
+void evel_json_encode_measurement(EVEL_JSON_BUFFER * jbuf,
+                                  EVENT_MEASUREMENT * event)
+{
+  MEASUREMENT_CPU_USE * cpu_use = NULL;
+  MEASUREMENT_FSYS_USE * fsys_use = NULL;
+  MEASUREMENT_LATENCY_BUCKET * bucket = NULL;
+  MEASUREMENT_VNIC_USE * vnic_use = NULL;
+  MEASUREMENT_ERRORS * errors = NULL;
+  MEASUREMENT_FEATURE_USE * feature_use = NULL;
+  MEASUREMENT_CODEC_USE * codec_use = NULL;
+  MEASUREMENT_GROUP * measurement_group = NULL;
+  CUSTOM_MEASUREMENT * custom_measurement = NULL;
+  DLIST_ITEM * item = NULL;
+  DLIST_ITEM * nested_item = NULL;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_MEASUREMENT);
+
+  evel_json_encode_header(jbuf, &event->header);
+  evel_json_open_named_object(jbuf, "measurementsForVfScalingFields");
+
+  /***************************************************************************/
+  /* Mandatory fields.                                                       */
+  /***************************************************************************/
+  evel_enc_kv_double(jbuf, "measurementInterval", event->measurement_interval);
+
+  /***************************************************************************/
+  /* Optional fields.                                                        */
+  /***************************************************************************/
+  evel_enc_kv_opt_int(jbuf, "concurrentSessions", &event->concurrent_sessions);
+  evel_enc_kv_opt_int(jbuf, "configuredEntities", &event->configured_entities);
+
+  /***************************************************************************/
+  /* CPU Use list.                                                           */
+  /***************************************************************************/
+  evel_json_checkpoint(jbuf);
+  if (evel_json_open_opt_named_list(jbuf, "cpuUsageArray"))
+  {
+    bool item_added = false;
+
+    item = dlist_get_first(&event->cpu_usage);
+    while (item != NULL)
+    {
+      cpu_use = (MEASUREMENT_CPU_USE*) item->item;
+      assert(cpu_use != NULL);
+
+      if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec,
+                                          "cpuUsageArray",
+                                          cpu_use->id))
+      {
+        evel_json_open_object(jbuf);
+        evel_enc_kv_string(jbuf, "cpuIdentifier", cpu_use->id);
+        evel_enc_kv_double(jbuf, "percentUsage", cpu_use->usage);
+        evel_json_close_object(jbuf);
+        item_added = true;
+      }
+      item = dlist_get_next(item);
+    }
+    evel_json_close_list(jbuf);
+
+    /*************************************************************************/
+    /* If we've not written anything, rewind to before we opened the list.   */
+    /*************************************************************************/
+    if (!item_added)
+    {
+      evel_json_rewind(jbuf);
+    }
+  }
+
+  /***************************************************************************/
+  /* Filesystem Usage list.                                                  */
+  /***************************************************************************/
+  evel_json_checkpoint(jbuf);
+  if (evel_json_open_opt_named_list(jbuf, "filesystemUsageArray"))
+  {
+    bool item_added = false;
+
+    item = dlist_get_first(&event->filesystem_usage);
+    while (item != NULL)
+    {
+      fsys_use = (MEASUREMENT_FSYS_USE *) item->item;
+      assert(fsys_use != NULL);
+
+      if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec,
+                                          "filesystemUsageArray",
+                                          fsys_use->filesystem_name))
+      {
+        evel_json_open_object(jbuf);
+        evel_enc_kv_double(
+          jbuf, "blockConfigured", fsys_use->block_configured);
+        evel_enc_kv_int(jbuf, "blockIops", fsys_use->block_iops);
+        evel_enc_kv_double(jbuf, "blockUsed", fsys_use->block_used);
+        evel_enc_kv_double(
+          jbuf, "ephemeralConfigured", fsys_use->ephemeral_configured);
+        evel_enc_kv_int(jbuf, "ephemeralIops", fsys_use->ephemeral_iops);
+        evel_enc_kv_double(jbuf, "ephemeralUsed", fsys_use->ephemeral_used);
+        evel_enc_kv_string(jbuf, "filesystemName", fsys_use->filesystem_name);
+        evel_json_close_object(jbuf);
+        item_added = true;
+      }
+      item = dlist_get_next(item);
+    }
+    evel_json_close_list(jbuf);
+
+    /*************************************************************************/
+    /* If we've not written anything, rewind to before we opened the list.   */
+    /*************************************************************************/
+    if (!item_added)
+    {
+      evel_json_rewind(jbuf);
+    }
+  }
+
+  /***************************************************************************/
+  /* Latency distribution.                                                   */
+  /***************************************************************************/
+  item = dlist_get_first(&event->latency_distribution);
+  if ((item != NULL) &&
+      evel_json_open_opt_named_list(jbuf, "latencyDistribution"))
+  {
+    while (item != NULL)
+    {
+      bucket = (MEASUREMENT_LATENCY_BUCKET*) item->item;
+      assert(bucket != NULL);
+
+      evel_json_open_object(jbuf);
+      evel_enc_kv_opt_double(
+        jbuf, "lowEndOfLatencyBucket", &bucket->low_end);
+      evel_enc_kv_opt_double(
+        jbuf, "highEndOfLatencyBucket", &bucket->high_end);
+      evel_enc_kv_int(jbuf, "countsInTheBucket", bucket->count);
+      evel_json_close_object(jbuf);
+      item = dlist_get_next(item);
+    }
+    evel_json_close_list(jbuf);
+  }
+
+  evel_enc_kv_opt_double(
+    jbuf, "meanRequestLatency", &event->mean_request_latency);
+  evel_enc_kv_opt_double(jbuf, "memoryConfigured", &event->memory_configured);
+  evel_enc_kv_opt_double(jbuf, "memoryUsed", &event->memory_used);
+  evel_enc_kv_opt_int(jbuf, "requestRate", &event->request_rate);
+
+  /***************************************************************************/
+  /* vNIC Usage                                                              */
+  /***************************************************************************/
+  evel_json_checkpoint(jbuf);
+  if (evel_json_open_opt_named_list(jbuf, "vNicUsageArray"))
+  {
+    bool item_added = false;
+
+    item = dlist_get_first(&event->vnic_usage);
+    while (item != NULL)
+    {
+      vnic_use = (MEASUREMENT_VNIC_USE *) item->item;
+      assert(vnic_use != NULL);
+
+      if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec,
+                                          "vNicUsageArray",
+                                          vnic_use->vnic_id))
+      {
+        evel_json_open_object(jbuf);
+
+        /*********************************************************************/
+        /* Mandatory fields.                                                 */
+        /*********************************************************************/
+        evel_enc_kv_int(jbuf, "bytesIn", vnic_use->bytes_in);
+        evel_enc_kv_int(jbuf, "bytesOut", vnic_use->bytes_out);
+        evel_enc_kv_int(jbuf, "packetsIn", vnic_use->packets_in);
+        evel_enc_kv_int(jbuf, "packetsOut", vnic_use->packets_out);
+        evel_enc_kv_string(jbuf, "vNicIdentifier", vnic_use->vnic_id);
+
+        /*********************************************************************/
+        /* Optional fields.                                                  */
+        /*********************************************************************/
+        evel_enc_kv_opt_int(
+          jbuf, "broadcastPacketsIn", &vnic_use->broadcast_packets_in);
+        evel_enc_kv_opt_int(
+          jbuf, "broadcastPacketsOut", &vnic_use->broadcast_packets_out);
+        evel_enc_kv_opt_int(
+          jbuf, "multicastPacketsIn", &vnic_use->multicast_packets_in);
+        evel_enc_kv_opt_int(
+          jbuf, "multicastPacketsOut", &vnic_use->multicast_packets_out);
+        evel_enc_kv_opt_int(
+          jbuf, "unicastPacketsIn", &vnic_use->unicast_packets_in);
+        evel_enc_kv_opt_int(
+          jbuf, "unicastPacketsOut", &vnic_use->unicast_packets_out);
+
+        evel_json_close_object(jbuf);
+        item_added = true;
+      }
+      item = dlist_get_next(item);
+    }
+
+    evel_json_close_list(jbuf);
+
+    /*************************************************************************/
+    /* If we've not written anything, rewind to before we opened the list.   */
+    /*************************************************************************/
+    if (!item_added)
+    {
+      evel_json_rewind(jbuf);
+    }
+  }
+
+  evel_enc_kv_opt_double(
+    jbuf, "aggregateCpuUsage", &event->aggregate_cpu_usage);
+  evel_enc_kv_opt_int(
+    jbuf, "numberOfMediaPortsInUse", &event->media_ports_in_use);
+  evel_enc_kv_opt_double(
+    jbuf, "vnfcScalingMetric", &event->vnfc_scaling_metric);
+
+  /***************************************************************************/
+  /* Errors list.                                                            */
+  /***************************************************************************/
+  if ((event->errors != NULL) &&
+      evel_json_open_opt_named_object(jbuf, "errors"))
+  {
+    errors = event->errors;
+    evel_enc_kv_int(jbuf, "receiveDiscards", errors->receive_discards);
+    evel_enc_kv_int(jbuf, "receiveErrors", errors->receive_errors);
+    evel_enc_kv_int(jbuf, "transmitDiscards", errors->transmit_discards);
+    evel_enc_kv_int(jbuf, "transmitErrors", errors->transmit_errors);
+    evel_json_close_object(jbuf);
+  }
+
+  /***************************************************************************/
+  /* Feature Utilization list.                                               */
+  /***************************************************************************/
+  evel_json_checkpoint(jbuf);
+  if (evel_json_open_opt_named_list(jbuf, "featureUsageArray"))
+  {
+    bool item_added = false;
+
+    item = dlist_get_first(&event->feature_usage);
+    while (item != NULL)
+    {
+      feature_use = (MEASUREMENT_FEATURE_USE*) item->item;
+      assert(feature_use != NULL);
+
+      if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec,
+                                          "featureUsageArray",
+                                          feature_use->feature_id))
+      {
+        evel_json_open_object(jbuf);
+        evel_enc_kv_string(jbuf, "featureIdentifier", feature_use->feature_id);
+        evel_enc_kv_int(
+          jbuf, "featureUtilization", feature_use->feature_utilization);
+        evel_json_close_object(jbuf);
+        item_added = true;
+      }
+      item = dlist_get_next(item);
+    }
+    evel_json_close_list(jbuf);
+
+    /*************************************************************************/
+    /* If we've not written anything, rewind to before we opened the list.   */
+    /*************************************************************************/
+    if (!item_added)
+    {
+      evel_json_rewind(jbuf);
+    }
+  }
+
+  /***************************************************************************/
+  /* Codec Utilization list.                                                 */
+  /***************************************************************************/
+  evel_json_checkpoint(jbuf);
+  if (evel_json_open_opt_named_list(jbuf, "codecUsageArray"))
+  {
+    bool item_added = false;
+
+    item = dlist_get_first(&event->codec_usage);
+    while (item != NULL)
+    {
+      codec_use = (MEASUREMENT_CODEC_USE*) item->item;
+      assert(codec_use != NULL);
+
+      if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec,
+                                          "codecUsageArray",
+                                          codec_use->codec_id))
+      {
+        evel_json_open_object(jbuf);
+        evel_enc_kv_string(jbuf, "codecIdentifier", codec_use->codec_id);
+        evel_enc_kv_int(jbuf, "numberInUse", codec_use->number_in_use);
+        evel_json_close_object(jbuf);
+        item_added = true;
+      }
+      item = dlist_get_next(item);
+    }
+    evel_json_close_list(jbuf);
+
+    /*************************************************************************/
+    /* If we've not written anything, rewind to before we opened the list.   */
+    /*************************************************************************/
+    if (!item_added)
+    {
+      evel_json_rewind(jbuf);
+    }
+  }
+
+  /***************************************************************************/
+  /* Additional Measurement Groups list.                                     */
+  /***************************************************************************/
+  evel_json_checkpoint(jbuf);
+  if (evel_json_open_opt_named_list(jbuf, "additionalMeasurements"))
+  {
+    bool item_added = false;
+
+    item = dlist_get_first(&event->additional_measurements);
+    while (item != NULL)
+    {
+      measurement_group = (MEASUREMENT_GROUP *) item->item;
+      assert(measurement_group != NULL);
+
+      if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec,
+                                          "additionalMeasurements",
+                                          measurement_group->name))
+      {
+        evel_json_open_object(jbuf);
+        evel_enc_kv_string(jbuf, "name", measurement_group->name);
+        evel_json_open_opt_named_list(jbuf, "measurements");
+
+        /*********************************************************************/
+        /* Measurements list.                                                */
+        /*********************************************************************/
+        nested_item = dlist_get_first(&measurement_group->measurements);
+        while (nested_item != NULL)
+        {
+          custom_measurement = (CUSTOM_MEASUREMENT *) nested_item->item;
+          assert(custom_measurement != NULL);
+
+          evel_json_open_object(jbuf);
+          evel_enc_kv_string(jbuf, "name", custom_measurement->name);
+          evel_enc_kv_string(jbuf, "value", custom_measurement->value);
+          evel_json_close_object(jbuf);
+          nested_item = dlist_get_next(nested_item);
+        }
+        evel_json_close_list(jbuf);
+        evel_json_close_object(jbuf);
+        item_added = true;
+      }
+      item = dlist_get_next(item);
+    }
+    evel_json_close_list(jbuf);
+
+    /*************************************************************************/
+    /* If we've not written anything, rewind to before we opened the list.   */
+    /*************************************************************************/
+    if (!item_added)
+    {
+      evel_json_rewind(jbuf);
+    }
+  }
+
+  /***************************************************************************/
+  /* Although optional, we always generate the version.  Note that this      */
+  /* closes the object, too.                                                 */
+  /***************************************************************************/
+  evel_enc_version(jbuf,
+                   "measurementsForVfScalingVersion",
+                   event->major_version,
+                   event->major_version);
+  evel_json_close_object(jbuf);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Free a Measurement.
+ *
+ * Free off the Measurement supplied.  Will free all the contained allocated
+ * memory.
+ *
+ * @note It does not free the Measurement itself, since that may be part of a
+ * larger structure.
+ *****************************************************************************/
+void evel_free_measurement(EVENT_MEASUREMENT * event)
+{
+  MEASUREMENT_CPU_USE * cpu_use = NULL;
+  MEASUREMENT_FSYS_USE * fsys_use = NULL;
+  MEASUREMENT_LATENCY_BUCKET * bucket = NULL;
+  MEASUREMENT_VNIC_USE * vnic_use = NULL;
+  MEASUREMENT_FEATURE_USE * feature_use = NULL;
+  MEASUREMENT_CODEC_USE * codec_use = NULL;
+  MEASUREMENT_GROUP * measurement_group = NULL;
+  CUSTOM_MEASUREMENT * measurement = NULL;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.  As an internal API we don't allow freeing NULL    */
+  /* events as we do on the public API.                                      */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_MEASUREMENT);
+
+  /***************************************************************************/
+  /* Free all internal strings then the header itself.                       */
+  /***************************************************************************/
+  cpu_use = dlist_pop_last(&event->cpu_usage);
+  while (cpu_use != NULL)
+  {
+    EVEL_DEBUG("Freeing CPU use Info (%s)", cpu_use->id);
+    free(cpu_use->id);
+    free(cpu_use);
+    cpu_use = dlist_pop_last(&event->cpu_usage);
+  }
+
+  fsys_use = dlist_pop_last(&event->filesystem_usage);
+  while (fsys_use != NULL)
+  {
+    EVEL_DEBUG("Freeing Filesystem Use info (%s)", fsys_use->filesystem_name);
+    free(fsys_use->filesystem_name);
+    free(fsys_use);
+    fsys_use = dlist_pop_last(&event->filesystem_usage);
+  }
+
+  bucket = dlist_pop_last(&event->latency_distribution);
+  while (bucket != NULL)
+  {
+    EVEL_DEBUG("Freeing Latency Bucket");
+    free(bucket);
+    bucket = dlist_pop_last(&event->latency_distribution);
+  }
+
+  vnic_use = dlist_pop_last(&event->vnic_usage);
+  while (vnic_use != NULL)
+  {
+    EVEL_DEBUG("Freeing vNIC use Info (%s)", vnic_use->vnic_id);
+    evel_free_measurement_vnic_use(vnic_use);
+    free(vnic_use);
+    vnic_use = dlist_pop_last(&event->vnic_usage);
+  }
+
+  codec_use = dlist_pop_last(&event->codec_usage);
+  while (codec_use != NULL)
+  {
+    EVEL_DEBUG("Freeing Codec use Info (%s)", codec_use->codec_id);
+    free(codec_use->codec_id);
+    free(codec_use);
+    codec_use = dlist_pop_last(&event->codec_usage);
+  }
+
+  if (event->errors != NULL)
+  {
+    EVEL_DEBUG("Freeing Errors");
+    free(event->errors);
+  }
+
+  feature_use = dlist_pop_last(&event->feature_usage);
+  while (feature_use != NULL)
+  {
+    EVEL_DEBUG("Freeing Feature use Info (%s)", feature_use->feature_id);
+    free(feature_use->feature_id);
+    free(feature_use);
+    feature_use = dlist_pop_last(&event->feature_usage);
+  }
+
+  measurement_group = dlist_pop_last(&event->additional_measurements);
+  while (measurement_group != NULL)
+  {
+    EVEL_DEBUG("Freeing Measurement Group (%s)", measurement_group->name);
+
+    measurement = dlist_pop_last(&measurement_group->measurements);
+    while (measurement != NULL)
+    {
+      EVEL_DEBUG("Freeing Measurement (%s)", measurement->name);
+      free(measurement->name);
+      free(measurement->value);
+      free(measurement);
+      measurement = dlist_pop_last(&measurement_group->measurements);
+    }
+    free(measurement_group->name);
+    free(measurement_group);
+    measurement_group = dlist_pop_last(&event->additional_measurements);
+  }
+
+  evel_free_header(&event->header);
+
+  EVEL_EXIT();
+}
diff --git a/vnfs/VES/code/evel_library/evel_service.c b/vnfs/VES/code/evel_library/evel_service.c
new file mode 100644 (file)
index 0000000..0369951
--- /dev/null
@@ -0,0 +1,1313 @@
+/**************************************************************************//**
+ * @file
+ * Implementation of EVEL functions relating to Service.
+ *
+ * License
+ * -------
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:  This product includes
+ *    software developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "evel_throttle.h"
+
+/**************************************************************************//**
+ * Create a new Service event.
+ *
+ * @note    The mandatory fields on the Service must be supplied to
+ *          this factory function and are immutable once set.  Optional fields
+ *          have explicit setter functions, but again values may only be set
+ *          once so that the event has immutable properties.
+ * @param vendor_id     The vendor id to encode in the event instance id.
+ * @param event_id      The vendor event id to encode in the event instance id.
+ * @returns pointer to the newly manufactured ::EVENT_SERVICE.  If the event
+ *          is not used (i.e. posted) it must be released using
+ *          ::evel_free_service.
+ * @retval  NULL  Failed to create the event.
+ *****************************************************************************/
+EVENT_SERVICE * evel_new_service(const char * const vendor_id,
+                                 const char * const event_id)
+{
+  EVENT_SERVICE * event = NULL;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(vendor_id != NULL);
+  assert(event_id != NULL);
+
+  /***************************************************************************/
+  /* Allocate the Service event.                                           */
+  /***************************************************************************/
+  event = malloc(sizeof(EVENT_SERVICE));
+  if (event == NULL)
+  {
+    log_error_state("Out of memory");
+    goto exit_label;
+  }
+  memset(event, 0, sizeof(EVENT_SERVICE));
+  EVEL_DEBUG("New Service event is at %lp", event);
+
+  /***************************************************************************/
+  /* Initialize the header & the Service fields.                           */
+  /***************************************************************************/
+  evel_init_header(&event->header);
+  event->header.event_domain = EVEL_DOMAIN_SERVICE;
+  event->major_version = EVEL_SERVICE_MAJOR_VERSION;
+  event->minor_version = EVEL_SERVICE_MINOR_VERSION;
+  evel_init_event_instance_id(&event->instance_id, vendor_id, event_id);
+  evel_init_option_string(&event->correlator);
+  dlist_initialize(&event->additional_fields);
+  evel_init_option_string(&event->codec);
+  evel_init_option_string(&event->callee_side_codec);
+  evel_init_option_string(&event->caller_side_codec);
+  evel_init_option_string(&event->rtcp_data);
+  evel_init_option_string(&event->adjacency_name);
+  evel_init_option_string(&event->endpoint_description);
+  evel_init_option_int(&event->endpoint_jitter);
+  evel_init_option_int(&event->endpoint_rtp_oct_disc);
+  evel_init_option_int(&event->endpoint_rtp_oct_recv);
+  evel_init_option_int(&event->endpoint_rtp_oct_sent);
+  evel_init_option_int(&event->endpoint_rtp_pkt_disc);
+  evel_init_option_int(&event->endpoint_rtp_pkt_recv);
+  evel_init_option_int(&event->endpoint_rtp_pkt_sent);
+  evel_init_option_int(&event->local_jitter);
+  evel_init_option_int(&event->local_rtp_oct_disc);
+  evel_init_option_int(&event->local_rtp_oct_recv);
+  evel_init_option_int(&event->local_rtp_oct_sent);
+  evel_init_option_int(&event->local_rtp_pkt_disc);
+  evel_init_option_int(&event->local_rtp_pkt_recv);
+  evel_init_option_int(&event->local_rtp_pkt_sent);
+  evel_init_option_double(&event->mos_cqe);
+  evel_init_option_int(&event->packets_lost);
+  evel_init_option_double(&event->packet_loss_percent);
+  evel_init_option_int(&event->r_factor);
+  evel_init_option_int(&event->round_trip_delay);
+  evel_init_option_string(&event->phone_number);
+
+exit_label:
+
+  EVEL_EXIT();
+  return event;
+}
+
+/**************************************************************************//**
+ * Set the Event Type property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param type          The Event Type to be set. ASCIIZ string. The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_service_type_set(EVENT_SERVICE * const event,
+                           const char * const type)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_header_type_set.                      */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_header_type_set(&event->header, type);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Add a name/value pair to the Service, under the additionalFields array.
+ *
+ * The name and value are null delimited ASCII strings.  The library takes
+ * a copy so the caller does not have to preserve values after the function
+ * returns.
+ *
+ * @param event     Pointer to the Service event.
+ * @param name      ASCIIZ string with the field's name.  The caller does not
+ *                  need to preserve the value once the function returns.
+ * @param value     ASCIIZ string with the field's value.  The caller does not
+ *                  need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_service_addl_field_add(EVENT_SERVICE * const event,
+                                 const char * const name,
+                                 const char * const value)
+{
+  OTHER_FIELD * nv_pair = NULL;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  assert(name != NULL);
+  assert(value != NULL);
+
+  EVEL_DEBUG("Adding name=%s value=%s", name, value);
+  nv_pair = malloc(sizeof(OTHER_FIELD));
+  assert(nv_pair != NULL);
+  nv_pair->name = strdup(name);
+  nv_pair->value = strdup(value);
+  assert(nv_pair->name != NULL);
+  assert(nv_pair->value != NULL);
+
+  dlist_push_last(&event->additional_fields, nv_pair);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Product Id property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param product_id    The vendor product id to be set. ASCIIZ string. The
+ *                      caller does not need to preserve the value once the
+ *                      function returns.
+ *****************************************************************************/
+void evel_service_product_id_set(EVENT_SERVICE * const event,
+                                 const char * const product_id)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_string(&event->instance_id.product_id,
+                         product_id,
+                         "Product Id");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Subsystem Id property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param subsystem_id  The vendor subsystem id to be set. ASCIIZ string. The
+ *                      caller does not need to preserve the value once the
+ *                      function returns.
+ *****************************************************************************/
+void evel_service_subsystem_id_set(EVENT_SERVICE * const event,
+                                   const char * const subsystem_id)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_string(&event->instance_id.subsystem_id,
+                         subsystem_id,
+                         "Subsystem Id");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Friendly Name property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param friendly_name The vendor friendly name to be set. ASCIIZ string. The
+ *                      caller does not need to preserve the value once the
+ *                      function returns.
+ *****************************************************************************/
+void evel_service_friendly_name_set(EVENT_SERVICE * const event,
+                                    const char * const friendly_name)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_string(&event->instance_id.event_friendly_name,
+                         friendly_name,
+                         "Friendly Name");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Correlator property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param correlator    The correlator to be set. ASCIIZ string. The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_service_correlator_set(EVENT_SERVICE * const event,
+                                 const char * const correlator)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_string(&event->correlator,
+                         correlator,
+                         "Correlator");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Codec property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param codec         The codec to be set. ASCIIZ string. The caller does not
+ *                      need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_service_codec_set(EVENT_SERVICE * const event,
+                            const char * const codec)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_string(&event->codec,
+                         codec,
+                         "Codec");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Callee Side Codec property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param codec         The codec to be set. ASCIIZ string. The caller does not
+ *                      need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_service_callee_codec_set(EVENT_SERVICE * const event,
+                                   const char * const codec)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_string(&event->callee_side_codec,
+                         codec,
+                         "Callee Side Codec");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Caller Side Codec property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param codec         The codec to be set. ASCIIZ string. The caller does not
+ *                      need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_service_caller_codec_set(EVENT_SERVICE * const event,
+                                   const char * const codec)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_string(&event->caller_side_codec,
+                         codec,
+                         "Caller Side Codec");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the RTCP Data property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param rtcp_data     The RTCP Data to be set. ASCIIZ string. The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_service_rtcp_data_set(EVENT_SERVICE * const event,
+                                const char * const rtcp_data)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_string(&event->rtcp_data,
+                         rtcp_data,
+                         "RTCP Data");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Adjacency Name property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param adjacency_name
+ *                      The adjacency name to be set. ASCIIZ string. The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_service_adjacency_name_set(EVENT_SERVICE * const event,
+                                     const char * const adjacency_name)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_string(&event->adjacency_name,
+                         adjacency_name,
+                         "Adjacency Name");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Endpoint Descriptor property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param endpoint_desc The endpoint descriptor to be set.
+ *****************************************************************************/
+void evel_service_endpoint_desc_set(
+                                EVENT_SERVICE * const event,
+                                const EVEL_SERVICE_ENDPOINT_DESC endpoint_desc)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_string(&event->endpoint_description,
+                         evel_service_endpoint_desc(endpoint_desc),
+                         "Endpoint Description");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Endpoint Jitter property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param jitter        The jitter to be set.
+ *****************************************************************************/
+void evel_service_endpoint_jitter_set(EVENT_SERVICE * const event,
+                                      const int jitter)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_int(&event->endpoint_jitter,
+                      jitter,
+                      "Endpoint Jitter");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Endpoint Rtp Octets Discarded property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param rtp_oct_disc  The discard count.
+ *****************************************************************************/
+void evel_service_endpoint_rtp_oct_disc_set(EVENT_SERVICE * const event,
+                                            const int rtp_oct_disc)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_int(&event->endpoint_rtp_oct_disc,
+                      rtp_oct_disc,
+                      "Endpoint Rtp Octets Discarded");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Endpoint Rtp Octets Received property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param rtp_oct_recv  The receive count.
+ *****************************************************************************/
+void evel_service_endpoint_rtp_oct_recv_set(EVENT_SERVICE * const event,
+                                            const int rtp_oct_recv)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_int(&event->endpoint_rtp_oct_recv,
+                      rtp_oct_recv,
+                      "Endpoint Rtp Octets Received");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Endpoint Rtp Octets Sent property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param rtp_oct_sent  The send count.
+ *****************************************************************************/
+void evel_service_endpoint_rtp_oct_sent_set(EVENT_SERVICE * const event,
+                                            const int rtp_oct_sent)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_int(&event->endpoint_rtp_oct_sent,
+                      rtp_oct_sent,
+                      "Endpoint Rtp Octets Sent");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Endpoint Rtp Packets Discarded property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param rtp_pkt_disc  The discard count.
+ *****************************************************************************/
+void evel_service_endpoint_rtp_pkt_disc_set(EVENT_SERVICE * const event,
+                                            const int rtp_pkt_disc)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_int(&event->endpoint_rtp_pkt_disc,
+                      rtp_pkt_disc,
+                      "Endpoint Rtp Packets Discarded");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Endpoint Rtp Packets Received property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param rtp_pkt_recv  The receive count.
+ *****************************************************************************/
+void evel_service_endpoint_rtp_pkt_recv_set(EVENT_SERVICE * const event,
+                                            const int rtp_pkt_recv)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_int(&event->endpoint_rtp_pkt_recv,
+                      rtp_pkt_recv,
+                      "Endpoint Rtp Packets Received");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Endpoint Rtp Packets Sent property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param rtp_pkt_sent  The send count.
+ *****************************************************************************/
+void evel_service_endpoint_rtp_pkt_sent_set(EVENT_SERVICE * const event,
+                                            const int rtp_pkt_sent)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_int(&event->endpoint_rtp_pkt_sent,
+                      rtp_pkt_sent,
+                      "Endpoint Rtp Packets Sent");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Local Jitter property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param jitter        The jitter to be set.
+ *****************************************************************************/
+void evel_service_local_jitter_set(EVENT_SERVICE * const event,
+                                   const int jitter)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_int(&event->local_jitter,
+                      jitter,
+                      "Local Jitter");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Local Rtp Octets Discarded property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param rtp_oct_disc  The discard count.
+ *****************************************************************************/
+void evel_service_local_rtp_oct_disc_set(EVENT_SERVICE * const event,
+                                         const int rtp_oct_disc)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_int(&event->local_rtp_oct_disc,
+                      rtp_oct_disc,
+                      "Local Rtp Octets Discarded");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Local Rtp Octets Received property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param rtp_oct_recv  The receive count.
+ *****************************************************************************/
+void evel_service_local_rtp_oct_recv_set(EVENT_SERVICE * const event,
+                                         const int rtp_oct_recv)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_int(&event->local_rtp_oct_recv,
+                      rtp_oct_recv,
+                      "Local Rtp Octets Received");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Local Rtp Octets Sent property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param rtp_oct_sent  The send count.
+ *****************************************************************************/
+void evel_service_local_rtp_oct_sent_set(EVENT_SERVICE * const event,
+                                         const int rtp_oct_sent)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_int(&event->local_rtp_oct_sent,
+                      rtp_oct_sent,
+                      "Local Rtp Octets Sent");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Local Rtp Packets Discarded property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param rtp_pkt_disc  The discard count.
+ *****************************************************************************/
+void evel_service_local_rtp_pkt_disc_set(EVENT_SERVICE * const event,
+                                         const int rtp_pkt_disc)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_int(&event->local_rtp_pkt_disc,
+                      rtp_pkt_disc,
+                      "Local Rtp Packets Discarded");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Local Rtp Packets Received property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param rtp_pkt_recv  The receive count.
+ *****************************************************************************/
+void evel_service_local_rtp_pkt_recv_set(EVENT_SERVICE * const event,
+                                         const int rtp_pkt_recv)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_int(&event->local_rtp_pkt_recv,
+                      rtp_pkt_recv,
+                      "Local Rtp Packets Received");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Local Rtp Packets Sent property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param rtp_pkt_sent  The send count.
+ *****************************************************************************/
+void evel_service_local_rtp_pkt_sent_set(EVENT_SERVICE * const event,
+                                         const int rtp_pkt_sent)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_int(&event->local_rtp_pkt_sent,
+                      rtp_pkt_sent,
+                      "Local Rtp Packets Sent");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Mos Cqe property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param mos_cqe       The mosCqe to be set.
+ *****************************************************************************/
+void evel_service_mos_cqe_set(EVENT_SERVICE * const event,
+                              const double mos_cqe)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_double(&event->mos_cqe,
+                         mos_cqe,
+                         "Mos Cqe");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Packets Lost property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param packets_lost  The number of packets lost to be set.
+ *****************************************************************************/
+void evel_service_packets_lost_set(EVENT_SERVICE * const event,
+                                   const int packets_lost)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_int(&event->packets_lost,
+                      packets_lost,
+                      "Packets Lost");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the packet Loss Percent property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param packet_loss_percent
+ *                      The packet loss in percent.
+ *****************************************************************************/
+void evel_service_packet_loss_percent_set(EVENT_SERVICE * const event,
+                                          const double packet_loss_percent)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_double(&event->packet_loss_percent,
+                         packet_loss_percent,
+                         "Packet Loss Percent");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the R Factor property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param r_factor      The R Factor to be set.
+ *****************************************************************************/
+void evel_service_r_factor_set(EVENT_SERVICE * const event,
+                               const int r_factor)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_int(&event->r_factor,
+                      r_factor,
+                      "R Factor");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Round Trip Delay property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param round_trip_delay
+ *                      The Round trip delay to be set.
+ *****************************************************************************/
+void evel_service_round_trip_delay_set(EVENT_SERVICE * const event,
+                                       const int round_trip_delay)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_int(&event->round_trip_delay,
+                      round_trip_delay,
+                      "Round Trip Delay");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Phone Number property of the Service event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Service event.
+ * @param phone_number  The Phone Number to be set. ASCIIZ string. The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_service_phone_number_set(EVENT_SERVICE * const event,
+                                   const char * const phone_number)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_set_option_string.                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+  evel_set_option_string(&event->phone_number,
+                         phone_number,
+                         "Phone Number");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Encode the Service in JSON according to AT&T's schema for the
+ * event type.
+ *
+ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
+ * @param event         Pointer to the ::EVENT_HEADER to encode.
+ *****************************************************************************/
+void evel_json_encode_service(EVEL_JSON_BUFFER * const jbuf,
+                                EVENT_SERVICE * const event)
+{
+  OTHER_FIELD * nv_pair = NULL;
+  DLIST_ITEM * dlist_item = NULL;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+
+  evel_json_encode_header(jbuf, &event->header);
+  evel_json_open_named_object(jbuf, "serviceEventsFields");
+
+  /***************************************************************************/
+  /* Mandatory fields                                                        */
+  /***************************************************************************/
+  evel_json_encode_instance_id(jbuf, &event->instance_id);
+  evel_enc_version(jbuf,
+                   "serviceEventsFieldsVersion",
+                   event->major_version,
+                   event->minor_version);
+
+  /***************************************************************************/
+  /* Optional fields                                                         */
+  /***************************************************************************/
+  evel_enc_kv_opt_string(jbuf, "correlator", &event->correlator);
+
+  /***************************************************************************/
+  /* Checkpoint, so that we can wind back if all fields are suppressed.      */
+  /***************************************************************************/
+  evel_json_checkpoint(jbuf);
+  if (evel_json_open_opt_named_list(jbuf, "additionalFields"))
+  {
+    bool added = false;
+
+    dlist_item = dlist_get_first(&event->additional_fields);
+    while (dlist_item != NULL)
+    {
+      nv_pair = (OTHER_FIELD *) dlist_item->item;
+      assert(nv_pair != NULL);
+
+      if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec,
+                                          "additionalFields",
+                                          nv_pair->name))
+      {
+        evel_json_open_object(jbuf);
+        evel_enc_kv_string(jbuf, "name", nv_pair->name);
+        evel_enc_kv_string(jbuf, "value", nv_pair->value);
+        evel_json_close_object(jbuf);
+        added = true;
+      }
+      dlist_item = dlist_get_next(dlist_item);
+    }
+    evel_json_close_list(jbuf);
+
+    /*************************************************************************/
+    /* If we've not written anything, rewind to before we opened the list.   */
+    /*************************************************************************/
+    if (!added)
+    {
+      evel_json_rewind(jbuf);
+    }
+  }
+
+  /***************************************************************************/
+  /* Optional fields within JSON equivalent object: codecSelected            */
+  /***************************************************************************/
+  evel_json_checkpoint(jbuf);
+  if (evel_json_open_opt_named_object(jbuf, "codecSelected"))
+  {
+    bool added = false;
+    added |= evel_enc_kv_opt_string(jbuf,
+                                    "codec",
+                                    &event->codec);
+    evel_json_close_object(jbuf);
+
+    /*************************************************************************/
+    /* If the object is empty, rewind to before we opened it.                */
+    /*************************************************************************/
+    if (!added)
+    {
+      evel_json_rewind(jbuf);
+    }
+  }
+
+  /***************************************************************************/
+  /* Optional fields within JSON equivalent object: codecSelectedTranscoding */
+  /***************************************************************************/
+  evel_json_checkpoint(jbuf);
+  if (evel_json_open_opt_named_object(jbuf, "codecSelectedTranscoding"))
+  {
+    bool added = false;
+    added |= evel_enc_kv_opt_string(jbuf,
+                                    "calleeSideCodec",
+                                    &event->callee_side_codec);
+    added |= evel_enc_kv_opt_string(jbuf,
+                                    "callerSideCodec",
+                                    &event->caller_side_codec);
+    evel_json_close_object(jbuf);
+
+    /*************************************************************************/
+    /* If the object is empty, rewind to before we opened it.                */
+    /*************************************************************************/
+    if (!added)
+    {
+      evel_json_rewind(jbuf);
+    }
+  }
+
+  /***************************************************************************/
+  /* Optional fields within JSON equivalent object: midCallRtcp              */
+  /***************************************************************************/
+  evel_json_checkpoint(jbuf);
+  if (evel_json_open_opt_named_object(jbuf, "midCallRtcp"))
+  {
+    bool added = false;
+    added |= evel_enc_kv_opt_string(jbuf,
+                                    "rtcpData",
+                                    &event->rtcp_data);
+    evel_json_close_object(jbuf);
+
+    /*************************************************************************/
+    /* If the object is empty, rewind to before we opened it.                */
+    /*************************************************************************/
+    if (!added)
+    {
+      evel_json_rewind(jbuf);
+    }
+  }
+
+  /***************************************************************************/
+  /* Optional fields within JSON equivalent object: endOfCallVqmSummaries    */
+  /***************************************************************************/
+  evel_json_checkpoint(jbuf);
+  if (evel_json_open_opt_named_object(jbuf, "endOfCallVqmSummaries"))
+  {
+    bool added = false;
+    added |= evel_enc_kv_opt_string(jbuf,
+                                    "adjacencyName",
+                                    &event->adjacency_name);
+    added |= evel_enc_kv_opt_string(jbuf,
+                                    "endpointDescription",
+                                    &event->endpoint_description);
+    added |= evel_enc_kv_opt_int(jbuf,
+                                 "endpointJitter",
+                                 &event->endpoint_jitter);
+    added |= evel_enc_kv_opt_int(jbuf,
+                                 "endpointRtpOctetsDiscarded",
+                                 &event->endpoint_rtp_oct_disc);
+    added |= evel_enc_kv_opt_int(jbuf,
+                                 "endpointRtpOctetsReceived",
+                                 &event->endpoint_rtp_oct_recv);
+    added |= evel_enc_kv_opt_int(jbuf,
+                                 "endpointRtpOctetsSent",
+                                 &event->endpoint_rtp_oct_sent);
+    added |= evel_enc_kv_opt_int(jbuf,
+                                 "endpointRtpPacketsDiscarded",
+                                 &event->endpoint_rtp_pkt_disc);
+    added |= evel_enc_kv_opt_int(jbuf,
+                                 "endpointRtpPacketsReceived",
+                                 &event->endpoint_rtp_pkt_recv);
+    added |= evel_enc_kv_opt_int(jbuf,
+                                 "endpointRtpPacketsSent",
+                                 &event->endpoint_rtp_pkt_sent);
+    added |= evel_enc_kv_opt_int(jbuf,
+                                 "localJitter",
+                                 &event->local_jitter);
+    added |= evel_enc_kv_opt_int(jbuf,
+                                 "localRtpOctetsDiscarded",
+                                 &event->local_rtp_oct_disc);
+    added |= evel_enc_kv_opt_int(jbuf,
+                                 "localRtpOctetsReceived",
+                                 &event->local_rtp_oct_recv);
+    added |= evel_enc_kv_opt_int(jbuf,
+                                 "localRtpOctetsSent",
+                                 &event->local_rtp_oct_sent);
+    added |= evel_enc_kv_opt_int(jbuf,
+                                 "localRtpPacketsDiscarded",
+                                 &event->local_rtp_pkt_disc);
+    added |= evel_enc_kv_opt_int(jbuf,
+                                 "localRtpPacketsReceived",
+                                 &event->local_rtp_pkt_recv);
+    added |= evel_enc_kv_opt_int(jbuf,
+                                 "localRtpPacketsSent",
+                                 &event->local_rtp_pkt_sent);
+    added |= evel_enc_kv_opt_double(jbuf,
+                                    "mosCqe",
+                                    &event->mos_cqe);
+    added |= evel_enc_kv_opt_int(jbuf,
+                                 "packetsLost",
+                                 &event->packets_lost);
+    added |= evel_enc_kv_opt_double(jbuf,
+                                    "packetLossPercent",
+                                    &event->packet_loss_percent);
+    added |= evel_enc_kv_opt_int(jbuf,
+                                 "rFactor",
+                                 &event->r_factor);
+    added |= evel_enc_kv_opt_int(jbuf,
+                                 "roundTripDelay",
+                                 &event->round_trip_delay);
+    evel_json_close_object(jbuf);
+
+    /*************************************************************************/
+    /* If the object is empty, rewind to before we opened it.                */
+    /*************************************************************************/
+    if (!added)
+    {
+      evel_json_rewind(jbuf);
+    }
+  }
+
+  /***************************************************************************/
+  /* Optional fields within JSON equivalent object: marker                   */
+  /***************************************************************************/
+  evel_json_checkpoint(jbuf);
+  if (evel_json_open_opt_named_object(jbuf, "marker"))
+  {
+    bool added = false;
+    added |= evel_enc_kv_opt_string(jbuf, "phoneNumber", &event->phone_number);
+    evel_json_close_object(jbuf);
+
+    /*************************************************************************/
+    /* If the object is empty, rewind to before we opened it.                */
+    /*************************************************************************/
+    if (!added)
+    {
+      evel_json_rewind(jbuf);
+    }
+  }
+
+  evel_json_close_object(jbuf);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Free a Service event.
+ *
+ * Free off the event supplied.  Will free all the contained allocated memory.
+ *
+ * @note It does not free the event itself, since that may be part of a larger
+ * structure.
+ *****************************************************************************/
+void evel_free_service(EVENT_SERVICE * const event)
+{
+  OTHER_FIELD * nv_pair = NULL;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SERVICE);
+
+  /***************************************************************************/
+  /* Free all internal strings then the header itself.                       */
+  /***************************************************************************/
+  nv_pair = dlist_pop_last(&event->additional_fields);
+  while (nv_pair != NULL)
+  {
+    EVEL_DEBUG("Freeing Other Field (%s, %s)", nv_pair->name, nv_pair->value);
+    free(nv_pair->name);
+    free(nv_pair->value);
+    free(nv_pair);
+    nv_pair = dlist_pop_last(&event->additional_fields);
+  }
+  evel_free_option_string(&event->correlator);
+  evel_free_option_string(&event->codec);
+  evel_free_option_string(&event->callee_side_codec);
+  evel_free_option_string(&event->caller_side_codec);
+  evel_free_option_string(&event->rtcp_data);
+  evel_free_option_string(&event->adjacency_name);
+  evel_free_option_string(&event->endpoint_description);
+  evel_free_option_string(&event->phone_number);
+  evel_free_event_instance_id(&event->instance_id);
+  evel_free_header(&event->header);
+
+  EVEL_EXIT();
+}
diff --git a/vnfs/VES/code/evel_library/evel_signaling.c b/vnfs/VES/code/evel_library/evel_signaling.c
new file mode 100644 (file)
index 0000000..102e89e
--- /dev/null
@@ -0,0 +1,509 @@
+/**************************************************************************//**
+ * @file
+ * Implementation of EVEL functions relating to Signaling.
+ *
+ * License
+ * -------
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:  This product includes
+ *    software developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "evel_throttle.h"
+
+/**************************************************************************//**
+ * Create a new Signaling event.
+ *
+ * @note    The mandatory fields on the Signaling must be supplied to
+ *          this factory function and are immutable once set.  Optional fields
+ *          have explicit setter functions, but again values may only be set
+ *          once so that the event has immutable properties.
+ * @param vendor_id     The vendor id to encode in the event instance id.
+ * @param event_id      The vendor event id to encode in the event instance id.
+ * @returns pointer to the newly manufactured ::EVENT_SIGNALING.  If the event
+ *          is not used (i.e. posted) it must be released using
+ *          ::evel_free_signaling.
+ * @retval  NULL  Failed to create the event.
+ *****************************************************************************/
+EVENT_SIGNALING * evel_new_signaling(const char * const vendor_id,
+                                     const char * const event_id)
+{
+  EVENT_SIGNALING * event = NULL;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(vendor_id != NULL);
+  assert(event_id != NULL);
+
+  /***************************************************************************/
+  /* Allocate the Signaling event.                                           */
+  /***************************************************************************/
+  event = malloc(sizeof(EVENT_SIGNALING));
+  if (event == NULL)
+  {
+    log_error_state("Out of memory");
+    goto exit_label;
+  }
+  memset(event, 0, sizeof(EVENT_SIGNALING));
+  EVEL_DEBUG("New Signaling event is at %lp", event);
+
+  /***************************************************************************/
+  /* Initialize the header & the Signaling fields.                           */
+  /***************************************************************************/
+  evel_init_header(&event->header);
+  event->header.event_domain = EVEL_DOMAIN_SIGNALING;
+  event->major_version = EVEL_SIGNALING_MAJOR_VERSION;
+  event->minor_version = EVEL_SIGNALING_MINOR_VERSION;
+  evel_init_event_instance_id(&event->instance_id, vendor_id, event_id);
+  evel_init_option_string(&event->correlator);
+  evel_init_option_string(&event->local_ip_address);
+  evel_init_option_string(&event->local_port);
+  evel_init_option_string(&event->remote_ip_address);
+  evel_init_option_string(&event->remote_port);
+  evel_init_option_string(&event->compressed_sip);
+  evel_init_option_string(&event->summary_sip);
+
+exit_label:
+
+  EVEL_EXIT();
+  return event;
+}
+
+/**************************************************************************//**
+ * Set the Event Type property of the Signaling event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Signaling event.
+ * @param type          The Event Type to be set. ASCIIZ string. The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_signaling_type_set(EVENT_SIGNALING * const event,
+                             const char * const type)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_header_type_set.                      */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SIGNALING);
+  evel_header_type_set(&event->header, type);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Local Ip Address property of the Signaling event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Signaling event.
+ * @param local_ip_address
+ *                      The Local Ip Address to be set. ASCIIZ string. The
+ *                      caller does not need to preserve the value once the
+ *                      function returns.
+ *****************************************************************************/
+void evel_signaling_local_ip_address_set(EVENT_SIGNALING * const event,
+                                         const char * const local_ip_address)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SIGNALING);
+  assert(local_ip_address != NULL);
+
+  evel_set_option_string(&event->local_ip_address,
+                         local_ip_address,
+                         "Local Ip Address");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Local Port property of the Signaling event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Signaling event.
+ * @param local_port    The Local Port to be set. ASCIIZ string. The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_signaling_local_port_set(EVENT_SIGNALING * const event,
+                                   const char * const local_port)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SIGNALING);
+  assert(local_port != NULL);
+
+  evel_set_option_string(&event->local_port,
+                         local_port,
+                         "Local Port");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Remote Ip Address property of the Signaling event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Signaling event.
+ * @param remote_ip_address
+ *                      The Remote Ip Address to be set. ASCIIZ string. The
+ *                      caller does not need to preserve the value once the
+ *                      function returns.
+ *****************************************************************************/
+void evel_signaling_remote_ip_address_set(EVENT_SIGNALING * const event,
+                                          const char * const remote_ip_address)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SIGNALING);
+  assert(remote_ip_address != NULL);
+
+  evel_set_option_string(&event->remote_ip_address,
+                         remote_ip_address,
+                         "Remote Ip Address");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Remote Port property of the Signaling event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Signaling event.
+ * @param remote_port   The Remote Port to be set. ASCIIZ string. The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_signaling_remote_port_set(EVENT_SIGNALING * const event,
+                                    const char * const remote_port)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SIGNALING);
+  assert(remote_port != NULL);
+
+  evel_set_option_string(&event->remote_port,
+                         remote_port,
+                         "Remote Port");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Compressed SIP property of the Signaling event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Signaling event.
+ * @param compressed_sip
+ *                      The Compressed SIP to be set. ASCIIZ string. The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_signaling_compressed_sip_set(EVENT_SIGNALING * const event,
+                                       const char * const compressed_sip)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SIGNALING);
+  assert(compressed_sip != NULL);
+
+  evel_set_option_string(&event->compressed_sip,
+                         compressed_sip,
+                         "Compressed SIP");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Summary SIP property of the Signaling event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Signaling event.
+ * @param summary_sip   The Summary SIP to be set. ASCIIZ string. The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_signaling_summary_sip_set(EVENT_SIGNALING * const event,
+                                    const char * const summary_sip)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SIGNALING);
+  assert(summary_sip != NULL);
+
+  evel_set_option_string(&event->summary_sip,
+                         summary_sip,
+                         "Summary SIP");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Product Id property of the Signaling event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Signaling event.
+ * @param product_id    The vendor product id to be set. ASCIIZ string. The
+ *                      caller does not need to preserve the value once the
+ *                      function returns.
+ *****************************************************************************/
+void evel_signaling_product_id_set(EVENT_SIGNALING * const event,
+                                   const char * const product_id)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_header_type_set.                      */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SIGNALING);
+  evel_set_option_string(&event->instance_id.product_id,
+                         product_id,
+                         "Product Id");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Subsystem Id property of the Signaling event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Signaling event.
+ * @param subsystem_id  The vendor subsystem id to be set. ASCIIZ string. The
+ *                      caller does not need to preserve the value once the
+ *                      function returns.
+ *****************************************************************************/
+void evel_signaling_subsystem_id_set(EVENT_SIGNALING * const event,
+                                     const char * const subsystem_id)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_header_type_set.                      */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SIGNALING);
+  evel_set_option_string(&event->instance_id.subsystem_id,
+                         subsystem_id,
+                         "Subsystem Id");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Friendly Name property of the Signaling event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Signaling event.
+ * @param friendly_name The vendor friendly name to be set. ASCIIZ string. The
+ *                      caller does not need to preserve the value once the
+ *                      function returns.
+ *****************************************************************************/
+void evel_signaling_friendly_name_set(EVENT_SIGNALING * const event,
+                                      const char * const friendly_name)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_header_type_set.                      */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SIGNALING);
+  evel_set_option_string(&event->instance_id.event_friendly_name,
+                         friendly_name,
+                         "Friendly Name");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Correlator property of the Signaling event.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param event         Pointer to the Signaling event.
+ * @param correlator    The correlator to be set. ASCIIZ string. The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_signaling_correlator_set(EVENT_SIGNALING * const event,
+                                   const char * const correlator)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_header_type_set.                      */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SIGNALING);
+  evel_set_option_string(&event->correlator,
+                         correlator,
+                         "Correlator");
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Encode the Signaling in JSON according to AT&T's schema for the
+ * event type.
+ *
+ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
+ * @param event         Pointer to the ::EVENT_HEADER to encode.
+ *****************************************************************************/
+void evel_json_encode_signaling(EVEL_JSON_BUFFER * const jbuf,
+                                EVENT_SIGNALING * const event)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SIGNALING);
+
+  evel_json_encode_header(jbuf, &event->header);
+  evel_json_open_named_object(jbuf, "signalingFields");
+
+  /***************************************************************************/
+  /* Mandatory fields                                                        */
+  /***************************************************************************/
+  evel_json_encode_instance_id(jbuf, &event->instance_id);
+  evel_enc_version(jbuf,
+                   "signalingFieldsVersion",
+                   event->major_version,
+                   event->minor_version);
+
+  /***************************************************************************/
+  /* Optional fields                                                         */
+  /***************************************************************************/
+  evel_enc_kv_opt_string(jbuf, "correlator", &event->correlator);
+  evel_enc_kv_opt_string(jbuf, "localIpAddress", &event->local_ip_address);
+  evel_enc_kv_opt_string(jbuf, "localPort", &event->local_port);
+  evel_enc_kv_opt_string(jbuf, "remoteIpAddress", &event->remote_ip_address);
+  evel_enc_kv_opt_string(jbuf, "remotePort", &event->remote_port);
+  evel_enc_kv_opt_string(jbuf, "compressedSip", &event->compressed_sip);
+  evel_enc_kv_opt_string(jbuf, "summarySip", &event->summary_sip);
+  evel_json_close_object(jbuf);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Free a Signaling event.
+ *
+ * Free off the event supplied.  Will free all the contained allocated memory.
+ *
+ * @note It does not free the event itself, since that may be part of a larger
+ * structure.
+ *****************************************************************************/
+void evel_free_signaling(EVENT_SIGNALING * const event)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.  As an internal API we don't allow freeing NULL    */
+  /* events as we do on the public API.                                      */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SIGNALING);
+
+  evel_free_header(&event->header);
+  evel_free_event_instance_id(&event->instance_id);
+  evel_free_option_string(&event->correlator);
+  evel_free_option_string(&event->local_ip_address);
+  evel_free_option_string(&event->local_port);
+  evel_free_option_string(&event->remote_ip_address);
+  evel_free_option_string(&event->remote_port);
+  evel_free_option_string(&event->compressed_sip);
+  evel_free_option_string(&event->summary_sip);
+
+  EVEL_EXIT();
+}
diff --git a/vnfs/VES/code/evel_library/evel_state_change.c b/vnfs/VES/code/evel_library/evel_state_change.c
new file mode 100644 (file)
index 0000000..4b4671d
--- /dev/null
@@ -0,0 +1,295 @@
+/**************************************************************************//**
+ * @file
+ * Implementation of EVEL functions relating to the State Change.
+ *
+ * License
+ * -------
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:  This product includes
+ *    software developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "evel_throttle.h"
+
+/**************************************************************************//**
+ * Create a new State Change event.
+ *
+ * @note    The mandatory fields on the State Change must be supplied to this
+ *          factory function and are immutable once set.  Optional fields have
+ *          explicit setter functions, but again values may only be set once
+ *          so that the State Change has immutable properties.
+ *
+ * @param new_state     The new state of the reporting entity.
+ * @param old_state     The old state of the reporting entity.
+ * @param interface     The card or port name of the reporting entity.
+ *
+ * @returns pointer to the newly manufactured ::EVENT_STATE_CHANGE.  If the
+ *          event is not used it must be released using
+ *          ::evel_free_state_change
+ * @retval  NULL  Failed to create the event.
+ *****************************************************************************/
+EVENT_STATE_CHANGE * evel_new_state_change(const EVEL_ENTITY_STATE new_state,
+                                           const EVEL_ENTITY_STATE old_state,
+                                           const char * const interface)
+{
+  EVENT_STATE_CHANGE * state_change = NULL;
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(new_state < EVEL_MAX_ENTITY_STATES);
+  assert(old_state < EVEL_MAX_ENTITY_STATES);
+  assert(interface != NULL);
+
+  /***************************************************************************/
+  /* Allocate the State Change.                                              */
+  /***************************************************************************/
+  state_change = malloc(sizeof(EVENT_STATE_CHANGE));
+  if (state_change == NULL)
+  {
+    log_error_state("Out of memory");
+    goto exit_label;
+  }
+  memset(state_change, 0, sizeof(EVENT_STATE_CHANGE));
+  EVEL_DEBUG("New State Change is at %lp", state_change);
+
+  /***************************************************************************/
+  /* Initialize the header & the State Change fields.  Optional string       */
+  /* values are uninitialized (NULL).                                        */
+  /***************************************************************************/
+  evel_init_header(&state_change->header);
+  state_change->header.event_domain = EVEL_DOMAIN_STATE_CHANGE;
+  state_change->major_version = EVEL_STATE_CHANGE_MAJOR_VERSION;
+  state_change->minor_version = EVEL_STATE_CHANGE_MINOR_VERSION;
+  state_change->new_state = new_state;
+  state_change->old_state = old_state;
+  state_change->state_interface = strdup(interface);
+  dlist_initialize(&state_change->additional_fields);
+
+exit_label:
+  EVEL_EXIT();
+  return state_change;
+}
+
+/**************************************************************************//**
+ * Free a State Change.
+ *
+ * Free off the State Change supplied.  Will free all the contained allocated
+ * memory.
+ *
+ * @note It does not free the State Change itself, since that may be part of a
+ * larger structure.
+ *****************************************************************************/
+void evel_free_state_change(EVENT_STATE_CHANGE * const state_change)
+{
+  STATE_CHANGE_ADDL_FIELD * addl_field = NULL;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.  As an internal API we don't allow freeing NULL    */
+  /* events as we do on the public API.                                      */
+  /***************************************************************************/
+  assert(state_change != NULL);
+  assert(state_change->header.event_domain == EVEL_DOMAIN_STATE_CHANGE);
+
+  /***************************************************************************/
+  /* Free all internal strings then the header itself.                       */
+  /***************************************************************************/
+  addl_field = dlist_pop_last(&state_change->additional_fields);
+  while (addl_field != NULL)
+  {
+    EVEL_DEBUG("Freeing Additional Field (%s, %s)",
+               addl_field->name,
+               addl_field->value);
+    free(addl_field->name);
+    free(addl_field->value);
+    free(addl_field);
+    addl_field = dlist_pop_last(&state_change->additional_fields);
+  }
+  free(state_change->state_interface);
+  evel_free_header(&state_change->header);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Event Type property of the State Change.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param state_change  Pointer to the ::EVENT_STATE_CHANGE.
+ * @param type          The Event Type to be set. ASCIIZ string. The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_state_change_type_set(EVENT_STATE_CHANGE * const state_change,
+                                const char * const type)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_header_type_set.                      */
+  /***************************************************************************/
+  assert(state_change != NULL);
+  assert(state_change->header.event_domain == EVEL_DOMAIN_STATE_CHANGE);
+  evel_header_type_set(&state_change->header, type);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Add an additional field name/value pair to the State Change.
+ *
+ * The name and value are null delimited ASCII strings.  The library takes
+ * a copy so the caller does not have to preserve values after the function
+ * returns.
+ *
+ * @param state_change  Pointer to the ::EVENT_STATE_CHANGE.
+ * @param name          ASCIIZ string with the attribute's name.  The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ * @param value         ASCIIZ string with the attribute's value.  The caller
+ *                      does not need to preserve the value once the function
+ *                      returns.
+ *****************************************************************************/
+void evel_state_change_addl_field_add(EVENT_STATE_CHANGE * const state_change,
+                                      const char * const name,
+                                      const char * const value)
+{
+  STATE_CHANGE_ADDL_FIELD * addl_field = NULL;
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(state_change != NULL);
+  assert(state_change->header.event_domain == EVEL_DOMAIN_STATE_CHANGE);
+  assert(name != NULL);
+  assert(value != NULL);
+
+  EVEL_DEBUG("Adding name=%s value=%s", name, value);
+  addl_field = malloc(sizeof(STATE_CHANGE_ADDL_FIELD));
+  assert(addl_field != NULL);
+  memset(addl_field, 0, sizeof(STATE_CHANGE_ADDL_FIELD));
+  addl_field->name = strdup(name);
+  addl_field->value = strdup(value);
+  assert(addl_field->name != NULL);
+  assert(addl_field->value != NULL);
+
+  dlist_push_last(&state_change->additional_fields, addl_field);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Encode the state change as a JSON state change.
+ *
+ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
+ * @param state_change  Pointer to the ::EVENT_STATE_CHANGE to encode.
+ *****************************************************************************/
+void evel_json_encode_state_change(EVEL_JSON_BUFFER * jbuf,
+                                   EVENT_STATE_CHANGE * state_change)
+{
+  STATE_CHANGE_ADDL_FIELD * addl_field = NULL;
+  DLIST_ITEM * addl_field_item = NULL;
+  char * new_state;
+  char * old_state;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(state_change != NULL);
+  assert(state_change->header.event_domain == EVEL_DOMAIN_STATE_CHANGE);
+
+  new_state = evel_entity_state(state_change->new_state);
+  old_state = evel_entity_state(state_change->old_state);
+
+  evel_json_encode_header(jbuf, &state_change->header);
+  evel_json_open_named_object(jbuf, "stateChangeFields");
+
+  /***************************************************************************/
+  /* Mandatory fields.                                                       */
+  /***************************************************************************/
+  evel_enc_kv_string(jbuf, "newState", new_state);
+  evel_enc_kv_string(jbuf, "oldState", old_state);
+  evel_enc_kv_string(jbuf, "stateInterface", state_change->state_interface);
+
+  /***************************************************************************/
+  /* Optional fields.                                                        */
+  /***************************************************************************/
+  evel_json_checkpoint(jbuf);
+  if (evel_json_open_opt_named_list(jbuf, "additionalFields"))
+  {
+    bool item_added = false;
+
+    addl_field_item = dlist_get_first(&state_change->additional_fields);
+    while (addl_field_item != NULL)
+    {
+      addl_field = (STATE_CHANGE_ADDL_FIELD *) addl_field_item->item;
+      assert(addl_field != NULL);
+
+      if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec,
+                                          "additionalFields",
+                                          addl_field->name))
+      {
+        evel_json_open_object(jbuf);
+        evel_enc_kv_string(jbuf, "name", addl_field->name);
+        evel_enc_kv_string(jbuf, "value", addl_field->value);
+        evel_json_close_object(jbuf);
+        item_added = true;
+      }
+      addl_field_item = dlist_get_next(addl_field_item);
+    }
+    evel_json_close_list(jbuf);
+
+    /*************************************************************************/
+    /* If we've not written anything, rewind to before we opened the list.   */
+    /*************************************************************************/
+    if (!item_added)
+    {
+      evel_json_rewind(jbuf);
+    }
+  }
+
+  evel_enc_version(jbuf,
+                   "stateChangeFieldsVersion",
+                   state_change->major_version,
+                   state_change->minor_version);
+
+  evel_json_close_object(jbuf);
+
+  EVEL_EXIT();
+}
diff --git a/vnfs/VES/code/evel_library/evel_strings.c b/vnfs/VES/code/evel_library/evel_strings.c
new file mode 100644 (file)
index 0000000..1f410cb
--- /dev/null
@@ -0,0 +1,477 @@
+/**************************************************************************//**
+ * @file
+ * Implementation of EVEL functions to convert common enum types to strings.
+ *
+ * License
+ * -------
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:  This product includes
+ *    software developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "evel_internal.h"
+
+/**************************************************************************//**
+ * Map an ::EVEL_COUNTER_CRITICALITIES enum value to the equivalent string.
+ *
+ * @param criticality   The criticality to convert.
+ * @returns The equivalent string.
+ *****************************************************************************/
+char * evel_criticality(const EVEL_COUNTER_CRITICALITIES criticality)
+{
+  char * result;
+
+  EVEL_ENTER();
+
+  switch (criticality)
+  {
+    case EVEL_COUNTER_CRITICALITY_CRIT:
+      result = "CRIT";
+      break;
+
+    case EVEL_COUNTER_CRITICALITY_MAJ:
+      result = "MAJ";
+      break;
+
+    default:
+      EVEL_ERROR("Unexpected counter criticality %d", criticality);
+      assert(0);
+  }
+
+  EVEL_EXIT();
+
+  return result;
+}
+
+/**************************************************************************//**
+ * Map an ::EVEL_SEVERITIES enum value to the equivalent string.
+ *
+ * @param severity      The severity to convert.
+ * @returns The equivalent string.
+ *****************************************************************************/
+char * evel_severity(const EVEL_SEVERITIES severity)
+{
+  char * result;
+
+  EVEL_ENTER();
+
+  switch (severity)
+  {
+    case EVEL_SEVERITY_CRITICAL:
+      result = "CRITICAL";
+      break;
+
+    case EVEL_SEVERITY_MAJOR:
+      result = "MAJOR";
+      break;
+
+    case EVEL_SEVERITY_MINOR:
+      result = "MINOR";
+      break;
+
+    case EVEL_SEVERITY_WARNING:
+      result = "WARNING";
+      break;
+
+    case EVEL_SEVERITY_NORMAL:
+      result = "NORMAL";
+      break;
+
+    default:
+      EVEL_ERROR("Unexpected event severity %d", severity);
+      assert(0);
+  }
+
+  EVEL_EXIT();
+
+  return result;
+}
+
+/**************************************************************************//**
+ * Map an ::EVEL_ALERT_ACTIONS enum value to the equivalent string.
+ *
+ * @param alert_action  The alert_action to convert.
+ * @returns The equivalent string.
+ *****************************************************************************/
+char * evel_alert_action(const EVEL_ALERT_ACTIONS alert_action)
+{
+  char * result;
+
+  EVEL_ENTER();
+
+  switch (alert_action)
+  {
+    case EVEL_ALERT_ACTION_CLEAR:
+      result = "CLEAR";
+      break;
+
+    case EVEL_ALERT_ACTION_CONT:
+      result = "CONT";
+      break;
+
+    case EVEL_ALERT_ACTION_SET:
+      result = "SET";
+      break;
+
+    default:
+      EVEL_ERROR("Unexpected alert action %d", alert_action);
+      assert(0);
+  }
+
+  EVEL_EXIT();
+
+  return result;
+}
+
+/**************************************************************************//**
+ * Map an ::EVEL_ALERT_TYPES enum value to the equivalent string.
+ *
+ * @param alert_type    The alert_type to convert.
+ * @returns The equivalent string.
+ *****************************************************************************/
+char * evel_alert_type(const EVEL_ALERT_TYPES alert_type)
+{
+  char * result;
+
+  EVEL_ENTER();
+
+  switch (alert_type)
+  {
+    case EVEL_ALERT_TYPE_CARD:
+      result = "CARD-ANOMALY";
+      break;
+
+    case EVEL_ALERT_TYPE_ELEMENT:
+      result = "ELEMENT-ANOMALY";
+      break;
+
+    case EVEL_ALERT_TYPE_INTERFACE:
+      result = "INTERFACE-ANOMALY";
+      break;
+
+    case EVEL_ALERT_TYPE_SERVICE:
+      result = "SERVICE-ANOMALY";
+      break;
+
+    default:
+      EVEL_ERROR("Unexpected alert type %d", alert_type);
+      assert(0);
+  }
+
+  EVEL_EXIT();
+
+  return result;
+}
+
+/**************************************************************************//**
+ * Map an ::EVEL_EVENT_DOMAINS enum value to the equivalent string.
+ *
+ * @param domain        The domain to convert.
+ * @returns The equivalent string.
+ *****************************************************************************/
+char * evel_event_domain(const EVEL_EVENT_DOMAINS domain)
+{
+  char * result;
+
+  EVEL_ENTER();
+
+  switch (domain)
+  {
+    case EVEL_DOMAIN_HEARTBEAT:
+      result = "heartbeat";
+      break;
+
+    case EVEL_DOMAIN_FAULT:
+      result = "fault";
+      break;
+
+    case EVEL_DOMAIN_MEASUREMENT:
+      result = "measurementsForVfScaling";
+      break;
+
+    case EVEL_DOMAIN_REPORT:
+      result = "measurementsForVfReporting";
+      break;
+
+    case EVEL_DOMAIN_MOBILE_FLOW:
+      result = "mobileFlow";
+      break;
+
+    case EVEL_DOMAIN_SERVICE:
+      result = "serviceEvents";
+      break;
+
+    case EVEL_DOMAIN_SIGNALING:
+      result = "signaling";
+      break;
+
+    case EVEL_DOMAIN_STATE_CHANGE:
+      result = "stateChange";
+      break;
+
+    case EVEL_DOMAIN_SYSLOG:
+      result = "syslog";
+      break;
+
+    case EVEL_DOMAIN_OTHER:
+      result = "other";
+      break;
+
+    default:
+      result = NULL;
+      EVEL_ERROR("Unexpected domain %d", domain);
+      assert(0);
+  }
+
+  EVEL_EXIT();
+
+  return result;
+}
+
+/**************************************************************************//**
+ * Map an ::EVEL_EVENT_PRIORITIES enum value to the equivalent string.
+ *
+ * @param priority      The priority to convert.
+ * @returns The equivalent string.
+ *****************************************************************************/
+char * evel_event_priority(const EVEL_EVENT_PRIORITIES priority)
+{
+  char * result;
+
+  EVEL_ENTER();
+
+  switch (priority)
+  {
+    case EVEL_PRIORITY_HIGH:
+      result = "High";
+      break;
+
+    case EVEL_PRIORITY_MEDIUM:
+      result = "Medium";
+      break;
+
+    case EVEL_PRIORITY_NORMAL:
+      result = "Normal";
+      break;
+
+    case EVEL_PRIORITY_LOW:
+      result = "Low";
+      break;
+
+    default:
+      result = NULL;
+      EVEL_ERROR("Unexpected priority %d", priority);
+      assert(0);
+  }
+
+  EVEL_EXIT();
+
+  return result;
+}
+
+/**************************************************************************//**
+ * Map an ::EVEL_SOURCE_TYPES enum value to the equivalent string.
+ *
+ * @param source_type   The source type to convert.
+ * @returns The equivalent string.
+ *****************************************************************************/
+char * evel_source_type(const EVEL_SOURCE_TYPES source_type)
+{
+  char * result;
+
+  EVEL_ENTER();
+
+  switch (source_type)
+  {
+    case EVEL_SOURCE_OTHER:
+      result = "other";
+      break;
+
+    case EVEL_SOURCE_ROUTER:
+      result = "router";
+      break;
+
+    case EVEL_SOURCE_SWITCH:
+      result = "switch";
+      break;
+
+    case EVEL_SOURCE_HOST:
+      result = "host";
+      break;
+
+    case EVEL_SOURCE_CARD:
+      result = "card";
+      break;
+
+    case EVEL_SOURCE_PORT:
+      result = "port";
+      break;
+
+    case EVEL_SOURCE_SLOT_THRESHOLD:
+      result = "slotThreshold";
+      break;
+
+    case EVEL_SOURCE_PORT_THRESHOLD:
+      result = "portThreshold";
+      break;
+
+    case EVEL_SOURCE_VIRTUAL_MACHINE:
+      result = "virtualMachine";
+      break;
+
+    case EVEL_SOURCE_VIRTUAL_NETWORK_FUNCTION:
+      result = "virtualNetworkFunction";
+      break;
+
+    default:
+      result = NULL;
+      EVEL_ERROR("Unexpected Event Source Type %d", (int) source_type);
+      assert(0);
+  }
+
+  EVEL_EXIT();
+
+  return result;
+}
+
+/**************************************************************************//**
+ * Map an ::EVEL_VF_STATUSES enum value to the equivalent string.
+ *
+ * @param vf_status     The vf_status to convert.
+ * @returns The equivalent string.
+ *****************************************************************************/
+char * evel_vf_status(const EVEL_VF_STATUSES vf_status)
+{
+  char * result;
+
+  EVEL_ENTER();
+
+  switch (vf_status)
+  {
+    case EVEL_VF_STATUS_ACTIVE:
+      result = "Active";
+      break;
+
+    case EVEL_VF_STATUS_IDLE:
+      result = "Idle";
+      break;
+
+    case EVEL_VF_STATUS_PREP_TERMINATE:
+      result = "Preparing to terminate";
+      break;
+
+    case EVEL_VF_STATUS_READY_TERMINATE:
+      result = "Ready to terminate";
+      break;
+
+    case EVEL_VF_STATUS_REQ_TERMINATE:
+      result = "Requesting termination";
+      break;
+
+    default:
+      result = NULL;
+      EVEL_ERROR("Unexpected VF Status %d", vf_status);
+      assert(0);
+  }
+
+  EVEL_EXIT();
+
+  return result;
+}
+
+/**************************************************************************//**
+ * Convert a ::EVEL_ENTITY_STATE to it's string form for JSON encoding.
+ *
+ * @param state         The entity state to encode.
+ *
+ * @returns the corresponding string
+ *****************************************************************************/
+char * evel_entity_state(const EVEL_ENTITY_STATE state)
+{
+  char * result;
+
+  EVEL_ENTER();
+
+  switch (state)
+  {
+    case EVEL_ENTITY_STATE_IN_SERVICE:
+      result = "inService";
+      break;
+
+    case EVEL_ENTITY_STATE_MAINTENANCE:
+      result = "maintenance";
+      break;
+
+    case EVEL_ENTITY_STATE_OUT_OF_SERVICE:
+      result = "outOfService";
+      break;
+
+    default:
+      EVEL_ERROR("Unexpected entity state %d", state);
+      assert(0);
+  }
+
+  EVEL_EXIT();
+
+  return result;
+}
+
+/**************************************************************************//**
+ * Convert a ::EVEL_SERVICE_ENDPOINT_DESC to string form for JSON encoding.
+ *
+ * @param endpoint_desc endpoint description to encode.
+ *
+ * @returns the corresponding string
+ *****************************************************************************/
+char * evel_service_endpoint_desc(const EVEL_ENTITY_STATE endpoint_desc)
+{
+  char * result;
+
+  EVEL_ENTER();
+
+  switch (endpoint_desc)
+  {
+    case EVEL_SERVICE_ENDPOINT_CALLEE:
+      result = "Callee";
+      break;
+
+    case EVEL_SERVICE_ENDPOINT_CALLER:
+      result = "Caller";
+      break;
+
+    default:
+      EVEL_ERROR("Unexpected endpoint description %d", endpoint_desc);
+      assert(0);
+  }
+
+  EVEL_EXIT();
+
+  return result;
+}
diff --git a/vnfs/VES/code/evel_library/evel_syslog.c b/vnfs/VES/code/evel_library/evel_syslog.c
new file mode 100644 (file)
index 0000000..64a9488
--- /dev/null
@@ -0,0 +1,500 @@
+/**************************************************************************//**
+ * @file
+ * Implementation of EVEL functions relating to the Syslog.
+ *
+ * License
+ * -------
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:  This product includes
+ *    software developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "evel_throttle.h"
+
+/**************************************************************************//**
+ * Create a new Syslog event.
+ *
+ * @note    The mandatory fields on the Syslog must be supplied to this factory
+ *          function and are immutable once set.  Optional fields have explicit
+ *          setter functions, but again values may only be set once so that the
+ *          Syslog has immutable properties.
+ * @param   event_source_type  The type of Syslog event source.
+ * @param   syslog_msg         The Syslog event message.
+ * @param   syslog_tag         The messgaeId identifying the type of message.
+ * @returns pointer to the newly manufactured ::EVENT_SYSLOG.  If the event is
+ *          not used (i.e. posted) it must be released using
+ *          ::evel_free_syslog.
+ * @retval  NULL  Failed to create the event.
+ *****************************************************************************/
+EVENT_SYSLOG * evel_new_syslog(EVEL_SOURCE_TYPES event_source_type,
+                               const char * const syslog_msg,
+                               const char * const syslog_tag)
+{
+  EVENT_SYSLOG * syslog = NULL;
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(event_source_type < EVEL_MAX_SOURCE_TYPES);
+  assert(syslog_msg != NULL);
+  assert(syslog_tag != NULL);
+
+  /***************************************************************************/
+  /* Allocate the Syslog.                                                    */
+  /***************************************************************************/
+  syslog = malloc(sizeof(EVENT_SYSLOG));
+  if (syslog == NULL)
+  {
+    log_error_state("Out of memory");
+    goto exit_label;
+  }
+  memset(syslog, 0, sizeof(EVENT_SYSLOG));
+  EVEL_DEBUG("New Syslog is at %lp", syslog);
+
+  /***************************************************************************/
+  /* Initialize the header & the Syslog fields.  Optional string values are  */
+  /* uninitialized (NULL).                                                   */
+  /***************************************************************************/
+  evel_init_header(&syslog->header);
+  syslog->header.event_domain = EVEL_DOMAIN_SYSLOG;
+  syslog->major_version = EVEL_SYSLOG_MAJOR_VERSION;
+  syslog->minor_version = EVEL_SYSLOG_MINOR_VERSION;
+  syslog->event_source_type = event_source_type;
+  syslog->syslog_msg = strdup(syslog_msg);
+  syslog->syslog_tag = strdup(syslog_tag);
+  dlist_initialize(&syslog->additional_fields);
+  evel_init_option_int(&syslog->syslog_facility);
+  evel_init_option_int(&syslog->syslog_proc_id);
+  evel_init_option_int(&syslog->syslog_ver);
+  evel_init_option_string(&syslog->event_source_host);
+  evel_init_option_string(&syslog->syslog_proc);
+  evel_init_option_string(&syslog->syslog_s_data);
+
+exit_label:
+  EVEL_EXIT();
+  return syslog;
+}
+
+/**************************************************************************//**
+ * Set the Event Type property of the Syslog.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param syslog      Pointer to the syslog.
+ * @param type        The Event Type to be set. ASCIIZ string. The caller
+ *                    does not need to preserve the value once the function
+ *                    returns.
+ *****************************************************************************/
+void evel_syslog_type_set(EVENT_SYSLOG * syslog,
+                          const char * const type)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions and call evel_header_type_set.                      */
+  /***************************************************************************/
+  assert(syslog != NULL);
+  assert(syslog->header.event_domain == EVEL_DOMAIN_SYSLOG);
+  evel_header_type_set(&syslog->header, type);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Add an additional value name/value pair to the Syslog.
+ *
+ * The name and value are null delimited ASCII strings.  The library takes
+ * a copy so the caller does not have to preserve values after the function
+ * returns.
+ *
+ * @param syslog    Pointer to the syslog.
+ * @param name      ASCIIZ string with the attribute's name.  The caller
+ *                  does not need to preserve the value once the function
+ *                  returns.
+ * @param value     ASCIIZ string with the attribute's value.  The caller
+ *                  does not need to preserve the value once the function
+ *                  returns.
+ *****************************************************************************/
+void evel_syslog_addl_field_add(EVENT_SYSLOG * syslog,
+                                char * name,
+                                char * value)
+{
+  SYSLOG_ADDL_FIELD * addl_field = NULL;
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(syslog != NULL);
+  assert(syslog->header.event_domain == EVEL_DOMAIN_SYSLOG);
+  assert(name != NULL);
+  assert(value != NULL);
+
+  EVEL_DEBUG("Adding name=%s value=%s", name, value);
+  addl_field = malloc(sizeof(SYSLOG_ADDL_FIELD));
+  assert(addl_field != NULL);
+  memset(addl_field, 0, sizeof(SYSLOG_ADDL_FIELD));
+  addl_field->name = strdup(name);
+  addl_field->value = strdup(value);
+  assert(addl_field->name != NULL);
+  assert(addl_field->value != NULL);
+
+  dlist_push_last(&syslog->additional_fields, addl_field);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Event Source Host property of the Syslog.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param syslog     Pointer to the Syslog.
+ * @param host       The Event Source Host to be set. ASCIIZ string. The caller
+ *                   does not need to preserve the value once the function
+ *                   returns.
+ *****************************************************************************/
+void evel_syslog_event_source_host_set(EVENT_SYSLOG * syslog,
+                                       const char * const host)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(syslog != NULL);
+  assert(syslog->header.event_domain == EVEL_DOMAIN_SYSLOG);
+  assert(host != NULL);
+
+  evel_set_option_string(&syslog->event_source_host,
+                         host,
+                         "Event Source Host");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Facility property of the Syslog.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param syslog      Pointer to the Syslog.
+ * @param facility    The Syslog Facility to be set.  ASCIIZ string. The caller
+ *                    does not need to preserve the value once the function
+ *                    returns.
+ *****************************************************************************/
+void evel_syslog_facility_set(EVENT_SYSLOG * syslog,
+                              EVEL_SYSLOG_FACILITIES facility)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(syslog != NULL);
+  assert(syslog->header.event_domain == EVEL_DOMAIN_SYSLOG);
+  assert(facility < EVEL_MAX_SYSLOG_FACILITIES);
+
+  evel_set_option_int(&syslog->syslog_facility,
+                      facility,
+                      "Facility");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Process property of the Syslog.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param syslog     Pointer to the Syslog.
+ * @param proc       The Process to be set. ASCIIZ string. The caller does not
+ *                   need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_syslog_proc_set(EVENT_SYSLOG * syslog, const char * const proc)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(syslog != NULL);
+  assert(syslog->header.event_domain == EVEL_DOMAIN_SYSLOG);
+  assert(proc != NULL);
+
+  evel_set_option_string(&syslog->syslog_proc, proc, "Process");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Process ID property of the Syslog.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param syslog     Pointer to the Syslog.
+ * @param proc_id    The Process ID to be set. ASCIIZ string. The caller does
+ *                   not need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_syslog_proc_id_set(EVENT_SYSLOG * syslog, int proc_id)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(syslog != NULL);
+  assert(syslog->header.event_domain == EVEL_DOMAIN_SYSLOG);
+  assert(proc_id > 0);
+
+  evel_set_option_int(&syslog->syslog_proc_id,
+                      proc_id,
+                      "Process ID");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Version property of the Syslog.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param syslog     Pointer to the Syslog.
+ * @param version    The Version to be set. ASCIIZ string. The caller does not
+ *                   need to preserve the value once the function returns.
+ *****************************************************************************/
+void evel_syslog_version_set(EVENT_SYSLOG * syslog, int version)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(syslog != NULL);
+  assert(syslog->header.event_domain == EVEL_DOMAIN_SYSLOG);
+  assert(version >= 0);
+
+  evel_set_option_int(&syslog->syslog_ver,
+                      version,
+                      "Version");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the Structured Data property of the Syslog.
+ *
+ * @note  The property is treated as immutable: it is only valid to call
+ *        the setter once.  However, we don't assert if the caller tries to
+ *        overwrite, just ignoring the update instead.
+ *
+ * @param syslog     Pointer to the Syslog.
+ * @param s_data     The Structured Data to be set. ASCIIZ string. The caller
+ *                   does not need to preserve the value once the function
+ *                   returns.
+ *****************************************************************************/
+void evel_syslog_s_data_set(EVENT_SYSLOG * syslog, const char * const s_data)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(syslog != NULL);
+  assert(syslog->header.event_domain == EVEL_DOMAIN_SYSLOG);
+  assert(s_data != NULL);
+
+  evel_set_option_string(&syslog->syslog_s_data,
+                         s_data,
+                         "Structured Data");
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Encode the Syslog in JSON according to AT&T's schema for the event type.
+ *
+ * @param jbuf          Pointer to the ::EVEL_JSON_BUFFER to encode into.
+ * @param event         Pointer to the ::EVENT_HEADER to encode.
+ *****************************************************************************/
+void evel_json_encode_syslog(EVEL_JSON_BUFFER * jbuf,
+                             EVENT_SYSLOG * event)
+{
+  char * event_source_type;
+  SYSLOG_ADDL_FIELD * addl_field = NULL;
+  DLIST_ITEM * addl_field_item = NULL;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SYSLOG);
+
+  event_source_type = evel_source_type(event->event_source_type);
+
+  evel_json_encode_header(jbuf, &event->header);
+  evel_json_open_named_object(jbuf, "syslogFields");
+
+  /***************************************************************************/
+  /* Mandatory fields                                                        */
+  /***************************************************************************/
+  evel_enc_kv_string(jbuf, "eventSourceType", event_source_type);
+  evel_enc_kv_string(jbuf, "syslogMsg", event->syslog_msg);
+  evel_enc_kv_string(jbuf, "syslogTag", event->syslog_tag);
+  evel_enc_version(
+    jbuf, "syslogFieldsVersion", event->major_version, event->minor_version);
+
+  /***************************************************************************/
+  /* Optional fields                                                         */
+  /***************************************************************************/
+  evel_json_checkpoint(jbuf);
+  if (evel_json_open_opt_named_list(jbuf, "additionalFields"))
+  {
+    bool item_added = false;
+
+    addl_field_item = dlist_get_first(&event->additional_fields);
+    while (addl_field_item != NULL)
+    {
+      addl_field = (SYSLOG_ADDL_FIELD *) addl_field_item->item;
+      assert(addl_field != NULL);
+
+      if (!evel_throttle_suppress_nv_pair(jbuf->throttle_spec,
+                                          "additionalFields",
+                                          addl_field->name))
+      {
+        evel_json_open_object(jbuf);
+        evel_enc_kv_string(jbuf, "name", addl_field->name);
+        evel_enc_kv_string(jbuf, "value", addl_field->value);
+        evel_json_close_object(jbuf);
+        item_added = true;
+      }
+      addl_field_item = dlist_get_next(addl_field_item);
+    }
+    evel_json_close_list(jbuf);
+
+    /*************************************************************************/
+    /* If we've not written anything, rewind to before we opened the list.   */
+    /*************************************************************************/
+    if (!item_added)
+    {
+      evel_json_rewind(jbuf);
+    }
+  }
+
+  evel_enc_kv_opt_string(jbuf, "eventSourceHost", &event->event_source_host);
+  evel_enc_kv_opt_int(jbuf, "syslogFacility", &event->syslog_facility);
+  evel_enc_kv_opt_string(jbuf, "syslogProc", &event->syslog_proc);
+  evel_enc_kv_opt_int(jbuf, "syslogProcId", &event->syslog_proc_id);
+  evel_enc_kv_opt_string(jbuf, "syslogSData", &event->syslog_s_data);
+  evel_enc_kv_opt_int(jbuf, "syslogVer", &event->syslog_ver);
+  evel_json_close_object(jbuf);
+
+  EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_KERNEL == 0);
+  EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_USER == 1);
+  EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_MAIL == 2);
+  EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_SYSTEM_DAEMON == 3);
+  EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_SECURITY_AUTH == 4);
+  EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_INTERNAL == 5);
+  EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_LINE_PRINTER == 6);
+  EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_NETWORK_NEWS == 7);
+  EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_UUCP == 8);
+  EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_CLOCK_DAEMON == 9);
+  EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_SECURITY_AUTH2 == 10);
+  EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_FTP_DAEMON == 11);
+  EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_NTP == 12);
+  EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_LOG_AUDIT == 13);
+  EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_LOG_ALERT == 14);
+  EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_CLOCK_DAEMON2 == 15);
+  EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_LOCAL0 == 16);
+  EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_LOCAL1 == 17);
+  EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_LOCAL2 == 18);
+  EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_LOCAL3 == 19);
+  EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_LOCAL4 == 20);
+  EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_LOCAL5 == 21);
+  EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_LOCAL6 == 22);
+  EVEL_CT_ASSERT(EVEL_SYSLOG_FACILITY_LOCAL7 == 23);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Free a Syslog.
+ *
+ * Free off the Syslog supplied.  Will free all the contained allocated memory.
+ *
+ * @note It does not free the Syslog itself, since that may be part of a
+ * larger structure.
+ *****************************************************************************/
+void evel_free_syslog(EVENT_SYSLOG * event)
+{
+  SYSLOG_ADDL_FIELD * addl_field = NULL;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.  As an internal API we don't allow freeing NULL    */
+  /* events as we do on the public API.                                      */
+  /***************************************************************************/
+  assert(event != NULL);
+  assert(event->header.event_domain == EVEL_DOMAIN_SYSLOG);
+
+  /***************************************************************************/
+  /* Free all internal strings then the header itself.                       */
+  /***************************************************************************/
+  addl_field = dlist_pop_last(&event->additional_fields);
+  while (addl_field != NULL)
+  {
+    EVEL_DEBUG("Freeing Additional Field (%s, %s)",
+               addl_field->name,
+               addl_field->value);
+    free(addl_field->name);
+    free(addl_field->value);
+    free(addl_field);
+    addl_field = dlist_pop_last(&event->additional_fields);
+  }
+
+  evel_free_option_string(&event->event_source_host);
+  free(event->syslog_msg);
+  evel_free_option_string(&event->syslog_proc);
+  evel_free_option_string(&event->syslog_s_data);
+  free(event->syslog_tag);
+  evel_free_header(&event->header);
+
+  EVEL_EXIT();
+}
diff --git a/vnfs/VES/code/evel_library/evel_throttle.c b/vnfs/VES/code/evel_library/evel_throttle.c
new file mode 100644 (file)
index 0000000..866ece0
--- /dev/null
@@ -0,0 +1,2114 @@
+/**************************************************************************//**
+ * @file
+ * Event Manager
+ *
+ * Simple event manager that is responsible for taking events (Heartbeats,
+ * Faults and Measurements) from the ring-buffer and posting them to the API.
+ *
+ * License
+ * -------
+ *
+ * Copyright(c) <2016>, AT&T Intellectual Property.  All other rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:  This product includes
+ *    software developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <pthread.h>
+#include <search.h>
+
+#include "evel_throttle.h"
+
+/*****************************************************************************/
+/* The Event Throttling State for all domains, indexed by                    */
+/* ::EVEL_EVENT_DOMAINS, corresponding to JSON eventDomain.                  */
+/*                                                                           */
+/* A given domain is in a throttled state if ::evel_throttle_spec is         */
+/* non-NULL.                                                                 */
+/*****************************************************************************/
+static EVEL_THROTTLE_SPEC * evel_throttle_spec[EVEL_MAX_DOMAINS];
+
+/*****************************************************************************/
+/* The current measurement interval.  Default: MEASUREMENT_INTERVAL_UKNOWN.  */
+/* Must be protected by evel_measurement_interval_mutex.                     */
+/*****************************************************************************/
+static int evel_measurement_interval;
+
+/*****************************************************************************/
+/* Mutex protecting evel_measurement_interval from contention between an     */
+/* EVEL client reading it, and the EVEL event handler updating it.           */
+/*****************************************************************************/
+static pthread_mutex_t evel_measurement_interval_mutex;
+
+/*****************************************************************************/
+/* Flag stating that we have received a "provideThrottlingState" command.    */
+/* Set during JSON processing and cleared on sending the throttling state.   */
+/*****************************************************************************/
+static bool evel_provide_throttling_state;
+
+/*****************************************************************************/
+/* Holder for the "commandType" value during JSON processing.                */
+/*****************************************************************************/
+static char * evel_command_type_value;
+
+/*****************************************************************************/
+/* Holder for the "measurementInterval" value during JSON processing.        */
+/*****************************************************************************/
+static char * evel_measurement_interval_value;
+
+/*****************************************************************************/
+/* Holder for the "eventDomain" value during JSON processing.                */
+/*****************************************************************************/
+static char * evel_throttle_spec_domain_value;
+
+/*****************************************************************************/
+/* Decoded version of ::evel_throttle_spec_domain_value.                     */
+/*****************************************************************************/
+static EVEL_EVENT_DOMAINS evel_throttle_spec_domain;
+
+/*****************************************************************************/
+/* During JSON processing of a single throttling specification, we collect   */
+/* parameters in this working ::EVEL_THROTTLE_SPEC                           */
+/*****************************************************************************/
+static EVEL_THROTTLE_SPEC * evel_temp_throttle;
+
+/*****************************************************************************/
+/* State tracking our progress through the command list                      */
+/*****************************************************************************/
+EVEL_JSON_COMMAND_STATE evel_json_command_state;
+
+/*****************************************************************************/
+/* Debug strings for ::EVEL_JSON_COMMAND_STATE.                              */
+/*****************************************************************************/
+static const char * const evel_jcs_strings[EVEL_JCS_MAX] = {
+  "EVEL_JCS_START",
+  "EVEL_JCS_COMMAND_LIST",
+  "EVEL_JCS_COMMAND_LIST_ENTRY",
+  "EVEL_JCS_COMMAND",
+  "EVEL_JCS_SPEC",
+  "EVEL_JCS_FIELD_NAMES",
+  "EVEL_JCS_PAIRS_LIST",
+  "EVEL_JCS_PAIRS_LIST_ENTRY",
+  "EVEL_JCS_NV_PAIR_NAMES"
+};
+
+/*****************************************************************************/
+/* Debug strings for JSON token type.                                        */
+/*****************************************************************************/
+#define JSON_TOKEN_TYPES                (JSMN_PRIMITIVE + 1)
+static const char * const evel_json_token_strings[JSON_TOKEN_TYPES] = {
+  "JSMN_UNDEFINED",
+  "JSMN_OBJECT",
+  "JSMN_ARRAY",
+  "JSMN_STRING",
+  "JSMN_PRIMITIVE"
+};
+
+/*****************************************************************************/
+/* Debug strings for JSON domains.                                           */
+/*****************************************************************************/
+static const char * evel_domain_strings[EVEL_MAX_DOMAINS] = {
+  "internal",
+  "heartbeat",
+  "fault",
+  "measurementsForVfScaling",
+  "mobileFlow",
+  "report",
+  "serviceEvents",
+  "signaling",
+  "stateChange",
+  "syslog",
+  "other"
+};
+
+/*****************************************************************************/
+/* Local prototypes.                                                         */
+/*****************************************************************************/
+static void evel_throttle_finalize(EVEL_THROTTLE_SPEC * throttle_spec);
+static struct hsearch_data * evel_throttle_hash_create(DLIST * hash_keys);
+static void evel_throttle_free(EVEL_THROTTLE_SPEC * throttle_spec);
+static void evel_throttle_free_nv_pair(EVEL_SUPPRESSED_NV_PAIRS * nv_pairs);
+static void evel_init_json_stack(EVEL_JSON_STACK * json_stack,
+                                 const MEMORY_CHUNK * const chunk);
+static bool evel_stack_push(EVEL_JSON_STACK * const json_stack,
+                            const int num_required,
+                            const EVEL_JSON_STATE new_state);
+static void evel_stack_pop(EVEL_JSON_STACK * const json_stack);
+static void evel_stack_cleanup(EVEL_JSON_STACK * const json_stack);
+static char * evel_stack_strdup(const MEMORY_CHUNK * const chunk,
+                                const jsmntok_t * const token);
+static void evel_stack_store_key(EVEL_JSON_STACK * const json_stack,
+                                 const jsmntok_t * const token);
+static void evel_stack_store_value(EVEL_JSON_STACK * const json_stack,
+                                   const jsmntok_t * const token);
+static void evel_stack_store_item(EVEL_JSON_STACK * const json_stack,
+                                  const jsmntok_t * const token);
+static void evel_set_command_state(const EVEL_JSON_COMMAND_STATE new_state);
+static void evel_debug_token(const MEMORY_CHUNK * const chunk,
+                             const jsmntok_t * const token);
+static void evel_command_list_response(MEMORY_CHUNK * const post);
+static int evel_json_encode_throttle(char * const json, const int max_size);
+static int evel_json_encode_throttle_spec(char * const json,
+                                          const int max_size,
+                                          const EVEL_EVENT_DOMAINS domain);
+static int evel_json_encode_nv_pairs(char * const json,
+                                     const int max_size,
+                                     EVEL_SUPPRESSED_NV_PAIRS * nv_pairs);
+static void evel_close_command();
+static void evel_open_command();
+static void evel_set_throttling_spec();
+static void evel_set_measurement_interval();
+static void evel_open_throttle_spec();
+static void evel_close_throttle_spec();
+static EVEL_EVENT_DOMAINS evel_decode_domain(char * domain_value);
+static void evel_open_nv_pairs_list_entry();
+static void evel_close_nv_pairs_list_entry();
+static void evel_store_nv_pair_field_name(char * const value);
+static void evel_store_nv_pair_name(char * const item);
+static void evel_store_suppressed_field_name(char * const item);
+static EVEL_SUPPRESSED_NV_PAIRS * evel_get_last_nv_pairs();
+
+/**************************************************************************//**
+ * Return the current measurement interval provided by the Event Listener.
+ *
+ * @returns The current measurement interval
+ * @retval  EVEL_MEASUREMENT_INTERVAL_UKNOWN (0) - interval has not been
+ *          specified
+ *****************************************************************************/
+int evel_get_measurement_interval()
+{
+  int result;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Lock, read, unlock.                                                     */
+  /***************************************************************************/
+  pthread_mutex_lock(&evel_measurement_interval_mutex);
+  result = evel_measurement_interval;
+  pthread_mutex_unlock(&evel_measurement_interval_mutex);
+
+  EVEL_EXIT();
+
+  return result;
+}
+
+/**************************************************************************//**
+ * Return the ::EVEL_THROTTLE_SPEC for a given domain.
+ *
+ * @param domain        The domain for which to return state.
+ *****************************************************************************/
+EVEL_THROTTLE_SPEC * evel_get_throttle_spec(EVEL_EVENT_DOMAINS domain)
+{
+  EVEL_THROTTLE_SPEC * result;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(domain < EVEL_MAX_DOMAINS);
+
+  result = evel_throttle_spec[domain];
+
+  EVEL_EXIT();
+
+  return result;
+}
+
+/**************************************************************************//**
+ * Determine whether a field_name should be suppressed.
+ *
+ * @param throttle_spec Throttle specification for the domain being encoded.
+ * @param field_name    The field name to encoded or suppress.
+ * @return true if the field_name should be suppressed, false otherwise.
+ *****************************************************************************/
+bool evel_throttle_suppress_field(EVEL_THROTTLE_SPEC * throttle_spec,
+                                  const char * const field_name)
+{
+  bool suppress = false;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(field_name != NULL);
+
+  /***************************************************************************/
+  /* If the throttle spec and hash table exist, query the field_names table. */
+  /***************************************************************************/
+  if ((throttle_spec != NULL) && (throttle_spec->hash_field_names != NULL))
+  {
+    ENTRY hash_query;
+    ENTRY * hash_result;
+    hash_query.key = (char * const) field_name;
+    suppress = (hsearch_r(hash_query,
+                          FIND,
+                          &hash_result,
+                          throttle_spec->hash_field_names) != 0);
+  }
+
+  EVEL_EXIT();
+
+  return suppress;
+}
+
+/**************************************************************************//**
+ * Determine whether a name-value pair should be allowed (not suppressed).
+ *
+ * @param throttle_spec Throttle specification for the domain being encoded.
+ * @param field_name    The field name holding the name-value pairs.
+ * @param name          The name of the name-value pair to encoded or suppress.
+ * @return true if the name-value pair should be suppressed, false otherwise.
+ *****************************************************************************/
+bool evel_throttle_suppress_nv_pair(EVEL_THROTTLE_SPEC * throttle_spec,
+                                    const char * const field_name,
+                                    const char * const name)
+{
+  EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
+  bool hit = false;
+  bool suppress = false;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(field_name != NULL);
+  assert(name != NULL);
+
+  /***************************************************************************/
+  /* If the throttle spec and hash table exist, query the nv_pairs table.    */
+  /***************************************************************************/
+  if ((throttle_spec != NULL) && (throttle_spec->hash_nv_pairs_list != NULL))
+  {
+    ENTRY hash_query;
+    ENTRY * hash_result;
+    hash_query.key = (char * const) field_name;
+    hit = (hsearch_r(hash_query,
+                     FIND,
+                     &hash_result,
+                     throttle_spec->hash_nv_pairs_list) != 0);
+    if (hit)
+    {
+      nv_pairs = hash_result->data;
+    }
+  }
+
+  /***************************************************************************/
+  /* If we got a hit, and the nv_pairs and hash table exist, query the       */
+  /* nv_pairs table.                                                         */
+  /***************************************************************************/
+  if (hit && (nv_pairs != NULL) && (nv_pairs->hash_nv_pair_names != NULL))
+  {
+    ENTRY hash_query;
+    ENTRY * hash_result;
+    hash_query.key = (char * const) name;
+    suppress = (hsearch_r(hash_query,
+                          FIND,
+                          &hash_result,
+                          nv_pairs->hash_nv_pair_names) != 0);
+  }
+
+  EVEL_EXIT();
+
+  return suppress;
+}
+
+/**************************************************************************//**
+ * Initialize event throttling to the default state.
+ *
+ * Called from ::evel_initialize.
+ *****************************************************************************/
+void evel_throttle_initialize()
+{
+  int pthread_rc;
+  int ii;
+
+  EVEL_ENTER();
+
+  for (ii = 0; ii < EVEL_MAX_DOMAINS; ii++)
+  {
+    evel_throttle_spec[ii] = NULL;
+  }
+
+  pthread_rc = pthread_mutex_init(&evel_measurement_interval_mutex, NULL);
+  assert(pthread_rc == 0);
+
+  evel_measurement_interval = EVEL_MEASUREMENT_INTERVAL_UKNOWN;
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Clean up event throttling.
+ *
+ * Called from ::evel_terminate.
+ *****************************************************************************/
+void evel_throttle_terminate()
+{
+  int pthread_rc;
+  int ii;
+
+  EVEL_ENTER();
+
+  for (ii = 0; ii < EVEL_MAX_DOMAINS; ii++)
+  {
+    if (evel_throttle_spec[ii] != NULL)
+    {
+      evel_throttle_free(evel_throttle_spec[ii]);
+      evel_throttle_spec[ii] = NULL;
+    }
+  }
+
+  pthread_rc = pthread_mutex_destroy(&evel_measurement_interval_mutex);
+  assert(pthread_rc == 0);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Finalize a single ::EVEL_THROTTLE_SPEC.
+ *
+ * Now that the specification is collected, build hash tables to simplify the
+ * throttling itself.
+ *
+ * @param throttle_spec The ::EVEL_THROTTLE_SPEC to finalize.
+ *****************************************************************************/
+void evel_throttle_finalize(EVEL_THROTTLE_SPEC * throttle_spec)
+{
+  int nv_pairs_count;
+  DLIST_ITEM * dlist_item;
+  ENTRY * add_result;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(throttle_spec != NULL);
+
+  /***************************************************************************/
+  /* Populate the hash table for suppressed field names.                     */
+  /***************************************************************************/
+  throttle_spec->hash_field_names =
+             evel_throttle_hash_create(&throttle_spec->suppressed_field_names);
+
+  /***************************************************************************/
+  /* Create the hash table for suppressed nv pairs.                          */
+  /***************************************************************************/
+  nv_pairs_count = dlist_count(&throttle_spec->suppressed_nv_pairs_list);
+  if (nv_pairs_count > 0)
+  {
+    throttle_spec->hash_nv_pairs_list = calloc(1, sizeof(struct hsearch_data));
+    assert(throttle_spec->hash_nv_pairs_list != NULL);
+
+    /*************************************************************************/
+    /* Provide plenty of space in the table - see hcreate_r notes.           */
+    /*************************************************************************/
+    if (hcreate_r(nv_pairs_count * 2, throttle_spec->hash_nv_pairs_list) == 0)
+    {
+      EVEL_ERROR("Failed to create hash table");
+      free(throttle_spec->hash_nv_pairs_list);
+      throttle_spec->hash_nv_pairs_list = NULL;
+    }
+  }
+
+  /***************************************************************************/
+  /* Populate the hash tables under suppressed field names.                  */
+  /***************************************************************************/
+  dlist_item = dlist_get_first(&throttle_spec->suppressed_nv_pairs_list);
+  while (dlist_item != NULL)
+  {
+    EVEL_SUPPRESSED_NV_PAIRS * nv_pairs = dlist_item->item;
+    ENTRY hash_add;
+
+    /*************************************************************************/
+    /* Set the key to the string, and the item to the nv_pairs.              */
+    /*************************************************************************/
+    assert(nv_pairs != NULL);
+    hash_add.key = nv_pairs->nv_pair_field_name;
+    hash_add.data = nv_pairs;
+    hsearch_r(hash_add, ENTER, &add_result, throttle_spec->hash_nv_pairs_list);
+
+    /*************************************************************************/
+    /* Create the nv_pair_names hash since we're in here.                    */
+    /*************************************************************************/
+    nv_pairs->hash_nv_pair_names =
+      evel_throttle_hash_create(&nv_pairs->suppressed_nv_pair_names);
+
+    dlist_item = dlist_get_next(dlist_item);
+  }
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Create and populate a hash table from a DLIST of keys.
+ *
+ * @param hash_keys     Pointer to a DLIST of hash table keys.
+ * @return Pointer to the created hash-table, or NULL on failure.
+ *****************************************************************************/
+struct hsearch_data * evel_throttle_hash_create(DLIST * hash_keys)
+{
+  int key_count;
+  struct hsearch_data * hash_table;
+  ENTRY * add_result;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(hash_keys != NULL);
+
+  /***************************************************************************/
+  /* Count the keys and if there are any, populate the hash table with them. */
+  /***************************************************************************/
+  key_count = dlist_count(hash_keys);
+  if (key_count > 0)
+  {
+    EVEL_DEBUG("Populating table for %d keys", key_count);
+
+    hash_table = calloc(1, sizeof(struct hsearch_data));
+    assert(hash_table != NULL);
+
+    /*************************************************************************/
+    /* We need to leave plenty of space in the table - see hcreate_r notes.  */
+    /*************************************************************************/
+    if (hcreate_r(key_count * 2, hash_table) != 0)
+    {
+      DLIST_ITEM * dlist_item;
+      dlist_item = dlist_get_first(hash_keys);
+      while (dlist_item != NULL)
+      {
+        assert(dlist_item->item != NULL);
+
+        /*********************************************************************/
+        /* Set the key and data to the item, which is a string in this case. */
+        /*********************************************************************/
+        ENTRY hash_add;
+        hash_add.key = dlist_item->item;
+        hash_add.data = dlist_item->item;
+        hsearch_r(hash_add, ENTER, &add_result, hash_table);
+        dlist_item = dlist_get_next(dlist_item);
+      }
+    }
+    else
+    {
+      EVEL_ERROR("Failed to create hash table");
+      free(hash_table);
+      hash_table = NULL;
+    }
+  }
+  else
+  {
+    hash_table = NULL;
+  }
+
+  EVEL_EXIT();
+
+  return hash_table;
+}
+
+/**************************************************************************//**
+ * Free resources associated with a single ::EVEL_THROTTLE_SPEC.
+ *
+ * @param throttle_spec The ::EVEL_THROTTLE_SPEC to free.
+ *****************************************************************************/
+void evel_throttle_free(EVEL_THROTTLE_SPEC * throttle_spec)
+{
+  char * field_name;
+  EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(throttle_spec != NULL);
+
+  /***************************************************************************/
+  /* Free any hash tables.                                                   */
+  /***************************************************************************/
+  if (throttle_spec->hash_field_names != NULL)
+  {
+    hdestroy_r(throttle_spec->hash_field_names);
+    free(throttle_spec->hash_field_names);
+  }
+  if (throttle_spec->hash_nv_pairs_list != NULL)
+  {
+    hdestroy_r(throttle_spec->hash_nv_pairs_list);
+    free(throttle_spec->hash_nv_pairs_list);
+  }
+
+  /***************************************************************************/
+  /* Iterate through the linked lists, freeing memory.                       */
+  /***************************************************************************/
+  field_name = dlist_pop_last(&throttle_spec->suppressed_field_names);
+  while (field_name != NULL)
+  {
+    free(field_name);
+    field_name = dlist_pop_last(&throttle_spec->suppressed_field_names);
+  }
+
+  nv_pairs = dlist_pop_last(&throttle_spec->suppressed_nv_pairs_list);
+  while (nv_pairs != NULL)
+  {
+    evel_throttle_free_nv_pair(nv_pairs);
+    nv_pairs = dlist_pop_last(&throttle_spec->suppressed_nv_pairs_list);
+  }
+
+  free(throttle_spec);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Free resources associated with a single ::EVEL_SUPPRESSED_NV_PAIR.
+ *
+ * @param nv_pair       The ::EVEL_SUPPRESSED_NV_PAIR to free.
+ *****************************************************************************/
+void evel_throttle_free_nv_pair(EVEL_SUPPRESSED_NV_PAIRS * nv_pairs)
+{
+  char * suppressed_name;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(nv_pairs != NULL);
+
+  /***************************************************************************/
+  /* Free any hash tables.                                                   */
+  /***************************************************************************/
+  if (nv_pairs->hash_nv_pair_names != NULL)
+  {
+    hdestroy_r(nv_pairs->hash_nv_pair_names);
+    free(nv_pairs->hash_nv_pair_names);
+  }
+
+  /***************************************************************************/
+  /* Iterate through the linked lists, freeing memory.                       */
+  /***************************************************************************/
+  suppressed_name = dlist_pop_last(&nv_pairs->suppressed_nv_pair_names);
+  while (suppressed_name != NULL)
+  {
+    free(suppressed_name);
+    suppressed_name = dlist_pop_last(&nv_pairs->suppressed_nv_pair_names);
+  }
+  if (nv_pairs->nv_pair_field_name != NULL)
+  {
+    free(nv_pairs->nv_pair_field_name);
+  }
+  free(nv_pairs);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Handle a JSON response from the listener, as a list of tokens from JSMN.
+ *
+ * @param chunk         Memory chunk containing the JSON buffer.
+ * @param json_tokens   Array of tokens to handle.
+ * @param num_tokens    The number of tokens to handle.
+ * @param post          The memory chunk in which to place any resulting POST.
+ * @return true if the command was handled, false otherwise.
+ *****************************************************************************/
+bool evel_handle_command_list(const MEMORY_CHUNK * const chunk,
+                              const jsmntok_t * const json_tokens,
+                              const int num_tokens,
+                              MEMORY_CHUNK * const post)
+{
+  EVEL_JSON_STACK stack;
+  EVEL_JSON_STACK * json_stack = &stack;
+  EVEL_JSON_STACK_ENTRY * entry;
+
+  bool json_ok = true;
+  int token_index = 0;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(chunk != NULL);
+  assert(json_tokens != NULL);
+  assert(num_tokens < EVEL_MAX_RESPONSE_TOKENS);
+
+  /***************************************************************************/
+  /* Collect one top-level item.                                             */
+  /***************************************************************************/
+  evel_init_json_stack(json_stack, chunk);
+
+  /***************************************************************************/
+  /* Initialize JSON processing variables.                                   */
+  /***************************************************************************/
+  evel_provide_throttling_state = false;
+  evel_command_type_value = NULL;
+  evel_measurement_interval_value = NULL;
+  evel_throttle_spec_domain_value = NULL;
+  evel_throttle_spec_domain = EVEL_MAX_DOMAINS;
+  evel_temp_throttle = NULL;
+  evel_json_command_state = EVEL_JCS_START;
+
+  /***************************************************************************/
+  /* Loop through the tokens, keeping a stack of state representing the      */
+  /* nested JSON structure (see json_state). We also track our way through   */
+  /* the ::EVEL_JSON_COMMAND_STATE as we go.                                 */
+  /***************************************************************************/
+  while (json_ok && (token_index < num_tokens))
+  {
+    const jsmntok_t * const token = &json_tokens[token_index];
+
+    if (EVEL_DEBUG_ON())
+    {
+      evel_debug_token(chunk, token);
+    }
+
+    /*************************************************************************/
+    /* We may have popped or pushed, so always re-evaluate the stack entry.  */
+    /*************************************************************************/
+    entry = &json_stack->entry[json_stack->level];
+
+    switch(token->type)
+    {
+      case JSMN_OBJECT:
+        if ((entry->json_state == EVEL_JSON_ITEM) ||
+            (entry->json_state == EVEL_JSON_VALUE))
+        {
+          json_ok = evel_stack_push(json_stack, token->size, EVEL_JSON_KEY);
+        }
+        else
+        {
+          EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
+                     entry->json_state, token_index, token->type);
+          json_ok = false;
+        }
+        break;
+
+      case JSMN_ARRAY:
+        if ((entry->json_state == EVEL_JSON_ITEM) ||
+            (entry->json_state == EVEL_JSON_VALUE))
+        {
+          json_ok = evel_stack_push(json_stack, token->size, EVEL_JSON_ITEM);
+        }
+        else
+        {
+          EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
+                     entry->json_state, token_index, token->type);
+          json_ok = false;
+        }
+        break;
+
+      case JSMN_STRING:
+        if (entry->json_state == EVEL_JSON_KEY)
+        {
+          evel_stack_store_key(json_stack, token);
+        }
+        else if (entry->json_state == EVEL_JSON_VALUE)
+        {
+          evel_stack_store_value(json_stack, token);
+        }
+        else if (entry->json_state == EVEL_JSON_ITEM)
+        {
+          evel_stack_store_item(json_stack, token);
+        }
+        else
+        {
+          EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
+                     entry->json_state, token_index, token->type);
+          json_ok = false;
+        }
+        break;
+
+      case JSMN_PRIMITIVE:
+        if (entry->json_state == EVEL_JSON_VALUE)
+        {
+          evel_stack_store_value(json_stack, token);
+        }
+        else if (entry->json_state == EVEL_JSON_ITEM)
+        {
+          evel_stack_store_item(json_stack, token);
+        }
+        else
+        {
+          EVEL_ERROR("Unexpected JSON state %d at token %d (%d)",
+                     entry->json_state, token_index, token->type);
+          json_ok = false;
+        }
+        break;
+
+      case JSMN_UNDEFINED:
+      default:
+        EVEL_ERROR("Unexpected JSON format at token %d (%d)",
+                   token_index, token->type);
+        json_ok = false;
+        break;
+    }
+
+    /*************************************************************************/
+    /* Pop the stack if we're counted enough nested items.                   */
+    /*************************************************************************/
+    evel_stack_pop(json_stack);
+
+    token_index++;
+  }
+
+  /***************************************************************************/
+  /* Cleanup the stack - we may have exited without winding it back, if the  */
+  /* input was not well formed.                                              */
+  /***************************************************************************/
+  evel_stack_cleanup(json_stack);
+
+  /***************************************************************************/
+  /* We may want to generate and POST a response to the command list.        */
+  /***************************************************************************/
+  if (json_ok)
+  {
+    evel_command_list_response(post);
+  }
+
+  /***************************************************************************/
+  /* Make sure we're clean on exit.                                          */
+  /***************************************************************************/
+  assert(evel_command_type_value == NULL);
+  assert(evel_measurement_interval_value == NULL);
+  assert(evel_throttle_spec_domain_value == NULL);
+  assert(evel_throttle_spec_domain == EVEL_MAX_DOMAINS);
+  assert(evel_temp_throttle == NULL);
+
+  EVEL_EXIT();
+
+  return json_ok;
+}
+
+/**************************************************************************//**
+ * Copy a copy of an element, in string form.
+ *
+ * The caller must manage memory allocated for the copied string.
+ *
+ * @param chunk         Memory chunk containing the JSON buffer.
+ * @param token         The token to copy from.
+ * @return the copy of the element.
+ *****************************************************************************/
+char * evel_stack_strdup(const MEMORY_CHUNK * const chunk,
+                         const jsmntok_t * const token)
+{
+  char temp_char;
+  char * result;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Call strdup to copy the string, inserting a temporary \0 for the call.  */
+  /***************************************************************************/
+  temp_char = chunk->memory[token->end];
+  chunk->memory[token->end] = '\0';
+  result = strdup(chunk->memory + token->start);
+  assert(result != NULL);
+  chunk->memory[token->end] = temp_char;
+
+  EVEL_EXIT();
+
+  return result;
+}
+
+/**************************************************************************//**
+ * Copy a copy of an element, in string form.
+ *
+ * @param json_stack    The JSON stack to initialize.
+ * @param chunk         The underlying memory chunk used for parsing.
+ *****************************************************************************/
+void evel_init_json_stack(EVEL_JSON_STACK * json_stack,
+                          const MEMORY_CHUNK * const chunk)
+{
+  EVEL_JSON_STACK_ENTRY * entry;
+
+  EVEL_ENTER();
+
+  json_stack->level = 0;
+  entry = json_stack->entry;
+  entry->json_state = EVEL_JSON_ITEM;
+  entry->json_count = 0;
+  entry->num_required = 1;
+  entry->json_key = NULL;
+  json_stack->chunk = chunk;
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Push a new entry on the stack
+ *
+ * @param json_stack    The stack.
+ * @param num_required  The number of elements required.
+ * @param new_state     The state for the new entry.
+ * @return false if we cannot push onto the stack.
+ *****************************************************************************/
+bool evel_stack_push(EVEL_JSON_STACK * const json_stack,
+                     const int num_required,
+                     const EVEL_JSON_STATE new_state)
+{
+  EVEL_JSON_STACK_ENTRY * entry;
+  char * key;
+  bool result;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(json_stack != NULL);
+  assert(json_stack->level >= 0);
+  assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
+  assert((new_state == EVEL_JSON_ITEM) || (new_state == EVEL_JSON_KEY));
+
+  /***************************************************************************/
+  /* Check nesting depth, and stop processing if we hit the limit.           */
+  /***************************************************************************/
+  if ((json_stack->level + 1) >= EVEL_JSON_STACK_DEPTH)
+  {
+    EVEL_ERROR("JSON Nesting is too deep - stop processing");
+    result = false;
+    goto exit_label;
+  }
+
+  /***************************************************************************/
+  /* Evaluate cases where we recurse and are interested in the contents.     */
+  /***************************************************************************/
+  entry = &json_stack->entry[json_stack->level];
+  key = entry->json_key;
+
+  /***************************************************************************/
+  /* Note that this is the key before we drop a level.                       */
+  /***************************************************************************/
+  if (key != NULL)
+  {
+    EVEL_DEBUG("Push with key: %s", key);
+
+    switch (evel_json_command_state)
+    {
+      case EVEL_JCS_START:
+        if (strcmp(key, "commandList") == 0)
+        {
+          evel_set_command_state(EVEL_JCS_COMMAND_LIST);
+        }
+        break;
+
+      case EVEL_JCS_COMMAND_LIST_ENTRY:
+        if (strcmp(key, "command") == 0)
+        {
+          evel_open_command();
+          evel_set_command_state(EVEL_JCS_COMMAND);
+        }
+        break;
+
+      case EVEL_JCS_COMMAND:
+        if (strcmp(key, "eventDomainThrottleSpecification") == 0)
+        {
+          evel_open_throttle_spec();
+          evel_set_command_state(EVEL_JCS_SPEC);
+        }
+        break;
+
+      case EVEL_JCS_SPEC:
+        if (strcmp(key, "suppressedFieldNames") == 0)
+        {
+          evel_set_command_state(EVEL_JCS_FIELD_NAMES);
+        }
+        else if (strcmp(key, "suppressedNvPairsList") == 0)
+        {
+          evel_set_command_state(EVEL_JCS_PAIRS_LIST);
+        }
+        break;
+
+      case EVEL_JCS_PAIRS_LIST_ENTRY:
+        if (strcmp(key, "suppressedNvPairNames") == 0)
+        {
+          evel_set_command_state(EVEL_JCS_NV_PAIR_NAMES);
+        }
+        break;
+
+      case EVEL_JCS_FIELD_NAMES:
+      case EVEL_JCS_PAIRS_LIST:
+      case EVEL_JCS_NV_PAIR_NAMES:
+      default:
+        EVEL_ERROR("Unexpected JSON key %s in state %d",
+                   key,
+                   evel_json_command_state);
+        break;
+    }
+  }
+  else
+  {
+    EVEL_DEBUG("Push with no key");
+
+    /*************************************************************************/
+    /* If we're pushing without a key, then we're in an array.  We switch    */
+    /* state based on the existing state and stack level.                    */
+    /*************************************************************************/
+    const int COMMAND_LIST_LEVEL = 2;
+    const int NV_PAIRS_LIST_LEVEL = 6;
+
+    if ((evel_json_command_state == EVEL_JCS_PAIRS_LIST) &&
+        (json_stack->level == NV_PAIRS_LIST_LEVEL))
+    {
+      /***********************************************************************/
+      /* We are entering an object within the "suppressedNvPairsList" array. */
+      /***********************************************************************/
+      evel_open_nv_pairs_list_entry();
+      evel_set_command_state(EVEL_JCS_PAIRS_LIST_ENTRY);
+    }
+
+    if ((evel_json_command_state == EVEL_JCS_COMMAND_LIST) &&
+        (json_stack->level == COMMAND_LIST_LEVEL))
+    {
+      /***********************************************************************/
+      /* We are entering an object within the "commandList" array.           */
+      /***********************************************************************/
+      evel_set_command_state(EVEL_JCS_COMMAND_LIST_ENTRY);
+    }
+  }
+
+  /***************************************************************************/
+  /* Push the stack and initialize the entry.                                */
+  /***************************************************************************/
+  json_stack->level++;
+  entry++;
+  EVEL_DEBUG("Stack Push -> %d", json_stack->level);
+  entry = &json_stack->entry[json_stack->level];
+  entry->json_count = 0;
+  entry->num_required = num_required;
+  entry->json_state = new_state;
+  entry->json_key = NULL;
+  result = true;
+
+exit_label:
+
+  EVEL_EXIT();
+
+  return result;
+}
+
+/**************************************************************************//**
+ * Pop any stack entries which have collected the required number of items.
+ *
+ * @param json_stack    The stack.
+ *****************************************************************************/
+void evel_stack_pop(EVEL_JSON_STACK * const json_stack)
+{
+  EVEL_JSON_STACK_ENTRY * entry;
+  char * key;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(json_stack != NULL);
+  assert(json_stack->level >= 0);
+  assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
+
+  entry = &json_stack->entry[json_stack->level];
+  while ((json_stack->level > 0) && (entry->json_count == entry->num_required))
+  {
+    key = entry->json_key;
+
+    switch (evel_json_command_state)
+    {
+      case EVEL_JCS_COMMAND_LIST:
+        evel_set_command_state(EVEL_JCS_START);
+        break;
+
+      case EVEL_JCS_COMMAND_LIST_ENTRY:
+        evel_set_command_state(EVEL_JCS_COMMAND_LIST);
+        break;
+
+      case EVEL_JCS_COMMAND:
+        evel_close_command();
+        evel_set_command_state(EVEL_JCS_COMMAND_LIST_ENTRY);
+        break;
+
+      case EVEL_JCS_SPEC:
+        evel_close_throttle_spec();
+        evel_set_command_state(EVEL_JCS_COMMAND);
+        break;
+
+      case EVEL_JCS_FIELD_NAMES:
+        evel_set_command_state(EVEL_JCS_SPEC);
+        break;
+
+      case EVEL_JCS_PAIRS_LIST:
+        evel_set_command_state(EVEL_JCS_SPEC);
+        break;
+
+      case EVEL_JCS_PAIRS_LIST_ENTRY:
+        evel_close_nv_pairs_list_entry();
+        evel_set_command_state(EVEL_JCS_PAIRS_LIST);
+        break;
+
+      case EVEL_JCS_NV_PAIR_NAMES:
+        evel_set_command_state(EVEL_JCS_PAIRS_LIST_ENTRY);
+        break;
+
+      default:
+        break;
+    }
+
+    /*************************************************************************/
+    /* Free off any key that was duplicated and stored.                      */
+    /*************************************************************************/
+    if (key != NULL)
+    {
+      free(key);
+      entry->json_key = NULL;
+    }
+
+    /*************************************************************************/
+    /* We just reached the required number of key-value pairs or items, so   */
+    /* pop the stack.                                                        */
+    /*************************************************************************/
+    json_stack->level--;
+    entry--;
+
+    EVEL_DEBUG("Stack Pop  -> %d", json_stack->level);
+
+    /*************************************************************************/
+    /* We just completed collection of an ITEM (within an ARRAY) or a VALUE  */
+    /* (within an OBJECT).  Either way, we need to count it.                 */
+    /*************************************************************************/
+    entry->json_count++;
+
+    /*************************************************************************/
+    /* If we just completed a VALUE, then we expect the next element to be a */
+    /* key, if there is a next element.                                      */
+    /*************************************************************************/
+    if (entry->json_state == EVEL_JSON_VALUE)
+    {
+      entry->json_state = EVEL_JSON_KEY;
+    }
+  }
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Pop all stack entries, freeing any memory as we go.
+ *
+ * @param json_stack    The stack.
+ *****************************************************************************/
+void evel_stack_cleanup(EVEL_JSON_STACK * const json_stack)
+{
+  EVEL_JSON_STACK_ENTRY * entry;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(json_stack != NULL);
+  assert(json_stack->level >= 0);
+  assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
+
+  entry = &json_stack->entry[json_stack->level];
+  while ((json_stack->level > 0))
+  {
+    /*************************************************************************/
+    /* Free off any key that was duplicated and stored.                      */
+    /*************************************************************************/
+    if (entry->json_key != NULL)
+    {
+      free(entry->json_key);
+      entry->json_key = NULL;
+    }
+
+    /*************************************************************************/
+    /* We just reached the required number of key-value pairs or items, so   */
+    /* pop the stack.                                                        */
+    /*************************************************************************/
+    json_stack->level--;
+    entry--;
+  }
+
+  /***************************************************************************/
+  /* If we hit EVEL_JSON_STACK_DEPTH, we exit the loop and can leave these   */
+  /* values hanging - so clean them up.                                      */
+  /***************************************************************************/
+  if (evel_command_type_value != NULL)
+  {
+    free(evel_command_type_value);
+    evel_command_type_value = NULL;
+  }
+  if (evel_measurement_interval_value != NULL)
+  {
+    free(evel_measurement_interval_value);
+    evel_measurement_interval_value = NULL;
+  }
+  if (evel_throttle_spec_domain_value != NULL)
+  {
+    free(evel_throttle_spec_domain_value);
+    evel_throttle_spec_domain_value = NULL;
+  }
+  evel_throttle_spec_domain = EVEL_MAX_DOMAINS;
+  if (evel_temp_throttle != NULL)
+  {
+    evel_throttle_free(evel_temp_throttle);
+    evel_temp_throttle = NULL;
+  }
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Store a key in the JSON stack.
+ *
+ * We always store the most recent key at each level in the stack.
+ *
+ * @param json_stack    The stack.
+ * @param token         The token holding the key.
+ *****************************************************************************/
+void evel_stack_store_key(EVEL_JSON_STACK * const json_stack,
+                          const jsmntok_t * const token)
+{
+  EVEL_JSON_STACK_ENTRY * entry;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(json_stack != NULL);
+  assert(json_stack->level >= 0);
+  assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
+
+  /***************************************************************************/
+  /* Free any previously stored key, replacing it with the new one.          */
+  /***************************************************************************/
+  entry = &json_stack->entry[json_stack->level];
+  if (entry->json_key != NULL)
+  {
+    free(entry->json_key);
+  }
+  entry->json_key = evel_stack_strdup(json_stack->chunk, token);
+
+  /***************************************************************************/
+  /* Switch state to collecting the corresponding value.                     */
+  /***************************************************************************/
+  entry->json_state = EVEL_JSON_VALUE;
+
+  EVEL_DEBUG("Stored key: %s", entry->json_key);
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Store a value in the JSON stack.
+ *
+ * @param json_stack    The stack.
+ * @param token         The token holding the value.
+ *****************************************************************************/
+void evel_stack_store_value(EVEL_JSON_STACK * const json_stack,
+                            const jsmntok_t * const token)
+{
+  EVEL_JSON_STACK_ENTRY * entry;
+  char * value;
+  bool stored;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(json_stack != NULL);
+  assert(json_stack->level >= 0);
+  assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
+
+  /***************************************************************************/
+  /* Based on the (key, state), work out whether we're expecting a value,    */
+  /* then store or ignore it as required.                                    */
+  /***************************************************************************/
+  entry = &json_stack->entry[json_stack->level];
+  value = evel_stack_strdup(json_stack->chunk, token);
+  stored = false;
+  EVEL_DEBUG("Store value: %s", value);
+
+  switch (evel_json_command_state)
+  {
+    case EVEL_JCS_COMMAND:
+      if (strcmp(entry->json_key, "commandType") == 0)
+      {
+        evel_command_type_value = value;
+        stored = true;
+      }
+      else if (strcmp(entry->json_key, "measurementInterval") == 0)
+      {
+        evel_measurement_interval_value = value;
+        stored = true;
+      }
+      break;
+
+    case EVEL_JCS_SPEC:
+      if (strcmp(entry->json_key, "eventDomain") == 0)
+      {
+        evel_throttle_spec_domain_value = value;
+        stored = true;
+      }
+      break;
+
+    case EVEL_JCS_PAIRS_LIST_ENTRY:
+      if (strcmp(entry->json_key, "nvPairFieldName") == 0)
+      {
+        evel_store_nv_pair_field_name(value);
+        stored = true;
+      }
+      break;
+
+    default:
+      EVEL_DEBUG("Ignoring value in state: %s",
+                 evel_jcs_strings[evel_json_command_state]);
+      break;
+  }
+
+  if (!stored)
+  {
+    EVEL_DEBUG("Ignored value: %s", value);
+    free(value);
+  }
+
+  /***************************************************************************/
+  /* Switch state to another key.                                            */
+  /***************************************************************************/
+  entry->json_state = EVEL_JSON_KEY;
+
+  /***************************************************************************/
+  /* Count the key-value pair.                                               */
+  /***************************************************************************/
+  entry->json_count++;
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Store an item in the JSON stack - a string or primitive in an array.
+ *
+ * @param json_stack    The stack.
+ * @param token         The token holding the item.
+ *****************************************************************************/
+void evel_stack_store_item(EVEL_JSON_STACK * const json_stack,
+                           const jsmntok_t * const token)
+{
+  EVEL_JSON_STACK_ENTRY * entry;
+  char * item;
+  bool stored;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(json_stack != NULL);
+  assert(json_stack->level >= 0);
+  assert(json_stack->level < EVEL_JSON_STACK_DEPTH);
+
+  /***************************************************************************/
+  /* Based on the state, work out whether we're expecting an item, then      */
+  /* store or ignore it as required.                                         */
+  /***************************************************************************/
+  entry = &json_stack->entry[json_stack->level];
+  item = evel_stack_strdup(json_stack->chunk, token);
+  stored = false;
+  EVEL_DEBUG("Store item: %s", item);
+
+  switch (evel_json_command_state)
+  {
+    case EVEL_JCS_NV_PAIR_NAMES:
+      evel_store_nv_pair_name(item);
+      stored = true;
+      break;
+
+    case EVEL_JCS_FIELD_NAMES:
+      evel_store_suppressed_field_name(item);
+      stored = true;
+      break;
+
+    default:
+      EVEL_DEBUG("Ignoring item in state: %s",
+                 evel_jcs_strings[evel_json_command_state]);
+      break;
+  }
+
+  if (!stored)
+  {
+    EVEL_DEBUG("Ignored item: %s", item);
+    free(item);
+  }
+
+  /***************************************************************************/
+  /* We need another item.  This is purely defensive.                        */
+  /***************************************************************************/
+  entry->json_state = EVEL_JSON_ITEM;
+
+  /***************************************************************************/
+  /* Count the item.                                                         */
+  /***************************************************************************/
+  entry->json_count++;
+}
+
+/**************************************************************************//**
+ * Set the JSON command state to a new value.
+ *
+ * @param new_state     The new state to set.
+ *****************************************************************************/
+void evel_set_command_state(const EVEL_JSON_COMMAND_STATE new_state)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(evel_json_command_state < EVEL_JCS_MAX);
+  assert(new_state < EVEL_JCS_MAX);
+
+  /***************************************************************************/
+  /* Provide common debug, and set the new state.                            */
+  /***************************************************************************/
+  EVEL_DEBUG("Command State: %s -> %s",
+             evel_jcs_strings[evel_json_command_state],
+             evel_jcs_strings[new_state]);
+  evel_json_command_state = new_state;
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Produce debug output from a JSON token.
+ *
+ * @param chunk         Memory chunk containing the JSON buffer.
+ * @param token         Token to dump.
+ *****************************************************************************/
+void evel_debug_token(const MEMORY_CHUNK * const chunk,
+                      const jsmntok_t * const token)
+{
+  char temp_char;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(token->type > 0);
+  assert(token->type < JSON_TOKEN_TYPES);
+
+  /***************************************************************************/
+  /* Log the token, leaving it in the state in which it started.             */
+  /***************************************************************************/
+  temp_char = chunk->memory[token->end];
+  chunk->memory[token->end] = '\0';
+  EVEL_DEBUG("JSON token type: %s", evel_json_token_strings[token->type]);
+  EVEL_DEBUG("JSON token: %s", chunk->memory + token->start);
+  chunk->memory[token->end] = temp_char;
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Post a response to the commandList.
+ *
+ * @param post          Memory chunk in which to post a response.
+ *****************************************************************************/
+void evel_command_list_response(MEMORY_CHUNK * const post)
+{
+  char * json_post;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(post != NULL);
+  assert(post->memory == NULL);
+
+  if (evel_provide_throttling_state)
+  {
+    EVEL_DEBUG("Provide throttling state");
+
+    /*************************************************************************/
+    /* Encode the response, making it printf-able for debug.                 */
+    /*************************************************************************/
+    json_post = malloc(EVEL_MAX_JSON_BODY);
+    assert(json_post != NULL);
+    post->size = evel_json_encode_throttle(json_post, EVEL_MAX_JSON_BODY - 1);
+    post->memory = json_post;
+    post->memory[post->size] = '\0';
+    evel_provide_throttling_state = false;
+  }
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Encode the full throttling specification according to AT&T's schema.
+ *
+ * @param json          Pointer to where to store the JSON encoded data.
+ * @param max_size      Size of storage available in json_body.
+ * @returns Number of bytes actually written.
+ *****************************************************************************/
+int evel_json_encode_throttle(char * const json, const int max_size)
+{
+  bool throttled;
+  int domain;
+  int offset;
+  bool domain_added;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(json != NULL);
+  assert(max_size > 0);
+
+  /***************************************************************************/
+  /* Work out if we're throttled.                                            */
+  /***************************************************************************/
+  throttled = false;
+  for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++)
+  {
+    if (evel_throttle_spec[domain] != NULL)
+    {
+      throttled = true;
+    }
+  }
+
+  /***************************************************************************/
+  /* Encode the response.                                                    */
+  /***************************************************************************/
+  offset = 0;
+  offset += snprintf(json + offset, max_size - offset,
+                     "{\"eventThrottlingState\": {");
+  offset += snprintf(json + offset, max_size - offset,
+                     "\"eventThrottlingMode\": \"%s\"",
+                     throttled ? "throttled" : "normal");
+  if (throttled)
+  {
+    offset += snprintf(json + offset, max_size - offset,
+                       ", \"eventDomainThrottleSpecificationList\": [");
+
+    domain_added = false;
+    for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++)
+    {
+      if (evel_throttle_spec[domain] != NULL)
+      {
+        if (domain_added)
+        {
+          offset += snprintf(json + offset, max_size - offset, ", ");
+        }
+
+        offset += evel_json_encode_throttle_spec(json + offset,
+                                                 max_size - offset,
+                                                 domain);
+        domain_added = true;
+      }
+    }
+
+    offset += snprintf(json + offset, max_size - offset, "]");
+  }
+
+  offset += snprintf(json + offset, max_size - offset, "}}");
+
+  EVEL_EXIT();
+
+  return offset;
+}
+
+/**************************************************************************//**
+ * Encode a throttling specification for a domain.
+ *
+ * @param json          Pointer to where to store the JSON encoded data.
+ * @param max_size      Size of storage available in json_body.
+ * @returns Number of bytes actually written.
+ *****************************************************************************/
+int evel_json_encode_throttle_spec(char * const json,
+                                   const int max_size,
+                                   const EVEL_EVENT_DOMAINS domain)
+{
+  int offset;
+  EVEL_THROTTLE_SPEC * throttle_spec;
+  DLIST_ITEM * dlist_item;
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(domain >= EVEL_DOMAIN_FAULT);
+  assert(domain < EVEL_MAX_DOMAINS);
+  assert(evel_throttle_spec[domain] != NULL);
+
+  throttle_spec = evel_throttle_spec[domain];
+
+  /***************************************************************************/
+  /* Encode the domain.                                                      */
+  /***************************************************************************/
+  offset = 0;
+  offset += snprintf(json + offset, max_size - offset,
+                     "{");
+  offset += snprintf(json + offset, max_size - offset,
+                     "\"eventDomain\": \"%s\"",
+                     evel_domain_strings[domain]);
+
+  /***************************************************************************/
+  /* Encode "suppressedFieldNames".                                          */
+  /***************************************************************************/
+  dlist_item = dlist_get_first(&throttle_spec->suppressed_field_names);
+  if (dlist_item != NULL)
+  {
+    offset += snprintf(json + offset, max_size - offset,
+                       ", \"suppressedFieldNames\": [");
+    while (dlist_item != NULL)
+    {
+      char * suppressed_field = dlist_item->item;
+      assert(suppressed_field != NULL);
+
+      offset += snprintf(json + offset, max_size - offset,
+                         "\"%s\"", suppressed_field);
+      dlist_item = dlist_get_next(dlist_item);
+      if (dlist_item != NULL)
+      {
+        offset += snprintf(json + offset, max_size - offset, ", ");
+      }
+    }
+
+    offset += snprintf(json + offset, max_size - offset, "]");
+  }
+
+  /***************************************************************************/
+  /* Encode "suppressedNvPairsList".                                         */
+  /***************************************************************************/
+  dlist_item = dlist_get_first(&throttle_spec->suppressed_nv_pairs_list);
+  if (dlist_item != NULL)
+  {
+    offset += snprintf(json + offset, max_size - offset,
+                       ", \"suppressedNvPairsList\": [");
+    while (dlist_item != NULL)
+    {
+      offset += evel_json_encode_nv_pairs(json + offset,
+                                          max_size - offset,
+                                          dlist_item->item);
+      dlist_item = dlist_get_next(dlist_item);
+      if (dlist_item != NULL)
+      {
+        offset += snprintf(json + offset, max_size - offset, ", ");
+      }
+    }
+
+    offset += snprintf(json + offset, max_size - offset, "]");
+  }
+
+  offset += snprintf(json + offset, max_size - offset, "}");
+
+  EVEL_EXIT();
+
+  return offset;
+}
+
+/**************************************************************************//**
+ * Encode a single "suppressedNvPairsListEntry".
+ *
+ * @param json          Pointer to where to store the JSON encoded data.
+ * @param max_size      Size of storage available in json_body.
+ * @returns Number of bytes actually written.
+ *****************************************************************************/
+int evel_json_encode_nv_pairs(char * const json,
+                              const int max_size,
+                              EVEL_SUPPRESSED_NV_PAIRS * nv_pairs)
+{
+  DLIST_ITEM * dlist_item;
+  char * name;
+  int offset;
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(nv_pairs != NULL);
+  assert(nv_pairs->nv_pair_field_name != NULL);
+  assert(!dlist_is_empty(&nv_pairs->suppressed_nv_pair_names));
+
+  /***************************************************************************/
+  /* Encode it.                                                              */
+  /***************************************************************************/
+  offset = 0;
+  offset += snprintf(json + offset, max_size - offset, "{");
+  offset += snprintf(json + offset, max_size - offset,
+                     "\"nvPairFieldName\": \"%s\"",
+                     nv_pairs->nv_pair_field_name);
+  dlist_item = dlist_get_first(&nv_pairs->suppressed_nv_pair_names);
+  offset += snprintf(json + offset, max_size - offset,
+                     ", \"suppressedNvPairNames\": [");
+  while (dlist_item != NULL)
+  {
+    name = dlist_item->item;
+    assert(name != NULL);
+    offset += snprintf(json + offset, max_size - offset, "\"%s\"", name);
+    dlist_item = dlist_get_next(dlist_item);
+    if (dlist_item != NULL)
+    {
+      offset += snprintf(json + offset, max_size - offset, ", ");
+    }
+  }
+  offset += snprintf(json + offset, max_size - offset, "]");
+  offset += snprintf(json + offset, max_size - offset, "}");
+
+  EVEL_EXIT();
+
+  return offset;
+}
+
+/**************************************************************************//**
+ * Method called when we open a "command" object.
+ *****************************************************************************/
+void evel_open_command()
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Make some assertions.                                                   */
+  /***************************************************************************/
+  assert(evel_command_type_value == NULL);
+  assert(evel_measurement_interval_value == NULL);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Method called when we close a "command" object.
+ *****************************************************************************/
+void evel_close_command()
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* If a commandType was provided, fan out and handle it now what we have   */
+  /* fathered all related information.                                       */
+  /*                                                                         */
+  /* Note that we handle throttling specification and measurement interval   */
+  /* updates immediately on closing the command (not the list). We could     */
+  /* reject *all* commands in a list if any of them are invalid, but we are  */
+  /* take a best-effort strategy here - any valid-looking command gets       */
+  /* implemented regardless of what follows.                                 */
+  /***************************************************************************/
+  if (evel_command_type_value != NULL)
+  {
+    EVEL_DEBUG("Closing command %s", evel_command_type_value);
+
+    if (strcmp(evel_command_type_value, "provideThrottlingState") == 0)
+    {
+      evel_provide_throttling_state = true;
+    }
+    else if (strcmp(evel_command_type_value, "throttlingSpecification") == 0)
+    {
+      evel_set_throttling_spec();
+    }
+    else if (strcmp(evel_command_type_value, "measurementIntervalChange") == 0)
+    {
+      evel_set_measurement_interval();
+    }
+    else
+    {
+      EVEL_ERROR("Ignoring unknown commandType: %s\n",
+                 evel_command_type_value);
+    }
+
+    /*************************************************************************/
+    /* Free the captured "commandType" value.                                */
+    /*************************************************************************/
+    free(evel_command_type_value);
+    evel_command_type_value = NULL;
+  }
+
+  /***************************************************************************/
+  /* There could be an unused working throttle spec at this point - if the   */
+  /* "throttlingSpecification" commandType was not provided, or an invalid   */
+  /* domain was provided, or was not provided at all.                        */
+  /***************************************************************************/
+  if (evel_temp_throttle != NULL)
+  {
+    evel_throttle_free(evel_temp_throttle);
+    evel_temp_throttle = NULL;
+  }
+
+  /***************************************************************************/
+  /* Similarly, the domain could be set.                                     */
+  /***************************************************************************/
+  evel_throttle_spec_domain = EVEL_MAX_DOMAINS;
+
+  /***************************************************************************/
+  /* There could be an unused measurement interval value at this point - if  */
+  /* the "measurementIntervalChange" command was not provided.               */
+  /***************************************************************************/
+  if (evel_measurement_interval_value != NULL)
+  {
+    free(evel_measurement_interval_value);
+    evel_measurement_interval_value = NULL;
+  }
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the provided throttling specification, when the command closes.
+ *****************************************************************************/
+void evel_set_throttling_spec()
+{
+  EVEL_ENTER();
+
+  if ((evel_throttle_spec_domain >= 0) &&
+      (evel_throttle_spec_domain < EVEL_MAX_DOMAINS))
+  {
+    EVEL_DEBUG("Updating throttle spec for domain: %s",
+               evel_domain_strings[evel_throttle_spec_domain]);
+
+    /*************************************************************************/
+    /* Free off the previous throttle specification for the domain, if there */
+    /* is one.                                                               */
+    /*************************************************************************/
+    if (evel_throttle_spec[evel_throttle_spec_domain] != NULL)
+    {
+      evel_throttle_free(evel_throttle_spec[evel_throttle_spec_domain]);
+    }
+
+    /*************************************************************************/
+    /* Finalize the working throttling spec, if there is one.                */
+    /*************************************************************************/
+    if (evel_temp_throttle != NULL)
+    {
+      evel_throttle_finalize(evel_temp_throttle);
+    }
+
+    /*************************************************************************/
+    /* Replace the throttle specification for the domain with the working    */
+    /* throttle specification.  This could be NULL, if an empty throttle     */
+    /* specification has been received for a domain.                         */
+    /*************************************************************************/
+    evel_throttle_spec[evel_throttle_spec_domain] = evel_temp_throttle;
+    evel_temp_throttle = NULL;
+  }
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Set the provided measurement interval, when the command closes.
+ *****************************************************************************/
+void evel_set_measurement_interval()
+{
+  EVEL_ENTER();
+
+  if (evel_measurement_interval_value != NULL)
+  {
+    const long int value = strtol(evel_measurement_interval_value, NULL, 10);
+
+    if ((value >= 0) && (value <= INT_MAX))
+    {
+      /***********************************************************************/
+      /* Lock, update, unlock.                                               */
+      /***********************************************************************/
+      EVEL_DEBUG("Updating measurement interval to %d\n", value);
+
+      pthread_mutex_lock(&evel_measurement_interval_mutex);
+      evel_measurement_interval = value;
+      pthread_mutex_unlock(&evel_measurement_interval_mutex);
+    }
+    else
+    {
+      EVEL_ERROR("Ignoring invalid measurement interval: %s",
+                 evel_measurement_interval_value);
+    }
+  }
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Method called when we open an "eventDomainThrottleSpecification" object.
+ *****************************************************************************/
+void evel_open_throttle_spec()
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(evel_throttle_spec_domain_value == NULL);
+  assert(evel_throttle_spec_domain == EVEL_MAX_DOMAINS);
+  assert(evel_temp_throttle == NULL);
+
+  /***************************************************************************/
+  /* Allocate and initialize an ::EVEL_THROTTLE_SPEC in which to hold        */
+  /* captured JSON elements.                                                 */
+  /***************************************************************************/
+  evel_temp_throttle = malloc(sizeof(EVEL_THROTTLE_SPEC));
+  assert(evel_temp_throttle != NULL);
+  dlist_initialize(&evel_temp_throttle->suppressed_field_names);
+  dlist_initialize(&evel_temp_throttle->suppressed_nv_pairs_list);
+  evel_temp_throttle->hash_field_names = NULL;
+  evel_temp_throttle->hash_nv_pairs_list = NULL;
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Method called when we close an "eventDomainThrottleSpecification" object.
+ *****************************************************************************/
+void evel_close_throttle_spec()
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Decode, free and blank a captured event domain value.                   */
+  /***************************************************************************/
+  if (evel_throttle_spec_domain_value != NULL)
+  {
+    evel_throttle_spec_domain =
+                           evel_decode_domain(evel_throttle_spec_domain_value);
+    free(evel_throttle_spec_domain_value);
+    evel_throttle_spec_domain_value = NULL;
+  }
+
+  /***************************************************************************/
+  /* Free off an empty working throttle spec, to stop it being used.  This   */
+  /* state should be represented by a NULL pointer for the domain.           */
+  /***************************************************************************/
+  if (evel_temp_throttle != NULL)
+  {
+    if (dlist_is_empty(&evel_temp_throttle->suppressed_field_names) &&
+        dlist_is_empty(&evel_temp_throttle->suppressed_nv_pairs_list))
+    {
+      free(evel_temp_throttle);
+      evel_temp_throttle = NULL;
+    }
+  }
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Convert a value for an "eventDomain" into an ::EVEL_EVENT_DOMAINS.
+ *
+ * @param domain_value  The domain string value to decode.
+ * @returns The matching ::EVEL_EVENT_DOMAINS, or ::EVEL_MAX_DOMAINS on error.
+ *****************************************************************************/
+EVEL_EVENT_DOMAINS evel_decode_domain(char * domain_value)
+{
+  EVEL_EVENT_DOMAINS result;
+  int ii;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(domain_value != NULL);
+
+  result = EVEL_MAX_DOMAINS;
+  for (ii = EVEL_DOMAIN_FAULT; ii < EVEL_MAX_DOMAINS; ii++)
+  {
+    assert(evel_domain_strings[ii] != NULL);
+    if (strcmp(evel_domain_strings[ii], domain_value) == 0)
+    {
+      result = ii;
+    }
+  }
+
+  EVEL_EXIT();
+
+  return result;
+}
+
+/**************************************************************************//**
+ * Method called when we open a "suppressedNvPairsListEntry" object.
+ *****************************************************************************/
+void evel_open_nv_pairs_list_entry()
+{
+  EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(evel_temp_throttle != NULL);
+
+  /***************************************************************************/
+  /* Allocate and initialize an ::EVEL_SUPPRESSED_NV_PAIRS, and add it to    */
+  /* the list.                                                               */
+  /***************************************************************************/
+  nv_pairs = malloc(sizeof(EVEL_SUPPRESSED_NV_PAIRS));
+  assert(nv_pairs != NULL);
+  nv_pairs->nv_pair_field_name = NULL;
+  dlist_initialize(&nv_pairs->suppressed_nv_pair_names);
+  nv_pairs->hash_nv_pair_names = NULL;
+  dlist_push_last(&evel_temp_throttle->suppressed_nv_pairs_list, nv_pairs);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Method called when we close a "suppressedNvPairsListEntry" object.
+ *****************************************************************************/
+void evel_close_nv_pairs_list_entry()
+{
+  EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
+  EVEL_SUPPRESSED_NV_PAIRS * popped;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Get the latest nv pairs.  This also performs the required checks.       */
+  /***************************************************************************/
+  nv_pairs = evel_get_last_nv_pairs();
+
+  /***************************************************************************/
+  /* For a "suppressedNvPairsListEntry" to have any meaning, we need both    */
+  /* "nvPairFieldName" and "suppressedNvPairNames".  If we don't, then pop   */
+  /* and free whatever we just collected.                                    */
+  /***************************************************************************/
+  if ((nv_pairs->nv_pair_field_name == NULL) ||
+      dlist_is_empty(&nv_pairs->suppressed_nv_pair_names))
+  {
+    popped = dlist_pop_last(&evel_temp_throttle->suppressed_nv_pairs_list);
+    assert(popped == nv_pairs);
+    evel_throttle_free_nv_pair(popped);
+  }
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Store an "nvPairFieldName" value in the working throttle spec.
+ *
+ * @param value         The value to store.
+ *****************************************************************************/
+void evel_store_nv_pair_field_name(char * const value)
+{
+  EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Get the latest nv pairs.  This also performs the required checks.       */
+  /***************************************************************************/
+  nv_pairs = evel_get_last_nv_pairs();
+
+  /***************************************************************************/
+  /* Store the value.                                                        */
+  /***************************************************************************/
+  nv_pairs->nv_pair_field_name = value;
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Store a "suppressedNvPairNames" item in the working throttle spec.
+ *
+ * @param item          The item to store.
+ *****************************************************************************/
+void evel_store_nv_pair_name(char * const item)
+{
+  EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Get the latest nv pairs.  This also performs the required checks.       */
+  /***************************************************************************/
+  nv_pairs = evel_get_last_nv_pairs();
+
+  /***************************************************************************/
+  /* Store the item.                                                         */
+  /***************************************************************************/
+  dlist_push_last(&nv_pairs->suppressed_nv_pair_names, item);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Store a "suppressedFieldNames" item in the working throttle spec.
+ *
+ * @param item          The item to store.
+ *****************************************************************************/
+void evel_store_suppressed_field_name(char * const item)
+{
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(evel_temp_throttle != NULL);
+
+  /***************************************************************************/
+  /* Store the item.                                                         */
+  /***************************************************************************/
+  dlist_push_last(&evel_temp_throttle->suppressed_field_names, item);
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Get the last added suppressed nv pairs list entry in the working spec.
+ *
+ * @returns The last entry.
+ *****************************************************************************/
+EVEL_SUPPRESSED_NV_PAIRS * evel_get_last_nv_pairs()
+{
+  DLIST_ITEM * dlist_item;
+  EVEL_SUPPRESSED_NV_PAIRS * nv_pairs;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(evel_temp_throttle != NULL);
+
+  /***************************************************************************/
+  /* Get the pair that was added when we opened the list entry.              */
+  /***************************************************************************/
+  dlist_item = dlist_get_last(&evel_temp_throttle->suppressed_nv_pairs_list);
+  assert(dlist_item != NULL);
+  nv_pairs = dlist_item->item;
+  assert(nv_pairs != NULL);
+
+  EVEL_EXIT();
+
+  return nv_pairs;
+}
diff --git a/vnfs/VES/code/evel_library/evel_throttle.h b/vnfs/VES/code/evel_library/evel_throttle.h
new file mode 100644 (file)
index 0000000..5f02cd2
--- /dev/null
@@ -0,0 +1,228 @@
+#ifndef EVEL_THROTTLE_INCLUDED
+#define EVEL_THROTTLE_INCLUDED
+
+/**************************************************************************//**
+ * @file
+ * EVEL throttle definitions.
+ *
+ * These are internal definitions related to throttling specicications, which
+ * are required within the library but are not intended for external
+ * consumption.
+ *
+ * License
+ * -------
+ *
+ * Copyright(c) <2016>, AT&T Intellectual Property.  All other rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:  This product includes
+ *    software developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "evel_internal.h"
+#include "jsmn.h"
+
+/*****************************************************************************/
+/* Maximum depth of JSON response that we can handle.                        */
+/*****************************************************************************/
+#define EVEL_JSON_STACK_DEPTH           10
+
+/**************************************************************************//**
+ * Maximum number of tokens that we allow for in a JSON response.
+ *****************************************************************************/
+#define EVEL_MAX_RESPONSE_TOKENS        1024
+
+/**************************************************************************//**
+ * The nature of the next token that we are iterating through.  Within an
+ * object, we alternate between collecting keys and values.  Within an array,
+ * we only collect items.
+ *****************************************************************************/
+typedef enum {
+  EVEL_JSON_KEY,
+  EVEL_JSON_VALUE,
+  EVEL_JSON_ITEM
+} EVEL_JSON_STATE;
+
+/**************************************************************************//**
+ * States which we move through during JSON processing, tracking our way
+ * through the supported JSON structure.
+ *****************************************************************************/
+typedef enum
+{
+  /***************************************************************************/
+  /* Initial state.                                                          */
+  /***************************************************************************/
+  EVEL_JCS_START,
+
+  /***************************************************************************/
+  /* {"commandList": [                                                       */
+  /***************************************************************************/
+  EVEL_JCS_COMMAND_LIST,
+
+  /***************************************************************************/
+  /* {"commandList": [{                                                      */
+  /***************************************************************************/
+  EVEL_JCS_COMMAND_LIST_ENTRY,
+
+  /***************************************************************************/
+  /* {"commandList": [{"command": {                                          */
+  /***************************************************************************/
+  EVEL_JCS_COMMAND,
+
+  /***************************************************************************/
+  /* ... "eventDomainThrottleSpecification": {                               */
+  /***************************************************************************/
+  EVEL_JCS_SPEC,
+
+  /***************************************************************************/
+  /* ... "suppressedFieldNames": [                                           */
+  /***************************************************************************/
+  EVEL_JCS_FIELD_NAMES,
+
+  /***************************************************************************/
+  /* ... "suppressedNvPairsList": [                                          */
+  /***************************************************************************/
+  EVEL_JCS_PAIRS_LIST,
+
+  /***************************************************************************/
+  /* ... "suppressedNvPairsList": [{                                         */
+  /***************************************************************************/
+  EVEL_JCS_PAIRS_LIST_ENTRY,
+
+  /***************************************************************************/
+  /* ... "suppressedNvPairNames": [                                          */
+  /***************************************************************************/
+  EVEL_JCS_NV_PAIR_NAMES,
+
+  EVEL_JCS_MAX
+} EVEL_JSON_COMMAND_STATE;
+
+/**************************************************************************//**
+ * An entry in the JSON stack.
+ *****************************************************************************/
+typedef struct evel_json_stack_entry {
+
+  /***************************************************************************/
+  /* The number of elements required at this level.                          */
+  /***************************************************************************/
+  int num_required;
+
+  /***************************************************************************/
+  /* The number of elements collected at this level.                         */
+  /***************************************************************************/
+  int json_count;
+
+  /***************************************************************************/
+  /* The collection state at this level in the JSON stack.                   */
+  /***************************************************************************/
+  EVEL_JSON_STATE json_state;
+
+  /***************************************************************************/
+  /* The key being collected (if json_state is EVEL_JSON_VALUE), or NULL.    */
+  /***************************************************************************/
+  char * json_key;
+
+} EVEL_JSON_STACK_ENTRY;
+
+/**************************************************************************//**
+ * The JSON stack.
+ *****************************************************************************/
+typedef struct evel_json_stack {
+
+  /***************************************************************************/
+  /* The current position of the stack - starting at zero.                   */
+  /***************************************************************************/
+  int level;
+
+  /***************************************************************************/
+  /* The stack itself.                                                       */
+  /***************************************************************************/
+  EVEL_JSON_STACK_ENTRY entry[EVEL_JSON_STACK_DEPTH];
+
+  /***************************************************************************/
+  /* The underlying memory chunk.                                            */
+  /***************************************************************************/
+  const MEMORY_CHUNK * chunk;
+
+} EVEL_JSON_STACK;
+
+/**************************************************************************//**
+ * Initialize event throttling to the default state.
+ *
+ * Called from ::evel_initialize.
+ *****************************************************************************/
+void evel_throttle_initialize();
+
+/**************************************************************************//**
+ * Clean up event throttling.
+ *
+ * Called from ::evel_terminate.
+ *****************************************************************************/
+void evel_throttle_terminate();
+
+/**************************************************************************//**
+ * Handle a JSON response from the listener, as a list of tokens from JSMN.
+ *
+ * @param chunk         Memory chunk containing the JSON buffer.
+ * @param json_tokens   Array of tokens to handle.
+ * @param num_tokens    The number of tokens to handle.
+ * @param post          The memory chunk in which to place any resulting POST.
+ * @return true if the command was handled, false otherwise.
+ *****************************************************************************/
+bool evel_handle_command_list(const MEMORY_CHUNK * const chunk,
+                              const jsmntok_t * const json_tokens,
+                              const int num_tokens,
+                              MEMORY_CHUNK * const post);
+
+/**************************************************************************//**
+ * Return the ::EVEL_THROTTLE_SPEC for a given domain.
+ *
+ * @param domain        The domain for which to return state.
+ *****************************************************************************/
+EVEL_THROTTLE_SPEC * evel_get_throttle_spec(EVEL_EVENT_DOMAINS domain);
+
+/**************************************************************************//**
+ * Determine whether a field_name should be suppressed.
+ *
+ * @param throttle_spec Throttle specification for the domain being encoded.
+ * @param field_name    The field name to encoded or suppress.
+ * @return true if the field_name should be suppressed, false otherwise.
+ *****************************************************************************/
+bool evel_throttle_suppress_field(EVEL_THROTTLE_SPEC * throttle_spec,
+                                  const char * const field_name);
+
+/**************************************************************************//**
+ * Determine whether a name-value pair should be allowed (not suppressed).
+ *
+ * @param throttle_spec Throttle specification for the domain being encoded.
+ * @param field_name    The field name holding the name-value pairs.
+ * @param name          The name of the name-value pair to encoded or suppress.
+ * @return true if the name-value pair should be suppressed, false otherwise.
+ *****************************************************************************/
+bool evel_throttle_suppress_nv_pair(EVEL_THROTTLE_SPEC * throttle_spec,
+                                    const char * const field_name,
+                                    const char * const name);
+
+#endif
diff --git a/vnfs/VES/code/evel_library/jsmn.c b/vnfs/VES/code/evel_library/jsmn.c
new file mode 100644 (file)
index 0000000..e7765eb
--- /dev/null
@@ -0,0 +1,311 @@
+#include "jsmn.h"
+
+/**
+ * Allocates a fresh unused token from the token pull.
+ */
+static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
+               jsmntok_t *tokens, size_t num_tokens) {
+       jsmntok_t *tok;
+       if (parser->toknext >= num_tokens) {
+               return NULL;
+       }
+       tok = &tokens[parser->toknext++];
+       tok->start = tok->end = -1;
+       tok->size = 0;
+#ifdef JSMN_PARENT_LINKS
+       tok->parent = -1;
+#endif
+       return tok;
+}
+
+/**
+ * Fills token type and boundaries.
+ */
+static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
+                            int start, int end) {
+       token->type = type;
+       token->start = start;
+       token->end = end;
+       token->size = 0;
+}
+
+/**
+ * Fills next available token with JSON primitive.
+ */
+static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
+               size_t len, jsmntok_t *tokens, size_t num_tokens) {
+       jsmntok_t *token;
+       int start;
+
+       start = parser->pos;
+
+       for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
+               switch (js[parser->pos]) {
+#ifndef JSMN_STRICT
+                       /* In strict mode primitive must be followed by "," or "}" or "]" */
+                       case ':':
+#endif
+                       case '\t' : case '\r' : case '\n' : case ' ' :
+                       case ','  : case ']'  : case '}' :
+                               goto found;
+               }
+               if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
+                       parser->pos = start;
+                       return JSMN_ERROR_INVAL;
+               }
+       }
+#ifdef JSMN_STRICT
+       /* In strict mode primitive must be followed by a comma/object/array */
+       parser->pos = start;
+       return JSMN_ERROR_PART;
+#endif
+
+found:
+       if (tokens == NULL) {
+               parser->pos--;
+               return 0;
+       }
+       token = jsmn_alloc_token(parser, tokens, num_tokens);
+       if (token == NULL) {
+               parser->pos = start;
+               return JSMN_ERROR_NOMEM;
+       }
+       jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
+#ifdef JSMN_PARENT_LINKS
+       token->parent = parser->toksuper;
+#endif
+       parser->pos--;
+       return 0;
+}
+
+/**
+ * Fills next token with JSON string.
+ */
+static int jsmn_parse_string(jsmn_parser *parser, const char *js,
+               size_t len, jsmntok_t *tokens, size_t num_tokens) {
+       jsmntok_t *token;
+
+       int start = parser->pos;
+
+       parser->pos++;
+
+       /* Skip starting quote */
+       for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
+               char c = js[parser->pos];
+
+               /* Quote: end of string */
+               if (c == '\"') {
+                       if (tokens == NULL) {
+                               return 0;
+                       }
+                       token = jsmn_alloc_token(parser, tokens, num_tokens);
+                       if (token == NULL) {
+                               parser->pos = start;
+                               return JSMN_ERROR_NOMEM;
+                       }
+                       jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
+#ifdef JSMN_PARENT_LINKS
+                       token->parent = parser->toksuper;
+#endif
+                       return 0;
+               }
+
+               /* Backslash: Quoted symbol expected */
+               if (c == '\\' && parser->pos + 1 < len) {
+                       int i;
+                       parser->pos++;
+                       switch (js[parser->pos]) {
+                               /* Allowed escaped symbols */
+                               case '\"': case '/' : case '\\' : case 'b' :
+                               case 'f' : case 'r' : case 'n'  : case 't' :
+                                       break;
+                               /* Allows escaped symbol \uXXXX */
+                               case 'u':
+                                       parser->pos++;
+                                       for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
+                                               /* If it isn't a hex character we have an error */
+                                               if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
+                                                                       (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
+                                                                       (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
+                                                       parser->pos = start;
+                                                       return JSMN_ERROR_INVAL;
+                                               }
+                                               parser->pos++;
+                                       }
+                                       parser->pos--;
+                                       break;
+                               /* Unexpected symbol */
+                               default:
+                                       parser->pos = start;
+                                       return JSMN_ERROR_INVAL;
+                       }
+               }
+       }
+       parser->pos = start;
+       return JSMN_ERROR_PART;
+}
+
+/**
+ * Parse JSON string and fill tokens.
+ */
+int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
+               jsmntok_t *tokens, unsigned int num_tokens) {
+       int r;
+       int i;
+       jsmntok_t *token;
+       int count = parser->toknext;
+
+       for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
+               char c;
+               jsmntype_t type;
+
+               c = js[parser->pos];
+               switch (c) {
+                       case '{': case '[':
+                               count++;
+                               if (tokens == NULL) {
+                                       break;
+                               }
+                               token = jsmn_alloc_token(parser, tokens, num_tokens);
+                               if (token == NULL)
+                                       return JSMN_ERROR_NOMEM;
+                               if (parser->toksuper != -1) {
+                                       tokens[parser->toksuper].size++;
+#ifdef JSMN_PARENT_LINKS
+                                       token->parent = parser->toksuper;
+#endif
+                               }
+                               token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
+                               token->start = parser->pos;
+                               parser->toksuper = parser->toknext - 1;
+                               break;
+                       case '}': case ']':
+                               if (tokens == NULL)
+                                       break;
+                               type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
+#ifdef JSMN_PARENT_LINKS
+                               if (parser->toknext < 1) {
+                                       return JSMN_ERROR_INVAL;
+                               }
+                               token = &tokens[parser->toknext - 1];
+                               for (;;) {
+                                       if (token->start != -1 && token->end == -1) {
+                                               if (token->type != type) {
+                                                       return JSMN_ERROR_INVAL;
+                                               }
+                                               token->end = parser->pos + 1;
+                                               parser->toksuper = token->parent;
+                                               break;
+                                       }
+                                       if (token->parent == -1) {
+                                               break;
+                                       }
+                                       token = &tokens[token->parent];
+                               }
+#else
+                               for (i = parser->toknext - 1; i >= 0; i--) {
+                                       token = &tokens[i];
+                                       if (token->start != -1 && token->end == -1) {
+                                               if (token->type != type) {
+                                                       return JSMN_ERROR_INVAL;
+                                               }
+                                               parser->toksuper = -1;
+                                               token->end = parser->pos + 1;
+                                               break;
+                                       }
+                               }
+                               /* Error if unmatched closing bracket */
+                               if (i == -1) return JSMN_ERROR_INVAL;
+                               for (; i >= 0; i--) {
+                                       token = &tokens[i];
+                                       if (token->start != -1 && token->end == -1) {
+                                               parser->toksuper = i;
+                                               break;
+                                       }
+                               }
+#endif
+                               break;
+                       case '\"':
+                               r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
+                               if (r < 0) return r;
+                               count++;
+                               if (parser->toksuper != -1 && tokens != NULL)
+                                       tokens[parser->toksuper].size++;
+                               break;
+                       case '\t' : case '\r' : case '\n' : case ' ':
+                               break;
+                       case ':':
+                               parser->toksuper = parser->toknext - 1;
+                               break;
+                       case ',':
+                               if (tokens != NULL && parser->toksuper != -1 &&
+                                               tokens[parser->toksuper].type != JSMN_ARRAY &&
+                                               tokens[parser->toksuper].type != JSMN_OBJECT) {
+#ifdef JSMN_PARENT_LINKS
+                                       parser->toksuper = tokens[parser->toksuper].parent;
+#else
+                                       for (i = parser->toknext - 1; i >= 0; i--) {
+                                               if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
+                                                       if (tokens[i].start != -1 && tokens[i].end == -1) {
+                                                               parser->toksuper = i;
+                                                               break;
+                                                       }
+                                               }
+                                       }
+#endif
+                               }
+                               break;
+#ifdef JSMN_STRICT
+                       /* In strict mode primitives are: numbers and booleans */
+                       case '-': case '0': case '1' : case '2': case '3' : case '4':
+                       case '5': case '6': case '7' : case '8': case '9':
+                       case 't': case 'f': case 'n' :
+                               /* And they must not be keys of the object */
+                               if (tokens != NULL && parser->toksuper != -1) {
+                                       jsmntok_t *t = &tokens[parser->toksuper];
+                                       if (t->type == JSMN_OBJECT ||
+                                                       (t->type == JSMN_STRING && t->size != 0)) {
+                                               return JSMN_ERROR_INVAL;
+                                       }
+                               }
+#else
+                       /* In non-strict mode every unquoted value is a primitive */
+                       default:
+#endif
+                               r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
+                               if (r < 0) return r;
+                               count++;
+                               if (parser->toksuper != -1 && tokens != NULL)
+                                       tokens[parser->toksuper].size++;
+                               break;
+
+#ifdef JSMN_STRICT
+                       /* Unexpected char in strict mode */
+                       default:
+                               return JSMN_ERROR_INVAL;
+#endif
+               }
+       }
+
+       if (tokens != NULL) {
+               for (i = parser->toknext - 1; i >= 0; i--) {
+                       /* Unmatched opened object or array */
+                       if (tokens[i].start != -1 && tokens[i].end == -1) {
+                               return JSMN_ERROR_PART;
+                       }
+               }
+       }
+
+       return count;
+}
+
+/**
+ * Creates a new parser based over a given  buffer with an array of tokens
+ * available.
+ */
+void jsmn_init(jsmn_parser *parser) {
+       parser->pos = 0;
+       parser->toknext = 0;
+       parser->toksuper = -1;
+}
+
diff --git a/vnfs/VES/code/evel_library/jsmn.h b/vnfs/VES/code/evel_library/jsmn.h
new file mode 100644 (file)
index 0000000..01ca99c
--- /dev/null
@@ -0,0 +1,76 @@
+#ifndef __JSMN_H_
+#define __JSMN_H_
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * JSON type identifier. Basic types are:
+ *     o Object
+ *     o Array
+ *     o String
+ *     o Other primitive: number, boolean (true/false) or null
+ */
+typedef enum {
+       JSMN_UNDEFINED = 0,
+       JSMN_OBJECT = 1,
+       JSMN_ARRAY = 2,
+       JSMN_STRING = 3,
+       JSMN_PRIMITIVE = 4
+} jsmntype_t;
+
+enum jsmnerr {
+       /* Not enough tokens were provided */
+       JSMN_ERROR_NOMEM = -1,
+       /* Invalid character inside JSON string */
+       JSMN_ERROR_INVAL = -2,
+       /* The string is not a full JSON packet, more bytes expected */
+       JSMN_ERROR_PART = -3
+};
+
+/**
+ * JSON token description.
+ * @param              type    type (object, array, string etc.)
+ * @param              start   start position in JSON data string
+ * @param              end             end position in JSON data string
+ */
+typedef struct {
+       jsmntype_t type;
+       int start;
+       int end;
+       int size;
+#ifdef JSMN_PARENT_LINKS
+       int parent;
+#endif
+} jsmntok_t;
+
+/**
+ * JSON parser. Contains an array of token blocks available. Also stores
+ * the string being parsed now and current position in that string
+ */
+typedef struct {
+       unsigned int pos; /* offset in the JSON string */
+       unsigned int toknext; /* next token to allocate */
+       int toksuper; /* superior token node, e.g parent object or array */
+} jsmn_parser;
+
+/**
+ * Create JSON parser over an array of tokens
+ */
+void jsmn_init(jsmn_parser *parser);
+
+/**
+ * Run JSON parser. It parses a JSON data string into and array of tokens, each describing
+ * a single JSON object.
+ */
+int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
+               jsmntok_t *tokens, unsigned int num_tokens);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __JSMN_H_ */
diff --git a/vnfs/VES/code/evel_library/license.md b/vnfs/VES/code/evel_library/license.md
new file mode 100644 (file)
index 0000000..9851dca
--- /dev/null
@@ -0,0 +1,95 @@
+# Licensing {#licensing}
+
+# Introduction {#lic_intro}
+
+This Licensing section describes licensing of IPR in the EVEL Library.
+  
+# Licensed Software {#lic_software}
+
+## EVEL Library {#lic_evel}
+
+Copyright(c) <2016>, AT&T Intellectual Property.  All other rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:  This product includes
+   software developed by the AT&T.
+4. Neither the name of AT&T nor the names of its contributors may be used to
+   endorse or promote products derived from this software without specific
+   prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+## libcurl {#lic_libcurl}
+
+The EVEL Library makes use of the the [cURL Library]
+(https://curl.haxx.se/libcurl/) in order to send and receive HTTP data.
+
+### License
+
+COPYRIGHT AND PERMISSION NOTICE
+
+Copyright (c) 1996 - 2016, Daniel Stenberg, daniel@haxx.se, and many 
+contributors, see the THANKS file.
+
+All rights reserved.
+
+Permission to use, copy, modify, and distribute this software for any purpose 
+with or without fee is hereby granted, provided that the above copyright notice 
+and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN 
+NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 
+OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder shall not be 
+used in advertising or otherwise to promote the sale, use or other dealings in 
+this Software without prior written authorization of the copyright holder.
+
+## JSMN {#lic_jsmn}
+
+The EVEL Library makes use of the [JSMN library](http://zserge.com/jsmn.html)
+in order to decode JSON data.
+
+### License {#lic_jsmn_license}
+
+Copyright (c) 2010 Serge A. Zaitsev
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+  
\ No newline at end of file
diff --git a/vnfs/VES/code/evel_library/metadata.c b/vnfs/VES/code/evel_library/metadata.c
new file mode 100644 (file)
index 0000000..dfdca05
--- /dev/null
@@ -0,0 +1,607 @@
+/**************************************************************************//**
+ * @file
+ * Wrap the OpenStack metadata service.
+ *
+ * License
+ * -------
+ *
+ * Copyright(c) <2016>, AT&T Intellectual Property.  All other rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:  This product includes
+ *    software developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <string.h>
+#include <assert.h>
+#include <malloc.h>
+
+#include <curl/curl.h>
+
+#include "evel.h"
+#include "evel_internal.h"
+#include "jsmn.h"
+#include "metadata.h"
+
+/**************************************************************************//**
+ * URL on the link-local IP address where we can get the metadata in
+ * machine-friendly format.
+ *****************************************************************************/
+static const char * OPENSTACK_METADATA_URL =
+                      "http://169.254.169.254/openstack/latest/meta_data.json";
+
+/**************************************************************************//**
+ * How long we're prepared to wait for the metadata service to respond in
+ * seconds.
+ *****************************************************************************/
+static const int OPENSTACK_METADATA_TIMEOUT = 2;
+
+/**************************************************************************//**
+ * Size of fields extracted from metadata service.
+ *****************************************************************************/
+#define MAX_METADATA_STRING  64
+
+/**************************************************************************//**
+ * UUID of the VM extracted from the OpenStack metadata service.
+ *****************************************************************************/
+static char vm_uuid[MAX_METADATA_STRING+1] = {0};
+
+/**************************************************************************//**
+ * Name of the VM extracted from the OpenStack metadata service.
+ *****************************************************************************/
+static char vm_name[MAX_METADATA_STRING+1] = {0};
+
+/**************************************************************************//**
+ * How many metadata elements we allow for in the retrieved JSON.
+ *****************************************************************************/
+static const int MAX_METADATA_TOKENS = 128;
+
+/*****************************************************************************/
+/* Local prototypes.                                                         */
+/*****************************************************************************/
+static EVEL_ERR_CODES json_get_top_level_string(const char * json_string,
+                                                const jsmntok_t *tokens,
+                                                int json_token_count,
+                                                const char * key,
+                                                char * value);
+static EVEL_ERR_CODES json_get_string(const char * json_string,
+                                      const jsmntok_t *tokens,
+                                      int json_token_count,
+                                      const char * key,
+                                      char * value);
+static int jsoneq(const char *json, const jsmntok_t *tok, const char *s);
+
+/**************************************************************************//**
+ * Download metadata from the OpenStack metadata service.
+ *
+ * @param verbosity   Controls whether to generate debug to stdout.  Zero:
+ *                    none.  Non-zero: generate debug.
+ * @returns Status code
+ * @retval  EVEL_SUCCESS      On success
+ * @retval  ::EVEL_ERR_CODES  On failure.
+ *****************************************************************************/
+EVEL_ERR_CODES openstack_metadata(int verbosity)
+{
+  int rc = EVEL_SUCCESS;
+  CURLcode curl_rc = CURLE_OK;
+  CURL * curl_handle = NULL;
+  MEMORY_CHUNK rx_chunk;
+  char curl_err_string[CURL_ERROR_SIZE] = "<NULL>";
+  jsmn_parser json_parser;
+  jsmntok_t tokens[MAX_METADATA_TOKENS];
+  int json_token_count = 0;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Initialize dummy values for the metadata - needed for test              */
+  /* environments.                                                           */
+  /***************************************************************************/
+  openstack_metadata_initialize();
+
+  /***************************************************************************/
+  /* Get a curl handle which we'll use for accessing the metadata service.   */
+  /***************************************************************************/
+  curl_handle = curl_easy_init();
+  if (curl_handle == NULL)
+  {
+    rc = EVEL_CURL_LIBRARY_FAIL;
+    EVEL_ERROR("Failed to get libcurl handle");
+    goto exit_label;
+  }
+
+  /***************************************************************************/
+  /* Prime the library to give friendly error codes.                         */
+  /***************************************************************************/
+  curl_rc = curl_easy_setopt(curl_handle,
+                             CURLOPT_ERRORBUFFER,
+                             curl_err_string);
+  if (curl_rc != CURLE_OK)
+  {
+    rc = EVEL_CURL_LIBRARY_FAIL;
+    EVEL_ERROR("Failed to initialize libcurl to provide friendly errors. "
+               "Error code=%d", curl_rc);
+    goto exit_label;
+  }
+
+  /***************************************************************************/
+  /* Set the URL for the metadata API.                                       */
+  /***************************************************************************/
+  curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, OPENSTACK_METADATA_URL);
+  if (curl_rc != CURLE_OK)
+  {
+    rc = EVEL_CURL_LIBRARY_FAIL;
+    EVEL_ERROR("Failed to initialize libcurl with the API URL. "
+               "Error code=%d (%s)", curl_rc, curl_err_string);
+    goto exit_label;
+  }
+
+  /***************************************************************************/
+  /* send all data to this function.                                         */
+  /***************************************************************************/
+  curl_rc = curl_easy_setopt(curl_handle,
+                             CURLOPT_WRITEFUNCTION,
+                             evel_write_callback);
+  if (curl_rc != CURLE_OK)
+  {
+    rc = EVEL_CURL_LIBRARY_FAIL;
+    EVEL_ERROR("Failed to initialize libcurl with the write callback. "
+             "Error code=%d (%s)", curl_rc, curl_err_string);
+    goto exit_label;
+  }
+
+  /***************************************************************************/
+  /* some servers don't like requests that are made without a user-agent     */
+  /* field, so we provide one.                                               */
+  /***************************************************************************/
+  curl_rc = curl_easy_setopt(curl_handle,
+                             CURLOPT_USERAGENT,
+                             "libcurl-agent/1.0");
+  if (curl_rc != CURLE_OK)
+  {
+    rc = EVEL_CURL_LIBRARY_FAIL;
+    EVEL_ERROR("Failed to initialize libcurl to upload.  Error code=%d (%s)",
+               curl_rc, curl_err_string);
+    goto exit_label;
+  }
+
+  /***************************************************************************/
+  /* Set the timeout for the operation.                                      */
+  /***************************************************************************/
+  curl_rc = curl_easy_setopt(curl_handle,
+                             CURLOPT_TIMEOUT,
+                             OPENSTACK_METADATA_TIMEOUT);
+  if (curl_rc != CURLE_OK)
+  {
+    rc = EVEL_NO_METADATA;
+    EVEL_ERROR("Failed to initialize libcurl to set timeout. "
+               "Error code=%d (%s)", curl_rc, curl_err_string);
+    goto exit_label;
+  }
+
+  /***************************************************************************/
+  /* Create the memory chunk to be used for the response to the post.  The   */
+  /* will be realloced.                                                      */
+  /***************************************************************************/
+  rx_chunk.memory = malloc(1);
+  assert(rx_chunk.memory != NULL);
+  rx_chunk.size = 0;
+
+  /***************************************************************************/
+  /* Point to the data to be received.                                       */
+  /***************************************************************************/
+  curl_rc = curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&rx_chunk);
+  if (curl_rc != CURLE_OK)
+  {
+    rc = EVEL_CURL_LIBRARY_FAIL;
+    EVEL_ERROR("Failed to initialize libcurl to receive metadata. "
+               "Error code=%d (%s)", curl_rc, curl_err_string);
+    goto exit_label;
+  }
+  EVEL_DEBUG("Initialized data to receive");
+
+  /***************************************************************************/
+  /* If running in verbose mode generate more output.                        */
+  /***************************************************************************/
+  if (verbosity > 0)
+  {
+    curl_rc = curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
+    if (curl_rc != CURLE_OK)
+    {
+      rc = EVEL_CURL_LIBRARY_FAIL;
+      log_error_state("Failed to initialize libcurl to be verbose. "
+                      "Error code=%d", curl_rc);
+      goto exit_label;
+    }
+  }
+
+  /***************************************************************************/
+  /* Now run off and do what you've been told!                               */
+  /***************************************************************************/
+  curl_rc = curl_easy_perform(curl_handle);
+  if (curl_rc != CURLE_OK)
+  {
+    rc = EVEL_CURL_LIBRARY_FAIL;
+    EVEL_ERROR("Failed to transfer the data from metadata service. "
+               "Error code=%d (%s)", curl_rc, curl_err_string);
+  }
+  else
+  {
+    /*************************************************************************/
+    /* We have some metadata available, so break it out into tokens.         */
+    /*************************************************************************/
+    EVEL_DEBUG("Received metadata size = %d", rx_chunk.size);
+    EVEL_INFO("Received metadata = %s", rx_chunk.memory);
+    jsmn_init(&json_parser);
+    json_token_count = jsmn_parse(&json_parser,
+                                  rx_chunk.memory, rx_chunk.size,
+                                  tokens, MAX_METADATA_TOKENS);
+
+    /*************************************************************************/
+    /* Check that we parsed some data and that the top level is as expected. */
+    /*************************************************************************/
+    if (json_token_count < 0 || tokens[0].type != JSMN_OBJECT)
+    {
+      rc = EVEL_BAD_METADATA;
+      EVEL_ERROR("Failed to parse received JSON OpenStack metadata.  "
+                 "Error code=%d", json_token_count);
+      goto exit_label;
+    }
+    else
+    {
+      EVEL_DEBUG("Extracted %d tokens from the JSON OpenStack metadata.  ",
+                                                             json_token_count);
+    }
+
+    /*************************************************************************/
+    /* Find the keys we want from the metadata.                              */
+    /*************************************************************************/
+    if (json_get_string(rx_chunk.memory,
+                        tokens,
+                        json_token_count,
+                        "uuid",
+                        vm_uuid) != EVEL_SUCCESS)
+    {
+      rc = EVEL_BAD_METADATA;
+      EVEL_ERROR("Failed to extract UUID from OpenStack metadata");
+    }
+    else
+    {
+      EVEL_DEBUG("UUID: %s", vm_uuid);
+    }
+    if (json_get_top_level_string(rx_chunk.memory,
+                                  tokens,
+                                  json_token_count,
+                                  "name",
+                                  vm_name) != EVEL_SUCCESS)
+    {
+      rc = EVEL_BAD_METADATA;
+      EVEL_ERROR("Failed to extract VM Name from OpenStack metadata");
+    }
+    else
+    {
+      EVEL_DEBUG("VM Name: %s", vm_name);
+    }
+  }
+
+exit_label:
+
+  /***************************************************************************/
+  /* Shut down the cURL library in a tidy manner.                            */
+  /***************************************************************************/
+  if (curl_handle != NULL)
+  {
+    curl_easy_cleanup(curl_handle);
+    curl_handle = NULL;
+  }
+  free(rx_chunk.memory);
+
+  EVEL_EXIT();
+  return rc;
+}
+
+/**************************************************************************//**
+ * Initialize default values for vm_name and vm_uuid - for testing purposes.
+ *****************************************************************************/
+void openstack_metadata_initialize()
+{
+  strncpy(vm_uuid,
+          "Dummy VM UUID - No Metadata available",
+          MAX_METADATA_STRING);
+  strncpy(vm_name,
+          "Dummy VM name - No Metadata available",
+          MAX_METADATA_STRING);
+}
+
+/**************************************************************************//**
+ * Get a string value from supplied JSON by matching the key.
+ *
+ * As the structure of the metadata we're looking at is pretty straightforward
+ * we don't do anything complex (a la XPath) to extract nested keys with the
+ * same leaf name, for example.  Simply walk the structure until we find a
+ * string with the correct value.
+ *
+ * @param[in] json_string   The string which contains the JSON and has already
+ *                          been parsed.
+ * @param[in] tokens        The tokens which the JSON parser found in the JSON.
+ * @param[in] json_token_count  How many tokens were found.
+ * @param[in] key           The key we're looking for.
+ * @param[out] value        The string we found at @p key.
+ *
+ * @returns Status code
+ * @retval  EVEL_SUCCESS      On success - contents of @p value updated.
+ * @retval  EVEL_JSON_KEY_NOT_FOUND  Key not found - @p value not updated.
+ * @retval  EVEL_BAD_JSON     Parser hit unexpected data - @p value not
+ *                            updated.
+ *****************************************************************************/
+static EVEL_ERR_CODES json_get_string(const char * json_string,
+                                      const jsmntok_t * tokens,
+                                      int json_token_count,
+                                      const char * key,
+                                      char * value)
+{
+  EVEL_ERR_CODES rc = EVEL_JSON_KEY_NOT_FOUND;
+  int token_num = 0;
+  int token_len = 0;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check assumptions.                                                      */
+  /***************************************************************************/
+  assert(json_string != NULL);
+  assert(tokens != NULL);
+  assert(json_token_count >= 0);
+  assert(key != NULL);
+  assert(value != NULL);
+
+  for (token_num = 0; token_num < json_token_count; token_num++)
+  {
+    switch(tokens[token_num].type)
+    {
+    case JSMN_OBJECT:
+      EVEL_DEBUG("Skipping object");
+      break;
+
+    case JSMN_ARRAY:
+      EVEL_DEBUG("Skipping array");
+      break;
+
+    case JSMN_STRING:
+      /***********************************************************************/
+      /* This is a string, so may be what we want.  Compare keys.            */
+      /***********************************************************************/
+      if (jsoneq(json_string, &tokens[token_num], key) == 0)
+      {
+        token_len = tokens[token_num + 1].end - tokens[token_num + 1].start;
+        EVEL_DEBUG("Token %d len %d matches at %d to %d", token_num,
+                                                   tokens[token_num + 1].start,
+                                                   tokens[token_num + 1].end);
+        strncpy(value, json_string + tokens[token_num + 1].start, token_len);
+        value[token_len] = '\0';
+        EVEL_DEBUG("Extracted key: \"%s\" Value: \"%s\"", key, value);
+        rc = EVEL_SUCCESS;
+        goto exit_label;
+      }
+      else
+      {
+        EVEL_DEBUG("String key did not match");
+      }
+
+      /***********************************************************************/
+      /* Step over the value, whether we used it or not.                     */
+      /***********************************************************************/
+      token_num++;
+      break;
+
+    case JSMN_PRIMITIVE:
+      EVEL_INFO("Skipping primitive");
+      break;
+
+    case JSMN_UNDEFINED:
+    default:
+      rc = EVEL_BAD_JSON_FORMAT;
+      EVEL_ERROR("Unexpected JSON format at token %d (%d)",
+                  token_num,
+                  tokens[token_num].type);
+      goto exit_label;
+    }
+  }
+
+exit_label:
+  EVEL_EXIT();
+  return rc;
+}
+
+/**************************************************************************//**
+ * Get a top-level string value from supplied JSON by matching the key.
+ *
+ * Unlike json_get_string, this only returns a value that is in the top-level
+ * JSON object.
+ *
+ * @param[in] json_string   The string which contains the JSON and has already
+ *                          been parsed.
+ * @param[in] tokens        The tokens which the JSON parser found in the JSON.
+ * @param[in] json_token_count  How many tokens were found.
+ * @param[in] key           The key we're looking for.
+ * @param[out] value        The string we found at @p key.
+ *
+ * @returns Status code
+ * @retval  EVEL_SUCCESS      On success - contents of @p value updated.
+ * @retval  EVEL_JSON_KEY_NOT_FOUND  Key not found - @p value not updated.
+ * @retval  EVEL_BAD_JSON     Parser hit unexpected data - @p value not
+ *                            updated.
+ *****************************************************************************/
+static EVEL_ERR_CODES json_get_top_level_string(const char * json_string,
+                                                const jsmntok_t * tokens,
+                                                int json_token_count,
+                                                const char * key,
+                                                char * value)
+{
+  EVEL_ERR_CODES rc = EVEL_JSON_KEY_NOT_FOUND;
+  int token_num = 0;
+  int token_len = 0;
+  int bracket_count = 0;
+  int string_index = 0;
+  int increment = 0;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check assumptions.                                                      */
+  /***************************************************************************/
+  assert(json_string != NULL);
+  assert(tokens != NULL);
+  assert(json_token_count >= 0);
+  assert(key != NULL);
+  assert(value != NULL);
+
+  for (token_num = 0; token_num < json_token_count; token_num++)
+  {
+    switch(tokens[token_num].type)
+    {
+    case JSMN_OBJECT:
+      EVEL_DEBUG("Skipping object");
+      break;
+
+    case JSMN_ARRAY:
+      EVEL_DEBUG("Skipping array");
+      break;
+
+    case JSMN_STRING:
+      /***********************************************************************/
+      /* This is a string, so may be what we want.  Compare keys.            */
+      /***********************************************************************/
+      if (jsoneq(json_string, &tokens[token_num], key) == 0)
+      {
+        /*********************************************************************/
+        /* Count the difference in the number of opening and closing         */
+        /* brackets up to this token.  This needs to be 1 for a top-level    */
+        /* string.  Let's just hope we don't have any strings containing     */
+        /* brackets.                                                         */
+        /*********************************************************************/
+        increment = ((string_index < tokens[token_num].start) ? 1 : -1);
+
+        while (string_index != tokens[token_num].start)
+        {
+          if (json_string[string_index] == '{')
+          {
+            bracket_count += increment;
+          }
+          else if (json_string[string_index] == '}')
+          {
+            bracket_count -= increment;
+          }
+
+          string_index += increment;
+        }
+
+        if (bracket_count == 1)
+        {
+          token_len = tokens[token_num + 1].end - tokens[token_num + 1].start;
+          EVEL_DEBUG("Token %d len %d matches at top level at %d to %d",
+                     token_num,
+                     tokens[token_num + 1].start,
+                     tokens[token_num + 1].end);
+          strncpy(value, json_string + tokens[token_num + 1].start, token_len);
+          value[token_len] = '\0';
+          EVEL_DEBUG("Extracted key: \"%s\" Value: \"%s\"", key, value);
+          rc = EVEL_SUCCESS;
+          goto exit_label;
+        }
+        else
+        {
+          EVEL_DEBUG("String key did match, but not at top level");
+        }
+      }
+      else
+      {
+        EVEL_DEBUG("String key did not match");
+      }
+
+      /***********************************************************************/
+      /* Step over the value, whether we used it or not.                     */
+      /***********************************************************************/
+      token_num++;
+      break;
+
+    case JSMN_PRIMITIVE:
+      EVEL_INFO("Skipping primitive");
+      break;
+
+    case JSMN_UNDEFINED:
+    default:
+      rc = EVEL_BAD_JSON_FORMAT;
+      EVEL_ERROR("Unexpected JSON format at token %d (%d)",
+                  token_num,
+                  tokens[token_num].type);
+      goto exit_label;
+    }
+  }
+
+exit_label:
+  EVEL_EXIT();
+  return rc;
+}
+
+/**************************************************************************//**
+ * Compare a JSON string token with a value.
+ *
+ * @param[in] json The string which contains the JSON and has already been
+ *                 parsed.
+ * @param[in] tok  The token which the JSON parser found in the JSON.
+ * @param[in] s    The string we're looking for.
+ *
+ * @returns        Whether the token matches the string or not.
+ * @retval  0      Value matches
+ * @retval  -1     Value does not match.
+ *****************************************************************************/
+static int jsoneq(const char *json, const jsmntok_t *tok, const char *s) {
+  if (tok->type == JSMN_STRING && (int) strlen(s) == tok->end - tok->start &&
+      strncmp(json + tok->start, s, tok->end - tok->start) == 0) {
+    return 0;
+  }
+  return -1;
+}
+
+/**************************************************************************//**
+ * Get the VM name provided by the metadata service.
+ *
+ * @returns VM name
+ *****************************************************************************/
+const char *openstack_vm_name()
+{
+  return vm_name;
+}
+
+/**************************************************************************//**
+ * Get the VM UUID provided by the metadata service.
+ *
+ * @returns VM UUID
+ *****************************************************************************/
+const char *openstack_vm_uuid()
+{
+  return vm_uuid;
+}
diff --git a/vnfs/VES/code/evel_library/metadata.h b/vnfs/VES/code/evel_library/metadata.h
new file mode 100644 (file)
index 0000000..d9d0cc1
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef METADATA_INCLUDED
+#define METADATA_INCLUDED
+/**************************************************************************//**
+ * @file
+ * Wrap the OpenStack metadata service.
+ *
+ * License
+ * -------
+ *
+ * Copyright(c) <2016>, AT&T Intellectual Property.  All other rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:  This product includes
+ *    software developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+
+#include "evel.h"
+
+/**************************************************************************//**
+ * Download metadata from the OpenStack metadata service.
+ *
+ * @param verbosity   Controls whether to generate debug to stdout.  Zero:
+ *                    none.  Non-zero: generate debug.
+ * @returns Status code
+ * @retval  EVEL_SUCCESS      On success
+ * @retval  ::EVEL_ERR_CODES  On failure.
+ *****************************************************************************/
+EVEL_ERR_CODES openstack_metadata(int verbosity);
+
+/**************************************************************************//**
+ * Initialize default values for vm_name and vm_uuid - for testing purposes.
+ *****************************************************************************/
+void openstack_metadata_initialize();
+
+/**************************************************************************//**
+ * Get the VM name provided by the metadata service.
+ *
+ * @returns VM name
+ *****************************************************************************/
+const char *openstack_vm_name();
+
+/**************************************************************************//**
+ * Get the VM UUID provided by the metadata service.
+ *
+ * @returns VM UUID
+ *****************************************************************************/
+const char *openstack_vm_uuid();
+
+#endif
diff --git a/vnfs/VES/code/evel_library/quickstart.md b/vnfs/VES/code/evel_library/quickstart.md
new file mode 100644 (file)
index 0000000..1c735cc
--- /dev/null
@@ -0,0 +1,445 @@
+# Quick Start Guide {#quickstart}
+
+# Introduction {#qs_intro}
+
+This Quick-Start section describes how to:
+
+  *  Install and compile the supplied library code
+  *  Integrate an existing project to use the EVEL library
+  
+# Installation {#qs_install}
+
+The library is supplied as a source-code compressed-tar file. It is 
+straightforward to install and build to integrate with an existing or new
+development project.
+
+## Unpack the Source Code {#qs_unpack}
+
+The file should unpacked into your development environment:
+```
+$ mkdir evel
+$ cd evel
+$ tar zxvf evel-library-package.tgz
+```
+### Satisfy Dependencies {#qs_depend}
+
+Note that all commands in this section are based on CentOS package management
+tools and you may need to substitute the appropriate tools/packages for your
+distribution, for example `apt-get` for Ubuntu.
+
+Ensure that GCC development tools are available.
+
+```
+$ sudo yum install gcc
+```
+Additionally, the library has a dependency on the cURL library, so you'll need 
+the development tools for libCurl installed. (At runtime, only the runtime 
+library is required, of course.)
+
+```
+$ sudo yum install libcurl-devel
+```
+If you wish to make the project documentation, then Doxygen and Graphviz are
+required. (Again, this is only in the development environment, not the runtime 
+environment!)
+
+```
+$ sudo yum install doxygen graphviz
+```
+
+Note that some distributions have quite old versions of Doxygen by default and 
+it may be necessary to install a later version to use all the features.
+
+If you want to build PDFs from the LaTeX you will need a texlive install.
+
+```
+$ sudo yum install texlive
+```
+
+### Test Build {#qs_build}
+Make sure that the library makes cleanly:
+
+```
+$ cd bldjobs
+$ make
+Making dependency file evel_unit.d for evel_unit.c
+Making dependency file evel_test_control.d for evel_test_control.c
+Making dependency file evel_demo.d for evel_demo.c
+Making dependency file jsmn.d for jsmn.c
+Making dependency file evel_logging.d for evel_logging.c
+Making dependency file evel_event_mgr.d for evel_event_mgr.c
+Making dependency file evel_internal_event.d for evel_internal_event.c
+Making dependency file evel_throttle.d for evel_throttle.c
+Making dependency file evel_syslog.d for evel_syslog.c
+Making dependency file evel_strings.d for evel_strings.c
+Making dependency file evel_state_change.d for evel_state_change.c
+Making dependency file evel_scaling_measurement.d for evel_scaling_measurement.c
+Making dependency file evel_signaling.d for evel_signaling.c
+Making dependency file evel_service.d for evel_service.c
+Making dependency file evel_reporting_measurement.d for evel_reporting_measurement.c
+Making dependency file evel_json_buffer.d for evel_json_buffer.c
+Making dependency file evel_other.d for evel_other.c
+Making dependency file evel_option.d for evel_option.c
+Making dependency file evel_mobile_flow.d for evel_mobile_flow.c
+Making dependency file evel_fault.d for evel_fault.c
+Making dependency file evel_event.d for evel_event.c
+Making dependency file double_list.d for double_list.c
+Making dependency file ring_buffer.d for ring_buffer.c
+Making dependency file metadata.d for metadata.c
+Making dependency file evel.d for evel.c
+Making evel.o from evel.c
+Making metadata.o from metadata.c
+Making ring_buffer.o from ring_buffer.c
+Making double_list.o from double_list.c
+Making evel_event.o from evel_event.c
+Making evel_fault.o from evel_fault.c
+Making evel_mobile_flow.o from evel_mobile_flow.c
+Making evel_option.o from evel_option.c
+Making evel_other.o from evel_other.c
+Making evel_json_buffer.o from evel_json_buffer.c
+Making evel_reporting_measurement.o from evel_reporting_measurement.c
+Making evel_service.o from evel_service.c
+Making evel_signaling.o from evel_signaling.c
+Making evel_scaling_measurement.o from evel_scaling_measurement.c
+Making evel_state_change.o from evel_state_change.c
+Making evel_strings.o from evel_strings.c
+Making evel_syslog.o from evel_syslog.c
+Making evel_throttle.o from evel_throttle.c
+Making evel_internal_event.o from evel_internal_event.c
+Making evel_event_mgr.o from evel_event_mgr.c
+Making evel_logging.o from evel_logging.c
+Making jsmn.o from jsmn.c
+Linking API Shared Library
+Linking API Static Library
+Making evel_demo.o from evel_demo.c
+Making evel_test_control.o from evel_test_control.c
+Linking EVEL demo
+Making EVEL training
+$
+``` 
+You should now be able to run the demo CLI application.  Since it will want to
+dynamically link to the library that you've just made, you will need to set 
+your `LD_LIBRARY_PATH` appropriately first. Make sure that you specify
+your actual directory paths correctly in the following:
+
+```
+$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/centos/evel/libs/x86_64
+$ ../output/x86_64/evel_demo
+evel_demo [--help]
+          --fqdn <domain>
+          --port <port_number>
+          [--path <path>]
+          [--topic <topic>]
+          [--username <username>]
+          [--password <password>]
+          [--https]
+          [--cycles <cycles>]
+          [--nothrott]
+
+Demonstrate use of the ECOMP Vendor Event Listener API.
+
+  -h         Display this usage message.
+  --help
+
+  -f         The FQDN or IP address to the RESTful API.
+  --fqdn
+
+  -n         The port number the RESTful API.
+  --port
+
+  -p         The optional path prefix to the RESTful API.
+  --path
+
+  -t         The optional topic part of the RESTful API.
+  --topic
+
+  -u         The optional username for basic authentication of requests.
+  --username
+
+  -w         The optional password for basic authentication of requests.
+  --password
+
+  -s         Use HTTPS rather than HTTP for the transport.
+  --https
+
+  -c         Loop <cycles> times round the main loop.  Default = 1.
+  --cycles
+
+  -v         Generate much chattier logs.
+  --verbose
+
+  -x         Exclude throttling commands from demonstration.
+  --nothrott
+
+$
+```
+Assuming that all worked as expected, you are ready to start integrating with 
+your application. It probably makes sense to make the LD_LIBRARY_PATH change
+above permanent by incorporating it into your `.bash_profile` file.
+
+### Project Documentation {#qs_build_docs}
+
+The source comes with its own documentation included. The documentation can be
+built using the `docs` target in the Makefile. By default this builds HTML
+and LaTeX documentation, the latter being used to prepare PDFs.
+
+To make the documentation:
+```
+$ cd bldjobs
+$ make docs
+Cleaning docs...
+Making Doxygen documentation
+$ 
+```
+
+There is a make target that is intended to install the documentation on a
+"team server" - it will need adaptation for your team's environment - see the 
+`docs_install` target in the Makefile:
+
+```
+$ make docs_install
+Cleaning docs...
+Making Doxygen documentation
+Copying docs to team web-server...
+Enter passphrase for key '/data/home/.ssh/id_rsa':
+annotated.html                           100% 8088     7.9KB/s   00:00    
+arrowdown.png                            100%  246     0.2KB/s   00:00    
+arrowright.png                           100%  229     0.2KB/s   00:00    
+  ...
+$
+```
+
+# Project Integration {#qs_integrate}
+
+There are two key steps to the integration which have to be undertaken:
+
+  * Initialization/Termination of the library.
+  * Creation & posting of individual events.
+  
+Additionally, it may be necessary to consider changes to the EVEL library's
+source code if assumptions made by the library are either not satisfied or 
+inconvenient.  In particular:
+
+  * If the project already uses libcurl then the global initialization of the
+    library should be removed from the _EVEL Library_.
+  * The _EVEL Library_ uses `syslog` for event logging. If the project uses a
+    different event logging process, then EVEL's event logging macros should be
+    rewritten appropriately.
+
+These steps are considered in the [Normal Use](@ref qs_normal_use) and 
+[EVEL Adaptation](@ref qs_adaptation) sections below.
+
+## Normal Use         {#qs_normal_use}
+
+The _EVEL Library_ should be integrated with your project at a per-process 
+level: each process is an independent client of the ECOMP Vendor Event Listener
+API.
+
+### Initialization {#qs_initialize}
+
+The _EVEL Library_ should be initialized before the process becomes 
+multi-threaded. This constraint arises from the use of libcurl which imposes 
+the constraint that initialization occurs before the system is multi-threaded.
+This is described in more detail in the libcurl documentation for the
+[curl_global_init](https://curl.haxx.se/libcurl/c/curl_global_init.html) 
+function.
+
+Initialization stores configuration of the Vendor Event Listener API's details,
+such as the FQDN or IP address of the service, so the initializing process must
+have either extracted this information from its configuration or have this 
+information "hard-wired" into the application, so that it is available at the 
+point the `evel_initialize()` function is called:
+
+```C
+  #include "evel.h"
+  ...
+  if (evel_initialize(api_fqdn,
+                      api_port,
+                      api_path,
+                      api_topic,
+                      api_secure,
+                      "Alice",
+                      "This isn't very secure!",
+                      EVEL_SOURCE_VIRTUAL_MACHINE,
+                      "EVEL demo client",
+                      verbose_mode))
+  {
+    fprintf(stderr, "Failed to initialize the EVEL library!!!");
+    exit(-1);
+  }
+  ...
+```
+Once initialization has occurred successfully, the application may raise events
+and may also use the logging functions such as EVEL_INFO().
+
+Initialization is entirely local (there is no interaction with the service) so
+it is very unlikely to fail, unless the application environment is seriously 
+degraded.
+
+### Event Generation {#qs_generate}
+
+Generating events is a two stage process:
+
+  1.  Firstly, the _EVEL Library_ is called to allocate an event of the correct
+      type. 
+    * If this is successful, the caller is given a pointer to the event.
+    * All mandatory fields on the event are provided to this factory function
+      and are thereafter immutable.
+    * The application may add any necessary optional fields to the event, using
+      the pointer previously returned.
+  2.  The event is sent to the JSON API using the evel_post_event() function.
+    * At this point, the application relinquishes all responsibility for the 
+      event:
+      * It will be posted to the JSON API, if possible.
+      * Whether or not the posting is successful, the memory used will be 
+        freed.
+        
+In practice this looks like:
+
+```C
+  #include "evel.h"
+  ...
+
+  /***************************************************************************/
+  /* Create a new Fault object, setting mandatory fields as we do so...      */
+  /***************************************************************************/
+  fault = evel_new_fault("My alarm condition",
+                         "It broke very badly",
+                         EVEL_PRIORITY_NORMAL,
+                         EVEL_SEVERITY_MAJOR);
+  if (fault != NULL)
+  {
+    /*************************************************************************/
+    /* We have a Fault object - add some optional fields to it...            */
+    /*************************************************************************/
+    evel_fault_type_set(fault, "Bad things happen...");
+    evel_fault_interface_set(fault, "My Interface Card");
+    evel_fault_addl_info_add(fault, "name1", "value1");
+    evel_fault_addl_info_add(fault, "name2", "value2");
+    
+    /*************************************************************************/
+    /* Finally, post the Fault.  In practice this will only ever fail if     */
+    /* local ring-buffer is full because of event overload.                  */
+    /*************************************************************************/
+    evel_rc = evel_post_event((EVENT_HEADER *)fault);
+    if (evel_rc != EVEL_SUCCESS)
+    {
+      EVEL_ERROR("Post failed %d (%s)", evel_rc, evel_error_string());
+    }
+  }
+  ...
+```
+### Event Types {#qs_event_types}
+
+The _EVEL Library_ supports the following types of events:
+
+  1.  Faults
+  
+      These represent the **fault** domain in the event schema.
+      
+  2.  Measurements
+  
+      These represent the **measurementsForVfScaling** domain in the event
+      schema.
+      
+  3.  Reports
+  
+      This is an experimental type, designed to allow VNFs to report 
+      application-level statistics unencumbered with platform measurements.
+      The formal AT&T schema has been updated to include this experimental
+      type as **measurementsForVfReporting**. 
+
+  4.  Mobile Flow
+
+      These represent the **mobileFlow** domain in the event schema.
+
+  5.  Other
+
+      These represent the **other** domain in the event schema.
+
+  6.  Service Events
+
+      These represent the **serviceEvents** domain in the event schema.
+
+  7.  Signaling
+
+      These represent the **signaling** domain in the event schema.
+
+  8.  State Change
+
+      These represent the **stateChange** domain in the event schema.
+
+  9.  Syslog
+
+      These represent the **syslog** domain in the event schema.
+
+### Throttling {#qs_throttling}
+
+The _EVEL library_ supports the following command types as defined in the JSON API:
+
+  1.  commandType: throttlingSpecification
+
+    This is handled internally by the EVEL library, which stores the provided
+    throttling specification internally and applies it to all subsequent events.
+
+  2. commandType: provideThrottlingState
+
+    This is handled internally by the EVEL library, which returns the current
+    throttling specification for each domain.
+
+  3. commandType: measurementIntervalChange
+
+    This is handled by the EVEL library, which makes the latest measurement
+    interval available via the ::evel_get_measurement_interval function.
+    The application is responsible for checking and adhering to the latest
+    provided interval.
+
+### Termination {#qs_termination}
+
+Termination of the _EVEL Library_ is swift and brutal!  Events in the buffer
+at the time are "dropped on the floor" rather than waiting for the buffer to 
+deplete first.
+
+```C
+  #include "evel.h"
+  ...
+  
+  /***************************************************************************/
+  /* Shutdown the library.                                                   */
+  /***************************************************************************/
+  evel_terminate();
+  
+  ...
+``` 
+
+## EVEL Adaptation       {#qs_adaptation}
+
+The _EVEL Library_ is relatively simple and should be easy to adapt into other
+project environments.
+
+### LibcURL Lifecycle
+
+There are two circumstances where initialization of libcurl may be required:
+
+  1.  If libcurl is used by the project already, and therefore already takes 
+      responsibility of its initialization, then the libcurl initialization and 
+      termination functions should be removed from evel_initialize() and 
+      evel_terminate() respectively.
+  2.  If the project is unable to satisfy the constraint that libcurl 
+      initialization takes place in a single-threaded environment at the point
+      that the _EVEL Library_ can be initialized (for example, if MT code is 
+      necessary to read the configuration parameters required for 
+      _EVEL Library_ initialization) then it may be necessary to extract the 
+      libcurl functions and call them separately, earlier in the program's 
+      operation.
+      
+### Event Logging
+
+The _EVEL Library_ uses `syslog` for logging.  If this is inappropriate then
+the log_debug() and log_initialize() functions should be rewritten accordingly.
+
+**Note**: it would be a really bad idea to use the _EVEL Library_ itself for this 
+logging function. 
+[Turtles all the way down...](https://en.wikipedia.org/wiki/Turtles_all_the_way_down)
+  
+  
\ No newline at end of file
diff --git a/vnfs/VES/code/evel_library/readme.md b/vnfs/VES/code/evel_library/readme.md
new file mode 100644 (file)
index 0000000..3cf5708
--- /dev/null
@@ -0,0 +1,236 @@
+# EVEL Library Overview {#mainpage}
+
+# Introduction
+
+The ECOMP Vendor Event Listener ("EVEL") library encapsulates the use of
+AT&T's JSON API to the collector function within the ECOMP infrastructure.
+
+As such, it provides a reference implementation of the EVEL JSON API which
+can either be directly as part of a project or can be used to inform the
+independent implementation of an equivalent binding to the API in another
+development environment.
+
+This section provides an overview of the library and how it is integrated
+into the target application.  If all you want is a set of instructions to
+get you started, the @ref quickstart "Quick Start" section is for you.  If
+you want a more in-depth understanding of the _EVEL Library_ then this section
+provides an overview and then you can read the detailed API documentation for 
+each function. The documentation for evel.h is a good starting point, since 
+that defines the public API of the _EVEL Library_.
+
+# Library Structure 
+
+The API is designed to be used on multi-process platforms where each process
+may be multi-threaded.  Each process using this library will create an
+independent HTTP client (using libcURL).  Each process will have a single
+thread running the HTTP client but that thread receives work on a
+ring-buffer from however may threads are required to implement the function.
+
+**Note**: libcurl imposes a constraint that it is initialized before
+the process starts multi-threaded operation.
+
+# Typical Usage
+
+The library is designed to be very straightforward to use and lightweight to
+integrate into projects. The only serious external dependency is on libcURL.
+
+The supplied Makefile produces a single library **libevel.so** or
+**libevel.a** which your application needs to be linked against.
+
+Each process within the application which wants to generate events needs to
+call ::evel_initialize at the start of day (observing the above warning
+about not being MT safe at this stage.)   The initialization specifies the
+details of where the API is located.  Management of configuration is the
+responsibility of the client.
+
+Once initialized, and now MT-safe, there are factory functions to produce
+new events:
+- Faults  - ::evel_new_fault
+- Measurements - ::evel_new_measurement
+- Report - ::evel_new_report
+- State Change - ::evel_new_state_change
+- Syslog - ::evel_new_syslog
+- Other - ::evel_new_other
+- Mobile Flow - ::evel_new_mobile_flow
+
+There is also a factory function ::evel_new_mobile_gtp_flow_metrics to create
+the parameter gtp_per_flow_metrics, which is then configured and passed to the
+::evel_new_mobile_flow factory function.
+
+The event structures are initialized with mandatory fields at the point of
+creation and optional fields may be added thereafter.  Once set, values in
+the structures are immutable.
+
+Once the event is prepared, it may be posted, using ::evel_post_event,  at
+which point the calling thread relinquishes all responsibility for the
+event.  It will be freed once successfully or unsuccessfully posted to the
+API.  If, for any reason, you change your mind and don't want to post a
+created event, it must be destroyed with ::evel_free_event.
+
+Finally, at the end of day, the library can be terminated cleanly by calling
+::evel_terminate.
+
+## Example Code
+
+The following fragment illustrates the above usage:
+
+```C
+
+  if (evel_initialize(api_fqdn,
+                      api_port,
+                      api_path,
+                      api_topic,
+                      api_secure,
+                      "Alice",
+                      "This isn't very secure!",
+                      EVEL_SOURCE_VIRTUAL_MACHINE,
+                      "EVEL demo client",
+                      verbose_mode))
+  {
+    fprintf(stderr, "Failed to initialize the EVEL library!!!");
+    exit(-1);
+  }
+
+  ...
+
+  fault = evel_new_fault("My alarm condition",
+                         "It broke very badly",
+                         EVEL_PRIORITY_NORMAL,
+                         EVEL_SEVERITY_MAJOR);
+  if (fault != NULL)
+  {
+    evel_fault_type_set(fault, "Bad things happen...");
+    evel_fault_interface_set(fault, "My Interface Card");
+    evel_fault_addl_info_add(fault, "name1", "value1");
+    evel_fault_addl_info_add(fault, "name2", "value2");
+    evel_rc = evel_post_event((EVENT_HEADER *)fault);
+    if (evel_rc != EVEL_SUCCESS)
+    {
+      EVEL_ERROR("Post failed %d (%s)", evel_rc, evel_error_string());
+    }
+  }
+
+```
+
+The public API to the library is defined in evel.h.  The internal APIs
+within library are defined in separate headers (<em>e.g.</em>
+evel_internal.h), but these should not need to be included by the code
+using the library.
+
+# Example Application
+
+A simple command-line application to generate events is provided as part of
+the source package (the above code fragment is taken from that application).
+
+The following illustrates its operation to a co-located "test-collector":
+```
+$ ./evel_demo --fqdn 127.0.0.1 --port 30000 --path vendor_event_listener --topic example_vnf --verbose
+./evel_demo built Feb 26 2016 18:14:48
+* About to connect() to 169.254.169.254 port 80 (#0)
+*   Trying 169.254.169.254... * Timeout
+* connect() timed out!
+* Closing connection #0
+* About to connect() to 127.0.0.1 port 30000 (#0)
+*   Trying 127.0.0.1... * connected
+* Connected to 127.0.0.1 (127.0.0.1) port 30000 (#0)
+* Server auth using Basic with user 'Alice'
+> POST /vendor_event_listener/eventListener/v1/example_vnf HTTP/1.1
+Authorization: Basic QWxpY2U6VGhpcyBpc24ndCB2ZXJ5IHNlY3VyZSE=
+User-Agent: libcurl-agent/1.0
+Host: 127.0.0.1:30000
+Accept: */*
+Content-type: application/json
+Content-Length: 510
+
+* HTTP 1.0, assume close after body
+< HTTP/1.0 204 No Content
+< Date: Fri, 04 Mar 2016 15:37:22 GMT
+< Server: WSGIServer/0.1 Python/2.6.6
+< 
+* Closing connection #0
+* About to connect() to 127.0.0.1 port 30000 (#0)
+*   Trying 127.0.0.1... * connected
+* Connected to 127.0.0.1 (127.0.0.1) port 30000 (#0)
+* Server auth using Basic with user 'Alice'
+> POST /vendor_event_listener/eventListener/v1/example_vnf HTTP/1.1
+Authorization: Basic QWxpY2U6VGhpcyBpc24ndCB2ZXJ5IHNlY3VyZSE=
+User-Agent: libcurl-agent/1.0
+Host: 127.0.0.1:30000
+Accept: */*
+Content-type: application/json
+Content-Length: 865
+
+* HTTP 1.0, assume close after body
+< HTTP/1.0 204 No Content
+< Date: Fri, 04 Mar 2016 15:37:22 GMT
+< Server: WSGIServer/0.1 Python/2.6.6
+< 
+* Closing connection #0
+* About to connect() to 127.0.0.1 port 30000 (#0)
+*   Trying 127.0.0.1... * connected
+* Connected to 127.0.0.1 (127.0.0.1) port 30000 (#0)
+* Server auth using Basic with user 'Alice'
+> POST /vendor_event_listener/eventListener/v1/example_vnf HTTP/1.1
+Authorization: Basic QWxpY2U6VGhpcyBpc24ndCB2ZXJ5IHNlY3VyZSE=
+User-Agent: libcurl-agent/1.0
+Host: 127.0.0.1:30000
+Accept: */*
+Content-type: application/json
+Content-Length: 2325
+
+* HTTP 1.0, assume close after body
+< HTTP/1.0 204 No Content
+< Date: Fri, 04 Mar 2016 15:37:22 GMT
+< Server: WSGIServer/0.1 Python/2.6.6
+< 
+* Closing connection #0
+^C
+
+Interrupted - quitting!
+$
+```
+
+# Restrictions and Limitations
+
+## Constraint Validation
+
+The _EVEL Library_ has been designed to be production-safe code with the
+emphasis at this stage being in correctness of operation rather than
+raw performance.
+
+The API tries to check as much information as possible to avoid misuse and
+will **assert()** if constraints are not satisfied.  This is likely to lead
+to the rapid discovery of coding errors by programmers, but does mean that
+the application can fail abruptly if the library is misused in any way.
+
+## Performance
+
+The default Makefile avoids aggressive optimizations so that any core-files
+are easy to interpret.  Production code should use greater optimization
+levels.
+
+As described above, the HTTP client is single threaded and will run all
+transactions synchronously.  As transactions are serialized, a client that
+generates a lot of events will be paced by the round-trip time.
+
+It would be a straightforward enhancement to use the multi-thread API into
+libcurl and use a pool of client threads to run transactions in parallel if
+this ever became a bottleneck.
+
+## Logging
+
+The initialization of the library includes the log verbosity.  The verbose
+operation makes the library very chatty so syslog may get rather clogged
+with detailed diagnostics.  It is possible to configure syslog to put these
+events into a separate file.  A trivial syslog.conf file would be:
+
+```
+
+# Log all user messages so debug information is captured.
+
+user.*      /var/log/debug
+```
+
+If verbose logging is enabled, the cURL library will generate information 
+about the HTTP operations on **stdout**. 
+
diff --git a/vnfs/VES/code/evel_library/ring_buffer.c b/vnfs/VES/code/evel_library/ring_buffer.c
new file mode 100644 (file)
index 0000000..3795ed3
--- /dev/null
@@ -0,0 +1,206 @@
+/**************************************************************************//**
+ * @file
+ * A ring buffer with multi-threaded synchronization.
+ *
+ * License
+ * -------
+ *
+ * Copyright(c) <2016>, AT&T Intellectual Property.  All other rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:  This product includes
+ *    software developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <assert.h>
+#include <malloc.h>
+
+#include "ring_buffer.h"
+#include "evel.h"
+
+/**************************************************************************//**
+ * Ring buffer initialization.
+ *
+ * Initialize the buffer supplied to the specified size.
+ *
+ * @param   buffer  Pointer to the ring-buffer to be initialized.
+ * @param   size    How many elements to be stored in the ring-buffer.
+ *
+ * @returns Nothing
+******************************************************************************/
+void ring_buffer_initialize(ring_buffer * buffer, int size)
+{
+  int pthread_rc = 0;
+
+  EVEL_ENTER();
+
+  /***************************************************************************/
+  /* Check assumptions.                                                      */
+  /***************************************************************************/
+  assert(buffer != NULL);
+  assert(size > 0);
+
+  /***************************************************************************/
+  /* Initialize the synchronization objects.                                 */
+  /***************************************************************************/
+  pthread_rc = pthread_mutex_init(&buffer->ring_mutex, NULL);
+  assert(pthread_rc == 0);
+  pthread_rc = pthread_cond_init(&buffer->ring_cv, NULL);
+  assert(pthread_rc == 0);
+
+  /***************************************************************************/
+  /* Allocate the ring buffer itself.                                        */
+  /***************************************************************************/
+  buffer->ring = malloc(size * sizeof(void *));
+  assert(buffer->ring != NULL);
+
+  /***************************************************************************/
+  /* Initialize the ring as empty.                                           */
+  /***************************************************************************/
+  buffer->next_write = 0;
+  buffer->next_read = 0;
+  buffer->size = size;
+
+  EVEL_EXIT();
+}
+
+/**************************************************************************//**
+ * Read an element from a ring_buffer.
+ *
+ * Reads an element from the ring_buffer, advancing the next-read position.
+ * Operation is synchronized and therefore MT-safe.  Blocks if no data is
+ * available.
+ *
+ * @param   buffer  Pointer to the ring-buffer to be read.
+ *
+ * @returns Pointer to the element read from the buffer.
+******************************************************************************/
+void * ring_buffer_read(ring_buffer * buffer)
+{
+  void *msg = NULL;
+  EVEL_DEBUG("RBR: Ring buffer read");
+
+  pthread_mutex_lock(&buffer->ring_mutex);
+  while (1)
+  {
+    EVEL_DEBUG("RBR: got lock. NR=%d NW=%d",
+               buffer->next_read,
+               buffer->next_write);
+    if(buffer->next_read != buffer->next_write)
+    {
+      EVEL_DEBUG("RBR: buffer has item available");
+      msg = (buffer->ring)[buffer->next_read];
+      buffer->ring[buffer->next_read] = NULL;
+      buffer->next_read = (buffer->next_read + 1) % buffer->size;
+      EVEL_DEBUG("RBR: next read location is %d", buffer->next_read);
+      pthread_mutex_unlock(&buffer->ring_mutex);
+      break;
+    }
+    else
+    {
+      EVEL_DEBUG("RBR: Waiting for condition variable");
+      pthread_cond_wait(&buffer->ring_cv, &buffer->ring_mutex);
+      EVEL_DEBUG("RBR: Condition variable wait completed");
+    }
+  }
+  EVEL_DEBUG("RBR: Ring buffer read returning data at %lp", msg);
+  return msg;
+}
+
+/**************************************************************************//**
+ * Write an element into a ring_buffer.
+ *
+ * Writes an element into the ring_buffer, advancing the next-write position.
+ * Operation is synchronized and therefore MT-safe.  Fails if the buffer is
+ * full without blocking.
+ *
+ * @param   buffer  Pointer to the ring-buffer to be written.
+ * @param   msg     Pointer to data to be stored in the ring_buffer.
+ *
+ * @returns Number of items written.
+ * @retval  1       The data was written successfully.
+ * @retval  0       The ring_buffer was full so no data written.
+******************************************************************************/
+int ring_buffer_write(ring_buffer * buffer, void * msg)
+{
+  int item_count = 0;
+  int items_written = 0;
+  EVEL_DEBUG("RBW: Ring Buffer Write message at %lp", msg);
+
+  pthread_mutex_lock(&buffer->ring_mutex);
+  EVEL_DEBUG("RBW: got lock. NR=%d NW=%d SZ=%d",
+             buffer->next_read,
+             buffer->next_write,
+             buffer->size);
+
+  item_count = (buffer->next_write - buffer->next_read) % buffer->size;
+  if (item_count < 0)
+  {
+    item_count += buffer->size;
+  }
+  if (item_count < buffer->size - 1)
+  {
+    EVEL_DEBUG("RBW: %d items in buffer", item_count);
+    buffer->ring[buffer->next_write] = msg;
+    buffer->next_write = (buffer->next_write + 1) % buffer->size;
+    EVEL_DEBUG("RBW: next write location is %d", buffer->next_write);
+    items_written = 1;
+  }
+  else
+  {
+    EVEL_ERROR("RBW: ring buffer full - unable to write event");
+  }
+
+  pthread_mutex_unlock(&buffer->ring_mutex);
+  EVEL_DEBUG("RBW: released lock");
+  pthread_cond_signal(&buffer->ring_cv);
+
+  return items_written;
+}
+
+/**************************************************************************//**
+ * Tests whether there is data in the ring_buffer.
+ *
+ * Tests whether there is currently data in the ring_buffer without blocking.
+ *
+ * @param   buffer  Pointer to the ring-buffer to be tested.
+ *
+ * @returns Whether there is data in the ring_buffer.
+ * @retval  0       There isn't any data in the ring_buffer.
+ * @retval  1       There is data in the ring_buffer.
+******************************************************************************/
+int ring_buffer_is_empty(ring_buffer * buffer)
+{
+  int is_empty = 0;
+  EVEL_DEBUG("RBE: Ring empty check");
+
+  pthread_mutex_lock(&buffer->ring_mutex);
+  is_empty = (buffer->next_read == buffer->next_write);
+  pthread_mutex_unlock(&buffer->ring_mutex);
+
+  EVEL_DEBUG("RBE: Ring state= %d", is_empty);
+  return is_empty;
+}
+
diff --git a/vnfs/VES/code/evel_library/ring_buffer.h b/vnfs/VES/code/evel_library/ring_buffer.h
new file mode 100644 (file)
index 0000000..c687050
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef RING_BUFFER_INCLUDED
+#define RING_BUFFER_INCLUDED
+
+/**************************************************************************//**
+ * @file
+ * A ring buffer.
+ *
+ * License
+ * -------
+ *
+ * Copyright(c) <2016>, AT&T Intellectual Property.  All other rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:  This product includes
+ *    software developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <pthread.h>
+
+/**************************************************************************//**
+ * Ring buffer structure.
+ *****************************************************************************/
+typedef struct ring_buffer
+{
+    int size;
+    int next_write;
+    int next_read;
+    void ** ring;
+    pthread_cond_t ring_cv;
+    pthread_mutex_t ring_mutex;
+} ring_buffer;
+
+/**************************************************************************//**
+ * Ring buffer initialization.
+ *
+ * Initialize the buffer supplied to the specified size.
+ *
+ * @param   buffer  Pointer to the ring-buffer to be initialized.
+ * @param   size    How many elements to be stored in the ring-buffer.
+ *
+ * @returns Nothing
+******************************************************************************/
+void ring_buffer_initialize(ring_buffer * buffer, int size);
+
+/**************************************************************************//**
+ * Read an element from a ring_buffer.
+ *
+ * Reads an element from the ring_buffer, advancing the next-read position.
+ * Operation is synchronized and therefore MT-safe.  Blocks if no data is
+ * available.
+ *
+ * @param   buffer  Pointer to the ring-buffer to be read.
+ *
+ * @returns Pointer to the element read from the buffer.
+******************************************************************************/
+void * ring_buffer_read(ring_buffer * buffer);
+
+/**************************************************************************//**
+ * Write an element into a ring_buffer.
+ *
+ * Writes an element into the ring_buffer, advancing the next-write position.
+ * Operation is synchronized and therefore MT-safe.  Fails if the buffer is
+ * full without blocking.
+ *
+ * @param   buffer  Pointer to the ring-buffer to be written.
+ * @param   msg     Pointer to data to be stored in the ring_buffer.
+ *
+ * @returns Number of items written.
+ * @retval  1       The data was written successfully.
+ * @retval  0       The ring_buffer was full so no data written.
+******************************************************************************/
+int ring_buffer_write(ring_buffer * buffer, void * msg);
+
+/**************************************************************************//**
+ * Tests whether there is data in the ring_buffer.
+ *
+ * Tests whether there is currently data in the ring_buffer without blocking.
+ *
+ * @param   buffer  Pointer to the ring-buffer to be tested.
+ *
+ * @returns Whether there is data in the ring_buffer.
+ * @retval  0       There isn't any data in the ring_buffer.
+ * @retval  1       There is data in the ring_buffer.
+******************************************************************************/
+int ring_buffer_is_empty(ring_buffer * buffer);
+
+#endif
diff --git a/vnfs/VES/code/evel_training/.DS_Store b/vnfs/VES/code/evel_training/.DS_Store
new file mode 100644 (file)
index 0000000..5008ddf
Binary files /dev/null and b/vnfs/VES/code/evel_training/.DS_Store differ
diff --git a/vnfs/VES/code/evel_training/.gitignore b/vnfs/VES/code/evel_training/.gitignore
new file mode 100644 (file)
index 0000000..ee7aeaf
--- /dev/null
@@ -0,0 +1 @@
+*/hello_evel_world
diff --git a/vnfs/VES/code/evel_unit/evel_unit.c b/vnfs/VES/code/evel_unit/evel_unit.c
new file mode 100644 (file)
index 0000000..8d84370
--- /dev/null
@@ -0,0 +1,3453 @@
+/**************************************************************************//**
+ * @file
+ * Unit tests for JSON encoding and throttling.
+ *
+ * This software is intended to show the essential elements of the library's
+ * use.
+ *
+ * License
+ * -------
+ *
+ * Copyright(c) <2016>, AT&T Intellectual Property.  All other rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:  This product includes software
+ * developed by the AT&T.
+ * 4. Neither the name of AT&T nor the names of its contributors may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+#include "evel.h"
+#include "evel_internal.h"
+#include "evel_throttle.h"
+#include "metadata.h"
+
+typedef enum {
+  SERVICE_NONE,
+  SERVICE_CODEC,
+  SERVICE_TRANSCODING,
+  SERVICE_RTCP,
+  SERVICE_EOC_VQM,
+  SERVICE_MARKER
+} SERVICE_TEST;
+
+/*****************************************************************************/
+/* Local prototypes.                                                         */
+/*****************************************************************************/
+static void test_encode_heartbeat();
+static void test_encode_header_overrides();
+static void test_encode_fault();
+static void test_encode_fault_with_escaping();
+static void test_encode_measurement();
+static void test_encode_mobile_mand();
+static void test_encode_mobile_opts();
+static void test_encode_other();
+static void test_encode_report();
+static void test_encode_service();
+static void test_encode_service_subset(const SERVICE_TEST service_test);
+static void test_encode_signaling();
+static void test_encode_state_change();
+static void test_encode_syslog();
+static void test_json_response_junk();
+static void test_json_provide_throttle_state();
+static void test_json_measurement_interval();
+static void test_json_throttle_spec_field();
+static void test_json_throttle_spec_nv_pair();
+static void test_json_throttle_spec_two_domains();
+static void test_json_throttle_spec_bad_command_type();
+static void test_encode_fault_throttled();
+static void test_encode_measurement_throttled();
+static void test_encode_mobile_throttled();
+static void test_encode_other_throttled();
+static void test_encode_report_throttled();
+static void test_encode_service_throttled();
+static void test_encode_signaling_throttled();
+static void test_encode_state_change_throttled();
+static void test_encode_syslog_throttled();
+static void compare_strings(char * expected,
+                            char * actual,
+                            int max_size,
+                            char * description);
+
+/**************************************************************************//**
+ * Main function.
+ *
+ * Runs all unit test cases, and fails hard on the first failure.
+ *
+ * @param[in] argc  Argument count.
+ * @param[in] argv  Argument vector - for usage see usage_text.
+ *****************************************************************************/
+int main(int argc, char ** argv)
+{
+  assert(argc >= 0);
+  assert(argv != NULL);
+
+  /***************************************************************************/
+  /* Fix our timezone to UTC.                                                */
+  /***************************************************************************/
+  putenv("TZ=UTC");
+
+  /***************************************************************************/
+  /* Initialize metadata.                                                    */
+  /***************************************************************************/
+  openstack_metadata_initialize();
+
+  /***************************************************************************/
+  /* Minimal initialisation to exercise the encoders.                        */
+  /***************************************************************************/
+  functional_role = "UNIT TEST";
+  log_initialize(EVEL_LOG_DEBUG, "EVEL");
+
+  /***************************************************************************/
+  /* Test each encoder.                                                      */
+  /***************************************************************************/
+  test_encode_heartbeat();
+  test_encode_header_overrides();
+  test_encode_fault();
+  test_encode_measurement();
+  test_encode_mobile_mand();
+  test_encode_mobile_opts();
+  test_encode_other();
+  test_encode_report();
+  test_encode_service();
+  test_encode_signaling();
+  test_encode_state_change();
+  test_encode_syslog();
+
+  /***************************************************************************/
+  /* Test JSON Throttle.                                                     */
+  /***************************************************************************/
+  test_json_response_junk();
+  test_json_provide_throttle_state();
+  test_json_measurement_interval();
+  test_json_throttle_spec_field();
+  test_json_throttle_spec_nv_pair();
+  test_json_throttle_spec_two_domains();
+  test_json_throttle_spec_bad_command_type();
+
+  /***************************************************************************/
+  /* Test each encoder with throttling applied.                              */
+  /***************************************************************************/
+  test_encode_fault_throttled();
+  test_encode_measurement_throttled();
+  test_encode_mobile_throttled();
+  test_encode_other_throttled();
+  test_encode_report_throttled();
+  test_encode_service_throttled();
+  test_encode_signaling_throttled();
+  test_encode_state_change_throttled();
+  test_encode_syslog_throttled();
+
+  /***************************************************************************/
+  /* Test character escaping.                                                */
+  /***************************************************************************/
+  test_encode_fault_with_escaping();
+
+  printf ("\nAll Tests Passed\n");
+
+  return 0;
+}
+
+/*****************************************************************************/
+/* We link with this gettimeofday so that we get a fixed result              */
+/*****************************************************************************/
+int gettimeofday(struct timeval *tv,
+                 struct timezone *tz __attribute__((unused)))
+{
+  tv->tv_sec = 1;
+  tv->tv_usec = 2;
+  return 0;
+}
+
+void test_encode_heartbeat()
+{
+  char * expected =
+    "{\"event\": {"
+    "\"commonEventHeader\": {"
+    "\"domain\": \"heartbeat\", "
+    "\"eventId\": \"121\", "
+    "\"functionalRole\": \"UNIT TEST\", "
+    "\"lastEpochMicrosec\": 1000002, "
+    "\"priority\": \"Normal\", "
+    "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", "
+    "\"sequence\": 121, "
+    "\"sourceName\": \"Dummy VM name - No Metadata available\", "
+    "\"startEpochMicrosec\": 1000002, "
+    "\"version\": 1.2, "
+    "\"eventType\": \"Autonomous heartbeat\", "
+    "\"reportingEntityId\": \"Dummy VM UUID - No Metadata available\", "
+    "\"sourceId\": \"Dummy VM UUID - No Metadata available\""
+    "}}}";
+
+  size_t json_size = 0;
+  char json_body[EVEL_MAX_JSON_BODY];
+
+  /***************************************************************************/
+  /* Test the VM name/uuid once.                                             */
+  /***************************************************************************/
+  evel_set_next_event_sequence(121);
+
+  EVENT_HEADER * heartbeat = evel_new_heartbeat();
+  assert(heartbeat != NULL);
+
+  json_size = evel_json_encode_event(
+    json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) heartbeat);
+  compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Heartbeat");
+  assert((json_size == strlen(json_body)) && "Bad size returned");
+
+  evel_free_event(heartbeat);
+}
+
+void test_encode_header_overrides()
+{
+  char * expected =
+    "{\"event\": {"
+    "\"commonEventHeader\": {"
+    "\"domain\": \"heartbeat\", "
+    "\"eventId\": \"121\", "
+    "\"functionalRole\": \"UNIT TEST\", "
+    "\"lastEpochMicrosec\": 1000, "
+    "\"priority\": \"Normal\", "
+    "\"reportingEntityName\": \"entity_name_override\", "
+    "\"sequence\": 121, "
+    "\"sourceName\": \"Dummy VM name - No Metadata available\", "
+    "\"startEpochMicrosec\": 1001, "
+    "\"version\": 1.2, "
+    "\"eventType\": \"Autonomous heartbeat\", "
+    "\"reportingEntityId\": \"entity_id_override\", "
+    "\"sourceId\": \"Dummy VM UUID - No Metadata available\""
+    "}}}";
+
+  size_t json_size = 0;
+  char json_body[EVEL_MAX_JSON_BODY];
+
+  /***************************************************************************/
+  /* Test the VM name/uuid once.                                             */
+  /***************************************************************************/
+  evel_set_next_event_sequence(121);
+
+  EVENT_HEADER * heartbeat = evel_new_heartbeat();
+  assert(heartbeat != NULL);
+
+  evel_start_epoch_set(heartbeat, 1001);
+  evel_last_epoch_set(heartbeat, 1000);
+  evel_reporting_entity_name_set(heartbeat, "entity_name_override");
+  evel_reporting_entity_id_set(heartbeat, "entity_id_override");
+
+  json_size = evel_json_encode_event(
+    json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) heartbeat);
+  compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Heartbeat");
+  assert((json_size == strlen(json_body)) && "Bad size returned");
+
+  evel_free_event(heartbeat);
+}
+
+void test_encode_fault()
+{
+  char * expected =
+    "{\"event\": {"
+    "\"commonEventHeader\": {"
+    "\"domain\": \"fault\", "
+    "\"eventId\": \"122\", "
+    "\"functionalRole\": \"UNIT TEST\", "
+    "\"lastEpochMicrosec\": 1000002, "
+    "\"priority\": \"Normal\", "
+    "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", "
+    "\"sequence\": 122, "
+    "\"sourceName\": \"Dummy VM name - No Metadata available\", "
+    "\"startEpochMicrosec\": 1000002, "
+    "\"version\": 1.2, "
+    "\"eventType\": \"Bad things happen...\", "
+    "\"reportingEntityId\": \"Dummy VM UUID - No Metadata available\", "
+    "\"sourceId\": \"Dummy VM UUID - No Metadata available\""
+    "}, "
+    "\"faultFields\": {"
+    "\"alarmCondition\": \"My alarm condition\", "
+    "\"eventSeverity\": \"MAJOR\", "
+    "\"eventSourceType\": \"other\", "
+    "\"specificProblem\": \"It broke very badly\", "
+    "\"vfStatus\": \"Active\", "
+    "\"faultFieldsVersion\": 1.1, "
+    "\"alarmAdditionalInformation\": ["
+    "{\"name\": \"name1\", "
+    "\"value\": \"value1\"}, "
+    "{\"name\": \"name2\", "
+    "\"value\": \"value2\"}], "
+    "\"alarmInterfaceA\": \"My Interface Card\""
+    "}}}";
+
+  size_t json_size = 0;
+  char json_body[EVEL_MAX_JSON_BODY];
+  evel_set_next_event_sequence(122);
+  EVENT_FAULT * fault = evel_new_fault("My alarm condition",
+                                       "It broke very badly",
+                                       EVEL_PRIORITY_NORMAL,
+                                       EVEL_SEVERITY_MAJOR);
+  assert(fault != NULL);
+  evel_fault_type_set(fault, "Bad things happen...");
+  evel_fault_interface_set(fault, "My Interface Card");
+  evel_fault_addl_info_add(fault, "name1", "value1");
+  evel_fault_addl_info_add(fault, "name2", "value2");
+
+  json_size = evel_json_encode_event(
+    json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) fault);
+  compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Fault");
+  assert((json_size == strlen(json_body)) && "Bad size returned");
+
+  evel_free_event(fault);
+}
+
+void test_encode_measurement()
+{
+  char * expected =
+    "{\"event\": "
+    "{\"commonEventHeader\": {"
+    "\"domain\": \"measurementsForVfScaling\", "
+    "\"eventId\": \"123\", "
+    "\"functionalRole\": \"UNIT TEST\", "
+    "\"lastEpochMicrosec\": 3000, "
+    "\"priority\": \"Normal\", "
+    "\"reportingEntityName\": \"entity_name\", "
+    "\"sequence\": 123, "
+    "\"sourceName\": \"Dummy VM name - No Metadata available\", "
+    "\"startEpochMicrosec\": 2000, "
+    "\"version\": 1.2, "
+    "\"eventType\": \"Perf management...\", "
+    "\"reportingEntityId\": \"entity_id\", "
+    "\"sourceId\": \"Dummy VM UUID - No Metadata available\""
+    "}, "
+    "\"measurementsForVfScalingFields\": "
+    "{"
+    "\"measurementInterval\": 5.500000, "
+    "\"concurrentSessions\": 1, "
+    "\"configuredEntities\": 2, "
+    "\"cpuUsageArray\": ["
+    "{\"cpuIdentifier\": \"cpu1\", "
+    "\"percentUsage\": 11.110000}, "
+    "{\"cpuIdentifier\": \"cpu2\", "
+    "\"percentUsage\": 22.220000}], "
+    "\"filesystemUsageArray\": ["
+    "{\"blockConfigured\": 100.110000, "
+    "\"blockIops\": 33, "
+    "\"blockUsed\": 100.220000, "
+    "\"ephemeralConfigured\": 100.110000, "
+    "\"ephemeralIops\": 44, "
+    "\"ephemeralUsed\": 200.220000, "
+    "\"filesystemName\": \"00-11-22\"}, "
+    "{\"blockConfigured\": 300.110000, "
+    "\"blockIops\": 55, "
+    "\"blockUsed\": 300.220000, "
+    "\"ephemeralConfigured\": 300.110000, "
+    "\"ephemeralIops\": 66, "
+    "\"ephemeralUsed\": 400.220000, "
+    "\"filesystemName\": \"33-44-55\"}], "
+    "\"latencyDistribution\": ["
+    "{\"countsInTheBucket\": 20}, "
+    "{\"lowEndOfLatencyBucket\": 10.000000, "
+    "\"highEndOfLatencyBucket\": 20.000000, "
+    "\"countsInTheBucket\": 30}], "
+    "\"meanRequestLatency\": 4.400000, "
+    "\"memoryConfigured\": 6.600000, "
+    "\"memoryUsed\": 3.300000, "
+    "\"requestRate\": 7, "
+    "\"vNicUsageArray\": ["
+    "{"
+    "\"bytesIn\": 3, "
+    "\"bytesOut\": 4, "
+    "\"packetsIn\": 100, "
+    "\"packetsOut\": 200, "
+    "\"vNicIdentifier\": \"eth0\""
+    "}, "
+    "{"
+    "\"bytesIn\": 13, "
+    "\"bytesOut\": 14, "
+    "\"packetsIn\": 110, "
+    "\"packetsOut\": 240, "
+    "\"vNicIdentifier\": \"eth1\", "
+    "\"broadcastPacketsIn\": 11, "
+    "\"broadcastPacketsOut\": 12, "
+    "\"multicastPacketsIn\": 15, "
+    "\"multicastPacketsOut\": 16, "
+    "\"unicastPacketsIn\": 17, "
+    "\"unicastPacketsOut\": 18"
+    "}"
+    "], "
+    "\"aggregateCpuUsage\": 8.800000, "
+    "\"numberOfMediaPortsInUse\": 1234, "
+    "\"vnfcScalingMetric\": 1234.567800, "
+    "\"errors\": {"
+    "\"receiveDiscards\": 1, "
+    "\"receiveErrors\": 0, "
+    "\"transmitDiscards\": 2, "
+    "\"transmitErrors\": 1}, "
+    "\"featureUsageArray\": ["
+    "{\"featureIdentifier\": \"FeatureA\", "
+    "\"featureUtilization\": 123}, "
+    "{\"featureIdentifier\": \"FeatureB\", "
+    "\"featureUtilization\": 567}], "
+    "\"codecUsageArray\": ["
+    "{\"codecIdentifier\": \"G711a\", "
+    "\"numberInUse\": 91}, "
+    "{\"codecIdentifier\": \"G729ab\", "
+    "\"numberInUse\": 92}], "
+    "\"additionalMeasurements\": ["
+    "{\"name\": \"Group1\", "
+    "\"measurements\": ["
+    "{\"name\": \"Name1\", "
+    "\"value\": \"Value1\"}]}, "
+    "{\"name\": \"Group2\", "
+    "\"measurements\": ["
+    "{\"name\": \"Name1\", "
+    "\"value\": \"Value1\"}, "
+    "{\"name\": \"Name2\", "
+    "\"value\": \"Value2\"}]}], "
+    "\"measurementsForVfScalingVersion\": 1.1}}}";
+
+  size_t json_size = 0;
+  char json_body[EVEL_MAX_JSON_BODY];
+  EVENT_MEASUREMENT * measurement = NULL;
+  MEASUREMENT_LATENCY_BUCKET * bucket = NULL;
+  MEASUREMENT_VNIC_USE * vnic_use = NULL;
+
+  /***************************************************************************/
+  /* Measurement.                                                            */
+  /***************************************************************************/
+  evel_set_next_event_sequence(123);
+  measurement = evel_new_measurement(5.5);
+  assert(measurement != NULL);
+  evel_measurement_type_set(measurement, "Perf management...");
+  evel_measurement_conc_sess_set(measurement, 1);
+  evel_measurement_cfg_ents_set(measurement, 2);
+  evel_measurement_mean_req_lat_set(measurement, 4.4);
+  evel_measurement_mem_cfg_set(measurement, 6.6);
+  evel_measurement_mem_used_set(measurement, 3.3);
+  evel_measurement_request_rate_set(measurement, 7);
+  evel_measurement_agg_cpu_use_set(measurement, 8.8);
+  evel_measurement_cpu_use_add(measurement, "cpu1", 11.11);
+  evel_measurement_cpu_use_add(measurement, "cpu2", 22.22);
+  evel_measurement_fsys_use_add(measurement,"00-11-22",100.11, 100.22, 33,
+                                200.11, 200.22, 44);
+  evel_measurement_fsys_use_add(measurement,"33-44-55",300.11, 300.22, 55,
+                                400.11, 400.22, 66);
+  evel_start_epoch_set(&measurement->header, 2000);
+  evel_last_epoch_set(&measurement->header, 3000);
+  evel_reporting_entity_name_set(&measurement->header, "entity_name");
+  evel_reporting_entity_id_set(&measurement->header, "entity_id");
+
+  /***************************************************************************/
+  /* Latency Bucket with no optional parameters.                             */
+  /***************************************************************************/
+  bucket = evel_new_meas_latency_bucket(20);
+  evel_meas_latency_bucket_add(measurement, bucket);
+
+  /***************************************************************************/
+  /* Latency Bucket with all optional parameters.                            */
+  /***************************************************************************/
+  bucket = evel_new_meas_latency_bucket(30);
+  evel_meas_latency_bucket_low_end_set(bucket, 10.0);
+  evel_meas_latency_bucket_high_end_set(bucket, 20.0);
+  evel_meas_latency_bucket_add(measurement, bucket);
+
+  /***************************************************************************/
+  /* vNIC Use with no optional parameters.                                   */
+  /***************************************************************************/
+  vnic_use = evel_new_measurement_vnic_use("eth0", 100, 200, 3, 4);
+  evel_meas_vnic_use_add(measurement, vnic_use);
+
+  /***************************************************************************/
+  /* vNIC Use with all optional parameters.                                  */
+  /***************************************************************************/
+  vnic_use = evel_new_measurement_vnic_use("eth1", 110, 240, 13, 14);
+  evel_vnic_use_bcast_pkt_in_set(vnic_use, 11);
+  evel_vnic_use_bcast_pkt_out_set(vnic_use, 12);
+  evel_vnic_use_mcast_pkt_in_set(vnic_use, 15);
+  evel_vnic_use_mcast_pkt_out_set(vnic_use, 16);
+  evel_vnic_use_ucast_pkt_in_set(vnic_use, 17);
+  evel_vnic_use_ucast_pkt_out_set(vnic_use, 18);
+  evel_meas_vnic_use_add(measurement, vnic_use);
+
+  evel_measurement_errors_set(measurement, 1, 0, 2, 1);
+
+  evel_measurement_feature_use_add(measurement, "FeatureA", 123);
+  evel_measurement_feature_use_add(measurement, "FeatureB", 567);
+
+  evel_measurement_codec_use_add(measurement, "G711a", 91);
+  evel_measurement_codec_use_add(measurement, "G729ab", 92);
+
+  evel_measurement_media_port_use_set(measurement, 1234);
+
+  evel_measurement_vnfc_scaling_metric_set(measurement, 1234.5678);
+
+  evel_measurement_custom_measurement_add(measurement,
+                                          "Group1", "Name1", "Value1");
+  evel_measurement_custom_measurement_add(measurement,
+                                          "Group2", "Name1", "Value1");
+  evel_measurement_custom_measurement_add(measurement,
+                                          "Group2", "Name2", "Value2");
+
+  json_size = evel_json_encode_event(
+    json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) measurement);
+  compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Measurement");
+  assert((json_size == strlen(json_body)) && "Bad size returned");
+
+  evel_free_event(measurement);
+}
+
+void test_encode_mobile_mand()
+{
+  char * expected =
+    "{\"event\": "
+    "{\"commonEventHeader\": {"
+    "\"domain\": \"mobileFlow\", "
+    "\"eventId\": \"1241\", "
+    "\"functionalRole\": \"UNIT TEST\", "
+    "\"lastEpochMicrosec\": 1000002, "
+    "\"priority\": \"Normal\", "
+    "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", "
+    "\"sequence\": 1241, "
+    "\"sourceName\": \"Dummy VM name - No Metadata available\", "
+    "\"startEpochMicrosec\": 1000002, "
+    "\"version\": 1.2, "
+    "\"reportingEntityId\": \"Dummy VM UUID - No Metadata available\", "
+    "\"sourceId\": \"Dummy VM UUID - No Metadata available\""
+    "}, "
+    "\"mobileFlowFields\": {"
+    "\"flowDirection\": \"Outbound\", "
+    "\"gtpPerFlowMetrics\": {"
+    "\"avgBitErrorRate\": 12.300000, "
+    "\"avgPacketDelayVariation\": 3.120000, "
+    "\"avgPacketLatency\": 100, "
+    "\"avgReceiveThroughput\": 2100, "
+    "\"avgTransmitThroughput\": 500, "
+    "\"flowActivationEpoch\": 1470409421, "
+    "\"flowActivationMicrosec\": 987, "
+    "\"flowDeactivationEpoch\": 1470409431, "
+    "\"flowDeactivationMicrosec\": 11, "
+    "\"flowDeactivationTime\": \"Fri, 05 Aug 2016 15:03:51 +0000\", "
+    "\"flowStatus\": \"Working\", "
+    "\"maxPacketDelayVariation\": 87, "
+    "\"numActivationFailures\": 3, "
+    "\"numBitErrors\": 17, "
+    "\"numBytesReceived\": 123654, "
+    "\"numBytesTransmitted\": 4561, "
+    "\"numDroppedPackets\": 0, "
+    "\"numL7BytesReceived\": 12, "
+    "\"numL7BytesTransmitted\": 10, "
+    "\"numLostPackets\": 1, "
+    "\"numOutOfOrderPackets\": 3, "
+    "\"numPacketErrors\": 7, "
+    "\"numPacketsReceivedExclRetrans\": 899, "
+    "\"numPacketsReceivedInclRetrans\": 901, "
+    "\"numPacketsTransmittedInclRetrans\": 302, "
+    "\"numRetries\": 6, "
+    "\"numTimeouts\": 2, "
+    "\"numTunneledL7BytesReceived\": 0, "
+    "\"roundTripTime\": 110, "
+    "\"timeToFirstByte\": 225"
+    "}, "
+    "\"ipProtocolType\": \"TCP\", "
+    "\"ipVersion\": \"IPv4\", "
+    "\"otherEndpointIpAddress\": \"2.3.4.1\", "
+    "\"otherEndpointPort\": 2341, "
+    "\"reportingEndpointIpAddr\": \"4.2.3.1\", "
+    "\"reportingEndpointPort\": 4321"
+    "}}}";
+
+  size_t json_size = 0;
+  char json_body[EVEL_MAX_JSON_BODY];
+  MOBILE_GTP_PER_FLOW_METRICS * metrics = NULL;
+  EVENT_MOBILE_FLOW * mobile_flow = NULL;
+
+  /***************************************************************************/
+  /* Mobile.                                                                 */
+  /***************************************************************************/
+  evel_set_next_event_sequence(1241);
+
+  metrics = evel_new_mobile_gtp_flow_metrics(12.3,
+                                             3.12,
+                                             100,
+                                             2100,
+                                             500,
+                                             1470409421,
+                                             987,
+                                             1470409431,
+                                             11,
+                                             (time_t)1470409431,
+                                             "Working",
+                                             87,
+                                             3,
+                                             17,
+                                             123654,
+                                             4561,
+                                             0,
+                                             12,
+                                             10,
+                                             1,
+                                             3,
+                                             7,
+                                             899,
+                                             901,
+                                             302,
+                                             6,
+                                             2,
+                                             0,
+                                             110,
+                                             225);
+  assert(metrics != NULL);
+  mobile_flow = evel_new_mobile_flow("Outbound",
+                                     metrics,
+                                     "TCP",
+                                     "IPv4",
+                                     "2.3.4.1",
+                                     2341,
+                                     "4.2.3.1",
+                                     4321);
+  assert(mobile_flow != NULL);
+
+  json_size = evel_json_encode_event(
+    json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) mobile_flow);
+  compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Mobile");
+  assert((json_size == strlen(json_body)) && "Bad size returned");
+
+  evel_free_event(mobile_flow);
+}
+
+void test_encode_mobile_opts()
+{
+  char * expected =
+    "{\"event\": "
+    "{\"commonEventHeader\": {"
+    "\"domain\": \"mobileFlow\", "
+    "\"eventId\": \"1242\", "
+    "\"functionalRole\": \"UNIT TEST\", "
+    "\"lastEpochMicrosec\": 1000002, "
+    "\"priority\": \"Normal\", "
+    "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", "
+    "\"sequence\": 1242, "
+    "\"sourceName\": \"Dummy VM name - No Metadata available\", "
+    "\"startEpochMicrosec\": 1000002, "
+    "\"version\": 1.2, "
+    "\"eventType\": \"Mobile flow...\", "
+    "\"reportingEntityId\": \"Dummy VM UUID - No Metadata available\", "
+    "\"sourceId\": \"Dummy VM UUID - No Metadata available\""
+    "}, "
+    "\"mobileFlowFields\": {"
+    "\"flowDirection\": \"Inbound\", "
+    "\"gtpPerFlowMetrics\": {"
+    "\"avgBitErrorRate\": 132.000100, "
+    "\"avgPacketDelayVariation\": 31.200000, "
+    "\"avgPacketLatency\": 101, "
+    "\"avgReceiveThroughput\": 2101, "
+    "\"avgTransmitThroughput\": 501, "
+    "\"flowActivationEpoch\": 1470409422, "
+    "\"flowActivationMicrosec\": 988, "
+    "\"flowDeactivationEpoch\": 1470409432, "
+    "\"flowDeactivationMicrosec\": 12, "
+    "\"flowDeactivationTime\": \"Fri, 05 Aug 2016 15:03:52 +0000\", "
+    "\"flowStatus\": \"Inactive\", "
+    "\"maxPacketDelayVariation\": 88, "
+    "\"numActivationFailures\": 4, "
+    "\"numBitErrors\": 18, "
+    "\"numBytesReceived\": 123655, "
+    "\"numBytesTransmitted\": 4562, "
+    "\"numDroppedPackets\": 1, "
+    "\"numL7BytesReceived\": 13, "
+    "\"numL7BytesTransmitted\": 11, "
+    "\"numLostPackets\": 2, "
+    "\"numOutOfOrderPackets\": 4, "
+    "\"numPacketErrors\": 8, "
+    "\"numPacketsReceivedExclRetrans\": 900, "
+    "\"numPacketsReceivedInclRetrans\": 902, "
+    "\"numPacketsTransmittedInclRetrans\": 303, "
+    "\"numRetries\": 7, "
+    "\"numTimeouts\": 3, "
+    "\"numTunneledL7BytesReceived\": 1, "
+    "\"roundTripTime\": 111, "
+    "\"timeToFirstByte\": 226, "
+    "\"ipTosCountList\": ["
+    "[\"1\", 13], "
+    "[\"4\", 99], "
+    "[\"17\", 1]], "
+    "\"ipTosList\": [\"1\", \"4\", \"17\"], "
+    "\"tcpFlagList\": [\"CWR\", \"URG\"], "
+    "\"tcpFlagCountList\": [[\"CWR\", 10], [\"URG\", 121]], "
+    "\"mobileQciCosList\": [\"conversational\", \"65\"], "
+    "\"mobileQciCosCountList\": [[\"conversational\", 11], [\"65\", 122]], "
+    "\"durConnectionFailedStatus\": 12, "
+    "\"durTunnelFailedStatus\": 13, "
+    "\"flowActivatedBy\": \"Remote\", "
+    "\"flowActivationTime\": \"Fri, 05 Aug 2016 15:03:43 +0000\", "
+    "\"flowDeactivatedBy\": \"Remote\", "
+    "\"gtpConnectionStatus\": \"Connected\", "
+    "\"gtpTunnelStatus\": \"Not tunneling\", "
+    "\"largePacketRtt\": 80, "
+    "\"largePacketThreshold\": 600.000000, "
+    "\"maxReceiveBitRate\": 1357924680, "
+    "\"maxTransmitBitRate\": 235711, "
+    "\"numGtpEchoFailures\": 1, "
+    "\"numGtpTunnelErrors\": 4, "
+    "\"numHttpErrors\": 2"
+    "}, "
+    "\"ipProtocolType\": \"UDP\", "
+    "\"ipVersion\": \"IPv6\", "
+    "\"otherEndpointIpAddress\": \"2.3.4.2\", "
+    "\"otherEndpointPort\": 2342, "
+    "\"reportingEndpointIpAddr\": \"4.2.3.2\", "
+    "\"reportingEndpointPort\": 4322, "
+    "\"applicationType\": \"Demo application\", "
+    "\"appProtocolType\": \"GSM\", "
+    "\"appProtocolVersion\": \"1\", "
+    "\"cid\": \"65535\", "
+    "\"connectionType\": \"S1-U\", "
+    "\"ecgi\": \"e65535\", "
+    "\"gtpProtocolType\": \"GTP-U\", "
+    "\"gtpVersion\": \"1\", "
+    "\"httpHeader\": \"http://www.something.com\", "
+    "\"imei\": \"209917614823\", "
+    "\"imsi\": \"355251/05/850925/8\", "
+    "\"lac\": \"1\", "
+    "\"mcc\": \"410\", "
+    "\"mnc\": \"04\", "
+    "\"msisdn\": \"6017123456789\", "
+    "\"otherFunctionalRole\": \"MME\", "
+    "\"rac\": \"514\", "
+    "\"radioAccessTechnology\": \"LTE\", "
+    "\"sac\": \"1\", "
+    "\"samplingAlgorithm\": 1, "
+    "\"tac\": \"2099\", "
+    "\"tunnelId\": \"Tunnel 1\", "
+    "\"vlanId\": \"15\""
+    "}}}";
+
+  size_t json_size = 0;
+  char json_body[EVEL_MAX_JSON_BODY];
+  MOBILE_GTP_PER_FLOW_METRICS * metrics = NULL;
+  EVENT_MOBILE_FLOW * mobile_flow = NULL;
+
+  /***************************************************************************/
+  /* Mobile.                                                                 */
+  /***************************************************************************/
+  evel_set_next_event_sequence(1242);
+
+  metrics = evel_new_mobile_gtp_flow_metrics(132.0001,
+                                             31.2,
+                                             101,
+                                             2101,
+                                             501,
+                                             1470409422,
+                                             988,
+                                             1470409432,
+                                             12,
+                                             (time_t)1470409432,
+                                             "Inactive",
+                                             88,
+                                             4,
+                                             18,
+                                             123655,
+                                             4562,
+                                             1,
+                                             13,
+                                             11,
+                                             2,
+                                             4,
+                                             8,
+                                             900,
+                                             902,
+                                             303,
+                                             7,
+                                             3,
+                                             1,
+                                             111,
+                                             226);
+  assert(metrics != NULL);
+
+  evel_mobile_gtp_metrics_dur_con_fail_set(metrics, 12);
+  evel_mobile_gtp_metrics_dur_tun_fail_set(metrics, 13);
+  evel_mobile_gtp_metrics_act_by_set(metrics, "Remote");
+  evel_mobile_gtp_metrics_act_time_set(metrics, (time_t)1470409423);
+  evel_mobile_gtp_metrics_deact_by_set(metrics, "Remote");
+  evel_mobile_gtp_metrics_con_status_set(metrics, "Connected");
+  evel_mobile_gtp_metrics_tun_status_set(metrics, "Not tunneling");
+  evel_mobile_gtp_metrics_iptos_set(metrics, 1, 13);
+  evel_mobile_gtp_metrics_iptos_set(metrics, 17, 1);
+  evel_mobile_gtp_metrics_iptos_set(metrics, 4, 99);
+  evel_mobile_gtp_metrics_large_pkt_rtt_set(metrics, 80);
+  evel_mobile_gtp_metrics_large_pkt_thresh_set(metrics, 600.0);
+  evel_mobile_gtp_metrics_max_rcv_bit_rate_set(metrics, 1357924680);
+  evel_mobile_gtp_metrics_max_trx_bit_rate_set(metrics, 235711);
+  evel_mobile_gtp_metrics_num_echo_fail_set(metrics, 1);
+  evel_mobile_gtp_metrics_num_tun_fail_set(metrics, 4);
+  evel_mobile_gtp_metrics_num_http_errors_set(metrics, 2);
+  evel_mobile_gtp_metrics_tcp_flag_count_add(metrics, EVEL_TCP_CWR, 10);
+  evel_mobile_gtp_metrics_tcp_flag_count_add(metrics, EVEL_TCP_URG, 121);
+  evel_mobile_gtp_metrics_qci_cos_count_add(
+                                metrics, EVEL_QCI_COS_UMTS_CONVERSATIONAL, 11);
+  evel_mobile_gtp_metrics_qci_cos_count_add(
+                                            metrics, EVEL_QCI_COS_LTE_65, 122);
+
+  mobile_flow = evel_new_mobile_flow("Inbound",
+                                     metrics,
+                                     "UDP",
+                                     "IPv6",
+                                     "2.3.4.2",
+                                     2342,
+                                     "4.2.3.2",
+                                     4322);
+  assert(mobile_flow != NULL);
+
+  evel_mobile_flow_type_set(mobile_flow, "Mobile flow...");
+  evel_mobile_flow_app_type_set(mobile_flow, "Demo application");
+  evel_mobile_flow_app_prot_type_set(mobile_flow, "GSM");
+  evel_mobile_flow_app_prot_ver_set(mobile_flow, "1");
+  evel_mobile_flow_cid_set(mobile_flow, "65535");
+  evel_mobile_flow_con_type_set(mobile_flow, "S1-U");
+  evel_mobile_flow_ecgi_set(mobile_flow, "e65535");
+  evel_mobile_flow_gtp_prot_type_set(mobile_flow, "GTP-U");
+  evel_mobile_flow_gtp_prot_ver_set(mobile_flow, "1");
+  evel_mobile_flow_http_header_set(mobile_flow,
+                                   "http://www.something.com");
+  evel_mobile_flow_imei_set(mobile_flow, "209917614823");
+  evel_mobile_flow_imsi_set(mobile_flow, "355251/05/850925/8");
+  evel_mobile_flow_lac_set(mobile_flow, "1");
+  evel_mobile_flow_mcc_set(mobile_flow, "410");
+  evel_mobile_flow_mnc_set(mobile_flow, "04");
+  evel_mobile_flow_msisdn_set(mobile_flow, "6017123456789");
+  evel_mobile_flow_other_func_role_set(mobile_flow, "MME");
+  evel_mobile_flow_rac_set(mobile_flow, "514");
+  evel_mobile_flow_radio_acc_tech_set(mobile_flow, "LTE");
+  evel_mobile_flow_sac_set(mobile_flow, "1");
+  evel_mobile_flow_samp_alg_set(mobile_flow, 1);
+  evel_mobile_flow_tac_set(mobile_flow, "2099");
+  evel_mobile_flow_tunnel_id_set(mobile_flow, "Tunnel 1");
+  evel_mobile_flow_vlan_id_set(mobile_flow, "15");
+
+  json_size = evel_json_encode_event(
+    json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) mobile_flow);
+  compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Mobile");
+  assert((json_size == strlen(json_body)) && "Bad size returned");
+
+  evel_free_event(mobile_flow);
+}
+
+void test_encode_report()
+{
+  char * expected =
+    "{\"event\": "
+    "{\"commonEventHeader\": {"
+    "\"domain\": \"measurementsForVfReporting\", "
+    "\"eventId\": \"125\", "
+    "\"functionalRole\": \"UNIT TEST\", "
+    "\"lastEpochMicrosec\": 1000002, "
+    "\"priority\": \"Normal\", "
+    "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", "
+    "\"sequence\": 125, "
+    "\"sourceName\": \"Dummy VM name - No Metadata available\", "
+    "\"startEpochMicrosec\": 1000002, "
+    "\"version\": 1.2, "
+    "\"eventType\": \"Perf reporting...\", "
+    "\"reportingEntityId\": \"Dummy VM UUID - No Metadata available\", "
+    "\"sourceId\": \"Dummy VM UUID - No Metadata available\""
+    "}, "
+    "\"measurementsForVfReportingFields\": "
+    "{\"measurementInterval\": 1.100000, "
+    "\"featureUsageArray\": ["
+    "{\"featureIdentifier\": \"FeatureA\", "
+    "\"featureUtilization\": 123}, "
+    "{\"featureIdentifier\": \"FeatureB\", "
+    "\"featureUtilization\": 567}], "
+    "\"additionalMeasurements\": ["
+    "{\"name\": \"Group1\", "
+    "\"measurements\": ["
+    "{\"name\": \"Name1\", "
+    "\"value\": \"Value1\"}]}, "
+    "{\"name\": \"Group2\", "
+    "\"measurements\": ["
+    "{\"name\": \"Name1\", "
+    "\"value\": \"Value1\"}, "
+    "{\"name\": \"Name2\", "
+    "\"value\": \"Value2\"}]}], "
+    "\"measurementFieldsVersion\": 1.1}}}";
+
+  size_t json_size = 0;
+  char json_body[EVEL_MAX_JSON_BODY];
+  EVENT_REPORT * report = NULL;
+
+  /***************************************************************************/
+  /* Report.                                                                 */
+  /***************************************************************************/
+  evel_set_next_event_sequence(125);
+  report = evel_new_report(1.1);
+  assert(report != NULL);
+  evel_report_type_set(report, "Perf reporting...");
+  evel_report_feature_use_add(report, "FeatureA", 123);
+  evel_report_feature_use_add(report, "FeatureB", 567);
+  evel_report_custom_measurement_add(report, "Group1", "Name1", "Value1");
+  evel_report_custom_measurement_add(report, "Group2", "Name1", "Value1");
+  evel_report_custom_measurement_add(report, "Group2", "Name2", "Value2");
+
+  json_size = evel_json_encode_event(
+    json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) report);
+  compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Report");
+  assert((json_size == strlen(json_body)) && "Bad size returned");
+
+  evel_free_event(report);
+}
+
+void test_encode_service()
+{
+  test_encode_service_subset(SERVICE_NONE);
+  test_encode_service_subset(SERVICE_CODEC);
+  test_encode_service_subset(SERVICE_TRANSCODING);
+  test_encode_service_subset(SERVICE_RTCP);
+  test_encode_service_subset(SERVICE_EOC_VQM);
+  test_encode_service_subset(SERVICE_MARKER);
+}
+
+void test_encode_service_subset(const SERVICE_TEST service_test)
+{
+  char * expected_start =
+    "{\"event\": "
+    "{\"commonEventHeader\": {"
+    "\"domain\": \"serviceEvents\", "
+    "\"eventId\": \"2000\", "
+    "\"functionalRole\": \"UNIT TEST\", "
+    "\"lastEpochMicrosec\": 1000002, "
+    "\"priority\": \"Normal\", "
+    "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", "
+    "\"sequence\": 2000, "
+    "\"sourceName\": \"Dummy VM name - No Metadata available\", "
+    "\"startEpochMicrosec\": 1000002, "
+    "\"version\": 1.2, "
+    "\"eventType\": \"Service Event\", "
+    "\"reportingEntityId\": \"Dummy VM UUID - No Metadata available\", "
+    "\"sourceId\": \"Dummy VM UUID - No Metadata available\""
+    "}, "
+    "\"serviceEventsFields\": {"
+    "\"eventInstanceIdentifier\": "
+    "{"
+    "\"vendorId\": \"vendor_x_id\", "
+    "\"eventId\": \"vendor_x_event_id\", "
+    "\"productId\": \"vendor_x_product_id\", "
+    "\"subsystemId\": \"vendor_x_subsystem_id\", "
+    "\"eventFriendlyName\": \"vendor_x_frieldly_name\""
+    "}, "
+    "\"serviceEventsFieldsVersion\": 1.1, "
+    "\"correlator\": \"vendor_x_correlator\", "
+    "\"additionalFields\": ["
+    "{\"name\": \"Name1\", \"value\": \"Value1\"}, "
+    "{\"name\": \"Name2\", \"value\": \"Value2\"}, "
+    "{\"name\": \"Name3\", \"value\": \"Value3\"}, "
+    "{\"name\": \"Name4\", \"value\": \"Value4\"}]";
+  char * expected_codec =
+    ", "
+    "\"codecSelected\": {"
+    "\"codec\": \"PCMA\""
+    "}";
+  char * expected_transcoding =
+    ", "
+    "\"codecSelectedTranscoding\": {"
+    "\"calleeSideCodec\": \"PCMA\", "
+    "\"callerSideCodec\": \"G729A\""
+    "}";
+  char * expected_rtcp =
+    ", "
+    "\"midCallRtcp\": {"
+    "\"rtcpData\": \"some_rtcp_data\""
+    "}";
+  char * expected_eoc_vqm =
+    ", "
+    "\"endOfCallVqmSummaries\": {"
+    "\"adjacencyName\": \"vendor_x_adjacency\", "
+    "\"endpointDescription\": \"Caller\", "
+    "\"endpointJitter\": 66, "
+    "\"endpointRtpOctetsDiscarded\": 100, "
+    "\"endpointRtpOctetsReceived\": 200, "
+    "\"endpointRtpOctetsSent\": 300, "
+    "\"endpointRtpPacketsDiscarded\": 400, "
+    "\"endpointRtpPacketsReceived\": 500, "
+    "\"endpointRtpPacketsSent\": 600, "
+    "\"localJitter\": 99, "
+    "\"localRtpOctetsDiscarded\": 150, "
+    "\"localRtpOctetsReceived\": 250, "
+    "\"localRtpOctetsSent\": 350, "
+    "\"localRtpPacketsDiscarded\": 450, "
+    "\"localRtpPacketsReceived\": 550, "
+    "\"localRtpPacketsSent\": 650, "
+    "\"mosCqe\": 12.255000, "
+    "\"packetsLost\": 157, "
+    "\"packetLossPercent\": 0.232000, "
+    "\"rFactor\": 11, "
+    "\"roundTripDelay\": 15"
+    "}";
+  char * expected_marker =
+    ", "
+    "\"marker\": {"
+    "\"phoneNumber\": \"0888888888\""
+    "}";
+  char * expected_end =
+    "}}}";
+
+  char * expected_middle = NULL;
+  switch (service_test)
+  {
+    case SERVICE_NONE:
+      expected_middle = "";
+      break;
+    case SERVICE_CODEC:
+      expected_middle = expected_codec;
+      break;
+    case SERVICE_TRANSCODING:
+      expected_middle = expected_transcoding;
+      break;
+    case SERVICE_RTCP:
+      expected_middle = expected_rtcp;
+      break;
+    case SERVICE_EOC_VQM:
+      expected_middle = expected_eoc_vqm;
+      break;
+    case SERVICE_MARKER:
+      expected_middle = expected_marker;
+      break;
+  }
+  assert(expected_middle != NULL);
+
+  int offset = 0;
+  char expected[EVEL_MAX_JSON_BODY];
+  offset = snprintf(expected + offset,
+                    EVEL_MAX_JSON_BODY - offset,
+                    "%s%s%s",
+                    expected_start,
+                    expected_middle,
+                    expected_end);
+
+  size_t json_size = 0;
+  char json_body[EVEL_MAX_JSON_BODY];
+  EVENT_SERVICE * event = NULL;
+  evel_set_next_event_sequence(2000);
+  event = evel_new_service("vendor_x_id", "vendor_x_event_id");
+  assert(event != NULL);
+  evel_service_type_set(event, "Service Event");
+  evel_service_product_id_set(event, "vendor_x_product_id");
+  evel_service_subsystem_id_set(event, "vendor_x_subsystem_id");
+  evel_service_friendly_name_set(event, "vendor_x_frieldly_name");
+  evel_service_correlator_set(event, "vendor_x_correlator");
+
+  switch (service_test)
+  {
+    case SERVICE_NONE:
+      break;
+    case SERVICE_CODEC:
+      evel_service_codec_set(event, "PCMA");
+      break;
+    case SERVICE_TRANSCODING:
+      evel_service_callee_codec_set(event, "PCMA");
+      evel_service_caller_codec_set(event, "G729A");
+      break;
+    case SERVICE_RTCP:
+      evel_service_rtcp_data_set(event, "some_rtcp_data");
+      break;
+    case SERVICE_EOC_VQM:
+      evel_service_adjacency_name_set(event, "vendor_x_adjacency");
+      evel_service_endpoint_desc_set(event, EVEL_SERVICE_ENDPOINT_CALLER);
+      evel_service_endpoint_jitter_set(event, 66);
+      evel_service_endpoint_rtp_oct_disc_set(event, 100);
+      evel_service_endpoint_rtp_oct_recv_set(event, 200);
+      evel_service_endpoint_rtp_oct_sent_set(event, 300);
+      evel_service_endpoint_rtp_pkt_disc_set(event, 400);
+      evel_service_endpoint_rtp_pkt_recv_set(event, 500);
+      evel_service_endpoint_rtp_pkt_sent_set(event, 600);
+      evel_service_local_jitter_set(event, 99);
+      evel_service_local_rtp_oct_disc_set(event, 150);
+      evel_service_local_rtp_oct_recv_set(event, 250);
+      evel_service_local_rtp_oct_sent_set(event, 350);
+      evel_service_local_rtp_pkt_disc_set(event, 450);
+      evel_service_local_rtp_pkt_recv_set(event, 550);
+      evel_service_local_rtp_pkt_sent_set(event, 650);
+      evel_service_mos_cqe_set(event, 12.255);
+      evel_service_packets_lost_set(event, 157);
+      evel_service_packet_loss_percent_set(event, 0.232);
+      evel_service_r_factor_set(event, 11);
+      evel_service_round_trip_delay_set(event, 15);
+      break;
+    case SERVICE_MARKER:
+      evel_service_phone_number_set(event, "0888888888");
+      break;
+  }
+
+  evel_service_addl_field_add(event, "Name1", "Value1");
+  evel_service_addl_field_add(event, "Name2", "Value2");
+  evel_service_addl_field_add(event, "Name3", "Value3");
+  evel_service_addl_field_add(event, "Name4", "Value4");
+  json_size = evel_json_encode_event(
+    json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) event);
+  compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Service");
+  assert((json_size == strlen(json_body)) && "Bad size returned");
+
+  evel_free_event(event);
+}
+
+void test_encode_signaling()
+{
+  char * expected =
+    "{\"event\": "
+    "{\"commonEventHeader\": {"
+    "\"domain\": \"signaling\", "
+    "\"eventId\": \"2001\", "
+    "\"functionalRole\": \"UNIT TEST\", "
+    "\"lastEpochMicrosec\": 1000002, "
+    "\"priority\": \"Normal\", "
+    "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", "
+    "\"sequence\": 2001, "
+    "\"sourceName\": \"Dummy VM name - No Metadata available\", "
+    "\"startEpochMicrosec\": 1000002, "
+    "\"version\": 1.2, "
+    "\"eventType\": \"Signaling\", "
+    "\"reportingEntityId\": \"Dummy VM UUID - No Metadata available\", "
+    "\"sourceId\": \"Dummy VM UUID - No Metadata available\""
+    "}, "
+    "\"signalingFields\": {"
+    "\"eventInstanceIdentifier\": "
+    "{"
+    "\"vendorId\": \"vendor_x_id\", "
+    "\"eventId\": \"vendor_x_event_id\", "
+    "\"productId\": \"vendor_x_product_id\", "
+    "\"subsystemId\": \"vendor_x_subsystem_id\", "
+    "\"eventFriendlyName\": \"vendor_x_frieldly_name\""
+    "}, "
+    "\"signalingFieldsVersion\": 1.1, "
+    "\"correlator\": \"vendor_x_correlator\", "
+    "\"localIpAddress\": \"1.0.3.1\", "
+    "\"localPort\": \"1031\", "
+    "\"remoteIpAddress\": \"5.3.3.0\", "
+    "\"remotePort\": \"5330\", "
+    "\"compressedSip\": \"compressed_sip\", "
+    "\"summarySip\": \"summary_sip\""
+    "}}}";
+
+  size_t json_size = 0;
+  char json_body[EVEL_MAX_JSON_BODY];
+  EVENT_SIGNALING * event = NULL;
+  evel_set_next_event_sequence(2001);
+  event = evel_new_signaling("vendor_x_id", "vendor_x_event_id");
+  assert(event != NULL);
+  evel_signaling_type_set(event, "Signaling");
+  evel_signaling_product_id_set(event, "vendor_x_product_id");
+  evel_signaling_subsystem_id_set(event, "vendor_x_subsystem_id");
+  evel_signaling_friendly_name_set(event, "vendor_x_frieldly_name");
+  evel_signaling_correlator_set(event, "vendor_x_correlator");
+  evel_signaling_local_ip_address_set(event, "1.0.3.1");
+  evel_signaling_local_port_set(event, "1031");
+  evel_signaling_remote_ip_address_set(event, "5.3.3.0");
+  evel_signaling_remote_port_set(event, "5330");
+  evel_signaling_compressed_sip_set(event, "compressed_sip");
+  evel_signaling_summary_sip_set(event, "summary_sip");
+  json_size = evel_json_encode_event(
+    json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) event);
+  compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Signaling");
+  assert((json_size == strlen(json_body)) && "Bad size returned");
+
+  evel_free_event(event);
+}
+
+void test_encode_state_change()
+{
+  char * expected =
+    "{\"event\": "
+    "{\"commonEventHeader\": {"
+    "\"domain\": \"stateChange\", "
+    "\"eventId\": \"128\", "
+    "\"functionalRole\": \"UNIT TEST\", "
+    "\"lastEpochMicrosec\": 1000002, "
+    "\"priority\": \"Normal\", "
+    "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", "
+    "\"sequence\": 128, "
+    "\"sourceName\": \"Dummy VM name - No Metadata available\", "
+    "\"startEpochMicrosec\": 1000002, "
+    "\"version\": 1.2, "
+    "\"eventType\": \"SC Type\", "
+    "\"reportingEntityId\": \"Dummy VM UUID - No Metadata available\", "
+    "\"sourceId\": \"Dummy VM UUID - No Metadata available\""
+    "}, "
+    "\"stateChangeFields\": {"
+    "\"newState\": \"inService\", "
+    "\"oldState\": \"outOfService\", "
+    "\"stateInterface\": \"An Interface\", "
+    "\"additionalFields\": ["
+    "{\"name\": \"Name1\", "
+    "\"value\": \"Value1\"}, "
+    "{\"name\": \"Name2\", "
+    "\"value\": \"Value2\"}"
+    "], "
+    "\"stateChangeFieldsVersion\": 1.1"
+    "}}}";
+
+  size_t json_size = 0;
+  char json_body[EVEL_MAX_JSON_BODY];
+  EVENT_STATE_CHANGE * state_change = NULL;
+  evel_set_next_event_sequence(128);
+  state_change = evel_new_state_change(EVEL_ENTITY_STATE_IN_SERVICE,
+                                       EVEL_ENTITY_STATE_OUT_OF_SERVICE,
+                                       "An Interface");
+  assert(state_change != NULL);
+  evel_state_change_type_set(state_change, "SC Type");
+  evel_state_change_addl_field_add(state_change, "Name1", "Value1");
+  evel_state_change_addl_field_add(state_change, "Name2", "Value2");
+
+  json_size = evel_json_encode_event(
+    json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) state_change);
+  compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "StateChange");
+  assert((json_size == strlen(json_body)) && "Bad size returned");
+
+  evel_free_event(state_change);
+}
+
+void test_encode_syslog()
+{
+  char * expected =
+    "{\"event\": "
+    "{\"commonEventHeader\": {"
+    "\"domain\": \"syslog\", "
+    "\"eventId\": \"126\", "
+    "\"functionalRole\": \"UNIT TEST\", "
+    "\"lastEpochMicrosec\": 1000002, "
+    "\"priority\": \"Normal\", "
+    "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", "
+    "\"sequence\": 126, "
+    "\"sourceName\": \"Dummy VM name - No Metadata available\", "
+    "\"startEpochMicrosec\": 1000002, "
+    "\"version\": 1.2, "
+    "\"eventType\": \"SL Type\", "
+    "\"reportingEntityId\": \"Dummy VM UUID - No Metadata available\", "
+    "\"sourceId\": \"Dummy VM UUID - No Metadata available\""
+    "}, "
+    "\"syslogFields\": {"
+    "\"eventSourceType\": \"virtualNetworkFunction\", "
+    "\"syslogMsg\": \"SL Message\", "
+    "\"syslogTag\": \"SL Tag\", "
+    "\"syslogFieldsVersion\": 1.1, "
+    "\"eventSourceHost\": \"SL Host\", "
+    "\"syslogFacility\": 6, "
+    "\"syslogProc\": \"SL Proc\", "
+    "\"syslogProcId\": 2, "
+    "\"syslogSData\": \"SL SDATA\", "
+    "\"syslogVer\": 1"
+    "}}}";
+  size_t json_size = 0;
+  char json_body[EVEL_MAX_JSON_BODY];
+  EVENT_SYSLOG * syslog = NULL;
+  evel_set_next_event_sequence(126);
+  syslog = evel_new_syslog(EVEL_SOURCE_VIRTUAL_NETWORK_FUNCTION,
+                           "SL Message",
+                           "SL Tag");
+  assert(syslog != NULL);
+  evel_syslog_type_set(syslog, "SL Type");
+  evel_syslog_event_source_host_set(syslog, "SL Host");
+  evel_syslog_facility_set(syslog, EVEL_SYSLOG_FACILITY_LINE_PRINTER);
+  evel_syslog_proc_set(syslog, "SL Proc");
+  evel_syslog_proc_id_set(syslog, 2);
+  evel_syslog_version_set(syslog, 1);
+  evel_syslog_s_data_set(syslog, "SL SDATA");
+
+  json_size = evel_json_encode_event(
+    json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) syslog);
+  compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Syslog");
+  assert((json_size == strlen(json_body)) && "Bad size returned");
+
+  evel_free_event(syslog);
+}
+
+void test_encode_other()
+{
+  char * expected =
+    "{\"event\": "
+    "{\"commonEventHeader\": {"
+    "\"domain\": \"other\", "
+    "\"eventId\": \"129\", "
+    "\"functionalRole\": \"UNIT TEST\", "
+    "\"lastEpochMicrosec\": 1000002, "
+    "\"priority\": \"Normal\", "
+    "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", "
+    "\"sequence\": 129, "
+    "\"sourceName\": \"Dummy VM name - No Metadata available\", "
+    "\"startEpochMicrosec\": 1000002, "
+    "\"version\": 1.2, "
+    "\"eventType\": \"Other Type\", "
+    "\"reportingEntityId\": \"Dummy VM UUID - No Metadata available\", "
+    "\"sourceId\": \"Dummy VM UUID - No Metadata available\""
+    "}, "
+    "\"otherFields\": ["
+    "{\"name\": \"Other field 1\", "
+    "\"value\": \"Other value 1\"}, "
+    "{\"name\": \"Other field 2\", "
+    "\"value\": \"Other value 2\"}"
+    "]"
+    "}}";
+
+  size_t json_size = 0;
+  char json_body[EVEL_MAX_JSON_BODY];
+  EVENT_OTHER * other = NULL;
+  evel_set_next_event_sequence(129);
+  other = evel_new_other();
+  assert(other != NULL);
+  evel_other_type_set(other, "Other Type");
+  evel_other_field_add(other,
+                       "Other field 1",
+                       "Other value 1");
+  evel_other_field_add(other,
+                       "Other field 2",
+                       "Other value 2");
+
+  json_size = evel_json_encode_event(
+    json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) other);
+  compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Other");
+  assert((json_size == strlen(json_body)) && "Bad size returned");
+
+  evel_free_event(other);
+}
+
+void compare_strings(char * expected,
+                     char * actual,
+                     int max_size,
+                     char * description)
+{
+  if (strncmp(expected, actual, max_size) != 0)
+  {
+    int diff = 0;
+    while (diff < max_size)
+    {
+      if (expected[diff] != actual[diff])
+      {
+        break;
+      }
+      diff++;
+    }
+
+    printf("Comparison Failure at Offset %d\n\n", diff);
+    printf("Expected:\n%s\n", expected);
+    printf("Actual:\n%s\n", actual);
+    printf("Description: %s\n", description);
+    assert(0);
+  }
+}
+
+/**************************************************************************//**
+ * Copy a json string to a ::MEMORY_CHUNK for testing.
+ *
+ * @param chunk         The memory chunk.
+ * @param string        The json string.
+ *****************************************************************************/
+void copy_string_to_chunk(MEMORY_CHUNK * chunk, char * string)
+{
+  int mem_size;
+
+  /***************************************************************************/
+  /* Check preconditions.                                                    */
+  /***************************************************************************/
+  assert(chunk != NULL);
+  assert(string != NULL);
+
+  mem_size = strlen(string) + 1;
+  chunk->memory = malloc(mem_size);
+  memcpy(chunk->memory, string, mem_size);
+  chunk->size = mem_size;
+}
+
+/**************************************************************************//**
+ * Copy a json string to a ::MEMORY_CHUNK for testing.
+ *
+ * @param json          The JSON string.
+ * @param post          Memory chunk to post a response.
+ *****************************************************************************/
+void handle_json_response(char * json, MEMORY_CHUNK * post)
+{
+  MEMORY_CHUNK chunk;
+  post->memory = NULL;
+  post->size = 0;
+  copy_string_to_chunk(&chunk, json);
+  evel_handle_event_response(&chunk, post);
+  free(chunk.memory);
+}
+
+/**************************************************************************//**
+ * Test that a non-"commandList" JSON buffer leaves the throttle state off.
+ *****************************************************************************/
+void test_json_response_junk()
+{
+  MEMORY_CHUNK post;
+  int domain;
+  char * json_junk =
+    "{"
+    "\"junk1\": ["
+    "\"1\", \"2\", \"3\"], "
+    "\"junk2\": ["
+    "\"1\", \"2\", \"3\"]"
+    "}";
+
+  evel_throttle_initialize();
+  handle_json_response(json_junk, &post);
+
+  /***************************************************************************/
+  /* Check that all domains are not throttled.                               */
+  /***************************************************************************/
+  for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++)
+  {
+    assert(evel_get_throttle_spec(domain) == NULL);
+  }
+
+  /***************************************************************************/
+  /* Check that we generated no post.                                        */
+  /***************************************************************************/
+  assert(post.memory == NULL);
+
+  evel_throttle_terminate();
+}
+
+char * json_command_list_provide =
+  "{"
+  "\"commandList\": ["
+  "{"
+  "\"command\": {"
+  "\"commandType\": \"provideThrottlingState\""
+  "}"
+  "}"
+  "]"
+  "}";
+
+char * json_command_list_fault_clear =
+  "{"
+  "\"commandList\": ["
+  "{"
+  "\"command\": {"
+  "\"commandType\": \"throttlingSpecification\", "
+  "\"eventDomainThrottleSpecification\": {"
+  "\"eventDomain\": \"fault\""
+  "}"
+  "}"
+  "}"
+  "]"
+  "}";
+
+char * json_command_list_syslog_clear =
+  "{"
+  "\"commandList\": ["
+  "{"
+  "\"command\": {"
+  "\"commandType\": \"throttlingSpecification\", "
+  "\"eventDomainThrottleSpecification\": {"
+  "\"eventDomain\": \"syslog\""
+  "}"
+  "}"
+  "}"
+  "]"
+  "}";
+
+char * expected_throttle_state_normal =
+  "{"
+  "\"eventThrottlingState\": {"
+  "\"eventThrottlingMode\": \"normal\"}"
+  "}";
+
+/**************************************************************************//**
+ * Test that we can return the default throttling state.
+ *****************************************************************************/
+void test_json_provide_throttle_state()
+{
+  MEMORY_CHUNK post;
+  int domain;
+
+  char * expected_post = expected_throttle_state_normal;
+
+  evel_throttle_initialize();
+  handle_json_response(json_command_list_provide, &post);
+
+  /***************************************************************************/
+  /* Check that all domains are not throttled.                               */
+  /***************************************************************************/
+  for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++)
+  {
+    assert(evel_get_throttle_spec(domain) == NULL);
+  }
+
+  /***************************************************************************/
+  /* Check that we generated a throttling specification post.                */
+  /***************************************************************************/
+  assert(post.memory != NULL);
+  compare_strings(expected_post, post.memory, strlen(expected_post),
+                  "Throttle State Normal");
+  free(post.memory);
+
+  evel_throttle_terminate();
+}
+
+/**************************************************************************//**
+ * Test the measurement interval handling and API.
+ *****************************************************************************/
+void test_json_measurement_interval()
+{
+  MEMORY_CHUNK post;
+  char * json_command_list_interval_only =
+    "{"
+    "\"commandList\": ["
+    "{"
+    "\"command\": {"
+    "\"measurementInterval\": 60"
+    "}"
+    "}"
+    "]"
+    "}";
+
+  char * json_command_list_interval_first =
+    "{"
+    "\"commandList\": ["
+    "{"
+    "\"command\": {"
+    "\"measurementInterval\": 30, "
+    "\"commandType\": \"measurementIntervalChange\""
+    "}"
+    "}"
+    "]"
+    "}";
+
+  char * json_command_list_command_first =
+    "{"
+    "\"commandList\": ["
+    "{"
+    "\"command\": {"
+    "\"commandType\": \"measurementIntervalChange\", "
+    "\"measurementInterval\": 60"
+    "}"
+    "}"
+    "]"
+    "}";
+
+  evel_throttle_initialize();
+  assert(evel_get_measurement_interval() == EVEL_MEASUREMENT_INTERVAL_UKNOWN);
+
+  /***************************************************************************/
+  /* Check that we're not handling stuff when we shouldn't.                  */
+  /***************************************************************************/
+  handle_json_response(json_command_list_interval_only, &post);
+  assert(post.memory == NULL);
+  assert(evel_get_measurement_interval() == EVEL_MEASUREMENT_INTERVAL_UKNOWN);
+
+  /***************************************************************************/
+  /* Check that we're OK with the interval coming first.                     */
+  /***************************************************************************/
+  handle_json_response(json_command_list_interval_first, &post);
+  assert(post.memory == NULL);
+  assert(evel_get_measurement_interval() == 30);
+
+  /***************************************************************************/
+  /* Check that we're OK with the command type coming first.                 */
+  /***************************************************************************/
+  handle_json_response(json_command_list_command_first, &post);
+  assert(post.memory == NULL);
+  assert(evel_get_measurement_interval() == 60);
+
+  evel_throttle_terminate();
+}
+
+/**************************************************************************//**
+ * Test a single domain, single field suppression.
+ *****************************************************************************/
+void test_json_throttle_spec_field()
+{
+  MEMORY_CHUNK post;
+  int domain;
+
+  char * json_command_list_fault_single =
+    "{"
+    "\"commandList\": ["
+    "{"
+    "\"command\": {"
+    "\"commandType\": \"throttlingSpecification\", "
+    "\"eventDomainThrottleSpecification\": {"
+    "\"eventDomain\": \"fault\", "
+    "\"suppressedFieldNames\": [\"alarmInterfaceA\"]"
+    "}"
+    "}"
+    "}"
+    "]"
+    "}";
+
+  char * json_command_list_fault_double =
+    "{"
+    "\"commandList\": ["
+    "{"
+    "\"command\": {"
+    "\"commandType\": \"throttlingSpecification\", "
+    "\"eventDomainThrottleSpecification\": {"
+    "\"eventDomain\": \"fault\", "
+    "\"suppressedFieldNames\": ["
+    "\"alarmInterfaceA\", \"alarmAdditionalInformation\"]"
+    "}"
+    "}"
+    "}"
+    "]"
+    "}";
+
+  char * expected_post_fault_single =
+    "{"
+    "\"eventThrottlingState\": {"
+    "\"eventThrottlingMode\": \"throttled\", "
+    "\"eventDomainThrottleSpecificationList\": ["
+    "{"
+    "\"eventDomain\": \"fault\", "
+    "\"suppressedFieldNames\": [\"alarmInterfaceA\"]"
+    "}"
+    "]"
+    "}"
+    "}";
+
+  char * expected_post_fault_double =
+    "{"
+    "\"eventThrottlingState\": {"
+    "\"eventThrottlingMode\": \"throttled\", "
+    "\"eventDomainThrottleSpecificationList\": ["
+    "{"
+    "\"eventDomain\": \"fault\", "
+    "\"suppressedFieldNames\": ["
+    "\"alarmInterfaceA\", \"alarmAdditionalInformation\"]"
+    "}"
+    "]"
+    "}"
+    "}";
+
+  /***************************************************************************/
+  /* Initialize and provide a specification with a single fault suppressed.  */
+  /***************************************************************************/
+  evel_throttle_initialize();
+  handle_json_response(json_command_list_fault_single, &post);
+
+  /***************************************************************************/
+  /* Check that the FAULT domain is throttled.                               */
+  /***************************************************************************/
+  assert(evel_get_throttle_spec(EVEL_DOMAIN_FAULT) != NULL);
+  for (domain = EVEL_DOMAIN_MEASUREMENT; domain < EVEL_MAX_DOMAINS; domain++)
+  {
+    if (domain != EVEL_DOMAIN_FAULT)
+    {
+      assert(evel_get_throttle_spec(domain) == NULL);
+    }
+  }
+  assert(post.memory == NULL);
+
+  /***************************************************************************/
+  /* Request and verify the throttling state.                                */
+  /***************************************************************************/
+  handle_json_response(json_command_list_provide, &post);
+  assert(post.memory != NULL);
+  compare_strings(expected_post_fault_single,
+                  post.memory,
+                  strlen(expected_post_fault_single),
+                  "Fault - Single Field");
+  free(post.memory);
+  post.memory = NULL;
+
+  /***************************************************************************/
+  /* Update a specification with two faults suppressed.                      */
+  /***************************************************************************/
+  handle_json_response(json_command_list_fault_double, &post);
+
+  /***************************************************************************/
+  /* Check that the FAULT domain is throttled.                               */
+  /***************************************************************************/
+  assert(evel_get_throttle_spec(EVEL_DOMAIN_FAULT) != NULL);
+  for (domain = EVEL_DOMAIN_MEASUREMENT; domain < EVEL_MAX_DOMAINS; domain++)
+  {
+    if (domain != EVEL_DOMAIN_FAULT)
+    {
+      assert(evel_get_throttle_spec(domain) == NULL);
+    }
+  }
+  assert(post.memory == NULL);
+
+  /***************************************************************************/
+  /* Request and verify the throttling state.                                */
+  /***************************************************************************/
+  handle_json_response(json_command_list_provide, &post);
+  assert(post.memory != NULL);
+  compare_strings(expected_post_fault_double,
+                  post.memory,
+                  strlen(expected_post_fault_double),
+                  "Fault - Double Field");
+  free(post.memory);
+  post.memory = NULL;
+
+  /***************************************************************************/
+  /* Now clear the FAULT domain.                                             */
+  /***************************************************************************/
+  handle_json_response(json_command_list_fault_clear, &post);
+  for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++)
+  {
+    assert(evel_get_throttle_spec(domain) == NULL);
+  }
+
+  evel_throttle_terminate();
+}
+
+/**************************************************************************//**
+ * Test a single domain, nv_pair suppression.
+ *****************************************************************************/
+void test_json_throttle_spec_nv_pair()
+{
+  MEMORY_CHUNK post;
+  int domain;
+
+  char * json_command_list_fault_pair_single =
+    "{"
+    "\"commandList\": ["
+    "{"
+    "\"command\": {"
+    "\"commandType\": \"throttlingSpecification\", "
+    "\"eventDomainThrottleSpecification\": {"
+    "\"eventDomain\": \"fault\", "
+    "\"suppressedNvPairsList\": ["
+    "{"
+    "\"nvPairFieldName\": \"alarmAdditionalInformation\", "
+    "\"suppressedNvPairNames\": [\"name1\"]"
+    "}"
+    "]"
+    "}"
+    "}"
+    "}"
+    "]"
+    "}";
+
+  char * json_command_list_fault_pair_double =
+    "{"
+    "\"commandList\": ["
+    "{"
+    "\"command\": {"
+    "\"commandType\": \"throttlingSpecification\", "
+    "\"eventDomainThrottleSpecification\": {"
+    "\"eventDomain\": \"fault\", "
+    "\"suppressedNvPairsList\": ["
+    "{"
+    "\"nvPairFieldName\": \"alarmAdditionalInformation\", "
+    "\"suppressedNvPairNames\": [\"name1\", \"name2\"]"
+    "}"
+    "]"
+    "}"
+    "}"
+    "}"
+    "]"
+    "}";
+
+  char * expected_post_fault_pair_single =
+    "{"
+    "\"eventThrottlingState\": {"
+    "\"eventThrottlingMode\": \"throttled\", "
+    "\"eventDomainThrottleSpecificationList\": ["
+    "{"
+    "\"eventDomain\": \"fault\", "
+    "\"suppressedNvPairsList\": ["
+    "{"
+    "\"nvPairFieldName\": \"alarmAdditionalInformation\", "
+    "\"suppressedNvPairNames\": [\"name1\"]"
+    "}"
+    "]"
+    "}"
+    "]"
+    "}"
+    "}";
+
+  char * expected_post_fault_pair_double =
+    "{"
+    "\"eventThrottlingState\": {"
+    "\"eventThrottlingMode\": \"throttled\", "
+    "\"eventDomainThrottleSpecificationList\": ["
+    "{"
+    "\"eventDomain\": \"fault\", "
+    "\"suppressedNvPairsList\": ["
+    "{"
+    "\"nvPairFieldName\": \"alarmAdditionalInformation\", "
+    "\"suppressedNvPairNames\": [\"name1\", \"name2\"]"
+    "}"
+    "]"
+    "}"
+    "]"
+    "}"
+    "}";
+
+  /***************************************************************************/
+  /* Initialize and provide a specification with a single nvpair with a      */
+  /* single sub-field suppressed.                                            */
+  /***************************************************************************/
+  evel_throttle_initialize();
+  handle_json_response(json_command_list_fault_pair_single, &post);
+
+  /***************************************************************************/
+  /* Check that the FAULT domain is throttled.                               */
+  /***************************************************************************/
+  assert(evel_get_throttle_spec(EVEL_DOMAIN_FAULT) != NULL);
+  for (domain = EVEL_DOMAIN_MEASUREMENT; domain < EVEL_MAX_DOMAINS; domain++)
+  {
+    if (domain != EVEL_DOMAIN_FAULT)
+    {
+      assert(evel_get_throttle_spec(domain) == NULL);
+    }
+  }
+  assert(post.memory == NULL);
+
+  /***************************************************************************/
+  /* Request and verify the throttling state.                                */
+  /***************************************************************************/
+  handle_json_response(json_command_list_provide, &post);
+  assert(post.memory != NULL);
+  compare_strings(expected_post_fault_pair_single,
+                  post.memory,
+                  strlen(expected_post_fault_pair_single),
+                  "Fault - Single Pair, Single Field");
+  free(post.memory);
+  post.memory = NULL;
+
+  /***************************************************************************/
+  /* Update a specification with a single nvpair with two sub-fields         */
+  /* suppressed.                                                             */
+  /***************************************************************************/
+  handle_json_response(json_command_list_fault_pair_double, &post);
+
+  /***************************************************************************/
+  /* Check that the FAULT domain is throttled.                               */
+  /***************************************************************************/
+  assert(evel_get_throttle_spec(EVEL_DOMAIN_FAULT) != NULL);
+  for (domain = EVEL_DOMAIN_MEASUREMENT; domain < EVEL_MAX_DOMAINS; domain++)
+  {
+    if (domain != EVEL_DOMAIN_FAULT)
+    {
+      assert(evel_get_throttle_spec(domain) == NULL);
+    }
+  }
+  assert(post.memory == NULL);
+
+  /***************************************************************************/
+  /* Request and verify the throttling state.                                */
+  /***************************************************************************/
+  handle_json_response(json_command_list_provide, &post);
+  assert(post.memory != NULL);
+  compare_strings(expected_post_fault_pair_double,
+                  post.memory,
+                  strlen(expected_post_fault_pair_double),
+                  "Fault - Double Field");
+  free(post.memory);
+  post.memory = NULL;
+
+  /***************************************************************************/
+  /* Now clear the FAULT domain.                                             */
+  /***************************************************************************/
+  handle_json_response(json_command_list_fault_clear, &post);
+  for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++)
+  {
+    assert(evel_get_throttle_spec(domain) == NULL);
+  }
+
+  evel_throttle_terminate();
+}
+
+/**************************************************************************//**
+ * Test two domains, nv_pair suppression.
+ *****************************************************************************/
+void test_json_throttle_spec_two_domains()
+{
+  MEMORY_CHUNK post;
+  int domain;
+
+  char * json_command_list_two_domains =
+    "{"
+    "\"commandList\": ["
+    "{"
+    "\"command\": {"
+    "\"commandType\": \"throttlingSpecification\", "
+    "\"eventDomainThrottleSpecification\": {"
+    "\"eventDomain\": \"fault\", "
+    "\"suppressedFieldNames\": [\"alarmInterfaceA\"], "
+    "\"suppressedNvPairsList\": ["
+    "{"
+    "\"nvPairFieldName\": \"alarmAdditionalInformation\", "
+    "\"suppressedNvPairNames\": [\"name1\"]"
+    "}]}}}, "
+    "{"
+    "\"command\": {"
+    "\"commandType\": \"throttlingSpecification\", "
+    "\"eventDomainThrottleSpecification\": {"
+    "\"eventDomain\": \"syslog\", "
+    "\"suppressedFieldNames\": [\"syslogProcId\"], "
+    "\"suppressedNvPairsList\": ["
+    "{"
+    "\"nvPairFieldName\": \"additionalFields\", "
+    "\"suppressedNvPairNames\": [\"name1\"]"
+    "}]}}}"
+    "]"
+    "}";
+
+  char * expected_post_two_domains =
+    "{"
+    "\"eventThrottlingState\": {"
+    "\"eventThrottlingMode\": \"throttled\", "
+    "\"eventDomainThrottleSpecificationList\": ["
+    "{"
+    "\"eventDomain\": \"fault\", "
+    "\"suppressedFieldNames\": [\"alarmInterfaceA\"], "
+    "\"suppressedNvPairsList\": ["
+    "{"
+    "\"nvPairFieldName\": \"alarmAdditionalInformation\", "
+    "\"suppressedNvPairNames\": [\"name1\"]"
+    "}]}, "
+    "{"
+    "\"eventDomain\": \"syslog\", "
+    "\"suppressedFieldNames\": [\"syslogProcId\"], "
+    "\"suppressedNvPairsList\": ["
+    "{"
+    "\"nvPairFieldName\": \"additionalFields\", "
+    "\"suppressedNvPairNames\": [\"name1\"]"
+    "}]}"
+    "]"
+    "}"
+    "}";
+
+  /***************************************************************************/
+  /* Initialize and provide a specification with a single nvpair with a      */
+  /* single sub-field suppressed.                                            */
+  /***************************************************************************/
+  evel_throttle_initialize();
+  handle_json_response(json_command_list_two_domains, &post);
+
+  /***************************************************************************/
+  /* Check that the FAULT and SYSLOG domains are throttled.                  */
+  /***************************************************************************/
+  assert(evel_get_throttle_spec(EVEL_DOMAIN_FAULT) != NULL);
+  assert(evel_get_throttle_spec(EVEL_DOMAIN_SYSLOG) != NULL);
+  for (domain = EVEL_DOMAIN_MEASUREMENT; domain < EVEL_MAX_DOMAINS; domain++)
+  {
+    if ((domain != EVEL_DOMAIN_FAULT) && (domain != EVEL_DOMAIN_SYSLOG))
+    {
+      assert(evel_get_throttle_spec(domain) == NULL);
+    }
+  }
+  assert(post.memory == NULL);
+
+  /***************************************************************************/
+  /* Request and verify the throttling state.                                */
+  /***************************************************************************/
+  handle_json_response(json_command_list_provide, &post);
+  assert(post.memory != NULL);
+  compare_strings(expected_post_two_domains,
+                  post.memory,
+                  strlen(expected_post_two_domains),
+                  "Fault - Two Domains");
+  free(post.memory);
+  post.memory = NULL;
+
+  /***************************************************************************/
+  /* Now clear the FAULT and SYSLOG domains.                                 */
+  /***************************************************************************/
+  handle_json_response(json_command_list_fault_clear, &post);
+  assert(evel_get_throttle_spec(EVEL_DOMAIN_FAULT) == NULL);
+  assert(evel_get_throttle_spec(EVEL_DOMAIN_SYSLOG) != NULL);
+  handle_json_response(json_command_list_syslog_clear, &post);
+  for (domain = EVEL_DOMAIN_FAULT; domain < EVEL_MAX_DOMAINS; domain++)
+  {
+    assert(evel_get_throttle_spec(domain) == NULL);
+  }
+
+  evel_throttle_terminate();
+}
+
+/**************************************************************************//**
+ * Test bad command type.
+ *****************************************************************************/
+void test_json_throttle_spec_bad_command_type()
+{
+  MEMORY_CHUNK post;
+  int domain;
+
+  /***************************************************************************/
+  /* Search for "dodgy" in the JSON, and you will see the dodgy bits we're   */
+  /* handling in these tests.                                                */
+  /***************************************************************************/
+  #define NUM_BAD_COMMANDS 8
+  char * json_command_list_dodgy_command =
+    "{"
+    "\"commandList\": ["
+    "{"
+    "\"command\": {"
+    "\"commandType\": \"dodgyCommand\", "
+    "\"eventDomainThrottleSpecification\": {"
+    "\"eventDomain\": \"fault\", "
+    "\"suppressedFieldNames\": [\"alarmInterfaceA\"], "
+    "\"suppressedNvPairsList\": ["
+    "{"
+    "\"nvPairFieldName\": \"alarmAdditionalInformation\", "
+    "\"suppressedNvPairNames\": [\"name1\"]"
+    "}]}}}"
+    "]"
+    "}";
+
+  char * json_command_list_dodgy_spec =
+    "{"
+    "\"commandList\": ["
+    "{"
+    "\"command\": {"
+    "\"commandType\": \"throttlingSpecification\", "
+    "\"dodgyEventDomainThrottleSpecification\": {"
+    "\"eventDomain\": \"fault\", "
+    "\"suppressedFieldNames\": [\"alarmInterfaceA\"], "
+    "\"suppressedNvPairsList\": ["
+    "{"
+    "\"nvPairFieldName\": \"alarmAdditionalInformation\", "
+    "\"suppressedNvPairNames\": [\"name1\"]"
+    "}]}}}"
+    "]"
+    "}";
+
+  char * json_command_list_dodgy_event_domain_key =
+    "{"
+    "\"commandList\": ["
+    "{"
+    "\"command\": {"
+    "\"commandType\": \"throttlingSpecification\", "
+    "\"eventDomainThrottleSpecification\": {"
+    "\"dodgyEventDomainKey\": \"fault\", "
+    "\"suppressedFieldNames\": [\"alarmInterfaceA\"], "
+    "\"suppressedNvPairsList\": ["
+    "{"
+    "\"nvPairFieldName\": \"alarmAdditionalInformation\", "
+    "\"suppressedNvPairNames\": [\"name1\"]"
+    "}]}}}"
+    "]"
+    "}";
+
+  char * json_command_list_dodgy_event_domain =
+    "{"
+    "\"commandList\": ["
+    "{"
+    "\"command\": {"
+    "\"commandType\": \"throttlingSpecification\", "
+    "\"eventDomainThrottleSpecification\": {"
+    "\"eventDomain\": \"dodgyEventDomain\", "
+    "\"suppressedFieldNames\": [\"alarmInterfaceA\"], "
+    "\"suppressedNvPairsList\": ["
+    "{"
+    "\"nvPairFieldName\": \"alarmAdditionalInformation\", "
+    "\"suppressedNvPairNames\": [\"name1\"]"
+    "}]}}}"
+    "]"
+    "}";
+
+  char * json_command_list_dodgy_field_names_key =
+    "{"
+    "\"commandList\": ["
+    "{"
+    "\"command\": {"
+    "\"commandType\": \"throttlingSpecification\", "
+    "\"eventDomainThrottleSpecification\": {"
+    "\"eventDomain\": \"fault\", "
+    "\"suppressedNvPairsList\": ["
+    "{"
+    "\"nvPairFieldName\": \"alarmAdditionalInformation\", "
+    "\"suppressedNvPairNames\": [\"name1\"]"
+    "}]}}}"
+    "]"
+    "}";
+
+  char * json_command_list_dodgy_pair_names_list_key =
+    "{"
+    "\"commandList\": ["
+    "{"
+    "\"command\": {"
+    "\"commandType\": \"throttlingSpecification\", "
+    "\"eventDomainThrottleSpecification\": {"
+    "\"eventDomain\": \"fault\", "
+    "\"suppressedFieldNames\": [\"alarmInterfaceA\"], "
+    "\"dodgySuppressedNvPairsListKey\": ["
+    "{"
+    "\"nvPairFieldName\": \"alarmAdditionalInformation\", "
+    "\"suppressedNvPairNames\": [\"name1\"]"
+    "}]}}}"
+    "]"
+    "}";
+
+  char * json_command_list_dodgy_pair_field_name_key =
+    "{"
+    "\"commandList\": ["
+    "{"
+    "\"command\": {"
+    "\"commandType\": \"throttlingSpecification\", "
+    "\"eventDomainThrottleSpecification\": {"
+    "\"eventDomain\": \"fault\", "
+    "\"suppressedFieldNames\": [\"alarmInterfaceA\"], "
+    "\"suppressedNvPairsList\": ["
+    "{"
+    "\"dodgyNvPairFieldNameKey\": \"alarmAdditionalInformation\", "
+    "\"suppressedNvPairNames\": [\"name1\"]"
+    "}]}}}"
+    "]"
+    "}";
+
+  char * json_command_list_dodgy_pair_names_key =
+    "{"
+    "\"commandList\": ["
+    "{"
+    "\"command\": {"
+    "\"commandType\": \"throttlingSpecification\", "
+    "\"eventDomainThrottleSpecification\": {"
+    "\"eventDomain\": \"fault\", "
+    "\"suppressedFieldNames\": [\"alarmInterfaceA\"], "
+    "\"suppressedNvPairsList\": ["
+    "{"
+    "\"nvPairFieldName\": \"alarmAdditionalInformation\", "
+    "\"dodgySuppressedNvPairNamesKey\": [\"name1\"]"
+    "}]}}}"
+    "]"
+    "}";
+
+  char * json_command_list_dodgy_depth =
+    "{"
+    "\"commandList\": ["
+    "{"
+    "\"command\": {"
+    "\"commandType\": \"throttlingSpecification\", "
+    "\"eventDomainThrottleSpecification\": {"
+    "\"eventDomain\": \"fault\", "
+    "\"suppressedFieldNames\": [\"alarmInterfaceA\"], "
+    "\"suppressedNvPairsList\": ["
+    "{"
+    "\"nvPairFieldName\": \"alarmAdditionalInformation\", "
+    "\"dodgySuppressedNvPairNamesKey\": "
+    "[\"name1\", [[[[[[[[]]]]]]]]]"
+    "}]}}}"
+    "]"
+    "}";
+
+  char * expected_throttle_state_dodgy_field_names_key =
+    "{"
+    "\"eventThrottlingState\": {"
+    "\"eventThrottlingMode\": \"throttled\", "
+    "\"eventDomainThrottleSpecificationList\": ["
+    "{"
+    "\"eventDomain\": \"fault\", "
+    "\"suppressedNvPairsList\": ["
+    "{"
+    "\"nvPairFieldName\": \"alarmAdditionalInformation\", "
+    "\"suppressedNvPairNames\": [\"name1\"]"
+    "}]}"
+    "]"
+    "}"
+    "}";
+
+  char * expected_throttle_state_dodgy_pair_names_list_key =
+    "{"
+    "\"eventThrottlingState\": {"
+    "\"eventThrottlingMode\": \"throttled\", "
+    "\"eventDomainThrottleSpecificationList\": ["
+    "{"
+    "\"eventDomain\": \"fault\", "
+    "\"suppressedFieldNames\": [\"alarmInterfaceA\"]"
+    "}"
+    "]"
+    "}"
+    "}";
+
+  char * expected_throttle_state_dodgy_pair_field_name_key =
+    "{"
+    "\"eventThrottlingState\": {"
+    "\"eventThrottlingMode\": \"throttled\", "
+    "\"eventDomainThrottleSpecificationList\": ["
+    "{"
+    "\"eventDomain\": \"fault\", "
+    "\"suppressedFieldNames\": [\"alarmInterfaceA\"]"
+    "}"
+    "]"
+    "}"
+    "}";
+
+  char * expected_throttle_state_dodgy_pair_names_key =
+    "{"
+    "\"eventThrottlingState\": {"
+    "\"eventThrottlingMode\": \"throttled\", "
+    "\"eventDomainThrottleSpecificationList\": ["
+    "{"
+    "\"eventDomain\": \"fault\", "
+    "\"suppressedFieldNames\": [\"alarmInterfaceA\"]"
+    "}"
+    "]"
+    "}"
+    "}";
+
+  char * json_command_lists[] = {
+    json_command_list_dodgy_command,
+    json_command_list_dodgy_spec,
+    json_command_list_dodgy_event_domain_key,
+    json_command_list_dodgy_event_domain,
+    json_command_list_dodgy_depth,
+    json_command_list_dodgy_field_names_key,
+    json_command_list_dodgy_pair_names_list_key,
+    json_command_list_dodgy_pair_field_name_key,
+    json_command_list_dodgy_pair_names_key
+  };
+
+  char * expected_posts[] = {
+    expected_throttle_state_normal,
+    expected_throttle_state_normal,
+    expected_throttle_state_normal,
+    expected_throttle_state_normal,
+    expected_throttle_state_normal,
+    expected_throttle_state_dodgy_field_names_key,
+    expected_throttle_state_dodgy_pair_names_list_key,
+    expected_throttle_state_dodgy_pair_field_name_key,
+    expected_throttle_state_dodgy_pair_names_key
+   };
+
+  const int num_commands =
+    sizeof(json_command_lists) / sizeof(json_command_lists[0]);
+  const int num_posts =
+    sizeof(expected_posts) / sizeof(expected_posts[0]);
+  assert(num_commands == num_posts);
+
+  /***************************************************************************/
+  /* Initialize and provide a specification with a single nvpair with a      */
+  /* single sub-field suppressed.                                            */
+  /***************************************************************************/
+  evel_throttle_initialize();
+
+  int ii;
+  for (ii = 0; ii < num_commands; ii++)
+  {
+    EVEL_DEBUG("Testing commandList[%d] = %s\n", ii, json_command_lists[ii]);
+    handle_json_response(json_command_lists[ii], &post);
+
+    /*************************************************************************/
+    /* Check that throttling is in a normal state - because we ignored the   */
+    /* command / .....                                                       */
+    /*************************************************************************/
+    for (domain = EVEL_DOMAIN_MEASUREMENT; domain < EVEL_MAX_DOMAINS; domain++)
+    {
+      assert(evel_get_throttle_spec(domain) == NULL);
+    }
+    if (expected_posts[ii] == expected_throttle_state_normal)
+    {
+      assert(evel_get_throttle_spec(EVEL_DOMAIN_FAULT) == NULL);
+    }
+    else
+    {
+      assert(evel_get_throttle_spec(EVEL_DOMAIN_FAULT) != NULL);
+    }
+    assert(post.memory == NULL);
+
+    /*************************************************************************/
+    /* Request and verify the throttling state.                              */
+    /*************************************************************************/
+    handle_json_response(json_command_list_provide, &post);
+    assert(post.memory != NULL);
+    compare_strings(expected_posts[ii],
+                    post.memory,
+                    strlen(expected_posts[ii]),
+                    "Throttle State Normal");
+    free(post.memory);
+    post.memory = NULL;
+  }
+
+  evel_throttle_terminate();
+}
+
+void test_encode_fault_throttled()
+{
+  MEMORY_CHUNK post;
+
+  /***************************************************************************/
+  /* We also test suppression of the event header parameters here.           */
+  /***************************************************************************/
+  char * json_command_list =
+    "{"
+    "\"commandList\": ["
+    "{"
+    "\"command\": {"
+    "\"commandType\": \"throttlingSpecification\", "
+    "\"eventDomainThrottleSpecification\": {"
+    "\"eventDomain\": \"fault\", "
+    "\"suppressedFieldNames\": ["
+    "\"alarmInterfaceA\", "
+    "\"eventType\", "
+    "\"reportingEntityId\", "
+    "\"sourceId\"], "
+    "\"suppressedNvPairsList\": ["
+    "{"
+    "\"nvPairFieldName\": \"alarmAdditionalInformation\", "
+    "\"suppressedNvPairNames\": [\"name3\", \"name4\"]"
+    "}]}}}"
+    "]"
+    "}";
+
+  char * expected =
+    "{\"event\": {"
+    "\"commonEventHeader\": {"
+    "\"domain\": \"fault\", "
+    "\"eventId\": \"122\", "
+    "\"functionalRole\": \"UNIT TEST\", "
+    "\"lastEpochMicrosec\": 1000002, "
+    "\"priority\": \"Normal\", "
+    "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", "
+    "\"sequence\": 122, "
+    "\"sourceName\": \"Dummy VM name - No Metadata available\", "
+    "\"startEpochMicrosec\": 1000002, "
+    "\"version\": 1.2"
+    "}, "
+    "\"faultFields\": {"
+    "\"alarmCondition\": \"My alarm condition\", "
+    "\"eventSeverity\": \"MAJOR\", "
+    "\"eventSourceType\": \"other\", "
+    "\"specificProblem\": \"It broke very badly\", "
+    "\"vfStatus\": \"Active\", "
+    "\"faultFieldsVersion\": 1.1, "
+    "\"alarmAdditionalInformation\": ["
+    "{\"name\": \"name1\", "
+    "\"value\": \"value1\"}, "
+    "{\"name\": \"name2\", "
+    "\"value\": \"value2\"}]"
+    "}}}";
+
+  /***************************************************************************/
+  /* Initialize and provide a specification with a single fault suppressed.  */
+  /***************************************************************************/
+  evel_throttle_initialize();
+  handle_json_response(json_command_list, &post);
+
+  /***************************************************************************/
+  /* Check that the domain is throttled.                                     */
+  /***************************************************************************/
+  assert(evel_get_throttle_spec(EVEL_DOMAIN_FAULT) != NULL);
+  assert(post.memory == NULL);
+
+  size_t json_size = 0;
+  char json_body[EVEL_MAX_JSON_BODY];
+  evel_set_next_event_sequence(122);
+  EVENT_FAULT * fault = evel_new_fault("My alarm condition",
+                                       "It broke very badly",
+                                       EVEL_PRIORITY_NORMAL,
+                                       EVEL_SEVERITY_MAJOR);
+  assert(fault != NULL);
+  evel_fault_type_set(fault, "Bad things happen...");
+  evel_fault_addl_info_add(fault, "name1", "value1");
+  evel_fault_addl_info_add(fault, "name2", "value2");
+
+  /***************************************************************************/
+  /* Suppressed fields.                                                      */
+  /***************************************************************************/
+  evel_fault_interface_set(fault, "My Interface Card");
+  evel_fault_addl_info_add(fault, "name3", "value3");
+  evel_fault_addl_info_add(fault, "name4", "value4");
+
+  json_size = evel_json_encode_event(
+    json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) fault);
+  compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Fault");
+  assert((json_size == strlen(json_body)) && "Bad size returned");
+
+  evel_free_event(fault);
+  evel_throttle_terminate();
+}
+
+void test_encode_measurement_throttled()
+{
+  MEMORY_CHUNK post;
+
+  /***************************************************************************/
+  /* We also test suppression of the event header parameters here.           */
+  /***************************************************************************/
+  char * json_command_list =
+    "{"
+    "\"commandList\": ["
+    "{"
+    "\"command\": {"
+    "\"commandType\": \"throttlingSpecification\", "
+    "\"eventDomainThrottleSpecification\": {"
+    "\"eventDomain\": \"measurementsForVfScaling\", "
+    "\"suppressedFieldNames\": ["
+    "\"errors\", "
+    "\"vnfcScalingMetric\", "
+    "\"numberOfMediaPortsInUse\", "
+    "\"aggregateCpuUsage\", "
+    "\"requestRate\", "
+    "\"memoryUsed\", "
+    "\"memoryConfigured\", "
+    "\"meanRequestLatency\", "
+    "\"latencyDistribution\", "
+    "\"concurrentSessions\", "
+    "\"configuredEntities\", "
+    "\"eventType\", "
+    "\"reportingEntityId\", "
+    "\"sourceId\"], "
+    "\"suppressedNvPairsList\": ["
+    "{"
+    "\"nvPairFieldName\": \"cpuUsageArray\", "
+    "\"suppressedNvPairNames\": [\"cpu3\", \"cpu4\"]"
+    "}, "
+    "{"
+    "\"nvPairFieldName\": \"filesystemUsageArray\", "
+    "\"suppressedNvPairNames\": [\"00-11-22\", \"33-44-55\"]"
+    "}, "
+    "{"
+    "\"nvPairFieldName\": \"vNicUsageArray\", "
+    "\"suppressedNvPairNames\": [\"eth1\", \"eth0\"]"
+    "}, "
+    "{"
+    "\"nvPairFieldName\": \"featureUsageArray\", "
+    "\"suppressedNvPairNames\": [\"FeatureB\", \"FeatureC\"]"
+    "},"
+    "{"
+    "\"nvPairFieldName\": \"codecUsageArray\", "
+    "\"suppressedNvPairNames\": [\"G729ab\"]"
+    "},"
+    "{"
+    "\"nvPairFieldName\": \"additionalMeasurements\", "
+    "\"suppressedNvPairNames\": [\"Group2\"]"
+    "}"
+    "]}}}"
+    "]"
+    "}";
+
+  char * expected =
+    "{\"event\": "
+    "{\"commonEventHeader\": {"
+    "\"domain\": \"measurementsForVfScaling\", "
+    "\"eventId\": \"123\", "
+    "\"functionalRole\": \"UNIT TEST\", "
+    "\"lastEpochMicrosec\": 1000002, "
+    "\"priority\": \"Normal\", "
+    "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", "
+    "\"sequence\": 123, "
+    "\"sourceName\": \"Dummy VM name - No Metadata available\", "
+    "\"startEpochMicrosec\": 1000002, "
+    "\"version\": 1.2"
+    "}, "
+    "\"measurementsForVfScalingFields\": "
+    "{"
+    "\"measurementInterval\": 5.500000, "
+    "\"cpuUsageArray\": ["
+    "{\"cpuIdentifier\": \"cpu1\", "
+    "\"percentUsage\": 11.110000}, "
+    "{\"cpuIdentifier\": \"cpu2\", "
+    "\"percentUsage\": 22.220000}], "
+    "\"filesystemUsageArray\": ["
+    "{\"blockConfigured\": 500.110000, "
+    "\"blockIops\": 77, "
+    "\"blockUsed\": 500.220000, "
+    "\"ephemeralConfigured\": 500.110000, "
+    "\"ephemeralIops\": 88, "
+    "\"ephemeralUsed\": 600.220000, "
+    "\"filesystemName\": \"66-77-88\"}], "
+    "\"featureUsageArray\": ["
+    "{\"featureIdentifier\": \"FeatureA\", "
+    "\"featureUtilization\": 123}], "
+    "\"codecUsageArray\": ["
+    "{\"codecIdentifier\": \"G711a\", "
+    "\"numberInUse\": 91}], "
+    "\"additionalMeasurements\": ["
+    "{\"name\": \"Group1\", "
+    "\"measurements\": ["
+    "{\"name\": \"Name1\", "
+    "\"value\": \"Value1\"}]}], "
+    "\"measurementsForVfScalingVersion\": 1.1}}}";
+
+  /***************************************************************************/
+  /* Initialize and provide a specification with a single fault suppressed.  */
+  /***************************************************************************/
+  evel_throttle_initialize();
+  handle_json_response(json_command_list, &post);
+
+  /***************************************************************************/
+  /* Check that the domain is throttled.                                     */
+  /***************************************************************************/
+  assert(evel_get_throttle_spec(EVEL_DOMAIN_MEASUREMENT) != NULL);
+  assert(post.memory == NULL);
+
+  size_t json_size = 0;
+  char json_body[EVEL_MAX_JSON_BODY];
+  evel_set_next_event_sequence(123);
+  EVENT_MEASUREMENT * measurement = evel_new_measurement(5.5);
+  MEASUREMENT_LATENCY_BUCKET * bucket = NULL;
+  MEASUREMENT_VNIC_USE * vnic_use = NULL;
+  assert(measurement != NULL);
+
+  evel_measurement_type_set(measurement, "Perf management...");
+  evel_measurement_conc_sess_set(measurement, 1);
+  evel_measurement_cfg_ents_set(measurement, 2);
+  evel_measurement_mean_req_lat_set(measurement, 4.4);
+  evel_measurement_mem_cfg_set(measurement, 6.6);
+  evel_measurement_mem_used_set(measurement, 3.3);
+  evel_measurement_request_rate_set(measurement, 7);
+  evel_measurement_agg_cpu_use_set(measurement, 8.8);
+  evel_measurement_cpu_use_add(measurement, "cpu1", 11.11);
+  evel_measurement_cpu_use_add(measurement, "cpu2", 22.22);
+  evel_measurement_cpu_use_add(measurement, "cpu3", 33.33);
+  evel_measurement_cpu_use_add(measurement, "cpu4", 44.44);
+  evel_measurement_fsys_use_add(measurement, "00-11-22",
+                                100.11, 100.22, 33,
+                                200.11, 200.22, 44);
+  evel_measurement_fsys_use_add(measurement, "33-44-55",
+                                300.11, 300.22, 55,
+                                400.11, 400.22, 66);
+  evel_measurement_fsys_use_add(measurement, "66-77-88",
+                                500.11, 500.22, 77,
+                                600.11, 600.22, 88);
+
+  bucket = evel_new_meas_latency_bucket(20);
+  evel_meas_latency_bucket_add(measurement, bucket);
+
+  bucket = evel_new_meas_latency_bucket(30);
+  evel_meas_latency_bucket_low_end_set(bucket, 10.0);
+  evel_meas_latency_bucket_high_end_set(bucket, 20.0);
+  evel_meas_latency_bucket_add(measurement, bucket);
+
+  vnic_use = evel_new_measurement_vnic_use("eth0", 100, 200, 3, 4);
+  evel_vnic_use_bcast_pkt_in_set(vnic_use, 1);
+  evel_vnic_use_bcast_pkt_out_set(vnic_use, 2);
+  evel_vnic_use_mcast_pkt_in_set(vnic_use, 5);
+  evel_vnic_use_mcast_pkt_out_set(vnic_use, 6);
+  evel_vnic_use_ucast_pkt_in_set(vnic_use, 7);
+  evel_vnic_use_ucast_pkt_out_set(vnic_use, 8);
+  evel_meas_vnic_use_add(measurement, vnic_use);
+
+  vnic_use = evel_new_measurement_vnic_use("eth1", 110, 240, 13, 14);
+  evel_vnic_use_bcast_pkt_in_set(vnic_use, 11);
+  evel_vnic_use_bcast_pkt_out_set(vnic_use, 12);
+  evel_vnic_use_mcast_pkt_in_set(vnic_use, 15);
+  evel_vnic_use_mcast_pkt_out_set(vnic_use, 16);
+  evel_vnic_use_ucast_pkt_in_set(vnic_use, 17);
+  evel_vnic_use_ucast_pkt_out_set(vnic_use, 18);
+  evel_meas_vnic_use_add(measurement, vnic_use);
+
+  evel_measurement_errors_set(measurement, 1, 0, 2, 1);
+  evel_measurement_feature_use_add(measurement, "FeatureA", 123);
+  evel_measurement_feature_use_add(measurement, "FeatureB", 567);
+  evel_measurement_codec_use_add(measurement, "G711a", 91);
+  evel_measurement_codec_use_add(measurement, "G729ab", 92);
+  evel_measurement_media_port_use_set(measurement, 1234);
+  evel_measurement_vnfc_scaling_metric_set(measurement, 1234.5678);
+  evel_measurement_custom_measurement_add(measurement,
+                                          "Group1", "Name1", "Value1");
+  evel_measurement_custom_measurement_add(measurement,
+                                          "Group2", "Name1", "Value1");
+  evel_measurement_custom_measurement_add(measurement,
+                                          "Group2", "Name2", "Value2");
+
+  json_size = evel_json_encode_event(
+    json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) measurement);
+  compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Measurement");
+  assert((json_size == strlen(json_body)) && "Bad size returned");
+
+  evel_free_event(measurement);
+  evel_throttle_terminate();
+}
+
+void test_encode_mobile_throttled()
+{
+  MEMORY_CHUNK post;
+
+  /***************************************************************************/
+  /* We also test suppression of the event header parameters here.           */
+  /***************************************************************************/
+  char * json_command_list =
+    "{"
+    "\"commandList\": ["
+    "{"
+    "\"command\": {"
+    "\"commandType\": \"throttlingSpecification\", "
+    "\"eventDomainThrottleSpecification\": {"
+    "\"eventDomain\": \"mobileFlow\", "
+    "\"suppressedFieldNames\": ["
+    "\"applicationType\", "
+    "\"appProtocolType\", "
+    "\"appProtocolVersion\", "
+    "\"cid\", "
+    "\"connectionType\", "
+    "\"ecgi\", "
+    "\"gtpProtocolType\", "
+    "\"gtpVersion\", "
+    "\"httpHeader\", "
+    "\"imei\", "
+    "\"imsi\", "
+    "\"lac\", "
+    "\"mcc\", "
+    "\"mnc\", "
+    "\"msisdn\", "
+    "\"otherFunctionalRole\", "
+    "\"rac\", "
+    "\"radioAccessTechnology\", "
+    "\"sac\", "
+    "\"samplingAlgorithm\", "
+    "\"tac\", "
+    "\"tunnelId\", "
+    "\"vlanId\", "
+    "\"eventType\", "
+    "\"reportingEntityId\", "
+    "\"sourceId\"], "
+    "\"suppressedNvPairsList\": ["
+    "]}}}"
+    "]"
+    "}";
+
+  char * expected =
+    "{\"event\": "
+    "{\"commonEventHeader\": {"
+    "\"domain\": \"mobileFlow\", "
+    "\"eventId\": \"1242\", "
+    "\"functionalRole\": \"UNIT TEST\", "
+    "\"lastEpochMicrosec\": 1000002, "
+    "\"priority\": \"Normal\", "
+    "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", "
+    "\"sequence\": 1242, "
+    "\"sourceName\": \"Dummy VM name - No Metadata available\", "
+    "\"startEpochMicrosec\": 1000002, "
+    "\"version\": 1.2"
+    "}, "
+    "\"mobileFlowFields\": {"
+    "\"flowDirection\": \"Inbound\", "
+    "\"gtpPerFlowMetrics\": {"
+    "\"avgBitErrorRate\": 132.000100, "
+    "\"avgPacketDelayVariation\": 31.200000, "
+    "\"avgPacketLatency\": 101, "
+    "\"avgReceiveThroughput\": 2101, "
+    "\"avgTransmitThroughput\": 501, "
+    "\"flowActivationEpoch\": 1470409422, "
+    "\"flowActivationMicrosec\": 988, "
+    "\"flowDeactivationEpoch\": 1470409432, "
+    "\"flowDeactivationMicrosec\": 12, "
+    "\"flowDeactivationTime\": \"Fri, 05 Aug 2016 15:03:52 +0000\", "
+    "\"flowStatus\": \"Inactive\", "
+    "\"maxPacketDelayVariation\": 88, "
+    "\"numActivationFailures\": 4, "
+    "\"numBitErrors\": 18, "
+    "\"numBytesReceived\": 123655, "
+    "\"numBytesTransmitted\": 4562, "
+    "\"numDroppedPackets\": 1, "
+    "\"numL7BytesReceived\": 13, "
+    "\"numL7BytesTransmitted\": 11, "
+    "\"numLostPackets\": 2, "
+    "\"numOutOfOrderPackets\": 4, "
+    "\"numPacketErrors\": 8, "
+    "\"numPacketsReceivedExclRetrans\": 900, "
+    "\"numPacketsReceivedInclRetrans\": 902, "
+    "\"numPacketsTransmittedInclRetrans\": 303, "
+    "\"numRetries\": 7, "
+    "\"numTimeouts\": 3, "
+    "\"numTunneledL7BytesReceived\": 1, "
+    "\"roundTripTime\": 111, "
+    "\"timeToFirstByte\": 226, "
+    "\"ipTosCountList\": ["
+    "[\"1\", 13], "
+    "[\"4\", 99], "
+    "[\"17\", 1]], "
+    "\"ipTosList\": [\"1\", \"4\", \"17\"], "
+    "\"tcpFlagList\": [\"CWR\", \"URG\"], "
+    "\"tcpFlagCountList\": [[\"CWR\", 10], [\"URG\", 121]], "
+    "\"mobileQciCosList\": [\"conversational\", \"65\"], "
+    "\"mobileQciCosCountList\": [[\"conversational\", 11], [\"65\", 122]], "
+    "\"durConnectionFailedStatus\": 12, "
+    "\"durTunnelFailedStatus\": 13, "
+    "\"flowActivatedBy\": \"Remote\", "
+    "\"flowActivationTime\": \"Fri, 05 Aug 2016 15:03:43 +0000\", "
+    "\"flowDeactivatedBy\": \"Remote\", "
+    "\"gtpConnectionStatus\": \"Connected\", "
+    "\"gtpTunnelStatus\": \"Not tunneling\", "
+    "\"largePacketRtt\": 80, "
+    "\"largePacketThreshold\": 600.000000, "
+    "\"maxReceiveBitRate\": 1357924680, "
+    "\"maxTransmitBitRate\": 235711, "
+    "\"numGtpEchoFailures\": 1, "
+    "\"numGtpTunnelErrors\": 4, "
+    "\"numHttpErrors\": 2"
+    "}, "
+    "\"ipProtocolType\": \"UDP\", "
+    "\"ipVersion\": \"IPv6\", "
+    "\"otherEndpointIpAddress\": \"2.3.4.2\", "
+    "\"otherEndpointPort\": 2342, "
+    "\"reportingEndpointIpAddr\": \"4.2.3.2\", "
+    "\"reportingEndpointPort\": 4322"
+    "}}}";
+
+  /***************************************************************************/
+  /* Initialize and provide a specification with a single fault suppressed.  */
+  /***************************************************************************/
+  evel_throttle_initialize();
+  handle_json_response(json_command_list, &post);
+
+  /***************************************************************************/
+  /* Check that the domain is throttled.                                     */
+  /***************************************************************************/
+  assert(evel_get_throttle_spec(EVEL_DOMAIN_MOBILE_FLOW) != NULL);
+  assert(post.memory == NULL);
+
+  size_t json_size = 0;
+  char json_body[EVEL_MAX_JSON_BODY];
+  MOBILE_GTP_PER_FLOW_METRICS * metrics = NULL;
+  EVENT_MOBILE_FLOW * mobile_flow = NULL;
+
+  /***************************************************************************/
+  /* Mobile.                                                                 */
+  /***************************************************************************/
+  evel_set_next_event_sequence(1242);
+
+  metrics = evel_new_mobile_gtp_flow_metrics(132.0001,
+                                             31.2,
+                                             101,
+                                             2101,
+                                             501,
+                                             1470409422,
+                                             988,
+                                             1470409432,
+                                             12,
+                                             (time_t)1470409432,
+                                             "Inactive",
+                                             88,
+                                             4,
+                                             18,
+                                             123655,
+                                             4562,
+                                             1,
+                                             13,
+                                             11,
+                                             2,
+                                             4,
+                                             8,
+                                             900,
+                                             902,
+                                             303,
+                                             7,
+                                             3,
+                                             1,
+                                             111,
+                                             226);
+  assert(metrics != NULL);
+
+  evel_mobile_gtp_metrics_dur_con_fail_set(metrics, 12);
+  evel_mobile_gtp_metrics_dur_tun_fail_set(metrics, 13);
+  evel_mobile_gtp_metrics_act_by_set(metrics, "Remote");
+  evel_mobile_gtp_metrics_act_time_set(metrics, (time_t)1470409423);
+  evel_mobile_gtp_metrics_deact_by_set(metrics, "Remote");
+  evel_mobile_gtp_metrics_con_status_set(metrics, "Connected");
+  evel_mobile_gtp_metrics_tun_status_set(metrics, "Not tunneling");
+  evel_mobile_gtp_metrics_iptos_set(metrics, 1, 13);
+  evel_mobile_gtp_metrics_iptos_set(metrics, 17, 1);
+  evel_mobile_gtp_metrics_iptos_set(metrics, 4, 99);
+  evel_mobile_gtp_metrics_large_pkt_rtt_set(metrics, 80);
+  evel_mobile_gtp_metrics_large_pkt_thresh_set(metrics, 600.0);
+  evel_mobile_gtp_metrics_max_rcv_bit_rate_set(metrics, 1357924680);
+  evel_mobile_gtp_metrics_max_trx_bit_rate_set(metrics, 235711);
+  evel_mobile_gtp_metrics_num_echo_fail_set(metrics, 1);
+  evel_mobile_gtp_metrics_num_tun_fail_set(metrics, 4);
+  evel_mobile_gtp_metrics_num_http_errors_set(metrics, 2);
+  evel_mobile_gtp_metrics_tcp_flag_count_add(metrics, EVEL_TCP_CWR, 10);
+  evel_mobile_gtp_metrics_tcp_flag_count_add(metrics, EVEL_TCP_URG, 121);
+  evel_mobile_gtp_metrics_qci_cos_count_add(
+                                metrics, EVEL_QCI_COS_UMTS_CONVERSATIONAL, 11);
+  evel_mobile_gtp_metrics_qci_cos_count_add(
+                                            metrics, EVEL_QCI_COS_LTE_65, 122);
+
+  mobile_flow = evel_new_mobile_flow("Inbound",
+                                     metrics,
+                                     "UDP",
+                                     "IPv6",
+                                     "2.3.4.2",
+                                     2342,
+                                     "4.2.3.2",
+                                     4322);
+  assert(mobile_flow != NULL);
+
+  evel_mobile_flow_type_set(mobile_flow, "Mobile flow...");
+  evel_mobile_flow_app_type_set(mobile_flow, "Demo application");
+  evel_mobile_flow_app_prot_type_set(mobile_flow, "GSM");
+  evel_mobile_flow_app_prot_ver_set(mobile_flow, "1");
+  evel_mobile_flow_cid_set(mobile_flow, "65535");
+  evel_mobile_flow_con_type_set(mobile_flow, "S1-U");
+  evel_mobile_flow_ecgi_set(mobile_flow, "e65535");
+  evel_mobile_flow_gtp_prot_type_set(mobile_flow, "GTP-U");
+  evel_mobile_flow_gtp_prot_ver_set(mobile_flow, "1");
+  evel_mobile_flow_http_header_set(mobile_flow,
+                                   "http://www.something.com");
+  evel_mobile_flow_imei_set(mobile_flow, "209917614823");
+  evel_mobile_flow_imsi_set(mobile_flow, "355251/05/850925/8");
+  evel_mobile_flow_lac_set(mobile_flow, "1");
+  evel_mobile_flow_mcc_set(mobile_flow, "410");
+  evel_mobile_flow_mnc_set(mobile_flow, "04");
+  evel_mobile_flow_msisdn_set(mobile_flow, "6017123456789");
+  evel_mobile_flow_other_func_role_set(mobile_flow, "MME");
+  evel_mobile_flow_rac_set(mobile_flow, "514");
+  evel_mobile_flow_radio_acc_tech_set(mobile_flow, "LTE");
+  evel_mobile_flow_sac_set(mobile_flow, "1");
+  evel_mobile_flow_samp_alg_set(mobile_flow, 1);
+  evel_mobile_flow_tac_set(mobile_flow, "2099");
+  evel_mobile_flow_tunnel_id_set(mobile_flow, "Tunnel 1");
+  evel_mobile_flow_vlan_id_set(mobile_flow, "15");
+
+  json_size = evel_json_encode_event(
+    json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) mobile_flow);
+  compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Mobile");
+  assert((json_size == strlen(json_body)) && "Bad size returned");
+
+  evel_free_event(mobile_flow);
+  evel_throttle_terminate();
+}
+
+void test_encode_other_throttled()
+{
+  MEMORY_CHUNK post;
+
+  /***************************************************************************/
+  /* We also test suppression of the event header parameters here.           */
+  /***************************************************************************/
+  char * json_command_list =
+    "{"
+    "\"commandList\": ["
+    "{"
+    "\"command\": {"
+    "\"commandType\": \"throttlingSpecification\", "
+    "\"eventDomainThrottleSpecification\": {"
+    "\"eventDomain\": \"other\", "
+    "\"suppressedFieldNames\": ["
+    "\"eventType\", "
+    "\"reportingEntityId\", "
+    "\"sourceId\"], "
+    "\"suppressedNvPairsList\": ["
+    "]}}}"
+    "]"
+    "}";
+
+  char * expected =
+    "{\"event\": "
+    "{\"commonEventHeader\": {"
+    "\"domain\": \"other\", "
+    "\"eventId\": \"129\", "
+    "\"functionalRole\": \"UNIT TEST\", "
+    "\"lastEpochMicrosec\": 1000002, "
+    "\"priority\": \"Normal\", "
+    "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", "
+    "\"sequence\": 129, "
+    "\"sourceName\": \"Dummy VM name - No Metadata available\", "
+    "\"startEpochMicrosec\": 1000002, "
+    "\"version\": 1.2"
+    "}, "
+    "\"otherFields\": ["
+    "{\"name\": \"Other field 1\", "
+    "\"value\": \"Other value 1\"}, "
+    "{\"name\": \"Other field 2\", "
+    "\"value\": \"Other value 2\"}"
+    "]"
+    "}}";
+
+  /***************************************************************************/
+  /* Initialize and provide a specification with a single fault suppressed.  */
+  /***************************************************************************/
+  evel_throttle_initialize();
+  handle_json_response(json_command_list, &post);
+
+  /***************************************************************************/
+  /* Check that the domain is throttled.                                     */
+  /***************************************************************************/
+  assert(evel_get_throttle_spec(EVEL_DOMAIN_OTHER) != NULL);
+  assert(post.memory == NULL);
+
+  size_t json_size = 0;
+  char json_body[EVEL_MAX_JSON_BODY];
+  EVENT_OTHER * other = NULL;
+  evel_set_next_event_sequence(129);
+  other = evel_new_other();
+  assert(other != NULL);
+  evel_other_type_set(other, "Other Type");
+  evel_other_field_add(other,
+                       "Other field 1",
+                       "Other value 1");
+  evel_other_field_add(other,
+                       "Other field 2",
+                       "Other value 2");
+
+  json_size = evel_json_encode_event(
+    json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) other);
+  compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Other");
+  assert((json_size == strlen(json_body)) && "Bad size returned");
+
+  evel_free_event(other);
+  evel_throttle_terminate();
+}
+
+void test_encode_report_throttled()
+{
+  MEMORY_CHUNK post;
+
+  /***************************************************************************/
+  /* We also test suppression of the event header parameters here.           */
+  /***************************************************************************/
+  char * json_command_list =
+    "{"
+    "\"commandList\": ["
+    "{"
+    "\"command\": {"
+    "\"commandType\": \"throttlingSpecification\", "
+    "\"eventDomainThrottleSpecification\": {"
+    "\"eventDomain\": \"report\", "
+    "\"suppressedFieldNames\": ["
+    "\"eventType\", "
+    "\"reportingEntityId\", "
+    "\"sourceId\"], "
+    "\"suppressedNvPairsList\": ["
+    "{"
+    "\"nvPairFieldName\": \"featureUsageArray\", "
+    "\"suppressedNvPairNames\": [\"FeatureB\", \"FeatureC\"]"
+    "},"
+    "{"
+    "\"nvPairFieldName\": \"additionalMeasurements\", "
+    "\"suppressedNvPairNames\": [\"Group2\"]"
+    "}"
+    "]}}}"
+    "]"
+    "}";
+
+  char * expected =
+    "{\"event\": "
+    "{\"commonEventHeader\": {"
+    "\"domain\": \"measurementsForVfReporting\", "
+    "\"eventId\": \"125\", "
+    "\"functionalRole\": \"UNIT TEST\", "
+    "\"lastEpochMicrosec\": 1000002, "
+    "\"priority\": \"Normal\", "
+    "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", "
+    "\"sequence\": 125, "
+    "\"sourceName\": \"Dummy VM name - No Metadata available\", "
+    "\"startEpochMicrosec\": 1000002, "
+    "\"version\": 1.2"
+    "}, "
+    "\"measurementsForVfReportingFields\": "
+    "{\"measurementInterval\": 1.100000, "
+    "\"featureUsageArray\": ["
+    "{\"featureIdentifier\": \"FeatureA\", "
+    "\"featureUtilization\": 123}], "
+    "\"additionalMeasurements\": ["
+    "{\"name\": \"Group1\", "
+    "\"measurements\": ["
+    "{\"name\": \"Name1\", "
+    "\"value\": \"Value1\"}]}], "
+    "\"measurementFieldsVersion\": 1.1}}}";
+
+  /***************************************************************************/
+  /* Initialize and provide a specification with a single fault suppressed.  */
+  /***************************************************************************/
+  evel_throttle_initialize();
+  handle_json_response(json_command_list, &post);
+
+  /***************************************************************************/
+  /* Check that the domain is throttled.                                     */
+  /***************************************************************************/
+  assert(evel_get_throttle_spec(EVEL_DOMAIN_REPORT) != NULL);
+  assert(post.memory == NULL);
+
+  size_t json_size = 0;
+  char json_body[EVEL_MAX_JSON_BODY];
+  EVENT_REPORT * report = NULL;
+
+  /***************************************************************************/
+  /* Report.                                                                 */
+  /***************************************************************************/
+  evel_set_next_event_sequence(125);
+  report = evel_new_report(1.1);
+  assert(report != NULL);
+  evel_report_type_set(report, "Perf reporting...");
+  evel_report_feature_use_add(report, "FeatureA", 123);
+  evel_report_feature_use_add(report, "FeatureB", 567);
+  evel_report_custom_measurement_add(report, "Group1", "Name1", "Value1");
+  evel_report_custom_measurement_add(report, "Group2", "Name1", "Value1");
+  evel_report_custom_measurement_add(report, "Group2", "Name2", "Value2");
+
+  json_size = evel_json_encode_event(
+    json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) report);
+  compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Report");
+  assert((json_size == strlen(json_body)) && "Bad size returned");
+
+  evel_free_event(report);
+  evel_throttle_terminate();
+}
+
+void test_encode_service_throttled()
+{
+  MEMORY_CHUNK post;
+
+  /***************************************************************************/
+  /* We also test suppression of the event header parameters here.           */
+  /***************************************************************************/
+  char * json_command_list =
+    "{"
+    "\"commandList\": ["
+    "{"
+    "\"command\": {"
+    "\"commandType\": \"throttlingSpecification\", "
+    "\"eventDomainThrottleSpecification\": {"
+    "\"eventDomain\": \"serviceEvents\", "
+    "\"suppressedFieldNames\": ["
+    "\"eventType\", "
+    "\"correlator\", "
+    "\"codecSelected\", "
+    "\"codecSelectedTranscoding\", "
+    "\"endOfCallVqmSummaries\", "
+    "\"midCallRtcp\", "
+    "\"marker\", "
+    "\"reportingEntityId\", "
+    "\"sourceId\"], "
+    "\"suppressedNvPairsList\": ["
+    "{"
+    "\"nvPairFieldName\": \"additionalFields\", "
+    "\"suppressedNvPairNames\": [\"Name1\", \"Name3\"]"
+    "}"
+    "]}}}"
+    "]"
+    "}";
+
+  char * expected =
+    "{\"event\": "
+    "{\"commonEventHeader\": {"
+    "\"domain\": \"serviceEvents\", "
+    "\"eventId\": \"2000\", "
+    "\"functionalRole\": \"UNIT TEST\", "
+    "\"lastEpochMicrosec\": 1000002, "
+    "\"priority\": \"Normal\", "
+    "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", "
+    "\"sequence\": 2000, "
+    "\"sourceName\": \"Dummy VM name - No Metadata available\", "
+    "\"startEpochMicrosec\": 1000002, "
+    "\"version\": 1.2"
+    "}, "
+    "\"serviceEventsFields\": {"
+    "\"eventInstanceIdentifier\": "
+    "{"
+    "\"vendorId\": \"vendor_x_id\", "
+    "\"eventId\": \"vendor_x_event_id\", "
+    "\"productId\": \"vendor_x_product_id\", "
+    "\"subsystemId\": \"vendor_x_subsystem_id\", "
+    "\"eventFriendlyName\": \"vendor_x_frieldly_name\""
+    "}, "
+    "\"serviceEventsFieldsVersion\": 1.1, "
+    "\"additionalFields\": ["
+    "{\"name\": \"Name2\", \"value\": \"Value2\"}, "
+    "{\"name\": \"Name4\", \"value\": \"Value4\"}]"
+    "}}}";
+
+  /***************************************************************************/
+  /* Initialize and provide a specification with a single fault suppressed.  */
+  /***************************************************************************/
+  evel_throttle_initialize();
+  handle_json_response(json_command_list, &post);
+
+  /***************************************************************************/
+  /* Check that the domain is throttled.                                     */
+  /***************************************************************************/
+  assert(evel_get_throttle_spec(EVEL_DOMAIN_SERVICE) != NULL);
+  assert(post.memory == NULL);
+
+  size_t json_size = 0;
+  char json_body[EVEL_MAX_JSON_BODY];
+  EVENT_SERVICE * event = NULL;
+  evel_set_next_event_sequence(2000);
+  event = evel_new_service("vendor_x_id", "vendor_x_event_id");
+  assert(event != NULL);
+  evel_service_type_set(event, "Service Event");
+  evel_service_product_id_set(event, "vendor_x_product_id");
+  evel_service_subsystem_id_set(event, "vendor_x_subsystem_id");
+  evel_service_friendly_name_set(event, "vendor_x_frieldly_name");
+  evel_service_correlator_set(event, "vendor_x_correlator");
+  evel_service_codec_set(event, "PCMA");
+  evel_service_codec_set(event, "PCMA");
+  evel_service_callee_codec_set(event, "PCMA");
+  evel_service_caller_codec_set(event, "G729A");
+  evel_service_rtcp_data_set(event, "some_rtcp_data");
+  evel_service_adjacency_name_set(event, "vendor_x_adjacency");
+  evel_service_endpoint_desc_set(event, EVEL_SERVICE_ENDPOINT_CALLER);
+  evel_service_endpoint_jitter_set(event, 66);
+  evel_service_endpoint_rtp_oct_disc_set(event, 100);
+  evel_service_endpoint_rtp_oct_recv_set(event, 200);
+  evel_service_endpoint_rtp_oct_sent_set(event, 300);
+  evel_service_endpoint_rtp_pkt_disc_set(event, 400);
+  evel_service_endpoint_rtp_pkt_recv_set(event, 500);
+  evel_service_endpoint_rtp_pkt_sent_set(event, 600);
+  evel_service_local_jitter_set(event, 99);
+  evel_service_local_rtp_oct_disc_set(event, 150);
+  evel_service_local_rtp_oct_recv_set(event, 250);
+  evel_service_local_rtp_oct_sent_set(event, 350);
+  evel_service_local_rtp_pkt_disc_set(event, 450);
+  evel_service_local_rtp_pkt_recv_set(event, 550);
+  evel_service_local_rtp_pkt_sent_set(event, 650);
+  evel_service_mos_cqe_set(event, 12.255);
+  evel_service_packets_lost_set(event, 157);
+  evel_service_packet_loss_percent_set(event, 0.232);
+  evel_service_r_factor_set(event, 11);
+  evel_service_round_trip_delay_set(event, 15);
+  evel_service_phone_number_set(event, "0888888888");
+  evel_service_addl_field_add(event, "Name1", "Value1");
+  evel_service_addl_field_add(event, "Name2", "Value2");
+  evel_service_addl_field_add(event, "Name3", "Value3");
+  evel_service_addl_field_add(event, "Name4", "Value4");
+  json_size = evel_json_encode_event(
+    json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) event);
+  compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Service");
+  assert((json_size == strlen(json_body)) && "Bad size returned");
+
+  evel_free_event(event);
+  evel_throttle_terminate();
+}
+
+void test_encode_signaling_throttled()
+{
+  MEMORY_CHUNK post;
+
+  /***************************************************************************/
+  /* We also test suppression of the event header parameters here.           */
+  /***************************************************************************/
+  char * json_command_list =
+    "{"
+    "\"commandList\": ["
+    "{"
+    "\"command\": {"
+    "\"commandType\": \"throttlingSpecification\", "
+    "\"eventDomainThrottleSpecification\": {"
+    "\"eventDomain\": \"signaling\", "
+    "\"suppressedFieldNames\": ["
+    "\"correlator\", "
+    "\"eventType\", "
+    "\"reportingEntityId\", "
+    "\"sourceId\", "
+    "\"localIpAddress\", "
+    "\"localPort\", "
+    "\"remoteIpAddress\", "
+    "\"remotePort\", "
+    "\"compressedSip\", "
+    "\"summarySip\"], "
+    "\"suppressedNvPairsList\": ["
+    "]}}}"
+    "]"
+    "}";
+
+  char * expected =
+    "{\"event\": "
+    "{\"commonEventHeader\": {"
+    "\"domain\": \"signaling\", "
+    "\"eventId\": \"2001\", "
+    "\"functionalRole\": \"UNIT TEST\", "
+    "\"lastEpochMicrosec\": 1000002, "
+    "\"priority\": \"Normal\", "
+    "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", "
+    "\"sequence\": 2001, "
+    "\"sourceName\": \"Dummy VM name - No Metadata available\", "
+    "\"startEpochMicrosec\": 1000002, "
+    "\"version\": 1.2"
+    "}, "
+    "\"signalingFields\": {"
+    "\"eventInstanceIdentifier\": "
+    "{"
+    "\"vendorId\": \"vendor_x_id\", "
+    "\"eventId\": \"vendor_x_event_id\", "
+    "\"productId\": \"vendor_x_product_id\", "
+    "\"subsystemId\": \"vendor_x_subsystem_id\", "
+    "\"eventFriendlyName\": \"vendor_x_frieldly_name\""
+    "}, "
+    "\"signalingFieldsVersion\": 1.1"
+    "}}}";
+
+  /***************************************************************************/
+  /* Initialize and provide a specification with a single fault suppressed.  */
+  /***************************************************************************/
+  evel_throttle_initialize();
+  handle_json_response(json_command_list, &post);
+
+  /***************************************************************************/
+  /* Check that the domain is throttled.                                     */
+  /***************************************************************************/
+  assert(evel_get_throttle_spec(EVEL_DOMAIN_SIGNALING) != NULL);
+  assert(post.memory == NULL);
+
+  size_t json_size = 0;
+  char json_body[EVEL_MAX_JSON_BODY];
+  EVENT_SIGNALING * event = NULL;
+  evel_set_next_event_sequence(2001);
+  event = evel_new_signaling("vendor_x_id", "vendor_x_event_id");
+  assert(event != NULL);
+  evel_signaling_type_set(event, "Signaling");
+  evel_signaling_product_id_set(event, "vendor_x_product_id");
+  evel_signaling_subsystem_id_set(event, "vendor_x_subsystem_id");
+  evel_signaling_friendly_name_set(event, "vendor_x_frieldly_name");
+  evel_signaling_correlator_set(event, "vendor_x_correlator");
+  evel_signaling_local_ip_address_set(event, "1.0.3.1");
+  evel_signaling_local_port_set(event, "1031");
+  evel_signaling_remote_ip_address_set(event, "5.3.3.0");
+  evel_signaling_remote_port_set(event, "5330");
+  evel_signaling_compressed_sip_set(event, "compressed_sip");
+  evel_signaling_summary_sip_set(event, "summary_sip");
+  json_size = evel_json_encode_event(
+    json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) event);
+  compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Signaling");
+  assert((json_size == strlen(json_body)) && "Bad size returned");
+
+  evel_free_event(event);
+  evel_throttle_terminate();
+}
+
+void test_encode_state_change_throttled()
+{
+  MEMORY_CHUNK post;
+
+  /***************************************************************************/
+  /* We also test suppression of the event header parameters here.           */
+  /***************************************************************************/
+  char * json_command_list =
+    "{"
+    "\"commandList\": ["
+    "{"
+    "\"command\": {"
+    "\"commandType\": \"throttlingSpecification\", "
+    "\"eventDomainThrottleSpecification\": {"
+    "\"eventDomain\": \"stateChange\", "
+    "\"suppressedFieldNames\": ["
+    "\"eventType\", "
+    "\"reportingEntityId\", "
+    "\"sourceId\"], "
+    "\"suppressedNvPairsList\": ["
+    "{"
+    "\"nvPairFieldName\": \"additionalFields\", "
+    "\"suppressedNvPairNames\": [\"Name1\"]"
+    "},"
+    "]}}}"
+    "]"
+    "}";
+
+  char * expected =
+    "{\"event\": "
+    "{\"commonEventHeader\": {"
+    "\"domain\": \"stateChange\", "
+    "\"eventId\": \"128\", "
+    "\"functionalRole\": \"UNIT TEST\", "
+    "\"lastEpochMicrosec\": 1000002, "
+    "\"priority\": \"Normal\", "
+    "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", "
+    "\"sequence\": 128, "
+    "\"sourceName\": \"Dummy VM name - No Metadata available\", "
+    "\"startEpochMicrosec\": 1000002, "
+    "\"version\": 1.2"
+    "}, "
+    "\"stateChangeFields\": {"
+    "\"newState\": \"inService\", "
+    "\"oldState\": \"outOfService\", "
+    "\"stateInterface\": \"An Interface\", "
+    "\"additionalFields\": ["
+    "{\"name\": \"Name2\", "
+    "\"value\": \"Value2\"}"
+    "], "
+    "\"stateChangeFieldsVersion\": 1.1"
+    "}}}";
+
+  /***************************************************************************/
+  /* Initialize and provide a specification with a single fault suppressed.  */
+  /***************************************************************************/
+  evel_throttle_initialize();
+  handle_json_response(json_command_list, &post);
+
+  /***************************************************************************/
+  /* Check that the domain is throttled.                                     */
+  /***************************************************************************/
+  assert(evel_get_throttle_spec(EVEL_DOMAIN_STATE_CHANGE) != NULL);
+  assert(post.memory == NULL);
+
+  size_t json_size = 0;
+  char json_body[EVEL_MAX_JSON_BODY];
+  EVENT_STATE_CHANGE * state_change = NULL;
+  evel_set_next_event_sequence(128);
+  state_change = evel_new_state_change(EVEL_ENTITY_STATE_IN_SERVICE,
+                                       EVEL_ENTITY_STATE_OUT_OF_SERVICE,
+                                       "An Interface");
+  assert(state_change != NULL);
+  evel_state_change_type_set(state_change, "SC Type");
+  evel_state_change_addl_field_add(state_change, "Name1", "Value1");
+  evel_state_change_addl_field_add(state_change, "Name2", "Value2");
+
+  json_size = evel_json_encode_event(
+    json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) state_change);
+  compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "StateChange");
+  assert((json_size == strlen(json_body)) && "Bad size returned");
+
+  evel_free_event(state_change);
+  evel_throttle_terminate();
+}
+
+void test_encode_syslog_throttled()
+{
+  MEMORY_CHUNK post;
+
+  /***************************************************************************/
+  /* We also test suppression of the event header parameters here.           */
+  /***************************************************************************/
+  char * json_command_list =
+    "{"
+    "\"commandList\": ["
+    "{"
+    "\"command\": {"
+    "\"commandType\": \"throttlingSpecification\", "
+    "\"eventDomainThrottleSpecification\": {"
+    "\"eventDomain\": \"syslog\", "
+    "\"suppressedFieldNames\": ["
+    "\"eventSourceHost\", "
+    "\"syslogFacility\", "
+    "\"syslogProc\", "
+    "\"syslogProcId\", "
+    "\"syslogSData\", "
+    "\"syslogVer\", "
+    "\"eventType\", "
+    "\"reportingEntityId\", "
+    "\"sourceId\"], "
+    "\"suppressedNvPairsList\": ["
+    "{"
+    "\"nvPairFieldName\": \"additionalFields\", "
+    "\"suppressedNvPairNames\": [\"Name2\"]"
+    "},"
+    "]}}}"
+    "]"
+    "}";
+
+  char * expected =
+    "{\"event\": "
+    "{\"commonEventHeader\": {"
+    "\"domain\": \"syslog\", "
+    "\"eventId\": \"126\", "
+    "\"functionalRole\": \"UNIT TEST\", "
+    "\"lastEpochMicrosec\": 1000002, "
+    "\"priority\": \"Normal\", "
+    "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", "
+    "\"sequence\": 126, "
+    "\"sourceName\": \"Dummy VM name - No Metadata available\", "
+    "\"startEpochMicrosec\": 1000002, "
+    "\"version\": 1.2"
+    "}, "
+    "\"syslogFields\": {"
+    "\"eventSourceType\": \"virtualNetworkFunction\", "
+    "\"syslogMsg\": \"SL Message\", "
+    "\"syslogTag\": \"SL Tag\", "
+    "\"syslogFieldsVersion\": 1.1, "
+    "\"additionalFields\": ["
+    "{\"name\": \"Name1\", "
+    "\"value\": \"Value1\"}"
+    "]"
+    "}}}";
+
+  /***************************************************************************/
+  /* Initialize and provide a specification with a single fault suppressed.  */
+  /***************************************************************************/
+  evel_throttle_initialize();
+  handle_json_response(json_command_list, &post);
+
+  /***************************************************************************/
+  /* Check that the domain is throttled.                                     */
+  /***************************************************************************/
+  assert(evel_get_throttle_spec(EVEL_DOMAIN_SYSLOG) != NULL);
+  assert(post.memory == NULL);
+
+  size_t json_size = 0;
+  char json_body[EVEL_MAX_JSON_BODY];
+  EVENT_SYSLOG * syslog = NULL;
+  evel_set_next_event_sequence(126);
+  syslog = evel_new_syslog(EVEL_SOURCE_VIRTUAL_NETWORK_FUNCTION,
+                           "SL Message",
+                           "SL Tag");
+  assert(syslog != NULL);
+  evel_syslog_type_set(syslog, "SL Type");
+  evel_syslog_event_source_host_set(syslog, "SL Host");
+  evel_syslog_facility_set(syslog, EVEL_SYSLOG_FACILITY_LINE_PRINTER);
+  evel_syslog_proc_set(syslog, "SL Proc");
+  evel_syslog_proc_id_set(syslog, 2);
+  evel_syslog_version_set(syslog, 1);
+  evel_syslog_s_data_set(syslog, "SL SDATA");
+  evel_syslog_addl_field_add(syslog, "Name1", "Value1");
+  evel_syslog_addl_field_add(syslog, "Name2", "Value2");
+
+  json_size = evel_json_encode_event(
+    json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) syslog);
+  compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Syslog");
+  assert((json_size == strlen(json_body)) && "Bad size returned");
+
+  evel_free_event(syslog);
+  evel_throttle_terminate();
+}
+
+void test_encode_fault_with_escaping()
+{
+  char * expected =
+    "{\"event\": {"
+    "\"commonEventHeader\": {"
+    "\"domain\": \"fault\", "
+    "\"eventId\": \"122\", "
+    "\"functionalRole\": \"UNIT TEST\", "
+    "\"lastEpochMicrosec\": 1000002, "
+    "\"priority\": \"Normal\", "
+    "\"reportingEntityName\": \"Dummy VM name - No Metadata available\", "
+    "\"sequence\": 122, "
+    "\"sourceName\": \"Dummy VM name - No Metadata available\", "
+    "\"startEpochMicrosec\": 1000002, "
+    "\"version\": 1.2, "
+    "\"eventType\": \"Bad things happen...\\\\\", "
+    "\"reportingEntityId\": \"Dummy VM UUID - No Metadata available\", "
+    "\"sourceId\": \"Dummy VM UUID - No Metadata available\""
+    "}, "
+    "\"faultFields\": {"
+    "\"alarmCondition\": \"My alarm condition\", "
+    "\"eventSeverity\": \"MAJOR\", "
+    "\"eventSourceType\": \"other\", "
+    "\"specificProblem\": \"It broke \\\"very\\\" badly\", "
+    "\"vfStatus\": \"Active\", "
+    "\"faultFieldsVersion\": 1.1, "
+    "\"alarmAdditionalInformation\": ["
+    "{\"name\": \"name1\", "
+    "\"value\": \"value1\"}, "
+    "{\"name\": \"name2\", "
+    "\"value\": \"value2\"}], "
+    "\"alarmInterfaceA\": \"My Interface Card\""
+    "}}}";
+
+  size_t json_size = 0;
+  char json_body[EVEL_MAX_JSON_BODY];
+  evel_set_next_event_sequence(122);
+  EVENT_FAULT * fault = evel_new_fault("My alarm condition",
+                                       "It broke \"very\" badly",
+                                       EVEL_PRIORITY_NORMAL,
+                                       EVEL_SEVERITY_MAJOR);
+  assert(fault != NULL);
+  evel_fault_type_set(fault, "Bad things happen...\\");
+  evel_fault_interface_set(fault, "My Interface Card");
+  evel_fault_addl_info_add(fault, "name1", "value1");
+  evel_fault_addl_info_add(fault, "name2", "value2");
+
+  json_size = evel_json_encode_event(
+    json_body, EVEL_MAX_JSON_BODY, (EVENT_HEADER *) fault);
+  compare_strings(expected, json_body, EVEL_MAX_JSON_BODY, "Fault");
+  assert((json_size == strlen(json_body)) && "Bad size returned");
+
+  evel_free_event(fault);
+}
diff --git a/vnfs/VES/dep.xml b/vnfs/VES/dep.xml
new file mode 100644 (file)
index 0000000..fa2f1f8
--- /dev/null
@@ -0,0 +1,55 @@
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" 
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+  <id>demo</id>
+  <formats>
+    <format>tar.gz</format>
+  </formats>
+  <fileSets>
+
+    <fileSet>
+      <directory>bldjobs</directory>
+      <outputDirectory>bldjobs</outputDirectory>
+      <includes>
+        <include>**</include>
+      </includes>
+    </fileSet>
+
+    <fileSet>
+      <directory>code</directory>
+      <outputDirectory>code</outputDirectory>
+      <includes>
+        <include>**</include>
+      </includes>
+    </fileSet>
+
+    <fileSet>
+      <directory>docs</directory>
+      <outputDirectory>docs</outputDirectory>
+      <includes>
+        <include>**</include>
+      </includes>
+    </fileSet>
+
+    <fileSet>
+      <directory>libs</directory>
+      <outputDirectory>libs</outputDirectory>
+      <includes>
+        <include>**</include>
+      </includes>
+    </fileSet>
+
+   <fileSet>
+      <directory>.</directory>
+      <outputDirectory>/</outputDirectory>
+      <includes>
+        <include>*.md</include>
+      </includes>
+    </fileSet>
+
+  </fileSets>
+</assembly>
+
+
+
+
diff --git a/vnfs/VES/docs/source/evel/README b/vnfs/VES/docs/source/evel/README
new file mode 100644 (file)
index 0000000..89e7a3a
--- /dev/null
@@ -0,0 +1 @@
+Generated source code documentation.
\ No newline at end of file
diff --git a/vnfs/VES/libs/x86_64/README b/vnfs/VES/libs/x86_64/README
new file mode 100644 (file)
index 0000000..760fdc1
--- /dev/null
@@ -0,0 +1 @@
+Generated libraries.
\ No newline at end of file
diff --git a/vnfs/VES/libs/x86_64/libevel.a b/vnfs/VES/libs/x86_64/libevel.a
new file mode 100755 (executable)
index 0000000..a56ea84
Binary files /dev/null and b/vnfs/VES/libs/x86_64/libevel.a differ
diff --git a/vnfs/VES/output/.DS_Store b/vnfs/VES/output/.DS_Store
new file mode 100644 (file)
index 0000000..e34c832
Binary files /dev/null and b/vnfs/VES/output/.DS_Store differ
diff --git a/vnfs/VES/output/x86_64/README b/vnfs/VES/output/x86_64/README
new file mode 100644 (file)
index 0000000..d1c9f1f
--- /dev/null
@@ -0,0 +1 @@
+Generated executables.
\ No newline at end of file
diff --git a/vnfs/VES/pom.xml b/vnfs/VES/pom.xml
new file mode 100644 (file)
index 0000000..0d535f6
--- /dev/null
@@ -0,0 +1,56 @@
+<!--<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">-->
+<project>
+<parent>
+    <groupId>org.openecomp.demo.vnf</groupId>
+    <artifactId>demo-aggregator</artifactId>
+    <version>1.0.0</version>
+<relativePath>../pom.xml</relativePath>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.openecomp.demo.vnf.ves</groupId>
+  <artifactId>ves</artifactId>
+ <!-- <name>vfw_pg_streams</name>-->
+  <version>1.0.0</version>
+  <build>
+    <plugins>
+
+       <plugin>
+        <artifactId>maven-jar-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>default-jar</id>
+            <phase>never</phase>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <version>2.5.3</version>
+        <configuration>
+          <descriptor>dep.xml</descriptor>
+        </configuration>
+        <executions>
+          <execution>
+            <id>create-archive</id>
+            <phase>package</phase>
+            <goals>
+              <goal>single</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+
+<plugin>
+  <groupId>org.apache.maven.plugins</groupId>
+  <artifactId>maven-deploy-plugin</artifactId>
+  <configuration>
+    <skip>false</skip>
+  </configuration>
+</plugin>
+
+    </plugins>
+  </build>
+
+</project>
diff --git a/vnfs/VES/readme.md b/vnfs/VES/readme.md
new file mode 100644 (file)
index 0000000..65ce4ef
--- /dev/null
@@ -0,0 +1,28 @@
+# ECOMP Vendor Event Listener Library
+
+This project contains a C library that supports interfacing to AT&T's ECOMP
+Vendor Event Listener. For an overview of ECOMP, see the 
+[ECOMP White Paper](http://att.com/ECOMP).
+
+Developed in 2016 for AT&T by:
+ * Alok Gupta (https://github.com/ag1367)
+ * Paul Potochniak (https://github.com/pp8491)
+ * Gayathri Patrachari(https://github.com/gp2421)
+
+Current Maintainers: 
+ * Alok Gupta (https://github.com/ag1367)
+ * Paul Potochniak (https://github.com/pp8491)
+ * Gayathri Patrachari(https://github.com/gp2421)
+
+# Installation
+
+For installation instructions, clone this repo and load the 
+[installation guide](./docs/source/evel/html/quickstart.html) in your web browser.
+
+Full source-code documentation is included with the code and can be built from 
+the included Makefile. See the [readme file](./code/evel_library/readme.md).
+
+# Use
+
+Clone this repo and load the [user guide](./docs/source/evel/html/index.html)
+in your web browser.
\ No newline at end of file
diff --git a/vnfs/VESreporting_vFW/LICENSE.TXT b/vnfs/VESreporting_vFW/LICENSE.TXT
new file mode 100644 (file)
index 0000000..ae12da2
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * ============LICENSE_START==========================================
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ===================================================================
+ * 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.
+ * ============LICENSE_END============================================
+ *
+ * ECOMP and OpenECOMP are trademarks 
+ * and service marks of AT&T Intellectual Property.
+ *
+ */
diff --git a/vnfs/VESreporting_vFW/Makefile b/vnfs/VESreporting_vFW/Makefile
new file mode 100644 (file)
index 0000000..77ca574
--- /dev/null
@@ -0,0 +1,45 @@
+#############################################################################
+#
+# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+#
+# 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.
+#
+#############################################################################
+
+CC=gcc
+
+ARCH=$(shell getconf LONG_BIT)
+CODE_ROOT=$(CURDIR)/../../..
+LIBS_DIR=$(CODE_ROOT)/libs/x86_$(ARCH)
+INCLUDE_DIR=$(CODE_ROOT)/code/evel_library
+
+#******************************************************************************
+# Standard compiler flags.                                                    *
+#******************************************************************************
+CPPFLAGS=
+CFLAGS=-Wall -g -fPIC
+
+all:   vpp_measurement_reporter
+
+clean:
+       rm -f vpp_measurement_reporter
+
+vpp_measurement_reporter: vpp_measurement_reporter.c
+       $(CC) $(CPPFLAGS) $(CFLAGS) -o vpp_measurement_reporter \
+                                    -L $(LIBS_DIR) \
+                                    -I $(INCLUDE_DIR) \
+                               vpp_measurement_reporter.c \
+                              -lpthread \
+                              -level \
+                              -lcurl
+
+
diff --git a/vnfs/VESreporting_vFW/README.md b/vnfs/VESreporting_vFW/README.md
new file mode 100644 (file)
index 0000000..dc47e62
--- /dev/null
@@ -0,0 +1,25 @@
+
+PROJECT DESCRIPTION
+---
+This project contains the source code and scripts for the periodic generation of network measurement reports. The folder contains:
+
+ - README.md: this file.
+
+ - LICENSE.TXT: the license text.
+
+ - vpp_measurement_reporter.c: source code that uses the ECOMP Vendor Event Listener Library (VES) to read metrics from the network interface and send periodic measurement reports to the VES collector in DCAE. The VES library used here has been cloned from the GitHub repository at https://github.com/att/evel-library on February 1, 2017.
+
+ - Makefile: makefile that compiles vpp_measurement_reporter.c and generates vpp_measurement_reporter binary.
+
+ - go-client.sh: bash script that starts up the vpp_measurement_reporter binary generated by Makefile. It reads input parameters like DCAE IP address and port from configuration files contained in /opt/config.
+
+
+USAGE
+---
+To run the vpp_measurement_reporter, please execute the following steps:
+
+ - Make the go-client.sh script executable
+        chmod +x go-client.sh
+
+ - Run the go-client.sh script
+        ./go-client.sh  
diff --git a/vnfs/VESreporting_vFW/dep.xml b/vnfs/VESreporting_vFW/dep.xml
new file mode 100644 (file)
index 0000000..fc18229
--- /dev/null
@@ -0,0 +1,25 @@
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" 
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+  <id>demo</id>
+  <formats>
+    <format>tar.gz</format>
+  </formats>
+  <fileSets>
+
+    <fileSet>
+      <directory>.</directory>
+      <outputDirectory>/</outputDirectory>
+      <includes>
+        <include>*.sh</include>
+       <include>*.md</include>
+       <include>*.TXT</include>
+       <include>*.c</include>
+       <include>Makefile</include>
+      </includes>
+    </fileSet>
+
+  </fileSets>
+</assembly>
+
+
diff --git a/vnfs/VESreporting_vFW/go-client.sh b/vnfs/VESreporting_vFW/go-client.sh
new file mode 100755 (executable)
index 0000000..3d1b159
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+export LD_LIBRARY_PATH="/opt/VES/libs/x86_64/"
+DCAE_COLLECTOR_IP=$(cat /opt/config/dcae_collector_ip.txt)
+DCAE_COLLECTOR_PORT=$(cat /opt/config/dcae_collector_port.txt)
+./vpp_measurement_reporter $DCAE_COLLECTOR_IP $DCAE_COLLECTOR_PORT eth1
diff --git a/vnfs/VESreporting_vFW/pom.xml b/vnfs/VESreporting_vFW/pom.xml
new file mode 100644 (file)
index 0000000..f6eaef3
--- /dev/null
@@ -0,0 +1,54 @@
+<!--<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">-->
+<project>
+<parent>
+    <groupId>org.openecomp.demo.vnf</groupId>
+    <artifactId>demo-aggregator</artifactId>
+    <version>1.0.0</version>
+<relativePath>../pom.xml</relativePath>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.openecomp.demo.vnf.ves</groupId>
+  <artifactId>ves_vfw_reporting</artifactId>
+ <!-- <name>vfw_pg_streams</name>-->
+  <version>1.0.0</version>
+  <build>
+    <plugins>
+
+       <plugin>
+        <artifactId>maven-jar-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>default-jar</id>
+            <phase>never</phase>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <version>2.5.3</version>
+        <configuration>
+          <descriptor>dep.xml</descriptor>
+        </configuration>
+        <executions>
+          <execution>
+            <id>create-archive</id>
+            <phase>package</phase>
+            <goals>
+              <goal>single</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+<plugin>
+  <groupId>org.apache.maven.plugins</groupId>
+  <artifactId>maven-deploy-plugin</artifactId>
+  <configuration>
+    <skip>false</skip>
+  </configuration>
+</plugin>
+
+    </plugins>
+  </build>
+
+</project>
diff --git a/vnfs/VESreporting_vFW/vpp_measurement_reporter.c b/vnfs/VESreporting_vFW/vpp_measurement_reporter.c
new file mode 100644 (file)
index 0000000..e73b00b
--- /dev/null
@@ -0,0 +1,232 @@
+
+/*************************************************************************//**
+ *
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include "evel.h"
+
+#define BUFSIZE 128
+#define READ_INTERVAL 10
+
+typedef struct dummy_vpp_metrics_struct {
+  int bytes_in;
+  int bytes_out;
+  int packets_in;
+  int packets_out;
+} vpp_metrics_struct;
+
+void read_vpp_metrics(vpp_metrics_struct *, char *);
+
+int main(int argc, char** argv)
+{
+  EVEL_ERR_CODES evel_rc = EVEL_SUCCESS;
+  EVENT_MEASUREMENT* vpp_m = NULL;
+  EVENT_HEADER* vpp_m_header = NULL;
+  int bytes_in_this_round;
+  int bytes_out_this_round;
+  int packets_in_this_round;
+  int packets_out_this_round;
+  vpp_metrics_struct* last_vpp_metrics = malloc(sizeof(vpp_metrics_struct));
+  vpp_metrics_struct* curr_vpp_metrics = malloc(sizeof(vpp_metrics_struct));
+  struct timeval time_val;
+  time_t start_epoch;
+  time_t last_epoch;
+  char hostname[BUFSIZE];
+  char* fqdn = argv[1];
+  int port = atoi(argv[2]);
+  char* vnic = argv[3];
+
+  printf("\nVector Packet Processing (VPP) measurement collection\n");
+  fflush(stdout);
+
+  if (argc != 4)
+  {
+    fprintf(stderr, "Usage: %s <FQDN>|<IP address> <port> <interface>\n", argv[0]);
+    exit(-1);
+  }
+
+  /**************************************************************************/
+  /* Initialize                                                             */
+  /**************************************************************************/
+  if(evel_initialize(fqdn,                         /* FQDN                  */
+                     port,                        /* Port                  */
+                     NULL,                         /* optional path         */
+                     NULL,                         /* optional topic        */
+                     0,                            /* HTTPS?                */
+                     "",                           /* Username              */
+                     "",                           /* Password              */
+                     EVEL_SOURCE_VIRTUAL_MACHINE,  /* Source type           */
+                     "vFirewall",                         /* Role                  */
+                     1))                           /* Verbosity             */
+  {
+    fprintf(stderr, "\nFailed to initialize the EVEL library!!!\n");
+    exit(-1);
+  }
+  else
+  {
+    printf("\nInitialization completed\n");
+  }
+
+  gethostname(hostname, BUFSIZE);
+  memset(last_vpp_metrics, 0, sizeof(vpp_metrics_struct));
+  read_vpp_metrics(last_vpp_metrics, vnic);
+  gettimeofday(&time_val, NULL);
+  start_epoch = time_val.tv_sec * 1000000 + time_val.tv_usec;
+  sleep(READ_INTERVAL);
+
+  /***************************************************************************/
+  /* Collect metrics from the VNIC                                           */
+  /***************************************************************************/
+  while(1) {
+    memset(curr_vpp_metrics, 0, sizeof(vpp_metrics_struct));
+    read_vpp_metrics(curr_vpp_metrics, vnic);
+
+    if(curr_vpp_metrics->bytes_in - last_vpp_metrics->bytes_in > 0) {
+      bytes_in_this_round = curr_vpp_metrics->bytes_in - last_vpp_metrics->bytes_in;
+    }
+    else {
+      bytes_in_this_round = 0;
+    }
+    if(curr_vpp_metrics->bytes_out - last_vpp_metrics->bytes_out > 0) {
+      bytes_out_this_round = curr_vpp_metrics->bytes_out - last_vpp_metrics->bytes_out;
+    }
+    else {
+      bytes_out_this_round = 0;
+    }
+    if(curr_vpp_metrics->packets_in - last_vpp_metrics->packets_in > 0) {
+      packets_in_this_round = curr_vpp_metrics->packets_in - last_vpp_metrics->packets_in;
+    }
+    else {
+      packets_in_this_round = 0;
+    }
+    if(curr_vpp_metrics->packets_out - last_vpp_metrics->packets_out > 0) {
+      packets_out_this_round = curr_vpp_metrics->packets_out - last_vpp_metrics->packets_out;
+    }
+    else {
+      packets_out_this_round = 0;
+    }
+
+    vpp_m = evel_new_measurement(READ_INTERVAL);
+
+    if(vpp_m != NULL) {
+      printf("New measurement report created...\n");
+      evel_measurement_vnic_use_add(vpp_m,             /* Pointer to the measurement      */ 
+                                    vnic,              /* ASCII string with the vNIC's ID */
+                   packets_in_this_round,              /* Packets received                */
+                  packets_out_this_round,              /* Packets transmitted             */
+                                        0,             /* Broadcast packets received      */
+                                        0,             /* Broadcast packets transmitted   */
+                     bytes_in_this_round,              /* Total bytes received            */
+                    bytes_out_this_round,              /* Total bytes transmitted         */
+                                       0,              /* Multicast packets received      */
+                                       0,              /* Multicast packets transmitted   */
+                                       0,              /* Unicast packets received        */
+                                       0);             /* Unicast packets transmitted     */
+
+      /***************************************************************************/
+      /* Set parameters in the MEASUREMENT header packet                         */
+      /***************************************************************************/
+      last_epoch = start_epoch + READ_INTERVAL * 1000000;
+      vpp_m_header = (EVENT_HEADER *)vpp_m;
+      vpp_m_header->start_epoch_microsec = start_epoch;
+      vpp_m_header->last_epoch_microsec = last_epoch;
+      strcpy(vpp_m_header->reporting_entity_id.value, "No UUID available");
+      strcpy(vpp_m_header->reporting_entity_name, hostname);
+      evel_rc = evel_post_event(vpp_m_header);
+
+      if(evel_rc == EVEL_SUCCESS) {
+        printf("Measurement report correctly sent to the collector!\n");
+      }
+      else {
+        printf("Post failed %d (%s)\n", evel_rc, evel_error_string());
+      }
+    }
+    else {
+      printf("New measurement report failed (%s)\n", evel_error_string());
+    }
+
+    last_vpp_metrics->bytes_in = curr_vpp_metrics->bytes_in;
+    last_vpp_metrics->bytes_out = curr_vpp_metrics->bytes_out;
+    last_vpp_metrics->packets_in = curr_vpp_metrics->packets_in;
+    last_vpp_metrics->packets_out = curr_vpp_metrics->packets_out;
+    gettimeofday(&time_val, NULL);
+    start_epoch = time_val.tv_sec * 1000000 + time_val.tv_usec;
+
+    sleep(READ_INTERVAL);
+  }
+
+  /***************************************************************************/
+  /* Terminate                                                               */
+  /***************************************************************************/
+  sleep(1);
+  free(last_vpp_metrics);
+  free(curr_vpp_metrics);
+  evel_terminate();
+  printf("Terminated\n");
+
+  return 0;
+}
+
+void read_vpp_metrics(vpp_metrics_struct *vpp_metrics, char *vnic) {
+  // Define an array of char that contains the parameters of the unix 'cut' command
+  char* params[] = {"-f3", "-f11", "-f4", "-f12"};
+  // Define the unix command to execute in order to read metrics from the vNIC
+  char* cmd_prefix = "sudo cat /proc/net/dev | grep \"";
+  char* cmd_mid = "\" | tr -s \' \' | cut -d\' \' ";
+  char cmd[BUFSIZE];
+  // Define other variables
+  char buf[BUFSIZE];           /* buffer used to store VPP metrics     */
+  int temp[] = {0, 0, 0, 0};   /* temp array that contains VPP values  */
+  FILE *fp;                    /* file descriptor to pipe cmd to shell */
+  int i;
+
+  for(i = 0; i < 4; i++) {
+    // Clear buffers
+    memset(buf, 0, BUFSIZE);
+    memset(cmd, 0, BUFSIZE);
+    // Build shell command to read metrics from the vNIC
+    strcat(cmd, cmd_prefix);
+    strcat(cmd, vnic);
+    strcat(cmd, cmd_mid);
+    strcat(cmd, params[i]);
+    
+    // Open a pipe and read VPP values
+    if ((fp = popen(cmd, "r")) == NULL) {
+        printf("Error opening pipe!\n");
+        return;
+    }
+
+    while (fgets(buf, BUFSIZE, fp) != NULL);
+    temp[i] = atoi(buf);
+
+    if(pclose(fp))  {
+        printf("Command not found or exited with error status\n");
+        return;
+    }
+  }
+
+  // Store metrics read from the vNIC in the struct passed from the main function
+  vpp_metrics->bytes_in = temp[0];
+  vpp_metrics->bytes_out = temp[1];
+  vpp_metrics->packets_in = temp[2];
+  vpp_metrics->packets_out = temp[3];
+}
diff --git a/vnfs/VESreporting_vLB/LICENSE.TXT b/vnfs/VESreporting_vLB/LICENSE.TXT
new file mode 100644 (file)
index 0000000..ae12da2
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * ============LICENSE_START==========================================
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ===================================================================
+ * 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.
+ * ============LICENSE_END============================================
+ *
+ * ECOMP and OpenECOMP are trademarks 
+ * and service marks of AT&T Intellectual Property.
+ *
+ */
diff --git a/vnfs/VESreporting_vLB/Makefile b/vnfs/VESreporting_vLB/Makefile
new file mode 100644 (file)
index 0000000..094adab
--- /dev/null
@@ -0,0 +1,41 @@
+
+#############################################################################
+#
+# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+#
+# 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.
+#
+#############################################################################
+
+CC=gcc
+
+ARCH=$(shell getconf LONG_BIT)
+CODE_ROOT=$(CURDIR)/../../..
+LIBS_DIR=$(CODE_ROOT)/libs/x86_$(ARCH)
+INCLUDE_DIR=$(CODE_ROOT)/code/evel_library
+
+#******************************************************************************
+# Standard compiler flags.                                                    *
+#******************************************************************************
+CPPFLAGS=
+CFLAGS=-Wall -g -fPIC
+
+all:   vpp_measurement_reporter
+
+clean:
+       rm -f vpp_measurement_reporter
+
+vpp_measurement_reporter: vpp_measurement_reporter.c
+       $(CC) $(CPPFLAGS) $(CFLAGS) -o vpp_measurement_reporter \
+                                    -L $(LIBS_DIR) \
+                                    -I $(INCLUDE_DIR) \
+                               vpp_measurement_reporter.c -lm -lpthread -level -lcurl
diff --git a/vnfs/VESreporting_vLB/README.md b/vnfs/VESreporting_vLB/README.md
new file mode 100644 (file)
index 0000000..dc47e62
--- /dev/null
@@ -0,0 +1,25 @@
+
+PROJECT DESCRIPTION
+---
+This project contains the source code and scripts for the periodic generation of network measurement reports. The folder contains:
+
+ - README.md: this file.
+
+ - LICENSE.TXT: the license text.
+
+ - vpp_measurement_reporter.c: source code that uses the ECOMP Vendor Event Listener Library (VES) to read metrics from the network interface and send periodic measurement reports to the VES collector in DCAE. The VES library used here has been cloned from the GitHub repository at https://github.com/att/evel-library on February 1, 2017.
+
+ - Makefile: makefile that compiles vpp_measurement_reporter.c and generates vpp_measurement_reporter binary.
+
+ - go-client.sh: bash script that starts up the vpp_measurement_reporter binary generated by Makefile. It reads input parameters like DCAE IP address and port from configuration files contained in /opt/config.
+
+
+USAGE
+---
+To run the vpp_measurement_reporter, please execute the following steps:
+
+ - Make the go-client.sh script executable
+        chmod +x go-client.sh
+
+ - Run the go-client.sh script
+        ./go-client.sh  
diff --git a/vnfs/VESreporting_vLB/dep.xml b/vnfs/VESreporting_vLB/dep.xml
new file mode 100644 (file)
index 0000000..fc18229
--- /dev/null
@@ -0,0 +1,25 @@
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" 
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+  <id>demo</id>
+  <formats>
+    <format>tar.gz</format>
+  </formats>
+  <fileSets>
+
+    <fileSet>
+      <directory>.</directory>
+      <outputDirectory>/</outputDirectory>
+      <includes>
+        <include>*.sh</include>
+       <include>*.md</include>
+       <include>*.TXT</include>
+       <include>*.c</include>
+       <include>Makefile</include>
+      </includes>
+    </fileSet>
+
+  </fileSets>
+</assembly>
+
+
diff --git a/vnfs/VESreporting_vLB/go-client.sh b/vnfs/VESreporting_vLB/go-client.sh
new file mode 100755 (executable)
index 0000000..3d1b159
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+export LD_LIBRARY_PATH="/opt/VES/libs/x86_64/"
+DCAE_COLLECTOR_IP=$(cat /opt/config/dcae_collector_ip.txt)
+DCAE_COLLECTOR_PORT=$(cat /opt/config/dcae_collector_port.txt)
+./vpp_measurement_reporter $DCAE_COLLECTOR_IP $DCAE_COLLECTOR_PORT eth1
diff --git a/vnfs/VESreporting_vLB/pom.xml b/vnfs/VESreporting_vLB/pom.xml
new file mode 100644 (file)
index 0000000..0478395
--- /dev/null
@@ -0,0 +1,55 @@
+<!--<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">-->
+<project>
+<parent>
+    <groupId>org.openecomp.demo.vnf</groupId>
+    <artifactId>demo-aggregator</artifactId>
+    <version>1.0.0</version>
+<relativePath>../pom.xml</relativePath>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.openecomp.demo.vnf.ves</groupId>
+  <artifactId>ves_vlb_reporting</artifactId>
+ <!-- <name>vfw_pg_streams</name>-->
+  <version>1.0.0</version>
+  <build>
+    <plugins>
+
+       <plugin>
+        <artifactId>maven-jar-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>default-jar</id>
+            <phase>never</phase>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <version>2.5.3</version>
+        <configuration>
+          <descriptor>dep.xml</descriptor>
+        </configuration>
+        <executions>
+          <execution>
+            <id>create-archive</id>
+            <phase>package</phase>
+            <goals>
+              <goal>single</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+<plugin>
+  <groupId>org.apache.maven.plugins</groupId>
+  <artifactId>maven-deploy-plugin</artifactId>
+  <configuration>
+    <skip>false</skip>
+  </configuration>
+</plugin>
+
+    </plugins>
+  </build>
+
+</project>
diff --git a/vnfs/VESreporting_vLB/vpp_measurement_reporter.c b/vnfs/VESreporting_vLB/vpp_measurement_reporter.c
new file mode 100644 (file)
index 0000000..1a1e7ac
--- /dev/null
@@ -0,0 +1,246 @@
+
+/*************************************************************************//**
+ *
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/time.h>
+#include <math.h>
+
+#include "evel.h"
+
+#define BUFSIZE 128
+#define READ_INTERVAL 10
+
+typedef struct dummy_vpp_metrics_struct {
+  int bytes_in;
+  int bytes_out;
+  int packets_in;
+  int packets_out;
+} vpp_metrics_struct;
+
+void read_vpp_metrics(vpp_metrics_struct *, char *);
+
+int main(int argc, char** argv)
+{
+  EVEL_ERR_CODES evel_rc = EVEL_SUCCESS;
+  EVENT_MEASUREMENT* vpp_m = NULL;
+  EVENT_HEADER* vpp_m_header = NULL;
+  int bytes_in_this_round;
+  int bytes_out_this_round;
+  int packets_in_this_round;
+  int packets_out_this_round;
+  vpp_metrics_struct* last_vpp_metrics = malloc(sizeof(vpp_metrics_struct));
+  vpp_metrics_struct* curr_vpp_metrics = malloc(sizeof(vpp_metrics_struct));
+  struct timeval time_val;
+  time_t start_epoch;
+  time_t last_epoch;
+  char hostname[BUFSIZE];
+  char* fqdn = argv[1];
+  int port = atoi(argv[2]);
+  char* vnic = argv[3];
+
+  printf("\nVector Packet Processing (VPP) measurement collection\n");
+  fflush(stdout);
+
+  if (argc != 4)
+  {
+    fprintf(stderr, "Usage: %s <FQDN>|<IP address> <port> <interface>\n", argv[0]);
+    exit(-1);
+  }
+
+  /**************************************************************************/
+  /* Initialize                                                             */
+  /**************************************************************************/
+  if(evel_initialize(fqdn,                         /* FQDN                  */
+                     port,                        /* Port                  */
+                     NULL,                         /* optional path         */
+                     NULL,                         /* optional topic        */
+                     0,                            /* HTTPS?                */
+                     "",                           /* Username              */
+                     "",                           /* Password              */
+                     EVEL_SOURCE_VIRTUAL_MACHINE,  /* Source type           */
+                     "vLoadBalancer",              /* Role                  */
+                     1))                           /* Verbosity             */
+  {
+    fprintf(stderr, "\nFailed to initialize the EVEL library!!!\n");
+    exit(-1);
+  }
+  else
+  {
+    printf("\nInitialization completed\n");
+  }
+
+  gethostname(hostname, BUFSIZE);
+  memset(last_vpp_metrics, 0, sizeof(vpp_metrics_struct));
+  read_vpp_metrics(last_vpp_metrics, vnic);
+  gettimeofday(&time_val, NULL);
+  start_epoch = time_val.tv_sec * 1000000 + time_val.tv_usec;
+  sleep(READ_INTERVAL);
+
+  /***************************************************************************/
+  /* Collect metrics from the VNIC                                           */
+  /***************************************************************************/
+  while(1) {
+    // Read the number of vDNSs currently active
+    int active_dns = 0;
+    FILE* fd = fopen("active_dns.txt", "r");
+    while(!feof(fd)) {
+      if(fscanf(fd, "%d", &active_dns) != 1) /* Avoid infinite loops if the file doesn't contain exactly one number */
+        break;
+    }
+
+    if(fclose(fd))  {
+      printf("Error when closing file\n");
+      return 1;
+    }
+
+    memset(curr_vpp_metrics, 0, sizeof(vpp_metrics_struct));
+    read_vpp_metrics(curr_vpp_metrics, vnic);
+
+    if(active_dns > 0 && (curr_vpp_metrics->bytes_in - last_vpp_metrics->bytes_in > 0)) {
+      bytes_in_this_round = (int) round((curr_vpp_metrics->bytes_in - last_vpp_metrics->bytes_in) / active_dns);
+    }
+    else {
+      bytes_in_this_round = 0;
+    }
+    if(active_dns > 0 && (curr_vpp_metrics->bytes_out - last_vpp_metrics->bytes_out > 0)) {
+      bytes_out_this_round = (int) round((curr_vpp_metrics->bytes_out - last_vpp_metrics->bytes_out) / active_dns);
+    }
+    else {
+      bytes_out_this_round = 0;
+    }
+    if(active_dns > 0 && (curr_vpp_metrics->packets_in - last_vpp_metrics->packets_in > 0)) {
+      packets_in_this_round = (int) round((curr_vpp_metrics->packets_in - last_vpp_metrics->packets_in) / active_dns);
+    }
+    else {
+      packets_in_this_round = 0;
+    }
+    if(active_dns > 0 && (curr_vpp_metrics->packets_out - last_vpp_metrics->packets_out > 0)) {
+      packets_out_this_round = (int) round((curr_vpp_metrics->packets_out - last_vpp_metrics->packets_out) / active_dns);
+    }
+    else {
+      packets_out_this_round = 0;
+    }
+
+    vpp_m = evel_new_measurement(READ_INTERVAL);
+
+    if(vpp_m != NULL) {
+      printf("New measurement report created...\n");
+      evel_measurement_vnic_use_add(vpp_m,             /* Pointer to the measurement      */ 
+                                    vnic,              /* ASCII string with the vNIC's ID */
+                   packets_in_this_round,              /* Packets received                */
+                  packets_out_this_round,              /* Packets transmitted             */
+                                        0,             /* Broadcast packets received      */
+                                        0,             /* Broadcast packets transmitted   */
+                     bytes_in_this_round,              /* Total bytes received            */
+                    bytes_out_this_round,              /* Total bytes transmitted         */
+                                       0,              /* Multicast packets received      */
+                                       0,              /* Multicast packets transmitted   */
+                                       0,              /* Unicast packets received        */
+                                       0);             /* Unicast packets transmitted     */
+
+      /***************************************************************************/
+      /* Set parameters in the MEASUREMENT header packet                         */
+      /***************************************************************************/
+      last_epoch = start_epoch + READ_INTERVAL * 1000000;
+      vpp_m_header = (EVENT_HEADER *)vpp_m;
+      vpp_m_header->start_epoch_microsec = start_epoch;
+      vpp_m_header->last_epoch_microsec = last_epoch;
+      strcpy(vpp_m_header->reporting_entity_id.value, "No UUID available");
+      strcpy(vpp_m_header->reporting_entity_name, hostname);
+      evel_rc = evel_post_event(vpp_m_header);
+
+      if(evel_rc == EVEL_SUCCESS) {
+        printf("Measurement report correctly sent to the collector!\n");
+      }
+      else {
+        printf("Post failed %d (%s)\n", evel_rc, evel_error_string());
+      }
+    }
+    else {
+      printf("New measurement report failed (%s)\n", evel_error_string());
+    }
+
+    last_vpp_metrics->bytes_in = curr_vpp_metrics->bytes_in;
+    last_vpp_metrics->bytes_out = curr_vpp_metrics->bytes_out;
+    last_vpp_metrics->packets_in = curr_vpp_metrics->packets_in;
+    last_vpp_metrics->packets_out = curr_vpp_metrics->packets_out;
+    gettimeofday(&time_val, NULL);
+    start_epoch = time_val.tv_sec * 1000000 + time_val.tv_usec;
+
+    sleep(READ_INTERVAL);
+  }
+
+  /***************************************************************************/
+  /* Terminate                                                               */
+  /***************************************************************************/
+  sleep(1);
+  free(last_vpp_metrics);
+  free(curr_vpp_metrics);
+  evel_terminate();
+  printf("Terminated\n");
+
+  return 0;
+}
+
+void read_vpp_metrics(vpp_metrics_struct *vpp_metrics, char *vnic) {
+  // Define an array of char that contains the parameters of the unix 'cut' command
+  char* params[] = {"-f3", "-f11", "-f4", "-f12"};
+  // Define the unix command to execute in order to read metrics from the vNIC
+  char* cmd_prefix = "sudo cat /proc/net/dev | grep \"";
+  char* cmd_mid = "\" | tr -s \' \' | cut -d\' \' ";
+  char cmd[BUFSIZE];
+  // Define other variables
+  char buf[BUFSIZE];           /* buffer used to store VPP metrics     */
+  int temp[] = {0, 0, 0, 0};   /* temp array that contains VPP values  */
+  FILE *fp;                    /* file descriptor to pipe cmd to shell */
+  int i;
+
+  for(i = 0; i < 4; i++) {
+    // Clear buffers
+    memset(buf, 0, BUFSIZE);
+    memset(cmd, 0, BUFSIZE);
+    // Build shell command to read metrics from the vNIC
+    strcat(cmd, cmd_prefix);
+    strcat(cmd, vnic);
+    strcat(cmd, cmd_mid);
+    strcat(cmd, params[i]);
+    
+    // Open a pipe and read VPP values
+    if ((fp = popen(cmd, "r")) == NULL) {
+      printf("Error opening pipe!\n");
+      return;
+    }
+
+    while (fgets(buf, BUFSIZE, fp) != NULL);
+    temp[i] = atoi(buf);
+
+    if(pclose(fp))  {
+      printf("Command not found or exited with error status\n");
+      return;
+    }
+  }
+
+  // Store metrics read from the vNIC in the struct passed from the main function
+  vpp_metrics->bytes_in = temp[0];
+  vpp_metrics->bytes_out = temp[1];
+  vpp_metrics->packets_in = temp[2];
+  vpp_metrics->packets_out = temp[3];
+}
diff --git a/vnfs/honeycomb_plugin/.DS_Store b/vnfs/honeycomb_plugin/.DS_Store
new file mode 100644 (file)
index 0000000..f20da4b
Binary files /dev/null and b/vnfs/honeycomb_plugin/.DS_Store differ
diff --git a/vnfs/honeycomb_plugin/sample_plugin/.DS_Store b/vnfs/honeycomb_plugin/sample_plugin/.DS_Store
new file mode 100644 (file)
index 0000000..c7a6a7a
Binary files /dev/null and b/vnfs/honeycomb_plugin/sample_plugin/.DS_Store differ
diff --git a/vnfs/honeycomb_plugin/sample_plugin/LICENSE.TXT b/vnfs/honeycomb_plugin/sample_plugin/LICENSE.TXT
new file mode 100644 (file)
index 0000000..5640474
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * ============LICENSE_START==========================================
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ===================================================================
+ * 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.
+ * ============LICENSE_END============================================
+ *
+ * ECOMP and OpenECOMP are trademarks 
+ * and service marks of AT&T Intellectual Property.
+ *
+ */
\ No newline at end of file
diff --git a/vnfs/honeycomb_plugin/sample_plugin/README.md b/vnfs/honeycomb_plugin/sample_plugin/README.md
new file mode 100755 (executable)
index 0000000..2719e64
--- /dev/null
@@ -0,0 +1,16 @@
+# Honeycomb plugin for VPP's packet generator plugin
+
+This plugin provides REST API to enable/disable streams on the VPP's packet generator. 
+
+
+Buid instructions:
+
+From the sample_pluging folder execute: mvn -s settings.xml clean install.
+
+
+Run instruction:
+
+From the sample_pluging folder execute: ./sample-distribution/target/sample-distribution-1.0.0-hc/sample-distribution-1.0.0/honeycomb
+
+
+In order to allow access to REST API from an external machine, modify the "restconf-binding-address" parameter in sample-distribution/target/sample-distribution-1.0.0-hc/sample-distribution-1.0.0/config/honeycomb.json
diff --git a/vnfs/honeycomb_plugin/sample_plugin/parent-pom/pom.xml b/vnfs/honeycomb_plugin/sample_plugin/parent-pom/pom.xml
new file mode 100644 (file)
index 0000000..16cd604
--- /dev/null
@@ -0,0 +1,244 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright (c) 2016 Cisco and/or its affiliates.
+  ~
+  ~ 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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+
+<parent>
+    <groupId>org.openecomp.demo.vnf</groupId>
+    <artifactId>demo-aggregator</artifactId>
+    <version>1.0.0</version>
+    <relativePath>../../../pom.xml</relativePath>
+</parent>
+
+    <properties>
+        <nexusproxy>http://nexus.fd.io/content</nexusproxy>
+        <start.script.template>
+#!/bin/sh -
+STATUS=100
+
+while [ $STATUS -eq 100 ]
+do
+  %s
+  STATUS=$?
+  echo "Honeycomb exited with status: $STATUS"
+  if [ $STATUS -eq 100 ]
+  then
+    echo "Restarting..."
+  fi
+done
+        </start.script.template>
+        <exec.parameters>-Xms32m -Xmx128m -XX:MetaspaceSize=32m -XX:MaxMetaspaceSize=128m</exec.parameters>
+        <exec.parameters.minimal>-client -Xms20m -Xmx32m -XX:MetaspaceSize=5m -XX:MaxMetaspaceSize=32m -XX:MaxMetaspaceExpansion=1m -Xss512k -XX:+UseSerialGC -Djava.compiler=NONE -Xverify:none -noverify</exec.parameters.minimal>
+        <debug.parameters>-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005</debug.parameters>
+        <guice.version>4.1.0</guice.version>
+        <guice.config.version>1.2.0</guice.config.version>
+        <restconf.version>1.3.2-Beryllium-SR2</restconf.version>
+        <netconf.version>1.0.2-Beryllium-SR2</netconf.version>
+        <jersey.version>1.19.1</jersey.version>
+        <jetty.version>9.3.11.v20160721</jetty.version>
+        <servlet.version>3.1.0</servlet.version>
+        <yangtools.version>0.8.2-Beryllium-SR2</yangtools.version>
+        <mdsal.version>1.3.2-Beryllium-SR2</mdsal.version>
+        <!-- Used by mdsal as provided/runtime dependency-->
+        <osgi.core.version>5.0.0</osgi.core.version>
+    </properties>
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>io.fd.honeycomb.common</groupId>
+    <artifactId>minimal-distribution-parent</artifactId>
+    <version>1.16.9</version>
+    <packaging>pom</packaging>
+
+    <!-- Generate executable shell script -->
+    <build>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-compiler-plugin</artifactId>
+                    <version>3.3</version>
+                    <configuration>
+                        <!-- Use google's error-prone static analysis-->
+                        <compilerId>javac-with-errorprone</compilerId>
+                        <forceJavacCompilerUse>true</forceJavacCompilerUse>
+                        <showWarnings>true</showWarnings>
+                        <source>1.8</source>
+                        <target>1.8</target>
+                    </configuration>
+                    <dependencies>
+                        <dependency>
+                            <groupId>org.codehaus.plexus</groupId>
+                            <artifactId>plexus-compiler-javac-errorprone</artifactId>
+                            <version>2.5</version>
+                        </dependency>
+                        <!-- override plexus-compiler-javac-errorprone's dependency on
+                             Error Prone with the latest version -->
+                        <dependency>
+                            <groupId>com.google.errorprone</groupId>
+                            <artifactId>error_prone_core</artifactId>
+                            <version>2.0.9</version>
+                        </dependency>
+                    </dependencies>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-jar-plugin</artifactId>
+                    <version>2.6</version>
+                    <configuration>
+                        <archive>
+                            <manifest>
+                                <mainClass>${main.class}</mainClass>
+                                <addClasspath>true</addClasspath>
+                                <classpathPrefix>lib/</classpathPrefix>
+                                <useUniqueVersions>false</useUniqueVersions>
+                                <classpathMavenRepositoryLayout>true</classpathMavenRepositoryLayout>
+                            </manifest>
+                            <manifestEntries>
+                                <Class-Path>config/ cert/</Class-Path>
+                            </manifestEntries>
+                        </archive>
+                    </configuration>
+                </plugin>
+
+                <!-- Copy all dependencies -->
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-dependency-plugin</artifactId>
+                    <version>2.10</version>
+                    <executions>
+                        <execution>
+                            <id>copy-dependencies</id>
+                            <phase>package</phase>
+                            <goals>
+                                <goal>copy-dependencies</goal>
+                            </goals>
+                            <configuration>
+                                <outputDirectory>${project.build.directory}/lib</outputDirectory>
+                                <useBaseVersion>true</useBaseVersion>
+                                <useRepositoryLayout>true</useRepositoryLayout>
+                                <excludeArtifactIds>yang-jmx-generator</excludeArtifactIds>
+                            </configuration>
+                        </execution>
+                        <execution>
+                            <id>unpack-configuration</id>
+                            <phase>prepare-package</phase>
+                            <goals>
+                                <goal>unpack-dependencies</goal>
+                            </goals>
+                            <configuration>
+                                <includes>**/honeycomb-minimal-resources/</includes>
+                                <outputDirectory>${project.build.outputDirectory}/</outputDirectory>
+                            </configuration>
+                        </execution>
+                    </executions>
+                </plugin>
+
+                <!-- Generate shell script -->
+                <plugin>
+                    <groupId>org.codehaus.gmaven</groupId>
+                    <artifactId>groovy-maven-plugin</artifactId>
+                    <version>2.0</version>
+                    <executions>
+                        <execution>
+                            <phase>package</phase>
+                            <goals>
+                                <goal>execute</goal>
+                            </goals>
+                            <configuration>
+                                <!-- TODO add remote debug option -->
+                                <!-- TODO add clean option -->
+                                <!-- TODO add shutdown script -->
+                                <!-- TODO add restart script -->
+                                <!-- TODO pass options to JVM? -->
+                                <source>
+                                    import java.nio.file.Paths
+
+                                    log.info "Generating shell exec script"
+                                    def scriptTemplate = properties.getOrDefault("start.script.template", "")
+                                    def args = properties.getOrDefault("exec.parameters", "")
+                                    log.debug "Additional shell exec script properties: ${args}"
+                                    def javaArgs = "${args} -jar \$(dirname \$0)/${project.artifactId}-${project.version}.jar"
+                                    def scriptParent = Paths.get(project.build.outputDirectory, "honeycomb-minimal-resources")
+                                    scriptParent.toFile().mkdirs()
+                                    def scriptContent = "java " + javaArgs
+                                    log.info "Generating shell exec script as ${scriptContent}"
+                                    def scriptPath = Paths.get(scriptParent.toString(), "honeycomb")
+                                    log.info "Writing shell exec script to ${scriptPath}"
+                                    scriptPath.toFile().text = String.format(scriptTemplate, scriptContent)
+                                    scriptPath.toFile().setExecutable(true)
+
+                                    scriptPath = Paths.get(scriptParent.toString(), "honeycomb-start")
+                                    log.info "Writing shell exec script to ${scriptPath}"
+                                    scriptPath.toFile().text = "\$(dirname \$0)/honeycomb &amp;"
+                                    scriptPath.toFile().setExecutable(true)
+
+                                    def debug_args = properties.getOrDefault("debug.parameters", "")
+                                    def debugScriptContent = "java" + " ${debug_args} " + javaArgs
+                                    log.info "Generating shell debug script as ${debugScriptContent}"
+                                    scriptPath = Paths.get(scriptParent.toString(), "honeycomb-debug")
+                                    log.info "Writing shell debug script to ${scriptPath}"
+                                    scriptPath.toFile().text = String.format(scriptTemplate, debugScriptContent)
+                                    scriptPath.toFile().setExecutable(true)
+                                </source>
+                            </configuration>
+                        </execution>
+                    </executions>
+                </plugin>
+
+                <!-- Build archives -->
+                <plugin>
+                    <artifactId>maven-assembly-plugin</artifactId>
+                    <version>2.5.3</version>
+                    <dependencies>
+                        <dependency>
+                            <groupId>io.fd.honeycomb.common</groupId>
+                            <artifactId>minimal-assembly-descriptor</artifactId>
+                            <version>1.16.9</version>
+                        </dependency>
+                    </dependencies>
+                    <executions>
+                        <execution>
+                            <id>create-archive</id>
+                            <phase>package</phase>
+                            <goals>
+                                <goal>single</goal>
+                            </goals>
+                            <configuration>
+                                <descriptorRefs>
+                                    <descriptorRef>honeycomb-minimal</descriptorRef>
+                                </descriptorRefs>
+                            </configuration>
+                        </execution>
+                    </executions>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+
+<!--    <distributionManagement>
+        <repository>
+            <id>fdio-release</id>
+            <url>${nexusproxy}/repositories/fd.io.release/</url>
+        </repository>
+        <snapshotRepository>
+            <id>fdio-snapshot</id>
+            <url>${nexusproxy}/repositories/fd.io.snapshot/</url>
+        </snapshotRepository>
+    </distributionManagement>
+-->
+</project>
diff --git a/vnfs/honeycomb_plugin/sample_plugin/pom.xml b/vnfs/honeycomb_plugin/sample_plugin/pom.xml
new file mode 100755 (executable)
index 0000000..2da40d3
--- /dev/null
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ 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.
+--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <parent>
+    <groupId>org.opendaylight.odlparent</groupId>
+    <artifactId>odlparent</artifactId>
+    <version>1.6.2-Beryllium-SR2</version>
+  </parent>
+
+  <groupId>org.openecomp.demo.vnf</groupId>
+  <artifactId>sample-plugin-aggregator</artifactId>
+  <version>1.0.0</version>
+  <name>sample-plugin-aggregator</name>
+  <packaging>pom</packaging>
+  <modelVersion>4.0.0</modelVersion>
+  <prerequisites>
+    <maven>3.1.1</maven>
+  </prerequisites>
+
+  <modules>
+    <module>sample-plugin-api</module>
+    <module>sample-plugin-impl</module>
+    <module>sample-distribution</module>
+  </modules>
+
+  <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-install-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/vnfs/honeycomb_plugin/sample_plugin/sample-distribution/.DS_Store b/vnfs/honeycomb_plugin/sample_plugin/sample-distribution/.DS_Store
new file mode 100644 (file)
index 0000000..935eda9
Binary files /dev/null and b/vnfs/honeycomb_plugin/sample_plugin/sample-distribution/.DS_Store differ
diff --git a/vnfs/honeycomb_plugin/sample_plugin/sample-distribution/pom.xml b/vnfs/honeycomb_plugin/sample_plugin/sample-distribution/pom.xml
new file mode 100755 (executable)
index 0000000..0d8ddd7
--- /dev/null
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <!-- <parent>
+    <groupId>io.fd.honeycomb.common</groupId>
+    <artifactId>minimal-distribution-parent</artifactId>
+    <version>1.16.9</version>
+  </parent>
+-->
+<parent>
+<groupId>io.fd.honeycomb.common</groupId>
+    <artifactId>minimal-distribution-parent</artifactId>
+    <version>1.16.9</version>
+<relativePath>../parent-pom/pom.xml</relativePath>
+</parent>
+<!--
+<parent>
+    <groupId>org.openecomp.demo.vnf</groupId>
+    <artifactId>demo-aggregator</artifactId>
+    <version>1.0.0</version>
+<relativePath>../../../pom.xml</relativePath>
+  </parent>
+-->
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.openecomp.demo.vnf</groupId>
+  <artifactId>sample-distribution</artifactId>
+  <version>1.0.0</version>
+
+  <properties>
+    <main.class>io.fd.honeycomb.vpp.integration.distro.Main</main.class>
+    <v3po.version>1.16.9</v3po.version>
+    <lisp.version>1.16.9</lisp.version>
+    <vpp.common.min.distro.version>1.16.9</vpp.common.min.distro.version>
+    <vppnsh.version>1.16.9</vppnsh.version>
+  </properties>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.gmaven</groupId>
+        <artifactId>groovy-maven-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <artifactId>maven-assembly-plugin</artifactId>
+      </plugin>
+
+<plugin>
+  <groupId>org.apache.maven.plugins</groupId>
+  <artifactId>maven-deploy-plugin</artifactId>
+  <configuration>
+    <skip>false</skip>
+  </configuration>
+</plugin>
+
+<plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-install-plugin</artifactId>
+        <configuration>
+          <skip>false</skip>
+        </configuration>
+      </plugin>
+
+    </plugins>
+  </build>
+
+  <dependencies>
+    <dependency>
+      <groupId>io.fd.honeycomb.vpp</groupId>
+      <artifactId>minimal-distribution</artifactId>
+      <version>${vpp.common.min.distro.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>io.fd.honeycomb.v3po</groupId>
+      <artifactId>v3po2vpp</artifactId>
+      <version>${v3po.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>io.fd.honeycomb.lisp</groupId>
+      <artifactId>lisp2vpp</artifactId>
+      <version>${lisp.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>io.fd.honeycomb.vppnsh</groupId>
+      <artifactId>vppnsh-impl</artifactId>
+      <version>${vppnsh.version}</version>
+    </dependency>
+<dependency>
+      <groupId>org.openecomp.demo.vnf</groupId>
+      <artifactId>sample-plugin-impl</artifactId>
+      <version>1.0.0</version>
+    </dependency>
+  </dependencies>
+
+</project>
diff --git a/vnfs/honeycomb_plugin/sample_plugin/sample-distribution/src/.DS_Store b/vnfs/honeycomb_plugin/sample_plugin/sample-distribution/src/.DS_Store
new file mode 100644 (file)
index 0000000..6816049
Binary files /dev/null and b/vnfs/honeycomb_plugin/sample_plugin/sample-distribution/src/.DS_Store differ
diff --git a/vnfs/honeycomb_plugin/sample_plugin/sample-distribution/src/main/.DS_Store b/vnfs/honeycomb_plugin/sample_plugin/sample-distribution/src/main/.DS_Store
new file mode 100644 (file)
index 0000000..7db2c2e
Binary files /dev/null and b/vnfs/honeycomb_plugin/sample_plugin/sample-distribution/src/main/.DS_Store differ
diff --git a/vnfs/honeycomb_plugin/sample_plugin/sample-distribution/src/main/java/.DS_Store b/vnfs/honeycomb_plugin/sample_plugin/sample-distribution/src/main/java/.DS_Store
new file mode 100644 (file)
index 0000000..0645048
Binary files /dev/null and b/vnfs/honeycomb_plugin/sample_plugin/sample-distribution/src/main/java/.DS_Store differ
diff --git a/vnfs/honeycomb_plugin/sample_plugin/sample-distribution/src/main/java/io/.DS_Store b/vnfs/honeycomb_plugin/sample_plugin/sample-distribution/src/main/java/io/.DS_Store
new file mode 100644 (file)
index 0000000..47336c3
Binary files /dev/null and b/vnfs/honeycomb_plugin/sample_plugin/sample-distribution/src/main/java/io/.DS_Store differ
diff --git a/vnfs/honeycomb_plugin/sample_plugin/sample-distribution/src/main/java/io/fd/.DS_Store b/vnfs/honeycomb_plugin/sample_plugin/sample-distribution/src/main/java/io/fd/.DS_Store
new file mode 100644 (file)
index 0000000..0bb0440
Binary files /dev/null and b/vnfs/honeycomb_plugin/sample_plugin/sample-distribution/src/main/java/io/fd/.DS_Store differ
diff --git a/vnfs/honeycomb_plugin/sample_plugin/sample-distribution/src/main/java/io/fd/honeycomb/.DS_Store b/vnfs/honeycomb_plugin/sample_plugin/sample-distribution/src/main/java/io/fd/honeycomb/.DS_Store
new file mode 100644 (file)
index 0000000..70a4762
Binary files /dev/null and b/vnfs/honeycomb_plugin/sample_plugin/sample-distribution/src/main/java/io/fd/honeycomb/.DS_Store differ
diff --git a/vnfs/honeycomb_plugin/sample_plugin/sample-distribution/src/main/java/io/fd/honeycomb/tutorial/Main.java b/vnfs/honeycomb_plugin/sample_plugin/sample-distribution/src/main/java/io/fd/honeycomb/tutorial/Main.java
new file mode 100755 (executable)
index 0000000..d16c422
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * 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.
+ */
+
+package io.fd.honeycomb.vpp.integration.distro;
+
+import com.google.common.collect.Lists;
+import com.google.inject.Module;
+import io.fd.honeycomb.lisp.LispModule;
+import io.fd.honeycomb.translate.v3po.V3poModule;
+import io.fd.honeycomb.vpp.distro.VppCommonModule;
+import io.fd.honeycomb.vppnsh.impl.VppNshModule;
+import java.util.List;
+
+public class Main {
+
+    public static void main(String[] args) {
+        final List<Module> sampleModules = Lists.newArrayList(io.fd.honeycomb.infra.distro.Main.BASE_MODULES);
+
+        // All the plugins should be listed here
+        sampleModules.add(new VppCommonModule());
+        sampleModules.add(new V3poModule());
+        sampleModules.add(new LispModule());
+        sampleModules.add(new VppNshModule());
+        sampleModules.add(new io.fd.honeycomb.tutorial.Module());
+
+        io.fd.honeycomb.infra.distro.Main.init(sampleModules);
+    }
+}
diff --git a/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-api/.DS_Store b/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-api/.DS_Store
new file mode 100644 (file)
index 0000000..935eda9
Binary files /dev/null and b/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-api/.DS_Store differ
diff --git a/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-api/pom.xml b/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-api/pom.xml
new file mode 100755 (executable)
index 0000000..74506eb
--- /dev/null
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ 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.
+--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <groupId>io.fd.honeycomb.common</groupId>
+    <artifactId>api-parent</artifactId>
+    <version>1.16.9</version>
+    <relativePath>../../common/api-parent</relativePath>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.openecomp.demo.vnf</groupId>
+  <artifactId>sample-plugin-api</artifactId>
+  <version>1.0.0</version>
+  <packaging>bundle</packaging>
+
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.opendaylight.mdsal.model</groupId>
+        <artifactId>mdsal-model-artifacts</artifactId>
+        <version>0.8.2-Beryllium-SR2</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>iana-if-type-2014-05-08</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-yang-types-20130715</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-interfaces</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-inet-types-2013-07-15</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>yang-ext</artifactId>
+    </dependency>
+  </dependencies>
+
+<build>
+<plugins>
+<plugin>
+  <groupId>org.apache.maven.plugins</groupId>
+  <artifactId>maven-deploy-plugin</artifactId>
+  <configuration>
+    <skip>true</skip>
+  </configuration>
+</plugin>
+</plugins>
+</build>
+
+</project>
diff --git a/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-api/src/.DS_Store b/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-api/src/.DS_Store
new file mode 100644 (file)
index 0000000..6816049
Binary files /dev/null and b/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-api/src/.DS_Store differ
diff --git a/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-api/src/main/.DS_Store b/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-api/src/main/.DS_Store
new file mode 100644 (file)
index 0000000..45c9ff1
Binary files /dev/null and b/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-api/src/main/.DS_Store differ
diff --git a/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-api/src/main/yang/sample-plugin.yang b/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-api/src/main/yang/sample-plugin.yang
new file mode 100755 (executable)
index 0000000..df92978
--- /dev/null
@@ -0,0 +1,77 @@
+//*************************************************************//
+//
+// Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+//
+// 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.
+//
+//******************************************************************
+
+
+module sample-plugin {
+
+    yang-version 1;
+    namespace "urn:opendaylight:params:xml:ns:yang:sample-plugin";
+    prefix "sample-plugin";
+
+    import ietf-inet-types { prefix "inet"; }
+
+    description
+        "This YANG module defines the generic configuration and
+        operational data for sample-plugin in VPP";
+
+    revision "2016-09-18" {
+        description "Initial revision of sample-plugin model";
+    }
+
+    container sample-plugin {
+        uses sample-plugin-params;
+        description "Configuration data of sample-plugin in Honeycomb";
+
+        // READ
+        // curl -u admin:admin http://localhost:8181/restconf/config/sample-plugin:sample-plugin
+
+        // WRITE
+        // curl http://localhost:8181/restconf/operational/sample-plugin:sample-plugin
+
+    }
+
+    container sample-plugin-state {
+        config false;
+        uses sample-plugin-params;
+        description "Operational data of sample-plugin persisted in VPP";
+
+        // READ
+        // curl -u admin:admin  http://localhost:8181/restconf/operational/sample-plugin:sample-plugin-state
+    }
+
+    grouping sample-plugin-params {
+        container pg-streams {
+            list pg-stream {
+
+                key id;
+                leaf id {
+                    type string;
+                }
+
+                leaf is-enabled {
+                  type boolean;
+                }
+            }
+        }
+    }
+
+    notification sample-notification {
+        leaf content {
+            type string;
+        }
+    }
+}
diff --git a/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/.DS_Store b/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/.DS_Store
new file mode 100644 (file)
index 0000000..935eda9
Binary files /dev/null and b/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/.DS_Store differ
diff --git a/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/Readme.adoc b/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/Readme.adoc
new file mode 100755 (executable)
index 0000000..c3ca794
--- /dev/null
@@ -0,0 +1,3 @@
+--Documentation for sample-plugin --
+
+TODO Replace with general description whats the purpose of sample-plugin and how it works
diff --git a/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/pom.xml b/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/pom.xml
new file mode 100755 (executable)
index 0000000..59f3c1f
--- /dev/null
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ 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.
+--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>io.fd.honeycomb.common</groupId>
+        <artifactId>impl-parent</artifactId>
+        <version>1.16.9</version>
+        <relativePath>../../common/impl-parent</relativePath>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.openecomp.demo.vnf</groupId>
+    <artifactId>sample-plugin-impl</artifactId>
+    <version>1.0.0</version>
+    <packaging>bundle</packaging>
+
+    <properties>
+        <honeycomb.infra.version>1.16.9</honeycomb.infra.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.openecomp.demo.vnf</groupId>
+            <artifactId>sample-plugin-api</artifactId>
+            <version>1.0.0</version>
+        </dependency>
+
+        <!-- Honeycomb infrastructure-->
+        <dependency>
+            <groupId>io.fd.honeycomb</groupId>
+            <artifactId>translate-api</artifactId>
+            <version>${honeycomb.infra.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.fd.honeycomb.vpp</groupId>
+            <artifactId>vpp-translate-utils</artifactId>
+            <version>1.16.9</version>
+        </dependency>
+
+        <dependency>
+            <groupId>io.fd.honeycomb</groupId>
+            <artifactId>notification-api</artifactId>
+            <version>${honeycomb.infra.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>io.fd.honeycomb</groupId>
+            <artifactId>translate-spi</artifactId>
+            <version>${honeycomb.infra.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>io.fd.honeycomb</groupId>
+            <artifactId>cfg-init</artifactId>
+            <version>${honeycomb.infra.version}</version>
+        </dependency>
+
+        <!-- DI -->
+        <dependency>
+            <groupId>com.google.inject</groupId>
+            <artifactId>guice</artifactId>
+            <version>${guice.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>net.jmob</groupId>
+            <artifactId>guice.conf</artifactId>
+            <version>${guice.config.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.inject.extensions</groupId>
+            <artifactId>guice-multibindings</artifactId>
+            <version>${guice.version}</version>
+        </dependency>
+
+        <!-- VPP's core Java APIs -->
+        <dependency>
+            <groupId>io.fd.vpp</groupId>
+            <artifactId>jvpp-core</artifactId>
+            <version>16.09</version>
+        </dependency>
+    </dependencies>
+
+<build>
+<plugins>
+<plugin>
+  <groupId>org.apache.maven.plugins</groupId>
+  <artifactId>maven-deploy-plugin</artifactId>
+  <configuration>
+    <skip>true</skip>
+  </configuration>
+</plugin>
+</plugins>
+</build>
+
+</project>
diff --git a/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/src/main/java/io/fd/honeycomb/tutorial/Module.java b/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/src/main/java/io/fd/honeycomb/tutorial/Module.java
new file mode 100755 (executable)
index 0000000..8cd4600
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * 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.
+ */
+
+/*
+ * Modifications copyright (c) 2017 AT&T Intellectual Property
+ */
+
+package io.fd.honeycomb.tutorial;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.multibindings.Multibinder;
+import io.fd.honeycomb.data.init.DataTreeInitializer;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import io.fd.honeycomb.tutorial.init.ConfigDataInitializer;
+//import io.fd.honeycomb.tutorial.read.ModuleStateReaderFactory;
+import io.fd.honeycomb.tutorial.write.ModuleWriterFactory;
+import net.jmob.guice.conf.core.ConfigurationModule;
+
+/**
+ * Module class instantiating sample-plugin plugin components.
+ */
+public final class Module extends AbstractModule {
+
+    @Override
+    protected void configure() {
+        // requests injection of properties
+        install(ConfigurationModule.create());
+        requestInjection(ModuleConfiguration.class);
+
+        // bind naming context instance for reader and writer factories
+        // the first parameter is artificial name prefix in cases a name needs to be reconstructed for a vxlan tunnel
+        // that is present in VPP but not in Honeycomb (could be extracted into configuration)
+        // the second parameter is just the naming context ID (could be extracted into configuration)
+        binder().bind(NamingContext.class).toInstance(new NamingContext("pgstream", "pgstream-context"));
+
+        // creates reader factory binding
+        // can hold multiple binding for separate yang modules
+      //  final Multibinder<ReaderFactory> readerFactoryBinder = Multibinder.newSetBinder(binder(), ReaderFactory.class);
+      //  readerFactoryBinder.addBinding().to(ModuleStateReaderFactory.class);
+
+        // create writer factory binding
+        // can hold multiple binding for separate yang modules
+        final Multibinder<WriterFactory> writerFactoryBinder = Multibinder.newSetBinder(binder(), WriterFactory.class);
+        writerFactoryBinder.addBinding().to(ModuleWriterFactory.class);
+
+        // create initializer binding
+        // can hold multiple binding for separate yang modules
+        final Multibinder<DataTreeInitializer> initializerBinder =
+                Multibinder.newSetBinder(binder(), DataTreeInitializer.class);
+        initializerBinder.addBinding().to(ConfigDataInitializer.class);
+
+        // Disable notification producer for now
+//        Multibinder.newSetBinder(binder(), ManagedNotificationProducer.class).addBinding()
+//                .to(SampleNotificationProducer.class);
+    }
+}
diff --git a/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/src/main/java/io/fd/honeycomb/tutorial/ModuleConfiguration.java b/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/src/main/java/io/fd/honeycomb/tutorial/ModuleConfiguration.java
new file mode 100755 (executable)
index 0000000..ef6be6e
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * 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.
+ */
+
+package io.fd.honeycomb.tutorial;
+
+import net.jmob.guice.conf.core.BindConfig;
+import net.jmob.guice.conf.core.InjectConfig;
+import net.jmob.guice.conf.core.Syntax;
+
+/**
+ * Class containing static configuration for sample-plugin module,<br>
+ * either loaded from property file sample-plugin.json from classpath.
+ * <p/>
+ * Further documentation for the configuration injection can be found at:
+ * https://github.com/yyvess/gconf
+ */
+@BindConfig(value = "sample-plugin", syntax = Syntax.JSON)
+public final class ModuleConfiguration {
+
+    // TODO change the sample property to real plugin configuration
+    // If there is no such configuration, remove this, sample-plugin.json resource and its wiring from Module class
+
+    /**
+     * Sample property that's injected from external json configuration file.
+     */
+    @InjectConfig("sample-prop")
+    public String sampleProp;
+
+    /**
+     * Constant name used to identify sample-plugin plugin specific components during dependency injection.
+     */
+    public static final String ELEMENT_SERVICE_NAME = "element-service";
+}
diff --git a/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/src/main/java/io/fd/honeycomb/tutorial/init/ConfigDataInitializer.java b/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/src/main/java/io/fd/honeycomb/tutorial/init/ConfigDataInitializer.java
new file mode 100755 (executable)
index 0000000..8a7f4d1
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * 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.
+ */
+
+package io.fd.honeycomb.tutorial.init;
+
+import io.fd.honeycomb.data.init.AbstractDataTreeConverter;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.SamplePlugin;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.SamplePluginBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.SamplePluginState;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Initialize configuration data based on operational data.
+ * <p/>
+ * Very useful when a plugin is initiated but the underlying layer already contains some operation state.
+ * Deriving the configuration from existing operational state enables reconciliation in case when Honeycomb's persistence
+ * is not available to do the work for us.
+ */
+public final class ConfigDataInitializer extends AbstractDataTreeConverter<SamplePluginState, SamplePlugin> {
+
+    @Inject
+    public ConfigDataInitializer(@Named("honeycomb-initializer") @Nonnull final DataBroker bindingDataBroker) {
+        super(bindingDataBroker, InstanceIdentifier.create(SamplePluginState.class), InstanceIdentifier.create(SamplePlugin.class));
+    }
+
+    @Override
+    public SamplePlugin convert(final SamplePluginState operationalData) {
+        // Transfer all the operational data into configuration
+        return new SamplePluginBuilder()
+                .setPgStreams(operationalData.getPgStreams())
+                .build();
+    }
+}
diff --git a/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/src/main/java/io/fd/honeycomb/tutorial/notif/SampleNotificationProducer.java b/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/src/main/java/io/fd/honeycomb/tutorial/notif/SampleNotificationProducer.java
new file mode 100755 (executable)
index 0000000..6ae1394
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * 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.
+ */
+
+package io.fd.honeycomb.tutorial.notif;
+
+import io.fd.honeycomb.notification.ManagedNotificationProducer;
+import io.fd.honeycomb.notification.NotificationCollector;
+import java.util.Collection;
+import java.util.Collections;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.SampleNotification;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.SampleNotificationBuilder;
+import org.opendaylight.yangtools.yang.binding.Notification;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Notification producer for sample plugin
+ */
+public class SampleNotificationProducer implements ManagedNotificationProducer {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SampleNotificationProducer.class);
+
+    private Thread thread;
+
+    @Override
+    public void start(@Nonnull final NotificationCollector collector) {
+        LOG.info("Starting notification stream for interfaces");
+
+        // Simulating notification producer
+        thread = new Thread(() -> {
+            while(true) {
+                if (Thread.currentThread().isInterrupted()) {
+                    return;
+                }
+
+                try {
+                    Thread.sleep(2000);
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                    break;
+                }
+
+                final SampleNotification notification = new SampleNotificationBuilder()
+                        .setContent("Hello world " + System.currentTimeMillis())
+                        .build();
+                LOG.info("Emitting notification: {}", notification);
+                collector.onNotification(notification);
+            }
+        }, "NotificationProducer");
+        thread.setDaemon(true);
+        thread.start();
+    }
+
+    @Override
+    public void stop() {
+        if(thread != null) {
+            thread.interrupt();
+        }
+    }
+
+    @Nonnull
+    @Override
+    public Collection<Class<? extends Notification>> getNotificationTypes() {
+        // Producing only this single type of notification
+        return Collections.singleton(SampleNotification.class);
+    }
+
+    @Override
+    public void close() throws Exception {
+        stop();
+    }
+}
diff --git a/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/src/main/java/io/fd/honeycomb/tutorial/write/ModuleWriterFactory.java b/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/src/main/java/io/fd/honeycomb/tutorial/write/ModuleWriterFactory.java
new file mode 100755 (executable)
index 0000000..ad7669b
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * 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.
+ */
+
+/*
+ * Modifications copyright (c) 2017 AT&T Intellectual Property
+ */
+package io.fd.honeycomb.tutorial.write;
+
+import com.google.inject.Inject;
+import io.fd.honeycomb.translate.impl.write.GenericWriter;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.SamplePlugin;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.sample.plugin.params.PgStreams;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.sample.plugin.params.pg.streams.PgStream;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.core.future.FutureJVppCore;
+
+/**
+ * Factory producing writers for sample-plugin plugin's data.
+ */
+public final class ModuleWriterFactory implements WriterFactory {
+
+    private static final InstanceIdentifier<SamplePlugin> ROOT_CONTAINER_ID = InstanceIdentifier.create(SamplePlugin.class);
+
+    /**
+     * Injected vxlan naming context shared with writer, provided by this plugin
+     */
+    @Inject
+    private NamingContext pgNamingContext;
+    /**
+     * Injected jvpp core APIs, provided by Honeycomb's infrastructure
+     */
+    @Inject
+    private FutureJVppCore jvppCore;
+
+    @Override
+    public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) {
+        // Unlike ReaderFactory, there's no need to add structural writers, just the writers that actually do something
+
+        // register writer for vxlan tunnel
+        registry.add(new GenericWriter<>(
+                // What part of subtree this writer handles is identified by an InstanceIdentifier
+                ROOT_CONTAINER_ID.child(PgStreams.class).child(PgStream.class),
+                // Customizer (the actual translation code to do the heavy lifting)
+                new PgWriteCustomizer(jvppCore, pgNamingContext)));
+    }
+}
diff --git a/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/src/main/java/io/fd/honeycomb/tutorial/write/PgWriteCustomizer.java b/vnfs/honeycomb_plugin/sample_plugin/sample-plugin-impl/src/main/java/io/fd/honeycomb/tutorial/write/PgWriteCustomizer.java
new file mode 100755 (executable)
index 0000000..7a146f6
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * 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.
+ */
+
+ /*
+ * Modifications copyright (c) 2017 AT&T Intellectual Property
+ */
+
+package io.fd.honeycomb.tutorial.write;
+
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.sample.plugin.params.pg.streams.PgStream;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.sample.plugin.rev160918.sample.plugin.params.pg.streams.PgStreamKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.jvpp.VppBaseCallException;
+import org.openvpp.jvpp.core.dto.PgEnableDisable;
+import org.openvpp.jvpp.core.dto.PgEnableDisableReply;
+import org.openvpp.jvpp.core.future.FutureJVppCore;
+
+import java.util.Arrays;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Writer for {@link VxlanTunnel} list node from our YANG model.
+ */
+public final class PgWriteCustomizer implements ListWriterCustomizer<PgStream, PgStreamKey> {
+
+
+    private static final Logger LOG = LoggerFactory.getLogger(PgWriteCustomizer.class);
+
+    /**
+     * JVpp APIs
+     */
+    private final FutureJVppCore jvppCore;
+    /**
+     * Shared vxlan tunnel naming context
+     */
+    private final NamingContext pgStreamNamingContext;
+
+    public PgWriteCustomizer(final FutureJVppCore jvppCore, final NamingContext pgStreamNamingContext) {
+        this.jvppCore = jvppCore;
+        this.pgStreamNamingContext = pgStreamNamingContext;
+    }
+
+    @Override
+    public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<PgStream> id,
+                                       @Nonnull final PgStream dataAfter,
+                                       @Nonnull final WriteContext writeContext) throws WriteFailedException {
+        // Create and set vxlan tunnel add request
+        final PgEnableDisable pgEnableDisable = new PgEnableDisable();
+        // 1 for add, 0 for delete
+        //look into this file: ~/vpp/build-root/build-vpp-native/vpp-api/java/jvpp-core/org/openvpp/jvpp/core/dto/PgEnableDisable.java
+        pgEnableDisable.isEnabled = 1;//public byte
+        String sName = dataAfter.getId();
+        //pgEnableDisable.streamName = sName.getBytes();//public byte[]
+        byte[] tempArray = sName.getBytes();
+        LOG.info("Going to copy array!!!");
+        String tempMsg = "";
+        pgEnableDisable.streamName = new byte[tempArray.length+1];
+        for(int i = 0; i < tempArray.length; i++){
+             tempMsg = "copying: i= "+i+" value: "+tempArray[i];
+             LOG.info(tempMsg);
+             pgEnableDisable.streamName[i] = tempArray[i];
+        }
+
+        //System.arraycopy( sName.getBytes(), 0, pgEnableDisable.streamName, 0, sName.length());
+        pgEnableDisable.streamNameLength = sName.length() + 1;//public int
+        String logMsg = "######***** Enabling: "+sName+" len: "+sName.length()+" getBytes:" + Arrays.toString(pgEnableDisable.streamName);
+        LOG.info(logMsg);
+        // dataAfter is the new vxlanTunnel configuration
+        //final boolean isIpv6 = dataAfter.getSrc().getIpv6Address() != null;
+        //vxlanAddDelTunnel.isIpv6 = TranslateUtils.booleanToByte(isIpv6);
+        //vxlanAddDelTunnel.srcAddress = TranslateUtils.ipAddressToArray(isIpv6, dataAfter.getSrc());
+        //vxlanAddDelTunnel.dstAddress = TranslateUtils.ipAddressToArray(isIpv6, dataAfter.getDst());
+        // There are other input parameters that are not exposed by our YANG model, default values will be used
+
+        try {
+            final PgEnableDisableReply replyForWrite = TranslateUtils
+                    .getReplyForWrite(jvppCore.pgEnableDisable(pgEnableDisable).toCompletableFuture(), id);
+
+            // VPP returns the index of new vxlan tunnel
+            //final int newVxlanTunnelIndex = replyForWrite.swIfIndex;
+            // It's important to store it in context so that reader knows to which name a vxlan tunnel is mapped
+            pgStreamNamingContext.addName(1, dataAfter.getId(), writeContext.getMappingContext());
+        } catch (VppBaseCallException e) {
+            throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
+        }
+    }
+
+    @Override
+    public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<PgStream> id,
+                                        @Nonnull final PgStream dataBefore,
+                                        @Nonnull final PgStream dataAfter, @Nonnull final WriteContext writeContext)
+            throws WriteFailedException {
+        // Not supported at VPP API level, throw exception
+        throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter,
+                new UnsupportedOperationException("Vxlan tunnel update is not supported by VPP"));
+    }
+
+    @Override
+    public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<PgStream> id,
+                                        @Nonnull final PgStream dataBefore,
+                                        @Nonnull final WriteContext writeContext) throws WriteFailedException {
+        // Create and set vxlan tunnel add request
+        //final VxlanAddDelTunnel vxlanAddDelTunnel = new VxlanAddDelTunnel();
+        final PgEnableDisable pgEnableDisable = new PgEnableDisable();
+        // 1 for add, 0 for delete
+        //vxlanAddDelTunnel.isAdd = 0;
+        pgEnableDisable.isEnabled = 0;//public byte
+
+        String sName = dataBefore.getId();
+        pgEnableDisable.streamName = sName.getBytes();//public byte[]
+        pgEnableDisable.streamNameLength = sName.length()+1;//public int
+
+        String logMsg1 = "***** Disabling: "+sName+" len: "+sName.length()+" getBytes:" + Arrays.toString(pgEnableDisable.streamName);
+        LOG.info(logMsg1);
+        // Vxlan tunnel is identified by its attributes when deleting, not index, so set all attributes
+        // dataBefore is the vxlan tunnel that's being deleted
+        //final boolean isIpv6 = dataBefore.getSrc().getIpv6Address() != null;
+        //vxlanAddDelTunnel.isIpv6 = TranslateUtils.booleanToByte(isIpv6);
+        //vxlanAddDelTunnel.srcAddress = TranslateUtils.ipAddressToArray(isIpv6, dataBefore.getSrc());
+        //vxlanAddDelTunnel.dstAddress = TranslateUtils.ipAddressToArray(isIpv6, dataBefore.getDst());
+        // There are other input parameters that are not exposed by our YANG model, default values will be used
+
+        try {
+           // final VxlanAddDelTunnelReply replyForWrite = TranslateUtils
+           //         .getReplyForWrite(jvppCore.vxlanAddDelTunnel(vxlanAddDelTunnel).toCompletableFuture(), id);
+          final PgEnableDisableReply replyForWrite = TranslateUtils
+                    .getReplyForWrite(jvppCore.pgEnableDisable(pgEnableDisable).toCompletableFuture(), id);
+           // It's important to remove the mapping from context
+           pgStreamNamingContext.removeName(dataBefore.getId(), writeContext.getMappingContext());
+        } catch (VppBaseCallException e) {
+            throw new WriteFailedException.DeleteFailedException(id, e);
+        }
+    }
+}
diff --git a/vnfs/honeycomb_plugin/sample_plugin/settings.xml b/vnfs/honeycomb_plugin/sample_plugin/settings.xml
new file mode 100644 (file)
index 0000000..28acd41
--- /dev/null
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=2 tabstop=2: -->
+<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
+  <profiles>
+    <profile>
+      <id>fd.io-release</id>
+      <repositories>
+        <repository>
+          <id>fd.io-mirror</id>
+          <name>fd.io-mirror</name>
+          <url>https://nexus.fd.io/content/groups/public/</url>
+          <releases>
+            <enabled>true</enabled>
+            <updatePolicy>never</updatePolicy>
+          </releases>
+          <snapshots>
+            <enabled>false</enabled>
+          </snapshots>
+        </repository>
+      </repositories>
+      <pluginRepositories>
+        <pluginRepository>
+          <id>fd.io-mirror</id>
+          <name>fd.io-mirror</name>
+          <url>https://nexus.fd.io/content/repositories/public/</url>
+          <releases>
+            <enabled>true</enabled>
+            <updatePolicy>never</updatePolicy>
+          </releases>
+          <snapshots>
+            <enabled>false</enabled>
+          </snapshots>
+        </pluginRepository>
+      </pluginRepositories>
+    </profile>
+    <profile>
+      <id>fd.io-snapshots</id>
+      <repositories>
+        <repository>
+          <id>fd.io-snapshot</id>
+          <name>fd.io-snapshot</name>
+          <url>https://nexus.fd.io/content/repositories/fd.io.snapshot/</url>
+          <releases>
+            <enabled>false</enabled>
+          </releases>
+          <snapshots>
+            <enabled>true</enabled>
+          </snapshots>
+        </repository>
+      </repositories>
+      <pluginRepositories>
+        <pluginRepository>
+          <id>fd.io-snapshot</id>
+          <name>fd.io-snapshot</name>
+          <url>https://nexus.fd.io/content/repositories/fd.io.snapshot/</url>
+          <releases>
+            <enabled>false</enabled>
+          </releases>
+          <snapshots>
+            <enabled>true</enabled>
+          </snapshots>
+        </pluginRepository>
+      </pluginRepositories>
+    </profile>
+    <profile>
+      <id>opendaylight-snapshots</id>
+      <repositories>
+        <repository>
+          <id>opendaylight-snapshot</id>
+          <name>opendaylight-snapshot</name>
+          <url>https://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/</url>
+          <releases>
+            <enabled>false</enabled>
+          </releases>
+          <snapshots>
+            <enabled>true</enabled>
+          </snapshots>
+        </repository>
+      </repositories>
+      <pluginRepositories>
+        <pluginRepository>
+          <id>opendaylight-shapshot</id>
+          <name>opendaylight-snapshot</name>
+          <url>https://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/</url>
+          <releases>
+            <enabled>false</enabled>
+          </releases>
+          <snapshots>
+            <enabled>true</enabled>
+          </snapshots>
+        </pluginRepository>
+      </pluginRepositories>
+    </profile>
+  </profiles>
+  <activeProfiles>
+    <activeProfile>fd.io-release</activeProfile>
+    <activeProfile>fd.io-snapshots</activeProfile>
+    <activeProfile>opendaylight-snapshots</activeProfile>
+  </activeProfiles>
+</settings>
\ No newline at end of file
diff --git a/vnfs/pom.xml b/vnfs/pom.xml
new file mode 100755 (executable)
index 0000000..6d85bc2
--- /dev/null
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ 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.
+--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+<!--  <parent>
+    <groupId>org.opendaylight.odlparent</groupId>
+    <artifactId>odlparent</artifactId>
+    <version>1.6.2-Beryllium-SR2</version>
+  </parent>
+-->
+  <groupId>org.openecomp.demo.vnf</groupId>
+  <artifactId>demo-aggregator</artifactId>
+  <version>1.0.0</version>
+  <name>demo-aggregator</name>
+  <packaging>pom</packaging>
+  <modelVersion>4.0.0</modelVersion>
+  <prerequisites>
+    <maven>3.1.1</maven>
+  </prerequisites>
+
+  <modules>
+  <module>honeycomb_plugin/sample_plugin</module>
+    <module>vFW/pg_streams</module>
+    <module>vLB/dns_streams</module>
+    <module>VES</module>
+    <module>VESreporting_vLB</module>
+    <module>VESreporting_vFW</module>
+  </modules>
+
+  <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-install-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+
+<distributionManagement>
+        <repository>
+            <id>nexus</id>
+            <name>OpenECOMP Release Repository</name>
+            <url>https://ecomp-nexus:8443/repository/raw</url>
+        </repository>
+    </distributionManagement>
+
+</project>
diff --git a/vnfs/settings.xml b/vnfs/settings.xml
new file mode 100644 (file)
index 0000000..4787fbc
--- /dev/null
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=2 tabstop=2: -->
+<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
+  <profiles>
+    <profile>
+      <id>fd.io-release</id>
+      <repositories>
+        <repository>
+          <id>fd.io-mirror</id>
+          <name>fd.io-mirror</name>
+          <url>https://nexus.fd.io/content/groups/public/</url>
+          <releases>
+            <enabled>true</enabled>
+            <updatePolicy>never</updatePolicy>
+          </releases>
+          <snapshots>
+            <enabled>false</enabled>
+          </snapshots>
+        </repository>
+      </repositories>
+      <pluginRepositories>
+        <pluginRepository>
+          <id>fd.io-mirror</id>
+          <name>fd.io-mirror</name>
+          <url>https://nexus.fd.io/content/repositories/public/</url>
+          <releases>
+            <enabled>true</enabled>
+            <updatePolicy>never</updatePolicy>
+          </releases>
+          <snapshots>
+            <enabled>false</enabled>
+          </snapshots>
+        </pluginRepository>
+      </pluginRepositories>
+    </profile>
+    <profile>
+      <id>fd.io-snapshots</id>
+      <repositories>
+        <repository>
+          <id>fd.io-snapshot</id>
+          <name>fd.io-snapshot</name>
+          <url>https://nexus.fd.io/content/repositories/fd.io.snapshot/</url>
+          <releases>
+            <enabled>false</enabled>
+          </releases>
+          <snapshots>
+            <enabled>true</enabled>
+          </snapshots>
+        </repository>
+      </repositories>
+      <pluginRepositories>
+        <pluginRepository>
+          <id>fd.io-snapshot</id>
+          <name>fd.io-snapshot</name>
+          <url>https://nexus.fd.io/content/repositories/fd.io.snapshot/</url>
+          <releases>
+            <enabled>false</enabled>
+          </releases>
+          <snapshots>
+            <enabled>true</enabled>
+          </snapshots>
+        </pluginRepository>
+      </pluginRepositories>
+    </profile>
+    <profile>
+      <id>opendaylight-snapshots</id>
+      <repositories>
+        <repository>
+          <id>opendaylight-snapshot</id>
+          <name>opendaylight-snapshot</name>
+          <url>https://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/</url>
+          <releases>
+            <enabled>false</enabled>
+          </releases>
+          <snapshots>
+            <enabled>true</enabled>
+          </snapshots>
+        </repository>
+      </repositories>
+      <pluginRepositories>
+        <pluginRepository>
+          <id>opendaylight-shapshot</id>
+          <name>opendaylight-snapshot</name>
+          <url>https://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/</url>
+          <releases>
+            <enabled>false</enabled>
+          </releases>
+          <snapshots>
+            <enabled>true</enabled>
+          </snapshots>
+        </pluginRepository>
+      </pluginRepositories>
+    </profile>
+  </profiles>
+  <activeProfiles>
+   <activeProfile>fd.io-release</activeProfile>
+    <activeProfile>fd.io-snapshots</activeProfile>
+    <activeProfile>opendaylight-snapshots</activeProfile>
+  </activeProfiles>
+
+<servers>
+  <server>
+      <id>nexus</id>
+      <username></username>
+      <password></password>
+    </server>
+  </servers>
+
+</settings>
diff --git a/vnfs/vFW/.DS_Store b/vnfs/vFW/.DS_Store
new file mode 100644 (file)
index 0000000..0a07575
Binary files /dev/null and b/vnfs/vFW/.DS_Store differ
diff --git a/vnfs/vFW/pg_streams/.DS_Store b/vnfs/vFW/pg_streams/.DS_Store
new file mode 100644 (file)
index 0000000..7e99a06
Binary files /dev/null and b/vnfs/vFW/pg_streams/.DS_Store differ
diff --git a/vnfs/vFW/pg_streams/dep.xml b/vnfs/vFW/pg_streams/dep.xml
new file mode 100644 (file)
index 0000000..5355773
--- /dev/null
@@ -0,0 +1,17 @@
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" 
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+  <id>demo</id>
+  <formats>
+    <format>tar.gz</format>
+  </formats>
+  <fileSets>
+    <fileSet>
+      <directory>.</directory>
+      <outputDirectory>/</outputDirectory>
+      <includes>
+        <include>stream*</include>
+      </includes>
+    </fileSet>
+  </fileSets>
+</assembly>
diff --git a/vnfs/vFW/pg_streams/pom.xml b/vnfs/vFW/pg_streams/pom.xml
new file mode 100644 (file)
index 0000000..41358e7
--- /dev/null
@@ -0,0 +1,56 @@
+<!--<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">-->
+<project>
+
+<parent>
+    <groupId>org.openecomp.demo.vnf</groupId>
+    <artifactId>demo-aggregator</artifactId>
+    <version>1.0.0</version>
+<relativePath>../../pom.xml</relativePath>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.openecomp.demo.vnf.vfw</groupId>
+  <artifactId>vfw_pg_streams</artifactId>
+ <!-- <name>vfw_pg_streams</name>-->
+  <version>1.0.0</version>
+  <build>
+    <plugins>
+
+       <plugin>
+        <artifactId>maven-jar-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>default-jar</id>
+            <phase>never</phase>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <version>2.5.3</version>
+        <configuration>
+          <descriptor>dep.xml</descriptor>
+        </configuration>
+        <executions>
+          <execution>
+            <id>create-archive</id>
+            <phase>package</phase>
+            <goals>
+              <goal>single</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+<plugin>
+  <groupId>org.apache.maven.plugins</groupId>
+  <artifactId>maven-deploy-plugin</artifactId>
+  <configuration>
+    <skip>false</skip>
+  </configuration>
+</plugin>
+
+    </plugins>
+  </build>
+
+</project>
diff --git a/vnfs/vFW/pg_streams/stream_fw_udp1 b/vnfs/vFW/pg_streams/stream_fw_udp1
new file mode 100644 (file)
index 0000000..2fa448c
--- /dev/null
@@ -0,0 +1,12 @@
+packet-generator new {
+  name fw_udp1
+  rate 10
+  node ip4-input
+  size 64-64
+  no-recycle
+  data {
+    UDP: 192.168.10.31 -> 192.168.20.32
+    UDP: 15320 -> 8080 
+    length 128 checksum 0 incrementing 1
+  }
+}
diff --git a/vnfs/vFW/pg_streams/stream_fw_udp10 b/vnfs/vFW/pg_streams/stream_fw_udp10
new file mode 100644 (file)
index 0000000..e24bd2b
--- /dev/null
@@ -0,0 +1,12 @@
+packet-generator new {
+  name fw_udp10
+  rate 10
+  node ip4-input
+  size 64-64
+  no-recycle
+  data {
+    UDP: 192.168.10.31 -> 192.168.20.32
+    UDP: 15320 -> 8080 
+    length 128 checksum 0 incrementing 1
+  }
+}
diff --git a/vnfs/vFW/pg_streams/stream_fw_udp2 b/vnfs/vFW/pg_streams/stream_fw_udp2
new file mode 100644 (file)
index 0000000..71f8538
--- /dev/null
@@ -0,0 +1,12 @@
+packet-generator new {
+  name fw_udp2
+  rate 10
+  node ip4-input
+  size 64-64
+  no-recycle
+  data {
+    UDP: 192.168.10.31 -> 192.168.20.32
+    UDP: 15320 -> 8080 
+    length 128 checksum 0 incrementing 1
+  }
+}
diff --git a/vnfs/vFW/pg_streams/stream_fw_udp3 b/vnfs/vFW/pg_streams/stream_fw_udp3
new file mode 100644 (file)
index 0000000..5142072
--- /dev/null
@@ -0,0 +1,12 @@
+packet-generator new {
+  name fw_udp3
+  rate 10
+  node ip4-input
+  size 64-64
+  no-recycle
+  data {
+    UDP: 192.168.10.31 -> 192.168.20.32
+    UDP: 15320 -> 8080 
+    length 128 checksum 0 incrementing 1
+  }
+}
diff --git a/vnfs/vFW/pg_streams/stream_fw_udp4 b/vnfs/vFW/pg_streams/stream_fw_udp4
new file mode 100644 (file)
index 0000000..ff78a9f
--- /dev/null
@@ -0,0 +1,12 @@
+packet-generator new {
+  name fw_udp4
+  rate 10
+  node ip4-input
+  size 64-64
+  no-recycle
+  data {
+    UDP: 192.168.10.31 -> 192.168.20.32
+    UDP: 15320 -> 8080 
+    length 128 checksum 0 incrementing 1
+  }
+}
diff --git a/vnfs/vFW/pg_streams/stream_fw_udp5 b/vnfs/vFW/pg_streams/stream_fw_udp5
new file mode 100644 (file)
index 0000000..823b291
--- /dev/null
@@ -0,0 +1,12 @@
+packet-generator new {
+  name fw_udp5
+  rate 10
+  node ip4-input
+  size 64-64
+  no-recycle
+  data {
+    UDP: 192.168.10.31 -> 192.168.20.32
+    UDP: 15320 -> 8080 
+    length 128 checksum 0 incrementing 1
+  }
+}
diff --git a/vnfs/vFW/pg_streams/stream_fw_udp6 b/vnfs/vFW/pg_streams/stream_fw_udp6
new file mode 100644 (file)
index 0000000..e5ad8a9
--- /dev/null
@@ -0,0 +1,12 @@
+packet-generator new {
+  name fw_udp6
+  rate 10
+  node ip4-input
+  size 64-64
+  no-recycle
+  data {
+    UDP: 192.168.10.31 -> 192.168.20.32
+    UDP: 15320 -> 8080 
+    length 128 checksum 0 incrementing 1
+  }
+}
diff --git a/vnfs/vFW/pg_streams/stream_fw_udp7 b/vnfs/vFW/pg_streams/stream_fw_udp7
new file mode 100644 (file)
index 0000000..11239e7
--- /dev/null
@@ -0,0 +1,12 @@
+packet-generator new {
+  name fw_udp7
+  rate 10
+  node ip4-input
+  size 64-64
+  no-recycle
+  data {
+    UDP: 192.168.10.31 -> 192.168.20.32
+    UDP: 15320 -> 8080 
+    length 128 checksum 0 incrementing 1
+  }
+}
diff --git a/vnfs/vFW/pg_streams/stream_fw_udp8 b/vnfs/vFW/pg_streams/stream_fw_udp8
new file mode 100644 (file)
index 0000000..5ce3284
--- /dev/null
@@ -0,0 +1,12 @@
+packet-generator new {
+  name fw_udp8
+  rate 10
+  node ip4-input
+  size 64-64
+  no-recycle
+  data {
+    UDP: 192.168.10.31 -> 192.168.20.32
+    UDP: 15320 -> 8080 
+    length 128 checksum 0 incrementing 1
+  }
+}
diff --git a/vnfs/vFW/pg_streams/stream_fw_udp9 b/vnfs/vFW/pg_streams/stream_fw_udp9
new file mode 100644 (file)
index 0000000..d72503c
--- /dev/null
@@ -0,0 +1,12 @@
+packet-generator new {
+  name fw_udp9
+  rate 10
+  node ip4-input
+  size 64-64
+  no-recycle
+  data {
+    UDP: 192.168.10.31 -> 192.168.20.32
+    UDP: 15320 -> 8080 
+    length 128 checksum 0 incrementing 1
+  }
+}
diff --git a/vnfs/vFW/scripts/.DS_Store b/vnfs/vFW/scripts/.DS_Store
new file mode 100644 (file)
index 0000000..e97f86f
Binary files /dev/null and b/vnfs/vFW/scripts/.DS_Store differ
diff --git a/vnfs/vFW/scripts/run_traffic_fw_demo.sh b/vnfs/vFW/scripts/run_traffic_fw_demo.sh
new file mode 100755 (executable)
index 0000000..b7a356e
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+curl -X PUT -H "Authorization: Basic YWRtaW46YWRtaW4=" -H "Content-Type: application/json" -H "Cache-Control: no-cache" -H "Postman-Token: 9005870c-900b-2e2e-0902-ef2009bb0ff7" -d '{"pg-streams":{"pg-stream": [{"id":"fw_udp1", "is-enabled":"true"},{"id":"fw_udp2", "is-enabled":"true"},{"id":"fw_udp3", "is-enabled":"true"},{"id":"fw_udp4", "is-enabled":"true"},{"id":"fw_udp5", "is-enabled":"true"}]}}' "http://localhost:8183/restconf/config/sample-plugin:sample-plugin/pg-streams"
+
+sleep 300
+
+while [ 1 ] 
+do
+curl -X PUT -H "Authorization: Basic YWRtaW46YWRtaW4=" -H "Content-Type: application/json" -H "Cache-Control: no-cache" -H "Postman-Token: 9005870c-900b-2e2e-0902-ef2009bb0ff7" -d '{"pg-streams":{"pg-stream": [{"id":"fw_udp1", "is-enabled":"true"},{"id":"fw_udp2", "is-enabled":"true"},{"id":"fw_udp3", "is-enabled":"true"},{"id":"fw_udp4", "is-enabled":"true"},{"id":"fw_udp5", "is-enabled":"true"},{"id":"fw_udp6", "is-enabled":"true"},{"id":"fw_udp7", "is-enabled":"true"},{"id":"fw_udp8", "is-enabled":"true"},{"id":"fw_udp9", "is-enabled":"true"},{"id":"fw_udp10", "is-enabled":"true"}]}}' "http://localhost:8183/restconf/config/sample-plugin:sample-plugin/pg-streams"
+sleep 300
+curl -X PUT -H "Authorization: Basic YWRtaW46YWRtaW4=" -H "Content-Type: application/json" -H "Cache-Control: no-cache" -H "Postman-Token: 9005870c-900b-2e2e-0902-ef2009bb0ff7" -d '{"pg-streams":{"pg-stream": [{"id":"fw_udp1", "is-enabled":"true"}]}}' "http://localhost:8183/restconf/config/sample-plugin:sample-plugin/pg-streams"
+sleep 300
+done
diff --git a/vnfs/vFW/scripts/v_firewall_init.sh b/vnfs/vFW/scripts/v_firewall_init.sh
new file mode 100644 (file)
index 0000000..fe16cef
--- /dev/null
@@ -0,0 +1,47 @@
+#!/bin/bash
+
+# Start VPP
+start vpp
+sleep 1
+
+# Configure VPP for vFirewall
+IPADDR1=$(ifconfig eth1 | grep "inet addr" | tr -s ' ' | cut -d' ' -f3 | cut -d':' -f2)
+IPADDR2=$(ifconfig eth2 | grep "inet addr" | tr -s ' ' | cut -d' ' -f3 | cut -d':' -f2)
+HWADDR1=$(ifconfig eth1 | grep HWaddr | tr -s ' ' | cut -d' ' -f5)
+HWADDR2=$(ifconfig eth2 | grep HWaddr | tr -s ' ' | cut -d' ' -f5)
+FAKE_HWADDR1=$(echo -n 00; dd bs=1 count=5 if=/dev/urandom 2>/dev/null | hexdump -v -e '/1 ":%02X"')
+FAKE_HWADDR2=$(echo -n 00; dd bs=1 count=5 if=/dev/urandom 2>/dev/null | hexdump -v -e '/1 ":%02X"')
+
+ifconfig eth1 down
+ifconfig eth2 down
+ifconfig eth1 hw ether $FAKE_HWADDR1
+ifconfig eth2 hw ether $FAKE_HWADDR2
+ip addr flush dev eth1
+ip addr flush dev eth2
+ifconfig eth1 up
+ifconfig eth2 up
+vppctl tap connect tap111 hwaddr $HWADDR1
+vppctl tap connect tap222 hwaddr $HWADDR2
+vppctl set int ip address tap-0 $IPADDR1"/24"
+vppctl set int ip address tap-1 $IPADDR2"/24"
+vppctl set int state tap-0 up
+vppctl set int state tap-1 up
+brctl addbr br0
+brctl addif br0 tap111
+brctl addif br0 eth1
+brctl addbr br1
+brctl addif br1 tap222
+brctl addif br1 eth2
+ifconfig br0 up
+ifconfig br1 up
+sleep 1
+
+# Start HoneyComb
+echo "" > /var/lib/honeycomb/persist/context/data.json
+echo "" > /var/lib/honeycomb/persist/config/data.json
+/opt/honeycomb/sample-distribution-1.0.0/honeycomb &>/dev/null &disown
+sleep 1
+
+# Start VES client
+cd /opt/VES/code/evel_training/VESreporting/
+./go-client.sh &>/dev/null &disown 
diff --git a/vnfs/vFW/scripts/v_packetgen_init.sh b/vnfs/vFW/scripts/v_packetgen_init.sh
new file mode 100644 (file)
index 0000000..6846966
--- /dev/null
@@ -0,0 +1,61 @@
+#!/bin/bash
+
+# Start VPP
+start vpp
+sleep 1
+
+# Configure VPP for vPacketGenerator
+IPADDR1=$(ifconfig eth1 | grep "inet addr" | tr -s ' ' | cut -d' ' -f3 | cut -d':' -f2)
+HWADDR1=$(ifconfig eth1 | grep HWaddr | tr -s ' ' | cut -d' ' -f5)
+FAKE_HWADDR1=$(echo -n 00; dd bs=1 count=5 if=/dev/urandom 2>/dev/null | hexdump -v -e '/1 ":%02X"')
+PROTECTED_NET_CIDR=$(cat /opt/config/protected_net_cidr.txt)
+FW_IPADDR=$(cat /opt/config/fw_ipaddr.txt)
+SINK_IPADDR=$(cat /opt/config/sink_ipaddr.txt)
+
+ifconfig eth1 down
+ifconfig eth1 hw ether $FAKE_HWADDR1
+ip addr flush dev eth1
+ifconfig eth1 up
+vppctl tap connect tap111 hwaddr $HWADDR1
+vppctl set int ip address tap-0 $IPADDR1"/24"
+vppctl set int state tap-0 up
+brctl addbr br0
+brctl addif br0 tap111
+brctl addif br0 eth1
+ifconfig br0 up
+vppctl ip route add $PROTECTED_NET_CIDR via $FW_IPADDR
+sleep 1
+
+# Install packet streams
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$SINK_IPADDR"/" /opt/pg_streams/stream_fw_udp1
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$SINK_IPADDR"/" /opt/pg_streams/stream_fw_udp2
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$SINK_IPADDR"/" /opt/pg_streams/stream_fw_udp3
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$SINK_IPADDR"/" /opt/pg_streams/stream_fw_udp4
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$SINK_IPADDR"/" /opt/pg_streams/stream_fw_udp5
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$SINK_IPADDR"/" /opt/pg_streams/stream_fw_udp6
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$SINK_IPADDR"/" /opt/pg_streams/stream_fw_udp7
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$SINK_IPADDR"/" /opt/pg_streams/stream_fw_udp8
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$SINK_IPADDR"/" /opt/pg_streams/stream_fw_udp9
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$SINK_IPADDR"/" /opt/pg_streams/stream_fw_udp10
+vppctl exec /opt/pg_streams/stream_fw_udp1
+vppctl exec /opt/pg_streams/stream_fw_udp2
+vppctl exec /opt/pg_streams/stream_fw_udp3
+vppctl exec /opt/pg_streams/stream_fw_udp4
+vppctl exec /opt/pg_streams/stream_fw_udp5
+vppctl exec /opt/pg_streams/stream_fw_udp6
+vppctl exec /opt/pg_streams/stream_fw_udp7
+vppctl exec /opt/pg_streams/stream_fw_udp8
+vppctl exec /opt/pg_streams/stream_fw_udp9
+vppctl exec /opt/pg_streams/stream_fw_udp10
+sleep 1
+
+# Start HoneyComb
+echo "" > /var/lib/honeycomb/persist/context/data.json
+echo "" > /var/lib/honeycomb/persist/config/data.json
+/opt/honeycomb/sample-distribution-1.0.0/honeycomb &>/dev/null &disown
+sleep 20
+
+# Enable traffic flows
+cd /opt
+chmod +x run_traffic_fw_demo.sh
+./run_traffic_fw_demo.sh &>/dev/null &disown
diff --git a/vnfs/vFW/scripts/v_sink_init.sh b/vnfs/vFW/scripts/v_sink_init.sh
new file mode 100644 (file)
index 0000000..16a6750
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+# Set the IP address of the protected network interface of the vFirewall as a default gateway to the unprotected network
+PROTECTED_NET_GW=$(cat /opt/config/protected_net_gw.txt)
+UNPROTECTED_NET=$(cat /opt/config/unprotected_net.txt)
+
+route add -net $UNPROTECTED_NET netmask 255.255.255.0 gw $PROTECTED_NET_GW
diff --git a/vnfs/vFW/scripts/vfirewall.sh b/vnfs/vFW/scripts/vfirewall.sh
new file mode 100644 (file)
index 0000000..0c57d73
--- /dev/null
@@ -0,0 +1,98 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides:
+# Required-Start:    $remote_fs $syslog
+# Required-Stop:     $remote_fs $syslog
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Start daemon at boot time
+# Description:       Enable service provided by daemon.
+### END INIT INFO
+
+dir="/opt"
+cmd="./v_firewall_init.sh"
+user="root"
+
+name=`basename $0`
+pid_file="/var/run/$name.pid"
+stdout_log="/var/log/$name.log"
+stderr_log="/var/log/$name.err"
+
+get_pid() {
+    cat "$pid_file"
+}
+
+is_running() {
+    [ -f "$pid_file" ] && ps `get_pid` > /dev/null 2>&1
+}
+
+case "$1" in
+    start)
+    if is_running; then
+        echo "Already started"
+    else
+        echo "Starting $name"
+        cd "$dir"
+        if [ -z "$user" ]; then
+            sudo $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        else
+            sudo -u "$user" $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        fi
+        echo $! > "$pid_file"
+        if ! is_running; then
+            echo "Unable to start, see $stdout_log and $stderr_log"
+            exit 1
+        fi
+    fi
+    ;;
+    stop)
+    if is_running; then
+        echo -n "Stopping $name.."
+        kill `get_pid`
+        for i in {1..10}
+        do
+            if ! is_running; then
+                break
+            fi
+
+            echo -n "."
+            sleep 1
+        done
+        echo
+
+        if is_running; then
+            echo "Not stopped; may still be shutting down or shutdown may have failed"
+            exit 1
+        else
+            echo "Stopped"
+            if [ -f "$pid_file" ]; then
+                rm "$pid_file"
+            fi
+        fi
+    else
+        echo "Not running"
+    fi
+    ;;
+    restart)
+    $0 stop
+    if is_running; then
+        echo "Unable to stop, will not attempt to start"
+        exit 1
+    fi
+    $0 start
+    ;;
+    status)
+    if is_running; then
+        echo "Running"
+    else
+        echo "Stopped"
+        exit 1
+    fi
+    ;;
+    *)
+    echo "Usage: $0 {start|stop|restart|status}"
+    exit 1
+    ;;
+esac
+
+exit 0
diff --git a/vnfs/vFW/scripts/vpacketgen.sh b/vnfs/vFW/scripts/vpacketgen.sh
new file mode 100644 (file)
index 0000000..bd1178a
--- /dev/null
@@ -0,0 +1,98 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides:
+# Required-Start:    $remote_fs $syslog
+# Required-Stop:     $remote_fs $syslog
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Start daemon at boot time
+# Description:       Enable service provided by daemon.
+### END INIT INFO
+
+dir="/opt"
+cmd="./v_packetgen_init.sh"
+user="root"
+
+name=`basename $0`
+pid_file="/var/run/$name.pid"
+stdout_log="/var/log/$name.log"
+stderr_log="/var/log/$name.err"
+
+get_pid() {
+    cat "$pid_file"
+}
+
+is_running() {
+    [ -f "$pid_file" ] && ps `get_pid` > /dev/null 2>&1
+}
+
+case "$1" in
+    start)
+    if is_running; then
+        echo "Already started"
+    else
+        echo "Starting $name"
+        cd "$dir"
+        if [ -z "$user" ]; then
+            sudo $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        else
+            sudo -u "$user" $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        fi
+        echo $! > "$pid_file"
+        if ! is_running; then
+            echo "Unable to start, see $stdout_log and $stderr_log"
+            exit 1
+        fi
+    fi
+    ;;
+    stop)
+    if is_running; then
+        echo -n "Stopping $name.."
+        kill `get_pid`
+        for i in {1..10}
+        do
+            if ! is_running; then
+                break
+            fi
+
+            echo -n "."
+            sleep 1
+        done
+        echo
+
+        if is_running; then
+            echo "Not stopped; may still be shutting down or shutdown may have failed"
+            exit 1
+        else
+            echo "Stopped"
+            if [ -f "$pid_file" ]; then
+                rm "$pid_file"
+            fi
+        fi
+    else
+        echo "Not running"
+    fi
+    ;;
+    restart)
+    $0 stop
+    if is_running; then
+        echo "Unable to stop, will not attempt to start"
+        exit 1
+    fi
+    $0 start
+    ;;
+    status)
+    if is_running; then
+        echo "Running"
+    else
+        echo "Stopped"
+        exit 1
+    fi
+    ;;
+    *)
+    echo "Usage: $0 {start|stop|restart|status}"
+    exit 1
+    ;;
+esac
+
+exit 0
diff --git a/vnfs/vFW/scripts/vsink.sh b/vnfs/vFW/scripts/vsink.sh
new file mode 100644 (file)
index 0000000..a6862b0
--- /dev/null
@@ -0,0 +1,98 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides:
+# Required-Start:    $remote_fs $syslog
+# Required-Stop:     $remote_fs $syslog
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Start daemon at boot time
+# Description:       Enable service provided by daemon.
+### END INIT INFO
+
+dir="/opt"
+cmd="./v_sink_init.sh"
+user="root"
+
+name=`basename $0`
+pid_file="/var/run/$name.pid"
+stdout_log="/var/log/$name.log"
+stderr_log="/var/log/$name.err"
+
+get_pid() {
+    cat "$pid_file"
+}
+
+is_running() {
+    [ -f "$pid_file" ] && ps `get_pid` > /dev/null 2>&1
+}
+
+case "$1" in
+    start)
+    if is_running; then
+        echo "Already started"
+    else
+        echo "Starting $name"
+        cd "$dir"
+        if [ -z "$user" ]; then
+            sudo $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        else
+            sudo -u "$user" $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        fi
+        echo $! > "$pid_file"
+        if ! is_running; then
+            echo "Unable to start, see $stdout_log and $stderr_log"
+            exit 1
+        fi
+    fi
+    ;;
+    stop)
+    if is_running; then
+        echo -n "Stopping $name.."
+        kill `get_pid`
+        for i in {1..10}
+        do
+            if ! is_running; then
+                break
+            fi
+
+            echo -n "."
+            sleep 1
+        done
+        echo
+
+        if is_running; then
+            echo "Not stopped; may still be shutting down or shutdown may have failed"
+            exit 1
+        else
+            echo "Stopped"
+            if [ -f "$pid_file" ]; then
+                rm "$pid_file"
+            fi
+        fi
+    else
+        echo "Not running"
+    fi
+    ;;
+    restart)
+    $0 stop
+    if is_running; then
+        echo "Unable to stop, will not attempt to start"
+        exit 1
+    fi
+    $0 start
+    ;;
+    status)
+    if is_running; then
+        echo "Running"
+    else
+        echo "Stopped"
+        exit 1
+    fi
+    ;;
+    *)
+    echo "Usage: $0 {start|stop|restart|status}"
+    exit 1
+    ;;
+esac
+
+exit 0
diff --git a/vnfs/vLB/.DS_Store b/vnfs/vLB/.DS_Store
new file mode 100644 (file)
index 0000000..5866cee
Binary files /dev/null and b/vnfs/vLB/.DS_Store differ
diff --git a/vnfs/vLB/DNSClient/.DS_Store b/vnfs/vLB/DNSClient/.DS_Store
new file mode 100644 (file)
index 0000000..210fb02
Binary files /dev/null and b/vnfs/vLB/DNSClient/.DS_Store differ
diff --git a/vnfs/vLB/DNSClient/LICENSE.TXT b/vnfs/vLB/DNSClient/LICENSE.TXT
new file mode 100644 (file)
index 0000000..ae12da2
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * ============LICENSE_START==========================================
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ===================================================================
+ * 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.
+ * ============LICENSE_END============================================
+ *
+ * ECOMP and OpenECOMP are trademarks 
+ * and service marks of AT&T Intellectual Property.
+ *
+ */
diff --git a/vnfs/vLB/DNSClient/README.txt b/vnfs/vLB/DNSClient/README.txt
new file mode 100644 (file)
index 0000000..ce192bb
--- /dev/null
@@ -0,0 +1,14 @@
+README
+---
+
+Run the dnsclient.sh script to start the FDClient Java binary. The DNSMembershipManager should be activated first. FDClient will periodically send keep-alive messages to the FDServer.
+- java FDClient [process id] [server IP address] [port] [timeout (sec)] [debug]
+  - [process id]: ID of this process
+  - [server IP address]: IP address of the remote server
+  - [port]: port where the server listens for incoming packets
+  - [timeout (sec)]: how often send a packet to the server
+  - [debug]: verbose mode (TRUE: >=1, FALSE: <=0)
+- Example: java FDClient p1 192.168.9.100 8888 10 1
+
+Please change the default parameters in the dnsclient.sh script as appropriate for your configuration.
+  
diff --git a/vnfs/vLB/DNSClient/pom.xml b/vnfs/vLB/DNSClient/pom.xml
new file mode 100644 (file)
index 0000000..cfb7db9
--- /dev/null
@@ -0,0 +1,51 @@
+<project>
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.openecomp.demo.vnf.lb</groupId>
+  <artifactId>dns-client</artifactId>
+  <name>DNS Client</name>
+  <packaging>jar</packaging>
+  <version>1.0.0</version>
+  
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <version>2.3.2</version>
+        <configuration>
+          <archive>
+            <manifest>
+              <mainClass>main.java.DNSServer</mainClass>
+            </manifest>
+          </archive>
+        </configuration>
+    </plugin>
+
+    <plugin>
+      <groupId>org.apache.maven.plugins</groupId>
+      <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>false</skip>
+        </configuration>
+    </plugin>
+
+    <plugin>
+      <groupId>org.apache.maven.plugins</groupId>
+      <artifactId>maven-install-plugin</artifactId>
+      <configuration>
+        <skip>false</skip>
+      </configuration>
+     </plugin>
+    </plugins>
+  </build>
+
+  <distributionManagement>
+      <repository>
+          <id>nexus</id>
+          <name>OpenECOMP Release Repository</name>
+          <url>https://ecomp-nexus:8443/repository/raw</url>
+      </repository>
+  </distributionManagement>
+
+</project>
diff --git a/vnfs/vLB/DNSClient/src/.DS_Store b/vnfs/vLB/DNSClient/src/.DS_Store
new file mode 100644 (file)
index 0000000..dba6f68
Binary files /dev/null and b/vnfs/vLB/DNSClient/src/.DS_Store differ
diff --git a/vnfs/vLB/DNSClient/src/main/.DS_Store b/vnfs/vLB/DNSClient/src/main/.DS_Store
new file mode 100644 (file)
index 0000000..9206bc7
Binary files /dev/null and b/vnfs/vLB/DNSClient/src/main/.DS_Store differ
diff --git a/vnfs/vLB/DNSClient/src/main/java/.DS_Store b/vnfs/vLB/DNSClient/src/main/java/.DS_Store
new file mode 100644 (file)
index 0000000..05c3547
Binary files /dev/null and b/vnfs/vLB/DNSClient/src/main/java/.DS_Store differ
diff --git a/vnfs/vLB/DNSClient/src/main/java/DNSServer.java b/vnfs/vLB/DNSClient/src/main/java/DNSServer.java
new file mode 100644 (file)
index 0000000..483819f
--- /dev/null
@@ -0,0 +1,85 @@
+
+/*************************************************************************//**
+ *
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+package main.java;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+
+/*
+ * Client-side Failure Detector (FD) implementation.
+ * @param server_addr: IP address of the remote server
+ * @param port: the port that the FD service listens for incoming UDP packets
+ * @param timeout: how often the FD checks the status of client processes
+ * @param debug: debug mode on/off
+ */
+
+public class DNSServer {
+
+       public static void main(String[] args) throws IOException {
+               if(args.length != 5) {
+                       System.out.println("Missing input parameters");
+                       System.out.println("Usage:");
+                       System.out.print("\t- java FDClient [process ID] [server IP address] [server port] [timeout (sec)] [debug]\n");
+                       System.exit(0);
+               }
+               // IP address and port of the remote server
+               String PID = args[0];
+               String SERVER_ADDR = args[1];
+               int PORT = Integer.parseInt(args[2]);
+               long TIMEOUT = Long.parseLong(args[3]) * 1000; // convert the FD timeout to milliseconds
+               int debug = Integer.parseInt(args[4]);
+               boolean DEBUG;
+               if(debug <= 0)
+                       DEBUG = false;
+               else
+                       DEBUG = true;
+               
+               // Run FD client
+               new FDClient(PID, SERVER_ADDR, PORT, TIMEOUT, DEBUG);
+               
+               // Listen for reply messages
+               @SuppressWarnings("resource")
+               DatagramSocket sock = new DatagramSocket(PORT);
+               byte[] buffer = new byte[256];
+               boolean gre_tunnel_enabled = false;
+               
+               while(true) {
+                       DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
+            sock.receive(packet);
+            String[] content = new String(packet.getData()).trim().split(":"); // Remove leading and trailing spaces
+            String msg_type = content[0];
+            String ip = content[1];
+            // Process only PING UDP packets
+            if(msg_type.equals("PONG")) {
+                               if(DEBUG) System.out.println("Reply message received from process " + ip);
+                               if(!gre_tunnel_enabled) {
+                                       // Set GRE tunnel towards load balancer
+                                       String script = new String("bash /opt/FDclient/set_gre_tunnel.sh " + ip);
+                           Runtime.getRuntime().exec(script);
+                                       if(DEBUG) System.out.println("GRE tunnel towards load balancer " + ip + " done");
+                                       gre_tunnel_enabled = true;
+                               }
+            }
+            else {
+               if(DEBUG) System.out.println("The received message is not a PONG. Received content: " + content);
+            }
+               }
+       }
+}
diff --git a/vnfs/vLB/DNSClient/src/main/java/FDClient.java b/vnfs/vLB/DNSClient/src/main/java/FDClient.java
new file mode 100644 (file)
index 0000000..8665937
--- /dev/null
@@ -0,0 +1,73 @@
+
+/*************************************************************************//**
+ *
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+package main.java;
+
+import java.io.*;
+import java.net.*;
+
+/*
+ * Client-side Failure Detector (FD) implementation.
+ * @param server_addr: IP address of the remote server
+ * @param port: the port that the FD service listens for incoming UDP packets
+ * @param timeout: how often the FD checks the status of client processes
+ * @param debug: debug mode on/off
+ */
+
+public class FDClient implements Runnable {
+       private String PID;
+       private String SERVER_ADDR;
+       private int PORT;
+       private long TIMEOUT;
+       private boolean DEBUG;
+       
+       public FDClient(String pid, String server_addr, int port, long timeout, boolean debug) throws IOException {
+               PID = pid;
+               SERVER_ADDR = server_addr;
+               PORT = port;
+               TIMEOUT = timeout;
+               DEBUG = debug;
+               (new Thread(this)).start();
+       }
+
+       @SuppressWarnings("resource")
+       @Override
+       public void run() {
+               // Define a DatagramSocket object to send packets to the server
+               try {
+                       DatagramSocket sock = new DatagramSocket();
+                       InetAddress IPAddress = InetAddress.getByName(SERVER_ADDR);
+
+                       // Allocate buffer for the PING message
+                       String content = "PING:" + PID;
+                       byte[] buffer = content.getBytes();
+               
+                       // Sent a PING message every TIMEOUT milliseconds
+                       while(true) {
+                               DatagramPacket packet = new DatagramPacket(buffer, buffer.length, IPAddress, PORT);
+                               sock.send(packet);
+
+                               if(DEBUG) System.out.println("Sent PING message to server " + SERVER_ADDR + ":" + PORT);
+                               try {
+                                       Thread.sleep(TIMEOUT);
+                               }
+                               catch(InterruptedException e) {}
+                       } 
+               } catch(IOException e) {}
+       }
+}
diff --git a/vnfs/vLB/DNSManager/.DS_Store b/vnfs/vLB/DNSManager/.DS_Store
new file mode 100644 (file)
index 0000000..cc896b0
Binary files /dev/null and b/vnfs/vLB/DNSManager/.DS_Store differ
diff --git a/vnfs/vLB/DNSManager/LICENSE.TXT b/vnfs/vLB/DNSManager/LICENSE.TXT
new file mode 100644 (file)
index 0000000..ae12da2
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * ============LICENSE_START==========================================
+ * ===================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ===================================================================
+ * 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.
+ * ============LICENSE_END============================================
+ *
+ * ECOMP and OpenECOMP are trademarks 
+ * and service marks of AT&T Intellectual Property.
+ *
+ */
diff --git a/vnfs/vLB/DNSManager/README.txt b/vnfs/vLB/DNSManager/README.txt
new file mode 100644 (file)
index 0000000..4c690dc
--- /dev/null
@@ -0,0 +1,17 @@
+README
+---
+
+Run the dnsmembership.sh script before activating DNS clients. dnsmembership.sh starts the DNSMembershipManager Java class, which uses the FDServer Java class to keep track of the remote DNS servers that are currently active. Example:
+
+./dnsmembership.sh
+
+The script will call the DNSMembershipManager binary with default parameters:
+- java DNSMembershipManager [port] [timeout (sec)] [threshold] [debug]
+  - [port]: port where the server listens for incoming packets
+  - [timeout (sec)]: how often update the status of remote processes (clients)
+  - [threshold]: how many missed packet are required to suspect a remote process to be dead
+  - [debug]: verbose mode (TRUE: >=1, FALSE: <=0) 
+- Example: java DNSMembershipManager 8888 10 3 1
+
+Please change the default parameters in the dnsmembership.sh script as appropriate for your configuration.
+  
diff --git a/vnfs/vLB/DNSManager/pom.xml b/vnfs/vLB/DNSManager/pom.xml
new file mode 100644 (file)
index 0000000..20287f0
--- /dev/null
@@ -0,0 +1,51 @@
+<project>
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.openecomp.demo.vnf.lb</groupId>
+  <artifactId>dns-manager</artifactId>
+  <name>DNS Manager</name>
+  <packaging>jar</packaging>
+  <version>1.0.0</version>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <version>2.3.2</version>
+        <configuration>
+          <archive>
+            <manifest>
+              <mainClass>main.java.DNSMembershipManager</mainClass>
+            </manifest>
+          </archive>
+        </configuration>
+    </plugin>
+
+    <plugin>
+      <groupId>org.apache.maven.plugins</groupId>
+      <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>false</skip>
+        </configuration>
+    </plugin>
+
+    <plugin>
+      <groupId>org.apache.maven.plugins</groupId>
+      <artifactId>maven-install-plugin</artifactId>
+      <configuration>
+        <skip>false</skip>
+      </configuration>
+     </plugin>
+    </plugins>
+  </build>
+
+  <distributionManagement>
+      <repository>
+          <id>nexus</id>
+          <name>OpenECOMP Release Repository</name>
+          <url>https://ecomp-nexus:8443/repository/raw</url>
+      </repository>
+  </distributionManagement>
+
+</project>
diff --git a/vnfs/vLB/DNSManager/src/.DS_Store b/vnfs/vLB/DNSManager/src/.DS_Store
new file mode 100644 (file)
index 0000000..201b6cf
Binary files /dev/null and b/vnfs/vLB/DNSManager/src/.DS_Store differ
diff --git a/vnfs/vLB/DNSManager/src/main/.DS_Store b/vnfs/vLB/DNSManager/src/main/.DS_Store
new file mode 100644 (file)
index 0000000..d0f5e85
Binary files /dev/null and b/vnfs/vLB/DNSManager/src/main/.DS_Store differ
diff --git a/vnfs/vLB/DNSManager/src/main/java/.DS_Store b/vnfs/vLB/DNSManager/src/main/java/.DS_Store
new file mode 100644 (file)
index 0000000..097132b
Binary files /dev/null and b/vnfs/vLB/DNSManager/src/main/java/.DS_Store differ
diff --git a/vnfs/vLB/DNSManager/src/main/java/DNSMembershipManager.java b/vnfs/vLB/DNSManager/src/main/java/DNSMembershipManager.java
new file mode 100644 (file)
index 0000000..a597f3e
--- /dev/null
@@ -0,0 +1,95 @@
+
+/*************************************************************************//**
+ *
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+package main.java;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+public class DNSMembershipManager {
+       /*
+        * Uses Failure Detector (FD) to keep track of the DNS servers currently active.
+        * @param port: the port that the FD service listens for incoming UDP packets
+        * @param timeout: how often the FD checks the status of client processes
+        * @param threshold: number of missing ping messages before declaring a client dead
+        * @param debug: debug mode on/off
+        */
+       
+       static Set<String> active = new HashSet<String>();
+       
+       @SuppressWarnings("static-access")
+       public static void main(String[] args) throws IOException, InterruptedException {
+               if(args.length != 5) {
+                       System.out.println("Missing input parameters");
+                       System.out.println("Usage:");
+                       System.out.print("\t- java FDServer [public IP address] [port] [timeout (sec)] [threshold] [debug]\n");
+                       System.exit(0);
+               }
+               
+               // Input parameters: PORT, TIMEOUT, THRESHOLD
+               String IPADDR = args[0];
+               int PORT = Integer.parseInt(args[1]);
+               long TIMEOUT = Long.parseLong(args[2]) * 1000; // convert the FD timeout to milliseconds
+               int THRESHOLD = Integer.parseInt(args[3]);
+               int debug = Integer.parseInt(args[4]);
+               boolean DEBUG;
+               if(debug <= 0)
+                       DEBUG = false;
+               else
+                       DEBUG = true;
+               
+               // Start Failure Detector
+               FDServer fd = new FDServer(IPADDR, PORT, TIMEOUT, THRESHOLD, DEBUG);
+               
+               // Check the status of client processes periodically. We use the same timeout value as FD
+               Set<String> active = new HashSet<String>();
+               while(true) {
+                       Set<String> alive_this_round = fd.getAliveProcesses();
+                       Iterator<String> iter = alive_this_round.iterator();
+                       String pid;
+                       
+                       // Check if there is some new DNS active
+                       while(iter.hasNext()) {
+                               pid = iter.next();
+                               if(!active.contains(pid)) {
+                                       active.add(pid);
+                                       // Add the new vDNS to the set of vDNS servers
+                                       String script = new String("bash /opt/FDserver/add_dns.sh " + pid);
+                           Runtime.getRuntime().exec(script);
+                                       if(DEBUG) System.out.println("Adding process " + pid + " to the list of DNSs");
+                               }
+                       }
+                       
+                       // Remove possible dead DNSs
+                       iter = active.iterator();
+                       while(iter.hasNext()) {
+                               pid = iter.next();
+                               if(!alive_this_round.contains(pid)) {
+                                       iter.remove(); // remove element from the iterator to avoid ConcurrentModificationException
+                                       // Remove the new vDNS from the set of vDNS servers
+                                       String script = new String("bash /opt/FDserver/remove_dns.sh " + pid);
+                           Runtime.getRuntime().exec(script);
+                                       if(DEBUG) System.out.println("Removing process " + pid + " from the list of DNSs");
+                               }
+                       }
+                       Thread.currentThread().sleep(TIMEOUT);
+               }
+       }
+}
diff --git a/vnfs/vLB/DNSManager/src/main/java/FDServer.java b/vnfs/vLB/DNSManager/src/main/java/FDServer.java
new file mode 100644 (file)
index 0000000..4b64c58
--- /dev/null
@@ -0,0 +1,161 @@
+
+/*************************************************************************//**
+ *
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+package main.java;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+
+/*
+ * Server-side Failure Detector (FD) implementation.
+ * @param port: the port that the FD service listens for incoming UDP packets
+ * @param timeout: how often the FD checks the status of client processes
+ * @param threshold: number of missing ping messages before declaring a client dead
+ * @param debug: debug mode on/off
+ */
+
+public class FDServer implements Runnable {
+       // Input parameters
+       private String IP_ADDR;
+       private int PORT;
+       private long TIMEOUT;
+       private int THRESHOLD;
+       private boolean DEBUG;
+       
+       // Data structures that store information about alive processes, processes alive/dead this round
+       private Map<String, Integer> alive = new ConcurrentHashMap<String, Integer>(); // Key: process IP address; Value: # consecutive missed pings
+       private Set<String> alive_this_round = ConcurrentHashMap.newKeySet(); // Needs to be synchronized because it is accessed by multiple threads
+       private Set<String> dead = new HashSet<String>();
+       
+       public FDServer(String ip_addr, int port, long timeout, int threshold, boolean debug) throws IOException {
+               IP_ADDR = ip_addr;
+               PORT = port;
+               TIMEOUT = timeout;
+               THRESHOLD = threshold;
+               DEBUG = debug;
+               (new Thread(this)).start();
+       }
+       
+       @Override
+       public void run() {
+               try {
+                       runFD();
+               } catch (IOException e) {
+                       e.printStackTrace();
+               }       
+       }
+       
+       private void runFD() throws IOException {
+               // Check the status of client processes periodically
+               TimerTask timer = new TimerTask() {
+                       public void run() {
+                               checkClientStatus();
+                       }
+               };
+               new Timer().scheduleAtFixedRate(timer, 0, TIMEOUT);
+               
+               // Define a DatagramSocket object for receiving incoming UDP packets
+               @SuppressWarnings("resource")
+               DatagramSocket sock = new DatagramSocket(PORT);
+               byte[] buffer = new byte[256];
+               
+               // Wait for incoming PING messages from remote clients
+               while(true) {
+                       DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
+            sock.receive(packet);
+            String[] content = new String(packet.getData()).trim().split(":"); // Remove leading and trailing spaces
+            String msg_type = content[0];
+            String pid = content[1];
+            // Process only PING UDP packets
+            if(msg_type.equals("PING")) {
+               String ip = packet.getAddress().getHostAddress();
+               alive_this_round.add(pid);
+                               if(DEBUG) System.out.println("Keep-alive message received from process " + pid + " (sender IP Address: " + ip +")");
+                               sendReplyMessage(packet.getAddress());
+            }
+            else {
+               if(DEBUG) System.out.println("The received message is not a PING. Received content: " + content);
+            }
+               }
+       }
+       
+       private void sendReplyMessage(InetAddress address) throws IOException {
+               DatagramSocket sock = new DatagramSocket();
+               // Allocate buffer for the PING message
+               String content = "PONG:" + IP_ADDR;
+               byte[] buffer = content.getBytes();
+               // Sent a PONG message
+               DatagramPacket packet = new DatagramPacket(buffer, buffer.length, address, PORT);
+               sock.send(packet);
+               sock.close();
+       }
+
+       // Update the list of processes that are alive
+       private void checkClientStatus() {
+               if(DEBUG) System.out.println("/================================/");
+               if(DEBUG) System.out.println("Update status of remote processes");
+               // Check if a process alive the previous round is still alive
+               // Otherwise increment its counter
+               Set<String> alive_processes = alive.keySet();
+               Iterator<String> iter = alive_processes.iterator();
+               while(iter.hasNext()) {
+                       String process = iter.next();
+                       if(!alive_this_round.contains(process)) {
+                               int counter = alive.get(process) + 1;
+                               alive.put(process, counter);
+                               if(DEBUG) System.out.println("Process " + process + " hasn't sent a message " + counter + " time(s) in a row");
+                               // If the number of consecutive missed ping messages reached the threshold, 
+                               // then assume the process to be dead
+                               if(counter == THRESHOLD) {
+                                       dead.add(process);
+                                       if(DEBUG) System.out.println("Process " + process + " is dead");
+                               }
+                       }
+               }
+               
+               // Processes alive this round
+               iter = alive_this_round.iterator();
+               while(iter.hasNext()) {
+                       String process = iter.next();
+                       alive.put(process, 0);
+                       if(DEBUG) System.out.println("Process " + process + " is alive this round");
+               }
+                       
+               
+               // Remove dead processes
+               iter = dead.iterator();
+               while(iter.hasNext()) {
+                       String process = iter.next();
+                       if(alive.containsKey(process))
+                               alive.remove(process);
+                       if(DEBUG) System.out.println("Process " + process + " is removed from the list of alive processes");
+               }
+               
+               // Cleanup
+               alive_this_round.clear();
+               dead.clear();
+               if(DEBUG) System.out.println();
+       }
+       
+       // Return the set of alive processes to up-stream applications
+       public Set<String> getAliveProcesses() {
+               return alive.keySet();
+       }
+}
diff --git a/vnfs/vLB/dns_streams/.DS_Store b/vnfs/vLB/dns_streams/.DS_Store
new file mode 100644 (file)
index 0000000..5008ddf
Binary files /dev/null and b/vnfs/vLB/dns_streams/.DS_Store differ
diff --git a/vnfs/vLB/dns_streams/dep.xml b/vnfs/vLB/dns_streams/dep.xml
new file mode 100644 (file)
index 0000000..5355773
--- /dev/null
@@ -0,0 +1,17 @@
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" 
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+  <id>demo</id>
+  <formats>
+    <format>tar.gz</format>
+  </formats>
+  <fileSets>
+    <fileSet>
+      <directory>.</directory>
+      <outputDirectory>/</outputDirectory>
+      <includes>
+        <include>stream*</include>
+      </includes>
+    </fileSet>
+  </fileSets>
+</assembly>
diff --git a/vnfs/vLB/dns_streams/pom.xml b/vnfs/vLB/dns_streams/pom.xml
new file mode 100644 (file)
index 0000000..a0f33ff
--- /dev/null
@@ -0,0 +1,58 @@
+<!--<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">-->
+<project>
+
+<parent>
+    <groupId>org.openecomp.demo.vnf</groupId>
+    <artifactId>demo-aggregator</artifactId>
+    <version>1.0.0</version>
+<relativePath>../../pom.xml</relativePath>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.openecomp.demo.vnf.vlb</groupId>
+  <artifactId>vlb_dns_streams</artifactId>
+ <!-- <name>vfw_pg_streams</name>-->
+  <version>1.0.0</version>
+  <build>
+    <plugins>
+
+       <plugin>
+        <artifactId>maven-jar-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>default-jar</id>
+            <phase>never</phase>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <version>2.5.3</version>
+        <configuration>
+          <descriptor>dep.xml</descriptor>
+        </configuration>
+        <executions>
+          <execution>
+            <id>create-archive</id>
+            <phase>package</phase>
+            <goals>
+              <goal>single</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+
+<plugin>
+  <groupId>org.apache.maven.plugins</groupId>
+  <artifactId>maven-deploy-plugin</artifactId>
+  <configuration>
+    <skip>false</skip>
+  </configuration>
+</plugin>
+
+
+    </plugins>
+  </build>
+
+</project>
diff --git a/vnfs/vLB/dns_streams/stream_dns1 b/vnfs/vLB/dns_streams/stream_dns1
new file mode 100644 (file)
index 0000000..ff9fdc5
--- /dev/null
@@ -0,0 +1,13 @@
+packet-generator new {
+  name dns1
+  rate 10
+  node ip4-input
+  size 100-100
+  no-recycle
+  data {
+    UDP: 104.130.226.226 -> 104.130.169.190
+    UDP: 15320 -> 53
+    length 53
+    hex 0x22c60100000100000000000005686f73743107646e7364656d6f096f70656e65636f6d70036f72670000010001
+  }
+}
diff --git a/vnfs/vLB/dns_streams/stream_dns10 b/vnfs/vLB/dns_streams/stream_dns10
new file mode 100644 (file)
index 0000000..9f28e20
--- /dev/null
@@ -0,0 +1,13 @@
+packet-generator new {
+  name dns10
+  rate 10
+  node ip4-input
+  size 100-100
+  no-recycle
+  data {
+    UDP: 104.130.226.226 -> 104.130.169.190
+    UDP: 15320 -> 53
+    length 54
+    hex 0x867b0100000100000000000006686f7374313007646e7364656d6f096f70656e65636f6d70036f72670000010001
+  }
+}
diff --git a/vnfs/vLB/dns_streams/stream_dns2 b/vnfs/vLB/dns_streams/stream_dns2
new file mode 100644 (file)
index 0000000..0b3d6c6
--- /dev/null
@@ -0,0 +1,13 @@
+packet-generator new {
+  name dns2
+  rate 10
+  node ip4-input
+  size 100-100
+  no-recycle
+  data {
+    UDP: 104.130.226.226 -> 104.130.169.190
+    UDP: 15320 -> 53
+    length 53
+    hex 0x23550100000100000000000005686f73743207646e7364656d6f096f70656e65636f6d70036f72670000010001
+  }
+}
diff --git a/vnfs/vLB/dns_streams/stream_dns3 b/vnfs/vLB/dns_streams/stream_dns3
new file mode 100644 (file)
index 0000000..531ba8e
--- /dev/null
@@ -0,0 +1,13 @@
+packet-generator new {
+  name dns3
+  rate 10
+  node ip4-input
+  size 100-100
+  no-recycle
+  data {
+    UDP: 104.130.226.226 -> 104.130.169.190
+    UDP: 15320 -> 53
+    length 53
+    hex 0x7b110100000100000000000005686f73743307646e7364656d6f096f70656e65636f6d70036f72670000010001
+  }
+}
diff --git a/vnfs/vLB/dns_streams/stream_dns4 b/vnfs/vLB/dns_streams/stream_dns4
new file mode 100644 (file)
index 0000000..2bfd4cb
--- /dev/null
@@ -0,0 +1,13 @@
+packet-generator new {
+  name dns4
+  rate 10
+  node ip4-input
+  size 100-100
+  no-recycle
+  data {
+    UDP: 104.130.226.226 -> 104.130.169.190
+    UDP: 15320 -> 53
+    length 53
+    hex 0x63910100000100000000000005686f73743407646e7364656d6f096f70656e65636f6d70036f72670000010001
+  }
+}
diff --git a/vnfs/vLB/dns_streams/stream_dns5 b/vnfs/vLB/dns_streams/stream_dns5
new file mode 100644 (file)
index 0000000..c853c57
--- /dev/null
@@ -0,0 +1,13 @@
+packet-generator new {
+  name dns5
+  rate 10
+  node ip4-input
+  size 100-100
+  no-recycle
+  data {
+    UDP: 104.130.226.226 -> 104.130.169.190
+    UDP: 15320 -> 53
+    length 53
+    hex 0x054e0100000100000000000005686f73743507646e7364656d6f096f70656e65636f6d70036f72670000010001
+  }
+}
diff --git a/vnfs/vLB/dns_streams/stream_dns6 b/vnfs/vLB/dns_streams/stream_dns6
new file mode 100644 (file)
index 0000000..dab5156
--- /dev/null
@@ -0,0 +1,13 @@
+packet-generator new {
+  name dns6
+  rate 10
+  node ip4-input
+  size 100-100
+  no-recycle
+  data {
+    UDP: 104.130.226.226 -> 104.130.169.190
+    UDP: 15320 -> 53
+    length 53
+    hex 0xb9d80100000100000000000005686f73743607646e7364656d6f096f70656e65636f6d70036f72670000010001
+  }
+}
diff --git a/vnfs/vLB/dns_streams/stream_dns7 b/vnfs/vLB/dns_streams/stream_dns7
new file mode 100644 (file)
index 0000000..1cca61e
--- /dev/null
@@ -0,0 +1,13 @@
+packet-generator new {
+  name dns7
+  rate 10
+  node ip4-input
+  size 100-100
+  no-recycle
+  data {
+    UDP: 104.130.226.226 -> 104.130.169.190
+    UDP: 15320 -> 53
+    length 53
+    hex 0x36f30100000100000000000005686f73743707646e7364656d6f096f70656e65636f6d70036f72670000010001
+  }
+}
diff --git a/vnfs/vLB/dns_streams/stream_dns8 b/vnfs/vLB/dns_streams/stream_dns8
new file mode 100644 (file)
index 0000000..ce76bca
--- /dev/null
@@ -0,0 +1,13 @@
+packet-generator new {
+  name dns8
+  rate 10
+  node ip4-input
+  size 100-100
+  no-recycle
+  data {
+    UDP: 104.130.226.226 -> 104.130.169.190
+    UDP: 15320 -> 53
+    length 53
+    hex 0x09860100000100000000000005686f73743807646e7364656d6f096f70656e65636f6d70036f72670000010001
+  }
+}
diff --git a/vnfs/vLB/dns_streams/stream_dns9 b/vnfs/vLB/dns_streams/stream_dns9
new file mode 100644 (file)
index 0000000..0cc3132
--- /dev/null
@@ -0,0 +1,13 @@
+packet-generator new {
+  name dns9
+  rate 10
+  node ip4-input
+  size 100-100
+  no-recycle
+  data {
+    UDP: 104.130.226.226 -> 104.130.169.190
+    UDP: 15320 -> 53
+    length 53
+    hex 0x12610100000100000000000005686f73743907646e7364656d6f096f70656e65636f6d70036f72670000010001
+  }
+}
diff --git a/vnfs/vLB/scripts/.DS_Store b/vnfs/vLB/scripts/.DS_Store
new file mode 100644 (file)
index 0000000..b7b2ad3
Binary files /dev/null and b/vnfs/vLB/scripts/.DS_Store differ
diff --git a/vnfs/vLB/scripts/add_dns.sh b/vnfs/vLB/scripts/add_dns.sh
new file mode 100644 (file)
index 0000000..04dfc77
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+if [ ! "$#" -eq 1 ]
+then
+  echo "Usage: ./add_dns.sh [remote DNS server]"
+  exit
+fi
+
+DNS_IPADDR=$1
+MY_PUBLIC_IP=$(cat /opt/config/local_public_ipaddr.txt)
+MY_PRIVATE_IP=$(cat /opt/config/local_private_ipaddr.txt)
+
+vppctl lb as $MY_PUBLIC_IP"/32" $DNS_IPADDR
+GRE=$(vppctl create gre tunnel src $MY_PRIVATE_IP dst $DNS_IPADDR)
+vppctl set int state $GRE up
+
+# Update the number of vDNSs currently active
+FD="/opt/VES/code/evel_training/VESreporting/active_dns.txt"
+CURR_DNS=$(cat $FD)
+let CURR_DNS=$CURR_DNS+1
+echo $CURR_DNS > $FD
diff --git a/vnfs/vLB/scripts/db_dnsdemo_openecomp_org b/vnfs/vLB/scripts/db_dnsdemo_openecomp_org
new file mode 100644 (file)
index 0000000..631614a
--- /dev/null
@@ -0,0 +1,24 @@
+;
+; BIND data file for local loopback interface
+;
+$TTL    604800
+@       IN      SOA     dnsdemo.openecomp.org. admin.dnsdemo.openecomp.org. (
+                              3         ; Serial
+                         604800         ; Refresh
+                          86400         ; Retry
+                        2419200         ; Expire
+                         604800 )       ; Negative Cache TTL
+; name servers - NS records
+    IN      NS      dnsdemo.openecomp.org.
+; name servers - A records
+dnsdemo.openecomp.org.                IN      A       10.0.100.100
+host1.dnsdemo.openecomp.org.          IN      A       10.0.100.101
+host2.dnsdemo.openecomp.org.          IN      A       10.0.100.102
+host3.dnsdemo.openecomp.org.          IN      A       10.0.100.103
+host4.dnsdemo.openecomp.org.          IN      A       10.0.100.104
+host5.dnsdemo.openecomp.org.          IN      A       10.0.100.105
+host6.dnsdemo.openecomp.org.          IN      A       10.0.100.106
+host7.dnsdemo.openecomp.org.          IN      A       10.0.100.107
+host8.dnsdemo.openecomp.org.          IN      A       10.0.100.108
+host9.dnsdemo.openecomp.org.          IN      A       10.0.100.109
+host10.dnsdemo.openecomp.org.         IN      A       10.0.100.110
diff --git a/vnfs/vLB/scripts/dnsclient.sh b/vnfs/vLB/scripts/dnsclient.sh
new file mode 100644 (file)
index 0000000..1de11ed
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+LB_OAM_INT=$(cat /opt/config/lb_oam_int.txt)
+PID=$(cat /opt/config/local_private_ipaddr.txt)
+
+java -jar dns-client-1.0.0.jar $PID $LB_OAM_INT 8888 10 0
diff --git a/vnfs/vLB/scripts/dnsmembership.sh b/vnfs/vLB/scripts/dnsmembership.sh
new file mode 100644 (file)
index 0000000..073216b
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+MY_PUBLIC_IP=$(cat /opt/config/local_public_ipaddr.txt)
+
+java -jar dns-manager-1.0.0.jar $MY_PUBLIC_IP 8888 10 3 0
diff --git a/vnfs/vLB/scripts/named.conf.local b/vnfs/vLB/scripts/named.conf.local
new file mode 100644 (file)
index 0000000..1b5c9f0
--- /dev/null
@@ -0,0 +1,12 @@
+//
+// Do any local configuration here
+//
+
+// Consider adding the 1918 zones here, if they are not used in your
+// organization
+//include "/etc/bind/zones.rfc1918";
+
+zone "dnsdemo.openecomp.org" {
+        type master;
+        file "/etc/bind/zones/db.dnsdemo.openecomp.org"; # zone file path
+};
diff --git a/vnfs/vLB/scripts/named.conf.options b/vnfs/vLB/scripts/named.conf.options
new file mode 100644 (file)
index 0000000..1daa65c
--- /dev/null
@@ -0,0 +1,39 @@
+acl "trusted" {
+        x.x.x.x;
+};
+options {
+        directory "/var/cache/bind";
+
+        recursion no;                  # enables recursive queries
+        allow-recursion { trusted; };  # allows recursive queries from "trusted” clients i.e. LB only
+        listen-on { x.x.x.x; };                # ns1 IP address - listen on this address only
+        allow-transfer { none; };      # disable zone transfers by default
+
+        forwarders {
+                8.8.8.8;
+                8.8.4.4;
+        };
+
+
+        // If there is a firewall between you and nameservers you want
+        // to talk to, you may need to fix the firewall to allow multiple
+        // ports to talk.  See http://www.kb.cert.org/vuls/id/800113
+
+        // If your ISP provided one or more IP addresses for stable
+        // nameservers, you probably want to use them as forwarders.
+        // Uncomment the following block, and insert the addresses replacing
+        // the all-0's placeholder.
+
+        // forwarders {
+        //      0.0.0.0;
+        // };
+
+        //========================================================================
+        // If BIND logs error messages about the root key being expired,
+        // you will need to update your keys.  See https://www.isc.org/bind-keys
+        //========================================================================
+        dnssec-validation auto;
+
+        auth-nxdomain no;              # conform to RFC1035
+        listen-on-v6 { any; };
+};
diff --git a/vnfs/vLB/scripts/remove_dns.sh b/vnfs/vLB/scripts/remove_dns.sh
new file mode 100644 (file)
index 0000000..1d505ab
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+if [ ! "$#" -eq 1 ]
+then
+  echo "Usage: ./add_dns.sh [remote DNS server]"
+  exit
+fi
+
+DNS_IPADDR=$1
+MY_PUBLIC_IP=$(cat /opt/config/local_public_ipaddr.txt)
+MY_PRIVATE_IP=$(cat /opt/config/local_private_ipaddr.txt)
+
+vppctl lb as $MY_PUBLIC_ID"/32" $DNS_IPADDR del
+vppctl create gre tunnel src $MY_PRIVATE_IP dst $DNS_IPADDR del
+
+# Update the number of vDNSs currently active
+FD="/opt/VES/code/evel_training/VESreporting/active_dns.txt"
+CURR_DNS=$(cat $FD)
+let CURR_DNS=$CURR_DNS-1
+if [[ $CURR_DNS -lt 0 ]]
+then 
+  CURR_DNS=0
+fi
+echo $CURR_DNS > $FD
diff --git a/vnfs/vLB/scripts/run_streams_dns.sh b/vnfs/vLB/scripts/run_streams_dns.sh
new file mode 100755 (executable)
index 0000000..4d4e543
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+vppctl packet-gen disable
+vppctl packet-gen enable-stream dns1
+vppctl packet-gen enable-stream dns2
+sleep 300
+vppctl packet-gen enable-stream dns3
+vppctl packet-gen enable-stream dns4
+vppctl packet-gen enable-stream dns5
diff --git a/vnfs/vLB/scripts/set_gre_tunnel.sh b/vnfs/vLB/scripts/set_gre_tunnel.sh
new file mode 100644 (file)
index 0000000..2fa6c64
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+if [ ! "$#" -eq 1 ]
+then
+  echo "Usage: ./set_gre_tunnel.sh [LB public IP address]"
+  exit
+fi
+
+LB_PUBLIC_IP=$1
+LB_PRIVATE_IP=$(cat /opt/config/lb_private_ipaddr.txt)
+MY_PRIVATE_IP=$(cat /opt/config/local_private_ipaddr.txt)
+
+sed -i "s/x.x.x.x/"$LB_PUBLIC_IP"/g" /etc/bind/named.conf.options
+
+ip tunnel add gre123 mode gre remote $LB_PRIVATE_IP local $MY_PRIVATE_IP ttl 255
+ip link set gre123 up
+ip addr add $LB_PUBLIC_IP"/24" dev gre123
+ifconfig eth0 down
+route add default dev gre123
+
+service bind9 restart
diff --git a/vnfs/vLB/scripts/v_dns_init.sh b/vnfs/vLB/scripts/v_dns_init.sh
new file mode 100755 (executable)
index 0000000..51ddba7
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+cd /opt/FDclient
+./dnsclient.sh &>/dev/null &disown
+cd ~
diff --git a/vnfs/vLB/scripts/v_lb_init.sh b/vnfs/vLB/scripts/v_lb_init.sh
new file mode 100755 (executable)
index 0000000..d130c1e
--- /dev/null
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+# Start VPP
+start vpp
+sleep 1
+
+# Configure VPP for vPacketGenerator
+IPADDR1=$(ifconfig eth0 | grep "inet addr" | tr -s ' ' | cut -d' ' -f3 | cut -d':' -f2)
+IPADDR2=$(ifconfig eth1 | grep "inet addr" | tr -s ' ' | cut -d' ' -f3 | cut -d':' -f2)
+HWADDR1=$(ifconfig eth0 | grep HWaddr | tr -s ' ' | cut -d' ' -f5)
+HWADDR2=$(ifconfig eth1 | grep HWaddr | tr -s ' ' | cut -d' ' -f5)
+FAKE_HWADDR1=$(echo -n 00; dd bs=1 count=5 if=/dev/urandom 2>/dev/null |hexdump -v -e '/1 ":%02X"')
+FAKE_HWADDR2=$(echo -n 00; dd bs=1 count=5 if=/dev/urandom 2>/dev/null |hexdump -v -e '/1 ":%02X"')
+GW=$(route | grep default | awk '{print $2}')
+
+ifconfig eth0 down
+ifconfig eth0 hw ether $FAKE_HWADDR1
+ip addr flush dev eth0
+ifconfig eth0 up
+vppctl tap connect tappub hwaddr $HWADDR1
+vppctl set int ip address tap-0 $IPADDR1"/24"
+vppctl set int state tap-0 up
+brctl addbr br0
+brctl addif br0 tappub
+brctl addif br0 eth0
+ifconfig br0 up
+
+ifconfig eth1 down
+ifconfig eth1 hw ether $FAKE_HWADDR2
+ip addr flush dev eth1
+ifconfig eth1 up
+vppctl tap connect tap111 hwaddr $HWADDR2
+vppctl set int ip address tap-1 $IPADDR2"/24"
+vppctl set int state tap-1 up
+brctl addbr br1
+brctl addif br1 tap111
+brctl addif br1 eth1
+ifconfig br1 up
+sleep 1
+
+vppctl lb conf ip4-src-address $IPADDR2
+vppctl lb vip $IPADDR1"/32" encap gre4
+vppctl ip route add 0.0.0.0/0 via $GW
+sleep 1
+
+cd /opt/FDserver
+./dnsmembership.sh &>/dev/null &disown
+
+# Start VES client
+cd /opt/VES/code/evel_training/VESreporting/
+echo 0 > active_dns.txt
+./go-client.sh &>/dev/null &disown
diff --git a/vnfs/vLB/scripts/v_packetgen_for_dns_demo_init.sh b/vnfs/vLB/scripts/v_packetgen_for_dns_demo_init.sh
new file mode 100644 (file)
index 0000000..ba7f56c
--- /dev/null
@@ -0,0 +1,97 @@
+#!/bin/bash
+
+# Start VPP
+start vpp
+sleep 1
+
+# Configure VPP for vPacketGenerator
+IPADDR1=$(ifconfig eth0 | grep "inet addr" | tr -s ' ' | cut -d' ' -f3 | cut -d':' -f2)
+HWADDR1=$(ifconfig eth0 | grep HWaddr | tr -s ' ' | cut -d' ' -f5)
+FAKE_HWADDR1=$(echo -n 00; dd bs=1 count=5 if=/dev/urandom 2>/dev/null | hexdump -v -e '/1 ":%02X"')
+VLB_IPADDR=$(cat /opt/config/vlb_ipaddr.txt)
+GW=$(route | grep default | awk '{print $2}')
+
+ifconfig eth0 down
+ifconfig eth0 hw ether $FAKE_HWADDR1
+ip addr flush dev eth0
+ifconfig eth0 up
+vppctl tap connect tap111 hwaddr $HWADDR1
+vppctl set int ip address tap-0 $IPADDR1"/24"
+vppctl set int state tap-0 up
+brctl addbr br0
+brctl addif br0 tap111
+brctl addif br0 eth0
+ifconfig br0 up
+vppctl ip route add 0.0.0.0/0 via $GW
+sleep 1
+
+
+#Let's set br0 with public IP and valid MAC so that Linux will have public network access
+ifconfig br0 hw ether $HWADDR1
+ifconfig br0 $IPADDR1 netmask 255.255.255.0
+route add default gw $GW
+
+#Adding static arp entry for VPP so that it will be able to send packets to default GW
+ping -c 1 $VLB_IPADDR &>/dev/null &disown
+sleep 3
+
+GW_MAC=$(arp -n | grep -w $GW | tr -s ' ' | cut -d' ' -f3)
+VLB_MAC=$(arp -n | grep -w $VLB_IPADDR | tr -s ' ' | cut -d' ' -f3)
+
+#if VLB in our network, we will use its mac
+if [ ! -z "$VLB_MAC" ]; then
+vppctl set ip arp tap-0 $VLB_IPADDR $VLB_MAC
+fi
+
+# in any case let's add arp entry for default gw
+vppctl set ip arp tap-0 $GW $GW_MAC
+
+
+# Install packet streams
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$VLB_IPADDR"/" /opt/dns_streams/stream_dns1
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$VLB_IPADDR"/" /opt/dns_streams/stream_dns2
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$VLB_IPADDR"/" /opt/dns_streams/stream_dns3
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$VLB_IPADDR"/" /opt/dns_streams/stream_dns4
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$VLB_IPADDR"/" /opt/dns_streams/stream_dns5
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$VLB_IPADDR"/" /opt/dns_streams/stream_dns6
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$VLB_IPADDR"/" /opt/dns_streams/stream_dns7
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$VLB_IPADDR"/" /opt/dns_streams/stream_dns8
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$VLB_IPADDR"/" /opt/dns_streams/stream_dns9
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$VLB_IPADDR"/" /opt/dns_streams/stream_dns10
+
+#sed -i -e "s/.*-> 53.*/    UDP: $RANDOM -> 53/" /opt/dns_streams/stream_dns*
+
+sed -i -e "s/.*-> 53.*/    UDP: $RANDOM -> 53/" /opt/dns_streams/stream_dns1
+sed -i -e "s/.*-> 53.*/    UDP: $RANDOM -> 53/" /opt/dns_streams/stream_dns2
+sed -i -e "s/.*-> 53.*/    UDP: $RANDOM -> 53/" /opt/dns_streams/stream_dns3
+sed -i -e "s/.*-> 53.*/    UDP: $RANDOM -> 53/" /opt/dns_streams/stream_dns4
+sed -i -e "s/.*-> 53.*/    UDP: $RANDOM -> 53/" /opt/dns_streams/stream_dns5
+sed -i -e "s/.*-> 53.*/    UDP: $RANDOM -> 53/" /opt/dns_streams/stream_dns6
+sed -i -e "s/.*-> 53.*/    UDP: $RANDOM -> 53/" /opt/dns_streams/stream_dns7
+sed -i -e "s/.*-> 53.*/    UDP: $RANDOM -> 53/" /opt/dns_streams/stream_dns8
+sed -i -e "s/.*-> 53.*/    UDP: $RANDOM -> 53/" /opt/dns_streams/stream_dns9
+sed -i -e "s/.*-> 53.*/    UDP: $RANDOM -> 53/" /opt/dns_streams/stream_dns10
+
+vppctl exec /opt/dns_streams/stream_dns1
+vppctl exec /opt/dns_streams/stream_dns2
+vppctl exec /opt/dns_streams/stream_dns3
+vppctl exec /opt/dns_streams/stream_dns4
+vppctl exec /opt/dns_streams/stream_dns5
+vppctl exec /opt/dns_streams/stream_dns6
+vppctl exec /opt/dns_streams/stream_dns7
+vppctl exec /opt/dns_streams/stream_dns8
+vppctl exec /opt/dns_streams/stream_dns9
+vppctl exec /opt/dns_streams/stream_dns10
+sleep 1
+
+# Start HoneyComb
+echo "" > /var/lib/honeycomb/persist/context/data.json
+echo "" > /var/lib/honeycomb/persist/config/data.json
+/opt/honeycomb/sample-distribution-1.0.0/honeycomb &>/dev/null &disown
+sleep 20
+
+# Enable traffic flows
+cd /opt
+chmod +x run_streams_dns.sh
+#./run_streams_dns.sh &>/dev/null &disown
+
diff --git a/vnfs/vLB/scripts/vdns.sh b/vnfs/vLB/scripts/vdns.sh
new file mode 100644 (file)
index 0000000..e3f6f11
--- /dev/null
@@ -0,0 +1,98 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides:
+# Required-Start:    $remote_fs $syslog
+# Required-Stop:     $remote_fs $syslog
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Start daemon at boot time
+# Description:       Enable service provided by daemon.
+### END INIT INFO
+
+dir="/opt"
+cmd="./v_dns_init.sh"
+user="root"
+
+name=`basename $0`
+pid_file="/var/run/$name.pid"
+stdout_log="/var/log/$name.log"
+stderr_log="/var/log/$name.err"
+
+get_pid() {
+    cat "$pid_file"
+}
+
+is_running() {
+    [ -f "$pid_file" ] && ps `get_pid` > /dev/null 2>&1
+}
+
+case "$1" in
+    start)
+    if is_running; then
+        echo "Already started"
+    else
+        echo "Starting $name"
+        cd "$dir"
+        if [ -z "$user" ]; then
+            sudo $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        else
+            sudo -u "$user" $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        fi
+        echo $! > "$pid_file"
+        if ! is_running; then
+            echo "Unable to start, see $stdout_log and $stderr_log"
+            exit 1
+        fi
+    fi
+    ;;
+    stop)
+    if is_running; then
+        echo -n "Stopping $name.."
+        kill `get_pid`
+        for i in {1..10}
+        do
+            if ! is_running; then
+                break
+            fi
+
+            echo -n "."
+            sleep 1
+        done
+        echo
+
+        if is_running; then
+            echo "Not stopped; may still be shutting down or shutdown may have failed"
+            exit 1
+        else
+            echo "Stopped"
+            if [ -f "$pid_file" ]; then
+                rm "$pid_file"
+            fi
+        fi
+    else
+        echo "Not running"
+    fi
+    ;;
+    restart)
+    $0 stop
+    if is_running; then
+        echo "Unable to stop, will not attempt to start"
+        exit 1
+    fi
+    $0 start
+    ;;
+    status)
+    if is_running; then
+        echo "Running"
+    else
+        echo "Stopped"
+        exit 1
+    fi
+    ;;
+    *)
+    echo "Usage: $0 {start|stop|restart|status}"
+    exit 1
+    ;;
+esac
+
+exit 0
diff --git a/vnfs/vLB/scripts/vdnspacketgen_change_streams_ports.sh b/vnfs/vLB/scripts/vdnspacketgen_change_streams_ports.sh
new file mode 100644 (file)
index 0000000..9bd7716
--- /dev/null
@@ -0,0 +1,53 @@
+#!/bin/bash
+
+#Disable all streams via Honeycomb (so that it will in consistent state)
+curl -X PUT -H "Authorization: Basic YWRtaW46YWRtaW4=" -H "Content-Type: application/json" -H "Cache-Control: no-cache" -d '{"pg-streams":{"pg-stream": []}}' "http://localhost:8183/restconf/config/sample-plugin:sample-plugin/pg-streams"
+
+vppctl pac del dns1
+vppctl pac del dns2
+vppctl pac del dns3
+vppctl pac del dns4
+vppctl pac del dns5
+vppctl pac del dns6
+vppctl pac del dns7
+vppctl pac del dns8
+vppctl pac del dns9
+vppctl pac del dns10
+
+
+#Update destination (vLB) IP
+VLB_IPADDR=$(cat /opt/config/vlb_ipaddr.txt)
+IPADDR1=$(ifconfig br0 | grep "inet addr" | tr -s ' ' | cut -d' ' -f3 | cut -d':' -f2)
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$VLB_IPADDR"/" /opt/dns_streams/stream_dns1
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$VLB_IPADDR"/" /opt/dns_streams/stream_dns2
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$VLB_IPADDR"/" /opt/dns_streams/stream_dns3
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$VLB_IPADDR"/" /opt/dns_streams/stream_dns4
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$VLB_IPADDR"/" /opt/dns_streams/stream_dns5
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$VLB_IPADDR"/" /opt/dns_streams/stream_dns6
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$VLB_IPADDR"/" /opt/dns_streams/stream_dns7
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$VLB_IPADDR"/" /opt/dns_streams/stream_dns8
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$VLB_IPADDR"/" /opt/dns_streams/stream_dns9
+sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$VLB_IPADDR"/" /opt/dns_streams/stream_dns10
+
+#Update source ports (make them random)
+sed -i -e "s/.*-> 53.*/    UDP: $RANDOM -> 53/" /opt/dns_streams/stream_dns1
+sed -i -e "s/.*-> 53.*/    UDP: $RANDOM -> 53/" /opt/dns_streams/stream_dns2
+sed -i -e "s/.*-> 53.*/    UDP: $RANDOM -> 53/" /opt/dns_streams/stream_dns3
+sed -i -e "s/.*-> 53.*/    UDP: $RANDOM -> 53/" /opt/dns_streams/stream_dns4
+sed -i -e "s/.*-> 53.*/    UDP: $RANDOM -> 53/" /opt/dns_streams/stream_dns5
+sed -i -e "s/.*-> 53.*/    UDP: $RANDOM -> 53/" /opt/dns_streams/stream_dns6
+sed -i -e "s/.*-> 53.*/    UDP: $RANDOM -> 53/" /opt/dns_streams/stream_dns7
+sed -i -e "s/.*-> 53.*/    UDP: $RANDOM -> 53/" /opt/dns_streams/stream_dns8
+sed -i -e "s/.*-> 53.*/    UDP: $RANDOM -> 53/" /opt/dns_streams/stream_dns9
+sed -i -e "s/.*-> 53.*/    UDP: $RANDOM -> 53/" /opt/dns_streams/stream_dns10
+
+vppctl exec /opt/dns_streams/stream_dns1
+vppctl exec /opt/dns_streams/stream_dns2
+vppctl exec /opt/dns_streams/stream_dns3
+vppctl exec /opt/dns_streams/stream_dns4
+vppctl exec /opt/dns_streams/stream_dns5
+vppctl exec /opt/dns_streams/stream_dns6
+vppctl exec /opt/dns_streams/stream_dns7
+vppctl exec /opt/dns_streams/stream_dns8
+vppctl exec /opt/dns_streams/stream_dns9
+vppctl exec /opt/dns_streams/stream_dns10
\ No newline at end of file
diff --git a/vnfs/vLB/scripts/vlb.sh b/vnfs/vLB/scripts/vlb.sh
new file mode 100644 (file)
index 0000000..5ab6c40
--- /dev/null
@@ -0,0 +1,98 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides:
+# Required-Start:    $remote_fs $syslog
+# Required-Stop:     $remote_fs $syslog
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Start daemon at boot time
+# Description:       Enable service provided by daemon.
+### END INIT INFO
+
+dir="/opt"
+cmd="./v_lb_init.sh"
+user="root"
+
+name=`basename $0`
+pid_file="/var/run/$name.pid"
+stdout_log="/var/log/$name.log"
+stderr_log="/var/log/$name.err"
+
+get_pid() {
+    cat "$pid_file"
+}
+
+is_running() {
+    [ -f "$pid_file" ] && ps `get_pid` > /dev/null 2>&1
+}
+
+case "$1" in
+    start)
+    if is_running; then
+        echo "Already started"
+    else
+        echo "Starting $name"
+        cd "$dir"
+        if [ -z "$user" ]; then
+            sudo $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        else
+            sudo -u "$user" $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        fi
+        echo $! > "$pid_file"
+        if ! is_running; then
+            echo "Unable to start, see $stdout_log and $stderr_log"
+            exit 1
+        fi
+    fi
+    ;;
+    stop)
+    if is_running; then
+        echo -n "Stopping $name.."
+        kill `get_pid`
+        for i in {1..10}
+        do
+            if ! is_running; then
+                break
+            fi
+
+            echo -n "."
+            sleep 1
+        done
+        echo
+
+        if is_running; then
+            echo "Not stopped; may still be shutting down or shutdown may have failed"
+            exit 1
+        else
+            echo "Stopped"
+            if [ -f "$pid_file" ]; then
+                rm "$pid_file"
+            fi
+        fi
+    else
+        echo "Not running"
+    fi
+    ;;
+    restart)
+    $0 stop
+    if is_running; then
+        echo "Unable to stop, will not attempt to start"
+        exit 1
+    fi
+    $0 start
+    ;;
+    status)
+    if is_running; then
+        echo "Running"
+    else
+        echo "Stopped"
+        exit 1
+    fi
+    ;;
+    *)
+    echo "Usage: $0 {start|stop|restart|status}"
+    exit 1
+    ;;
+esac
+
+exit 0
diff --git a/vnfs/vLB/scripts/vpacketgenfordnsdemo.sh b/vnfs/vLB/scripts/vpacketgenfordnsdemo.sh
new file mode 100644 (file)
index 0000000..427e533
--- /dev/null
@@ -0,0 +1,99 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides:
+# Required-Start:    $remote_fs $syslog
+# Required-Stop:     $remote_fs $syslog
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Start daemon at boot time
+# Description:       Enable service provided by daemon.
+### END INIT INFO
+
+dir="/opt"
+cmd="./v_packetgen_for_dns_demo_init.sh"
+user="root"
+
+name=`basename $0`
+pid_file="/var/run/$name.pid"
+stdout_log="/var/log/$name.log"
+stderr_log="/var/log/$name.err"
+
+get_pid() {
+    cat "$pid_file"
+}
+
+is_running() {
+    [ -f "$pid_file" ] && ps `get_pid` > /dev/null 2>&1
+}
+
+case "$1" in
+    start)
+    if is_running; then
+        echo "Already started"
+    else
+        echo "Starting $name"
+        cd "$dir"
+        if [ -z "$user" ]; then
+            sudo $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        else
+            sudo -u "$user" $cmd >> "$stdout_log" 2>> "$stderr_log" &
+        fi
+        echo $! > "$pid_file"
+        if ! is_running; then
+            echo "Unable to start, see $stdout_log and $stderr_log"
+            exit 1
+        fi
+    fi
+    ;;
+    stop)
+    if is_running; then
+        echo -n "Stopping $name.."
+        kill `get_pid`
+        for i in {1..10}
+        do
+            if ! is_running; then
+                break
+            fi
+
+            echo -n "."
+            sleep 1
+        done
+        echo
+
+        if is_running; then
+            echo "Not stopped; may still be shutting down or shutdown may have failed"
+            exit 1
+        else
+            echo "Stopped"
+            if [ -f "$pid_file" ]; then
+                rm "$pid_file"
+            fi
+        fi
+    else
+        echo "Not running"
+    fi
+    ;;
+    restart)
+    $0 stop
+    if is_running; then
+        echo "Unable to stop, will not attempt to start"
+        exit 1
+    fi
+    $0 start
+    ;;
+    status)
+    if is_running; then
+        echo "Running"
+    else
+        echo "Stopped"
+        exit 1
+    fi
+    ;;
+    *)
+    echo "Usage: $0 {start|stop|restart|status}"
+    exit 1
+    ;;
+esac
+
+exit 0
+