diff options
144 files changed, 26531 insertions, 2292 deletions
diff --git a/boot/aai2_vm_init.sh b/boot/aai2_vm_init.sh deleted file mode 100644 index ffe0955f..00000000 --- a/boot/aai2_vm_init.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -AAI_INSTANCE=$(cat /opt/config/aai_instance.txt) - -cd /opt/test-config -git pull - -if [[ $AAI_INSTANCE == "aai_instance_1" ]] -then - ./deploy_vm1.sh -elif [[ $AAI_INSTANCE == "aai_instance_2" ]] -then - ./deploy_vm2.sh -else - echo "Invalid instance. Exiting..." -fi diff --git a/boot/aai_install.sh b/boot/aai_install.sh index d4a04ed4..9ee49d7f 100644 --- a/boot/aai_install.sh +++ b/boot/aai_install.sh @@ -5,7 +5,10 @@ NEXUS_REPO=$(cat /opt/config/nexus_repo.txt) ARTIFACTS_VERSION=$(cat /opt/config/artifacts_version.txt) DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt) CLOUD_ENV=$(cat /opt/config/cloud_env.txt) +GERRIT_BRANCH=$(cat /opt/config/gerrit_branch.txt) +AAI_INSTANCE=$(cat /opt/config/aai_instance.txt) MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1) +CODE_REPO=$(cat /opt/config/remote_repo.txt) # Add host name to /etc/host to avoid warnings in openstack images if [[ $CLOUD_ENV != "rackspace" ]] @@ -46,9 +49,10 @@ then fi # Download dependencies -add-apt-repository -y ppa:openjdk-r/ppa +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list apt-get update -apt-get install -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make +apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make # Download scripts from Nexus curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/aai_vm_init.sh -o /opt/aai_vm_init.sh @@ -89,7 +93,20 @@ echo "nameserver "$DNS_IP_ADDR >> /etc/resolvconf/resolv.conf.d/head resolvconf -u # Run docker containers -mkdir -p /opt/openecomp/aai/logs -mkdir -p /opt/openecomp/aai/data cd /opt +git clone -b $GERRIT_BRANCH --single-branch $CODE_REPO + +if [[ $AAI_INSTANCE == "aai_instance_1" ]] +then + mkdir -p /opt/aai/logroot/AAI-RESOURCES + mkdir -p /opt/aai/logroot/AAI-TRAVERSAL + mkdir -p /opt/aai/logroot/AAI-ML + mkdir -p /opt/aai/logroot/AAI-SDB + mkdir -p /opt/aai/logroot/AAI-DRMS + mkdir -p /opt/aai/logroot/AAI-UI + chown -R 999:999 /opt/aai/logroot/AAI-RESOURCES /opt/aai/logroot/AAI-TRAVERSAL + + sleep 300 +fi + ./aai_vm_init.sh
\ No newline at end of file diff --git a/boot/aai_vm_init.sh b/boot/aai_vm_init.sh index 6fcf7b0e..ffe0955f 100644 --- a/boot/aai_vm_init.sh +++ b/boot/aai_vm_init.sh @@ -1,43 +1,16 @@ #!/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) -DOCKER_IMAGE_VERSION=$(cat /opt/config/docker_version.txt) +AAI_INSTANCE=$(cat /opt/config/aai_instance.txt) -# Pull HBase container from a public docker hub -docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO -docker pull $NEXUS_DOCKER_REPO/aaidocker/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/aaidocker/aai-hbase-1.2.3 +cd /opt/test-config +git pull -# Wait 3 minutes before instantiating the A&AI container -sleep 180 - -docker pull $NEXUS_DOCKER_REPO/openecomp/ajsc-aai:$DOCKER_IMAGE_VERSION -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 AAI_REPO_PATH=r/aai -e AAI_CHEF_ENV=simpledemo -d -e AAI_CHEF_LOC=/var/chef/aai-data/environments -e docker_gitbranch=release-1.0.0 $NEXUS_DOCKER_REPO/openecomp/ajsc-aai:$DOCKER_IMAGE_VERSION - -docker pull $NEXUS_DOCKER_REPO/openecomp/model-loader:$DOCKER_IMAGE_VERSION -docker rm -f model-loader-service - -# Start Model Loader container only if SDC is up and running -# Use the default SDC private IP address if no file exists or the file is empty -if [[ -s "/opt/config/sdc_ip_addr.txt" ]] +if [[ $AAI_INSTANCE == "aai_instance_1" ]] +then + ./deploy_vm1.sh +elif [[ $AAI_INSTANCE == "aai_instance_2" ]] then - SDC_IP_ADDR=$(cat /opt/config/sdc_ip_addr.txt) + ./deploy_vm2.sh else - SDC_IP_ADDR="10.0.3.1" + echo "Invalid instance. Exiting..." fi - -# Run Health Check against SDC and verify that all five components are up -RES=$(curl http://$SDC_IP_ADDR:8181/sdc1/rest/healthCheck | grep -c "OK") -while [[ $RES -lt 5 ]] -do - RES=$(curl http://$SDC_IP_ADDR:8181/sdc1/rest/healthCheck | grep -c "OK") -done - -# At this point, SDC is healthy and Model Loader container can start -docker run --name=model-loader-service -it -d -e DISTR_CLIENT_ASDC_ADDRESS=c2.vm1.sdc.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/openecomp/model-loader:$DOCKER_IMAGE_VERSION - diff --git a/boot/appc_install.sh b/boot/appc_install.sh index c2d4512c..b241efe7 100644 --- a/boot/appc_install.sh +++ b/boot/appc_install.sh @@ -7,6 +7,7 @@ DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt) CLOUD_ENV=$(cat /opt/config/cloud_env.txt) GERRIT_BRANCH=$(cat /opt/config/gerrit_branch.txt) MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1) +CODE_REPO=$(cat /opt/config/remote_repo.txt) # Add host name to /etc/host to avoid warnings in openstack images if [[ $CLOUD_ENV != "rackspace" ]] @@ -47,9 +48,10 @@ then fi # Download dependencies -add-apt-repository -y ppa:openjdk-r/ppa +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list apt-get update -apt-get install -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make +apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make # Download scripts from Nexus curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/appc_vm_init.sh -o /opt/appc_vm_init.sh @@ -91,5 +93,5 @@ resolvconf -u # Clone Gerrit repository and run docker containers cd /opt -git clone -b $GERRIT_BRANCH --single-branch http://gerrit.onap.org/r/appc/deployment.git appc +git clone -b $GERRIT_BRANCH --single-branch $CODE_REPO appc ./appc_vm_init.sh
\ No newline at end of file diff --git a/boot/appc_vm_init.sh b/boot/appc_vm_init.sh index 90b09eaf..3baaf37b 100644 --- a/boot/appc_vm_init.sh +++ b/boot/appc_vm_init.sh @@ -5,6 +5,7 @@ NEXUS_PASSWD=$(cat /opt/config/nexus_password.txt) export NEXUS_DOCKER_REPO=$(cat /opt/config/nexus_docker_repo.txt) DMAAP_TOPIC=$(cat /opt/config/dmaap_topic.txt) DOCKER_IMAGE_VERSION=$(cat /opt/config/docker_version.txt) +DGBUILDER_IMAGE_VERSION=$(cat /opt/config/dgbuilder_version.txt) export MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1) cd /opt/appc @@ -18,7 +19,7 @@ docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO docker pull $NEXUS_DOCKER_REPO/openecomp/appc-image:$DOCKER_IMAGE_VERSION docker tag $NEXUS_DOCKER_REPO/openecomp/appc-image:$DOCKER_IMAGE_VERSION openecomp/appc-image:latest -docker pull $NEXUS_DOCKER_REPO/openecomp/dgbuilder-sdnc-image:$DOCKER_IMAGE_VERSION -docker tag $NEXUS_DOCKER_REPO/openecomp/dgbuilder-sdnc-image:$DOCKER_IMAGE_VERSION openecomp/dgbuilder-sdnc-image:latest +docker pull $NEXUS_DOCKER_REPO/onap/ccsdk-dgbuilder-image:$DGBUILDER_IMAGE_VERSION +docker tag $NEXUS_DOCKER_REPO/onap/ccsdk-dgbuilder-image/$DGBUILDER_IMAGE_VERSION onap/ccsdk-dgbuilder-image:latest /opt/docker/docker-compose up -d diff --git a/boot/bind_zones b/boot/bind_zones index 0893ca64..0c8a114b 100644 --- a/boot/bind_zones +++ b/boot/bind_zones @@ -41,9 +41,9 @@ c1.vm1.dcae.simpledemo.openecomp.org. IN A dcae_ip_addr c2.vm1.dcae.simpledemo.openecomp.org. IN A dcae_ip_addr c3.vm1.dcae.simpledemo.openecomp.org IN A dcae_ip_addr -vm1.mso.simpledemo.openecomp.org. IN A mso_ip_addr -c1.vm1.mso.simpledemo.openecomp.org. IN A mso_ip_addr -c1.vm1.mso.simpledemo.openecomp.org. IN A mso_ip_addr +vm1.mso.simpledemo.openecomp.org. IN A so_ip_addr +c1.vm1.mso.simpledemo.openecomp.org. IN A so_ip_addr +c1.vm1.mso.simpledemo.openecomp.org. IN A so_ip_addr vm1.policy.simpledemo.openecomp.org. IN A policy_ip_addr c1.vm1.policy.simpledemo.openecomp.org. IN A policy_ip_addr @@ -69,14 +69,22 @@ vm1.portal.simpledemo.openecomp.org. IN A portal_ip_addr c1.vm1.portal.simpledemo.openecomp.org. IN A portal_ip_addr c2.vm1.portal.simpledemo.openecomp.org. IN A portal_ip_addr +vm1.clamp.simpledemo.openecomp.org. IN A clamp_ip_addr +c1.vm1.clamp.simpledemo.openecomp.org. IN A clamp_ip_addr +c2.vm1.clamp.simpledemo.openecomp.org. IN A clamp_ip_addr + ;vm1.aaf.simpledemo.openecomp.org. IN A aaf_ip_addr -vm1.mr.simpledemo.openecomp.org. IN A mr_ip_addr +vm1.mr.simpledemo.openecomp.org. IN A mr_ip_addr + +vm1.openo.simpledemo.openecomp.org. IN A openo_ip_addr ;CNAMES ;A&AI aai.api.simpledemo.openecomp.org. IN CNAME vm1.aai.simpledemo.openecomp.org. +aai.ui.simpledemo.openecomp.org. IN CNAME vm1.aai.simpledemo.openecomp.org. +aai.searchservice.simpledemo.openecomp.org. IN CNAME vm1.aai.simpledemo.openecomp.org. aai.hbase.simpledemo.openecomp.org. IN CNAME vm2.aai.simpledemo.openecomp.org. aai.gremlinserver.simpledemo.openecomp.org. IN CNAME vm2.aai.simpledemo.openecomp.org. aai.elasticsearch.simpledemo.openecomp.org. IN CNAME vm2.aai.simpledemo.openecomp.org. @@ -90,7 +98,7 @@ sdc.api.simpledemo.openecomp.org. IN CNAME vm1.sdc.simpledemo.openecomp.org. ;DCAE dcae.api.simpledemo.openecomp.org. IN CNAME vm1.dcae.simpledemo.openecomp.org. -;MSO +;SO mso.api.simpledemo.openecomp.org. IN CNAME vm1.mso.simpledemo.openecomp.org. ;Policy @@ -113,5 +121,15 @@ collector.api.simpledemo.openecomp.org. IN A dcae_coll_ip_addr ;dbc.api.simpledemo.openecomp.org. IN CNAME vm1.mr.simpledemo.openecomp.org. ;drprov.api.simpledemo.openecomp.org. IN CNAME vm1.mr.simpledemo.openecomp.org. +;CLAMP +clamp.api.simpledemo.openecomp.org. IN CNAME vm1.clamp.simpledemo.openecomp.org. + ;AAF ;aaf.api.simpledemo.openecomp.org. IN CNAME vm1.aaf.simpledemo.openecomp.org. + +;OPEN-O +msb.api.simpledemo.openecomp.org. IN CNAME vm1.openo.simpledemo.openecomp.org. +mvim.api.simpledemo.openecomp.org. IN CNAME vm1.openo.simpledemo.openecomp.org. +vnfsdk.api.simpledemo.openecomp.org. IN CNAME vm1.openo.simpledemo.openecomp.org. +vfc.api.simpledemo.openecomp.org. IN CNAME vm1.openo.simpledemo.openecomp.org. +uui.api.simpledemo.openecomp.org. IN CNAME vm1.openo.simpledemo.openecomp.org. diff --git a/boot/mso_install.sh b/boot/clamp_install.sh index e7d47dfd..26e8f06f 100644 --- a/boot/mso_install.sh +++ b/boot/clamp_install.sh @@ -5,9 +5,9 @@ NEXUS_REPO=$(cat /opt/config/nexus_repo.txt) ARTIFACTS_VERSION=$(cat /opt/config/artifacts_version.txt) DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt) CLOUD_ENV=$(cat /opt/config/cloud_env.txt) -OPENSTACK_API_KEY=$(cat /opt/config/openstack_api_key.txt) GERRIT_BRANCH=$(cat /opt/config/gerrit_branch.txt) MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1) +CODE_REPO=$(cat /opt/config/remote_repo.txt) # Add host name to /etc/host to avoid warnings in openstack images if [[ $CLOUD_ENV != "rackspace" ]] @@ -48,17 +48,18 @@ then fi # Download dependencies -add-apt-repository -y ppa:openjdk-r/ppa +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list apt-get update -apt-get install -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make +apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make # Download scripts from Nexus -curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/mso_vm_init.sh -o /opt/mso_vm_init.sh -curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/mso_serv.sh -o /opt/mso_serv.sh -chmod +x /opt/mso_vm_init.sh -chmod +x /opt/mso_serv.sh -mv /opt/mso_serv.sh /etc/init.d -update-rc.d mso_serv.sh defaults +curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/clamp_vm_init.sh -o /opt/clamp_vm_init.sh +curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/clamp_serv.sh -o /opt/clamp_serv.sh +chmod +x /opt/clamp_vm_init.sh +chmod +x /opt/clamp_serv.sh +mv /opt/clamp_serv.sh /etc/init.d +update-rc.d clamp_serv.sh defaults # Download and install docker-engine and docker-compose echo "deb https://apt.dockerproject.org/repo ubuntu-xenial main" | sudo tee /etc/apt/sources.list.d/docker.list @@ -92,9 +93,7 @@ resolvconf -u # Clone Gerrit repository cd /opt -git clone -b $GERRIT_BRANCH --single-branch http://gerrit.onap.org/r/so/docker-config.git test_lab -MSO_ENCRYPTION_KEY=$(cat /opt/test_lab/encryption.key) -echo -n "$OPENSTACK_API_KEY" | openssl aes-128-ecb -e -K $MSO_ENCRYPTION_KEY -nosalt | xxd -c 256 -p > /opt/config/api_key.txt +git clone -b $GERRIT_BRANCH --single-branch $CODE_REPO # Rename network interface in openstack Ubuntu 16.04 images. Then, reboot the VM to pick up changes if [[ $CLOUD_ENV != "rackspace" ]] @@ -109,4 +108,4 @@ then fi # Run docker containers. For openstack Ubuntu 16.04 images this will run as a service after the VM has restarted -./mso_vm_init.sh +./clamp_vm_init.sh diff --git a/boot/asdc_serv.sh b/boot/clamp_serv.sh index 7d2539eb..ed311849 100644 --- a/boot/asdc_serv.sh +++ b/boot/clamp_serv.sh @@ -10,7 +10,7 @@ ### END INIT INFO dir="/opt" -cmd="./asdc_vm_init.sh" +cmd="./clamp_vm_init.sh" user="root" name=`basename $0` diff --git a/boot/clamp_vm_init.sh b/boot/clamp_vm_init.sh new file mode 100644 index 00000000..f8b26e30 --- /dev/null +++ b/boot/clamp_vm_init.sh @@ -0,0 +1,30 @@ +#!/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_IMAGE_VERSION=$(cat /opt/config/docker_version.txt) + +# Fetch the latest code/scripts +cd /opt/clamp +git pull + +# Remove unused folders as only extra/ folder is used for docker compose +rm -rf pom.xml +rm -rf src/ + +# No configuration change here as directly done in the CLAMP repo + +# Pull the clamp docker image from nexus +# Maria db will be pulled automatically from docker.io during docker-compose +docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO + +docker pull $NEXUS_DOCKER_REPO/onap/clamp:$DOCKER_IMAGE_VERSION + +cd extra/docker/clamp/ + +# Change the Clamp docker image name in the docker-compose.yml to match the one downloaded +sed -i "/image: onap\/clamp/c\ image: $NEXUS_DOCKER_REPO\/onap\/clamp:$DOCKER_IMAGE_VERSION" docker-compose.yml + +# Start Clamp and MariaDB containers with docker compose and clamp/extra/docker/clamp/docker-compose.yml +/opt/docker/docker-compose up -d diff --git a/boot/cli_install.sh b/boot/cli_install.sh new file mode 100644 index 00000000..57f0edc6 --- /dev/null +++ b/boot/cli_install.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +#******************************************************************************* +# Copyright 2017 Huawei Technologies Co., Ltd. +# +# 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. +#******************************************************************************* + +CLI_LATEST_BINARY="https://nexus.onap.org/service/local/artifact/maven/redirect?r=snapshots&g=org.onap.cli&a=cli-zip&e=zip&v=LATEST" +CLI_INSTALL_DIR=/opt/onap/cli +CLI_ZIP=cli.zip +CLI_BIN=/usr/bin/onap +export ONAP_CLI_HOME=$CLI_INSTALL_DIR + +#create install dir +if [ -d $CLI_INSTALL_DIR ] +then + mv $CLI_INSTALL_DIR $CLI_INSTALL_DIR/../cli_`date +"%m-%d-%y-%H-%M-%S"` + rm $CLI_BIN +fi + +mkdir -p $CLI_INSTALL_DIR +cd $CLI_INSTALL_DIR + +#Download and unzip CLI +apt-get install -y wget unzip openjdk-8-jre +wget -O $CLI_ZIP $CLI_LATEST_BINARY + +unzip $CLI_ZIP +if [ ! -d ./data ]; then mkdir ./data; fi +if [ ! -d ./onap-cli-schema ]; then mkdir ./onap-cli-schema; fi +chmod +x ./bin/onap.sh + +#Make onap available in path +ln ./bin/onap.sh $CLI_BIN + +#Print the version +onap -v + +cd - diff --git a/boot/db_openecomp_org b/boot/db_openecomp_org deleted file mode 100644 index be42b603..00000000 --- a/boot/db_openecomp_org +++ /dev/null @@ -1,109 +0,0 @@ -; -; 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/db_simpledemo_openecomp_org b/boot/db_simpledemo_openecomp_org index f7d2b9dc..942be995 100644 --- a/boot/db_simpledemo_openecomp_org +++ b/boot/db_simpledemo_openecomp_org @@ -69,15 +69,20 @@ 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.aaf.simpledemo.openecomp.org. IN A 10.0.13.1 -vm1.mr.simpledemo.openecomp.org. IN A 10.0.11.1 +vm1.mr.simpledemo.openecomp.org. IN A 10.0.11.1 + +vm1.clamp.simpledemo.openecomp.org. IN A 10.0.12.1 +c1.vm1.clamp.simpledemo.openecomp.org. IN A 10.0.12.1 +c2.vm1.clamp.simpledemo.openecomp.org. IN A 10.0.12.1 ;CNAMES ;A&AI aai.api.simpledemo.openecomp.org. IN CNAME vm1.aai.simpledemo.openecomp.org. aai.ui.simpledemo.openecomp.org. IN CNAME vm1.aai.simpledemo.openecomp.org. +aai.searchservice.simpledemo.openecomp.org. IN CNAME vm1.aai.simpledemo.openecomp.org. aai.hbase.simpledemo.openecomp.org. IN CNAME vm2.aai.simpledemo.openecomp.org. aai.gremlinserver.simpledemo.openecomp.org. IN CNAME vm2.aai.simpledemo.openecomp.org. aai.elasticsearch.simpledemo.openecomp.org. IN CNAME vm2.aai.simpledemo.openecomp.org. @@ -114,5 +119,8 @@ 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. +;CLAMP +clamp.api.simpledemo.openecomp.org. IN CNAME vm1.clamp.simpledemo.openecomp.org. + ;AAF aaf.api.simpledemo.openecomp.org. IN CNAME vm1.aaf.simpledemo.openecomp.org. diff --git a/boot/dcae_install.sh b/boot/dcae_install.sh index 4cf78964..09a9e33d 100644 --- a/boot/dcae_install.sh +++ b/boot/dcae_install.sh @@ -6,6 +6,8 @@ ARTIFACTS_VERSION=$(cat /opt/config/artifacts_version.txt) DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt) CLOUD_ENV=$(cat /opt/config/cloud_env.txt) GERRIT_BRANCH=$(cat /opt/config/gerrit_branch.txt) +CODE_REPO=$(cat /opt/config/remote_repo.txt) +MR_REPO=$(cat /opt/config/mr_repo.txt) BASE=$(cat /opt/config/dcae_base_environment.txt) PUBLIC_NET_ID=$(cat /opt/config/public_net_id.txt) @@ -78,9 +80,10 @@ then fi # Download dependencies -add-apt-repository -y ppa:openjdk-r/ppa +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list apt-get update -apt-get install -y apt-transport-https ca-certificates wget make openjdk-8-jdk git ntp ntpdate +apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget make openjdk-8-jdk git ntp ntpdate # Download scripts from Nexus curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/dcae_vm_init.sh -o /opt/dcae_vm_init.sh @@ -122,7 +125,7 @@ resolvconf -u # Clone Gerrit repository cd /opt -git clone -b $GERRIT_BRANCH --single-branch http://gerrit.onap.org/r/dcae/demo/startup/controller.git dcae-startup-vm-controller +git clone -b $GERRIT_BRANCH --single-branch $CODE_REPO dcae-startup-vm-controller # Build a configuration file for the DCAE Controller. cd /opt/dcae-startup-vm-controller @@ -154,7 +157,7 @@ NEXUS-RAWURL: $NEXUS_REPO DOCKER-REGISTRY: $DOCKER_REGISTRY DOCKER-VERSION: $DOCKER_VERSION -GIT-MR-REPO: http://gerrit.onap.org/r/dcae/demo/startup/message-router.git +GIT-MR-REPO: $MR_REPO public_net_id: $PUBLIC_NET_ID dcae_ip_addr: $DCAE_IP_ADDR diff --git a/boot/dns_install.sh b/boot/dns_install.sh index e76f371a..27ea2233 100644 --- a/boot/dns_install.sh +++ b/boot/dns_install.sh @@ -50,9 +50,10 @@ then fi # Download dependencies -add-apt-repository -y ppa:openjdk-r/ppa +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list apt-get update -apt-get install -y apt-transport-https ca-certificates wget openjdk-8-jdk bind9 bind9utils bind9-doc ntp ntpdate make +apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget openjdk-8-jdk bind9 bind9utils bind9-doc ntp ntpdate make # Download script mkdir /etc/bind/zones @@ -70,7 +71,7 @@ then sed -i "s/appc_ip_addr/"$(cat /opt/config/appc_ip_addr.txt)"/g" /etc/bind/zones/db.simpledemo.openecomp.org sed -i "s/dcae_ip_addr/"$(cat /opt/config/dcae_ip_addr.txt)"/g" /etc/bind/zones/db.simpledemo.openecomp.org sed -i "s/dns_ip_addr/"$(cat /opt/config/dns_ip_addr.txt)"/g" /etc/bind/zones/db.simpledemo.openecomp.org - sed -i "s/mso_ip_addr/"$(cat /opt/config/mso_ip_addr.txt)"/g" /etc/bind/zones/db.simpledemo.openecomp.org + sed -i "s/so_ip_addr/"$(cat /opt/config/so_ip_addr.txt)"/g" /etc/bind/zones/db.simpledemo.openecomp.org sed -i "s/mr_ip_addr/"$(cat /opt/config/mr_ip_addr.txt)"/g" /etc/bind/zones/db.simpledemo.openecomp.org sed -i "s/policy_ip_addr/"$(cat /opt/config/policy_ip_addr.txt)"/g" /etc/bind/zones/db.simpledemo.openecomp.org sed -i "s/portal_ip_addr/"$(cat /opt/config/portal_ip_addr.txt)"/g" /etc/bind/zones/db.simpledemo.openecomp.org @@ -79,6 +80,8 @@ then sed -i "s/sdnc_ip_addr/"$(cat /opt/config/sdnc_ip_addr.txt)"/g" /etc/bind/zones/db.simpledemo.openecomp.org sed -i "s/vid_ip_addr/"$(cat /opt/config/vid_ip_addr.txt)"/g" /etc/bind/zones/db.simpledemo.openecomp.org sed -i "s/dcae_coll_ip_addr/"$(cat /opt/config/dcae_coll_ip_addr.txt)"/g" /etc/bind/zones/db.simpledemo.openecomp.org + sed -i "s/clamp_ip_addr/"$(cat /opt/config/clamp_ip_addr.txt)"/g" /etc/bind/zones/db.simpledemo.openecomp.org + sed -i "s/openo_ip_addr/"$(cat /opt/config/openo_ip_addr.txt)"/g" /etc/bind/zones/db.simpledemo.openecomp.org fi # Configure Bind diff --git a/boot/mr_install.sh b/boot/mr_install.sh index 8c6ee206..e2168383 100644 --- a/boot/mr_install.sh +++ b/boot/mr_install.sh @@ -7,6 +7,7 @@ DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt) CLOUD_ENV=$(cat /opt/config/cloud_env.txt) GERRIT_BRANCH=$(cat /opt/config/gerrit_branch.txt) MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1) +CODE_REPO=$(cat /opt/config/remote_repo.txt) # Add host name to /etc/host to avoid warnings in openstack images if [[ $CLOUD_ENV != "rackspace" ]] @@ -47,9 +48,10 @@ then fi # Download dependencies -add-apt-repository -y ppa:openjdk-r/ppa +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list apt-get update -apt-get install -y apt-transport-https ca-certificates wget make openjdk-8-jdk git ntp ntpdate +apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget make openjdk-8-jdk git ntp ntpdate # Download scripts from Nexus curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/mr_vm_init.sh -o /opt/mr_vm_init.sh @@ -91,5 +93,5 @@ resolvconf -u # Clone Gerrit repository and run docker containers cd /opt -git clone -b $GERRIT_BRANCH --single-branch http://gerrit.onap.org/r/dcae/demo/startup/message-router.git dcae-startup-vm-message-router +git clone -b $GERRIT_BRANCH --single-branch $CODE_REPO dcae-startup-vm-message-router ./mr_vm_init.sh
\ No newline at end of file diff --git a/boot/msb_vm_init.sh b/boot/msb_vm_init.sh new file mode 100644 index 00000000..cbce0609 --- /dev/null +++ b/boot/msb_vm_init.sh @@ -0,0 +1,83 @@ +#!/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_IMAGE_VERSION=$(cat /opt/config/msb_docker.txt) + +source /opt/config/onap_ips.txt + +# start up MSB +docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO +docker pull $NEXUS_DOCKER_REPO/onap/msb/msb_discovery:$DOCKER_IMAGE_VERSION +docker pull $NEXUS_DOCKER_REPO/onap/msb/msb_apigateway:$DOCKER_IMAGE_VERSION + +docker rm -f msb_consul +docker rm -f msb_discovery +docker rm -f msb_apigateway + +docker run -d -p 8500:8500 --name msb_consul consul +CONSUL_IP=`sudo docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' msb_consul` + +docker run -d -p 10081:10081 -e CONSUL_IP=$CONSUL_IP --name msb_discovery $NEXUS_DOCKER_REPO/onap/msb/msb_discovery:$DOCKER_IMAGE_VERSION +DISCOVERY_IP=`sudo docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' msb_discovery` + +docker run -d -p 80:80 -e CONSUL_IP=$CONSUL_IP -e SDCLIENT_IP=$DISCOVERY_IP -e "ROUTE_LABELS=visualRange:0|1" --name msb_apigateway $NEXUS_DOCKER_REPO/onap/msb/msb_apigateway:$DOCKER_IMAGE_VERSION + +# Allow the MSB container to come up before registering services +sleep 20 + +# register ONAP services to MSB +#aai +curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "aai-cloudInfrastructure", "version": "v11", "url": "/aai/v11/cloud-infrastructure","protocol": "REST", "nodes": [ {"ip": "'$AAI_IP1'","port": "8443"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services" + +curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "aai-cloudInfrastructure-deprecated", "version": "v11", "url": "/aai/v11/cloud-infrastructure","path": "/aai/v11/cloud-infrastructure","protocol": "REST", "nodes": [ {"ip": "'$AAI_IP1'","port": "8443"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services" + +curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "aai-business", "version": "v11", "url": "/aai/v11/business","protocol": "REST", "nodes": [ {"ip": "'$AAI_IP1'","port": "8443"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services" + +curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "aai-business-deprecated", "version": "v11", "url": "/aai/v11/business","path": "/aai/v11/business","protocol": "REST", "nodes": [ {"ip": "'$AAI_IP1'","port": "8443"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services" + +curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "aai-search", "version": "v11", "url": "/aai/v11/search","protocol": "REST", "nodes": [ {"ip": "'$AAI_IP1'","port": "8443"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services" + +curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "aai-search-deprecated", "version": "v11", "url": "/aai/v11/search","path": "/aai/v11/search","protocol": "REST", "nodes": [ {"ip": "'$AAI_IP1'","port": "8443"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services" + +curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "aai-actions", "version": "v11", "url": "/aai/v11/actions","protocol": "REST", "nodes": [ {"ip": "'$AAI_IP1'","port": "8443"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services" + +curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "aai-actions-deprecated", "version": "v11", "url": "/aai/v11/actions","path": "/aai/v11/actions","protocol": "REST", "nodes": [ {"ip": "'$AAI_IP1'","port": "8443"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services" + +curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "aai-service-design-and-creation", "version": "v11", "url": "/aai/v11/service-design-and-creation","protocol": "REST", "nodes": [ {"ip": "'$AAI_IP1'","port": "8443"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services" + +curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "aai-service-design-and-creation-deprecated", "version": "v11", "url": "/aai/v11/service-design-and-creation","path": "/aai/v11/service-design-and-creation","protocol": "REST", "nodes": [ {"ip": "'$AAI_IP1'","port": "8443"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services" + +curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "aai-network", "version": "v11", "url": "/aai/v11/network","protocol": "REST", "nodes": [ {"ip": "'$AAI_IP1'","port": "8443"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services" + +curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "aai-network-deprecated", "version": "v11", "url": "/aai/v11/network","path": "/aai/v11/network","protocol": "REST", "nodes": [ {"ip": "'$AAI_IP1'","port": "8443"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services" + +#so +curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "so", "version": "v1", "url": "/ecomp/mso/infra","protocol": "REST", "nodes": [ {"ip": "'$SO_IP'","port": "8080"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services" + +curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "so-deprecated", "version": "v1", "url": "/ecomp/mso/infra","path": "/ecomp/mso/infra","protocol": "REST", "nodes": [ {"ip": "'$SO_IP'","port": "8080"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services" + +#Dmaap message router +#curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "message-router", "version": "v1", "url": "/","protocol": "REST", "nodes": [ {"ip": "'$DMAAP_IP'","port": "3904"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services" + +#policy +curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "policy-pdp", "version": "v1", "url": "/pdp","protocol": "REST", "nodes": [ {"ip": "'$POLICY_IP'","port": "8081"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services" + +curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "policy-pdp-deprecated", "version": "v1", "url": "/pdp","path": "/pdp","protocol": "REST", "nodes": [ {"ip": "'$POLICY_IP'","port": "8081"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services" + +#portal +curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "portal", "version": "v2", "url": "/","protocol": "REST", "nodes": [ {"ip": "'$PORTAL_IP'","port": "8989"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services" + +#sdc +curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "sdc", "version": "v1", "url": "/sdc/v1","protocol": "REST", "nodes": [ {"ip": "'$SDC_IP'","port": "8080"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services" + +curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "sdc-deprecated", "version": "v1", "url": "/sdc/v1","path": "/sdc/v1","protocol": "REST", "nodes": [ {"ip": "'$SDC_IP'","port": "8080"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services" + +#sdnc +curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "sdnc", "version": "v1", "url": "/","protocol": "REST", "nodes": [ {"ip": "'$SDNC_IP'","port": "8282"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services" + +curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "sdnc", "version": "v1", "url": "/restconf","path": "/restconf","protocol": "REST", "nodes": [ {"ip": "'$SDNC_IP'","port": "8282"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services" + +#multi-vim +curl -X POST -H "Content-Type: application/json" -d '{"serviceName": "multicloud-titanium_cloud", "version": "v0", "url": "/api/multicloud-titanium_cloud/v0","protocol": "REST", "nodes": [ {"ip": "'$OPENO_IP'","port": "9005"}]}' "http://$OPENO_IP:10081/api/microservices/v1/services"
\ No newline at end of file diff --git a/boot/mvim_vm_init.sh b/boot/mvim_vm_init.sh new file mode 100755 index 00000000..f8776bd4 --- /dev/null +++ b/boot/mvim_vm_init.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# Establish environment variables +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_IMAGE_VERSION=$(cat /opt/config/mvim_docker.txt) + +source /opt/config/onap_ips.txt + +# Refresh images +docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO +docker pull $NEXUS_DOCKER_REPO/onap/multicloud/framework:$DOCKER_IMAGE_VERSION +docker pull $NEXUS_DOCKER_REPO/onap/multicloud/vio:$DOCKER_IMAGE_VERSION +docker pull $NEXUS_DOCKER_REPO/onap/multicloud/openstack-ocata:$DOCKER_IMAGE_VERSION +docker pull $NEXUS_DOCKER_REPO/onap/multicloud/openstack-windriver:$DOCKER_IMAGE_VERSION + +docker rm -f multicloud-broker +docker rm -f multicloud-vio +docker rm -f multicloud-ocata +docker rm -f multicloud-windriver + +docker run -d -t -e MSB_ADDR=$OPENO_IP -e AAI_ADDR=$AAI_IP1 -p 9001:9001 --name multicloud-broker $NEXUS_DOCKER_REPO/onap/multicloud/framework:$DOCKER_IMAGE_VERSION +docker run -d -t -e MSB_ADDR=$OPENO_IP -e AAI_ADDR=$AAI_IP1 -p 9004:9004 --name multicloud-vio $NEXUS_DOCKER_REPO/onap/multicloud/vio:$DOCKER_IMAGE_VERSION +docker run -d -t -e MSB_ADDR=$OPENO_IP -e AAI_ADDR=$AAI_IP1 -p 9006:9006 --name multicloud-ocata $NEXUS_DOCKER_REPO/onap/multicloud/openstack-ocata:$DOCKER_IMAGE_VERSION +docker run -d -t -e MSB_ADDR=$OPENO_IP -e AAI_ADDR=$AAI_IP1 -p 9005:9005 --name multicloud-windriver $NEXUS_DOCKER_REPO/onap/multicloud/openstack-windriver:$DOCKER_IMAGE_VERSION
\ No newline at end of file diff --git a/boot/openo_all_serv.sh b/boot/openo_all_serv.sh new file mode 100644 index 00000000..e451fb1b --- /dev/null +++ b/boot/openo_all_serv.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +bash /opt/msb_vm_init.sh &>/dev/null &disown +bash /opt/vnfsdk_vm_init.sh &>/dev/null &disown +bash /opt/mvim_vm_init.sh &>/dev/null &disown +bash /opt/vfc_vm_init.sh &>/dev/null &disown +bash /opt/uui_vm_init.sh &>/dev/null &disown
\ No newline at end of file diff --git a/boot/openo_install.sh b/boot/openo_install.sh new file mode 100644 index 00000000..0f36497a --- /dev/null +++ b/boot/openo_install.sh @@ -0,0 +1,120 @@ +#!/bin/bash + +# Read configuration files +NEXUS_REPO=$(cat /opt/config/nexus_repo.txt) +ARTIFACTS_VERSION=$(cat /opt/config/artifacts_version.txt) +DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt) +CLOUD_ENV=$(cat /opt/config/cloud_env.txt) +VNFSDK_BRANCH=$(cat /opt/config/vnfsdk_branch.txt) +MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1) +VNFSDK_REPO=$(cat /opt/config/vnfsdk_repo.txt) + +# Add host name to /etc/host to avoid warnings in openstack images +if [[ $CLOUD_ENV != "rackspace" ]] +then + echo 127.0.0.1 $(hostname) >> /etc/hosts + + # Allow remote login as root + mv /root/.ssh/authorized_keys /root/.ssh/authorized_keys.bk + cp /home/ubuntu/.ssh/authorized_keys /root/.ssh +fi + +# Set private IP in /etc/network/interfaces manually in the presence of public interface +# Some VM images don't add the private interface automatically, we have to do it during the component installation +if [[ $CLOUD_ENV == "openstack_nofloat" ]] +then + LOCAL_IP=$(cat /opt/config/local_ip_addr.txt) + CIDR=$(cat /opt/config/oam_network_cidr.txt) + BITMASK=$(echo $CIDR | cut -d"/" -f2) + + # Compute the netmask based on the network cidr + if [[ $BITMASK == "8" ]] + then + NETMASK=255.0.0.0 + elif [[ $BITMASK == "16" ]] + then + NETMASK=255.255.0.0 + elif [[ $BITMASK == "24" ]] + then + NETMASK=255.255.255.0 + fi + + echo "auto eth1" >> /etc/network/interfaces + echo "iface eth1 inet static" >> /etc/network/interfaces + echo " address $LOCAL_IP" >> /etc/network/interfaces + echo " netmask $NETMASK" >> /etc/network/interfaces + echo " mtu $MTU" >> /etc/network/interfaces + ifup eth1 +fi + +# Download dependencies +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +apt-get update +apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget openjdk-8-jdk git unzip mysql-client-core-5.6 ntp ntpdate make + +# Download scripts from Nexus +curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/vnfsdk_vm_init.sh -o /opt/vnfsdk_vm_init.sh +curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/msb_vm_init.sh -o /opt/msb_vm_init.sh +curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/mvim_vm_init.sh -o /opt/mvim_vm_init.sh +curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/vfc_vm_init.sh -o /opt/vfc_vm_init.sh +curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/uui_vm_init.sh -o /opt/uui_vm_init.sh +curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/openo_all_serv.sh -o /opt/openo_all_serv.sh +curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/openo_serv.sh -o /opt/openo_serv.sh +chmod +x /opt/vnfsdk_vm_init.sh +chmod +x /opt/msb_vm_init.sh +chmod +x /opt/mvim_vm_init.sh +chmod +x /opt/vfc_vm_init.sh +chmod +x /opt/uui_vm_init.sh +chmod +x /opt/openo_all_serv.sh +chmod +x /opt/openo_serv.sh +mv /opt/openo_serv.sh /etc/init.d +update-rc.d openo_serv.sh defaults + +# Download and install docker-engine and docker-compose +echo "deb https://apt.dockerproject.org/repo ubuntu-xenial main" | sudo tee /etc/apt/sources.list.d/docker.list +apt-get update +apt-get install -y linux-image-extra-$(uname -r) linux-image-extra-virtual +apt-get install -y --allow-unauthenticated docker-engine + +mkdir /opt/docker +curl -L https://github.com/docker/compose/releases/download/1.9.0/docker-compose-`uname -s`-`uname -m` > /opt/docker/docker-compose +chmod +x /opt/docker/docker-compose + +# Set the MTU size of docker containers to the minimum MTU size supported by vNICs. OpenStack deployments may need to know the external DNS IP +DNS_FLAG="" +if [ -s /opt/config/dns_ip_addr.txt ] +then + DNS_FLAG=$DNS_FLAG"--dns $(cat /opt/config/dns_ip_addr.txt) " +fi +if [ -s /opt/config/external_dns.txt ] +then + DNS_FLAG=$DNS_FLAG"--dns $(cat /opt/config/external_dns.txt) " +fi +echo "DOCKER_OPTS=\"$DNS_FLAG--mtu=$MTU\"" >> /etc/default/docker + +cp /lib/systemd/system/docker.service /etc/systemd/system +sed -i "/ExecStart/s/$/ --mtu=$MTU/g" /etc/systemd/system/docker.service +service docker restart + +# DNS IP address configuration +echo "nameserver "$DNS_IP_ADDR >> /etc/resolvconf/resolv.conf.d/head +resolvconf -u + +# Clone Gerrit repository and run docker containers +cd /opt +git clone -b $VNFSDK_BRANCH --single-branch $VNFSDK_REPO + +# Rename network interface in openstack Ubuntu 16.04 images. Then, reboot the VM to pick up changes +if [[ $CLOUD_ENV != "rackspace" ]] +then + sed -i "s/GRUB_CMDLINE_LINUX=.*/GRUB_CMDLINE_LINUX=\"net.ifnames=0 biosdevname=0\"/g" /etc/default/grub + grub-mkconfig -o /boot/grub/grub.cfg + sed -i "s/ens[0-9]*/eth0/g" /etc/network/interfaces.d/*.cfg + sed -i "s/ens[0-9]*/eth0/g" /etc/udev/rules.d/70-persistent-net.rules + echo 'network: {config: disabled}' >> /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg + echo "APT::Periodic::Unattended-Upgrade \"0\";" >> /etc/apt/apt.conf.d/10periodic + reboot +fi + +./openo_all_serv.sh
\ No newline at end of file diff --git a/boot/openo_serv.sh b/boot/openo_serv.sh new file mode 100644 index 00000000..0afa931e --- /dev/null +++ b/boot/openo_serv.sh @@ -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="./openo_all_serv.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_install.sh b/boot/policy_install.sh index 18cc3def..3f6ea5d1 100644 --- a/boot/policy_install.sh +++ b/boot/policy_install.sh @@ -7,6 +7,7 @@ DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt) CLOUD_ENV=$(cat /opt/config/cloud_env.txt) GERRIT_BRANCH=$(cat /opt/config/gerrit_branch.txt) MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1) +CODE_REPO=$(cat /opt/config/remote_repo.txt) # Add host name to /etc/host to avoid warnings in openstack images if [[ $CLOUD_ENV != "rackspace" ]] @@ -47,9 +48,10 @@ then fi # Download dependencies -add-apt-repository -y ppa:openjdk-r/ppa +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list apt-get update -apt-get install -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make +apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make # Download scripts from Nexus curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/policy_vm_init.sh -o /opt/policy_vm_init.sh @@ -91,5 +93,5 @@ resolvconf -u # Clone Gerrit repository and run docker containers cd /opt -git clone -b $GERRIT_BRANCH --single-branch http://gerrit.onap.org/r/policy/docker.git policy +git clone -b $GERRIT_BRANCH --single-branch $CODE_REPO policy ./policy_vm_init.sh
\ No newline at end of file diff --git a/boot/portal_install.sh b/boot/portal_install.sh index 6b1c34f0..c1b816e0 100644 --- a/boot/portal_install.sh +++ b/boot/portal_install.sh @@ -7,6 +7,7 @@ DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt) CLOUD_ENV=$(cat /opt/config/cloud_env.txt) GERRIT_BRANCH=$(cat /opt/config/gerrit_branch.txt) MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1) +CODE_REPO=$(cat /opt/config/remote_repo.txt) # Add host name to /etc/host to avoid warnings in openstack images if [[ $CLOUD_ENV != "rackspace" ]] @@ -47,9 +48,10 @@ then fi # Download dependencies -add-apt-repository -y ppa:openjdk-r/ppa +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list apt-get update -apt-get install -y apt-transport-https ca-certificates wget openjdk-8-jdk git unzip mysql-client-core-5.6 ntp ntpdate make +apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget openjdk-8-jdk git unzip mysql-client-core-5.6 ntp ntpdate make # Download scripts from Nexus curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/portal_vm_init.sh -o /opt/portal_vm_init.sh @@ -92,5 +94,6 @@ resolvconf -u # Clone Gerrit repository and run docker containers mkdir -p /PROJECT/OpenSource/UbuntuEP/logs cd /opt -git clone -b $GERRIT_BRANCH --single-branch http://gerrit.onap.org/r/portal.git +git clone -b $GERRIT_BRANCH --single-branch $CODE_REPO + ./portal_vm_init.sh
\ No newline at end of file diff --git a/boot/portal_vm_init.sh b/boot/portal_vm_init.sh index 5f34aae8..5b201e09 100755 --- a/boot/portal_vm_init.sh +++ b/boot/portal_vm_init.sh @@ -1,71 +1,45 @@ #!/bin/bash -# Starts docker containers for ONAP Portal +# Starts docker containers for ONAP Portal in Rackspace. +# Version for Amsterdam/R1 uses docker-compose. # be verbose set -x -# Refresh source area with start scripts -cd /opt/portal -git pull -cd /opt - # Establish environment variables 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_IMAGE_VERSION=$(cat /opt/config/docker_version.txt) -# Get container, image and tag names used below -source portal/deliveries/os_settings.sh +# Refresh configuration and scripts +cd /opt/portal +git pull +cd deliveries + +# Get image names used below from docker-compose environment file +source .env -# Unpack property files -unzip -o portal/deliveries/etc.zip -d /PROJECT/OpenSource/UbuntuEP/ +# Copy property files +ETC=/PROJECT/OpenSource/UbuntuEP/etc +mkdir -p $ETC +cp -r properties_rackspace/* $ETC # Refresh images docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO -docker pull $NEXUS_DOCKER_REPO/openecomp/${DB_TAG_NAME}:$DOCKER_IMAGE_VERSION -docker pull $NEXUS_DOCKER_REPO/openecomp/${EP_TAG_NAME}:$DOCKER_IMAGE_VERSION -docker pull $NEXUS_DOCKER_REPO/openecomp/${WMS_TAG_NAME}:$DOCKER_IMAGE_VERSION - -# Remove lingering containers; order matters. -docker rm -f $DB_CONT_NAME -docker rm -f $DB_VOL_NAME -docker rm -f $EP_CONT_NAME -docker rm -f $WMS_CONT_NAME - -docker create --name $DB_VOL_NAME -v /var/lib/mysql mariadb -docker tag $NEXUS_DOCKER_REPO/openecomp/${DB_TAG_NAME}:$DOCKER_IMAGE_VERSION $DB_IMG_NAME -docker tag $NEXUS_DOCKER_REPO/openecomp/${EP_TAG_NAME}:$DOCKER_IMAGE_VERSION $EP_IMG_NAME -# WMS image has no version in the registry -docker tag $NEXUS_DOCKER_REPO/openecomp/${WMS_TAG_NAME}:$DOCKER_IMAGE_VERSION ${WMS_IMG_NAME}:latest - -# Recreate the named containers -cd portal/deliveries -echo "Starting database" -./dbstart.sh -echo "Delaying for database" -sleep 10 -echo "Starting apps" -./new_start.sh -echo "Starting widget-ms" -./widget_ms_start.sh - -sleep 180 +docker pull $NEXUS_DOCKER_REPO/openecomp/${DB_IMG_NAME}:$DOCKER_IMAGE_VERSION +docker pull $NEXUS_DOCKER_REPO/openecomp/${EP_IMG_NAME}:$DOCKER_IMAGE_VERSION +docker pull $NEXUS_DOCKER_REPO/openecomp/${WMS_IMG_NAME}:$DOCKER_IMAGE_VERSION +# Add CLI docker image +docker pull $NEXUS_DOCKER_REPO/onap/cli:$DOCKER_IMAGE_VERSION + +# Tag them as expected by docker-compose file +docker tag $NEXUS_DOCKER_REPO/openecomp/${DB_IMG_NAME}:$DOCKER_IMAGE_VERSION $DB_IMG_NAME:$PORTAL_TAG +docker tag $NEXUS_DOCKER_REPO/openecomp/${EP_IMG_NAME}:$DOCKER_IMAGE_VERSION $EP_IMG_NAME:$PORTAL_TAG +docker tag $NEXUS_DOCKER_REPO/openecomp/${WMS_IMG_NAME}:$DOCKER_IMAGE_VERSION $WMS_IMG_NAME:$PORTAL_TAG +# Add tagging for CLI docker image as expected by docker-compose file +docker tag $NEXUS_DOCKER_REPO/onap/cli:$DOCKER_IMAGE_VERSION onap/cli:$PORTAL_TAG + +# docker-compose is not in /usr/bin +/opt/docker/docker-compose down +/opt/docker/docker-compose up -d -if [ ! -e /opt/config/boot.txt ] -then - if [ -e /opt/config/public_ip.txt ] - then - IP_ADDRESS=$(cat /opt/config/public_ip.txt) - else - IP_ADDRESS=$(ifconfig eth0 | grep "inet addr" | tr -s ' ' | cut -d' ' -f3 | cut -d':' -f2) - fi - # Wait until MySQL is running... - while [[ $(netstat -vulntp |grep -i mysql | awk '{print $4}') != ":::3306" ]] - do - sleep 1 - done - # no longer necessary; done at docker build time - # mysql -u root -p'Aa123456' -h $IP_ADDRESS < /opt/portal/deliveries/Apps_Users_OnBoarding_Script.sql - echo "yes" > /opt/config/boot.txt -fi diff --git a/boot/robot_install.sh b/boot/robot_install.sh index caf5bef4..3447a01f 100644 --- a/boot/robot_install.sh +++ b/boot/robot_install.sh @@ -7,6 +7,7 @@ DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt) CLOUD_ENV=$(cat /opt/config/cloud_env.txt) GERRIT_BRANCH=$(cat /opt/config/gerrit_branch.txt) MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1) +CODE_REPO=$(cat /opt/config/remote_repo.txt) # Add host name to /etc/host to avoid warnings in openstack images if [[ $CLOUD_ENV != "rackspace" ]] @@ -47,9 +48,10 @@ then fi # Download dependencies -add-apt-repository -y ppa:openjdk-r/ppa +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list apt-get update -apt-get install -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make +apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make # Download scripts from Nexus curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/robot_vm_init.sh -o /opt/robot_vm_init.sh @@ -93,7 +95,7 @@ resolvconf -u mkdir -p /opt/eteshare/logs mkdir -p /opt/eteshare/config cd /opt -git clone -b $GERRIT_BRANCH --single-branch http://gerrit.onap.org/r/testsuite/properties.git testsuite/properties +git clone -b $GERRIT_BRANCH --single-branch $CODE_REPO testsuite/properties # Rename network interface in openstack Ubuntu 16.04 images. Then, reboot the VM to pick up changes if [[ $CLOUD_ENV != "rackspace" ]] diff --git a/boot/robot_vm_init.sh b/boot/robot_vm_init.sh index 5b682729..7831348d 100644 --- a/boot/robot_vm_init.sh +++ b/boot/robot_vm_init.sh @@ -22,13 +22,14 @@ cp demo.sh /opt # sed -i "s/10.0.1.1/"$(cat /opt/config/aai1_ip_addr.txt)"/g" /opt/eteshare/config/integration_robot_properties.py # sed -i "s/10.0.2.1/"$(cat /opt/config/appc_ip_addr.txt)"/g" /opt/eteshare/config/integration_robot_properties.py # sed -i "s/10.0.4.1/"$(cat /opt/config/dcae_ip_addr.txt)"/g" /opt/eteshare/config/integration_robot_properties.py -# sed -i "s/10.0.5.1/"$(cat /opt/config/mso_ip_addr.txt)"/g" /opt/eteshare/config/integration_robot_properties.py +# sed -i "s/10.0.5.1/"$(cat /opt/config/so_ip_addr.txt)"/g" /opt/eteshare/config/integration_robot_properties.py # sed -i "s/10.0.11.1/"$(cat /opt/config/mr_ip_addr.txt)"/g" /opt/eteshare/config/integration_robot_properties.py # sed -i "s/10.0.6.1/"$(cat /opt/config/policy_ip_addr.txt)"/g" /opt/eteshare/config/integration_robot_properties.py # sed -i "s/10.0.9.1/"$(cat /opt/config/portal_ip_addr.txt)"/g" /opt/eteshare/config/integration_robot_properties.py # sed -i "s/10.0.3.1/"$(cat /opt/config/sdc_ip_addr.txt)"/g" /opt/eteshare/config/integration_robot_properties.py # sed -i "s/10.0.7.1/"$(cat /opt/config/sdnc_ip_addr.txt)"/g" /opt/eteshare/config/integration_robot_properties.py # sed -i "s/10.0.8.1/"$(cat /opt/config/vid_ip_addr.txt)"/g" /opt/eteshare/config/integration_robot_properties.py +# sed -i "s/10.0.12.1/"$(cat /opt/config/clamp_ip_addr.txt)"/g" /opt/eteshare/config/integration_robot_properties.py # sed -i "s/https:\/\/identity.api.rackspacecloud.com/"$(cat /opt/config/keystone.txt)"/g" /opt/eteshare/config/integration_robot_properties.py #fi diff --git a/boot/asdc_ext_volume_partitions.txt b/boot/sdc_ext_volume_partitions.txt index b00c6ae2..b00c6ae2 100644 --- a/boot/asdc_ext_volume_partitions.txt +++ b/boot/sdc_ext_volume_partitions.txt diff --git a/boot/asdc_install.sh b/boot/sdc_install.sh index 59d6c836..2c32266c 100644 --- a/boot/asdc_install.sh +++ b/boot/sdc_install.sh @@ -7,6 +7,7 @@ DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt) CLOUD_ENV=$(cat /opt/config/cloud_env.txt) GERRIT_BRANCH=$(cat /opt/config/gerrit_branch.txt) MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1) +CODE_REPO=$(cat /opt/config/remote_repo.txt) # Add host name to /etc/host to avoid warnings in openstack images if [[ $CLOUD_ENV != "rackspace" ]] @@ -47,17 +48,18 @@ then fi # Download dependencies -add-apt-repository -y ppa:openjdk-r/ppa +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list apt-get update -apt-get install -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make +apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make # Download scripts from Nexus -curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/asdc_vm_init.sh -o /opt/asdc_vm_init.sh -curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/asdc_serv.sh -o /opt/asdc_serv.sh -chmod +x /opt/asdc_vm_init.sh -chmod +x /opt/asdc_serv.sh -mv /opt/asdc_serv.sh /etc/init.d -update-rc.d asdc_serv.sh defaults +curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/sdc_vm_init.sh -o /opt/sdc_vm_init.sh +curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/sdc_serv.sh -o /opt/sdc_serv.sh +chmod +x /opt/sdc_vm_init.sh +chmod +x /opt/sdc_serv.sh +mv /opt/sdc_serv.sh /etc/init.d +update-rc.d sdc_serv.sh defaults # Download and install docker-engine and docker-compose echo "deb https://apt.dockerproject.org/repo ubuntu-xenial main" | sudo tee /etc/apt/sources.list.d/docker.list @@ -70,17 +72,17 @@ curl -L https://github.com/docker/compose/releases/download/1.9.0/docker-compose chmod +x /opt/docker/docker-compose # Create partition and mount the external volume -curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/asdc_ext_volume_partitions.txt -o /opt/asdc_ext_volume_partitions.txt +curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/sdc_ext_volume_partitions.txt -o /opt/sdc_ext_volume_partitions.txt if [[ $CLOUD_ENV == "rackspace" ]] then DISK="xvdb" else DISK=$(ls /dev |grep -e '^.*db$') - sed -i "s/xvdb/$DISK/g" /opt/asdc_ext_volume_partitions.txt + sed -i "s/xvdb/$DISK/g" /opt/sdc_ext_volume_partitions.txt fi -sfdisk /dev/$DISK < /opt/asdc_ext_volume_partitions.txt +sfdisk /dev/$DISK < /opt/sdc_ext_volume_partitions.txt mkfs -t ext4 /dev/$DISK"1" mkdir -p /data mount /dev/$DISK"1" /data @@ -116,7 +118,7 @@ chmod 777 /data chmod 777 /data/logs/BE chmod 777 /data/logs/FE -git clone -b $GERRIT_BRANCH --single-branch http://gerrit.onap.org/r/sdc.git +git clone -b $GERRIT_BRANCH --single-branch $CODE_REPO cat > /root/.bash_aliases << EOF alias dcls='/data/scripts/docker_clean.sh \$1' @@ -138,4 +140,4 @@ then fi # Run docker containers. For openstack Ubuntu 16.04 images this will run as a service after the VM has restarted -./asdc_vm_init.sh +./sdc_vm_init.sh diff --git a/boot/mso_serv.sh b/boot/sdc_serv.sh index 00ee4170..b48c8484 100644 --- a/boot/mso_serv.sh +++ b/boot/sdc_serv.sh @@ -10,7 +10,7 @@ ### END INIT INFO dir="/opt" -cmd="./mso_vm_init.sh" +cmd="./sdc_vm_init.sh" user="root" name=`basename $0` diff --git a/boot/asdc_vm_init.sh b/boot/sdc_vm_init.sh index dd15c0a1..dd15c0a1 100644 --- a/boot/asdc_vm_init.sh +++ b/boot/sdc_vm_init.sh diff --git a/boot/sdnc_install.sh b/boot/sdnc_install.sh index 88148764..3b5c5cfa 100644 --- a/boot/sdnc_install.sh +++ b/boot/sdnc_install.sh @@ -7,6 +7,7 @@ DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt) CLOUD_ENV=$(cat /opt/config/cloud_env.txt) GERRIT_BRANCH=$(cat /opt/config/gerrit_branch.txt) MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1) +CODE_REPO=$(cat /opt/config/remote_repo.txt) # Add host name to /etc/host to avoid warnings in openstack images if [[ $CLOUD_ENV != "rackspace" ]] @@ -47,9 +48,10 @@ then fi # Download dependencies -add-apt-repository -y ppa:openjdk-r/ppa +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list apt-get update -apt-get install -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make +apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make # Download scripts from Nexus curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/sdnc_vm_init.sh -o /opt/sdnc_vm_init.sh @@ -91,5 +93,5 @@ resolvconf -u # Clone Gerrit repository and run docker containers cd /opt -git clone -b $GERRIT_BRANCH --single-branch http://gerrit.onap.org/r/sdnc/oam.git sdnc +git clone -b $GERRIT_BRANCH --single-branch $CODE_REPO sdnc ./sdnc_vm_init.sh
\ No newline at end of file diff --git a/boot/sdnc_vm_init.sh b/boot/sdnc_vm_init.sh index bc5b0369..f23f122a 100644 --- a/boot/sdnc_vm_init.sh +++ b/boot/sdnc_vm_init.sh @@ -4,6 +4,7 @@ NEXUS_USERNAME=$(cat /opt/config/nexus_username.txt) NEXUS_PASSWD=$(cat /opt/config/nexus_password.txt) export NEXUS_DOCKER_REPO=$(cat /opt/config/nexus_docker_repo.txt) DOCKER_IMAGE_VERSION=$(cat /opt/config/docker_version.txt) +DGBUILDER_IMAGE_VERSION=$(cat /opt/config/dgbuilder_version.txt) export MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1) export DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt) @@ -19,7 +20,7 @@ docker tag $NEXUS_DOCKER_REPO/openecomp/sdnc-image:$DOCKER_IMAGE_VERSION openeco docker pull $NEXUS_DOCKER_REPO/openecomp/admportal-sdnc-image:$DOCKER_IMAGE_VERSION docker tag $NEXUS_DOCKER_REPO/openecomp/admportal-sdnc-image:$DOCKER_IMAGE_VERSION openecomp/admportal-sdnc-image:latest -docker pull $NEXUS_DOCKER_REPO/openecomp/dgbuilder-sdnc-image:$DOCKER_IMAGE_VERSION -docker tag $NEXUS_DOCKER_REPO/openecomp/dgbuilder-sdnc-image:$DOCKER_IMAGE_VERSION openecomp/dgbuilder-sdnc-image:latest +docker pull $NEXUS_DOCKER_REPO/onap/ccsdk-dgbuilder-image:$DGBUILDER_IMAGE_VERSION +docker tag $NEXUS_DOCKER_REPO/onap/ccsdk-dgbuilder-image/$DGBUILDER_IMAGE_VERSION onap/ccsdk-dgbuilder-image:latest /opt/docker/docker-compose up -d diff --git a/boot/aai2_install.sh b/boot/so_install.sh index d2708018..d9a8a646 100644 --- a/boot/aai2_install.sh +++ b/boot/so_install.sh @@ -5,9 +5,10 @@ NEXUS_REPO=$(cat /opt/config/nexus_repo.txt) ARTIFACTS_VERSION=$(cat /opt/config/artifacts_version.txt) DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt) CLOUD_ENV=$(cat /opt/config/cloud_env.txt) +OPENSTACK_API_KEY=$(cat /opt/config/openstack_api_key.txt) GERRIT_BRANCH=$(cat /opt/config/gerrit_branch.txt) -AAI_INSTANCE=$(cat /opt/config/aai_instance.txt) MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1) +CODE_REPO=$(cat /opt/config/remote_repo.txt) # Add host name to /etc/host to avoid warnings in openstack images if [[ $CLOUD_ENV != "rackspace" ]] @@ -48,20 +49,21 @@ then fi # Download dependencies -add-apt-repository -y ppa:openjdk-r/ppa +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list apt-get update -apt-get install -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make +apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make # Download scripts from Nexus -curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/aai2_vm_init.sh -o /opt/aai2_vm_init.sh -curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/aai2_serv.sh -o /opt/aai2_serv.sh -chmod +x /opt/aai2_vm_init.sh -chmod +x /opt/aai2_serv.sh -mv /opt/aai2_serv.sh /etc/init.d -update-rc.d aai2_serv.sh defaults +curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/so_vm_init.sh -o /opt/so_vm_init.sh +curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/so_serv.sh -o /opt/so_serv.sh +chmod +x /opt/so_vm_init.sh +chmod +x /opt/so_serv.sh +mv /opt/so_serv.sh /etc/init.d +update-rc.d so_serv.sh defaults # Download and install docker-engine and docker-compose -echo "deb https://apt.dockerproject.org/repo ubuntu-trusty main" | sudo tee /etc/apt/sources.list.d/docker.list +echo "deb https://apt.dockerproject.org/repo ubuntu-xenial main" | sudo tee /etc/apt/sources.list.d/docker.list apt-get update apt-get install -y linux-image-extra-$(uname -r) linux-image-extra-virtual apt-get install -y --allow-unauthenticated docker-engine @@ -90,21 +92,23 @@ service docker restart echo "nameserver "$DNS_IP_ADDR >> /etc/resolvconf/resolv.conf.d/head resolvconf -u -# Run docker containers +# Clone Gerrit repository cd /opt -git clone -b $GERRIT_BRANCH --single-branch http://gerrit.onap.org/r/aai/test-config +git clone -b $GERRIT_BRANCH --single-branch $CODE_REPO test_lab +SO_ENCRYPTION_KEY=$(cat /opt/test_lab/encryption.key) +echo -n "$OPENSTACK_API_KEY" | openssl aes-128-ecb -e -K $SO_ENCRYPTION_KEY -nosalt | xxd -c 256 -p > /opt/config/api_key.txt -if [[ $AAI_INSTANCE == "aai_instance_1" ]] +# Rename network interface in openstack Ubuntu 16.04 images. Then, reboot the VM to pick up changes +if [[ $CLOUD_ENV != "rackspace" ]] then - mkdir -p /opt/aai/logroot/AAI-RESOURCES - mkdir -p /opt/aai/logroot/AAI-TRAVERSAL - mkdir -p /opt/aai/logroot/AAI-ML - mkdir -p /opt/aai/logroot/AAI-SDB - mkdir -p /opt/aai/logroot/AAI-DRMS - mkdir -p /opt/aai/logroot/AAI-UI - chown -R 999:999 /opt/aai/logroot/AAI-RESOURCES /opt/aai/logroot/AAI-TRAVERSAL - - sleep 300 + sed -i "s/GRUB_CMDLINE_LINUX=.*/GRUB_CMDLINE_LINUX=\"net.ifnames=0 biosdevname=0\"/g" /etc/default/grub + grub-mkconfig -o /boot/grub/grub.cfg + sed -i "s/ens[0-9]*/eth0/g" /etc/network/interfaces.d/*.cfg + sed -i "s/ens[0-9]*/eth0/g" /etc/udev/rules.d/70-persistent-net.rules + echo 'network: {config: disabled}' >> /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg + echo "APT::Periodic::Unattended-Upgrade \"0\";" >> /etc/apt/apt.conf.d/10periodic + reboot fi -./aai2_vm_init.sh
\ No newline at end of file +# Run docker containers. For openstack Ubuntu 16.04 images this will run as a service after the VM has restarted +./so_vm_init.sh diff --git a/boot/aai2_serv.sh b/boot/so_serv.sh index add00097..d324447f 100644 --- a/boot/aai2_serv.sh +++ b/boot/so_serv.sh @@ -10,7 +10,7 @@ ### END INIT INFO dir="/opt" -cmd="./aai2_vm_init.sh" +cmd="./so_vm_init.sh" user="root" name=`basename $0` diff --git a/boot/mso_vm_init.sh b/boot/so_vm_init.sh index e39f6b06..d767a149 100644 --- a/boot/mso_vm_init.sh +++ b/boot/so_vm_init.sh @@ -58,7 +58,7 @@ else EOF fi -# Update the MSO configuration file. +# Update the SO configuration file. read -d '' MSO_CONFIG_UPDATES <<-EOF { "default_attributes": @@ -97,5 +97,5 @@ export MSO_CONFIG_UPDATES cd /opt/test_lab git pull chmod +x deploy.sh -#This script takes in input 2 nexus repos (the first one for the MSO image, the second one for mariadb) +#This script takes in input 2 nexus repos (the first one for the SO image, the second one for mariadb) ./deploy.sh $NEXUS_DOCKER_REPO $NEXUS_USERNAME $NEXUS_PASSWD $NEXUS_DOCKER_REPO $NEXUS_USERNAME $NEXUS_PASSWD diff --git a/boot/uui_vm_init.sh b/boot/uui_vm_init.sh new file mode 100755 index 00000000..ebec9e3d --- /dev/null +++ b/boot/uui_vm_init.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# Establish environment variables +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_IMAGE_VERSION=$(cat /opt/config/uui_docker.txt) + +source /opt/config/onap_ips.txt + +# Refresh images +docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO +docker pull $NEXUS_DOCKER_REPO/onap/uui/ui:$DOCKER_IMAGE_VERSION +docker pull $NEXUS_DOCKER_REPO/onap/uui/server:$DOCKER_IMAGE_VERSION + +docker rm -f uui_ui +docker rm -f uui_server + +# Insert docker run instructions here +docker run -i -t -d --name uui_ui -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/uui/ui:$DOCKER_IMAGE_VERSION +docker run -i -t -d --name uui_server -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/uui/server:$DOCKER_IMAGE_VERSION
\ No newline at end of file diff --git a/boot/vfc_vm_init.sh b/boot/vfc_vm_init.sh new file mode 100755 index 00000000..5badc201 --- /dev/null +++ b/boot/vfc_vm_init.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +# Establish environment variables +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_IMAGE_VERSION=$(cat /opt/config/vfc_docker.txt) + +source /opt/config/onap_ips.txt + +# Refresh images +docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO +docker pull $NEXUS_DOCKER_REPO/onap/vfc/catalog:$DOCKER_IMAGE_VERSION +docker pull $NEXUS_DOCKER_REPO/onap/vfc/emsdriver:$DOCKER_IMAGE_VERSION +docker pull $NEXUS_DOCKER_REPO/onap/vfc/gvnfmdriver:$DOCKER_IMAGE_VERSION +docker pull $NEXUS_DOCKER_REPO/onap/vfc/jujudriver:$DOCKER_IMAGE_VERSION +docker pull $NEXUS_DOCKER_REPO/onap/vfc/nfvo/svnfm/huawei:$DOCKER_IMAGE_VERSION +docker pull $NEXUS_DOCKER_REPO/onap/vfc/nslcm:$DOCKER_IMAGE_VERSION +docker pull $NEXUS_DOCKER_REPO/onap/vfc/resmanagement:$DOCKER_IMAGE_VERSION +docker pull $NEXUS_DOCKER_REPO/onap/vfc/vnflcm:$DOCKER_IMAGE_VERSION +docker pull $NEXUS_DOCKER_REPO/onap/vfc/vnfmgr:$DOCKER_IMAGE_VERSION +docker pull $NEXUS_DOCKER_REPO/onap/vfc/vnfres:$DOCKER_IMAGE_VERSION +docker pull $NEXUS_DOCKER_REPO/onap/vfc/ztesdncdriver:$DOCKER_IMAGE_VERSION +docker pull $NEXUS_DOCKER_REPO/onap/vfc/ztevmanagerdriver:$DOCKER_IMAGE_VERSION + +docker rm -f vfc_catalog +docker rm -f vfc_emsdriver +docker rm -f vfc_gvnfmdriver +docker rm -f vfc_jujudriver +docker rm -f vfc_svnfm_huawei +docker rm -f vfc_nslcm +docker rm -f vfc_resmanagement +docker rm -f vfc_vnflcm +docker rm -f vfc_vnfmgr +docker rm -f vfc_vnfres +docker rm -f vfc_ztesdncdriver +docker rm -f vfc_ztevmanagerdriver + +# Insert docker run instructions here +docker run -i -t -d --name vfc_catalog -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/vfc/catalog:$DOCKER_IMAGE_VERSION +docker run -i -t -d --name vfc_emsdriver -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/vfc/emsdriver:$DOCKER_IMAGE_VERSION +docker run -i -t -d --name vfc_gvnfmdriver -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/vfc/gvnfmdriver:$DOCKER_IMAGE_VERSION +docker run -i -t -d --name vfc_jujudriver -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/vfc/jujudriver:$DOCKER_IMAGE_VERSION +docker run -i -t -d --name vfc_svnfm_huawei -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/vfc/nfvo/svnfm/huawei:$DOCKER_IMAGE_VERSION +docker run -i -t -d --name vfc_nslcm -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/vfc/nslcm:$DOCKER_IMAGE_VERSION +docker run -i -t -d --name vfc_resmanagement -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/vfc/resmanagement:$DOCKER_IMAGE_VERSION +docker run -i -t -d --name vfc_vnflcm -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/vfc/vnflcm:$DOCKER_IMAGE_VERSION +docker run -i -t -d --name vfc_vnfmgr -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/vfc/vnfmgr:$DOCKER_IMAGE_VERSION +docker run -i -t -d --name vfc_vnfres -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/vfc/vnfres:$DOCKER_IMAGE_VERSION +docker run -i -t -d --name vfc_ztesdncdriver -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/vfc/ztesdncdriver:$DOCKER_IMAGE_VERSION +docker run -i -t -d --name vfc_ztevmanagerdriver -e MSB_ADDR=$OPENO_IP:80 $NEXUS_DOCKER_REPO/onap/vfc/ztevmanagerdriver:$DOCKER_IMAGE_VERSION
\ No newline at end of file diff --git a/boot/vid_install.sh b/boot/vid_install.sh index d9f775cc..118995c4 100644 --- a/boot/vid_install.sh +++ b/boot/vid_install.sh @@ -7,6 +7,7 @@ DNS_IP_ADDR=$(cat /opt/config/dns_ip_addr.txt) CLOUD_ENV=$(cat /opt/config/cloud_env.txt) GERRIT_BRANCH=$(cat /opt/config/gerrit_branch.txt) MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1) +CODE_REPO=$(cat /opt/config/remote_repo.txt) # Add host name to /etc/host to avoid warnings in openstack images if [[ $CLOUD_ENV != "rackspace" ]] @@ -47,9 +48,10 @@ then fi # Download dependencies -add-apt-repository -y ppa:openjdk-r/ppa +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list apt-get update -apt-get install -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make +apt-get install --allow-unauthenticated -y apt-transport-https ca-certificates wget openjdk-8-jdk git ntp ntpdate make # Download scripts from Nexus curl -k $NEXUS_REPO/org.onap.demo/boot/$ARTIFACTS_VERSION/vid_vm_init.sh -o /opt/vid_vm_init.sh @@ -91,5 +93,5 @@ resolvconf -u # Clone Gerrit repository and run docker containers cd /opt -git clone -b $GERRIT_BRANCH --single-branch http://gerrit.onap.org/r/vid.git +git clone -b $GERRIT_BRANCH --single-branch $CODE_REPO ./vid_vm_init.sh
\ No newline at end of file diff --git a/boot/vnfsdk_vm_init.sh b/boot/vnfsdk_vm_init.sh new file mode 100755 index 00000000..fa28285f --- /dev/null +++ b/boot/vnfsdk_vm_init.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# Starts docker containers for VNFSDK VNF repository. +# Version for Amsterdam/R1 uses docker-compose. + +# be verbose +set -x + +# Establish environment variables +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) +export MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1) +#DOCKER_IMAGE_VERSION=$(cat /opt/config/docker_version.txt) --> not needed at the moment + +# Refresh configuration and scripts +cd /opt/refrepo +git pull +cd vnfmarket-be/deployment/install + +# Get image names used below from docker-compose environment file +source .env + +# Refresh images +docker login -u $NEXUS_USERNAME -p $NEXUS_PASSWD $NEXUS_DOCKER_REPO +docker pull $NEXUS_DOCKER_REPO/onap/refrepo:${REFREPO_TAG} +docker pull $NEXUS_DOCKER_REPO/onap/refrepo:${POSTGRES_TAG} + +# docker-compose is not in /usr/bin +/opt/docker/docker-compose down +/opt/docker/docker-compose up -d + diff --git a/heat/ONAP/onap_openstack.env b/heat/ONAP/onap_openstack.env index b94bcca2..74a9c8ed 100644 --- a/heat/ONAP/onap_openstack.env +++ b/heat/ONAP/onap_openstack.env @@ -20,6 +20,8 @@ parameters: flavor_xlarge: PUT THE XLARGE FLAVOR NAME HERE + flavor_xxlarge: PUT THE XXLARGE FLAVOR NAME HERE + vm_base_name: vm1 key_name: onap_key @@ -38,10 +40,6 @@ parameters: artifacts_version: 1.1.0-SNAPSHOT - docker_version: 1.1-STAGING-latest - - gerrit_branch: master - openstack_tenant_id: PUT YOUR OPENSTACK PROJECT ID HERE openstack_username: PUT YOUR OPENSTACK USERNAME HERE @@ -67,10 +65,10 @@ parameters: dns_list: PUT THE ADDRESS OF THE EXTERNAL DNS HERE (e.g. a comma-separated list of IP addresses in your /etc/resolv.conf in UNIX-based Operating Systems) external_dns: PUT THE FIRST ADDRESS OF THE EXTERNAL DNS LIST HERE + oam_network_cidr: 10.0.0.0/16 ### Private IP addresses ### - oam_network_cidr: 10.0.0.0/16 aai1_ip_addr: 10.0.1.1 aai2_ip_addr: 10.0.1.2 appc_ip_addr: 10.0.2.1 @@ -81,7 +79,7 @@ parameters: dcae_hdp2_ip_addr: 10.0.4.104 dcae_hdp3_ip_addr: 10.0.4.105 dns_ip_addr: 10.0.100.1 - mso_ip_addr: 10.0.5.1 + so_ip_addr: 10.0.5.1 mr_ip_addr: 10.0.11.1 policy_ip_addr: 10.0.6.1 portal_ip_addr: 10.0.9.1 @@ -89,6 +87,8 @@ parameters: sdc_ip_addr: 10.0.3.1 sdnc_ip_addr: 10.0.7.1 vid_ip_addr: 10.0.8.1 + clamp_ip_addr: 10.0.12.1 + openo_ip_addr: 10.0.14.1 dcae_coll_float_ip: PUT DCAE COLLECTOR FLOATING IP HERE dcae_db_float_ip: PUT DCAE DATABASE FLOATING IP HERE @@ -114,4 +114,62 @@ parameters: gitlab_branch: master - dcae_code_version: 1.1.0
\ No newline at end of file + dcae_code_version: 1.1.0 + + + ################################ + # # + # Docker versions and branches # + # # + ################################ + + aai_branch: master + appc_branch: master + so_branch: master + mr_branch: master + dcae_branch: master + policy_branch: master + portal_branch: master + robot_branch: master + sdc_branch: master + sdnc_branch: master + vid_branch: master + clamp_branch: master + vnfsdk_branch: master + + aai_docker: 1.1-STAGING-latest + appc_docker: 1.1-STAGING-latest + so_docker: 1.1-STAGING-latest + mr_docker: 1.1-STAGING-latest + dcae_docker: 1.1-STAGING-latest + policy_docker: 1.1-STAGING-latest + portal_docker: 1.1-STAGING-latest + robot_docker: 1.1-STAGING-latest + sdc_docker: 1.1-STAGING-latest + sdnc_docker: 1.2-STAGING-latest + vid_docker: 1.1-STAGING-latest + clamp_docker: 1.1-STAGING-latest + msb_docker: latest + mvim_docker: latest + vfc_docker: latest + uui_docker: latest + dgbuilder_docker: 0.1-STAGING-latest + + ##################### + # # + # ONAP repositories # + # # + ##################### + aai_repo: http://gerrit.onap.org/r/aai/test-config + appc_repo: http://gerrit.onap.org/r/appc/deployment.git + dcae_repo: http://gerrit.onap.org/r/dcae/demo/startup/controller.git + mr_repo: http://gerrit.onap.org/r/dcae/demo/startup/message-router.git + so_repo: http://gerrit.onap.org/r/so/docker-config.git + policy_repo: http://gerrit.onap.org/r/policy/docker.git + portal_repo: http://gerrit.onap.org/r/portal.git + robot_repo: http://gerrit.onap.org/r/testsuite/properties.git + sdc_repo: http://gerrit.onap.org/r/sdc.git + sdnc_repo: http://gerrit.onap.org/r/sdnc/oam.git + vid_repo: http://gerrit.onap.org/r/vid.git + clamp_repo: http://gerrit.onap.org/r/clamp.git + vnfsdk_repo: http://gerrit.onap.org/r/vnfsdk/refrepo.git diff --git a/heat/ONAP/onap_openstack.yaml b/heat/ONAP/onap_openstack.yaml index 48339997..8258232e 100644 --- a/heat/ONAP/onap_openstack.yaml +++ b/heat/ONAP/onap_openstack.yaml @@ -68,6 +68,10 @@ parameters: type: string description: Name of the Extra Large Flavor supported by the cloud provider + flavor_xxlarge: + type: string + description: Name of the Extra Extra Large Flavor supported by the cloud provider + vm_base_name: type: string description: Base name of ONAP VMs @@ -100,15 +104,6 @@ parameters: type: string description: Artifacts version of ONAP components - docker_version: - type: string - label: Version number of ONAP docker images - - gerrit_branch: - type: string - label: Gerrit code branch - description: Gerrit branch where to download the code from - dmaap_topic: type: string description: DMaaP Topic name @@ -127,7 +122,7 @@ parameters: openstack_api_key: type: string - description: Openstack API Key + description: Openstack password or API Key horizon_url: type: string @@ -155,102 +150,61 @@ parameters: type: string description: First element of the dns_list for ONAP network - ### Private IP addresses ### oam_network_cidr: type: string description: CIDR of the OAM ONAP network + ### Private IP addresses ### aai1_ip_addr: type: string - description: AAI Instance 1 IP Address - aai2_ip_addr: type: string - description: AAI Instance 2 IP Address - appc_ip_addr: type: string - description: APP-C IP Address - dcae_ip_addr: type: string - description: DCAE IP Address - dcae_coll_ip_addr: type: string - description: DCAE Collector IP Address - dcae_db_ip_addr: type: string - description: DCAE Database IP Address - dcae_hdp1_ip_addr: type: string - description: Hadoop VM1 IP Address - dcae_hdp2_ip_addr: type: string - description: Hadoop VM2 IP Address - dcae_hdp3_ip_addr: type: string - description: Hadoop VM3 IP Address - dns_ip_addr: type: string - description: DNS IP Address - - mso_ip_addr: + so_ip_addr: type: string - description: MSO IP Address - mr_ip_addr: type: string - description: Message Router IP Address - policy_ip_addr: type: string - description: Policy Engine IP Address - portal_ip_addr: type: string - description: Portal IP Address - robot_ip_addr: type: string - description: Robot Framework IP Address - sdc_ip_addr: type: string - description: SDC IP Address - sdnc_ip_addr: type: string - description: SDN-C IP Address - vid_ip_addr: type: string - description: VID IP Address - + clamp_ip_addr: + type: string + openo_ip_addr: + type: string dcae_coll_float_ip: type: string - description: DCAE Collector Floating IP Address - dcae_db_float_ip: type: string - description: DCAE Collector Database Floating IP Address - dcae_hdp1_float_ip: type: string - description: Hadoop VM1 Floating IP Address - dcae_hdp2_float_ip: type: string - description: Hadoop VM2 Floating IP Address - dcae_hdp3_float_ip: type: string - description: Hadoop VM3 Floating IP Address ########################### # # @@ -290,6 +244,107 @@ parameters: type: string description: DCAE Code Version Number + ##################### + # # + # ONAP repositories # + # # + ##################### + + aai_repo: + type: string + appc_repo: + type: string + dcae_repo: + type: string + mr_repo: + type: string + so_repo: + type: string + policy_repo: + type: string + portal_repo: + type: string + robot_repo: + type: string + sdc_repo: + type: string + sdnc_repo: + type: string + vid_repo: + type: string + clamp_repo: + type: string + vnfsdk_repo: + type: string + + ################################ + # # + # Docker versions and branches # + # # + ################################ + + aai_docker: + type: string + appc_docker: + type: string + so_docker: + type: string + mr_docker: + type: string + dcae_docker: + type: string + policy_docker: + type: string + portal_docker: + type: string + robot_docker: + type: string + sdc_docker: + type: string + sdnc_docker: + type: string + vid_docker: + type: string + clamp_docker: + type: string + msb_docker: + type: string + mvim_docker: + type: string + vfc_docker: + type: string + uui_docker: + type: string + dgbuilder_docker: + type: string + + aai_branch: + type: string + appc_branch: + type: string + so_branch: + type: string + mr_branch: + type: string + dcae_branch: + type: string + policy_branch: + type: string + portal_branch: + type: string + robot_branch: + type: string + sdc_branch: + type: string + sdnc_branch: + type: string + vid_branch: + type: string + clamp_branch: + type: string + vnfsdk_branch: + type: string + ############# # # @@ -319,24 +374,24 @@ resources: # ONAP management private network - oam_ecomp: + oam_onap: type: OS::Neutron::Net properties: name: str_replace: - template: oam_ecomp_rand + template: oam_onap_rand params: rand: { get_resource: random-str } - oam_ecomp_subnet: + oam_onap_subnet: type: OS::Neutron::Subnet properties: name: str_replace: - template: oam_ecomp_rand + template: oam_onap_rand params: rand: { get_resource: random-str } - network_id: { get_resource: oam_ecomp } + network_id: { get_resource: oam_onap } cidr: { get_param: oam_network_cidr } dns_nameservers: { get_param: dns_list } @@ -350,15 +405,15 @@ resources: type: OS::Neutron::RouterInterface properties: router_id: { get_resource: router } - subnet_id: { get_resource: oam_ecomp_subnet } + subnet_id: { get_resource: oam_onap_subnet } # DNS Server instantiation dns_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: dns_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: dns_ip_addr }}] dns_floating_ip: type: OS::Neutron::FloatingIP @@ -385,14 +440,14 @@ resources: params: __nexus_repo__: { get_param: nexus_repo } __artifacts_version__: { get_param: artifacts_version } - __oam_network_cidr__: { get_attr: [oam_ecomp_subnet, cidr] } + __oam_network_cidr__: { get_attr: [oam_onap_subnet, cidr] } __dns_ip_addr__: { get_param: dns_ip_addr } __aai1_ip_addr__: { get_param: aai1_ip_addr } __aai2_ip_addr__: { get_param: aai2_ip_addr } __appc_ip_addr__: { get_param: appc_ip_addr } __dcae_ip_addr__: { get_param: dcae_ip_addr } __dcae_coll_ip_addr__: { get_param: dcae_coll_ip_addr } - __mso_ip_addr__: { get_param: mso_ip_addr } + __so_ip_addr__: { get_param: so_ip_addr } __mr_ip_addr__: { get_param: mr_ip_addr } __policy_ip_addr__: { get_param: policy_ip_addr } __portal_ip_addr__: { get_param: portal_ip_addr } @@ -400,6 +455,8 @@ resources: __sdc_ip_addr__: { get_param: sdc_ip_addr } __sdnc_ip_addr__: { get_param: sdnc_ip_addr } __vid_ip_addr__: { get_param: vid_ip_addr } + __clamp_ip_addr__: { get_param: clamp_ip_addr } + __openo_ip_addr__: { get_param: openo_ip_addr } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } template: | @@ -417,7 +474,7 @@ resources: echo "__appc_ip_addr__" > /opt/config/appc_ip_addr.txt echo "__dcae_ip_addr__" > /opt/config/dcae_ip_addr.txt echo "__dcae_coll_ip_addr__" > /opt/config/dcae_coll_ip_addr.txt - echo "__mso_ip_addr__" > /opt/config/mso_ip_addr.txt + echo "__so_ip_addr__" > /opt/config/so_ip_addr.txt echo "__mr_ip_addr__" > /opt/config/mr_ip_addr.txt echo "__policy_ip_addr__" > /opt/config/policy_ip_addr.txt echo "__portal_ip_addr__" > /opt/config/portal_ip_addr.txt @@ -425,6 +482,8 @@ resources: echo "__sdc_ip_addr__" > /opt/config/sdc_ip_addr.txt echo "__sdnc_ip_addr__" > /opt/config/sdnc_ip_addr.txt echo "__vid_ip_addr__" > /opt/config/vid_ip_addr.txt + echo "__clamp_ip_addr__" > /opt/config/clamp_ip_addr.txt + echo "__openo_ip_addr__" > /opt/config/openo_ip_addr.txt echo "__external_dns__" > /opt/config/external_dns.txt # Download and run install script @@ -438,8 +497,8 @@ resources: aai1_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: aai1_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: aai1_ip_addr }}] aai1_floating_ip: type: OS::Neutron::FloatingIP @@ -472,10 +531,11 @@ resources: __dmaap_topic__: { get_param: dmaap_topic } __artifacts_version__: { get_param: artifacts_version } __dns_ip_addr__: { get_param: dns_ip_addr } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: aai_docker } + __gerrit_branch__: { get_param: aai_branch } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __aai_repo__: { get_param: aai_repo } template: | #!/bin/bash @@ -493,19 +553,20 @@ resources: echo "aai_instance_1" > /opt/config/aai_instance.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__aai_repo__" > /opt/config/remote_repo.txt # Download and run install script - curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai2_install.sh -o /opt/aai2_install.sh + curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai_install.sh -o /opt/aai_install.sh cd /opt - chmod +x aai2_install.sh - ./aai2_install.sh + chmod +x aai_install.sh + ./aai_install.sh aai2_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: aai2_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: aai2_ip_addr }}] aai2_floating_ip: type: OS::Neutron::FloatingIP @@ -537,10 +598,11 @@ resources: __dmaap_topic__: { get_param: dmaap_topic } __artifacts_version__: { get_param: artifacts_version } __dns_ip_addr__: { get_param: dns_ip_addr } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: aai_docker } + __gerrit_branch__: { get_param: aai_branch } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __aai_repo__: { get_param: aai_repo } template: | #!/bin/bash @@ -558,40 +620,41 @@ resources: echo "aai_instance_2" > /opt/config/aai_instance.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__aai_repo__" > /opt/config/remote_repo.txt # Download and run install script - curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai2_install.sh -o /opt/aai2_install.sh + curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai_install.sh -o /opt/aai_install.sh cd /opt - chmod +x aai2_install.sh - ./aai2_install.sh + chmod +x aai_install.sh + ./aai_install.sh - # MSO instantiation - mso_private_port: + # SO instantiation + so_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: mso_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: so_ip_addr }}] - mso_floating_ip: + so_floating_ip: type: OS::Neutron::FloatingIP properties: floating_network_id: { get_param: public_net_id } - port_id: { get_resource: mso_private_port } + port_id: { get_resource: so_private_port } - mso_vm: + so_vm: type: OS::Nova::Server properties: image: { get_param: ubuntu_1604_image } flavor: { get_param: flavor_large } name: str_replace: - template: base-mso + template: base-so params: base: { get_param: vm_base_name } key_name: { get_resource: vm_key } networks: - - port: { get_resource: mso_private_port } + - port: { get_resource: so_private_port } user_data_format: RAW user_data: str_replace: @@ -608,10 +671,11 @@ resources: __dmaap_topic__: { get_param: dmaap_topic } __artifacts_version__: { get_param: artifacts_version } __dns_ip_addr__: { get_param: dns_ip_addr } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: so_docker } + __gerrit_branch__: { get_param: so_branch } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __so_repo__: { get_param: so_repo } template: | #!/bin/bash @@ -633,20 +697,21 @@ resources: echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__so_repo__" > /opt/config/remote_repo.txt # Download and run install script - curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/mso_install.sh -o /opt/mso_install.sh + curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/so_install.sh -o /opt/so_install.sh cd /opt - chmod +x mso_install.sh - ./mso_install.sh + chmod +x so_install.sh + ./so_install.sh # Message Router instantiation mrouter_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: mr_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: mr_ip_addr }}] mrouter_floating_ip: type: OS::Neutron::FloatingIP @@ -677,9 +742,10 @@ resources: __nexus_password__: { get_param: nexus_password } __artifacts_version__: { get_param: artifacts_version } __dns_ip_addr__: { get_param: dns_ip_addr } - __gerrit_branch__: { get_param: gerrit_branch } + __gerrit_branch__: { get_param: mr_branch } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __mr_repo__: { get_param: mr_repo } template: | #!/bin/bash @@ -694,6 +760,7 @@ resources: echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__mr_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/mr_install.sh -o /opt/mr_install.sh @@ -706,8 +773,8 @@ resources: robot_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: robot_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: robot_ip_addr }}] robot_floating_ip: type: OS::Neutron::FloatingIP @@ -736,30 +803,34 @@ resources: __nexus_docker_repo__: { get_param: nexus_docker_repo } __nexus_username__: { get_param: nexus_username } __nexus_password__: { get_param: nexus_password } - __network_name__: { get_attr: [oam_ecomp, name] } + __network_name__: { get_attr: [oam_onap, name] } __openstack_username__: { get_param: openstack_username } __openstack_api_key__: { get_param : openstack_api_key } + __openstack_tenant_id__: { get_param: openstack_tenant_id } __artifacts_version__: { get_param: artifacts_version } __openstack_region__: { get_param: openstack_region } __dns_ip_addr__: { get_param: dns_ip_addr } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: mr_docker } + __gerrit_branch__: { get_param: mr_branch } __cloud_env__: { get_param: cloud_env } __keystone_url__: { get_param: keystone_url } __aai1_ip_addr__: { get_param: aai1_ip_addr } __aai2_ip_addr__: { get_param: aai2_ip_addr } __appc_ip_addr__: { get_param: appc_ip_addr } __dcae_ip_addr__: { get_param: dcae_ip_addr } - __mso_ip_addr__: { get_param: mso_ip_addr } + __so_ip_addr__: { get_param: so_ip_addr } __mr_ip_addr__: { get_param: mr_ip_addr } __policy_ip_addr__: { get_param: policy_ip_addr } __portal_ip_addr__: { get_param: portal_ip_addr } __sdc_ip_addr__: { get_param: sdc_ip_addr } __sdnc_ip_addr__: { get_param: sdnc_ip_addr } __vid_ip_addr__: { get_param: vid_ip_addr } + __clamp_ip_addr__: { get_param: clamp_ip_addr } + __openo_ip_addr__: { get_param: openo_ip_addr } __external_dns__: { get_param: external_dns } - __vm_image_name__: { get_param: ubuntu_1404_image} - __vm_flavor__: { get_param: flavor_medium} + __vm_image_name__: { get_param: ubuntu_1404_image } + __vm_flavor__: { get_param: flavor_medium } + __robot_repo__: { get_param: robot_repo } template: | #!/bin/bash @@ -772,6 +843,7 @@ resources: echo "__network_name__" > /opt/config/network.txt echo "__openstack_username__" > /opt/config/openstack_username.txt echo "__openstack_api_key__" > /opt/config/openstack_password.txt + echo "__openstack_tenant_id__" > /opt/config/openstack_tenant_id.txt echo "__openstack_region__" > /opt/config/region.txt echo "__artifacts_version__" > /opt/config/artifacts_version.txt echo "__docker_version__" > /opt/config/docker_version.txt @@ -782,17 +854,20 @@ resources: echo "__aai2_ip_addr__" > /opt/config/aai2_ip_addr.txt echo "__appc_ip_addr__" > /opt/config/appc_ip_addr.txt echo "__dcae_ip_addr__" > /opt/config/dcae_ip_addr.txt - echo "__mso_ip_addr__" > /opt/config/mso_ip_addr.txt + echo "__so_ip_addr__" > /opt/config/so_ip_addr.txt echo "__mr_ip_addr__" > /opt/config/mr_ip_addr.txt echo "__policy_ip_addr__" > /opt/config/policy_ip_addr.txt echo "__portal_ip_addr__" > /opt/config/portal_ip_addr.txt echo "__sdc_ip_addr__" > /opt/config/sdc_ip_addr.txt echo "__sdnc_ip_addr__" > /opt/config/sdnc_ip_addr.txt echo "__vid_ip_addr__" > /opt/config/vid_ip_addr.txt + echo "__clamp_ip_addr__" > /opt/config/clamp_ip_addr.txt + echo "__openo_ip_addr__" > /opt/config/openo_ip_addr.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt echo "__vm_image_name__" > /opt/config/vm_image_name.txt echo "__vm_flavor__" > /opt/config/vm_flavor.txt + echo "__robot_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/robot_install.sh -o /opt/robot_install.sh @@ -805,8 +880,8 @@ resources: vid_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: vid_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: vid_ip_addr }}] vid_floating_ip: type: OS::Neutron::FloatingIP @@ -837,10 +912,11 @@ resources: __nexus_password__: { get_param: nexus_password } __artifacts_version__: { get_param: artifacts_version } __dns_ip_addr__: { get_param: dns_ip_addr } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: vid_docker } + __gerrit_branch__: { get_param: vid_branch } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __vid_repo__: { get_param: vid_repo } template: | #!/bin/bash @@ -856,6 +932,7 @@ resources: echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__vid_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/vid_install.sh -o /opt/vid_install.sh @@ -868,8 +945,8 @@ resources: sdnc_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: sdnc_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: sdnc_ip_addr }}] sdnc_floating_ip: type: OS::Neutron::FloatingIP @@ -900,10 +977,12 @@ resources: __nexus_password__: { get_param: nexus_password } __artifacts_version__: { get_param: artifacts_version } __dns_ip_addr__: { get_param: dns_ip_addr } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: sdnc_docker } + __gerrit_branch__: { get_param: sdnc_branch } + __dgbuilder_docker__: { get_param: dgbuilder_docker } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __sdnc_repo__: { get_param: sdnc_repo } template: | #!/bin/bash @@ -917,8 +996,10 @@ resources: echo "__dns_ip_addr__" > /opt/config/dns_ip_addr.txt echo "__docker_version__" > /opt/config/docker_version.txt echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt + echo "__dgbuilder_docker__" > /opt/config/dgbuilder_version.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__sdnc_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/sdnc_install.sh -o /opt/sdnc_install.sh @@ -931,8 +1012,8 @@ resources: sdc_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: sdc_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: sdc_ip_addr }}] sdc_floating_ip: type: OS::Neutron::FloatingIP @@ -975,10 +1056,11 @@ resources: __dns_ip_addr__: { get_param: dns_ip_addr } __mr_ip_addr__: { get_param: mr_ip_addr } __public_ip__: { get_attr: [sdc_floating_ip, floating_ip_address] } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: sdc_docker } + __gerrit_branch__: { get_param: sdc_branch } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __sdc_repo__: { get_param: sdc_repo } template: | #!/bin/bash @@ -997,20 +1079,21 @@ resources: echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__sdc_repo__" > /opt/config/remote_repo.txt # Download and run install script - curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/asdc_install.sh -o /opt/asdc_install.sh + curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/sdc_install.sh -o /opt/sdc_install.sh cd /opt - chmod +x asdc_install.sh - ./asdc_install.sh + chmod +x sdc_install.sh + ./sdc_install.sh # PORTAL instantiation portal_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: portal_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: portal_ip_addr }}] portal_floating_ip: type: OS::Neutron::FloatingIP @@ -1042,10 +1125,11 @@ resources: __artifacts_version__: { get_param: artifacts_version } __dns_ip_addr__: { get_param: dns_ip_addr } __public_ip__: { get_attr: [portal_floating_ip, floating_ip_address] } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: portal_docker } + __gerrit_branch__: { get_param: portal_branch } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __portal_repo__: { get_param: portal_repo } template: | #!/bin/bash @@ -1062,6 +1146,7 @@ resources: echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__portal_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/portal_install.sh -o /opt/portal_install.sh @@ -1074,8 +1159,8 @@ resources: dcae_c_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: dcae_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: dcae_ip_addr }}] dcae_c_floating_ip: type: OS::Neutron::FloatingIP @@ -1111,7 +1196,7 @@ resources: __dcae_state__: { get_param: dcae_state } __artifacts_version__: { get_param: artifacts_version } __tenant_id__: { get_param: openstack_tenant_id } - __openstack_private_network_name__: { get_attr: [oam_ecomp, name] } + __openstack_private_network_name__: { get_attr: [oam_onap, name] } __openstack_user__: { get_param: openstack_username } __openstack_password__: { get_param: openstack_api_key } __openstack_auth_method__: { get_param: openstack_auth_method } @@ -1122,8 +1207,8 @@ resources: __openstack_region__: { get_param: openstack_region } __horizon_url__: { get_param: horizon_url } __keystone_url__: { get_param: keystone_url } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: dcae_docker } + __gerrit_branch__: { get_param: dcae_branch } __dcae_code_version__: { get_param: dcae_code_version } __cloud_env__: { get_param: cloud_env } __public_net_id__: { get_param: public_net_id } @@ -1147,6 +1232,8 @@ resources: __flavor_medium__: { get_param: flavor_medium } __flavor_large__: { get_param: flavor_large } __flavor_xlarge__: { get_param: flavor_xlarge } + __dcae_repo__: { get_param: dcae_repo } + __mr_repo__: { get_param: mr_repo } template: | #!/bin/bash @@ -1199,6 +1286,8 @@ resources: echo "__flavor_medium__" > /opt/config/flavor_medium.txt echo "__flavor_large__" > /opt/config/flavor_large.txt echo "__flavor_xlarge__" > /opt/config/flavor_xlarge.txt + echo "__dcae_repo__" > /opt/config/remote_repo.txt + echo "__mr_repo__" > /opt/config/mr_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/dcae_install.sh -o /opt/dcae_install.sh @@ -1211,8 +1300,8 @@ resources: policy_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: policy_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: policy_ip_addr }}] policy_floating_ip: type: OS::Neutron::FloatingIP @@ -1244,10 +1333,11 @@ resources: __artifacts_version__: { get_param: artifacts_version } __dns_ip_addr__: { get_param: dns_ip_addr } __public_ip__: { get_attr: [policy_floating_ip, floating_ip_address] } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: policy_docker } + __gerrit_branch__: { get_param: policy_branch } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __policy_repo__: { get_param: policy_repo } template: | #!/bin/bash @@ -1264,6 +1354,7 @@ resources: echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__policy_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/policy_install.sh -o /opt/policy_install.sh @@ -1276,8 +1367,8 @@ resources: appc_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: appc_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: appc_ip_addr }}] appc_floating_ip: type: OS::Neutron::FloatingIP @@ -1309,10 +1400,12 @@ resources: __dmaap_topic__: { get_param: dmaap_topic } __artifacts_version__: { get_param: artifacts_version } __dns_ip_addr__: { get_param: dns_ip_addr } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: appc_docker } + __gerrit_branch__: { get_param: appc_branch } + __dgbuilder_docker__: { get_param: dgbuilder_docker } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __appc_repo__: { get_param: appc_repo } template: | #!/bin/bash @@ -1327,11 +1420,195 @@ resources: echo "__dmaap_topic__" > /opt/config/dmaap_topic.txt echo "__docker_version__" > /opt/config/docker_version.txt echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt + echo "__dgbuilder_docker__" > /opt/config/dgbuilder_version.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__appc_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/appc_install.sh -o /opt/appc_install.sh cd /opt chmod +x appc_install.sh - ./appc_install.sh
\ No newline at end of file + ./appc_install.sh + + + # CLAMP instantiation + clamp_private_port: + type: OS::Neutron::Port + properties: + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: clamp_ip_addr }}] + + clamp_floating_ip: + type: OS::Neutron::FloatingIP + properties: + floating_network_id: { get_param: public_net_id } + port_id: { get_resource: clamp_private_port } + + clamp_vm: + type: OS::Nova::Server + properties: + image: { get_param: ubuntu_1604_image } + flavor: { get_param: flavor_medium } + name: + str_replace: + template: base-clamp + params: + base: { get_param: vm_base_name } + key_name: { get_resource: vm_key } + networks: + - port: { get_resource: clamp_private_port } + user_data_format: RAW + user_data: + str_replace: + params: + __nexus_repo__: { get_param: nexus_repo } + __nexus_docker_repo__: { get_param: nexus_docker_repo } + __nexus_username__: { get_param: nexus_username } + __nexus_password__: { get_param: nexus_password } + __openstack_username__: { get_param: openstack_username } + __openstack_tenant_id__: { get_param: openstack_tenant_id } + __openstack_api_key__: { get_param: openstack_api_key } + __openstack_region__: { get_param: openstack_region } + __keystone_url__: { get_param: keystone_url } + __dmaap_topic__: { get_param: dmaap_topic } + __artifacts_version__: { get_param: artifacts_version } + __dns_ip_addr__: { get_param: dns_ip_addr } + __docker_version__: { get_param: clamp_docker } + __gerrit_branch__: { get_param: clamp_branch } + __cloud_env__: { get_param: cloud_env } + __external_dns__: { get_param: external_dns } + __clamp_repo__: { get_param: clamp_repo } + template: | + #!/bin/bash + + # Create configuration files + mkdir -p /opt/config + echo "__nexus_repo__" > /opt/config/nexus_repo.txt + echo "__nexus_docker_repo__" > /opt/config/nexus_docker_repo.txt + echo "__nexus_username__" > /opt/config/nexus_username.txt + echo "__nexus_password__" > /opt/config/nexus_password.txt + echo "__artifacts_version__" > /opt/config/artifacts_version.txt + echo "__dns_ip_addr__" > /opt/config/dns_ip_addr.txt + echo "__dmaap_topic__" > /opt/config/dmaap_topic.txt + echo "__openstack_username__" > /opt/config/openstack_username.txt + echo "__openstack_tenant_id__" > /opt/config/tenant_id.txt + echo "__openstack_api_key__" > /opt/config/openstack_api_key.txt + echo "__openstack_region__" > /opt/config/openstack_region.txt + echo "__keystone_url__" > /opt/config/keystone.txt + echo "__docker_version__" > /opt/config/docker_version.txt + echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt + echo "__cloud_env__" > /opt/config/cloud_env.txt + echo "__external_dns__" > /opt/config/external_dns.txt + echo "__clamp_repo__" > /opt/config/remote_repo.txt + + # Download and run install script + curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/clamp_install.sh -o /opt/clamp_install.sh + cd /opt + chmod +x clamp_install.sh + ./clamp_install.sh + + + # OPEN-O VM instantiation + openo_private_port: + type: OS::Neutron::Port + properties: + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: openo_ip_addr }}] + + openo_floating_ip: + type: OS::Neutron::FloatingIP + properties: + floating_network_id: { get_param: public_net_id } + port_id: { get_resource: openo_private_port } + + openo_vm: + type: OS::Nova::Server + properties: + image: { get_param: ubuntu_1604_image } + flavor: { get_param: flavor_xxlarge } + name: + str_replace: + template: base-openo-server + params: + base: { get_param: vm_base_name } + key_name: { get_resource: vm_key } + networks: + - port: { get_resource: openo_private_port } + user_data_format: RAW + user_data: + str_replace: + params: + __nexus_repo__: { get_param: nexus_repo } + __nexus_docker_repo__: { get_param: nexus_docker_repo } + __nexus_username__: { get_param: nexus_username } + __nexus_password__: { get_param: nexus_password } + __artifacts_version__: { get_param: artifacts_version } + __dns_ip_addr__: { get_param: dns_ip_addr } + __oam_network_cidr__: { get_param: oam_network_cidr } + __aai1_ip_addr__: { get_param: aai1_ip_addr } + __aai2_ip_addr__: { get_param: aai2_ip_addr } + __appc_ip_addr__: { get_param: appc_ip_addr } + __dcae_ip_addr__: { get_param: dcae_ip_addr } + __dcae_coll_ip_addr__: { get_param: dcae_coll_ip_addr } + __so_ip_addr__: { get_param: so_ip_addr } + __mr_ip_addr__: { get_param: mr_ip_addr } + __policy_ip_addr__: { get_param: policy_ip_addr } + __portal_ip_addr__: { get_param: portal_ip_addr } + __robot_ip_addr__: { get_param: robot_ip_addr } + __sdc_ip_addr__: { get_param: sdc_ip_addr } + __sdnc_ip_addr__: { get_param: sdnc_ip_addr } + __vid_ip_addr__: { get_param: vid_ip_addr } + __clamp_ip_addr__: { get_param: clamp_ip_addr } + __openo_ip_addr__: { get_param: openo_ip_addr } + __cloud_env__: { get_param: cloud_env } + __external_dns__: { get_param: external_dns } + __vnfsdk_branch__: { get_param: vnfsdk_branch } + __msb_docker__: { get_param: msb_docker } + __mvim_docker__: { get_param: mvim_docker } + __vfc_docker__: { get_param: vfc_docker } + __uui_docker__: { get_param: uui_docker } + __vnfsdk_repo__: { get_param: vnfsdk_repo } + template: | + #!/bin/bash + + # Create configuration files + mkdir -p /opt/config + echo "__nexus_repo__" > /opt/config/nexus_repo.txt + echo "__nexus_docker_repo__" > /opt/config/nexus_docker_repo.txt + echo "__nexus_username__" > /opt/config/nexus_username.txt + echo "__nexus_password__" > /opt/config/nexus_password.txt + echo "__cloud_env__" > /opt/config/cloud_env.txt + echo "__artifacts_version__" > /opt/config/artifacts_version.txt + echo "__oam_network_cidr__" > /opt/config/oam_network_cidr.txt + echo "__dns_ip_addr__" > /opt/config/dns_ip_addr.txt + echo "__external_dns__" > /opt/config/external_dns.txt + echo "__vnfsdk_branch__" > /opt/config/vnfsdk_branch.txt + echo "__msb_docker__" > /opt/config/msb_docker.txt + echo "__mvim_docker__" > /opt/config/mvim_docker.txt + echo "__vfc_docker__" > /opt/config/vfc_docker.txt + echo "__uui_docker__" > /opt/config/uui_docker.txt + echo "__vnfsdk_repo__" > /opt/config/vnfsdk_repo.txt + + # Create env file with the IP address of all ONAP components + echo "export AAI_IP1=__aai1_ip_addr__" >> /opt/config/onap_ips.txt + echo "export AAI_IP2=__aai2_ip_addr__" >> /opt/config/onap_ips.txt + echo "export APPC_IP=__appc_ip_addr__" >> /opt/config/onap_ips.txt + echo "export DCAE_IP=__dcae_ip_addr__" >> /opt/config/onap_ips.txt + echo "export DCAE_COLL_IP=__dcae_coll_ip_addr__" >> /opt/config/onap_ips.txt + echo "export SO_IP=__so_ip_addr__" >> /opt/config/onap_ips.txt + echo "export MR_IP=__mr_ip_addr__" >> /opt/config/onap_ips.txt + echo "export POLICY_IP=__policy_ip_addr__" >> /opt/config/onap_ips.txt + echo "export PORTAL_IP=__portal_ip_addr__" >> /opt/config/onap_ips.txt + echo "export ROBOT_IP=__robot_ip_addr__" >> /opt/config/onap_ips.txt + echo "export SDC_IP=__sdc_ip_addr__" >> /opt/config/onap_ips.txt + echo "export SDNC_IP=__sdnc_ip_addr__" >> /opt/config/onap_ips.txt + echo "export VID_IP=__vid_ip_addr__" >> /opt/config/onap_ips.txt + echo "export CLAMP_IP=__clamp_ip_addr__" >> /opt/config/onap_ips.txt + echo "export OPENO_IP=__openo_ip_addr__" >> /opt/config/onap_ips.txt + + # Download and run install script + curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/openo_install.sh -o /opt/openo_install.sh + cd /opt + chmod +x openo_install.sh + ./openo_install.sh
\ No newline at end of file diff --git a/heat/ONAP/onap_openstack_float.env b/heat/ONAP/onap_openstack_float.env index 4f3a42df..4b7e9f4f 100644 --- a/heat/ONAP/onap_openstack_float.env +++ b/heat/ONAP/onap_openstack_float.env @@ -24,6 +24,8 @@ parameters: flavor_xlarge: PUT THE XLARGE FLAVOR NAME HERE + flavor_xxlarge: PUT THE XXLARGE FLAVOR NAME HERE + vm_base_name: vm1 key_name: onap_key @@ -42,10 +44,6 @@ parameters: artifacts_version: 1.1.0-SNAPSHOT - docker_version: 1.1-STAGING-latest - - gerrit_branch: master - openstack_tenant_id: PUT YOUR OPENSTACK PROJECT ID HERE openstack_username: PUT YOUR OPENSTACK USERNAME HERE @@ -71,6 +69,7 @@ parameters: dns_list: PUT THE ADDRESS OF THE EXTERNAL DNS HERE (e.g. a comma-separated list of IP addresses in your /etc/resolv.conf in UNIX-based Operating Systems) external_dns: PUT THE FIRST ADDRESS OF THE EXTERNAL DNS LIST HERE + oam_network_cidr: 10.0.0.0/16 ### Floating IP addresses ### @@ -84,7 +83,7 @@ parameters: dcae_hdp2_float_ip: PUT DCAE HADOOP VM2 FLOATING IP HERE dcae_hdp3_float_ip: PUT DCAE HADOOP VM3 FLOATING IP HERE dns_float_ip: PUT DNS FLOATING IP HERE - mso_float_ip: PUT MSO FLOATING IP HERE + so_float_ip: PUT SO FLOATING IP HERE mr_float_ip: PUT MESSAGE ROUTER FLOATING IP HERE policy_float_ip: PUT POLICY FLOATING IP HERE portal_float_ip: PUT PORTAL FLOATING IP HERE @@ -92,11 +91,11 @@ parameters: sdc_float_ip: PUT SDC FLOATING IP HERE sdnc_float_ip: PUT SDN-C FLOATING IP HERE vid_float_ip: PUT VID FLOATING IP HERE - + clamp_float_ip: PUT CLAMP FLOATING IP HERE + openo_float_ip: PUT OPEN-O FLOATING IP HERE ### Private IP addresses ### - oam_network_cidr: 10.0.0.0/16 aai1_ip_addr: 10.0.1.1 aai2_ip_addr: 10.0.1.2 appc_ip_addr: 10.0.2.1 @@ -107,7 +106,7 @@ parameters: dcae_hdp2_ip_addr: 10.0.4.104 dcae_hdp3_ip_addr: 10.0.4.105 dns_ip_addr: 10.0.100.1 - mso_ip_addr: 10.0.5.1 + so_ip_addr: 10.0.5.1 mr_ip_addr: 10.0.11.1 policy_ip_addr: 10.0.6.1 portal_ip_addr: 10.0.9.1 @@ -115,6 +114,8 @@ parameters: sdc_ip_addr: 10.0.3.1 sdnc_ip_addr: 10.0.7.1 vid_ip_addr: 10.0.8.1 + clamp_ip_addr: 10.0.12.1 + openo_ip_addr: 10.0.14.1 ########################### # # @@ -135,3 +136,61 @@ parameters: gitlab_branch: master dcae_code_version: 1.1.0 + + + ################################ + # # + # Docker versions and branches # + # # + ################################ + + aai_branch: master + appc_branch: master + so_branch: master + mr_branch: master + dcae_branch: master + policy_branch: master + portal_branch: master + robot_branch: master + sdc_branch: master + sdnc_branch: master + vid_branch: master + clamp_branch: master + vnfsdk_branch: master + + aai_docker: 1.1-STAGING-latest + appc_docker: 1.1-STAGING-latest + so_docker: 1.1-STAGING-latest + mr_docker: 1.1-STAGING-latest + dcae_docker: 1.1-STAGING-latest + policy_docker: 1.1-STAGING-latest + portal_docker: 1.1-STAGING-latest + robot_docker: 1.1-STAGING-latest + sdc_docker: 1.1-STAGING-latest + sdnc_docker: 1.2-STAGING-latest + vid_docker: 1.1-STAGING-latest + clamp_docker: 1.1-STAGING-latest + msb_docker: latest + mvim_docker: latest + vfc_docker: latest + uui_docker: latest + dgbuilder_docker: 0.1-STAGING-latest + + ##################### + # # + # ONAP repositories # + # # + ##################### + aai_repo: http://gerrit.onap.org/r/aai/test-config + appc_repo: http://gerrit.onap.org/r/appc/deployment.git + dcae_repo: http://gerrit.onap.org/r/dcae/demo/startup/controller.git + mr_repo: http://gerrit.onap.org/r/dcae/demo/startup/message-router.git + so_repo: http://gerrit.onap.org/r/so/docker-config.git + policy_repo: http://gerrit.onap.org/r/policy/docker.git + portal_repo: http://gerrit.onap.org/r/portal.git + robot_repo: http://gerrit.onap.org/r/testsuite/properties.git + sdc_repo: http://gerrit.onap.org/r/sdc.git + sdnc_repo: http://gerrit.onap.org/r/sdnc/oam.git + vid_repo: http://gerrit.onap.org/r/vid.git + clamp_repo: http://gerrit.onap.org/r/clamp.git + vnfsdk_repo: http://gerrit.onap.org/r/vnfsdk/refrepo.git diff --git a/heat/ONAP/onap_openstack_float.yaml b/heat/ONAP/onap_openstack_float.yaml index af49a776..438be715 100644 --- a/heat/ONAP/onap_openstack_float.yaml +++ b/heat/ONAP/onap_openstack_float.yaml @@ -44,14 +44,6 @@ parameters: type: string description: Public network for floating IP address allocation - public_subnet_id: - type: string - description: Public network subnet id - - router_gateway_ip: - type: string - description: Public network gateway IP address - ubuntu_1404_image: type: string description: Name of the Ubuntu 14.04 image @@ -76,6 +68,10 @@ parameters: type: string description: Name of the Extra Large Flavor supported by the cloud provider + flavor_xxlarge: + type: string + description: Name of the Extra Extra Large Flavor supported by the cloud provider + vm_base_name: type: string description: Base name of ONAP VMs @@ -108,15 +104,6 @@ parameters: type: string description: Artifacts version of ONAP components - docker_version: - type: string - label: Version number of ONAP docker images - - gerrit_branch: - type: string - label: Gerrit code branch - description: Gerrit branch where to download the code from - dmaap_topic: type: string description: DMaaP Topic name @@ -135,7 +122,7 @@ parameters: openstack_api_key: type: string - description: Openstack API Key + description: Openstack password or API Key horizon_url: type: string @@ -149,6 +136,7 @@ parameters: type: string description: Cloud Provider Name + ###################### # # # Network parameters # @@ -163,155 +151,94 @@ parameters: type: string description: First element of the dns_list for ONAP network + oam_network_cidr: + type: string + description: CIDR of the OAM ONAP network + ### Floating IP addresses ### aai1_float_ip: type: string - description: AAI Instance 1 Floating IP Address - aai2_float_ip: type: string - description: AAI Instance 2 Floating IP Address - appc_float_ip: type: string - description: APP-C Floating IP Address - dcae_float_ip: type: string - description: DCAE Floating IP Address - dcae_coll_float_ip: type: string - description: DCAE Collector Floating IP Address - dcae_db_float_ip: type: string - description: DCAE Collector Database Floating IP Address - dcae_hdp1_float_ip: type: string - description: Hadoop VM1 Floating IP Address - dcae_hdp2_float_ip: type: string - description: Hadoop VM2 Floating IP Address - dcae_hdp3_float_ip: type: string - description: Hadoop VM3 Floating IP Address - dns_float_ip: type: string - description: DNS Floating IP Address - - mso_float_ip: + so_float_ip: type: string - description: MSO Floating IP Address - mr_float_ip: type: string - description: Message Router Floating IP Address - policy_float_ip: type: string - description: Policy Engine Floating IP Address - portal_float_ip: type: string - description: Portal Floating IP Address - robot_float_ip: type: string - description: Robot Framework Floating IP Address - sdc_float_ip: type: string - description: SDC Floating IP Address - sdnc_float_ip: type: string - description: SDN-C Floating IP Address - vid_float_ip: type: string - description: VID Floating IP Address - - ### Private IP addresses ### - oam_network_cidr: + clamp_float_ip: type: string - description: CIDR of the OAM ONAP network + openo_float_ip: + type: string + + ### Private IP addresses ### aai1_ip_addr: type: string - description: AAI Instance 1 IP Address - aai2_ip_addr: type: string - description: AAI Instance 2 IP Address - appc_ip_addr: type: string - description: APP-C IP Address - dcae_ip_addr: type: string - description: DCAE IP Address - dcae_coll_ip_addr: type: string - description: DCAE Collector IP Address - dcae_db_ip_addr: type: string - description: DCAE Database IP Address - dcae_hdp1_ip_addr: type: string - description: Hadoop VM1 IP Address - dcae_hdp2_ip_addr: type: string - description: Hadoop VM2 IP Address - dcae_hdp3_ip_addr: type: string - description: Hadoop VM3 IP Address - dns_ip_addr: type: string - description: DNS IP Address - - mso_ip_addr: + so_ip_addr: type: string - description: MSO IP Address - mr_ip_addr: type: string - description: Message Router IP Address - policy_ip_addr: type: string - description: Policy Engine IP Address - portal_ip_addr: type: string - description: Portal IP Address - robot_ip_addr: type: string - description: Robot Framework IP Address - sdc_ip_addr: type: string - description: SDC IP Address - sdnc_ip_addr: type: string - description: SDN-C IP Address - vid_ip_addr: type: string - description: VID IP Address + clamp_ip_addr: + type: string + openo_ip_addr: + type: string ########################### @@ -352,6 +279,107 @@ parameters: type: string description: DCAE Code Version Number + ##################### + # # + # ONAP repositories # + # # + ##################### + + aai_repo: + type: string + appc_repo: + type: string + dcae_repo: + type: string + mr_repo: + type: string + so_repo: + type: string + policy_repo: + type: string + portal_repo: + type: string + robot_repo: + type: string + sdc_repo: + type: string + sdnc_repo: + type: string + vid_repo: + type: string + clamp_repo: + type: string + vnfsdk_repo: + type: string + + ################################ + # # + # Docker versions and branches # + # # + ################################ + + aai_docker: + type: string + appc_docker: + type: string + so_docker: + type: string + mr_docker: + type: string + dcae_docker: + type: string + policy_docker: + type: string + portal_docker: + type: string + robot_docker: + type: string + sdc_docker: + type: string + sdnc_docker: + type: string + vid_docker: + type: string + clamp_docker: + type: string + msb_docker: + type: string + mvim_docker: + type: string + vfc_docker: + type: string + uui_docker: + type: string + dgbuilder_docker: + type: string + + aai_branch: + type: string + appc_branch: + type: string + so_branch: + type: string + mr_branch: + type: string + dcae_branch: + type: string + policy_branch: + type: string + portal_branch: + type: string + robot_branch: + type: string + sdc_branch: + type: string + sdnc_branch: + type: string + vid_branch: + type: string + clamp_branch: + type: string + vnfsdk_branch: + type: string + ############# # # @@ -381,24 +409,24 @@ resources: # ONAP management private network - oam_ecomp: + oam_onap: type: OS::Neutron::Net properties: name: str_replace: - template: oam_ecomp_rand + template: oam_onap_rand params: rand: { get_resource: random-str } - oam_ecomp_subnet: + oam_onap_subnet: type: OS::Neutron::Subnet properties: name: str_replace: - template: oam_ecomp_rand + template: oam_onap_rand params: rand: { get_resource: random-str } - network_id: { get_resource: oam_ecomp } + network_id: { get_resource: oam_onap } cidr: { get_param: oam_network_cidr } dns_nameservers: { get_param: dns_list } @@ -415,15 +443,15 @@ resources: type: OS::Neutron::RouterInterface properties: router_id: { get_resource: router } - subnet_id: { get_resource: oam_ecomp_subnet } + subnet_id: { get_resource: oam_onap_subnet } # DNS Server instantiation dns_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: dns_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: dns_ip_addr }}] dns_floating_ip: type: OS::Neutron::FloatingIP @@ -451,14 +479,14 @@ resources: params: __nexus_repo__: { get_param: nexus_repo } __artifacts_version__: { get_param: artifacts_version } - __oam_network_cidr__: { get_attr: [oam_ecomp_subnet, cidr] } + __oam_network_cidr__: { get_attr: [oam_onap_subnet, cidr] } __dns_ip_addr__: { get_param: dns_ip_addr } __aai1_ip_addr__: { get_param: aai1_ip_addr } __aai2_ip_addr__: { get_param: aai2_ip_addr } __appc_ip_addr__: { get_param: appc_ip_addr } __dcae_ip_addr__: { get_param: dcae_ip_addr } __dcae_coll_ip_addr__: { get_param: dcae_coll_ip_addr } - __mso_ip_addr__: { get_param: mso_ip_addr } + __so_ip_addr__: { get_param: so_ip_addr } __mr_ip_addr__: { get_param: mr_ip_addr } __policy_ip_addr__: { get_param: policy_ip_addr } __portal_ip_addr__: { get_param: portal_ip_addr } @@ -466,6 +494,8 @@ resources: __sdc_ip_addr__: { get_param: sdc_ip_addr } __sdnc_ip_addr__: { get_param: sdnc_ip_addr } __vid_ip_addr__: { get_param: vid_ip_addr } + __clamp_ip_addr__: { get_param: clamp_ip_addr } + __openo_ip_addr__: { get_param: openo_ip_addr } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } template: | @@ -483,7 +513,7 @@ resources: echo "__appc_ip_addr__" > /opt/config/appc_ip_addr.txt echo "__dcae_ip_addr__" > /opt/config/dcae_ip_addr.txt echo "__dcae_coll_ip_addr__" > /opt/config/dcae_coll_ip_addr.txt - echo "__mso_ip_addr__" > /opt/config/mso_ip_addr.txt + echo "__so_ip_addr__" > /opt/config/so_ip_addr.txt echo "__mr_ip_addr__" > /opt/config/mr_ip_addr.txt echo "__policy_ip_addr__" > /opt/config/policy_ip_addr.txt echo "__portal_ip_addr__" > /opt/config/portal_ip_addr.txt @@ -491,6 +521,8 @@ resources: echo "__sdc_ip_addr__" > /opt/config/sdc_ip_addr.txt echo "__sdnc_ip_addr__" > /opt/config/sdnc_ip_addr.txt echo "__vid_ip_addr__" > /opt/config/vid_ip_addr.txt + echo "__clamp_ip_addr__" > /opt/config/clamp_ip_addr.txt + echo "__openo_ip_addr__" > /opt/config/openo_ip_addr.txt echo "__external_dns__" > /opt/config/external_dns.txt # Download and run install script @@ -504,8 +536,8 @@ resources: aai1_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: aai1_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: aai1_ip_addr }}] aai1_floating_ip: type: OS::Neutron::FloatingIP @@ -539,10 +571,11 @@ resources: __dmaap_topic__: { get_param: dmaap_topic } __artifacts_version__: { get_param: artifacts_version } __dns_ip_addr__: { get_param: dns_ip_addr } - __docker_version__: { get_param: docker_version } + __docker_version__: { get_param: aai_docker } __cloud_env__: { get_param: cloud_env } - __gerrit_branch__: { get_param: gerrit_branch } + __gerrit_branch__: { get_param: aai_branch } __external_dns__: { get_param: external_dns } + __aai_repo__: { get_param: aai_repo } template: | #!/bin/bash @@ -560,19 +593,20 @@ resources: echo "aai_instance_1" > /opt/config/aai_instance.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__aai_repo__" > /opt/config/remote_repo.txt # Download and run install script - curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai2_install.sh -o /opt/aai2_install.sh + curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai_install.sh -o /opt/aai_install.sh cd /opt - chmod +x aai2_install.sh - ./aai2_install.sh + chmod +x aai_install.sh + ./aai_install.sh aai2_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: aai2_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: aai2_ip_addr }}] aai2_floating_ip: type: OS::Neutron::FloatingIP @@ -605,10 +639,11 @@ resources: __dmaap_topic__: { get_param: dmaap_topic } __artifacts_version__: { get_param: artifacts_version } __dns_ip_addr__: { get_param: dns_ip_addr } - __docker_version__: { get_param: docker_version } + __docker_version__: { get_param: aai_docker } __cloud_env__: { get_param: cloud_env } - __gerrit_branch__: { get_param: gerrit_branch } + __gerrit_branch__: { get_param: aai_branch } __external_dns__: { get_param: external_dns } + __aai_repo__: { get_param: aai_repo } template: | #!/bin/bash @@ -626,41 +661,42 @@ resources: echo "aai_instance_2" > /opt/config/aai_instance.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__aai_repo__" > /opt/config/remote_repo.txt # Download and run install script - curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai2_install.sh -o /opt/aai2_install.sh + curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai_install.sh -o /opt/aai_install.sh cd /opt - chmod +x aai2_install.sh - ./aai2_install.sh + chmod +x aai_install.sh + ./aai_install.sh - # MSO instantiation - mso_private_port: + # SO instantiation + so_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: mso_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: so_ip_addr }}] - mso_floating_ip: + so_floating_ip: type: OS::Neutron::FloatingIP properties: floating_network_id: { get_param: public_net_id } - port_id: { get_resource: mso_private_port } - floating_ip_address: { get_param: mso_float_ip } + port_id: { get_resource: so_private_port } + floating_ip_address: { get_param: so_float_ip } - mso_vm: + so_vm: type: OS::Nova::Server properties: image: { get_param: ubuntu_1604_image } flavor: { get_param: flavor_large } name: str_replace: - template: base-mso + template: base-so params: base: { get_param: vm_base_name } key_name: { get_resource: vm_key } networks: - - port: { get_resource: mso_private_port } + - port: { get_resource: so_private_port } user_data_format: RAW user_data: str_replace: @@ -677,10 +713,11 @@ resources: __dmaap_topic__: { get_param: dmaap_topic } __artifacts_version__: { get_param: artifacts_version } __dns_ip_addr__: { get_param: dns_ip_addr } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: so_docker } + __gerrit_branch__: { get_param: so_branch } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __so_repo__: { get_param: so_repo } template: | #!/bin/bash @@ -702,20 +739,21 @@ resources: echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__so_repo__" > /opt/config/remote_repo.txt # Download and run install script - curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/mso_install.sh -o /opt/mso_install.sh + curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/so_install.sh -o /opt/so_install.sh cd /opt - chmod +x mso_install.sh - ./mso_install.sh + chmod +x so_install.sh + ./so_install.sh # Message Router instantiation mrouter_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: mr_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: mr_ip_addr }}] mrouter_floating_ip: type: OS::Neutron::FloatingIP @@ -747,9 +785,10 @@ resources: __nexus_password__: { get_param: nexus_password } __artifacts_version__: { get_param: artifacts_version } __dns_ip_addr__: { get_param: dns_ip_addr } - __gerrit_branch__: { get_param: gerrit_branch } + __gerrit_branch__: { get_param: mr_branch } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __mr_repo__: { get_param: mr_repo } template: | #!/bin/bash @@ -764,6 +803,7 @@ resources: echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__mr_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/mr_install.sh -o /opt/mr_install.sh @@ -776,8 +816,8 @@ resources: robot_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: robot_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: robot_ip_addr }}] robot_floating_ip: type: OS::Neutron::FloatingIP @@ -807,30 +847,34 @@ resources: __nexus_docker_repo__: { get_param: nexus_docker_repo } __nexus_username__: { get_param: nexus_username } __nexus_password__: { get_param: nexus_password } - __network_name__: { get_attr: [oam_ecomp, name] } + __network_name__: { get_attr: [oam_onap, name] } __openstack_username__: { get_param: openstack_username } __openstack_api_key__: { get_param : openstack_api_key } + __openstack_tenant_id__: { get_param: openstack_tenant_id } __artifacts_version__: { get_param: artifacts_version } __openstack_region__: { get_param: openstack_region } __dns_ip_addr__: { get_param: dns_ip_addr } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: robot_docker } + __gerrit_branch__: { get_param: robot_branch } __keystone_url__: { get_param: keystone_url } __aai1_ip_addr__: { get_param: aai1_ip_addr } __aai2_ip_addr__: { get_param: aai2_ip_addr } __appc_ip_addr__: { get_param: appc_ip_addr } __dcae_ip_addr__: { get_param: dcae_ip_addr } - __mso_ip_addr__: { get_param: mso_ip_addr } + __so_ip_addr__: { get_param: so_ip_addr } __mr_ip_addr__: { get_param: mr_ip_addr } __policy_ip_addr__: { get_param: policy_ip_addr } __portal_ip_addr__: { get_param: portal_ip_addr } __sdc_ip_addr__: { get_param: sdc_ip_addr } __sdnc_ip_addr__: { get_param: sdnc_ip_addr } __vid_ip_addr__: { get_param: vid_ip_addr } + __clamp_ip_addr__: { get_param: clamp_ip_addr } + __openo_ip_addr__: { get_param: openo_ip_addr } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } - __vm_image_name__: { get_param: ubuntu_1404_image} - __vm_flavor__: { get_param: flavor_medium} + __vm_image_name__: { get_param: ubuntu_1404_image } + __vm_flavor__: { get_param: flavor_medium } + __robot_repo__: { get_param: robot_repo } template: | #!/bin/bash @@ -843,6 +887,7 @@ resources: echo "__network_name__" > /opt/config/network.txt echo "__openstack_username__" > /opt/config/openstack_username.txt echo "__openstack_api_key__" > /opt/config/openstack_password.txt + echo "__openstack_tenant_id__" > /opt/config/openstack_tenant_id.txt echo "__openstack_region__" > /opt/config/region.txt echo "__artifacts_version__" > /opt/config/artifacts_version.txt echo "__docker_version__" > /opt/config/docker_version.txt @@ -853,17 +898,20 @@ resources: echo "__aai2_ip_addr__" > /opt/config/aai2_ip_addr.txt echo "__appc_ip_addr__" > /opt/config/appc_ip_addr.txt echo "__dcae_ip_addr__" > /opt/config/dcae_ip_addr.txt - echo "__mso_ip_addr__" > /opt/config/mso_ip_addr.txt + echo "__so_ip_addr__" > /opt/config/so_ip_addr.txt echo "__mr_ip_addr__" > /opt/config/mr_ip_addr.txt echo "__policy_ip_addr__" > /opt/config/policy_ip_addr.txt echo "__portal_ip_addr__" > /opt/config/portal_ip_addr.txt echo "__sdc_ip_addr__" > /opt/config/sdc_ip_addr.txt echo "__sdnc_ip_addr__" > /opt/config/sdnc_ip_addr.txt echo "__vid_ip_addr__" > /opt/config/vid_ip_addr.txt + echo "__clamp_ip_addr__" > /opt/config/clamp_ip_addr.txt + echo "__openo_ip_addr__" > /opt/config/openo_ip_addr.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt echo "__vm_image_name__" > /opt/config/vm_image_name.txt echo "__vm_flavor__" > /opt/config/vm_flavor.txt + echo "__robot_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/robot_install.sh -o /opt/robot_install.sh @@ -876,8 +924,8 @@ resources: vid_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: vid_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: vid_ip_addr }}] vid_floating_ip: type: OS::Neutron::FloatingIP @@ -909,10 +957,11 @@ resources: __nexus_password__: { get_param: nexus_password } __artifacts_version__: { get_param: artifacts_version } __dns_ip_addr__: { get_param: dns_ip_addr } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: vid_docker } + __gerrit_branch__: { get_param: vid_branch } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __vid_repo__: { get_param: vid_repo } template: | #!/bin/bash @@ -928,6 +977,7 @@ resources: echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__vid_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/vid_install.sh -o /opt/vid_install.sh @@ -940,8 +990,8 @@ resources: sdnc_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: sdnc_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: sdnc_ip_addr }}] sdnc_floating_ip: type: OS::Neutron::FloatingIP @@ -973,10 +1023,12 @@ resources: __nexus_password__: { get_param: nexus_password } __artifacts_version__: { get_param: artifacts_version } __dns_ip_addr__: { get_param: dns_ip_addr } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: sdnc_docker } + __gerrit_branch__: { get_param: sdnc_branch } + __dgbuilder_docker__: { get_param: dgbuilder_docker } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __sdnc_repo__: { get_param: sdnc_repo } template: | #!/bin/bash @@ -990,8 +1042,10 @@ resources: echo "__dns_ip_addr__" > /opt/config/dns_ip_addr.txt echo "__docker_version__" > /opt/config/docker_version.txt echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt + echo "__dgbuilder_docker__" > /opt/config/dgbuilder_version.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__sdnc_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/sdnc_install.sh -o /opt/sdnc_install.sh @@ -1004,8 +1058,8 @@ resources: sdc_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: sdc_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: sdc_ip_addr }}] sdc_floating_ip: type: OS::Neutron::FloatingIP @@ -1049,10 +1103,11 @@ resources: __dns_ip_addr__: { get_param: dns_ip_addr } __mr_ip_addr__: { get_param: mr_ip_addr } __public_ip__: { get_attr: [sdc_floating_ip, floating_ip_address] } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: sdc_docker } + __gerrit_branch__: { get_param: sdc_branch } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __sdc_repo__: { get_param: sdc_repo } template: | #!/bin/bash @@ -1071,20 +1126,21 @@ resources: echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__sdc_repo__" > /opt/config/remote_repo.txt # Download and run install script - curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/asdc_install.sh -o /opt/asdc_install.sh + curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/sdc_install.sh -o /opt/sdc_install.sh cd /opt - chmod +x asdc_install.sh - ./asdc_install.sh + chmod +x sdc_install.sh + ./sdc_install.sh # PORTAL instantiation portal_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: portal_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: portal_ip_addr }}] portal_floating_ip: type: OS::Neutron::FloatingIP @@ -1117,10 +1173,11 @@ resources: __artifacts_version__: { get_param: artifacts_version } __dns_ip_addr__: { get_param: dns_ip_addr } __public_ip__: { get_attr: [portal_floating_ip, floating_ip_address] } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: portal_docker } + __gerrit_branch__: { get_param: portal_branch } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __portal_repo__: { get_param: portal_repo } template: | #!/bin/bash @@ -1137,6 +1194,7 @@ resources: echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__portal_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/portal_install.sh -o /opt/portal_install.sh @@ -1149,8 +1207,8 @@ resources: dcae_c_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: dcae_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: dcae_ip_addr }}] dcae_c_floating_ip: type: OS::Neutron::FloatingIP @@ -1187,7 +1245,7 @@ resources: __dcae_state__: { get_param: dcae_state } __artifacts_version__: { get_param: artifacts_version } __tenant_id__: { get_param: openstack_tenant_id } - __openstack_private_network_name__: { get_attr: [oam_ecomp, name] } + __openstack_private_network_name__: { get_attr: [oam_onap, name] } __openstack_user__: { get_param: openstack_username } __openstack_password__: { get_param: openstack_api_key } __openstack_auth_method__: { get_param: openstack_auth_method } @@ -1198,8 +1256,8 @@ resources: __openstack_region__: { get_param: openstack_region } __horizon_url__: { get_param: horizon_url } __keystone_url__: { get_param: keystone_url } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: dcae_docker } + __gerrit_branch__: { get_param: dcae_branch } __dcae_code_version__: { get_param: dcae_code_version } __cloud_env__: { get_param: cloud_env } __public_net_id__: { get_param: public_net_id } @@ -1223,6 +1281,8 @@ resources: __flavor_medium__: { get_param: flavor_medium } __flavor_large__: { get_param: flavor_large } __flavor_xlarge__: { get_param: flavor_xlarge } + __dcae_repo__: { get_param: dcae_repo } + __mr_repo__: { get_param: mr_repo } template: | #!/bin/bash @@ -1275,6 +1335,8 @@ resources: echo "__flavor_medium__" > /opt/config/flavor_medium.txt echo "__flavor_large__" > /opt/config/flavor_large.txt echo "__flavor_xlarge__" > /opt/config/flavor_xlarge.txt + echo "__dcae_repo__" > /opt/config/remote_repo.txt + echo "__mr_repo__" > /opt/config/mr_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/dcae_install.sh -o /opt/dcae_install.sh @@ -1287,8 +1349,8 @@ resources: policy_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: policy_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: policy_ip_addr }}] policy_floating_ip: type: OS::Neutron::FloatingIP @@ -1321,10 +1383,11 @@ resources: __artifacts_version__: { get_param: artifacts_version } __dns_ip_addr__: { get_param: dns_ip_addr } __public_ip__: { get_attr: [policy_floating_ip, floating_ip_address] } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: policy_docker } + __gerrit_branch__: { get_param: policy_branch } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __policy_repo__: { get_param: policy_repo } template: | #!/bin/bash @@ -1341,6 +1404,7 @@ resources: echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__policy_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/policy_install.sh -o /opt/policy_install.sh @@ -1353,8 +1417,8 @@ resources: appc_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: appc_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: appc_ip_addr }}] appc_floating_ip: type: OS::Neutron::FloatingIP @@ -1387,10 +1451,12 @@ resources: __dmaap_topic__: { get_param: dmaap_topic } __artifacts_version__: { get_param: artifacts_version } __dns_ip_addr__: { get_param: dns_ip_addr } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: appc_docker } + __gerrit_branch__: { get_param: appc_branch } + __dgbuilder_docker__: { get_param: dgbuilder_docker } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __appc_repo__: { get_param: appc_repo } template: | #!/bin/bash @@ -1405,11 +1471,197 @@ resources: echo "__dmaap_topic__" > /opt/config/dmaap_topic.txt echo "__docker_version__" > /opt/config/docker_version.txt echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt + echo "__dgbuilder_docker__" > /opt/config/dgbuilder_version.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__appc_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/appc_install.sh -o /opt/appc_install.sh cd /opt chmod +x appc_install.sh - ./appc_install.sh
\ No newline at end of file + ./appc_install.sh + + + # CLAMP instantiation + clamp_private_port: + type: OS::Neutron::Port + properties: + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: clamp_ip_addr }}] + + clamp_floating_ip: + type: OS::Neutron::FloatingIP + properties: + floating_network_id: { get_param: public_net_id } + port_id: { get_resource: clamp_private_port } + floating_ip_address: { get_param: clamp_float_ip } + + clamp_vm: + type: OS::Nova::Server + properties: + image: { get_param: ubuntu_1604_image } + flavor: { get_param: flavor_medium } + name: + str_replace: + template: base-clamp + params: + base: { get_param: vm_base_name } + key_name: { get_resource: vm_key } + networks: + - port: { get_resource: clamp_private_port } + user_data_format: RAW + user_data: + str_replace: + params: + __nexus_repo__: { get_param: nexus_repo } + __nexus_docker_repo__: { get_param: nexus_docker_repo } + __nexus_username__: { get_param: nexus_username } + __nexus_password__: { get_param: nexus_password } + __openstack_username__: { get_param: openstack_username } + __openstack_tenant_id__: { get_param: openstack_tenant_id } + __openstack_api_key__: { get_param: openstack_api_key } + __openstack_region__: { get_param: openstack_region } + __keystone_url__: { get_param: keystone_url } + __dmaap_topic__: { get_param: dmaap_topic } + __artifacts_version__: { get_param: artifacts_version } + __dns_ip_addr__: { get_param: dns_ip_addr } + __docker_version__: { get_param: clamp_docker } + __gerrit_branch__: { get_param: clamp_branch } + __cloud_env__: { get_param: cloud_env } + __external_dns__: { get_param: external_dns } + __clamp_repo__: { get_param: clamp_repo } + template: | + #!/bin/bash + + # Create configuration files + mkdir -p /opt/config + echo "__nexus_repo__" > /opt/config/nexus_repo.txt + echo "__nexus_docker_repo__" > /opt/config/nexus_docker_repo.txt + echo "__nexus_username__" > /opt/config/nexus_username.txt + echo "__nexus_password__" > /opt/config/nexus_password.txt + echo "__artifacts_version__" > /opt/config/artifacts_version.txt + echo "__dns_ip_addr__" > /opt/config/dns_ip_addr.txt + echo "__dmaap_topic__" > /opt/config/dmaap_topic.txt + echo "__openstack_username__" > /opt/config/openstack_username.txt + echo "__openstack_tenant_id__" > /opt/config/tenant_id.txt + echo "__openstack_api_key__" > /opt/config/openstack_api_key.txt + echo "__openstack_region__" > /opt/config/openstack_region.txt + echo "__keystone_url__" > /opt/config/keystone.txt + echo "__docker_version__" > /opt/config/docker_version.txt + echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt + echo "__cloud_env__" > /opt/config/cloud_env.txt + echo "__external_dns__" > /opt/config/external_dns.txt + echo "__clamp_repo__" > /opt/config/remote_repo.txt + + # Download and run install script + curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/clamp_install.sh -o /opt/clamp_install.sh + cd /opt + chmod +x clamp_install.sh + ./clamp_install.sh + + + # OPEN-O VM instantiation + openo_private_port: + type: OS::Neutron::Port + properties: + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: openo_ip_addr }}] + + openo_floating_ip: + type: OS::Neutron::FloatingIP + properties: + floating_network_id: { get_param: public_net_id } + port_id: { get_resource: openo_private_port } + floating_ip_address: { get_param: onap_float_ip } + + openo_vm: + type: OS::Nova::Server + properties: + image: { get_param: ubuntu_1604_image } + flavor: { get_param: flavor_xxlarge } + name: + str_replace: + template: base-openo-server + params: + base: { get_param: vm_base_name } + key_name: { get_resource: vm_key } + networks: + - port: { get_resource: openo_private_port } + user_data_format: RAW + user_data: + str_replace: + params: + __nexus_repo__: { get_param: nexus_repo } + __nexus_docker_repo__: { get_param: nexus_docker_repo } + __nexus_username__: { get_param: nexus_username } + __nexus_password__: { get_param: nexus_password } + __artifacts_version__: { get_param: artifacts_version } + __dns_ip_addr__: { get_param: dns_ip_addr } + __oam_network_cidr__: { get_param: oam_network_cidr } + __aai1_ip_addr__: { get_param: aai1_ip_addr } + __aai2_ip_addr__: { get_param: aai2_ip_addr } + __appc_ip_addr__: { get_param: appc_ip_addr } + __dcae_ip_addr__: { get_param: dcae_ip_addr } + __dcae_coll_ip_addr__: { get_param: dcae_coll_ip_addr } + __so_ip_addr__: { get_param: so_ip_addr } + __mr_ip_addr__: { get_param: mr_ip_addr } + __policy_ip_addr__: { get_param: policy_ip_addr } + __portal_ip_addr__: { get_param: portal_ip_addr } + __robot_ip_addr__: { get_param: robot_ip_addr } + __sdc_ip_addr__: { get_param: sdc_ip_addr } + __sdnc_ip_addr__: { get_param: sdnc_ip_addr } + __vid_ip_addr__: { get_param: vid_ip_addr } + __clamp_ip_addr__: { get_param: clamp_ip_addr } + __openo_ip_addr__: { get_param: openo_ip_addr } + __cloud_env__: { get_param: cloud_env } + __external_dns__: { get_param: external_dns } + __vnfsdk_branch__: { get_param: vnfsdk_branch } + __msb_docker__: { get_param: msb_docker } + __mvim_docker__: { get_param: mvim_docker } + __vfc_docker__: { get_param: vfc_docker } + __uui_docker__: { get_param: uui_docker } + __vnfsdk_repo__: { get_param: vnfsdk_repo } + template: | + #!/bin/bash + + # Create configuration files + mkdir -p /opt/config + echo "__nexus_repo__" > /opt/config/nexus_repo.txt + echo "__nexus_docker_repo__" > /opt/config/nexus_docker_repo.txt + echo "__nexus_username__" > /opt/config/nexus_username.txt + echo "__nexus_password__" > /opt/config/nexus_password.txt + echo "__cloud_env__" > /opt/config/cloud_env.txt + echo "__artifacts_version__" > /opt/config/artifacts_version.txt + echo "__oam_network_cidr__" > /opt/config/oam_network_cidr.txt + echo "__dns_ip_addr__" > /opt/config/dns_ip_addr.txt + echo "__external_dns__" > /opt/config/external_dns.txt + echo "__vnfsdk_branch__" > /opt/config/vnfsdk_branch.txt + echo "__msb_docker__" > /opt/config/msb_docker.txt + echo "__mvim_docker__" > /opt/config/mvim_docker.txt + echo "__vfc_docker__" > /opt/config/vfc_docker.txt + echo "__uui_docker__" > /opt/config/uui_docker.txt + echo "__vnfsdk_repo__" > /opt/config/vnfsdk_repo.txt + + # Create env file with the IP address of all ONAP components + echo "export AAI_IP1=__aai1_ip_addr__" >> /opt/config/onap_ips.txt + echo "export AAI_IP2=__aai2_ip_addr__" >> /opt/config/onap_ips.txt + echo "export APPC_IP=__appc_ip_addr__" >> /opt/config/onap_ips.txt + echo "export DCAE_IP=__dcae_ip_addr__" >> /opt/config/onap_ips.txt + echo "export DCAE_COLL_IP=__dcae_coll_ip_addr__" >> /opt/config/onap_ips.txt + echo "export SO_IP=__so_ip_addr__" >> /opt/config/onap_ips.txt + echo "export MR_IP=__mr_ip_addr__" >> /opt/config/onap_ips.txt + echo "export POLICY_IP=__policy_ip_addr__" >> /opt/config/onap_ips.txt + echo "export PORTAL_IP=__portal_ip_addr__" >> /opt/config/onap_ips.txt + echo "export ROBOT_IP=__robot_ip_addr__" >> /opt/config/onap_ips.txt + echo "export SDC_IP=__sdc_ip_addr__" >> /opt/config/onap_ips.txt + echo "export SDNC_IP=__sdnc_ip_addr__" >> /opt/config/onap_ips.txt + echo "export VID_IP=__vid_ip_addr__" >> /opt/config/onap_ips.txt + echo "export CLAMP_IP=__clamp_ip_addr__" >> /opt/config/onap_ips.txt + echo "export OPENO_IP=__openo_ip_addr__" >> /opt/config/onap_ips.txt + + # Download and run install script + curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/openo_install.sh -o /opt/openo_install.sh + cd /opt + chmod +x openo_install.sh + ./openo_install.sh
\ No newline at end of file diff --git a/heat/ONAP/onap_openstack_nofloat.env b/heat/ONAP/onap_openstack_nofloat.env index dad932be..086eced4 100644 --- a/heat/ONAP/onap_openstack_nofloat.env +++ b/heat/ONAP/onap_openstack_nofloat.env @@ -20,6 +20,8 @@ parameters: flavor_xlarge: PUT THE XLARGE FLAVOR NAME HERE + flavor_xlarge: PUT THE XLARGE FLAVOR NAME HERE + vm_base_name: vm1 key_name: onap_key @@ -38,10 +40,6 @@ parameters: artifacts_version: 1.1.0-SNAPSHOT - docker_version: 1.1-STAGING-latest - - gerrit_branch: master - openstack_tenant_id: PUT YOUR OPENSTACK PROJECT ID HERE openstack_username: PUT YOUR OPENSTACK USERNAME HERE @@ -66,8 +64,10 @@ parameters: ###################### external_dns: PUT THE ADDRESS OF THE EXTERNAL DNS HERE - oam_network_cidr: 10.0.0.0/16 + + ### Private IP addresses ### + aai1_ip_addr: 10.0.1.1 aai2_ip_addr: 10.0.1.2 appc_ip_addr: 10.0.2.1 @@ -78,7 +78,7 @@ parameters: dcae_hdp2_ip_addr: 10.0.4.104 dcae_hdp3_ip_addr: 10.0.4.105 dns_ip_addr: 10.0.100.1 - mso_ip_addr: 10.0.5.1 + so_ip_addr: 10.0.5.1 mr_ip_addr: 10.0.11.1 policy_ip_addr: 10.0.6.1 portal_ip_addr: 10.0.9.1 @@ -86,7 +86,8 @@ parameters: sdc_ip_addr: 10.0.3.1 sdnc_ip_addr: 10.0.7.1 vid_ip_addr: 10.0.8.1 - + clamp_ip_addr: 10.0.12.1 + openo_ip_addr: 10.0.14.1 ########################### # # @@ -108,3 +109,60 @@ parameters: dcae_code_version: 1.1.0 + + ################################ + # # + # Docker versions and branches # + # # + ################################ + + aai_branch: master + appc_branch: master + so_branch: master + mr_branch: master + dcae_branch: master + policy_branch: master + portal_branch: master + robot_branch: master + sdc_branch: master + sdnc_branch: master + vid_branch: master + clamp_branch: master + vnfsdk_branch: master + + aai_docker: 1.1-STAGING-latest + appc_docker: 1.1-STAGING-latest + so_docker: 1.1-STAGING-latest + mr_docker: 1.1-STAGING-latest + dcae_docker: 1.1-STAGING-latest + policy_docker: 1.1-STAGING-latest + portal_docker: 1.1-STAGING-latest + robot_docker: 1.1-STAGING-latest + sdc_docker: 1.1-STAGING-latest + sdnc_docker: 1.2-STAGING-latest + vid_docker: 1.1-STAGING-latest + clamp_docker: 1.1-STAGING-latest + msb_docker: latest + mvim_docker: latest + vfc_docker: latest + uui_docker: latest + dgbuilder_docker: 0.1-STAGING-latest + + ##################### + # # + # ONAP repositories # + # # + ##################### + aai_repo: http://gerrit.onap.org/r/aai/test-config + appc_repo: http://gerrit.onap.org/r/appc/deployment.git + dcae_repo: http://gerrit.onap.org/r/dcae/demo/startup/controller.git + mr_repo: http://gerrit.onap.org/r/dcae/demo/startup/message-router.git + so_repo: http://gerrit.onap.org/r/so/docker-config.git + policy_repo: http://gerrit.onap.org/r/policy/docker.git + portal_repo: http://gerrit.onap.org/r/portal.git + robot_repo: http://gerrit.onap.org/r/testsuite/properties.git + sdc_repo: http://gerrit.onap.org/r/sdc.git + sdnc_repo: http://gerrit.onap.org/r/sdnc/oam.git + vid_repo: http://gerrit.onap.org/r/vid.git + clamp_repo: http://gerrit.onap.org/r/clamp.git + vnfsdk_repo: http://gerrit.onap.org/r/vnfsdk/refrepo.git diff --git a/heat/ONAP/onap_openstack_nofloat.yaml b/heat/ONAP/onap_openstack_nofloat.yaml index b505d725..0d857ce2 100644 --- a/heat/ONAP/onap_openstack_nofloat.yaml +++ b/heat/ONAP/onap_openstack_nofloat.yaml @@ -68,6 +68,10 @@ parameters: type: string description: Name of the Extra Large Flavor supported by the cloud provider + flavor_xxlarge: + type: string + description: Name of the Extra Extra Large Flavor supported by the cloud provider + vm_base_name: type: string description: Base name of ONAP VMs @@ -100,15 +104,6 @@ parameters: type: string description: Artifacts version of ONAP components - docker_version: - type: string - label: Version number of ONAP docker images - - gerrit_branch: - type: string - label: Gerrit code branch - description: Gerrit branch where to download the code from - dmaap_topic: type: string description: DMaaP Topic name @@ -127,7 +122,7 @@ parameters: openstack_api_key: type: string - description: Openstack API Key + description: Openstack password or API Key horizon_url: type: string @@ -151,83 +146,52 @@ parameters: type: string description: External DNS for OAM ONAP network - ### Private IP addresses ### oam_network_cidr: type: string description: CIDR of the OAM ONAP network + ### Private IP addresses ### + aai1_ip_addr: type: string - description: AAI Instance 1 IP Address - aai2_ip_addr: type: string - description: AAI Instance 2 IP Address - appc_ip_addr: type: string - description: APP-C IP Address - dcae_ip_addr: type: string - description: DCAE IP Address - dcae_coll_ip_addr: type: string - description: DCAE Collector IP Address - dcae_db_ip_addr: type: string - description: DCAE Database IP Address - dcae_hdp1_ip_addr: type: string - description: Hadoop VM1 IP Address - dcae_hdp2_ip_addr: type: string - description: Hadoop VM2 IP Address - dcae_hdp3_ip_addr: type: string - description: Hadoop VM3 IP Address - dns_ip_addr: type: string - description: DNS IP Address - - mso_ip_addr: + so_ip_addr: type: string - description: MSO IP Address - mr_ip_addr: type: string - description: Message Router IP Address - policy_ip_addr: type: string - description: Policy Engine IP Address - portal_ip_addr: type: string - description: Portal IP Address - robot_ip_addr: type: string - description: Robot Framework IP Address - sdc_ip_addr: type: string - description: SDC IP Address - sdnc_ip_addr: type: string - description: SDN-C IP Address - vid_ip_addr: type: string - description: VID IP Address - + clamp_ip_addr: + type: string + openo_ip_addr: + type: string ########################### # # @@ -267,6 +231,107 @@ parameters: type: string description: DCAE Code Version Number + ##################### + # # + # ONAP repositories # + # # + ##################### + + aai_repo: + type: string + appc_repo: + type: string + dcae_repo: + type: string + mr_repo: + type: string + so_repo: + type: string + policy_repo: + type: string + portal_repo: + type: string + robot_repo: + type: string + sdc_repo: + type: string + sdnc_repo: + type: string + vid_repo: + type: string + clamp_repo: + type: string + vnfsdk_repo: + type: string + + ################################ + # # + # Docker versions and branches # + # # + ################################ + + aai_docker: + type: string + appc_docker: + type: string + so_docker: + type: string + mr_docker: + type: string + dcae_docker: + type: string + policy_docker: + type: string + portal_docker: + type: string + robot_docker: + type: string + sdc_docker: + type: string + sdnc_docker: + type: string + vid_docker: + type: string + clamp_docker: + type: string + msb_docker: + type: string + mvim_docker: + type: string + vfc_docker: + type: string + uui_docker: + type: string + dgbuilder_docker: + type: string + + aai_branch: + type: string + appc_branch: + type: string + so_branch: + type: string + mr_branch: + type: string + dcae_branch: + type: string + policy_branch: + type: string + portal_branch: + type: string + robot_branch: + type: string + sdc_branch: + type: string + sdnc_branch: + type: string + vid_branch: + type: string + clamp_branch: + type: string + vnfsdk_branch: + type: string + ############# # # @@ -296,24 +361,24 @@ resources: # ONAP management private network - oam_ecomp: + oam_onap: type: OS::Neutron::Net properties: name: str_replace: - template: oam_ecomp_rand + template: oam_onap_rand params: rand: { get_resource: random-str } - oam_ecomp_subnet: + oam_onap_subnet: type: OS::Neutron::Subnet properties: name: str_replace: - template: oam_ecomp_rand + template: oam_onap_rand params: rand: { get_resource: random-str } - network_id: { get_resource: oam_ecomp } + network_id: { get_resource: oam_onap } cidr: { get_param: oam_network_cidr } @@ -321,8 +386,8 @@ resources: dns_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: dns_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: dns_ip_addr }}] dns_vm: type: OS::Nova::Server @@ -351,7 +416,7 @@ resources: __appc_ip_addr__: { get_param: appc_ip_addr } __dcae_ip_addr__: { get_param: dcae_ip_addr } __dcae_coll_ip_addr__: { get_param: dcae_coll_ip_addr } - __mso_ip_addr__: { get_param: mso_ip_addr } + __so_ip_addr__: { get_param: so_ip_addr } __mr_ip_addr__: { get_param: mr_ip_addr } __policy_ip_addr__: { get_param: policy_ip_addr } __portal_ip_addr__: { get_param: portal_ip_addr } @@ -359,6 +424,8 @@ resources: __sdc_ip_addr__: { get_param: sdc_ip_addr } __sdnc_ip_addr__: { get_param: sdnc_ip_addr } __vid_ip_addr__: { get_param: vid_ip_addr } + __clamp_ip_addr__: { get_param: clamp_ip_addr } + __openo_ip_addr__: { get_param: openo_ip_addr } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } template: | @@ -376,7 +443,7 @@ resources: echo "__appc_ip_addr__" > /opt/config/appc_ip_addr.txt echo "__dcae_ip_addr__" > /opt/config/dcae_ip_addr.txt echo "__dcae_coll_ip_addr__" > /opt/config/dcae_coll_ip_addr.txt - echo "__mso_ip_addr__" > /opt/config/mso_ip_addr.txt + echo "__so_ip_addr__" > /opt/config/so_ip_addr.txt echo "__mr_ip_addr__" > /opt/config/mr_ip_addr.txt echo "__policy_ip_addr__" > /opt/config/policy_ip_addr.txt echo "__portal_ip_addr__" > /opt/config/portal_ip_addr.txt @@ -384,6 +451,8 @@ resources: echo "__sdc_ip_addr__" > /opt/config/sdc_ip_addr.txt echo "__sdnc_ip_addr__" > /opt/config/sdnc_ip_addr.txt echo "__vid_ip_addr__" > /opt/config/vid_ip_addr.txt + echo "__clamp_ip_addr__" > /opt/config/clamp_ip_addr.txt + echo "__openo_ip_addr__" > /opt/config/openo_ip_addr.txt echo "__external_dns__" > /opt/config/external_dns.txt # Download and run install script @@ -397,8 +466,8 @@ resources: aai1_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: aai1_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: aai1_ip_addr }}] aai1_vm: type: OS::Nova::Server @@ -428,10 +497,11 @@ resources: __dns_ip_addr__: { get_param: dns_ip_addr } __aai_ip_addr__: { get_param: aai1_ip_addr } __oam_network_cidr__: { get_param: oam_network_cidr } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: aai_docker } + __gerrit_branch__: { get_param: aai_branch } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __aai_repo__: { get_param: aai_repo } template: | #!/bin/bash @@ -451,19 +521,20 @@ resources: echo "aai_instance_1" > /opt/config/aai_instance.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__aai_repo__" > /opt/config/remote_repo.txt # Download and run install script - curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai2_install.sh -o /opt/aai2_install.sh + curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai_install.sh -o /opt/aai_install.sh cd /opt - chmod +x aai2_install.sh - ./aai2_install.sh + chmod +x aai_install.sh + ./aai_install.sh aai2_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: aai2_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: aai2_ip_addr }}] aai2_vm: type: OS::Nova::Server @@ -492,10 +563,11 @@ resources: __dns_ip_addr__: { get_param: dns_ip_addr } __aai_ip_addr__: { get_param: aai2_ip_addr } __oam_network_cidr__: { get_param: oam_network_cidr } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: aai_docker } + __gerrit_branch__: { get_param: aai_branch } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __aai_repo__: { get_param: aai_repo } template: | #!/bin/bash @@ -515,35 +587,36 @@ resources: echo "aai_instance_2" > /opt/config/aai_instance.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__aai_repo__" > /opt/config/remote_repo.txt # Download and run install script - curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai2_install.sh -o /opt/aai2_install.sh + curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai_install.sh -o /opt/aai_install.sh cd /opt - chmod +x aai2_install.sh - ./aai2_install.sh + chmod +x aai_install.sh + ./aai_install.sh - # MSO instantiation - mso_private_port: + # SO instantiation + so_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: mso_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: so_ip_addr }}] - mso_vm: + so_vm: type: OS::Nova::Server properties: image: { get_param: ubuntu_1604_image } flavor: { get_param: flavor_large } name: str_replace: - template: base-mso + template: base-so params: base: { get_param: vm_base_name } key_name: { get_resource: vm_key } networks: - network: { get_param: public_net_id } - - port: { get_resource: mso_private_port } + - port: { get_resource: so_private_port } user_data_format: RAW user_data: str_replace: @@ -560,12 +633,13 @@ resources: __dmaap_topic__: { get_param: dmaap_topic } __artifacts_version__: { get_param: artifacts_version } __dns_ip_addr__: { get_param: dns_ip_addr } - __mso_ip_addr__: { get_param: mso_ip_addr } + __so_ip_addr__: { get_param: so_ip_addr } __oam_network_cidr__: { get_param: oam_network_cidr } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: so_docker } + __gerrit_branch__: { get_param: so_branch } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __so_repo__: { get_param: so_repo } template: | #!/bin/bash @@ -576,7 +650,7 @@ resources: echo "__nexus_username__" > /opt/config/nexus_username.txt echo "__nexus_password__" > /opt/config/nexus_password.txt echo "__artifacts_version__" > /opt/config/artifacts_version.txt - echo "__mso_ip_addr__" > /opt/config/local_ip_addr.txt + echo "__so_ip_addr__" > /opt/config/local_ip_addr.txt echo "__dns_ip_addr__" > /opt/config/dns_ip_addr.txt echo "__oam_network_cidr__" > /opt/config/oam_network_cidr.txt echo "__dmaap_topic__" > /opt/config/dmaap_topic.txt @@ -589,20 +663,21 @@ resources: echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__so_repo__" > /opt/config/remote_repo.txt # Download and run install script - curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/mso_install.sh -o /opt/mso_install.sh + curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/so_install.sh -o /opt/so_install.sh cd /opt - chmod +x mso_install.sh - ./mso_install.sh + chmod +x so_install.sh + ./so_install.sh # Message Router instantiation mrouter_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: mr_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: mr_ip_addr }}] mrouter_vm: type: OS::Nova::Server @@ -630,9 +705,10 @@ resources: __mr_ip_addr__: { get_param: mr_ip_addr } __dns_ip_addr__: { get_param: dns_ip_addr } __oam_network_cidr__: { get_param: oam_network_cidr } - __gerrit_branch__: { get_param: gerrit_branch } + __gerrit_branch__: { get_param: mr_gerrit } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __mr_repo__: { get_param: mr_repo } template: | #!/bin/bash @@ -649,6 +725,7 @@ resources: echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__mr_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/mr_install.sh -o /opt/mr_install.sh @@ -661,8 +738,8 @@ resources: robot_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: robot_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: robot_ip_addr }}] robot_vm: type: OS::Nova::Server @@ -686,32 +763,36 @@ resources: __nexus_docker_repo__: { get_param: nexus_docker_repo } __nexus_username__: { get_param: nexus_username } __nexus_password__: { get_param: nexus_password } - __network_name__: { get_attr: [oam_ecomp, name] } + __network_name__: { get_attr: [oam_onap, name] } __openstack_username__: { get_param: openstack_username } __openstack_api_key__: { get_param : openstack_api_key } + __openstack_tenant_id__: { get_param: openstack_tenant_id } __artifacts_version__: { get_param: artifacts_version } __openstack_region__: { get_param: openstack_region } __robot_ip_addr__: { get_param: robot_ip_addr } __dns_ip_addr__: { get_param: dns_ip_addr } __oam_network_cidr__: { get_param: oam_network_cidr } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: robot_docker } + __gerrit_branch__: { get_param: robot_branch } __keystone_url__: { get_param: keystone_url } __aai1_ip_addr__: { get_param: aai1_ip_addr } __aai2_ip_addr__: { get_param: aai2_ip_addr } __appc_ip_addr__: { get_param: appc_ip_addr } __dcae_ip_addr__: { get_param: dcae_ip_addr } - __mso_ip_addr__: { get_param: mso_ip_addr } + __so_ip_addr__: { get_param: so_ip_addr } __mr_ip_addr__: { get_param: mr_ip_addr } __policy_ip_addr__: { get_param: policy_ip_addr } __portal_ip_addr__: { get_param: portal_ip_addr } __sdc_ip_addr__: { get_param: sdc_ip_addr } __sdnc_ip_addr__: { get_param: sdnc_ip_addr } __vid_ip_addr__: { get_param: vid_ip_addr } + __clamp_ip_addr__: { get_param: clamp_ip_addr } + __openo_ip_addr__: { get_param: openo_ip_addr } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } - __vm_image_name__: { get_param: ubuntu_1404_image} - __vm_flavor__: { get_param: flavor_medium} + __vm_image_name__: { get_param: ubuntu_1404_image } + __vm_flavor__: { get_param: flavor_medium } + __robot_repo__: { get_param: robot_repo } template: | #!/bin/bash @@ -724,6 +805,7 @@ resources: echo "__network_name__" > /opt/config/network.txt echo "__openstack_username__" > /opt/config/openstack_username.txt echo "__openstack_api_key__" > /opt/config/openstack_password.txt + echo "__openstack_tenant_id__" > /opt/config/openstack_tenant_id.txt echo "__openstack_region__" > /opt/config/region.txt echo "__artifacts_version__" > /opt/config/artifacts_version.txt echo "__robot_ip_addr__" > /opt/config/local_ip_addr.txt @@ -736,17 +818,20 @@ resources: echo "__aai2_ip_addr__" > /opt/config/aai2_ip_addr.txt echo "__appc_ip_addr__" > /opt/config/appc_ip_addr.txt echo "__dcae_ip_addr__" > /opt/config/dcae_ip_addr.txt - echo "__mso_ip_addr__" > /opt/config/mso_ip_addr.txt + echo "__so_ip_addr__" > /opt/config/so_ip_addr.txt echo "__mr_ip_addr__" > /opt/config/mr_ip_addr.txt echo "__policy_ip_addr__" > /opt/config/policy_ip_addr.txt echo "__portal_ip_addr__" > /opt/config/portal_ip_addr.txt echo "__sdc_ip_addr__" > /opt/config/sdc_ip_addr.txt echo "__sdnc_ip_addr__" > /opt/config/sdnc_ip_addr.txt echo "__vid_ip_addr__" > /opt/config/vid_ip_addr.txt + echo "__clamp_ip_addr__" > /opt/config/clamp_ip_addr.txt + echo "__openo_ip_addr__" > /opt/config/openo_ip_addr.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt echo "__vm_image_name__" > /opt/config/vm_image_name.txt echo "__vm_flavor__" > /opt/config/vm_flavor.txt + echo "__robot_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/robot_install.sh -o /opt/robot_install.sh @@ -759,8 +844,8 @@ resources: vid_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: vid_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: vid_ip_addr }}] vid_vm: type: OS::Nova::Server @@ -788,10 +873,11 @@ resources: __vid_ip_addr__: { get_param: vid_ip_addr } __dns_ip_addr__: { get_param: dns_ip_addr } __oam_network_cidr__: { get_param: oam_network_cidr } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: vid_docker } + __gerrit_branch__: { get_param: vid_branch } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __vid_repo__: { get_param: vid_repo } template: | #!/bin/bash @@ -809,6 +895,7 @@ resources: echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__vid_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/vid_install.sh -o /opt/vid_install.sh @@ -821,8 +908,8 @@ resources: sdnc_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: sdnc_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: sdnc_ip_addr }}] sdnc_vm: type: OS::Nova::Server @@ -850,10 +937,12 @@ resources: __sdnc_ip_addr__: { get_param: sdnc_ip_addr } __dns_ip_addr__: { get_param: dns_ip_addr } __oam_network_cidr__: { get_param: oam_network_cidr } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: sdnc_docker } + __gerrit_branch__: { get_param: sdnc_branch } + __dgbuilder_docker__: { get_param: dgbuilder_docker } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __sdnc_repo__: { get_param: sdnc_repo } template: | #!/bin/bash @@ -869,8 +958,10 @@ resources: echo "__oam_network_cidr__" > /opt/config/oam_network_cidr.txt echo "__docker_version__" > /opt/config/docker_version.txt echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt + echo "__dgbuilder_docker__" > /opt/config/dgbuilder_version.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__sdnc_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/sdnc_install.sh -o /opt/sdnc_install.sh @@ -883,8 +974,8 @@ resources: sdc_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: sdc_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: sdc_ip_addr }}] sdc_volume_data: type: OS::Cinder::Volume @@ -923,10 +1014,11 @@ resources: __dns_ip_addr__: { get_param: dns_ip_addr } __oam_network_cidr__: { get_param: oam_network_cidr } __mr_ip_addr__: { get_param: mr_ip_addr } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: sdc_docker } + __gerrit_branch__: { get_param: sdc_branch } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __sdc_repo__: { get_param: sdc_repo } template: | #!/bin/bash @@ -946,20 +1038,21 @@ resources: echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__sdc_repo__" > /opt/config/remote_repo.txt # Download and run install script - curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/asdc_install.sh -o /opt/asdc_install.sh + curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/sdc_install.sh -o /opt/sdc_install.sh cd /opt - chmod +x asdc_install.sh - ./asdc_install.sh + chmod +x sdc_install.sh + ./sdc_install.sh # PORTAL instantiation portal_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: portal_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: portal_ip_addr }}] portal_vm: type: OS::Nova::Server @@ -987,10 +1080,11 @@ resources: __portal_ip_addr__: { get_param: portal_ip_addr } __dns_ip_addr__: { get_param: dns_ip_addr } __oam_network_cidr__: { get_param: oam_network_cidr } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: portal_docker } + __gerrit_branch__: { get_param: portal_branch } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __portal_repo__: { get_param: portal_repo } template: | #!/bin/bash @@ -1008,6 +1102,7 @@ resources: echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__portal_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/portal_install.sh -o /opt/portal_install.sh @@ -1020,8 +1115,8 @@ resources: dcae_c_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: dcae_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: dcae_ip_addr }}] dcae_c_vm: type: OS::Nova::Server @@ -1053,7 +1148,7 @@ resources: __dcae_state__: { get_param: dcae_state } __artifacts_version__: { get_param: artifacts_version } __tenant_id__: { get_param: openstack_tenant_id } - __openstack_private_network_name__: { get_attr: [oam_ecomp, name] } + __openstack_private_network_name__: { get_attr: [oam_onap, name] } __openstack_user__: { get_param: openstack_username } __openstack_password__: { get_param: openstack_api_key } __openstack_auth_method__: { get_param: openstack_auth_method } @@ -1064,8 +1159,8 @@ resources: __openstack_region__: { get_param: openstack_region } __horizon_url__: { get_param: horizon_url } __keystone_url__: { get_param: keystone_url } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: dcae_docker } + __gerrit_branch__: { get_param: dcae_branch } __dcae_code_version__: { get_param: dcae_code_version } __cloud_env__: { get_param: cloud_env } __public_net_id__: { get_param: public_net_id } @@ -1083,6 +1178,8 @@ resources: __flavor_medium__: { get_param: flavor_medium } __flavor_large__: { get_param: flavor_large } __flavor_xlarge__: { get_param: flavor_xlarge } + __dcae_repo__: { get_param: dcae_repo } + __mr_repo__: { get_param: mr_repo } template: | #!/bin/bash @@ -1130,6 +1227,8 @@ resources: echo "__flavor_medium__" > /opt/config/flavor_medium.txt echo "__flavor_large__" > /opt/config/flavor_large.txt echo "__flavor_xlarge__" > /opt/config/flavor_xlarge.txt + echo "__dcae_repo__" > /opt/config/remote_repo.txt + echo "__mr_repo__" > /opt/config/mr_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/dcae_install.sh -o /opt/dcae_install.sh @@ -1142,8 +1241,8 @@ resources: policy_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: policy_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: policy_ip_addr }}] policy_vm: type: OS::Nova::Server @@ -1171,10 +1270,11 @@ resources: __policy_ip_addr__: { get_param: policy_ip_addr } __dns_ip_addr__: { get_param: dns_ip_addr } __oam_network_cidr__: { get_param: oam_network_cidr } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: policy_docker } + __gerrit_branch__: { get_param: policy_branch } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __policy_repo__: { get_param: policy_repo } template: | #!/bin/bash @@ -1192,6 +1292,7 @@ resources: echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__policy_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/policy_install.sh -o /opt/policy_install.sh @@ -1204,8 +1305,8 @@ resources: appc_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": { get_param: appc_ip_addr }}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: appc_ip_addr }}] appc_vm: type: OS::Nova::Server @@ -1234,10 +1335,12 @@ resources: __appc_ip_addr__: { get_param: appc_ip_addr } __dns_ip_addr__: { get_param: dns_ip_addr } __oam_network_cidr__: { get_param: oam_network_cidr } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: appc_docker } + __gerrit_branch__: { get_param: appc_branch } + __dgbuilder_docker__: { get_param: dgbuilder_docker } __cloud_env__: { get_param: cloud_env } __external_dns__: { get_param: external_dns } + __appc_repo__: { get_param: appc_repo } template: | #!/bin/bash @@ -1254,11 +1357,189 @@ resources: echo "__dmaap_topic__" > /opt/config/dmaap_topic.txt echo "__docker_version__" > /opt/config/docker_version.txt echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt + echo "__dgbuilder_docker__" > /opt/config/dgbuilder_version.txt echo "__cloud_env__" > /opt/config/cloud_env.txt echo "__external_dns__" > /opt/config/external_dns.txt + echo "__appc_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/appc_install.sh -o /opt/appc_install.sh cd /opt chmod +x appc_install.sh - ./appc_install.sh
\ No newline at end of file + ./appc_install.sh + + + # CLAMP instantiation + clamp_private_port: + type: OS::Neutron::Port + properties: + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: clamp_ip_addr }}] + + clamp_vm: + type: OS::Nova::Server + properties: + image: { get_param: ubuntu_1604_image } + flavor: { get_param: flavor_medium } + name: + str_replace: + template: base-clamp + params: + base: { get_param: vm_base_name } + key_name: { get_resource: vm_key } + networks: + - network: { get_param: public_net_id } + - port: { get_resource: clamp_private_port } + user_data_format: RAW + user_data: + str_replace: + params: + __nexus_repo__: { get_param: nexus_repo } + __nexus_docker_repo__: { get_param: nexus_docker_repo } + __nexus_username__: { get_param: nexus_username } + __nexus_password__: { get_param: nexus_password } + __openstack_username__: { get_param: openstack_username } + __openstack_tenant_id__: { get_param: openstack_tenant_id } + __openstack_api_key__: { get_param: openstack_api_key } + __openstack_region__: { get_param: openstack_region } + __keystone_url__: { get_param: keystone_url } + __dmaap_topic__: { get_param: dmaap_topic } + __artifacts_version__: { get_param: artifacts_version } + __dns_ip_addr__: { get_param: dns_ip_addr } + __clamp_ip_addr__: { get_param: clamp_ip_addr } + __oam_network_cidr__: { get_param: oam_network_cidr } + __docker_version__: { get_param: clamp_docker } + __gerrit_branch__: { get_param: clamp_branch } + __cloud_env__: { get_param: cloud_env } + __external_dns__: { get_param: external_dns } + __clamp_repo__: { get_param: clamp_repo } + template: | + #!/bin/bash + + # Create configuration files + mkdir -p /opt/config + echo "__nexus_repo__" > /opt/config/nexus_repo.txt + echo "__nexus_docker_repo__" > /opt/config/nexus_docker_repo.txt + echo "__nexus_username__" > /opt/config/nexus_username.txt + echo "__nexus_password__" > /opt/config/nexus_password.txt + echo "__artifacts_version__" > /opt/config/artifacts_version.txt + echo "__clamp_ip_addr__" > /opt/config/local_ip_addr.txt + echo "__dns_ip_addr__" > /opt/config/dns_ip_addr.txt + echo "__oam_network_cidr__" > /opt/config/oam_network_cidr.txt + echo "__dmaap_topic__" > /opt/config/dmaap_topic.txt + echo "__openstack_username__" > /opt/config/openstack_username.txt + echo "__openstack_tenant_id__" > /opt/config/tenant_id.txt + echo "__openstack_api_key__" > /opt/config/openstack_api_key.txt + echo "__openstack_region__" > /opt/config/openstack_region.txt + echo "__keystone_url__" > /opt/config/keystone.txt + echo "__docker_version__" > /opt/config/docker_version.txt + echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt + echo "__cloud_env__" > /opt/config/cloud_env.txt + echo "__external_dns__" > /opt/config/external_dns.txt + echo "__clamp_repo__" > /opt/config/remote_repo.txt + + # Download and run install script + curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/clamp_install.sh -o /opt/clamp_install.sh + cd /opt + chmod +x clamp_install.sh + ./clamp_install.sh + + + # OPEN-O VM instantiation + openo_private_port: + type: OS::Neutron::Port + properties: + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": { get_param: openo_ip_addr }}] + + openo_vm: + type: OS::Nova::Server + properties: + image: { get_param: ubuntu_1604_image } + flavor: { get_param: flavor_xxlarge } + name: + str_replace: + template: base-openo-server + params: + base: { get_param: vm_base_name } + key_name: { get_resource: vm_key } + networks: + - network: { get_param: public_net_id } + - port: { get_resource: openo_private_port } + user_data_format: RAW + user_data: + str_replace: + params: + __nexus_repo__: { get_param: nexus_repo } + __nexus_docker_repo__: { get_param: nexus_docker_repo } + __nexus_username__: { get_param: nexus_username } + __nexus_password__: { get_param: nexus_password } + __artifacts_version__: { get_param: artifacts_version } + __dns_ip_addr__: { get_param: dns_ip_addr } + __oam_network_cidr__: { get_param: oam_network_cidr } + __aai1_ip_addr__: { get_param: aai1_ip_addr } + __aai2_ip_addr__: { get_param: aai2_ip_addr } + __appc_ip_addr__: { get_param: appc_ip_addr } + __dcae_ip_addr__: { get_param: dcae_ip_addr } + __dcae_coll_ip_addr__: { get_param: dcae_coll_ip_addr } + __so_ip_addr__: { get_param: so_ip_addr } + __mr_ip_addr__: { get_param: mr_ip_addr } + __policy_ip_addr__: { get_param: policy_ip_addr } + __portal_ip_addr__: { get_param: portal_ip_addr } + __robot_ip_addr__: { get_param: robot_ip_addr } + __sdc_ip_addr__: { get_param: sdc_ip_addr } + __sdnc_ip_addr__: { get_param: sdnc_ip_addr } + __vid_ip_addr__: { get_param: vid_ip_addr } + __clamp_ip_addr__: { get_param: clamp_ip_addr } + __openo_ip_addr__: { get_param: openo_ip_addr } + __cloud_env__: { get_param: cloud_env } + __external_dns__: { get_param: external_dns } + __vnfsdk_branch__: { get_param: vnfsdk_branch } + __msb_docker__: { get_param: msb_docker } + __mvim_docker__: { get_param: mvim_docker } + __vfc_docker__: { get_param: vfc_docker } + __uui_docker__: { get_param: uui_docker } + __vnfsdk_repo__: { get_param: vnfsdk_repo } + template: | + #!/bin/bash + + # Create configuration files + mkdir -p /opt/config + echo "__nexus_repo__" > /opt/config/nexus_repo.txt + echo "__nexus_docker_repo__" > /opt/config/nexus_docker_repo.txt + echo "__nexus_username__" > /opt/config/nexus_username.txt + echo "__nexus_password__" > /opt/config/nexus_password.txt + echo "__cloud_env__" > /opt/config/cloud_env.txt + echo "__artifacts_version__" > /opt/config/artifacts_version.txt + echo "__oam_network_cidr__" > /opt/config/oam_network_cidr.txt + echo "__dns_ip_addr__" > /opt/config/dns_ip_addr.txt + echo "__external_dns__" > /opt/config/external_dns.txt + echo "__vnfsdk_branch__" > /opt/config/vnfsdk_branch.txt + echo "__msb_docker__" > /opt/config/msb_docker.txt + echo "__mvim_docker__" > /opt/config/mvim_docker.txt + echo "__vfc_docker__" > /opt/config/vfc_docker.txt + echo "__uui_docker__" > /opt/config/uui_docker.txt + echo "__vnfsdk_repo__" > /opt/config/vnfsdk_repo.txt + + # Create env file with the IP address of all ONAP components + echo "export AAI_IP1=__aai1_ip_addr__" >> /opt/config/onap_ips.txt + echo "export AAI_IP2=__aai2_ip_addr__" >> /opt/config/onap_ips.txt + echo "export APPC_IP=__appc_ip_addr__" >> /opt/config/onap_ips.txt + echo "export DCAE_IP=__dcae_ip_addr__" >> /opt/config/onap_ips.txt + echo "export DCAE_COLL_IP=__dcae_coll_ip_addr__" >> /opt/config/onap_ips.txt + echo "export SO_IP=__so_ip_addr__" >> /opt/config/onap_ips.txt + echo "export MR_IP=__mr_ip_addr__" >> /opt/config/onap_ips.txt + echo "export POLICY_IP=__policy_ip_addr__" >> /opt/config/onap_ips.txt + echo "export PORTAL_IP=__portal_ip_addr__" >> /opt/config/onap_ips.txt + echo "export ROBOT_IP=__robot_ip_addr__" >> /opt/config/onap_ips.txt + echo "export SDC_IP=__sdc_ip_addr__" >> /opt/config/onap_ips.txt + echo "export SDNC_IP=__sdnc_ip_addr__" >> /opt/config/onap_ips.txt + echo "export VID_IP=__vid_ip_addr__" >> /opt/config/onap_ips.txt + echo "export CLAMP_IP=__clamp_ip_addr__" >> /opt/config/onap_ips.txt + echo "export OPENO_IP=__openo_ip_addr__" >> /opt/config/onap_ips.txt + + # Download and run install script + curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/openo_install.sh -o /opt/openo_install.sh + cd /opt + chmod +x openo_install.sh + ./openo_install.sh diff --git a/heat/ONAP/onap_rackspace.env b/heat/ONAP/onap_rackspace.env index 422dce3b..d92b3c71 100644 --- a/heat/ONAP/onap_rackspace.env +++ b/heat/ONAP/onap_rackspace.env @@ -32,10 +32,6 @@ parameters: artifacts_version: 1.1.0-SNAPSHOT - docker_version: 1.1-STAGING-latest - - gerrit_branch: master - cloud_env: rackspace @@ -59,10 +55,51 @@ parameters: # IP Address of DCAE VMs - dcae_ip_addr: 10.0.4.1 dcae_coll_ip_addr: 10.0.4.102 dcae_db_ip_addr: 10.0.4.101 dcae_hdp1_ip_addr: 10.0.4.103 dcae_hdp2_ip_addr: 10.0.4.104 - dcae_hdp3_ip_addr: 10.0.4.105
\ No newline at end of file + dcae_hdp3_ip_addr: 10.0.4.105 + + # ONAP repositories, docker versions, and Gerrit branches + + aai_repo: http://gerrit.onap.org/r/aai/test-config + appc_repo: http://gerrit.onap.org/r/appc/deployment.git + dcae_repo: http://gerrit.onap.org/r/dcae/demo/startup/controller.git + mr_repo: http://gerrit.onap.org/r/dcae/demo/startup/message-router.git + so_repo: http://gerrit.onap.org/r/so/docker-config.git + policy_repo: http://gerrit.onap.org/r/policy/docker.git + portal_repo: http://gerrit.onap.org/r/portal.git + robot_repo: http://gerrit.onap.org/r/testsuite/properties.git + sdc_repo: http://gerrit.onap.org/r/sdc.git + sdnc_repo: http://gerrit.onap.org/r/sdnc/oam.git + vid_repo: http://gerrit.onap.org/r/vid.git + clamp_repo: http://gerrit.onap.org/r/clamp.git + + aai_branch: master + appc_branch: master + so_branch: master + mr_branch: master + dcae_branch: master + policy_branch: master + portal_branch: master + robot_branch: master + sdc_branch: master + sdnc_branch: master + vid_branch: master + clamp_branch: master + + aai_docker: 1.1-STAGING-latest + appc_docker: 1.1-STAGING-latest + so_docker: 1.1-STAGING-latest + mr_docker: 1.1-STAGING-latest + dcae_docker: 1.1-STAGING-latest + policy_docker: 1.1-STAGING-latest + portal_docker: 1.1-STAGING-latest + robot_docker: 1.1-STAGING-latest + sdc_docker: 1.1-STAGING-latest + sdnc_docker: 1.2-STAGING-latest + vid_docker: 1.1-STAGING-latest + clamp_docker: 1.1-STAGING-latest + dgbuilder_docker: 0.1-STAGING-latest diff --git a/heat/ONAP/onap_rackspace.yaml b/heat/ONAP/onap_rackspace.yaml index f62043a2..27652a4b 100644 --- a/heat/ONAP/onap_rackspace.yaml +++ b/heat/ONAP/onap_rackspace.yaml @@ -89,14 +89,6 @@ parameters: type: string description: Artifacts version of ONAP components - docker_version: - type: string - description: Docker version of ONAP docker images - - gerrit_branch: - type: string - description: Gerrit branch where to download the code from - cloud_env: type: string description: Cloud Provider Name @@ -105,7 +97,7 @@ parameters: # Parameters for DCAE instantiation dcae_base_environment: type: string - description: DCAE Base Environment configuration (RACKSPACE/2-NIC/...) + description: DCAE Base Environment configuration (for this template, only RACKSPACE is supported) dcae_zone: type: string @@ -159,6 +151,84 @@ parameters: type: string description: Hadoop VM3 IP Address + # ONAP repositories, docker versions, and Gerrit branches + aai_repo: + type: string + appc_repo: + type: string + dcae_repo: + type: string + mr_repo: + type: string + so_repo: + type: string + policy_repo: + type: string + portal_repo: + type: string + robot_repo: + type: string + sdc_repo: + type: string + sdnc_repo: + type: string + vid_repo: + type: string + clamp_repo: + type: string + + aai_docker: + type: string + appc_docker: + type: string + so_docker: + type: string + mr_docker: + type: string + dcae_docker: + type: string + policy_docker: + type: string + portal_docker: + type: string + robot_docker: + type: string + sdc_docker: + type: string + sdnc_docker: + type: string + vid_docker: + type: string + clamp_docker: + type: string + dgbuilder_docker: + type: string + + aai_branch: + type: string + appc_branch: + type: string + so_branch: + type: string + mr_branch: + type: string + dcae_branch: + type: string + policy_branch: + type: string + portal_branch: + type: string + robot_branch: + type: string + sdc_branch: + type: string + sdnc_branch: + type: string + vid_branch: + type: string + clamp_branch: + type: string + resources: random-str: @@ -181,24 +251,24 @@ resources: # ONAP management private network - oam_ecomp: + oam_onap: type: OS::Neutron::Net properties: name: str_replace: - template: oam_ecomp_rand + template: oam_onap_rand params: rand: { get_resource: random-str } - oam_ecomp_subnet: + oam_onap_subnet: type: OS::Neutron::Subnet properties: name: str_replace: - template: oam_ecomp_rand + template: oam_onap_rand params: rand: { get_resource: random-str } - network_id: { get_resource: oam_ecomp } + network_id: { get_resource: oam_onap } cidr: 10.0.0.0/16 @@ -206,8 +276,8 @@ resources: dns_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": 10.0.0.1}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.0.1}] dns_vm: type: OS::Nova::Server @@ -250,8 +320,8 @@ resources: aai1_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": 10.0.1.1}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.1.1}] aai1_volume: type: OS::Cinder::Volume @@ -288,9 +358,10 @@ resources: __nexus_password__: { get_param: nexus_password } __dmaap_topic__: { get_param: dmaap_topic } __artifacts_version__: { get_param: artifacts_version } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: aai_docker } + __gerrit_branch__: { get_param: aai_branch } __cloud_env__: { get_param: cloud_env } + __aai_repo__: { get_param: aai_repo } template: | #!/bin/bash @@ -307,19 +378,20 @@ resources: echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt echo "aai_instance_1" > /opt/config/aai_instance.txt echo "__cloud_env__" > /opt/config/cloud_env.txt + echo "__aai_repo__" > /opt/config/remote_repo.txt # Download and run install script - curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai2_install.sh -o /opt/aai2_install.sh + curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai_install.sh -o /opt/aai_install.sh cd /opt - chmod +x aai2_install.sh - ./aai2_install.sh + chmod +x aai_install.sh + ./aai_install.sh aai2_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": 10.0.1.2}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.1.2}] aai2_volume: type: OS::Cinder::Volume @@ -355,9 +427,10 @@ resources: __nexus_password__: { get_param: nexus_password } __dmaap_topic__: { get_param: dmaap_topic } __artifacts_version__: { get_param: artifacts_version } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: aai_docker } + __gerrit_branch__: { get_param: aai_branch } __cloud_env__: { get_param: cloud_env } + __aai_repo__: { get_param: aai_repo } template: | #!/bin/bash @@ -374,35 +447,36 @@ resources: echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt echo "aai_instance_2" > /opt/config/aai_instance.txt echo "__cloud_env__" > /opt/config/cloud_env.txt + echo "__aai_repo__" > /opt/config/remote_repo.txt # Download and run install script - curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai2_install.sh -o /opt/aai2_install.sh + curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/aai_install.sh -o /opt/aai_install.sh cd /opt - chmod +x aai2_install.sh - ./aai2_install.sh + chmod +x aai_install.sh + ./aai_install.sh - # MSO instantiation - mso_private_port: + # SO instantiation + so_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": 10.0.5.1}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.5.1}] - mso_vm: + so_vm: type: OS::Nova::Server properties: image: Ubuntu 16.04 LTS (Xenial Xerus) (PVHVM) flavor: 4 GB General Purpose v1 name: str_replace: - template: base-mso + template: base-so params: base: { get_param: vm_base_name } key_name: { get_resource: vm_key } networks: - network: { get_param: public_net_id } - - port: { get_resource: mso_private_port } + - port: { get_resource: so_private_port } user_data_format: RAW user_data: str_replace: @@ -416,9 +490,10 @@ resources: __openstack_api_key__: { get_param: openstack_api_key } __dmaap_topic__: { get_param: dmaap_topic } __artifacts_version__: { get_param: artifacts_version } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: so_docker } + __gerrit_branch__: { get_param: so_branch } __cloud_env__: { get_param: cloud_env } + __so_repo__: { get_param: so_repo } template: | #!/bin/bash @@ -437,20 +512,21 @@ resources: echo "__docker_version__" > /opt/config/docker_version.txt echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt echo "__cloud_env__" > /opt/config/cloud_env.txt + echo "__so_repo__" > /opt/config/remote_repo.txt # Download and run install script - curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/mso_install.sh -o /opt/mso_install.sh + curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/so_install.sh -o /opt/so_install.sh cd /opt - chmod +x mso_install.sh - ./mso_install.sh + chmod +x so_install.sh + ./so_install.sh # Message Router instantiation mrouter_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": 10.0.11.1}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.11.1}] mrouter_vm: type: OS::Nova::Server @@ -475,8 +551,9 @@ resources: __nexus_username__: { get_param: nexus_username } __nexus_password__: { get_param: nexus_password } __artifacts_version__: { get_param: artifacts_version } - __gerrit_branch__: { get_param: gerrit_branch } + __gerrit_branch__: { get_param: mr_branch } __cloud_env__: { get_param: cloud_env } + __mr_repo__: { get_param: mr_repo } template: | #!/bin/bash @@ -490,6 +567,7 @@ resources: echo "10.0.0.1" > /opt/config/dns_ip_addr.txt echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt echo "__cloud_env__" > /opt/config/cloud_env.txt + echo "__mr_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/mr_install.sh -o /opt/mr_install.sh @@ -502,8 +580,8 @@ resources: robot_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": 10.0.10.1}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.10.1}] robot_vm: type: OS::Nova::Server @@ -527,15 +605,17 @@ resources: __nexus_docker_repo__: { get_param: nexus_docker_repo } __nexus_username__: { get_param: nexus_username } __nexus_password__: { get_param: nexus_password } - __network_name__: { get_attr: [oam_ecomp, name] } + __network_name__: { get_attr: [oam_onap, name] } __openstack_username__: { get_param: openstack_username } __openstack_api_key__: { get_param : openstack_api_key } __openstack_password__: { get_param: openstack_password } + __openstack_tenant_id__: { get_param: openstack_tenant_id } __artifacts_version__: { get_param: artifacts_version } __openstack_region__: { get_param: openstack_region } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: robot_docker } + __gerrit_branch__: { get_param: robot_branch } __cloud_env__: { get_param: cloud_env } + __robot_repo__: { get_param: robot_repo } template: | #!/bin/bash @@ -549,6 +629,7 @@ resources: echo "__openstack_username__" > /opt/config/openstack_username.txt echo "__openstack_password__" > /opt/config/openstack_password.txt echo "__openstack_api_key__" > /opt/config/openstack_api_key.txt + echo "__openstack_tenant_id__" > /opt/config/openstack_tenant_id.txt echo "__openstack_region__" > /opt/config/region.txt echo "__artifacts_version__" > /opt/config/artifacts_version.txt echo "__docker_version__" > /opt/config/docker_version.txt @@ -559,16 +640,18 @@ resources: echo "10.0.1.2" > /opt/config/aai2_ip_addr.txt echo "10.0.2.1" > /opt/config/appc_ip_addr.txt echo "10.0.4.1" > /opt/config/dcae_ip_addr.txt - echo "10.0.5.1" > /opt/config/mso_ip_addr.txt + echo "10.0.5.1" > /opt/config/so_ip_addr.txt echo "10.0.11.1" > /opt/config/mr_ip_addr.txt echo "10.0.6.1" > /opt/config/policy_ip_addr.txt echo "10.0.9.1" > /opt/config/portal_ip_addr.txt echo "10.0.3.1" > /opt/config/sdc_ip_addr.txt echo "10.0.7.1" > /opt/config/sdnc_ip_addr.txt echo "10.0.8.1" > /opt/config/vid_ip_addr.txt + echo "10.0.12.1" > /opt/config/clamp_ip_addr.txt echo "Ubuntu 14.04 LTS (Trusty Tahr) (PVHVM)" > /opt/config/vm_image_name.txt echo "4 GB General Purpose v1" > /opt/config/vm_flavor.txt echo "__cloud_env__" > /opt/config/cloud_env.txt + echo "__robot_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/robot_install.sh -o /opt/robot_install.sh @@ -581,8 +664,8 @@ resources: vid_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": 10.0.8.1}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.8.1}] vid_vm: type: OS::Nova::Server @@ -607,9 +690,10 @@ resources: __nexus_username__: { get_param: nexus_username } __nexus_password__: { get_param: nexus_password } __artifacts_version__: { get_param: artifacts_version } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: vid_docker } + __gerrit_branch__: { get_param: vid_branch } __cloud_env__: { get_param: cloud_env } + __vid_repo__: { get_param: vid_repo } template: | #!/bin/bash @@ -624,6 +708,7 @@ resources: echo "__docker_version__" > /opt/config/docker_version.txt echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt echo "__cloud_env__" > /opt/config/cloud_env.txt + echo "__vid_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/vid_install.sh -o /opt/vid_install.sh @@ -636,8 +721,8 @@ resources: sdnc_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": 10.0.7.1}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.7.1}] sdnc_vm: type: OS::Nova::Server @@ -662,9 +747,11 @@ resources: __nexus_username__: { get_param: nexus_username } __nexus_password__: { get_param: nexus_password } __artifacts_version__: { get_param: artifacts_version } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: sdnc_docker } + __gerrit_branch__: { get_param: sdnc_branch } + __dgbuilder_docker__: { get_param: dgbuilder_docker } __cloud_env__: { get_param: cloud_env } + __sdnc_repo__: { get_param: sdnc_repo } template: | #!/bin/bash @@ -678,7 +765,9 @@ resources: echo "10.0.0.1" > /opt/config/dns_ip_addr.txt echo "__docker_version__" > /opt/config/docker_version.txt echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt + echo "__dgbuilder_docker__" > /opt/config/dgbuilder_version.txt echo "__cloud_env__" > /opt/config/cloud_env.txt + echo "__sdnc_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/sdnc_install.sh -o /opt/sdnc_install.sh @@ -691,8 +780,8 @@ resources: sdc_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": 10.0.3.1}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.3.1}] sdc_volume_local: type: OS::Cinder::Volume @@ -742,9 +831,10 @@ resources: __nexus_password__: { get_param: nexus_password } __env_name__: { get_param: dmaap_topic } __artifacts_version__: { get_param: artifacts_version } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: sdc_docker } + __gerrit_branch__: { get_param: sdc_branch } __cloud_env__: { get_param: cloud_env } + __sdc_repo__: { get_param: sdc_repo } template: | #!/bin/bash @@ -761,20 +851,21 @@ resources: echo "__docker_version__" > /opt/config/docker_version.txt echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt echo "__cloud_env__" > /opt/config/cloud_env.txt + echo "__sdc_repo__" > /opt/config/remote_repo.txt # Download and run install script - curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/asdc_install.sh -o /opt/asdc_install.sh + curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/sdc_install.sh -o /opt/sdc_install.sh cd /opt - chmod +x asdc_install.sh - ./asdc_install.sh + chmod +x sdc_install.sh + ./sdc_install.sh # PORTAL instantiation portal_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": 10.0.9.1}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.9.1}] portal_volume: type: OS::Cinder::Volume @@ -809,9 +900,10 @@ resources: __nexus_username__: { get_param: nexus_username } __nexus_password__: { get_param: nexus_password } __artifacts_version__: { get_param: artifacts_version } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: portal_docker } + __gerrit_branch__: { get_param: portal_branch } __cloud_env__: { get_param: cloud_env } + __portal_repo__: { get_param: portal_repo } template: | #!/bin/bash @@ -826,6 +918,7 @@ resources: echo "__docker_version__" > /opt/config/docker_version.txt echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt echo "__cloud_env__" > /opt/config/cloud_env.txt + echo "__portal_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/portal_install.sh -o /opt/portal_install.sh @@ -838,8 +931,8 @@ resources: dcae_c_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": 10.0.4.1}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.4.1}] dcae_c_vm: type: OS::Nova::Server properties: @@ -868,7 +961,7 @@ resources: __dcae_state__: { get_param: dcae_state } __artifacts_version__: { get_param: artifacts_version } __tenant_id__: { get_param: openstack_tenant_id } - __openstack_private_network_name__: { get_attr: [oam_ecomp, name] } + __openstack_private_network_name__: { get_attr: [oam_onap, name] } __openstack_user__: { get_param: openstack_username } __openstack_password__: { get_param: openstack_api_key } __openstack_auth_method__: { get_param: openstack_auth_method } @@ -877,8 +970,8 @@ resources: __pub_key__: { get_param: pub_key } __nexus_repo_root__: { get_param: nexus_repo_root } __openstack_region__: { get_param: openstack_region } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: dcae_docker } + __gerrit_branch__: { get_param: dcae_branch } __cloud_env__: { get_param: cloud_env } __dcae_code_version__: { get_param: dcae_code_version } __public_net_id__: { get_param: public_net_id } @@ -889,6 +982,8 @@ resources: __dcae_hdp1_ip_addr__: { get_param: dcae_hdp1_ip_addr } __dcae_hdp2_ip_addr__: { get_param: dcae_hdp2_ip_addr } __dcae_hdp3_ip_addr__: { get_param: dcae_hdp3_ip_addr } + __dcae_repo__: { get_param: dcae_repo } + __mr_repo__: { get_param: mr_repo } template: | #!/bin/bash @@ -928,6 +1023,8 @@ resources: echo "__dcae_hdp1_ip_addr__" > /opt/config/dcae_hdp1_ip_addr.txt echo "__dcae_hdp2_ip_addr__" > /opt/config/dcae_hdp2_ip_addr.txt echo "__dcae_hdp3_ip_addr__" > /opt/config/dcae_hdp3_ip_addr.txt + echo "__dcae_repo__" > /opt/config/remote_repo.txt + echo "__mr_repo__" > /opt/config/mr_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/dcae_install.sh -o /opt/dcae_install.sh @@ -940,8 +1037,8 @@ resources: policy_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": 10.0.6.1}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.6.1}] policy_volume: type: OS::Cinder::Volume @@ -976,9 +1073,10 @@ resources: __nexus_username__: { get_param: nexus_username } __nexus_password__: { get_param: nexus_password } __artifacts_version__: { get_param: artifacts_version } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: policy_docker } + __gerrit_branch__: { get_param: policy_branch } __cloud_env__: { get_param: cloud_env } + __policy_repo__: { get_param: policy_repo } template: | #!/bin/bash @@ -993,6 +1091,7 @@ resources: echo "__docker_version__" > /opt/config/docker_version.txt echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt echo "__cloud_env__" > /opt/config/cloud_env.txt + echo "__policy_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/policy_install.sh -o /opt/policy_install.sh @@ -1005,8 +1104,8 @@ resources: appc_private_port: type: OS::Neutron::Port properties: - network: { get_resource: oam_ecomp } - fixed_ips: [{"subnet": { get_resource: oam_ecomp_subnet }, "ip_address": 10.0.2.1}] + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.2.1}] appc_vm: type: OS::Nova::Server @@ -1032,9 +1131,11 @@ resources: __nexus_password__: { get_param: nexus_password } __dmaap_topic__: { get_param: dmaap_topic } __artifacts_version__: { get_param: artifacts_version } - __docker_version__: { get_param: docker_version } - __gerrit_branch__: { get_param: gerrit_branch } + __docker_version__: { get_param: appc_docker } + __gerrit_branch__: { get_param: appc_branch } + __dgbuilder_docker__: { get_param: dgbuilder_docker } __cloud_env__: { get_param: cloud_env } + __appc_repo__: { get_param: appc_repo } template: | #!/bin/bash @@ -1049,10 +1150,77 @@ resources: echo "__dmaap_topic__" > /opt/config/dmaap_topic.txt echo "__docker_version__" > /opt/config/docker_version.txt echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt + echo "__dgbuilder_docker__" > /opt/config/dgbuilder_version.txt echo "__cloud_env__" > /opt/config/cloud_env.txt + echo "__appc_repo__" > /opt/config/remote_repo.txt # Download and run install script curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/appc_install.sh -o /opt/appc_install.sh cd /opt chmod +x appc_install.sh - ./appc_install.sh
\ No newline at end of file + ./appc_install.sh + + + # CLAMP instantiation + clamp_private_port: + type: OS::Neutron::Port + properties: + network: { get_resource: oam_onap } + fixed_ips: [{"subnet": { get_resource: oam_onap_subnet }, "ip_address": 10.0.12.1}] + + clamp_vm: + type: OS::Nova::Server + properties: + image: Ubuntu 16.04 LTS (Xenial Xerus) (PVHVM) + flavor: 4 GB General Purpose v1 + name: + str_replace: + template: base-clamp + params: + base: { get_param: vm_base_name } + key_name: { get_resource: vm_key } + networks: + - network: { get_param: public_net_id } + - port: { get_resource: clamp_private_port } + user_data_format: RAW + user_data: + str_replace: + params: + __nexus_repo__: { get_param: nexus_repo } + __nexus_docker_repo__: { get_param: nexus_docker_repo } + __nexus_username__: { get_param: nexus_username } + __nexus_password__: { get_param: nexus_password } + __openstack_username__: { get_param: openstack_username } + __openstack_tenant_id__: { get_param: openstack_tenant_id } + __openstack_api_key__: { get_param: openstack_api_key } + __dmaap_topic__: { get_param: dmaap_topic } + __artifacts_version__: { get_param: artifacts_version } + __docker_version__: { get_param: clamp_docker } + __gerrit_branch__: { get_param: clamp_branch } + __cloud_env__: { get_param: cloud_env } + __clamp_repo__: { get_param: clamp_repo } + template: | + #!/bin/bash + + # Create configuration files + mkdir -p /opt/config + echo "__nexus_repo__" > /opt/config/nexus_repo.txt + echo "__nexus_docker_repo__" > /opt/config/nexus_docker_repo.txt + echo "__nexus_username__" > /opt/config/nexus_username.txt + echo "__nexus_password__" > /opt/config/nexus_password.txt + echo "__artifacts_version__" > /opt/config/artifacts_version.txt + echo "10.0.0.1" > /opt/config/dns_ip_addr.txt + echo "__dmaap_topic__" > /opt/config/dmaap_topic.txt + echo "__openstack_username__" > /opt/config/openstack_username.txt + echo "__openstack_tenant_id__" > /opt/config/tenant_id.txt + echo "__openstack_api_key__" > /opt/config/openstack_api_key.txt + echo "__docker_version__" > /opt/config/docker_version.txt + echo "__gerrit_branch__" > /opt/config/gerrit_branch.txt + echo "__cloud_env__" > /opt/config/cloud_env.txt + echo "__clamp_repo__" > /opt/config/remote_repo.txt + + # Download and run install script + curl -k __nexus_repo__/org.onap.demo/boot/__artifacts_version__/clamp_install.sh -o /opt/clamp_install.sh + cd /opt + chmod +x clamp_install.sh + ./clamp_install.sh diff --git a/heat/vCPE/infra/base_vcpe_infra_rackspace.env b/heat/vCPE/infra/base_vcpe_infra_rackspace.env index 4de60903..689d1cf0 100644 --- a/heat/vCPE/infra/base_vcpe_infra_rackspace.env +++ b/heat/vCPE/infra/base_vcpe_infra_rackspace.env @@ -17,8 +17,9 @@ parameters: vdns_private_ip_1: 10.0.101.3 vweb_private_ip_0: 10.2.0.10 vweb_private_ip_1: 10.0.101.40 + mr_ip_addr: 10.0.11.1 vaaa_name_0: zdcpe1cpe01aaa01 - vdns_name_0: zdcpe11cpe01dns01 + vdns_name_0: zdcpe1cpe01dns01 vdhcp_name_0: zdcpe1cpe01dhcp01 vweb_name_0: zdcpe1cpe01web01 vnf_id: vCPE_Infrastructure_demo_app diff --git a/heat/vCPE/infra/base_vcpe_infra_rackspace.yaml b/heat/vCPE/infra/base_vcpe_infra_rackspace.yaml index 6b9160bc..c0a18756 100644 --- a/heat/vCPE/infra/base_vcpe_infra_rackspace.yaml +++ b/heat/vCPE/infra/base_vcpe_infra_rackspace.yaml @@ -76,7 +76,7 @@ parameters: vaaa_private_ip_0: type: string label: vAAA private IP address towards the CPE_SIGNAL private network - description: Private IP address that is assigned to the vAAA to communicate with the vCPE components + description: Private IP address that is assigned to the vAAA to communicate with the vCPE components vaaa_private_ip_1: type: string label: vAAA private IP address towards the ONAP management network @@ -137,6 +137,10 @@ parameters: type: string label: DCAE collector port description: Port of the DCAE collector + mr_ip_addr: + type: string + label: Message Router IP address + description: IP address of the Message Router that for vDHCP configuration key_name: type: string label: Key pair name @@ -370,9 +374,10 @@ resources: str_replace: params: __oam_ipaddr__ : { get_param: vdhcp_private_ip_1 } - __cpe_signal_ipaddr__: { get_param: vdhcp_private_ip_0 } - __oam_cidr__: { get_param: onap_private_net_cidr } - __cpe_signal_net_cidr__: { get_param: cpe_signal_net_cidr } + __cpe_signal_ipaddr__ : { get_param: vdhcp_private_ip_0 } + __oam_cidr__ : { get_param: onap_private_net_cidr } + __cpe_signal_net_cidr__ : { get_param: cpe_signal_net_cidr } + __mr_ip_addr__ : { get_param: mr_ip_addr } __repo_url_blob__ : { get_param: repo_url_blob } __repo_url_artifacts__ : { get_param: repo_url_artifacts } __demo_artifacts_version__ : { get_param: demo_artifacts_version } @@ -387,6 +392,7 @@ resources: echo "__cpe_signal_ipaddr__" > /opt/config/cpe_signal_ipaddr.txt echo "__oam_cidr__" > /opt/config/oam_cidr.txt echo "__cpe_signal_net_cidr__" > /opt/config/cpe_signal_net_cidr.txt + echo "__mr_ip_addr__" > /opt/config/mr_ip_addr.txt echo "__repo_url_blob__" > /opt/config/repo_url_blob.txt echo "__repo_url_artifacts__" > /opt/config/repo_url_artifacts.txt echo "__demo_artifacts_version__" > /opt/config/demo_artifacts_version.txt diff --git a/heat/vCPE/vbng/base_vcpe_vbng_rackspace.env b/heat/vCPE/vbng/base_vcpe_vbng_rackspace.env index e50d4834..cc391c49 100644 --- a/heat/vCPE/vbng/base_vcpe_vbng_rackspace.env +++ b/heat/vCPE/vbng/base_vcpe_vbng_rackspace.env @@ -13,7 +13,7 @@ cpe_signal_private_net_cidr: 10.4.0.0/24 vbng_private_ip_0: 10.3.0.1 vbng_private_ip_1: 10.0.101.10 - vbng_private_ip_2: 10.4.0.3
+ vbng_private_ip_2: 10.4.0.3 vbng_private_ip_3: 10.1.0.10 vbng_name_0: zdcpe1cpe01bng01 vnf_id: vCPE_Infrastructure_Metro_vBNG_demo_app @@ -27,3 +27,6 @@ key_name: vbng_key pub_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQXYJYYi3/OUZXUiCYWdtc7K0m5C0dJKVxPG0eI8EWZrEHYdfYe6WoTSDJCww+1qlBSpA5ac/Ba4Wn9vh+lR1vtUKkyIC/nrYb90ReUd385Glkgzrfh5HdR5y5S2cL/Frh86lAn9r6b3iWTJD8wBwXFyoe1S2nMTOIuG4RPNvfmyCTYVh8XTCCE8HPvh3xv2r4egawG1P4Q4UDwk+hDBXThY2KS8M5/8EMyxHV0ImpLbpYCTBA6KYDIRtqmgS6iKyy8v2D1aSY5mc9J0T5t9S2Gv+VZQNWQDDKNFnxqYaAo1uEoq/i1q63XC5AD3ckXb2VT6dp23BQMdDfbHyUWfJN cloud_env: rackspace + vpp_source_repo_url: https://gerrit.fd.io/r/vpp + vpp_source_repo_branch: stable/1704 + vpp_patch_url: https://gerrit.onap.org/r/#/c/11083/5/vnfs/vCPE/vpp-radius-client-for-vbng/src/patches/Vpp-Integrate-FreeRADIUS-Client-for-vBNG.patch diff --git a/heat/vCPE/vbng/base_vcpe_vbng_rackspace.yaml b/heat/vCPE/vbng/base_vcpe_vbng_rackspace.yaml index d5c0eed8..8a49e171 100644 --- a/heat/vCPE/vbng/base_vcpe_vbng_rackspace.yaml +++ b/heat/vCPE/vbng/base_vcpe_vbng_rackspace.yaml @@ -145,6 +145,18 @@ parameters: type: string label: Cloud environment description: Cloud environment (e.g., openstack, rackspace) + vpp_source_repo_url: + type: string + label: VPP Source Git Repo + description: URL for VPP source codes + vpp_source_repo_branch: + type: string + label: VPP Source Git Branch + description: Git Branch for the VPP source codes + vpp_patch_url: + type: string + label: VPP Patch URL + description: URL for VPP patch for vBNG ############# # # @@ -240,6 +252,9 @@ resources: __demo_artifacts_version__ : { get_param: demo_artifacts_version } __install_script_version__ : { get_param: install_script_version } __cloud_env__ : { get_param: cloud_env } + __vpp_source_repo_url__ : { get_param: vpp_source_repo_url } + __vpp_source_repo_branch__ : { get_param: vpp_source_repo_branch } + __vpp_patch_url__ : { get_param: vpp_patch_url } template: | #!/bin/bash @@ -260,6 +275,9 @@ resources: echo "__demo_artifacts_version__" > /opt/config/demo_artifacts_version.txt echo "__install_script_version__" > /opt/config/install_script_version.txt echo "__cloud_env__" > /opt/config/cloud_env.txt + echo "__vpp_source_repo_url__" > /opt/config/vpp_source_repo_url.txt + echo "__vpp_source_repo_branch__" > /opt/config/vpp_source_repo_branch.txt + echo "__vpp_patch_url__" > /opt/config/vpp_patch_url.txt # Download and run install script curl -k __repo_url_blob__/org.onap.demo/vnfs/vcpe/__install_script_version__/v_bng_install.sh -o /opt/v_bng_install.sh diff --git a/heat/vCPE/vbrgemu/base_vcpe_vbrgemu_rackspace.env b/heat/vCPE/vbrgemu/base_vcpe_vbrgemu_rackspace.env index 0d4d894e..719e7c9b 100644 --- a/heat/vCPE/vbrgemu/base_vcpe_vbrgemu_rackspace.env +++ b/heat/vCPE/vbrgemu/base_vcpe_vbrgemu_rackspace.env @@ -7,8 +7,9 @@ vbrgemu_bng_private_net_cidr: 10.3.0.0/24 vbrgemu_private_net_cidr: 192.168.1.0/24 vbrgemu_private_ip_0: 10.3.0.2 - vbrgemu_private_ip_1: 192.168.1.1
- vbrgemu_name_0: zdcpe11cpe01brgemu01 + vbrgemu_private_ip_1: 192.168.1.1 + sdnc_ip: 10.0.7.1 + vbrgemu_name_0: zdcpe1cpe01brgemu01 vnf_id: vCPE_Infrastructure_BGREMU_demo_app vf_module_id: vCPE_Customer_BRGEMU repo_url_blob: https://nexus.onap.org/content/sites/raw @@ -18,3 +19,8 @@ key_name: vbrgemu_key pub_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQXYJYYi3/OUZXUiCYWdtc7K0m5C0dJKVxPG0eI8EWZrEHYdfYe6WoTSDJCww+1qlBSpA5ac/Ba4Wn9vh+lR1vtUKkyIC/nrYb90ReUd385Glkgzrfh5HdR5y5S2cL/Frh86lAn9r6b3iWTJD8wBwXFyoe1S2nMTOIuG4RPNvfmyCTYVh8XTCCE8HPvh3xv2r4egawG1P4Q4UDwk+hDBXThY2KS8M5/8EMyxHV0ImpLbpYCTBA6KYDIRtqmgS6iKyy8v2D1aSY5mc9J0T5t9S2Gv+VZQNWQDDKNFnxqYaAo1uEoq/i1q63XC5AD3ckXb2VT6dp23BQMdDfbHyUWfJN cloud_env: rackspace + vpp_source_repo_url: https://gerrit.fd.io/r/vpp + vpp_source_repo_branch: stable/1704 + hc2vpp_source_repo_url: https://gerrit.fd.io/r/hc2vpp + hc2vpp_source_repo_branch: stable/1704 + vpp_patch_url: https://gerrit.onap.org/r/#/c/11083/5/vnfs/vCPE/vpp-option-82-for-vbrg/src/patches/VPP-Add-Option82-Nat-Filter-For-vBRG.patch diff --git a/heat/vCPE/vbrgemu/base_vcpe_vbrgemu_rackspace.yaml b/heat/vCPE/vbrgemu/base_vcpe_vbrgemu_rackspace.yaml index 6f926eb5..a6f42ba2 100644 --- a/heat/vCPE/vbrgemu/base_vcpe_vbrgemu_rackspace.yaml +++ b/heat/vCPE/vbrgemu/base_vcpe_vbrgemu_rackspace.yaml @@ -111,6 +111,26 @@ parameters: type: string label: Cloud environment description: Cloud environment (e.g., openstack, rackspace) + vpp_source_repo_url: + type: string + label: VPP Source Git Repo + description: URL for VPP source codes + vpp_source_repo_branch: + type: string + label: VPP Source Git Branch + description: Git Branch for the VPP source codes + hc2vpp_source_repo_url: + type: string + label: Honeycomb Source Git Repo + description: URL for Honeycomb source codes + hc2vpp_source_repo_branch: + type: string + label: Honeycomb Source Git Branch + description: Git Branch for the Honeycomb source codes + vpp_patch_url: + type: string + label: VPP Patch URL + description: URL for VPP patch for vBRG Emulator ############# # # @@ -187,6 +207,11 @@ resources: __demo_artifacts_version__ : { get_param: demo_artifacts_version } __install_script_version__ : { get_param: install_script_version } __cloud_env__ : { get_param: cloud_env } + __vpp_source_repo_url__ : { get_param: vpp_source_repo_url } + __vpp_source_repo_branch__ : { get_param: vpp_source_repo_branch } + __hc2vpp_source_repo_url__ : { get_param: hc2vpp_source_repo_url } + __hc2vpp_source_repo_branch__ : { get_param: hc2vpp_source_repo_branch } + __vpp_patch_url__ : { get_param: vpp_patch_url } template: | #!/bin/bash @@ -200,6 +225,12 @@ resources: echo "__demo_artifacts_version__" > /opt/config/demo_artifacts_version.txt echo "__install_script_version__" > /opt/config/install_script_version.txt echo "__cloud_env__" > /opt/config/cloud_env.txt + echo "__vpp_source_repo_url__" > /opt/config/vpp_source_repo_url.txt + echo "__vpp_source_repo_branch__" > /opt/config/vpp_source_repo_branch.txt + echo "__hc2vpp_source_repo_url__" > /opt/config/hc2vpp_source_repo_url.txt + echo "__hc2vpp_source_repo_branch__" > /opt/config/hc2vpp_source_repo_branch.txt + echo "__vpp_patch_url__" > /opt/config/vpp_patch_url.txt + echo "__sdnc_ip__" > /opt/config/ip.txt # Download and run install script curl -k __repo_url_blob__/org.onap.demo/vnfs/vcpe/__install_script_version__/v_brgemu_install.sh -o /opt/v_brgemu_install.sh diff --git a/heat/vCPE/vgmux/base_vcpe_vgmux_rackspace.env b/heat/vCPE/vgmux/base_vcpe_vgmux_rackspace.env index 76dd86ef..de15d1b5 100644 --- a/heat/vCPE/vgmux/base_vcpe_vgmux_rackspace.env +++ b/heat/vCPE/vgmux/base_vcpe_vgmux_rackspace.env @@ -12,7 +12,7 @@ vgmux_private_ip_0: 10.1.0.20 vgmux_private_ip_1: 10.0.101.20 vgmux_private_ip_2: 10.5.0.20 - vgmux_name_0: zdcpe11cpe01mux01 + vgmux_name_0: zdcpe1cpe01mux01 vnf_id: vCPE_Infrastructure_vGMUX_demo_app vf_module_id: vCPE_Intrastructure_Metro_vGMUX dcae_collector_ip: 10.0.4.102 @@ -24,3 +24,9 @@ key_name: vbng_key pub_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQXYJYYi3/OUZXUiCYWdtc7K0m5C0dJKVxPG0eI8EWZrEHYdfYe6WoTSDJCww+1qlBSpA5ac/Ba4Wn9vh+lR1vtUKkyIC/nrYb90ReUd385Glkgzrfh5HdR5y5S2cL/Frh86lAn9r6b3iWTJD8wBwXFyoe1S2nMTOIuG4RPNvfmyCTYVh8XTCCE8HPvh3xv2r4egawG1P4Q4UDwk+hDBXThY2KS8M5/8EMyxHV0ImpLbpYCTBA6KYDIRtqmgS6iKyy8v2D1aSY5mc9J0T5t9S2Gv+VZQNWQDDKNFnxqYaAo1uEoq/i1q63XC5AD3ckXb2VT6dp23BQMdDfbHyUWfJN cloud_env: rackspace + vpp_source_repo_url: https://gerrit.fd.io/r/vpp + vpp_source_repo_branch: stable/1704 + hc2vpp_source_repo_url: https://gerrit.fd.io/r/hc2vpp + hc2vpp_source_repo_branch: stable/1704 + vpp_patch_url: https://gerrit.onap.org/r/#/c/11083/5/vnfs/vCPE/vpp-ves-agent-for-vgmux/src/patches/Vpp-Add-VES-agent-for-vG-MUX.patch + h2vpp_patch_url: https://gerrit.onap.org/r/#/c/11083/5/vnfs/vCPE/vpp-ves-agent-for-vgmux/src/patches/Hc2vpp-Add-VES-agent-for-vG-MUX.patch diff --git a/heat/vCPE/vgmux/base_vcpe_vgmux_rackspace.yaml b/heat/vCPE/vgmux/base_vcpe_vgmux_rackspace.yaml index b6e212a1..6cbaef11 100644 --- a/heat/vCPE/vgmux/base_vcpe_vgmux_rackspace.yaml +++ b/heat/vCPE/vgmux/base_vcpe_vgmux_rackspace.yaml @@ -133,6 +133,30 @@ parameters: type: string label: Cloud environment description: Cloud environment (e.g., openstack, rackspace) + vpp_source_repo_url: + type: string + label: VPP Source Git Repo + description: URL for VPP source codes + vpp_source_repo_branch: + type: string + label: VPP Source Git Branch + description: Git Branch for the VPP source codes + hc2vpp_source_repo_url: + type: string + label: Honeycomb Source Git Repo + description: URL for Honeycomb source codes + hc2vpp_source_repo_branch: + type: string + label: Honeycomb Source Git Branch + description: Git Branch for the Honeycomb source codes + vpp_patch_url: + type: string + label: VPP Patch URL + description: URL for VPP patch for vG-MUX + hc2vpp_patch_url: + type: string + label: Honeycomb Patch URL + description: URL for Honeycomb patch for vG-MUX ############# # # @@ -230,6 +254,12 @@ resources: __demo_artifacts_version__ : { get_param: demo_artifacts_version } __install_script_version__ : { get_param: install_script_version } __cloud_env__ : { get_param: cloud_env } + __vpp_source_repo_url__ : { get_param: vpp_source_repo_url } + __vpp_source_repo_branch__ : { get_param: vpp_source_repo_branch } + __hc2vpp_source_repo_url__ : { get_param: hc2vpp_source_repo_url } + __hc2vpp_source_repo_branch__ : { get_param: hc2vpp_source_repo_branch } + __vpp_patch_url__ : { get_param: vpp_patch_url } + __hc2vpp_patch_url__ : { get_param: hc2vpp_patch_url } template: | #!/bin/bash @@ -246,6 +276,12 @@ resources: echo "__demo_artifacts_version__" > /opt/config/demo_artifacts_version.txt echo "__install_script_version__" > /opt/config/install_script_version.txt echo "__cloud_env__" > /opt/config/cloud_env.txt + echo "__vpp_source_repo_url__" > /opt/config/vpp_source_repo_url.txt + echo "__vpp_source_repo_branch__" > /opt/config/vpp_source_repo_branch.txt + echo "__vpp_patch_url__" > /opt/config/vpp_patch_url.txt + echo "__hc2vpp_source_repo_url__" > /opt/config/hc2vpp_source_repo_url.txt + echo "__hc2vpp_source_repo_branch__" > /opt/config/hc2vpp_source_repo_branch.txt + echo "__hc2vpp_patch_url__" > /opt/config/hc2vpp_patch_url.txt # Download and run install script curl -k __repo_url_blob__/org.onap.demo/vnfs/vcpe/__install_script_version__/v_gmux_install.sh -o /opt/v_gmux_install.sh diff --git a/heat/vCPE/vgw/base_vcpe_vgw_rackspace.env b/heat/vCPE/vgw/base_vcpe_vgw_rackspace.env index 33da8d73..c2a1b643 100644 --- a/heat/vCPE/vgw/base_vcpe_vgw_rackspace.env +++ b/heat/vCPE/vgw/base_vcpe_vgw_rackspace.env @@ -12,7 +12,7 @@ vgw_private_ip_0: 10.5.0.21 vgw_private_ip_1: 10.0.101.30 vgw_private_ip_2: 10.2.0.2 - vgw_name_0: zdcpe11cpe01gw01 + vgw_name_0: zdcpe1cpe01gw01 vnf_id: vCPE_Infrastructure_GW_demo_app vf_module_id: vCPE_Customer_GW dcae_collector_ip: 10.0.4.102 @@ -24,3 +24,7 @@ key_name: vgw_key pub_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQXYJYYi3/OUZXUiCYWdtc7K0m5C0dJKVxPG0eI8EWZrEHYdfYe6WoTSDJCww+1qlBSpA5ac/Ba4Wn9vh+lR1vtUKkyIC/nrYb90ReUd385Glkgzrfh5HdR5y5S2cL/Frh86lAn9r6b3iWTJD8wBwXFyoe1S2nMTOIuG4RPNvfmyCTYVh8XTCCE8HPvh3xv2r4egawG1P4Q4UDwk+hDBXThY2KS8M5/8EMyxHV0ImpLbpYCTBA6KYDIRtqmgS6iKyy8v2D1aSY5mc9J0T5t9S2Gv+VZQNWQDDKNFnxqYaAo1uEoq/i1q63XC5AD3ckXb2VT6dp23BQMdDfbHyUWfJN cloud_env: rackspace + vpp_source_repo_url: https://gerrit.fd.io/r/vpp + vpp_source_repo_branch: stable/1704 + hc2vpp_source_repo_url: https://gerrit.fd.io/r/hc2vpp + hc2vpp_source_repo_branch: stable/1704 diff --git a/heat/vCPE/vgw/base_vcpe_vgw_rackspace.yaml b/heat/vCPE/vgw/base_vcpe_vgw_rackspace.yaml index 0621556a..d8fe4cde 100644 --- a/heat/vCPE/vgw/base_vcpe_vgw_rackspace.yaml +++ b/heat/vCPE/vgw/base_vcpe_vgw_rackspace.yaml @@ -133,6 +133,22 @@ parameters: type: string label: Cloud environment description: Cloud environment (e.g., openstack, rackspace) + vpp_source_repo_url: + type: string + label: VPP Source Git Repo + description: URL for VPP source codes + vpp_source_repo_branch: + type: string + label: VPP Source Git Branch + description: Git Branch for the VPP source codes + hc2vpp_source_repo_url: + type: string + label: Honeycomb Source Git Repo + description: URL for Honeycomb source codes + hc2vpp_source_repo_branch: + type: string + label: Honeycomb Source Git Branch + description: Git Branch for the Honeycomb source codes ############# # # @@ -207,6 +223,10 @@ resources: __demo_artifacts_version__ : { get_param: demo_artifacts_version } __install_script_version__ : { get_param: install_script_version } __cloud_env__ : { get_param: cloud_env } + __vpp_source_repo_url__ : { get_param: vpp_source_repo_url } + __vpp_source_repo_branch__ : { get_param: vpp_source_repo_branch } + __hc2vpp_source_repo_url__ : { get_param: hc2vpp_source_repo_url } + __hc2vpp_source_repo_branch__ : { get_param: hc2vpp_source_repo_branch } template: | #!/bin/bash @@ -222,6 +242,10 @@ resources: echo "__demo_artifacts_version__" > /opt/config/demo_artifacts_version.txt echo "__install_script_version__" > /opt/config/install_script_version.txt echo "__cloud_env__" > /opt/config/cloud_env.txt + echo "__vpp_source_repo_url__" > /opt/config/vpp_source_repo_url.txt + echo "__vpp_source_repo_branch__" > /opt/config/vpp_source_repo_branch.txt + echo "__hc2vpp_source_repo_url__" > /opt/config/hc2vpp_source_repo_url.txt + echo "__hc2vpp_source_repo_branch__" > /opt/config/hc2vpp_source_repo_branch.txt # Download and run install script curl -k __repo_url_blob__/org.onap.demo/vnfs/vcpe/__install_script_version__/v_gw_install.sh -o /opt/v_gw_install.sh diff --git a/heat/vFW/.DS_Store b/heat/vFW/.DS_Store Binary files differdeleted file mode 100644 index e2759ef9..00000000 --- a/heat/vFW/.DS_Store +++ /dev/null diff --git a/heat/vFW/base_vfw_openstack.env b/heat/vFW/base_vfw.env index 7040f867..9790d0e8 100644 --- a/heat/vFW/base_vfw_openstack.env +++ b/heat/vFW/base_vfw.env @@ -29,4 +29,4 @@ parameters: install_script_version: 1.1.0-SNAPSHOT
key_name: vfw_key
pub_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQXYJYYi3/OUZXUiCYWdtc7K0m5C0dJKVxPG0eI8EWZrEHYdfYe6WoTSDJCww+1qlBSpA5ac/Ba4Wn9vh+lR1vtUKkyIC/nrYb90ReUd385Glkgzrfh5HdR5y5S2cL/Frh86lAn9r6b3iWTJD8wBwXFyoe1S2nMTOIuG4RPNvfmyCTYVh8XTCCE8HPvh3xv2r4egawG1P4Q4UDwk+hDBXThY2KS8M5/8EMyxHV0ImpLbpYCTBA6KYDIRtqmgS6iKyy8v2D1aSY5mc9J0T5t9S2Gv+VZQNWQDDKNFnxqYaAo1uEoq/i1q63XC5AD3ckXb2VT6dp23BQMdDfbHyUWfJN
- cloud_env: openstack
+ cloud_env: PUT openstack OR rackspace HERE
diff --git a/heat/vFW/base_vfw_openstack.yaml b/heat/vFW/base_vfw.yaml index 4900c55c..77b53a83 100644 --- a/heat/vFW/base_vfw_openstack.yaml +++ b/heat/vFW/base_vfw.yaml @@ -208,16 +208,13 @@ resources: vfw_private_0_port:
type: OS::Neutron::Port
properties:
- security_groups: []
- port_security_enabled: False
network: { get_resource: unprotected_private_network }
fixed_ips: [{"subnet": { get_resource: unprotected_private_subnet }, "ip_address": { get_param: vfw_private_ip_0 }}]
vfw_private_1_port:
type: OS::Neutron::Port
properties:
- security_groups: []
- port_security_enabled: False
+ allowed_address_pairs: [{ "ip_address": { get_param: vpg_private_ip_0 }}]
network: { get_resource: protected_private_network }
fixed_ips: [{"subnet": { get_resource: protected_private_subnet }, "ip_address": { get_param: vfw_private_ip_1 }}]
diff --git a/heat/vFW/base_vfw_rackspace.env b/heat/vFW/base_vfw_rackspace.env deleted file mode 100644 index 0f6175d1..00000000 --- a/heat/vFW/base_vfw_rackspace.env +++ /dev/null @@ -1,32 +0,0 @@ -parameters: - vfw_image_name: Ubuntu 14.04 LTS (Trusty Tahr) (PVHVM) - vfw_flavor_name: 4 GB General Purpose v1 - public_net_id: 00000000-0000-0000-0000-000000000000 - unprotected_private_net_id: zdfw1fwl01_unprotected - protected_private_net_id: zdfw1fwl01_protected - onap_private_net_id: PUT THE ONAP PRIVATE NETWORK NAME HERE - onap_private_subnet_id: PUT THE ONAP PRIVATE NETWORK NAME HERE - unprotected_private_net_cidr: 192.168.10.0/24 - protected_private_net_cidr: 192.168.20.0/24 - onap_private_net_cidr: 10.0.0.0/16 - vfw_private_ip_0: 192.168.10.100 - vfw_private_ip_1: 192.168.20.100 - vfw_private_ip_2: 10.0.100.1 - vpg_private_ip_0: 192.168.10.200 - vpg_private_ip_1: 10.0.100.2 - vsn_private_ip_0: 192.168.20.250 - vsn_private_ip_1: 10.0.100.3 - vfw_name_0: zdfw1fwl01fwl01 - vpg_name_0: zdfw1fwl01pgn01 - vsn_name_0: zdfw1fwl01snk01 - vnf_id: vFirewall_demo_app - vf_module_id: vFirewall - dcae_collector_ip: 10.0.4.102 - dcae_collector_port: 8080 - repo_url_blob: https://nexus.onap.org/content/sites/raw - repo_url_artifacts: https://nexus.onap.org/content/groups/staging - demo_artifacts_version: 1.1.0 - install_script_version: 1.1.0-SNAPSHOT - key_name: vfw_key - pub_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQXYJYYi3/OUZXUiCYWdtc7K0m5C0dJKVxPG0eI8EWZrEHYdfYe6WoTSDJCww+1qlBSpA5ac/Ba4Wn9vh+lR1vtUKkyIC/nrYb90ReUd385Glkgzrfh5HdR5y5S2cL/Frh86lAn9r6b3iWTJD8wBwXFyoe1S2nMTOIuG4RPNvfmyCTYVh8XTCCE8HPvh3xv2r4egawG1P4Q4UDwk+hDBXThY2KS8M5/8EMyxHV0ImpLbpYCTBA6KYDIRtqmgS6iKyy8v2D1aSY5mc9J0T5t9S2Gv+VZQNWQDDKNFnxqYaAo1uEoq/i1q63XC5AD3ckXb2VT6dp23BQMdDfbHyUWfJN - cloud_env: rackspace diff --git a/heat/vFW/base_vfw_rackspace.yaml b/heat/vFW/base_vfw_rackspace.yaml deleted file mode 100644 index 51ac2861..00000000 --- a/heat/vFW/base_vfw_rackspace.yaml +++ /dev/null @@ -1,377 +0,0 @@ -########################################################################## -# -#==================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 is a trademark and service mark of AT&T Intellectual Property. -# -########################################################################## - -heat_template_version: 2013-05-23 - -description: Heat template that deploys vFirewall demo app for ONAP - -############## -# # -# PARAMETERS # -# # -############## - -parameters: - vfw_image_name: - type: string - label: Image name or ID - description: Image to be used for compute instance - vfw_flavor_name: - type: string - label: Flavor - description: Type of instance (flavor) to be used - public_net_id: - type: string - label: Public network name or ID - description: Public network that enables remote connection to VNF - unprotected_private_net_id: - type: string - label: Unprotected private network name or ID - description: Private network that connects vPacketGenerator with vFirewall - protected_private_net_id: - type: string - label: Protected private network name or ID - description: Private network that connects vFirewall with vSink - onap_private_net_id: - type: string - label: ONAP management network name or ID - description: Private network that connects ONAP components and the VNF - onap_private_subnet_id: - type: string - label: ONAP management sub-network name or ID - description: Private sub-network that connects ONAP components and the VNF - unprotected_private_net_cidr: - type: string - label: Unprotected private network CIDR - description: The CIDR of the unprotected private network - protected_private_net_cidr: - type: string - label: Protected private network CIDR - description: The CIDR of the protected private network - onap_private_net_cidr: - type: string - label: ONAP private network CIDR - description: The CIDR of the protected private network - vfw_private_ip_0: - type: string - label: vFirewall private IP address towards the unprotected network - description: Private IP address that is assigned to the vFirewall to communicate with the vPacketGenerator - vfw_private_ip_1: - type: string - label: vFirewall private IP address towards the protected network - description: Private IP address that is assigned to the vFirewall to communicate with the vSink - vfw_private_ip_2: - type: string - label: vFirewall private IP address towards the ONAP management network - description: Private IP address that is assigned to the vFirewall to communicate with ONAP components - vpg_private_ip_0: - type: string - label: vPacketGenerator private IP address towards the unprotected network - description: Private IP address that is assigned to the vPacketGenerator to communicate with the vFirewall - vpg_private_ip_1: - type: string - label: vPacketGenerator private IP address towards the ONAP management network - description: Private IP address that is assigned to the vPacketGenerator to communicate with ONAP components - vsn_private_ip_0: - type: string - label: vSink private IP address towards the protected network - description: Private IP address that is assigned to the vSink to communicate with the vFirewall - vsn_private_ip_1: - type: string - label: vSink private IP address towards the ONAP management network - description: Private IP address that is assigned to the vSink to communicate with ONAP components - vfw_name_0: - type: string - label: vFirewall name - description: Name of the vFirewall - vpg_name_0: - type: string - label: vPacketGenerator name - description: Name of the vPacketGenerator - vsn_name_0: - type: string - label: vSink name - description: Name of the vSink - vnf_id: - type: string - label: VNF ID - description: The VNF ID is provided by ECOMP - vf_module_id: - type: string - label: vFirewall module ID - description: The vFirewall Module ID is provided by ECOMP - dcae_collector_ip: - type: string - label: DCAE collector IP address - description: IP address of the DCAE collector - dcae_collector_port: - type: string - label: DCAE collector port - description: Port of the DCAE collector - key_name: - type: string - label: Key pair name - description: Public/Private key pair name - pub_key: - type: string - label: Public key - description: Public key to be installed on the compute instance - repo_url_blob: - type: string - label: Repository URL - description: URL of the repository that hosts the demo packages - repo_url_artifacts: - type: string - label: Repository URL - description: URL of the repository that hosts the demo packages - install_script_version: - type: string - label: Installation script version number - description: Version number of the scripts that install the vFW demo app - demo_artifacts_version: - type: string - label: Artifacts version used in demo vnfs - description: Artifacts (jar, tar.gz) version used in demo vnfs - cloud_env: - type: string - label: Cloud environment - description: Cloud environment (e.g., openstack, rackspace) - -############# -# # -# RESOURCES # -# # -############# - -resources: - random-str: - type: OS::Heat::RandomString - properties: - length: 4 - - my_keypair: - type: OS::Nova::KeyPair - properties: - name: - str_replace: - template: base_rand - params: - base: { get_param: key_name } - rand: { get_resource: random-str } - public_key: { get_param: pub_key } - save_private_key: false - - unprotected_private_network: - type: OS::Neutron::Net - properties: - name: { get_param: unprotected_private_net_id } - - protected_private_network: - type: OS::Neutron::Net - properties: - name: { get_param: protected_private_net_id } - - unprotected_private_subnet: - type: OS::Neutron::Subnet - properties: - network_id: { get_resource: unprotected_private_network } - cidr: { get_param: unprotected_private_net_cidr } - - protected_private_subnet: - type: OS::Neutron::Subnet - properties: - network_id: { get_resource: protected_private_network } - cidr: { get_param: protected_private_net_cidr } - - # Virtual Firewall instantiation - vfw_private_0_port: - type: OS::Neutron::Port - properties: - network: { get_resource: unprotected_private_network } - fixed_ips: [{"subnet": { get_resource: unprotected_private_subnet }, "ip_address": { get_param: vfw_private_ip_0 }}] - - vfw_private_1_port: - type: OS::Neutron::Port - properties: - network: { get_resource: protected_private_network } - fixed_ips: [{"subnet": { get_resource: protected_private_subnet }, "ip_address": { get_param: vfw_private_ip_1 }}] - - vfw_private_2_port: - type: OS::Neutron::Port - properties: - network: { get_param: onap_private_net_id } - fixed_ips: [{"subnet": { get_param: onap_private_subnet_id }, "ip_address": { get_param: vfw_private_ip_2 }}] - - vfw_0: - type: OS::Nova::Server - properties: - image: { get_param: vfw_image_name } - flavor: { get_param: vfw_flavor_name } - name: { get_param: vfw_name_0 } - key_name: { get_resource: my_keypair } - networks: - - network: { get_param: public_net_id } - - port: { get_resource: vfw_private_0_port } - - port: { get_resource: vfw_private_1_port } - - port: { get_resource: vfw_private_2_port } - metadata: {vnf_id: { get_param: vnf_id }, vf_module_id: { get_param: vf_module_id }} - user_data_format: RAW - user_data: - str_replace: - params: - __dcae_collector_ip__ : { get_param: dcae_collector_ip } - __dcae_collector_port__ : { get_param: dcae_collector_port } - __repo_url_blob__ : { get_param: repo_url_blob } - __repo_url_artifacts__ : { get_param: repo_url_artifacts } - __demo_artifacts_version__ : { get_param: demo_artifacts_version } - __install_script_version__ : { get_param: install_script_version } - __cloud_env__ : { get_param: cloud_env } - template: | - #!/bin/bash - - # Create configuration files - mkdir /opt/config - echo "__dcae_collector_ip__" > /opt/config/dcae_collector_ip.txt - echo "__dcae_collector_port__" > /opt/config/dcae_collector_port.txt - echo "__repo_url_blob__" > /opt/config/repo_url_blob.txt - echo "__repo_url_artifacts__" > /opt/config/repo_url_artifacts.txt - echo "__demo_artifacts_version__" > /opt/config/demo_artifacts_version.txt - echo "__install_script_version__" > /opt/config/install_script_version.txt - echo "__cloud_env__" > /opt/config/cloud_env.txt - - # Download and run install script - curl -k __repo_url_blob__/org.onap.demo/vnfs/vfw/__install_script_version__/v_firewall_install.sh -o /opt/v_firewall_install.sh - cd /opt - chmod +x v_firewall_install.sh - ./v_firewall_install.sh - - - # Virtual Packet Generator instantiation - vpg_private_0_port: - type: OS::Neutron::Port - properties: - network: { get_resource: unprotected_private_network } - fixed_ips: [{"subnet": { get_resource: unprotected_private_subnet }, "ip_address": { get_param: vpg_private_ip_0 }}] - - vpg_private_1_port: - type: OS::Neutron::Port - properties: - network: { get_param: onap_private_net_id } - fixed_ips: [{"subnet": { get_param: onap_private_subnet_id }, "ip_address": { get_param: vpg_private_ip_1 }}] - - vpg_0: - type: OS::Nova::Server - properties: - image: { get_param: vfw_image_name } - flavor: { get_param: vfw_flavor_name } - name: { get_param: vpg_name_0 } - key_name: { get_resource: my_keypair } - networks: - - network: { get_param: public_net_id } - - port: { get_resource: vpg_private_0_port } - - port: { get_resource: vpg_private_1_port } - metadata: {vnf_id: { get_param: vnf_id }, vf_module_id: { get_param: vf_module_id }} - user_data_format: RAW - user_data: - str_replace: - params: - __fw_ipaddr__: { get_param: vfw_private_ip_0 } - __protected_net_cidr__: { get_param: protected_private_net_cidr } - __sink_ipaddr__: { get_param: vsn_private_ip_0 } - __repo_url_blob__ : { get_param: repo_url_blob } - __repo_url_artifacts__ : { get_param: repo_url_artifacts } - __demo_artifacts_version__ : { get_param: demo_artifacts_version } - __install_script_version__ : { get_param: install_script_version } - __cloud_env__ : { get_param: cloud_env } - template: | - #!/bin/bash - - # Create configuration files - mkdir /opt/config - echo "__fw_ipaddr__" > /opt/config/fw_ipaddr.txt - echo "__protected_net_cidr__" > /opt/config/protected_net_cidr.txt - echo "__sink_ipaddr__" > /opt/config/sink_ipaddr.txt - echo "__repo_url_blob__" > /opt/config/repo_url_blob.txt - echo "__repo_url_artifacts__" > /opt/config/repo_url_artifacts.txt - echo "__demo_artifacts_version__" > /opt/config/demo_artifacts_version.txt - echo "__install_script_version__" > /opt/config/install_script_version.txt - echo "__cloud_env__" > /opt/config/cloud_env.txt - - # Download and run install script - curl -k __repo_url_blob__/org.onap.demo/vnfs/vfw/__install_script_version__/v_packetgen_install.sh -o /opt/v_packetgen_install.sh - cd /opt - chmod +x v_packetgen_install.sh - ./v_packetgen_install.sh - - - # Virtual Sink instantiation - vsn_private_0_port: - type: OS::Neutron::Port - properties: - network: { get_resource: protected_private_network } - fixed_ips: [{"subnet": { get_resource: protected_private_subnet }, "ip_address": { get_param: vsn_private_ip_0 }}] - - vsn_private_1_port: - type: OS::Neutron::Port - properties: - network: { get_param: onap_private_net_id } - fixed_ips: [{"subnet": { get_param: onap_private_subnet_id }, "ip_address": { get_param: vsn_private_ip_1 }}] - - vsn_0: - type: OS::Nova::Server - properties: - image: { get_param: vfw_image_name } - flavor: { get_param: vfw_flavor_name } - name: { get_param: vsn_name_0 } - key_name: { get_resource: my_keypair } - networks: - - network: { get_param: public_net_id } - - port: { get_resource: vsn_private_0_port } - - port: { get_resource: vsn_private_1_port } - metadata: {vnf_id: { get_param: vnf_id }, vf_module_id: { get_param: vf_module_id }} - user_data_format: RAW - user_data: - str_replace: - params: - __protected_net_gw__: { get_param: vfw_private_ip_1 } - __unprotected_net__: { get_param: unprotected_private_net_cidr } - __repo_url_blob__ : { get_param: repo_url_blob } - __install_script_version__ : { get_param: install_script_version } - __cloud_env__ : { get_param: cloud_env } - template: | - #!/bin/bash - - # Create configuration files - mkdir /opt/config - echo "__protected_net_gw__" > /opt/config/protected_net_gw.txt - echo "__unprotected_net__" > /opt/config/unprotected_net.txt - echo "__repo_url_blob__" > /opt/config/repo_url_blob.txt - echo "__install_script_version__" > /opt/config/install_script_version.txt - echo "__cloud_env__" > /opt/config/cloud_env.txt - - # Download and run install script - curl -k __repo_url_blob__/org.onap.demo/vnfs/vfw/__install_script_version__/v_sink_install.sh -o /opt/v_sink_install.sh - cd /opt - chmod +x v_sink_install.sh - ./v_sink_install.sh
\ No newline at end of file diff --git a/heat/vLB/base_vlb_openstack.env b/heat/vLB/base_vlb.env index afcfccfd..50da384f 100644 --- a/heat/vLB/base_vlb_openstack.env +++ b/heat/vLB/base_vlb.env @@ -3,16 +3,25 @@ parameters: vlb_flavor_name: PUT THE FLAVOR NAME HERE public_net_id: PUT THE NETWORK ID HERE vlb_private_net_id: zdfw1lb01_private + pktgen_private_net_id: zdfw1pktgen01_private onap_private_net_id: PUT THE ONAP PRIVATE NETWORK NAME HERE onap_private_subnet_id: PUT THE ONAP PRIVATE NETWORK NAME HERE vlb_private_net_cidr: 192.168.10.0/24 + pktgen_private_net_cidr: 192.168.9.0/24 onap_private_net_cidr: PUT THE ONAP NETWORK CIDR HERE vlb_private_ip_0: 192.168.10.111 vlb_private_ip_1: ASSIGN A PRIVATE ADDRESS IN THE ONAP NETWORK SPACE TO THE VLB + vlb_private_ip_2: 192.168.9.111 vdns_private_ip_0: 192.168.10.211 vdns_private_ip_1: ASSIGN A PRIVATE ADDRESS IN THE ONAP NETWORK SPACE TO THE VDNS + vpg_private_ip_0: 192.168.9.110 + vpg_private_ip_1: ASSIGN A PRIVATE ADDRESS IN THE ONAP NETWORK SPACE TO THE VPKTGEN + vip: 192.168.9.112 + gre_ipaddr: 192.168.10.112 + pg_int: 192.168.9.109 vlb_name_0: zdfw1lb01lb01 vdns_name_0: zdfw1lb01dns01 + vpg_name_0: zdfw1lb01pg01 vnf_id: vLoadBalancer_demo_app vf_module_id: vLoadBalancer dcae_collector_ip: PUT THE ADDRESS OF THE DCAE COLLECTOR HERE @@ -23,4 +32,4 @@ parameters: install_script_version: 1.1.0-SNAPSHOT key_name: vlb_key pub_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQXYJYYi3/OUZXUiCYWdtc7K0m5C0dJKVxPG0eI8EWZrEHYdfYe6WoTSDJCww+1qlBSpA5ac/Ba4Wn9vh+lR1vtUKkyIC/nrYb90ReUd385Glkgzrfh5HdR5y5S2cL/Frh86lAn9r6b3iWTJD8wBwXFyoe1S2nMTOIuG4RPNvfmyCTYVh8XTCCE8HPvh3xv2r4egawG1P4Q4UDwk+hDBXThY2KS8M5/8EMyxHV0ImpLbpYCTBA6KYDIRtqmgS6iKyy8v2D1aSY5mc9J0T5t9S2Gv+VZQNWQDDKNFnxqYaAo1uEoq/i1q63XC5AD3ckXb2VT6dp23BQMdDfbHyUWfJN - cloud_env: openstack + cloud_env: PUT openstack OR backspace HERE diff --git a/heat/vLB/base_vlb_openstack.yaml b/heat/vLB/base_vlb.yaml index 18a0d76e..fa4fea0a 100644 --- a/heat/vLB/base_vlb_openstack.yaml +++ b/heat/vLB/base_vlb.yaml @@ -49,6 +49,10 @@ parameters: type: string label: vLoadBalancer private network name or ID description: Private network that connects vLoadBalancer with vDNSs + pktgen_private_net_id: + type: string + label: vPacketGen private network name or ID + description: Private network that connects vLoadBalancer with vPacketGen onap_private_net_id: type: string label: ECOMP management network name or ID @@ -61,6 +65,10 @@ parameters: type: string label: vLoadBalancer private network CIDR description: The CIDR of the vLoadBalancer private network + pktgen_private_net_cidr: + type: string + label: vPacketGen private network CIDR + description: The CIDR of the vPacketGen private network onap_private_net_cidr: type: string label: ONAP private network CIDR @@ -73,6 +81,10 @@ parameters: type: string label: vLoadBalancer private IP address towards the ONAP management network description: Private IP address that is assigned to the vLoadBalancer to communicate with ONAP components + vlb_private_ip_2: + type: string + label: vLoadBalancer private IP address towards the vPacketGen network + description: Private IP address that is assigned to the vLoadBalancer to communicate with vPacketGen vdns_private_ip_0: type: string label: vDNS private IP address towards the private network @@ -81,6 +93,26 @@ parameters: type: string label: vDNS private IP address towards the ONAP management network description: Private IP address that is assigned to the vDNS to communicate with ONAP components + vpg_private_ip_0: + type: string + label: vPacketGen private IP address towards the vPacketGen private network + description: Private IP address that is assigned to the vPacketGen to communicate with the vLoadBalancer + vpg_private_ip_1: + type: string + label: vPacketGen private IP address towards the ONAP management network + description: Private IP address that is assigned to the vPacketGen to communicate with ONAP components + vip: + type: string + label: Virtual Private IP of the vLoadBalancer + description: Virtual Private IP that is assigned to the vLoadBalancer's VPP layer + gre_ipaddr: + type: string + label: IP Address of the GRE tunnel + description: IP address assigned to the GRE tunnel on the vLoadBalancer + pg_int: + type: string + label: IP Address of the output vPacketGen interface + description: IP address assigned to the output interface of the vPacketGen's VPP layer vlb_name_0: type: string label: vLoadBalancer name @@ -89,6 +121,10 @@ parameters: type: string label: vDNS name description: Name of the vDNS + vpg_name_0: + type: string + label: vPKTGEN name + description: Name of the vPKTGEN vnf_id: type: string label: VNF ID @@ -171,6 +207,18 @@ resources: network_id: { get_resource: vlb_private_network } cidr: { get_param: vlb_private_net_cidr } + pktgen_private_network: + type: OS::Neutron::Net + properties: + name: { get_param: pktgen_private_net_id } + + pktgen_private_subnet: + type: OS::Neutron::Subnet + properties: + name: { get_param: pktgen_private_net_id } + network_id: { get_resource: pktgen_private_network } + cidr: { get_param: pktgen_private_net_cidr } + vlb_private_0_port: type: OS::Neutron::Port properties: @@ -183,6 +231,12 @@ resources: network: { get_param: onap_private_net_id } fixed_ips: [{"subnet": { get_param: onap_private_subnet_id }, "ip_address": { get_param: vlb_private_ip_1 }}] + vlb_private_2_port: + type: OS::Neutron::Port + properties: + network: { get_resource: pktgen_private_network } + fixed_ips: [{"subnet": { get_resource: pktgen_private_subnet }, "ip_address": { get_param: vlb_private_ip_2 }}] + vlb_0: type: OS::Nova::Server properties: @@ -194,6 +248,7 @@ resources: - network: { get_param: public_net_id } - port: { get_resource: vlb_private_0_port } - port: { get_resource: vlb_private_1_port } + - port: { get_resource: vlb_private_2_port } metadata: {vnf_id: { get_param: vnf_id }, vf_module_id: { get_param: vf_module_id }} user_data_format: RAW user_data: @@ -201,7 +256,11 @@ resources: params: __dcae_collector_ip__: { get_param: dcae_collector_ip } __dcae_collector_port__: { get_param: dcae_collector_port } - __local_private_ipaddr__: { get_param: vlb_private_ip_0 } + __ip_to_dns_net__: { get_param: vlb_private_ip_0 } + __ip_to_pktgen_net__: { get_param: vlb_private_ip_2 } + __vip__: { get_param: vip } + __gre_ipaddr__: { get_param: gre_ipaddr } + __pktgen_ipaddr__: { get_param: vpg_private_ip_0 } __oam_private_ipaddr__: { get_param: vlb_private_ip_1 } __repo_url_blob__: { get_param: repo_url_blob } __repo_url_artifacts__: { get_param: repo_url_artifacts } @@ -209,6 +268,8 @@ resources: __install_script_version__: { get_param: install_script_version } __vlb_private_net_cidr__: { get_param: vlb_private_net_cidr } __onap_private_net_cidr__: { get_param: onap_private_net_cidr } + __pktgen_private_net_cidr__: { get_param: pktgen_private_net_cidr } + __pktgen_mac__: { get_attr: [vpg_private_0_port, mac_address] } __cloud_env__: { get_param: cloud_env } template: | #!/bin/bash @@ -217,14 +278,20 @@ resources: mkdir /opt/config echo "__dcae_collector_ip__" > /opt/config/dcae_collector_ip.txt echo "__dcae_collector_port__" > /opt/config/dcae_collector_port.txt - echo "__local_private_ipaddr__" > /opt/config/local_private_ipaddr.txt + echo "__ip_to_dns_net__" > /opt/config/ip_to_dns_net.txt + echo "__ip_to_pktgen_net__" > /opt/config/ip_to_pktgen_net.txt + echo "__vip__" > /opt/config/vip.txt + echo "__gre_ipaddr__" > /opt/config/gre_ipaddr.txt + echo "__pktgen_ipaddr__" > /opt/config/pktgen_ipaddr.txt echo "__oam_private_ipaddr__" > /opt/config/oam_private_ipaddr.txt echo "__repo_url_blob__" > /opt/config/repo_url_blob.txt echo "__repo_url_artifacts__" > /opt/config/repo_url_artifacts.txt echo "__demo_artifacts_version__" > /opt/config/demo_artifacts_version.txt echo "__install_script_version__" > /opt/config/install_script_version.txt echo "__vlb_private_net_cidr__" > /opt/config/vlb_private_net_cidr.txt + echo "__pktgen_private_net_cidr__" > /opt/config/pktgen_private_net_cidr.txt echo "__onap_private_net_cidr__" > /opt/config/onap_private_net_cidr.txt + echo "__pktgen_mac__" > /opt/config/pktgen_mac.txt echo "__cloud_env__" > /opt/config/cloud_env.txt # Download and run install script @@ -294,4 +361,68 @@ resources: curl -k __repo_url_blob__/org.onap.demo/vnfs/vlb/__install_script_version__/v_dns_install.sh -o /opt/v_dns_install.sh cd /opt chmod +x v_dns_install.sh - ./v_dns_install.sh
\ No newline at end of file + ./v_dns_install.sh + + + vpg_private_0_port: + type: OS::Neutron::Port + properties: + network: { get_resource: pktgen_private_network } + fixed_ips: [{"subnet": { get_resource: pktgen_private_subnet }, "ip_address": { get_param: vpg_private_ip_0 }}] + + vpg_private_1_port: + type: OS::Neutron::Port + properties: + network: { get_param: onap_private_net_id } + fixed_ips: [{"subnet": { get_param: onap_private_subnet_id }, "ip_address": { get_param: vpg_private_ip_1 }}] + + vpg_0: + type: OS::Nova::Server + properties: + image: { get_param: vlb_image_name } + flavor: { get_param: vlb_flavor_name } + name: { get_param: vpg_name_0 } + key_name: { get_resource: my_keypair } + networks: + - network: { get_param: public_net_id } + - port: { get_resource: vpg_private_0_port } + - port: { get_resource: vpg_private_1_port } + user_data_format: RAW + user_data: + str_replace: + params: + __repo_url_blob__: { get_param: repo_url_blob } + __repo_url_artifacts__: { get_param: repo_url_artifacts } + __local_private_ipaddr__: { get_param: vpg_private_ip_0 } + __oam_private_ipaddr__: { get_param: vpg_private_ip_1 } + __onap_private_net_cidr__: { get_param: onap_private_net_cidr } + __pktgen_private_net_cidr__: { get_param: pktgen_private_net_cidr } + __vlb_ipaddr__: { get_param: vlb_private_ip_2 } + __demo_artifacts_version__: { get_param: demo_artifacts_version } + __install_script_version__: { get_param: install_script_version } + __pg_int__: { get_param: pg_int } + __vlb_mac__: { get_attr: [vlb_private_2_port, mac_address] } + __cloud_env__: { get_param: cloud_env } + template: | + #!/bin/bash + + # Create configuration files + mkdir /opt/config + echo "__oam_private_ipaddr__" > /opt/config/oam_private_ipaddr.txt + echo "__onap_private_net_cidr__" > /opt/config/onap_private_net_cidr.txt + echo "__local_private_ipaddr__" > /opt/config/local_private_ipaddr.txt + echo "__pktgen_private_net_cidr__" > /opt/config/pktgen_private_net_cidr.txt + echo "__vlb_ipaddr__" > /opt/config/vlb_ipaddr.txt + echo "__repo_url_blob__" > /opt/config/repo_url_blob.txt + echo "__repo_url_artifacts__" > /opt/config/repo_url_artifacts.txt + echo "__demo_artifacts_version__" > /opt/config/demo_artifacts_version.txt + echo "__install_script_version__" > /opt/config/install_script_version.txt + echo "__pg_int__" > /opt/config/pg_int.txt + echo "__vlb_mac__" > /opt/config/vlb_mac.txt + echo "__cloud_env__" > /opt/config/cloud_env.txt + + # Download and run install script + curl -k __repo_url_blob__/org.onap.demo/vnfs/vlb/__install_script_version__/v_packetgen_install.sh -o /opt/v_packetgen_install.sh + cd /opt + chmod +x v_packetgen_install.sh + ./v_packetgen_install.sh
\ No newline at end of file diff --git a/heat/vLB/base_vlb_rackspace.env b/heat/vLB/base_vlb_rackspace.env deleted file mode 100644 index e4c31843..00000000 --- a/heat/vLB/base_vlb_rackspace.env +++ /dev/null @@ -1,26 +0,0 @@ -parameters: - vlb_image_name: Ubuntu 14.04 LTS (Trusty Tahr) (PVHVM) - vlb_flavor_name: 4 GB General Purpose v1 - public_net_id: 00000000-0000-0000-0000-000000000000 - vlb_private_net_id: zdfw1lb01_private - onap_private_net_id: PUT THE ONAP PRIVATE NETWORK NAME HERE - onap_private_subnet_id: PUT THE ONAP PRIVATE NETWORK NAME HERE - vlb_private_net_cidr: 192.168.10.0/24 - onap_private_net_cidr: 10.0.0.0/16 - vlb_private_ip_0: 192.168.10.111 - vlb_private_ip_1: 10.0.100.4 - vdns_private_ip_0: 192.168.10.211 - vdns_private_ip_1: 10.0.100.5 - vlb_name_0: zdfw1lb01lb01 - vdns_name_0: zdfw1lb01dns01 - vnf_id: vLoadBalancer_demo_app - vf_module_id: vLoadBalancer - dcae_collector_ip: 10.0.4.102 - dcae_collector_port: 8080 - repo_url_blob: https://nexus.onap.org/content/sites/raw - repo_url_artifacts: https://nexus.onap.org/content/groups/staging - demo_artifacts_version: 1.1.0 - install_script_version: 1.1.0-SNAPSHOT - key_name: vlb_key - pub_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQXYJYYi3/OUZXUiCYWdtc7K0m5C0dJKVxPG0eI8EWZrEHYdfYe6WoTSDJCww+1qlBSpA5ac/Ba4Wn9vh+lR1vtUKkyIC/nrYb90ReUd385Glkgzrfh5HdR5y5S2cL/Frh86lAn9r6b3iWTJD8wBwXFyoe1S2nMTOIuG4RPNvfmyCTYVh8XTCCE8HPvh3xv2r4egawG1P4Q4UDwk+hDBXThY2KS8M5/8EMyxHV0ImpLbpYCTBA6KYDIRtqmgS6iKyy8v2D1aSY5mc9J0T5t9S2Gv+VZQNWQDDKNFnxqYaAo1uEoq/i1q63XC5AD3ckXb2VT6dp23BQMdDfbHyUWfJN - cloud_env: rackspace diff --git a/heat/vLB/base_vlb_rackspace.yaml b/heat/vLB/base_vlb_rackspace.yaml deleted file mode 100644 index 316f4cfb..00000000 --- a/heat/vLB/base_vlb_rackspace.yaml +++ /dev/null @@ -1,287 +0,0 @@ -########################################################################## -# -#==================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 is a trademark and service mark of AT&T Intellectual Property. -# -########################################################################## - -heat_template_version: 2013-05-23 - -description: Heat template to deploy vLoadBalancer/vDNS demo app for ONAP - -############## -# # -# PARAMETERS # -# # -############## - -parameters: - vlb_image_name: - type: string - label: Image name or ID - description: Image to be used for compute instance - vlb_flavor_name: - type: string - label: Flavor - description: Type of instance (flavor) to be used - public_net_id: - type: string - label: Public network name or ID - description: Public network that enables remote connection to VNF - vlb_private_net_id: - type: string - label: vLoadBalancer private network name or ID - description: Private network that connects vLoadBalancer with vDNSs - onap_private_net_id: - type: string - label: ONAP management network name or ID - description: Private network that connects ONAP components and the VNF - onap_private_subnet_id: - type: string - label: ONAP management sub-network name or ID - description: Private sub-network that connects ONAP components and the VNF - vlb_private_net_cidr: - type: string - label: vLoadBalancer private network CIDR - description: The CIDR of the vLoadBalancer private network - onap_private_net_cidr: - type: string - label: ONAP private network CIDR - description: The CIDR of the protected private network - vlb_private_ip_0: - type: string - label: vLoadBalancer private IP address towards the private network - description: Private IP address that is assigned to the vLoadBalancer to communicate with the vDNSs - vlb_private_ip_1: - type: string - label: vLoadBalancer private IP address towards the ONAP management network - description: Private IP address that is assigned to the vLoadBalancer to communicate with ONAP components - vdns_private_ip_0: - type: string - label: vDNS private IP address towards the private network - description: Private IP address that is assigned to the vDNS to communicate with the vLoadBalancer - vdns_private_ip_1: - type: string - label: vDNS private IP address towards the ONAP management network - description: Private IP address that is assigned to the vDNS to communicate with ONAP components - vlb_name_0: - type: string - label: vLoadBalancer name - description: Name of the vLoadBalancer - vdns_name_0: - type: string - label: vDNS name - description: Name of the vDNS - vnf_id: - type: string - label: VNF ID - description: The VNF ID is provided by ONAP - vf_module_id: - type: string - label: vFirewall module ID - description: The vLoadBalancer Module ID is provided by ONAP - dcae_collector_ip: - type: string - label: DCAE collector IP address - description: IP address of the DCAE collector - dcae_collector_port: - type: string - label: DCAE collector port - description: Port of the DCAE collector - key_name: - type: string - label: Key pair name - description: Public/Private key pair name - pub_key: - type: string - label: Public key - description: Public key to be installed on the compute instance - repo_url_blob: - type: string - label: Repository URL - description: URL of the repository that hosts the demo packages - repo_url_artifacts: - type: string - label: Repository URL - description: URL of the repository that hosts the demo packages - install_script_version: - type: string - label: Installation script version number - description: Version number of the scripts that install the vFW demo app - demo_artifacts_version: - type: string - label: Artifacts version used in demo vnfs - description: Artifacts (jar, tar.gz) version used in demo vnfs - cloud_env: - type: string - label: Cloud environment - description: Cloud environment (e.g., openstack, rackspace) - -############# -# # -# RESOURCES # -# # -############# - -resources: - - random-str: - type: OS::Heat::RandomString - properties: - length: 4 - - my_keypair: - type: OS::Nova::KeyPair - properties: - name: - str_replace: - template: base_rand - params: - base: { get_param: key_name } - rand: { get_resource: random-str } - public_key: { get_param: pub_key } - save_private_key: false - - vlb_private_network: - type: OS::Neutron::Net - properties: - name: { get_param: vlb_private_net_id } - - vlb_private_subnet: - type: OS::Neutron::Subnet - properties: - name: { get_param: vlb_private_net_id } - network_id: { get_resource: vlb_private_network } - cidr: { get_param: vlb_private_net_cidr } - - # Virtual Load Balancer Instantiation - vlb_private_0_port: - type: OS::Neutron::Port - properties: - network: { get_resource: vlb_private_network } - fixed_ips: [{"subnet": { get_resource: vlb_private_subnet }, "ip_address": { get_param: vlb_private_ip_0 }}] - - vlb_private_1_port: - type: OS::Neutron::Port - properties: - network: { get_param: onap_private_net_id } - fixed_ips: [{"subnet": { get_param: onap_private_subnet_id }, "ip_address": { get_param: vlb_private_ip_1 }}] - - vlb_0: - type: OS::Nova::Server - properties: - image: { get_param: vlb_image_name } - flavor: { get_param: vlb_flavor_name } - name: { get_param: vlb_name_0 } - key_name: { get_resource: my_keypair } - networks: - - network: { get_param: public_net_id } - - port: { get_resource: vlb_private_0_port } - - port: { get_resource: vlb_private_1_port } - metadata: {vnf_id: { get_param: vnf_id }, vf_module_id: { get_param: vf_module_id }} - user_data_format: RAW - user_data: - str_replace: - params: - __dcae_collector_ip__: { get_param: dcae_collector_ip } - __dcae_collector_port__: { get_param: dcae_collector_port } - __local_private_ipaddr__: { get_param: vlb_private_ip_0 } - __repo_url_blob__ : { get_param: repo_url_blob } - __repo_url_artifacts__ : { get_param: repo_url_artifacts } - __demo_artifacts_version__ : { get_param: demo_artifacts_version } - __install_script_version__ : { get_param: install_script_version } - __cloud_env__ : { get_param: cloud_env } - template: | - #!/bin/bash - - # Create configuration files - mkdir /opt/config - echo "__dcae_collector_ip__" > /opt/config/dcae_collector_ip.txt - echo "__dcae_collector_port__" > /opt/config/dcae_collector_port.txt - echo "__local_private_ipaddr__" > /opt/config/local_private_ipaddr.txt - echo "__repo_url_blob__" > /opt/config/repo_url_blob.txt - echo "__repo_url_artifacts__" > /opt/config/repo_url_artifacts.txt - echo "__demo_artifacts_version__" > /opt/config/demo_artifacts_version.txt - echo "__install_script_version__" > /opt/config/install_script_version.txt - echo "__cloud_env__" > /opt/config/cloud_env.txt - - # Download and run install script - curl -k __repo_url_blob__/org.onap.demo/vnfs/vlb/__install_script_version__/v_lb_install.sh -o /opt/v_lb_install.sh - cd /opt - chmod +x v_lb_install.sh - ./v_lb_install.sh - - - # Virtual DNS Instantiation - vdns_private_0_port: - type: OS::Neutron::Port - properties: - network: { get_resource: vlb_private_network } - fixed_ips: [{"subnet": { get_resource: vlb_private_subnet }, "ip_address": { get_param: vdns_private_ip_0 }}] - - vdns_private_1_port: - type: OS::Neutron::Port - properties: - network: { get_param: onap_private_net_id } - fixed_ips: [{"subnet": { get_param: onap_private_subnet_id }, "ip_address": { get_param: vdns_private_ip_1 }}] - - vdns_0: - type: OS::Nova::Server - properties: - image: { get_param: vlb_image_name } - flavor: { get_param: vlb_flavor_name } - name: { get_param: vdns_name_0 } - key_name: { get_resource: my_keypair } - networks: - - network: { get_param: public_net_id } - - port: { get_resource: vdns_private_0_port } - - port: { get_resource: vdns_private_1_port } - metadata: {vnf_id: { get_param: vnf_id }, vf_module_id: { get_param: vf_module_id }} - user_data_format: RAW - user_data: - str_replace: - params: - __lb_oam_int__ : { get_param: vlb_private_ip_1 } - __lb_private_ipaddr__: { get_param: vlb_private_ip_0 } - __local_private_ipaddr__: { get_param: vdns_private_ip_0 } - __repo_url_blob__ : { get_param: repo_url_blob } - __repo_url_artifacts__ : { get_param: repo_url_artifacts } - __demo_artifacts_version__ : { get_param: demo_artifacts_version } - __install_script_version__ : { get_param: install_script_version } - __cloud_env__ : { get_param: cloud_env } - template: | - #!/bin/bash - - # Create configuration files - mkdir /opt/config - echo "__lb_oam_int__" > /opt/config/lb_oam_int.txt - echo "__lb_private_ipaddr__" > /opt/config/lb_private_ipaddr.txt - echo "__local_private_ipaddr__" > /opt/config/local_private_ipaddr.txt - echo "__repo_url_blob__" > /opt/config/repo_url_blob.txt - echo "__repo_url_artifacts__" > /opt/config/repo_url_artifacts.txt - echo "__demo_artifacts_version__" > /opt/config/demo_artifacts_version.txt - echo "__install_script_version__" > /opt/config/install_script_version.txt - echo "__cloud_env__" > /opt/config/cloud_env.txt - - # Download and run install script - curl -k __repo_url_blob__/org.onap.demo/vnfs/vlb/__install_script_version__/v_dns_install.sh -o /opt/v_dns_install.sh - cd /opt - chmod +x v_dns_install.sh - ./v_dns_install.sh
\ No newline at end of file diff --git a/heat/vLB/dnsscaling_openstack.env b/heat/vLB/dnsscaling.env index 3cc328f4..5a7839b8 100644 --- a/heat/vLB/dnsscaling_openstack.env +++ b/heat/vLB/dnsscaling.env @@ -20,4 +20,4 @@ parameters: install_script_version: 1.1.0-SNAPSHOT key_name: vlb_key_scaling pub_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQXYJYYi3/OUZXUiCYWdtc7K0m5C0dJKVxPG0eI8EWZrEHYdfYe6WoTSDJCww+1qlBSpA5ac/Ba4Wn9vh+lR1vtUKkyIC/nrYb90ReUd385Glkgzrfh5HdR5y5S2cL/Frh86lAn9r6b3iWTJD8wBwXFyoe1S2nMTOIuG4RPNvfmyCTYVh8XTCCE8HPvh3xv2r4egawG1P4Q4UDwk+hDBXThY2KS8M5/8EMyxHV0ImpLbpYCTBA6KYDIRtqmgS6iKyy8v2D1aSY5mc9J0T5t9S2Gv+VZQNWQDDKNFnxqYaAo1uEoq/i1q63XC5AD3ckXb2VT6dp23BQMdDfbHyUWfJN - cloud_env: openstack + cloud_env: PUT openstack OR backspace HERE
\ No newline at end of file diff --git a/heat/vLB/dnsscaling_openstack.yaml b/heat/vLB/dnsscaling.yaml index 20718276..20718276 100644 --- a/heat/vLB/dnsscaling_openstack.yaml +++ b/heat/vLB/dnsscaling.yaml diff --git a/heat/vLB/dnsscaling_rackspace.env b/heat/vLB/dnsscaling_rackspace.env deleted file mode 100644 index 619b35c7..00000000 --- a/heat/vLB/dnsscaling_rackspace.env +++ /dev/null @@ -1,21 +0,0 @@ -parameters: - vlb_image_name: Ubuntu 14.04 LTS (Trusty Tahr) (PVHVM) - vlb_flavor_name: 4 GB General Purpose v1 - public_net_id: 00000000-0000-0000-0000-000000000000 - vlb_private_net_id: zdfw1lb01_private - onap_private_net_id: PUT THE ONAP PRIVATE NETWORK NAME HERE - onap_private_subnet_id: PUT THE ONAP PRIVATE NETWORK NAME HERE - vlb_private_ip_0: 192.168.10.111 - vlb_private_ip_1: 10.0.100.4 - vdns_private_ip_0: 192.168.10.212 - vdns_private_ip_1: 10.0.100.6 - vdns_name_0: zdfw1lb01dns02 - vnf_id: vLoadBalancer_demo_app - vf_module_id: vLoadBalancer - repo_url_blob: https://nexus.onap.org/content/sites/raw - repo_url_artifacts: https://nexus.onap.org/content/groups/staging - demo_artifacts_version: 1.1.0 - install_script_version: 1.1.0-SNAPSHOT - key_name: vlb_key_scaling - pub_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQXYJYYi3/OUZXUiCYWdtc7K0m5C0dJKVxPG0eI8EWZrEHYdfYe6WoTSDJCww+1qlBSpA5ac/Ba4Wn9vh+lR1vtUKkyIC/nrYb90ReUd385Glkgzrfh5HdR5y5S2cL/Frh86lAn9r6b3iWTJD8wBwXFyoe1S2nMTOIuG4RPNvfmyCTYVh8XTCCE8HPvh3xv2r4egawG1P4Q4UDwk+hDBXThY2KS8M5/8EMyxHV0ImpLbpYCTBA6KYDIRtqmgS6iKyy8v2D1aSY5mc9J0T5t9S2Gv+VZQNWQDDKNFnxqYaAo1uEoq/i1q63XC5AD3ckXb2VT6dp23BQMdDfbHyUWfJN - cloud_env: rackspace diff --git a/heat/vLB/dnsscaling_rackspace.yaml b/heat/vLB/dnsscaling_rackspace.yaml deleted file mode 100644 index 7a53a561..00000000 --- a/heat/vLB/dnsscaling_rackspace.yaml +++ /dev/null @@ -1,197 +0,0 @@ -########################################################################## -# -#==================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 is a trademark and service mark of AT&T Intellectual Property. -# -########################################################################## - -heat_template_version: 2013-05-23 - -description: Heat template to deploy a vDNS for ONAP (scaling-up scenario) - -############## -# # -# PARAMETERS # -# # -############## - -parameters: - vlb_image_name: - type: string - label: Image name or ID - description: Image to be used for compute instance - vlb_flavor_name: - type: string - label: Flavor - description: Type of instance (flavor) to be used - public_net_id: - type: string - label: Public network name or ID - description: Public network that enables remote connection to VNF - vlb_private_net_id: - type: string - label: vLoadBalancer private network name or ID - description: Private network that connects vLoadBalancer with vDNSs - onap_private_net_id: - type: string - label: ONAP management network name or ID - description: Private network that connects ONAP components and the VNF - onap_private_subnet_id: - type: string - label: ONAP management sub-network name or ID - description: Private sub-network that connects ONAP components and the VNF - vlb_private_ip_0: - type: string - label: vLoadBalancer private IP address towards the private network - description: Private IP address that is assigned to the vLoadBalancer to communicate with the vDNSs - vlb_private_ip_1: - type: string - label: vLoadBalancer private IP address towards the ONAP management network - description: Private IP address that is assigned to the vLoadBalancer to communicate with ONAP components - vdns_private_ip_0: - type: string - label: vDNS private IP address towards the private network - description: Private IP address that is assigned to the vDNS to communicate with the vLoadBalancer - vdns_private_ip_1: - type: string - label: vDNS private IP address towards the ONAP management network - description: Private IP address that is assigned to the vDNS to communicate with ONAP components - vdns_name_0: - type: string - label: vDNS name - description: Name of the vDNS - vnf_id: - type: string - label: VNF ID - description: The VNF ID is provided by ONAP - vf_module_id: - type: string - label: vFirewall module ID - description: The vLoadBalancer Module ID is provided by ONAP - key_name: - type: string - label: Key pair name - description: Public/Private key pair name - pub_key: - type: string - label: Public key - description: Public key to be installed on the compute instance - repo_url_blob: - type: string - label: Repository URL - description: URL of the repository that hosts the demo packages - repo_url_artifacts: - type: string - label: Repository URL - description: URL of the repository that hosts the demo packages - install_script_version: - type: string - label: Installation script version number - description: Version number of the scripts that install the vFW demo app - demo_artifacts_version: - type: string - label: Artifacts version used in demo vnfs - description: Artifacts (jar, tar.gz) version used in demo vnfs - cloud_env: - type: string - label: Cloud environment - description: Cloud environment (e.g., openstack, rackspace) - -############# -# # -# RESOURCES # -# # -############# - -resources: - - random-str: - type: OS::Heat::RandomString - properties: - length: 4 - - my_keypair: - type: OS::Nova::KeyPair - properties: - name: - str_replace: - template: base_rand - params: - base: { get_param: key_name } - rand: { get_resource: random-str } - public_key: { get_param: pub_key } - save_private_key: false - - # Virtual DNS Instantiation - vdns_private_0_port: - type: OS::Neutron::Port - properties: - network: { get_param: vlb_private_net_id } - fixed_ips: [{"subnet": { get_param: vlb_private_net_id }, "ip_address": { get_param: vdns_private_ip_0 }}] - - vdns_private_1_port: - type: OS::Neutron::Port - properties: - network: { get_param: onap_private_net_id } - fixed_ips: [{"subnet": { get_param: onap_private_subnet_id }, "ip_address": { get_param: vdns_private_ip_1 }}] - - vdns_0: - type: OS::Nova::Server - properties: - image: { get_param: vlb_image_name } - flavor: { get_param: vlb_flavor_name } - name: { get_param: vdns_name_0 } - key_name: { get_resource: my_keypair } - networks: - - network: { get_param: public_net_id } - - port: { get_resource: vdns_private_0_port } - - port: { get_resource: vdns_private_1_port } - metadata: {vnf_id: { get_param: vnf_id }, vf_module_id: { get_param: vf_module_id }} - user_data_format: RAW - user_data: - str_replace: - params: - __lb_oam_int__ : { get_param: vlb_private_ip_1 } - __lb_private_ipaddr__: { get_param: vlb_private_ip_0 } - __local_private_ipaddr__: { get_param: vdns_private_ip_0 } - __repo_url_blob__ : { get_param: repo_url_blob } - __repo_url_artifacts__ : { get_param: repo_url_artifacts } - __demo_artifacts_version__ : { get_param: demo_artifacts_version } - __install_script_version__ : { get_param: install_script_version } - __cloud_env__ : { get_param: cloud_env } - template: | - #!/bin/bash - - # Create configuration files - mkdir /opt/config - echo "__lb_oam_int__" > /opt/config/lb_oam_int.txt - echo "__lb_private_ipaddr__" > /opt/config/lb_private_ipaddr.txt - echo "__local_private_ipaddr__" > /opt/config/local_private_ipaddr.txt - echo "__repo_url_blob__" > /opt/config/repo_url_blob.txt - echo "__repo_url_artifacts__" > /opt/config/repo_url_artifacts.txt - echo "__demo_artifacts_version__" > /opt/config/demo_artifacts_version.txt - echo "__install_script_version__" > /opt/config/install_script_version.txt - echo "__cloud_env__" > /opt/config/cloud_env.txt - - # Download and run install script - curl -k __repo_url_blob__/org.onap.demo/vnfs/vlb/__install_script_version__/v_dns_install.sh -o /opt/v_dns_install.sh - cd /opt - chmod +x v_dns_install.sh - ./v_dns_install.sh
\ No newline at end of file diff --git a/heat/vLB/packet_gen_vlb.env b/heat/vLB/packet_gen_vlb.env deleted file mode 100644 index 362b8a99..00000000 --- a/heat/vLB/packet_gen_vlb.env +++ /dev/null @@ -1,13 +0,0 @@ -parameters: - vpg_image_name: Ubuntu 14.04 LTS (Trusty Tahr) (PVHVM) - vpg_flavor_name: 4 GB General Purpose v1 - public_net_id: 00000000-0000-0000-0000-000000000000 - vlb_ipaddr: INSERT THE PUBLIC ADDRESS OF THE vLB HERE - vpg_name_0: ziad1vdnspg01pg01 - repo_url_blob: https://nexus.onap.org/content/sites/raw - repo_url_artifacts: https://nexus.onap.org/content/groups/staging - demo_artifacts_version: 1.1.0 - install_script_version: 1.1.0-SNAPSHOT - key_name: dns_packetgen_key - pub_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQXYJYYi3/OUZXUiCYWdtc7K0m5C0dJKVxPG0eI8EWZrEHYdfYe6WoTSDJCww+1qlBSpA5ac/Ba4Wn9vh+lR1vtUKkyIC/nrYb90ReUd385Glkgzrfh5HdR5y5S2cL/Frh86lAn9r6b3iWTJD8wBwXFyoe1S2nMTOIuG4RPNvfmyCTYVh8XTCCE8HPvh3xv2r4egawG1P4Q4UDwk+hDBXThY2KS8M5/8EMyxHV0ImpLbpYCTBA6KYDIRtqmgS6iKyy8v2D1aSY5mc9J0T5t9S2Gv+VZQNWQDDKNFnxqYaAo1uEoq/i1q63XC5AD3ckXb2VT6dp23BQMdDfbHyUWfJN - cloud_env: PUT THE CLOUD ENVIRONMENT HERE (rackspace or openstack) diff --git a/heat/vLB/packet_gen_vlb.yaml b/heat/vLB/packet_gen_vlb.yaml deleted file mode 100644 index e41ede8e..00000000 --- a/heat/vLB/packet_gen_vlb.yaml +++ /dev/null @@ -1,146 +0,0 @@ -########################################################################## -# -#==================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 is a trademark and service mark of AT&T Intellectual Property. -# -########################################################################## - -heat_template_version: 2013-05-23 - -description: Heat template to deploy a packet generator for the vLoadBalancer/vDNS demo app for ONAP - -############## -# # -# PARAMETERS # -# # -############## - -parameters: - public_net_id: - type: string - label: Public network name or ID - description: Public network that enables remote connection to VNF - vpg_image_name: - type: string - label: Image name or ID - description: Image to be used for compute instance - vpg_flavor_name: - type: string - label: Flavor - description: Type of instance (flavor) to be used - vpg_name_0: - type: string - label: vPacketGenerator name - description: Name of the vPacketGenerator - key_name: - type: string - label: Key pair name - description: Public/Private key pair name - pub_key: - type: string - label: Public key - description: Public key to be installed on the compute instance - repo_url_blob: - type: string - label: Repository URL - description: URL of the repository that hosts the demo packages - repo_url_artifacts: - type: string - label: Repository URL - description: URL of the repository that hosts the demo packages - vlb_ipaddr: - type: string - label: Public IP of the vLoadBalancer to which we want to send traffic - description: Public IP of the vLoadBalancer to which we want to send traffic - install_script_version: - type: string - label: Installation script version number - description: Version number of the scripts that install the vFW demo app - demo_artifacts_version: - type: string - label: Artifacts version used in demo vnfs - description: Artifacts (jar, tar.gz) version used in demo vnfs - cloud_env: - type: string - label: Cloud environment - description: Cloud environment (e.g., openstack, rackspace) - -############# -# # -# RESOURCES # -# # -############# - -resources: - - random-str: - type: OS::Heat::RandomString - properties: - length: 4 - - my_keypair: - type: OS::Nova::KeyPair - properties: - name: - str_replace: - template: base_rand - params: - base: { get_param: key_name } - rand: { get_resource: random-str } - public_key: { get_param: pub_key } - save_private_key: false - - - vpg_0: - type: OS::Nova::Server - properties: - image: { get_param: vpg_image_name } - flavor: { get_param: vpg_flavor_name } - name: { get_param: vpg_name_0 } - key_name: { get_resource: my_keypair } - networks: - - network: { get_param: public_net_id } - user_data_format: RAW - user_data: - str_replace: - params: - __repo_url_blob__ : { get_param: repo_url_blob } - __repo_url_artifacts__ : { get_param: repo_url_artifacts } - __vlb_ipaddr__: { get_param: vlb_ipaddr } - __demo_artifacts_version__ : { get_param: demo_artifacts_version } - __install_script_version__ : { get_param: install_script_version } - __cloud_env__: { get_param: cloud_env } - template: | - #!/bin/bash - - # Create configuration files - mkdir /opt/config - echo "__vlb_ipaddr__" > /opt/config/vlb_ipaddr.txt - echo "__repo_url_blob__" > /opt/config/repo_url_blob.txt - echo "__repo_url_artifacts__" > /opt/config/repo_url_artifacts.txt - echo "__demo_artifacts_version__" > /opt/config/demo_artifacts_version.txt - echo "__install_script_version__" > /opt/config/install_script_version.txt - echo "__cloud_env__" > /opt/config/cloud_env.txt - - # Download and run install script - curl -k __repo_url_blob__/org.onap.demo/vnfs/vlb/__install_script_version__/v_packetgen_install.sh -o /opt/v_packetgen_install.sh - cd /opt - chmod +x v_packetgen_install.sh - ./v_packetgen_install.sh
\ No newline at end of file @@ -28,7 +28,7 @@ <groupId>org.onap.demo.vnf</groupId> <artifactId>demo-aggregator</artifactId> <version>1.1.0-SNAPSHOT</version> - <name>demo-aggregator</name> + <name>demo</name> <packaging>pom</packaging> <modelVersion>4.0.0</modelVersion> <prerequisites> @@ -51,6 +51,10 @@ <module>vnfs/vCPE/kea-sdnc-notify-mod</module> </modules> + <properties> + <sonar.skip>true</sonar.skip> + </properties> + <build> <plugins> <plugin> diff --git a/vagrant/create_onap.sh b/vagrant/create_onap.sh index 9b4dfc06..0b4ed572 100755 --- a/vagrant/create_onap.sh +++ b/vagrant/create_onap.sh @@ -2,7 +2,7 @@ set -ex source /vagrant/openrc -cp /demo/heat/OpenECOMP/* . +cp /demo/heat/ONAP/* . # Parameters used across all ONAP components pub_net=$(openstack network list -f value|grep public | cut -f1 -d' ') diff --git a/vnfs/VES/bldjobs/Doxyfile b/vnfs/VES/bldjobs/Doxyfile index f96ead25..ba51f787 100644 --- a/vnfs/VES/bldjobs/Doxyfile +++ b/vnfs/VES/bldjobs/Doxyfile @@ -1,5 +1,22 @@ # Doxyfile 1.6.1 +# License +# ------- +# +# 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. + + # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # diff --git a/vnfs/VES/bldjobs/Makefile b/vnfs/VES/bldjobs/Makefile index 21d7a824..6c0aaada 100644 --- a/vnfs/VES/bldjobs/Makefile +++ b/vnfs/VES/bldjobs/Makefile @@ -10,33 +10,19 @@ # License # ------- # -# Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved. +# 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. # -# 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) diff --git a/vnfs/VES5.0/evel/evel-library/bldjobs/Makefile b/vnfs/VES5.0/evel/evel-library/bldjobs/Makefile index b1e15e5e..d37d0e4b 100644 --- a/vnfs/VES5.0/evel/evel-library/bldjobs/Makefile +++ b/vnfs/VES5.0/evel/evel-library/bldjobs/Makefile @@ -140,6 +140,7 @@ API_SOURCES=$(EVELLIB_ROOT)/evel.c \ $(EVELLIB_ROOT)/evel_throttle.c \ $(EVELLIB_ROOT)/evel_internal_event.c \ $(EVELLIB_ROOT)/evel_event_mgr.c \ + $(EVELLIB_ROOT)/evel_threshold_cross.c \ $(EVELLIB_ROOT)/evel_voicequality.c \ $(EVELLIB_ROOT)/evel_logging.c \ $(EVELLIB_ROOT)/jsmn.c diff --git a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel.h b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel.h index be0c5f0e..0ae1713e 100644 --- a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel.h +++ b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel.h @@ -738,10 +738,10 @@ MEASUREMENT_DISK_USE * evel_measurement_new_disk_use_add(EVENT_MEASUREMENT * mea typedef struct measurement_fsys_use { char * filesystem_name; double block_configured; - int block_iops; + double block_iops; double block_used; double ephemeral_configured; - int ephemeral_iops; + double ephemeral_iops; double ephemeral_used; } MEASUREMENT_FSYS_USE; @@ -1486,6 +1486,21 @@ size_t evel_write_callback(void *contents, EVENT_HEADER * evel_new_heartbeat(void); /**************************************************************************//** + * Create a new heartbeat event of given name and type. + * + * @note that the heartbeat is just a "naked" commonEventHeader! + * + * @param event_name Unique Event Name confirming Domain AsdcModel Description + * @param event_id A universal identifier of the event for: troubleshooting correlation, analysis, etc + * + * @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_nameid(const char* ev_name, const char *ev_id); + + +/**************************************************************************//** * Free an event header. * * Free off the event header supplied. Will free all the contained allocated @@ -1560,6 +1575,23 @@ void evel_reporting_entity_name_set(EVENT_HEADER * const header, void evel_reporting_entity_id_set(EVENT_HEADER * const header, const char * const entity_id); +/**************************************************************************//** + * Set the NFC Naming code property of the event header. + * + * @param header Pointer to the ::EVENT_HEADER. + * @param nfcnamingcode String + *****************************************************************************/ +void evel_nfcnamingcode_set(EVENT_HEADER * const header, + const char * const nfcnam); +/**************************************************************************//** + * Set the NF Naming code property of the event header. + * + * @param header Pointer to the ::EVENT_HEADER. + * @param nfnamingcode String + *****************************************************************************/ +void evel_nfnamingcode_set(EVENT_HEADER * const header, + const char * const nfnam); + /*****************************************************************************/ /*****************************************************************************/ /* */ @@ -1575,6 +1607,8 @@ void evel_reporting_entity_id_set(EVENT_HEADER * const header, * 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 event_name Unique Event Name + * @param event_id A universal identifier of the event for analysis etc * @param condition The condition indicated by the Fault. * @param specific_problem The specific problem triggering the fault. * @param priority The priority of the event. @@ -1586,7 +1620,8 @@ void evel_reporting_entity_id_set(EVENT_HEADER * const header, * 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, +EVENT_FAULT * evel_new_fault(const char* ev_name, const char *ev_id, + const char * const condition, const char * const specific_problem, EVEL_EVENT_PRIORITIES priority, EVEL_SEVERITIES severity, @@ -1678,13 +1713,15 @@ void evel_fault_type_set(EVENT_FAULT * fault, const char * const type); * that the Measurement has immutable properties. * * @param measurement_interval + * @param event_name Unique Event Name + * @param event_id A universal identifier of the event for analysis etc * * @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 * evel_new_measurement(double measurement_interval,const char* ev_name, const char *ev_id); /**************************************************************************//** * Free a Measurement. @@ -1918,10 +1955,10 @@ void evel_measurement_fsys_use_add(EVENT_MEASUREMENT * measurement, char * filesystem_name, double block_configured, double block_used, - int block_iops, + double block_iops, double ephemeral_configured, double ephemeral_used, - int ephemeral_iops); + double ephemeral_iops); /**************************************************************************//** * Add a Feature usage value name/value pair to the Measurement. @@ -2557,13 +2594,15 @@ void evel_measurement_vnic_performance_add(EVENT_MEASUREMENT * const measurement * that the Report has immutable properties. * * @param measurement_interval + * @param event_name Unique Event Name + * @param event_id A universal identifier of the event for analysis etc * * @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); +EVENT_REPORT * evel_new_report(double measurement_interval,const char* ev_name, const char *ev_id); /**************************************************************************//** * Free a Report. @@ -2637,6 +2676,8 @@ void evel_report_custom_measurement_add(EVENT_REPORT * report, * explicit setter functions, but again values may only be set once so * that the Mobile Flow has immutable properties. * + * @param event_name Unique Event Name + * @param event_id A universal identifier of the event for analysis etc * @param flow_direction * @param gtp_per_flow_metrics * @param ip_protocol_type @@ -2652,6 +2693,7 @@ void evel_report_custom_measurement_add(EVENT_REPORT * report, * @retval NULL Failed to create the event. *****************************************************************************/ EVENT_MOBILE_FLOW * evel_new_mobile_flow( + const char* ev_name, const char *ev_id, const char * const flow_direction, MOBILE_GTP_PER_FLOW_METRICS * gtp_per_flow_metrics, const char * const ip_protocol_type, @@ -3372,6 +3414,8 @@ void evel_mobile_gtp_metrics_qci_cos_count_add( * 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 event_name Unique Event Name + * @param event_id A universal identifier of the event for analysis etc * @param vendor_name The vendor id to encode in the event vnf field. * @param module The module to encode in the event. * @param vnfname The Virtual network function to encode in the event. @@ -3380,7 +3424,8 @@ void evel_mobile_gtp_metrics_qci_cos_count_add( * ::evel_free_signaling. * @retval NULL Failed to create the event. *****************************************************************************/ -EVENT_SIGNALING * evel_new_signaling(const char * const vendor_name, +EVENT_SIGNALING * evel_new_signaling(const char* ev_name, const char *ev_id, + const char * const vendor_name, const char * const correlator, const char * const local_ip_address, const char * const local_port, @@ -3582,6 +3627,8 @@ void evel_signaling_summary_sip_set(EVENT_SIGNALING * const event, * setter functions, but again values may only be set once so that the * Syslog has immutable properties. * + * @param event_name Unique Event Name + * @param event_id A universal identifier of the event for analysis etc * @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. @@ -3591,7 +3638,8 @@ void evel_signaling_summary_sip_set(EVENT_SIGNALING * const event, * ::evel_free_state_change * @retval NULL Failed to create the event. *****************************************************************************/ -EVENT_STATE_CHANGE * evel_new_state_change(const EVEL_ENTITY_STATE new_state, +EVENT_STATE_CHANGE * evel_new_state_change(const char* ev_name, const char *ev_id, + const EVEL_ENTITY_STATE new_state, const EVEL_ENTITY_STATE old_state, const char * const interface); @@ -3656,6 +3704,8 @@ void evel_state_change_addl_field_add(EVENT_STATE_CHANGE * const state_change, * setter functions, but again values may only be set once so that the * Syslog has immutable properties. * + * @param event_name Unique Event Name + * @param event_id A universal identifier of the event for analysis etc * @param event_source_type * @param syslog_msg * @param syslog_tag @@ -3665,7 +3715,8 @@ void evel_state_change_addl_field_add(EVENT_STATE_CHANGE * const state_change, * 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, +EVENT_SYSLOG * evel_new_syslog(const char* ev_name, const char *ev_id, + EVEL_SOURCE_TYPES event_source_type, const char * const syslog_msg, const char * const syslog_tag); @@ -3834,12 +3885,14 @@ void evel_syslog_severity_set(EVENT_SYSLOG * syslog, const char * const severty) /**************************************************************************//** * Create a new other event. * + * @param event_name Unique Event Name + * @param event_id A universal identifier of the event for analysis etc * * @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); +EVENT_OTHER * evel_new_other(const char* ev_name, const char *ev_id); /**************************************************************************//** * Free an Other. @@ -3987,6 +4040,8 @@ typedef struct voice_quality_additional_info { * factory function and are immutable once set. Optional fields have * explicit setter functions, but again values may only be set once * so that the Voice Quality has immutable properties. + * @param event_name Unique Event Name + * @param event_id A universal identifier of the event for analysis etc * @param calleeSideCodec Callee codec for the call. * @param callerSideCodec Caller codec for the call. * @param correlator Constant across all events on this call. @@ -3998,7 +4053,8 @@ typedef struct voice_quality_additional_info { ::evel_free_voice_quality. * @retval NULL Failed to create the event. *****************************************************************************/ -EVENT_VOICE_QUALITY * evel_new_voice_quality(const char * const calleeSideCodec, +EVENT_VOICE_QUALITY * evel_new_voice_quality(const char* ev_name, const char *ev_id, + const char * const calleeSideCodec, const char * const callerSideCodec, const char * const correlator, const char * const midCallRtcp, const char * const vendorVnfNameFields); @@ -4248,6 +4304,8 @@ typedef struct event_threshold_cross { * setter functions, but again values may only be set once so that the * TCA has immutable properties. * + * @param event_name Unique Event Name + * @param event_id A universal identifier of the event for analysis etc * @param char* tcriticality Performance Counter Criticality MAJ MIN, * @param char* tname Performance Counter Threshold name * @param char* tthresholdCrossed Counter Threshold crossed value @@ -4265,6 +4323,7 @@ typedef struct event_threshold_cross { * @retval NULL Failed to create the event. *****************************************************************************/ EVENT_THRESHOLD_CROSS * evel_new_threshold_cross( + const char* ev_name, const char *ev_id, char * tcriticality, char * tname, char * tthresholdCrossed, diff --git a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_event.c b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_event.c index 6d025abe..ced29b2c 100644 --- a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_event.c +++ b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_event.c @@ -52,6 +52,51 @@ void evel_set_next_event_sequence(const int sequence) EVEL_EXIT(); } + +/**************************************************************************//** + * Create a new heartbeat event of given name and type. + * + * @note that the heartbeat is just a "naked" commonEventHeader! + * + * @param event_name Unique Event Name: in format + * {DomainAbbreviation}_{AsdcModel or ApplicationPlatform}_{DescriptionOfInfoBeingConveyed} + * @param event_id Uniquely identify event for correlation and analysis + * + * @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_nameid(const char* ev_name, const char *ev_id) +{ + EVENT_HEADER * heartbeat = NULL; + EVEL_ENTER(); + + assert(ev_name != NULL); + assert(ev_id != NULL); + + /***************************************************************************/ + /* 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_nameid(heartbeat,ev_name,ev_id); + +exit_label: + EVEL_EXIT(); + return heartbeat; +} + /**************************************************************************//** * Create a new heartbeat event. * @@ -141,6 +186,55 @@ void evel_init_header(EVENT_HEADER * const header,const char *const eventname) EVEL_EXIT(); } + +/**************************************************************************//** + * Initialize a newly created event header. + * + * @param header Pointer to the header being initialized. + *****************************************************************************/ +void evel_init_header_nameid(EVENT_HEADER * const header,const char *const eventname, const char *eventid) +{ + struct timeval tv; + + EVEL_ENTER(); + + assert(header != NULL); + assert(eventname != NULL); + assert(eventid != 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; + header->event_id = strdup(eventid); + header->event_name = strdup(eventname); + 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_init_option_string(&header->nfcnaming_code); + evel_init_option_string(&header->nfnaming_code); + evel_force_option_string(&header->reporting_entity_id, openstack_vm_uuid()); + evel_force_option_string(&header->source_id, openstack_vm_uuid()); + evel_init_option_intheader(&header->internal_field); + + EVEL_EXIT(); +} + /**************************************************************************//** * Set the Event Type property of the event header. * diff --git a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_event_mgr.c b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_event_mgr.c index de4296df..a96124ab 100644 --- a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_event_mgr.c +++ b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_event_mgr.c @@ -144,6 +144,16 @@ EVEL_ERR_CODES event_handler_initialize(const char * const event_api_url, evel_throt_api_url = strdup(throt_api_url); assert(evel_throt_api_url != NULL); + + curl_version_info_data *d = curl_version_info(CURLVERSION_NOW); + /* compare with the 24 bit hex number in 8 bit fields */ + if(d->version_num >= 0x072100) { + /* this is libcurl 7.33.0 or later */ + EVEL_INFO("7.33 or later Curl version %x.",d->version_num); + } + else { + EVEL_INFO("Old Curl version."); + } /***************************************************************************/ /* Start the CURL library. Note that this initialization is not threadsafe */ /* which imposes a constraint that the EVEL library is initialized before */ @@ -408,7 +418,7 @@ EVEL_ERR_CODES event_handler_terminate() /*************************************************************************/ /* Make sure that the event handler knows it's time to die. */ /*************************************************************************/ - event = evel_new_internal_event(EVT_CMD_TERMINATE); + event = evel_new_internal_event(EVT_CMD_TERMINATE,"EVELinternal","EVELid"); if (event == NULL) { /***********************************************************************/ diff --git a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_fault.c b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_fault.c index 7cbadfe6..c211f607 100644 --- a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_fault.c +++ b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_fault.c @@ -36,6 +36,8 @@ * 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 event_name Unique Event Name confirming Domain AsdcModel Description + * @param event_id A universal identifier of the event for: troubleshooting correlation, analysis, etc * @param condition The condition indicated by the Fault. * @param specific_problem The specific problem triggering the fault. * @param priority The priority of the event. @@ -47,7 +49,9 @@ * 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, +EVENT_FAULT * evel_new_fault(const char * ev_name, + const char * ev_id, + const char * const condition, const char * const specific_problem, EVEL_EVENT_PRIORITIES priority, EVEL_SEVERITIES severity, @@ -81,7 +85,7 @@ EVENT_FAULT * evel_new_fault(const char * const condition, /* Initialize the header & the fault fields. Optional string values are */ /* uninitialized (NULL). */ /***************************************************************************/ - evel_init_header(&fault->header,"Fault"); + evel_init_header_nameid(&fault->header,ev_name,ev_id); fault->header.event_domain = EVEL_DOMAIN_FAULT; fault->header.priority = priority; fault->major_version = EVEL_FAULT_MAJOR_VERSION; diff --git a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_heartbeat_fields.c b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_heartbeat_fields.c index 73773edc..872af1f8 100644 --- a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_heartbeat_fields.c +++ b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_heartbeat_fields.c @@ -35,6 +35,8 @@ * 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 event_name Unique Event Name confirming Domain AsdcModel Description + * @param event_id A universal identifier of the event for: troubleshooting correlation, analysis, etc * @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_HEARTBEAT_FIELD. If the event @@ -42,7 +44,7 @@ * ::evel_free_hrtbt_field. * @retval NULL Failed to create the event. *****************************************************************************/ -EVENT_HEARTBEAT_FIELD * evel_new_heartbeat_field(int interval) +EVENT_HEARTBEAT_FIELD * evel_new_heartbeat_field(int interval,const char* ev_name, const char *ev_id) { EVENT_HEARTBEAT_FIELD * event = NULL; @@ -68,7 +70,7 @@ EVENT_HEARTBEAT_FIELD * evel_new_heartbeat_field(int interval) /***************************************************************************/ /* Initialize the header & the Heartbeat fields fields. */ /***************************************************************************/ - evel_init_header(&event->header,"HeartbeatFields"); + evel_init_header_nameid(&event->header,ev_name,ev_id); event->header.event_domain = EVEL_DOMAIN_HEARTBEAT_FIELD; event->major_version = EVEL_HEARTBEAT_FIELD_MAJOR_VERSION; event->minor_version = EVEL_HEARTBEAT_FIELD_MINOR_VERSION; diff --git a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_internal.h b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_internal.h index f057fe87..46f71af1 100644 --- a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_internal.h +++ b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_internal.h @@ -226,7 +226,7 @@ EVEL_ERR_CODES event_handler_run(); * ::evel_free_event. * @retval NULL Failed to create the event. *****************************************************************************/ -EVENT_INTERNAL * evel_new_internal_event(EVT_HANDLER_COMMAND command); +EVENT_INTERNAL * evel_new_internal_event(EVT_HANDLER_COMMAND command,const char* ev_name, const char *ev_id); /**************************************************************************//** * Free an internal event. diff --git a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_internal_event.c b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_internal_event.c index 511c7d51..cb56c880 100644 --- a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_internal_event.c +++ b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_internal_event.c @@ -43,12 +43,14 @@ * 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. + * @param event_name Unique Event Name confirming Domain AsdcModel Description + * @param event_id A universal identifier of the event for: troubleshooting correlation, analysis, etc * @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 * evel_new_internal_event(EVT_HANDLER_COMMAND command,const char* ev_name, const char *ev_id) { EVENT_INTERNAL * event = NULL; EVEL_ENTER(); @@ -73,7 +75,7 @@ EVENT_INTERNAL * evel_new_internal_event(EVT_HANDLER_COMMAND command) /***************************************************************************/ /* Initialize the header & the event fields. */ /***************************************************************************/ - evel_init_header(&event->header,NULL); + evel_init_header_nameid(&event->header,ev_name,ev_id); event->header.event_domain = EVEL_DOMAIN_INTERNAL; event->command = command; diff --git a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_mobile_flow.c b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_mobile_flow.c index 0716e45f..5085d6a9 100644 --- a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_mobile_flow.c +++ b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_mobile_flow.c @@ -80,6 +80,8 @@ void evel_json_encode_mobile_flow_gtp_flow_metrics( * 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 event_name Unique Event Name confirming Domain AsdcModel Description + * @param event_id A universal identifier of the event for: troubleshooting correlation, analysis, etc * @param flow_direction Flow direction. * @param gtp_per_flow_metrics GTP per-flow metrics. * @param ip_protocol_type IP protocol type. @@ -93,7 +95,7 @@ void evel_json_encode_mobile_flow_gtp_flow_metrics( * ::evel_free_mobile_flow. * @retval NULL Failed to create the event. *****************************************************************************/ -EVENT_MOBILE_FLOW * evel_new_mobile_flow( +EVENT_MOBILE_FLOW * evel_new_mobile_flow(const char* ev_name, const char *ev_id, const char * const flow_direction, MOBILE_GTP_PER_FLOW_METRICS * gtp_per_flow_metrics, const char * const ip_protocol_type, @@ -134,7 +136,7 @@ EVENT_MOBILE_FLOW * evel_new_mobile_flow( /* Initialize the header & the Mobile Flow fields. Optional string values */ /* are uninitialized (NULL). */ /***************************************************************************/ - evel_init_header(&mobile_flow->header,"MobileFlow"); + evel_init_header_nameid(&mobile_flow->header,ev_name,ev_id); 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; diff --git a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_other.c b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_other.c index 447ac9a4..c7a227b3 100644 --- a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_other.c +++ b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_other.c @@ -39,7 +39,7 @@ * 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 * evel_new_other(const char *ev_name, const char *ev_id) { EVENT_OTHER * other = NULL; EVEL_ENTER(); @@ -64,7 +64,7 @@ EVENT_OTHER * evel_new_other() /* Initialize the header & the Other fields. Optional string values are */ /* uninitialized (NULL). */ /***************************************************************************/ - evel_init_header(&other->header,"OtherEvent"); + evel_init_header_nameid(&other->header,ev_name,ev_id); other->header.event_domain = EVEL_DOMAIN_OTHER; other->major_version = EVEL_OTHER_EVENT_MAJOR_VERSION; other->minor_version = EVEL_OTHER_EVENT_MINOR_VERSION; diff --git a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_reporting_measurement.c b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_reporting_measurement.c index a7397237..38a17313 100644 --- a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_reporting_measurement.c +++ b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_reporting_measurement.c @@ -44,12 +44,13 @@ * that the Report has immutable properties. * * @param measurement_interval - + * @param event_name Unique Event Name + * @param event_id A universal identifier of the event for analysis etc * @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 * evel_new_report(double measurement_interval,const char *ev_name, const char *ev_id) { EVENT_REPORT * report = NULL; @@ -75,7 +76,7 @@ EVENT_REPORT * evel_new_report(double measurement_interval) /***************************************************************************/ /* Initialize the header & the report fields. */ /***************************************************************************/ - evel_init_header(&report->header,"Report"); + evel_init_header_nameid(&report->header,ev_name,ev_id); report->header.event_domain = EVEL_DOMAIN_REPORT; report->measurement_interval = measurement_interval; @@ -328,7 +329,7 @@ void evel_json_encode_report(EVEL_JSON_BUFFER * jbuf, { evel_json_open_object(jbuf); evel_enc_kv_string(jbuf, "name", measurement_group->name); - evel_json_open_named_list(jbuf, "measurements"); + evel_json_open_named_list(jbuf, "arrayOfFields"); /*********************************************************************/ /* Measurements list. */ diff --git a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_scaling_measurement.c b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_scaling_measurement.c index f1b38e3c..7920d81b 100644 --- a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_scaling_measurement.c +++ b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_scaling_measurement.c @@ -37,13 +37,15 @@ * that the Measurement has immutable properties. * * @param measurement_interval + * @param event_name Unique Event Name confirming Domain AsdcModel Description + * @param event_id A universal identifier of the event for: troubleshooting correlation, analysis, etc * * @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 * evel_new_measurement(double measurement_interval, const char* ev_name, const char *ev_id) { EVENT_MEASUREMENT * measurement = NULL; @@ -69,7 +71,7 @@ EVENT_MEASUREMENT * evel_new_measurement(double measurement_interval) /***************************************************************************/ /* Initialize the header & the measurement fields. */ /***************************************************************************/ - evel_init_header(&measurement->header,"vnfScalingMeasurement"); + evel_init_header_nameid(&measurement->header,ev_name,ev_id); measurement->header.event_domain = EVEL_DOMAIN_MEASUREMENT; measurement->measurement_interval = measurement_interval; dlist_initialize(&measurement->additional_info); @@ -1531,10 +1533,10 @@ void evel_measurement_fsys_use_add(EVENT_MEASUREMENT * measurement, char * filesystem_name, double block_configured, double block_used, - int block_iops, + double block_iops, double ephemeral_configured, double ephemeral_used, - int ephemeral_iops) + double ephemeral_iops) { MEASUREMENT_FSYS_USE * fsys_use = NULL; EVEL_ENTER(); @@ -1547,10 +1549,10 @@ void evel_measurement_fsys_use_add(EVENT_MEASUREMENT * measurement, assert(filesystem_name != NULL); assert(block_configured >= 0.0); assert(block_used >= 0.0); - assert(block_iops >= 0); + assert(block_iops >= 0.0); assert(ephemeral_configured >= 0.0); assert(ephemeral_used >= 0.0); - assert(ephemeral_iops >= 0); + assert(ephemeral_iops >= 0.0); /***************************************************************************/ /* Allocate a container for the value and push onto the list. */ @@ -1563,7 +1565,7 @@ void evel_measurement_fsys_use_add(EVENT_MEASUREMENT * measurement, 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_configured = ephemeral_configured; fsys_use->ephemeral_used = ephemeral_used; fsys_use->ephemeral_iops = ephemeral_iops; @@ -3201,15 +3203,15 @@ void evel_json_encode_measurement(EVEL_JSON_BUFFER * jbuf, fsys_use->filesystem_name)) { evel_json_open_object(jbuf); + evel_enc_kv_string(jbuf, "filesystemName", fsys_use->filesystem_name); 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, "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, "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; } @@ -3516,7 +3518,7 @@ void evel_json_encode_measurement(EVEL_JSON_BUFFER * jbuf, { evel_json_open_object(jbuf); evel_enc_kv_string(jbuf, "name", measurement_group->name); - evel_json_open_opt_named_list(jbuf, "measurements"); + evel_json_open_opt_named_list(jbuf, "arrayOfFields"); /*********************************************************************/ /* Measurements list. */ @@ -3711,3 +3713,4 @@ void evel_free_measurement(EVENT_MEASUREMENT * event) EVEL_EXIT(); } + diff --git a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_sipsignaling.c b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_sipsignaling.c index 09c95cd0..45f53487 100644 --- a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_sipsignaling.c +++ b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_sipsignaling.c @@ -33,6 +33,8 @@ * 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 event_name Unique Event Name confirming Domain AsdcModel Description + * @param event_id A universal identifier of the event for: troubleshooting correlation, analysis, etc * @param vendor_name The vendor id to encode in the event vnf field. * @param module The module to encode in the event. * @param vnfname The Virtual network function to encode in the event. @@ -41,7 +43,8 @@ * ::evel_free_signaling. * @retval NULL Failed to create the event. *****************************************************************************/ -EVENT_SIGNALING * evel_new_signaling(const char * const vendor_name, +EVENT_SIGNALING * evel_new_signaling(const char* ev_name, const char *ev_id, + const char * const vendor_name, const char * const correlator, const char * const local_ip_address, const char * const local_port, @@ -72,7 +75,7 @@ EVENT_SIGNALING * evel_new_signaling(const char * const vendor_name, /***************************************************************************/ /* Initialize the header & the Signaling fields. */ /***************************************************************************/ - evel_init_header(&event->header,"SipSignaling"); + evel_init_header_nameid(&event->header,ev_name,ev_id); event->header.event_domain = EVEL_DOMAIN_SIPSIGNALING; event->major_version = EVEL_SIGNALING_MAJOR_VERSION; event->minor_version = EVEL_SIGNALING_MINOR_VERSION; diff --git a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_state_change.c b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_state_change.c index c9de5065..8915afaf 100644 --- a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_state_change.c +++ b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_state_change.c @@ -34,6 +34,8 @@ * explicit setter functions, but again values may only be set once * so that the State Change has immutable properties. * + * @param event_name Unique Event Name confirming Domain AsdcModel Description + * @param event_id A universal identifier of the event for: troubleshooting correlation, analysis, etc * @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. @@ -43,7 +45,9 @@ * ::evel_free_state_change * @retval NULL Failed to create the event. *****************************************************************************/ -EVENT_STATE_CHANGE * evel_new_state_change(const EVEL_ENTITY_STATE new_state, +EVENT_STATE_CHANGE * evel_new_state_change(const char* ev_name, + const char *ev_id, + const EVEL_ENTITY_STATE new_state, const EVEL_ENTITY_STATE old_state, const char * const interface) { @@ -73,7 +77,7 @@ EVENT_STATE_CHANGE * evel_new_state_change(const EVEL_ENTITY_STATE new_state, /* Initialize the header & the State Change fields. Optional string */ /* values are uninitialized (NULL). */ /***************************************************************************/ - evel_init_header(&state_change->header,"StateChange"); + evel_init_header_nameid(&state_change->header,ev_name,ev_id); 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; diff --git a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_syslog.c b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_syslog.c index fb22df9f..85b0ec91 100644 --- a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_syslog.c +++ b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_syslog.c @@ -33,6 +33,8 @@ * 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_name Unique Event Name confirming Domain AsdcModel Description + * @param event_id A universal identifier of the event for: troubleshooting correlation, analysis, etc * @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. @@ -41,7 +43,8 @@ * ::evel_free_syslog. * @retval NULL Failed to create the event. *****************************************************************************/ -EVENT_SYSLOG * evel_new_syslog(EVEL_SOURCE_TYPES event_source_type, +EVENT_SYSLOG * evel_new_syslog(const char* ev_name, const char *ev_id, + EVEL_SOURCE_TYPES event_source_type, const char * const syslog_msg, const char * const syslog_tag) { @@ -71,7 +74,7 @@ EVENT_SYSLOG * evel_new_syslog(EVEL_SOURCE_TYPES event_source_type, /* Initialize the header & the Syslog fields. Optional string values are */ /* uninitialized (NULL). */ /***************************************************************************/ - evel_init_header(&syslog->header,"Syslog"); + evel_init_header_nameid(&syslog->header,ev_name,ev_id); syslog->header.event_domain = EVEL_DOMAIN_SYSLOG; syslog->major_version = EVEL_SYSLOG_MAJOR_VERSION; syslog->minor_version = EVEL_SYSLOG_MINOR_VERSION; diff --git a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_threshold_cross.c b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_threshold_cross.c index a0a9cc3d..f4fa620f 100644 --- a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_threshold_cross.c +++ b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_threshold_cross.c @@ -35,6 +35,8 @@ * setter functions, but again values may only be set once so that the * TCA has immutable properties. * + * @param event_name Unique Event Name confirming Domain AsdcVnfModel Description + * @param event_id A universal identifier of the event for: troubleshooting correlation, analysis, etc * @param char* tcriticality Performance Counter Criticality MAJ MIN, * @param char* tname Performance Counter Threshold name * @param char* tthresholdCrossed Counter Threshold crossed value @@ -51,7 +53,8 @@ * ::evel_free_threshold_cross * @retval NULL Failed to create the event. *****************************************************************************/ -EVENT_THRESHOLD_CROSS * evel_new_threshold_cross( char * tcriticality, +EVENT_THRESHOLD_CROSS * evel_new_threshold_cross(const char * ev_name, const char * ev_id, + char * tcriticality, char * tname, char * tthresholdCrossed, char * tvalue, @@ -87,7 +90,7 @@ EVENT_THRESHOLD_CROSS * evel_new_threshold_cross( char * tcriticality, /***************************************************************************/ /* Initialize the header & the threshold crossing fields. */ /***************************************************************************/ - evel_init_header(&event->header,"thresholdCrossingAlert"); + evel_init_header_nameid(&event->header,ev_name,ev_id); event->header.event_domain = EVEL_DOMAIN_THRESHOLD_CROSS; event->major_version = EVEL_THRESHOLD_CROSS_MAJOR_VERSION; event->minor_version = EVEL_THRESHOLD_CROSS_MINOR_VERSION; diff --git a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_voicequality.c b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_voicequality.c index c3826cab..cf2ec878 100644 --- a/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_voicequality.c +++ b/vnfs/VES5.0/evel/evel-library/code/evel_library/evel_voicequality.c @@ -34,6 +34,8 @@ * factory function and are immutable once set. Optional fields have * explicit setter functions, but again values may only be set once * so that the Voice Quality has immutable properties. + * @param event_name Unique Event Name + * @param event_id A universal identifier of the event for analysis etc. * @param calleeSideCodec Callee codec for the call. * @param callerSideCodec Caller codec for the call. * @param correlator Constant across all events on this call. @@ -45,7 +47,8 @@ ::evel_free_voice_quality. * @retval NULL Failed to create the event. *****************************************************************************/ -EVENT_VOICE_QUALITY * evel_new_voice_quality(const char * const calleeSideCodec, +EVENT_VOICE_QUALITY * evel_new_voice_quality(const char* ev_name, const char *ev_id, + const char * const calleeSideCodec, const char * const callerSideCodec, const char * const correlator, const char * const midCallRtcp, const char * const vendorName) { @@ -82,7 +85,7 @@ EVENT_VOICE_QUALITY * evel_new_voice_quality(const char * const calleeSideCodec, /* Initialize the header & the fault fields. Optional integer values are */ /* initialized as 0. */ /***************************************************************************/ - evel_init_header(&voiceQuality->header,"voiceQuality"); + evel_init_header_nameid(&voiceQuality->header,ev_name,ev_id); voiceQuality->header.event_domain = EVEL_DOMAIN_VOICE_QUALITY; voiceQuality->major_version = EVEL_VOICEQ_MAJOR_VERSION; voiceQuality->minor_version = EVEL_VOICEQ_MINOR_VERSION; diff --git a/vnfs/VES5.0/evel/evel-test-collector/code/collector/rest_dispatcher.pyc b/vnfs/VES5.0/evel/evel-test-collector/code/collector/rest_dispatcher.pyc Binary files differdeleted file mode 100644 index 7a084e5f..00000000 --- a/vnfs/VES5.0/evel/evel-test-collector/code/collector/rest_dispatcher.pyc +++ /dev/null diff --git a/vnfs/VES5.0/evel/evel-test-collector/docs/att_interface_definition/event_format_updated.json b/vnfs/VES5.0/evel/evel-test-collector/docs/att_interface_definition/event_format_updated.json index 986ed8f5..160add52 100644 --- a/vnfs/VES5.0/evel/evel-test-collector/docs/att_interface_definition/event_format_updated.json +++ b/vnfs/VES5.0/evel/evel-test-collector/docs/att_interface_definition/event_format_updated.json @@ -2,48 +2,37 @@ "$schema": "http://json-schema.org/draft-04/schema#",
"definitions": {
- "attCopyrightNotice": {
- "description": "Copyright (c) <2016>, AT&T Intellectual Property. All other rights reserved",
- "type": "object",
- "properties": {
- "useAndRedistribution": {
- "description": "Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:",
- "type": "string"
- },
- "condition1": {
- "description": "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.",
- "type": "string"
- },
- "condition2": {
- "description": "Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.",
- "type": "string"
- },
- "condition3": {
- "description": "All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes software developed by the AT&T.",
- "type": "string"
- },
- "condition4": {
- "description": "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.",
- "type": "string"
- },
- "disclaimerLine1": {
- "description": "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",
- "type": "string"
- },
- "disclaimerLine2": {
- "description": "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",
- "type": "string"
- },
- "disclaimerLine3": {
- "description": "(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,",
- "type": "string"
+ "attCopyrightNotice": {
+ "description": "Copyright (c) <2017>, AT&T Intellectual Property. All rights reserved. Licensed under the Apache License, Version 2.0 (the License)",
+ "type": "object",
+ "properties": {
+ "useAndRedistribution": {
+ "description": "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",
+ "type": "string"
+ },
+ "licenseLink": "http://www.apache.org/licenses/LICENSE-2.0",
+ "condition1": {
+ "description": "Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an AS IS BASIS,",
+ "type": "string"
+ },
+ "condition2": {
+ "description": "Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.",
+ "type": "string"
+ },
+ "condition3": {
+ "description": "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.",
+ "type": "string"
+ },
+ "condition4": {
+ "description": "See the License for the specific language governing permissions and limitations under the License.",
+ "type": "string"
+ },
+ "Trademarks": {
+ "description": "ECOMP and OpenECOMP are trademarks and service marks of AT&T Intellectual Property.",
+ "type": "string"
+ }
+ }
},
- "disclaimerLine4": {
- "description": "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.",
- "type": "string"
- }
- }
- },
"codecsInUse": {
"description": "number of times an identified codec was used over the measurementInterval",
"type": "object",
@@ -1704,11 +1693,11 @@ "type": "string"
},
"vfModuleName": {
- "description": "ASDC vfModuleName for the vfModule generating the event",
+ "description": "SDC vfModuleName for the vfModule generating the event",
"type": "string"
},
"vnfName": {
- "description": "ASDC modelName for the VNF generating the event",
+ "description": "SDC modelName for the VNF generating the event",
"type": "string"
}
},
diff --git a/vnfs/VESreporting_vFW5.0/vpp_measurement_reporter.c b/vnfs/VESreporting_vFW5.0/vpp_measurement_reporter.c index 05f52af5..8604d0cd 100644 --- a/vnfs/VESreporting_vFW5.0/vpp_measurement_reporter.c +++ b/vnfs/VESreporting_vFW5.0/vpp_measurement_reporter.c @@ -245,7 +245,7 @@ int main(int argc, char** argv) packets_out_this_round = 0; } - vpp_m = evel_new_measurement(READ_INTERVAL); + vpp_m = evel_new_measurement(READ_INTERVAL,"Measurement_vVNF","TrafficStats_1.2.3.4"); vnic_performance = (MEASUREMENT_VNIC_PERFORMANCE *)evel_measurement_new_vnic_performance("eth0", "true"); evel_meas_vnic_performance_add(vpp_m, vnic_performance); @@ -277,6 +277,8 @@ int main(int argc, char** argv) evel_last_epoch_set(&vpp_m->header, epoch_now); epoch_start = epoch_now; + evel_nfcnamingcode_set(&vpp_m->header, "vVNF"); + evel_nfnamingcode_set(&vpp_m->header, "vVNF"); //strcpy(vpp_m_header->reporting_entity_id.value, "No UUID available"); //strcpy(vpp_m_header->reporting_entity_name, hostname); evel_reporting_entity_name_set(&vpp_m->header, "fwll"); diff --git a/vnfs/VESreporting_vLB5.0/vpp_measurement_reporter.c b/vnfs/VESreporting_vLB5.0/vpp_measurement_reporter.c index afbbce8d..98450f0f 100644 --- a/vnfs/VESreporting_vLB5.0/vpp_measurement_reporter.c +++ b/vnfs/VESreporting_vLB5.0/vpp_measurement_reporter.c @@ -206,7 +206,7 @@ int main(int argc, char** argv) packets_out_this_round = 0; } - vpp_m = evel_new_measurement(READ_INTERVAL); + vpp_m = evel_new_measurement(READ_INTERVAL,"Measurement_vVNF","TrafficStats_1.2.3.4"); vnic_performance = (MEASUREMENT_VNIC_PERFORMANCE *)evel_measurement_new_vnic_performance("eth0", "true"); evel_meas_vnic_performance_add(vpp_m, vnic_performance); @@ -237,9 +237,11 @@ int main(int argc, char** argv) evel_last_epoch_set(&vpp_m->header, epoch_now); epoch_start = epoch_now; + evel_nfcnamingcode_set(&vpp_m->header, "vVNF"); + evel_nfnamingcode_set(&vpp_m->header, "vVNF"); //strcpy(vpp_m_header->reporting_entity_id.value, "No UUID available"); //strcpy(vpp_m_header->reporting_entity_name, hostname); - evel_reporting_entity_name_set(&vpp_m->header, hostname); + evel_reporting_entity_name_set(&vpp_m->header, "lbll"); evel_reporting_entity_id_set(&vpp_m->header, "No UUID available"); evel_rc = evel_post_event(vpp_m_header); diff --git a/vnfs/vCPE/kea-sdnc-notify-mod/etc/kea-sdnc-notify.conf b/vnfs/vCPE/kea-sdnc-notify-mod/etc/kea-sdnc-notify.conf index 1a8ee2e3..6fd09843 100644 --- a/vnfs/vCPE/kea-sdnc-notify-mod/etc/kea-sdnc-notify.conf +++ b/vnfs/vCPE/kea-sdnc-notify-mod/etc/kea-sdnc-notify.conf @@ -1,3 +1,4 @@ -{"url": "http://localhost/sdnc.php?macaddr=", +{ + "url": "http://DMAAP_IPADDR:3904/events/VCPE-DHCP-EVENT/", "siaddr": "siaddr" } diff --git a/vnfs/vCPE/kea-sdnc-notify-mod/etc/kea-sdnc-notify.conf.test b/vnfs/vCPE/kea-sdnc-notify-mod/etc/kea-sdnc-notify.conf.test new file mode 100644 index 00000000..beba0f15 --- /dev/null +++ b/vnfs/vCPE/kea-sdnc-notify-mod/etc/kea-sdnc-notify.conf.test @@ -0,0 +1,4 @@ +{ + "url": "http://localhost/sdnc.php", + "siaddr": "siaddr" +} diff --git a/vnfs/vCPE/kea-sdnc-notify-mod/src/pkt4_send.cc b/vnfs/vCPE/kea-sdnc-notify-mod/src/pkt4_send.cc index 231a0a8b..70d86289 100644 --- a/vnfs/vCPE/kea-sdnc-notify-mod/src/pkt4_send.cc +++ b/vnfs/vCPE/kea-sdnc-notify-mod/src/pkt4_send.cc @@ -84,10 +84,12 @@ int pkt4_send(CalloutHandle& handle) { hwaddr = hwaddr_ptr->toText(false); yiaddr = new_yiaddr.toText(); msg_name = response4_ptr->getName(); - post_data = "{ macaddr=" + hwaddr + "&yiaddr=" + yiaddr + "&msg=" + msg_name + "}"; - final_url = json_params[0] + hwaddr; + /* POST string for DMaaP */ + post_data = "{\n\"macaddr\":\"" + hwaddr + "\",\n\"yiaddr\":\"" + yiaddr + "\",\n\"msg_name\":\"" + msg_name + "\"\n}"; + final_url = json_params[0] ; LOG_DEBUG(logger, 0, "SNL_BASE").arg(final_url); LOG_DEBUG(logger, 0, "SNL_BASE").arg(yiaddr); + LOG_DEBUG(logger, 0, "SNL_BASE").arg(post_data); if ( msg_name == "DHCPACK") @@ -106,6 +108,7 @@ int pkt4_send(CalloutHandle& handle) { return(1); } + list = curl_slist_append(list, "Content-type: application/json"); list = curl_slist_append(list, "Accept: application/json"); if (list == NULL) { curl_easy_cleanup(curl); @@ -126,15 +129,11 @@ int pkt4_send(CalloutHandle& handle) { curl_opt_res += curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); curl_opt_res += curl_easy_setopt(curl, CURLOPT_HEADER, 1L); - // If we don't set a timeout, curl will try for 300 seconds by default. + // Default curl timeout is 300 seconds curl_opt_res += curl_easy_setopt(curl, CURLOPT_TIMEOUT, 1L); curl_opt_res += curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 1L); - // libcurl's docs say to cast as void, don't blame me. curl_opt_res += curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)response_memfile); - // CURLOPT_URL takes a char* curl_opt_res += curl_easy_setopt(curl, CURLOPT_URL, (final_url).c_str()); - - // let curl use strlen curl_opt_res += curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, -1L ); curl_opt_res += curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data.c_str() ); curl_opt_res += curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list); diff --git a/vnfs/vCPE/scripts/kea-dhcp4_no_hook.conf b/vnfs/vCPE/scripts/kea-dhcp4_no_hook.conf new file mode 100644 index 00000000..3e2287d1 --- /dev/null +++ b/vnfs/vCPE/scripts/kea-dhcp4_no_hook.conf @@ -0,0 +1,59 @@ +{ +"Dhcp4": + { +# For testing, you can use veth pair as described in README.md + "interfaces-config": { + "interfaces": ["eth0" ] + }, + + "lease-database": { + "type": "memfile" + }, + + "expired-leases-processing": { + "reclaim-timer-wait-time": 10, + "flush-reclaimed-timer-wait-time": 25, + "hold-reclaimed-time": 3600, + "max-reclaim-leases": 100, + "max-reclaim-time": 250, + "unwarned-reclaim-cycles": 5 + }, + + "valid-lifetime": 300, + +# Ensure you set some sensible defaults for the siaddr and option-data, +# otherwise the options won't be added at all. +# Also keep in mind that if kea doesn't receive the desired values for some +# reason, these values will be sent to the client. + "subnet4": [ + { "subnet": "10.2.0.0/24", + "pools" : [ { "pool": "10.2.0.2 - 10.2.0.255"} ], + "next-server": "10.2.0.1", + "option-data": [ + {"name": "tftp-server-name", + "data": "10.2.0.1"}, + {"name": "boot-file-name", + "data": "/dev/null"} + ] + } + ] + +}, + +"Logging": +{ + "loggers": [ + { + "name": "kea-dhcp4", + "output_options": [ + { + "output": "/var/log/kea-dhcp4.log" + } + ], + "severity": "DEBUG", + "debuglevel": 0 + }, + ] +} + +} diff --git a/vnfs/vCPE/scripts/kea-sdnc-notify.conf b/vnfs/vCPE/scripts/kea-sdnc-notify.conf index 1a8ee2e3..6fd09843 100644 --- a/vnfs/vCPE/scripts/kea-sdnc-notify.conf +++ b/vnfs/vCPE/scripts/kea-sdnc-notify.conf @@ -1,3 +1,4 @@ -{"url": "http://localhost/sdnc.php?macaddr=", +{ + "url": "http://DMAAP_IPADDR:3904/events/VCPE-DHCP-EVENT/", "siaddr": "siaddr" } diff --git a/vnfs/vCPE/scripts/v_aaa_install.sh b/vnfs/vCPE/scripts/v_aaa_install.sh index a4a34aca..797da69c 100644 --- a/vnfs/vCPE/scripts/v_aaa_install.sh +++ b/vnfs/vCPE/scripts/v_aaa_install.sh @@ -48,9 +48,10 @@ then fi # Download required dependencies -add-apt-repository -y ppa:openjdk-r/ppa +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list apt-get update -apt-get install -y wget openjdk-8-jdk apt-transport-https ca-certificates g++ libcurl4-gnutls-dev +apt-get install --allow-unauthenticated -y wget openjdk-8-jdk apt-transport-https ca-certificates g++ libcurl4-gnutls-dev sleep 1 # Download DHCP config files @@ -62,6 +63,9 @@ chmod +x v_aaa.sh mv v_aaa.sh /etc/init.d update-rc.d v_aaa.sh defaults +# Download and install FreeRADIUS as AAA server +apt-get install -y freeradius + # Rename network interface in openstack Ubuntu 16.04 images. Then, reboot the VM to pick up changes if [[ $CLOUD_ENV != "rackspace" ]] then diff --git a/vnfs/vCPE/scripts/v_bng_init.sh b/vnfs/vCPE/scripts/v_bng_init.sh index a9bf588e..6fb2eadc 100644 --- a/vnfs/vCPE/scripts/v_bng_init.sh +++ b/vnfs/vCPE/scripts/v_bng_init.sh @@ -1 +1,4 @@ #!/bin/bash + +systemctl start vpp + diff --git a/vnfs/vCPE/scripts/v_bng_install.sh b/vnfs/vCPE/scripts/v_bng_install.sh index dad8b2f7..02025b2e 100644 --- a/vnfs/vCPE/scripts/v_bng_install.sh +++ b/vnfs/vCPE/scripts/v_bng_install.sh @@ -4,6 +4,9 @@ REPO_URL_BLOB=$(cat /opt/config/repo_url_blob.txt) REPO_URL_ARTIFACTS=$(cat /opt/config/repo_url_artifacts.txt) DEMO_ARTIFACTS_VERSION=$(cat /opt/config/demo_artifacts_version.txt) INSTALL_SCRIPT_VERSION=$(cat /opt/config/install_script_version.txt) +VPP_SOURCE_REPO_URL=$(cat /opt/config/vpp_source_repo_url.txt) +VPP_SOURCE_REPO_BRANCH=$(cat /opt/config/vpp_source_repo_branch.txt) +VPP_PATCH_URL=$(cat /opt/config/vpp_patch_url.txt) CLOUD_ENV=$(cat /opt/config/cloud_env.txt) # Convert Network CIDR to Netmask @@ -68,11 +71,280 @@ then fi # Download required dependencies -add-apt-repository -y ppa:openjdk-r/ppa +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list apt-get update -apt-get install -y wget openjdk-8-jdk apt-transport-https ca-certificates g++ libcurl4-gnutls-dev +apt-get install --allow-unauthenticated -y wget openjdk-8-jdk apt-transport-https ca-certificates g++ libcurl4-gnutls-dev sleep 1 +# Install the tools required for download codes +apt-get install -y expect git patch + +#Download and build the VPP codes +cd /opt +git clone ${VPP_SOURCE_REPO_URL} -b ${VPP_SOURCE_REPO_BRANCH} vpp +wget -O Vpp-Integrate-FreeRADIUS-Client-for-vBNG.patch ${VPP_PATCH_URL} + +cd vpp +patch -p1 < Vpp-Integrate-FreeRADIUS-Client-for-vBNG.patch +expect -c " + set timeout 60; + spawn make install-dep; + expect { + \"Do you want to continue?*\" {send \"Y\r\"; interact} + } +" + +cd build-root +./bootstrap.sh +make V=0 PLATFORM=vpp TAG=vpp install-deb + +# Install the FreeRADIUS client since we need the lib +cd /opt +git clone https://github.com/FreeRADIUS/freeradius-client.git +cd freeradius-client +./configure +make && make install +cd /usr/local/lib && ln -s -f libfreeradius-client.so.2.0.0 libfreeradiusclient.so +ldconfig + +# Install the VPP package +cd /opt/vpp/build-root +dpkg -i *.deb +systemctl stop vpp + +# Auto-start configuration for the VPP +cat > /etc/vpp/startup.conf << EOF + +unix { + nodaemon + log /tmp/vpp.log + full-coredump + cli-listen localhost:5002 + startup-config /etc/vpp/setup.gate +} + +api-trace { + on +} + +api-segment { + gid vpp +} + +cpu { + ## In the VPP there is one main thread and optionally the user can create worker(s) + ## The main thread and worker thread(s) can be pinned to CPU core(s) manually or automatically + + ## Manual pinning of thread(s) to CPU core(s) + + ## Set logical CPU core where main thread runs + # main-core 1 + + ## Set logical CPU core(s) where worker threads are running + # corelist-workers 2-3,18-19 + + ## Automatic pinning of thread(s) to CPU core(s) + + ## Sets number of CPU core(s) to be skipped (1 ... N-1) + ## Skipped CPU core(s) are not used for pinning main thread and working thread(s). + ## The main thread is automatically pinned to the first available CPU core and worker(s) + ## are pinned to next free CPU core(s) after core assigned to main thread + # skip-cores 4 + + ## Specify a number of workers to be created + ## Workers are pinned to N consecutive CPU cores while skipping "skip-cores" CPU core(s) + ## and main thread's CPU core + # workers 2 + + ## Set scheduling policy and priority of main and worker threads + + ## Scheduling policy options are: other (SCHED_OTHER), batch (SCHED_BATCH) + ## idle (SCHED_IDLE), fifo (SCHED_FIFO), rr (SCHED_RR) + # scheduler-policy fifo + + ## Scheduling priority is used only for "real-time policies (fifo and rr), + ## and has to be in the range of priorities supported for a particular policy + # scheduler-priority 50 +} + +# dpdk { + ## Change default settings for all intefaces + # dev default { + ## Number of receive queues, enables RSS + ## Default is 1 + # num-rx-queues 3 + + ## Number of transmit queues, Default is equal + ## to number of worker threads or 1 if no workers treads + # num-tx-queues 3 + + ## Number of descriptors in transmit and receive rings + ## increasing or reducing number can impact performance + ## Default is 1024 for both rx and tx + # num-rx-desc 512 + # num-tx-desc 512 + + ## VLAN strip offload mode for interface + ## Default is off + # vlan-strip-offload on + # } + + ## Whitelist specific interface by specifying PCI address + # dev 0000:02:00.0 + + ## Whitelist specific interface by specifying PCI address and in + ## addition specify custom parameters for this interface + # dev 0000:02:00.1 { + # num-rx-queues 2 + # } + + ## Change UIO driver used by VPP, Options are: igb_uio, vfio-pci + ## and uio_pci_generic (default) + # uio-driver vfio-pci + + ## Disable mutli-segment buffers, improves performance but + ## disables Jumbo MTU support + # no-multi-seg + + ## Increase number of buffers allocated, needed only in scenarios with + ## large number of interfaces and worker threads. Value is per CPU socket. + ## Default is 16384 + # num-mbufs 128000 + + ## Change hugepages allocation per-socket, needed only if there is need for + ## larger number of mbufs. Default is 256M on each detected CPU socket + # socket-mem 2048,2048 +# } + +EOF + +cat > /etc/vpp/setup.gate << EOF +set int state GigabitEthernet0/8/0 up +set interface ip address GigabitEthernet0/8/0 10.4.0.4/24 + +set int state GigabitEthernet0/9/0 up +set interface ip address GigabitEthernet0/9/0 10.4.0.3/24 + +set vbng dhcp4 remote 10.4.0.1 local 10.4.0.3 +set vbng aaa config /etc/vpp/vbng-aaa.cfg nas-port 5060 +EOF + +cat > /etc/vpp/vbng-aaa.cfg << EOF +# General settings + +# specify which authentication comes first respectively which +# authentication is used. possible values are: "radius" and "local". +# if you specify "radius,local" then the RADIUS server is asked +# first then the local one. if only one keyword is specified only +# this server is asked. +auth_order radius,local + +# maximum login tries a user has +login_tries 2 + +# timeout for all login tries +# if this time is exceeded the user is kicked out +login_timeout 5 + +# name of the nologin file which when it exists disables logins. +# it may be extended by the ttyname which will result in +# a terminal specific lock (e.g. /etc/nologin.ttyS2 will disable +# logins on /dev/ttyS2) +nologin /etc/nologin + +# name of the issue file. it's only display when no username is passed +# on the radlogin command line +issue /usr/local/etc/radiusclient/issue + +# RADIUS settings + +# RADIUS server to use for authentication requests. this config +# item can appear more then one time. if multiple servers are +# defined they are tried in a round robin fashion if one +# server is not answering. +# optionally you can specify a the port number on which is remote +# RADIUS listens separated by a colon from the hostname. if +# no port is specified /etc/services is consulted of the radius +# service. if this fails also a compiled in default is used. +#authserver 10.4.0.2 +authserver localhost + +# RADIUS server to use for accouting requests. All that I +# said for authserver applies, too. +# +#acctserver 10.4.0.2 +acctserver localhost + +# file holding shared secrets used for the communication +# between the RADIUS client and server +servers /usr/local/etc/radiusclient/servers + +# dictionary of allowed attributes and values +# just like in the normal RADIUS distributions +dictionary /usr/local/etc/radiusclient/dictionary + +# program to call for a RADIUS authenticated login +login_radius /usr/local/sbin/login.radius + +# file which holds sequence number for communication with the +# RADIUS server +seqfile /var/run/radius.seq + +# file which specifies mapping between ttyname and NAS-Port attribute +mapfile /usr/local/etc/radiusclient/port-id-map + +# default authentication realm to append to all usernames if no +# realm was explicitly specified by the user +# the radiusd directly form Livingston doesnt use any realms, so leave +# it blank then +default_realm + +# time to wait for a reply from the RADIUS server +radius_timeout 10 + +# resend request this many times before trying the next server +radius_retries 3 + +# The length of time in seconds that we skip a nonresponsive RADIUS +# server for transaction requests. Server(s) being in the "dead" state +# are tried only after all other non-dead servers have been tried and +# failed or timeouted. The deadtime interval starts when the server +# does not respond to an authentication/accounting request transmissions. +# When the interval expires, the "dead" server would be re-tried again, +# and if it's still down then it will be considered "dead" for another +# such interval and so on. This option is no-op if there is only one +# server in the list. Set to 0 in order to disable the feature. +radius_deadtime 0 + +# local address from which radius packets have to be sent +bindaddr * + +# LOCAL settings + +# program to execute for local login +# it must support the -f flag for preauthenticated login +login_local /bin/login +EOF + +cat >> /usr/local/etc/radiusclient/dictionary << EOF + +# +# DHCP Proxy/Relay attributes +# +ATTRIBUTE DHCP-Agent-Circuit-Id 82.1 integer +ATTRIBUTE DHCP-Agent-Remote-Id 82.2 string +ATTRIBUTE DHCP-Relay-Circuit-Id 82.1 integer +ATTRIBUTE DHCP-Relay-Remote-Id 82.2 string + +EOF + +cat >> /usr/local/etc/radiusclient/servers << EOF +10.4.0.2 testing123 +localhost/localhost testing123 + +EOF + # Download DHCP config files cd /opt wget $REPO_URL_BLOB/org.onap.demo/vnfs/vcpe/$INSTALL_SCRIPT_VERSION/v_bng_init.sh @@ -94,4 +366,4 @@ then reboot fi -./v_bng_init.sh
\ No newline at end of file +./v_bng_init.sh diff --git a/vnfs/vCPE/scripts/v_brgemu_init.sh b/vnfs/vCPE/scripts/v_brgemu_init.sh index a9bf588e..1bf8a500 100644 --- a/vnfs/vCPE/scripts/v_brgemu_init.sh +++ b/vnfs/vCPE/scripts/v_brgemu_init.sh @@ -1 +1,6 @@ #!/bin/bash + +systemctl start vpp +systemctl start honeycomb + +/opt/set_nat.sh diff --git a/vnfs/vCPE/scripts/v_brgemu_install.sh b/vnfs/vCPE/scripts/v_brgemu_install.sh index 10976da1..c4626a41 100644 --- a/vnfs/vCPE/scripts/v_brgemu_install.sh +++ b/vnfs/vCPE/scripts/v_brgemu_install.sh @@ -4,6 +4,11 @@ REPO_URL_BLOB=$(cat /opt/config/repo_url_blob.txt) REPO_URL_ARTIFACTS=$(cat /opt/config/repo_url_artifacts.txt) DEMO_ARTIFACTS_VERSION=$(cat /opt/config/demo_artifacts_version.txt) INSTALL_SCRIPT_VERSION=$(cat /opt/config/install_script_version.txt) +VPP_SOURCE_REPO_URL=$(cat /opt/config/vpp_source_repo_url.txt) +VPP_SOURCE_REPO_BRANCH=$(cat /opt/config/vpp_source_repo_branch.txt) +VPP_PATCH_URL=$(cat /opt/config/vpp_patch_url.txt) +HC2VPP_SOURCE_REPO_URL=$(cat /opt/config/hc2vpp_source_repo_url.txt) +HC2VPP_SOURCE_REPO_BRANCH=$(cat /opt/config/hc2vpp_source_repo_branch.txt) CLOUD_ENV=$(cat /opt/config/cloud_env.txt) # Convert Network CIDR to Netmask @@ -38,11 +43,347 @@ then fi # Download required dependencies -add-apt-repository -y ppa:openjdk-r/ppa +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list apt-get update -apt-get install -y wget openjdk-8-jdk apt-transport-https ca-certificates g++ libcurl4-gnutls-dev +apt-get install --allow-unauthenticated -y wget openjdk-8-jdk apt-transport-https ca-certificates g++ libcurl4-gnutls-dev sleep 1 +# Install the tools required for download codes +apt-get install -y expect git patch + +#Download and build the VPP codes +cd /opt +git clone ${VPP_SOURCE_REPO_URL} -b ${VPP_SOURCE_REPO_BRANCH} vpp +wget -O VPP-Add-Option82-Nat-Filter-For-vBRG.patch ${VPP_PATCH_URL} + +cd vpp +patch -p1 < ../VPP-Add-Option82-Nat-Filter-For-vBRG.patch +expect -c " + set timeout 60; + spawn make install-dep; + expect { + \"Do you want to continue?*\" {send \"Y\r\"; interact} + } +" + +cd build-root +./bootstrap.sh +make V=0 PLATFORM=vpp TAG=vpp install-deb + +# Install the VPP package +dpkg -i *.deb +systemctl stop vpp + +# Auto-start configuration for the VPP +cat > /etc/vpp/startup.conf << EOF + +unix { + nodaemon + log /tmp/vpp.log + full-coredump + cli-listen localhost:5002 + startup-config /etc/vpp/setup.gate +} + +api-trace { + on +} + +api-segment { + gid vpp +} + +cpu { + ## In the VPP there is one main thread and optionally the user can create worker(s) + ## The main thread and worker thread(s) can be pinned to CPU core(s) manually or automatically + + ## Manual pinning of thread(s) to CPU core(s) + + ## Set logical CPU core where main thread runs + # main-core 1 + + ## Set logical CPU core(s) where worker threads are running + # corelist-workers 2-3,18-19 + + ## Automatic pinning of thread(s) to CPU core(s) + + ## Sets number of CPU core(s) to be skipped (1 ... N-1) + ## Skipped CPU core(s) are not used for pinning main thread and working thread(s). + ## The main thread is automatically pinned to the first available CPU core and worker(s) + ## are pinned to next free CPU core(s) after core assigned to main thread + # skip-cores 4 + + ## Specify a number of workers to be created + ## Workers are pinned to N consecutive CPU cores while skipping "skip-cores" CPU core(s) + ## and main thread's CPU core + # workers 2 + + ## Set scheduling policy and priority of main and worker threads + + ## Scheduling policy options are: other (SCHED_OTHER), batch (SCHED_BATCH) + ## idle (SCHED_IDLE), fifo (SCHED_FIFO), rr (SCHED_RR) + # scheduler-policy fifo + + ## Scheduling priority is used only for "real-time policies (fifo and rr), + ## and has to be in the range of priorities supported for a particular policy + # scheduler-priority 50 +} + +# dpdk { + ## Change default settings for all intefaces + # dev default { + ## Number of receive queues, enables RSS + ## Default is 1 + # num-rx-queues 3 + + ## Number of transmit queues, Default is equal + ## to number of worker threads or 1 if no workers treads + # num-tx-queues 3 + + ## Number of descriptors in transmit and receive rings + ## increasing or reducing number can impact performance + ## Default is 1024 for both rx and tx + # num-rx-desc 512 + # num-tx-desc 512 + + ## VLAN strip offload mode for interface + ## Default is off + # vlan-strip-offload on + # } + + ## Whitelist specific interface by specifying PCI address + # dev 0000:02:00.0 + + ## Whitelist specific interface by specifying PCI address and in + ## addition specify custom parameters for this interface + # dev 0000:02:00.1 { + # num-rx-queues 2 + # } + + ## Change UIO driver used by VPP, Options are: igb_uio, vfio-pci + ## and uio_pci_generic (default) + # uio-driver vfio-pci + + ## Disable mutli-segment buffers, improves performance but + ## disables Jumbo MTU support + # no-multi-seg + + ## Increase number of buffers allocated, needed only in scenarios with + ## large number of interfaces and worker threads. Value is per CPU socket. + ## Default is 16384 + # num-mbufs 128000 + + ## Change hugepages allocation per-socket, needed only if there is need for + ## larger number of mbufs. Default is 256M on each detected CPU socket + # socket-mem 2048,2048 +# } + +EOF + +cat > /etc/vpp/setup.gate << EOF +set int state GigabitEthernet0/8/0 up +set dhcp client intfc GigabitEthernet0/8/0 hostname brg-emulator + +tap connect lstack +set int state tap-0 up + +set interface l2 bridge tap-0 10 0 +set bridge-domain arp term 10 +EOF + +cat >> /opt/config/ip.txt << EOF +hcip: 192.168.1.20 +EOF + +#set nat rule +cat > /opt/set_nat.sh << EOF +#! /bin/bash + +while : +do + if [[ ! $(ps -aux | grep [[:alnum:]]*/vpp/startup.conf | wc -l) = 2 ]]; then + #echo "vpp not running" + continue + fi + flag=0 + while read -r line + do + if [ flag = 0 ]; then + re=${line#*/[0-9]/[0-9]} + if [ "$line" != "$re" ]; then + flag=1 + else + flag=0 + continue + fi + else + ip=${line%/*} + if [[ $ip = *\.*\.*\.* ]]; then + #echo "ip address is $ip" + if [ ! -f /opt/config/ip.txt ]; then + echo "file /opt/config/ip.txt doesn't exists" + continue + fi + while read -r tap_ip + do + if [[ $tap_ip = hcip* ]]; then + tap_ip=${tap_ip#*" "} + echo "hc tap ip address is $tap_ip" + vppctl snat add static mapping local $tap_ip external $ip + exit 0 + fi + done < /opt/config/ip.txt + else + if [[ ! $ip = */[0-9] ]]; then + flag=0 + #echo "not correct" + fi + fi + fi + done < <(vppctl show int addr) + sleep 1 +done +EOF +# Download and install HC2VPP from source +cd /opt +git clone ${HC2VPP_SOURCE_REPO_URL} -b ${HC2VPP_SOURCE_REPO_BRANCH} hc2vpp + +apt-get install -y maven +cat > ~/.m2/settings.xml << EOF +<?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> +EOF + +cd hc2vpp +mvn clean install +l_version=$(cat pom.xml | grep "<version>" | head -1) +l_version=$(echo "${l_version%<*}") +l_version=$(echo "${l_version#*>}") +mv vpp-integration/minimal-distribution/target/vpp-integration-distribution-${l_version}-hc/vpp-integration-distribution-${l_version} /opt/honeycomb +sed -i 's/127.0.0.1/0.0.0.0/g' /opt/honeycomb/config/honeycomb.json + +# Create systemctl service for Honeycomb +cat > /etc/systemd/system/honeycomb.service << EOF +[Unit] +Description=Honeycomb Agent for the VPP control plane +Documentation=https://wiki.fd.io/view/Honeycomb +Requires=vpp.service +After=vpp.service + +[Service] +ExecStart=/opt/honeycomb/honeycomb +Restart=always +RestartSec=10 + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable /etc/systemd/system/honeycomb.service + # Download DHCP config files cd /opt wget $REPO_URL_BLOB/org.onap.demo/vnfs/vcpe/$INSTALL_SCRIPT_VERSION/v_brgemu_init.sh @@ -64,4 +405,4 @@ then reboot fi -./v_brgemu_init.sh
\ No newline at end of file +./v_brgemu_init.sh diff --git a/vnfs/vCPE/scripts/v_dhcp_install.sh b/vnfs/vCPE/scripts/v_dhcp_install.sh index d88ed509..f3697048 100644 --- a/vnfs/vCPE/scripts/v_dhcp_install.sh +++ b/vnfs/vCPE/scripts/v_dhcp_install.sh @@ -5,6 +5,7 @@ REPO_URL_ARTIFACTS=$(cat /opt/config/repo_url_artifacts.txt) DEMO_ARTIFACTS_VERSION=$(cat /opt/config/demo_artifacts_version.txt) INSTALL_SCRIPT_VERSION=$(cat /opt/config/install_script_version.txt) CLOUD_ENV=$(cat /opt/config/cloud_env.txt) +MR_IP_ADDR=$(cat /opt/config/mr_ip_addr.txt) # Convert Network CIDR to Netmask cdr2mask () { @@ -48,12 +49,13 @@ then fi # Download required dependencies -add-apt-repository -y ppa:openjdk-r/ppa +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list apt-get update -apt-get install -y wget openjdk-8-jdk apt-transport-https ca-certificates kea-dhcp4-server g++ libcurl4-gnutls-dev libboost-dev kea-dev +apt-get install --allow-unauthenticated -y wget openjdk-8-jdk apt-transport-https ca-certificates kea-dhcp4-server g++ libcurl4-gnutls-dev libboost-dev kea-dev sleep 1 -# download the kea hook +# Download the kea hook cd /opt wget $REPO_URL_ARTIFACTS/org/onap/demo/vnf/vcpe/kea-sdnc-notify-mod/$DEMO_ARTIFACTS_VERSION/kea-sdnc-notify-mod-$DEMO_ARTIFACTS_VERSION-demo.tar.gz tar -zxvf kea-sdnc-notify-mod-$DEMO_ARTIFACTS_VERSION-demo.tar.gz @@ -78,6 +80,7 @@ update-rc.d v_dhcp.sh defaults # Configure DHCP cp kea-dhcp4.conf /etc/kea-dhcp4-server.conf mv kea-dhcp4.conf /etc/kea/kea-dhcp4.conf +sed -i "s/DMAAP_IPADDR/"$MR_IP_ADDR"/g" kea-sdnc-notify.conf mv kea-sdnc-notify.conf /etc/kea/kea-sdnc-notify.conf sleep 1 diff --git a/vnfs/vCPE/scripts/v_dns_init.sh b/vnfs/vCPE/scripts/v_dns_init.sh index a9bf588e..dd85a92d 100644 --- a/vnfs/vCPE/scripts/v_dns_init.sh +++ b/vnfs/vCPE/scripts/v_dns_init.sh @@ -1 +1,4 @@ #!/bin/bash + +service kea-dhcp4-server start +service bind9 restart
\ No newline at end of file diff --git a/vnfs/vCPE/scripts/v_dns_install.sh b/vnfs/vCPE/scripts/v_dns_install.sh index 02ab69bf..feaa770e 100644 --- a/vnfs/vCPE/scripts/v_dns_install.sh +++ b/vnfs/vCPE/scripts/v_dns_install.sh @@ -48,20 +48,27 @@ then fi # Download required dependencies -add-apt-repository -y ppa:openjdk-r/ppa +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list apt-get update -apt-get install -y wget openjdk-8-jdk apt-transport-https ca-certificates g++ libcurl4-gnutls-dev +apt-get install --allow-unauthenticated -y wget openjdk-8-jdk bind9 bind9utils bind9-doc apt-transport-https ca-certificates kea-dhcp4-server g++ libcurl4-gnutls-dev libboost-dev kea-dev sleep 1 -# Download DHCP config files +# Download DNS and DHCP config files cd /opt +wget $REPO_URL_BLOB/org.onap.demo/vnfs/vcpe/$INSTALL_SCRIPT_VERSION/kea-dhcp4_no_hook.conf wget $REPO_URL_BLOB/org.onap.demo/vnfs/vcpe/$INSTALL_SCRIPT_VERSION/v_dns_init.sh wget $REPO_URL_BLOB/org.onap.demo/vnfs/vcpe/$INSTALL_SCRIPT_VERSION/v_dns.sh +mv kea-dhcp4_no_hook.conf /etc/kea/kea-dhcp4.conf chmod +x v_dns_init.sh chmod +x v_dns.sh mv v_dns.sh /etc/init.d update-rc.d v_dns.sh defaults +# Install Bind +mkdir /etc/bind/zones +sed -i "s/OPTIONS=.*/OPTIONS=\"-4 -u bind\"/g" /etc/default/bind9 + # Rename network interface in openstack Ubuntu 16.04 images. Then, reboot the VM to pick up changes if [[ $CLOUD_ENV != "rackspace" ]] then diff --git a/vnfs/vCPE/scripts/v_gmux_init.sh b/vnfs/vCPE/scripts/v_gmux_init.sh index a9bf588e..41730d3a 100644 --- a/vnfs/vCPE/scripts/v_gmux_init.sh +++ b/vnfs/vCPE/scripts/v_gmux_init.sh @@ -1 +1,6 @@ #!/bin/bash + +systemctl start vpp +systemctl start honeycomb +systemctl start autosave + diff --git a/vnfs/vCPE/scripts/v_gmux_install.sh b/vnfs/vCPE/scripts/v_gmux_install.sh index b43cf7bf..9ab81403 100644 --- a/vnfs/vCPE/scripts/v_gmux_install.sh +++ b/vnfs/vCPE/scripts/v_gmux_install.sh @@ -4,6 +4,12 @@ REPO_URL_BLOB=$(cat /opt/config/repo_url_blob.txt) REPO_URL_ARTIFACTS=$(cat /opt/config/repo_url_artifacts.txt) DEMO_ARTIFACTS_VERSION=$(cat /opt/config/demo_artifacts_version.txt) INSTALL_SCRIPT_VERSION=$(cat /opt/config/install_script_version.txt) +VPP_SOURCE_REPO_URL=$(cat /opt/config/vpp_source_repo_url.txt) +VPP_SOURCE_REPO_BRANCH=$(cat /opt/config/vpp_source_repo_branch.txt) +VPP_PATCH_URL=$(cat /opt/config/vpp_patch_url.txt) +HC2VPP_SOURCE_REPO_URL=$(cat /opt/config/hc2vpp_source_repo_url.txt) +HC2VPP_SOURCE_REPO_BRANCH=$(cat /opt/config/hc2vpp_source_repo_branch.txt) +HC2VPP_PATCH_URL=$(cat /opt/config/hc2vpp_patch_url.txt) CLOUD_ENV=$(cat /opt/config/cloud_env.txt) # Convert Network CIDR to Netmask @@ -58,11 +64,474 @@ then fi # Download required dependencies -add-apt-repository -y ppa:openjdk-r/ppa +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list apt-get update -apt-get install -y wget openjdk-8-jdk apt-transport-https ca-certificates g++ libcurl4-gnutls-dev +apt-get install --allow-unauthenticated -y wget openjdk-8-jdk apt-transport-https ca-certificates g++ libcurl4-gnutls-dev sleep 1 +# Install the tools required for download codes +apt-get install -y expect git patch make + +#Download and build the VPP codes +cd /opt +git clone ${VPP_SOURCE_REPO_URL} -b ${VPP_SOURCE_REPO_BRANCH} vpp +wget -O Vpp-Add-VES-agent-for-vG-MUX.patch ${VPP_PATCH_URL} + +cd vpp +patch -p1 < ../Vpp-Add-VES-agent-for-vG-MUX.patch +expect -c " + spawn make install-dep; + expect { + \"Do you want to continue?*\" {send \"Y\r\"; interact} + } +" + +# Install the evel-library first since we need the lib +cd /opt +apt-get install -y libcurl4-openssl-dev +git clone http://gerrit.onap.org/r/demo +cd demo/vnfs/VES5.0/evel/evel-library/bldjobs +make +cp ../libs/x86_64/libevel.so /usr/lib +ldconfig + +cd /opt/vpp/build-root +./bootstrap.sh +make V=0 PLATFORM=vpp TAG=vpp install-deb + +# Install the VPP package +apt install -y python-ply-lex-3.5 python-ply-yacc-3.5 python-pycparser python-cffi +dpkg -i *.deb +systemctl stop vpp + +# Auto-start configuration for the VPP +cat > /etc/vpp/startup.conf << EOF + +unix { + nodaemon + log /tmp/vpp.log + full-coredump + cli-listen localhost:5002 + startup-config /etc/vpp/setup.gate +} + +api-trace { + on +} + +api-segment { + gid vpp +} + +cpu { + ## In the VPP there is one main thread and optionally the user can create worker(s) + ## The main thread and worker thread(s) can be pinned to CPU core(s) manually or automatically + + ## Manual pinning of thread(s) to CPU core(s) + + ## Set logical CPU core where main thread runs + # main-core 1 + + ## Set logical CPU core(s) where worker threads are running + # corelist-workers 2-3,18-19 + + ## Automatic pinning of thread(s) to CPU core(s) + + ## Sets number of CPU core(s) to be skipped (1 ... N-1) + ## Skipped CPU core(s) are not used for pinning main thread and working thread(s). + ## The main thread is automatically pinned to the first available CPU core and worker(s) + ## are pinned to next free CPU core(s) after core assigned to main thread + # skip-cores 4 + + ## Specify a number of workers to be created + ## Workers are pinned to N consecutive CPU cores while skipping "skip-cores" CPU core(s) + ## and main thread's CPU core + # workers 2 + + ## Set scheduling policy and priority of main and worker threads + + ## Scheduling policy options are: other (SCHED_OTHER), batch (SCHED_BATCH) + ## idle (SCHED_IDLE), fifo (SCHED_FIFO), rr (SCHED_RR) + # scheduler-policy fifo + + ## Scheduling priority is used only for "real-time policies (fifo and rr), + ## and has to be in the range of priorities supported for a particular policy + # scheduler-priority 50 +} + +# dpdk { + ## Change default settings for all intefaces + # dev default { + ## Number of receive queues, enables RSS + ## Default is 1 + # num-rx-queues 3 + + ## Number of transmit queues, Default is equal + ## to number of worker threads or 1 if no workers treads + # num-tx-queues 3 + + ## Number of descriptors in transmit and receive rings + ## increasing or reducing number can impact performance + ## Default is 1024 for both rx and tx + # num-rx-desc 512 + # num-tx-desc 512 + + ## VLAN strip offload mode for interface + ## Default is off + # vlan-strip-offload on + # } + + ## Whitelist specific interface by specifying PCI address + # dev 0000:02:00.0 + + ## Whitelist specific interface by specifying PCI address and in + ## addition specify custom parameters for this interface + # dev 0000:02:00.1 { + # num-rx-queues 2 + # } + + ## Change UIO driver used by VPP, Options are: igb_uio, vfio-pci + ## and uio_pci_generic (default) + # uio-driver vfio-pci + + ## Disable mutli-segment buffers, improves performance but + ## disables Jumbo MTU support + # no-multi-seg + + ## Increase number of buffers allocated, needed only in scenarios with + ## large number of interfaces and worker threads. Value is per CPU socket. + ## Default is 16384 + # num-mbufs 128000 + + ## Change hugepages allocation per-socket, needed only if there is need for + ## larger number of mbufs. Default is 256M on each detected CPU socket + # socket-mem 2048,2048 +# } + +EOF + +cat > /etc/vpp/setup.gate << EOF +set int state GigabitEthernet0/8/0 up +set int ip address GigabitEthernet0/8/0 10.1.0.20/24 + +set int state GigabitEthernet0/9/0 up +set int ip address GigabitEthernet0/9/0 10.5.0.20/24 + +create vxlan tunnel src 10.5.0.20 dst 10.5.0.21 vni 100 +EOF + +# Download and install HC2VPP from source +cd /opt +git clone ${HC2VPP_SOURCE_REPO_URL} -b ${HC2VPP_SOURCE_REPO_BRANCH} hc2vpp +wget -O Hc2vpp-Add-VES-agent-for-vG-MUX.patch ${HC2VPP_PATCH_URL} + +apt-get install -y maven +cat > ~/.m2/settings.xml << EOF +<?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> +EOF + +cd hc2vpp +patch -p1 < ../Hc2vpp-Add-VES-agent-for-vG-MUX.patch +mvn clean install +l_version=$(cat pom.xml | grep "<version>" | head -1) +l_version=$(echo "${l_version%<*}") +l_version=$(echo "${l_version#*>}") +mv vpp-integration/minimal-distribution/target/vpp-integration-distribution-${l_version}-hc/vpp-integration-distribution-${l_version} /opt/honeycomb +sed -i 's/127.0.0.1/0.0.0.0/g' /opt/honeycomb/config/honeycomb.json + +# Create systemctl service for Honeycomb +cat > /etc/systemd/system/honeycomb.service << EOF +[Unit] +Description=Honeycomb Agent for the VPP control plane +Documentation=https://wiki.fd.io/view/Honeycomb +Requires=vpp.service +After=vpp.service + +[Service] +ExecStart=/opt/honeycomb/honeycomb +Restart=always +RestartSec=10 + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable /etc/systemd/system/honeycomb.service + +#Create a systemd service for auto-save +cat > /usr/bin/save_config << EOF +#!/bin/bash + +######################################################################### +# +# Copyright (c) 2017 Intel 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. +# +########################################################################## + +############################### Variables ################################ +VPP_SETUP_GATE=/etc/vpp/setup.gate + +############################### Functions ################################ + +# Write the commands to the startup scripts. +# +# We could set VPP configuration to the startup.conf. +# Write the configuration to the startup scripts so we could +# restore the system after rebooting. +# +write_startup_scripts() +{ + local cmd=${2} + local is_add=${1} + + if [[ ${is_add} == add ]] ;then + while read -r line + do + if [[ ${line} == ${cmd} ]] ;then + return 0 + fi + done < ${VPP_SETUP_GATE} + + echo "${cmd}" >> ${VPP_SETUP_GATE} + else + while read -r line + do + if [[ ${line} == ${cmd} ]] ;then + sed -i "/${line}/d" ${VPP_SETUP_GATE} + return 0 + fi + done < ${VPP_SETUP_GATE} + fi +} + +# Saves the VES agent configuration to the startup script. +# +# Get the current VES agent configuration from the bash command: +# $vppctl show ves agent +# Server Addr Server Port Interval Enabled +# 127.0.0.1 8080 10 True +# Set the VES agent configuration with the bash command: +# $vppctl set ves agent server 127.0.0.1 port 8080 intval 10 +# +save_ves_config() +{ + local server="" + local port="" + local intval="" + + local ves_config=`vppctl show ves agent | head -2 | tail -1` + if [ "${ves_config}" != "" ] ;then + server=`echo ${ves_config} | awk '{ print $1 }'` + port=`echo ${ves_config} | awk '{ print $2 }'` + intval=`echo ${ves_config} | awk '{ print $3 }'` + write_startup_scripts add "set ves agent server ${server} port ${port} intval ${intval}" + fi +} + +# Save the VxLAN Tunnel Configuration to the startup script. +# +# Get the current VxLAN tunnel configuration with bash command: +# $vppctl show vxlan tunnel +# [0] src 10.3.0.2 dst 10.1.0.20 vni 100 sw_if_index 1 encap_fib_index 0 fib_entry_index 7 decap_next l2 +# [1] src 10.5.0.20 dst 10.5.0.21 vni 100 sw_if_index 2 encap_fib_index 0 fib_entry_index 8 decap_next l2 +# Set the VxLAN Tunnel with the bash command: +# $vppctl create vxlan tunnel src 10.3.0.2 dst 10.1.0.20 vni 100 +# vxlan_tunnel0 +save_vxlan_tunnel() +{ + local src="" + local dst="" + local vni="" + + vppctl show vxlan tunnel | while read line + do + if [ "${line}" != "" ] ;then + src=`echo ${line} | awk '{ print $3 }'` + dst=`echo ${line} | awk '{ print $5 }'` + vni=`echo ${line} | awk '{ print $7 }'` + + write_startup_scripts add "create vxlan tunnel src ${src} dst ${dst} vni ${vni}" + fi + done +} + +# Save the VxLAN tunnel L2 xconnect configuration to the startup script. +# +# Get the Current L2 Address configuration with bash command: +# $vppctl show int addr +# local0 (dn): +# vxlan_tunnel0 (up): +# l2 xconnect vxlan_tunnel1 +# vxlan_tunnel1 (up): +# l2 xconnect vxlan_tunnel0 +# Save the VxLAN tunnel L2 xconnect configuration with bash command: +# $vppctl set interface l2 xconnect vxlan_tunnel0 vxlan_tunnel1 +# +save_vxlan_xconnect() +{ + local ingress="" + local egress="" + + vppctl show int addr | while read line + do + if [[ ${line} == vxlan_tunnel* ]] ;then + read next + while [[ ${next} != l2* ]] || [[ ${next} == "" ]] + do + line=`echo ${next}` + read next + done + if [[ ${next} == l2* ]] ;then + ingress=`echo ${line} | awk '{ print $1 }'` + egress=`echo ${next} | awk '{ print $3 }'` + write_startup_scripts add "set interface l2 xconnect ${ingress} ${egress}" + fi + fi + done +} + +################################# MAIN ################################### + +save_ves_config + +save_vxlan_tunnel + +save_vxlan_xconnect + +EOF +chmod a+x /usr/bin/save_config +cat > /etc/systemd/system/autosave.service << EOF +[Unit] +Description=Run Scripts at Start and Stop +Requires=vpp.service +After=vpp.service + +[Service] +Type=oneshot +RemainAfterExit=true +ExecStop=/usr/bin/save_config + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable /etc/systemd/system/autosave.service + # Download DHCP config files cd /opt wget $REPO_URL_BLOB/org.onap.demo/vnfs/vcpe/$INSTALL_SCRIPT_VERSION/v_gmux_init.sh @@ -84,4 +553,4 @@ then reboot fi -./v_gmux_init.sh
\ No newline at end of file +./v_gmux_init.sh diff --git a/vnfs/vCPE/scripts/v_gw_init.sh b/vnfs/vCPE/scripts/v_gw_init.sh index a9bf588e..344374d3 100644 --- a/vnfs/vCPE/scripts/v_gw_init.sh +++ b/vnfs/vCPE/scripts/v_gw_init.sh @@ -1 +1,5 @@ #!/bin/bash + +systemctl start vpp +systemctl start honeycomb + diff --git a/vnfs/vCPE/scripts/v_gw_install.sh b/vnfs/vCPE/scripts/v_gw_install.sh index cafb204d..3a12d7ed 100644 --- a/vnfs/vCPE/scripts/v_gw_install.sh +++ b/vnfs/vCPE/scripts/v_gw_install.sh @@ -4,6 +4,10 @@ REPO_URL_BLOB=$(cat /opt/config/repo_url_blob.txt) REPO_URL_ARTIFACTS=$(cat /opt/config/repo_url_artifacts.txt) DEMO_ARTIFACTS_VERSION=$(cat /opt/config/demo_artifacts_version.txt) INSTALL_SCRIPT_VERSION=$(cat /opt/config/install_script_version.txt) +VPP_SOURCE_REPO_URL=$(cat /opt/config/vpp_source_repo_url.txt) +VPP_SOURCE_REPO_BRANCH=$(cat /opt/config/vpp_source_repo_branch.txt) +HC2VPP_SOURCE_REPO_URL=$(cat /opt/config/hc2vpp_source_repo_url.txt) +HC2VPP_SOURCE_REPO_BRANCH=$(cat /opt/config/hc2vpp_source_repo_branch.txt) CLOUD_ENV=$(cat /opt/config/cloud_env.txt) # Convert Network CIDR to Netmask @@ -48,11 +52,314 @@ then fi # Download required dependencies -add-apt-repository -y ppa:openjdk-r/ppa +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list apt-get update -apt-get install -y wget openjdk-8-jdk apt-transport-https ca-certificates g++ libcurl4-gnutls-dev +apt-get install --allow-unauthenticated -y wget openjdk-8-jdk apt-transport-https ca-certificates g++ libcurl4-gnutls-dev sleep 1 +# Install the tools required for download codes +apt-get install -y expect git + +#Download and build the VPP codes +cd /opt +git clone ${VPP_SOURCE_REPO_URL} -b ${VPP_SOURCE_REPO_BRANCH} vpp + +cd vpp +expect -c " + set timeout 60; + spawn make install-dep; + expect { + \"Do you want to continue?*\" {send \"Y\r\"; interact} + } +" + +cd build-root +./bootstrap.sh +make V=0 PLATFORM=vpp TAG=vpp install-deb + +# Install the VPP package +dpkg -i *.deb +systemctl stop vpp + +# Auto-start configuration for the VPP +cat > /etc/vpp/startup.conf << EOF + +unix { + nodaemon + log /tmp/vpp.log + full-coredump + cli-listen localhost:5002 + startup-config /etc/vpp/setup.gate +} + +api-trace { + on +} + +api-segment { + gid vpp +} + +cpu { + ## In the VPP there is one main thread and optionally the user can create worker(s) + ## The main thread and worker thread(s) can be pinned to CPU core(s) manually or automatically + + ## Manual pinning of thread(s) to CPU core(s) + + ## Set logical CPU core where main thread runs + # main-core 1 + + ## Set logical CPU core(s) where worker threads are running + # corelist-workers 2-3,18-19 + + ## Automatic pinning of thread(s) to CPU core(s) + + ## Sets number of CPU core(s) to be skipped (1 ... N-1) + ## Skipped CPU core(s) are not used for pinning main thread and working thread(s). + ## The main thread is automatically pinned to the first available CPU core and worker(s) + ## are pinned to next free CPU core(s) after core assigned to main thread + # skip-cores 4 + + ## Specify a number of workers to be created + ## Workers are pinned to N consecutive CPU cores while skipping "skip-cores" CPU core(s) + ## and main thread's CPU core + # workers 2 + + ## Set scheduling policy and priority of main and worker threads + + ## Scheduling policy options are: other (SCHED_OTHER), batch (SCHED_BATCH) + ## idle (SCHED_IDLE), fifo (SCHED_FIFO), rr (SCHED_RR) + # scheduler-policy fifo + + ## Scheduling priority is used only for "real-time policies (fifo and rr), + ## and has to be in the range of priorities supported for a particular policy + # scheduler-priority 50 +} + +# dpdk { + ## Change default settings for all intefaces + # dev default { + ## Number of receive queues, enables RSS + ## Default is 1 + # num-rx-queues 3 + + ## Number of transmit queues, Default is equal + ## to number of worker threads or 1 if no workers treads + # num-tx-queues 3 + + ## Number of descriptors in transmit and receive rings + ## increasing or reducing number can impact performance + ## Default is 1024 for both rx and tx + # num-rx-desc 512 + # num-tx-desc 512 + + ## VLAN strip offload mode for interface + ## Default is off + # vlan-strip-offload on + # } + + ## Whitelist specific interface by specifying PCI address + # dev 0000:02:00.0 + + ## Whitelist specific interface by specifying PCI address and in + ## addition specify custom parameters for this interface + # dev 0000:02:00.1 { + # num-rx-queues 2 + # } + + ## Change UIO driver used by VPP, Options are: igb_uio, vfio-pci + ## and uio_pci_generic (default) + # uio-driver vfio-pci + + ## Disable mutli-segment buffers, improves performance but + ## disables Jumbo MTU support + # no-multi-seg + + ## Increase number of buffers allocated, needed only in scenarios with + ## large number of interfaces and worker threads. Value is per CPU socket. + ## Default is 16384 + # num-mbufs 128000 + + ## Change hugepages allocation per-socket, needed only if there is need for + ## larger number of mbufs. Default is 256M on each detected CPU socket + # socket-mem 2048,2048 +# } + +EOF + +cat > /etc/vpp/setup.gate << EOF +set int state GigabitEthernet0/8/0 up +set int ip address GigabitEthernet0/8/0 10.5.0.21/24 + +set int state GigabitEthernet0/9/0 up +set dhcp client intfc GigabitEthernet0/9/0 hostname vg-1 + +tap connect lstack address 192.168.1.1/24 +set int state tap-0 up + +create vxlan tunnel src 10.5.0.21 dst 10.5.0.20 vni 100 + +set interface l2 bridge tap-0 10 0 +set interface l2 bridge vxlan_tunnel0 10 1 +set bridge-domain arp term 10 + +set int ip address vxlan_tunnel0 192.168.1.254/24 +set interface snat in vxlan_tunnel0 out GigabitEthernet0/9/0 +EOF + +# Download and install HC2VPP from source +cd /opt +git clone ${HC2VPP_SOURCE_REPO_URL} -b ${HC2VPP_SOURCE_REPO_BRANCH} hc2vpp + +apt-get install -y maven +cat > ~/.m2/settings.xml << EOF +<?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> +EOF + +cd hc2vpp +mvn clean install +l_version=$(cat pom.xml | grep "<version>" | head -1) +l_version=$(echo "${l_version%<*}") +l_version=$(echo "${l_version#*>}") +mv vpp-integration/minimal-distribution/target/vpp-integration-distribution-${l_version}-hc/vpp-integration-distribution-${l_version} /opt/honeycomb +sed -i 's/127.0.0.1/0.0.0.0/g' /opt/honeycomb/config/honeycomb.json + +# Create systemctl service for Honeycomb +cat > /etc/systemd/system/honeycomb.service << EOF +[Unit] +Description=Honeycomb Agent for the VPP control plane +Documentation=https://wiki.fd.io/view/Honeycomb +Requires=vpp.service +After=vpp.service + +[Service] +ExecStart=/opt/honeycomb/honeycomb +Restart=always +RestartSec=10 + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable /etc/systemd/system/honeycomb.service + +# Install the DHCP server and config +apt-get install -y isc-dhcp-server +cat >> /etc/dhcp/dhcpd.conf << EOF +subnet 192.168.1.0 netmask 255.255.255.0 { + range 192.168.1.2 192.168.1.253; + option subnet-mask 255.255.255.0; + option routers 192.168.1.254; + option broadcast-address 192.168.1.255; + default-lease-time 600; + max-lease-time 7200; +} +EOF + # Download DHCP config files cd /opt wget $REPO_URL_BLOB/org.onap.demo/vnfs/vcpe/$INSTALL_SCRIPT_VERSION/v_gw_init.sh @@ -74,4 +381,4 @@ then reboot fi -./v_gw_init.sh
\ No newline at end of file +./v_gw_init.sh diff --git a/vnfs/vCPE/scripts/v_web_install.sh b/vnfs/vCPE/scripts/v_web_install.sh index 94d3ebd7..e207dd09 100644 --- a/vnfs/vCPE/scripts/v_web_install.sh +++ b/vnfs/vCPE/scripts/v_web_install.sh @@ -48,9 +48,10 @@ then fi # Download required dependencies -add-apt-repository -y ppa:openjdk-r/ppa +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list apt-get update -apt-get install -y wget openjdk-8-jdk apt-transport-https ca-certificates g++ libcurl4-gnutls-dev +apt-get install --allow-unauthenticated -y wget openjdk-8-jdk apt-transport-https ca-certificates g++ libcurl4-gnutls-dev sleep 1 # Download DHCP config files @@ -62,6 +63,19 @@ chmod +x v_web.sh mv v_web.sh /etc/init.d update-rc.d v_web.sh defaults +# Install Apache2 web server +apt-get update +apt install -y apache2 +mv /var/www/html/index.html /var/www/html/index.html.example +cat > /var/www/html/index.html << EOF +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<body> +<center><h1>Welcome to the vCPE Use Case Web Server!</h1><center> +</body> +</html> +EOF + # Rename network interface in openstack Ubuntu 16.04 images. Then, reboot the VM to pick up changes if [[ $CLOUD_ENV != "rackspace" ]] then diff --git a/vnfs/vCPE/vpp-option-82-for-vbrg/src/patches/VPP-Add-Option82-Nat-Filter-For-vBRG.patch b/vnfs/vCPE/vpp-option-82-for-vbrg/src/patches/VPP-Add-Option82-Nat-Filter-For-vBRG.patch new file mode 100755 index 00000000..73b19150 --- /dev/null +++ b/vnfs/vCPE/vpp-option-82-for-vbrg/src/patches/VPP-Add-Option82-Nat-Filter-For-vBRG.patch @@ -0,0 +1,99 @@ +diff --git a/src/plugins/snat/out2in.c b/src/plugins/snat/out2in.c +index 5c12b47..f7c7caf 100644 +--- a/src/plugins/snat/out2in.c ++++ b/src/plugins/snat/out2in.c +@@ -1,3 +1,4 @@ ++ + /* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); +@@ -658,6 +659,26 @@ snat_out2in_node_fn (vlib_main_t * vm, + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + ++ //FOR BRG ++ ip4_address_t * sdnc_addr = malloc(4); ++ char line_input[128]; ++ char * path = "/opt/config/ip.txt"; ++ FILE * f = fopen(path, "r"); ++ if (f == NULL) ++ printf("cannot open such file\n"); ++ ++ while (fgets(line_input, 128, f) != NULL){ ++ if (!strcmp(strtok(line_input, " "),"sdnc_ip:")){ ++ char * ip = strtok(NULL, " "); ++ char * num = strtok(ip, "."); ++ sdnc_addr->data[0] = atoi(num); ++ for (int i = 1; i < 4; i ++){ ++ num = strtok(NULL, "."); ++ sdnc_addr->data[i] = atoi(num); ++ } ++ } ++ } ++ + while (n_left_from > 0) + { + u32 n_left_to_next; +@@ -733,6 +754,13 @@ snat_out2in_node_fn (vlib_main_t * vm, + + proto0 = ip_proto_to_snat_proto (ip0->protocol); + ++ //for BRG ++ if (PREDICT_TRUE (ip0->src_address.data_u32 != sdnc_addr->data_u32)) ++ { ++ next0 = SNAT_OUT2IN_NEXT_LOOKUP; ++ goto trace0; ++ } ++ + if (PREDICT_FALSE (proto0 == ~0)) + { + snat_out2in_unknown_proto(sm, b0, ip0, rx_fib_index0); +@@ -871,6 +899,13 @@ snat_out2in_node_fn (vlib_main_t * vm, + + proto1 = ip_proto_to_snat_proto (ip1->protocol); + ++ //for BRG ++ if (PREDICT_TRUE (ip1->src_address.data_u32 != sdnc_addr->data_u32)) ++ { ++ next1 = SNAT_OUT2IN_NEXT_LOOKUP; ++ goto trace1; ++ } ++ + if (PREDICT_FALSE (proto1 == ~0)) + { + snat_out2in_unknown_proto(sm, b1, ip1, rx_fib_index1); +@@ -1033,6 +1068,13 @@ snat_out2in_node_fn (vlib_main_t * vm, + + proto0 = ip_proto_to_snat_proto (ip0->protocol); + ++ //for BRG ++ if (PREDICT_TRUE (ip0->src_address.data_u32 != sdnc_addr->data_u32)) ++ { ++ next0 = SNAT_OUT2IN_NEXT_LOOKUP; ++ goto trace00; ++ } ++ + if (PREDICT_FALSE (proto0 == ~0)) + { + snat_out2in_unknown_proto(sm, b0, ip0, rx_fib_index0); +diff --git a/src/vnet/dhcp/client.c b/src/vnet/dhcp/client.c +index 014f17a..296e1a7 100644 +--- a/src/vnet/dhcp/client.c ++++ b/src/vnet/dhcp/client.c +@@ -427,6 +427,16 @@ send_dhcp_pkt (dhcp_client_main_t * dcm, dhcp_client_t * c, + clib_memcpy (o->data, c->option_55_data, vec_len(c->option_55_data)); + o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); + ++ /*send option 82*/ ++ u8 sub2_len = vec_len(hw->hw_address); ++ o->option = 82; ++ o->length = sub2_len + 2; ++ u8 sub_option = 2; ++ clib_memcpy (o->data, &sub_option, 1); ++ clib_memcpy (o->data + 1,&sub2_len, 1); ++ clib_memcpy (o->data + 2, hw->hw_address, vec_len(hw->hw_address)); ++ o = (dhcp_option_t *) (((uword) o) + (o->length +2)); ++ + /* End of list */ + o->option = 0xff; + o->length = 0; diff --git a/vnfs/vCPE/vpp-radius-client-for-vbng/src/patches/Vpp-Integrate-FreeRADIUS-Client-for-vBNG.patch b/vnfs/vCPE/vpp-radius-client-for-vbng/src/patches/Vpp-Integrate-FreeRADIUS-Client-for-vBNG.patch new file mode 100644 index 00000000..4a9218b2 --- /dev/null +++ b/vnfs/vCPE/vpp-radius-client-for-vbng/src/patches/Vpp-Integrate-FreeRADIUS-Client-for-vBNG.patch @@ -0,0 +1,13239 @@ +From 0a97fd92483349178a6750ec4a232fea4f9864df Mon Sep 17 00:00:00 2001 +From: Johnson Li <johnson.li@intel.com> +Date: Fri, 8 Sep 2017 17:09:58 +0800 +Subject: [PATCH] Integrate FreeRADIUS Client for vBNG + +Signed-off-by: Johnson Li <johnson.li@intel.com> + +diff --git a/src/configure.ac b/src/configure.ac +index fb2ead6d..ef5537da 100644 +--- a/src/configure.ac ++++ b/src/configure.ac +@@ -152,6 +152,7 @@ PLUGIN_ENABLED(ioam) + PLUGIN_ENABLED(ixge) + PLUGIN_ENABLED(lb) + PLUGIN_ENABLED(memif) ++PLUGIN_ENABLED(vbng) + PLUGIN_ENABLED(sixrd) + PLUGIN_ENABLED(snat) + +diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am +index 623892e7..d6f607fc 100644 +--- a/src/plugins/Makefile.am ++++ b/src/plugins/Makefile.am +@@ -61,6 +61,10 @@ if ENABLE_MEMIF_PLUGIN + include memif.am + endif + ++if ENABLE_VBNG_PLUGIN ++include vbng.am ++endif ++ + if ENABLE_SIXRD_PLUGIN + include sixrd.am + endif +diff --git a/src/plugins/vbng.am b/src/plugins/vbng.am +new file mode 100644 +index 00000000..99398f49 +--- /dev/null ++++ b/src/plugins/vbng.am +@@ -0,0 +1,32 @@ ++# Copyright (c) 2017 Intel 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. ++ ++vppplugins_LTLIBRARIES += vbng_plugin.la ++ ++vbng_plugin_la_LDFLAGS = $(AM_LDFLAGS) -lfreeradiusclient ++ ++vbng_plugin_la_SOURCES = vbng/vbng_dhcp4_node.c \ ++ vbng/vbng_dhcp4.c \ ++ vbng/vbng_api.c \ ++ vbng/vbng_aaa.c ++ ++BUILT_SOURCES += vbng/vbng.api.h \ ++ vbng/vbng.api.json ++ ++API_FILES += vbng/vbng.api ++ ++nobase_apiinclude_HEADERS += vbng/vbng_all_api_h.h \ ++ vbng/vbng_msg_enum.h \ ++ vbng/vbng.api.h ++ ++# vi:syntax=automake +diff --git a/src/plugins/vbng/etc/dictionary b/src/plugins/vbng/etc/dictionary +new file mode 100644 +index 00000000..45f4189c +--- /dev/null ++++ b/src/plugins/vbng/etc/dictionary +@@ -0,0 +1,274 @@ ++# ++# Updated 97/06/13 to livingston-radius-2.01 miquels@cistron.nl ++# ++# This file contains dictionary translations for parsing ++# requests and generating responses. All transactions are ++# composed of Attribute/Value Pairs. The value of each attribute ++# is specified as one of 4 data types. Valid data types are: ++# ++# string - 0-253 octets ++# ipaddr - 4 octets in network byte order ++# integer - 32 bit value in big endian order (high byte first) ++# date - 32 bit value in big endian order - seconds since ++# 00:00:00 GMT, Jan. 1, 1970 ++# ++# Enumerated values are stored in the user file with dictionary ++# VALUE translations for easy administration. ++# ++# Example: ++# ++# ATTRIBUTE VALUE ++# --------------- ----- ++# Framed-Protocol = PPP ++# 7 = 1 (integer encoding) ++# ++ ++# ++# Following are the proper new names. Use these. ++# ++ATTRIBUTE User-Name 1 string ++ATTRIBUTE Password 2 string ++ATTRIBUTE CHAP-Password 3 string ++ATTRIBUTE NAS-IP-Address 4 ipaddr ++ATTRIBUTE NAS-Port-Id 5 integer ++ATTRIBUTE Service-Type 6 integer ++ATTRIBUTE Framed-Protocol 7 integer ++ATTRIBUTE Framed-IP-Address 8 ipaddr ++ATTRIBUTE Framed-IP-Netmask 9 ipaddr ++ATTRIBUTE Framed-Routing 10 integer ++ATTRIBUTE Filter-Id 11 string ++ATTRIBUTE Framed-MTU 12 integer ++ATTRIBUTE Framed-Compression 13 integer ++ATTRIBUTE Login-IP-Host 14 ipaddr ++ATTRIBUTE Login-Service 15 integer ++ATTRIBUTE Login-TCP-Port 16 integer ++ATTRIBUTE Reply-Message 18 string ++ATTRIBUTE Callback-Number 19 string ++ATTRIBUTE Callback-Id 20 string ++ATTRIBUTE Framed-Route 22 string ++ATTRIBUTE Framed-IPX-Network 23 ipaddr ++ATTRIBUTE State 24 string ++ATTRIBUTE Class 25 string ++ATTRIBUTE Vendor-Specific 26 string ++ATTRIBUTE Session-Timeout 27 integer ++ATTRIBUTE Idle-Timeout 28 integer ++ATTRIBUTE Termination-Action 29 integer ++ATTRIBUTE Called-Station-Id 30 string ++ATTRIBUTE Calling-Station-Id 31 string ++ATTRIBUTE NAS-Identifier 32 string ++ATTRIBUTE Proxy-State 33 string ++ATTRIBUTE Login-LAT-Service 34 string ++ATTRIBUTE Login-LAT-Node 35 string ++ATTRIBUTE Login-LAT-Group 36 string ++ATTRIBUTE Framed-AppleTalk-Link 37 integer ++ATTRIBUTE Framed-AppleTalk-Network 38 integer ++ATTRIBUTE Framed-AppleTalk-Zone 39 string ++ATTRIBUTE Acct-Status-Type 40 integer ++ATTRIBUTE Acct-Delay-Time 41 integer ++ATTRIBUTE Acct-Input-Octets 42 integer ++ATTRIBUTE Acct-Output-Octets 43 integer ++ATTRIBUTE Acct-Session-Id 44 string ++ATTRIBUTE Acct-Authentic 45 integer ++ATTRIBUTE Acct-Session-Time 46 integer ++ATTRIBUTE Acct-Input-Packets 47 integer ++ATTRIBUTE Acct-Output-Packets 48 integer ++ATTRIBUTE Acct-Terminate-Cause 49 integer ++ATTRIBUTE Acct-Multi-Session-Id 50 string ++ATTRIBUTE Acct-Link-Count 51 integer ++ATTRIBUTE Acct-Input-Gigawords 52 integer ++ATTRIBUTE Acct-Output-Gigawords 53 integer ++ATTRIBUTE Event-Timestamp 55 integer ++ATTRIBUTE CHAP-Challenge 60 string ++ATTRIBUTE NAS-Port-Type 61 integer ++ATTRIBUTE Port-Limit 62 integer ++ATTRIBUTE Login-LAT-Port 63 integer ++ATTRIBUTE Connect-Info 77 string ++ ++# ++# RFC3162 IPv6 attributes ++# ++ATTRIBUTE NAS-IPv6-Address 95 string ++ATTRIBUTE Framed-Interface-Id 96 string ++ATTRIBUTE Framed-IPv6-Prefix 97 ipv6prefix ++ATTRIBUTE Login-IPv6-Host 98 string ++ATTRIBUTE Framed-IPv6-Route 99 string ++ATTRIBUTE Framed-IPv6-Pool 100 string ++ ++# ++# RFC6911 IPv6 attributes ++# ++ATTRIBUTE Framed-IPv6-Address 168 ipv6addr ++ATTRIBUTE DNS-Server-IPv6-Address 169 ipv6addr ++ATTRIBUTE Route-IPv6-Information 170 ipv6prefix ++ ++# ++# Experimental Non Protocol Attributes used by Cistron-Radiusd ++# ++ATTRIBUTE Huntgroup-Name 221 string ++ATTRIBUTE User-Category 1029 string ++ATTRIBUTE Group-Name 1030 string ++ATTRIBUTE Simultaneous-Use 1034 integer ++ATTRIBUTE Strip-User-Name 1035 integer ++ATTRIBUTE Fall-Through 1036 integer ++ATTRIBUTE Add-Port-To-IP-Address 1037 integer ++ATTRIBUTE Exec-Program 1038 string ++ATTRIBUTE Exec-Program-Wait 1039 string ++ATTRIBUTE Hint 1040 string ++ ++# ++# Non-Protocol Attributes ++# These attributes are used internally by the server ++# ++ATTRIBUTE Expiration 21 date ++ATTRIBUTE Auth-Type 1000 integer ++ATTRIBUTE Menu 1001 string ++ATTRIBUTE Termination-Menu 1002 string ++ATTRIBUTE Prefix 1003 string ++ATTRIBUTE Suffix 1004 string ++ATTRIBUTE Group 1005 string ++ATTRIBUTE Crypt-Password 1006 string ++ATTRIBUTE Connect-Rate 1007 integer ++ ++# ++# Integer Translations ++# ++ ++# User Types ++ ++VALUE Service-Type Login-User 1 ++VALUE Service-Type Framed-User 2 ++VALUE Service-Type Callback-Login-User 3 ++VALUE Service-Type Callback-Framed-User 4 ++VALUE Service-Type Outbound-User 5 ++VALUE Service-Type Administrative-User 6 ++VALUE Service-Type NAS-Prompt-User 7 ++VALUE Service-Type Authenticate-Only 8 ++VALUE Service-Type Callback-NAS-Prompt 9 ++VALUE Service-Type Call-Check 10 ++VALUE Service-Type Callback-Administrative 11 ++ ++# Framed Protocols ++ ++VALUE Framed-Protocol PPP 1 ++VALUE Framed-Protocol SLIP 2 ++VALUE Framed-Protocol ARAP 3 ++VALUE Framed-Protocol GANDALF-SLMLP 4 ++VALUE Framed-Protocol XYLOGICS-IPX-SLIP 5 ++VALUE Framed-Protocol X75 6 ++ ++# Framed Routing Values ++ ++VALUE Framed-Routing None 0 ++VALUE Framed-Routing Broadcast 1 ++VALUE Framed-Routing Listen 2 ++VALUE Framed-Routing Broadcast-Listen 3 ++ ++# Framed Compression Types ++ ++VALUE Framed-Compression None 0 ++VALUE Framed-Compression Van-Jacobson-TCP-IP 1 ++VALUE Framed-Compression IPX-Header 2 ++VALUE Framed-Compression Stac-LZS 3 ++ ++# Login Services ++ ++VALUE Login-Service Telnet 0 ++VALUE Login-Service Rlogin 1 ++VALUE Login-Service TCP-Clear 2 ++VALUE Login-Service PortMaster 3 ++VALUE Login-Service LAT 4 ++VALUE Login-Service X.25-PAD 5 ++VALUE Login-Service X.25-T3POS 6 ++VALUE Login-Service TCP-Clear-Quiet 8 ++ ++# Status Types ++ ++VALUE Acct-Status-Type Start 1 ++VALUE Acct-Status-Type Stop 2 ++VALUE Acct-Status-Type Alive 3 ++VALUE Acct-Status-Type Accounting-On 7 ++VALUE Acct-Status-Type Accounting-Off 8 ++ ++# Authentication Types ++ ++VALUE Acct-Authentic RADIUS 1 ++VALUE Acct-Authentic Local 2 ++VALUE Acct-Authentic Remote 3 ++ ++# Termination Options ++ ++VALUE Termination-Action Default 0 ++VALUE Termination-Action RADIUS-Request 1 ++ ++# NAS Port Types, available in 3.3.1 and later ++ ++VALUE NAS-Port-Type Async 0 ++VALUE NAS-Port-Type Sync 1 ++VALUE NAS-Port-Type ISDN 2 ++VALUE NAS-Port-Type ISDN-V120 3 ++VALUE NAS-Port-Type ISDN-V110 4 ++VALUE NAS-Port-Type Virtual 5 ++VALUE NAS-Port-Type PIAFS 6 ++VALUE NAS-Port-Type HDLC-Clear-Channel 7 ++VALUE NAS-Port-Type X.25 8 ++VALUE NAS-Port-Type X.75 9 ++VALUE NAS-Port-Type G.3-Fax 10 ++VALUE NAS-Port-Type SDSL 11 ++VALUE NAS-Port-Type ADSL-CAP 12 ++VALUE NAS-Port-Type ADSL-DMT 13 ++VALUE NAS-Port-Type IDSL 14 ++VALUE NAS-Port-Type Ethernet 15 ++ ++# Acct Terminate Causes, available in 3.3.2 and later ++ ++VALUE Acct-Terminate-Cause User-Request 1 ++VALUE Acct-Terminate-Cause Lost-Carrier 2 ++VALUE Acct-Terminate-Cause Lost-Service 3 ++VALUE Acct-Terminate-Cause Idle-Timeout 4 ++VALUE Acct-Terminate-Cause Session-Timeout 5 ++VALUE Acct-Terminate-Cause Admin-Reset 6 ++VALUE Acct-Terminate-Cause Admin-Reboot 7 ++VALUE Acct-Terminate-Cause Port-Error 8 ++VALUE Acct-Terminate-Cause NAS-Error 9 ++VALUE Acct-Terminate-Cause NAS-Request 10 ++VALUE Acct-Terminate-Cause NAS-Reboot 11 ++VALUE Acct-Terminate-Cause Port-Unneeded 12 ++VALUE Acct-Terminate-Cause Port-Preempted 13 ++VALUE Acct-Terminate-Cause Port-Suspended 14 ++VALUE Acct-Terminate-Cause Service-Unavailable 15 ++VALUE Acct-Terminate-Cause Callback 16 ++VALUE Acct-Terminate-Cause User-Error 17 ++VALUE Acct-Terminate-Cause Host-Request 18 ++ ++# ++# Non-Protocol Integer Translations ++# ++ ++VALUE Auth-Type Local 0 ++VALUE Auth-Type System 1 ++VALUE Auth-Type SecurID 2 ++VALUE Auth-Type Crypt-Local 3 ++VALUE Auth-Type Reject 4 ++ ++# ++# Cistron extensions ++# ++VALUE Auth-Type Pam 253 ++VALUE Auth-Type Accept 254 ++ ++# ++# Experimental Non-Protocol Integer Translations for Cistron-Radiusd ++# ++VALUE Fall-Through No 0 ++VALUE Fall-Through Yes 1 ++VALUE Add-Port-To-IP-Address No 0 ++VALUE Add-Port-To-IP-Address Yes 1 ++ ++# ++# Configuration Values ++# uncomment these two lines to turn account expiration on ++# ++ ++#VALUE Server-Config Password-Expiration 30 ++#VALUE Server-Config Password-Warning 5 ++ +diff --git a/src/plugins/vbng/etc/dictionary.ascend b/src/plugins/vbng/etc/dictionary.ascend +new file mode 100644 +index 00000000..a02c207d +--- /dev/null ++++ b/src/plugins/vbng/etc/dictionary.ascend +@@ -0,0 +1,297 @@ ++# ++# Ascend dictionary. ++# ++# Enable by putting the line "$INCLUDE dictionary.ascend" into ++# the main dictionary file. ++# ++# Version: 1.00 21-Jul-1997 Jens Glaser <jens@regio.net> ++# ++ ++ ++# ++# Ascend specific extensions ++# Used by ASCEND MAX/Pipeline products ++# ++ATTRIBUTE Ascend-FCP-Parameter 119 string ++ATTRIBUTE Ascend-Modem-PortNo 120 integer ++ATTRIBUTE Ascend-Modem-SlotNo 121 integer ++ATTRIBUTE Ascend-Modem-ShelfNo 122 integer ++ATTRIBUTE Ascend-Call-Attempt-Limit 123 integer ++ATTRIBUTE Ascend-Call-Block-Duration 124 integer ++ATTRIBUTE Ascend-Maximum-Call-Duration 125 integer ++ATTRIBUTE Ascend-Temporary-Rtes 126 integer ++ATTRIBUTE Tunneling-Protocol 127 integer ++ATTRIBUTE Ascend-Shared-Profile-Enable 128 integer ++ATTRIBUTE Ascend-Primary-Home-Agent 129 string ++ATTRIBUTE Ascend-Secondary-Home-Agent 130 string ++ATTRIBUTE Ascend-Dialout-Allowed 131 integer ++ATTRIBUTE Ascend-Client-Gateway 132 ipaddr ++ATTRIBUTE Ascend-BACP-Enable 133 integer ++ATTRIBUTE Ascend-DHCP-Maximum-Leases 134 integer ++ATTRIBUTE Ascend-Client-Primary-DNS 135 ipaddr ++ATTRIBUTE Ascend-Client-Secondary-DNS 136 ipaddr ++ATTRIBUTE Ascend-Client-Assign-DNS 137 integer ++ATTRIBUTE Ascend-User-Acct-Type 138 integer ++ATTRIBUTE Ascend-User-Acct-Host 139 ipaddr ++ATTRIBUTE Ascend-User-Acct-Port 140 integer ++ATTRIBUTE Ascend-User-Acct-Key 141 string ++ATTRIBUTE Ascend-User-Acct-Base 142 integer ++ATTRIBUTE Ascend-User-Acct-Time 143 integer ++ATTRIBUTE Ascend-Assign-IP-Client 144 ipaddr ++ATTRIBUTE Ascend-Assign-IP-Server 145 ipaddr ++ATTRIBUTE Ascend-Assign-IP-Global-Pool 146 string ++ATTRIBUTE Ascend-DHCP-Reply 147 integer ++ATTRIBUTE Ascend-DHCP-Pool-Number 148 integer ++ATTRIBUTE Ascend-Expect-Callback 149 integer ++ATTRIBUTE Ascend-Event-Type 150 integer ++ATTRIBUTE Ascend-Session-Svr-Key 151 string ++ATTRIBUTE Ascend-Multicast-Rate-Limit 152 integer ++ATTRIBUTE Ascend-IF-Netmask 153 ipaddr ++ATTRIBUTE Ascend-Remote-Addr 154 ipaddr ++ATTRIBUTE Ascend-Multicast-Client 155 integer ++ATTRIBUTE Ascend-FR-Circuit-Name 156 string ++ATTRIBUTE Ascend-FR-LinkUp 157 integer ++ATTRIBUTE Ascend-FR-Nailed-Grp 158 integer ++ATTRIBUTE Ascend-FR-Type 159 integer ++ATTRIBUTE Ascend-FR-Link-Mgt 160 integer ++ATTRIBUTE Ascend-FR-N391 161 integer ++ATTRIBUTE Ascend-FR-DCE-N392 162 integer ++ATTRIBUTE Ascend-FR-DTE-N392 163 integer ++ATTRIBUTE Ascend-FR-DCE-N393 164 integer ++ATTRIBUTE Ascend-FR-DTE-N393 165 integer ++ATTRIBUTE Ascend-FR-T391 166 integer ++ATTRIBUTE Ascend-FR-T392 167 integer ++ATTRIBUTE Ascend-Bridge-Address 168 string ++ATTRIBUTE Ascend-TS-Idle-Limit 169 integer ++ATTRIBUTE Ascend-TS-Idle-Mode 170 integer ++ATTRIBUTE Ascend-DBA-Monitor 171 integer ++ATTRIBUTE Ascend-Base-Channel-Count 172 integer ++ATTRIBUTE Ascend-Minimum-Channels 173 integer ++ATTRIBUTE Ascend-IPX-Route 174 string ++ATTRIBUTE Ascend-FT1-Caller 175 integer ++ATTRIBUTE Ascend-Backup 176 string ++ATTRIBUTE Ascend-Call-Type 177 integer ++ATTRIBUTE Ascend-Group 178 string ++ATTRIBUTE Ascend-FR-DLCI 179 integer ++ATTRIBUTE Ascend-FR-Profile-Name 180 string ++ATTRIBUTE Ascend-Ara-PW 181 string ++ATTRIBUTE Ascend-IPX-Node-Addr 182 string ++ATTRIBUTE Ascend-Home-Agent-IP-Addr 183 ipaddr ++ATTRIBUTE Ascend-Home-Agent-Password 184 string ++ATTRIBUTE Ascend-Home-Network-Name 185 string ++ATTRIBUTE Ascend-Home-Agent-UDP-Port 186 integer ++ATTRIBUTE Ascend-Multilink-ID 187 integer ++ATTRIBUTE Ascend-Num-In-Multilink 188 integer ++ATTRIBUTE Ascend-First-Dest 189 ipaddr ++ATTRIBUTE Ascend-Pre-Input-Octets 190 integer ++ATTRIBUTE Ascend-Pre-Output-Octets 191 integer ++ATTRIBUTE Ascend-Pre-Input-Packets 192 integer ++ATTRIBUTE Ascend-Pre-Output-Packets 193 integer ++ATTRIBUTE Ascend-Maximum-Time 194 integer ++ATTRIBUTE Ascend-Disconnect-Cause 195 integer ++ATTRIBUTE Ascend-Connect-Progress 196 integer ++ATTRIBUTE Ascend-Data-Rate 197 integer ++ATTRIBUTE Ascend-PreSession-Time 198 integer ++ATTRIBUTE Ascend-Token-Idle 199 integer ++ATTRIBUTE Ascend-Token-Immediate 200 integer ++ATTRIBUTE Ascend-Require-Auth 201 integer ++ATTRIBUTE Ascend-Number-Sessions 202 string ++ATTRIBUTE Ascend-Authen-Alias 203 string ++ATTRIBUTE Ascend-Token-Expiry 204 integer ++ATTRIBUTE Ascend-Menu-Selector 205 string ++ATTRIBUTE Ascend-Menu-Item 206 string ++ATTRIBUTE Ascend-PW-Warntime 207 integer ++ATTRIBUTE Ascend-PW-Lifetime 208 integer ++ATTRIBUTE Ascend-IP-Direct 209 ipaddr ++ATTRIBUTE Ascend-PPP-VJ-Slot-Comp 210 integer ++ATTRIBUTE Ascend-PPP-VJ-1172 211 integer ++ATTRIBUTE Ascend-PPP-Async-Map 212 integer ++ATTRIBUTE Ascend-Third-Prompt 213 string ++ATTRIBUTE Ascend-Send-Secret 214 string ++ATTRIBUTE Ascend-Receive-Secret 215 string ++ATTRIBUTE Ascend-IPX-Peer-Mode 216 integer ++ATTRIBUTE Ascend-IP-Pool-Definition 217 string ++ATTRIBUTE Ascend-Assign-IP-Pool 218 integer ++ATTRIBUTE Ascend-FR-Direct 219 integer ++ATTRIBUTE Ascend-FR-Direct-Profile 220 string ++ATTRIBUTE Ascend-FR-Direct-DLCI 221 integer ++ATTRIBUTE Ascend-Handle-IPX 222 integer ++ATTRIBUTE Ascend-Netware-timeout 223 integer ++ATTRIBUTE Ascend-IPX-Alias 224 integer ++ATTRIBUTE Ascend-Metric 225 integer ++ATTRIBUTE Ascend-PRI-Number-Type 226 integer ++ATTRIBUTE Ascend-Dial-Number 227 string ++ATTRIBUTE Ascend-Route-IP 228 integer ++ATTRIBUTE Ascend-Route-IPX 229 integer ++ATTRIBUTE Ascend-Bridge 230 integer ++ATTRIBUTE Ascend-Send-Auth 231 integer ++ATTRIBUTE Ascend-Send-Passwd 232 string ++ATTRIBUTE Ascend-Link-Compression 233 integer ++ATTRIBUTE Ascend-Target-Util 234 integer ++ATTRIBUTE Ascend-Maximum-Channels 235 integer ++ATTRIBUTE Ascend-Inc-Channel-Count 236 integer ++ATTRIBUTE Ascend-Dec-Channel-Count 237 integer ++ATTRIBUTE Ascend-Seconds-Of-History 238 integer ++ATTRIBUTE Ascend-History-Weigh-Type 239 integer ++ATTRIBUTE Ascend-Add-Seconds 240 integer ++ATTRIBUTE Ascend-Remove-Seconds 241 integer ++ATTRIBUTE Ascend-Idle-Limit 244 integer ++ATTRIBUTE Ascend-Preempt-Limit 245 integer ++ATTRIBUTE Ascend-Callback 246 integer ++ATTRIBUTE Ascend-Data-Svc 247 integer ++ATTRIBUTE Ascend-Force-56 248 integer ++ATTRIBUTE Ascend-Billing-Number 249 string ++ATTRIBUTE Ascend-Call-By-Call 250 integer ++ATTRIBUTE Ascend-Transit-Number 251 string ++ATTRIBUTE Ascend-Host-Info 252 string ++ATTRIBUTE Ascend-PPP-Address 253 ipaddr ++ATTRIBUTE Ascend-MPP-Idle-Percent 254 integer ++ATTRIBUTE Ascend-Xmit-Rate 255 integer ++ ++ ++ ++# Ascend protocols ++VALUE Service-Type Dialout-Framed-User 5 ++VALUE Framed-Protocol ARA 255 ++VALUE Framed-Protocol MPP 256 ++VALUE Framed-Protocol EURAW 257 ++VALUE Framed-Protocol EUUI 258 ++VALUE Framed-Protocol X25 259 ++VALUE Framed-Protocol COMB 260 ++VALUE Framed-Protocol FR 261 ++VALUE Framed-Protocol MP 262 ++VALUE Framed-Protocol FR-CIR 263 ++ ++ ++# ++# Ascend specific extensions ++# Used by ASCEND MAX/Pipeline products (see above) ++# ++ ++VALUE Ascend-FR-Direct FR-Direct-No 0 ++VALUE Ascend-FR-Direct FR-Direct-Yes 1 ++VALUE Ascend-Handle-IPX Handle-IPX-None 0 ++VALUE Ascend-Handle-IPX Handle-IPX-Client 1 ++VALUE Ascend-Handle-IPX Handle-IPX-Server 2 ++VALUE Ascend-IPX-Peer-Mode IPX-Peer-Router 0 ++VALUE Ascend-IPX-Peer-Mode IPX-Peer-Dialin 1 ++VALUE Ascend-Call-Type Nailed 1 ++VALUE Ascend-Call-Type Nailed/Mpp 2 ++VALUE Ascend-Call-Type Perm/Switched 3 ++VALUE Ascend-FT1-Caller FT1-No 0 ++VALUE Ascend-FT1-Caller FT1-Yes 1 ++VALUE Ascend-PRI-Number-Type Unknown-Number 0 ++VALUE Ascend-PRI-Number-Type Intl-Number 1 ++VALUE Ascend-PRI-Number-Type National-Number 2 ++VALUE Ascend-PRI-Number-Type Local-Number 4 ++VALUE Ascend-PRI-Number-Type Abbrev-Number 5 ++VALUE Ascend-Route-IPX Route-IPX-No 0 ++VALUE Ascend-Route-IPX Route-IPX-Yes 1 ++VALUE Ascend-Bridge Bridge-No 0 ++VALUE Ascend-Bridge Bridge-Yes 1 ++VALUE Ascend-TS-Idle-Mode TS-Idle-None 0 ++VALUE Ascend-TS-Idle-Mode TS-Idle-Input 1 ++VALUE Ascend-TS-Idle-Mode TS-Idle-Input-Output 2 ++VALUE Ascend-Send-Auth Send-Auth-None 0 ++VALUE Ascend-Send-Auth Send-Auth-PAP 1 ++VALUE Ascend-Send-Auth Send-Auth-CHAP 2 ++VALUE Ascend-Send-Auth Send-Auth-MS-CHAP 3 ++VALUE Ascend-Link-Compression Link-Comp-None 0 ++VALUE Ascend-Link-Compression Link-Comp-Stac 1 ++VALUE Ascend-Link-Compression Link-Comp-Stac-Draft-9 2 ++VALUE Ascend-Link-Compression Link-Comp-MS-Stac 3 ++VALUE Ascend-History-Weigh-Type History-Constant 0 ++VALUE Ascend-History-Weigh-Type History-Linear 1 ++VALUE Ascend-History-Weigh-Type History-Quadratic 2 ++VALUE Ascend-Callback Callback-No 0 ++VALUE Ascend-Callback Callback-Yes 1 ++VALUE Ascend-Expect-Callback Expect-Callback-No 0 ++VALUE Ascend-Expect-Callback Expect-Callback-Yes 1 ++VALUE Ascend-Data-Svc Switched-Voice-Bearer 0 ++VALUE Ascend-Data-Svc Switched-56KR 1 ++VALUE Ascend-Data-Svc Switched-64K 2 ++VALUE Ascend-Data-Svc Switched-64KR 3 ++VALUE Ascend-Data-Svc Switched-56K 4 ++VALUE Ascend-Data-Svc Switched-384KR 5 ++VALUE Ascend-Data-Svc Switched-384K 6 ++VALUE Ascend-Data-Svc Switched-1536K 7 ++VALUE Ascend-Data-Svc Switched-1536KR 8 ++VALUE Ascend-Data-Svc Switched-128K 9 ++VALUE Ascend-Data-Svc Switched-192K 10 ++VALUE Ascend-Data-Svc Switched-256K 11 ++VALUE Ascend-Data-Svc Switched-320K 12 ++VALUE Ascend-Data-Svc Switched-384K-MR 13 ++VALUE Ascend-Data-Svc Switched-448K 14 ++VALUE Ascend-Data-Svc Switched-512K 15 ++VALUE Ascend-Data-Svc Switched-576K 16 ++VALUE Ascend-Data-Svc Switched-640K 17 ++VALUE Ascend-Data-Svc Switched-704K 18 ++VALUE Ascend-Data-Svc Switched-768K 19 ++VALUE Ascend-Data-Svc Switched-832K 20 ++VALUE Ascend-Data-Svc Switched-896K 21 ++VALUE Ascend-Data-Svc Switched-960K 22 ++VALUE Ascend-Data-Svc Switched-1024K 23 ++VALUE Ascend-Data-Svc Switched-1088K 24 ++VALUE Ascend-Data-Svc Switched-1152K 25 ++VALUE Ascend-Data-Svc Switched-1216K 26 ++VALUE Ascend-Data-Svc Switched-1280K 27 ++VALUE Ascend-Data-Svc Switched-1344K 28 ++VALUE Ascend-Data-Svc Switched-1408K 29 ++VALUE Ascend-Data-Svc Switched-1472K 30 ++VALUE Ascend-Data-Svc Switched-1600K 31 ++VALUE Ascend-Data-Svc Switched-1664K 32 ++VALUE Ascend-Data-Svc Switched-1728K 33 ++VALUE Ascend-Data-Svc Switched-1792K 34 ++VALUE Ascend-Data-Svc Switched-1856K 35 ++VALUE Ascend-Data-Svc Switched-1920K 36 ++VALUE Ascend-Data-Svc Switched-inherited 37 ++VALUE Ascend-Data-Svc Switched-restricted-bearer-x30 38 ++VALUE Ascend-Data-Svc Switched-clear-bearer-v110 39 ++VALUE Ascend-Data-Svc Switched-restricted-64-x30 40 ++VALUE Ascend-Data-Svc Switched-clear-56-v110 41 ++VALUE Ascend-Data-Svc Switched-modem 42 ++VALUE Ascend-Data-Svc Switched-atmodem 43 ++VALUE Ascend-Data-Svc Nailed-56KR 1 ++VALUE Ascend-Data-Svc Nailed-64K 2 ++VALUE Ascend-Force-56 Force-56-No 0 ++VALUE Ascend-Force-56 Force-56-Yes 1 ++VALUE Ascend-PW-Lifetime Lifetime-In-Days 0 ++VALUE Ascend-PW-Warntime Days-Of-Warning 0 ++VALUE Ascend-PPP-VJ-1172 PPP-VJ-1172 1 ++VALUE Ascend-PPP-VJ-Slot-Comp VJ-Slot-Comp-No 1 ++VALUE Ascend-Require-Auth Not-Require-Auth 0 ++VALUE Ascend-Require-Auth Require-Auth 1 ++VALUE Ascend-Token-Immediate Tok-Imm-No 0 ++VALUE Ascend-Token-Immediate Tok-Imm-Yes 1 ++VALUE Ascend-DBA-Monitor DBA-Transmit 0 ++VALUE Ascend-DBA-Monitor DBA-Transmit-Recv 1 ++VALUE Ascend-DBA-Monitor DBA-None 2 ++VALUE Ascend-FR-Type Ascend-FR-DTE 0 ++VALUE Ascend-FR-Type Ascend-FR-DCE 1 ++VALUE Ascend-FR-Type Ascend-FR-NNI 2 ++VALUE Ascend-FR-Link-Mgt Ascend-FR-No-Link-Mgt 0 ++VALUE Ascend-FR-Link-Mgt Ascend-FR-T1-617D 1 ++VALUE Ascend-FR-Link-Mgt Ascend-FR-Q-933A 2 ++VALUE Ascend-FR-LinkUp Ascend-LinkUp-Default 0 ++VALUE Ascend-FR-LinkUp Ascend-LinkUp-AlwaysUp 1 ++VALUE Ascend-Multicast-Client Multicast-No 0 ++VALUE Ascend-Multicast-Client Multicast-Yes 1 ++VALUE Ascend-User-Acct-Type Ascend-User-Acct-None 0 ++VALUE Ascend-User-Acct-Type Ascend-User-Acct-User 1 ++VALUE Ascend-User-Acct-Type Ascend-User-Acct-User-Default 2 ++VALUE Ascend-User-Acct-Base Base-10 0 ++VALUE Ascend-User-Acct-Base Base-16 1 ++VALUE Ascend-DHCP-Reply DHCP-Reply-No 0 ++VALUE Ascend-DHCP-Reply DHCP-Reply-Yes 1 ++VALUE Ascend-Client-Assign-DNS DNS-Assign-No 0 ++VALUE Ascend-Client-Assign-DNS DNS-Assign-Yes 1 ++VALUE Ascend-Event-Type Ascend-ColdStart 1 ++VALUE Ascend-Event-Type Ascend-Session-Event 2 ++VALUE Ascend-BACP-Enable BACP-No 0 ++VALUE Ascend-BACP-Enable BACP-Yes 1 ++VALUE Ascend-Dialout-Allowed Dialout-Not-Allowed 0 ++VALUE Ascend-Dialout-Allowed Dialout-Allowed 1 ++VALUE Ascend-Shared-Profile-Enable Shared-Profile-No 0 ++VALUE Ascend-Shared-Profile-Enable Shared-Profile-Yes 1 ++VALUE Ascend-Temporary-Rtes Temp-Rtes-No 0 ++VALUE Ascend-Temporary-Rtes Temp-Rtes-Yes 1 +diff --git a/src/plugins/vbng/etc/dictionary.compat b/src/plugins/vbng/etc/dictionary.compat +new file mode 100644 +index 00000000..4c85ea87 +--- /dev/null ++++ b/src/plugins/vbng/etc/dictionary.compat +@@ -0,0 +1,47 @@ ++# ++# Obsolete names for backwards compatibility with older users files. ++# Move the $INCLUDE in the main dictionary file to the end if you want ++# these names to be used in the "details" logfile. ++# ++ATTRIBUTE Client-Id 4 ipaddr ++ATTRIBUTE Client-Port-Id 5 integer ++ATTRIBUTE User-Service-Type 6 integer ++ATTRIBUTE Framed-Address 8 ipaddr ++ATTRIBUTE Framed-Netmask 9 ipaddr ++ATTRIBUTE Framed-Filter-Id 11 string ++ATTRIBUTE Login-Host 14 ipaddr ++ATTRIBUTE Login-Port 16 integer ++ATTRIBUTE Old-Password 17 string ++ATTRIBUTE Port-Message 18 string ++ATTRIBUTE Dialback-No 19 string ++ATTRIBUTE Dialback-Name 20 string ++ATTRIBUTE Challenge-State 24 string ++VALUE Framed-Compression Van-Jacobsen-TCP-IP 1 ++VALUE Framed-Compression VJ-TCP-IP 1 ++VALUE Service-Type Shell-User 6 ++VALUE Auth-Type Unix 1 ++VALUE Service-Type Dialback-Login-User 3 ++VALUE Service-Type Dialback-Framed-User 4 ++ ++# ++# For compatibility with MERIT users files. ++# ++ATTRIBUTE NAS-Port 5 integer ++ATTRIBUTE Login-Host 14 ipaddr ++ATTRIBUTE Login-Callback-Number 19 string ++ATTRIBUTE Framed-Callback-Id 20 string ++ATTRIBUTE Client-Port-DNIS 30 string ++ATTRIBUTE Caller-ID 31 string ++VALUE Service-Type Login 1 ++VALUE Service-Type Framed 2 ++VALUE Service-Type Callback-Login 3 ++VALUE Service-Type Callback-Framed 4 ++VALUE Service-Type Exec-User 7 ++ ++# ++# For compatibility with ESVA RADIUS, Old Cistron RADIUS ++# ++ATTRIBUTE Session 1034 integer ++ATTRIBUTE User-Name-Is-Star 1035 integer ++VALUE User-Name-Is-Star No 0 ++VALUE User-Name-Is-Star Yes 1 +diff --git a/src/plugins/vbng/etc/dictionary.dhcp b/src/plugins/vbng/etc/dictionary.dhcp +new file mode 100644 +index 00000000..cf329348 +--- /dev/null ++++ b/src/plugins/vbng/etc/dictionary.dhcp +@@ -0,0 +1,440 @@ ++# -*- text -*- ++# Copyright (C) 2011 The FreeRADIUS Server project and contributors ++############################################################################## ++# ++# DHCP to RADUS gateway dictionary. ++# ++# http://www.iana.org/assignments/bootp-dhcp-parameters ++# ++# Also http://www.networksorcery.com/enp/protocol/bootp/options.htm ++# ++# http://www.bind9.net/rfc-dhcp ++# ++# $Id: 73632c57d3860bb30749a1df4dad2320d5f79f31 $ ++# ++############################################################################## ++ ++# ++ ++# This is really Apollo's number, but since they're out of business, ++# I don't think they'll be needing this. ++# ++# HP owns the Apollo assets, but let's not worry about that. ++# ++# The vendor codes are 2 octets, because we need 256 numbers ++# for the base DHCP options, PLUS a few for the DHCP headers, ++# which aren't in option format. ++# ++# On top of that, a number of options are really TLV's. ++# We need to be able to understand them, too. ++# ++VENDOR DHCP 54 format=2,1 ++ ++BEGIN-VENDOR DHCP ++ ++ATTRIBUTE DHCP-Opcode 256 byte ++ATTRIBUTE DHCP-Hardware-Type 257 byte ++ATTRIBUTE DHCP-Hardware-Address-Length 258 byte ++ATTRIBUTE DHCP-Hop-Count 259 byte ++ATTRIBUTE DHCP-Transaction-Id 260 integer ++ATTRIBUTE DHCP-Number-of-Seconds 261 short ++ATTRIBUTE DHCP-Flags 262 short ++ATTRIBUTE DHCP-Client-IP-Address 263 ipaddr ++ATTRIBUTE DHCP-Your-IP-Address 264 ipaddr ++ATTRIBUTE DHCP-Server-IP-Address 265 ipaddr ++ATTRIBUTE DHCP-Gateway-IP-Address 266 ipaddr ++ATTRIBUTE DHCP-Client-Hardware-Address 267 ether # 16 octets ++ATTRIBUTE DHCP-Server-Host-Name 268 string # 64 octets ++ATTRIBUTE DHCP-Boot-Filename 269 string # 128 octets ++ ++ATTRIBUTE DHCP-Relay-To-IP-Address 270 ipaddr ++ATTRIBUTE DHCP-Relay-Max-Hop-Count 271 integer ++ ++# This is copied from the request packet, giaddr, and ++# added to the reply packet by the server core. ++ATTRIBUTE DHCP-Relay-IP-Address 272 ipaddr ++ ++VALUE DHCP-Flags Broadcast 0x8000 ++ ++VALUE DHCP-Hardware-Type Ethernet 1 ++VALUE DHCP-Hardware-Type Experiemental-Ethernet 2 ++VALUE DHCP-Hardware-Type AX.25 3 ++VALUE DHCP-Hardware-Type Proteon-Token-Ring 4 ++VALUE DHCP-Hardware-Type Chaos 5 ++VALUE DHCP-Hardware-Type IEEE-802 6 ++VALUE DHCP-Hardware-Type Arcnet 7 ++VALUE DHCP-Hardware-Type Hyperchannel 8 ++VALUE DHCP-Hardware-Type Lanstar 9 ++VALUE DHCP-Hardware-Type Autonet-Short-Address 10 ++VALUE DHCP-Hardware-Type LocalTalk 11 ++VALUE DHCP-Hardware-Type LocalNet 12 ++VALUE DHCP-Hardware-Type Ultra-Link 13 ++VALUE DHCP-Hardware-Type SMDS 14 ++VALUE DHCP-Hardware-Type Frame-Relay 15 ++VALUE DHCP-Hardware-Type ATM-16 16 ++VALUE DHCP-Hardware-Type HDLC 17 ++VALUE DHCP-Hardware-Type Fibre-Channel 18 ++VALUE DHCP-Hardware-Type ATM-19 19 ++VALUE DHCP-Hardware-Type Serial-Line 20 ++VALUE DHCP-Hardware-Type ATM-21 21 ++VALUE DHCP-Hardware-Type MIL-STD-188-220 22 ++VALUE DHCP-Hardware-Type Metricom 23 ++VALUE DHCP-Hardware-Type IEEE-1394 24 ++VALUE DHCP-Hardware-Type MAPOS 25 ++VALUE DHCP-Hardware-Type Twinaxial 26 ++VALUE DHCP-Hardware-Type EUI-64 27 ++VALUE DHCP-Hardware-Type HIPARP 28 ++VALUE DHCP-Hardware-Type IP-Over-ISO-7816-3 29 ++VALUE DHCP-Hardware-Type ARPSec 30 ++VALUE DHCP-Hardware-Type IPSec-Tunnel 31 ++VALUE DHCP-Hardware-Type Infiniband 32 ++VALUE DHCP-Hardware-Type CAI-TIA-102 33 ++ ++############################################################################## ++# ++# DHCP Options, with comments. For now, many are "octets", ++# as FreeRADIUS doesn't handle complex data structures. ++# ++############################################################################## ++ ++#ATTRIBUTE DHCP-Pad 0 octets ++ATTRIBUTE DHCP-Subnet-Mask 1 ipaddr ++# Time Offset in twos-complement notation. ++ATTRIBUTE DHCP-Time-Offset 2 integer ++ATTRIBUTE DHCP-Router-Address 3 ipaddr array ++ATTRIBUTE DHCP-Time-Server 4 ipaddr array ++ATTRIBUTE DHCP-IEN-116-Name-Server 5 ipaddr array ++ATTRIBUTE DHCP-Domain-Name-Server 6 ipaddr array ++# Logging-Server addresses ++ATTRIBUTE DHCP-Log-Server 7 ipaddr array ++ATTRIBUTE DHCP-Quotes-Server 8 ipaddr array ++ATTRIBUTE DHCP-LPR-Server 9 ipaddr array ++ATTRIBUTE DHCP-Impress-Server 10 ipaddr array ++ATTRIBUTE DHCP-RLP-Server 11 ipaddr array ++# Hostname string ++ATTRIBUTE DHCP-Hostname 12 string ++# Size of boot file in 512 byte ++ATTRIBUTE DHCP-Boot-File-Size 13 short ++# Client to dump and name ++ATTRIBUTE DHCP-Merit-Dump-File 14 octets ++ATTRIBUTE DHCP-Domain-Name 15 string ++ATTRIBUTE DHCP-Swap-Server 16 ipaddr ++# Path name for root disk ++ATTRIBUTE DHCP-Root-Path 17 string ++ATTRIBUTE DHCP-Bootp-Extensions-Path 18 string ++ATTRIBUTE DHCP-IP-Forward-Enable 19 byte ++ATTRIBUTE DHCP-Source-Route-Enable 20 byte ++# Routing Policy Filters ++ATTRIBUTE DHCP-Policy-Filter 21 octets ++ATTRIBUTE DHCP-Max-Datagram-Reassembly-Sz 22 short ++ATTRIBUTE DHCP-Default-IP-TTL 23 octets ++ATTRIBUTE DHCP-Path-MTU-Aging-Timeout 24 integer ++ATTRIBUTE DHCP-Path-MTU-Plateau-Table 25 short array ++ATTRIBUTE DHCP-Interface-MTU-Size 26 short ++ATTRIBUTE DHCP-All-Subnets-Are-Local 27 byte ++ATTRIBUTE DHCP-Broadcast-Address 28 ipaddr ++ATTRIBUTE DHCP-Perform-Mask-Discovery 29 byte ++ATTRIBUTE DHCP-Provide-Mask-To-Others 30 byte ++ATTRIBUTE DHCP-Perform-Router-Discovery 31 byte ++ATTRIBUTE DHCP-Router-Solicitation-Address 32 ipaddr ++# first is destination address, second is router. ++ATTRIBUTE DHCP-Static-Routes 33 ipaddr array ++ATTRIBUTE DHCP-Trailer-Encapsulation 34 byte ++ATTRIBUTE DHCP-ARP-Cache-Timeout 35 integer ++ATTRIBUTE DHCP-Ethernet-Encapsulation 36 byte ++ATTRIBUTE DHCP-Default-TCP-TTL 37 byte ++ATTRIBUTE DHCP-Keep-Alive-Interval 38 integer ++ATTRIBUTE DHCP-Keep-Alive-Garbage 39 byte ++ATTRIBUTE DHCP-NIS-Domain-Name 40 string ++ATTRIBUTE DHCP-NIS-Servers 41 ipaddr array ++ATTRIBUTE DHCP-NTP-Servers 42 ipaddr array ++# N Vendor Specific Information ++ATTRIBUTE DHCP-Vendor 43 octets # tlv ++ATTRIBUTE DHCP-NETBIOS-Name-Servers 44 ipaddr array ++ATTRIBUTE DHCP-NETBIOS-Dgm-Dist-Servers 45 ipaddr array ++ATTRIBUTE DHCP-NETBIOS-Node-Type 46 byte ++# N NETBIOS Scope ++ATTRIBUTE DHCP-NETBIOS 47 octets ++ATTRIBUTE DHCP-X-Window-Font-Server 48 ipaddr array ++ATTRIBUTE DHCP-X-Window-Display-Mgr 49 ipaddr array ++ATTRIBUTE DHCP-Requested-IP-Address 50 ipaddr ++ATTRIBUTE DHCP-IP-Address-Lease-Time 51 integer ++# Overload "sname" or "file" ++ATTRIBUTE DHCP-Overload 52 byte ++ATTRIBUTE DHCP-Message-Type 53 byte ++ATTRIBUTE DHCP-DHCP-Server-Identifier 54 ipaddr ++ ++# Array of 1-byte numbers indicating which options the client ++# would like to see in the response. ++ATTRIBUTE DHCP-Parameter-Request-List 55 byte array ++ATTRIBUTE DHCP-DHCP-Error-Message 56 octets ++ATTRIBUTE DHCP-DHCP-Maximum-Msg-Size 57 short ++ATTRIBUTE DHCP-Renewal-Time 58 integer ++ATTRIBUTE DHCP-Rebinding-Time 59 integer ++ATTRIBUTE DHCP-Vendor-Class-Identifier 60 string ++ ++# Client Identifier ++# First octets is DHCP-Hardware-Type, rest are type-specific data, ++# e.g. MAC address. ++ATTRIBUTE DHCP-Client-Identifier 61 ether ++ATTRIBUTE DHCP-Netware-Domain-Name 62 octets ++ATTRIBUTE DHCP-Netware-Sub-Options 63 octets ++ATTRIBUTE DHCP-NIS-Client-Domain-Name 64 octets ++ATTRIBUTE DHCP-NIS-Server-Address 65 ipaddr ++ATTRIBUTE DHCP-TFTP-Server-Name 66 string ++ATTRIBUTE DHCP-Boot-File-Name 67 string ++# Home Agent Addresses ++ATTRIBUTE DHCP-Home-Agent-Address 68 octets ++ATTRIBUTE DHCP-SMTP-Server-Address 69 ipaddr array ++ATTRIBUTE DHCP-POP3-Server-Address 70 ipaddr array ++ATTRIBUTE DHCP-NNTP-Server-Address 71 ipaddr array ++ATTRIBUTE DHCP-WWW-Server-Address 72 ipaddr array ++ATTRIBUTE DHCP-Finger-Server-Address 73 ipaddr array ++ATTRIBUTE DHCP-IRC-Server-Address 74 ipaddr array ++ATTRIBUTE DHCP-StreetTalk-Server-Address 75 ipaddr array ++ATTRIBUTE DHCP-STDA-Server-Address 76 ipaddr array ++# User Class Information ++ATTRIBUTE DHCP-User-Class 77 octets ++# directory agent information ++ATTRIBUTE DHCP-Directory-Agent 78 octets ++# service location agent scope ++ATTRIBUTE DHCP-Service-Scope 79 octets ++# Rapid Commit ++ATTRIBUTE DHCP-Rapid-Commit 80 octets ++# Fully Qualified Domain Name ++ATTRIBUTE DHCP-Client-FQDN 81 string ++# Relay Agent Information ++ATTRIBUTE DHCP-Relay-Agent-Information 82 tlv ++ ++ATTRIBUTE DHCP-Agent-Circuit-Id 82.1 octets ++ATTRIBUTE DHCP-Agent-Remote-Id 82.2 octets ++ ++ATTRIBUTE DHCP-Relay-Circuit-Id 82.1 octets ++ATTRIBUTE DHCP-Relay-Remote-Id 82.2 octets ++ ++# 3 is reserved and shouldn't be used for anything ++ATTRIBUTE DHCP-Docsis-Device-Class 82.4 integer ++ATTRIBUTE DHCP-Relay-Link-Selection 82.5 ipaddr ++ATTRIBUTE DHCP-Subscriber-Id 82.6 string ++ ++# AGH! RADIUS inside of DHCP! ++ATTRIBUTE DHCP-RADIUS-Attributes 82.7 octets ++ ++# Horribly complicated ++ATTRIBUTE DHCP-Authentication-Information 82.8 octets ++ATTRIBUTE DHCP-Vendor-Specific-Information 82.9 octets ++ATTRIBUTE DHCP-Relay-Agent-Flags 82.10 byte ++ATTRIBUTE DHCP-Server-Identifier-Override 82.11 ipaddr ++ ++# Internet Storage Name Service ++ATTRIBUTE DHCP-iSNS 83 octets ++# Novell Directory Services ++ATTRIBUTE DHCP-NDS-Servers 85 octets ++# Novell Directory Services ++ATTRIBUTE DHCP-NDS-Tree-Name 86 octets ++# Novell Directory Services ++ATTRIBUTE DHCP-NDS-Context 87 octets ++# Authentication ++ATTRIBUTE DHCP-Authentication 90 octets ++ ++ATTRIBUTE DHCP-Client-Last-Txn-Time 91 octets ++ ++ATTRIBUTE DHCP-associated-ip 92 octets ++# Client System Architecture ++ATTRIBUTE DHCP-Client-System 93 octets ++# Client Network Device Interface ++ATTRIBUTE DHCP-Client-NDI 94 octets ++# Lightweight Directory Access Protocol ++ATTRIBUTE DHCP-LDAP 95 octets ++# UUID/GUID-based Client Identifier ++ATTRIBUTE DHCP-UUID/GUID 97 octets ++# Open Group's User Authentication ++ATTRIBUTE DHCP-User-Auth 98 octets ++# NetInfo Parent-Server Address ++ATTRIBUTE DHCP-Netinfo-Address 112 octets ++# NetInfo Parent-Server Tag ++ATTRIBUTE DHCP-Netinfo-Tag 113 octets ++# URL ++ATTRIBUTE DHCP-URL 114 octets ++# DHCP Auto-Configuration ++ATTRIBUTE DHCP-Auto-Config 116 byte ++# Name Service Search ++ATTRIBUTE DHCP-Name-Service-Search 117 octets ++# Subnet Selection Option ++ATTRIBUTE DHCP-Subnet-Selection-Option 118 octets ++# DNS domain serach list ++ATTRIBUTE DHCP-Domain-Search 119 octets ++# SIP-Servers DHCP Option ++ATTRIBUTE DHCP-SIP-Servers-DHCP-Option 120 octets ++# Classless Static Route Option ++ATTRIBUTE DHCP-Classless-Static-Route 121 octets ++# CableLabs Client Configuration ++ATTRIBUTE DHCP-CCC 122 octets ++# 16 GeoConf Option ++ATTRIBUTE DHCP-GeoConf-Option 123 octets ++ ++# Vendor Class ++# ++# String name that defines the vendor space used for the TLV's ++# in option 125. ++# ++ATTRIBUTE DHCP-V-I-Vendor-Class 124 octets ++# Vendor-Specific ++ATTRIBUTE DHCP-V-I-Vendor-Specific 125 octets # tlv ++ATTRIBUTE DHCP-Etherboot 128 ether ++# (for IP Phone software load) ++ATTRIBUTE DHCP-TFTP-Server-IP-Address 128 octets ++ ++ATTRIBUTE DHCP-Call-Server-IP-address 129 octets ++ ++ATTRIBUTE DHCP-Ethernet-Interface 130 octets ++ ++ATTRIBUTE DHCP-Vendor-Discrimination-Str 130 octets ++ ++ATTRIBUTE DHCP-Remote-Stats-Svr-IP-Address 131 octets ++ ++ATTRIBUTE DHCP-IEEE-802.1Q-L2-Priority 132 octets ++ ++ATTRIBUTE DHCP-IEEE-802.1P-VLAN-ID 133 octets ++ ++ATTRIBUTE DHCP-Diffserv-Code-Point 134 octets ++ ++ATTRIBUTE DHCP-HTTP-Proxy 135 octets ++ ++ATTRIBUTE DHCP-Cisco-TFTP-Server-IP-Addresses 150 ipaddr array ++ ++ATTRIBUTE DHCP-End-Of-Options 255 byte ++ ++VALUE DHCP-Opcode Client-Message 1 ++VALUE DHCP-Opcode Server-Message 2 ++ ++VALUE DHCP-Message-Type DHCP-Do-Not-Respond 0 ++VALUE DHCP-Message-Type DHCP-Discover 1 ++VALUE DHCP-Message-Type DHCP-Offer 2 ++VALUE DHCP-Message-Type DHCP-Request 3 ++VALUE DHCP-Message-Type DHCP-Decline 4 ++VALUE DHCP-Message-Type DHCP-Ack 5 ++VALUE DHCP-Message-Type DHCP-NAK 6 ++VALUE DHCP-Message-Type DHCP-Release 7 ++VALUE DHCP-Message-Type DHCP-Inform 8 ++VALUE DHCP-Message-Type DHCP-Force-Renew 9 ++ ++VALUE DHCP-Parameter-Request-List DHCP-Subnet-Mask 1 ++VALUE DHCP-Parameter-Request-List DHCP-Time-Offset 2 ++VALUE DHCP-Parameter-Request-List DHCP-Router-Address 3 ++VALUE DHCP-Parameter-Request-List DHCP-Time-Server 4 ++VALUE DHCP-Parameter-Request-List DHCP-IEN-116-Name-Server 5 ++VALUE DHCP-Parameter-Request-List DHCP-Domain-Name-Server 6 ++VALUE DHCP-Parameter-Request-List DHCP-Log-Server 7 ++VALUE DHCP-Parameter-Request-List DHCP-Quotes-Server 8 ++VALUE DHCP-Parameter-Request-List DHCP-LPR-Server 9 ++VALUE DHCP-Parameter-Request-List DHCP-Impress-Server 10 ++VALUE DHCP-Parameter-Request-List DHCP-RLP-Server 11 ++VALUE DHCP-Parameter-Request-List DHCP-Hostname 12 ++VALUE DHCP-Parameter-Request-List DHCP-Boot-File-Size 13 ++VALUE DHCP-Parameter-Request-List DHCP-Merit-Dump-File 14 ++VALUE DHCP-Parameter-Request-List DHCP-Domain-Name 15 ++VALUE DHCP-Parameter-Request-List DHCP-Swap-Server 16 ++VALUE DHCP-Parameter-Request-List DHCP-Root-Path 17 ++VALUE DHCP-Parameter-Request-List DHCP-Bootp-Extensions-Path 18 ++VALUE DHCP-Parameter-Request-List DHCP-IP-Forward-Enable 19 ++VALUE DHCP-Parameter-Request-List DHCP-Source-Route-Enable 20 ++VALUE DHCP-Parameter-Request-List DHCP-Policy-Filter 21 ++VALUE DHCP-Parameter-Request-List DHCP-Max-Datagram-Reassembly-Sz 22 ++VALUE DHCP-Parameter-Request-List DHCP-Default-IP-TTL 23 ++VALUE DHCP-Parameter-Request-List DHCP-Path-MTU-Aging-Timeout 24 ++VALUE DHCP-Parameter-Request-List DHCP-Path-MTU-Plateau-Table 25 ++VALUE DHCP-Parameter-Request-List DHCP-Interface-MTU-Size 26 ++VALUE DHCP-Parameter-Request-List DHCP-All-Subnets-Are-Local 27 ++VALUE DHCP-Parameter-Request-List DHCP-Broadcast-Address 28 ++VALUE DHCP-Parameter-Request-List DHCP-Perform-Mask-Discovery 29 ++VALUE DHCP-Parameter-Request-List DHCP-Provide-Mask-To-Others 30 ++VALUE DHCP-Parameter-Request-List DHCP-Perform-Router-Discovery 31 ++VALUE DHCP-Parameter-Request-List DHCP-Router-Solicitation-Address 32 ++VALUE DHCP-Parameter-Request-List DHCP-Static-Routes 33 ++VALUE DHCP-Parameter-Request-List DHCP-Trailer-Encapsulation 34 ++VALUE DHCP-Parameter-Request-List DHCP-ARP-Cache-Timeout 35 ++VALUE DHCP-Parameter-Request-List DHCP-Ethernet-Encapsulation 36 ++VALUE DHCP-Parameter-Request-List DHCP-Default-TCP-TTL 37 ++VALUE DHCP-Parameter-Request-List DHCP-Keep-Alive-Interval 38 ++VALUE DHCP-Parameter-Request-List DHCP-Keep-Alive-Garbage 39 ++VALUE DHCP-Parameter-Request-List DHCP-NIS-Domain-Name 40 ++VALUE DHCP-Parameter-Request-List DHCP-NIS-Servers 41 ++VALUE DHCP-Parameter-Request-List DHCP-NTP-Servers 42 ++VALUE DHCP-Parameter-Request-List DHCP-Vendor 43 ++VALUE DHCP-Parameter-Request-List DHCP-NETBIOS-Name-Servers 44 ++VALUE DHCP-Parameter-Request-List DHCP-NETBIOS-Dgm-Dist-Servers 45 ++VALUE DHCP-Parameter-Request-List DHCP-NETBIOS-Node-Type 46 ++VALUE DHCP-Parameter-Request-List DHCP-NETBIOS 47 ++VALUE DHCP-Parameter-Request-List DHCP-X-Window-Font-Server 48 ++VALUE DHCP-Parameter-Request-List DHCP-X-Window-Display-Mgr 49 ++VALUE DHCP-Parameter-Request-List DHCP-Requested-IP-Address 50 ++VALUE DHCP-Parameter-Request-List DHCP-IP-Address-Lease-Time 51 ++VALUE DHCP-Parameter-Request-List DHCP-Overload 52 ++VALUE DHCP-Parameter-Request-List DHCP-Message-Type 53 ++VALUE DHCP-Parameter-Request-List DHCP-DHCP-Server-Identifier 54 ++VALUE DHCP-Parameter-Request-List DHCP-Parameter-Request-List 55 ++VALUE DHCP-Parameter-Request-List DHCP-DHCP-Error-Message 56 ++VALUE DHCP-Parameter-Request-List DHCP-DHCP-Maximum-Msg-Size 57 ++VALUE DHCP-Parameter-Request-List DHCP-Renewal-Time 58 ++VALUE DHCP-Parameter-Request-List DHCP-Rebinding-Time 59 ++VALUE DHCP-Parameter-Request-List DHCP-Class-Identifier 60 ++VALUE DHCP-Parameter-Request-List DHCP-Client-Identifier 61 ++VALUE DHCP-Parameter-Request-List DHCP-Netware-Domain-Name 62 ++VALUE DHCP-Parameter-Request-List DHCP-Netware-Sub-Options 63 ++VALUE DHCP-Parameter-Request-List DHCP-NIS-Client-Domain-Name 64 ++VALUE DHCP-Parameter-Request-List DHCP-NIS-Server-Address 65 ++VALUE DHCP-Parameter-Request-List DHCP-TFTP-Server-Name 66 ++VALUE DHCP-Parameter-Request-List DHCP-Boot-File-Name 67 ++VALUE DHCP-Parameter-Request-List DHCP-Home-Agent-Address 68 ++VALUE DHCP-Parameter-Request-List DHCP-SMTP-Server-Address 69 ++VALUE DHCP-Parameter-Request-List DHCP-POP3-Server-Address 70 ++VALUE DHCP-Parameter-Request-List DHCP-NNTP-Server-Address 71 ++VALUE DHCP-Parameter-Request-List DHCP-WWW-Server-Address 72 ++VALUE DHCP-Parameter-Request-List DHCP-Finger-Server-Address 73 ++VALUE DHCP-Parameter-Request-List DHCP-IRC-Server-Address 74 ++VALUE DHCP-Parameter-Request-List DHCP-StreetTalk-Server-Address 75 ++VALUE DHCP-Parameter-Request-List DHCP-STDA-Server-Address 76 ++VALUE DHCP-Parameter-Request-List DHCP-User-Class 77 ++VALUE DHCP-Parameter-Request-List DHCP-Directory-Agent 78 ++VALUE DHCP-Parameter-Request-List DHCP-Service-Scope 79 ++VALUE DHCP-Parameter-Request-List DHCP-Rapid-Commit 80 ++VALUE DHCP-Parameter-Request-List DHCP-Client-FQDN 81 ++VALUE DHCP-Parameter-Request-List DHCP-Relay-Agent-Information 82 ++VALUE DHCP-Parameter-Request-List DHCP-iSNS 83 ++VALUE DHCP-Parameter-Request-List DHCP-NDS-Servers 85 ++VALUE DHCP-Parameter-Request-List DHCP-NDS-Tree-Name 86 ++VALUE DHCP-Parameter-Request-List DHCP-NDS-Context 87 ++VALUE DHCP-Parameter-Request-List DHCP-Authentication 90 ++VALUE DHCP-Parameter-Request-List DHCP-Client-Last-Txn-Time 91 ++VALUE DHCP-Parameter-Request-List DHCP-associated-ip 92 ++VALUE DHCP-Parameter-Request-List DHCP-Client-System 93 ++VALUE DHCP-Parameter-Request-List DHCP-Client-NDI 94 ++VALUE DHCP-Parameter-Request-List DHCP-LDAP 95 ++VALUE DHCP-Parameter-Request-List DHCP-UUID/GUID 97 ++VALUE DHCP-Parameter-Request-List DHCP-User-Auth 98 ++VALUE DHCP-Parameter-Request-List DHCP-Netinfo-Address 112 ++VALUE DHCP-Parameter-Request-List DHCP-Netinfo-Tag 113 ++VALUE DHCP-Parameter-Request-List DHCP-URL 114 ++VALUE DHCP-Parameter-Request-List DHCP-Auto-Config 116 ++VALUE DHCP-Parameter-Request-List DHCP-Name-Service-Search 117 ++VALUE DHCP-Parameter-Request-List DHCP-Subnet-Selection-Option 118 ++VALUE DHCP-Parameter-Request-List DHCP-Domain-Search 119 ++VALUE DHCP-Parameter-Request-List DHCP-SIP-Servers-DHCP-Option 120 ++VALUE DHCP-Parameter-Request-List DHCP-Classless-Static-Route 121 ++VALUE DHCP-Parameter-Request-List DHCP-CCC 122 ++VALUE DHCP-Parameter-Request-List DHCP-GeoConf-Option 123 ++VALUE DHCP-Parameter-Request-List DHCP-V-I-Vendor-Class 124 ++VALUE DHCP-Parameter-Request-List DHCP-V-I-Vendor-Specific 125 ++VALUE DHCP-Parameter-Request-List DHCP-Etherboot 128 ++VALUE DHCP-Parameter-Request-List DHCP-TFTP-Server-IP-Address 128 ++VALUE DHCP-Parameter-Request-List DHCP-Call-Server-IP-address 129 ++VALUE DHCP-Parameter-Request-List DHCP-Ethernet-Interface 130 ++VALUE DHCP-Parameter-Request-List DHCP-Vendor-Discrimination-Str 130 ++VALUE DHCP-Parameter-Request-List DHCP-Remote-Stats-Svr-IP-Address 131 ++VALUE DHCP-Parameter-Request-List DHCP-IEEE-802.1P-VLAN-ID 132 ++VALUE DHCP-Parameter-Request-List DHCP-IEEE-802.1Q-L2-Priority 133 ++VALUE DHCP-Parameter-Request-List DHCP-Diffserv-Code-Point 134 ++VALUE DHCP-Parameter-Request-List DHCP-HTTP-Proxy 135 ++ ++END-VENDOR DHCP +diff --git a/src/plugins/vbng/etc/dictionary.merit b/src/plugins/vbng/etc/dictionary.merit +new file mode 100644 +index 00000000..7d675e50 +--- /dev/null ++++ b/src/plugins/vbng/etc/dictionary.merit +@@ -0,0 +1,17 @@ ++# ++# Experimental extensions, configuration only (for check-items) ++# Names/numbers as per the MERIT extensions (if possible). ++# ++ATTRIBUTE NAS-Identifier 32 string ++ATTRIBUTE Proxy-State 33 string ++ATTRIBUTE Login-LAT-Service 34 string ++ATTRIBUTE Login-LAT-Node 35 string ++ATTRIBUTE Login-LAT-Group 36 string ++ATTRIBUTE Framed-AppleTalk-Link 37 integer ++ATTRIBUTE Framed-AppleTalk-Network 38 integer ++ATTRIBUTE Framed-AppleTalk-Zone 39 string ++ATTRIBUTE Acct-Input-Packets 47 integer ++ATTRIBUTE Acct-Output-Packets 48 integer ++# 8 is a MERIT extension. ++VALUE Service-Type Authenticate-Only 8 ++ +diff --git a/src/plugins/vbng/etc/dictionary.sip b/src/plugins/vbng/etc/dictionary.sip +new file mode 100644 +index 00000000..149fa4cb +--- /dev/null ++++ b/src/plugins/vbng/etc/dictionary.sip +@@ -0,0 +1,77 @@ ++# ++# Updated 97/06/13 to livingston-radius-2.01 miquels@cistron.nl ++# ++# This file contains dictionary translations for parsing ++# requests and generating responses. All transactions are ++# composed of Attribute/Value Pairs. The value of each attribute ++# is specified as one of 4 data types. Valid data types are: ++# ++# string - 0-253 octets ++# ipaddr - 4 octets in network byte order ++# integer - 32 bit value in big endian order (high byte first) ++# date - 32 bit value in big endian order - seconds since ++# 00:00:00 GMT, Jan. 1, 1970 ++# ++# Enumerated values are stored in the user file with dictionary ++# VALUE translations for easy administration. ++# ++# Example: ++# ++# ATTRIBUTE VALUE ++# --------------- ----- ++# Framed-Protocol = PPP ++# 7 = 1 (integer encoding) ++# ++ ++# ++# Experimental SIP Attributes/Values (draft-sterman-aaa-sip-00.txt etc) ++# ++ATTRIBUTE Sip-Method 101 integer ++ATTRIBUTE Sip-Response-Code 102 integer ++ATTRIBUTE Sip-CSeq 103 string ++ATTRIBUTE Sip-To-Tag 104 string ++ATTRIBUTE Sip-From-Tag 105 string ++ATTRIBUTE Sip-Branch-ID 106 string ++ATTRIBUTE Sip-Translated-Request-URI 107 string ++ATTRIBUTE Sip-Source-IP-Address 108 ipaddr ++ATTRIBUTE Sip-Source-Port 109 integer ++ATTRIBUTE Sip-User-ID 110 string ++ATTRIBUTE Sip-User-Realm 111 string ++ATTRIBUTE Sip-User-Nonce 112 string ++ATTRIBUTE Sip-User-Method 113 string ++ATTRIBUTE Sip-User-Digest-URI 114 string ++ATTRIBUTE Sip-User-Nonce-Count 115 string ++ATTRIBUTE Sip-User-QOP 116 string ++ATTRIBUTE Sip-User-Opaque 117 string ++ATTRIBUTE Sip-User-Response 118 string ++ATTRIBUTE Sip-User-CNonce 119 string ++ATTRIBUTE Sip-URI-User 208 string ++ATTRIBUTE Sip-Req-URI 210 string ++ATTRIBUTE Sip-CC 212 string ++ATTRIBUTE Sip-RPId 213 string ++ATTRIBUTE Digest-Response 206 string ++ATTRIBUTE Digest-Attributes 207 string ++ATTRIBUTE Digest-Realm 1063 string ++ATTRIBUTE Digest-Nonce 1064 string ++ATTRIBUTE Digest-Method 1065 string ++ATTRIBUTE Digest-URI 1066 string ++ATTRIBUTE Digest-QOP 1067 string ++ATTRIBUTE Digest-Algorithm 1068 string ++ATTRIBUTE Digest-Body-Digest 1069 string ++ATTRIBUTE Digest-CNonce 1070 string ++ATTRIBUTE Digest-Nonce-Count 1071 string ++ATTRIBUTE Digest-User-Name 1072 string ++ ++VALUE Service-Type SIP 15 ++ ++VALUE Sip-Method Other 0 ++VALUE Sip-Method Invite 1 ++VALUE Sip-Method Cancel 2 ++VALUE Sip-Method Ack 3 ++VALUE Sip-Method Bye 4 ++ ++VALUE Sip-Response-Code Other 0 ++VALUE Sip-Response-Code Invite 1 ++VALUE Sip-Response-Code Cancel 2 ++VALUE Sip-Response-Code Ack 3 ++VALUE Sip-Response-Code Bye 4 +diff --git a/src/plugins/vbng/etc/issue b/src/plugins/vbng/etc/issue +new file mode 100644 +index 00000000..62544873 +--- /dev/null ++++ b/src/plugins/vbng/etc/issue +@@ -0,0 +1,5 @@ ++(\I) ++----------------------------------------------------- ++\S \R (\N) (port \L) ++----------------------------------------------------- ++ +diff --git a/src/plugins/vbng/etc/port-id-map b/src/plugins/vbng/etc/port-id-map +new file mode 100644 +index 00000000..9088a0b9 +--- /dev/null ++++ b/src/plugins/vbng/etc/port-id-map +@@ -0,0 +1,24 @@ ++# ++# port-id-map ++# ++# This file describes the ttyname to port id mapping. The port id ++# is reported as part of a RADIUS authentication or accouting request. ++# ++#ttyname (as returned by ttyname(3)) port-id ++/dev/tty1 1 ++/dev/tty2 2 ++/dev/tty3 3 ++/dev/tty4 4 ++/dev/tty5 5 ++/dev/tty6 6 ++/dev/tty7 7 ++/dev/tty8 8 ++/dev/ttyS0 9 ++/dev/ttyS1 10 ++/dev/ttyS2 11 ++/dev/ttyS3 12 ++/dev/ttyS4 13 ++/dev/ttyS5 14 ++/dev/ttyS6 15 ++/dev/ttyS7 16 ++ +\ No newline at end of file +diff --git a/src/plugins/vbng/etc/radiusclient.conf b/src/plugins/vbng/etc/radiusclient.conf +new file mode 100644 +index 00000000..3a315b46 +--- /dev/null ++++ b/src/plugins/vbng/etc/radiusclient.conf +@@ -0,0 +1,92 @@ ++# General settings ++ ++# specify which authentication comes first respectively which ++# authentication is used. possible values are: "radius" and "local". ++# if you specify "radius,local" then the RADIUS server is asked ++# first then the local one. if only one keyword is specified only ++# this server is asked. ++auth_order radius,local ++ ++# maximum login tries a user has ++login_tries 4 ++ ++# timeout for all login tries ++# if this time is exceeded the user is kicked out ++login_timeout 60 ++ ++# name of the nologin file which when it exists disables logins. ++# it may be extended by the ttyname which will result in ++# a terminal specific lock (e.g. /etc/nologin.ttyS2 will disable ++# logins on /dev/ttyS2) ++nologin /etc/nologin ++ ++# name of the issue file. it's only display when no username is passed ++# on the radlogin command line ++issue /usr/local/etc/radiusclient/issue ++ ++# RADIUS settings ++ ++# RADIUS server to use for authentication requests. this config ++# item can appear more then one time. if multiple servers are ++# defined they are tried in a round robin fashion if one ++# server is not answering. ++# optionally you can specify a the port number on which is remote ++# RADIUS listens separated by a colon from the hostname. if ++# no port is specified /etc/services is consulted of the radius ++# service. if this fails also a compiled in default is used. ++authserver localhost ++ ++# RADIUS server to use for accouting requests. All that I ++# said for authserver applies, too. ++# ++acctserver localhost ++ ++# file holding shared secrets used for the communication ++# between the RADIUS client and server ++servers /usr/local/etc/radiusclient/servers ++ ++# dictionary of allowed attributes and values ++# just like in the normal RADIUS distributions ++dictionary /usr/local/etc/radiusclient/dictionary ++ ++# program to call for a RADIUS authenticated login ++login_radius /usr/local/sbin/login.radius ++ ++# file which holds sequence number for communication with the ++# RADIUS server ++seqfile /var/run/radius.seq ++ ++# file which specifies mapping between ttyname and NAS-Port attribute ++mapfile /usr/local/etc/radiusclient/port-id-map ++ ++# default authentication realm to append to all usernames if no ++# realm was explicitly specified by the user ++# the radiusd directly form Livingston doesnt use any realms, so leave ++# it blank then ++default_realm ++ ++# time to wait for a reply from the RADIUS server ++radius_timeout 10 ++ ++# resend request this many times before trying the next server ++radius_retries 3 ++ ++# The length of time in seconds that we skip a nonresponsive RADIUS ++# server for transaction requests. Server(s) being in the "dead" state ++# are tried only after all other non-dead servers have been tried and ++# failed or timeouted. The deadtime interval starts when the server ++# does not respond to an authentication/accounting request transmissions. ++# When the interval expires, the "dead" server would be re-tried again, ++# and if it's still down then it will be considered "dead" for another ++# such interval and so on. This option is no-op if there is only one ++# server in the list. Set to 0 in order to disable the feature. ++radius_deadtime 0 ++ ++# local address from which radius packets have to be sent ++bindaddr * ++ ++# LOCAL settings ++ ++# program to execute for local login ++# it must support the -f flag for preauthenticated login ++login_local /bin/login +diff --git a/src/plugins/vbng/etc/radiusclient.conf.in b/src/plugins/vbng/etc/radiusclient.conf.in +new file mode 100644 +index 00000000..fdf62e6d +--- /dev/null ++++ b/src/plugins/vbng/etc/radiusclient.conf.in +@@ -0,0 +1,92 @@ ++# General settings ++ ++# specify which authentication comes first respectively which ++# authentication is used. possible values are: "radius" and "local". ++# if you specify "radius,local" then the RADIUS server is asked ++# first then the local one. if only one keyword is specified only ++# this server is asked. ++auth_order radius,local ++ ++# maximum login tries a user has ++login_tries 4 ++ ++# timeout for all login tries ++# if this time is exceeded the user is kicked out ++login_timeout 60 ++ ++# name of the nologin file which when it exists disables logins. ++# it may be extended by the ttyname which will result in ++# a terminal specific lock (e.g. /etc/nologin.ttyS2 will disable ++# logins on /dev/ttyS2) ++nologin /etc/nologin ++ ++# name of the issue file. it's only display when no username is passed ++# on the radlogin command line ++issue @pkgsysconfdir@/issue ++ ++# RADIUS settings ++ ++# RADIUS server to use for authentication requests. this config ++# item can appear more then one time. if multiple servers are ++# defined they are tried in a round robin fashion if one ++# server is not answering. ++# optionally you can specify a the port number on which is remote ++# RADIUS listens separated by a colon from the hostname. if ++# no port is specified /etc/services is consulted of the radius ++# service. if this fails also a compiled in default is used. ++authserver localhost ++ ++# RADIUS server to use for accouting requests. All that I ++# said for authserver applies, too. ++# ++acctserver localhost ++ ++# file holding shared secrets used for the communication ++# between the RADIUS client and server ++servers @pkgsysconfdir@/servers ++ ++# dictionary of allowed attributes and values ++# just like in the normal RADIUS distributions ++dictionary @pkgsysconfdir@/dictionary ++ ++# program to call for a RADIUS authenticated login ++login_radius @sbindir@/login.radius ++ ++# file which holds sequence number for communication with the ++# RADIUS server ++seqfile /var/run/radius.seq ++ ++# file which specifies mapping between ttyname and NAS-Port attribute ++mapfile @pkgsysconfdir@/port-id-map ++ ++# default authentication realm to append to all usernames if no ++# realm was explicitly specified by the user ++# the radiusd directly form Livingston doesnt use any realms, so leave ++# it blank then ++default_realm ++ ++# time to wait for a reply from the RADIUS server ++radius_timeout 10 ++ ++# resend request this many times before trying the next server ++radius_retries 3 ++ ++# The length of time in seconds that we skip a nonresponsive RADIUS ++# server for transaction requests. Server(s) being in the "dead" state ++# are tried only after all other non-dead servers have been tried and ++# failed or timeouted. The deadtime interval starts when the server ++# does not respond to an authentication/accounting request transmissions. ++# When the interval expires, the "dead" server would be re-tried again, ++# and if it's still down then it will be considered "dead" for another ++# such interval and so on. This option is no-op if there is only one ++# server in the list. Set to 0 in order to disable the feature. ++radius_deadtime 0 ++ ++# local address from which radius packets have to be sent ++bindaddr * ++ ++# LOCAL settings ++ ++# program to execute for local login ++# it must support the -f flag for preauthenticated login ++login_local /bin/login +diff --git a/src/plugins/vbng/etc/servers b/src/plugins/vbng/etc/servers +new file mode 100644 +index 00000000..50eddd39 +--- /dev/null ++++ b/src/plugins/vbng/etc/servers +@@ -0,0 +1,10 @@ ++## Server Name or Client/Server pair Key ++## ---------------- --------------- ++# ++#portmaster.elemental.net hardlyasecret ++#portmaster2.elemental.net donttellanyone ++# ++## uncomment the following line for simple testing of radlogin ++## with freeradius-server ++# ++#localhost/localhost testing123 +diff --git a/src/plugins/vbng/include/freeradius-client.h b/src/plugins/vbng/include/freeradius-client.h +new file mode 100644 +index 00000000..96c75460 +--- /dev/null ++++ b/src/plugins/vbng/include/freeradius-client.h +@@ -0,0 +1,528 @@ ++/* ++ * $Id: freeradius-client.h,v 1.18 2010/06/15 09:22:51 aland Exp $ ++ * ++ * Copyright (C) 1995,1996,1997,1998 Lars Fenneberg ++ * ++ * Copyright 1992 Livingston Enterprises, Inc. ++ * ++ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan ++ * and Merit Network, Inc. All Rights Reserved ++ * ++ * See the file COPYRIGHT for the respective terms and conditions. ++ * If the file is missing contact me at lf@elemental.net ++ * and I'll send you a copy. ++ * ++ */ ++ ++#ifndef FREERADIUS_CLIENT_H ++#define FREERADIUS_CLIENT_H ++ ++#ifdef CP_DEBUG ++#define DEBUG(args, ...) rc_log(## args) ++#else ++#define DEBUG(args, ...) ; ++#endif ++ ++#include <sys/types.h> ++/* ++ * Include for C99 uintX_t defines is stdint.h on most systems. Solaris uses ++ * inttypes.h instead. Comment out the stdint include if you get an error, ++ * and uncomment the inttypes.h include. ++ */ ++#include <stdint.h> ++/* #include <inttypes.h> */ ++#include <stdio.h> ++#include <time.h> ++ ++#undef __BEGIN_DECLS ++#undef __END_DECLS ++#ifdef __cplusplus ++# define __BEGIN_DECLS extern "C" { ++# define __END_DECLS } ++#else ++# define __BEGIN_DECLS /* empty */ ++# define __END_DECLS /* empty */ ++#endif ++ ++#define AUTH_VECTOR_LEN 16 ++#define AUTH_PASS_LEN (3 * 16) /* multiple of 16 */ ++#define AUTH_ID_LEN 64 ++#define AUTH_STRING_LEN 253 /* maximum of 253 */ ++ ++#define BUFFER_LEN 8192 ++ ++#define NAME_LENGTH 32 ++#define GETSTR_LENGTH 128 /* must be bigger than AUTH_PASS_LEN */ ++ ++#define MAX_SECRET_LENGTH (3 * 16) /* MUST be multiple of 16 */ ++ ++#define VENDOR(x) (((x) >> 16) & 0xffff) ++#define ATTRID(x) ((x) & 0xffff) ++ ++#define PW_MAX_MSG_SIZE 4096 ++ ++/* codes for radius_buildreq, radius_getport, etc. */ ++#define AUTH 0 ++#define ACCT 1 ++ ++/* defines for config.c */ ++ ++#define SERVER_MAX 8 ++ ++#define AUTH_LOCAL_FST (1<<0) ++#define AUTH_RADIUS_FST (1<<1) ++#define AUTH_LOCAL_SND (1<<2) ++#define AUTH_RADIUS_SND (1<<3) ++ ++typedef struct server { ++ int max; ++ char *name[SERVER_MAX]; ++ uint16_t port[SERVER_MAX]; ++ char *secret[SERVER_MAX]; ++ double deadtime_ends[SERVER_MAX]; ++} SERVER; ++ ++typedef struct pw_auth_hdr ++{ ++ uint8_t code; ++ uint8_t id; ++ uint16_t length; ++ uint8_t vector[AUTH_VECTOR_LEN]; ++ uint8_t data[2]; ++} AUTH_HDR; ++ ++struct rc_conf ++{ ++ struct _option *config_options; ++ uint32_t this_host_ipaddr; ++ uint32_t *this_host_bind_ipaddr; ++ struct map2id_s *map2id_list; ++ struct dict_attr *dictionary_attributes; ++ struct dict_value *dictionary_values; ++ struct dict_vendor *dictionary_vendors; ++ char buf[GETSTR_LENGTH]; ++ char buf1[14]; ++ char ifname[512]; ++}; ++ ++typedef struct rc_conf rc_handle; ++ ++#define AUTH_HDR_LEN 20 ++#define CHAP_VALUE_LENGTH 16 ++ ++#define PW_AUTH_UDP_PORT 1645 ++#define PW_ACCT_UDP_PORT 1646 ++ ++#define PW_TYPE_STRING 0 ++#define PW_TYPE_INTEGER 1 ++#define PW_TYPE_IPADDR 2 ++#define PW_TYPE_DATE 3 ++#define PW_TYPE_IPV6ADDR 4 ++#define PW_TYPE_IPV6PREFIX 5 ++ ++/* standard RADIUS codes */ ++ ++#define PW_ACCESS_REQUEST 1 ++#define PW_ACCESS_ACCEPT 2 ++#define PW_ACCESS_REJECT 3 ++#define PW_ACCOUNTING_REQUEST 4 ++#define PW_ACCOUNTING_RESPONSE 5 ++#define PW_ACCOUNTING_STATUS 6 ++#define PW_PASSWORD_REQUEST 7 ++#define PW_PASSWORD_ACK 8 ++#define PW_PASSWORD_REJECT 9 ++#define PW_ACCOUNTING_MESSAGE 10 ++#define PW_ACCESS_CHALLENGE 11 ++#define PW_STATUS_SERVER 12 ++#define PW_STATUS_CLIENT 13 ++ ++ ++/* standard RADIUS attribute-value pairs */ ++ ++#define PW_USER_NAME 1 /* string */ ++#define PW_USER_PASSWORD 2 /* string */ ++#define PW_CHAP_PASSWORD 3 /* string */ ++#define PW_NAS_IP_ADDRESS 4 /* ipaddr */ ++#define PW_NAS_PORT 5 /* integer */ ++#define PW_SERVICE_TYPE 6 /* integer */ ++#define PW_FRAMED_PROTOCOL 7 /* integer */ ++#define PW_FRAMED_IP_ADDRESS 8 /* ipaddr */ ++#define PW_FRAMED_IP_NETMASK 9 /* ipaddr */ ++#define PW_FRAMED_ROUTING 10 /* integer */ ++#define PW_FILTER_ID 11 /* string */ ++#define PW_FRAMED_MTU 12 /* integer */ ++#define PW_FRAMED_COMPRESSION 13 /* integer */ ++#define PW_LOGIN_IP_HOST 14 /* ipaddr */ ++#define PW_LOGIN_SERVICE 15 /* integer */ ++#define PW_LOGIN_PORT 16 /* integer */ ++#define PW_OLD_PASSWORD 17 /* string */ /* deprecated */ ++#define PW_REPLY_MESSAGE 18 /* string */ ++#define PW_LOGIN_CALLBACK_NUMBER 19 /* string */ ++#define PW_FRAMED_CALLBACK_ID 20 /* string */ ++#define PW_EXPIRATION 21 /* date */ /* deprecated */ ++#define PW_FRAMED_ROUTE 22 /* string */ ++#define PW_FRAMED_IPX_NETWORK 23 /* integer */ ++#define PW_STATE 24 /* string */ ++#define PW_CLASS 25 /* string */ ++#define PW_VENDOR_SPECIFIC 26 /* string */ ++#define PW_SESSION_TIMEOUT 27 /* integer */ ++#define PW_IDLE_TIMEOUT 28 /* integer */ ++#define PW_TERMINATION_ACTION 29 /* integer */ ++#define PW_CALLED_STATION_ID 30 /* string */ ++#define PW_CALLING_STATION_ID 31 /* string */ ++#define PW_NAS_IDENTIFIER 32 /* string */ ++#define PW_PROXY_STATE 33 /* string */ ++#define PW_LOGIN_LAT_SERVICE 34 /* string */ ++#define PW_LOGIN_LAT_NODE 35 /* string */ ++#define PW_LOGIN_LAT_GROUP 36 /* string */ ++#define PW_FRAMED_APPLETALK_LINK 37 /* integer */ ++#define PW_FRAMED_APPLETALK_NETWORK 38 /* integer */ ++#define PW_FRAMED_APPLETALK_ZONE 39 /* string */ ++#define PW_EVENT_TIMESTAMP 55 /* integer */ ++#define PW_CHAP_CHALLENGE 60 /* string */ ++#define PW_NAS_PORT_TYPE 61 /* integer */ ++#define PW_PORT_LIMIT 62 /* integer */ ++#define PW_LOGIN_LAT_PORT 63 /* string */ ++#define PW_CONNECT_INFO 77 /* string */ ++#define PW_MESSAGE_AUTHENTICATOR 80 /* string */ ++ ++/* RFC3162 IPv6 attributes */ ++ ++#define PW_NAS_IPV6_ADDRESS 95 /* string */ ++#define PW_FRAMED_INTERFACE_ID 96 /* string */ ++#define PW_FRAMED_IPV6_PREFIX 97 /* string */ ++#define PW_LOGIN_IPV6_HOST 98 /* string */ ++#define PW_FRAMED_IPV6_ROUTE 99 /* string */ ++#define PW_FRAMED_IPV6_POOL 100 /* string */ ++ ++/* RFC6911 IPv6 attributes */ ++#define PW_FRAMED_IPV6_ADDRESS 168 /* ipaddr6 */ ++#define PW_DNS_SERVER_IPV6_ADDRESS 169 /* ipaddr6 */ ++#define PW_ROUTE_IPV6_INFORMATION 170 /* ipv6prefix */ ++ ++/* Accounting */ ++ ++#define PW_ACCT_STATUS_TYPE 40 /* integer */ ++#define PW_ACCT_DELAY_TIME 41 /* integer */ ++#define PW_ACCT_INPUT_OCTETS 42 /* integer */ ++#define PW_ACCT_OUTPUT_OCTETS 43 /* integer */ ++#define PW_ACCT_SESSION_ID 44 /* string */ ++#define PW_ACCT_AUTHENTIC 45 /* integer */ ++#define PW_ACCT_SESSION_TIME 46 /* integer */ ++#define PW_ACCT_INPUT_PACKETS 47 /* integer */ ++#define PW_ACCT_OUTPUT_PACKETS 48 /* integer */ ++#define PW_ACCT_TERMINATE_CAUSE 49 /* integer */ ++#define PW_ACCT_MULTI_SESSION_ID 50 /* string */ ++#define PW_ACCT_LINK_COUNT 51 /* integer */ ++#define PW_ACCT_INPUT_GIGAWORDS 52 /* integer */ ++#define PW_ACCT_OUTPUT_GIGAWORDS 53 /* integer */ ++ ++/* Experimental SIP-specific attributes (draft-sterman-aaa-sip-00.txt etc) */ ++ ++#define PW_DIGEST_RESPONSE 206 /* string */ ++#define PW_DIGEST_ATTRIBUTES 207 /* string */ ++#define PW_DIGEST_REALM 1063 /* string */ ++#define PW_DIGEST_NONCE 1064 /* string */ ++#define PW_DIGEST_METHOD 1065 /* string */ ++#define PW_DIGEST_URI 1066 /* string */ ++#define PW_DIGEST_QOP 1067 /* string */ ++#define PW_DIGEST_ALGORITHM 1068 /* string */ ++#define PW_DIGEST_BODY_DIGEST 1069 /* string */ ++#define PW_DIGEST_CNONCE 1070 /* string */ ++#define PW_DIGEST_NONCE_COUNT 1071 /* string */ ++#define PW_DIGEST_USER_NAME 1072 /* string */ ++ ++/* Merit Experimental Extensions */ ++ ++#define PW_USER_ID 222 /* string */ ++#define PW_USER_REALM 223 /* string */ ++ ++/* Integer Translations */ ++ ++/* SERVICE TYPES */ ++ ++#define PW_LOGIN 1 ++#define PW_FRAMED 2 ++#define PW_CALLBACK_LOGIN 3 ++#define PW_CALLBACK_FRAMED 4 ++#define PW_OUTBOUND 5 ++#define PW_ADMINISTRATIVE 6 ++#define PW_NAS_PROMPT 7 ++#define PW_AUTHENTICATE_ONLY 8 ++#define PW_CALLBACK_NAS_PROMPT 9 ++ ++/* FRAMED PROTOCOLS */ ++ ++#define PW_PPP 1 ++#define PW_SLIP 2 ++#define PW_ARA 3 ++#define PW_GANDALF 4 ++#define PW_XYLOGICS 5 ++ ++/* FRAMED ROUTING VALUES */ ++ ++#define PW_NONE 0 ++#define PW_BROADCAST 1 ++#define PW_LISTEN 2 ++#define PW_BROADCAST_LISTEN 3 ++ ++/* FRAMED COMPRESSION TYPES */ ++ ++#define PW_VAN_JACOBSON_TCP_IP 1 ++#define PW_IPX_HEADER_COMPRESSION 2 ++ ++/* LOGIN SERVICES */ ++ ++#define PW_TELNET 0 ++#define PW_RLOGIN 1 ++#define PW_TCP_CLEAR 2 ++#define PW_PORTMASTER 3 ++#define PW_LAT 4 ++#define PW_X25_PAD 5 ++#define PW_X25_T3POS 6 ++ ++/* TERMINATION ACTIONS */ ++ ++#define PW_DEFAULT 0 ++#define PW_RADIUS_REQUEST 1 ++ ++/* PROHIBIT PROTOCOL */ ++ ++#define PW_DUMB 0 /* 1 and 2 are defined in FRAMED PROTOCOLS */ ++#define PW_AUTH_ONLY 3 ++#define PW_ALL 255 ++ ++/* ACCOUNTING STATUS TYPES */ ++ ++#define PW_STATUS_START 1 ++#define PW_STATUS_STOP 2 ++#define PW_STATUS_ALIVE 3 ++#define PW_STATUS_MODEM_START 4 ++#define PW_STATUS_MODEM_STOP 5 ++#define PW_STATUS_CANCEL 6 ++#define PW_ACCOUNTING_ON 7 ++#define PW_ACCOUNTING_OFF 8 ++ ++/* ACCOUNTING TERMINATION CAUSES */ ++ ++#define PW_USER_REQUEST 1 ++#define PW_LOST_CARRIER 2 ++#define PW_LOST_SERVICE 3 ++#define PW_ACCT_IDLE_TIMEOUT 4 ++#define PW_ACCT_SESSION_TIMEOUT 5 ++#define PW_ADMIN_RESET 6 ++#define PW_ADMIN_REBOOT 7 ++#define PW_PORT_ERROR 8 ++#define PW_NAS_ERROR 9 ++#define PW_NAS_REQUEST 10 ++#define PW_NAS_REBOOT 11 ++#define PW_PORT_UNNEEDED 12 ++#define PW_PORT_PREEMPTED 13 ++#define PW_PORT_SUSPENDED 14 ++#define PW_SERVICE_UNAVAILABLE 15 ++#define PW_CALLBACK 16 ++#define PW_USER_ERROR 17 ++#define PW_HOST_REQUEST 18 ++ ++/* NAS PORT TYPES */ ++ ++#define PW_ASYNC 0 ++#define PW_SYNC 1 ++#define PW_ISDN_SYNC 2 ++#define PW_ISDN_SYNC_V120 3 ++#define PW_ISDN_SYNC_V110 4 ++#define PW_VIRTUAL 5 ++ ++/* AUTHENTIC TYPES */ ++#define PW_RADIUS 1 ++#define PW_LOCAL 2 ++#define PW_REMOTE 3 ++ ++/* Server data structures */ ++ ++typedef struct dict_attr ++{ ++ char name[NAME_LENGTH + 1]; /* attribute name */ ++ int value; /* attribute index */ ++ int type; /* string, int, etc. */ ++ struct dict_attr *next; ++} DICT_ATTR; ++ ++typedef struct dict_value ++{ ++ char attrname[NAME_LENGTH +1]; ++ char name[NAME_LENGTH + 1]; ++ int value; ++ struct dict_value *next; ++} DICT_VALUE; ++ ++typedef struct dict_vendor ++{ ++ char vendorname[NAME_LENGTH +1]; ++ int vendorpec; ++ struct dict_vendor *next; ++} DICT_VENDOR; ++ ++typedef struct value_pair ++{ ++ char name[NAME_LENGTH + 1]; ++ int attribute; ++ int type; ++ uint32_t lvalue; ++ char strvalue[AUTH_STRING_LEN + 1]; ++ struct value_pair *next; ++} VALUE_PAIR; ++ ++/* don't change this, as it has to be the same as in the Merit radiusd code */ ++#define MGMT_POLL_SECRET "Hardlyasecret" ++ ++/* Define return codes from "SendServer" utility */ ++ ++#define BADRESP_RC -2 ++#define ERROR_RC -1 ++#define OK_RC 0 ++#define TIMEOUT_RC 1 ++#define REJECT_RC 2 ++ ++typedef struct send_data /* Used to pass information to sendserver() function */ ++{ ++ uint8_t code; /* RADIUS packet code */ ++ uint8_t seq_nbr; /* Packet sequence number */ ++ char *server; /* Name/addrress of RADIUS server */ ++ int svc_port; /* RADIUS protocol destination port */ ++ char *secret; /* Shared secret of RADIUS server */ ++ int timeout; /* Session timeout in seconds */ ++ int retries; ++ VALUE_PAIR *send_pairs; /* More a/v pairs to send */ ++ VALUE_PAIR *receive_pairs; /* Where to place received a/v pairs */ ++} SEND_DATA; ++ ++#ifndef MIN ++#define MIN(a, b) ((a) < (b) ? (a) : (b)) ++#endif ++#ifndef MAX ++#define MAX(a, b) ((a) > (b) ? (a) : (b)) ++#endif ++ ++#ifndef PATH_MAX ++#define PATH_MAX 1024 ++#endif ++ ++typedef struct env ++{ ++ int maxsize, size; ++ char **env; ++} ENV; ++ ++#define ENV_SIZE 128 ++ ++__BEGIN_DECLS ++ ++/* Function prototypes */ ++ ++/* avpair.c */ ++ ++VALUE_PAIR *rc_avpair_add(rc_handle const *, VALUE_PAIR **, int, void const *, int, int); ++int rc_avpair_assign(VALUE_PAIR *, void const *, int); ++VALUE_PAIR *rc_avpair_new(rc_handle const *, int, void const *, int, int); ++VALUE_PAIR *rc_avpair_gen(rc_handle const *, VALUE_PAIR *, unsigned char const *, int, int); ++VALUE_PAIR *rc_avpair_get(VALUE_PAIR *, int, int); ++void rc_avpair_insert(VALUE_PAIR **, VALUE_PAIR *, VALUE_PAIR *); ++void rc_avpair_free(VALUE_PAIR *); ++int rc_avpair_parse(rc_handle const *, char const *, VALUE_PAIR **); ++int rc_avpair_tostr(rc_handle const *, VALUE_PAIR *, char *, int, char *, int); ++char *rc_avpair_log(rc_handle const *, VALUE_PAIR *, char *buf, size_t buf_len); ++VALUE_PAIR *rc_avpair_readin(rc_handle const *, FILE *); ++ ++/* buildreq.c */ ++ ++void rc_buildreq(rc_handle const *, SEND_DATA *, int, char *, unsigned short, char *, int, int); ++unsigned char rc_get_id(); ++int rc_auth(rc_handle *, uint32_t, VALUE_PAIR *, VALUE_PAIR **, char *); ++int rc_auth_proxy(rc_handle *, VALUE_PAIR *, VALUE_PAIR **, char *); ++int rc_acct(rc_handle *, uint32_t, VALUE_PAIR *); ++int rc_acct_proxy(rc_handle *, VALUE_PAIR *); ++int rc_check(rc_handle *, char *, char *, unsigned short, char *); ++ ++int rc_aaa(rc_handle *rh, uint32_t client_port, VALUE_PAIR *send, VALUE_PAIR **received, ++ char *msg, int add_nas_port, int request_type); ++ ++/* clientid.c */ ++ ++int rc_read_mapfile(rc_handle *, char const *); ++uint32_t rc_map2id(rc_handle const *, char const *); ++void rc_map2id_free(rc_handle *); ++ ++/* config.c */ ++ ++rc_handle *rc_read_config(char const *); ++char *rc_conf_str(rc_handle const *, char const *); ++int rc_conf_int(rc_handle const *, char const *); ++SERVER *rc_conf_srv(rc_handle const *, char const *); ++int rc_find_server(rc_handle const *, char const *, uint32_t *, char *); ++void rc_config_free(rc_handle *); ++int rc_add_config(rc_handle *, char const *, char const *, char const *, int); ++rc_handle *rc_config_init(rc_handle *); ++int test_config(rc_handle const *, char const *); ++ ++/* dict.c */ ++ ++int rc_read_dictionary(rc_handle *, char const *); ++DICT_ATTR *rc_dict_getattr(rc_handle const *, int); ++DICT_ATTR *rc_dict_findattr(rc_handle const *, char const *); ++DICT_VALUE *rc_dict_findval(rc_handle const *, char const *); ++DICT_VENDOR *rc_dict_findvend(rc_handle const *, char const *); ++DICT_VENDOR *rc_dict_getvend(rc_handle const *, int); ++DICT_VALUE * rc_dict_getval(rc_handle const *, uint32_t, char const *); ++void rc_dict_free(rc_handle *); ++ ++/* ip_util.c */ ++ ++struct hostent *rc_gethostbyname(char const *); ++struct hostent *rc_gethostbyaddr(char const *, size_t, int); ++uint32_t rc_get_ipaddr(char const *); ++int rc_good_ipaddr(char const *); ++char const *rc_ip_hostname(uint32_t); ++unsigned short rc_getport(int); ++int rc_own_hostname(char *, int); ++uint32_t rc_own_ipaddress(rc_handle *); ++uint32_t rc_own_bind_ipaddress(rc_handle *); ++struct sockaddr; ++int rc_get_srcaddr(struct sockaddr *, struct sockaddr *); ++ ++ ++/* log.c */ ++ ++void rc_openlog(char const *); ++void rc_log(int, char const *, ...); ++ ++/* sendserver.c */ ++ ++int rc_send_server(rc_handle *, SEND_DATA *, char *); ++ ++/* util.c */ ++ ++void rc_str2tm(char const *, struct tm *); ++char *rc_getifname(rc_handle *, char const *); ++char *rc_getstr(rc_handle *, char const *, int); ++void rc_mdelay(int); ++char *rc_mksid(rc_handle *); ++rc_handle *rc_new(void); ++void rc_destroy(rc_handle *); ++char *rc_fgetln(FILE *, size_t *); ++double rc_getctime(void); ++ ++/* env.c */ ++ ++struct env *rc_new_env(int); ++void rc_free_env(struct env *); ++int rc_add_env(struct env *, char const *, char const *); ++int rc_import_env(struct env *, char const **); ++ ++/* md5.c */ ++ ++void rc_md5_calc(unsigned char *, unsigned char const *, unsigned int); ++ ++__END_DECLS ++ ++#endif /* FREERADIUS_CLIENT_H */ +diff --git a/src/plugins/vbng/include/includes.h b/src/plugins/vbng/include/includes.h +new file mode 100644 +index 00000000..908f0e74 +--- /dev/null ++++ b/src/plugins/vbng/include/includes.h +@@ -0,0 +1,182 @@ ++/* ++ * $Id: includes.h,v 1.6 2007/06/21 18:07:22 cparker Exp $ ++ * ++ * Copyright (C) 1997 Lars Fenneberg ++ * ++ * Copyright 1992 Livingston Enterprises, Inc. ++ * ++ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan ++ * and Merit Network, Inc. All Rights Reserved ++ * ++ * See the file COPYRIGHT for the respective terms and conditions. ++ * If the file is missing contact me at lf@elemental.net ++ * and I'll send you a copy. ++ * ++ */ ++ ++#include "config.h" ++ ++/* AIX requires this to be the first thing in the file. */ ++#ifndef __GNUC__ ++# if HAVE_ALLOCA_H ++# include <alloca.h> ++# else ++# ifdef _AIX ++# pragma alloca ++# else ++# ifndef alloca /* predefined by HP cc +Olibcalls */ ++ char *alloca (); ++# endif ++# endif ++# endif ++#endif ++ ++#include <sys/types.h> ++ ++#include <ctype.h> ++#include <stdio.h> ++#include <errno.h> ++ ++#ifdef HAVE_NETDB_H ++#include <netdb.h> ++#endif ++ ++#ifdef HAVE_SYSLOG_H ++#include <syslog.h> ++#endif ++ ++#ifdef STDC_HEADERS ++# include <stdlib.h> ++# include <string.h> ++# include <stdarg.h> ++#else ++# include <stdarg.h> ++# ifndef HAVE_STRCHR ++# define strchr index ++# define strrchr rindex ++# endif ++#endif ++ ++/* I realize that this is ugly and unsafe.. :( */ ++#ifndef HAVE_SNPRINTF ++# define snprintf(buf, len, format, ...) sprintf(buf, format, __VA_ARGS__) ++#endif ++#ifndef HAVE_VSNPRINTF ++# define vsnprintf(buf, len, format, ap) vsprintf(buf, format, ap) ++#endif ++ ++#ifdef HAVE_UNISTD_H ++# include <unistd.h> ++#endif /* HAVE_UNISTD_H */ ++ ++#ifdef HAVE_FCNTL_H ++# include <fcntl.h> ++#endif ++ ++#ifdef HAVE_SYS_FCNTL_H ++# include <sys/fcntl.h> ++#endif ++ ++#ifdef HAVE_SYS_FILE_H ++# include <sys/file.h> ++#endif ++ ++#ifdef HAVE_SYS_STAT_H ++# include <sys/stat.h> ++#endif ++ ++#ifdef HAVE_SYS_UTSNAME_H ++# include <sys/utsname.h> ++#endif ++ ++#ifdef HAVE_SYS_IOCTL_H ++# include <sys/ioctl.h> ++#endif ++ ++#ifdef HAVE_CRYPT_H ++# include <crypt.h> ++#endif ++ ++#ifdef HAVE_LIMITS_H ++# include <limits.h> ++#endif ++ ++#ifdef HAVE_TERMIOS_H ++# include <termios.h> ++#endif ++ ++#ifndef PATH_MAX ++#define PATH_MAX 1024 ++#endif ++ ++#ifndef UCHAR_MAX ++# ifdef __STDC__ ++# define UCHAR_MAX 255U ++# else ++# define UCHAR_MAX 255 ++# endif ++#endif ++ ++#ifdef HAVE_PWD_H ++#include <pwd.h> ++#endif ++ ++#ifdef HAVE_SYS_SOCKET_H ++#include <sys/socket.h> ++#endif ++ ++#ifdef HAVE_NETINET_IN_H ++#include <netinet/in.h> ++#endif ++ ++#ifdef HAVE_ARPA_INET_H ++#include <arpa/inet.h> ++#endif ++ ++#if defined(HAVE_SIGNAL_H) ++# include <signal.h> ++#endif ++#if defined(HAVE_SYS_SIGNAL_H) ++# include <sys/signal.h> ++#endif ++ ++#ifdef NEED_SIG_PROTOTYPES ++int sigemptyset(sigset_t *); ++int sigaddset(sigset_t *, int); ++int sigprocmask (int, sigset_t *, sigset_t *); ++#endif ++ ++#if HAVE_GETOPT_H ++# include <getopt.h> ++#endif ++ ++#if defined(HAVE_SHADOW_H) && defined(HAVE_SHADOW_PASSWORDS) ++# include <shadow.h> ++#endif ++ ++#if TIME_WITH_SYS_TIME ++# include <sys/time.h> ++# include <time.h> ++#else ++# if HAVE_SYS_TIME_H ++# include <sys/time.h> ++# else ++# include <time.h> ++# endif ++#endif ++ ++/* ++ * prefer srandom/random over srand/rand as there generator has a ++ * better distribution of the numbers on certain systems. ++ * on Linux both generators are identical. ++ */ ++#ifndef HAVE_RANDOM ++# ifdef HAVE_RAND ++# define srandom srand ++# define random rand ++# endif ++#endif ++ ++/* rlib/lock.c */ ++int do_lock_exclusive(FILE *); ++int do_unlock(FILE *); +diff --git a/src/plugins/vbng/include/messages.h b/src/plugins/vbng/include/messages.h +new file mode 100644 +index 00000000..9a5f0e81 +--- /dev/null ++++ b/src/plugins/vbng/include/messages.h +@@ -0,0 +1,53 @@ ++/* ++ * $Id: messages.h,v 1.2 2004/02/23 20:10:39 sobomax Exp $ ++ * ++ * Copyright (C) 1995,1996 Lars Fenneberg ++ * ++ * Copyright 1992 Livingston Enterprises, Inc. ++ * ++ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan ++ * and Merit Network, Inc. All Rights Reserved ++ * ++ * See the file COPYRIGHT for the respective terms and conditions. ++ * If the file is missing contact me at lf@elemental.net ++ * and I'll send you a copy. ++ * ++ */ ++ ++/* ++ * Only messages that the user gets under normal use are in here. ++ * Error messages and such are still in the source code. ++ */ ++ ++#ifndef MESSAGES_H ++#define MESSAGES_H ++ ++/* radlogin.c */ ++ ++#define SC_LOGIN "login: " ++#define SC_PASSWORD "Password: " ++ ++#define SC_TIMEOUT "\r\nlogin timed out after %d seconds. Bye.\r\n" ++#define SC_EXCEEDED "Maximum login tries exceeded. Go away!\r\n" ++ ++#define SC_RADIUS_OK "RADIUS: Authentication OK\r\n" ++#define SC_RADIUS_FAILED "RADIUS: Authentication failure\r\n" ++ ++#define SC_LOCAL_OK "local: Authentication OK\r\n" ++#define SC_LOCAL_FAILED "local: Authentication failure\r\n" ++#define SC_NOLOGIN "\r\nSystem closed for maintenance. Try again later...\r\n" ++ ++#define SC_SERVER_REPLY "RADIUS: %s" ++ ++#define SC_DEFAULT_ISSUE "(\\I)\r\n\r\n\\S \\R (\\N) (port \\L)\r\n\r\n" ++ ++/* radacct.c */ ++ ++#define SC_ACCT_OK "RADIUS accounting OK\r\n" ++#define SC_ACCT_FAILED "RADIUS accounting failed (RC=%i)\r\n" ++ ++/* radstatus.c */ ++ ++#define SC_STATUS_FAILED "RADIUS: Status failure\r\n" ++ ++#endif /* MESSAGES_H */ +diff --git a/src/plugins/vbng/include/pathnames.h b/src/plugins/vbng/include/pathnames.h +new file mode 100644 +index 00000000..0256d473 +--- /dev/null ++++ b/src/plugins/vbng/include/pathnames.h +@@ -0,0 +1,28 @@ ++/* ++ * $Id: pathnames.h,v 1.2 2004/02/23 20:10:39 sobomax Exp $ ++ * ++ * Copyright (C) 1995,1996 Lars Fenneberg ++ * ++ * Copyright 1992 Livingston Enterprises, Inc. ++ * ++ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan ++ * and Merit Network, Inc. All Rights Reserved ++ * ++ * See the file COPYRIGHT for the respective terms and conditions. ++ * If the file is missing contact me at lf@elemental.net ++ * and I'll send you a copy. ++ * ++ */ ++ ++#ifndef PATHNAMES_H ++#define PATHNAMES_H ++ ++#define _PATH_DEV_URANDOM "/dev/urandom" /* Linux only */ ++#define _PATH_ETC_ISSUE "/etc/issue" ++ ++/* normally defined in the Makefile */ ++#ifndef _PATH_ETC_RADIUSCLIENT_CONF ++#define _PATH_ETC_RADIUSCLIENT_CONF "/etc/radiusclient.conf" ++#endif ++ ++#endif /* PATHNAMES_H */ +diff --git a/src/plugins/vbng/lib/avpair.c b/src/plugins/vbng/lib/avpair.c +new file mode 100644 +index 00000000..8ce2a8ec +--- /dev/null ++++ b/src/plugins/vbng/lib/avpair.c +@@ -0,0 +1,874 @@ ++/* ++ * $Id: avpair.c,v 1.26 2010/06/15 09:22:52 aland Exp $ ++ * ++ * Copyright (C) 1995 Lars Fenneberg ++ * ++ * Copyright 1992 Livingston Enterprises, Inc. ++ * ++ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan ++ * and Merit Network, Inc. All Rights Reserved ++ * ++ * See the file COPYRIGHT for the respective terms and conditions. ++ * If the file is missing contact me at lf@elemental.net ++ * and I'll send you a copy. ++ * ++ */ ++ ++#include <config.h> ++#include <includes.h> ++#include <freeradius-client.h> ++ ++/* ++ * Function: rc_avpair_add ++ * ++ * Purpose: add an attribute-value pair to the given list. ++ * ++ * Returns: pointer to added a/v pair upon success, NULL pointer upon failure. ++ * ++ * Remarks: Always appends the new pair to the end of the list. ++ * ++ */ ++ ++VALUE_PAIR *rc_avpair_add (rc_handle const *rh, VALUE_PAIR **list, int attrid, void const *pval, int len, int vendorpec) ++{ ++ VALUE_PAIR *vp; ++ ++ vp = rc_avpair_new (rh, attrid, pval, len, vendorpec); ++ ++ if (vp != NULL) ++ { ++ rc_avpair_insert (list, NULL, vp); ++ } ++ ++ return vp; ++ ++} ++ ++/* ++ * Function: rc_avpair_assign ++ * ++ * Purpose: assign the given value to an attribute-value pair. ++ * ++ * Returns: 0 on success, ++ * -1 on failure. ++ * ++ */ ++ ++int rc_avpair_assign (VALUE_PAIR *vp, void const *pval, int len) ++{ ++ ++ switch (vp->type) ++ { ++ case PW_TYPE_STRING: ++ if (len == -1) ++ len = (uint32_t)strlen((char const *)pval); ++ if (len > AUTH_STRING_LEN) { ++ rc_log(LOG_ERR, "rc_avpair_assign: bad attribute length"); ++ return -1; ++ } ++ memcpy(vp->strvalue, (char const *)pval, len); ++ vp->strvalue[len] = '\0'; ++ vp->lvalue = len; ++ break; ++ ++ case PW_TYPE_DATE: ++ case PW_TYPE_INTEGER: ++ case PW_TYPE_IPADDR: ++ vp->lvalue = * (uint32_t *) pval; ++ break; ++ case PW_TYPE_IPV6ADDR: ++ if (len != 16) { ++ rc_log(LOG_ERR, "rc_avpair_assign: bad IPv6 length"); ++ return -1; ++ } ++ memcpy(vp->strvalue, (char const *)pval, len); ++ vp->lvalue = len; ++ break; ++ ++ case PW_TYPE_IPV6PREFIX: ++ if (len < 2 || len > 18) { ++ rc_log(LOG_ERR, "rc_avpair_assign: bad IPv6 prefix length"); ++ return -1; ++ } ++ memcpy(vp->strvalue, (char const *)pval, len); ++ vp->lvalue = len; ++ break; ++ ++ default: ++ rc_log(LOG_ERR, "rc_avpair_assign: unknown attribute %d", vp->type); ++ return -1; ++ } ++ return 0; ++} ++ ++/* ++ * Function: rc_avpair_new ++ * ++ * Purpose: make a new attribute-value pair with given parameters. ++ * ++ * Returns: pointer to generated a/v pair when successful, NULL when failure. ++ * ++ */ ++ ++VALUE_PAIR *rc_avpair_new (rc_handle const *rh, int attrid, void const *pval, int len, int vendorpec) ++{ ++ VALUE_PAIR *vp = NULL; ++ DICT_ATTR *pda; ++ ++ attrid = attrid | (vendorpec << 16); ++ if ((pda = rc_dict_getattr (rh, attrid)) == NULL) ++ { ++ rc_log(LOG_ERR,"rc_avpair_new: unknown attribute %d", attrid); ++ return NULL; ++ } ++ if (vendorpec != 0 && rc_dict_getvend(rh, vendorpec) == NULL) ++ { ++ rc_log(LOG_ERR,"rc_avpair_new: unknown Vendor-Id %d", vendorpec); ++ return NULL; ++ } ++ if ((vp = malloc (sizeof (VALUE_PAIR))) != NULL) ++ { ++ strncpy (vp->name, pda->name, sizeof (vp->name)); ++ vp->attribute = attrid; ++ vp->next = NULL; ++ vp->type = pda->type; ++ if (rc_avpair_assign (vp, pval, len) == 0) ++ { ++ /* XXX: Fix up Digest-Attributes */ ++ switch (vp->attribute) { ++ case PW_DIGEST_REALM: ++ case PW_DIGEST_NONCE: ++ case PW_DIGEST_METHOD: ++ case PW_DIGEST_URI: ++ case PW_DIGEST_QOP: ++ case PW_DIGEST_ALGORITHM: ++ case PW_DIGEST_BODY_DIGEST: ++ case PW_DIGEST_CNONCE: ++ case PW_DIGEST_NONCE_COUNT: ++ case PW_DIGEST_USER_NAME: ++ /* overlapping! */ ++ if (vp->lvalue > AUTH_STRING_LEN - 2) ++ vp->lvalue = AUTH_STRING_LEN - 2; ++ memmove(&vp->strvalue[2], &vp->strvalue[0], vp->lvalue); ++ vp->strvalue[0] = vp->attribute - PW_DIGEST_REALM + 1; ++ vp->lvalue += 2; ++ vp->strvalue[1] = vp->lvalue; ++ vp->strvalue[vp->lvalue] = '\0'; ++ vp->attribute = PW_DIGEST_ATTRIBUTES; ++ default: ++ break; ++ } ++ return vp; ++ } ++ free (vp); ++ vp = NULL; ++ } ++ else ++ { ++ rc_log(LOG_CRIT,"rc_avpair_new: out of memory"); ++ } ++ ++ return vp; ++} ++ ++/* ++ * ++ * Function: rc_avpair_gen ++ * ++ * Purpose: takes attribute/value pairs from buffer and builds a ++ * value_pair list using allocated memory. Uses recursion. ++ * ++ * Returns: value_pair list or NULL on failure ++ */ ++ ++VALUE_PAIR * ++rc_avpair_gen(rc_handle const *rh, VALUE_PAIR *pair, unsigned char const *ptr, ++ int length, int vendorpec) ++{ ++ int attribute, attrlen, x_len; ++ unsigned char const *x_ptr; ++ uint32_t lvalue; ++ DICT_ATTR *attr; ++ VALUE_PAIR *rpair; ++ char buffer[(AUTH_STRING_LEN * 2) + 1]; ++ /* For hex string conversion. */ ++ char hex[3]; ++ ++ if (length < 2) { ++ rc_log(LOG_ERR, "rc_avpair_gen: received attribute with " ++ "invalid length"); ++ goto shithappens; ++ } ++ attrlen = ptr[1]; ++ if (length < attrlen || attrlen < 2) { ++ rc_log(LOG_ERR, "rc_avpair_gen: received attribute with " ++ "invalid length"); ++ goto shithappens; ++ } ++ ++ /* Advance to the next attribute and process recursively */ ++ if (length != attrlen) { ++ pair = rc_avpair_gen(rh, pair, ptr + attrlen, length - attrlen, ++ vendorpec); ++ if (pair == NULL) ++ return NULL; ++ } ++ ++ /* Actual processing */ ++ attribute = ptr[0] | (vendorpec << 16); ++ ptr += 2; ++ attrlen -= 2; ++ ++ /* VSA */ ++ if (attribute == PW_VENDOR_SPECIFIC) { ++ if (attrlen < 4) { ++ rc_log(LOG_ERR, "rc_avpair_gen: received VSA " ++ "attribute with invalid length"); ++ goto shithappens; ++ } ++ memcpy(&lvalue, ptr, 4); ++ vendorpec = ntohl(lvalue); ++ if (rc_dict_getvend(rh, vendorpec) == NULL) { ++ /* Warn and skip over the unknown VSA */ ++ rc_log(LOG_WARNING, "rc_avpair_gen: received VSA " ++ "attribute with unknown Vendor-Id %d", vendorpec); ++ return pair; ++ } ++ /* Process recursively */ ++ return rc_avpair_gen(rh, pair, ptr + 4, attrlen - 4, ++ vendorpec); ++ } ++ ++ /* Normal */ ++ attr = rc_dict_getattr(rh, attribute); ++ if (attr == NULL) { ++ buffer[0] = '\0'; /* Initial length. */ ++ x_ptr = ptr; ++ for (x_len = attrlen; x_len > 0; x_len--, x_ptr++) { ++ snprintf(hex, sizeof(hex), "%2.2X", x_ptr[0]); ++ strcat(buffer, hex); ++ } ++ if (vendorpec == 0) { ++ rc_log(LOG_WARNING, "rc_avpair_gen: received " ++ "unknown attribute %d of length %d: 0x%s", ++ attribute, attrlen + 2, buffer); ++ } else { ++ rc_log(LOG_WARNING, "rc_avpair_gen: received " ++ "unknown VSA attribute %d, vendor %d of " ++ "length %d: 0x%s", attribute & 0xffff, ++ VENDOR(attribute), attrlen + 2, buffer); ++ } ++ goto shithappens; ++ } ++ ++ rpair = malloc(sizeof(*rpair)); ++ if (rpair == NULL) { ++ rc_log(LOG_CRIT, "rc_avpair_gen: out of memory"); ++ goto shithappens; ++ } ++ memset(rpair, '\0', sizeof(*rpair)); ++ ++ /* Insert this new pair at the beginning of the list */ ++ rpair->next = pair; ++ pair = rpair; ++ strcpy(pair->name, attr->name); ++ pair->attribute = attr->value; ++ pair->type = attr->type; ++ ++ switch (attr->type) { ++ case PW_TYPE_STRING: ++ memcpy(pair->strvalue, (char *)ptr, (size_t)attrlen); ++ pair->strvalue[attrlen] = '\0'; ++ pair->lvalue = attrlen; ++ break; ++ ++ case PW_TYPE_INTEGER: ++ if (attrlen != 4) { ++ rc_log(LOG_ERR, "rc_avpair_gen: received INT " ++ "attribute with invalid length"); ++ goto shithappens; ++ } ++ case PW_TYPE_IPADDR: ++ if (attrlen != 4) { ++ rc_log(LOG_ERR, "rc_avpair_gen: received IPADDR" ++ " attribute with invalid length"); ++ goto shithappens; ++ } ++ memcpy((char *)&lvalue, (char *)ptr, 4); ++ pair->lvalue = ntohl(lvalue); ++ break; ++ case PW_TYPE_IPV6ADDR: ++ if (attrlen != 16) { ++ rc_log(LOG_ERR, "rc_avpair_gen: received IPV6ADDR" ++ " attribute with invalid length"); ++ goto shithappens; ++ } ++ memcpy(pair->strvalue, (char *)ptr, 16); ++ pair->lvalue = attrlen; ++ break; ++ case PW_TYPE_IPV6PREFIX: ++ if (attrlen > 18 || attrlen < 2) { ++ rc_log(LOG_ERR, "rc_avpair_gen: received IPV6PREFIX" ++ " attribute with invalid length: %d", attrlen); ++ goto shithappens; ++ } ++ memcpy(pair->strvalue, (char *)ptr, attrlen); ++ pair->lvalue = attrlen; ++ break; ++ case PW_TYPE_DATE: ++ if (attrlen != 4) { ++ rc_log(LOG_ERR, "rc_avpair_gen: received DATE " ++ "attribute with invalid length"); ++ goto shithappens; ++ } ++ ++ default: ++ rc_log(LOG_WARNING, "rc_avpair_gen: %s has unknown type", ++ attr->name); ++ goto shithappens; ++ } ++ return pair; ++ ++shithappens: ++ while (pair != NULL) { ++ rpair = pair->next; ++ free(pair); ++ pair = rpair; ++ } ++ return NULL; ++} ++ ++/* ++ * Function: rc_avpair_get ++ * ++ * Purpose: Find the first attribute value-pair (which matches the given ++ * attribute) from the specified value-pair list. ++ * ++ * Returns: found value_pair ++ * ++ */ ++ ++VALUE_PAIR *rc_avpair_get (VALUE_PAIR *vp, int attrid, int vendorpec) ++{ ++ for (; vp != NULL && !(ATTRID(vp->attribute) == ATTRID(attrid) && ++ VENDOR(vp->attribute) == vendorpec); vp = vp->next) ++ { ++ continue; ++ } ++ return vp; ++} ++ ++/* ++ * Function: rc_avpair_insert ++ * ++ * Purpose: Given the address of an existing list "a" and a pointer ++ * to an entry "p" in that list, add the value pair "b" to ++ * the "a" list after the "p" entry. If "p" is NULL, add ++ * the value pair "b" to the end of "a". ++ * ++ */ ++ ++void rc_avpair_insert (VALUE_PAIR **a, VALUE_PAIR *p, VALUE_PAIR *b) ++{ ++ VALUE_PAIR *this_node = NULL; ++ VALUE_PAIR *vp; ++ ++ if (b->next != NULL) ++ { ++ rc_log(LOG_CRIT, "rc_avpair_insert: value pair (0x%p) next ptr. (0x%p) not NULL", b, b->next); ++ abort (); ++ } ++ ++ if (*a == NULL) ++ { ++ *a = b; ++ return; ++ } ++ ++ vp = *a; ++ ++ if ( p == NULL) /* run to end of "a" list */ ++ { ++ while (vp != NULL) ++ { ++ this_node = vp; ++ vp = vp->next; ++ } ++ } ++ else /* look for the "p" entry in the "a" list */ ++ { ++ this_node = *a; ++ while (this_node != NULL) ++ { ++ if (this_node == p) ++ { ++ break; ++ } ++ this_node = this_node->next; ++ } ++ } ++ ++ b->next = this_node->next; ++ this_node->next = b; ++ ++ return; ++} ++ ++/* ++ * Function: rc_avpair_free ++ * ++ * Purpose: frees all value_pairs in the list ++ * ++ */ ++ ++void rc_avpair_free (VALUE_PAIR *pair) ++{ ++ VALUE_PAIR *next; ++ ++ while (pair != NULL) ++ { ++ next = pair->next; ++ free (pair); ++ pair = next; ++ } ++} ++ ++/* ++ * Function: rc_fieldcpy ++ * ++ * Purpose: Copy a data field from the buffer. Advance the buffer ++ * past the data field. Ensure that no more than len - 1 ++ * bytes are copied and that resulting string is terminated ++ * with '\0'. ++ * ++ */ ++ ++static void ++rc_fieldcpy(char *string, char const **uptr, char const *stopat, size_t len) ++{ ++ char const *ptr, *estring; ++ ++ ptr = *uptr; ++ estring = string + len - 1; ++ if (*ptr == '"') ++ { ++ ptr++; ++ while (*ptr != '"' && *ptr != '\0' && *ptr != '\n') ++ { ++ if (string < estring) ++ *string++ = *ptr; ++ ptr++; ++ } ++ if (*ptr == '"') ++ { ++ ptr++; ++ } ++ *string = '\0'; ++ *uptr = ptr; ++ return; ++ } ++ ++ while (*ptr != '\0' && strchr(stopat, *ptr) == NULL) ++ { ++ if (string < estring) ++ *string++ = *ptr; ++ ptr++; ++ } ++ *string = '\0'; ++ *uptr = ptr; ++ return; ++} ++ ++ ++/* ++ * Function: rc_avpair_parse ++ * ++ * Purpose: parses the buffer to extract the attribute-value pairs. ++ * ++ * Returns: 0 = successful parse of attribute-value pair, ++ * -1 = syntax (or other) error detected. ++ * ++ */ ++ ++#define PARSE_MODE_NAME 0 ++#define PARSE_MODE_EQUAL 1 ++#define PARSE_MODE_VALUE 2 ++#define PARSE_MODE_INVALID 3 ++ ++int rc_avpair_parse (rc_handle const *rh, char const *buffer, VALUE_PAIR **first_pair) ++{ ++ int mode; ++ char attrstr[AUTH_ID_LEN]; ++ char valstr[AUTH_STRING_LEN + 1], *p; ++ DICT_ATTR *attr = NULL; ++ DICT_VALUE *dval; ++ VALUE_PAIR *pair; ++ VALUE_PAIR *link; ++ struct tm *tm; ++ time_t timeval; ++ ++ mode = PARSE_MODE_NAME; ++ while (*buffer != '\n' && *buffer != '\0') ++ { ++ if (*buffer == ' ' || *buffer == '\t') ++ { ++ buffer++; ++ continue; ++ } ++ ++ switch (mode) ++ { ++ case PARSE_MODE_NAME: /* Attribute Name */ ++ rc_fieldcpy (attrstr, &buffer, " \t\n=,", sizeof(attrstr)); ++ if ((attr = ++ rc_dict_findattr (rh, attrstr)) == NULL) ++ { ++ rc_log(LOG_ERR, "rc_avpair_parse: unknown attribute"); ++ if (*first_pair) { ++ rc_avpair_free(*first_pair); ++ *first_pair = NULL; ++ } ++ return -1; ++ } ++ mode = PARSE_MODE_EQUAL; ++ break; ++ ++ case PARSE_MODE_EQUAL: /* Equal sign */ ++ if (*buffer == '=') ++ { ++ mode = PARSE_MODE_VALUE; ++ buffer++; ++ } ++ else ++ { ++ rc_log(LOG_ERR, "rc_avpair_parse: missing or misplaced equal sign"); ++ if (*first_pair) { ++ rc_avpair_free(*first_pair); ++ *first_pair = NULL; ++ } ++ return -1; ++ } ++ break; ++ ++ case PARSE_MODE_VALUE: /* Value */ ++ rc_fieldcpy (valstr, &buffer, " \t\n,", sizeof(valstr)); ++ ++ if ((pair = malloc (sizeof (VALUE_PAIR))) == NULL) ++ { ++ rc_log(LOG_CRIT, "rc_avpair_parse: out of memory"); ++ if (*first_pair) { ++ rc_avpair_free(*first_pair); ++ *first_pair = NULL; ++ } ++ return -1; ++ } ++ strcpy (pair->name, attr->name); ++ pair->attribute = attr->value; ++ pair->type = attr->type; ++ ++ switch (pair->type) ++ { ++ ++ case PW_TYPE_STRING: ++ strcpy (pair->strvalue, valstr); ++ pair->lvalue = (uint32_t)strlen(valstr); ++ break; ++ ++ case PW_TYPE_INTEGER: ++ if (isdigit (*valstr)) ++ { ++ pair->lvalue = atoi (valstr); ++ } ++ else ++ { ++ if ((dval = rc_dict_findval (rh, valstr)) ++ == NULL) ++ { ++ rc_log(LOG_ERR, "rc_avpair_parse: unknown attribute value: %s", valstr); ++ if (*first_pair) { ++ rc_avpair_free(*first_pair); ++ *first_pair = NULL; ++ } ++ free (pair); ++ return -1; ++ } ++ else ++ { ++ pair->lvalue = dval->value; ++ } ++ } ++ break; ++ ++ case PW_TYPE_IPADDR: ++ pair->lvalue = rc_get_ipaddr(valstr); ++ break; ++ ++ case PW_TYPE_IPV6ADDR: ++ if (inet_pton(AF_INET6, valstr, pair->strvalue) == 0) { ++ rc_log(LOG_ERR, "rc_avpair_parse: invalid IPv6 address %s", valstr); ++ free(pair); ++ return -1; ++ } ++ pair->lvalue = 16; ++ break; ++ ++ case PW_TYPE_IPV6PREFIX: ++ p = strchr(valstr, '/'); ++ if (p == NULL) { ++ rc_log(LOG_ERR, "rc_avpair_parse: invalid IPv6 prefix %s", valstr); ++ free(pair); ++ return -1; ++ } ++ *p = 0; ++ p++; ++ pair->strvalue[0] = 0; ++ pair->strvalue[1] = atoi(p); ++ ++ if (inet_pton(AF_INET6, valstr, pair->strvalue+2) == 0) { ++ rc_log(LOG_ERR, "rc_avpair_parse: invalid IPv6 prefix %s", valstr); ++ free(pair); ++ return -1; ++ } ++ pair->lvalue = 2+16; ++ break; ++ ++ case PW_TYPE_DATE: ++ timeval = time (0); ++ tm = localtime (&timeval); ++ tm->tm_hour = 0; ++ tm->tm_min = 0; ++ tm->tm_sec = 0; ++ rc_str2tm (valstr, tm); ++#ifdef TIMELOCAL ++ pair->lvalue = (uint32_t) timelocal (tm); ++#else /* TIMELOCAL */ ++ pair->lvalue = (uint32_t) mktime (tm); ++#endif /* TIMELOCAL */ ++ break; ++ ++ default: ++ rc_log(LOG_ERR, "rc_avpair_parse: unknown attribute type %d", pair->type); ++ if (*first_pair) { ++ rc_avpair_free(*first_pair); ++ *first_pair = NULL; ++ } ++ free (pair); ++ return -1; ++ } ++ ++ /* XXX: Fix up Digest-Attributes */ ++ switch (pair->attribute) { ++ case PW_DIGEST_REALM: ++ case PW_DIGEST_NONCE: ++ case PW_DIGEST_METHOD: ++ case PW_DIGEST_URI: ++ case PW_DIGEST_QOP: ++ case PW_DIGEST_ALGORITHM: ++ case PW_DIGEST_BODY_DIGEST: ++ case PW_DIGEST_CNONCE: ++ case PW_DIGEST_NONCE_COUNT: ++ case PW_DIGEST_USER_NAME: ++ /* overlapping! */ ++ if (pair->lvalue > AUTH_STRING_LEN - 2) ++ pair->lvalue = AUTH_STRING_LEN - 2; ++ memmove(&pair->strvalue[2], &pair->strvalue[0], pair->lvalue); ++ pair->strvalue[0] = pair->attribute - PW_DIGEST_REALM + 1; ++ pair->lvalue += 2; ++ pair->strvalue[1] = pair->lvalue; ++ pair->strvalue[pair->lvalue] = '\0'; ++ pair->attribute = PW_DIGEST_ATTRIBUTES; ++ } ++ ++ pair->next = NULL; ++ ++ if (*first_pair == NULL) ++ { ++ *first_pair = pair; ++ } ++ else ++ { ++ link = *first_pair; ++ while (link->next != NULL) ++ { ++ link = link->next; ++ } ++ link->next = pair; ++ } ++ ++ mode = PARSE_MODE_NAME; ++ break; ++ ++ default: ++ mode = PARSE_MODE_NAME; ++ break; ++ } ++ } ++ return 0; ++} ++ ++/* ++ * Function: rc_avpair_tostr ++ * ++ * Purpose: Translate an av_pair into two strings ++ * ++ * Returns: 0 on success, -1 on failure ++ * ++ */ ++ ++int rc_avpair_tostr (rc_handle const *rh, VALUE_PAIR *pair, char *name, int ln, char *value, int lv) ++{ ++ DICT_VALUE *dval; ++ char buffer[32]; ++ struct in_addr inad; ++ unsigned char *ptr; ++ ++ *name = *value = '\0'; ++ ++ if (!pair || pair->name[0] == '\0') { ++ rc_log(LOG_ERR, "rc_avpair_tostr: pair is NULL or empty"); ++ return -1; ++ } ++ ++ strncpy(name, pair->name, (size_t) ln); ++ ++ switch (pair->type) ++ { ++ case PW_TYPE_STRING: ++ lv--; ++ ptr = (unsigned char *) pair->strvalue; ++ if (pair->attribute == PW_DIGEST_ATTRIBUTES) { ++ pair->strvalue[*(ptr + 1)] = '\0'; ++ ptr += 2; ++ } ++ while (*ptr != '\0') ++ { ++ if (!(isprint (*ptr))) ++ { ++ snprintf (buffer, sizeof(buffer), "\\%03o", *ptr); ++ strncat(value, buffer, (size_t) lv); ++ lv -= 4; ++ if (lv < 0) break; ++ } ++ else ++ { ++ strncat(value, (char *)ptr, 1); ++ lv--; ++ if (lv <= 0) break; ++ } ++ ptr++; ++ } ++ break; ++ ++ case PW_TYPE_INTEGER: ++ dval = rc_dict_getval (rh, pair->lvalue, pair->name); ++ if (dval != NULL) ++ { ++ strncpy(value, dval->name, (size_t) lv-1); ++ } ++ else ++ { ++ snprintf(buffer, sizeof(buffer), "%ld", (long int)pair->lvalue); ++ strncpy(value, buffer, (size_t) lv); ++ } ++ break; ++ ++ case PW_TYPE_IPADDR: ++ inad.s_addr = htonl(pair->lvalue); ++ strncpy (value, inet_ntoa (inad), (size_t) lv-1); ++ break; ++ ++ case PW_TYPE_IPV6ADDR: ++ if (inet_ntop(AF_INET6, pair->strvalue, value, lv-1) == NULL) ++ return -1; ++ break; ++ ++ case PW_TYPE_IPV6PREFIX: { ++ uint8_t ip[16]; ++ uint8_t txt[48]; ++ if (pair->lvalue < 2) ++ return -1; ++ ++ memset(ip, 0, sizeof(ip)); ++ memcpy(ip, pair->strvalue+2, pair->lvalue-2); ++ ++ if (inet_ntop(AF_INET6, ip, txt, sizeof(txt)) == NULL) ++ return -1; ++ snprintf(value, lv-1, "%s/%u", txt, (unsigned)pair->strvalue[1]); ++ ++ break; ++ } ++ case PW_TYPE_DATE: ++ strftime (buffer, sizeof (buffer), "%m/%d/%y %H:%M:%S", ++ gmtime ((time_t *) & pair->lvalue)); ++ strncpy(value, buffer, lv-1); ++ break; ++ ++ default: ++ rc_log(LOG_ERR, "rc_avpair_tostr: unknown attribute type %d", pair->type); ++ return -1; ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Function: rc_avpair_log ++ * ++ * Purpose: format sequence of attribute value pairs into printable ++ * string. The caller should provide a storage buffer and the buffer length. ++ * Returns pointer to provided storage buffer. ++ * ++ */ ++char * ++rc_avpair_log(rc_handle const *rh, VALUE_PAIR *pair, char *buf, size_t buf_len) ++{ ++ size_t len, nlen; ++ VALUE_PAIR *vp; ++ char name[33], value[256]; ++ ++ len = 0; ++ for (vp = pair; vp != NULL; vp = vp->next) { ++ if (rc_avpair_tostr(rh, vp, name, sizeof(name), value, ++ sizeof(value)) == -1) ++ return NULL; ++ nlen = len + 32 + 3 + strlen(value) + 2 + 2; ++ if(nlen<buf_len-1) { ++ sprintf(buf + len, "%-32s = '%s'\n", name, value); ++ } else return buf; ++ len = nlen - 1; ++ } ++ return buf; ++} ++ ++/* ++ * Function: rc_avpair_readin ++ * ++ * Purpose: get a sequence of attribute value pairs from the file input ++ * and make them into a list of value_pairs ++ * ++ */ ++ ++VALUE_PAIR *rc_avpair_readin(rc_handle const *rh, FILE *input) ++{ ++ VALUE_PAIR *vp = NULL; ++ char buffer[1024], *q; ++ ++ while (fgets(buffer, sizeof(buffer), input) != NULL) ++ { ++ q = buffer; ++ ++ while(*q && isspace(*q)) q++; ++ ++ if ((*q == '\n') || (*q == '#') || (*q == '\0')) ++ continue; ++ ++ if (rc_avpair_parse(rh, q, &vp) < 0) { ++ rc_log(LOG_ERR, "rc_avpair_readin: malformed attribute: %s", buffer); ++ rc_avpair_free(vp); ++ return NULL; ++ } ++ } ++ ++ return vp; ++} +diff --git a/src/plugins/vbng/lib/buildreq.c b/src/plugins/vbng/lib/buildreq.c +new file mode 100644 +index 00000000..a71b1f99 +--- /dev/null ++++ b/src/plugins/vbng/lib/buildreq.c +@@ -0,0 +1,276 @@ ++/* ++ * $Id: buildreq.c,v 1.17 2010/02/04 10:27:09 aland Exp $ ++ * ++ * Copyright (C) 1995,1997 Lars Fenneberg ++ * ++ * See the file COPYRIGHT for the respective terms and conditions. ++ * If the file is missing contact me at lf@elemental.net ++ * and I'll send you a copy. ++ * ++ */ ++ ++#include <config.h> ++#include <includes.h> ++#include <freeradius-client.h> ++ ++unsigned char rc_get_id(); ++ ++/* ++ * Function: rc_buildreq ++ * ++ * Purpose: builds a skeleton RADIUS request using information from the ++ * config file. ++ * ++ */ ++ ++void rc_buildreq(rc_handle const *rh, SEND_DATA *data, int code, char *server, unsigned short port, ++ char *secret, int timeout, int retries) ++{ ++ data->server = server; ++ data->secret = secret; ++ data->svc_port = port; ++ data->seq_nbr = rc_get_id(); ++ data->timeout = timeout; ++ data->retries = retries; ++ data->code = code; ++} ++ ++/* ++ * Function: rc_get_id ++ * ++ * Purpose: generate random id ++ * ++ */ ++ ++unsigned char rc_get_id() ++{ ++ return (unsigned char)(random() & UCHAR_MAX); ++} ++ ++/* ++ * Function: rc_aaa ++ * ++ * Purpose: Builds an authentication/accounting request for port id client_port ++ * with the value_pairs send and submits it to a server ++ * ++ * Returns: received value_pairs in received, messages from the server in msg ++ * and 0 on success, negative on failure as return value ++ * ++ */ ++ ++int rc_aaa(rc_handle *rh, uint32_t client_port, VALUE_PAIR *send, VALUE_PAIR **received, ++ char *msg, int add_nas_port, int request_type) ++{ ++ SEND_DATA data; ++ VALUE_PAIR *adt_vp = NULL; ++ int result; ++ int i, skip_count; ++ SERVER *aaaserver; ++ int timeout = rc_conf_int(rh, "radius_timeout"); ++ int retries = rc_conf_int(rh, "radius_retries"); ++ int radius_deadtime = rc_conf_int(rh, "radius_deadtime"); ++ double start_time = 0; ++ double now = 0; ++ time_t dtime; ++ ++ if (request_type != PW_ACCOUNTING_REQUEST) { ++ aaaserver = rc_conf_srv(rh, "authserver"); ++ } else { ++ aaaserver = rc_conf_srv(rh, "acctserver"); ++ } ++ if (aaaserver == NULL) ++ return ERROR_RC; ++ ++ data.send_pairs = send; ++ data.receive_pairs = NULL; ++ ++ if (add_nas_port != 0) { ++ /* ++ * Fill in NAS-Port ++ */ ++ if (rc_avpair_add(rh, &(data.send_pairs), PW_NAS_PORT, ++ &client_port, 0, 0) == NULL) ++ return ERROR_RC; ++ } ++ ++ if (request_type == PW_ACCOUNTING_REQUEST) { ++ /* ++ * Fill in Acct-Delay-Time ++ */ ++ dtime = 0; ++ now = rc_getctime(); ++ adt_vp = rc_avpair_get(data.send_pairs, PW_ACCT_DELAY_TIME, 0); ++ if (adt_vp == NULL) { ++ adt_vp = rc_avpair_add(rh, &(data.send_pairs), ++ PW_ACCT_DELAY_TIME, &dtime, 0, 0); ++ if (adt_vp == NULL) ++ return ERROR_RC; ++ start_time = now; ++ } else { ++ start_time = now - adt_vp->lvalue; ++ } ++ } ++ ++ skip_count = 0; ++ result = ERROR_RC; ++ for (i=0; (i < aaaserver->max) && (result != OK_RC) && (result != BADRESP_RC) ++ ; i++, now = rc_getctime()) ++ { ++ if (aaaserver->deadtime_ends[i] != -1 && ++ aaaserver->deadtime_ends[i] > start_time) { ++ skip_count++; ++ continue; ++ } ++ if (data.receive_pairs != NULL) { ++ rc_avpair_free(data.receive_pairs); ++ data.receive_pairs = NULL; ++ } ++ rc_buildreq(rh, &data, request_type, aaaserver->name[i], ++ aaaserver->port[i], aaaserver->secret[i], timeout, retries); ++ ++ if (request_type == PW_ACCOUNTING_REQUEST) { ++ dtime = now - start_time; ++ rc_avpair_assign(adt_vp, &dtime, 0); ++ } ++ ++ result = rc_send_server (rh, &data, msg); ++ if (result == TIMEOUT_RC && radius_deadtime > 0) ++ aaaserver->deadtime_ends[i] = start_time + (double)radius_deadtime; ++ } ++ if (result == OK_RC || result == BADRESP_RC || skip_count == 0) ++ goto exit; ++ ++ result = ERROR_RC; ++ for (i=0; (i < aaaserver->max) && (result != OK_RC) && (result != BADRESP_RC) ++ ; i++) ++ { ++ if (aaaserver->deadtime_ends[i] == -1 || ++ aaaserver->deadtime_ends[i] <= start_time) { ++ continue; ++ } ++ if (data.receive_pairs != NULL) { ++ rc_avpair_free(data.receive_pairs); ++ data.receive_pairs = NULL; ++ } ++ rc_buildreq(rh, &data, request_type, aaaserver->name[i], ++ aaaserver->port[i], aaaserver->secret[i], timeout, retries); ++ ++ if (request_type == PW_ACCOUNTING_REQUEST) { ++ dtime = rc_getctime() - start_time; ++ rc_avpair_assign(adt_vp, &dtime, 0); ++ } ++ ++ result = rc_send_server (rh, &data, msg); ++ if (result != TIMEOUT_RC) ++ aaaserver->deadtime_ends[i] = -1; ++ } ++ ++exit: ++ if (request_type != PW_ACCOUNTING_REQUEST) { ++ *received = data.receive_pairs; ++ } else { ++ rc_avpair_free(data.receive_pairs); ++ } ++ ++ return result; ++} ++ ++/* ++ * Function: rc_auth ++ * ++ * Purpose: Builds an authentication request for port id client_port ++ * with the value_pairs send and submits it to a server ++ * ++ * Returns: received value_pairs in received, messages from the server in msg (if non-NULL), ++ * and 0 on success, negative on failure as return value ++ * ++ */ ++ ++int rc_auth(rc_handle *rh, uint32_t client_port, VALUE_PAIR *send, VALUE_PAIR **received, ++ char *msg) ++{ ++ ++ return rc_aaa(rh, client_port, send, received, msg, 1, PW_ACCESS_REQUEST); ++} ++ ++/* ++ * Function: rc_auth_proxy ++ * ++ * Purpose: Builds an authentication request ++ * with the value_pairs send and submits it to a server. ++ * Works for a proxy; does not add IP address, and does ++ * does not rely on config file. ++ * ++ * Returns: received value_pairs in received, messages from the server in msg (if non-NULL) ++ * and 0 on success, negative on failure as return value ++ * ++ */ ++ ++int rc_auth_proxy(rc_handle *rh, VALUE_PAIR *send, VALUE_PAIR **received, char *msg) ++{ ++ ++ return rc_aaa(rh, 0, send, received, msg, 0, PW_ACCESS_REQUEST); ++} ++ ++ ++/* ++ * Function: rc_acct ++ * ++ * Purpose: Builds an accounting request for port id client_port ++ * with the value_pairs send ++ * ++ * Remarks: NAS-IP-Address, NAS-Port and Acct-Delay-Time get filled ++ * in by this function, the rest has to be supplied. ++ */ ++ ++int rc_acct(rc_handle *rh, uint32_t client_port, VALUE_PAIR *send) ++{ ++ ++ return rc_aaa(rh, client_port, send, NULL, NULL, 1, PW_ACCOUNTING_REQUEST); ++} ++ ++/* ++ * Function: rc_acct_proxy ++ * ++ * Purpose: Builds an accounting request with the value_pairs send ++ * ++ */ ++ ++int rc_acct_proxy(rc_handle *rh, VALUE_PAIR *send) ++{ ++ ++ return rc_aaa(rh, 0, send, NULL, NULL, 0, PW_ACCOUNTING_REQUEST); ++} ++ ++/* ++ * Function: rc_check ++ * ++ * Purpose: ask the server hostname on the specified port for a ++ * status message ++ * ++ */ ++ ++int rc_check(rc_handle *rh, char *host, char *secret, unsigned short port, char *msg) ++{ ++ SEND_DATA data; ++ int result; ++ uint32_t service_type; ++ int timeout = rc_conf_int(rh, "radius_timeout"); ++ int retries = rc_conf_int(rh, "radius_retries"); ++ ++ data.send_pairs = data.receive_pairs = NULL; ++ ++ /* ++ * Fill in Service-Type ++ */ ++ ++ service_type = PW_ADMINISTRATIVE; ++ rc_avpair_add(rh, &(data.send_pairs), PW_SERVICE_TYPE, &service_type, 0, 0); ++ ++ rc_buildreq(rh, &data, PW_STATUS_SERVER, host, port, secret, timeout, retries); ++ result = rc_send_server (rh, &data, msg); ++ ++ rc_avpair_free(data.receive_pairs); ++ ++ return result; ++} +diff --git a/src/plugins/vbng/lib/clientid.c b/src/plugins/vbng/lib/clientid.c +new file mode 100644 +index 00000000..6901a04b +--- /dev/null ++++ b/src/plugins/vbng/lib/clientid.c +@@ -0,0 +1,146 @@ ++/* ++ * $Id: clientid.c,v 1.7 2007/07/11 17:29:29 cparker Exp $ ++ * ++ * Copyright (C) 1995,1996,1997 Lars Fenneberg ++ * ++ * See the file COPYRIGHT for the respective terms and conditions. ++ * If the file is missing contact me at lf@elemental.net ++ * and I'll send you a copy. ++ * ++ */ ++ ++#include <config.h> ++#include <includes.h> ++#include <freeradius-client.h> ++ ++struct map2id_s { ++ char *name; ++ uint32_t id; ++ ++ struct map2id_s *next; ++}; ++ ++/* ++ * Function: rc_read_mapfile ++ * ++ * Purpose: Read in the ttyname to port id map file ++ * ++ * Arguments: the file name of the map file ++ * ++ * Returns: zero on success, negative integer on failure ++ */ ++ ++int rc_read_mapfile(rc_handle *rh, char const *filename) ++{ ++ char buffer[1024]; ++ FILE *mapfd; ++ char *c, *name, *id, *q; ++ struct map2id_s *p; ++ int lnr = 0; ++ ++ if ((mapfd = fopen(filename,"r")) == NULL) ++ { ++ rc_log(LOG_ERR,"rc_read_mapfile: can't read %s: %s", filename, strerror(errno)); ++ return -1; ++ } ++ ++#define SKIP(p) while(*p && isspace(*p)) p++; ++ ++ while (fgets(buffer, sizeof(buffer), mapfd) != NULL) ++ { ++ lnr++; ++ ++ q = buffer; ++ ++ SKIP(q); ++ ++ if ((*q == '\n') || (*q == '#') || (*q == '\0')) ++ continue; ++ ++ if (( c = strchr(q, ' ')) || (c = strchr(q,'\t'))) { ++ ++ *c = '\0'; c++; ++ SKIP(c); ++ ++ name = q; ++ id = c; ++ ++ if ((p = (struct map2id_s *)malloc(sizeof(*p))) == NULL) { ++ rc_log(LOG_CRIT,"rc_read_mapfile: out of memory"); ++ fclose(mapfd); ++ return -1; ++ } ++ ++ p->name = strdup(name); ++ p->id = atoi(id); ++ p->next = rh->map2id_list; ++ rh->map2id_list = p; ++ ++ } else { ++ ++ rc_log(LOG_ERR, "rc_read_mapfile: malformed line in %s, line %d", filename, lnr); ++ fclose(mapfd); ++ return -1; ++ ++ } ++ } ++ ++#undef SKIP ++ ++ fclose(mapfd); ++ ++ return 0; ++} ++ ++/* ++ * Function: rc_map2id ++ * ++ * Purpose: Map ttyname to port id ++ * ++ * Arguments: full pathname of the tty ++ * ++ * Returns: port id, zero if no entry found ++ */ ++ ++uint32_t rc_map2id(rc_handle const *rh, char const *name) ++{ ++ struct map2id_s *p; ++ char ttyname[PATH_MAX]; ++ ++ *ttyname = '\0'; ++ if (*name != '/') ++ strcpy(ttyname, "/dev/"); ++ ++ strncat(ttyname, name, sizeof(ttyname)-strlen(ttyname)-1); ++ ++ for(p = rh->map2id_list; p; p = p->next) ++ if (!strcmp(ttyname, p->name)) return p->id; ++ ++ rc_log(LOG_WARNING,"rc_map2id: can't find tty %s in map database", ttyname); ++ ++ return 0; ++} ++ ++/* ++ * Function: rc_map2id_free ++ * ++ * Purpose: Free allocated map2id list ++ * ++ * Arguments: Radius Client handle ++ */ ++ ++void ++rc_map2id_free(rc_handle *rh) ++{ ++ struct map2id_s *p, *np; ++ ++ if (rh->map2id_list == NULL) ++ return; ++ ++ for(p = rh->map2id_list; p != NULL; p = np) { ++ np = p->next; ++ free(p->name); ++ free(p); ++ } ++ rh->map2id_list = NULL; ++} +diff --git a/src/plugins/vbng/lib/config.c b/src/plugins/vbng/lib/config.c +new file mode 100644 +index 00000000..1db78608 +--- /dev/null ++++ b/src/plugins/vbng/lib/config.c +@@ -0,0 +1,925 @@ ++/* ++ * $Id: config.c,v 1.23 2010/04/28 14:26:15 aland Exp $ ++ * ++ * Copyright (C) 1995,1996,1997 Lars Fenneberg ++ * ++ * Copyright 1992 Livingston Enterprises, Inc. ++ * ++ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan ++ * and Merit Network, Inc. All Rights Reserved ++ * ++ * See the file COPYRIGHT for the respective terms and conditions. ++ * If the file is missing contact me at lf@elemental.net ++ * and I'll send you a copy. ++ * ++ */ ++ ++#include <config.h> ++#include <includes.h> ++#include <freeradius-client.h> ++#include <options.h> ++ ++/* ++ * Function: find_option ++ * ++ * Purpose: find an option in the option list ++ * ++ * Returns: pointer to option on success, NULL otherwise ++ */ ++ ++static OPTION *find_option(rc_handle const *rh, char const *optname, unsigned int type) ++{ ++ int i; ++ ++ /* there're so few options that a binary search seems not necessary */ ++ for (i = 0; i < NUM_OPTIONS; i++) { ++ if (!strcmp(rh->config_options[i].name, optname) && ++ (rh->config_options[i].type & type)) ++ { ++ return &rh->config_options[i]; ++ } ++ } ++ ++ return NULL; ++} ++ ++/* ++ * Function: set_option_... ++ * ++ * Purpose: set a specific option doing type conversions ++ * ++ * Returns: 0 on success, -1 on failure ++ */ ++ ++static int set_option_str(char const *filename, int line, OPTION *option, char const *p) ++{ ++ if (p) { ++ option->val = (void *) strdup(p); ++ if (option->val == NULL) { ++ rc_log(LOG_CRIT, "read_config: out of memory"); ++ return -1; ++ } ++ } else { ++ option->val = NULL; ++ } ++ ++ return 0; ++} ++ ++static int set_option_int(char const *filename, int line, OPTION *option, char const *p) ++{ ++ int *iptr; ++ ++ if (p == NULL) { ++ rc_log(LOG_ERR, "%s: line %d: bogus option value", filename, line); ++ return -1; ++ } ++ ++ if ((iptr = malloc(sizeof(*iptr))) == NULL) { ++ rc_log(LOG_CRIT, "read_config: out of memory"); ++ return -1; ++ } ++ ++ *iptr = atoi(p); ++ option->val = (void *) iptr; ++ ++ return 0; ++} ++ ++static int set_option_srv(char const *filename, int line, OPTION *option, char const *p) ++{ ++ SERVER *serv; ++ char *p_pointer; ++ char *p_dupe; ++ char *p_save; ++ char *q; ++ char *s; ++ struct servent *svp; ++ ++ p_dupe = strdup(p); ++ ++ if (p_dupe == NULL) { ++ rc_log(LOG_ERR, "%s: line %d: Invalid option or memory failure", filename, line); ++ return -1; ++ } ++ ++ serv = (SERVER *) option->val; ++ if (serv == NULL) { ++ DEBUG(LOG_ERR, "option->val / server is NULL, allocating memory"); ++ serv = malloc(sizeof(*serv)); ++ if (serv == NULL) { ++ rc_log(LOG_CRIT, "read_config: out of memory"); ++ free(p_dupe); ++ return -1; ++ } ++ memset(serv, 0, sizeof(*serv)); ++ serv->max = 0; ++ } ++ ++ p_pointer = strtok_r(p_dupe, ", \t", &p_save); ++ ++ /* Check to see if we have 'servername:port' syntax */ ++ if ((q = strchr(p_pointer,':')) != NULL) { ++ *q = '\0'; ++ q++; ++ ++ /* Check to see if we have 'servername:port:secret' syntax */ ++ if((s = strchr(q,':')) != NULL) { ++ *s = '\0'; ++ s++; ++ serv->secret[serv->max] = strdup(s); ++ if (serv->secret[serv->max] == NULL) { ++ rc_log(LOG_CRIT, "read_config: out of memory"); ++ if (option->val == NULL) { ++ free(p_dupe); ++ free(serv); ++ } ++ return -1; ++ } ++ } ++ } ++ if(q && strlen(q) > 0) { ++ serv->port[serv->max] = atoi(q); ++ } else { ++ if (!strcmp(option->name,"authserver")) ++ if ((svp = getservbyname ("radius", "udp")) == NULL) ++ serv->port[serv->max] = PW_AUTH_UDP_PORT; ++ else ++ serv->port[serv->max] = ntohs ((unsigned int) svp->s_port); ++ else if (!strcmp(option->name, "acctserver")) ++ if ((svp = getservbyname ("radacct", "udp")) == NULL) ++ serv->port[serv->max] = PW_ACCT_UDP_PORT; ++ else ++ serv->port[serv->max] = ntohs ((unsigned int) svp->s_port); ++ else { ++ rc_log(LOG_ERR, "%s: line %d: no default port for %s", filename, line, option->name); ++ if (option->val == NULL) { ++ free(p_dupe); ++ free(serv); ++ } ++ return -1; ++ } ++ } ++ ++ serv->name[serv->max] = strdup(p_pointer); ++ if (serv->name[serv->max] == NULL) { ++ rc_log(LOG_CRIT, "read_config: out of memory"); ++ if (option->val == NULL) { ++ free(p_dupe); ++ free(serv); ++ } ++ return -1; ++ } ++ free(p_dupe); ++ ++ serv->deadtime_ends[serv->max] = -1; ++ serv->max++; ++ ++ if (option->val == NULL) ++ option->val = (void *)serv; ++ ++ return 0; ++} ++ ++static int set_option_auo(char const *filename, int line, OPTION *option, char const *p) ++{ ++ int *iptr; ++ char *p_dupe = NULL; ++ char *p_pointer = NULL; ++ char *p_save = NULL; ++ ++ p_dupe = strdup(p); ++ ++ if (p_dupe == NULL) { ++ rc_log(LOG_WARNING, "%s: line %d: bogus option value", filename, line); ++ return -1; ++ } ++ ++ if ((iptr = malloc(sizeof(iptr))) == NULL) { ++ rc_log(LOG_CRIT, "read_config: out of memory"); ++ free(p_dupe); ++ return -1; ++ } ++ ++ *iptr = 0; ++ /*if(strstr(p_dupe,", \t") != NULL) {*/ ++ p_pointer = strtok_r(p_dupe, ", \t", &p_save); ++ /*}*/ ++ ++ if (!strncmp(p_pointer, "local", 5)) ++ *iptr = AUTH_LOCAL_FST; ++ else if (!strncmp(p_pointer, "radius", 6)) ++ *iptr = AUTH_RADIUS_FST; ++ else { ++ rc_log(LOG_ERR,"%s: auth_order: unknown keyword: %s", filename, p); ++ free(iptr); ++ free(p_dupe); ++ return -1; ++ } ++ ++ p_pointer = strtok_r(NULL, ", \t", &p_save); ++ ++ if (p_pointer && (*p_pointer != '\0')) { ++ if ((*iptr & AUTH_RADIUS_FST) && !strcmp(p_pointer, "local")) ++ *iptr = (*iptr) | AUTH_LOCAL_SND; ++ else if ((*iptr & AUTH_LOCAL_FST) && !strcmp(p_pointer, "radius")) ++ *iptr = (*iptr) | AUTH_RADIUS_SND; ++ else { ++ rc_log(LOG_ERR,"%s: auth_order: unknown or unexpected keyword: %s", filename, p); ++ free(iptr); ++ free(p_dupe); ++ return -1; ++ } ++ } ++ ++ option->val = (void *) iptr; ++ ++ free(p_dupe); ++ return 0; ++} ++ ++ ++/* Function: rc_add_config ++ * ++ * Purpose: allow a config option to be added to rc_handle from inside a program ++ * ++ * Returns: 0 on success, -1 on failure ++ */ ++ ++int rc_add_config(rc_handle *rh, char const *option_name, char const *option_val, char const *source, int line) ++{ ++ OPTION *option; ++ ++ if ((option = find_option(rh, option_name, OT_ANY)) == NULL) ++ { ++ rc_log(LOG_ERR, "ERROR: unrecognized option: %s", option_name); ++ return -1; ++ } ++ ++ if (option->status != ST_UNDEF) ++ { ++ rc_log(LOG_ERR, "ERROR: duplicate option: %s", option_name); ++ return -1; ++ } ++ ++ switch (option->type) { ++ case OT_STR: ++ if (set_option_str(source, line, option, option_val) < 0) { ++ return -1; ++ } ++ break; ++ case OT_INT: ++ if (set_option_int(source, line, option, option_val) < 0) { ++ return -1; ++ } ++ break; ++ case OT_SRV: ++ if (set_option_srv(source, line, option, option_val) < 0) { ++ return -1; ++ } ++ break; ++ case OT_AUO: ++ if (set_option_auo(source, line, option, option_val) < 0) { ++ return -1; ++ } ++ break; ++ default: ++ rc_log(LOG_CRIT, "rc_add_config: impossible case branch!"); ++ abort(); ++ } ++ return 0; ++} ++ ++/* ++ * Function: rc_config_init ++ * ++ * Purpose: initialize the configuration structure from an external program. For use when not ++ * running a standalone client that reads from a config file. ++ * ++ * Returns: rc_handle on success, NULL on failure ++ */ ++ ++rc_handle * ++rc_config_init(rc_handle *rh) ++{ ++ int i; ++ SERVER *authservers; ++ SERVER *acctservers; ++ OPTION *acct; ++ OPTION *auth; ++ ++ rh->config_options = malloc(sizeof(config_options_default)); ++ if (rh->config_options == NULL) ++ { ++ rc_log(LOG_CRIT, "rc_config_init: out of memory"); ++ rc_destroy(rh); ++ return NULL; ++ } ++ memcpy(rh->config_options, &config_options_default, sizeof(config_options_default)); ++ ++ acct = find_option(rh, "acctserver", OT_ANY); ++ auth = find_option(rh, "authserver", OT_ANY); ++ authservers = malloc(sizeof(SERVER)); ++ acctservers = malloc(sizeof(SERVER)); ++ ++ if(authservers == NULL || acctservers == NULL) ++ { ++ rc_log(LOG_CRIT, "rc_config_init: error initializing server structs"); ++ rc_destroy(rh); ++ if(authservers) free(authservers); ++ if(acctservers) free(acctservers); ++ return NULL; ++ } ++ ++ ++ authservers->max = 0; ++ acctservers->max = 0; ++ ++ for(i=0; i < SERVER_MAX; i++) ++ { ++ authservers->name[i] = NULL; ++ authservers->secret[i] = NULL; ++ acctservers->name[i] = NULL; ++ acctservers->secret[i] = NULL; ++ } ++ acct->val = acctservers; ++ auth->val = authservers; ++ return rh; ++} ++ ++ ++/* ++ * Function: rc_read_config ++ * ++ * Purpose: read the global config file ++ * ++ * Returns: new rc_handle on success, NULL when failure ++ */ ++ ++rc_handle * ++rc_read_config(char const *filename) ++{ ++ FILE *configfd; ++ char buffer[512], *p; ++ OPTION *option; ++ int line; ++ size_t pos; ++ rc_handle *rh; ++ ++ srandom((unsigned int)(time(NULL)+getpid())); ++ ++ rh = rc_new(); ++ if (rh == NULL) ++ return NULL; ++ ++ rh->config_options = malloc(sizeof(config_options_default)); ++ if (rh->config_options == NULL) { ++ rc_log(LOG_CRIT, "rc_read_config: out of memory"); ++ rc_destroy(rh); ++ return NULL; ++ } ++ memcpy(rh->config_options, &config_options_default, sizeof(config_options_default)); ++ ++ if ((configfd = fopen(filename,"r")) == NULL) ++ { ++ rc_log(LOG_ERR,"rc_read_config: can't open %s: %s", filename, strerror(errno)); ++ rc_destroy(rh); ++ return NULL; ++ } ++ ++ line = 0; ++ while ((fgets(buffer, sizeof(buffer), configfd) != NULL)) ++ { ++ line++; ++ p = buffer; ++ ++ if ((*p == '\n') || (*p == '#') || (*p == '\0')) ++ continue; ++ ++ p[strlen(p)-1] = '\0'; ++ ++ ++ if ((pos = strcspn(p, "\t ")) == 0) { ++ rc_log(LOG_ERR, "%s: line %d: bogus format: %s", filename, line, p); ++ fclose(configfd); ++ rc_destroy(rh); ++ return NULL; ++ } ++ ++ p[pos] = '\0'; ++ ++ if ((option = find_option(rh, p, OT_ANY)) == NULL) { ++ rc_log(LOG_ERR, "%s: line %d: unrecognized keyword: %s", filename, line, p); ++ fclose(configfd); ++ rc_destroy(rh); ++ return NULL; ++ } ++ ++ if (option->status != ST_UNDEF) { ++ rc_log(LOG_ERR, "%s: line %d: duplicate option line: %s", filename, line, p); ++ fclose(configfd); ++ rc_destroy(rh); ++ return NULL; ++ } ++ ++ p += pos+1; ++ while (isspace(*p)) ++ p++; ++ pos = strlen(p) - 1; ++ while(pos != 0 && isspace(p[pos])) ++ pos--; ++ p[pos + 1] = '\0'; ++ ++ switch (option->type) { ++ case OT_STR: ++ if (set_option_str(filename, line, option, p) < 0) { ++ fclose(configfd); ++ rc_destroy(rh); ++ return NULL; ++ } ++ break; ++ case OT_INT: ++ if (set_option_int(filename, line, option, p) < 0) { ++ fclose(configfd); ++ rc_destroy(rh); ++ return NULL; ++ } ++ break; ++ case OT_SRV: ++ if (set_option_srv(filename, line, option, p) < 0) { ++ fclose(configfd); ++ rc_destroy(rh); ++ return NULL; ++ } ++ break; ++ case OT_AUO: ++ if (set_option_auo(filename, line, option, p) < 0) { ++ fclose(configfd); ++ rc_destroy(rh); ++ return NULL; ++ } ++ break; ++ default: ++ rc_log(LOG_CRIT, "rc_read_config: impossible case branch!"); ++ abort(); ++ } ++ } ++ fclose(configfd); ++ ++ if (test_config(rh, filename) == -1) { ++ rc_destroy(rh); ++ return NULL; ++ } ++ return rh; ++} ++ ++/* ++ * Function: rc_conf_str, rc_conf_int, rc_conf_src ++ * ++ * Purpose: get the value of a config option ++ * ++ * Returns: config option value ++ */ ++ ++char *rc_conf_str(rc_handle const *rh, char const *optname) ++{ ++ OPTION *option; ++ ++ option = find_option(rh, optname, OT_STR); ++ ++ if (option != NULL) { ++ return (char *)option->val; ++ } else { ++ rc_log(LOG_CRIT, "rc_conf_str: unkown config option requested: %s", optname); ++ abort(); ++ return NULL; ++ } ++} ++ ++int rc_conf_int(rc_handle const *rh, char const *optname) ++{ ++ OPTION *option; ++ ++ option = find_option(rh, optname, OT_INT|OT_AUO); ++ ++ if (option != NULL) { ++ if (option->val) { ++ return *((int *)option->val); ++ } else { ++ rc_log(LOG_ERR, "rc_conf_int: config option %s was not set", optname); ++ return 0; ++ } ++ } else { ++ rc_log(LOG_CRIT, "rc_conf_int: unkown config option requested: %s", optname); ++ abort(); ++ return 0; ++ } ++} ++ ++SERVER *rc_conf_srv(rc_handle const *rh, char const *optname) ++{ ++ OPTION *option; ++ ++ option = find_option(rh, optname, OT_SRV); ++ ++ if (option != NULL) { ++ return (SERVER *)option->val; ++ } else { ++ rc_log(LOG_CRIT, "rc_conf_srv: unkown config option requested: %s", optname); ++ abort(); ++ return NULL; ++ } ++} ++ ++/* ++ * Function: test_config ++ * ++ * Purpose: test the configuration the user supplied ++ * ++ * Returns: 0 on success, -1 when failure ++ */ ++ ++int test_config(rc_handle const *rh, char const *filename) ++{ ++#if 0 ++ struct stat st; ++ char *file; ++#endif ++ ++ if (!(rc_conf_srv(rh, "authserver")->max)) ++ { ++ rc_log(LOG_ERR,"%s: no authserver specified", filename); ++ return -1; ++ } ++ if (!(rc_conf_srv(rh, "acctserver")->max)) ++ { ++ rc_log(LOG_ERR,"%s: no acctserver specified", filename); ++ return -1; ++ } ++ if (!rc_conf_str(rh, "servers")) ++ { ++ rc_log(LOG_ERR,"%s: no servers file specified", filename); ++ return -1; ++ } ++ if (!rc_conf_str(rh, "dictionary")) ++ { ++ rc_log(LOG_ERR,"%s: no dictionary specified", filename); ++ return -1; ++ } ++ ++ if (rc_conf_int(rh, "radius_timeout") <= 0) ++ { ++ rc_log(LOG_ERR,"%s: radius_timeout <= 0 is illegal", filename); ++ return -1; ++ } ++ if (rc_conf_int(rh, "radius_retries") <= 0) ++ { ++ rc_log(LOG_ERR,"%s: radius_retries <= 0 is illegal", filename); ++ return -1; ++ } ++ if (rc_conf_int(rh, "radius_deadtime") < 0) ++ { ++ rc_log(LOG_ERR,"%s: radius_deadtime is illegal", filename); ++ return -1; ++ } ++#if 0 ++ file = rc_conf_str(rh, "login_local"); ++ if (stat(file, &st) == 0) ++ { ++ if (!S_ISREG(st.st_mode)) { ++ rc_log(LOG_ERR,"%s: not a regular file: %s", filename, file); ++ return -1; ++ } ++ } else { ++ rc_log(LOG_ERR,"%s: file not found: %s", filename, file); ++ return -1; ++ } ++ file = rc_conf_str(rh, "login_radius"); ++ if (stat(file, &st) == 0) ++ { ++ if (!S_ISREG(st.st_mode)) { ++ rc_log(LOG_ERR,"%s: not a regular file: %s", filename, file); ++ return -1; ++ } ++ } else { ++ rc_log(LOG_ERR,"%s: file not found: %s", filename, file); ++ return -1; ++ } ++#endif ++ ++ if (rc_conf_int(rh, "login_tries") <= 0) ++ { ++ rc_log(LOG_ERR,"%s: login_tries <= 0 is illegal", filename); ++ return -1; ++ } ++ if (rc_conf_str(rh, "seqfile") == NULL) ++ { ++ rc_log(LOG_ERR,"%s: seqfile not specified", filename); ++ return -1; ++ } ++ if (rc_conf_int(rh, "login_timeout") <= 0) ++ { ++ rc_log(LOG_ERR,"%s: login_timeout <= 0 is illegal", filename); ++ return -1; ++ } ++ if (rc_conf_str(rh, "mapfile") == NULL) ++ { ++ rc_log(LOG_ERR,"%s: mapfile not specified", filename); ++ return -1; ++ } ++ if (rc_conf_str(rh, "nologin") == NULL) ++ { ++ rc_log(LOG_ERR,"%s: nologin not specified", filename); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Function: rc_find_match ++ * ++ * Purpose: see if ip_addr is one of the ip addresses of hostname ++ * ++ * Returns: 0 on success, -1 when failure ++ * ++ */ ++ ++static int find_match (uint32_t *ip_addr, char const *hostname) ++{ ++ ++ uint32_t addr; ++ char **paddr; ++ struct hostent *hp; ++ ++ if (rc_good_ipaddr (hostname) == 0) ++ { ++ if (*ip_addr == ntohl(inet_addr (hostname))) ++ { ++ return 0; ++ } ++ return -1; ++ } ++ ++ if ((hp = rc_gethostbyname(hostname)) == NULL) ++ { ++ return -1; ++ } ++ ++ for (paddr = hp->h_addr_list; *paddr; paddr++) ++ { ++ addr = ** (uint32_t **) paddr; ++ if (ntohl(addr) == *ip_addr) ++ { ++ return 0; ++ } ++ } ++ return -1; ++} ++ ++/* ++ * Function: rc_ipaddr_local ++ * ++ * Purpose: checks if provided address is local address ++ * ++ * Returns: 0 if local, 1 if not local, -1 on failure ++ * ++ */ ++ ++static int ++rc_ipaddr_local(uint32_t ip_addr) ++{ ++ int temp_sock, res, serrno; ++ struct sockaddr_in sin; ++ ++ temp_sock = socket(AF_INET, SOCK_DGRAM, 0); ++ if (temp_sock == -1) ++ return -1; ++ memset(&sin, '\0', sizeof(sin)); ++ sin.sin_family = AF_INET; ++ sin.sin_addr.s_addr = htonl(ip_addr); ++ sin.sin_port = htons(0); ++ res = bind(temp_sock, (struct sockaddr *)&sin, sizeof(sin)); ++ serrno = errno; ++ close(temp_sock); ++ if (res == 0) ++ return 0; ++ if (serrno == EADDRNOTAVAIL) ++ return 1; ++ return -1; ++} ++ ++/* ++ * Function: rc_is_myname ++ * ++ * Purpose: check if provided name refers to ourselves ++ * ++ * Returns: 0 if yes, 1 if no and -1 on failure ++ * ++ */ ++ ++static int ++rc_is_myname(char const *hostname) ++{ ++ uint32_t addr; ++ char **paddr; ++ struct hostent *hp; ++ int res; ++ ++ if (rc_good_ipaddr(hostname) == 0) ++ return rc_ipaddr_local(ntohl(inet_addr(hostname))); ++ ++ if ((hp = rc_gethostbyname(hostname)) == NULL) ++ return -1; ++ for (paddr = hp->h_addr_list; *paddr; paddr++) { ++ addr = **(uint32_t **)paddr; ++ res = rc_ipaddr_local(ntohl(addr)); ++ if (res == 0 || res == -1) ++ return res; ++ } ++ return 1; ++} ++ ++/* ++ * Function: rc_find_server ++ * ++ * Purpose: locate a server in the rh config or if not found, check for a servers file ++ * ++ * Returns: 0 on success, -1 on failure ++ * ++ */ ++ ++int rc_find_server (rc_handle const *rh, char const *server_name, uint32_t *ip_addr, char *secret) ++{ ++ int i; ++ size_t len; ++ int result = 0; ++ FILE *clientfd; ++ char *h; ++ char *s; ++ char buffer[128]; ++ char hostnm[AUTH_ID_LEN + 1]; ++ char *buffer_save; ++ char *hostnm_save; ++ SERVER *authservers; ++ SERVER *acctservers; ++ ++ /* Lookup the IP address of the radius server */ ++ if ((*ip_addr = rc_get_ipaddr (server_name)) == (uint32_t) 0) ++ return -1; ++ ++ /* Check to see if the server secret is defined in the rh config */ ++ if( (authservers = rc_conf_srv(rh, "authserver")) != NULL ) ++ { ++ for( i = 0; i < authservers->max; i++ ) ++ { ++ if( (strncmp(server_name, authservers->name[i], strlen(server_name)) == 0) && ++ (authservers->secret[i] != NULL) ) ++ { ++ memset (secret, '\0', MAX_SECRET_LENGTH); ++ len = strlen (authservers->secret[i]); ++ if (len > MAX_SECRET_LENGTH) ++ { ++ len = MAX_SECRET_LENGTH; ++ } ++ strncpy (secret, authservers->secret[i], (size_t) len); ++ secret[MAX_SECRET_LENGTH] = '\0'; ++ return 0; ++ } ++ } ++ } ++ ++ if( (acctservers = rc_conf_srv(rh, "acctserver")) != NULL ) ++ { ++ for( i = 0; i < acctservers->max; i++ ) ++ { ++ if( (strncmp(server_name, acctservers->name[i], strlen(server_name)) == 0) && ++ (acctservers->secret[i] != NULL) ) ++ { ++ memset (secret, '\0', MAX_SECRET_LENGTH); ++ len = strlen (acctservers->secret[i]); ++ if (len > MAX_SECRET_LENGTH) ++ { ++ len = MAX_SECRET_LENGTH; ++ } ++ strncpy (secret, acctservers->secret[i], (size_t) len); ++ secret[MAX_SECRET_LENGTH] = '\0'; ++ return 0; ++ } ++ } ++ } ++ ++ /* We didn't find it in the rh_config or the servername is too long so look for a ++ * servers file to define the secret(s) ++ */ ++ ++ if ((clientfd = fopen (rc_conf_str(rh, "servers"), "r")) == NULL) ++ { ++ rc_log(LOG_ERR, "rc_find_server: couldn't open file: %s: %s", strerror(errno), rc_conf_str(rh, "servers")); ++ return -1; ++ } ++ ++ while (fgets (buffer, sizeof (buffer), clientfd) != NULL) ++ { ++ if (*buffer == '#') ++ continue; ++ ++ if ((h = strtok_r(buffer, " \t\n", &buffer_save)) == NULL) /* first hostname */ ++ continue; ++ ++ memset (hostnm, '\0', AUTH_ID_LEN); ++ len = strlen (h); ++ if (len > AUTH_ID_LEN) ++ { ++ len = AUTH_ID_LEN; ++ } ++ strncpy (hostnm, h, (size_t) len); ++ hostnm[AUTH_ID_LEN] = '\0'; ++ ++ if ((s = strtok_r (NULL, " \t\n", &buffer_save)) == NULL) /* and secret field */ ++ continue; ++ ++ memset (secret, '\0', MAX_SECRET_LENGTH); ++ len = strlen (s); ++ if (len > MAX_SECRET_LENGTH) ++ { ++ len = MAX_SECRET_LENGTH; ++ } ++ strncpy (secret, s, (size_t) len); ++ secret[MAX_SECRET_LENGTH] = '\0'; ++ ++ if (!strchr (hostnm, '/')) /* If single name form */ ++ { ++ if (find_match (ip_addr, hostnm) == 0) ++ { ++ result++; ++ break; ++ } ++ } ++ else /* <name1>/<name2> "paired" form */ ++ { ++ strtok_r(hostnm, "/", &hostnm_save); ++ if (rc_is_myname(hostnm) == 0) ++ { /* If we're the 1st name, target is 2nd */ ++ if (find_match (ip_addr, hostnm_save) == 0) ++ { ++ result++; ++ break; ++ } ++ } ++ else /* If we were 2nd name, target is 1st name */ ++ { ++ if (find_match (ip_addr, hostnm) == 0) ++ { ++ result++; ++ break; ++ } ++ } ++ } ++ } ++ fclose (clientfd); ++ if (result == 0) ++ { ++ memset (buffer, '\0', sizeof (buffer)); ++ memset (secret, '\0', MAX_SECRET_LENGTH); ++ rc_log(LOG_ERR, "rc_find_server: couldn't find RADIUS server %s in %s", ++ server_name, rc_conf_str(rh, "servers")); ++ return -1; ++ } ++ return 0; ++} ++ ++/* ++ * Function: rc_config_free ++ * ++ * Purpose: Free allocated config values ++ * ++ * Arguments: Radius Client handle ++ */ ++ ++void ++rc_config_free(rc_handle *rh) ++{ ++ int i, j; ++ SERVER *serv; ++ ++ if (rh->config_options == NULL) ++ return; ++ ++ for (i = 0; i < NUM_OPTIONS; i++) { ++ if (rh->config_options[i].val == NULL) ++ continue; ++ if (rh->config_options[i].type == OT_SRV) { ++ serv = (SERVER *)rh->config_options[i].val; ++ for (j = 0; j < serv->max; j++){ ++ free(serv->name[j]); ++ if(serv->secret[j]) free(serv->secret[j]); ++ } ++ free(serv); ++ } else { ++ free(rh->config_options[i].val); ++ } ++ } ++ free(rh->config_options); ++ rh->config_options = NULL; ++} +diff --git a/src/plugins/vbng/lib/dict.c b/src/plugins/vbng/lib/dict.c +new file mode 100644 +index 00000000..84dbba0e +--- /dev/null ++++ b/src/plugins/vbng/lib/dict.c +@@ -0,0 +1,519 @@ ++/* ++ * $Id: dict.c,v 1.10 2007/07/11 17:29:29 cparker Exp $ ++ * ++ * Copyright (C) 1995,1996,1997 Lars Fenneberg ++ * ++ * Copyright 1992 Livingston Enterprises, Inc. ++ * ++ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan ++ * and Merit Network, Inc. All Rights Reserved ++ * ++ * See the file COPYRIGHT for the respective terms and conditions. ++ * If the file is missing contact me at lf@elemental.net ++ * and I'll send you a copy. ++ * ++ */ ++ ++#include <config.h> ++#include <includes.h> ++#include <freeradius-client.h> ++ ++/* ++ * Function: rc_read_dictionary ++ * ++ * Purpose: Initialize the dictionary. Read all ATTRIBUTES into ++ * the dictionary_attributes list. Read all VALUES into ++ * the dictionary_values list. ++ * ++ */ ++ ++int rc_read_dictionary (rc_handle *rh, char const *filename) ++{ ++ FILE *dictfd; ++ char dummystr[AUTH_ID_LEN]; ++ char namestr[AUTH_ID_LEN]; ++ char valstr[AUTH_ID_LEN]; ++ char attrstr[AUTH_ID_LEN]; ++ char typestr[AUTH_ID_LEN]; ++ char optstr[AUTH_ID_LEN]; ++ char *cp, *ifilename; ++ int line_no; ++ DICT_ATTR *attr; ++ DICT_VALUE *dval; ++ DICT_VENDOR *dvend; ++ char buffer[256]; ++ int value; ++ int type; ++ unsigned attr_vendorspec = 0; ++ ++ if ((dictfd = fopen (filename, "r")) == NULL) ++ { ++ rc_log(LOG_ERR, "rc_read_dictionary: couldn't open dictionary %s: %s", ++ filename, strerror(errno)); ++ return -1; ++ } ++ ++ line_no = 0; ++ while (fgets (buffer, sizeof (buffer), dictfd) != NULL) ++ { ++ line_no++; ++ ++ /* Skip empty space */ ++ if (*buffer == '#' || *buffer == '\0' || *buffer == '\n' || \ ++ *buffer == '\r') ++ { ++ continue; ++ } ++ ++ /* Strip out comments */ ++ cp = strchr(buffer, '#'); ++ if (cp != NULL) ++ { ++ *cp = '\0'; ++ } ++ ++ if (strncmp (buffer, "ATTRIBUTE", 9) == 0) ++ { ++ optstr[0] = '\0'; ++ /* Read the ATTRIBUTE line */ ++ if (sscanf (buffer, "%63s%63s%63s%63s%63s", dummystr, namestr, ++ valstr, typestr, optstr) < 4) ++ { ++ rc_log(LOG_ERR, "rc_read_dictionary: invalid attribute on line %d of dictionary %s", ++ line_no, filename); ++ fclose(dictfd); ++ return -1; ++ } ++ ++ /* ++ * Validate all entries ++ */ ++ if (strlen (namestr) > NAME_LENGTH) ++ { ++ rc_log(LOG_ERR, "rc_read_dictionary: invalid name length on line %d of dictionary %s", ++ line_no, filename); ++ fclose(dictfd); ++ return -1; ++ } ++ ++ if (!isdigit (*valstr)) ++ { ++ rc_log(LOG_ERR, ++ "rc_read_dictionary: invalid value on line %d of dictionary %s", ++ line_no, filename); ++ fclose(dictfd); ++ return -1; ++ } ++ value = atoi (valstr); ++ ++ if (strcmp (typestr, "string") == 0) ++ { ++ type = PW_TYPE_STRING; ++ } ++ else if (strcmp (typestr, "integer") == 0) ++ { ++ type = PW_TYPE_INTEGER; ++ } ++ else if (strcmp (typestr, "ipaddr") == 0) ++ { ++ type = PW_TYPE_IPADDR; ++ } ++ else if (strcmp (typestr, "ipv6addr") == 0) ++ { ++ type = PW_TYPE_IPV6ADDR; ++ } ++ else if (strcmp (typestr, "ipv6prefix") == 0) ++ { ++ type = PW_TYPE_IPV6PREFIX; ++ } ++ else if (strcmp (typestr, "date") == 0) ++ { ++ type = PW_TYPE_DATE; ++ } ++ else ++ { ++ rc_log(LOG_ERR, ++ "rc_read_dictionary: invalid type on line %d of dictionary %s", ++ line_no, filename); ++ fclose(dictfd); ++ return -1; ++ } ++ ++ dvend = NULL; ++ if (optstr[0] != '\0') { ++ char *cp1; ++ for (cp1 = optstr; cp1 != NULL; cp1 = cp) { ++ cp = strchr(cp1, ','); ++ if (cp != NULL) { ++ *cp = '\0'; ++ cp++; ++ } ++ if (strncmp(cp1, "vendor=", 7) == 0) ++ cp1 += 7; ++ dvend = rc_dict_findvend(rh, cp1); ++ if (dvend == NULL) { ++ rc_log(LOG_ERR, ++ "rc_read_dictionary: unknown Vendor-Id %s on line %d of dictionary %s", ++ cp1, line_no, filename); ++ fclose(dictfd); ++ return -1; ++ } ++ } ++ } ++ ++ /* Create a new attribute for the list */ ++ if ((attr = malloc (sizeof (DICT_ATTR))) == NULL) ++ { ++ rc_log(LOG_CRIT, "rc_read_dictionary: out of memory"); ++ fclose(dictfd); ++ return -1; ++ } ++ strcpy (attr->name, namestr); ++ attr->value = value | (attr_vendorspec << 16); ++ attr->type = type; ++ ++ if (dvend != NULL) { ++ attr->value = value | (dvend->vendorpec << 16); ++ } else { ++ attr->value = value | (attr_vendorspec << 16); ++ } ++ ++ /* Insert it into the list */ ++ attr->next = rh->dictionary_attributes; ++ rh->dictionary_attributes = attr; ++ } ++ else if (strncmp (buffer, "VALUE", 5) == 0) ++ { ++ /* Read the VALUE line */ ++ if (sscanf (buffer, "%63s%63s%63s%63s", dummystr, attrstr, ++ namestr, valstr) != 4) ++ { ++ rc_log(LOG_ERR, ++ "rc_read_dictionary: invalid value entry on line %d of dictionary %s", ++ line_no, filename); ++ fclose(dictfd); ++ return -1; ++ } ++ ++ /* ++ * Validate all entries ++ */ ++ if (strlen (attrstr) > NAME_LENGTH) ++ { ++ rc_log(LOG_ERR, ++ "rc_read_dictionary: invalid attribute length on line %d of dictionary %s", ++ line_no, filename); ++ fclose(dictfd); ++ return -1; ++ } ++ ++ if (strlen (namestr) > NAME_LENGTH) ++ { ++ rc_log(LOG_ERR, ++ "rc_read_dictionary: invalid name length on line %d of dictionary %s", ++ line_no, filename); ++ fclose(dictfd); ++ return -1; ++ } ++ ++ if (!isdigit (*valstr)) ++ { ++ rc_log(LOG_ERR, ++ "rc_read_dictionary: invalid value on line %d of dictionary %s", ++ line_no, filename); ++ fclose(dictfd); ++ return -1; ++ } ++ value = atoi (valstr); ++ ++ /* Create a new VALUE entry for the list */ ++ if ((dval = malloc (sizeof (DICT_VALUE))) == NULL) ++ { ++ rc_log(LOG_CRIT, "rc_read_dictionary: out of memory"); ++ fclose(dictfd); ++ return -1; ++ } ++ strcpy (dval->attrname, attrstr); ++ strcpy (dval->name, namestr); ++ dval->value = value; ++ ++ /* Insert it into the list */ ++ dval->next = rh->dictionary_values; ++ rh->dictionary_values = dval; ++ } ++ else if (strncmp (buffer, "$INCLUDE", 8) == 0) ++ { ++ /* Read the $INCLUDE line */ ++ if (sscanf (buffer, "%63s%63s", dummystr, namestr) != 2) ++ { ++ rc_log(LOG_ERR, ++ "rc_read_dictionary: invalid include entry on line %d of dictionary %s", ++ line_no, filename); ++ fclose(dictfd); ++ return -1; ++ } ++ ifilename = namestr; ++ /* Append directory if necessary */ ++ if (namestr[0] != '/') { ++ cp = strrchr(filename, '/'); ++ if (cp != NULL) { ++ ifilename = alloca(AUTH_ID_LEN); ++ *cp = '\0'; ++ snprintf(ifilename, AUTH_ID_LEN, "%s/%s", filename, namestr); ++ *cp = '/'; ++ } ++ } ++ if (rc_read_dictionary(rh, ifilename) < 0) ++ { ++ fclose(dictfd); ++ return -1; ++ } ++ } ++ else if (strncmp (buffer, "END-VENDOR", 10) == 0) ++ { ++ attr_vendorspec = 0; ++ } ++ else if (strncmp (buffer, "BEGIN-VENDOR", 12) == 0) ++ { ++ DICT_VENDOR *v; ++ /* Read the vendor name */ ++ if (sscanf (buffer+12, "%63s", dummystr) != 1) ++ { ++ rc_log(LOG_ERR, ++ "rc_read_dictionary: invalid Vendor-Id on line %d of dictionary %s", ++ line_no, filename); ++ fclose(dictfd); ++ return -1; ++ } ++ ++ v = rc_dict_findvend(rh, dummystr); ++ if (v == NULL) { ++ rc_log(LOG_ERR, ++ "rc_read_dictionary: unknown Vendor %s on line %d of dictionary %s", ++ dummystr, line_no, filename); ++ fclose(dictfd); ++ return -1; ++ } ++ ++ attr_vendorspec = v->vendorpec; ++ } ++ else if (strncmp (buffer, "VENDOR", 6) == 0) ++ { ++ /* Read the VALUE line */ ++ if (sscanf (buffer, "%63s%63s%63s", dummystr, attrstr, valstr) != 3) ++ { ++ rc_log(LOG_ERR, ++ "rc_read_dictionary: invalid Vendor-Id on line %d of dictionary %s", ++ line_no, filename); ++ fclose(dictfd); ++ return -1; ++ } ++ ++ /* Validate all entries */ ++ if (strlen (attrstr) > NAME_LENGTH) ++ { ++ rc_log(LOG_ERR, ++ "rc_read_dictionary: invalid attribute length on line %d of dictionary %s", ++ line_no, filename); ++ fclose(dictfd); ++ return -1; ++ } ++ ++ if (!isdigit (*valstr)) ++ { ++ rc_log(LOG_ERR, ++ "rc_read_dictionary: invalid Vendor-Id on line %d of dictionary %s", ++ line_no, filename); ++ fclose(dictfd); ++ return -1; ++ } ++ value = atoi (valstr); ++ ++ /* Create a new VENDOR entry for the list */ ++ dvend = malloc(sizeof(DICT_VENDOR)); ++ if (dvend == NULL) ++ { ++ rc_log(LOG_CRIT, "rc_read_dictionary: out of memory"); ++ fclose(dictfd); ++ return -1; ++ } ++ strcpy (dvend->vendorname, attrstr); ++ dvend->vendorpec = value; ++ ++ /* Insert it into the list */ ++ dvend->next = rh->dictionary_vendors; ++ rh->dictionary_vendors = dvend; ++ } ++ } ++ fclose (dictfd); ++ return 0; ++} ++ ++/* ++ * Function: rc_dict_getattr ++ * ++ * Purpose: Return the full attribute structure based on the ++ * attribute id number. ++ * ++ */ ++ ++DICT_ATTR *rc_dict_getattr (rc_handle const *rh, int attribute) ++{ ++ DICT_ATTR *attr; ++ ++ attr = rh->dictionary_attributes; ++ while (attr != NULL) ++ { ++ if (attr->value == attribute) ++ { ++ return attr; ++ } ++ attr = attr->next; ++ } ++ return NULL; ++} ++ ++/* ++ * Function: rc_dict_findattr ++ * ++ * Purpose: Return the full attribute structure based on the ++ * attribute name. ++ * ++ */ ++ ++DICT_ATTR *rc_dict_findattr (rc_handle const *rh, char const *attrname) ++{ ++ DICT_ATTR *attr; ++ ++ attr = rh->dictionary_attributes; ++ while (attr != NULL) ++ { ++ if (strcasecmp (attr->name, attrname) == 0) ++ { ++ return attr; ++ } ++ attr = attr->next; ++ } ++ return NULL; ++} ++ ++ ++/* ++ * Function: rc_dict_findval ++ * ++ * Purpose: Return the full value structure based on the ++ * value name. ++ * ++ */ ++ ++DICT_VALUE *rc_dict_findval (rc_handle const *rh, char const *valname) ++{ ++ DICT_VALUE *val; ++ ++ val = rh->dictionary_values; ++ while (val != NULL) ++ { ++ if (strcasecmp (val->name, valname) == 0) ++ { ++ return val; ++ } ++ val = val->next; ++ } ++ return NULL; ++} ++ ++/* ++ * Function: rc_dict_findvend ++ * ++ * Purpose: Return the full vendor structure based on the ++ * vendor name. ++ * ++ */ ++ ++DICT_VENDOR * ++rc_dict_findvend(rc_handle const *rh, char const *vendorname) ++{ ++ DICT_VENDOR *vend; ++ ++ for (vend = rh->dictionary_vendors; vend != NULL; vend = vend->next) ++ if (strcasecmp(vend->vendorname, vendorname) == 0) ++ return vend; ++ return NULL; ++} ++ ++/* ++ * Function: rc_dict_getvend ++ * ++ * Purpose: Return the full vendor structure based on the ++ * vendor id number. ++ * ++ */ ++ ++DICT_VENDOR * ++rc_dict_getvend (rc_handle const *rh, int vendorpec) ++{ ++ DICT_VENDOR *vend; ++ ++ for (vend = rh->dictionary_vendors; vend != NULL; vend = vend->next) ++ if (vend->vendorpec == vendorpec) ++ return vend; ++ return NULL; ++} ++ ++/* ++ * Function: dict_getval ++ * ++ * Purpose: Return the full value structure based on the ++ * actual value and the associated attribute name. ++ * ++ */ ++ ++DICT_VALUE * ++rc_dict_getval (rc_handle const *rh, uint32_t value, char const *attrname) ++{ ++ DICT_VALUE *val; ++ ++ val = rh->dictionary_values; ++ while (val != NULL) ++ { ++ if (strcmp (val->attrname, attrname) == 0 && ++ val->value == value) ++ { ++ return val; ++ } ++ val = val->next; ++ } ++ return NULL; ++} ++ ++/* ++ * Function: rc_dict_free ++ * ++ * Purpose: Free allocated av lists ++ * ++ * Arguments: Radius Client handle ++ */ ++ ++void ++rc_dict_free(rc_handle *rh) ++{ ++ DICT_ATTR *attr, *nattr; ++ DICT_VALUE *val, *nval; ++ DICT_VENDOR *vend, *nvend; ++ ++ for (attr = rh->dictionary_attributes; attr != NULL; attr = nattr) { ++ nattr = attr->next; ++ free(attr); ++ } ++ for (val = rh->dictionary_values; val != NULL; val = nval) { ++ nval = val->next; ++ free(val); ++ } ++ for (vend = rh->dictionary_vendors; vend != NULL; vend = nvend) { ++ nvend = vend->next; ++ free(vend); ++ } ++ rh->dictionary_attributes = NULL; ++ rh->dictionary_values = NULL; ++ rh->dictionary_vendors = NULL; ++} +diff --git a/src/plugins/vbng/lib/env.c b/src/plugins/vbng/lib/env.c +new file mode 100644 +index 00000000..03dccf91 +--- /dev/null ++++ b/src/plugins/vbng/lib/env.c +@@ -0,0 +1,147 @@ ++/* ++ * $Id: env.c,v 1.6 2007/06/21 18:07:23 cparker Exp $ ++ * ++ * Copyright (C) 1995,1996,1997 Lars Fenneberg ++ * ++ * See the file COPYRIGHT for the respective terms and conditions. ++ * If the file is missing contact me at lf@elemental.net ++ * and I'll send you a copy. ++ * ++ */ ++ ++#include <config.h> ++#include <includes.h> ++#include <freeradius-client.h> ++ ++/* ++ * Function: rc_new_env ++ * ++ * Purpose: allocate space for a new environment ++ * ++ */ ++ ++ENV *rc_new_env(int size) ++{ ++ ENV *p; ++ ++ if (size < 1) ++ return NULL; ++ ++ if ((p = malloc(sizeof(*p))) == NULL) ++ return NULL; ++ ++ if ((p->env = malloc(size * sizeof(char *))) == NULL) ++ { ++ rc_log(LOG_CRIT, "rc_new_env: out of memory"); ++ free(p); ++ return NULL; ++ } ++ ++ p->env[0] = NULL; ++ ++ p->size = 0; ++ p->maxsize = size; ++ ++ return p; ++} ++ ++/* ++ * Function: rc_free_env ++ * ++ * Purpose: free the space used by an env structure ++ * ++ */ ++ ++void rc_free_env(ENV *env) ++{ ++ free(env->env); ++ free(env); ++} ++ ++/* ++ * Function: rc_add_env ++ * ++ * Purpose: add an environment entry ++ * ++ */ ++ ++int rc_add_env(ENV *env, char const *name, char const *value) ++{ ++ int i; ++ size_t len; ++ char *new_env; ++ ++ for (i = 0; env->env[i] != NULL; i++) ++ { ++ if (strncmp(env->env[i], name, MAX(strchr(env->env[i], '=') - env->env[i], (int)strlen(name))) == 0) ++ break; ++ } ++ ++ if (env->env[i]) ++ { ++ len = strlen(name)+strlen(value)+2; ++ if ((new_env = realloc(env->env[i], len)) == NULL) ++ return -1; ++ ++ env->env[i] = new_env; ++ ++ snprintf(env->env[i], len, "%s=%s", name, value); ++ } else { ++ if (env->size == (env->maxsize-1)) { ++ rc_log(LOG_CRIT, "rc_add_env: not enough space for environment (increase ENV_SIZE)"); ++ return -1; ++ } ++ ++ len = strlen(name)+strlen(value)+2; ++ if ((env->env[env->size] = malloc(len)) == NULL) { ++ rc_log(LOG_CRIT, "rc_add_env: out of memory"); ++ return -1; ++ } ++ ++ snprintf(env->env[env->size], len, "%s=%s", name, value); ++ ++ env->size++; ++ ++ env->env[env->size] = NULL; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Function: rc_import_env ++ * ++ * Purpose: imports an array of null-terminated strings ++ * ++ */ ++ ++int rc_import_env(ENV *env, char const **import) ++{ ++ char *es; ++ ++ while (*import) ++ { ++ es = strchr(*import, '='); ++ ++ if (!es) ++ { ++ import++; ++ continue; ++ } ++ ++ /* ok, i grant thats not very clean... */ ++ *es = '\0'; ++ ++ if (rc_add_env(env, *import, es+1) < 0) ++ { ++ *es = '='; ++ return -1; ++ } ++ ++ *es = '='; ++ ++ import++; ++ } ++ ++ return 0; ++} +diff --git a/src/plugins/vbng/lib/ip_util.c b/src/plugins/vbng/lib/ip_util.c +new file mode 100644 +index 00000000..d686a59e +--- /dev/null ++++ b/src/plugins/vbng/lib/ip_util.c +@@ -0,0 +1,390 @@ ++/* ++ * $Id: ip_util.c,v 1.14 2010/03/17 18:57:01 aland Exp $ ++ * ++ * Copyright (C) 1995,1996,1997 Lars Fenneberg ++ * ++ * Copyright 1992 Livingston Enterprises, Inc. ++ * ++ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan ++ * and Merit Network, Inc. All Rights Reserved ++ * ++ * See the file COPYRIGHT for the respective terms and conditions. ++ * If the file is missing contact me at lf@elemental.net ++ * and I'll send you a copy. ++ * ++ */ ++ ++#include <config.h> ++#include <includes.h> ++#include <freeradius-client.h> ++ ++#define HOSTBUF_SIZE 1024 ++ ++#if !defined(SA_LEN) ++#define SA_LEN(sa) \ ++ (((sa)->sa_family == AF_INET) ? \ ++ sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)) ++#endif ++ ++ ++static __thread size_t hostbuflen=HOSTBUF_SIZE; ++static __thread char *tmphostbuf=NULL; ++ ++/* ++ * Function: rc_gethostbyname ++ * ++ * Purpose: threadsafe replacement for gethostbyname. ++ * ++ * Returns: NULL on failure, hostent pointer on success ++ */ ++ ++struct hostent *rc_gethostbyname(char const *hostname) ++{ ++ struct hostent *hp; ++#ifdef GETHOSTBYNAME_R ++#if defined (GETHOSTBYNAMERSTYLE_SYSV) || defined (GETHOSTBYNAMERSTYLE_GNU) ++ struct hostent hostbuf; ++ int res; ++ int herr; ++ ++ if(!tmphostbuf) tmphostbuf = malloc(hostbuflen); ++#endif ++#endif ++ ++#ifdef GETHOSTBYNAME_R ++#if defined (GETHOSTBYNAMERSTYLE_GNU) ++ while ((res = gethostbyname_r(hostname, &hostbuf, tmphostbuf, hostbuflen, &hp, &herr)) == ERANGE) ++ { ++ /* Enlarge the buffer */ ++ hostbuflen *= 2; ++ tmphostbuf = realloc(tmphostbuf, hostbuflen); ++ } ++ if(res) return NULL; ++#elif defined (GETHOSTBYNAMERSTYLE_SYSV) ++ hp = gethostbyname_r(hostname, &hostbuf, tmphostbuf, hostbuflen, &herr); ++#else ++ hp = gethostbyname(hostname); ++#endif ++#else ++ hp = gethostbyname(hostname); ++#endif ++ ++ if (hp == NULL) { ++ return NULL; ++ } ++ return hp; ++} ++ ++/* ++ * Function: rc_gethostbyname ++ * ++ * Purpose: threadsafe replacement for gethostbyname. ++ * ++ * Returns: NULL on failure, hostent pointer on success ++ */ ++ ++struct hostent *rc_gethostbyaddr(char const *addr, size_t length, int format) ++{ ++ struct hostent *hp; ++#ifdef GETHOSTBYADDR_R ++#if defined (GETHOSTBYADDRRSTYLE_SYSV) || defined (GETHOSTBYADDRRSTYLE_GNU) ++ struct hostent hostbuf; ++ int res; ++ int herr; ++ ++ if(!tmphostbuf) tmphostbuf = malloc(hostbuflen); ++#endif ++#endif ++ ++#ifdef GETHOSTBYADDR_R ++#if defined (GETHOSTBYADDRRSTYLE_GNU) ++ while ((res = gethostbyaddr_r(addr, length, format, &hostbuf, tmphostbuf, hostbuflen, ++ &hp, &herr)) == ERANGE) ++ { ++ /* Enlarge the buffer */ ++ hostbuflen *= 2; ++ tmphostbuf = realloc(tmphostbuf, hostbuflen); ++ } ++ if(res) return NULL; ++#elif GETHOSTBYADDRSTYLE_SYSV ++ hp = gethostbyaddr_r(addr, length, format, &hostbuf, tmphostbuf, hostbuflen, &herr); ++#else ++ hp = gethostbyaddr((char *)&addr, sizeof(struct in_addr), AF_INET); ++#endif ++#else ++ hp = gethostbyaddr((char *)&addr, sizeof(struct in_addr), AF_INET); ++#endif ++ ++ if (hp == NULL) { ++ return NULL; ++ } ++ return hp; ++} ++ ++/* ++ * Function: rc_get_ipaddr ++ * ++ * Purpose: return an IP address in host long notation from a host ++ * name or address in dot notation. ++ * ++ * Returns: 0 on failure ++ */ ++ ++uint32_t rc_get_ipaddr (char const *host) ++{ ++ struct hostent *hp; ++ ++ if (rc_good_ipaddr (host) == 0) ++ { ++ return ntohl(inet_addr (host)); ++ } ++ else if ((hp = rc_gethostbyname(host)) == NULL) ++ { ++ rc_log(LOG_ERR,"rc_get_ipaddr: couldn't resolve hostname: %s", host); ++ return (uint32_t)0; ++ } ++ return ntohl((*(uint32_t *) hp->h_addr)); ++} ++ ++/* ++ * Function: rc_good_ipaddr ++ * ++ * Purpose: check for valid IP address in standard dot notation. ++ * ++ * Returns: 0 on success, -1 when failure ++ * ++ */ ++ ++int rc_good_ipaddr (char const *addr) ++{ ++ int dot_count; ++ int digit_count; ++ ++ if (addr == NULL) ++ return -1; ++ ++ dot_count = 0; ++ digit_count = 0; ++ while (*addr != '\0' && *addr != ' ') ++ { ++ if (*addr == '.') ++ { ++ dot_count++; ++ digit_count = 0; ++ } ++ else if (!isdigit (*addr)) ++ { ++ dot_count = 5; ++ } ++ else ++ { ++ digit_count++; ++ if (digit_count > 3) ++ { ++ dot_count = 5; ++ } ++ } ++ addr++; ++ } ++ if (dot_count != 3) ++ { ++ return -1; ++ } ++ else ++ { ++ return 0; ++ } ++} ++ ++/* ++ * Function: rc_ip_hostname ++ * ++ * Purpose: Return a printable host name (or IP address in dot notation) ++ * for the supplied IP address. ++ * ++ */ ++ ++char const *rc_ip_hostname (uint32_t h_ipaddr) ++{ ++ struct hostent *hp; ++ uint32_t n_ipaddr = htonl (h_ipaddr); ++ ++ if ((hp = rc_gethostbyaddr ((char *) &n_ipaddr, sizeof (struct in_addr), ++ AF_INET)) == NULL) { ++ rc_log(LOG_ERR,"rc_ip_hostname: couldn't look up host by addr: %08lX", h_ipaddr); ++ } ++ ++ return (hp == NULL) ? "unknown" : hp->h_name; ++} ++ ++/* ++ * Function: rc_getport ++ * ++ * Purpose: get the port number for the supplied request type ++ * ++ */ ++ ++unsigned short rc_getport(int type) ++{ ++ struct servent *svp; ++ ++ if ((svp = getservbyname ((type==AUTH)?"radius":"radacct", "udp")) == NULL) ++ { ++ return (type==AUTH) ? PW_AUTH_UDP_PORT : PW_ACCT_UDP_PORT; ++ } else { ++ return ntohs ((unsigned short) svp->s_port); ++ } ++} ++ ++/* ++ * Function: rc_own_hostname ++ * ++ * Purpose: get the hostname of this machine ++ * ++ * Returns -1 on failure, 0 on success ++ * ++ */ ++ ++int ++rc_own_hostname(char *hostname, int len) ++{ ++#ifdef HAVE_UNAME ++ struct utsname uts; ++#endif ++ ++#if defined(HAVE_UNAME) ++ if (uname(&uts) < 0) ++ { ++ rc_log(LOG_ERR,"rc_own_hostname: couldn't get own hostname"); ++ return -1; ++ } ++ strncpy(hostname, uts.nodename, len); ++#elif defined(HAVE_GETHOSTNAME) ++ if (gethostname(hostname, len) < 0) ++ { ++ rc_log(LOG_ERR,"rc_own_hostname: couldn't get own hostname"); ++ return -1; ++ } ++#elif defined(HAVE_SYSINFO) ++ if (sysinfo(SI_HOSTNAME, hostname, len) < 0) ++ { ++ rc_log(LOG_ERR,"rc_own_hostname: couldn't get own hostname"); ++ return -1; ++ } ++#else ++ return -1; ++#endif ++ ++ return 0; ++} ++ ++/* ++ * Function: rc_own_ipaddress ++ * ++ * Purpose: get the IP address of this host in host order ++ * ++ * Returns: IP address on success, 0 on failure ++ * ++ */ ++ ++uint32_t rc_own_ipaddress(rc_handle *rh) ++{ ++ char hostname[256]; ++ ++ if (!rh->this_host_ipaddr) { ++ if (rc_conf_str(rh, "bindaddr") == NULL || ++ strcmp(rc_conf_str(rh, "bindaddr"), "*") == 0) { ++ if (rc_own_hostname(hostname, sizeof(hostname)) < 0) ++ return 0; ++ } else { ++ strncpy(hostname, rc_conf_str(rh, "bindaddr"), sizeof(hostname)); ++ hostname[sizeof(hostname) - 1] = '\0'; ++ } ++ if ((rh->this_host_ipaddr = rc_get_ipaddr (hostname)) == 0) { ++ rc_log(LOG_ERR, "rc_own_ipaddress: couldn't get own IP address"); ++ return 0; ++ } ++ } ++ ++ return rh->this_host_ipaddr; ++} ++ ++/* ++ * Function: rc_own_bind_ipaddress ++ * ++ * Purpose: get the IP address to be used as a source address ++ * for sending requests in host order ++ * ++ * Returns: IP address ++ * ++ */ ++ ++uint32_t rc_own_bind_ipaddress(rc_handle *rh) ++{ ++ char hostname[256]; ++ uint32_t rval; ++ ++ if (rh->this_host_bind_ipaddr != NULL) ++ return *rh->this_host_bind_ipaddr; ++ ++ rh->this_host_bind_ipaddr = malloc(sizeof(*rh->this_host_bind_ipaddr)); ++ if (rh->this_host_bind_ipaddr == NULL) ++ rc_log(LOG_CRIT, "rc_own_bind_ipaddress: out of memory"); ++ if (rc_conf_str(rh, "bindaddr") == NULL || ++ strcmp(rc_conf_str(rh, "bindaddr"), "*") == 0) { ++ rval = INADDR_ANY; ++ } else { ++ strncpy(hostname, rc_conf_str(rh, "bindaddr"), sizeof(hostname)); ++ hostname[sizeof(hostname) - 1] = '\0'; ++ if ((rval = rc_get_ipaddr (hostname)) == 0) { ++ rc_log(LOG_ERR, "rc_own_ipaddress: couldn't get IP address from bindaddr"); ++ rval = INADDR_ANY; ++ } ++ } ++ if (rh->this_host_bind_ipaddr != NULL) ++ *rh->this_host_bind_ipaddr = rval; ++ ++ return rval; ++} ++ ++/* ++ * Function: rc_get_srcaddr ++ * ++ * Purpose: given remote address find local address which the ++ * system will use as a source address for sending ++ * datagrams to that remote address ++ * ++ * Returns: 0 in success, -1 on failure, address is filled into ++ * the first argument. ++ * ++ */ ++int ++rc_get_srcaddr(struct sockaddr *lia, struct sockaddr *ria) ++{ ++ int temp_sock; ++ socklen_t namelen; ++ ++ temp_sock = socket(ria->sa_family, SOCK_DGRAM, 0); ++ if (temp_sock == -1) { ++ rc_log(LOG_ERR, "rc_get_srcaddr: socket: %s", strerror(errno)); ++ return -1; ++ } ++ ++ if (connect(temp_sock, ria, SA_LEN(ria)) != 0) { ++ rc_log(LOG_ERR, "rc_get_srcaddr: connect: %s", ++ strerror(errno)); ++ close(temp_sock); ++ return -1; ++ } ++ ++ namelen = SA_LEN(ria); ++ if (getsockname(temp_sock, lia, &namelen) != 0) { ++ rc_log(LOG_ERR, "rc_get_srcaddr: getsockname: %s", ++ strerror(errno)); ++ close(temp_sock); ++ return -1; ++ } ++ ++ close(temp_sock); ++ return 0; ++} +diff --git a/src/plugins/vbng/lib/libfreeradiusclient.a b/src/plugins/vbng/lib/libfreeradiusclient.a +new file mode 100644 +index 0000000000000000000000000000000000000000..56c91fd880e9d435b62149ded2a0a9067cf8cbd6 +GIT binary patch +literal 367122 +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 +zZ!|xHY~Fp1$%{88XQaKI6goB(S00TJ&	VI+nMQ;@;Fm^CRi(C#c__rjCD}rq>HJ +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 +D0lJ|_ + +literal 0 +HcmV?d00001 + +diff --git a/src/plugins/vbng/lib/libfreeradiusclient.so b/src/plugins/vbng/lib/libfreeradiusclient.so +new file mode 100644 +index 0000000000000000000000000000000000000000..2603f0181c7c43542e59d2907d5bf6c4b0730916 +GIT binary patch +literal 216320 +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%0DhV@0HB5ucRTyXxDm +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 + +literal 0 +HcmV?d00001 + +diff --git a/src/plugins/vbng/lib/log.c b/src/plugins/vbng/lib/log.c +new file mode 100644 +index 00000000..09b01a2e +--- /dev/null ++++ b/src/plugins/vbng/lib/log.c +@@ -0,0 +1,57 @@ ++/* ++ * $Id: log.c,v 1.5 2007/06/21 18:07:23 cparker Exp $ ++ * ++ * Copyright (C) 1995,1996,1997 Lars Fenneberg ++ * ++ * See the file COPYRIGHT for the respective terms and conditions. ++ * If the file is missing contact me at lf@elemental.net ++ * and I'll send you a copy. ++ * ++ */ ++ ++#include <config.h> ++#include <includes.h> ++#include <freeradius-client.h> ++ ++/* ++ * Function: rc_openlog ++ * ++ * Purpose: open log ++ * ++ * Arguments: identification string ++ * ++ * Returns: nothing ++ * ++ */ ++ ++void rc_openlog(char const *ident) ++{ ++#ifndef _MSC_VER /* TODO: Fix me */ ++ openlog(ident, LOG_PID, RC_LOG_FACILITY); ++#endif ++} ++ ++/* ++ * Function: rc_log ++ * ++ * Purpose: log information ++ * ++ * Arguments: priority (just like syslog), rest like printf ++ * ++ * Returns: nothing ++ * ++ */ ++ ++void rc_log(int prio, char const *format, ...) ++{ ++ char buff[1024]; ++ va_list ap; ++ ++ va_start(ap,format); ++ vsnprintf(buff, sizeof(buff), format, ap); ++ va_end(ap); ++ ++#ifndef _MSC_VER /* TODO: Fix me */ ++ syslog(prio, "%s", buff); ++#endif ++} +diff --git a/src/plugins/vbng/lib/md5.c b/src/plugins/vbng/lib/md5.c +new file mode 100644 +index 00000000..2344fb9c +--- /dev/null ++++ b/src/plugins/vbng/lib/md5.c +@@ -0,0 +1,251 @@ ++#include "md5.h" ++ ++/* The below was retrieved from ++ * http://www.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/crypto/md5.c?rev=1.1 ++ * with the following changes: ++ * #includes commented out. ++ * Support context->count as uint32_t[2] instead of uint64_t ++ * u_int* to uint* ++ */ ++ ++/* ++ * This code implements the MD5 message-digest algorithm. ++ * The algorithm is due to Ron Rivest. This code was ++ * written by Colin Plumb in 1993, no copyright is claimed. ++ * This code is in the public domain; do with it what you wish. ++ * ++ * Equivalent code is available from RSA Data Security, Inc. ++ * This code has been tested against that, and is equivalent, ++ * except that you don't need to include two pages of legalese ++ * with every copy. ++ * ++ * To compute the message digest of a chunk of bytes, declare an ++ * MD5Context structure, pass it to MD5Init, call MD5Update as ++ * needed on buffers full of bytes, and then call MD5Final, which ++ * will fill a supplied 16-byte array with the digest. ++ */ ++ ++/*#include <sys/param.h>*/ ++/*#include <sys/systm.h>*/ ++/*#include <crypto/md5.h>*/ ++ ++#define PUT_64BIT_LE(cp, value) do { \ ++ (cp)[7] = (value)[1] >> 24; \ ++ (cp)[6] = (value)[1] >> 16; \ ++ (cp)[5] = (value)[1] >> 8; \ ++ (cp)[4] = (value)[1]; \ ++ (cp)[3] = (value)[0] >> 24; \ ++ (cp)[2] = (value)[0] >> 16; \ ++ (cp)[1] = (value)[0] >> 8; \ ++ (cp)[0] = (value)[0]; } while (0) ++ ++#define PUT_32BIT_LE(cp, value) do { \ ++ (cp)[3] = (value) >> 24; \ ++ (cp)[2] = (value) >> 16; \ ++ (cp)[1] = (value) >> 8; \ ++ (cp)[0] = (value); } while (0) ++ ++static uint8_t PADDING[MD5_BLOCK_LENGTH] = { ++ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ++}; ++ ++/* ++ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious ++ * initialization constants. ++ */ ++void ++MD5Init(MD5_CTX *ctx) ++{ ++ ctx->count[0] = 0; ++ ctx->count[1] = 0; ++ ctx->state[0] = 0x67452301; ++ ctx->state[1] = 0xefcdab89; ++ ctx->state[2] = 0x98badcfe; ++ ctx->state[3] = 0x10325476; ++} ++ ++/* ++ * Update context to reflect the concatenation of another buffer full ++ * of bytes. ++ */ ++void ++MD5Update(MD5_CTX *ctx, uint8_t const *input, size_t len) ++{ ++ size_t have, need; ++ ++ /* Check how many bytes we already have and how many more we need. */ ++ have = (size_t)((ctx->count[0] >> 3) & (MD5_BLOCK_LENGTH - 1)); ++ need = MD5_BLOCK_LENGTH - have; ++ ++ /* Update bitcount */ ++/* ctx->count += (uint64_t)len << 3;*/ ++ if ((ctx->count[0] += ((uint32_t)len << 3)) < (uint32_t)len) { ++ /* Overflowed ctx->count[0] */ ++ ctx->count[1]++; ++ } ++ ctx->count[1] += ((uint32_t)len >> 29); ++ ++ ++ ++ if (len >= need) { ++ if (have != 0) { ++ memcpy(ctx->buffer + have, input, need); ++ MD5Transform(ctx->state, ctx->buffer); ++ input += need; ++ len -= need; ++ have = 0; ++ } ++ ++ /* Process data in MD5_BLOCK_LENGTH-byte chunks. */ ++ while (len >= MD5_BLOCK_LENGTH) { ++ MD5Transform(ctx->state, input); ++ input += MD5_BLOCK_LENGTH; ++ len -= MD5_BLOCK_LENGTH; ++ } ++ } ++ ++ /* Handle any remaining bytes of data. */ ++ if (len != 0) ++ memcpy(ctx->buffer + have, input, len); ++} ++ ++/* ++ * Final wrapup - pad to 64-byte boundary with the bit pattern ++ * 1 0* (64-bit count of bits processed, MSB-first) ++ */ ++void ++MD5Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX *ctx) ++{ ++ uint8_t count[8]; ++ size_t padlen; ++ int i; ++ ++ /* Convert count to 8 bytes in little endian order. */ ++ PUT_64BIT_LE(count, ctx->count); ++ ++ /* Pad out to 56 mod 64. */ ++ padlen = MD5_BLOCK_LENGTH - ++ ((ctx->count[0] >> 3) & (MD5_BLOCK_LENGTH - 1)); ++ if (padlen < 1 + 8) ++ padlen += MD5_BLOCK_LENGTH; ++ MD5Update(ctx, PADDING, padlen - 8); /* padlen - 8 <= 64 */ ++ MD5Update(ctx, count, 8); ++ ++ if (digest != NULL) { ++ for (i = 0; i < 4; i++) ++ PUT_32BIT_LE(digest + i * 4, ctx->state[i]); ++ } ++ memset(ctx, 0, sizeof(*ctx)); /* in case it's sensitive */ ++} ++ ++ ++/* The four core functions - F1 is optimized somewhat */ ++ ++/* #define F1(x, y, z) (x & y | ~x & z) */ ++#define F1(x, y, z) (z ^ (x & (y ^ z))) ++#define F2(x, y, z) F1(z, x, y) ++#define F3(x, y, z) (x ^ y ^ z) ++#define F4(x, y, z) (y ^ (x | ~z)) ++ ++/* This is the central step in the MD5 algorithm. */ ++#define MD5STEP(f, w, x, y, z, data, s) \ ++ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) ++ ++/* ++ * The core of the MD5 algorithm, this alters an existing MD5 hash to ++ * reflect the addition of 16 longwords of new data. MD5Update blocks ++ * the data and converts bytes into longwords for this routine. ++ */ ++void ++MD5Transform(uint32_t state[4], uint8_t const block[MD5_BLOCK_LENGTH]) ++{ ++ uint32_t a, b, c, d, in[MD5_BLOCK_LENGTH / 4]; ++ ++ for (a = 0; a < MD5_BLOCK_LENGTH / 4; a++) { ++ in[a] = (uint32_t)( ++ (uint32_t)(block[a * 4 + 0]) | ++ (uint32_t)(block[a * 4 + 1]) << 8 | ++ (uint32_t)(block[a * 4 + 2]) << 16 | ++ (uint32_t)(block[a * 4 + 3]) << 24); ++ } ++ ++ a = state[0]; ++ b = state[1]; ++ c = state[2]; ++ d = state[3]; ++ ++ MD5STEP(F1, a, b, c, d, in[ 0] + 0xd76aa478, 7); ++ MD5STEP(F1, d, a, b, c, in[ 1] + 0xe8c7b756, 12); ++ MD5STEP(F1, c, d, a, b, in[ 2] + 0x242070db, 17); ++ MD5STEP(F1, b, c, d, a, in[ 3] + 0xc1bdceee, 22); ++ MD5STEP(F1, a, b, c, d, in[ 4] + 0xf57c0faf, 7); ++ MD5STEP(F1, d, a, b, c, in[ 5] + 0x4787c62a, 12); ++ MD5STEP(F1, c, d, a, b, in[ 6] + 0xa8304613, 17); ++ MD5STEP(F1, b, c, d, a, in[ 7] + 0xfd469501, 22); ++ MD5STEP(F1, a, b, c, d, in[ 8] + 0x698098d8, 7); ++ MD5STEP(F1, d, a, b, c, in[ 9] + 0x8b44f7af, 12); ++ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); ++ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); ++ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); ++ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); ++ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); ++ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); ++ ++ MD5STEP(F2, a, b, c, d, in[ 1] + 0xf61e2562, 5); ++ MD5STEP(F2, d, a, b, c, in[ 6] + 0xc040b340, 9); ++ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); ++ MD5STEP(F2, b, c, d, a, in[ 0] + 0xe9b6c7aa, 20); ++ MD5STEP(F2, a, b, c, d, in[ 5] + 0xd62f105d, 5); ++ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); ++ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); ++ MD5STEP(F2, b, c, d, a, in[ 4] + 0xe7d3fbc8, 20); ++ MD5STEP(F2, a, b, c, d, in[ 9] + 0x21e1cde6, 5); ++ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); ++ MD5STEP(F2, c, d, a, b, in[ 3] + 0xf4d50d87, 14); ++ MD5STEP(F2, b, c, d, a, in[ 8] + 0x455a14ed, 20); ++ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); ++ MD5STEP(F2, d, a, b, c, in[ 2] + 0xfcefa3f8, 9); ++ MD5STEP(F2, c, d, a, b, in[ 7] + 0x676f02d9, 14); ++ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); ++ ++ MD5STEP(F3, a, b, c, d, in[ 5] + 0xfffa3942, 4); ++ MD5STEP(F3, d, a, b, c, in[ 8] + 0x8771f681, 11); ++ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); ++ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); ++ MD5STEP(F3, a, b, c, d, in[ 1] + 0xa4beea44, 4); ++ MD5STEP(F3, d, a, b, c, in[ 4] + 0x4bdecfa9, 11); ++ MD5STEP(F3, c, d, a, b, in[ 7] + 0xf6bb4b60, 16); ++ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); ++ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); ++ MD5STEP(F3, d, a, b, c, in[ 0] + 0xeaa127fa, 11); ++ MD5STEP(F3, c, d, a, b, in[ 3] + 0xd4ef3085, 16); ++ MD5STEP(F3, b, c, d, a, in[ 6] + 0x04881d05, 23); ++ MD5STEP(F3, a, b, c, d, in[ 9] + 0xd9d4d039, 4); ++ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); ++ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); ++ MD5STEP(F3, b, c, d, a, in[2 ] + 0xc4ac5665, 23); ++ ++ MD5STEP(F4, a, b, c, d, in[ 0] + 0xf4292244, 6); ++ MD5STEP(F4, d, a, b, c, in[7 ] + 0x432aff97, 10); ++ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); ++ MD5STEP(F4, b, c, d, a, in[5 ] + 0xfc93a039, 21); ++ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); ++ MD5STEP(F4, d, a, b, c, in[3 ] + 0x8f0ccc92, 10); ++ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); ++ MD5STEP(F4, b, c, d, a, in[1 ] + 0x85845dd1, 21); ++ MD5STEP(F4, a, b, c, d, in[8 ] + 0x6fa87e4f, 6); ++ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); ++ MD5STEP(F4, c, d, a, b, in[6 ] + 0xa3014314, 15); ++ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); ++ MD5STEP(F4, a, b, c, d, in[4 ] + 0xf7537e82, 6); ++ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); ++ MD5STEP(F4, c, d, a, b, in[2 ] + 0x2ad7d2bb, 15); ++ MD5STEP(F4, b, c, d, a, in[9 ] + 0xeb86d391, 21); ++ ++ state[0] += a; ++ state[1] += b; ++ state[2] += c; ++ state[3] += d; ++} +diff --git a/src/plugins/vbng/lib/md5.h b/src/plugins/vbng/lib/md5.h +new file mode 100644 +index 00000000..fcbaf91f +--- /dev/null ++++ b/src/plugins/vbng/lib/md5.h +@@ -0,0 +1,86 @@ ++/* ++ * md5.h Structures and prototypes for md5. ++ * ++ * Version: $Id: md5.h,v 1.2 2007/06/21 18:07:24 cparker Exp $ ++ * License: BSD, but largely derived from a public domain source. ++ * ++ */ ++ ++#ifndef _RCRAD_MD5_H ++#define _RCRAD_MD5_H ++ ++#include "config.h" ++ ++#ifdef HAVE_NETTLE ++ ++#include <nettle/md5-compat.h> ++ ++#else ++ ++#ifdef HAVE_INTTYPES_H ++#include <inttypes.h> ++#endif ++ ++#ifdef HAVE_SYS_TYPES_H ++#include <sys/types.h> ++#endif ++ ++#ifdef HAVE_STDINT_H ++#include <stdint.h> ++#endif ++ ++#include <string.h> ++/* ++ * FreeRADIUS Client defines to ensure globally unique MD5 function names, ++ * so that we don't pick up vendor-specific broken MD5 libraries. ++ */ ++#define MD5_CTX librad_MD5_CTX ++#define MD5Init librad_MD5Init ++#define MD5Update librad_MD5Update ++#define MD5Final librad_MD5Final ++#define MD5Transform librad_MD5Transform ++ ++/* The below was retrieved from ++ * http://www.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/crypto/md5.h?rev=1.1 ++ * With the following changes: uint64_t => uint32_t[2] ++ * Commented out #include <sys/cdefs.h> ++ * Commented out the __BEGIN and __END _DECLS, and the __attributes. ++ */ ++ ++/* ++ * This code implements the MD5 message-digest algorithm. ++ * The algorithm is due to Ron Rivest. This code was ++ * written by Colin Plumb in 1993, no copyright is claimed. ++ * This code is in the public domain; do with it what you wish. ++ * ++ * Equivalent code is available from RSA Data Security, Inc. ++ * This code has been tested against that, and is equivalent, ++ * except that you don't need to include two pages of legalese ++ * with every copy. ++ */ ++ ++#define MD5_BLOCK_LENGTH 64 ++#define MD5_DIGEST_LENGTH 16 ++ ++typedef struct MD5Context { ++ uint32_t state[4]; /* state */ ++ uint32_t count[2]; /* number of bits, mod 2^64 */ ++ uint8_t buffer[MD5_BLOCK_LENGTH]; /* input buffer */ ++} MD5_CTX; ++ ++/* include <sys/cdefs.h> */ ++ ++/* __BEGIN_DECLS */ ++void MD5Init(MD5_CTX *); ++void MD5Update(MD5_CTX *, uint8_t const *, size_t) ++/* __attribute__((__bounded__(__string__,2,3)))*/; ++void MD5Final(uint8_t [MD5_DIGEST_LENGTH], MD5_CTX *) ++/* __attribute__((__bounded__(__minbytes__,1,MD5_DIGEST_LENGTH)))*/; ++void MD5Transform(uint32_t [4], uint8_t const [MD5_BLOCK_LENGTH]) ++/* __attribute__((__bounded__(__minbytes__,1,4)))*/ ++/* __attribute__((__bounded__(__minbytes__,2,MD5_BLOCK_LENGTH)))*/; ++/* __END_DECLS */ ++ ++#endif /* HAVE_NETTLE */ ++ ++#endif /* _RCRAD_MD5_H */ +diff --git a/src/plugins/vbng/lib/options.h b/src/plugins/vbng/lib/options.h +new file mode 100644 +index 00000000..05b66dfd +--- /dev/null ++++ b/src/plugins/vbng/lib/options.h +@@ -0,0 +1,57 @@ ++/* ++ * $Id: options.h,v 1.6 2008/03/05 16:35:20 cparker Exp $ ++ * ++ * Copyright (C) 1996 Lars Fenneberg ++ * ++ * See the file COPYRIGHT for the respective terms and conditions. ++ * If the file is missing contact me at lf@elemental.net ++ * and I'll send you a copy. ++ * ++ */ ++ ++#define OPTION_LEN 64 ++ ++/* ids for different option types */ ++#define OT_STR (1<<0) /* string */ ++#define OT_INT (1<<1) /* integer */ ++#define OT_SRV (1<<2) /* server list */ ++#define OT_AUO (1<<3) /* authentication order */ ++ ++#define OT_ANY ((unsigned int)~0) /* used internally */ ++ ++/* status types */ ++#define ST_UNDEF (1<<0) /* option is undefined */ ++ ++typedef struct _option { ++ char name[OPTION_LEN]; /* name of the option */ ++ int type, status; /* type and status */ ++ void *val; /* pointer to option value */ ++} OPTION; ++ ++static OPTION config_options_default[] = { ++/* internally used options */ ++{"config_file", OT_STR, ST_UNDEF, NULL}, ++/* General options */ ++{"auth_order", OT_AUO, ST_UNDEF, NULL}, ++{"login_tries", OT_INT, ST_UNDEF, NULL}, ++{"login_timeout", OT_INT, ST_UNDEF, NULL}, ++{"nologin", OT_STR, ST_UNDEF, NULL}, ++{"issue", OT_STR, ST_UNDEF, NULL}, ++/* RADIUS specific options */ ++{"authserver", OT_SRV, ST_UNDEF, NULL}, ++{"acctserver", OT_SRV, ST_UNDEF, NULL}, ++{"servers", OT_STR, ST_UNDEF, NULL}, ++{"dictionary", OT_STR, ST_UNDEF, NULL}, ++{"login_radius", OT_STR, ST_UNDEF, NULL}, ++{"seqfile", OT_STR, ST_UNDEF, NULL}, ++{"mapfile", OT_STR, ST_UNDEF, NULL}, ++{"default_realm", OT_STR, ST_UNDEF, NULL}, ++{"radius_timeout", OT_INT, ST_UNDEF, NULL}, ++{"radius_retries", OT_INT, ST_UNDEF, NULL}, ++{"radius_deadtime", OT_INT, ST_UNDEF, NULL}, ++{"bindaddr", OT_STR, ST_UNDEF, NULL}, ++/* local options */ ++{"login_local", OT_STR, ST_UNDEF, NULL}, ++}; ++ ++#define NUM_OPTIONS ((sizeof(config_options_default))/(sizeof(config_options_default[0]))) +diff --git a/src/plugins/vbng/lib/rc-md5.c b/src/plugins/vbng/lib/rc-md5.c +new file mode 100644 +index 00000000..be9fbcbd +--- /dev/null ++++ b/src/plugins/vbng/lib/rc-md5.c +@@ -0,0 +1,24 @@ ++/* MD5 message-digest algorithm */ ++ ++/* This file is licensed under the BSD License, but is largely derived from ++ * public domain source code ++ */ ++ ++/* ++ * FORCE MD5 TO USE OUR MD5 HEADER FILE! ++ * ++ * If we don't do this, it might pick up the systems broken MD5. ++ * - Alan DeKok <aland@ox.org> ++ */ ++#include "rc-md5.h" ++ ++void rc_md5_calc(unsigned char *output, unsigned char const *input, ++ size_t inlen) ++{ ++ MD5_CTX context; ++ ++ MD5Init(&context); ++ MD5Update(&context, input, inlen); ++ MD5Final(output, &context); ++} ++ +diff --git a/src/plugins/vbng/lib/rc-md5.h b/src/plugins/vbng/lib/rc-md5.h +new file mode 100644 +index 00000000..a30f16d3 +--- /dev/null ++++ b/src/plugins/vbng/lib/rc-md5.h +@@ -0,0 +1,27 @@ ++/* ++ * md5.h Structures and prototypes for md5. ++ * ++ * Version: $Id: md5.h,v 1.2 2007/06/21 18:07:24 cparker Exp $ ++ * License: BSD ++ * ++ */ ++ ++#ifndef _RC_MD5_H ++#define _RC_MD5_H ++ ++#include "config.h" ++ ++#ifdef HAVE_NETTLE ++ ++#include <nettle/md5-compat.h> ++ ++#else ++ ++#include "md5.h" ++ ++#endif /* HAVE_NETTLE */ ++ ++void rc_md5_calc(unsigned char *output, unsigned char const *input, ++ size_t inputlen); ++ ++#endif /* _RC_MD5_H */ +diff --git a/src/plugins/vbng/lib/sendserver.c b/src/plugins/vbng/lib/sendserver.c +new file mode 100644 +index 00000000..bfdd9a26 +--- /dev/null ++++ b/src/plugins/vbng/lib/sendserver.c +@@ -0,0 +1,631 @@ ++/* ++ * $Id: sendserver.c,v 1.30 2010/06/15 09:22:52 aland Exp $ ++ * ++ * Copyright (C) 1995,1996,1997 Lars Fenneberg ++ * ++ * Copyright 1992 Livingston Enterprises, Inc. ++ * ++ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan ++ * and Merit Network, Inc. All Rights Reserved ++ * ++ * See the file COPYRIGHT for the respective terms and conditions. ++ * If the file is missing contact me at lf@elemental.net ++ * and I'll send you a copy. ++ * ++ */ ++ ++#include <poll.h> ++ ++#include <config.h> ++#include <includes.h> ++#include <freeradius-client.h> ++#include <pathnames.h> ++ ++#define SA(p) ((struct sockaddr *)(p)) ++ ++static void rc_random_vector (unsigned char *); ++static int rc_check_reply (AUTH_HDR *, int, char const *, unsigned char const *, unsigned char); ++ ++/* ++ * Function: rc_pack_list ++ * ++ * Purpose: Packs an attribute value pair list into a buffer. ++ * ++ * Returns: Number of octets packed. ++ * ++ */ ++ ++static int rc_pack_list (VALUE_PAIR *vp, char *secret, AUTH_HDR *auth) ++{ ++ int length, i, pc, padded_length; ++ int total_length = 0; ++ size_t secretlen; ++ uint32_t lvalue, vendor; ++ unsigned char passbuf[MAX(AUTH_PASS_LEN, CHAP_VALUE_LENGTH)]; ++ unsigned char md5buf[256]; ++ unsigned char *buf, *vector, *vsa_length_ptr; ++ ++ buf = auth->data; ++ ++ while (vp != NULL) ++ { ++ vsa_length_ptr = NULL; ++ if (VENDOR(vp->attribute) != 0) { ++ *buf++ = PW_VENDOR_SPECIFIC; ++ vsa_length_ptr = buf; ++ *buf++ = 6; ++ vendor = htonl(VENDOR(vp->attribute)); ++ memcpy(buf, &vendor, sizeof(uint32_t)); ++ buf += 4; ++ total_length += 6; ++ } ++ *buf++ = (vp->attribute & 0xff); ++ ++ switch (vp->attribute) ++ { ++ case PW_USER_PASSWORD: ++ ++ /* Encrypt the password */ ++ ++ /* Chop off password at AUTH_PASS_LEN */ ++ length = vp->lvalue; ++ if (length > AUTH_PASS_LEN) ++ length = AUTH_PASS_LEN; ++ ++ /* Calculate the padded length */ ++ padded_length = (length+(AUTH_VECTOR_LEN-1)) & ~(AUTH_VECTOR_LEN-1); ++ ++ /* Record the attribute length */ ++ *buf++ = padded_length + 2; ++ if (vsa_length_ptr != NULL) *vsa_length_ptr += padded_length + 2; ++ ++ /* Pad the password with zeros */ ++ memset ((char *) passbuf, '\0', AUTH_PASS_LEN); ++ memcpy ((char *) passbuf, vp->strvalue, (size_t) length); ++ ++ secretlen = strlen (secret); ++ vector = (unsigned char *)auth->vector; ++ for(i = 0; i < padded_length; i += AUTH_VECTOR_LEN) ++ { ++ /* Calculate the MD5 digest*/ ++ strcpy ((char *) md5buf, secret); ++ memcpy ((char *) md5buf + secretlen, vector, ++ AUTH_VECTOR_LEN); ++ rc_md5_calc (buf, md5buf, secretlen + AUTH_VECTOR_LEN); ++ ++ /* Remeber the start of the digest */ ++ vector = buf; ++ ++ /* Xor the password into the MD5 digest */ ++ for (pc = i; pc < (i + AUTH_VECTOR_LEN); pc++) ++ { ++ *buf++ ^= passbuf[pc]; ++ } ++ } ++ ++ total_length += padded_length + 2; ++ ++ break; ++#if 0 ++ case PW_CHAP_PASSWORD: ++ ++ *buf++ = CHAP_VALUE_LENGTH + 2; ++ if (vsa_length_ptr != NULL) *vsa_length_ptr += CHAP_VALUE_LENGTH + 2; ++ ++ /* Encrypt the Password */ ++ length = vp->lvalue; ++ if (length > CHAP_VALUE_LENGTH) ++ { ++ length = CHAP_VALUE_LENGTH; ++ } ++ memset ((char *) passbuf, '\0', CHAP_VALUE_LENGTH); ++ memcpy ((char *) passbuf, vp->strvalue, (size_t) length); ++ ++ /* Calculate the MD5 Digest */ ++ secretlen = strlen (secret); ++ strcpy ((char *) md5buf, secret); ++ memcpy ((char *) md5buf + secretlen, (char *) auth->vector, ++ AUTH_VECTOR_LEN); ++ rc_md5_calc (buf, md5buf, secretlen + AUTH_VECTOR_LEN); ++ ++ /* Xor the password into the MD5 digest */ ++ for (i = 0; i < CHAP_VALUE_LENGTH; i++) ++ { ++ *buf++ ^= passbuf[i]; ++ } ++ total_length += CHAP_VALUE_LENGTH + 2; ++ ++ break; ++#endif ++ default: ++ switch (vp->type) ++ { ++ case PW_TYPE_STRING: ++ length = vp->lvalue; ++ *buf++ = length + 2; ++ if (vsa_length_ptr != NULL) *vsa_length_ptr += length + 2; ++ memcpy (buf, vp->strvalue, (size_t) length); ++ buf += length; ++ total_length += length + 2; ++ break; ++ ++ case PW_TYPE_IPV6ADDR: ++ length = 16; ++ if (vsa_length_ptr != NULL) *vsa_length_ptr += length + 2; ++ memcpy (buf, vp->strvalue, (size_t) length); ++ buf += length; ++ total_length += length + 2; ++ break; ++ ++ case PW_TYPE_IPV6PREFIX: ++ length = vp->lvalue; ++ if (vsa_length_ptr != NULL) *vsa_length_ptr += length + 2; ++ memcpy (buf, vp->strvalue, (size_t) length); ++ buf += length; ++ total_length += length + 2; ++ break; ++ ++ case PW_TYPE_INTEGER: ++ case PW_TYPE_IPADDR: ++ case PW_TYPE_DATE: ++ *buf++ = sizeof (uint32_t) + 2; ++ if (vsa_length_ptr != NULL) *vsa_length_ptr += sizeof(uint32_t) + 2; ++ lvalue = htonl (vp->lvalue); ++ memcpy (buf, (char *) &lvalue, sizeof (uint32_t)); ++ buf += sizeof (uint32_t); ++ total_length += sizeof (uint32_t) + 2; ++ break; ++ ++ default: ++ break; ++ } ++ break; ++ } ++ vp = vp->next; ++ } ++ return total_length; ++} ++ ++/* Function strappend ++ * ++ * Purpose: appends a string to the provided buffer ++ */ ++static void strappend(char *dest, unsigned max_size, int *pos, const char *src) ++{ ++ unsigned len = strlen(src) + 1; ++ ++ if (*pos == -1) ++ return; ++ ++ if (len + *pos > max_size) { ++ *pos = -1; ++ return; ++ } ++ ++ memcpy(&dest[*pos], src, len); ++ *pos += len-1; ++ return; ++} ++ ++/* ++ * Function: rc_send_server ++ * ++ * Purpose: send a request to a RADIUS server and wait for the reply ++ * ++ */ ++ ++int rc_send_server (rc_handle *rh, SEND_DATA *data, char *msg) ++{ ++ int sockfd; ++ struct sockaddr_in sinlocal; ++ struct sockaddr_in sinremote; ++ AUTH_HDR *auth, *recv_auth; ++ uint32_t auth_ipaddr, nas_ipaddr; ++ char *server_name; /* Name of server to query */ ++ socklen_t salen; ++ int result = 0; ++ int total_length; ++ int length, pos; ++ int retry_max; ++ size_t secretlen; ++ char secret[MAX_SECRET_LENGTH + 1]; ++ unsigned char vector[AUTH_VECTOR_LEN]; ++ char recv_buffer[BUFFER_LEN]; ++ char send_buffer[BUFFER_LEN]; ++ int retries; ++ VALUE_PAIR *vp; ++ struct pollfd pfd; ++ double start_time, timeout; ++ ++ server_name = data->server; ++ if (server_name == NULL || server_name[0] == '\0') ++ return ERROR_RC; ++ ++ if ((vp = rc_avpair_get(data->send_pairs, PW_SERVICE_TYPE, 0)) && \ ++ (vp->lvalue == PW_ADMINISTRATIVE)) ++ { ++ strcpy(secret, MGMT_POLL_SECRET); ++ if ((auth_ipaddr = rc_get_ipaddr(server_name)) == 0) ++ return ERROR_RC; ++ } ++ else ++ { ++ if(data->secret != NULL) ++ { ++ strncpy(secret, data->secret, MAX_SECRET_LENGTH); ++ } ++ /* ++ else ++ { ++ */ ++ if (rc_find_server (rh, server_name, &auth_ipaddr, secret) != 0) ++ { ++ rc_log(LOG_ERR, "rc_send_server: unable to find server: %s", server_name); ++ return ERROR_RC; ++ } ++ /*}*/ ++ } ++ ++ DEBUG(LOG_ERR, "DEBUG: rc_send_server: creating socket to: %s", server_name); ++ ++ sockfd = socket (AF_INET, SOCK_DGRAM, 0); ++ if (sockfd < 0) ++ { ++ memset (secret, '\0', sizeof (secret)); ++ rc_log(LOG_ERR, "rc_send_server: socket: %s", strerror(errno)); ++ return ERROR_RC; ++ } ++ ++ memset((char *)&sinlocal, '\0', sizeof(sinlocal)); ++ sinlocal.sin_family = AF_INET; ++ sinlocal.sin_addr.s_addr = htonl(rc_own_bind_ipaddress(rh)); ++ sinlocal.sin_port = htons((unsigned short) 0); ++ if (bind(sockfd, SA(&sinlocal), sizeof(sinlocal)) < 0) ++ { ++ close (sockfd); ++ memset (secret, '\0', sizeof (secret)); ++ rc_log(LOG_ERR, "rc_send_server: bind: %s: %s", server_name, strerror(errno)); ++ return ERROR_RC; ++ } ++ ++ retry_max = data->retries; /* Max. numbers to try for reply */ ++ retries = 0; /* Init retry cnt for blocking call */ ++ ++ memset ((char *)&sinremote, '\0', sizeof(sinremote)); ++ sinremote.sin_family = AF_INET; ++ sinremote.sin_addr.s_addr = htonl (auth_ipaddr); ++ sinremote.sin_port = htons ((unsigned short) data->svc_port); ++ ++ /* ++ * Fill in NAS-IP-Address (if needed) ++ */ ++ if (rc_avpair_get(data->send_pairs, PW_NAS_IP_ADDRESS, 0) == NULL) { ++ if (sinlocal.sin_addr.s_addr == htonl(INADDR_ANY)) { ++ if (rc_get_srcaddr(SA(&sinlocal), SA(&sinremote)) != 0) { ++ close (sockfd); ++ memset (secret, '\0', sizeof (secret)); ++ return ERROR_RC; ++ } ++ } ++ nas_ipaddr = ntohl(sinlocal.sin_addr.s_addr); ++ rc_avpair_add(rh, &(data->send_pairs), PW_NAS_IP_ADDRESS, ++ &nas_ipaddr, 0, 0); ++ } ++ ++ /* Build a request */ ++ auth = (AUTH_HDR *) send_buffer; ++ auth->code = data->code; ++ auth->id = data->seq_nbr; ++ ++ if (data->code == PW_ACCOUNTING_REQUEST) ++ { ++ total_length = rc_pack_list(data->send_pairs, secret, auth) + AUTH_HDR_LEN; ++ ++ auth->length = htons ((unsigned short) total_length); ++ ++ memset((char *) auth->vector, 0, AUTH_VECTOR_LEN); ++ secretlen = strlen (secret); ++ memcpy ((char *) auth + total_length, secret, secretlen); ++ rc_md5_calc (vector, (unsigned char *) auth, total_length + secretlen); ++ memcpy ((char *) auth->vector, (char *) vector, AUTH_VECTOR_LEN); ++ } ++ else ++ { ++ rc_random_vector (vector); ++ memcpy ((char *) auth->vector, (char *) vector, AUTH_VECTOR_LEN); ++ ++ total_length = rc_pack_list(data->send_pairs, secret, auth) + AUTH_HDR_LEN; ++ ++ auth->length = htons ((unsigned short) total_length); ++ } ++ ++ DEBUG(LOG_ERR, "DEBUG: local %s : 0, remote %s : %u\n", ++ inet_ntoa(sinlocal.sin_addr), ++ inet_ntoa(sinremote.sin_addr), data->svc_port); ++ ++ for (;;) ++ { ++ sendto (sockfd, (char *) auth, (unsigned int) total_length, (int) 0, ++ SA(&sinremote), sizeof (struct sockaddr_in)); ++ ++ pfd.fd = sockfd; ++ pfd.events = POLLIN; ++ pfd.revents = 0; ++ start_time = rc_getctime(); ++ for (timeout = data->timeout; timeout > 0; ++ timeout -= rc_getctime() - start_time) { ++ result = poll(&pfd, 1, timeout * 1000); ++ if (result != -1 || errno != EINTR) ++ break; ++ } ++ if (result == -1) ++ { ++ rc_log(LOG_ERR, "rc_send_server: poll: %s", strerror(errno)); ++ memset (secret, '\0', sizeof (secret)); ++ close (sockfd); ++ return ERROR_RC; ++ } ++ if (result == 1 && (pfd.revents & POLLIN) != 0) ++ break; ++ ++ /* ++ * Timed out waiting for response. Retry "retry_max" times ++ * before giving up. If retry_max = 0, don't retry at all. ++ */ ++ if (retries++ >= retry_max) ++ { ++ rc_log(LOG_ERR, ++ "rc_send_server: no reply from RADIUS server %s:%u, %s", ++ rc_ip_hostname (auth_ipaddr), data->svc_port, inet_ntoa(sinremote.sin_addr)); ++ close (sockfd); ++ memset (secret, '\0', sizeof (secret)); ++ return TIMEOUT_RC; ++ } ++ } ++ salen = sizeof(sinremote); ++ length = recvfrom (sockfd, (char *) recv_buffer, ++ (int) sizeof (recv_buffer), ++ (int) 0, SA(&sinremote), &salen); ++ ++ if (length <= 0) ++ { ++ rc_log(LOG_ERR, "rc_send_server: recvfrom: %s:%d: %s", server_name,\ ++ data->svc_port, strerror(errno)); ++ close (sockfd); ++ memset (secret, '\0', sizeof (secret)); ++ return ERROR_RC; ++ } ++ ++ recv_auth = (AUTH_HDR *)recv_buffer; ++ ++ if (length < AUTH_HDR_LEN || length < ntohs(recv_auth->length)) { ++ rc_log(LOG_ERR, "rc_send_server: recvfrom: %s:%d: reply is too short", ++ server_name, data->svc_port); ++ close(sockfd); ++ memset(secret, '\0', sizeof(secret)); ++ return ERROR_RC; ++ } ++ ++ result = rc_check_reply (recv_auth, BUFFER_LEN, secret, vector, data->seq_nbr); ++ ++ length = ntohs(recv_auth->length) - AUTH_HDR_LEN; ++ if (length > 0) { ++ data->receive_pairs = rc_avpair_gen(rh, NULL, recv_auth->data, ++ length, 0); ++ } else { ++ data->receive_pairs = NULL; ++ } ++ ++ close (sockfd); ++ memset (secret, '\0', sizeof (secret)); ++ ++ if (result != OK_RC) return result; ++ ++ if (msg) { ++ *msg = '\0'; ++ pos = 0; ++ vp = data->receive_pairs; ++ while (vp) ++ { ++ if ((vp = rc_avpair_get(vp, PW_REPLY_MESSAGE, 0))) ++ { ++ strappend(msg, PW_MAX_MSG_SIZE, &pos, vp->strvalue); ++ strappend(msg, PW_MAX_MSG_SIZE, &pos, "\n"); ++ vp = vp->next; ++ } ++ } ++ } ++ ++ if ((recv_auth->code == PW_ACCESS_ACCEPT) || ++ (recv_auth->code == PW_PASSWORD_ACK) || ++ (recv_auth->code == PW_ACCOUNTING_RESPONSE)) ++ { ++ result = OK_RC; ++ } ++ else if ((recv_auth->code == PW_ACCESS_REJECT) || ++ (recv_auth->code == PW_PASSWORD_REJECT)) ++ { ++ result = REJECT_RC; ++ } ++ else ++ { ++ result = BADRESP_RC; ++ } ++ ++ return result; ++} ++ ++/* ++ * Function: rc_check_reply ++ * ++ * Purpose: verify items in returned packet. ++ * ++ * Returns: OK_RC -- upon success, ++ * BADRESP_RC -- if anything looks funny. ++ * ++ */ ++ ++static int rc_check_reply (AUTH_HDR *auth, int bufferlen, char const *secret, unsigned char const *vector, uint8_t seq_nbr) ++{ ++ int secretlen; ++ int totallen; ++ unsigned char calc_digest[AUTH_VECTOR_LEN]; ++ unsigned char reply_digest[AUTH_VECTOR_LEN]; ++#ifdef DIGEST_DEBUG ++ uint8_t *ptr; ++#endif ++ ++ totallen = ntohs (auth->length); ++ secretlen = (int)strlen (secret); ++ ++ /* Do sanity checks on packet length */ ++ if ((totallen < 20) || (totallen > 4096)) ++ { ++ rc_log(LOG_ERR, "rc_check_reply: received RADIUS server response with invalid length"); ++ return BADRESP_RC; ++ } ++ ++ /* Verify buffer space, should never trigger with current buffer size and check above */ ++ if ((totallen + secretlen) > bufferlen) ++ { ++ rc_log(LOG_ERR, "rc_check_reply: not enough buffer space to verify RADIUS server response"); ++ return BADRESP_RC; ++ } ++ ++ /* Verify that id (seq. number) matches what we sent */ ++ if (auth->id != seq_nbr) ++ { ++ rc_log(LOG_ERR, "rc_check_reply: received non-matching id in RADIUS server response"); ++ return BADRESP_RC; ++ } ++ ++ /* Verify the reply digest */ ++ memcpy ((char *) reply_digest, (char *) auth->vector, AUTH_VECTOR_LEN); ++ memcpy ((char *) auth->vector, (char *) vector, AUTH_VECTOR_LEN); ++ memcpy ((char *) auth + totallen, secret, secretlen); ++#ifdef DIGEST_DEBUG ++ rc_log(LOG_ERR, "Calculating digest on:"); ++ for (ptr = (u_char *)auth; ptr < ((u_char *)auth) + totallen + secretlen; ptr += 32) { ++ char buf[65]; ++ int i; ++ ++ buf[0] = '\0'; ++ for (i = 0; i < 32; i++) { ++ if (ptr + i >= ((u_char *)auth) + totallen + secretlen) ++ break; ++ sprintf(buf + i * 2, "%.2X", ptr[i]); ++ } ++ rc_log(LOG_ERR, " %s", buf); ++ } ++#endif ++ rc_md5_calc (calc_digest, (unsigned char *) auth, totallen + secretlen); ++#ifdef DIGEST_DEBUG ++ rc_log(LOG_ERR, "Calculated digest is:"); ++ for (ptr = (u_char *)calc_digest; ptr < ((u_char *)calc_digest) + 16; ptr += 32) { ++ char buf[65]; ++ int i; ++ ++ buf[0] = '\0'; ++ for (i = 0; i < 32; i++) { ++ if (ptr + i >= ((u_char *)calc_digest) + 16) ++ break; ++ sprintf(buf + i * 2, "%.2X", ptr[i]); ++ } ++ rc_log(LOG_ERR, " %s", buf); ++ } ++ rc_log(LOG_ERR, "Reply digest is:"); ++ for (ptr = (u_char *)reply_digest; ptr < ((u_char *)reply_digest) + 16; ptr += 32) { ++ char buf[65]; ++ int i; ++ ++ buf[0] = '\0'; ++ for (i = 0; i < 32; i++) { ++ if (ptr + i >= ((u_char *)reply_digest) + 16) ++ break; ++ sprintf(buf + i * 2, "%.2X", ptr[i]); ++ } ++ rc_log(LOG_ERR, " %s", buf); ++ } ++#endif ++ ++ if (memcmp ((char *) reply_digest, (char *) calc_digest, ++ AUTH_VECTOR_LEN) != 0) ++ { ++#ifdef RADIUS_116 ++ /* the original Livingston radiusd v1.16 seems to have ++ a bug in digest calculation with accounting requests, ++ authentication request are ok. i looked at the code ++ but couldn't find any bugs. any help to get this ++ kludge out are welcome. preferably i want to ++ reproduce the calculation bug here to be compatible ++ to stock Livingston radiusd v1.16. -lf, 03/14/96 ++ */ ++ if (auth->code == PW_ACCOUNTING_RESPONSE) ++ return OK_RC; ++#endif ++ rc_log(LOG_ERR, "rc_check_reply: received invalid reply digest from RADIUS server"); ++ return BADRESP_RC; ++ } ++ ++ return OK_RC; ++ ++} ++ ++/* ++ * Function: rc_random_vector ++ * ++ * Purpose: generates a random vector of AUTH_VECTOR_LEN octets. ++ * ++ * Returns: the vector (call by reference) ++ * ++ */ ++ ++static void rc_random_vector (unsigned char *vector) ++{ ++ int randno; ++ int i; ++#if defined(HAVE_GETENTROPY) ++ if (getentropy(vector, AUTH_VECTOR_LEN) >= 0) { ++ return; ++ } /* else fall through */ ++#elif defined(HAVE_DEV_URANDOM) ++ int fd; ++ ++/* well, I added this to increase the security for user passwords. ++ we use /dev/urandom here, as /dev/random might block and we don't ++ need that much randomness. BTW, great idea, Ted! -lf, 03/18/95 */ ++ ++ if ((fd = open(_PATH_DEV_URANDOM, O_RDONLY)) >= 0) ++ { ++ unsigned char *pos; ++ int readcount; ++ ++ i = AUTH_VECTOR_LEN; ++ pos = vector; ++ while (i > 0) ++ { ++ readcount = read(fd, (char *)pos, i); ++ if (readcount >= 0) { ++ pos += readcount; ++ i -= readcount; ++ } else { ++ if (errno != EINTR && errno != EAGAIN) ++ goto fallback; ++ } ++ } ++ ++ close(fd); ++ return; ++ } /* else fall through */ ++#endif ++ fallback: ++ for (i = 0; i < AUTH_VECTOR_LEN;) ++ { ++ randno = random (); ++ memcpy ((char *) vector, (char *) &randno, sizeof (int)); ++ vector += sizeof (int); ++ i += sizeof (int); ++ } ++ ++ return; ++} +diff --git a/src/plugins/vbng/lib/util.c b/src/plugins/vbng/lib/util.c +new file mode 100644 +index 00000000..aa7c057d +--- /dev/null ++++ b/src/plugins/vbng/lib/util.c +@@ -0,0 +1,347 @@ ++/* ++ * $Id: util.c,v 1.10 2010/02/04 10:31:41 aland Exp $ ++ * ++ * Copyright (c) 1998 The NetBSD Foundation, Inc. ++ * ++ * Copyright (C) 1995,1996,1997 Lars Fenneberg ++ * ++ * Copyright 1992 Livingston Enterprises, Inc. ++ * ++ * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan ++ * and Merit Network, Inc. All Rights Reserved ++ * ++ * See the file COPYRIGHT for the respective terms and conditions. ++ * If the file is missing contact me at lf@elemental.net ++ * and I'll send you a copy. ++ * ++ */ ++ ++#include <sys/time.h> ++ ++#include <config.h> ++#include <includes.h> ++#include <freeradius-client.h> ++ ++#define RC_BUFSIZ 1024 ++ ++/* ++ * Function: rc_str2tm ++ * ++ * Purpose: Turns printable string into correct tm struct entries. ++ * ++ */ ++ ++static char const * months[] = ++ { ++ "Jan", "Feb", "Mar", "Apr", "May", "Jun", ++ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ++ }; ++ ++void rc_str2tm (char const *valstr, struct tm *tm) ++{ ++ int i; ++ ++ /* Get the month */ ++ for (i = 0; i < 12; i++) ++ { ++ if (strncmp (months[i], valstr, 3) == 0) ++ { ++ tm->tm_mon = i; ++ i = 13; ++ } ++ } ++ ++ /* Get the Day */ ++ tm->tm_mday = atoi (&valstr[4]); ++ ++ /* Now the year */ ++ tm->tm_year = atoi (&valstr[7]) - 1900; ++} ++ ++/* ++ * Function: rc_getifname ++ * ++ * Purpose: get the network interface name associated with this tty ++ * ++ */ ++ ++char *rc_getifname(rc_handle *rh, char const *tty) ++{ ++#if defined(BSD4_4) || defined(linux) ++ int fd; ++ ++ if ((fd = open(tty, O_RDWR|O_NDELAY)) < 0) { ++ rc_log(LOG_ERR, "rc_getifname: can't open %s: %s", tty, strerror(errno)); ++ return NULL; ++ } ++#endif ++ ++#ifdef BSD4_4 ++ strcpy(rh->ifname,ttyname(fd)); ++ if (strlen(rh->ifname) < 1) { ++ rc_log(LOG_ERR, "rc_getifname: can't get attached interface of %s: %s", tty, strerror(errno)); ++ close(fd); ++ return NULL; ++ } ++#elif linux ++ if (ioctl(fd, SIOCGIFNAME, rh->ifname) < 0) { ++ rc_log(LOG_ERR, "rc_getifname: can't ioctl %s: %s", tty, strerror(errno)); ++ close(fd); ++ return NULL; ++ } ++#else ++ return NULL; ++#endif ++ ++#if defined(BSD4_4) || defined(linux) ++ close(fd); ++ return rh->ifname; ++#endif ++} ++ ++/* ++ * Function: rc_getstr ++ * ++ * Purpose: Reads in a string from the user (with or witout echo) ++ * ++ */ ++#ifndef _MSC_VER ++char *rc_getstr (rc_handle *rh, char const *prompt, int do_echo) ++{ ++ int in, out; ++ char *p; ++ struct termios term_old, term_new; ++ int is_term, flags, old_flags; ++ char c; ++ int flushed = 0; ++ sigset_t newset; ++ sigset_t oldset; ++ ++ in = fileno(stdin); ++ out = fileno(stdout); ++ ++ (void) sigemptyset (&newset); ++ (void) sigaddset (&newset, SIGINT); ++ (void) sigaddset (&newset, SIGTSTP); ++ (void) sigaddset (&newset, SIGQUIT); ++ ++ (void) sigprocmask (SIG_BLOCK, &newset, &oldset); ++ ++ if ((is_term = isatty(in))) ++ { ++ ++ (void) tcgetattr (in, &term_old); ++ term_new = term_old; ++ if (do_echo) ++ term_new.c_lflag |= ECHO; ++ else ++ term_new.c_lflag &= ~ECHO; ++ ++ if (tcsetattr (in, TCSAFLUSH, &term_new) == 0) ++ flushed = 1; ++ ++ } ++ else ++ { ++ is_term = 0; ++ if ((flags = fcntl(in, F_GETFL, 0)) >= 0) { ++ old_flags = flags; ++ flags |= O_NONBLOCK; ++ ++ fcntl(in, F_SETFL, flags); ++ ++ while (read(in, &c, 1) > 0) ++ /* nothing */; ++ ++ fcntl(in, F_SETFL, old_flags); ++ ++ flushed = 1; ++ } ++ } ++ ++ (void)write(out, prompt, strlen(prompt)); ++ ++ /* well, this looks ugly, but it handles the following end of line ++ markers: \r \r\0 \r\n \n \n\r, at least at a second pass */ ++ ++ p = rh->buf; ++ for (;;) ++ { ++ if (read(in, &c, 1) <= 0) ++ return NULL; ++ ++ if (!flushed && ((c == '\0') || (c == '\r') || (c == '\n'))) { ++ flushed = 1; ++ continue; ++ } ++ ++ if ((c == '\r') || (c == '\n')) ++ break; ++ ++ flushed = 1; ++ ++ if (p < rh->buf + GETSTR_LENGTH) ++ { ++ if (do_echo && !is_term) ++ (void)write(out, &c, 1); ++ *p++ = c; ++ } ++ } ++ ++ *p = '\0'; ++ ++ if (!do_echo || !is_term) (void)write(out, "\r\n", 2); ++ ++ if (is_term) ++ tcsetattr (in, TCSAFLUSH, &term_old); ++ else { ++ if ((flags = fcntl(in, F_GETFL, 0)) >= 0) { ++ old_flags = flags; ++ flags |= O_NONBLOCK; ++ ++ fcntl(in, F_SETFL, flags); ++ ++ while (read(in, &c, 1) > 0) ++ /* nothing */; ++ ++ fcntl(in, F_SETFL, old_flags); ++ } ++ } ++ ++ (void) sigprocmask (SIG_SETMASK, &oldset, NULL); ++ ++ return rh->buf; ++} ++#endif ++void rc_mdelay(int msecs) ++{ ++ struct timeval tv; ++ ++ tv.tv_sec = (int) msecs / 1000; ++ tv.tv_usec = (msecs % 1000) * 1000; ++ ++ select(0, NULL, NULL, NULL, &tv); ++} ++ ++/* ++ * Function: rc_mksid ++ * ++ * Purpose: generate a quite unique string ++ * ++ * Remarks: not that unique at all... ++ * ++ */ ++ ++char * ++rc_mksid (rc_handle *rh) ++{ ++ snprintf (rh->buf1, sizeof(rh->buf1), "%08lX%04X", (unsigned long int) time (NULL), (unsigned int) getpid ()); ++ return rh->buf1; ++} ++ ++/* ++ * Function: rc_new ++ * ++ * Purpose: Initialises new Radius Client handle ++ * ++ */ ++ ++rc_handle * ++rc_new(void) ++{ ++ rc_handle *rh; ++ ++ rh = malloc(sizeof(*rh)); ++ if (rh == NULL) { ++ rc_log(LOG_CRIT, "rc_new: out of memory"); ++ return NULL; ++ } ++ memset(rh, 0, sizeof(*rh)); ++ return rh; ++} ++ ++/* ++ * Function: rc_destroy ++ * ++ * Purpose: Destroys Radius Client handle reclaiming all memory ++ * ++ */ ++ ++void ++rc_destroy(rc_handle *rh) ++{ ++ ++ rc_map2id_free(rh); ++ rc_dict_free(rh); ++ rc_config_free(rh); ++ if (rh->this_host_bind_ipaddr != NULL) ++ free(rh->this_host_bind_ipaddr); ++ free(rh); ++} ++ ++/* ++ * Function: rc_fgetln ++ * ++ * Purpose: Get next line from the stream. ++ * ++ */ ++ ++char * ++rc_fgetln(FILE *fp, size_t *len) ++{ ++ static char *buf = NULL; ++ static size_t bufsiz = 0; ++ char *ptr; ++ ++ if (buf == NULL) { ++ bufsiz = RC_BUFSIZ; ++ if ((buf = malloc(bufsiz)) == NULL) ++ return NULL; ++ } ++ ++ if (fgets(buf, (int)bufsiz, fp) == NULL) ++ return NULL; ++ *len = 0; ++ ++ while ((ptr = strchr(&buf[*len], '\n')) == NULL) { ++ size_t nbufsiz = bufsiz + RC_BUFSIZ; ++ char *nbuf = realloc(buf, nbufsiz); ++ ++ if (nbuf == NULL) { ++ int oerrno = errno; ++ free(buf); ++ errno = oerrno; ++ buf = NULL; ++ return NULL; ++ } else ++ buf = nbuf; ++ ++ *len = bufsiz; ++ if (fgets(&buf[bufsiz], RC_BUFSIZ, fp) == NULL) ++ return buf; ++ ++ bufsiz = nbufsiz; ++ } ++ ++ *len = (ptr - buf) + 1; ++ return buf; ++} ++ ++/* ++ * Function: rc_getctime ++ * ++ * Purpose: Get current time (seconds since epoch) expressed as ++ * double-precision floating point number. ++ * ++ */ ++ ++double ++rc_getctime(void) ++{ ++ struct timeval timev; ++ ++ if (gettimeofday(&timev, NULL) == -1) ++ return -1; ++ ++ return timev.tv_sec + ((double)timev.tv_usec) / 1000000.0; ++} +diff --git a/src/plugins/vbng/vbng.api b/src/plugins/vbng/vbng.api +new file mode 100644 +index 00000000..eba9a10f +--- /dev/null ++++ b/src/plugins/vbng/vbng.api +@@ -0,0 +1,50 @@ ++/* ++ * Copyright (c) 2017 Intel Corp 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. ++ */ ++ ++/** \brief vBNG DHCP config add / del request ++ @param client_index - opaque cookie to identify the sender ++ @param context - sender context, to match reply w/ request ++ @param rx_vrf_id - Rx/interface vrf id ++ @param server_vrf_id - server vrf id ++ @param is_add - add the config if non-zero, else delete ++ @param remote_addr[] - DHCP server address ++ @param local_addr[] - Local Address which could reach DHCP server ++*/ ++define vbng_dhcp4_config ++{ ++ u32 client_index; ++ u32 context; ++ u32 rx_vrf_id; ++ u32 server_vrf_id; ++ u8 is_add; ++ u8 remote_addr[16]; ++ u8 local_addr[16]; ++}; ++ ++/** \brief vBNG DHCP config response ++ @param context - sender context, to match reply w/ request ++ @param retval - return code for the request ++*/ ++define vbng_dhcp4_config_reply ++{ ++ u32 context; ++ i32 retval; ++}; ++ ++/* ++ * Local Variables: ++ * eval: (c-set-style "gnu") ++ * End: ++ */ +diff --git a/src/plugins/vbng/vbng_aaa.c b/src/plugins/vbng/vbng_aaa.c +new file mode 100644 +index 00000000..5e8861f7 +--- /dev/null ++++ b/src/plugins/vbng/vbng_aaa.c +@@ -0,0 +1,71 @@ ++/* ++ * Copyright (c) 2017 Intel 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. ++ */ ++ ++#include <ctype.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <unistd.h> ++ ++#include <vbng/include/freeradius-client.h> ++#include <vbng/vbng_aaa.h> ++ ++int ++process(void *rh, VALUE_PAIR *send, int nas_port) ++{ ++ VALUE_PAIR *received = NULL; ++ char msg[PW_MAX_MSG_SIZE]; ++ int retval; ++ ++ retval = rc_auth(rh, nas_port, send, &received, msg); ++ if (retval == OK_RC && received != NULL) { ++ rc_avpair_free(received); ++ } ++ ++ return retval; ++} ++ ++int ++vbng_auth(vbng_dhcp4_main_t *dm, int argc, char **argv) ++{ ++ int i, nas_port = dm->config.nas_port; ++ char *rc_conf = (char *)dm->config.config_file; ++ VALUE_PAIR *send, **vp; ++ void *rh; ++ ++ if ((rh = rc_read_config(rc_conf)) == NULL) { ++ fprintf(stderr, "error opening radius configuration file\n"); ++ return (1); ++ } ++ ++ if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary")) != 0) { ++ fprintf(stderr, "error reading radius dictionary\n"); ++ return (2); ++ } ++ ++ send = NULL; ++ vp = &send; ++ for (i = 0; i < argc; i++) { ++ if (rc_avpair_parse(rh, argv[i], vp) < 0) { ++ fprintf(stderr, "%s: can't parse AV pair\n", argv[i]); ++ return (3); ++ } ++ vp = &send->next; ++ } ++ ++ return process(rh, send, nas_port); ++} ++ +diff --git a/src/plugins/vbng/vbng_aaa.h b/src/plugins/vbng/vbng_aaa.h +new file mode 100644 +index 00000000..411a7533 +--- /dev/null ++++ b/src/plugins/vbng/vbng_aaa.h +@@ -0,0 +1,34 @@ ++/* ++ * vbng_aaa.h - vBNG FreeRADIUS client commons. ++ * ++ * Copyright (c) 2017 Intel 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. ++ */ ++#ifndef _VBNG_AAA_H_ ++#define _VBNG_AAA_H_ ++ ++#include <vbng/vbng_dhcp4.h> ++ ++/* Common configuration for RADIUS client */ ++#define AAA_DEFAULT_NAS_PORT 5060 ++#define AAA_DEFAULT_CONFIG_FILE "/etc/vpp/vbng-aaa.cfg" ++ ++#define BUF_LEN 4096 ++ ++/* String template for the vAAA attributes */ ++#define STR_TPL_ATTR_DHCP_AGENT_CIRCUIT_ID "DHCP-Agent-Circuit-Id=%c" ++#define STR_TPL_ATTR_DHCP_AGENT_REMOTE_ID "DHCP-Agent-Remote-Id=%c" ++ ++int vbng_auth(vbng_dhcp4_main_t *dm, int argc, char **argv); ++ ++#endif /* _VBNG_AAA_H_ */ +diff --git a/src/plugins/vbng/vbng_all_api_h.h b/src/plugins/vbng/vbng_all_api_h.h +new file mode 100644 +index 00000000..3f744275 +--- /dev/null ++++ b/src/plugins/vbng/vbng_all_api_h.h +@@ -0,0 +1,18 @@ ++/* ++ * vbng_all_api_h.h - skeleton vpp engine plug-in api #include file ++ * ++ * Copyright (c) 2017 Intel 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. ++ */ ++ ++#include <vbng/vbng.api.h> +diff --git a/src/plugins/vbng/vbng_api.c b/src/plugins/vbng/vbng_api.c +new file mode 100644 +index 00000000..4080f775 +--- /dev/null ++++ b/src/plugins/vbng/vbng_api.c +@@ -0,0 +1,123 @@ ++/* ++ *------------------------------------------------------------------ ++ * vbng_api.c - vbng api ++ * ++ * Copyright (c) 2017 Intel Corp 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. ++ *------------------------------------------------------------------ ++ */ ++ ++#include <vnet/vnet.h> ++#include <vlibmemory/api.h> ++ ++#include <vnet/interface.h> ++#include <vnet/api_errno.h> ++#include <vnet/dhcp/dhcp_proxy.h> ++#include <vnet/dhcp/client.h> ++#include <vnet/fib/fib_table.h> ++ ++#include <vbng/vbng_msg_enum.h> ++ ++#define vl_typedefs /* define message structures */ ++#include <vbng/vbng_all_api_h.h> ++#undef vl_typedefs ++ ++#define vl_endianfun /* define message structures */ ++#include <vbng/vbng_all_api_h.h> ++#undef vl_endianfun ++ ++/* instantiate all the print functions we know about */ ++#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) ++#define vl_printfun ++#include <vbng/vbng_all_api_h.h> ++#undef vl_printfun ++ ++#include <vlibapi/api_helper_macros.h> ++ ++#define foreach_vpe_api_msg \ ++_(VBNG_DHCP4_CONFIG,vbng_dhcp4_config) ++ ++static void vl_api_vbng_dhcp4_config_t_handler ++ (vl_api_vbng_dhcp4_config_t * mp) ++{ ++ vl_api_vbng_dhcp4_config_reply_t *rmp; ++ ip46_address_t src, server; ++ int rv = -1; ++ ++ ip46_address_reset (&src); ++ ip46_address_reset (&server); ++ ++ clib_memcpy (&src.ip4, mp->local_addr, sizeof (src.ip4)); ++ clib_memcpy (&server.ip4, mp->remote_addr, sizeof (server.ip4)); ++ ++ rv = dhcp4_proxy_set_server (&server, ++ &src, ++ (u32) ntohl (mp->rx_vrf_id), ++ (u32) ntohl (mp->server_vrf_id), ++ (int) (mp->is_add == 0)); ++ ++ ++ REPLY_MACRO (VL_API_VBNG_DHCP4_CONFIG_REPLY); ++} ++ ++/* ++ * vbng_api_hookup ++ * Add vpe's API message handlers to the table. ++ * vlib has alread mapped shared memory and ++ * added the client registration handlers. ++ * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process() ++ */ ++#define vl_msg_name_crc_list ++#include <vbng/vbng_all_api_h.h> ++#undef vl_msg_name_crc_list ++ ++static void ++setup_message_id_table (api_main_t * am) ++{ ++#define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id); ++ foreach_vl_msg_name_crc_vbng; ++#undef _ ++} ++ ++static clib_error_t * ++vbng_api_hookup (vlib_main_t * vm) ++{ ++ api_main_t *am = &api_main; ++ ++#define _(N,n) \ ++ vl_msg_api_set_handlers(VL_API_##N, #n, \ ++ vl_api_##n##_t_handler, \ ++ vl_noop_handler, \ ++ vl_api_##n##_t_endian, \ ++ vl_api_##n##_t_print, \ ++ sizeof(vl_api_##n##_t), 1); ++ foreach_vpe_api_msg; ++#undef _ ++ ++ /* ++ * Set up the (msg_name, crc, message-id) table ++ */ ++ setup_message_id_table (am); ++ ++ return 0; ++} ++ ++VLIB_API_INIT_FUNCTION (vbng_api_hookup); ++ ++/* ++ * fd.io coding-style-patch-verification: ON ++ * ++ * Local Variables: ++ * eval: (c-set-style "gnu") ++ * End: ++ */ +diff --git a/src/plugins/vbng/vbng_dhcp4.c b/src/plugins/vbng/vbng_dhcp4.c +new file mode 100644 +index 00000000..ed79df42 +--- /dev/null ++++ b/src/plugins/vbng/vbng_dhcp4.c +@@ -0,0 +1,160 @@ ++/* ++ * vbng_dhcp4.c: common dhcp v4 processing ++ * ++ * Copyright (c) 2017 Intel Corp and/or its affiliates and others. ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#include <vnet/fib/fib_table.h> ++#include <vnet/mfib/mfib_table.h> ++ ++#include <vbng/vbng_dhcp4.h> ++ ++/** ++ * @brief Shard 4/6 instance of DHCP main ++ */ ++vbng_dhcp4_main_t vbng_dhcp4_main; ++ ++void ++vbng_dhcp4_walk (vbng_dhcp4_walk_fn_t fn, ++ void *ctx) ++{ ++ vbng_dhcp4_main_t *vdm = &vbng_dhcp4_main; ++ dhcp_proxy_t * server; ++ u32 server_index, i; ++ ++ vec_foreach_index (i, vdm->dhcp_server_index_by_rx_fib_index) ++ { ++ server_index = vdm->dhcp_server_index_by_rx_fib_index[i]; ++ if (~0 == server_index) ++ continue; ++ ++ server = pool_elt_at_index (vdm->dhcp4_servers, server_index); ++ ++ if (!fn(server, ctx)) ++ break; ++ } ++} ++ ++static u32 ++dhcp_proxy_server_find (dhcp_proxy_t *proxy, ++ fib_protocol_t proto, ++ ip46_address_t *addr, ++ u32 server_table_id) ++{ ++ dhcp_server_t *server; ++ u32 ii, fib_index; ++ ++ vec_foreach_index(ii, proxy->dhcp_servers) ++ { ++ server = &proxy->dhcp_servers[ii]; ++ fib_index = fib_table_find(proto, server_table_id); ++ ++ if (ip46_address_is_equal(&server->dhcp_server, ++ addr) && ++ (server->server_fib_index == fib_index)) ++ { ++ return (ii); ++ } ++ } ++ return (~0); ++} ++ ++int ++vbng_dhcp4_server_del (fib_protocol_t proto, ++ u32 rx_fib_index, ++ ip46_address_t *addr, ++ u32 server_table_id) ++{ ++ vbng_dhcp4_main_t *vdm = &vbng_dhcp4_main; ++ dhcp_proxy_t *proxy = 0; ++ ++ proxy = vbng_dhcp4_get_server(vdm, rx_fib_index); ++ ++ if (NULL != proxy) ++ { ++ dhcp_server_t *server; ++ u32 index; ++ ++ index = dhcp_proxy_server_find(proxy, proto, addr, server_table_id); ++ ++ if (~0 != index) ++ { ++ server = &proxy->dhcp_servers[index]; ++ fib_table_unlock (server->server_fib_index, proto); ++ ++ vec_del1(proxy->dhcp_servers, index); ++ ++ if (0 == vec_len(proxy->dhcp_servers)) ++ { ++ /* no servers left, delete the proxy config */ ++ vdm->dhcp_server_index_by_rx_fib_index[rx_fib_index] = ~0; ++ vec_free(proxy->dhcp_servers); ++ pool_put (vdm->dhcp4_servers, proxy); ++ return (1); ++ } ++ } ++ } ++ ++ /* the proxy still exists */ ++ return (0); ++} ++ ++int ++vbng_dhcp4_server_add (fib_protocol_t proto, ++ ip46_address_t *addr, ++ ip46_address_t *src_address, ++ u32 rx_fib_index, ++ u32 server_table_id) ++{ ++ vbng_dhcp4_main_t *vdm = &vbng_dhcp4_main; ++ dhcp_proxy_t * proxy = 0; ++ int new = 0; ++ ++ proxy = vbng_dhcp4_get_server(vdm, rx_fib_index); ++ ++ if (NULL == proxy) ++ { ++ vec_validate_init_empty(vdm->dhcp_server_index_by_rx_fib_index, ++ rx_fib_index, ++ ~0); ++ ++ pool_get (vdm->dhcp4_servers, proxy); ++ memset (proxy, 0, sizeof (*proxy)); ++ new = 1; ++ ++ vdm->dhcp_server_index_by_rx_fib_index[rx_fib_index] = ++ proxy - vdm->dhcp4_servers; ++ ++ proxy->dhcp_src_address = *src_address; ++ proxy->rx_fib_index = rx_fib_index; ++ } ++ else ++ { ++ if (~0 != dhcp_proxy_server_find(proxy, proto, addr, server_table_id)) ++ { ++ return (new); ++ } ++ } ++ ++ dhcp_server_t server = { ++ .dhcp_server = *addr, ++ .server_fib_index = fib_table_find_or_create_and_lock(proto, ++ server_table_id), ++ }; ++ ++ vec_add1(proxy->dhcp_servers, server); ++ ++ return (new); ++} ++ +diff --git a/src/plugins/vbng/vbng_dhcp4.h b/src/plugins/vbng/vbng_dhcp4.h +new file mode 100644 +index 00000000..2f41575f +--- /dev/null ++++ b/src/plugins/vbng/vbng_dhcp4.h +@@ -0,0 +1,139 @@ ++/* ++ * vbng_dhcp4.h: DHCP v4 common functions/types ++ * ++ * Copyright (c) 2017 Intel Corp and/or its affiliates and others. ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef _VBNG_DHCP4_H_ ++#define _VBNG_DHCP4_H_ ++ ++#include <vnet/vnet.h> ++#include <vnet/dhcp/dhcp_proxy.h> ++#include <vnet/dhcp/dhcp4_packet.h> ++#include <vnet/ethernet/ethernet.h> ++#include <vnet/ip/ip.h> ++#include <vnet/ip/ip4.h> ++#include <vnet/ip/ip4_packet.h> ++#include <vnet/pg/pg.h> ++#include <vnet/ip/format.h> ++#include <vnet/udp/udp.h> ++ ++typedef enum { ++#define vbng_dhcp4_error(n,s) VBNG_DHCP4_ERROR_##n, ++#include <vbng/vbng_dhcp4_err.def> ++#undef vbng_dhcp4_error ++ VBNG_DHCP4_N_ERROR, ++} vbng_dhcp4_error_t; ++ ++#define VBNG_AAA_DISABLED 0 ++#define VBNG_AAA_ENABLED 1 ++ ++typedef struct { ++ int is_enabled; ++ u32 nas_port; /* AAA server port */ ++ u8 *config_file; /* Radius Client config file path */ ++} vbng_aaa_config_t; ++ ++/** ++ * @brief Global configuration for the vBNG plugin. ++ */ ++typedef struct { ++ /* Pool of DHCP servers */ ++ dhcp_proxy_t *dhcp4_servers; ++ ++ /* Pool of selected DHCP server. Zero is the default server */ ++ u32 * dhcp_server_index_by_rx_fib_index; ++ ++ /* to drop pkts in server-to-client direction */ ++ u32 error_drop_node_index; ++ ++ /* Configuration for the AAA client */ ++ vbng_aaa_config_t config; ++ ++ /* convenience */ ++ vlib_main_t * vlib_main; ++ vnet_main_t * vnet_main; ++} vbng_dhcp4_main_t; ++ ++extern vbng_dhcp4_main_t vbng_dhcp4_main; ++ ++/** ++ * @brief Add a new DHCP proxy server configuration. ++ * @return 1 is the config is new, ++ * 0 otherwise (implying a modify of an existing) ++ */ ++int vbng_dhcp4_server_add(fib_protocol_t proto, ++ ip46_address_t *addr, ++ ip46_address_t *src_address, ++ u32 rx_fib_iindex, ++ u32 server_table_id); ++ ++/** ++ * @brief Delete a DHCP proxy config ++ * @return 1 if the proxy is deleted, 0 otherwise ++ */ ++int vbng_dhcp4_server_del(fib_protocol_t proto, ++ u32 rx_fib_index, ++ ip46_address_t *addr, ++ u32 server_table_id); ++ ++u32 ++dhcp_proxy_rx_table_get_table_id (fib_protocol_t proto, ++ u32 fib_index); ++ ++/** ++ * @brief Callback function invoked for each DHCP proxy entry ++ * return 0 to break the walk, non-zero otherwise. ++ */ ++typedef int (*vbng_dhcp4_walk_fn_t)(dhcp_proxy_t *server, ++ void *ctx); ++ ++/** ++ * @brief Walk/Visit each vBNG DHCP server configurations ++ */ ++void vbng_dhcp4_walk(vbng_dhcp4_walk_fn_t fn, ++ void *ctx); ++ ++/** ++ * @brief Get the DHCP proxy server data for the FIB index ++ */ ++static inline dhcp_proxy_t * ++vbng_dhcp4_get_server(vbng_dhcp4_main_t *vm, ++ u32 rx_fib_index) ++{ ++ dhcp_proxy_t *s = NULL; ++ ++ if (vec_len(vm->dhcp_server_index_by_rx_fib_index) > rx_fib_index && ++ vm->dhcp_server_index_by_rx_fib_index[rx_fib_index] != ~0) ++ { ++ s = pool_elt_at_index ( ++ vm->dhcp4_servers, ++ vm->dhcp_server_index_by_rx_fib_index[rx_fib_index]); ++ } ++ ++ return (s); ++} ++ ++int vbng_dhcp4_set_server(ip46_address_t *addr, ++ ip46_address_t *src_addr, ++ u32 rx_table_id, ++ u32 server_table_id, ++ int is_del); ++ ++#define DHCP_PACKET_OPTION_82 82 ++#define DHCP_PACKET_OPTION82_SUB1 1 ++#define DHCP_PACKET_OPTION82_SUB2 2 ++#define DHCP_PACKET_OPTION82_SUB5 5 ++ ++#endif /* _VBNG_DHCP4_H_ */ +diff --git a/src/plugins/vbng/vbng_dhcp4_err.def b/src/plugins/vbng/vbng_dhcp4_err.def +new file mode 100644 +index 00000000..23f2d0d2 +--- /dev/null ++++ b/src/plugins/vbng/vbng_dhcp4_err.def +@@ -0,0 +1,29 @@ ++/* ++ * vbng_dhcp4_err.def: VBNG DHCP4 Errors ++ * ++ * Copyright (c) 2017 Intel Corp and/or its affiliates and others. ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++vbng_dhcp4_error (NONE, "no error") ++vbng_dhcp4_error (NO_SERVER, "no dhcp server configured") ++vbng_dhcp4_error (RELAY_TO_SERVER, "DHCP packets relayed to the server") ++vbng_dhcp4_error (RELAY_TO_CLIENT, "DHCP packets relayed to clients") ++vbng_dhcp4_error (NO_INTERFACE_ADDRESS, "DHCP no interface address") ++vbng_dhcp4_error (BAD_YIADDR, "DHCP packets with bad your_ip_address fields") ++vbng_dhcp4_error (BAD_SVR_FIB_OR_ADDRESS, "DHCP packets not from DHCP server or server FIB.") ++vbng_dhcp4_error (PKT_TOO_BIG, "DHCP packets which are too big.") ++vbng_dhcp4_error (AAA_FAILURE, "DHCP packets failed to pass the AAA check.") ++vbng_dhcp4_error (NO_OPTION_82, "DHCP option 82 missing") ++vbng_dhcp4_error (BAD_OPTION_82_ITF, "Bad DHCP option 82 interface value") ++vbng_dhcp4_error (BAD_OPTION_82_ADDR, "Bad DHCP option 82 address value") +diff --git a/src/plugins/vbng/vbng_dhcp4_node.c b/src/plugins/vbng/vbng_dhcp4_node.c +new file mode 100644 +index 00000000..205959bf +--- /dev/null ++++ b/src/plugins/vbng/vbng_dhcp4_node.c +@@ -0,0 +1,1024 @@ ++/* ++ * proxy_node.c: dhcp proxy node processing ++ * ++ * Copyright (c) 2013 Cisco and/or its affiliates and others. ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#include <vlib/vlib.h> ++#include <vnet/pg/pg.h> ++#include <vnet/fib/ip4_fib.h> ++#include <vnet/dhcp/client.h> ++#include <vnet/plugin/plugin.h> ++#include <vpp/app/version.h> ++ ++#include <vbng/vbng_dhcp4.h> ++#include <vbng/vbng_aaa.h> ++ ++static char * vbng_dhcp4_error_strings[] = { ++#define vbng_dhcp4_error(n,s) s, ++#include <vbng/vbng_dhcp4_err.def> ++#undef vbng_dhcp4_error ++}; ++ ++#define foreach_vbng_dhcp4_to_server_input_next \ ++ _ (DROP, "error-drop") \ ++ _ (LOOKUP, "ip4-lookup") \ ++ _ (SEND_TO_CLIENT, "vbng-dhcp-to-client") ++ ++typedef enum { ++#define _(s,n) VBNG_DHCP4_TO_SERVER_INPUT_NEXT_##s, ++ foreach_vbng_dhcp4_to_server_input_next ++#undef _ ++ VBNG_DHCP4_TO_SERVER_INPUT_N_NEXT, ++} vbng_dhcp4_to_server_input_next_t; ++ ++typedef struct { ++ /* 0 => to server, 1 => to client */ ++ int which; ++ ip4_address_t trace_ip4_address; ++ u32 error; ++ u32 sw_if_index; ++ u32 original_sw_if_index; ++} dhcp_proxy_trace_t; ++ ++#define VPP_DHCP_OPTION82_SUB1_SIZE 6 ++#define VPP_DHCP_OPTION82_SUB5_SIZE 6 ++#define VPP_DHCP_OPTION82_VSS_SIZE 12 ++#define VPP_DHCP_OPTION82_SIZE (VPP_DHCP_OPTION82_SUB1_SIZE + \ ++ VPP_DHCP_OPTION82_SUB5_SIZE + \ ++ VPP_DHCP_OPTION82_VSS_SIZE +3) ++ ++static vlib_node_registration_t vbng_dhcp4_to_server_node; ++static vlib_node_registration_t vbng_dhcp4_to_client_node; ++ ++static u8 * ++format_dhcp_proxy_trace (u8 * s, va_list * args) ++{ ++ CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); ++ CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); ++ dhcp_proxy_trace_t * t = va_arg (*args, dhcp_proxy_trace_t *); ++ ++ if (t->which == 0) ++ s = format (s, "DHCP proxy: sent to server %U\n", ++ format_ip4_address, &t->trace_ip4_address, t->error); ++ else ++ s = format (s, "DHCP proxy: broadcast to client from %U\n", ++ format_ip4_address, &t->trace_ip4_address); ++ ++ if (t->error != (u32)~0) ++ s = format (s, " error: %s\n", vbng_dhcp4_error_strings[t->error]); ++ ++ s = format (s, " original_sw_if_index: %d, sw_if_index: %d\n", ++ t->original_sw_if_index, t->sw_if_index); ++ ++ return s; ++} ++ ++static u8 * ++format_dhcp_proxy_header_with_length (u8 * s, va_list * args) ++{ ++ dhcp_header_t * h = va_arg (*args, dhcp_header_t *); ++ u32 max_header_bytes = va_arg (*args, u32); ++ u32 header_bytes; ++ ++ header_bytes = sizeof (h[0]); ++ if (max_header_bytes != 0 && header_bytes > max_header_bytes) ++ return format (s, "dhcp header truncated"); ++ ++ s = format (s, "DHCP Proxy"); ++ ++ return s; ++} ++ ++static uword ++vbng_dhcp_to_server_input (vlib_main_t * vm, ++ vlib_node_runtime_t * node, ++ vlib_frame_t * from_frame) ++{ ++ u32 n_left_from, next_index, * from, * to_next; ++ vbng_dhcp4_main_t *dm = &vbng_dhcp4_main; ++ from = vlib_frame_vector_args (from_frame); ++ n_left_from = from_frame->n_vectors; ++ u32 pkts_to_server=0, pkts_to_client=0, pkts_no_server=0; ++ u32 pkts_no_interface_address=0; ++ u32 pkts_too_big=0, pkts_aaa_fail = 0; ++ ip4_main_t * im = &ip4_main; ++ ++ next_index = node->cached_next_index; ++ ++ while (n_left_from > 0) ++ { ++ u32 n_left_to_next; ++ ++ vlib_get_next_frame (vm, node, next_index, ++ to_next, n_left_to_next); ++ ++ while (n_left_from > 0 && n_left_to_next > 0) ++ { ++ u32 bi0; ++ vlib_buffer_t * b0; ++ udp_header_t * u0; ++ dhcp_header_t * h0; ++ ip4_header_t * ip0; ++ u32 next0; ++ u32 old0, new0; ++ ip_csum_t sum0; ++ u32 error0 = (u32) ~0; ++ u32 sw_if_index = 0; ++ u32 original_sw_if_index = 0; ++ u8 *end = NULL; ++ u32 fib_index; ++ dhcp_proxy_t *proxy; ++ dhcp_server_t *server; ++ u32 rx_sw_if_index; ++ dhcp_option_t *o; ++ u32 len = 0; ++ vlib_buffer_free_list_t *fl; ++ u8 is_discover = 0; ++ ++ bi0 = from[0]; ++ from += 1; ++ n_left_from -= 1; ++ ++ b0 = vlib_get_buffer (vm, bi0); ++ ++ h0 = vlib_buffer_get_current (b0); ++ ++ /* ++ * udp_local hands us the DHCP header, need udp hdr, ++ * ip hdr to relay to server ++ */ ++ vlib_buffer_advance (b0, -(sizeof(*u0))); ++ u0 = vlib_buffer_get_current (b0); ++ ++ /* This blows. Return traffic has src_port = 67, dst_port = 67 */ ++ if (u0->src_port == clib_net_to_host_u16(UDP_DST_PORT_dhcp_to_server)) ++ { ++ vlib_buffer_advance (b0, sizeof(*u0)); ++ next0 = VBNG_DHCP4_TO_SERVER_INPUT_NEXT_SEND_TO_CLIENT; ++ error0 = 0; ++ pkts_to_client++; ++ goto do_enqueue; ++ } ++ ++ rx_sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX]; ++ ++ fib_index = im->fib_index_by_sw_if_index [rx_sw_if_index]; ++ proxy = vbng_dhcp4_get_server(dm, fib_index); ++ ++ if (PREDICT_FALSE (NULL == proxy)) ++ { ++ error0 = VBNG_DHCP4_ERROR_NO_SERVER; ++ next0 = VBNG_DHCP4_TO_SERVER_INPUT_NEXT_DROP; ++ pkts_no_server++; ++ goto do_trace; ++ } ++ ++ server = &proxy->dhcp_servers[0]; ++ vlib_buffer_advance (b0, -(sizeof(*ip0))); ++ ip0 = vlib_buffer_get_current (b0); ++ ++ /* disable UDP checksum */ ++ u0->checksum = 0; ++ sum0 = ip0->checksum; ++ old0 = ip0->dst_address.as_u32; ++ new0 = server->dhcp_server.ip4.as_u32; ++ ip0->dst_address.as_u32 = server->dhcp_server.ip4.as_u32; ++ sum0 = ip_csum_update (sum0, old0, new0, ++ ip4_header_t /* structure */, ++ dst_address /* changed member */); ++ ip0->checksum = ip_csum_fold (sum0); ++ ++ sum0 = ip0->checksum; ++ old0 = ip0->src_address.as_u32; ++ new0 = proxy->dhcp_src_address.ip4.as_u32; ++ ip0->src_address.as_u32 = new0; ++ sum0 = ip_csum_update (sum0, old0, new0, ++ ip4_header_t /* structure */, ++ src_address /* changed member */); ++ ip0->checksum = ip_csum_fold (sum0); ++ ++ /* Send to DHCP server via the configured FIB */ ++ vnet_buffer(b0)->sw_if_index[VLIB_TX] = ++ server->server_fib_index; ++ ++ h0->gateway_ip_address.as_u32 = proxy->dhcp_src_address.ip4.as_u32; ++ pkts_to_server++; ++ ++ o = (dhcp_option_t *) h0->options; ++ ++ fib_index = im->fib_index_by_sw_if_index ++ [vnet_buffer(b0)->sw_if_index[VLIB_RX]]; ++ ++ end = b0->data + b0->current_data + b0->current_length; ++ /* TLVs are not performance-friendly... */ ++ while (o->option != 0xFF /* end of options */ && (u8 *)o < end) ++ { ++ if (DHCP_PACKET_OPTION_MSG_TYPE == o->option) ++ { ++ if (DHCP_PACKET_DISCOVER == o->data[0]) ++ { ++ is_discover = 1; ++ } ++ } ++ ++ if (DHCP_PACKET_OPTION_82 == o->option) { ++ /* For Demo purpose only */ ++ if (dm->config.is_enabled) { ++ int i = 0, num_kvs = 0, retval = 0; ++ char *kv_pairs[1]; ++ char key_string[32]; ++ ++ if (DHCP_PACKET_OPTION82_SUB1 == o->data[0]) { ++ sprintf(key_string, STR_TPL_ATTR_DHCP_AGENT_CIRCUIT_ID, o->data[2]); ++ for (i = 1; i < o->data[1]; i++) { ++ sprintf(key_string, "%s%c", key_string, o->data[2 + i]); ++ } ++ } ++ ++ if (DHCP_PACKET_OPTION82_SUB2 == o->data[0]) { ++ sprintf(key_string, STR_TPL_ATTR_DHCP_AGENT_REMOTE_ID, o->data[2]); ++ for (i = 1; i < o->data[1]; i++) { ++ sprintf(key_string, "%s%c", key_string, o->data[2 + i]); ++ } ++ } ++ ++ kv_pairs[num_kvs] = key_string; ++ num_kvs++; ++ ++ retval = vbng_auth(dm, num_kvs, kv_pairs); ++ if (retval) { ++ if (retval == 1 /* TIMEOUT_RC */) { ++ dm->config.is_enabled = VBNG_AAA_DISABLED; ++ } ++ error0 = VBNG_DHCP4_ERROR_AAA_FAILURE; ++ next0 = VBNG_DHCP4_TO_SERVER_INPUT_NEXT_DROP; ++ pkts_aaa_fail++; ++ goto do_trace; ++ } ++ } ++ ++ fl = vlib_buffer_get_free_list (vm, b0->free_list_index); ++ if (((u8 *)o - (u8 *)b0->data + (VPP_DHCP_OPTION82_SUB1_SIZE + VPP_DHCP_OPTION82_SUB5_SIZE)) ++ > fl->n_data_bytes) ++ { ++ next0 = VBNG_DHCP4_TO_SERVER_INPUT_NEXT_DROP; ++ pkts_too_big++; ++ goto do_trace; ++ } ++ ++ /* Begin to appending new sub-options */ ++ { ++ vnet_main_t *vnm = vnet_get_main(); ++ u16 old_l0, new_l0, orig_len = 0; ++ ip4_address_t _ia0, * ia0 = &_ia0; ++ vnet_sw_interface_t *swif; ++ sw_if_index = 0; ++ original_sw_if_index = 0; ++ ++ original_sw_if_index = sw_if_index = ++ vnet_buffer(b0)->sw_if_index[VLIB_RX]; ++ swif = vnet_get_sw_interface (vnm, sw_if_index); ++ if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) ++ sw_if_index = swif->unnumbered_sw_if_index; ++ ++ /* ++ * Get the first ip4 address on the [client-side] ++ * RX interface, if not unnumbered. otherwise use ++ * the loopback interface's ip address. ++ */ ++ ia0 = ip4_interface_first_address(&ip4_main, sw_if_index, 0); ++ ++ if (ia0 == 0) ++ { ++ error0 = VBNG_DHCP4_ERROR_NO_INTERFACE_ADDRESS; ++ next0 = VBNG_DHCP4_TO_SERVER_INPUT_NEXT_DROP; ++ pkts_no_interface_address++; ++ goto do_trace; ++ } ++ ++ orig_len = o->length; ++ o->data[orig_len + 0] = 1; /* suboption 1, circuit ID (=FIB id) */ ++ o->data[orig_len + 1] = 4; /* length of suboption */ ++ o->data[orig_len + 2] = (original_sw_if_index >> 24) & 0xFF; ++ o->data[orig_len + 3] = (original_sw_if_index >> 16) & 0xFF; ++ o->data[orig_len + 4] = (original_sw_if_index >> 8) & 0xFF; ++ o->data[orig_len + 5] = (original_sw_if_index >> 0) & 0xFF; ++ o->data[orig_len + 6] = 5; /* suboption 5 (client RX intfc address) */ ++ o->data[orig_len + 7] = 4; /* length 4 */ ++ o->data[orig_len + 8] = ia0->as_u8[0]; ++ o->data[orig_len + 9] = ia0->as_u8[1]; ++ o->data[orig_len + 10] = ia0->as_u8[2]; ++ o->data[orig_len + 11] = ia0->as_u8[3]; ++ o->data[orig_len + 12] = 0xFF; ++ o->length += 12; /* 12 octets appended*/ ++ ++ len = o->length + 3; ++ b0->current_length += len; ++ /* Fix IP header length and checksum */ ++ old_l0 = ip0->length; ++ new_l0 = clib_net_to_host_u16 (old_l0); ++ new_l0 += len; ++ new_l0 = clib_host_to_net_u16 (new_l0); ++ ip0->length = new_l0; ++ sum0 = ip0->checksum; ++ sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t, ++ length /* changed member */); ++ ip0->checksum = ip_csum_fold (sum0); ++ ++ /* Fix UDP length */ ++ new_l0 = clib_net_to_host_u16 (u0->length); ++ new_l0 += len; ++ u0->length = clib_host_to_net_u16 (new_l0); ++ } ++ } ++ ++ o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); ++ } ++ ++ next0 = VBNG_DHCP4_TO_SERVER_INPUT_NEXT_LOOKUP; ++ ++ /* ++ * If we have multiple servers configured and this is the ++ * client's discover message, then send copies to each of ++ * those servers ++ */ ++ if (is_discover && vec_len(proxy->dhcp_servers) > 1) ++ { ++ u32 ii; ++ ++ for (ii = 1; ii < vec_len(proxy->dhcp_servers); ii++) ++ { ++ vlib_buffer_t *c0; ++ u32 ci0; ++ ++ c0 = vlib_buffer_copy(vm, b0); ++ ci0 = vlib_get_buffer_index(vm, c0); ++ server = &proxy->dhcp_servers[ii]; ++ ++ ip0 = vlib_buffer_get_current (c0); ++ ++ sum0 = ip0->checksum; ++ old0 = ip0->dst_address.as_u32; ++ new0 = server->dhcp_server.ip4.as_u32; ++ ip0->dst_address.as_u32 = server->dhcp_server.ip4.as_u32; ++ sum0 = ip_csum_update (sum0, old0, new0, ++ ip4_header_t /* structure */, ++ dst_address /* changed member */); ++ ip0->checksum = ip_csum_fold (sum0); ++ ++ to_next[0] = ci0; ++ to_next += 1; ++ n_left_to_next -= 1; ++ ++ vlib_validate_buffer_enqueue_x1 (vm, node, next_index, ++ to_next, n_left_to_next, ++ ci0, next0); ++ ++ if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) ++ { ++ dhcp_proxy_trace_t *tr; ++ ++ tr = vlib_add_trace (vm, node, c0, sizeof (*tr)); ++ tr->which = 0; /* to server */ ++ tr->error = error0; ++ tr->original_sw_if_index = original_sw_if_index; ++ tr->sw_if_index = sw_if_index; ++ if (next0 == VBNG_DHCP4_TO_SERVER_INPUT_NEXT_LOOKUP) ++ tr->trace_ip4_address.as_u32 = server->dhcp_server.ip4.as_u32; ++ } ++ ++ if (PREDICT_FALSE(0 == n_left_to_next)) ++ { ++ vlib_put_next_frame (vm, node, next_index, ++ n_left_to_next); ++ vlib_get_next_frame (vm, node, next_index, ++ to_next, n_left_to_next); ++ } ++ } ++ } ++ do_trace: ++ if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) ++ { ++ dhcp_proxy_trace_t *tr = vlib_add_trace (vm, node, ++ b0, sizeof (*tr)); ++ tr->which = 0; /* to server */ ++ tr->error = error0; ++ tr->original_sw_if_index = original_sw_if_index; ++ tr->sw_if_index = sw_if_index; ++ if (next0 == VBNG_DHCP4_TO_SERVER_INPUT_NEXT_LOOKUP) ++ tr->trace_ip4_address.as_u32 = ++ proxy->dhcp_servers[0].dhcp_server.ip4.as_u32; ++ } ++ ++ do_enqueue: ++ to_next[0] = bi0; ++ to_next += 1; ++ n_left_to_next -= 1; ++ ++ vlib_validate_buffer_enqueue_x1 (vm, node, next_index, ++ to_next, n_left_to_next, ++ bi0, next0); ++ } ++ ++ vlib_put_next_frame (vm, node, next_index, n_left_to_next); ++ } ++ ++ vlib_node_increment_counter (vm, vbng_dhcp4_to_server_node.index, ++ VBNG_DHCP4_ERROR_RELAY_TO_CLIENT, ++ pkts_to_client); ++ vlib_node_increment_counter (vm, vbng_dhcp4_to_server_node.index, ++ VBNG_DHCP4_ERROR_RELAY_TO_SERVER, ++ pkts_to_server); ++ vlib_node_increment_counter (vm, vbng_dhcp4_to_server_node.index, ++ VBNG_DHCP4_ERROR_NO_SERVER, ++ pkts_no_server); ++ vlib_node_increment_counter (vm, vbng_dhcp4_to_server_node.index, ++ VBNG_DHCP4_ERROR_NO_INTERFACE_ADDRESS, ++ pkts_no_interface_address); ++ vlib_node_increment_counter (vm, vbng_dhcp4_to_server_node.index, ++ VBNG_DHCP4_ERROR_PKT_TOO_BIG, ++ pkts_too_big); ++ vlib_node_increment_counter (vm, vbng_dhcp4_to_server_node.index, ++ VBNG_DHCP4_ERROR_AAA_FAILURE, ++ pkts_aaa_fail); ++ return from_frame->n_vectors; ++} ++ ++VLIB_REGISTER_NODE (vbng_dhcp4_to_server_node, static) = { ++ .function = vbng_dhcp_to_server_input, ++ .name = "vbng-dhcp-to-server", ++ /* Takes a vector of packets. */ ++ .vector_size = sizeof (u32), ++ ++ .n_errors = VBNG_DHCP4_N_ERROR, ++ .error_strings = vbng_dhcp4_error_strings, ++ ++ .n_next_nodes = VBNG_DHCP4_TO_SERVER_INPUT_N_NEXT, ++ .next_nodes = { ++#define _(s,n) [VBNG_DHCP4_TO_SERVER_INPUT_NEXT_##s] = n, ++ foreach_vbng_dhcp4_to_server_input_next ++#undef _ ++ }, ++ ++ .format_buffer = format_dhcp_proxy_header_with_length, ++ .format_trace = format_dhcp_proxy_trace, ++}; ++ ++static uword ++vbng_dhcp_to_client_input (vlib_main_t * vm, ++ vlib_node_runtime_t * node, ++ vlib_frame_t * from_frame) ++{ ++ u32 n_left_from, * from; ++ ethernet_main_t *em = ethernet_get_main (vm); ++ vbng_dhcp4_main_t *dm = &vbng_dhcp4_main; ++ vnet_main_t * vnm = vnet_get_main(); ++ ip4_main_t * im = &ip4_main; ++ ++ from = vlib_frame_vector_args (from_frame); ++ n_left_from = from_frame->n_vectors; ++ ++ while (n_left_from > 0) ++ { ++ u32 bi0; ++ vlib_buffer_t * b0; ++ udp_header_t * u0; ++ dhcp_header_t * h0; ++ ip4_header_t * ip0 = 0; ++ ip4_address_t * ia0 = 0; ++ u32 old0, new0; ++ ip_csum_t sum0; ++ ethernet_interface_t *ei0; ++ ethernet_header_t *mac0; ++ vnet_hw_interface_t *hi0; ++ vlib_frame_t *f0; ++ u32 * to_next0; ++ u32 sw_if_index = ~0; ++ vnet_sw_interface_t *si0; ++ u32 error0 = (u32)~0; ++ vnet_sw_interface_t *swif; ++ u32 fib_index; ++ dhcp_proxy_t *proxy; ++ dhcp_server_t *server; ++ u32 original_sw_if_index = (u32) ~0; ++ ip4_address_t relay_addr = { ++ .as_u32 = 0, ++ }; ++ ++ bi0 = from[0]; ++ from += 1; ++ n_left_from -= 1; ++ ++ b0 = vlib_get_buffer (vm, bi0); ++ h0 = vlib_buffer_get_current (b0); ++ ++ /* ++ * udp_local hands us the DHCP header, need udp hdr, ++ * ip hdr to relay to client ++ */ ++ vlib_buffer_advance (b0, -(sizeof(*u0))); ++ u0 = vlib_buffer_get_current (b0); ++ ++ vlib_buffer_advance (b0, -(sizeof(*ip0))); ++ ip0 = vlib_buffer_get_current (b0); ++ ++ { ++ dhcp_option_t *o = (dhcp_option_t *) h0->options; ++ dhcp_option_t *sub; ++ ++ /* Parse through TLVs looking for option 82. ++ The circuit-ID is the FIB number we need ++ to track down the client-facing interface */ ++ ++ while (o->option != 0xFF /* end of options */ && ++ (u8 *) o < (b0->data + b0->current_data + b0->current_length)) ++ { ++ if (o->option == 82) ++ { ++ sub = (dhcp_option_t *) &o->data[0]; ++ while (sub->option != 0xFF /* end of options */ && ++ (u8 *) sub < (u8 *)(o + o->length)) { ++ /* If this is one of ours, it will have ++ total length 12, circuit-id suboption type, ++ and the sw_if_index */ ++ if (sub->option == 1 && sub->length == 4) ++ { ++ sw_if_index = ((sub->data[0] << 24) | ++ (sub->data[1] << 16) | ++ (sub->data[2] << 8) | ++ (sub->data[3])); ++ } ++ else if (sub->option == 5 && sub->length == 4) ++ { ++ relay_addr.as_u8[0] = sub->data[0]; ++ relay_addr.as_u8[1] = sub->data[1]; ++ relay_addr.as_u8[2] = sub->data[2]; ++ relay_addr.as_u8[3] = sub->data[3]; ++ } ++ sub = (dhcp_option_t *) ++ (((uword) sub) + (sub->length + 2)); ++ } ++ ++ } ++ o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); ++ } ++ } ++ ++ if (sw_if_index == (u32)~0) ++ { ++ error0 = VBNG_DHCP4_ERROR_NO_OPTION_82; ++ ++ drop_packet: ++ vlib_node_increment_counter (vm, vbng_dhcp4_to_client_node.index, ++ error0, 1); ++ f0 = vlib_get_frame_to_node (vm, dm->error_drop_node_index); ++ to_next0 = vlib_frame_vector_args (f0); ++ to_next0[0] = bi0; ++ f0->n_vectors = 1; ++ vlib_put_frame_to_node (vm, dm->error_drop_node_index, f0); ++ goto do_trace; ++ } ++ ++ if (relay_addr.as_u32 == 0) ++ { ++ error0 = VBNG_DHCP4_ERROR_BAD_OPTION_82_ADDR; ++ goto drop_packet; ++ } ++ ++ if (sw_if_index >= vec_len (im->fib_index_by_sw_if_index)) ++ { ++ error0 = VBNG_DHCP4_ERROR_BAD_OPTION_82_ITF; ++ goto drop_packet; ++ } ++ ++ fib_index = im->fib_index_by_sw_if_index [sw_if_index]; ++ proxy = vbng_dhcp4_get_server(dm, fib_index); ++ ++ if (PREDICT_FALSE (NULL == proxy)) ++ { ++ error0 = VBNG_DHCP4_ERROR_NO_SERVER; ++ goto drop_packet; ++ } ++ ++ vec_foreach(server, proxy->dhcp_servers) ++ { ++ if (ip0->src_address.as_u32 == server->dhcp_server.ip4.as_u32) ++ { ++ goto server_found; ++ } ++ } ++ ++ error0 = VBNG_DHCP4_ERROR_BAD_SVR_FIB_OR_ADDRESS; ++ goto drop_packet; ++ ++ server_found: ++ vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index; ++ ++ swif = vnet_get_sw_interface (vnm, sw_if_index); ++ original_sw_if_index = sw_if_index; ++ if (swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED) ++ sw_if_index = swif->unnumbered_sw_if_index; ++ ++ ia0 = ip4_interface_first_address (&ip4_main, sw_if_index, 0); ++ if (ia0 == 0) ++ { ++ error0 = VBNG_DHCP4_ERROR_NO_INTERFACE_ADDRESS; ++ goto drop_packet; ++ } ++ ++ if (relay_addr.as_u32 != ia0->as_u32) ++ { ++ error0 = VBNG_DHCP4_ERROR_BAD_YIADDR; ++ goto drop_packet; ++ } ++ ++ u0->checksum = 0; ++ u0->dst_port = clib_net_to_host_u16 (UDP_DST_PORT_dhcp_to_client); ++ sum0 = ip0->checksum; ++ old0 = ip0->dst_address.as_u32; ++ new0 = 0xFFFFFFFF; ++ ip0->dst_address.as_u32 = new0; ++ sum0 = ip_csum_update (sum0, old0, new0, ++ ip4_header_t /* structure */, ++ dst_address /* offset of changed member */); ++ ip0->checksum = ip_csum_fold (sum0); ++ ++ sum0 = ip0->checksum; ++ old0 = ip0->src_address.as_u32; ++ new0 = ia0->as_u32; ++ ip0->src_address.as_u32 = new0; ++ sum0 = ip_csum_update (sum0, old0, new0, ++ ip4_header_t /* structure */, ++ src_address /* offset of changed member */); ++ ip0->checksum = ip_csum_fold (sum0); ++ ++ vlib_buffer_advance (b0, -(sizeof(ethernet_header_t))); ++ si0 = vnet_get_sw_interface (vnm, original_sw_if_index); ++ if (si0->type == VNET_SW_INTERFACE_TYPE_SUB) ++ vlib_buffer_advance (b0, -4 /* space for VLAN tag */); ++ ++ mac0 = vlib_buffer_get_current (b0); ++ ++ hi0 = vnet_get_sup_hw_interface (vnm, original_sw_if_index); ++ ei0 = pool_elt_at_index (em->interfaces, hi0->hw_instance); ++ clib_memcpy (mac0->src_address, ei0->address, sizeof (ei0->address)); ++ memset (mac0->dst_address, 0xff, sizeof (mac0->dst_address)); ++ mac0->type = (si0->type == VNET_SW_INTERFACE_TYPE_SUB) ? ++ clib_net_to_host_u16(0x8100) : clib_net_to_host_u16 (0x0800); ++ ++ if (si0->type == VNET_SW_INTERFACE_TYPE_SUB) ++ { ++ u32 * vlan_tag = (u32 *)(mac0+1); ++ u32 tmp; ++ tmp = (si0->sub.id << 16) | 0x0800; ++ *vlan_tag = clib_host_to_net_u32 (tmp); ++ } ++ ++ /* $$$ This needs to be rewritten, for sure */ ++ f0 = vlib_get_frame_to_node (vm, hi0->output_node_index); ++ to_next0 = vlib_frame_vector_args (f0); ++ to_next0[0] = bi0; ++ f0->n_vectors = 1; ++ vlib_put_frame_to_node (vm, hi0->output_node_index, f0); ++ ++ do_trace: ++ if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) ++ { ++ dhcp_proxy_trace_t *tr = vlib_add_trace (vm, node, ++ b0, sizeof (*tr)); ++ tr->which = 1; /* to client */ ++ tr->trace_ip4_address.as_u32 = ia0 ? ia0->as_u32 : 0; ++ tr->error = error0; ++ tr->original_sw_if_index = original_sw_if_index; ++ tr->sw_if_index = sw_if_index; ++ } ++ } ++ return from_frame->n_vectors; ++} ++ ++VLIB_REGISTER_NODE (vbng_dhcp4_to_client_node, static) = { ++ .function = vbng_dhcp_to_client_input, ++ .name = "vbng-dhcp-to-client", ++ /* Takes a vector of packets. */ ++ .vector_size = sizeof (u32), ++ ++ .n_errors = VBNG_DHCP4_N_ERROR, ++ .error_strings = vbng_dhcp4_error_strings, ++ .format_buffer = format_dhcp_proxy_header_with_length, ++ .format_trace = format_dhcp_proxy_trace, ++}; ++ ++static clib_error_t * ++vbng_dhcp4_proxy_init (vlib_main_t * vm) ++{ ++ vbng_dhcp4_main_t *dm = &vbng_dhcp4_main; ++ vlib_node_t * error_drop_node; ++ ++ error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop"); ++ dm->error_drop_node_index = error_drop_node->index; ++ ++ udp_register_dst_port (vm, UDP_DST_PORT_dhcp_to_client, ++ vbng_dhcp4_to_client_node.index, 1 /* is_ip4 */); ++ ++ udp_register_dst_port (vm, UDP_DST_PORT_dhcp_to_server, ++ vbng_dhcp4_to_server_node.index, 1 /* is_ip4 */); ++ ++ dm->vlib_main = vm; ++ dm->vnet_main = vnet_get_main(); ++ ++ return 0; ++} ++ ++/* *INDENT-OFF* */ ++VLIB_INIT_FUNCTION (vbng_dhcp4_proxy_init); ++/* *INDENT-ON* */ ++ ++int ++vbng_dhcp4_set_server (ip46_address_t *addr, ++ ip46_address_t *src_addr, ++ u32 rx_table_id, ++ u32 server_table_id, ++ int is_del) ++{ ++ u32 rx_fib_index = 0; ++ int rc = 0; ++ ++ const fib_prefix_t all_1s = ++ { ++ .fp_len = 32, ++ .fp_addr.ip4.as_u32 = 0xffffffff, ++ .fp_proto = FIB_PROTOCOL_IP4, ++ }; ++ ++ if (ip46_address_is_zero(addr)) ++ return VNET_API_ERROR_INVALID_DST_ADDRESS; ++ ++ if (ip46_address_is_zero(src_addr)) ++ return VNET_API_ERROR_INVALID_SRC_ADDRESS; ++ ++ rx_fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, ++ rx_table_id); ++ ++ if (is_del) ++ { ++ if (vbng_dhcp4_server_del (FIB_PROTOCOL_IP4, rx_fib_index, ++ addr, server_table_id)) ++ { ++ fib_table_entry_special_remove(rx_fib_index, ++ &all_1s, ++ FIB_SOURCE_DHCP); ++ fib_table_unlock (rx_fib_index, FIB_PROTOCOL_IP4); ++ } ++ } ++ else ++ { ++ if (vbng_dhcp4_server_add (FIB_PROTOCOL_IP4, ++ addr, src_addr, ++ rx_fib_index, server_table_id)) ++ { ++ fib_table_entry_special_add(rx_fib_index, ++ &all_1s, ++ FIB_SOURCE_DHCP, ++ FIB_ENTRY_FLAG_LOCAL); ++ fib_table_lock (rx_fib_index, FIB_PROTOCOL_IP4); ++ } ++ } ++ fib_table_unlock (rx_fib_index, FIB_PROTOCOL_IP4); ++ ++ return (rc); ++} ++ ++static clib_error_t * ++dhcp4_proxy_set_command_fn (vlib_main_t * vm, ++ unformat_input_t * input, ++ vlib_cli_command_t * cmd) ++{ ++ ip46_address_t server_addr, src_addr; ++ u32 server_table_id = 0, rx_table_id = 0; ++ int is_del = 0; ++ int set_src = 0, set_server = 0; ++ ++ memset(&server_addr, 0, sizeof(server_addr)); ++ memset(&src_addr, 0, sizeof(src_addr)); ++ ++ while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) ++ { ++ if (unformat (input, "remote %U", ++ unformat_ip4_address, &server_addr.ip4)) ++ set_server = 1; ++ else if (unformat (input, "server-fib-id %d", &server_table_id)) ++ ; ++ else if (unformat (input, "rx-fib-id %d", &rx_table_id)) ++ ; ++ else if (unformat(input, "local %U", ++ unformat_ip4_address, &src_addr.ip4)) ++ set_src = 1; ++ else if (unformat (input, "delete") || ++ unformat (input, "del")) ++ is_del = 1; ++ else ++ break; ++ } ++ ++ if (is_del || (set_server && set_src)) ++ { ++ int rv; ++ ++ rv = vbng_dhcp4_set_server (&server_addr, &src_addr, rx_table_id, ++ server_table_id, is_del); ++ switch (rv) ++ { ++ case 0: ++ return 0; ++ ++ case VNET_API_ERROR_INVALID_DST_ADDRESS: ++ return clib_error_return (0, "Invalid remote address"); ++ ++ case VNET_API_ERROR_INVALID_SRC_ADDRESS: ++ return clib_error_return (0, "Invalid local address"); ++ ++ case VNET_API_ERROR_NO_SUCH_ENTRY: ++ return clib_error_return ++ (0, "Fib id %d: no per-fib DHCP server configured", rx_table_id); ++ ++ default: ++ return clib_error_return (0, "BUG: rv %d", rv); ++ } ++ } ++ else ++ return clib_error_return (0, "parse error`%U'", ++ format_unformat_error, input); ++} ++ ++VLIB_CLI_COMMAND (vbng_dhcp4_set_command, static) = { ++ .path = "set vbng dhcp4", ++ .short_help = "set vbng dhcp4 [del] remote <ip-addr> local <ip-addr> [server-fib-id <n>] [rx-fib-id <n>]", ++ .function = dhcp4_proxy_set_command_fn, ++}; ++ ++static u8 * ++format_dhcp4_proxy_server (u8 * s, va_list * args) ++{ ++ dhcp_proxy_t *proxy = va_arg (*args, dhcp_proxy_t *); ++ ip4_fib_t * rx_fib, * server_fib; ++ dhcp_server_t *server; ++ ++ if (proxy == 0) ++ { ++ s = format (s, "%=14s%=16s%s", "RX FIB", "Src Address", ++ "Servers FIB,Address"); ++ return s; ++ } ++ ++ rx_fib = ip4_fib_get(proxy->rx_fib_index); ++ ++ s = format (s, "%=14u%=16U", ++ rx_fib->table_id, ++ format_ip46_address, &proxy->dhcp_src_address, IP46_TYPE_ANY); ++ ++ vec_foreach(server, proxy->dhcp_servers) ++ { ++ server_fib = ip4_fib_get(server->server_fib_index); ++ s = format (s, "%u,%U ", ++ server_fib->table_id, ++ format_ip46_address, &server->dhcp_server, IP46_TYPE_ANY); ++ } ++ return s; ++} ++ ++static int ++dhcp4_proxy_show_walk (dhcp_proxy_t *server, ++ void *ctx) ++{ ++ vlib_main_t * vm = ctx; ++ ++ vlib_cli_output (vm, "%U", format_dhcp4_proxy_server, server); ++ ++ return (1); ++} ++ ++static clib_error_t * ++vbng_dhcp4_show_command_fn (vlib_main_t * vm, ++ unformat_input_t * input, ++ vlib_cli_command_t * cmd) ++{ ++ vlib_cli_output (vm, "%U", format_dhcp4_proxy_server, NULL /* header line */); ++ ++ vbng_dhcp4_walk(dhcp4_proxy_show_walk, vm); ++ ++ return (NULL); ++} ++ ++VLIB_CLI_COMMAND (vbng_dhcp4_show_command, static) = { ++ .path = "show vbng dhcp4", ++ .short_help = "Display vbng DHCP4 configuration info", ++ .function = vbng_dhcp4_show_command_fn, ++}; ++ ++static clib_error_t * ++vbng_aaa_set_command_fn (vlib_main_t * vm, ++ unformat_input_t * input, ++ vlib_cli_command_t * cmd) ++{ ++ vbng_dhcp4_main_t *dm = &vbng_dhcp4_main; ++ u8 *config_file = NULL; ++ u32 nas_port = 0; ++ int set_config = 0, is_del = 0; ++ ++ while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) { ++ if (unformat (input, "nas-port %d", &nas_port)) ++ ; ++ else if (unformat (input, "config %v", &config_file)) ++ set_config = 1; ++ else if (unformat (input, "delete") || ++ unformat (input, "del")) ++ is_del = 1; ++ else ++ break; ++ } ++ ++ if (!is_del && set_config) { ++ if (dm->config.is_enabled == VBNG_AAA_ENABLED) { ++ return 0; ++ } ++ ++ if (nas_port) { ++ dm->config.nas_port = nas_port; ++ } else { ++ dm->config.nas_port = AAA_DEFAULT_NAS_PORT; ++ } ++ dm->config.config_file = config_file; ++ dm->config.is_enabled = VBNG_AAA_ENABLED; ++ } else if (is_del) { ++ if (dm->config.is_enabled == VBNG_AAA_DISABLED) { ++ return 0; ++ } ++ ++ vec_free (dm->config.config_file); ++ dm->config.config_file = format(0, "%s", AAA_DEFAULT_CONFIG_FILE); ++ dm->config.nas_port = AAA_DEFAULT_NAS_PORT; ++ dm->config.is_enabled = VBNG_AAA_DISABLED; ++ } else { ++ return clib_error_return (0, "parse error`%U'", ++ format_unformat_error, input); ++ } ++ ++ return 0; ++} ++ ++VLIB_CLI_COMMAND (vbng_aaa_set_command, static) = { ++ .path = "set vbng aaa", ++ .short_help = "set vbng aaa [del] config <file> [nas-port <n>]", ++ .function = vbng_aaa_set_command_fn, ++}; ++ ++static u8 * ++format_vbng_aaa_config(u8 *s, va_list *args) ++{ ++ vbng_dhcp4_main_t *dm = &vbng_dhcp4_main; ++ ++ s = format(s, "%=8s %=8s %s\n", "Enabled", ++ "NAS Port", "Config File"); ++ ++ s = format(s, "%=8s %=8d %v\n", ++ dm->config.is_enabled ? "True" : "False", ++ dm->config.nas_port, ++ dm->config.config_file); ++ ++ return s; ++} ++ ++static clib_error_t * ++vbng_aaa_show_command_fn (vlib_main_t * vm, ++ unformat_input_t * input, ++ vlib_cli_command_t * cmd) ++{ ++ vlib_cli_output (vm, "%U", format_vbng_aaa_config, NULL); ++ ++ return (NULL); ++} ++ ++VLIB_CLI_COMMAND (vbng_aaa_show_command, static) = { ++ .path = "show vbng aaa", ++ .short_help = "Display vbng AAA configuration info", ++ .function = vbng_aaa_show_command_fn, ++}; ++ ++/* *INDENT-OFF* */ ++VLIB_PLUGIN_REGISTER () = { ++ .version = VPP_BUILD_VER, ++ .description = "DHCP V4 Proxy With Radius Client", ++}; ++/* *INDENT-ON* */ +diff --git a/src/plugins/vbng/vbng_msg_enum.h b/src/plugins/vbng/vbng_msg_enum.h +new file mode 100644 +index 00000000..1dc1357f +--- /dev/null ++++ b/src/plugins/vbng/vbng_msg_enum.h +@@ -0,0 +1,31 @@ ++/* ++ * vbng_msg_enum.h - vpp engine plug-in message enumeration ++ * ++ * Copyright (c) 2017 Intel 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. ++ */ ++#ifndef _VBNG_MSG_ENUM_H_ ++#define _VBNG_MSG_ENUM_H_ ++ ++#include <vppinfra/byte_order.h> ++ ++#define vl_msg_id(n,h) n, ++typedef enum ++{ ++#include <vbng/vbng_all_api_h.h> ++ /* We'll want to know how many messages IDs we need... */ ++ VL_MSG_FIRST_AVAILABLE, ++} vl_msg_id_t; ++#undef vl_msg_id ++ ++#endif /* _VBNG_MSG_ENUM_H_ */ +diff --git a/src/vnet.am b/src/vnet.am +index 9e099f33..7c107f0f 100644 +--- a/src/vnet.am ++++ b/src/vnet.am +@@ -682,31 +682,31 @@ endif + ######################################## + # DHCP client + ######################################## +-libvnet_la_SOURCES += \ +- vnet/dhcp/client.c \ +- vnet/dhcp/client.h \ +- vnet/dhcp/dhcp_api.c +- +-nobase_include_HEADERS += \ +- vnet/dhcp/client.h \ +- vnet/dhcp/dhcp.api.h +- +-API_FILES += vnet/dhcp/dhcp.api ++#libvnet_la_SOURCES += \ ++# vnet/dhcp/client.c \ ++# vnet/dhcp/client.h \ ++# vnet/dhcp/dhcp_api.c ++# ++#nobase_include_HEADERS += \ ++# vnet/dhcp/client.h \ ++# vnet/dhcp/dhcp.api.h ++# ++#API_FILES += vnet/dhcp/dhcp.api + + ######################################## + # DHCP proxy + ######################################## +-libvnet_la_SOURCES += \ +- vnet/dhcp/dhcp6_proxy_node.c \ +- vnet/dhcp/dhcp4_proxy_node.c \ +- vnet/dhcp/dhcp_proxy.c +- +-nobase_include_HEADERS += \ +- vnet/dhcp/dhcp4_packet.h \ +- vnet/dhcp/dhcp6_packet.h \ +- vnet/dhcp/dhcp_proxy.h \ +- vnet/dhcp/dhcp6_proxy_error.def \ +- vnet/dhcp/dhcp4_proxy_error.def ++#libvnet_la_SOURCES += \ ++# vnet/dhcp/dhcp6_proxy_node.c \ ++# vnet/dhcp/dhcp4_proxy_node.c \ ++# vnet/dhcp/dhcp_proxy.c ++# ++#nobase_include_HEADERS += \ ++# vnet/dhcp/dhcp4_packet.h \ ++# vnet/dhcp/dhcp6_packet.h \ ++# vnet/dhcp/dhcp_proxy.h \ ++# vnet/dhcp/dhcp6_proxy_error.def \ ++# vnet/dhcp/dhcp4_proxy_error.def + + ######################################## + # ipv6 segment routing +diff --git a/src/vpp-api/java/Makefile.am b/src/vpp-api/java/Makefile.am +index f18e0c24..cadaa8d9 100644 +--- a/src/vpp-api/java/Makefile.am ++++ b/src/vpp-api/java/Makefile.am +@@ -149,6 +149,26 @@ jvpp-snat/io_fd_vpp_jvpp_snat_JVppSnatImpl.h: $(jvpp_registry_ok) $(jvpp_snat_js + endif + + # ++# VBNG Plugin ++# ++if ENABLE_VBNG_PLUGIN ++noinst_LTLIBRARIES += libjvpp_vbng.la ++libjvpp_vbng_la_SOURCES = jvpp-vbng/jvpp_vbng.c ++libjvpp_vbng_la_CPPFLAGS = -Ijvpp-vbng ++libjvpp_vbng_la_LIBADD = $(JVPP_LIBS) ++libjvpp_vbng_la_DEPENDENCIES = libjvpp_common.la ++ ++BUILT_SOURCES += jvpp-vbng/io_fd_vpp_jvpp_vbng_JVppVbngImpl.h ++JAR_FILES += jvpp-vbng-$(PACKAGE_VERSION).jar ++CLEANDIRS += jvpp-vbng/target ++ ++jvpp_vbng_json_files = @top_builddir@/plugins/vbng/vbng.api.json ++ ++jvpp-vbng/io_fd_vpp_jvpp_vbng_JVppVbngImpl.h: $(jvpp_registry_ok) $(jvpp_vbng_json_files) ++ $(call japigen,vbng,JVppVbngImpl) ++endif ++ ++# + # iOAM Trace Plugin + # + if ENABLE_IOAM_PLUGIN +diff --git a/src/vpp-api/java/jvpp-vbng/jvpp_vbng.c b/src/vpp-api/java/jvpp-vbng/jvpp_vbng.c +new file mode 100644 +index 00000000..b722a500 +--- /dev/null ++++ b/src/vpp-api/java/jvpp-vbng/jvpp_vbng.c +@@ -0,0 +1,108 @@ ++/* ++ * Copyright (c) 2017 Intel Corp 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. ++ */ ++ ++#include <vnet/vnet.h> ++ ++#include <vbng/vbng_msg_enum.h> ++#define vl_typedefs /* define message structures */ ++#include <vbng/vbng_all_api_h.h> ++#undef vl_typedefs ++ ++#include <vnet/api_errno.h> ++#include <vlibapi/api.h> ++#include <vlibmemory/api.h> ++ ++#if VPPJNI_DEBUG == 1 ++ #define DEBUG_LOG(...) clib_warning(__VA_ARGS__) ++#else ++ #define DEBUG_LOG(...) ++#endif ++ ++#include <jvpp-common/jvpp_common.h> ++ ++#include "jvpp-vbng/io_fd_vpp_jvpp_vbng_JVppVbngImpl.h" ++#include "jvpp_vbng.h" ++#include "jvpp-vbng/jvpp_vbng_gen.h" ++ ++/* ++ * Class: io_fd_vpp_jvpp_vbng_JVppVbngImpl ++ * Method: init0 ++ * Signature: (JI)V ++ */ ++JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_vbng_JVppVbngImpl_init0 ++ (JNIEnv *env, jclass clazz, jobject callback, jlong queue_address, jint my_client_index) { ++ vbng_main_t * plugin_main = &vbng_main; ++ clib_warning ("Java_io_fd_vpp_jvpp_vbng_JVppVbngImpl_init0"); ++ ++ plugin_main->my_client_index = my_client_index; ++ plugin_main->vl_input_queue = (unix_shared_memory_queue_t *)queue_address; ++ ++ plugin_main->callbackObject = (*env)->NewGlobalRef(env, callback); ++ plugin_main->callbackClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, callback)); ++ ++ // verify API has not changed since jar generation ++ #define _(N) \ ++ get_message_id(env, #N); ++ foreach_supported_api_message; ++ #undef _ ++ ++ #define _(N,n) \ ++ vl_msg_api_set_handlers(get_message_id(env, #N), #n, \ ++ vl_api_##n##_t_handler, \ ++ vl_noop_handler, \ ++ vl_noop_handler, \ ++ vl_noop_handler, \ ++ sizeof(vl_api_##n##_t), 1); ++ foreach_api_reply_handler; ++ #undef _ ++} ++ ++JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_vbng_JVppVbngImpl_close0 ++(JNIEnv *env, jclass clazz) { ++ vbng_main_t * plugin_main = &vbng_main; ++ ++ // cleanup: ++ (*env)->DeleteGlobalRef(env, plugin_main->callbackClass); ++ (*env)->DeleteGlobalRef(env, plugin_main->callbackObject); ++ ++ plugin_main->callbackClass = NULL; ++ plugin_main->callbackObject = NULL; ++} ++ ++/* Attach thread to JVM and cache class references when initiating JVPP VES */ ++jint JNI_OnLoad(JavaVM *vm, void *reserved) { ++ JNIEnv* env; ++ ++ if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { ++ return JNI_EVERSION; ++ } ++ ++ if (cache_class_references(env) != 0) { ++ clib_warning ("Failed to cache class references\n"); ++ return JNI_ERR; ++ } ++ ++ return JNI_VERSION_1_8; ++} ++ ++/* Clean up cached references when disposing JVPP VES */ ++void JNI_OnUnload(JavaVM *vm, void *reserved) { ++ JNIEnv* env; ++ if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { ++ return; ++ } ++ delete_class_references(env); ++} +diff --git a/src/vpp-api/java/jvpp-vbng/jvpp_vbng.h b/src/vpp-api/java/jvpp-vbng/jvpp_vbng.h +new file mode 100644 +index 00000000..62b4cda5 +--- /dev/null ++++ b/src/vpp-api/java/jvpp-vbng/jvpp_vbng.h +@@ -0,0 +1,42 @@ ++/* ++ * Copyright (c) 2017 Intel Corp 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. ++ */ ++#ifndef __included_jvpp_vbng_h__ ++#define __included_jvpp_vbng_h__ ++ ++#include <vnet/vnet.h> ++#include <vnet/ip/ip.h> ++#include <vnet/api_errno.h> ++#include <vlibapi/api.h> ++#include <vlibmemory/api.h> ++#include <jni.h> ++ ++/* Global state for JVPP-VES */ ++typedef struct { ++ /* Pointer to shared memory queue */ ++ unix_shared_memory_queue_t * vl_input_queue; ++ ++ /* VPP api client index */ ++ u32 my_client_index; ++ ++ /* Callback object and class references enabling asynchronous Java calls */ ++ jobject callbackObject; ++ jclass callbackClass; ++ ++} vbng_main_t; ++ ++vbng_main_t vbng_main __attribute__((aligned (64))); ++ ++#endif /* __included_jvpp_vbng_h__ */ +-- +2.12.2.windows.2 + diff --git a/vnfs/vCPE/vpp-ves-agent-for-vgmux/src/patches/Hc2vpp-Add-VES-agent-for-vG-MUX.patch b/vnfs/vCPE/vpp-ves-agent-for-vgmux/src/patches/Hc2vpp-Add-VES-agent-for-vG-MUX.patch new file mode 100644 index 00000000..8c2e31b7 --- /dev/null +++ b/vnfs/vCPE/vpp-ves-agent-for-vgmux/src/patches/Hc2vpp-Add-VES-agent-for-vG-MUX.patch @@ -0,0 +1,1079 @@ +From 9a00b1af18dfe4c2df185299b8bd2db7f5d061c0 Mon Sep 17 00:00:00 2001 +From: Johnson Li <johnson.li@intel.com> +Date: Fri, 8 Sep 2017 17:35:16 +0800 +Subject: [PATCH] Add VES agent configuration for vG-MUX + +Signed-off-by: Johnson Li <johnson.li@intel.com> + +diff --git a/pom.xml b/pom.xml +index 538a5d98..581bedfc 100644 +--- a/pom.xml ++++ b/pom.xml +@@ -44,13 +44,14 @@ + <module>nat</module> + <module>lisp</module> + <module>release-notes</module> +- <module>vpp-integration</module> + <module>acl</module> + <module>dhcp</module> ++ <module>ves</module> + <module>samples</module> + <module>vpp-classifier</module> + <module>l3</module> + <module>vpp-management</module> ++ <module>vpp-integration</module> + <module>it</module> + </modules> + </project> +\ No newline at end of file +diff --git a/ves/asciidoc/Readme.adoc b/ves/asciidoc/Readme.adoc +new file mode 100644 +index 00000000..682e7555 +--- /dev/null ++++ b/ves/asciidoc/Readme.adoc +@@ -0,0 +1,3 @@ ++= ves-agent ++ ++Overview of ves-agent +diff --git a/ves/pom.xml b/ves/pom.xml +new file mode 100644 +index 00000000..1ded0109 +--- /dev/null ++++ b/ves/pom.xml +@@ -0,0 +1,56 @@ ++<?xml version="1.0" encoding="UTF-8"?> ++<!-- ++ Copyright (c) 2017 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.hc2vpp.common</groupId> ++ <artifactId>hc2vpp-parent</artifactId> ++ <version>1.17.04.1-SNAPSHOT</version> ++ <relativePath>../common/hc2vpp-parent</relativePath> ++ </parent> ++ ++ <groupId>io.fd.hc2vpp.ves</groupId> ++ <artifactId>ves-agent</artifactId> ++ <version>1.17.04.1-SNAPSHOT</version> ++ <name>ves-agent</name> ++ <packaging>pom</packaging> ++ <modelVersion>4.0.0</modelVersion> ++ <description>Agent for VNF Event Stream plugin</description> ++ ++ <modules> ++ <module>ves-api</module> ++ <module>ves-impl</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/ves/ves-api/asciidoc/Readme.adoc b/ves/ves-api/asciidoc/Readme.adoc +new file mode 100644 +index 00000000..b561268c +--- /dev/null ++++ b/ves/ves-api/asciidoc/Readme.adoc +@@ -0,0 +1,3 @@ ++= vesagent-api ++ ++Overview of vesagent-api +\ No newline at end of file +diff --git a/ves/ves-api/pom.xml b/ves/ves-api/pom.xml +new file mode 100644 +index 00000000..78bf47b9 +--- /dev/null ++++ b/ves/ves-api/pom.xml +@@ -0,0 +1,52 @@ ++<?xml version="1.0" encoding="UTF-8"?> ++<!-- ++ Copyright (c) 2017 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.hc2vpp.common</groupId> ++ <artifactId>api-parent</artifactId> ++ <version>1.17.04.1-SNAPSHOT</version> ++ <relativePath>../../common/api-parent</relativePath> ++ </parent> ++ ++ <modelVersion>4.0.0</modelVersion> ++ <groupId>io.fd.hc2vpp.ves</groupId> ++ <artifactId>ves-api</artifactId> ++ <name>ves-api</name> ++ <version>1.17.04.1-SNAPSHOT</version> ++ <packaging>bundle</packaging> ++ ++ <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> ++</project> +diff --git a/ves/ves-api/src/main/yang/vesagent.yang b/ves/ves-api/src/main/yang/vesagent.yang +new file mode 100644 +index 00000000..a3c79797 +--- /dev/null ++++ b/ves/ves-api/src/main/yang/vesagent.yang +@@ -0,0 +1,71 @@ ++module vesagent { ++ ++ yang-version 1; ++ namespace "urn:opendaylight:params:xml:ns:yang:vpp:vesagent"; ++ prefix "vesagent"; ++ ++ description ++ "This YANG module defines the generic configuration and ++ operational data for VES Agent in VPP"; ++ ++ revision "2017-08-01" { ++ description ++ "Initial revision of VES Agent model"; ++ } ++ ++ import ietf-inet-types { ++ prefix inet; ++ } ++ ++ grouping vesagent-attributes { ++ container config { ++ description ++ "VNF Event Stream Agent configuration"; ++ ++ leaf server-addr { ++ type inet:ipv4-address; ++ description ++ "VES Collector's IP address."; ++ } ++ ++ leaf server-port { ++ type uint32; ++ description ++ "VES Collector's Server Port."; ++ } ++ ++ leaf read-interval { ++ type uint32; ++ description ++ "Seconds of time period for each loop."; ++ } ++ ++ leaf is-add { ++ type uint32; ++ description ++ "0-Delete VES agent, NonZero-Start VES agent."; ++ } ++ } ++ ++ container mode { ++ description ++ "VNF Event Stream Agent Working Mode."; ++ ++ leaf base-packet-loss { ++ type uint32; ++ description ++ "Base packet Loss for Demo Mode"; ++ } ++ ++ leaf working-mode { ++ type string; ++ description ++ "VES Working Mode, Demo Or Real Only."; ++ } ++ } ++ } ++ ++ container vesagent { ++ uses vesagent-attributes; ++ } ++} +diff --git a/ves/ves-impl/asciidoc/Readme.adoc b/ves/ves-impl/asciidoc/Readme.adoc +new file mode 100644 +index 00000000..e07fb05f +--- /dev/null ++++ b/ves/ves-impl/asciidoc/Readme.adoc +@@ -0,0 +1,3 @@ ++= vesagent-impl ++ ++Overview of vesagent-impl +\ No newline at end of file +diff --git a/ves/ves-impl/pom.xml b/ves/ves-impl/pom.xml +new file mode 100644 +index 00000000..5ed2c1b4 +--- /dev/null ++++ b/ves/ves-impl/pom.xml +@@ -0,0 +1,157 @@ ++<?xml version="1.0" encoding="UTF-8"?> ++<!-- ++ Copyright (c) 2017 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.hc2vpp.common</groupId> ++ <artifactId>vpp-impl-parent</artifactId> ++ <version>1.17.04.1-SNAPSHOT</version> ++ <relativePath>../../vpp-common/vpp-impl-parent</relativePath> ++ </parent> ++ ++ <modelVersion>4.0.0</modelVersion> ++ <groupId>io.fd.hc2vpp.ves</groupId> ++ <artifactId>ves-impl</artifactId> ++ <name>${project.artifactId}</name> ++ <version>1.17.04.1-SNAPSHOT</version> ++ <packaging>bundle</packaging> ++ ++ <properties> ++ <honeycomb.infra.version>1.17.04.1-SNAPSHOT</honeycomb.infra.version> ++ <hc2vpp.common.version>1.17.04.1-SNAPSHOT</hc2vpp.common.version> ++ </properties> ++ ++ <dependencies> ++ <dependency> ++ <groupId>${project.groupId}</groupId> ++ <artifactId>ves-api</artifactId> ++ <version>${project.version}</version> ++ </dependency> ++ ++ <!--VPP common--> ++ <dependency> ++ <groupId>io.fd.hc2vpp.common</groupId> ++ <artifactId>vpp-translate-utils</artifactId> ++ </dependency> ++ ++ <!-- JVPP --> ++ <dependency> ++ <groupId>io.fd.vpp</groupId> ++ <artifactId>jvpp-registry</artifactId> ++ </dependency> ++ <dependency> ++ <groupId>io.fd.vpp</groupId> ++ <artifactId>jvpp-ves</artifactId> ++ <version>17.04.2-SNAPSHOT</version> ++ </dependency> ++ ++ <!-- Honeycomb infrastructure--> ++ <dependency> ++ <groupId>io.fd.honeycomb</groupId> ++ <artifactId>minimal-distribution</artifactId> ++ <version>${honeycomb.infra.version}</version> ++ </dependency> ++ ++ <dependency> ++ <groupId>io.fd.honeycomb</groupId> ++ <artifactId>translate-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> ++ ++ <!-- Translation --> ++ <dependency> ++ <groupId>io.fd.hc2vpp.common</groupId> ++ <artifactId>vpp-translate-utils</artifactId> ++ </dependency> ++ ++ <!-- DI --> ++ <dependency> ++ <groupId>com.google.inject</groupId> ++ <artifactId>guice</artifactId> ++ </dependency> ++ <dependency> ++ <groupId>net.jmob</groupId> ++ <artifactId>guice.conf</artifactId> ++ </dependency> ++ <dependency> ++ <groupId>com.google.inject.extensions</groupId> ++ <artifactId>guice-multibindings</artifactId> ++ </dependency> ++ <dependency> ++ <groupId>io.fd.honeycomb</groupId> ++ <artifactId>translate-impl</artifactId> ++ <version>1.17.04.1-SNAPSHOT</version> ++ </dependency> ++ ++ ++ <!-- Testing dependencies--> ++ <dependency> ++ <groupId>com.google.inject</groupId> ++ <artifactId>guice</artifactId> ++ </dependency> ++ <dependency> ++ <groupId>net.jmob</groupId> ++ <artifactId>guice.conf</artifactId> ++ </dependency> ++ <dependency> ++ <groupId>com.google.inject.extensions</groupId> ++ <artifactId>guice-multibindings</artifactId> ++ </dependency> ++ ++ <dependency> ++ <groupId>junit</groupId> ++ <artifactId>junit</artifactId> ++ <scope>test</scope> ++ </dependency> ++ <dependency> ++ <groupId>io.fd.hc2vpp.common</groupId> ++ <artifactId>vpp-translate-test</artifactId> ++ <version>${hc2vpp.common.version}</version> ++ <scope>test</scope> ++ </dependency> ++ <dependency> ++ <groupId>org.mockito</groupId> ++ <artifactId>mockito-core</artifactId> ++ <scope>test</scope> ++ </dependency> ++ <dependency> ++ <groupId>com.google.inject.extensions</groupId> ++ <artifactId>guice-testlib</artifactId> ++ <scope>test</scope> ++ </dependency> ++ <dependency> ++ <groupId>org.hamcrest</groupId> ++ <artifactId>hamcrest-all</artifactId> ++ <scope>test</scope> ++ </dependency> ++ <dependency> ++ <groupId>io.fd.honeycomb.infra</groupId> ++ <artifactId>test-tools</artifactId> ++ <version>${project.version}</version> ++ <scope>test</scope> ++ </dependency> ++ </dependencies> ++</project> +diff --git a/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/VesModule.java b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/VesModule.java +new file mode 100644 +index 00000000..0cd60068 +--- /dev/null ++++ b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/VesModule.java +@@ -0,0 +1,67 @@ ++/* ++ * Copyright (c) 2017 Intel Corp 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.hc2vpp.ves; ++ ++import com.google.common.annotations.VisibleForTesting; ++import com.google.inject.AbstractModule; ++import com.google.inject.Provider; ++import com.google.inject.Singleton; ++import com.google.inject.multibindings.Multibinder; ++import io.fd.hc2vpp.ves.jvpp.JVppVesProvider; ++import io.fd.hc2vpp.ves.read.VesReaderFactory; ++import io.fd.hc2vpp.ves.write.VesWriterFactory; ++import io.fd.honeycomb.translate.read.ReaderFactory; ++import io.fd.honeycomb.translate.write.WriterFactory; ++import io.fd.vpp.jvpp.ves.future.FutureJVppVesFacade; ++import org.slf4j.Logger; ++import org.slf4j.LoggerFactory; ++ ++/** ++ * VesModule class instantiating ves plugin components. ++ */ ++public final class VesModule extends AbstractModule { ++ ++ private static final Logger LOG = LoggerFactory.getLogger(VesModule.class); ++ private final Class<? extends Provider<FutureJVppVesFacade>> jvppVesProviderClass; ++ ++ public VesModule() { ++ this(JVppVesProvider.class); ++ } ++ ++ @VisibleForTesting ++ VesModule(Class<? extends Provider<FutureJVppVesFacade>> jvppVesProvider) { ++ this.jvppVesProviderClass = jvppVesProvider; ++ } ++ ++ @Override ++ protected void configure() { ++ LOG.info("Installing VES Agent module"); ++ ++ // Bind to Plugin's JVPP ++ bind(FutureJVppVesFacade.class).toProvider(jvppVesProviderClass).in(Singleton.class); ++ ++ LOG.info("Injecting writers factories"); ++ final Multibinder<WriterFactory> writerFactoryBinder = Multibinder.newSetBinder(binder(), WriterFactory.class); ++ writerFactoryBinder.addBinding().to(VesWriterFactory.class); ++ ++ LOG.info("Injecting readers factories"); ++ final Multibinder<ReaderFactory> readerFactoryBinder = Multibinder.newSetBinder(binder(), ReaderFactory.class); ++ readerFactoryBinder.addBinding().to(VesReaderFactory.class); ++ ++ LOG.info("Module VES Agent successfully configured"); ++ } ++} +diff --git a/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/jvpp/JVppVesProvider.java b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/jvpp/JVppVesProvider.java +new file mode 100644 +index 00000000..8afed84e +--- /dev/null ++++ b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/jvpp/JVppVesProvider.java +@@ -0,0 +1,59 @@ ++/* ++ * Copyright (c) 2017 Intel Corp 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.hc2vpp.ves.jvpp; ++ ++import com.google.inject.Inject; ++import io.fd.honeycomb.infra.distro.ProviderTrait; ++import io.fd.vpp.jvpp.JVppRegistry; ++import io.fd.vpp.jvpp.ves.JVppVesImpl; ++import io.fd.vpp.jvpp.ves.future.FutureJVppVesFacade; ++import java.io.IOException; ++import org.slf4j.Logger; ++import org.slf4j.LoggerFactory; ++ ++/** ++ * Provides future API for jvpp-ves plugin. Must be a singleton due to shutdown hook usage. ++ * Registers shutdown hook to free plugin's resources on shutdown. ++ */ ++public final class JVppVesProvider extends ProviderTrait<FutureJVppVesFacade> { ++ ++ private static final Logger LOG = LoggerFactory.getLogger(JVppVesProvider.class); ++ ++ @Inject ++ private JVppRegistry registry; ++ ++ @Override ++ protected FutureJVppVesFacade create() { ++ try { ++ final JVppVesImpl jvppVes = new JVppVesImpl(); ++ Runtime.getRuntime().addShutdownHook(new Thread() { ++ @Override ++ public void run() { ++ LOG.info("Unloading jvpp-ves plugin"); ++ jvppVes.close(); ++ LOG.info("Successfully unloaded jvpp-ves plugin"); ++ } ++ }); ++ ++ LOG.info("Successfully loaded jvpp-ves plugin"); ++ return new FutureJVppVesFacade(registry, jvppVes); ++ } catch (IOException e) { ++ throw new IllegalStateException("Unable to open VPP management connection", e); ++ } ++ } ++} ++ +diff --git a/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/read/VesReaderFactory.java b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/read/VesReaderFactory.java +new file mode 100644 +index 00000000..bef652fd +--- /dev/null ++++ b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/read/VesReaderFactory.java +@@ -0,0 +1,50 @@ ++/* ++ * Copyright (c) 2017 Intel Corp 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.hc2vpp.ves.read; ++ ++import com.google.inject.Inject; ++import io.fd.honeycomb.translate.read.ReaderFactory; ++import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder; ++import io.fd.vpp.jvpp.core.future.FutureJVppCore; ++import javax.annotation.Nonnull; ++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.Vesagent; ++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.VesagentBuilder; ++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.vesagent.attributes.Config; ++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.vesagent.attributes.ConfigBuilder; ++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.vesagent.attributes.Mode; ++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.vesagent.attributes.ModeBuilder; ++import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; ++ ++/** ++ * Factory producing writers for VES Agent plugin's data. ++ */ ++public final class VesReaderFactory implements ReaderFactory { ++ ++ private static final InstanceIdentifier<Vesagent> VESAGENT_ID = InstanceIdentifier.create(Vesagent.class); ++ private static final InstanceIdentifier<Config> CONFIG_ID = InstanceIdentifier.create(Config.class); ++ private static final InstanceIdentifier<Mode> MODE_ID = InstanceIdentifier.create(Mode.class); ++ ++ @Inject ++ private FutureJVppCore vppApi; ++ ++ @Override ++ public void init(@Nonnull final ModifiableReaderRegistryBuilder registry) { ++ registry.addStructuralReader(VESAGENT_ID, VesagentBuilder.class); ++ registry.addStructuralReader(CONFIG_ID, ConfigBuilder.class); ++ registry.addStructuralReader(MODE_ID, ModeBuilder.class); ++ } ++} +diff --git a/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/write/VesConfigCustomizer.java b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/write/VesConfigCustomizer.java +new file mode 100644 +index 00000000..e06afa73 +--- /dev/null ++++ b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/write/VesConfigCustomizer.java +@@ -0,0 +1,127 @@ ++/* ++ * Copyright (c) 2017 Intel Corp 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.hc2vpp.ves.write; ++ ++import static com.google.common.base.Preconditions.checkArgument; ++ ++import io.fd.hc2vpp.common.translate.util.ByteDataTranslator; ++import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer; ++import io.fd.hc2vpp.common.translate.util.Ipv4Translator; ++import io.fd.hc2vpp.common.translate.util.Ipv6Translator; ++import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; ++import io.fd.honeycomb.translate.spi.write.WriterCustomizer; ++import io.fd.honeycomb.translate.write.WriteContext; ++import io.fd.honeycomb.translate.write.WriteFailedException; ++import io.fd.vpp.jvpp.core.future.FutureJVppCore; ++//import io.fd.vpp.jvpp.ves.future.FutureJVppVes; ++import io.fd.vpp.jvpp.ves.dto.VesAgentConfig; ++import io.fd.vpp.jvpp.ves.future.FutureJVppVesFacade; ++import javax.annotation.Nonnull; ++//import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.Vesagent; ++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.vesagent.attributes.Config; ++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.vesagent.attributes.ConfigBuilder; ++import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; ++import org.slf4j.Logger; ++import org.slf4j.LoggerFactory; ++ ++final class VesConfigCustomizer extends FutureJVppCustomizer implements WriterCustomizer<Config>, ++ JvppReplyConsumer, ByteDataTranslator, Ipv6Translator, Ipv4Translator { ++ private static final Logger LOG = LoggerFactory.getLogger(VesConfigCustomizer.class); ++ ++ private final FutureJVppVesFacade jvppVes; ++ ++ VesConfigCustomizer(final FutureJVppCore vppApi, final FutureJVppVesFacade jvppVes) { ++ super(vppApi); ++ this.jvppVes = jvppVes; ++ } ++ ++ @Override ++ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Config> iid, @Nonnull final Config dataAfter, ++ @Nonnull final WriteContext writeContext) throws WriteFailedException { ++ ConfigBuilder configBuilder = new ConfigBuilder(); ++ InstanceIdentifier<Config> id = iid; ++ ++ LOG.debug("Writing VES Agent Config {} dataAfter={}", id, dataAfter); ++ checkArgument(dataAfter.getServerAddr() != null && dataAfter.getServerAddr().getValue() != null ++ && dataAfter.getServerPort() != 0, "VES Server Address and Port need to be configured"); ++ ++ configBuilder.setServerAddr(dataAfter.getServerAddr()) ++ .setServerPort(dataAfter.getServerPort()) ++ .setReadInterval(dataAfter.getReadInterval()) ++ .setIsAdd(1L); ++ ++ setVesAgentConfig(id, configBuilder.build()); ++ } ++ ++ @Override ++ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Config> iid, @Nonnull final Config dataBefore, ++ @Nonnull final Config dataAfter, @Nonnull final WriteContext writeContext) ++ throws WriteFailedException { ++ ConfigBuilder configBuilder = new ConfigBuilder(); ++ InstanceIdentifier<Config> id = iid; ++ ++ checkArgument(dataBefore.getServerAddr() != null && dataBefore.getServerAddr().getValue() != null ++ && dataBefore.getServerPort() != 0, "VES Server Address and Port need to be configured"); ++ checkArgument(dataAfter.getServerAddr() != null && dataAfter.getServerAddr().getValue() != null ++ && dataAfter.getServerPort() != 0, "VES Server Address and Port need to be configured"); ++ ++ // remove old configuration: ++ configBuilder.setServerAddr(dataBefore.getServerAddr()) ++ .setServerPort(dataBefore.getServerPort()) ++ .setReadInterval(dataBefore.getReadInterval()) ++ .setIsAdd(0L); ++ setVesAgentConfig(id, configBuilder.build()); ++ ++ // and add new one: ++ configBuilder.setServerAddr(dataAfter.getServerAddr()) ++ .setServerPort(dataAfter.getServerPort()) ++ .setReadInterval(dataAfter.getReadInterval()) ++ .setIsAdd(1L); ++ setVesAgentConfig(id, configBuilder.build()); ++ } ++ ++ @Override ++ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Config> iid, @Nonnull final Config dataBefore, ++ @Nonnull final WriteContext writeContext) throws WriteFailedException { ++ ConfigBuilder configBuilder = new ConfigBuilder(); ++ InstanceIdentifier<Config> id = iid; ++ LOG.debug("Removing VES Agent {} dataBefore={}", id, dataBefore); ++ ++ checkArgument(dataBefore.getServerAddr() != null && dataBefore.getServerAddr().getValue() != null ++ && dataBefore.getServerPort() != 0, "VES Server Address and Port need to be dataBeforeured"); ++ ++ configBuilder.setServerAddr(dataBefore.getServerAddr()) ++ .setServerPort(dataBefore.getServerPort()) ++ .setReadInterval(dataBefore.getReadInterval()) ++ .setIsAdd(0L); ++ ++ setVesAgentConfig(id, configBuilder.build()); ++ } ++ ++ private void setVesAgentConfig(final InstanceIdentifier<Config> id, final Config config) ++ throws WriteFailedException { ++ final VesAgentConfig request = new VesAgentConfig(); ++ ++ request.serverPort = config.getServerPort().byteValue(); ++ request.readInterval = config.getReadInterval().byteValue(); ++ request.isAdd = config.getIsAdd().byteValue(); ++ request.serverAddr = ipv4AddressNoZoneToArray(config.getServerAddr().getValue()); ++ ++ LOG.debug("VES agent config change id={} request={}", id, request); ++ getReplyForWrite(jvppVes.vesAgentConfig(request).toCompletableFuture(), id); ++ } ++} +diff --git a/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/write/VesModeCustomizer.java b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/write/VesModeCustomizer.java +new file mode 100644 +index 00000000..8b6d5a9a +--- /dev/null ++++ b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/write/VesModeCustomizer.java +@@ -0,0 +1,97 @@ ++/* ++ * Copyright (c) 2017 Intel Corp 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.hc2vpp.ves.write; ++ ++import static com.google.common.base.Preconditions.checkArgument; ++ ++import io.fd.hc2vpp.common.translate.util.ByteDataTranslator; ++import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer; ++import io.fd.hc2vpp.common.translate.util.Ipv4Translator; ++import io.fd.hc2vpp.common.translate.util.Ipv6Translator; ++import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; ++import io.fd.honeycomb.translate.spi.write.WriterCustomizer; ++import io.fd.honeycomb.translate.write.WriteContext; ++import io.fd.honeycomb.translate.write.WriteFailedException; ++import io.fd.vpp.jvpp.core.future.FutureJVppCore; ++//import io.fd.vpp.jvpp.ves.future.FutureJVppVes; ++import io.fd.vpp.jvpp.ves.dto.VesAgentMode; ++import io.fd.vpp.jvpp.ves.future.FutureJVppVesFacade; ++import javax.annotation.Nonnull; ++//import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.Vesagent; ++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.vesagent.attributes.Mode; ++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.vesagent.attributes.ModeBuilder; ++import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; ++import org.slf4j.Logger; ++import org.slf4j.LoggerFactory; ++ ++final class VesModeCustomizer extends FutureJVppCustomizer implements WriterCustomizer<Mode>, ++ JvppReplyConsumer, ByteDataTranslator, Ipv6Translator, Ipv4Translator { ++ private static final Logger LOG = LoggerFactory.getLogger(VesModeCustomizer.class); ++ ++ private final FutureJVppVesFacade jvppVes; ++ ++ VesModeCustomizer(final FutureJVppCore vppApi, final FutureJVppVesFacade jvppVes) { ++ super(vppApi); ++ this.jvppVes = jvppVes; ++ } ++ ++ @Override ++ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Mode> iid, @Nonnull final Mode dataAfter, ++ @Nonnull final WriteContext writeContext) throws WriteFailedException { ++ LOG.debug("Writing VES Agent Working Mode {} dataAfter={}", iid, dataAfter); ++ ++ checkArgument(dataAfter.getWorkingMode() != null && dataAfter.getBasePacketLoss() <= 100, ++ "VES Agent Working Mode need to be correctly configured."); ++ ++ setVesAgentMode(iid, dataAfter); ++ } ++ ++ @Override ++ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Mode> iid, @Nonnull final Mode dataBefore, ++ @Nonnull final Mode dataAfter, @Nonnull final WriteContext writeContext) ++ throws WriteFailedException { ++ LOG.debug("Writing VES Agent Working Mode {} {}-->{}", iid, dataBefore, dataAfter); ++ ++ checkArgument(dataAfter.getWorkingMode() != null && dataAfter.getBasePacketLoss() <= 100, ++ "VES Agent Working Mode need to be correctly configured."); ++ ++ setVesAgentMode(iid, dataAfter); ++ } ++ ++ @Override ++ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Mode> iid, @Nonnull final Mode dataBefore, ++ @Nonnull final WriteContext writeContext) throws WriteFailedException { ++ ModeBuilder modeBuilder = new ModeBuilder(); ++ LOG.debug("Restoring VES Mode {} dataBefore={} to default.", iid, dataBefore); ++ ++ modeBuilder.setWorkingMode("Real") ++ .setBasePacketLoss(0L); ++ ++ setVesAgentMode(iid, modeBuilder.build()); ++ } ++ ++ private void setVesAgentMode(final InstanceIdentifier<Mode> id, final Mode mode) ++ throws WriteFailedException { ++ final VesAgentMode request = new VesAgentMode(); ++ ++ request.pktLossRate = mode.getBasePacketLoss().byteValue(); ++ request.workMode = mode.getWorkingMode().getBytes(); ++ ++ LOG.debug("VES agent working mode change id={} request={}", id, request); ++ getReplyForWrite(jvppVes.vesAgentMode(request).toCompletableFuture(), id); ++ } ++} +diff --git a/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/write/VesWriterFactory.java b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/write/VesWriterFactory.java +new file mode 100644 +index 00000000..581f0460 +--- /dev/null ++++ b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/write/VesWriterFactory.java +@@ -0,0 +1,54 @@ ++/* ++ * Copyright (c) 2017 Intel Corp 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.hc2vpp.ves.write; ++ ++import com.google.common.collect.ImmutableSet; ++import com.google.inject.Inject; ++import io.fd.honeycomb.translate.impl.write.GenericWriter; ++import io.fd.honeycomb.translate.write.WriterFactory; ++import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder; ++import io.fd.vpp.jvpp.core.future.FutureJVppCore; ++import io.fd.vpp.jvpp.ves.future.FutureJVppVesFacade; ++import javax.annotation.Nonnull; ++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.Vesagent; ++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.vesagent.attributes.Config; ++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.vesagent.attributes.Mode; ++import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; ++ ++/** ++ * Factory producing writers for VES Agent plugin's data. ++ */ ++public final class VesWriterFactory implements WriterFactory { ++ ++ private static final InstanceIdentifier<Vesagent> VESAGENT_ID = InstanceIdentifier.create(Vesagent.class); ++ ++ @Inject ++ private FutureJVppCore vppApi; ++ ++ @Inject ++ protected FutureJVppVesFacade futureVesFacade; ++ ++ @Override ++ public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) { ++ registry.add(new GenericWriter<>(VESAGENT_ID, ++ new VesagentCustomizer(vppApi, futureVesFacade))); ++ registry.add(new GenericWriter<>(VESAGENT_ID.child(Config.class), ++ new VesConfigCustomizer(vppApi, futureVesFacade))); ++ registry.add(new GenericWriter<>(VESAGENT_ID.child(Mode.class), ++ new VesModeCustomizer(vppApi, futureVesFacade))); ++ } ++} +diff --git a/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/write/VesagentCustomizer.java b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/write/VesagentCustomizer.java +new file mode 100644 +index 00000000..62e46cdb +--- /dev/null ++++ b/ves/ves-impl/src/main/java/io/fd/hc2vpp/ves/write/VesagentCustomizer.java +@@ -0,0 +1,131 @@ ++/* ++ * Copyright (c) 2017 Intel Corp 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.hc2vpp.ves.write; ++ ++import static com.google.common.base.Preconditions.checkArgument; ++ ++import io.fd.hc2vpp.common.translate.util.ByteDataTranslator; ++import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer; ++import io.fd.hc2vpp.common.translate.util.Ipv4Translator; ++import io.fd.hc2vpp.common.translate.util.Ipv6Translator; ++import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; ++import io.fd.honeycomb.translate.spi.write.WriterCustomizer; ++import io.fd.honeycomb.translate.write.WriteContext; ++import io.fd.honeycomb.translate.write.WriteFailedException; ++import io.fd.vpp.jvpp.core.future.FutureJVppCore; ++//import io.fd.vpp.jvpp.ves.future.FutureJVppVes; ++import io.fd.vpp.jvpp.ves.dto.VesAgentConfig; ++import io.fd.vpp.jvpp.ves.future.FutureJVppVesFacade; ++import javax.annotation.Nonnull; ++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.Vesagent; ++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.vesagent.attributes.Config; ++import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vesagent.rev170801.vesagent.attributes.ConfigBuilder; ++import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; ++import org.slf4j.Logger; ++import org.slf4j.LoggerFactory; ++ ++final class VesagentCustomizer extends FutureJVppCustomizer implements WriterCustomizer<Vesagent>, ++ JvppReplyConsumer, ByteDataTranslator, Ipv6Translator, Ipv4Translator { ++ private static final Logger LOG = LoggerFactory.getLogger(VesagentCustomizer.class); ++ ++ private final FutureJVppVesFacade jvppVes; ++ ++ VesagentCustomizer(final FutureJVppCore vppApi, final FutureJVppVesFacade jvppVes) { ++ super(vppApi); ++ this.jvppVes = jvppVes; ++ } ++ ++ @Override ++ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Vesagent> iid, @Nonnull final Vesagent dataAfter, ++ @Nonnull final WriteContext writeContext) throws WriteFailedException { ++ Config config = dataAfter.getConfig(); ++ ConfigBuilder configBuilder = new ConfigBuilder(); ++ InstanceIdentifier<Config> id = iid.child(Config.class); ++ ++ LOG.debug("Writing VES Agent Config {} dataAfter={}", id, config); ++ checkArgument(config.getServerAddr() != null && config.getServerAddr().getValue() != null ++ && config.getServerPort() != 0, "VES Server Address and Port need to be configured"); ++ ++ configBuilder.setServerAddr(config.getServerAddr()) ++ .setServerPort(config.getServerPort()) ++ .setReadInterval(config.getReadInterval()) ++ .setIsAdd(1L); ++ ++ setVesAgentConfig(id, configBuilder.build()); ++ } ++ ++ @Override ++ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Vesagent> iid, @Nonnull final Vesagent dataBefore, ++ @Nonnull final Vesagent dataAfter, @Nonnull final WriteContext writeContext) ++ throws WriteFailedException { ++ Config configBefore = dataBefore.getConfig(); ++ Config configAfter = dataAfter.getConfig(); ++ ConfigBuilder configBuilder = new ConfigBuilder(); ++ InstanceIdentifier<Config> id = iid.child(Config.class); ++ ++ checkArgument(configBefore.getServerAddr() != null && configBefore.getServerAddr().getValue() != null ++ && configBefore.getServerPort() != 0, "VES Server Address and Port need to be configured"); ++ checkArgument(configAfter.getServerAddr() != null && configAfter.getServerAddr().getValue() != null ++ && configAfter.getServerPort() != 0, "VES Server Address and Port need to be configured"); ++ ++ // remove old configuration: ++ configBuilder.setServerAddr(configBefore.getServerAddr()) ++ .setServerPort(configBefore.getServerPort()) ++ .setReadInterval(configBefore.getReadInterval()) ++ .setIsAdd(0L); ++ setVesAgentConfig(id, configBuilder.build()); ++ ++ // and add new one: ++ configBuilder.setServerAddr(configAfter.getServerAddr()) ++ .setServerPort(configAfter.getServerPort()) ++ .setReadInterval(configAfter.getReadInterval()) ++ .setIsAdd(1L); ++ setVesAgentConfig(id, configBuilder.build()); ++ } ++ ++ @Override ++ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Vesagent> iid, @Nonnull final Vesagent dataBefore, ++ @Nonnull final WriteContext writeContext) throws WriteFailedException { ++ Config config = dataBefore.getConfig(); ++ InstanceIdentifier<Config> id = iid.child(Config.class); ++ LOG.debug("Removing VES Agent {} dataBefore={}", id, config); ++ ++ checkArgument(config.getServerAddr() != null && config.getServerAddr().getValue() != null ++ && config.getServerPort() != 0, "VES Server Address and Port need to be configured"); ++ ++ ConfigBuilder configBuilder = new ConfigBuilder(); ++ configBuilder.setServerAddr(config.getServerAddr()) ++ .setServerPort(config.getServerPort()) ++ .setReadInterval(config.getReadInterval()) ++ .setIsAdd(0L); ++ ++ setVesAgentConfig(id, configBuilder.build()); ++ } ++ ++ private void setVesAgentConfig(final InstanceIdentifier<Config> id, final Config config) ++ throws WriteFailedException { ++ final VesAgentConfig request = new VesAgentConfig(); ++ ++ request.serverPort = config.getServerPort().byteValue(); ++ request.readInterval = config.getReadInterval().byteValue(); ++ request.isAdd = config.getIsAdd().byteValue(); ++ request.serverAddr = ipv4AddressNoZoneToArray(config.getServerAddr().getValue()); ++ ++ LOG.debug("VES agent config change id={} request={}", id, request); ++ getReplyForWrite(jvppVes.vesAgentConfig(request).toCompletableFuture(), id); ++ } ++} +diff --git a/vpp-integration/minimal-distribution/pom.xml b/vpp-integration/minimal-distribution/pom.xml +index e126114a..ca0e5b24 100644 +--- a/vpp-integration/minimal-distribution/pom.xml ++++ b/vpp-integration/minimal-distribution/pom.xml +@@ -40,6 +40,7 @@ + <routing.version>1.17.04.1-SNAPSHOT</routing.version> + <acl.version>1.17.04.1-SNAPSHOT</acl.version> + <dhcp.version>1.17.04.1-SNAPSHOT</dhcp.version> ++ <vesagent.version>1.17.04.1-SNAPSHOT</vesagent.version> + <vpp.classifier.version>1.17.04.1-SNAPSHOT</vpp.classifier.version> + <l3-impl.version>1.17.04.1-SNAPSHOT</l3-impl.version> + <vpp-management-impl.version>1.17.04.1-SNAPSHOT</vpp-management-impl.version> +@@ -63,6 +64,7 @@ + io.fd.hc2vpp.routing.RoutingModule, + io.fd.hc2vpp.acl.AclModule, + io.fd.hc2vpp.dhcp.DhcpModule, ++ io.fd.hc2vpp.ves.VesModule, + io.fd.hc2vpp.policer.PolicerModule, + // io.fd.hc2vpp.vppnsh.impl.VppNshModule, + <!-- Nsh module by default disabled, because it needs vpp-nsh plugin, which is not part of vpp codebase.--> +@@ -151,6 +153,11 @@ + <version>${dhcp.version}</version> + </dependency> + <dependency> ++ <groupId>io.fd.hc2vpp.ves</groupId> ++ <artifactId>ves-impl</artifactId> ++ <version>${vesagent.version}</version> ++ </dependency> ++ <dependency> + <groupId>io.fd.hc2vpp.management</groupId> + <artifactId>vpp-management-impl</artifactId> + <version>${vpp-management-impl.version}</version> +-- +2.12.2.windows.2 + diff --git a/vnfs/vCPE/vpp-ves-agent-for-vgmux/src/patches/Vpp-Add-VES-agent-for-vG-MUX.patch b/vnfs/vCPE/vpp-ves-agent-for-vgmux/src/patches/Vpp-Add-VES-agent-for-vG-MUX.patch new file mode 100644 index 00000000..edfb6a3b --- /dev/null +++ b/vnfs/vCPE/vpp-ves-agent-for-vgmux/src/patches/Vpp-Add-VES-agent-for-vG-MUX.patch @@ -0,0 +1,7299 @@ +From 3d16acbb7942682864fd9b8ca9ca15e4147325f1 Mon Sep 17 00:00:00 2001 +From: Johnson Li <johnson.li@intel.com> +Date: Fri, 22 Sep 2017 08:58:40 +0800 +Subject: [PATCH] Add VES Agent to report statistics + +Change Log: +v2: Use VES 5.x as agent library +v1: Add VES agent to report statistics + +Signed-off-by: Johnson Li <johnson.li@intel.com> + +diff --git a/src/configure.ac b/src/configure.ac +index fb2ead6d..ea641525 100644 +--- a/src/configure.ac ++++ b/src/configure.ac +@@ -154,6 +154,7 @@ PLUGIN_ENABLED(lb) + PLUGIN_ENABLED(memif) + PLUGIN_ENABLED(sixrd) + PLUGIN_ENABLED(snat) ++PLUGIN_ENABLED(ves) + + ############################################################################### + # Dependency checks +diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am +index 623892e7..84513755 100644 +--- a/src/plugins/Makefile.am ++++ b/src/plugins/Makefile.am +@@ -69,6 +69,10 @@ if ENABLE_SNAT_PLUGIN + include snat.am + endif + ++if ENABLE_VES_PLUGIN ++include ves.am ++endif ++ + include ../suffix-rules.mk + + # Remove *.la files +diff --git a/src/plugins/ves.am b/src/plugins/ves.am +new file mode 100644 +index 00000000..10f2194b +--- /dev/null ++++ b/src/plugins/ves.am +@@ -0,0 +1,35 @@ ++# Copyright (c) <current-year> <your-organization> ++# 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. ++ ++vppplugins_LTLIBRARIES += ves_plugin.la ++ ++LIBS_DIR=$(CURDIR)/ves/libs ++ves_plugin_la_LDFLAGS = $(AM_LDFLAGS) -L$(LIBS_DIR) ++ves_plugin_la_LDFLAGS += -Wl,--whole-archive -level -Wl,--no-whole-archive ++ves_plugin_la_LDFLAGS += -Wl,-lpthread,-lcurl ++ ++ves_plugin_la_SOURCES = ves/ves_node.c \ ++ ves/ves_api.c ++ ++BUILT_SOURCES += \ ++ ves/ves.api.h \ ++ ves/ves.api.json ++ ++API_FILES += ves/ves.api ++ ++nobase_apiinclude_HEADERS += \ ++ ves/ves_all_api_h.h \ ++ ves/ves_msg_enum.h \ ++ ves/ves.api.h ++ ++# vi:syntax=automake +diff --git a/src/plugins/ves/include/double_list.h b/src/plugins/ves/include/double_list.h +new file mode 100644 +index 00000000..5cf7e1af +--- /dev/null ++++ b/src/plugins/ves/include/double_list.h +@@ -0,0 +1,57 @@ ++/*************************************************************************//** ++ * ++ * 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. ++ * ++ ****************************************************************************/ ++ ++/**************************************************************************//** ++ * @file ++ * A simple double-linked list. ++ * ++ * @note No thread protection so you will need to use appropriate ++ * synchronization if use spans multiple threads. ++ * ++ ****************************************************************************/ ++ ++#ifndef DOUBLE_LIST_INCLUDED ++#define DOUBLE_LIST_INCLUDED ++ ++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/src/plugins/ves/include/evel.h b/src/plugins/ves/include/evel.h +new file mode 100644 +index 00000000..6aceec30 +--- /dev/null ++++ b/src/plugins/ves/include/evel.h +@@ -0,0 +1,4494 @@ ++#ifndef EVEL_INCLUDED ++#define EVEL_INCLUDED ++/*************************************************************************//** ++ * ++ * 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. ++ * ++ ****************************************************************************/ ++ ++/**************************************************************************//** ++ * @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. ++ *****************************************************************************/ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#include <stdbool.h> ++#include <stdio.h> ++#include <stdarg.h> ++#include <time.h> ++ ++#include "jsmn.h" ++#include "double_list.h" ++#include "hashtable.h" ++ ++/*****************************************************************************/ ++/* Supported API version. */ ++/*****************************************************************************/ ++#define EVEL_API_MAJOR_VERSION 5 ++#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_HEARTBEAT_FIELD,/** A Heartbeat field event. */ ++ EVEL_DOMAIN_SIPSIGNALING, /** A Signaling event. */ ++ EVEL_DOMAIN_STATE_CHANGE, /** A State Change event. */ ++ EVEL_DOMAIN_SYSLOG, /** A Syslog event. */ ++ EVEL_DOMAIN_OTHER, /** Another event. */ ++ EVEL_DOMAIN_THRESHOLD_CROSS, /** A Threshold Crossing Event */ ++ EVEL_DOMAIN_VOICE_QUALITY, /** A Voice Quality 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; ++ ++/**************************************************************************//** ++ * enrichment fields for internal VES Event Listener service use only, ++ * not supplied by event sources ++ *****************************************************************************/ ++typedef struct internal_header_fields ++{ ++ void *object; ++ EVEL_BOOLEAN is_set; ++} EVEL_OPTION_INTHEADER_FIELDS; ++ ++/*****************************************************************************/ ++/* 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 * event_name; ++ char * source_name; ++ 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; ++ EVEL_OPTION_INTHEADER_FIELDS internal_field; ++ EVEL_OPTION_STRING nfcnaming_code; ++ EVEL_OPTION_STRING nfnaming_code; ++ ++} EVENT_HEADER; ++ ++/*****************************************************************************/ ++/* Supported Fault version. */ ++/*****************************************************************************/ ++#define EVEL_FAULT_MAJOR_VERSION 2 ++#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 category; ++ 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; ++ ++ ++/**************************************************************************//** ++ * optional field block for fields specific to heartbeat events ++ *****************************************************************************/ ++typedef struct event_heartbeat_fields ++{ ++ /***************************************************************************/ ++ /* Header and version */ ++ /***************************************************************************/ ++ EVENT_HEADER header; ++ int major_version; ++ int minor_version; ++ ++ /***************************************************************************/ ++ /* Mandatory fields */ ++ /***************************************************************************/ ++ double heartbeat_version; ++ int heartbeat_interval; ++ ++ /***************************************************************************/ ++ /* Optional fields */ ++ /***************************************************************************/ ++ DLIST additional_info; ++ ++} EVENT_HEARTBEAT_FIELD; ++ ++/**************************************************************************//** ++ * tuple which provides the name of a key along with its value and ++ * relative order ++ *****************************************************************************/ ++typedef struct internal_key ++{ ++ char *keyname; ++ EVEL_OPTION_INT keyorder; ++ EVEL_OPTION_STRING keyvalue; ++} EVEL_INTERNAL_KEY; ++ ++/**************************************************************************//** ++ * meta-information about an instance of a jsonObject along with ++ * the actual object instance ++ *****************************************************************************/ ++typedef struct json_object_instance ++{ ++ ++ char *jsonstring; ++ unsigned long long objinst_epoch_microsec; ++ DLIST object_keys; /*EVEL_INTERNAL_KEY list */ ++ ++} EVEL_JSON_OBJECT_INSTANCE; ++#define MAX_JSON_TOKENS 128 ++/**************************************************************************//** ++ * Create a new json object instance. ++ * ++ * @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. ++ * @param yourjson json string. ++ * @returns pointer to the newly manufactured ::EVEL_JSON_OBJECT_INSTANCE. ++ * not used (i.e. posted) it must be released using ::evel_free_jsonobjectinstance. ++ * @retval NULL Failed to create the json object instance. ++ *****************************************************************************/ ++EVEL_JSON_OBJECT_INSTANCE * evel_new_jsonobjinstance(const char *const yourjson); ++/**************************************************************************//** ++ * Free an json object instance. ++ * ++ * Free off the json object instance supplied. ++ * Will free all the contained allocated memory. ++ * ++ *****************************************************************************/ ++void evel_free_jsonobjinst(EVEL_JSON_OBJECT_INSTANCE * objinst); ++ ++/**************************************************************************//** ++ * enrichment fields for internal VES Event Listener service use only, ++ * not supplied by event sources ++ *****************************************************************************/ ++typedef struct json_object ++{ ++ ++ char *object_name; ++ EVEL_OPTION_STRING objectschema; ++ EVEL_OPTION_STRING objectschemaurl; ++ EVEL_OPTION_STRING nfsubscribedobjname; ++ EVEL_OPTION_STRING nfsubscriptionid; ++ DLIST jsonobjectinstances; /* EVEL_JSON_OBJECT_INSTANCE list */ ++ ++} EVEL_JSON_OBJECT; ++ ++/**************************************************************************//** ++ * Create a new json object. ++ * ++ * @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. ++ * @param name name of the object. ++ * @returns pointer to the newly manufactured ::EVEL_JSON_OBJECT. ++ * not used (i.e. posted) it must be released using ::evel_free_jsonobject. ++ * @retval NULL Failed to create the json object. ++ *****************************************************************************/ ++EVEL_JSON_OBJECT * evel_new_jsonobject(const char *const name); ++/**************************************************************************//** ++ * Free an json object. ++ * ++ * Free off the json object instance supplied. ++ * Will free all the contained allocated memory. ++ * ++ *****************************************************************************/ ++void evel_free_jsonobject(EVEL_JSON_OBJECT * jsobj); ++/*****************************************************************************/ ++/* Supported Measurement version. */ ++/*****************************************************************************/ ++#define EVEL_MEASUREMENT_MAJOR_VERSION 2 ++#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_info; ++ DLIST additional_measurements; ++ DLIST additional_objects; ++ DLIST codec_usage; ++ EVEL_OPTION_INT concurrent_sessions; ++ EVEL_OPTION_INT configured_entities; ++ DLIST cpu_usage; ++ DLIST disk_usage; ++ MEASUREMENT_ERRORS * errors; ++ DLIST feature_usage; ++ DLIST filesystem_usage; ++ DLIST latency_distribution; ++ EVEL_OPTION_DOUBLE mean_request_latency; ++ DLIST mem_usage; ++ EVEL_OPTION_INT media_ports_in_use; ++ EVEL_OPTION_INT request_rate; ++ EVEL_OPTION_INT vnfc_scaling_metric; ++ DLIST vnic_usage; ++ ++} EVENT_MEASUREMENT; ++ ++/**************************************************************************//** ++ * CPU Usage. ++ * JSON equivalent field: cpuUsage ++ *****************************************************************************/ ++typedef struct measurement_cpu_use { ++ char * id; ++ double usage; ++ EVEL_OPTION_DOUBLE idle; ++ EVEL_OPTION_DOUBLE intrpt; ++ EVEL_OPTION_DOUBLE nice; ++ EVEL_OPTION_DOUBLE softirq; ++ EVEL_OPTION_DOUBLE steal; ++ EVEL_OPTION_DOUBLE sys; ++ EVEL_OPTION_DOUBLE user; ++ EVEL_OPTION_DOUBLE wait; ++} MEASUREMENT_CPU_USE; ++ ++ ++/**************************************************************************//** ++ * Disk Usage. ++ * JSON equivalent field: diskUsage ++ *****************************************************************************/ ++typedef struct measurement_disk_use { ++ char * id; ++ EVEL_OPTION_DOUBLE iotimeavg; ++ EVEL_OPTION_DOUBLE iotimelast; ++ EVEL_OPTION_DOUBLE iotimemax; ++ EVEL_OPTION_DOUBLE iotimemin; ++ EVEL_OPTION_DOUBLE mergereadavg; ++ EVEL_OPTION_DOUBLE mergereadlast; ++ EVEL_OPTION_DOUBLE mergereadmax; ++ EVEL_OPTION_DOUBLE mergereadmin; ++ EVEL_OPTION_DOUBLE mergewriteavg; ++ EVEL_OPTION_DOUBLE mergewritelast; ++ EVEL_OPTION_DOUBLE mergewritemax; ++ EVEL_OPTION_DOUBLE mergewritemin; ++ EVEL_OPTION_DOUBLE octetsreadavg; ++ EVEL_OPTION_DOUBLE octetsreadlast; ++ EVEL_OPTION_DOUBLE octetsreadmax; ++ EVEL_OPTION_DOUBLE octetsreadmin; ++ EVEL_OPTION_DOUBLE octetswriteavg; ++ EVEL_OPTION_DOUBLE octetswritelast; ++ EVEL_OPTION_DOUBLE octetswritemax; ++ EVEL_OPTION_DOUBLE octetswritemin; ++ EVEL_OPTION_DOUBLE opsreadavg; ++ EVEL_OPTION_DOUBLE opsreadlast; ++ EVEL_OPTION_DOUBLE opsreadmax; ++ EVEL_OPTION_DOUBLE opsreadmin; ++ EVEL_OPTION_DOUBLE opswriteavg; ++ EVEL_OPTION_DOUBLE opswritelast; ++ EVEL_OPTION_DOUBLE opswritemax; ++ EVEL_OPTION_DOUBLE opswritemin; ++ EVEL_OPTION_DOUBLE pendingopsavg; ++ EVEL_OPTION_DOUBLE pendingopslast; ++ EVEL_OPTION_DOUBLE pendingopsmax; ++ EVEL_OPTION_DOUBLE pendingopsmin; ++ EVEL_OPTION_DOUBLE timereadavg; ++ EVEL_OPTION_DOUBLE timereadlast; ++ EVEL_OPTION_DOUBLE timereadmax; ++ EVEL_OPTION_DOUBLE timereadmin; ++ EVEL_OPTION_DOUBLE timewriteavg; ++ EVEL_OPTION_DOUBLE timewritelast; ++ EVEL_OPTION_DOUBLE timewritemax; ++ EVEL_OPTION_DOUBLE timewritemin; ++ ++} MEASUREMENT_DISK_USE; ++ ++/**************************************************************************//** ++ * Add an additional Disk 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 Disk utilization. ++ *****************************************************************************/ ++MEASUREMENT_DISK_USE * evel_measurement_new_disk_use_add(EVENT_MEASUREMENT * measurement, char * id); ++ ++/**************************************************************************//** ++ * 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; ++ ++/**************************************************************************//** ++ * Memory Usage. ++ * JSON equivalent field: memoryUsage ++ *****************************************************************************/ ++typedef struct measurement_mem_use { ++ char * id; ++ char * vmid; ++ double membuffsz; ++ EVEL_OPTION_DOUBLE memcache; ++ EVEL_OPTION_DOUBLE memconfig; ++ EVEL_OPTION_DOUBLE memfree; ++ EVEL_OPTION_DOUBLE slabrecl; ++ EVEL_OPTION_DOUBLE slabunrecl; ++ EVEL_OPTION_DOUBLE memused; ++} MEASUREMENT_MEM_USE; ++ ++/**************************************************************************//** ++ * Add an additional Memory 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 Memory identifier. ++ * @param vmidentifier ASCIIZ string with the VM's identifier. ++ * @param membuffsz Memory Size. ++ * ++ * @return Returns pointer to memory use structure in measurements ++ *****************************************************************************/ ++MEASUREMENT_MEM_USE * evel_measurement_new_mem_use_add(EVENT_MEASUREMENT * measurement, ++ char * id, char *vmidentifier, double membuffsz); ++ ++/**************************************************************************//** ++ * Set kilobytes of memory used for cache ++ * ++ * @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 mem_use Pointer to the Memory Use. ++ * @param val double ++ *****************************************************************************/ ++void evel_measurement_mem_use_memcache_set(MEASUREMENT_MEM_USE * const mem_use, ++ const double val); ++/**************************************************************************//** ++ * Set kilobytes of memory configured in the virtual machine on which the VNFC reporting ++ * ++ * @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 mem_use Pointer to the Memory Use. ++ * @param val double ++ *****************************************************************************/ ++void evel_measurement_mem_use_memconfig_set(MEASUREMENT_MEM_USE * const mem_use, ++ const double val); ++/**************************************************************************//** ++ * Set kilobytes of physical RAM left unused by the system ++ * ++ * @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 mem_use Pointer to the Memory Use. ++ * @param val double ++ *****************************************************************************/ ++void evel_measurement_mem_use_memfree_set(MEASUREMENT_MEM_USE * const mem_use, ++ const double val); ++/**************************************************************************//** ++ * Set the part of the slab that can be reclaimed such as caches measured in kilobytes ++ * ++ * @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 mem_use Pointer to the Memory Use. ++ * @param val double ++ *****************************************************************************/ ++void evel_measurement_mem_use_slab_reclaimed_set(MEASUREMENT_MEM_USE * const mem_use, ++ const double val); ++/**************************************************************************//** ++ * Set the part of the slab that cannot be reclaimed such as caches measured in kilobytes ++ * ++ * @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 mem_use Pointer to the Memory Use. ++ * @param val double ++ *****************************************************************************/ ++void evel_measurement_mem_use_slab_unreclaimable_set(MEASUREMENT_MEM_USE * const mem_use, ++ const double val); ++/**************************************************************************//** ++ * Set the total memory minus the sum of free, buffered, cached and slab memory in kilobytes ++ * ++ * @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 mem_use Pointer to the Memory Use. ++ * @param val double ++ *****************************************************************************/ ++void evel_measurement_mem_use_usedup_set(MEASUREMENT_MEM_USE * const mem_use, ++ const double val); ++/**************************************************************************//** ++ * 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_performance { ++ /***************************************************************************/ ++ /* Optional fields */ ++ /***************************************************************************/ ++ /*Cumulative count of broadcast packets received as read at the end of ++ the measurement interval*/ ++ EVEL_OPTION_DOUBLE recvd_bcast_packets_acc; ++ /*Count of broadcast packets received within the measurement interval*/ ++ EVEL_OPTION_DOUBLE recvd_bcast_packets_delta; ++ /*Cumulative count of discarded packets received as read at the end of ++ the measurement interval*/ ++ EVEL_OPTION_DOUBLE recvd_discarded_packets_acc; ++ /*Count of discarded packets received within the measurement interval*/ ++ EVEL_OPTION_DOUBLE recvd_discarded_packets_delta; ++ /*Cumulative count of error packets received as read at the end of ++ the measurement interval*/ ++ EVEL_OPTION_DOUBLE recvd_error_packets_acc; ++ /*Count of error packets received within the measurement interval*/ ++ EVEL_OPTION_DOUBLE recvd_error_packets_delta; ++ /*Cumulative count of multicast packets received as read at the end of ++ the measurement interval*/ ++ EVEL_OPTION_DOUBLE recvd_mcast_packets_acc; ++ /*Count of mcast packets received within the measurement interval*/ ++ EVEL_OPTION_DOUBLE recvd_mcast_packets_delta; ++ /*Cumulative count of octets received as read at the end of ++ the measurement interval*/ ++ EVEL_OPTION_DOUBLE recvd_octets_acc; ++ /*Count of octets received within the measurement interval*/ ++ EVEL_OPTION_DOUBLE recvd_octets_delta; ++ /*Cumulative count of all packets received as read at the end of ++ the measurement interval*/ ++ EVEL_OPTION_DOUBLE recvd_total_packets_acc; ++ /*Count of all packets received within the measurement interval*/ ++ EVEL_OPTION_DOUBLE recvd_total_packets_delta; ++ /*Cumulative count of unicast packets received as read at the end of ++ the measurement interval*/ ++ EVEL_OPTION_DOUBLE recvd_ucast_packets_acc; ++ /*Count of unicast packets received within the measurement interval*/ ++ EVEL_OPTION_DOUBLE recvd_ucast_packets_delta; ++ /*Cumulative count of transmitted broadcast packets at the end of ++ the measurement interval*/ ++ EVEL_OPTION_DOUBLE tx_bcast_packets_acc; ++ /*Count of transmitted broadcast packets within the measurement interval*/ ++ EVEL_OPTION_DOUBLE tx_bcast_packets_delta; ++ /*Cumulative count of transmit discarded packets at the end of ++ the measurement interval*/ ++ EVEL_OPTION_DOUBLE tx_discarded_packets_acc; ++ /*Count of transmit discarded packets within the measurement interval*/ ++ EVEL_OPTION_DOUBLE tx_discarded_packets_delta; ++ /*Cumulative count of transmit error packets at the end of ++ the measurement interval*/ ++ EVEL_OPTION_DOUBLE tx_error_packets_acc; ++ /*Count of transmit error packets within the measurement interval*/ ++ EVEL_OPTION_DOUBLE tx_error_packets_delta; ++ /*Cumulative count of transmit multicast packets at the end of ++ the measurement interval*/ ++ EVEL_OPTION_DOUBLE tx_mcast_packets_acc; ++ /*Count of transmit multicast packets within the measurement interval*/ ++ EVEL_OPTION_DOUBLE tx_mcast_packets_delta; ++ /*Cumulative count of transmit octets at the end of ++ the measurement interval*/ ++ EVEL_OPTION_DOUBLE tx_octets_acc; ++ /*Count of transmit octets received within the measurement interval*/ ++ EVEL_OPTION_DOUBLE tx_octets_delta; ++ /*Cumulative count of all transmit packets at the end of ++ the measurement interval*/ ++ EVEL_OPTION_DOUBLE tx_total_packets_acc; ++ /*Count of transmit packets within the measurement interval*/ ++ EVEL_OPTION_DOUBLE tx_total_packets_delta; ++ /*Cumulative count of all transmit unicast packets at the end of ++ the measurement interval*/ ++ EVEL_OPTION_DOUBLE tx_ucast_packets_acc; ++ /*Count of transmit unicast packets within the measurement interval*/ ++ EVEL_OPTION_DOUBLE tx_ucast_packets_delta; ++ /* Indicates whether vNicPerformance values are likely inaccurate ++ due to counter overflow or other condtions*/ ++ char *valuesaresuspect; ++ char *vnic_id; ++ ++} MEASUREMENT_VNIC_PERFORMANCE; ++ ++/**************************************************************************//** ++ * 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 2 ++ ++/**************************************************************************//** ++ * 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; ++ DLIST additional_info; /* JSON: additionalFields */ ++ ++ /***************************************************************************/ ++ /* 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; ++ ++/*****************************************************************************/ ++/* Supported Other field version. */ ++/*****************************************************************************/ ++#define EVEL_OTHER_EVENT_MAJOR_VERSION 1 ++#define EVEL_OTHER_EVENT_MINOR_VERSION 1 ++ ++/**************************************************************************//** ++ * Other. ++ * JSON equivalent field: otherFields ++ *****************************************************************************/ ++typedef struct event_other { ++ EVENT_HEADER header; ++ int major_version; ++ int minor_version; ++ ++ HASHTABLE_T *namedarrays; /* HASHTABLE_T */ ++ DLIST jsonobjects; /* DLIST of EVEL_JSON_OBJECT */ ++ DLIST namedvalues; ++} EVENT_OTHER; ++ ++/**************************************************************************//** ++ * Other Field. ++ * JSON equivalent field: otherFields ++ *****************************************************************************/ ++typedef struct other_field { ++ char * name; ++ char * value; ++} OTHER_FIELD; ++ ++ ++/*****************************************************************************/ ++/* Supported Service Events version. */ ++/*****************************************************************************/ ++#define EVEL_HEARTBEAT_FIELD_MAJOR_VERSION 1 ++#define EVEL_HEARTBEAT_FIELD_MINOR_VERSION 1 ++ ++ ++/*****************************************************************************/ ++/* Supported Signaling version. */ ++/*****************************************************************************/ ++#define EVEL_SIGNALING_MAJOR_VERSION 2 ++#define EVEL_SIGNALING_MINOR_VERSION 1 ++ ++/**************************************************************************//** ++ * Vendor VNF Name fields. ++ * JSON equivalent field: vendorVnfNameFields ++ *****************************************************************************/ ++typedef struct vendor_vnfname_field { ++ char * vendorname; ++ EVEL_OPTION_STRING vfmodule; ++ EVEL_OPTION_STRING vnfname; ++} VENDOR_VNFNAME_FIELD; ++ ++/**************************************************************************//** ++ * Signaling. ++ * JSON equivalent field: signalingFields ++ *****************************************************************************/ ++typedef struct event_signaling { ++ /***************************************************************************/ ++ /* Header and version */ ++ /***************************************************************************/ ++ EVENT_HEADER header; ++ int major_version; ++ int minor_version; ++ ++ /***************************************************************************/ ++ /* Mandatory fields */ ++ /***************************************************************************/ ++ VENDOR_VNFNAME_FIELD vnfname_field; ++ 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 */ ++ ++ /***************************************************************************/ ++ /* Optional fields */ ++ /***************************************************************************/ ++ EVEL_OPTION_STRING compressed_sip; /* JSON: compressedSip */ ++ EVEL_OPTION_STRING summary_sip; /* JSON: summarySip */ ++ DLIST additional_info; ++ ++} EVENT_SIGNALING; ++ ++/**************************************************************************//** ++ * Sgnaling Additional Field. ++ * JSON equivalent field: additionalFields ++ *****************************************************************************/ ++typedef struct signaling_additional_field { ++ char * name; ++ char * value; ++} SIGNALING_ADDL_FIELD; ++ ++/*****************************************************************************/ ++/* Supported State Change version. */ ++/*****************************************************************************/ ++#define EVEL_STATE_CHANGE_MAJOR_VERSION 1 ++#define EVEL_STATE_CHANGE_MINOR_VERSION 2 ++ ++/**************************************************************************//** ++ * 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; ++ double version; ++ ++ /***************************************************************************/ ++ /* 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 2 ++ ++/**************************************************************************//** ++ * 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 */ ++ /***************************************************************************/ ++ EVEL_OPTION_STRING additional_filters; ++ EVEL_OPTION_STRING event_source_host; ++ EVEL_OPTION_INT syslog_facility; ++ EVEL_OPTION_INT syslog_priority; ++ EVEL_OPTION_STRING syslog_proc; ++ EVEL_OPTION_INT syslog_proc_id; ++ EVEL_OPTION_STRING syslog_s_data; ++ EVEL_OPTION_STRING syslog_sdid; ++ EVEL_OPTION_STRING syslog_severity; ++ double syslog_fver; ++ EVEL_OPTION_INT syslog_ver; ++ ++} EVENT_SYSLOG; ++ ++/**************************************************************************//** ++ * 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); ++ ++/**************************************************************************//** ++ * Initialize an event instance id. ++ * ++ * @param vfield Pointer to the event vnfname field 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_vendor_field(VENDOR_VNFNAME_FIELD * const vfield, ++ const char * const vendor_name); ++ ++/**************************************************************************//** ++ * Set the Vendor module property of the Vendor. ++ * ++ * @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 vfield Pointer to the Vendor field. ++ * @param module_name The module name to be set. ASCIIZ string. The caller ++ * does not need to preserve the value once the function ++ * returns. ++ *****************************************************************************/ ++void evel_vendor_field_module_set(VENDOR_VNFNAME_FIELD * const vfield, ++ const char * const module_name); ++/**************************************************************************//** ++ * Set the Vendor module property of the Vendor. ++ * ++ * @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 vfield Pointer to the Vendor field. ++ * @param module_name The module name to be set. ASCIIZ string. The caller ++ * does not need to preserve the value once the function ++ * returns. ++ *****************************************************************************/ ++void evel_vendor_field_vnfname_set(VENDOR_VNFNAME_FIELD * const vfield, ++ const char * const vnfname); ++/**************************************************************************//** ++ * Free an event instance id. ++ * ++ * @param vfield Pointer to the event vnfname_field being freed. ++ *****************************************************************************/ ++void evel_free_event_vendor_field(VENDOR_VNFNAME_FIELD * const vfield); ++ ++/**************************************************************************//** ++ * 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); ++ ++/**************************************************************************//** ++ * Create a new heartbeat event of given name and type. ++ * ++ * @note that the heartbeat is just a "naked" commonEventHeader! ++ * ++ * @param event_name Unique Event Name confirming Domain AsdcModel Description ++ * @param event_id A universal identifier of the event for: troubleshooting correlation, analysis, etc ++ * ++ * @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_nameid(const char* ev_name, const char *ev_id); ++ ++ ++/**************************************************************************//** ++ * 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,const char *const eventname); ++ ++/**************************************************************************//** ++ * 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); ++ ++/**************************************************************************//** ++ * Set the NFC Naming code property of the event header. ++ * ++ * @param header Pointer to the ::EVENT_HEADER. ++ * @param nfcnamingcode String ++ *****************************************************************************/ ++void evel_nfcnamingcode_set(EVENT_HEADER * const header, ++ const char * const nfcnam); ++/**************************************************************************//** ++ * Set the NF Naming code property of the event header. ++ * ++ * @param header Pointer to the ::EVENT_HEADER. ++ * @param nfnamingcode String ++ *****************************************************************************/ ++void evel_nfnamingcode_set(EVENT_HEADER * const header, ++ const char * const nfnam); ++ ++/*****************************************************************************/ ++/*****************************************************************************/ ++/* */ ++/* FAULT */ ++/* */ ++/*****************************************************************************/ ++/*****************************************************************************/ ++ ++/**************************************************************************//** ++ * 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 event_name Unique Event Name ++ * @param event_id A universal identifier of the event for analysis etc ++ * @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. ++ * @param ev_source_type Source of Alarm event ++ * @param version fault version ++ * @param status status of Virtual Function ++ * @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* ev_name, const char *ev_id, ++ const char * const condition, ++ const char * const specific_problem, ++ EVEL_EVENT_PRIORITIES priority, ++ EVEL_SEVERITIES severity, ++ EVEL_SOURCE_TYPES ev_source_type, ++ EVEL_VF_STATUSES status); ++ ++/**************************************************************************//** ++ * 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 Fault Category 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 category Category : license, link, routing, security, signaling. ++ * ASCIIZ string. The caller ++ * does not need to preserve the value once the function ++ * returns. ++ *****************************************************************************/ ++void evel_fault_category_set(EVENT_FAULT * fault, ++ const char * const category); ++ ++/**************************************************************************//** ++ * 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 ++ * @param event_name Unique Event Name ++ * @param event_id A universal identifier of the event for analysis etc ++ * ++ * @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,const char* ev_name, const char *ev_id); ++ ++/**************************************************************************//** ++ * 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 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. ++ *****************************************************************************/ ++MEASUREMENT_CPU_USE * evel_measurement_new_cpu_use_add(EVENT_MEASUREMENT * measurement, char * id, double usage); ++ ++/**************************************************************************//** ++ * Set the CPU Idle value in measurement interval ++ * percentage of CPU time spent in the idle task ++ * ++ * @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 cpu_use Pointer to the CPU Use. ++ * @param val double ++ *****************************************************************************/ ++void evel_measurement_cpu_use_idle_set(MEASUREMENT_CPU_USE *const cpu_use, ++ const double val); ++ ++/**************************************************************************//** ++ * Set the percentage of time spent servicing interrupts ++ * ++ * @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 cpu_use Pointer to the CPU Use. ++ * @param val double ++ *****************************************************************************/ ++void evel_measurement_cpu_use_interrupt_set(MEASUREMENT_CPU_USE * const cpu_use, ++ const double val); ++ ++/**************************************************************************//** ++ * Set the percentage of time spent running user space processes that have been niced ++ * ++ * @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 cpu_use Pointer to the CPU Use. ++ * @param val double ++ *****************************************************************************/ ++void evel_measurement_cpu_use_nice_set(MEASUREMENT_CPU_USE * const cpu_use, ++ const double val); ++ ++/**************************************************************************//** ++ * Set the percentage of time spent handling soft irq interrupts ++ * ++ * @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 cpu_use Pointer to the CPU Use. ++ * @param val double ++ *****************************************************************************/ ++void evel_measurement_cpu_use_softirq_set(MEASUREMENT_CPU_USE * const cpu_use, ++ const double val); ++/**************************************************************************//** ++ * Set the percentage of time spent in involuntary wait ++ * ++ * @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 cpu_use Pointer to the CPU Use. ++ * @param val double ++ *****************************************************************************/ ++void evel_measurement_cpu_use_steal_set(MEASUREMENT_CPU_USE * const cpu_use, ++ const double val); ++/**************************************************************************//** ++ * Set the percentage of time spent on system tasks running the kernel ++ * ++ * @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 cpu_use Pointer to the CPU Use. ++ * @param val double ++ *****************************************************************************/ ++void evel_measurement_cpu_use_system_set(MEASUREMENT_CPU_USE * const cpu_use, ++ const double val); ++/**************************************************************************//** ++ * Set the percentage of time spent running un-niced user space processes ++ * ++ * @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 cpu_use Pointer to the CPU Use. ++ * @param val double ++ *****************************************************************************/ ++void evel_measurement_cpu_use_usageuser_set(MEASUREMENT_CPU_USE * const cpu_use, ++ const double val); ++/**************************************************************************//** ++ * Set the percentage of CPU time spent waiting for I/O operations to complete ++ * ++ * @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 cpu_use Pointer to the CPU Use. ++ * @param val double ++ *****************************************************************************/ ++void evel_measurement_cpu_use_wait_set(MEASUREMENT_CPU_USE * const cpu_use, ++ const double val); ++ ++/**************************************************************************//** ++ * 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 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, ++ int 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_PERFORMANCE 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_PERFORMANCE has immutable ++ * properties. ++ * ++ * @param vnic_id ASCIIZ string with the vNIC's ID. ++ * @param val_suspect True or false confidence in data. ++ * ++ * @returns pointer to the newly manufactured ::MEASUREMENT_VNIC_PERFORMANCE. ++ * If the structure is not used it must be released using ++ * ::evel_measurement_free_vnic_performance. ++ * @retval NULL Failed to create the vNIC Use. ++ *****************************************************************************/ ++MEASUREMENT_VNIC_PERFORMANCE * evel_measurement_new_vnic_performance(char * const vnic_id, char * const val_suspect); ++ ++/**************************************************************************//** ++ * Free a vNIC Use. ++ * ++ * Free off the ::MEASUREMENT_VNIC_PERFORMANCE 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_measurement_free_vnic_performance(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance); ++ ++/**************************************************************************//** ++ * Set the Accumulated Broadcast Packets Received in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param recvd_bcast_packets_acc ++ *****************************************************************************/ ++void evel_vnic_performance_rx_bcast_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double recvd_bcast_packets_acc); ++/**************************************************************************//** ++ * Set the Delta Broadcast Packets Received in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param recvd_bcast_packets_delta ++ *****************************************************************************/ ++void evel_vnic_performance_rx_bcast_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double recvd_bcast_packets_delta); ++/**************************************************************************//** ++ * Set the Discarded Packets Received in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param recvd_discard_packets_acc ++ *****************************************************************************/ ++void evel_vnic_performance_rx_discard_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double recvd_discard_packets_acc); ++/**************************************************************************//** ++ * Set the Delta Discarded Packets Received in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param recvd_discard_packets_delta ++ *****************************************************************************/ ++void evel_vnic_performance_rx_discard_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double recvd_discard_packets_delta); ++/**************************************************************************//** ++ * Set the Error Packets Received in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param recvd_error_packets_acc ++ *****************************************************************************/ ++void evel_vnic_performance_rx_error_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double recvd_error_packets_acc); ++/**************************************************************************//** ++ * Set the Delta Error Packets Received in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param recvd_error_packets_delta ++ *****************************************************************************/ ++void evel_vnic_performance_rx_error_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double recvd_error_packets_delta); ++/**************************************************************************//** ++ * Set the Accumulated Multicast Packets Received in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param recvd_mcast_packets_acc ++ *****************************************************************************/ ++void evel_vnic_performance_rx_mcast_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double recvd_mcast_packets_acc); ++/**************************************************************************//** ++ * Set the Delta Multicast Packets Received in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param recvd_mcast_packets_delta ++ *****************************************************************************/ ++void evel_vnic_performance_rx_mcast_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double recvd_mcast_packets_delta); ++/**************************************************************************//** ++ * Set the Accumulated Octets Received in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param recvd_octets_acc ++ *****************************************************************************/ ++void evel_vnic_performance_rx_octets_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double recvd_octets_acc); ++/**************************************************************************//** ++ * Set the Delta Octets Received in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param recvd_octets_delta ++ *****************************************************************************/ ++void evel_vnic_performance_rx_octets_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double recvd_octets_delta); ++/**************************************************************************//** ++ * Set the Accumulated Total Packets Received in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param recvd_total_packets_acc ++ *****************************************************************************/ ++void evel_vnic_performance_rx_total_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double recvd_total_packets_acc); ++/**************************************************************************//** ++ * Set the Delta Total Packets Received in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param recvd_total_packets_delta ++ *****************************************************************************/ ++void evel_vnic_performance_rx_total_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double recvd_total_packets_delta); ++/**************************************************************************//** ++ * Set the Accumulated Unicast Packets Received in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param recvd_ucast_packets_acc ++ *****************************************************************************/ ++void evel_vnic_performance_rx_ucast_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double recvd_ucast_packets_acc); ++/**************************************************************************//** ++ * Set the Delta Unicast packets Received in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param recvd_ucast_packets_delta ++ *****************************************************************************/ ++void evel_vnic_performance_rx_ucast_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double recvd_ucast_packets_delta); ++/**************************************************************************//** ++ * Set the Transmitted Broadcast Packets in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param tx_bcast_packets_acc ++ *****************************************************************************/ ++void evel_vnic_performance_tx_bcast_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double tx_bcast_packets_acc); ++/**************************************************************************//** ++ * Set the Delta Broadcast packets Transmitted in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param tx_bcast_packets_delta ++ *****************************************************************************/ ++void evel_vnic_performance_tx_bcast_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double tx_bcast_packets_delta); ++/**************************************************************************//** ++ * Set the Transmitted Discarded Packets in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param tx_discarded_packets_acc ++ *****************************************************************************/ ++void evel_vnic_performance_tx_discarded_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double tx_discarded_packets_acc); ++/**************************************************************************//** ++ * Set the Delta Discarded packets Transmitted in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param tx_discarded_packets_delta ++ *****************************************************************************/ ++void evel_vnic_performance_tx_discarded_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double tx_discarded_packets_delta); ++/**************************************************************************//** ++ * Set the Transmitted Errored Packets in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param tx_error_packets_acc ++ *****************************************************************************/ ++void evel_vnic_performance_tx_error_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double tx_error_packets_acc); ++/**************************************************************************//** ++ * Set the Delta Errored packets Transmitted in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param tx_error_packets_delta ++ *****************************************************************************/ ++void evel_vnic_performance_tx_error_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double tx_error_packets_delta); ++/**************************************************************************//** ++ * Set the Transmitted Multicast Packets in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param tx_mcast_packets_acc ++ *****************************************************************************/ ++void evel_vnic_performance_tx_mcast_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double tx_mcast_packets_acc); ++/**************************************************************************//** ++ * Set the Delta Multicast packets Transmitted in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param tx_mcast_packets_delta ++ *****************************************************************************/ ++void evel_vnic_performance_tx_mcast_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double tx_mcast_packets_delta); ++/**************************************************************************//** ++ * Set the Transmitted Octets in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param tx_octets_acc ++ *****************************************************************************/ ++void evel_vnic_performance_tx_octets_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double tx_octets_acc); ++/**************************************************************************//** ++ * Set the Delta Octets Transmitted in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param tx_octets_delta ++ *****************************************************************************/ ++void evel_vnic_performance_tx_octets_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double tx_octets_delta); ++/**************************************************************************//** ++ * Set the Transmitted Total Packets in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param tx_total_packets_acc ++ *****************************************************************************/ ++void evel_vnic_performance_tx_total_pkt_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double tx_total_packets_acc); ++/**************************************************************************//** ++ * Set the Delta Total Packets Transmitted in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param tx_total_packets_delta ++ *****************************************************************************/ ++void evel_vnic_performance_tx_total_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double tx_total_packets_delta); ++/**************************************************************************//** ++ * Set the Transmitted Unicast Packets in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param tx_ucast_packets_acc ++ *****************************************************************************/ ++void evel_vnic_performance_tx_ucast_packets_acc_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double tx_ucast_packets_acc); ++/**************************************************************************//** ++ * Set the Delta Octets Transmitted in measurement interval ++ * property of the vNIC performance. ++ * ++ * @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_performance Pointer to the vNIC Use. ++ * @param tx_ucast_packets_delta ++ *****************************************************************************/ ++void evel_vnic_performance_tx_ucast_pkt_delta_set(MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance, ++ const double tx_ucast_packets_delta); ++ ++/**************************************************************************//** ++ * Add an additional vNIC Use to the specified Measurement event. ++ * ++ * @param measurement Pointer to the measurement. ++ * @param vnic_performance Pointer to the vNIC Use to add. ++ *****************************************************************************/ ++void evel_meas_vnic_performance_add(EVENT_MEASUREMENT * const measurement, ++ MEASUREMENT_VNIC_PERFORMANCE * const vnic_performance); ++ ++/**************************************************************************//** ++ * 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 valset true or false confidence level ++ * @param recvd_bcast_packets_acc Recieved broadcast packets ++ * @param recvd_bcast_packets_delta Received delta broadcast packets ++ * @param recvd_discarded_packets_acc Recieved discarded packets ++ * @param recvd_discarded_packets_delta Received discarded delta packets ++ * @param recvd_error_packets_acc Received error packets ++ * @param recvd_error_packets_delta, Received delta error packets ++ * @param recvd_mcast_packets_acc Received multicast packets ++ * @param recvd_mcast_packets_delta Received delta multicast packets ++ * @param recvd_octets_acc Received octets ++ * @param recvd_octets_delta Received delta octets ++ * @param recvd_total_packets_acc Received total packets ++ * @param recvd_total_packets_delta Received delta total packets ++ * @param recvd_ucast_packets_acc Received Unicast packets ++ * @param recvd_ucast_packets_delta Received delta unicast packets ++ * @param tx_bcast_packets_acc Transmitted broadcast packets ++ * @param tx_bcast_packets_delta Transmitted delta broadcast packets ++ * @param tx_discarded_packets_acc Transmitted packets discarded ++ * @param tx_discarded_packets_delta Transmitted delta discarded packets ++ * @param tx_error_packets_acc Transmitted error packets ++ * @param tx_error_packets_delta Transmitted delta error packets ++ * @param tx_mcast_packets_acc Transmitted multicast packets accumulated ++ * @param tx_mcast_packets_delta Transmitted delta multicast packets ++ * @param tx_octets_acc Transmitted octets ++ * @param tx_octets_delta Transmitted delta octets ++ * @param tx_total_packets_acc Transmitted total packets ++ * @param tx_total_packets_delta Transmitted delta total packets ++ * @param tx_ucast_packets_acc Transmitted Unicast packets ++ * @param tx_ucast_packets_delta Transmitted delta Unicast packets ++ *****************************************************************************/ ++void evel_measurement_vnic_performance_add(EVENT_MEASUREMENT * const measurement, ++ char * const vnic_id, ++ char * valset, ++ double recvd_bcast_packets_acc, ++ double recvd_bcast_packets_delta, ++ double recvd_discarded_packets_acc, ++ double recvd_discarded_packets_delta, ++ double recvd_error_packets_acc, ++ double recvd_error_packets_delta, ++ double recvd_mcast_packets_acc, ++ double recvd_mcast_packets_delta, ++ double recvd_octets_acc, ++ double recvd_octets_delta, ++ double recvd_total_packets_acc, ++ double recvd_total_packets_delta, ++ double recvd_ucast_packets_acc, ++ double recvd_ucast_packets_delta, ++ double tx_bcast_packets_acc, ++ double tx_bcast_packets_delta, ++ double tx_discarded_packets_acc, ++ double tx_discarded_packets_delta, ++ double tx_error_packets_acc, ++ double tx_error_packets_delta, ++ double tx_mcast_packets_acc, ++ double tx_mcast_packets_delta, ++ double tx_octets_acc, ++ double tx_octets_delta, ++ double tx_total_packets_acc, ++ double tx_total_packets_delta, ++ double tx_ucast_packets_acc, ++ double tx_ucast_packets_delta); ++ ++/*****************************************************************************/ ++/*****************************************************************************/ ++/* */ ++/* 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 ++ * @param event_name Unique Event Name ++ * @param event_id A universal identifier of the event for analysis etc ++ * ++ * @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,const char* ev_name, const char *ev_id); ++ ++/**************************************************************************//** ++ * 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 event_name Unique Event Name ++ * @param event_id A universal identifier of the event for analysis etc ++ * @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* ev_name, const char *ev_id, ++ 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); ++ ++/*****************************************************************************/ ++/*****************************************************************************/ ++/* */ ++/* 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 event_name Unique Event Name ++ * @param event_id A universal identifier of the event for analysis etc ++ * @param vendor_name The vendor id to encode in the event vnf field. ++ * @param module The module to encode in the event. ++ * @param vnfname The Virtual network function to encode in the event. ++ * @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* ev_name, const char *ev_id, ++ const char * const vendor_name, ++ const char * const correlator, ++ const char * const local_ip_address, ++ const char * const local_port, ++ const char * const remote_ip_address, ++ const char * const remote_port); ++ ++/**************************************************************************//** ++ * 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); ++ ++/**************************************************************************//** ++ * Add an additional value name/value pair to the SIP signaling. ++ * ++ * 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 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_signaling_addl_info_add(EVENT_SIGNALING * event, char * name, char * value); ++ ++/**************************************************************************//** ++ * 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 Vendor module 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 modulename The module name to be set. ASCIIZ string. The caller ++ * does not need to preserve the value once the function ++ * returns. ++ *****************************************************************************/ ++void evel_signaling_vnfmodule_name_set(EVENT_SIGNALING * const event, ++ const char * const module_name); ++/**************************************************************************//** ++ * Set the Vendor module 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 vnfname The Virtual Network function to be set. ASCIIZ string. ++ * The caller does not need to preserve the value once ++ * the function returns. ++ *****************************************************************************/ ++void evel_signaling_vnfname_set(EVENT_SIGNALING * const event, ++ const char * const vnfname); ++ ++/**************************************************************************//** ++ * 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 event_name Unique Event Name ++ * @param event_id A universal identifier of the event for analysis etc ++ * @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 char* ev_name, const char *ev_id, ++ 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_name Unique Event Name ++ * @param event_id A universal identifier of the event for analysis etc ++ * @param event_source_type ++ * @param syslog_msg ++ * @param syslog_tag ++ * @param version ++ * ++ * @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(const char* ev_name, const char *ev_id, ++ 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); ++ ++/**************************************************************************//** ++ * Set the Structured SDID 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 sdid The Structured Data to be set. ASCIIZ string. name@number ++ * Caller does not need to preserve the value once the function ++ * returns. ++ *****************************************************************************/ ++void evel_syslog_sdid_set(EVENT_SYSLOG * syslog, const char * const sdid); ++ ++/**************************************************************************//** ++ * Set the Structured Severity 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 sdid The Structured Data to be set. ASCIIZ string. ++ * Caller does not need to preserve the value once the function ++ * returns. ++ *****************************************************************************/ ++void evel_syslog_severity_set(EVENT_SYSLOG * syslog, const char * const severty); ++ ++ ++/*****************************************************************************/ ++/*****************************************************************************/ ++/* */ ++/* OTHER */ ++/* */ ++/*****************************************************************************/ ++/*****************************************************************************/ ++ ++/**************************************************************************//** ++ * Create a new other event. ++ * ++ * @param event_name Unique Event Name ++ * @param event_id A universal identifier of the event for analysis etc ++ * ++ * @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(const char* ev_name, const char *ev_id); ++ ++/**************************************************************************//** ++ * 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(); ++ ++/*****************************************************************************/ ++/* Supported Report version. */ ++/*****************************************************************************/ ++#define EVEL_VOICEQ_MAJOR_VERSION 1 ++#define EVEL_VOICEQ_MINOR_VERSION 1 ++ ++/**************************************************************************//** ++ * End of Call Voice Quality Metrices ++ * JSON equivalent field: endOfCallVqmSummaries ++ *****************************************************************************/ ++typedef struct end_of_call_vqm_summaries { ++ /***************************************************************************/ ++ /* Mandatory fields */ ++ /***************************************************************************/ ++ char* adjacencyName; ++ char* endpointDescription; ++ ++ /***************************************************************************/ ++ /* Optional fields */ ++ /***************************************************************************/ ++ EVEL_OPTION_INT endpointJitter; ++ EVEL_OPTION_INT endpointRtpOctetsDiscarded; ++ EVEL_OPTION_INT endpointRtpOctetsReceived; ++ EVEL_OPTION_INT endpointRtpOctetsSent; ++ EVEL_OPTION_INT endpointRtpPacketsDiscarded; ++ EVEL_OPTION_INT endpointRtpPacketsReceived; ++ EVEL_OPTION_INT endpointRtpPacketsSent; ++ EVEL_OPTION_INT localJitter; ++ EVEL_OPTION_INT localRtpOctetsDiscarded; ++ EVEL_OPTION_INT localRtpOctetsReceived; ++ EVEL_OPTION_INT localRtpOctetsSent; ++ EVEL_OPTION_INT localRtpPacketsDiscarded; ++ EVEL_OPTION_INT localRtpPacketsReceived; ++ EVEL_OPTION_INT localRtpPacketsSent; ++ EVEL_OPTION_INT mosCqe; ++ EVEL_OPTION_INT packetsLost; ++ EVEL_OPTION_INT packetLossPercent; ++ EVEL_OPTION_INT rFactor; ++ EVEL_OPTION_INT roundTripDelay; ++ ++} END_OF_CALL_VOICE_QUALITY_METRICS; ++ ++/**************************************************************************//** ++* Voice QUality. ++* JSON equivalent field: voiceQualityFields ++*****************************************************************************/ ++ ++typedef struct event_voiceQuality { ++ /***************************************************************************/ ++ /* Header and version */ ++ /***************************************************************************/ ++ EVENT_HEADER header; ++ int major_version; ++ int minor_version; ++ ++ /***************************************************************************/ ++ /* Mandatory fields */ ++ /***************************************************************************/ ++ ++ char *calleeSideCodec; ++ char *callerSideCodec; ++ char *correlator; ++ char *midCallRtcp; ++ VENDOR_VNFNAME_FIELD vendorVnfNameFields; ++ END_OF_CALL_VOICE_QUALITY_METRICS *endOfCallVqmSummaries; ++ ++ /***************************************************************************/ ++ /* Optional fields */ ++ /***************************************************************************/ ++ EVEL_OPTION_STRING phoneNumber; ++ DLIST additionalInformation; ++ ++} EVENT_VOICE_QUALITY; ++/**************************************************************************//** ++ * Voice Quality Additional Info. ++ * JSON equivalent field: additionalInformation ++ *****************************************************************************/ ++typedef struct voice_quality_additional_info { ++ char * name; ++ char * value; ++} VOICE_QUALITY_ADDL_INFO; ++ ++/**************************************************************************//** ++ * Create a new voice quality event. ++ * ++ * @note The mandatory fields on the Voice Quality 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 Voice Quality has immutable properties. ++ * @param event_name Unique Event Name ++ * @param event_id A universal identifier of the event for analysis etc ++ * @param calleeSideCodec Callee codec for the call. ++ * @param callerSideCodec Caller codec for the call. ++ * @param correlator Constant across all events on this call. ++ * @param midCallRtcp Base64 encoding of the binary RTCP data ++ * (excluding Eth/IP/UDP headers). ++ * @param vendorVnfNameFields Vendor, VNF and VfModule names. ++ * @returns pointer to the newly manufactured ::EVENT_VOICE_QUALITY. If the ++ * event is not used (i.e. posted) it must be released using ++ ::evel_free_voice_quality. ++ * @retval NULL Failed to create the event. ++ *****************************************************************************/ ++EVENT_VOICE_QUALITY * evel_new_voice_quality(const char* ev_name, const char *ev_id, ++ const char * const calleeSideCodec, ++ const char * const callerSideCodec, const char * const correlator, ++ const char * const midCallRtcp, const char * const vendorVnfNameFields); ++ ++/**************************************************************************//** ++ * Set the Callee side codec for Call for domain Voice Quality ++ * ++ * @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 voiceQuality Pointer to the Voice Quality Event. ++ * @param calleeCodecForCall The Callee Side Codec to be set. ASCIIZ ++ * string. The caller does not need to ++ * preserve the value once the function ++ * returns. ++ *****************************************************************************/ ++void evel_voice_quality_callee_codec_set(EVENT_VOICE_QUALITY * voiceQuality, ++ const char * const calleeCodecForCall); ++ ++/**************************************************************************//** ++ * Set the Caller side codec for Call for domain Voice Quality ++ * ++ * @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 voiceQuality Pointer to the Voice Quality Event. ++ * @param callerCodecForCall The Caller Side Codec to be set. ASCIIZ ++ * string. The caller does not need to ++ * preserve the value once the function ++ * returns. ++ *****************************************************************************/ ++void evel_voice_quality_caller_codec_set(EVENT_VOICE_QUALITY * voiceQuality, ++ const char * const callerCodecForCall); ++ ++/**************************************************************************//** ++ * Set the correlator for domain Voice Quality ++ * ++ * @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 voiceQuality Pointer to the Voice Quality Event. ++ * @param correlator The correlator value to be set. ASCIIZ ++ * string. The caller does not need to ++ * preserve the value once the function ++ * returns. ++ *****************************************************************************/ ++void evel_voice_quality_correlator_set(EVENT_VOICE_QUALITY * voiceQuality, ++ const char * const vCorrelator); ++ ++/**************************************************************************//** ++ * Set the RTCP Call Data for domain Voice Quality ++ * ++ * @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 voiceQuality Pointer to the Voice Quality Event. ++ * @param rtcpCallData The RTCP Call Data to be set. ASCIIZ ++ * string. The caller does not need to ++ * preserve the value once the function ++ * returns. ++ *****************************************************************************/ ++void evel_voice_quality_rtcp_data_set(EVENT_VOICE_QUALITY * voiceQuality, ++ const char * const rtcpCallData); ++ ++/**************************************************************************//** ++ * Set the Vendor VNF Name fields for domain Voice Quality ++ * ++ * @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 voiceQuality Pointer to the Voice Quality Event. ++ * @param nameFields The Vendor, VNF and VfModule names to be set. ++ * ASCIIZ string. The caller does not need to ++ * preserve the value once the function ++ * returns. ++ *****************************************************************************/ ++void evel_voice_quality_name_fields_set(EVENT_VOICE_QUALITY * voiceQuality, ++ const char * const nameFields); ++ ++/**************************************************************************//** ++ * Add an End of Call Voice Quality Metrices ++ ++ * The adjacencyName and endpointDescription is null delimited ASCII string. ++ * The library takes a copy so the caller does not have to preserve values ++ * after the function returns. ++ * ++ * @param voiceQuality Pointer to the measurement. ++ * @param adjacencyName Adjacency name ++ * @param endpointDescription Enumeration: ‘Caller’, ‘Callee’. ++ * @param endpointJitter Endpoint jitter ++ * @param endpointRtpOctetsDiscarded Endpoint RTP octets discarded. ++ * @param endpointRtpOctetsReceived Endpoint RTP octets received. ++ * @param endpointRtpOctetsSent Endpoint RTP octets sent ++ * @param endpointRtpPacketsDiscarded Endpoint RTP packets discarded. ++ * @param endpointRtpPacketsReceived Endpoint RTP packets received. ++ * @param endpointRtpPacketsSent Endpoint RTP packets sent. ++ * @param localJitter Local jitter. ++ * @param localRtpOctetsDiscarded Local RTP octets discarded. ++ * @param localRtpOctetsReceived Local RTP octets received. ++ * @param localRtpOctetsSent Local RTP octets sent. ++ * @param localRtpPacketsDiscarded Local RTP packets discarded. ++ * @param localRtpPacketsReceived Local RTP packets received. ++ * @param localRtpPacketsSent Local RTP packets sent. ++ * @param mosCqe Decimal range from 1 to 5 ++ * (1 decimal place) ++ * @param packetsLost No Packets lost ++ * @param packetLossPercent Calculated percentage packet loss ++ * @param rFactor rFactor from 0 to 100 ++ * @param roundTripDelay Round trip delay in milliseconds ++ *****************************************************************************/ ++void evel_voice_quality_end_metrics_add(EVENT_VOICE_QUALITY * voiceQuality, ++ const char * adjacencyName, EVEL_SERVICE_ENDPOINT_DESC endpointDescription, ++ int endpointJitter, ++ int endpointRtpOctetsDiscarded, ++ int endpointRtpOctetsReceived, ++ int endpointRtpOctetsSent, ++ int endpointRtpPacketsDiscarded, ++ int endpointRtpPacketsReceived, ++ int endpointRtpPacketsSent, ++ int localJitter, ++ int localRtpOctetsDiscarded, ++ int localRtpOctetsReceived, ++ int localRtpOctetsSent, ++ int localRtpPacketsDiscarded, ++ int localRtpPacketsReceived, ++ int localRtpPacketsSent, ++ int mosCqe, ++ int packetsLost, ++ int packetLossPercent, ++ int rFactor, ++ int roundTripDelay); ++ ++/**************************************************************************//** ++ * Free a Voice Quality. ++ * ++ * Free off the Voce Quality supplied. Will free all the contained allocated ++ * memory. ++ * ++ * @note It does not free the Voice Quality itself, since that may be part of a ++ * larger structure. ++ *****************************************************************************/ ++void evel_free_voice_quality(EVENT_VOICE_QUALITY * voiceQuality); ++ ++/**************************************************************************//** ++ * Add an additional value name/value pair to the Voice Quality. ++ * ++ * 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_voice_quality_addl_info_add(EVENT_VOICE_QUALITY * voiceQuality, char * name, char * value); ++ ++ ++/*****************************************************************************/ ++/*****************************************************************************/ ++/* */ ++/* THRESHOLD CROSSING ALERT */ ++/* */ ++/*****************************************************************************/ ++/*****************************************************************************/ ++ ++typedef enum evel_event_action { ++ EVEL_EVENT_ACTION_CLEAR, ++ EVEL_EVENT_ACTION_CONTINUE, ++ EVEL_EVENT_ACTION_SET, ++ EVEL_MAX_EVENT_ACTION ++}EVEL_EVENT_ACTION; ++ ++typedef enum evel_alert_type { ++ EVEL_CARD_ANOMALY, ++ EVEL_ELEMENT_ANOMALY, ++ EVEL_INTERFACE_ANOMALY, ++ EVEL_SERVICE_ANOMALY, ++ EVEL_MAX_ANOMALY ++}EVEL_ALERT_TYPE; ++ ++ ++typedef struct perf_counter { ++ char * criticality; ++ char * name; ++ char * thresholdCrossed; ++ char * value; ++}PERF_COUNTER; ++ ++ ++/*****************************************************************************/ ++/* Supported Threshold Crossing version. */ ++/*****************************************************************************/ ++#define EVEL_THRESHOLD_CROSS_MAJOR_VERSION 1 ++#define EVEL_THRESHOLD_CROSS_MINOR_VERSION 1 ++ ++/**************************************************************************//** ++ * Threshold Crossing. ++ * JSON equivalent field: Threshold Cross Fields ++ *****************************************************************************/ ++typedef struct event_threshold_cross { ++ /***************************************************************************/ ++ /* Header and version */ ++ /***************************************************************************/ ++ EVENT_HEADER header; ++ int major_version; ++ int minor_version; ++ ++ /***************************************************************************/ ++ /* Mandatory fields */ ++ /***************************************************************************/ ++ PERF_COUNTER additionalParameters; ++ EVEL_EVENT_ACTION alertAction; ++ char * alertDescription; ++ EVEL_ALERT_TYPE alertType; ++ unsigned long long collectionTimestamp; ++ EVEL_SEVERITIES eventSeverity; ++ unsigned long long eventStartTimestamp; ++ ++ /***************************************************************************/ ++ /* Optional fields */ ++ /***************************************************************************/ ++ DLIST additional_info; ++ EVEL_OPTION_STRING alertValue; ++ DLIST alertidList; ++ EVEL_OPTION_STRING dataCollector; ++ EVEL_OPTION_STRING elementType; ++ EVEL_OPTION_STRING interfaceName; ++ EVEL_OPTION_STRING networkService; ++ EVEL_OPTION_STRING possibleRootCause; ++ ++} EVENT_THRESHOLD_CROSS; ++ ++ ++/**************************************************************************//** ++ * Create a new Threshold Crossing Alert event. ++ * ++ * @note The mandatory fields on the TCA 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 ++ * TCA has immutable properties. ++ * ++ * @param event_name Unique Event Name ++ * @param event_id A universal identifier of the event for analysis etc ++ * @param char* tcriticality Performance Counter Criticality MAJ MIN, ++ * @param char* tname Performance Counter Threshold name ++ * @param char* tthresholdCrossed Counter Threshold crossed value ++ * @param char* tvalue Counter actual value ++ * @param EVEL_EVENT_ACTION talertAction Alert set continue or clear ++ * @param char* talertDescription ++ * @param EVEL_ALERT_TYPE talertType Kind of anamoly ++ * @param unsigned long long tcollectionTimestamp time at which alert was collected ++ * @param EVEL_SEVERITIES teventSeverity Severity of Alert ++ * @param unsigned long long teventStartTimestamp Time when this alert started ++ * ++ * @returns pointer to the newly manufactured ::EVENT_THRESHOLD_CROSS. If the ++ * event is not used it must be released using ++ * ::evel_free_threshold_cross ++ * @retval NULL Failed to create the event. ++ *****************************************************************************/ ++EVENT_THRESHOLD_CROSS * evel_new_threshold_cross( ++ const char* ev_name, const char *ev_id, ++ char * tcriticality, ++ char * tname, ++ char * tthresholdCrossed, ++ char * tvalue, ++ EVEL_EVENT_ACTION talertAction, ++ char * talertDescription, ++ EVEL_ALERT_TYPE talertType, ++ unsigned long long tcollectionTimestamp, ++ EVEL_SEVERITIES teventSeverity, ++ unsigned long long teventStartTimestamp); ++ ++/**************************************************************************//** ++ * Free a Threshold cross event. ++ * ++ * Free off the Threshold crossing event supplied. Will free all the contained allocated ++ * memory. ++ * ++ * @note It does not free the Threshold Cross itself, since that may be part of a ++ * larger structure. ++ *****************************************************************************/ ++void evel_free_threshold_cross(EVENT_THRESHOLD_CROSS * const tcp); ++ ++/**************************************************************************//** ++ * Set the Event Type property of the Threshold Cross. ++ * ++ * @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 tcp Pointer to the ::EVENT_THRESHOLD_CROSS. ++ * @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_threshold_cross_type_set(EVENT_THRESHOLD_CROSS * const tcp, char * type); ++ ++/**************************************************************************//** ++ * Add an optional additional alertid value to Alert. ++ * ++ * @param alertid Adds Alert ID ++ *****************************************************************************/ ++void evel_threshold_cross_alertid_add(EVENT_THRESHOLD_CROSS * const event,char * alertid); ++ ++ /**************************************************************************//** ++ * Set the TCA probable Root cause. ++ * ++ * @param sheader Possible root cause to Threshold ++ *****************************************************************************/ ++ void evel_threshold_cross_possible_rootcause_set(EVENT_THRESHOLD_CROSS * const event, char * sheader); ++ /**************************************************************************//** ++ * Set the TCA networking cause. ++ * ++ * @param sheader Possible networking service value to Threshold ++ *****************************************************************************/ ++ void evel_threshold_cross_networkservice_set(EVENT_THRESHOLD_CROSS * const event, char * sheader); ++ /**************************************************************************//** ++ * Set the TCA Interface name. ++ * ++ * @param sheader Interface name to threshold ++ *****************************************************************************/ ++ void evel_threshold_cross_interfacename_set(EVENT_THRESHOLD_CROSS * const event,char * sheader); ++ /**************************************************************************//** ++ * Set the TCA Data element type. ++ * ++ * @param sheader element type of Threshold ++ *****************************************************************************/ ++ void evel_threshold_cross_data_elementtype_set(EVENT_THRESHOLD_CROSS * const event,char * sheader); ++ /**************************************************************************//** ++ * Set the TCA Data collector value. ++ * ++ * @param sheader Data collector value ++ *****************************************************************************/ ++ void evel_threshold_cross_data_collector_set(EVENT_THRESHOLD_CROSS * const event,char * sheader); ++ /**************************************************************************//** ++ * Set the TCA alert value. ++ * ++ * @param sheader Possible alert value ++ *****************************************************************************/ ++ void evel_threshold_cross_alertvalue_set(EVENT_THRESHOLD_CROSS * const event,char * sheader); ++ ++/**************************************************************************//** ++ * Add an additional field name/value pair to the THRESHOLD CROSS event. ++ * ++ * 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_THRESHOLD_CROSS. ++ * @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_threshold_cross_addl_info_add(EVENT_THRESHOLD_CROSS * const tcp, ++ const char * const name, ++ const char * const value); ++ ++/*****************************************************************************/ ++/*****************************************************************************/ ++/* */ ++/* 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/src/plugins/ves/include/evel_internal.h b/src/plugins/ves/include/evel_internal.h +new file mode 100644 +index 00000000..46f71af1 +--- /dev/null ++++ b/src/plugins/ves/include/evel_internal.h +@@ -0,0 +1,858 @@ ++/*************************************************************************//** ++ * ++ * 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. ++ * ++ ****************************************************************************/ ++/**************************************************************************//** ++ * @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. ++ * ++ ****************************************************************************/ ++ ++#ifndef EVEL_INTERNAL_INCLUDED ++#define EVEL_INTERNAL_INCLUDED ++ ++#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,const char* ev_name, const char *ev_id); ++ ++/**************************************************************************//** ++ * 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); ++ ++/*****************************************************************************/ ++/* 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 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 Heartbeat fields 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_hrtbt_field(EVEL_JSON_BUFFER * const jbuf, ++ EVENT_HEARTBEAT_FIELD * 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); ++ ++ ++/**************************************************************************//** ++ * Initialize an ::EVEL_OPTION_INTHEADER_FIELDS to a not-set state. ++ * ++ * @param option Pointer to the ::EVEL_OPTION_INTHEADER_FIELDS. ++ *****************************************************************************/ ++void evel_init_option_intheader(EVEL_OPTION_INTHEADER_FIELDS * const option); ++/**************************************************************************//** ++ * Force the value of an ::EVEL_OPTION_INTHEADER_FIELDS. ++ * ++ * @param option Pointer to the ::EVEL_OPTION_INTHEADER_FIELDS. ++ * @param value The value to set. ++ *****************************************************************************/ ++void evel_force_option_intheader(EVEL_OPTION_INTHEADER_FIELDS * const option, ++ const void* value); ++/**************************************************************************//** ++ * Set the value of an ::EVEL_OPTION_INTHEADER_FIELDS. ++ * ++ * @param option Pointer to the ::EVEL_OPTION_INTHEADER_FIELDS. ++ * @param value The value to set. ++ * @param description Description to be used in logging. ++ *****************************************************************************/ ++void evel_set_option_intheader(EVEL_OPTION_INTHEADER_FIELDS * const option, ++ const void * value, ++ const char * const description); ++/**************************************************************************//** ++ * Free the underlying resources of an ::EVEL_OPTION_INTHEADER_FIELDS. ++ * ++ * @param option Pointer to the ::EVEL_OPTION_INTHEADER_FIELDS. ++ *****************************************************************************/ ++void evel_free_option_intheader(EVEL_OPTION_INTHEADER_FIELDS * const option); ++ ++#endif +diff --git a/src/plugins/ves/include/evel_throttle.h b/src/plugins/ves/include/evel_throttle.h +new file mode 100644 +index 00000000..c97b3c37 +--- /dev/null ++++ b/src/plugins/ves/include/evel_throttle.h +@@ -0,0 +1,214 @@ ++/*************************************************************************//** ++ * ++ * 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. ++ * ++ ****************************************************************************/ ++/**************************************************************************//** ++ * @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. ++ * ++ ****************************************************************************/ ++ ++#ifndef EVEL_THROTTLE_INCLUDED ++#define EVEL_THROTTLE_INCLUDED ++ ++#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/src/plugins/ves/include/hashtable.h b/src/plugins/ves/include/hashtable.h +new file mode 100644 +index 00000000..8be17dc1 +--- /dev/null ++++ b/src/plugins/ves/include/hashtable.h +@@ -0,0 +1,97 @@ ++#ifndef HASHTABLE_INCLUDED ++#define HASHTABLE_INCLUDED ++ ++/*************************************************************************//** ++ * ++ * 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. ++ * ++ ****************************************************************************/ ++ ++/**************************************************************************//** ++ * @file ++ * A simple hashtable. ++ * ++ * @note No thread protection so you will need to use appropriate ++ * synchronization if use spans multiple threads. ++*****************************************************************************/ ++ ++typedef struct entry_s { ++ char *key; ++ void *value; ++ struct entry_s *next; ++} ENTRY_T; ++ ++/**************************************************************************//** ++ * Hashtable structure ++ *****************************************************************************/ ++ ++typedef struct hashtable_s { ++ size_t size; ++ struct entry_s **table; ++} HASHTABLE_T; ++ ++/**************************************************************************//** ++ * Hashtable initialization. ++ * ++ * Initialize the list supplied to be empty. ++ * ++ * @param size Size of hashtable ++ ++ * @returns Hashtable pointer ++******************************************************************************/ ++/* Create a new hashtable. */ ++HASHTABLE_T *ht_create( size_t size ); ++ ++/**************************************************************************//** ++ * Hash a string for a particular hash table. ++ * ++ * Initialize the list supplied to be empty. ++ * ++ * @param hashtable Pointer to the hashtable ++ * @param key String ++ ++ * @returns hashvalue ++******************************************************************************/ ++size_t ht_hash( HASHTABLE_T *hashtable, char *key ); ++ ++/**************************************************************************//** ++ * Create a key-value pair. ++ * ++ * @param key key string ++ * @param value value string ++ * ++ * @returns hashtable entry ++******************************************************************************/ ++ENTRY_T *ht_newpair( char *key, void *value ); ++ ++/**************************************************************************//** ++ * Insert a key-value pair into a hash table. ++ * ++ * @param key key string ++ * @param value value string ++ * ++ * @returns Nothing ++******************************************************************************/ ++void ht_set( HASHTABLE_T *hashtable, char *key, void *value ); ++ ++/**************************************************************************//** ++ * Retrieve a key-value pair from a hash table. ++ * ++ * @param key key string ++ * ++ * @returns value string ++******************************************************************************/ ++void *ht_get( HASHTABLE_T *hashtable, char *key ); ++ ++#endif +diff --git a/src/plugins/ves/include/jsmn.h b/src/plugins/ves/include/jsmn.h +new file mode 100644 +index 00000000..4ae6d9b4 +--- /dev/null ++++ b/src/plugins/ves/include/jsmn.h +@@ -0,0 +1,93 @@ ++/*************************************************************************//** ++ * ++ * 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. ++ * ++ ****************************************************************************/ ++ ++#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/src/plugins/ves/include/metadata.h b/src/plugins/ves/include/metadata.h +new file mode 100644 +index 00000000..1ee44092 +--- /dev/null ++++ b/src/plugins/ves/include/metadata.h +@@ -0,0 +1,58 @@ ++#ifndef METADATA_INCLUDED ++#define METADATA_INCLUDED ++/*************************************************************************//** ++ * ++ * 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. ++ * ++ ****************************************************************************/ ++ ++/**************************************************************************//** ++ * @file ++ * Wrap the OpenStack metadata service. ++ * ++ ****************************************************************************/ ++ ++#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/src/plugins/ves/include/ring_buffer.h b/src/plugins/ves/include/ring_buffer.h +new file mode 100644 +index 00000000..1236b78b +--- /dev/null ++++ b/src/plugins/ves/include/ring_buffer.h +@@ -0,0 +1,96 @@ ++/*************************************************************************//** ++ * ++ * 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. ++ * ++ ****************************************************************************/ ++ ++#ifndef RING_BUFFER_INCLUDED ++#define RING_BUFFER_INCLUDED ++ ++/**************************************************************************//** ++ * @file ++ * Ring buffer to handle message requests. ++ * ++ ****************************************************************************/ ++ ++#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/src/plugins/ves/ves.api b/src/plugins/ves/ves.api +new file mode 100644 +index 00000000..a7106f8d +--- /dev/null ++++ b/src/plugins/ves/ves.api +@@ -0,0 +1,72 @@ ++/* ++ * Copyright (c) 2017 Intel 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. ++ */ ++ ++/** \brief VES Agent config add / del request ++ @param client_index - opaque cookie to identify the sender ++ @param context - sender context, to match reply w/ request ++ @param server_port - VES Server port ++ @param read_interval - Time period for each loop ++ @param is_add - add the config if non-zero, else delete ++ @param server_addr[] - server address ++*/ ++define ves_agent_config ++{ ++ u32 client_index; ++ u32 context; ++ u32 server_port; ++ u32 read_interval; ++ u32 is_add; ++ u8 server_addr[16]; ++}; ++ ++/** \brief VES Agent config response ++ @param context - sender context, to match reply w/ request ++ @param retval - return code for the request ++*/ ++define ves_agent_config_reply ++{ ++ u32 context; ++ i32 retval; ++}; ++ ++/** \brief VES Agent mode set request ++ @param client_index - opaque cookie to identify the sender ++ @param context - sender context, to match reply w/ request ++ @param pkt_loss_rate - Base packet loss rate if Demo Mode ++ @param work_mode[] - Agent's work mode, real or demo ++*/ ++define ves_agent_mode ++{ ++ u32 client_index; ++ u32 context; ++ u32 pkt_loss_rate; ++ u8 work_mode[8]; ++}; ++ ++/** \brief VES Agent Mode response ++ @param context - sender context, to match reply w/ request ++ @param retval - return code for the request ++*/ ++define ves_agent_mode_reply ++{ ++ u32 context; ++ i32 retval; ++}; ++ ++/* ++ * Local Variables: ++ * eval: (c-set-style "gnu") ++ * End: ++ */ +diff --git a/src/plugins/ves/ves_all_api_h.h b/src/plugins/ves/ves_all_api_h.h +new file mode 100644 +index 00000000..72b15697 +--- /dev/null ++++ b/src/plugins/ves/ves_all_api_h.h +@@ -0,0 +1,18 @@ ++/* ++ * ves_all_api_h.h - skeleton vpp engine plug-in api #include file ++ * ++ * Copyright (c) 2017 Intel 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. ++ */ ++ ++#include <ves/ves.api.h> +diff --git a/src/plugins/ves/ves_api.c b/src/plugins/ves/ves_api.c +new file mode 100644 +index 00000000..7a9b8004 +--- /dev/null ++++ b/src/plugins/ves/ves_api.c +@@ -0,0 +1,139 @@ ++/* ++ *------------------------------------------------------------------ ++ * ves_api.c - ves api ++ * ++ * Copyright (c) 2017 Intel 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. ++ *------------------------------------------------------------------ ++ */ ++ ++#include <vnet/vnet.h> ++#include <vlibmemory/api.h> ++ ++#include <vnet/interface.h> ++#include <vnet/api_errno.h> ++#include <vnet/ip/ip.h> ++#include <vnet/ip/ip4.h> ++ ++#include <ves/ves_node.h> ++ ++#include <ves/ves_msg_enum.h> /* define message IDs */ ++ ++#define vl_typedefs /* define message structures */ ++#include <ves/ves_all_api_h.h> ++#undef vl_typedefs ++ ++#define vl_endianfun /* define message structures */ ++#include <ves/ves_all_api_h.h> ++#undef vl_endianfun ++ ++/* instantiate all the print functions we know about */ ++#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) ++ ++#define vl_printfun ++#include <ves/ves_all_api_h.h> ++#undef vl_printfun ++ ++ ++#include <vlibapi/api_helper_macros.h> ++ ++#define foreach_vpe_api_msg \ ++_(VES_AGENT_CONFIG,ves_agent_config) \ ++_(VES_AGENT_MODE,ves_agent_mode) ++ ++static void vl_api_ves_agent_config_t_handler ++ (vl_api_ves_agent_config_t *mp) ++{ ++ vl_api_ves_agent_config_reply_t *rmp; ++ ip46_address_t server; ++ int rv = -1; ++ ++ ip46_address_reset (&server); ++ clib_memcpy (&server.ip4, mp->server_addr, sizeof (server.ip4)); ++ ++ rv = ves_set_server(&server, ++ (u32) ntohl (mp->server_port), ++ (u32) ntohl (mp->read_interval), ++ (int) (mp->is_add == 0)); ++ ++ REPLY_MACRO (VL_API_VES_AGENT_CONFIG_REPLY); ++} ++ ++static void vl_api_ves_agent_mode_t_handler ++ (vl_api_ves_agent_mode_t *mp) ++{ ++ vl_api_ves_agent_mode_reply_t *rmp; ++ ves_agent_mode_t mode = VES_AGENT_MODE_REAL; ++ int rv = -1; ++ ++ if (!strcmp((char *)mp->work_mode, "demo") ++ || !strcmp((char *)mp->work_mode, "Demo") ++ || !strcmp((char *)mp->work_mode, "DEMO")) ++ mode = VES_AGENT_MODE_DEMO; ++ ++ rv = ves_agent_set_mode(mode, (u32) ntohl(mp->pkt_loss_rate)); ++ ++ REPLY_MACRO (VL_API_VES_AGENT_MODE_REPLY); ++} ++ ++/* ++ * ves_api_hookup ++ * Add vpe's API message handlers to the table. ++ * vlib has alread mapped shared memory and ++ * added the client registration handlers. ++ * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process() ++ */ ++#define vl_msg_name_crc_list ++#include <ves/ves_all_api_h.h> ++#undef vl_msg_name_crc_list ++ ++static void ++setup_message_id_table (api_main_t * am) ++{ ++#define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id); ++ foreach_vl_msg_name_crc_ves; ++#undef _ ++} ++ ++static clib_error_t * ++ves_api_hookup (vlib_main_t * vm) ++{ ++ api_main_t *am = &api_main; ++ ++#define _(N,n) \ ++ vl_msg_api_set_handlers(VL_API_##N, #n, \ ++ vl_api_##n##_t_handler, \ ++ vl_noop_handler, \ ++ vl_api_##n##_t_endian, \ ++ vl_api_##n##_t_print, \ ++ sizeof(vl_api_##n##_t), 1); ++ foreach_vpe_api_msg; ++#undef _ ++ ++ /* ++ * Set up the (msg_name, crc, message-id) table ++ */ ++ setup_message_id_table (am); ++ ++ return 0; ++} ++ ++VLIB_API_INIT_FUNCTION (ves_api_hookup); ++ ++/* ++ * fd.io coding-style-patch-verification: ON ++ * ++ * Local Variables: ++ * eval: (c-set-style "gnu") ++ * End: ++ */ +diff --git a/src/plugins/ves/ves_msg_enum.h b/src/plugins/ves/ves_msg_enum.h +new file mode 100644 +index 00000000..6e8a5dfa +--- /dev/null ++++ b/src/plugins/ves/ves_msg_enum.h +@@ -0,0 +1,31 @@ ++/* ++ * ves_msg_enum.h - vpp engine plug-in message enumeration ++ * ++ * Copyright (c) 2017 Intel 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. ++ */ ++#ifndef _VES_MSG_ENUM_H_ ++#define _VES_MSG_ENUM_H_ ++ ++#include <vppinfra/byte_order.h> ++ ++#define vl_msg_id(n,h) n, ++typedef enum ++{ ++#include <ves/ves_all_api_h.h> ++ /* We'll want to know how many messages IDs we need... */ ++ VL_MSG_FIRST_AVAILABLE, ++} vl_msg_id_t; ++#undef vl_msg_id ++ ++#endif /* _VES_MSG_ENUM_H_ */ +diff --git a/src/plugins/ves/ves_node.c b/src/plugins/ves/ves_node.c +new file mode 100644 +index 00000000..7540dd16 +--- /dev/null ++++ b/src/plugins/ves/ves_node.c +@@ -0,0 +1,646 @@ ++/* ++ * Copyright (c) 2017 Intel 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. ++ */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <unistd.h> ++#include <string.h> ++#include <sys/time.h> ++ ++#include <vnet/plugin/plugin.h> ++#include <vpp/app/version.h> ++ ++#include "ves_node.h" ++ ++#define BUFSIZE 128 ++ ++typedef struct dummy_vpp_metrics_struct { ++ int bytes_in; ++ int bytes_out; ++ int packets_in; ++ int packets_out; ++} vpp_metrics_struct; ++ ++static vlib_node_registration_t ves_agent_process_node; ++vpp_metrics_struct *last_vpp_metrics; ++vpp_metrics_struct *curr_vpp_metrics; ++time_t start_epoch; ++time_t last_epoch; ++char hostname[BUFSIZE]; ++ ++static u8 *format_ves_agent_config(u8 *s, va_list *args); ++ ++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]; ++} ++ ++/**************************************************************************//** ++ * tap live cpu stats ++ *****************************************************************************/ ++void evel_get_cpu_stats(EVENT_MEASUREMENT * measurement) ++{ ++ FILE *fp; ++ char path[1024]; ++ double usage=0.0; ++ double idle; ++ double intrpt; ++ double nice; ++ double softirq; ++ double steal; ++ double sys; ++ double user; ++ double wait; ++ MEASUREMENT_CPU_USE *cpu_use = NULL; ++ ++ /* Open the command for reading. */ ++ //fp = popen("/bin/ls /etc/", "r"); ++ fp = popen("/usr/bin/top -bn 2 -d 0.01 | grep '^%Cpu' | tail -n 1 ", "r"); ++ if (fp == NULL) { ++ printf("Failed to run command\n" ); ++ exit(1); ++ } ++ ++ /* Read the output a line at a time - output it. */ ++ while (fgets(path, sizeof(path)-1, fp) != NULL) { ++ printf("%s", path+10); ++ sscanf(path+10," %lf us, %lf sy, %lf ni, %lf id, %lf wa, %lf hi, %lf si, %lf st", ++ &user,&sys,&nice,&idle,&wait,&intrpt,&softirq,&steal); ++ } ++ ++ /* close */ ++ pclose(fp); ++ ++ cpu_use = evel_measurement_new_cpu_use_add(measurement, "cpu1", usage); ++ if( cpu_use != NULL ){ ++ evel_measurement_cpu_use_idle_set(cpu_use,idle); ++ //evel_measurement_cpu_use_interrupt_set(cpu_use,intrpt); ++ //evel_measurement_cpu_use_nice_set(cpu_use,nice); ++ //evel_measurement_cpu_use_softirq_set(cpu_use,softirq); ++ //evel_measurement_cpu_use_steal_set(cpu_use,steal); ++ evel_measurement_cpu_use_system_set(cpu_use,sys); ++ evel_measurement_cpu_use_usageuser_set(cpu_use,user); ++ //evel_measurement_cpu_use_wait_set(cpu_use,wait); ++ //evel_measurement_cpu_use_add(measurement, "cpu2", usage,idle,intrpt,nice,softirq,steal,sys,user,wait); ++ } ++} ++ ++int ++ves_agent_report_vnic_stats(ves_agent_main_t *vam) ++{ ++ 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; ++ struct timeval time_val; ++ ++ /* Is not enabled, do nothing */ ++ if (vam->config.is_enabled == VES_AGENT_DISABLED) { ++ return 0; ++ } ++ ++ memset(curr_vpp_metrics, 0, sizeof(vpp_metrics_struct)); ++ read_vpp_metrics(curr_vpp_metrics, DEFAULT_MEASURE_ETH); ++ ++ 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(vam->config.read_interval, "Measurement_vGMUX", "Generic_traffic"); ++ if(vpp_m != NULL) { ++ char str_pkt_loss[12]; ++ MEASUREMENT_VNIC_PERFORMANCE * vnic_performance = NULL; ++ ++ printf("New measurement report created...\n"); ++ ++ vnic_performance = (MEASUREMENT_VNIC_PERFORMANCE *)evel_measurement_new_vnic_performance( ++ DEFAULT_MEASURE_ETH, "true"); ++ evel_meas_vnic_performance_add(vpp_m, vnic_performance); ++ evel_measurement_type_set(vpp_m, "HTTP request rate"); ++ evel_measurement_request_rate_set(vpp_m, rand()%10000); ++ ++ evel_vnic_performance_rx_total_pkt_delta_set(vnic_performance, packets_in_this_round); ++ evel_vnic_performance_tx_total_pkt_delta_set(vnic_performance, packets_out_this_round); ++ ++ evel_vnic_performance_rx_octets_delta_set(vnic_performance, bytes_in_this_round); ++ evel_vnic_performance_tx_octets_delta_set(vnic_performance, bytes_out_this_round); ++ evel_get_cpu_stats(vpp_m); ++ ++#if 0 ++ evel_measurement_vnic_use_add(vpp_m, /* Pointer to the measurement */ ++ DEFAULT_MEASURE_ETH, /* 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 */ ++#endif ++ ++ sprintf(str_pkt_loss, "%.1f %%", (double) vam->config.base_pkt_loss); ++ evel_measurement_custom_measurement_add(vpp_m, /* Pointer to the measurement */ ++ "ONAP-DCAE", /* measurement group's name */ ++ "Packet-Loss-Rate", /* the measurement's name */ ++ str_pkt_loss); /* The measurement's value */ ++ ++ last_epoch = start_epoch + vam->config.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; ++ ++ return 0; ++} ++ ++always_inline int ++ves_agent_start(ves_agent_main_t *vam) ++{ ++ vlib_main_t *vm = vam->vlib_main; ++ struct timeval time_val; ++ char fqdn[16]; /* "xxx.xxx.xxx.xxx" */ ++ //char *fqdn = "127.0.0.1"; /* "xxx.xxx.xxx.xxx" */ ++ ++ sprintf(fqdn, "%d.%d.%d.%d", vam->config.server_addr.data[0], ++ vam->config.server_addr.data[1], ++ vam->config.server_addr.data[2], ++ vam->config.server_addr.data[3]); ++ /* Always success. TODO: Error check in next version */ ++ last_vpp_metrics = malloc(sizeof(vpp_metrics_struct)); ++ curr_vpp_metrics = malloc(sizeof(vpp_metrics_struct)); ++ ++ if(evel_initialize(fqdn, /* FQDN */ ++ vam->config.server_port, /* Port */ ++ NULL, /* optional path */ ++ NULL, /* optional topic */ ++ 0, /* HTTPS? */ ++ "", /* Username */ ++ "", /* Password */ ++ EVEL_SOURCE_VIRTUAL_MACHINE, /* Source type */ ++ "vG-MUX", /* Role */ ++ 1)) /* Verbosity */ ++ { ++ fprintf(stderr, "\nFailed to initialize the EVEL library!!!\n"); ++ return -1; ++ } ++ ++ gethostname(hostname, BUFSIZE); ++ memset(last_vpp_metrics, 0, sizeof(vpp_metrics_struct)); ++ read_vpp_metrics(last_vpp_metrics, DEFAULT_MEASURE_ETH); ++ gettimeofday(&time_val, NULL); ++ start_epoch = time_val.tv_sec * 1000000 + time_val.tv_usec; ++ ++ vlib_process_wait_for_event_or_clock(vm, (f64)(vam->config.read_interval)); ++ ++ return 0; ++} ++ ++always_inline int ++ves_agent_stop(void) ++{ ++ sleep(1); ++ free(last_vpp_metrics); ++ free(curr_vpp_metrics); ++ evel_terminate(); ++ ++ return 0; ++} ++ ++/* *INDENT-OFF* */ ++VLIB_PLUGIN_REGISTER () = { ++ .version = VPP_BUILD_VER, ++ .description = "VNF Event Stream Agent", ++}; ++/* *INDENT-ON* */ ++ ++static uword ++ves_agent_process (vlib_main_t * vm, ++ vlib_node_runtime_t * rt, ++ vlib_frame_t * f) ++{ ++ ves_agent_main_t *vam = &ves_agent_main; ++ uword event_type; ++ uword * event_data = 0; ++ ++ if (vam->config.read_interval == 0) { ++ vam->config.read_interval = DEFAULT_READ_INTERVAL; ++ } ++ ++ while (1) ++ { ++ vlib_process_wait_for_event_or_clock(vm, (f64)(vam->config.read_interval)); ++ ++ event_type = vlib_process_get_events (vm, &event_data); ++ ++ switch (event_type) ++ { ++ case EVENT_VES_AGENT_START: ++ ves_agent_start(vam); ++ break; ++ case EVENT_VES_AGENT_STOP: ++ ves_agent_stop(); ++ break; ++ default: ++ ves_agent_report_vnic_stats(vam); ++ break; ++ } ++ ++ vec_reset_length (event_data); ++ } ++ ++ /* NOTREACHED */ ++ return 0; ++} ++ ++VLIB_REGISTER_NODE (ves_agent_process_node, static) = { ++ .function = ves_agent_process, ++ .type = VLIB_NODE_TYPE_PROCESS, ++ .name = "ves-agent-process", ++ .process_log2_n_stack_bytes = 16, ++}; ++ ++int ++ves_set_server (ip46_address_t *addr, ++ u32 server_port, ++ u32 read_interval, ++ int is_del) ++{ ++ ves_agent_main_t *vam = &ves_agent_main; ++ vlib_main_t *vm = vam->vlib_main; ++ int rc = 0; ++ ++ if (ip46_address_is_zero(addr)) ++ return VNET_API_ERROR_INVALID_DST_ADDRESS; ++ ++ if (is_del) ++ { ++ if (vam->config.is_enabled == VES_AGENT_DISABLED) { ++ return rc; ++ } ++ ++ if ((vam->config.server_addr.as_u32 != addr->ip4.as_u32) ++ || (vam->config.server_port != server_port)) ++ return VNET_API_ERROR_NO_SUCH_ENTRY; ++ ++ memset(&(vam->config.server_addr), 0, sizeof(ip4_address_t)); ++ vam->config.server_port = DEFAULT_SERVER_PORT; ++ vam->config.read_interval = DEFAULT_READ_INTERVAL; ++ vam->config.is_enabled = VES_AGENT_DISABLED; ++ vlib_process_signal_event (vm, ves_agent_process_node.index, ++ EVENT_VES_AGENT_STOP, 0); ++ } else { ++ // Already enabled the same config. ++ if ((vam->config.server_addr.as_u32 == addr->ip4.as_u32) ++ && (vam->config.server_port != server_port) ++ && vam->config.read_interval == read_interval ++ && vam->config.is_enabled == VES_AGENT_ENABLED) { ++ return rc; ++ } ++ ++ // Already enabled, but not exact match. ++ if (vam->config.is_enabled == VES_AGENT_ENABLED) { ++ return VNET_API_ERROR_VALUE_EXIST; ++ } ++ ++ vam->config.server_addr.as_u32 = addr->ip4.as_u32; ++ vam->config.server_port = server_port; ++ if (read_interval) { ++ vam->config.read_interval = read_interval; ++ } else { ++ vam->config.read_interval = DEFAULT_READ_INTERVAL; ++ } ++ vam->config.is_enabled = VES_AGENT_ENABLED; ++ vlib_process_signal_event (vm, ves_agent_process_node.index, ++ EVENT_VES_AGENT_START, 0); ++ } ++ ++ return (rc); ++} ++ ++static u8 * ++format_ves_agent_set_error(u8 *s, va_list *args) ++{ ++ s = format(s, "%s\n\n", "Caution, set fails due to enabled config:"); ++ s = format(s, "%U", format_ves_agent_config, NULL); ++ return s; ++} ++ ++static clib_error_t * ++ves_server_set_command_fn(vlib_main_t * vm, ++ unformat_input_t * input, ++ vlib_cli_command_t * cmd) ++{ ++ ip46_address_t server_addr; ++ u32 server_port = DEFAULT_SERVER_PORT, inter_val = DEFAULT_READ_INTERVAL; ++ int is_del = 0, set_server = 0; ++ ++ memset(&server_addr, 0, sizeof(server_addr)); ++ ++ while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) ++ { ++ if (unformat (input, "server %U", ++ unformat_ip4_address, &server_addr.ip4)) ++ set_server = 1; ++ else if (unformat (input, "port %u", &server_port)) ++ ; ++ else if (unformat (input, "intval %u", &inter_val)) ++ ; ++ else if (unformat (input, "delete") || ++ unformat (input, "del")) ++ is_del = 1; ++ else ++ break; ++ } ++ ++ if (is_del || set_server) ++ { ++ int rv; ++ ++ rv = ves_set_server (&server_addr, server_port, inter_val, is_del); ++ switch (rv) ++ { ++ case 0: ++ return 0; ++ ++ case VNET_API_ERROR_INVALID_DST_ADDRESS: ++ return clib_error_return (0, "Invalid address"); ++ ++ case VNET_API_ERROR_NO_SUCH_ENTRY: ++ return clib_error_return(0, "No such Entry found"); ++ ++ case VNET_API_ERROR_VALUE_EXIST: ++ vlib_cli_output (vm, "%U\n", format_ves_agent_set_error, NULL); ++ return clib_error_return (0, "BUG found!"); ++ ++ default: ++ return clib_error_return (0, "BUG: rv %d", rv); ++ } ++ } else { ++ return clib_error_return (0, "parse error`%U'", ++ format_unformat_error, input); ++ } ++} ++ ++VLIB_CLI_COMMAND (ves_server_set_command, static) = { ++ .path = "set ves agent", ++ .short_help = "set ves agent [del] server <ipaddr> port <port> [intval <inter-value>]", ++ .function = ves_server_set_command_fn, ++}; ++ ++static u8 * ++format_ves_agent_config(u8 *s, va_list *args) ++{ ++ ves_agent_main_t *vam = &ves_agent_main; ++ char fqdn[16]; /* "xxx.xxx.xxx.xxx" */ ++ ++ s = format(s, "%=16s %=12s %=8s %s\n", "Server Addr", ++ "Server Port", "Interval", "Enabled"); ++ if (vam->config.is_enabled == VES_AGENT_DISABLED) { ++ return s; ++ } ++ ++ sprintf(fqdn, "%d.%d.%d.%d", vam->config.server_addr.data[0], ++ vam->config.server_addr.data[1], ++ vam->config.server_addr.data[2], ++ vam->config.server_addr.data[3]); ++ ++ s = format(s, "%=16s %=12d %=8d %s\n", fqdn, ++ vam->config.server_port, ++ vam->config.read_interval, ++ vam->config.is_enabled ? "True" : "False"); ++ ++ return s; ++} ++ ++static clib_error_t * ++ves_server_show_command_fn(vlib_main_t * vm, ++ unformat_input_t * input, ++ vlib_cli_command_t * cmd) ++{ ++ vlib_cli_output (vm, "%U", format_ves_agent_config, NULL); ++ ++ return (NULL); ++} ++ ++VLIB_CLI_COMMAND (ves_server_show_command, static) = { ++ .path = "show ves agent", ++ .short_help = "Display VES Agent Configuration", ++ .function = ves_server_show_command_fn, ++}; ++ ++int ++ves_agent_set_mode(ves_agent_mode_t mode, ++ u32 pkt_loss_rate) ++{ ++ ves_agent_main_t *vam = &ves_agent_main; ++ int retval = 0; ++ ++ if (VES_AGENT_MODE_DEMO == mode) { ++ if (pkt_loss_rate > 100) { ++ vam->config.mode = VES_AGENT_MODE_REAL; ++ vam->config.base_pkt_loss = 0; ++ return 1; ++ } ++ vam->config.mode = VES_AGENT_MODE_DEMO; ++ vam->config.base_pkt_loss = pkt_loss_rate; ++ } else { /* Only demo or real for current stage */ ++ vam->config.mode = VES_AGENT_MODE_REAL; ++ vam->config.base_pkt_loss = 0; ++ } ++ ++ return retval; ++} ++ ++static clib_error_t * ++ves_mode_set_command_fn(vlib_main_t * vm, ++ unformat_input_t * input, ++ vlib_cli_command_t * cmd) ++{ ++ u32 pkt_loss_rate = 0; ++ ves_agent_mode_t mode = VES_AGENT_MODE_REAL; ++ int set_mode = 0; ++ ++ while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) ++ { ++ if (unformat (input, "demo") || unformat (input, "Demo") ++ || unformat (input, "DEMO")) ++ { ++ mode = VES_AGENT_MODE_DEMO; ++ set_mode = 1; ++ } ++ else if (unformat (input, "real") || unformat (input, "Real") ++ || unformat (input, "REAL")) ++ set_mode = 1; ++ else if (unformat (input, "base %u", &pkt_loss_rate)) ++ ; ++ else ++ break; ++ } ++ ++ if (set_mode) ++ { ++ int retval = ves_agent_set_mode(mode, pkt_loss_rate); ++ if (retval == 0) ++ return 0; ++ else ++ return clib_error_return (0, "BUG found!"); ++ } else { ++ return clib_error_return (0, "parse error`%U'", ++ format_unformat_error, input); ++ } ++} ++ ++VLIB_CLI_COMMAND (ves_mode_set_command, static) = { ++ .path = "set ves mode", ++ .short_help = "set ves mode <demo|real> [base <pkt-loss-rate>]", ++ .function = ves_mode_set_command_fn, ++}; ++ ++static inline u8 * ++format_ves_agent_mode(u8 *s, va_list *args) ++{ ++ ves_agent_main_t *vam = &ves_agent_main; ++ ++ s = format(s, "%=8s %s\n", "Mode", "Base Packet Loss Rate"); ++ ++ s = format(s, "%=8s %.1f %%\n", ++ vam->config.mode == VES_AGENT_MODE_DEMO ? "Demo" : "Real", ++ (double) vam->config.base_pkt_loss); ++ ++ return s; ++} ++ ++static clib_error_t * ++ves_agent_mode_show_command_fn(vlib_main_t * vm, ++ unformat_input_t * input, ++ vlib_cli_command_t * cmd) ++{ ++ vlib_cli_output (vm, "%U", format_ves_agent_mode, NULL); ++ ++ return (NULL); ++} ++ ++VLIB_CLI_COMMAND (ves_agent_mode_show_command, static) = { ++ .path = "show ves mode", ++ .short_help = "Display VES Agent Mode Information", ++ .function = ves_agent_mode_show_command_fn, ++}; ++ ++static clib_error_t * ++ves_agent_init(vlib_main_t * vm) ++{ ++ ves_agent_main_t *vam = &ves_agent_main; ++ ++ vam->vlib_main = vm; ++ vam->vnet_main = vnet_get_main(); ++ ++ return 0; ++} ++ ++VLIB_INIT_FUNCTION (ves_agent_init); ++ ++/* ++ * fd.io coding-style-patch-verification: ON ++ * ++ * Local Variables: ++ * eval: (c-set-style "gnu") ++ * End: ++ */ +diff --git a/src/plugins/ves/ves_node.h b/src/plugins/ves/ves_node.h +new file mode 100644 +index 00000000..7b773843 +--- /dev/null ++++ b/src/plugins/ves/ves_node.h +@@ -0,0 +1,66 @@ ++/* ++ * Copyright (c) 2017 Intel 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. ++ */ ++ ++#ifndef _VES_NODE_H_ ++#define _VES_NODE_H_ ++ ++#include <vnet/ip/ip.h> ++ ++#include "include/evel.h" ++ ++#define DEFAULT_SERVER_IP "127.0.0.1" ++#define DEFAULT_MEASURE_ETH "eth0" ++#define DEFAULT_SERVER_PORT 8080 ++#define DEFAULT_READ_INTERVAL 100 ++ ++typedef enum { ++ VES_AGENT_MODE_REAL = 0, ++ VES_AGENT_MODE_DEMO, ++ _NUM_VES_AGENT_MODES ++} ves_agent_mode_t; ++ ++/* VES Agent Server configuration */ ++typedef struct { ++ ip4_address_t server_addr; ++ u32 server_port; ++ u32 read_interval; ++ int is_enabled; ++ u32 base_pkt_loss; /* For demo only */ ++ ves_agent_mode_t mode; /* Demo or Real */ ++} ves_agent_config_t; ++ ++typedef struct { ++ ves_agent_config_t config; ++ ++ /* convenience */ ++ vlib_main_t * vlib_main; ++ vnet_main_t * vnet_main; ++} ves_agent_main_t; ++ ++ves_agent_main_t ves_agent_main; ++ ++#define EVENT_VES_AGENT_START 1 ++#define EVENT_VES_AGENT_STOP 0 ++ ++#define VES_AGENT_DISABLED 0 ++#define VES_AGENT_ENABLED 1 ++ ++int ves_set_server(ip46_address_t *addr, u32 server_port, ++ u32 read_interval, int is_del); ++ ++int ves_agent_set_mode(ves_agent_mode_t mode, ++ u32 pkt_loss_rate); ++ ++#endif /* _VES_NODE_H_ */ +diff --git a/src/vpp-api/java/Makefile.am b/src/vpp-api/java/Makefile.am +index f18e0c24..7f4738d8 100644 +--- a/src/vpp-api/java/Makefile.am ++++ b/src/vpp-api/java/Makefile.am +@@ -148,6 +148,26 @@ jvpp-snat/io_fd_vpp_jvpp_snat_JVppSnatImpl.h: $(jvpp_registry_ok) $(jvpp_snat_js + $(call japigen,snat,JVppSnatImpl) + endif + ++# ++# VES Plugin ++# ++if ENABLE_VES_PLUGIN ++noinst_LTLIBRARIES += libjvpp_ves.la ++libjvpp_ves_la_SOURCES = jvpp-ves/jvpp_ves.c ++libjvpp_ves_la_CPPFLAGS = -Ijvpp-ves ++libjvpp_ves_la_LIBADD = $(JVPP_LIBS) ++libjvpp_ves_la_DEPENDENCIES = libjvpp_common.la ++ ++BUILT_SOURCES += jvpp-ves/io_fd_vpp_jvpp_ves_JVppVesImpl.h ++JAR_FILES += jvpp-ves-$(PACKAGE_VERSION).jar ++CLEANDIRS += jvpp-ves/target ++ ++jvpp_ves_json_files = @top_builddir@/plugins/ves/ves.api.json ++ ++jvpp-ves/io_fd_vpp_jvpp_ves_JVppVesImpl.h: $(jvpp_registry_ok) $(jvpp_ves_json_files) ++ $(call japigen,ves,JVppVesImpl) ++endif ++ + # + # iOAM Trace Plugin + # +diff --git a/src/vpp-api/java/jvpp-ves/jvpp_ves.c b/src/vpp-api/java/jvpp-ves/jvpp_ves.c +new file mode 100644 +index 00000000..60e325b5 +--- /dev/null ++++ b/src/vpp-api/java/jvpp-ves/jvpp_ves.c +@@ -0,0 +1,108 @@ ++/* ++ * Copyright (c) 2017 Intel Corp 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. ++ */ ++ ++#include <vnet/vnet.h> ++ ++#include <ves/ves_msg_enum.h> ++#define vl_typedefs /* define message structures */ ++#include <ves/ves_all_api_h.h> ++#undef vl_typedefs ++ ++#include <vnet/api_errno.h> ++#include <vlibapi/api.h> ++#include <vlibmemory/api.h> ++ ++#if VPPJNI_DEBUG == 1 ++ #define DEBUG_LOG(...) clib_warning(__VA_ARGS__) ++#else ++ #define DEBUG_LOG(...) ++#endif ++ ++#include <jvpp-common/jvpp_common.h> ++ ++#include "jvpp-ves/io_fd_vpp_jvpp_ves_JVppVesImpl.h" ++#include "jvpp_ves.h" ++#include "jvpp-ves/jvpp_ves_gen.h" ++ ++/* ++ * Class: io_fd_vpp_jvpp_ves_JVppVesImpl ++ * Method: init0 ++ * Signature: (JI)V ++ */ ++JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_ves_JVppVesImpl_init0 ++ (JNIEnv *env, jclass clazz, jobject callback, jlong queue_address, jint my_client_index) { ++ ves_main_t * plugin_main = &ves_main; ++ clib_warning ("Java_io_fd_vpp_jvpp_ves_JVppVesImpl_init0"); ++ ++ plugin_main->my_client_index = my_client_index; ++ plugin_main->vl_input_queue = (unix_shared_memory_queue_t *)queue_address; ++ ++ plugin_main->callbackObject = (*env)->NewGlobalRef(env, callback); ++ plugin_main->callbackClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, callback)); ++ ++ // verify API has not changed since jar generation ++ #define _(N) \ ++ get_message_id(env, #N); ++ foreach_supported_api_message; ++ #undef _ ++ ++ #define _(N,n) \ ++ vl_msg_api_set_handlers(get_message_id(env, #N), #n, \ ++ vl_api_##n##_t_handler, \ ++ vl_noop_handler, \ ++ vl_noop_handler, \ ++ vl_noop_handler, \ ++ sizeof(vl_api_##n##_t), 1); ++ foreach_api_reply_handler; ++ #undef _ ++} ++ ++JNIEXPORT void JNICALL Java_io_fd_vpp_jvpp_ves_JVppVesImpl_close0 ++(JNIEnv *env, jclass clazz) { ++ ves_main_t * plugin_main = &ves_main; ++ ++ // cleanup: ++ (*env)->DeleteGlobalRef(env, plugin_main->callbackClass); ++ (*env)->DeleteGlobalRef(env, plugin_main->callbackObject); ++ ++ plugin_main->callbackClass = NULL; ++ plugin_main->callbackObject = NULL; ++} ++ ++/* Attach thread to JVM and cache class references when initiating JVPP VES */ ++jint JNI_OnLoad(JavaVM *vm, void *reserved) { ++ JNIEnv* env; ++ ++ if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { ++ return JNI_EVERSION; ++ } ++ ++ if (cache_class_references(env) != 0) { ++ clib_warning ("Failed to cache class references\n"); ++ return JNI_ERR; ++ } ++ ++ return JNI_VERSION_1_8; ++} ++ ++/* Clean up cached references when disposing JVPP VES */ ++void JNI_OnUnload(JavaVM *vm, void *reserved) { ++ JNIEnv* env; ++ if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_8) != JNI_OK) { ++ return; ++ } ++ delete_class_references(env); ++} +diff --git a/src/vpp-api/java/jvpp-ves/jvpp_ves.h b/src/vpp-api/java/jvpp-ves/jvpp_ves.h +new file mode 100644 +index 00000000..642101ca +--- /dev/null ++++ b/src/vpp-api/java/jvpp-ves/jvpp_ves.h +@@ -0,0 +1,43 @@ ++/* ++ * Copyright (c) 2017 Intel Corp 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. ++ */ ++#ifndef __included_jvpp_ves_h__ ++#define __included_jvpp_ves_h__ ++ ++#include <vnet/vnet.h> ++#include <vnet/ip/ip.h> ++#include <vnet/api_errno.h> ++#include <vlibapi/api.h> ++#include <vlibmemory/api.h> ++#include <jni.h> ++ ++/* Global state for JVPP-VES */ ++typedef struct { ++ /* Pointer to shared memory queue */ ++ unix_shared_memory_queue_t * vl_input_queue; ++ ++ /* VPP api client index */ ++ u32 my_client_index; ++ ++ /* Callback object and class references enabling asynchronous Java calls */ ++ jobject callbackObject; ++ jclass callbackClass; ++ ++} ves_main_t; ++ ++ves_main_t ves_main __attribute__((aligned (64))); ++ ++ ++#endif /* __included_jvpp_ves_h__ */ +-- +2.14.1.windows.1 + diff --git a/vnfs/vFW/scripts/v_firewall_install.sh b/vnfs/vFW/scripts/v_firewall_install.sh index 0a2c8da8..262a01b8 100644 --- a/vnfs/vFW/scripts/v_firewall_install.sh +++ b/vnfs/vFW/scripts/v_firewall_install.sh @@ -58,9 +58,10 @@ then fi # Download required dependencies -add-apt-repository -y ppa:openjdk-r/ppa +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list apt-get update -apt-get install -y make wget openjdk-8-jdk gcc libcurl4-openssl-dev python-pip bridge-utils apt-transport-https ca-certificates +apt-get install --allow-unauthenticated -y make wget openjdk-8-jdk gcc libcurl4-openssl-dev python-pip bridge-utils apt-transport-https ca-certificates pip install jsonschema # Download artifacts for virtual firewall @@ -73,11 +74,11 @@ wget $REPO_URL_ARTIFACTS/org/onap/demo/vnf/sample-distribution/$DEMO_ARTIFACTS_V wget $REPO_URL_ARTIFACTS/org/onap/demo/vnf/ves/ves/$DEMO_ARTIFACTS_VERSION/ves-$DEMO_ARTIFACTS_VERSION-demo.tar.gz wget $REPO_URL_ARTIFACTS/org/onap/demo/vnf/ves/ves_vfw_reporting/$DEMO_ARTIFACTS_VERSION/ves_vfw_reporting-$DEMO_ARTIFACTS_VERSION-demo.tar.gz -tar -zxvf ves-$DEMO_ARTIFACTS_VERSION-demo.tar.gz +tar -zmxvf ves-$DEMO_ARTIFACTS_VERSION-demo.tar.gz mv ves-$DEMO_ARTIFACTS_VERSION VES -tar -zxvf ves_vfw_reporting-$DEMO_ARTIFACTS_VERSION-demo.tar.gz +tar -zmxvf ves_vfw_reporting-$DEMO_ARTIFACTS_VERSION-demo.tar.gz mv ves_vfw_reporting-$DEMO_ARTIFACTS_VERSION VESreporting_vFW -tar -zxvf sample-distribution-$DEMO_ARTIFACTS_VERSION-hc.tar.gz +tar -zmxvf sample-distribution-$DEMO_ARTIFACTS_VERSION-hc.tar.gz mv sample-distribution-$DEMO_ARTIFACTS_VERSION honeycomb sed -i 's/"restconf-binding-address": "127.0.0.1",/"restconf-binding-address": "0.0.0.0",/g' honeycomb/sample-distribution-$DEMO_ARTIFACTS_VERSION/config/honeycomb.json mv VESreporting_vFW /opt/VES/code/evel_training/VESreporting diff --git a/vnfs/vFW/scripts/v_packetgen_install.sh b/vnfs/vFW/scripts/v_packetgen_install.sh index 4ec1e4e6..3f150fce 100644 --- a/vnfs/vFW/scripts/v_packetgen_install.sh +++ b/vnfs/vFW/scripts/v_packetgen_install.sh @@ -48,9 +48,10 @@ then fi # Download required dependencies -add-apt-repository -y ppa:openjdk-r/ppa +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list apt-get update -apt-get install -y make wget openjdk-8-jdk gcc libcurl4-openssl-dev python-pip bridge-utils apt-transport-https ca-certificates +apt-get install --allow-unauthenticated -y make wget openjdk-8-jdk gcc libcurl4-openssl-dev python-pip bridge-utils apt-transport-https ca-certificates pip install jsonschema # Download code for packet generator @@ -63,8 +64,8 @@ wget $REPO_URL_BLOB/org.onap.demo/vnfs/vfw/$INSTALL_SCRIPT_VERSION/run_traffic_f wget $REPO_URL_ARTIFACTS/org/onap/demo/vnf/sample-distribution/$DEMO_ARTIFACTS_VERSION/sample-distribution-$DEMO_ARTIFACTS_VERSION-hc.tar.gz wget $REPO_URL_ARTIFACTS/org/onap/demo/vnf/vfw/vfw_pg_streams/$DEMO_ARTIFACTS_VERSION/vfw_pg_streams-$DEMO_ARTIFACTS_VERSION-demo.tar.gz -tar -zxvf sample-distribution-$DEMO_ARTIFACTS_VERSION-hc.tar.gz -tar -zxvf vfw_pg_streams-$DEMO_ARTIFACTS_VERSION-demo.tar.gz +tar -zmxvf sample-distribution-$DEMO_ARTIFACTS_VERSION-hc.tar.gz +tar -zmxvf vfw_pg_streams-$DEMO_ARTIFACTS_VERSION-demo.tar.gz mv vfw_pg_streams-$DEMO_ARTIFACTS_VERSION pg_streams mv sample-distribution-$DEMO_ARTIFACTS_VERSION honeycomb sed -i 's/"restconf-binding-address": "127.0.0.1",/"restconf-binding-address": "0.0.0.0",/g' honeycomb/sample-distribution-$DEMO_ARTIFACTS_VERSION/config/honeycomb.json diff --git a/vnfs/vFW/scripts/v_sink_install.sh b/vnfs/vFW/scripts/v_sink_install.sh index 88c194d0..f01a0abd 100644 --- a/vnfs/vFW/scripts/v_sink_install.sh +++ b/vnfs/vFW/scripts/v_sink_install.sh @@ -46,9 +46,10 @@ then fi # Download required dependencies -add-apt-repository -y ppa:openjdk-r/ppa +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list apt-get update -apt-get install -y make wget openjdk-8-jdk apt-transport-https ca-certificates darkstat +apt-get install --allow-unauthenticated -y make wget openjdk-8-jdk apt-transport-https ca-certificates darkstat # Configure and run Darkstat sed -i "s/START_DARKSTAT=.*/START_DARKSTAT=yes/g" /etc/darkstat/init.cfg diff --git a/vnfs/vLB/.DS_Store b/vnfs/vLB/.DS_Store Binary files differdeleted file mode 100644 index b7ccbfd4..00000000 --- a/vnfs/vLB/.DS_Store +++ /dev/null diff --git a/vnfs/vLB/dns_streams/stream_dns1 b/vnfs/vLB/dns_streams/stream_dns1 index ff9fdc51..3d2de9b1 100644 --- a/vnfs/vLB/dns_streams/stream_dns1 +++ b/vnfs/vLB/dns_streams/stream_dns1 @@ -7,7 +7,7 @@ packet-generator new { data { UDP: 104.130.226.226 -> 104.130.169.190 UDP: 15320 -> 53 - length 53 - hex 0x22c60100000100000000000005686f73743107646e7364656d6f096f70656e65636f6d70036f72670000010001 + length 48 + hex 0x22c60100000100000000000005686f73743107646e7364656d6f046f6e6170036f72670000010001 } } diff --git a/vnfs/vLB/dns_streams/stream_dns10 b/vnfs/vLB/dns_streams/stream_dns10 index 9f28e20e..7c67ca31 100644 --- a/vnfs/vLB/dns_streams/stream_dns10 +++ b/vnfs/vLB/dns_streams/stream_dns10 @@ -7,7 +7,7 @@ packet-generator new { data { UDP: 104.130.226.226 -> 104.130.169.190 UDP: 15320 -> 53 - length 54 - hex 0x867b0100000100000000000006686f7374313007646e7364656d6f096f70656e65636f6d70036f72670000010001 + length 49 + hex 0x867b0100000100000000000006686f7374313007646e7364656d6f046f6e6170036f72670000010001 } } diff --git a/vnfs/vLB/dns_streams/stream_dns2 b/vnfs/vLB/dns_streams/stream_dns2 index 0b3d6c64..2696d36f 100644 --- a/vnfs/vLB/dns_streams/stream_dns2 +++ b/vnfs/vLB/dns_streams/stream_dns2 @@ -7,7 +7,7 @@ packet-generator new { data { UDP: 104.130.226.226 -> 104.130.169.190 UDP: 15320 -> 53 - length 53 - hex 0x23550100000100000000000005686f73743207646e7364656d6f096f70656e65636f6d70036f72670000010001 + length 48 + hex 0x23550100000100000000000005686f73743207646e7364656d6f046f6e6170036f72670000010001 } } diff --git a/vnfs/vLB/dns_streams/stream_dns3 b/vnfs/vLB/dns_streams/stream_dns3 index 531ba8e1..0a691d47 100644 --- a/vnfs/vLB/dns_streams/stream_dns3 +++ b/vnfs/vLB/dns_streams/stream_dns3 @@ -7,7 +7,7 @@ packet-generator new { data { UDP: 104.130.226.226 -> 104.130.169.190 UDP: 15320 -> 53 - length 53 - hex 0x7b110100000100000000000005686f73743307646e7364656d6f096f70656e65636f6d70036f72670000010001 + length 48 + hex 0x7b110100000100000000000005686f73743307646e7364656d6f046f6e6170036f72670000010001 } } diff --git a/vnfs/vLB/dns_streams/stream_dns4 b/vnfs/vLB/dns_streams/stream_dns4 index 2bfd4cba..eb1ea3ed 100644 --- a/vnfs/vLB/dns_streams/stream_dns4 +++ b/vnfs/vLB/dns_streams/stream_dns4 @@ -7,7 +7,7 @@ packet-generator new { data { UDP: 104.130.226.226 -> 104.130.169.190 UDP: 15320 -> 53 - length 53 - hex 0x63910100000100000000000005686f73743407646e7364656d6f096f70656e65636f6d70036f72670000010001 + length 48 + hex 0x63910100000100000000000005686f73743407646e7364656d6f046f6e6170036f72670000010001 } } diff --git a/vnfs/vLB/dns_streams/stream_dns5 b/vnfs/vLB/dns_streams/stream_dns5 index c853c57e..eb4d5eb3 100644 --- a/vnfs/vLB/dns_streams/stream_dns5 +++ b/vnfs/vLB/dns_streams/stream_dns5 @@ -7,7 +7,7 @@ packet-generator new { data { UDP: 104.130.226.226 -> 104.130.169.190 UDP: 15320 -> 53 - length 53 - hex 0x054e0100000100000000000005686f73743507646e7364656d6f096f70656e65636f6d70036f72670000010001 + length 48 + hex 0x054e0100000100000000000005686f73743507646e7364656d6f046f6e6170036f72670000010001 } } diff --git a/vnfs/vLB/dns_streams/stream_dns6 b/vnfs/vLB/dns_streams/stream_dns6 index dab51566..acfc6838 100644 --- a/vnfs/vLB/dns_streams/stream_dns6 +++ b/vnfs/vLB/dns_streams/stream_dns6 @@ -7,7 +7,7 @@ packet-generator new { data { UDP: 104.130.226.226 -> 104.130.169.190 UDP: 15320 -> 53 - length 53 - hex 0xb9d80100000100000000000005686f73743607646e7364656d6f096f70656e65636f6d70036f72670000010001 + length 48 + hex 0xb9d80100000100000000000005686f73743607646e7364656d6f046f6e6170036f72670000010001 } } diff --git a/vnfs/vLB/dns_streams/stream_dns7 b/vnfs/vLB/dns_streams/stream_dns7 index 1cca61ef..f2d6b2dd 100644 --- a/vnfs/vLB/dns_streams/stream_dns7 +++ b/vnfs/vLB/dns_streams/stream_dns7 @@ -7,7 +7,7 @@ packet-generator new { data { UDP: 104.130.226.226 -> 104.130.169.190 UDP: 15320 -> 53 - length 53 - hex 0x36f30100000100000000000005686f73743707646e7364656d6f096f70656e65636f6d70036f72670000010001 + length 48 + hex 0x36f30100000100000000000005686f73743707646e7364656d6f046f6e6170036f72670000010001 } } diff --git a/vnfs/vLB/dns_streams/stream_dns8 b/vnfs/vLB/dns_streams/stream_dns8 index ce76bcaf..0040eb68 100644 --- a/vnfs/vLB/dns_streams/stream_dns8 +++ b/vnfs/vLB/dns_streams/stream_dns8 @@ -7,7 +7,7 @@ packet-generator new { data { UDP: 104.130.226.226 -> 104.130.169.190 UDP: 15320 -> 53 - length 53 - hex 0x09860100000100000000000005686f73743807646e7364656d6f096f70656e65636f6d70036f72670000010001 + length 48 + hex 0x09860100000100000000000005686f73743807646e7364656d6f046f6e6170036f72670000010001 } } diff --git a/vnfs/vLB/dns_streams/stream_dns9 b/vnfs/vLB/dns_streams/stream_dns9 index 0cc3132d..b7f6af4c 100644 --- a/vnfs/vLB/dns_streams/stream_dns9 +++ b/vnfs/vLB/dns_streams/stream_dns9 @@ -7,7 +7,7 @@ packet-generator new { data { UDP: 104.130.226.226 -> 104.130.169.190 UDP: 15320 -> 53 - length 53 - hex 0x12610100000100000000000005686f73743907646e7364656d6f096f70656e65636f6d70036f72670000010001 + length 48 + hex 0x12610100000100000000000005686f73743907646e7364656d6f046f6e6170036f72670000010001 } } diff --git a/vnfs/vLB/scripts/.DS_Store b/vnfs/vLB/scripts/.DS_Store Binary files differdeleted file mode 100644 index 32f7ecab..00000000 --- a/vnfs/vLB/scripts/.DS_Store +++ /dev/null diff --git a/vnfs/vLB/scripts/add_dns.sh b/vnfs/vLB/scripts/add_dns.sh index 04dfc771..3574e085 100644 --- a/vnfs/vLB/scripts/add_dns.sh +++ b/vnfs/vLB/scripts/add_dns.sh @@ -7,15 +7,17 @@ then fi DNS_IPADDR=$1 -MY_PUBLIC_IP=$(cat /opt/config/local_public_ipaddr.txt) -MY_PRIVATE_IP=$(cat /opt/config/local_private_ipaddr.txt) +IP_TO_PKTGEN_NET=$(cat /opt/config/ip_to_pktgen_net.txt) +IP_TO_DNS_NET=$(cat /opt/config/ip_to_dns_net.txt) +GRE_IPADDR=$(cat /opt/config/gre_ipaddr.txt) -vppctl lb as $MY_PUBLIC_IP"/32" $DNS_IPADDR -GRE=$(vppctl create gre tunnel src $MY_PRIVATE_IP dst $DNS_IPADDR) +vppctl lb as $IP_TO_PKTGEN_NET"/32" $DNS_IPADDR +GRE=$(vppctl create gre tunnel src $IP_TO_DNS_NET dst $DNS_IPADDR) +vppctl set int ip address $GRE $GRE_IPADDR"/32" 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 +echo $CURR_DNS > $FD
\ No newline at end of file diff --git a/vnfs/vLB/scripts/dnsmembership.sh b/vnfs/vLB/scripts/dnsmembership.sh index 345dc3ff..e18ab803 100644 --- a/vnfs/vLB/scripts/dnsmembership.sh +++ b/vnfs/vLB/scripts/dnsmembership.sh @@ -1,6 +1,6 @@ #!/bin/bash -MY_PUBLIC_IP=$(cat /opt/config/local_public_ipaddr.txt) +IP_TO_PKTGEN_NET=$(cat /opt/config/ip_to_pktgen_net.txt) VERSION=$(cat /opt/config/demo_artifacts_version.txt) -java -jar dns-manager-$VERSION.jar $MY_PUBLIC_IP 8888 10 3 0 +java -jar dns-manager-$VERSION.jar $IP_TO_PKTGEN_NET 8888 10 3 0 diff --git a/vnfs/vLB/scripts/remove_dns.sh b/vnfs/vLB/scripts/remove_dns.sh index 1d505abe..f400aa0f 100644 --- a/vnfs/vLB/scripts/remove_dns.sh +++ b/vnfs/vLB/scripts/remove_dns.sh @@ -2,23 +2,23 @@ if [ ! "$#" -eq 1 ] then - echo "Usage: ./add_dns.sh [remote DNS server]" + echo "Usage: ./remove_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) +IP_TO_PKTGEN_NET=$(cat /opt/config/ip_to_pktgen_net.txt) +IP_TO_DNS_NET=$(cat /opt/config/ip_to_dns_net.txt) -vppctl lb as $MY_PUBLIC_ID"/32" $DNS_IPADDR del -vppctl create gre tunnel src $MY_PRIVATE_IP dst $DNS_IPADDR del +vppctl lb as $IP_TO_PKTGEN_NET"/32" $DNS_IPADDR del +vppctl create gre tunnel src $IP_TO_DNS_NET 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 +then CURR_DNS=0 fi -echo $CURR_DNS > $FD +echo $CURR_DNS > $FD
\ No newline at end of file diff --git a/vnfs/vLB/scripts/run_streams_dns.sh b/vnfs/vLB/scripts/run_streams_dns.sh index 4d4e5432..cf95fa53 100755 --- a/vnfs/vLB/scripts/run_streams_dns.sh +++ b/vnfs/vLB/scripts/run_streams_dns.sh @@ -3,7 +3,7 @@ vppctl packet-gen disable vppctl packet-gen enable-stream dns1 vppctl packet-gen enable-stream dns2 -sleep 300 +sleep 100 vppctl packet-gen enable-stream dns3 vppctl packet-gen enable-stream dns4 vppctl packet-gen enable-stream dns5 diff --git a/vnfs/vLB/scripts/v_dns_install.sh b/vnfs/vLB/scripts/v_dns_install.sh index 83441ac9..91cce8ab 100644 --- a/vnfs/vLB/scripts/v_dns_install.sh +++ b/vnfs/vLB/scripts/v_dns_install.sh @@ -42,19 +42,16 @@ then echo " address $IP" >> /etc/network/interfaces echo " netmask $NETMASK" >> /etc/network/interfaces echo " mtu $MTU" >> /etc/network/interfaces - - ifup eth1 - ifup eth2 fi # Download required dependencies -add-apt-repository -y ppa:openjdk-r/ppa +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list apt-get update -apt-get install -y wget openjdk-8-jdk bind9 bind9utils bind9-doc apt-transport-https ca-certificates +apt-get install --allow-unauthenticated -y wget openjdk-8-jdk bind9 bind9utils bind9-doc apt-transport-https ca-certificates sleep 1 # Download vDNS demo code for DNS Server -mkdir /opt/config mkdir /opt/FDclient cd /opt @@ -92,4 +89,17 @@ sleep 1 cd /opt mv vdns.sh /etc/init.d update-rc.d vdns.sh defaults + +# Rename network interface in openstack Ubuntu 16.04 images. Then, reboot the VM to pick up changes +if [[ $CLOUD_ENV != "rackspace" ]] +then + sed -i "s/GRUB_CMDLINE_LINUX=.*/GRUB_CMDLINE_LINUX=\"net.ifnames=0 biosdevname=0\"/g" /etc/default/grub + grub-mkconfig -o /boot/grub/grub.cfg + sed -i "s/ens[0-9]*/eth0/g" /etc/network/interfaces.d/*.cfg + sed -i "s/ens[0-9]*/eth0/g" /etc/udev/rules.d/70-persistent-net.rules + echo 'network: {config: disabled}' >> /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg + echo "APT::Periodic::Unattended-Upgrade \"0\";" >> /etc/apt/apt.conf.d/10periodic + reboot +fi + ./v_dns_init.sh
\ No newline at end of file diff --git a/vnfs/vLB/scripts/v_lb_init.sh b/vnfs/vLB/scripts/v_lb_init.sh index 8767a943..9223e043 100755 --- a/vnfs/vLB/scripts/v_lb_init.sh +++ b/vnfs/vLB/scripts/v_lb_init.sh @@ -1,7 +1,7 @@ #!/bin/bash # Start VPP -start vpp +systemctl start vpp sleep 1 # Compute the network CIDR from the Netmask @@ -25,30 +25,33 @@ mask2cidr() { echo "$nbits" } -IPADDR1_MASK=$(ifconfig eth0 | grep "Mask" | awk '{print $4}' | awk -F ":" '{print $2}') +IPADDR1_MASK=$(ifconfig eth3 | grep "Mask" | awk '{print $4}' | awk -F ":" '{print $2}') IPADDR1_CIDR=$(mask2cidr $IPADDR1_MASK) IPADDR2_MASK=$(ifconfig eth1 | grep "Mask" | awk '{print $4}' | awk -F ":" '{print $2}') IPADDR2_CIDR=$(mask2cidr $IPADDR2_MASK) # Configure VPP for vPacketGenerator -IPADDR1=$(ifconfig eth0 | grep "inet addr" | tr -s ' ' | cut -d' ' -f3 | cut -d':' -f2) +IPADDR1=$(ifconfig eth3 | 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) +HWADDR1=$(ifconfig eth3 | 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"') +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 -n | grep "^0.0.0.0" | awk '{print $2}') +PKTGEN_IPADDR=$(cat /opt/config/pktgen_ipaddr.txt) +PKTGEN_MAC=$(cat /opt/config/pktgen_mac.txt) +VIP=$(cat /opt/config/vip.txt) -ifconfig eth0 down -ifconfig eth0 hw ether $FAKE_HWADDR1 -ip addr flush dev eth0 -ifconfig eth0 up +ifconfig eth3 down +ifconfig eth3 hw ether $FAKE_HWADDR1 +ip addr flush dev eth3 +ifconfig eth3 up vppctl tap connect tappub hwaddr $HWADDR1 -vppctl set int ip address tap-0 $IPADDR1"/"$IPADDR1_CIDR +vppctl set int ip address tap-0 $VIP"/"$IPADDR1_CIDR vppctl set int state tap-0 up brctl addbr br0 brctl addif br0 tappub -brctl addif br0 eth0 +brctl addif br0 eth3 ifconfig br0 up ifconfig eth1 down @@ -66,13 +69,16 @@ 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 +vppctl set ip arp proxy $IPADDR1" - "$IPADDR1 +vppctl set interface proxy-arp tap-0 enable +vppctl set ip arp tap-0 $PKTGEN_IPADDR $PKTGEN_MAC + 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 +./go-client.sh &>/dev/null &disown
\ No newline at end of file diff --git a/vnfs/vLB/scripts/v_lb_install.sh b/vnfs/vLB/scripts/v_lb_install.sh index 394a6c8c..a6577c4a 100644 --- a/vnfs/vLB/scripts/v_lb_install.sh +++ b/vnfs/vLB/scripts/v_lb_install.sh @@ -25,7 +25,7 @@ then MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1) - IP=$(cat /opt/config/local_private_ipaddr.txt) + IP=$(cat /opt/config/ip_to_dns_net.txt) BITS=$(cat /opt/config/vlb_private_net_cidr.txt | cut -d"/" -f2) NETMASK=$(cdr2mask $BITS) echo "auto eth1" >> /etc/network/interfaces @@ -43,18 +43,24 @@ then echo " netmask $NETMASK" >> /etc/network/interfaces echo " mtu $MTU" >> /etc/network/interfaces - ifup eth1 - ifup eth2 + IP=$(cat /opt/config/ip_to_pktgen_net.txt) + BITS=$(cat /opt/config/pktgen_private_net_cidr.txt | cut -d"/" -f2) + NETMASK=$(cdr2mask $BITS) + echo "auto eth3" >> /etc/network/interfaces + echo "iface eth3 inet static" >> /etc/network/interfaces + echo " address $IP" >> /etc/network/interfaces + echo " netmask $NETMASK" >> /etc/network/interfaces + echo " mtu $MTU" >> /etc/network/interfaces fi # Download required dependencies -add-apt-repository -y ppa:openjdk-r/ppa +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list apt-get update -apt-get install -y make gcc wget openjdk-8-jdk bridge-utils libcurl4-openssl-dev apt-transport-https ca-certificates +apt-get install --allow-unauthenticated -y make gcc wget openjdk-8-jdk bridge-utils libcurl4-openssl-dev apt-transport-https ca-certificates sleep 1 # Download vLB demo code for load balancer -mkdir /opt/config mkdir /opt/FDserver cd /opt @@ -67,9 +73,9 @@ wget $REPO_URL_ARTIFACTS/org/onap/demo/vnf/vlb/dns-manager/$DEMO_ARTIFACTS_VERSI wget $REPO_URL_ARTIFACTS/org/onap/demo/vnf/ves/ves/$DEMO_ARTIFACTS_VERSION/ves-$DEMO_ARTIFACTS_VERSION-demo.tar.gz wget $REPO_URL_ARTIFACTS/org/onap/demo/vnf/ves/ves_vlb_reporting/$DEMO_ARTIFACTS_VERSION/ves_vlb_reporting-$DEMO_ARTIFACTS_VERSION-demo.tar.gz -tar -zxvf ves-$DEMO_ARTIFACTS_VERSION-demo.tar.gz +tar -zmxvf ves-$DEMO_ARTIFACTS_VERSION-demo.tar.gz mv ves-$DEMO_ARTIFACTS_VERSION VES -tar -zxvf ves_vlb_reporting-$DEMO_ARTIFACTS_VERSION-demo.tar.gz +tar -zmxvf ves_vlb_reporting-$DEMO_ARTIFACTS_VERSION-demo.tar.gz mv ves_vlb_reporting-$DEMO_ARTIFACTS_VERSION VESreporting_vLB mv VESreporting_vLB /opt/VES/code/evel_training/VESreporting @@ -86,16 +92,9 @@ chmod +x /opt/FDserver/dnsmembership.sh chmod +x /opt/FDserver/add_dns.sh chmod +x /opt/FDserver/remove_dns.sh -# Create a file with public IP of the VM if it doesn't exist. This is for VMs directly attached to the external network. -if [ ! -e /opt/config/local_public_ipaddr.txt ] -then - IP_ADDRESS=$(ifconfig eth0 | grep "inet addr" | tr -s ' ' | cut -d' ' -f3 | cut -d':' -f2) - echo $IP_ADDRESS > /opt/config/local_public_ipaddr.txt -fi - # Install VPP -export UBUNTU="trusty" -export RELEASE=".stable.1609" +export UBUNTU="xenial" +export RELEASE=".stable.1707" rm /etc/apt/sources.list.d/99fd.io.list echo "deb [trusted=yes] https://nexus.fd.io/content/repositories/fd.io$RELEASE.ubuntu.$UBUNTU.main/ ./" | sudo tee -a /etc/apt/sources.list.d/99fd.io.list apt-get update @@ -112,4 +111,17 @@ sleep 1 cd /opt mv vlb.sh /etc/init.d update-rc.d vlb.sh defaults + +# Rename network interface in openstack Ubuntu 16.04 images. Then, reboot the VM to pick up changes +if [[ $CLOUD_ENV != "rackspace" ]] +then + sed -i "s/GRUB_CMDLINE_LINUX=.*/GRUB_CMDLINE_LINUX=\"net.ifnames=0 biosdevname=0\"/g" /etc/default/grub + grub-mkconfig -o /boot/grub/grub.cfg + sed -i "s/ens[0-9]*/eth0/g" /etc/network/interfaces.d/*.cfg + sed -i "s/ens[0-9]*/eth0/g" /etc/udev/rules.d/70-persistent-net.rules + echo 'network: {config: disabled}' >> /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg + echo "APT::Periodic::Unattended-Upgrade \"0\";" >> /etc/apt/apt.conf.d/10periodic + reboot +fi + ./v_lb_init.sh
\ No newline at end of file diff --git a/vnfs/vLB/scripts/v_packetgen_for_dns_demo_init.sh b/vnfs/vLB/scripts/v_packetgen_init.sh index 9e7879bc..3e0de3e6 100644 --- a/vnfs/vLB/scripts/v_packetgen_for_dns_demo_init.sh +++ b/vnfs/vLB/scripts/v_packetgen_init.sh @@ -1,7 +1,7 @@ #!/bin/bash # Start VPP -start vpp +systemctl start vpp sleep 1 # Compute the network CIDR from the Netmask @@ -25,51 +25,37 @@ mask2cidr() { echo "$nbits" } -IPADDR1_MASK=$(ifconfig eth0 | grep "Mask" | awk '{print $4}' | awk -F ":" '{print $2}') +IPADDR1_MASK=$(ifconfig eth1 | grep "Mask" | awk '{print $4}' | awk -F ":" '{print $2}') IPADDR1_CIDR=$(mask2cidr $IPADDR1_MASK) # 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) +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"') VLB_IPADDR=$(cat /opt/config/vlb_ipaddr.txt) +VLB_MAC=$(cat /opt/config/vlb_mac.txt) GW=$(route -n | grep "^0.0.0.0" | awk '{print $2}') -ifconfig eth0 down -ifconfig eth0 hw ether $FAKE_HWADDR1 -ip addr flush dev eth0 -ifconfig eth0 up +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"/"$IPADDR1_CIDR vppctl set int state tap-0 up brctl addbr br0 brctl addif br0 tap111 -brctl addif br0 eth0 +brctl addif br0 eth1 ifconfig br0 up vppctl ip route add 0.0.0.0/0 via $GW sleep 1 - # 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 $IPADDR1_MASK 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 is in our network, we will use its MAC -if [ ! -z "$VLB_MAC" ] -then - vppctl set ip arp tap-0 $VLB_IPADDR $VLB_MAC -fi - -# Add arp entry for default GW -vppctl set ip arp tap-0 $GW $GW_MAC +sleep 1 +vppctl set ip arp tap-0 $VLB_IPADDR $VLB_MAC # Install packet streams sed -i -e "0,/UDP/ s/UDP:.*/UDP: "$IPADDR1" -> "$VLB_IPADDR"/" /opt/dns_streams/stream_dns1 @@ -104,17 +90,11 @@ 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 -VERSION=$(cat /opt/config/demo_artifacts_version.txt) -echo "" > /var/lib/honeycomb/persist/context/data.json -echo "" > /var/lib/honeycomb/persist/config/data.json -/opt/honeycomb/sample-distribution-$VERSION/honeycomb &>/dev/null &disown -sleep 20 +vppctl set int ip address pg0 $(cat /opt/config/pg_int.txt)"/"$IPADDR1_CIDR +sleep 1 # Enable traffic flows cd /opt chmod +x run_streams_dns.sh -./run_streams_dns.sh &>/dev/null &disown - +./run_streams_dns.sh &>/dev/null &disown
\ No newline at end of file diff --git a/vnfs/vLB/scripts/v_packetgen_install.sh b/vnfs/vLB/scripts/v_packetgen_install.sh index 2a2d7a24..ca2957a7 100644 --- a/vnfs/vLB/scripts/v_packetgen_install.sh +++ b/vnfs/vLB/scripts/v_packetgen_install.sh @@ -6,6 +6,14 @@ DEMO_ARTIFACTS_VERSION=$(cat /opt/config/demo_artifacts_version.txt) INSTALL_SCRIPT_VERSION=$(cat /opt/config/install_script_version.txt) CLOUD_ENV=$(cat /opt/config/cloud_env.txt) +# Convert Network CIDR to Netmask +cdr2mask () { + # Number of args to shift, 255..255, first non-255 byte, zeroes + set -- $(( 5 - ($1 / 8) )) 255 255 255 255 $(( (255 << (8 - ($1 % 8))) & 255 )) 0 0 0 + [ $1 -gt 1 ] && shift $1 || shift + echo ${1-0}.${2-0}.${3-0}.${4-0} +} + # OpenStack network configuration if [[ $CLOUD_ENV == "openstack" ]] then @@ -14,40 +22,54 @@ then # Allow remote login as root mv /root/.ssh/authorized_keys /root/.ssh/authorized_keys.bk cp /home/ubuntu/.ssh/authorized_keys /root/.ssh + + MTU=$(/sbin/ifconfig | grep MTU | sed 's/.*MTU://' | sed 's/ .*//' | sort -n | head -1) + + IP=$(cat /opt/config/local_private_ipaddr.txt) + BITS=$(cat /opt/config/pktgen_private_net_cidr.txt | cut -d"/" -f2) + NETMASK=$(cdr2mask $BITS) + echo "auto eth1" >> /etc/network/interfaces + echo "iface eth1 inet static" >> /etc/network/interfaces + echo " address $IP" >> /etc/network/interfaces + echo " netmask $NETMASK" >> /etc/network/interfaces + echo " mtu $MTU" >> /etc/network/interfaces + + IP=$(cat /opt/config/oam_private_ipaddr.txt) + BITS=$(cat /opt/config/onap_private_net_cidr.txt | cut -d"/" -f2) + NETMASK=$(cdr2mask $BITS) + echo "auto eth2" >> /etc/network/interfaces + echo "iface eth2 inet static" >> /etc/network/interfaces + echo " address $IP" >> /etc/network/interfaces + echo " netmask $NETMASK" >> /etc/network/interfaces + echo " mtu $MTU" >> /etc/network/interfaces fi # Download required dependencies -add-apt-repository -y ppa:openjdk-r/ppa +echo "deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list +echo "deb-src http://ppa.launchpad.net/openjdk-r/ppa/ubuntu $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/java.list apt-get update -apt-get install -y make wget openjdk-8-jdk gcc libcurl4-openssl-dev python-pip bridge-utils apt-transport-https ca-certificates +apt-get install --allow-unauthenticated -y make wget openjdk-8-jdk gcc libcurl4-openssl-dev python-pip bridge-utils apt-transport-https ca-certificates pip install jsonschema # Download vFirewall demo code for packet generator -mkdir /opt/config -mkdir /opt/honeycomb cd /opt -wget $REPO_URL_BLOB/org.onap.demo/vnfs/vlb/$INSTALL_SCRIPT_VERSION/v_packetgen_for_dns_demo_init.sh -wget $REPO_URL_BLOB/org.onap.demo/vnfs/vlb/$INSTALL_SCRIPT_VERSION/vpacketgenfordnsdemo.sh +wget $REPO_URL_BLOB/org.onap.demo/vnfs/vlb/$INSTALL_SCRIPT_VERSION/v_packetgen_init.sh +wget $REPO_URL_BLOB/org.onap.demo/vnfs/vlb/$INSTALL_SCRIPT_VERSION/vpacketgen.sh wget $REPO_URL_BLOB/org.onap.demo/vnfs/vlb/$INSTALL_SCRIPT_VERSION/run_streams_dns.sh wget $REPO_URL_BLOB/org.onap.demo/vnfs/vlb/$INSTALL_SCRIPT_VERSION/vdnspacketgen_change_streams_ports.sh -wget $REPO_URL_ARTIFACTS/org/onap/demo/vnf/sample-distribution/$DEMO_ARTIFACTS_VERSION/sample-distribution-$DEMO_ARTIFACTS_VERSION-hc.tar.gz wget $REPO_URL_ARTIFACTS/org/onap/demo/vnf/vlb/vlb_dns_streams/$DEMO_ARTIFACTS_VERSION/vlb_dns_streams-$DEMO_ARTIFACTS_VERSION-demo.tar.gz -tar -zxvf vpp.tar.gz -tar -zxvf sample-distribution-$DEMO_ARTIFACTS_VERSION-hc.tar.gz -mv sample-distribution-$DEMO_ARTIFACTS_VERSION honeycomb -sed -i 's/"restconf-binding-address": "127.0.0.1",/"restconf-binding-address": "0.0.0.0",/g' honeycomb/sample-distribution-$DEMO_ARTIFACTS_VERSION/config/honeycomb.json -tar -zxvf vlb_dns_streams-$DEMO_ARTIFACTS_VERSION-demo.tar.gz +tar -zmxvf vlb_dns_streams-$DEMO_ARTIFACTS_VERSION-demo.tar.gz mv vlb_dns_streams-$DEMO_ARTIFACTS_VERSION dns_streams rm *.tar.gz -chmod +x v_packetgen_for_dns_demo_init.sh -chmod +x vpacketgenfordnsdemo.sh +chmod +x v_packetgen_init.sh +chmod +x vpacketgen.sh chmod +x run_streams_dns.sh chmod +x vdnspacketgen_change_streams_ports.sh # Install VPP -export UBUNTU="trusty" -export RELEASE=".stable.1609" +export UBUNTU="xenial" +export RELEASE=".stable.1707" rm /etc/apt/sources.list.d/99fd.io.list echo "deb [trusted=yes] https://nexus.fd.io/content/repositories/fd.io$RELEASE.ubuntu.$UBUNTU.main/ ./" | sudo tee -a /etc/apt/sources.list.d/99fd.io.list apt-get update @@ -56,6 +78,22 @@ sleep 1 # Run instantiation script cd /opt -mv vpacketgenfordnsdemo.sh /etc/init.d -update-rc.d vpacketgenfordnsdemo.sh defaults -./v_packetgen_for_dns_demo_init.sh +mv vpacketgen.sh /etc/init.d +update-rc.d vpacketgen.sh defaults + +# Rename network interface in openstack Ubuntu 16.04 images. Then, reboot the VM to pick up changes +if [[ $CLOUD_ENV != "rackspace" ]] +then + sed -i "s/GRUB_CMDLINE_LINUX=.*/GRUB_CMDLINE_LINUX=\"net.ifnames=0 biosdevname=0\"/g" /etc/default/grub + grub-mkconfig -o /boot/grub/grub.cfg + sed -i "s/ens[0-9]*/eth0/g" /etc/network/interfaces.d/*.cfg + sed -i "s/ens[0-9]*/eth0/g" /etc/udev/rules.d/70-persistent-net.rules + echo 'network: {config: disabled}' >> /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg + echo "APT::Periodic::Unattended-Upgrade \"0\";" >> /etc/apt/apt.conf.d/10periodic + reboot +fi + +# Install a cron job that restart streams every minute. This allows to map streams to different vDNSs when we scale out the VNF +echo "* * * * * /opt/vdnspacketgen_change_streams_ports.sh" | crontab + +./v_packetgen_init.sh diff --git a/vnfs/vLB/scripts/vdnspacketgen_change_streams_ports.sh b/vnfs/vLB/scripts/vdnspacketgen_change_streams_ports.sh index 9bd77162..e4723880 100644 --- a/vnfs/vLB/scripts/vdnspacketgen_change_streams_ports.sh +++ b/vnfs/vLB/scripts/vdnspacketgen_change_streams_ports.sh @@ -1,7 +1,7 @@ #!/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" +#Disable all streams +killall -9 run_streams_dns.sh vppctl pac del dns1 vppctl pac del dns2 @@ -14,10 +14,9 @@ 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) +IPADDR1=$(cat /opt/config/local_private_ipaddr.txt) 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 @@ -50,4 +49,8 @@ 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 +vppctl exec /opt/dns_streams/stream_dns10 + +#Resume stream execution +cd /opt +./run_streams_dns.sh &>/dev/null &disown
\ No newline at end of file diff --git a/vnfs/vLB/scripts/vpacketgenfordnsdemo.sh b/vnfs/vLB/scripts/vpacketgen.sh index 427e5337..1d00fd9c 100644 --- a/vnfs/vLB/scripts/vpacketgenfordnsdemo.sh +++ b/vnfs/vLB/scripts/vpacketgen.sh @@ -10,7 +10,7 @@ ### END INIT INFO dir="/opt" -cmd="./v_packetgen_for_dns_demo_init.sh" +cmd="./v_packetgen_init.sh" user="root" name=`basename $0` |