From 36424f46ff5543c2ae475c60bb3e08f299c55799 Mon Sep 17 00:00:00 2001 From: Ed Warnicke Date: Sun, 10 Jan 2016 06:15:18 -0800 Subject: Initial honeycomb code commit. This commit drops the basic structure with disabled integration tests. The tests will be enabled in a follow-up patch, which sorts out the current .so loading problems. Change-Id: If70f2f13b2cf49af82996f884218ac05d335c2ed Signed-off-by: Ed Warnicke Signed-off-by: Robert Varga --- .gitignore | 15 + .gitreview | 4 + NOTES.txt | 141 ++++ common/api-parent/pom.xml | 58 ++ common/features-parent/pom.xml | 57 ++ .../features-parent/src/main/features/features.xml | 16 + common/impl-parent/pom.xml | 63 ++ common/it-parent/pom.xml | 60 ++ common/karaf-parent/pom.xml | 57 ++ common/pom.xml | 54 ++ pom.xml | 51 ++ v3po/api/pom.xml | 64 ++ v3po/api/src/main/yang/ietf-ip.yang | 742 +++++++++++++++++++++ v3po/api/src/main/yang/v3po.yang | 366 ++++++++++ v3po/artifacts/pom.xml | 46 ++ v3po/features/pom.xml | 135 ++++ v3po/features/src/main/features/features.xml | 54 ++ v3po/impl/pom.xml | 57 ++ v3po/impl/src/main/config/default-config.xml | 37 + .../io/fd/honeycomb/v3po/impl/DataRegistry.java | 24 + .../io/fd/honeycomb/v3po/impl/DataResolver.java | 26 + .../v3po/impl/DataResolverInterfaceState.java | 36 + .../v3po/impl/InterfaceStateIpv4Builder.java | 94 +++ .../v3po/impl/InterfaceStateIpv6Builder.java | 87 +++ .../v3po/impl/LoggingFuturesCallBack.java | 48 ++ .../io/fd/honeycomb/v3po/impl/V3poApiRequest.java | 461 +++++++++++++ .../io/fd/honeycomb/v3po/impl/V3poProvider.java | 326 +++++++++ .../io/fd/honeycomb/v3po/impl/V3poRequest.java | 28 + .../v3po/impl/VppBridgeDomainListener.java | 217 ++++++ .../v3po/impl/VppIetfInterfaceListener.java | 566 ++++++++++++++++ .../honeycomb/v3po/impl/VppPollOperDataImpl.java | 147 ++++ .../v3po/impl/VppStateBridgeDomainBuilder.java | 102 +++ .../honeycomb/v3po/impl/VppStateCustomBuilder.java | 73 ++ .../ns/yang/v3po/impl/rev141210/V3poModule.java | 41 ++ .../v3po/impl/rev141210/V3poModuleFactory.java | 28 + v3po/impl/src/main/yang/v3po-impl.yang | 35 + .../v3po/impl/rev141210/V3poModuleFactoryTest.java | 26 + .../yang/v3po/impl/rev141210/V3poModuleTest.java | 62 ++ v3po/it/pom.xml | 48 ++ .../test/java/io/fd/honeycomb/v3po/it/V3poIT.java | 77 +++ v3po/karaf/pom.xml | 71 ++ v3po/pom.xml | 60 ++ 42 files changed, 4760 insertions(+) create mode 100644 .gitignore create mode 100644 .gitreview create mode 100644 NOTES.txt create mode 100644 common/api-parent/pom.xml create mode 100644 common/features-parent/pom.xml create mode 100644 common/features-parent/src/main/features/features.xml create mode 100644 common/impl-parent/pom.xml create mode 100644 common/it-parent/pom.xml create mode 100644 common/karaf-parent/pom.xml create mode 100644 common/pom.xml create mode 100644 pom.xml create mode 100644 v3po/api/pom.xml create mode 100644 v3po/api/src/main/yang/ietf-ip.yang create mode 100644 v3po/api/src/main/yang/v3po.yang create mode 100644 v3po/artifacts/pom.xml create mode 100644 v3po/features/pom.xml create mode 100644 v3po/features/src/main/features/features.xml create mode 100644 v3po/impl/pom.xml create mode 100644 v3po/impl/src/main/config/default-config.xml create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/DataRegistry.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/DataResolver.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/DataResolverInterfaceState.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/InterfaceStateIpv4Builder.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/InterfaceStateIpv6Builder.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/LoggingFuturesCallBack.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poApiRequest.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poProvider.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poRequest.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppBridgeDomainListener.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppIetfInterfaceListener.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppPollOperDataImpl.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppStateBridgeDomainBuilder.java create mode 100644 v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppStateCustomBuilder.java create mode 100644 v3po/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModule.java create mode 100644 v3po/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactory.java create mode 100644 v3po/impl/src/main/yang/v3po-impl.yang create mode 100644 v3po/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactoryTest.java create mode 100644 v3po/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleTest.java create mode 100644 v3po/it/pom.xml create mode 100644 v3po/it/src/test/java/io/fd/honeycomb/v3po/it/V3poIT.java create mode 100644 v3po/karaf/pom.xml create mode 100644 v3po/pom.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..f7e7ccac7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*~ +.classpath +.project +.settings +target +*.iml +.idea +bin +xtend-gen +yang-gen-config +yang-gen-sal +target +.DS_Store +META-INF +maven-metadata-local.xml diff --git a/.gitreview b/.gitreview new file mode 100644 index 000000000..b9a899ed4 --- /dev/null +++ b/.gitreview @@ -0,0 +1,4 @@ +[gerrit] +host=gerrit.fd.io +port=29418 +project=honeycomb diff --git a/NOTES.txt b/NOTES.txt new file mode 100644 index 000000000..92f7d9c35 --- /dev/null +++ b/NOTES.txt @@ -0,0 +1,141 @@ + ODL Honeycomb Development Notes + =============================== +Links +===== +1) Ed's ODL Summit 2015 Honeycomb Application Development Tuturial +https://wiki.opendaylight.org/view/Controller_Core_Functionality_Tutorials:Application_Development_Tutorial +https://github.com/flavio-fernandes/odlHelloTutorial + +2) Maven +http://maven.apache.org/install.html +https://maven.apache.org/guides/mini/guide-proxies.html +https://maven.apache.org/ref/3.3.3/maven-settings/settings.html +https://maven.apache.org/guides/mini/guide-configuring-maven.html +http://maven.apache.org/plugins/maven-install-plugin/install-file-mojo.html +https://maven.apache.org/guides/mini/guide-3rd-party-jars-local.html + +3) OpenDayLight +https://wiki.opendaylight.org/view/GIT_Cheat_Sheet +https://www.opendaylight.org/project-lifecycle-releases +https://wiki.opendaylight.org/view/CrossProject:Integration_Group:System_Test:Step_by_Step_Guide +https://wiki.opendaylight.org/view/Simultaneous_Release:Beryllium_Release_Plan +https://wiki.opendaylight.org/view/OpenDaylight_Presentations:Main +https://wiki.opendaylight.org/view/YANG_Tools:YANG_to_Java_Mapping +https://github.com/opendaylight/mdsal/tree/master/model // IETF Yang Models +https://github.com/opendaylight/ovsdb/blob/master/southbound/southbound-api/pom.xml#L78 // for 2013-07-15 version of ietf-yang-types +https://github.com/opendaylight/ovsdb/blob/master/southbound/southbound-api/pom.xml#L54 // for mdsal.model +// Data Change Listener examples +https://github.com/opendaylight/vtn/blob/master/manager/neutron/src/main/java/org/opendaylight/vtn/manager/neutron/NeutronNetworkChangeListener.java +https://github.com/opendaylight/ovsdb/blob/master/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/OvsdbDataChangeListener.java +https://github.com/opendaylight/vpnservice/blob/078ae023c9cceb14aaadea10c81a5f1d90f47789/interfacemgr/interfacemgr-impl/src/main/java/org/opendaylight/vpnservice/interfacemgr/InterfaceManager.java + +Installation/Environment +======================== +1) Packages to install + apache-maven-3.3.3 (https://wiki.opendaylight.org/view/Install_On_Ubuntu_14.04) + openjdk-7-jdk + libssl-dev + eclipse + +2) Environment Variables: + export ODL_USERNAME=dwallace + export M2_HOME=/usr/local/apache-maven/apache-maven-3.3.3 + export PATH=/usr/local/apache-maven/apache-maven-3.3.3/bin:$PATH + export MAVEN_OPTS='-Xmx4096m -XX:MaxPermSize=2048m' + export JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64 + export PATH=$JAVA_HOME/bin:$PATH + +Building/Installing ODL +======================= + +How-To's +======== +1) Build ODL + - cd honeycomb/ + - mvn clean install + +4) Start up ODL + - cd honeycomb/v3po/karaf/target/assembly/bin + - sudo bash + - ./karaf + Note: use "./karaf debug" to enable remote debugging. + Note: DON'T USE CTRL-D to quit. That fails to clean up gracefully. + Best practice is to use "shutdown -f". + Note: Building will run karaf which will fail if another instance + is already running. It also touches/creates files in + v3po/karaf... See #5 below for clean up recipe. + +5) Testing with YANGUI + - DOESN'T WORK WITH FIREFOX! :-( + - Install google chrome. + - Start chrome and enter the URL: + http://localhost:8080/index.html#/yangui/index + - Select "Yang UI" on left region + - Expand (click on '+') v3po rev.2015.01.05 + - Expand (click on '+') operations + - Enter text ("Dave") in textbox next to "me" + - Select "Send" + - Results show up in "version" textbox: + "Yo Dave! VPP interface list is [GigabitEthernet8/0/1: 5, + TenGigabitEthernet86/0/0: 6, local0: 0]!" + +6) Pre-build clean up + - Running karaf as root touches files which will break the build. + Do the following to clean up before building: + + shutdown -f + sudo chown -R dwallace:floppy /scratch/dwallace/honeycomb-vpp/v3po/karaf + +7) Adding YANG models + NOTE: pom.xml dependency versions are managed via + specifications. When including + standard yang models (e.g. from org.opendaylight.mdsal.model), there + needs to be a depencency defined to tell + maven what version to download into the local repo. This isw + why each dependency in the section does not + contain version information. + - Add a dependency in .../honeycomb/v3po/api/pom.xml + - Add a dependency in .../honeycomb/v3po/features/pom.xml + - Add a bundle in ../honeycomb/v3po/features/pom.xml + NOTE: Yangtools don't unravel nested import statements, so all + imported yang models referenced in v3po.yang must be + explicitly imported (e.g. ietf-interfaces) + +8) Useful CURL commands for debugging netconf mounts +# show mounted nodes +curl -su admin:admin http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes?prettyPrint=true;echo + +# show node configuration +curl -su admin:admin http://localhost:8181/restconf/config/network-topology:network-topology/topology/topology-netconf/node/controller-config/yang-ext:mount/config:modules/module/odl-sal-netconf-connector-cfg:sal-netconf-connector/?prettyPrint=true;echo +curl -su admin:admin http://localhost:8181/restconf/config/network-topology:network-topology/topology/topology-netconf/node/controller-config/yang-ext:mount/config:modules/module/odl-sal-netconf-connector-cfg:sal-netconf-connector/controller-config?prettyPrint=true;echo +curl -su admin:admin http://localhost:8181/restconf/config/network-topology:network-topology/topology/topology-netconf/node/controller-config/yang-ext:mount/config:modules/module/odl-sal-netconf-connector-cfg:sal-netconf-connector/vpp1?prettyPrint=true;echo +curl -su admin:admin http://localhost:8181/restconf/config/network-topology:network-topology/topology/topology-netconf/node/controller-config/yang-ext:mount/config:modules/module/odl-sal-netconf-connector-cfg:sal-netconf-connector/vpp2?prettyPrint=true;echo + +# show node connection status +curl -su admin:admin http://localhost:8181/restconf/operational/network-topology:network-topology/topology/topology-netconf/node/?prettyPrint=true;echo +curl -su admin:admin http://localhost:8181/restconf/operational/network-topology:network-topology/topology/topology-netconf/node/controller-config?prettyPrint=true;echo +curl -su admin:admin http://localhost:8181/restconf/operational/network-topology:network-topology/topology/topology-netconf/node/vpp1?prettyPrint=true;echo +curl -su admin:admin http://localhost:8181/restconf/operational/network-topology:network-topology/topology/topology-netconf/node/vpp2?prettyPrint=true;echo + +# show mount config modules +curl -su admin:admin http://localhost:8181/restconf/config/network-topology:network-topology/topology/topology-netconf/node//yang-ext:mount/?prettyPrint=true;echo +curl -su admin:admin http://localhost:8181/restconf/config/network-topology:network-topology/topology/topology-netconf/node/controller-config/yang-ext:mount/?prettyPrint=true;echo +curl -su admin:admin http://localhost:8181/restconf/config/network-topology:network-topology/topology/topology-netconf/node/vpp1/yang-ext:mount/?prettyPrint=true;echo +curl -su admin:admin http://localhost:8181/restconf/config/network-topology:network-topology/topology/topology-netconf/node/vpp2/yang-ext:mount/?prettyPrint=true;echo + +# show mount config modules +curl -su admin:admin -H 'Accept: application/xml' -H 'Content-Type: application/xml' http://localhost:8181/restconf/config/network-topology:network-topology/topology/topology-netconf/node//yang-ext:mount/?prettyPrint=true;echo +curl -su admin:admin -H 'Accept: application/xml' -H 'Content-Type: application/xml' http://localhost:8181/restconf/config/network-topology:network-topology/topology/topology-netconf/node/controller-config/yang-ext:mount/?prettyPrint=true;echo +curl -su admin:admin -H 'Accept: application/xml' -H 'Content-Type: application/xml' http://localhost:8181/restconf/config/network-topology:network-topology/topology/topology-netconf/node/vpp1/yang-ext:mount/?prettyPrint=true;echo +curl -su admin:admin -H 'Accept: application/xml' -H 'Content-Type: application/xml' http://localhost:8181/restconf/config/network-topology:network-topology/topology/topology-netconf/node/vpp2/yang-ext:mount/?prettyPrint=true;echo + +# show mount operational modules +curl -su admin:admin http://localhost:8181/restconf/operational/network-topology:network-topology/topology/topology-netconf/node//yang-ext:mount/?prettyPrint=true;echo +curl -su admin:admin http://localhost:8181/restconf/operational/network-topology:network-topology/topology/topology-netconf/node/controller-config/yang-ext:mount/?prettyPrint=true;echo +curl -su admin:admin http://localhost:8181/restconf/operational/network-topology:network-topology/topology/topology-netconf/node/vpp1/yang-ext:mount/?prettyPrint=true;echo +curl -su admin:admin http://localhost:8181/restconf/operational/network-topology:network-topology/topology/topology-netconf/node/vpp2/yang-ext:mount/?prettyPrint=true;echo + +9) Clean up ODL cache/state +cd /scratch/dwallace/honeycomb-demo/r2demo/karaf/target/assembly/bin +sudo rm -rf ../data/* +sudo rm -f ../etc/opendaylight/current/* diff --git a/common/api-parent/pom.xml b/common/api-parent/pom.xml new file mode 100644 index 000000000..76c2aafe7 --- /dev/null +++ b/common/api-parent/pom.xml @@ -0,0 +1,58 @@ + + + + + org.opendaylight.mdsal + binding-parent + 0.8.0-SNAPSHOT + + + + 4.0.0 + io.fd.honeycomb.common + api-parent + 1.0.0-SNAPSHOT + pom + + + + maven-checkstyle-plugin + ${checkstyle.version} + + + check-license + + check + + none + + + + + org.apache.maven.plugins + maven-dependency-plugin + 2.10 + + + unpack-license + none + unpack + + + + + + diff --git a/common/features-parent/pom.xml b/common/features-parent/pom.xml new file mode 100644 index 000000000..a3dac7341 --- /dev/null +++ b/common/features-parent/pom.xml @@ -0,0 +1,57 @@ + + + + + org.opendaylight.odlparent + features-parent + 1.6.0-SNAPSHOT + + + io.fd.honeycomb.common + features-parent + 1.0.0-SNAPSHOT + 4.0.0 + pom + + + + maven-checkstyle-plugin + ${checkstyle.version} + + + check-license + + check + + none + + + + + org.apache.maven.plugins + maven-dependency-plugin + 2.10 + + + unpack-license + none + unpack + + + + + + diff --git a/common/features-parent/src/main/features/features.xml b/common/features-parent/src/main/features/features.xml new file mode 100644 index 000000000..7d78e78a0 --- /dev/null +++ b/common/features-parent/src/main/features/features.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/common/impl-parent/pom.xml b/common/impl-parent/pom.xml new file mode 100644 index 000000000..ac17c8a34 --- /dev/null +++ b/common/impl-parent/pom.xml @@ -0,0 +1,63 @@ + + + + + + + org.opendaylight.controller + config-parent + 0.4.0-SNAPSHOT + + + + 4.0.0 + io.fd.honeycomb.common + impl-parent + 1.0.0-SNAPSHOT + pom + + APACHE_HEADER.txt + + + + + maven-checkstyle-plugin + ${checkstyle.version} + + + check-license + + check + + none + + + + + org.apache.maven.plugins + maven-dependency-plugin + 2.10 + + + unpack-license + none + unpack + + + + + + diff --git a/common/it-parent/pom.xml b/common/it-parent/pom.xml new file mode 100644 index 000000000..9272cc4a8 --- /dev/null +++ b/common/it-parent/pom.xml @@ -0,0 +1,60 @@ + + + + + + + org.opendaylight.controller + mdsal-it-parent + 1.3.0-SNAPSHOT + + + + 4.0.0 + io.fd.honeycomb.common + it-parent + 1.0.0-SNAPSHOT + pom + + + + maven-checkstyle-plugin + ${checkstyle.version} + + + check-license + + check + + none + + + + + org.apache.maven.plugins + maven-dependency-plugin + 2.10 + + + unpack-license + none + unpack + + + + + + diff --git a/common/karaf-parent/pom.xml b/common/karaf-parent/pom.xml new file mode 100644 index 000000000..253dc361b --- /dev/null +++ b/common/karaf-parent/pom.xml @@ -0,0 +1,57 @@ + + + + + org.opendaylight.controller + karaf-parent + 1.6.0-SNAPSHOT + + + 4.0.0 + io.fd.honeycomb.common + karaf-parent + 1.0.0-SNAPSHOT + pom + + + + maven-checkstyle-plugin + ${checkstyle.version} + + + check-license + + check + + none + + + + + org.apache.maven.plugins + maven-dependency-plugin + 2.10 + + + unpack-license + none + unpack + + + + + + diff --git a/common/pom.xml b/common/pom.xml new file mode 100644 index 000000000..ad9f382ee --- /dev/null +++ b/common/pom.xml @@ -0,0 +1,54 @@ + + + + +io.fd.honeycomb.common + honeycomb-common-aggregator + 1.0.0-SNAPSHOT + honeycomb + pom + 4.0.0 + + 3.1.1 + + + api-parent + features-parent + impl-parent + it-parent + karaf-parent + + + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + org.apache.maven.plugins + maven-install-plugin + + true + + + + + + diff --git a/pom.xml b/pom.xml new file mode 100644 index 000000000..15fd690df --- /dev/null +++ b/pom.xml @@ -0,0 +1,51 @@ + + + + +io.fd.honeycomb + honeycomb-aggregator + 1.0.0-SNAPSHOT + honeycomb + pom + 4.0.0 + + 3.1.1 + + + common + v3po + + + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + org.apache.maven.plugins + maven-install-plugin + + true + + + + + + diff --git a/v3po/api/pom.xml b/v3po/api/pom.xml new file mode 100644 index 000000000..e31deea1f --- /dev/null +++ b/v3po/api/pom.xml @@ -0,0 +1,64 @@ + + + + + io.fd.honeycomb.common + api-parent + 1.0.0-SNAPSHOT + ../../common/api-parent + + + 4.0.0 + io.fd.honeycomb.v3po + v3po-api + 1.0.0-SNAPSHOT + bundle + + + + + org.opendaylight.mdsal.model + mdsal-model-artifacts + 0.8.0-SNAPSHOT + pom + import + + + + + + + org.opendaylight.mdsal.model + iana-if-type-2014-05-08 + + + org.opendaylight.mdsal.model + ietf-yang-types-20130715 + + + org.opendaylight.mdsal.model + ietf-interfaces + + + org.opendaylight.mdsal.model + ietf-inet-types-2013-07-15 + + + org.opendaylight.mdsal.model + yang-ext + + + diff --git a/v3po/api/src/main/yang/ietf-ip.yang b/v3po/api/src/main/yang/ietf-ip.yang new file mode 100644 index 000000000..f6c59edea --- /dev/null +++ b/v3po/api/src/main/yang/ietf-ip.yang @@ -0,0 +1,742 @@ +module ietf-ip { + + yang-version 1; + + namespace + "urn:ietf:params:xml:ns:yang:ietf-ip"; + + prefix ip; + + import ietf-interfaces { + prefix if; + } + import ietf-inet-types { + prefix inet; + } + import ietf-yang-types { + prefix yang; + } + + organization + "IETF NETMOD (NETCONF Data Modeling Language) Working Group"; + + contact + "WG Web: + WG List: + + WG Chair: Thomas Nadeau + + + WG Chair: Juergen Schoenwaelder + + + Editor: Martin Bjorklund + "; + + description + "This module contains a collection of YANG definitions for + configuring IP implementations. + + Copyright (c) 2014 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 7277; see + the RFC itself for full legal notices."; + + revision "2014-06-16" { + description "Initial revision."; + reference + "RFC 7277: A YANG Data Model for IP Management"; + + } + + + feature ipv4-non-contiguous-netmasks { + description + "Indicates support for configuring non-contiguous + subnet masks."; + } + + feature ipv6-privacy-autoconf { + description + "Indicates support for Privacy Extensions for Stateless Address + Autoconfiguration in IPv6."; + reference + "RFC 4941: Privacy Extensions for Stateless Address + Autoconfiguration in IPv6"; + + } + + typedef ip-address-origin { + type enumeration { + enum "other" { + value 0; + description + "None of the following."; + } + enum "static" { + value 1; + description + "Indicates that the address has been statically + configured - for example, using NETCONF or a Command Line + Interface."; + } + enum "dhcp" { + value 2; + description + "Indicates an address that has been assigned to this + system by a DHCP server."; + } + enum "link-layer" { + value 3; + description + "Indicates an address created by IPv6 stateless + autoconfiguration that embeds a link-layer address in its + interface identifier."; + } + enum "random" { + value 4; + description + "Indicates an address chosen by the system at + + random, e.g., an IPv4 address within 169.254/16, an + RFC 4941 temporary address, or an RFC 7217 semantically + opaque address."; + reference + "RFC 4941: Privacy Extensions for Stateless Address + Autoconfiguration in IPv6 + RFC 7217: A Method for Generating Semantically Opaque + Interface Identifiers with IPv6 Stateless + Address Autoconfiguration (SLAAC)"; + + } + } + description + "The origin of an address."; + } + + typedef neighbor-origin { + type enumeration { + enum "other" { + value 0; + description + "None of the following."; + } + enum "static" { + value 1; + description + "Indicates that the mapping has been statically + configured - for example, using NETCONF or a Command Line + Interface."; + } + enum "dynamic" { + value 2; + description + "Indicates that the mapping has been dynamically resolved + using, e.g., IPv4 ARP or the IPv6 Neighbor Discovery + protocol."; + } + } + description + "The origin of a neighbor entry."; + } + + augment /if:interfaces/if:interface { + description + "Parameters for configuring IP on interfaces. + + If an interface is not capable of running IP, the server + must not allow the client to configure these parameters."; + container ipv4 { + presence + "Enables IPv4 unless the 'enabled' leaf + (which defaults to 'true') is set to 'false'"; + description + "Parameters for the IPv4 address family."; + leaf enabled { + type boolean; + default 'true'; + description + "Controls whether IPv4 is enabled or disabled on this + interface. When IPv4 is enabled, this interface is + connected to an IPv4 stack, and the interface can send + and receive IPv4 packets."; + } + + leaf forwarding { + type boolean; + default 'false'; + description + "Controls IPv4 packet forwarding of datagrams received by, + but not addressed to, this interface. IPv4 routers + forward datagrams. IPv4 hosts do not (except those + source-routed via the host)."; + } + + leaf mtu { + type uint16 { + range "68..max"; + } + units "octets"; + description + "The size, in octets, of the largest IPv4 packet that the + interface will send and receive. + + The server may restrict the allowed values for this leaf, + depending on the interface's type. + + If this leaf is not configured, the operationally used MTU + depends on the interface's type."; + reference + "RFC 791: Internet Protocol"; + + } + + list address { + key "ip"; + description + "The list of configured IPv4 addresses on the interface."; + leaf ip { + type inet:ipv4-address-no-zone; + description + "The IPv4 address on the interface."; + } + + choice subnet { + mandatory true; + description + "The subnet can be specified as a prefix-length, or, + if the server supports non-contiguous netmasks, as + a netmask."; + leaf prefix-length { + type uint8 { + range "0..32"; + } + description + "The length of the subnet prefix."; + } + leaf netmask { + if-feature ipv4-non-contiguous-netmasks; + type yang:dotted-quad; + description + "The subnet specified as a netmask."; + } + } // choice subnet + } // list address + + list neighbor { + key "ip"; + description + "A list of mappings from IPv4 addresses to + link-layer addresses. + + Entries in this list are used as static entries in the + ARP Cache."; + reference + "RFC 826: An Ethernet Address Resolution Protocol"; + + leaf ip { + type inet:ipv4-address-no-zone; + description + "The IPv4 address of the neighbor node."; + } + + leaf link-layer-address { + type yang:phys-address; + mandatory true; + description + "The link-layer address of the neighbor node."; + } + } // list neighbor + } // container ipv4 + + container ipv6 { + presence + "Enables IPv6 unless the 'enabled' leaf + (which defaults to 'true') is set to 'false'"; + description + "Parameters for the IPv6 address family."; + leaf enabled { + type boolean; + default 'true'; + description + "Controls whether IPv6 is enabled or disabled on this + interface. When IPv6 is enabled, this interface is + connected to an IPv6 stack, and the interface can send + and receive IPv6 packets."; + } + + leaf forwarding { + type boolean; + default 'false'; + description + "Controls IPv6 packet forwarding of datagrams received by, + but not addressed to, this interface. IPv6 routers + forward datagrams. IPv6 hosts do not (except those + source-routed via the host)."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 (IPv6) + Section 6.2.1, IsRouter"; + + } + + leaf mtu { + type uint32 { + range "1280..max"; + } + units "octets"; + description + "The size, in octets, of the largest IPv6 packet that the + interface will send and receive. + + The server may restrict the allowed values for this leaf, + depending on the interface's type. + + If this leaf is not configured, the operationally used MTU + depends on the interface's type."; + reference + "RFC 2460: Internet Protocol, Version 6 (IPv6) Specification + Section 5"; + + } + + list address { + key "ip"; + description + "The list of configured IPv6 addresses on the interface."; + leaf ip { + type inet:ipv6-address-no-zone; + description + "The IPv6 address on the interface."; + } + + leaf prefix-length { + type uint8 { + range "0..128"; + } + mandatory true; + description + "The length of the subnet prefix."; + } + } // list address + + list neighbor { + key "ip"; + description + "A list of mappings from IPv6 addresses to + link-layer addresses. + + Entries in this list are used as static entries in the + Neighbor Cache."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 (IPv6)"; + + leaf ip { + type inet:ipv6-address-no-zone; + description + "The IPv6 address of the neighbor node."; + } + + leaf link-layer-address { + type yang:phys-address; + mandatory true; + description + "The link-layer address of the neighbor node."; + } + } // list neighbor + + leaf dup-addr-detect-transmits { + type uint32; + default '1'; + description + "The number of consecutive Neighbor Solicitation messages + sent while performing Duplicate Address Detection on a + tentative address. A value of zero indicates that + Duplicate Address Detection is not performed on + tentative addresses. A value of one indicates a single + transmission with no follow-up retransmissions."; + reference + "RFC 4862: IPv6 Stateless Address Autoconfiguration"; + + } + + container autoconf { + description + "Parameters to control the autoconfiguration of IPv6 + addresses, as described in RFC 4862."; + reference + "RFC 4862: IPv6 Stateless Address Autoconfiguration"; + + leaf create-global-addresses { + type boolean; + default 'true'; + description + "If enabled, the host creates global addresses as + described in RFC 4862."; + reference + "RFC 4862: IPv6 Stateless Address Autoconfiguration + Section 5.5"; + + } + + leaf create-temporary-addresses { + if-feature ipv6-privacy-autoconf; + type boolean; + default 'false'; + description + "If enabled, the host creates temporary addresses as + described in RFC 4941."; + reference + "RFC 4941: Privacy Extensions for Stateless Address + Autoconfiguration in IPv6"; + + } + + leaf temporary-valid-lifetime { + if-feature ipv6-privacy-autoconf; + type uint32; + units "seconds"; + default '604800'; + description + "The time period during which the temporary address + is valid."; + reference + "RFC 4941: Privacy Extensions for Stateless Address + Autoconfiguration in IPv6 + - TEMP_VALID_LIFETIME"; + + } + + leaf temporary-preferred-lifetime { + if-feature ipv6-privacy-autoconf; + type uint32; + units "seconds"; + default '86400'; + description + "The time period during which the temporary address is + preferred."; + reference + "RFC 4941: Privacy Extensions for Stateless Address + Autoconfiguration in IPv6 + - TEMP_PREFERRED_LIFETIME"; + + } + } // container autoconf + } // container ipv6 + } + + augment /if:interfaces-state/if:interface { + description + "Data nodes for the operational state of IP on interfaces."; + container ipv4 { + presence + "Present if IPv4 is enabled on this interface"; + config false; + description + "Interface-specific parameters for the IPv4 address family."; + leaf forwarding { + type boolean; + description + "Indicates whether IPv4 packet forwarding is enabled or + disabled on this interface."; + } + + leaf mtu { + type uint16 { + range "68..max"; + } + units "octets"; + description + "The size, in octets, of the largest IPv4 packet that the + interface will send and receive."; + reference + "RFC 791: Internet Protocol"; + + } + + list address { + key "ip"; + description + "The list of IPv4 addresses on the interface."; + leaf ip { + type inet:ipv4-address-no-zone; + description + "The IPv4 address on the interface."; + } + + choice subnet { + description + "The subnet can be specified as a prefix-length, or, + if the server supports non-contiguous netmasks, as + a netmask."; + leaf prefix-length { + type uint8 { + range "0..32"; + } + description + "The length of the subnet prefix."; + } + leaf netmask { + if-feature ipv4-non-contiguous-netmasks; + type yang:dotted-quad; + description + "The subnet specified as a netmask."; + } + } // choice subnet + + leaf origin { + type ip-address-origin; + description + "The origin of this address."; + } + } // list address + + list neighbor { + key "ip"; + description + "A list of mappings from IPv4 addresses to + link-layer addresses. + + This list represents the ARP Cache."; + reference + "RFC 826: An Ethernet Address Resolution Protocol"; + + leaf ip { + type inet:ipv4-address-no-zone; + description + "The IPv4 address of the neighbor node."; + } + + leaf link-layer-address { + type yang:phys-address; + description + "The link-layer address of the neighbor node."; + } + + leaf origin { + type neighbor-origin; + description + "The origin of this neighbor entry."; + } + } // list neighbor + } // container ipv4 + + container ipv6 { + presence + "Present if IPv6 is enabled on this interface"; + config false; + description + "Parameters for the IPv6 address family."; + leaf forwarding { + type boolean; + default 'false'; + description + "Indicates whether IPv6 packet forwarding is enabled or + disabled on this interface."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 (IPv6) + Section 6.2.1, IsRouter"; + + } + + leaf mtu { + type uint32 { + range "1280..max"; + } + units "octets"; + description + "The size, in octets, of the largest IPv6 packet that the + interface will send and receive."; + reference + "RFC 2460: Internet Protocol, Version 6 (IPv6) Specification + Section 5"; + + } + + list address { + key "ip"; + description + "The list of IPv6 addresses on the interface."; + leaf ip { + type inet:ipv6-address-no-zone; + description + "The IPv6 address on the interface."; + } + + leaf prefix-length { + type uint8 { + range "0..128"; + } + mandatory true; + description + "The length of the subnet prefix."; + } + + leaf origin { + type ip-address-origin; + description + "The origin of this address."; + } + + leaf status { + type enumeration { + enum "preferred" { + value 0; + description + "This is a valid address that can appear as the + destination or source address of a packet."; + } + enum "deprecated" { + value 1; + description + "This is a valid but deprecated address that should + no longer be used as a source address in new + communications, but packets addressed to such an + address are processed as expected."; + } + enum "invalid" { + value 2; + description + "This isn't a valid address, and it shouldn't appear + as the destination or source address of a packet."; + } + enum "inaccessible" { + value 3; + description + "The address is not accessible because the interface + to which this address is assigned is not + operational."; + } + enum "unknown" { + value 4; + description + "The status cannot be determined for some reason."; + } + enum "tentative" { + value 5; + description + "The uniqueness of the address on the link is being + verified. Addresses in this state should not be + used for general communication and should only be + used to determine the uniqueness of the address."; + } + enum "duplicate" { + value 6; + description + "The address has been determined to be non-unique on + the link and so must not be used."; + } + enum "optimistic" { + value 7; + description + "The address is available for use, subject to + restrictions, while its uniqueness on a link is + being verified."; + } + } + description + "The status of an address. Most of the states correspond + to states from the IPv6 Stateless Address + Autoconfiguration protocol."; + reference + "RFC 4293: Management Information Base for the + Internet Protocol (IP) + - IpAddressStatusTC + RFC 4862: IPv6 Stateless Address Autoconfiguration"; + + } + } // list address + + list neighbor { + key "ip"; + description + "A list of mappings from IPv6 addresses to + link-layer addresses. + + This list represents the Neighbor Cache."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 (IPv6)"; + + leaf ip { + type inet:ipv6-address-no-zone; + description + "The IPv6 address of the neighbor node."; + } + + leaf link-layer-address { + type yang:phys-address; + description + "The link-layer address of the neighbor node."; + } + + leaf origin { + type neighbor-origin; + description + "The origin of this neighbor entry."; + } + + leaf is-router { + type empty; + description + "Indicates that the neighbor node acts as a router."; + } + + leaf state { + type enumeration { + enum "incomplete" { + value 0; + description + "Address resolution is in progress, and the link-layer + address of the neighbor has not yet been + determined."; + } + enum "reachable" { + value 1; + description + "Roughly speaking, the neighbor is known to have been + reachable recently (within tens of seconds ago)."; + } + enum "stale" { + value 2; + description + "The neighbor is no longer known to be reachable, but + until traffic is sent to the neighbor no attempt + should be made to verify its reachability."; + } + enum "delay" { + value 3; + description + "The neighbor is no longer known to be reachable, and + traffic has recently been sent to the neighbor. + Rather than probe the neighbor immediately, however, + delay sending probes for a short while in order to + give upper-layer protocols a chance to provide + reachability confirmation."; + } + enum "probe" { + value 4; + description + "The neighbor is no longer known to be reachable, and + unicast Neighbor Solicitation probes are being sent + to verify reachability."; + } + } + description + "The Neighbor Unreachability Detection state of this + entry."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 (IPv6) + Section 7.3.2"; + + } + } // list neighbor + } // container ipv6 + } +} // module ietf-ip diff --git a/v3po/api/src/main/yang/v3po.yang b/v3po/api/src/main/yang/v3po.yang new file mode 100644 index 000000000..785e48146 --- /dev/null +++ b/v3po/api/src/main/yang/v3po.yang @@ -0,0 +1,366 @@ +module v3po { + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:v3po"; + prefix "v3po"; + + revision "2015-01-05" { + description "Initial revision of v3po model"; + } + + import iana-if-type { + prefix "ianaift"; + } + import ietf-interfaces { + prefix "if"; + } + import ietf-yang-types { + prefix "yang"; + } + import ietf-inet-types { + prefix "inet"; + } + import ietf-ip { + prefix "ip"; + } + import yang-ext { + prefix "ext"; + } + + typedef bridge-domain-ref { + type leafref { + path "/vpp/bridge-domains/bridge-domain/name"; + } + description + "This type is used by to reference a bridge domain table"; + } + + typedef bridged-virtual-interface-ref { + type leafref { + path "/if:interfaces/if:interface/l2/bridged-virtual-interface"; + } + description + "This type is used by to reference a bridged virtual interface"; + } + + identity vxlan-tunnel { + base if:interface-type; + } + + augment /if:interfaces/if:interface { + ext:augment-identifier "vpp-interface-augmentation"; + container ethernet { + when "../if:type = 'ianaift:ethernetCsmacd'"; + leaf mtu { + type uint16 { + range "64..9216"; + } + units "octets"; + default 9216; + description + "The size, in octets, of the largest packet that the + hardware interface will send and receive."; + } + } + container routing { + leaf vrf-id { + type uint32; + default 0; + } + } + container vxlan { + when "../if:type = 'v3po:vxlan-tunnel'"; + + leaf src { + /* mandatory true; */ + type inet:ipv4-address; + } + leaf dst { + /* mandatory true; */ + type inet:ipv4-address; + } + leaf vni { + /* mandatory true; */ + type uint32; + } + leaf encap-vrf-id { + type uint32; + } + } + container l2 { + description + "Parameters for configuring Layer2 features on interfaces."; + must "(not (../if:ipv4[if:enabled = 'true']/if:address/if:ip) and " + + "not (../if:ipv6[if:enabled = 'true']/if:address/if:ip))"; + + choice interconnection { + case xconnect-based { + leaf xconnect-outgoing-interface { + /* Don't allow selection of this interface */ + must "../../if:name != current()"; + type if:interface-ref; + description + "L2 xconnect mode"; + } + } + case bridge-based { + leaf bridge-domain { + type bridge-domain-ref; + description + "Interfaces in a bridge-domain forward packets to other + interfaces in the same bridge-domain based on + destination mac address."; + } + leaf split-horizon-group { + when "../bridge-domain"; + type uint8 { + range "0..255"; + } + default 0; + description + "Interface's split-horizon group. Interfaces in the same + bridge-domain and split-horizon group can not forward + packets between each other. "; + } + leaf bridged-virtual-interface { + when "../bridge-domain"; + type boolean; + default false; + description + "Interface forward packets in the bridge-domain + associated with the BVI."; + } + } + } + } + } + + container vpp { + description + "VPP config data"; + + container bridge-domains { + list bridge-domain { + key "name"; + max-elements 1024; + + leaf name { + type string; + } + leaf flood { + type boolean; + default true; + description + "Enable/disable L2 flooding."; + } + leaf forward { + type boolean; + default true; + description + "Enable/disable L2 forwarding."; + } + leaf learn { + type boolean; + default true; + description + "Enable/disable L2 learning."; + } + leaf unknown-unicast-flood { + type boolean; + default true; + } + leaf arp-termination { + type boolean; + default false; + } + list l2-fib { + key "phys-address"; + + leaf phys-address { + type yang:phys-address; + } + leaf action { + type enumeration { + enum "forward"; + enum "filter"; + } + mandatory true; + } + leaf outgoing-interface { + type if:interface-ref; + } + } + } + } + } + + augment /if:interfaces-state/if:interface { + ext:augment-identifier "vpp-interface-state-augmentation"; + + leaf description { + type string; + } + container ethernet { + when "../if:type = 'ianaift:ethernetCsmacd'"; + leaf mtu { + type uint16; + } + leaf manufacturer-description { + type string; + } + leaf duplex { + type enumeration { + enum "half"; + enum "full"; + } + } + } + container vxlan { + when "../if:type = 'v3po:vxlan-tunnel'"; + + leaf src { + type inet:ipv4-address; + } + leaf dst { + type inet:ipv4-address; + } + leaf vni { + type uint32; + } + leaf encap-vrf-id { + type uint32; + } + } + container l2 { + choice interconnection { + case xconnect-based { + leaf xconnect-outgoing-interface { + type if:interface-ref; + } + } + case bridge-based { + leaf bridge-domain { + type bridge-domain-ref; + } + leaf split-horizon-group { + type uint8; + } + leaf bridged-virtual-interface { + type boolean; + } + } + } + } + } + + augment /if:interfaces-state/if:interface/if:statistics { + ext:augment-identifier "vpp-interface-statistics-augmentation"; + leaf in-errors-no-buf { + type yang:counter64; + } + leaf in-errors-miss { + type yang:counter64; + } + leaf out-discards-fifo-full { + type yang:counter64; + } + } + + container vpp-state { + config false; + + description + "VPP operational data"; + + container bridge-domains { + list bridge-domain { + + key "name"; + leaf name { + type string; + } + leaf flood { + type boolean; + } + leaf unknown-unicast-flood { + type boolean; + } + leaf arp-termination { + type boolean; + } + leaf forward { + type boolean; + } + leaf learn { + type boolean; + } + list interface { + key "name"; + + leaf name { + type if:interface-state-ref; + } + + leaf split-horizon-group { + type uint8; + } + + leaf bridged-virtual-interface { + type boolean; + } + } + list l2-fib { + key "phys-address"; + + leaf phys-address { + type yang:phys-address; + } + leaf static-config { + type boolean; + } + leaf outgoing-interface { + when "../v3po:action = 'forward'"; + type if:interface-state-ref; + } + leaf action { + type enumeration { + enum "forward"; + enum "filter"; + } + mandatory true; + } + leaf bridged-virtual-interface { + when "../v3po:action = 'forward'"; + type boolean; + } + } + description + "bridge-domain operational data"; + } + } + + container version { + leaf name { + type string; + } + leaf build-directory { + type string; + } + leaf build-date { + type string; + } + leaf branch { + type string; + } + description + "vlib version info"; + } + } + + rpc vpp-poll-oper-data { + output { + leaf status { + type uint32; + } + } + } +} diff --git a/v3po/artifacts/pom.xml b/v3po/artifacts/pom.xml new file mode 100644 index 000000000..b4c283973 --- /dev/null +++ b/v3po/artifacts/pom.xml @@ -0,0 +1,46 @@ + + + + + + 4.0.0 + io.fd.honeycomb.v3po + v3po-artifacts + 1.0.0-SNAPSHOT + pom + + + + + ${project.groupId} + v3po-api + ${project.version} + + + ${project.groupId} + v3po-impl + ${project.version} + + + ${project.groupId} + v3po-features + ${project.version} + features + xml + + + + diff --git a/v3po/features/pom.xml b/v3po/features/pom.xml new file mode 100644 index 000000000..e95617451 --- /dev/null +++ b/v3po/features/pom.xml @@ -0,0 +1,135 @@ + + + + + io.fd.honeycomb.common + features-parent + 1.0.0-SNAPSHOT + ../../common/features-parent + + io.fd.honeycomb.v3po + v3po-features + 1.0.0-SNAPSHOT + ${project.artifactId} + 4.0.0 + + 3.1.1 + + + 0.8.0-SNAPSHOT + 1.3.0-SNAPSHOT + 1.3.0-SNAPSHOT + 1.0.0-SNAPSHOT + 0.8.0-SNAPSHOT + 0.3.0-SNAPSHOT + etc/opendaylight/karaf + + + + + + org.opendaylight.controller + mdsal-artifacts + ${mdsal.version} + pom + import + + + org.opendaylight.netconf + restconf-artifacts + ${restconf.version} + pom + import + + + org.opendaylight.netconf + netconf-artifacts + ${netconf.version} + pom + import + + + + + + org.opendaylight.yangtools + features-yangtools + features + ${yangtools.version} + xml + runtime + + + org.opendaylight.mdsal.model + features-mdsal-model + ${mdsal.model.version} + features + xml + runtime + + + org.opendaylight.controller + features-mdsal + features + xml + runtime + + + org.opendaylight.netconf + features-restconf + features + xml + runtime + + + org.opendaylight.netconf + features-netconf-connector + features + xml + runtime + + + org.opendaylight.dlux + features-dlux + features + ${dlux.version} + xml + runtime + + + ${project.groupId} + v3po-impl + ${project.version} + + + ${project.groupId} + v3po-impl + ${project.version} + xml + config + + + ${project.groupId} + v3po-api + ${project.version} + + + io.fd.vpp + vppjapi + 1.0.0-SNAPSHOT + + + diff --git a/v3po/features/src/main/features/features.xml b/v3po/features/src/main/features/features.xml new file mode 100644 index 000000000..2055dd935 --- /dev/null +++ b/v3po/features/src/main/features/features.xml @@ -0,0 +1,54 @@ + + + + + mvn:org.opendaylight.yangtools/features-yangtools/${yangtools.version}/xml/features + mvn:org.opendaylight.controller/features-mdsal/${mdsal.version}/xml/features + mvn:org.opendaylight.mdsal.model/features-mdsal-model/${mdsal.model.version}/xml/features + mvn:org.opendaylight.netconf/features-restconf/${restconf.version}/xml/features + mvn:org.opendaylight.netconf/features-netconf-connector/${netconf.version}/xml/features + mvn:org.opendaylight.dlux/features-dlux/${dlux.version}/xml/features + + + odl-mdsal-models + mvn:io.fd.honeycomb.v3po/v3po-api/${project.version} + + + + odl-mdsal-broker + odl-v3po-api + odl-netconf-connector-ssh + odl-netconf-mdsal + mvn:io.fd.honeycomb.v3po/v3po-impl/${project.version} + wrap:mvn:io.fd.vpp/vppjapi/1.0.0-SNAPSHOT + mvn:io.fd.honeycomb.v3po/v3po-impl/${project.version}/xml/config + + + + odl-v3po + odl-restconf + + + + odl-v3po-rest + odl-mdsal-apidocs + odl-mdsal-xsql + odl-dlux-yangui + + + diff --git a/v3po/impl/pom.xml b/v3po/impl/pom.xml new file mode 100644 index 000000000..9315c15cc --- /dev/null +++ b/v3po/impl/pom.xml @@ -0,0 +1,57 @@ + + + + + + + io.fd.honeycomb.common + impl-parent + 1.0.0-SNAPSHOT + ../../common/impl-parent + + + 4.0.0 + io.fd.honeycomb.v3po + v3po-impl + 1.0.0-SNAPSHOT + bundle + + + ${project.groupId} + v3po-api + ${project.version} + + + + io.fd.vpp + vppjapi + 1.0.0-SNAPSHOT + + + + + junit + junit + test + + + + org.mockito + mockito-all + test + + + diff --git a/v3po/impl/src/main/config/default-config.xml b/v3po/impl/src/main/config/default-config.xml new file mode 100644 index 000000000..08a090ea2 --- /dev/null +++ b/v3po/impl/src/main/config/default-config.xml @@ -0,0 +1,37 @@ + + + + + + urn:opendaylight:params:xml:ns:yang:v3po:impl?module=v3po-impl&revision=2014-12-10 + urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28 + + + + + + + prefix:v3po + v3po-default + + binding:binding-broker-osgi-registry + binding-osgi-broker + + + + + + diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/DataRegistry.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/DataRegistry.java new file mode 100644 index 000000000..5888dc998 --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/DataRegistry.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl; + +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public interface DataRegistry { + void registerModule(InstanceIdentifier path, DataResolver resolver); +} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/DataResolver.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/DataResolver.java new file mode 100644 index 000000000..5ada80f86 --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/DataResolver.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl; + +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public interface DataResolver { + public void resolve(InstanceIdentifier path, WriteTransaction tx); +} + diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/DataResolverInterfaceState.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/DataResolverInterfaceState.java new file mode 100644 index 000000000..fd2d48c01 --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/DataResolverInterfaceState.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package io.fd.honeycomb.v3po.impl; + +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +// Return Interface data from interfaces.state based on InstanceIdentifier +public class DataResolverInterfaceState implements DataResolver { + + @Override + public void resolve(InstanceIdentifier path, + WriteTransaction tx) { + InterfaceKey key = path.firstKeyOf(Interface.class); + String interfaceName = key.getName(); + + return; + } +} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/InterfaceStateIpv4Builder.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/InterfaceStateIpv4Builder.java new file mode 100644 index 000000000..5e2141d6f --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/InterfaceStateIpv4Builder.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl; + +import java.util.ArrayList; +import java.util.List; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.IpAddressOrigin; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.NeighborOrigin; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.AddressBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.Neighbor; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.NeighborBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.address.subnet.PrefixLength; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.address.subnet.PrefixLengthBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; + +public class InterfaceStateIpv4Builder { + private List
addrs = new ArrayList
(); + private List neighbors = new ArrayList(); + private Ipv4Builder ipv4Builder = new Ipv4Builder(); + + /** + * TODO-ADD-JAVADOC. + */ + public void addAddress(String ipv4Addr, short prefixLength, IpAddressOrigin origin) { + // address + AddressBuilder addrBuilder = new AddressBuilder(); + + // IpAddressOrigin.Static + addrBuilder.setOrigin(origin); // FIXME: how to find origin? + + PrefixLength prefixLen = new PrefixLengthBuilder().setPrefixLength(prefixLength).build(); + addrBuilder.setSubnet(prefixLen); + + addrBuilder.setIp(new Ipv4AddressNoZone(ipv4Addr)); + + addrs.add(addrBuilder.build()); + } + + /** + * TODO-ADD-JAVADOC. + */ + public void addNeighbor(String ipv4Addr, String physAddr, NeighborOrigin origin) { + // address neighbor + NeighborBuilder nbrBuilder = new NeighborBuilder(); + nbrBuilder.setIp(new Ipv4AddressNoZone(ipv4Addr)); + nbrBuilder.setLinkLayerAddress(new PhysAddress(physAddr)); // TODO ("00:00:00:00:00:00") + nbrBuilder.setOrigin(origin); + + neighbors.add(nbrBuilder.build()); + } + + /** + * TODO-ADD-JAVADOC. + */ + public void setForwarding(boolean fwd) { + ipv4Builder.setForwarding(fwd); + } + + /** + * TODO-ADD-JAVADOC. + */ + public void setMtu(int mtu) { + ipv4Builder.setMtu(mtu); + } + + /** + * TODO-ADD-JAVADOC. + */ + public Ipv4 build() { + ipv4Builder.setAddress(addrs); + ipv4Builder.setNeighbor(neighbors); + return ipv4Builder.build(); + } +} + diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/InterfaceStateIpv6Builder.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/InterfaceStateIpv6Builder.java new file mode 100644 index 000000000..42862a944 --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/InterfaceStateIpv6Builder.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl; + +import java.util.ArrayList; +import java.util.List; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6AddressNoZone; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.IpAddressOrigin; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.NeighborOrigin; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv6; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv6Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv6.Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv6.AddressBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv6.Neighbor; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv6.NeighborBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; + +public class InterfaceStateIpv6Builder { + private List
addrs = new ArrayList
(); + private List neighbors = new ArrayList(); + private Ipv6Builder ipv6Builder = new Ipv6Builder(); + + /** + * TODO-ADD-JAVADOC. + */ + public void addAddress(String ipv6Addr, short prefixLength, IpAddressOrigin origin) { + // address + AddressBuilder addrBuilder = new AddressBuilder(); + + // IpAddressOrigin.Static + addrBuilder.setOrigin(origin); // FIXME: how to find origin? + addrBuilder.setPrefixLength(prefixLength); + addrBuilder.setIp(new Ipv6AddressNoZone(ipv6Addr)); + + addrs.add(addrBuilder.build()); + } + + /** + * TODO-ADD-JAVADOC. + */ + public void addNeighbor(String ipv6Addr, String physAddr, NeighborOrigin origin) { + // address neighbor + NeighborBuilder nbrBuilder = new NeighborBuilder(); + nbrBuilder.setIp(new Ipv6AddressNoZone(ipv6Addr)); + nbrBuilder.setLinkLayerAddress(new PhysAddress(physAddr)); // TODO ("00:00:00:00:00:00") + nbrBuilder.setOrigin(origin); + + neighbors.add(nbrBuilder.build()); + } + + /** + * TODO-ADD-JAVADOC. + */ + public void setForwarding(boolean fwd) { + ipv6Builder.setForwarding(fwd); + } + + /** + * TODO-ADD-JAVADOC. + */ + public void setMtu(long mtu) { + ipv6Builder.setMtu(mtu); + } + + /** + * TODO-ADD-JAVADOC. + */ + public Ipv6 build() { + ipv6Builder.setAddress(addrs); + ipv6Builder.setNeighbor(neighbors); + return ipv6Builder.build(); + } +} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/LoggingFuturesCallBack.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/LoggingFuturesCallBack.java new file mode 100644 index 000000000..35795cb7b --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/LoggingFuturesCallBack.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl; + +import com.google.common.util.concurrent.FutureCallback; +import org.slf4j.Logger; + +public class LoggingFuturesCallBack implements FutureCallback { + + private static Logger LOG; + private String message; + + public LoggingFuturesCallBack(String message, Logger log) { + this.message = message; + this.LOG = log; + } + + @Override + public void onFailure(Throwable err) { + LOG.warn(message,err); + + } + + @Override + public void onSuccess(V arg0) { + /* suppress success messages + if (arg0 == null) { + LOG.info("Success!"); + } else { + LOG.info("Success! {}", arg0); + } + */ + } +} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poApiRequest.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poApiRequest.java new file mode 100644 index 000000000..f466adb53 --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poApiRequest.java @@ -0,0 +1,461 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl; + +import java.math.BigInteger; +import java.net.InetAddress; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.EthernetCsmacd; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.SoftwareLoopback; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state._interface.Statistics; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state._interface.StatisticsBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface2; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface2Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.IpAddressOrigin; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Counter32; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Counter64; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Gauge64; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStatisticsAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStatisticsAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Ethernet.Duplex; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.EthernetBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.L2Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Vxlan; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VxlanBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.l2.interconnection.BridgeBasedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.l2.interconnection.XconnectBasedBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.vppjapi.vppBridgeDomainDetails; +import org.openvpp.vppjapi.vppBridgeDomainInterfaceDetails; +import org.openvpp.vppjapi.vppIPv4Address; +import org.openvpp.vppjapi.vppIPv6Address; +import org.openvpp.vppjapi.vppInterfaceCounters; +import org.openvpp.vppjapi.vppInterfaceDetails; +import org.openvpp.vppjapi.vppVxlanTunnelDetails; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.primitives.Ints; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; +/* + * VPP API Class overriding interface details callback + */ +public class V3poApiRequest extends V3poRequest { + private static final Logger LOG = LoggerFactory.getLogger(V3poApiRequest.class); + public String ifNames = ""; + private VppPollOperDataImpl caller; + + public V3poApiRequest(VppPollOperDataImpl vppPollOperData) { + caller = vppPollOperData; + } + + private InstanceIdentifier getStateInterfaceIid(String interfaceName) { + return InstanceIdentifier.create(InterfacesState.class).child(Interface.class, + new InterfaceKey(interfaceName)); + } + + private InstanceIdentifier getStateInterfaceIpId(InstanceIdentifier iid) { + return iid.augmentation(Interface2.class); + } + + private InstanceIdentifier getStateInterfaceStatsId(InstanceIdentifier iid) { + return iid.child(Statistics.class); + } + + private static Counter64 getCounter64(long num) { + return new Counter64(BigInteger.valueOf(num)); + } + + private static Counter32 getCounter32(long num) { + return new Counter32(num); + } + + private Statistics buildInterfaceStatistics(vppInterfaceCounters ifCounters) { + if (ifCounters == null) { + return null; + } + StatisticsBuilder statsBuilder = new StatisticsBuilder(); + + statsBuilder.setInBroadcastPkts(getCounter64(ifCounters.rxBroadcast)); + statsBuilder.setInDiscards(getCounter32(ifCounters.rxDiscard)); + statsBuilder.setInErrors(getCounter32(ifCounters.rxError)); + statsBuilder.setInMulticastPkts(getCounter64(ifCounters.rxMulticast)); + statsBuilder.setInOctets(getCounter64(ifCounters.rxOctets)); + statsBuilder.setInUnicastPkts(getCounter64(ifCounters.rxUnicast)); + statsBuilder.setInUnknownProtos(getCounter32(ifCounters.rxUnknownProto)); + + statsBuilder.setOutBroadcastPkts(getCounter64(ifCounters.txBroadcast)); + statsBuilder.setOutDiscards(getCounter32(ifCounters.txDiscard)); + statsBuilder.setOutErrors(getCounter32(ifCounters.txError)); + statsBuilder.setOutMulticastPkts(getCounter64(ifCounters.txMulticast)); + statsBuilder.setOutOctets(getCounter64(ifCounters.txOctets)); + statsBuilder.setOutUnicastPkts(getCounter64(ifCounters.txUnicast)); + + VppInterfaceStatisticsAugmentationBuilder statsAugBuilder = + new VppInterfaceStatisticsAugmentationBuilder(); + statsAugBuilder.setInErrorsMiss(getCounter64(ifCounters.rxMiss)); + statsAugBuilder.setInErrorsNoBuf(getCounter64(ifCounters.rxFifoFull)); // FIXME? Is this right? + statsAugBuilder.setOutDiscardsFifoFull(getCounter64(ifCounters.txFifoFull)); + + statsBuilder.addAugmentation(VppInterfaceStatisticsAugmentation.class, + statsAugBuilder.build()); + + return statsBuilder.build(); + } + + private static String getMacAddress(byte[] mac) { + StringBuilder sb = new StringBuilder(18); + for (byte b : mac) { + if (sb.length() > 0) { + sb.append(':'); + } + sb.append(String.format("%02x", b)); + } + return sb.toString(); + } + + private static final Gauge64 vppSpeed0 = new Gauge64(BigInteger.ZERO); + private static final Gauge64 vppSpeed1 = new Gauge64(BigInteger.valueOf(10 * 1000000)); + private static final Gauge64 vppSpeed2 = new Gauge64(BigInteger.valueOf(100 * 1000000)); + private static final Gauge64 vppSpeed4 = new Gauge64(BigInteger.valueOf(1000 * 1000000)); + private static final Gauge64 vppSpeed8 = new Gauge64(BigInteger.valueOf(10000L * 1000000)); + private static final Gauge64 vppSpeed16 = new Gauge64(BigInteger.valueOf(40000L * 1000000)); + private static final Gauge64 vppSpeed32 = new Gauge64(BigInteger.valueOf(100000L * 1000000)); + + private static Gauge64 getSpeed(byte vppSpeed) { + switch (vppSpeed) { + case 1: return vppSpeed1; + case 2: return vppSpeed2; + case 4: return vppSpeed4; + case 8: return vppSpeed8; + case 16: return vppSpeed16; + case 32: return vppSpeed32; + default: return vppSpeed0; + } + } + + private static String ipv4IntToString(int ip) { + InetAddress addr = null; + byte[] bytes = Ints.toByteArray(ip); + try { + addr = InetAddress.getByAddress(bytes); + } catch (java.net.UnknownHostException e) { + e.printStackTrace(); + return null; + } + return addr.getHostAddress(); + } + + private Interface buildStateInterface(int ifIndex, + String interfaceName, + int supIfIndex, + byte[] physAddr, + byte adminUp, byte linkUp, + byte linkDuplex, byte linkSpeed, + int subId, byte subDot1ad, + byte subNumberOfTags, + int subOuterVlanId, + int subInnerVlanId, + byte subExactMatch, + byte subDefault, + byte subOuterVlanIdAny, + byte subInnerVlanIdAny, + int vtrOp, int vtrPushDot1q, + int vtrTag1, int vtrTag2, + Statistics stats) { + InterfaceBuilder ifBuilder = new InterfaceBuilder(); + java.lang.Class ifType; + + // FIXME: missing types for virtualethernet, subinterface, tap interface etc + if (interfaceName.startsWith("loop")) { + ifType = SoftwareLoopback.class; + } else if (interfaceName.startsWith("vxlan_tunnel")) { + ifType = VxlanTunnel.class; + } else { + ifType = EthernetCsmacd.class; + } + ifBuilder.setName(interfaceName) + .setType(ifType) + .setAdminStatus((adminUp == 0 ? AdminStatus.Down : AdminStatus.Up)) + .setOperStatus((linkUp == 0 ? OperStatus.Down : OperStatus.Up)); +/* + DataContainerNodeBuilder builder = ImmutableNodes.mapEntryBuilder() + .withNodeIdentifier(new NodeIdentifierWithPredicates(Interface.QNAME, NAME_QNAME, interfaceName)); + builder.withChild(ImmutableNodes.leafNode(IF_TYPE, SoftwareLoopback.QNAME))*/ + + // subinterface? + if (ifIndex != supIfIndex) { + // TODO: get name and set + } + + if (physAddr != null) { + ifBuilder.setPhysAddress(new PhysAddress(getMacAddress(physAddr))); + } + ifBuilder.setSpeed(getSpeed(linkSpeed)); + + if (stats != null) { + ifBuilder.setStatistics(stats); + } + int bdId = this.bridgeDomainIdFromInterfaceName(interfaceName); + vppBridgeDomainDetails bd = (bdId != -1 ? this.getBridgeDomainDetails(bdId) : null); + + String bdName = null; + short splitHorizonGroup = 0; + boolean bvi = false; + + if (bd != null) { + bdName = bd.name; + for (int ifIdx = 0; ifIdx < bd.interfaces.length; ifIdx++) { + vppBridgeDomainInterfaceDetails bdIf = bd.interfaces[ifIdx]; + + if (bdIf.interfaceName != interfaceName) { + continue; + } + if (bd.bviInterfaceName == interfaceName) { + bvi = true; + } + splitHorizonGroup = (short)bdIf.splitHorizonGroup; + } + } + + VppInterfaceStateAugmentationBuilder vppIfStateAugBuilder = + new VppInterfaceStateAugmentationBuilder(); + + vppIfStateAugBuilder.setDescription(this.getInterfaceDescription(interfaceName)); + + setStateInterfaceL2(vppIfStateAugBuilder, bdId != -1, false, null, + bdName, splitHorizonGroup, bvi); + + if (EthernetCsmacd.class == ifType) { + setStateInterfaceEthernet(vppIfStateAugBuilder, linkDuplex == 2, + "ACME Inc.", 1234); + } + + vppVxlanTunnelDetails[] vxlanDet = this.vxlanTunnelDump(ifIndex); + if (null != vxlanDet && vxlanDet.length >= 1) { + setStateInterfaceVxlan(vppIfStateAugBuilder, vxlanDet[0].srcAddress, + vxlanDet[0].dstAddress, vxlanDet[0].vni, + vxlanDet[0].encapVrfId); + } + + ifBuilder.addAugmentation(VppInterfaceStateAugmentation.class, + vppIfStateAugBuilder.build()); + + InterfaceStateIpv4Builder ipv4Builder = new InterfaceStateIpv4Builder(); +// TODO ipv4Builder.setMtu(1234); + + InetAddress addr = null; + + vppIPv4Address[] ipv4Addrs = ipv4AddressDump(interfaceName); + if (ipv4Addrs != null) { + for (vppIPv4Address vppAddr : ipv4Addrs) { + if (null == vppAddr) { + LOG.error("ipv4 address structure in null"); + continue; + } + + // FIXME: vppIPv4Address and vppIPv6 address can be the same if both will use + // byte array for ip + byte[] bytes = Ints.toByteArray(vppAddr.ip); + try { + addr = InetAddress.getByAddress(bytes); + } catch (java.net.UnknownHostException e) { + e.printStackTrace(); + continue; + } + + ipv4Builder.addAddress(addr.getHostAddress(), vppAddr.prefixLength, IpAddressOrigin.Static); + } + } + + InterfaceStateIpv6Builder ipv6Builder = new InterfaceStateIpv6Builder(); +// TODO ipv6Builder.setMtu(1234); + + vppIPv6Address[] ipv6Addrs = ipv6AddressDump(interfaceName); + if (ipv6Addrs != null) { + for (vppIPv6Address vppAddr : ipv6Addrs) { + if (null == vppAddr) { + LOG.error("ipv6 address structure in null"); + continue; + } + + byte[] bytes = vppAddr.ip; + try { + addr = InetAddress.getByAddress(bytes); + } catch (java.net.UnknownHostException e) { + e.printStackTrace(); + continue; + } + + ipv6Builder.addAddress(addr.getHostAddress(), vppAddr.prefixLength, IpAddressOrigin.Static); + } + } + Interface2Builder ipBuilder = new Interface2Builder(); + + ipBuilder.setIpv4(ipv4Builder.build()); + ipBuilder.setIpv6(ipv6Builder.build()); + + ifBuilder.addAugmentation(Interface2.class, ipBuilder.build()); + + return ifBuilder.build(); + } + + private void setStateInterfaceL2( + VppInterfaceStateAugmentationBuilder augBuilder, + boolean isL2BridgeBased, boolean isXconnect, + String xconnectOutgoingInterface, + String bdName, short splitHorizonGroup, boolean bvi) { + + L2Builder l2Builder = new L2Builder(); + + if (isXconnect) { + l2Builder.setInterconnection( + new XconnectBasedBuilder() + .setXconnectOutgoingInterface(xconnectOutgoingInterface) + .build()); + } else if (isL2BridgeBased) { + l2Builder.setInterconnection( + new BridgeBasedBuilder() + .setBridgeDomain(bdName) + .setSplitHorizonGroup(splitHorizonGroup) + .setBridgedVirtualInterface(bvi) + .build()); + } + + augBuilder.setL2(l2Builder.build()); + } + + private void setStateInterfaceEthernet( + VppInterfaceStateAugmentationBuilder augBuilder, + boolean isFullDuplex, String manufacturerDesc, Integer mtu) { + + EthernetBuilder ethBuilder = new EthernetBuilder(); + ethBuilder.setDuplex((isFullDuplex ? Duplex.Full : Duplex.Half)) + .setManufacturerDescription(manufacturerDesc) + .setMtu(mtu); + + augBuilder.setEthernet(ethBuilder.build()); + } + + private void setStateInterfaceVxlan( + VppInterfaceStateAugmentationBuilder augBuilder, int srcAddress, + int dstAddress, int vni, int encapVrfId) { + + String srcAddressStr = ipv4IntToString(srcAddress); + String dstAddressStr = ipv4IntToString(dstAddress); + + VxlanBuilder vxlanBuilder = new VxlanBuilder(); + Vxlan vxlan = vxlanBuilder + .setSrc(new Ipv4AddressNoZone(srcAddressStr)) + .setDst(new Ipv4AddressNoZone(dstAddressStr)) + .setVni((long)vni) + .setEncapVrfId((long)encapVrfId) + .build(); + + augBuilder.setVxlan(vxlan); + } + + private void writeToIfState(InstanceIdentifier iid, + Interface intf) { + DataBroker db = caller.getDataBroker(); + WriteTransaction transaction = db.newWriteOnlyTransaction(); + // TODO: how to delete existing interfaces that disappeared? (reset it before each dumpInterfaces call?) + + /*LOG.info("VPPOPER-INFO: Adding interface " + intf.getName() + + " to oper DataStore.");*/ + transaction.put(LogicalDatastoreType.OPERATIONAL, iid, intf); + + CheckedFuture future = + transaction.submit(); + Futures.addCallback(future, new LoggingFuturesCallBack( + "VPPOPER-WARNING: Failed to write " + + "interface to ietf-interfaces state", LOG)); + } + + private void processInterfaces(vppInterfaceDetails[] ifaces) { + for (vppInterfaceDetails swIf : ifaces) { + interfaceDetails(swIf); + } + } + + /** + * TODO-ADD-JAVADOC. + */ + public void swInterfaceDumpAll() { + vppInterfaceDetails[] ifaces; + + ifaces = swInterfaceDump((byte) 1, "Ether".getBytes()); + processInterfaces(ifaces); + + ifaces = swInterfaceDump((byte) 1, "lo".getBytes()); + processInterfaces(ifaces); + + ifaces = swInterfaceDump((byte) 1, "vxlan".getBytes()); + processInterfaces(ifaces); + + ifaces = swInterfaceDump((byte) 1, "l2tpv3_tunnel".getBytes()); + processInterfaces(ifaces); + + ifaces = swInterfaceDump((byte) 1, "tap".getBytes()); + processInterfaces(ifaces); + } + + private void interfaceDetails(vppInterfaceDetails swIf) { + /*LOG.info("Got interface {} (idx: {}) adminUp: {} linkUp: {} duplex: {} speed: {} subId: {}", + swIf.interfaceName, swIf.ifIndex, swIf.adminUp, swIf.linkUp, swIf.linkDuplex, swIf.linkSpeed, swIf.subId);*/ + + vppInterfaceCounters ifCounters = getInterfaceCounters(swIf.ifIndex); + + InstanceIdentifier iid = getStateInterfaceIid(swIf.interfaceName); + + Statistics stats = buildInterfaceStatistics(ifCounters); + + Interface intf = buildStateInterface(swIf.ifIndex, swIf.interfaceName, + swIf.supIfIndex, swIf.physAddr, + swIf.adminUp, swIf.linkUp, + swIf.linkDuplex, swIf.linkSpeed, + swIf.subId, swIf.subDot1ad, + swIf.subNumberOfTags, + swIf.subOuterVlanId, + swIf.subInnerVlanId, + swIf.subExactMatch, swIf.subDefault, + swIf.subOuterVlanIdAny, + swIf.subInnerVlanIdAny, + swIf.vtrOp, swIf.vtrPushDot1q, + swIf.vtrTag1, swIf.vtrTag2, stats); + writeToIfState(iid, intf); + + ifNames += " " + swIf.interfaceName; + } +} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poProvider.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poProvider.java new file mode 100644 index 000000000..3b546f16f --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poProvider.java @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl; + +import java.util.ArrayList; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration; +import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.EthernetCsmacd; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesStateBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.AddressBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.AddressKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLength; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLengthBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.V3poService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.EthernetBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.L2Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.RoutingBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.l2.interconnection.BridgeBasedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.vppjapi.vppApi; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; + +public class V3poProvider implements BindingAwareProvider, AutoCloseable { + + private static final Logger LOG = LoggerFactory.getLogger(V3poProvider.class); + private RpcRegistration v3poService; + private VppIetfInterfaceListener vppInterfaceListener; + private VppBridgeDomainListener vppBridgeDomainListener; + private static final vppApi api = new vppApi(); + private static DataBroker db; + VppPollOperDataImpl vppPollOperData; + + private void writeToBridgeDomain(String bdName, Boolean flood, + Boolean forward, Boolean learn, + Boolean unknownUnicastFlood, + Boolean arpTermination) { + + BridgeDomainBuilder bdBuilder = new BridgeDomainBuilder(); + bdBuilder.setName(bdName); + bdBuilder.setFlood(flood); + bdBuilder.setForward(forward); + bdBuilder.setLearn(learn); + bdBuilder.setUnknownUnicastFlood(unknownUnicastFlood); + bdBuilder.setArpTermination(arpTermination); + + LOG.info("VPPCFG-INFO: Adding Bridge Domain " + bdName + " to DataStore."); + InstanceIdentifier iid = + InstanceIdentifier.create(Vpp.class) + .child(BridgeDomains.class) + .child(BridgeDomain.class, new BridgeDomainKey(bdName)); + WriteTransaction transaction = db.newWriteOnlyTransaction(); + transaction.put(LogicalDatastoreType.CONFIGURATION, iid, bdBuilder.build()); + CheckedFuture future = transaction.submit(); + Futures.addCallback(future, new LoggingFuturesCallBack( + "VPPCFG-WARNING: Failed to write bridge domain " + bdName + " to Bridge Domains", LOG)); + } + + private void writeIpv4AddressToInterface(String name, Ipv4AddressNoZone ipv4Addr, short plen) { + AddressKey addrKey = new AddressKey(ipv4Addr); + AddressBuilder addrBuilder = new AddressBuilder(); + PrefixLength prefixLen = new PrefixLengthBuilder().setPrefixLength(plen).build(); + addrBuilder.setSubnet(prefixLen); + addrBuilder.setIp(new Ipv4AddressNoZone(ipv4Addr)); + addrBuilder.setKey(addrKey); + + List
addrs = new ArrayList
(); + addrs.add(addrBuilder.build()); + + Ipv4 ip4 = new Ipv4Builder().setAddress(addrs).build(); + Interface1Builder if1Builder = new Interface1Builder(); + if1Builder.setIpv4(ip4); + + InterfaceBuilder ifBuilder = new InterfaceBuilder(); + ifBuilder.setName(name); + ifBuilder.addAugmentation(Interface1.class, if1Builder.build()); + + LOG.info("VPPCFG-INFO: Adding ipv4 address {} to interface {} to DataStore.", ipv4Addr, name); + InstanceIdentifier iid = + InstanceIdentifier.create(Interfaces.class) + .child(Interface.class, new InterfaceKey(name)); + WriteTransaction transaction = db.newWriteOnlyTransaction(); + transaction.put(LogicalDatastoreType.CONFIGURATION, iid, ifBuilder.build()); + CheckedFuture future = transaction.submit(); + Futures.addCallback(future, new LoggingFuturesCallBack( + "VPPCFG-WARNING: Failed to write " + name + "interface to ietf-interfaces", LOG)); + } + + private void writeToInterface(String name, String description, + Boolean enabled, String bdName, int vrfId) { + VppInterfaceAugmentationBuilder ifAugBuilder = new VppInterfaceAugmentationBuilder(); + + EthernetBuilder ethBuilder = new EthernetBuilder(); + ethBuilder.setMtu(1234); + ifAugBuilder.setEthernet(ethBuilder.build()); + + if (bdName != null) { + BridgeBasedBuilder bridgeBuilder = new BridgeBasedBuilder(); + bridgeBuilder.setBridgeDomain(bdName); + bridgeBuilder.setSplitHorizonGroup((short)0); + bridgeBuilder.setBridgedVirtualInterface(false); + + L2Builder l2Builder = new L2Builder(); + l2Builder.setInterconnection(bridgeBuilder.build()); + ifAugBuilder.setL2(l2Builder.build()); + } + + if (vrfId > 0) { + RoutingBuilder rtBuilder = new RoutingBuilder(); + rtBuilder.setVrfId(new Long(vrfId)); + ifAugBuilder.setRouting(rtBuilder.build()); + } + + InterfaceBuilder ifBuilder = new InterfaceBuilder(); + ifBuilder.setName(name); + ifBuilder.setDescription(description); + ifBuilder.setType(EthernetCsmacd.class); + ifBuilder.setEnabled(enabled); + ifBuilder.setLinkUpDownTrapEnable(Interface.LinkUpDownTrapEnable.Disabled); + + ifBuilder.addAugmentation(VppInterfaceAugmentation.class, ifAugBuilder.build()); + + LOG.info("VPPCFG-INFO: Adding interface " + name + " to DataStore."); + InstanceIdentifier iid = InstanceIdentifier.create(Interfaces.class) + .child(Interface.class, new InterfaceKey(name)); + WriteTransaction transaction = db.newWriteOnlyTransaction(); + transaction.put(LogicalDatastoreType.CONFIGURATION, iid, ifBuilder.build()); + CheckedFuture future = transaction.submit(); + Futures.addCallback(future, new LoggingFuturesCallBack( + "VPPCFG-WARNING: Failed to write " + name + "interface to ietf-interfaces", LOG)); + } + + private void initializeVppConfig() { + + WriteTransaction transaction = db.newWriteOnlyTransaction(); + InstanceIdentifier viid = InstanceIdentifier.create(Vpp.class); + Vpp vpp = new VppBuilder().build(); + transaction.put(LogicalDatastoreType.CONFIGURATION, viid, vpp); + CheckedFuture future = transaction.submit(); + Futures.addCallback(future, new + LoggingFuturesCallBack<>("VPPCFG-WARNING: Failed to create Vpp " + + "configuration db.", + LOG)); + vppBridgeDomainListener = new VppBridgeDomainListener(db, api); + + LOG.info("VPPCFG-INFO: Preparing to initialize the IETF Interface " + "list configuration db."); + transaction = db.newWriteOnlyTransaction(); + InstanceIdentifier iid = InstanceIdentifier.create(Interfaces.class); + Interfaces intf = new InterfacesBuilder().build(); + transaction.put(LogicalDatastoreType.CONFIGURATION, iid, intf); + future = transaction.submit(); + Futures.addCallback(future, new + LoggingFuturesCallBack<>("VPPCFG-WARNING: Failed to create IETF " + + "Interface list configuration db.", + LOG)); + vppInterfaceListener = new VppIetfInterfaceListener(db, api); + + /* DAW-DEBUG: + try { + int wait = 3; + LOG.info("VPPCFG-INFO: Sleeping for {} seconds...", wait); + TimeUnit.SECONDS.sleep(wait); + } catch (InterruptedException e) { + LOG.info("VPPCFG-INFO: Sleep Interrupted!"); + } + LOG.info("VPPCFG-INFO: Nap complete. I feel much better now."); + */ + + /* Test DataChangeListener by writing to db */ + writeToBridgeDomain("CocaCola", true /*flood*/, true /*forward*/, + true /*learn*/, true /*uuFlood*/, + false /*arpTermination*/); + writeToBridgeDomain("PepsiCola", true /*flood*/, true /*forward*/, + true /*learn*/, true /*uuFlood*/, + false /*arpTermination*/); + + + writeToInterface("TenGigabitEthernet86/0/1", + "Physical 10GbE Interface (Transport)", + true, null, 7); + writeToInterface("TenGigabitEthernet86/0/0", "Physical 10GbE Interface", + true, "CocaCola", 0); + writeToInterface("GigabitEthernet8/0/1", "Physical 1GbE Interface", + true, "PepsiCola", 0); + + /* + writeIpv4AddressToInterface("GigabitEthernet86/0/1", + new Ipv4AddressNoZone("10.10.10.10"), + (short)24); + writeIpv4AddressToInterface("GigabitEthernet86/0/1", + new Ipv4AddressNoZone("11.11.11.10"), + (short)24); + writeIpv4AddressToInterface("GigabitEthernet86/0/1", + new Ipv4AddressNoZone("11.11.11.10"), + (short)24); + */ + /* Interfaces on virtual testbed VMs (e.g. js-cluster-1) */ + writeToBridgeDomain("Balvenie", true /*flood*/, true /*forward*/, + true /*learn*/, true /*uuFlood*/, + false /*arpTermination*/); + writeToBridgeDomain("Laphroaig", true /*flood*/, true /*forward*/, + true /*learn*/, true /*uuFlood*/, + false /*arpTermination*/); + writeToBridgeDomain("Glenfiddich", true /*flood*/, true /*forward*/, + true /*learn*/, true /*uuFlood*/, + false /*arpTermination*/); + writeToBridgeDomain("Macallan", true /*flood*/, true /*forward*/, + true /*learn*/, true /*uuFlood*/, + false /*arpTermination*/); + + writeToInterface("GigabitEthernet2/2/0", "Physical 1GbE Interface", + true, "Balvenie", 0); + writeToInterface("GigabitEthernet2/3/0", "Physical 1GbE Interface", + true, "Laphroaig", 0); + writeToInterface("GigabitEthernet2/4/0", "Physical 1GbE Interface", + true, "Glenfiddich", 0); + writeToInterface("GigabitEthernet2/5/0", "Physical 1GbE Interface", + true, "Macallan", 0); + writeToInterface("GigabitEthernet2/6/0", + "Physical 1GbE Interface (Transport)", + true, null, 7); + } + + /* operational data */ + + private void initVppOperational() { + /* + * List ifaces = new + * ArrayList(); + */ + LOG.info("VPPOPER-INFO: Preparing to initialize the IETF Interface " + "state list operational db."); + InterfacesState ifsState = new InterfacesStateBuilder().build(); + WriteTransaction tx = db.newWriteOnlyTransaction(); + InstanceIdentifier isid = InstanceIdentifier.builder(InterfacesState.class).build(); + tx.put(LogicalDatastoreType.OPERATIONAL, isid, ifsState); + Futures.addCallback(tx.submit(), new LoggingFuturesCallBack<>( + "VPPOPER-WARNING: Failed to create IETF " + "Interface state list operational db.", LOG)); + } + + private void startOperationalUpdateTimer() { + Timer timer = new Timer(); + + // fire task after 1 second and then repeat each 10 seconds + timer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + vppPollOperData.updateOperational(); + } + }, 1000, 10000); + } + + @Override + public void onSessionInitiated(ProviderContext session) { + LOG.info("VPP-INFO: V3poProvider Session Initiated"); + int rv = api.clientConnect("v3poODL"); + LOG.info("VPP-INFO: VPP api client connection return value = {}", rv); + if (rv != 0) { + LOG.error("VPP-ERROR: VPP api client connection failed: return value = {}", rv); + return; + } + db = session.getSALService(DataBroker.class); + initializeVppConfig(); + initVppOperational(); + + vppPollOperData = new VppPollOperDataImpl(db); + v3poService = session.addRpcImplementation(V3poService.class, + vppPollOperData); + startOperationalUpdateTimer(); + } + + @Override + public void close() throws Exception { + LOG.info("VPP-INFO: V3poProvider Closed"); + if (v3poService != null) { + v3poService.close(); + } + } +} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poRequest.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poRequest.java new file mode 100644 index 000000000..900161577 --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poRequest.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl; + +import org.openvpp.vppjapi.vppApi; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/* + * Abstract class overriding all callbacks with default error message + */ +public abstract class V3poRequest extends vppApi { + private static final Logger LOG = LoggerFactory.getLogger(V3poRequest.class); +} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppBridgeDomainListener.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppBridgeDomainListener.java new file mode 100644 index 000000000..94d8df7c7 --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppBridgeDomainListener.java @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl; + +import java.util.Collection; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataObjectModification; +import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener; +import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier; +import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.vppjapi.vppApi; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class VppBridgeDomainListener implements DataTreeChangeListener, + AutoCloseable { + private static final Logger LOG = + LoggerFactory.getLogger(VppBridgeDomainListener.class); + private ListenerRegistration registration; + private DataBroker db; + private vppApi api; + + private enum DataChangeType { + CREATE, UPDATE, DELETE + } + + /** + * TODO-ADD-JAVADOC. + */ + public VppBridgeDomainListener(DataBroker db, vppApi api) { + this.db = db; + this.api = api; + InstanceIdentifier iid = InstanceIdentifier + .create(Vpp.class) + .child(BridgeDomains.class) + .child(BridgeDomain.class); + LOG.info("VPPCFG-INFO: Register listener for VPP Bridge Domain data changes"); + + DataTreeIdentifier path = + new DataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, iid); + registration = this.db.registerDataTreeChangeListener(path, this); + } + + @Override + public void onDataTreeChanged(Collection> changes) { + + for (DataTreeModification change: changes) { + InstanceIdentifier iid = change.getRootPath().getRootIdentifier(); + DataObjectModification changeDiff = change.getRootNode(); + + switch (changeDiff.getModificationType()) { + case SUBTREE_MODIFIED: + case WRITE: + // create, modify or replace + createOrUpdateBridgeDomain(changeDiff); + break; + case DELETE: + deleteBridgeDomain(changeDiff); + break; + default: + LOG.info("Unsupported change type {} for {}", + changeDiff.getModificationType(), iid); + } + } + } + + // handles only CREATE and UPDATE calls + private void vppSetBridgeDomain(BridgeDomain bridgeDomain, DataChangeType type, + BridgeDomain originalBridgeDomain) { + int rv = -77; + int cnt = 0; + String bdName = bridgeDomain.getName(); + int bdId = api.findOrAddBridgeDomainId(bdName); + + LOG.info("VPPCFG-INFO: {} ", type); + LOG.info("VPPCFG-INFO: Name: " + bdName); + LOG.info("VPPCFG-INFO: Flood: {} ", bridgeDomain.isFlood()); + LOG.info("VPPCFG-INFO: Forward: {} ", bridgeDomain.isForward()); + LOG.info("VPPCFG-INFO: Learn: {} ", bridgeDomain.isLearn()); + LOG.info("VPPCFG-INFO: UnknownUnicastFlood: {} ", + bridgeDomain.isUnknownUnicastFlood()); + LOG.info("VPPCFG-INFO: ArpTermination: {} ", + bridgeDomain.isArpTermination()); + LOG.info("VPPCFG-INFO: {} ", type); + + switch (type) { + case CREATE: + case UPDATE: + byte flood = bridgeDomain.isFlood() ? (byte) 1 : (byte) 0; + byte forward = bridgeDomain.isForward() ? (byte) 1 : (byte) 0; + byte learn = bridgeDomain.isLearn() ? (byte) 1 : (byte) 0; + byte uuf = bridgeDomain.isUnknownUnicastFlood() ? (byte) 1 : (byte) 0; + byte arpTerm = bridgeDomain.isArpTermination() ? (byte) 1 : (byte) 0; + if ((bdId == -1) || (bdId == 0)) { + LOG.warn("VPPCFG-WARNING: Bridge Domain create/lookup failed" + + " (bdId = {})! Ignoring vppSetBridgeDomain request {}", + bdId, type); + return; + } else { + int ctxId = api.bridgeDomainAddDel(bdId, flood, forward, + learn, uuf, arpTerm, + (byte) 1 /* isAdd */); + LOG.info("VPPCFG-INFO: {} api.bridgeDomainAddDel({} ({})) " + + "ctxId = {}", type, bdName, bdId, ctxId); + while (rv == -77) { + rv = api.getRetval(ctxId, 1 /* release */); + cnt++; + } + LOG.info("VPPCFG-INFO: {} api.bridgeDomainAddDel({} ({})) " + + "retval {} after {} tries.", + type, bdName, bdId, rv, cnt); + + if (rv < 0) { + LOG.warn("VPPCFG-WARNING: {} api.bridgeDomainAddDel({}" + + " ({})) failed: retval {}!", + type, bdName, bdId, rv); + /* DAW-FIXME: throw exception on failure? */ + } + } + break; + default: + LOG.warn("VPPCFG-WARNING: Unknown DataChangeType {}! " + + "Ignoring vppSetBridgeDomain request", type); + return; + } + bdId = api.bridgeDomainIdFromName(bdName); + LOG.info("VPPCFG-INFO: {} api.bridgeDomainIdFromName({}) = {}", + type, bdName, bdId); + } + + private void createOrUpdateBridgeDomain(DataObjectModification changeDiff) { + if (changeDiff.getDataBefore() == null) { + vppSetBridgeDomain(changeDiff.getDataAfter(), + DataChangeType.CREATE, null); + } else { + vppSetBridgeDomain(changeDiff.getDataAfter(), + DataChangeType.UPDATE, + changeDiff.getDataBefore()); + } + } + + // handles DELETE calls + private void deleteBridgeDomain(DataObjectModification changeDiff) { + DataChangeType type = DataChangeType.DELETE; + BridgeDomain bridgeDomain = changeDiff.getDataBefore(); + String bdName = bridgeDomain.getName(); + int rv = -77; + int cnt = 0; + + LOG.info("VPPCFG-INFO: {} ", type); + LOG.info("VPPCFG-INFO: Name: " + bdName); + LOG.info("VPPCFG-INFO: Flood: {} ", bridgeDomain.isFlood()); + LOG.info("VPPCFG-INFO: Forward: {} ", bridgeDomain.isForward()); + LOG.info("VPPCFG-INFO: Learn: {} ", bridgeDomain.isLearn()); + LOG.info("VPPCFG-INFO: UnknownUnicastFlood: {} ", + bridgeDomain.isUnknownUnicastFlood()); + LOG.info("VPPCFG-INFO: ArpTermination: {} ", + bridgeDomain.isArpTermination()); + LOG.info("VPPCFG-INFO: {} ", type); + + int bdId = api.findOrAddBridgeDomainId(bdName); + if ((bdId == -1) || (bdId == 0)) { + LOG.warn("VPPCFG-WARNING: Unknown Bridge Domain {} " + + " (bdId = {})! Ignoring vppSetBridgeDomain request {}", + bdName, bdId, type); + return; + } else { + int ctxId = api.bridgeDomainAddDel(bdId, (byte) 0 /* flood */, + (byte) 0 /* forward */, + (byte) 0 /* learn */, + (byte) 0 /* uuf */, + (byte) 0 /* arpTerm */, + (byte) 0 /* isAdd */); + LOG.info("VPPCFG-INFO: {} api.bridgeDomainAddDel({} ({})) " + + "ctxId = {}", type, bdName, bdId, ctxId); + while (rv == -77) { + rv = api.getRetval(ctxId, 1 /* release */); + cnt++; + } + LOG.info("VPPCFG-INFO: {} api.bridgeDomainAddDel({} ({})) " + + "retval {} after {} tries.", + type, bdName, bdId, rv, cnt); + + if (rv < 0) { + LOG.warn("VPPCFG-WARNING: {} api.bridgeDomainAddDel({} ({}))" + + " failed: retval {}!", type, bdName, bdId, rv); + /* DAW-FIXME: throw exception on failure? */ + } + } + } + + @Override + public void close() throws Exception { + registration.close(); + } +} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppIetfInterfaceListener.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppIetfInterfaceListener.java new file mode 100644 index 000000000..7e6aa50f1 --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppIetfInterfaceListener.java @@ -0,0 +1,566 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl; + +import java.util.Collection; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataObjectModification; +import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener; +import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier; +import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.EthernetCsmacd; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv6; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.Subnet; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.Netmask; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLength; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Ethernet; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.L2; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Routing; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Vxlan; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.l2.Interconnection; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.l2.interconnection.BridgeBased; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.l2.interconnection.XconnectBased; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.vppjapi.vppApi; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class VppIetfInterfaceListener implements DataTreeChangeListener, AutoCloseable { + private static final Logger LOG = + LoggerFactory.getLogger(VppIetfInterfaceListener.class); + + private ListenerRegistration registration; + private DataBroker db; + private vppApi api; + + private enum DataChangeType { + CREATE, UPDATE, DELETE + } + + /** + * TODO-ADD-JAVADOC. + */ + public VppIetfInterfaceListener(DataBroker db, vppApi api) { + this.db = db; + this.api = api; + InstanceIdentifier iid = InstanceIdentifier + .create(Interfaces.class) + .child(Interface.class); + LOG.info("VPPCFG-INFO: Register listener for VPP Ietf Interface data changes"); + + DataTreeIdentifier path = + new DataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, iid); + + registration = this.db.registerDataTreeChangeListener(path, this); + } + + @Override + public void onDataTreeChanged(Collection> changes) { + LOG.info("VPPCFG-INFO: swIf onDataTreeChanged()"); + for (DataTreeModification change: changes) { + InstanceIdentifier iid = change.getRootPath().getRootIdentifier(); + DataObjectModification changeDiff = change.getRootNode(); + + switch (changeDiff.getModificationType()) { + case SUBTREE_MODIFIED: + case WRITE: + // create, modify or replace + createOrUpdateInterface(changeDiff); + break; + case DELETE: + deleteInterface(changeDiff); + break; + default: + LOG.info("Unsupported change type {} for {}", + changeDiff.getModificationType(), iid); + } + } + } + + private void vppSetVppInterfaceEthernetAndL2(int swIfIndex, + String swIfName, + VppInterfaceAugmentation + vppInterface) { + int ctxId = 0; + int rv = -77; + int cnt = 0; + String apiName = ""; + + LOG.info("VPPCFG-INFO: "); + LOG.info("VPPCFG-INFO: swIfIndex = {}", swIfIndex); + LOG.info("VPPCFG-INFO: swIfName = {}", swIfName); + LOG.info("VPPCFG-INFO: vppInterface = {}", vppInterface); + LOG.info("VPPCFG-INFO: "); + if (vppInterface != null) { + Ethernet vppEth = vppInterface.getEthernet(); + if (vppEth != null) { + LOG.info("VPPCFG-INFO: {} Ethernet MTU = {}", + swIfName, vppEth.getMtu()); + /* DAW-FIXME: Need vpe-api msg to configure the Ethernet MTU */ + } + + L2 vppL2 = vppInterface.getL2(); + if (vppL2 != null) { + Interconnection ic = vppL2.getInterconnection(); + if (ic instanceof XconnectBased) { + XconnectBased xc = (XconnectBased) ic; + String outSwIfName = xc.getXconnectOutgoingInterface(); + LOG.info("VPPCFG-INFO: XconnectBased"); + LOG.info("VPPCFG-INFO: XconnectOutgoingInterface = {}", + outSwIfName); + + int outSwIfIndex = api.swIfIndexFromName(outSwIfName); + if (swIfIndex != -1) { + apiName = "api.swInterfaceSetL2Xconnect"; + ctxId = + api.swInterfaceSetL2Xconnect(swIfIndex, + outSwIfIndex, + (byte)1 /* enable */); + LOG.info("VPPCFG-INFO: {}() : outSwIfName = {}, " + + "outSwIfIndex = {}, ctxId = {}", apiName, + outSwIfName, outSwIfIndex, ctxId); + cnt = 0; + rv = -77; + while (rv == -77) { + rv = api.getRetval(ctxId, 1 /* release */); + cnt++; + } + if (rv < 0) { + LOG.warn("VPPCFG-WARNING: {}() ctxId = {} failed:" + + " retval = {}!", apiName, ctxId, rv); + /* DAW-FIXME: throw exception on failure? */ + } else { + LOG.info("VPPCFG-INFO: {}() ctxId = {} retval = {}" + + " after {} tries.", apiName, ctxId, + rv, cnt); + } + + } else { + LOG.warn("VPPCFG-WARNING: Unknown Outgoing Interface ({})" + + " specified", outSwIfName); + } + + } else if (ic instanceof BridgeBased) { + BridgeBased bb = (BridgeBased) ic; + String bdName = bb.getBridgeDomain(); + int bdId = api.bridgeDomainIdFromName(bdName); + if (bdId > 0) { + byte bvi = + bb.isBridgedVirtualInterface() ? (byte) 1 : (byte) 0; + byte shg = bb.getSplitHorizonGroup().byteValue(); + + LOG.info("VPPCFG-INFO: BridgeBased"); + LOG.info("VPPCFG-INFO: BridgeDomain = {}, bdId = {}", + bdName, bdId); + LOG.info("VPPCFG-INFO: SplitHorizonGroup = {}", + shg); + LOG.info("VPPCFG-INFO: isBridgedVirtualInterface = {}", + bvi); + + apiName = "api.swInterfaceSetL2Bridge"; + ctxId = + api.swInterfaceSetL2Bridge(swIfIndex, + bdId, shg, bvi, + (byte)1 /* enable */); + LOG.info("VPPCFG-INFO: {}() : bdId = {}, shg = {}, " + + "bvi = {}, ctxId = {}", apiName, bdId, + shg, bvi, ctxId); + cnt = 0; + rv = -77; + while (rv == -77) { + rv = api.getRetval(ctxId, 1 /* release */); + cnt++; + } + if (rv < 0) { + LOG.warn("VPPCFG-WARNING:{}() ctxId = {} failed: " + + "retval = {}!", apiName, ctxId, rv); + /* DAW-FIXME: throw exception on failure? */ + } else { + LOG.info("VPPCFG-INFO: {}() ctxId = {} retval = {}" + + " after {} tries.", apiName, ctxId, + rv, cnt); + } + + } else { + LOG.error("VPPCFG-ERROR: Bridge Domain {} does not exist!", + bdName); + } + + } else { + LOG.error("VPPCFG-ERROR: unknonwn interconnection type!"); + } + } + } + } + + /** + * TODO-ADD-JAVADOC. + */ + public static int parseIp(String address) { + int result = 0; + + // iterate over each octet + for (String part : address.split("\\.")) { + // shift the previously parsed bits over by 1 byte + result = result << 8; + // set the low order bits to the current octet + result |= Integer.parseInt(part); + } + return result; + } + + private void createVxlanTunnel(String swIfName, Vxlan vxlan) { + Ipv4Address srcAddress = vxlan.getSrc(); + Ipv4Address dstAddress = vxlan.getDst(); + + int srcAddr = parseIp(srcAddress.getValue()); + int dstAddr = parseIp(dstAddress.getValue()); + int encapVrfId = vxlan.getEncapVrfId().intValue(); + int vni = vxlan.getVni().intValue(); + + int ctxId = api.vxlanAddDelTunnel((byte)1 /* is add */, srcAddr, dstAddr, encapVrfId, -1, vni); + String apiName = "api.vxlanAddDelTunnel"; + LOG.info("VPPCFG-INFO: {}({}, src: {}, dst: {} enabled ([]), ...) : " + + "ctxId = {}", apiName, swIfName, srcAddress.getValue(), + dstAddress.getValue(), ctxId); + + /* need to wait for creation of interface */ + int rv = -77; + int cnt = 0; + while (rv == -77) { + rv = api.getRetval(ctxId, 1 /* release */); + cnt++; + } + if (rv < 0) { + LOG.warn("VPPCFG-WARNING: {}() ctxId = {} failed: retval = {}!", apiName, ctxId, rv); + /* DAW-FIXME: throw exception on failure? */ + } else { + LOG.info("VPPCFG-INFO: {}() ctxId = {} retval = {} after {} tries.", apiName, ctxId, rv, cnt); + } + } + + private byte [] ipv4AddressNoZoneToArray(Ipv4AddressNoZone ipv4Addr) { + byte [] retval = new byte [4]; + String addr = ipv4Addr.getValue().toString(); + String [] dots = addr.split("\\."); + + for (int d = 3; d >= 0; d--) { + retval[d] = (byte)(Short.parseShort(dots[3 - d]) & 0xff); + } + return retval; + } + + private void vppSetInterface(Interface swIf, DataChangeType type, + Interface originalIf) { + VppInterfaceAugmentation vppInterface = + swIf.getAugmentation(VppInterfaceAugmentation.class); + int ctxId = 0; + int cnt = 0; + int rv = -77; + String apiName = ""; + + /* DAW-FIXME: If type == UPDATE, use originalDataObject to get + * state of api parameters which have not been changed. + * For now, all parameters must be set at the same time. + */ + LOG.info("VPPCFG-INFO: {} ", type); + LOG.info("VPPCFG-INFO: Name: " + swIf.getName()); + LOG.info("VPPCFG-INFO: Desc: " + swIf.getDescription()); + java.lang.Class + ifType = swIf.getType(); + if (ifType != null) { + LOG.info("VPPCFG-INFO: Type: " + swIf.getType().getSimpleName()); + } + LOG.info("VPPCFG-INFO: {} ", type); + + String swIfName = swIf.getName(); + int swIfIndex = api.swIfIndexFromName(swIfName); + + if ((ifType != null) && ifType.isAssignableFrom(EthernetCsmacd.class)) { + if (swIfIndex != -1) { + LOG.info("VPPCFG-INFO: {} : swIfIndex = {}", + swIfName, swIfIndex); + + /* set vpp ethernet and l2 containers */ + vppSetVppInterfaceEthernetAndL2(swIfIndex, swIfName, + vppInterface); + + byte enabled = swIf.isEnabled() ? (byte) 1 : (byte) 0; + apiName = "api.swInterfaceSetFlags"; + ctxId = api.swInterfaceSetFlags((int)swIfIndex, + (byte)enabled, + (byte)enabled, + (byte)0 /* deleted */); + LOG.info("VPPCFG-INFO: {}({} ([]), enabled ([]), ...) : " + + "ctxId = {}", apiName, swIfName, swIfIndex, + enabled, ctxId); + cnt = 0; + rv = -77; + while (rv == -77) { + rv = api.getRetval(ctxId, 1 /* release */); + cnt++; + } + if (rv < 0) { + LOG.warn("VPPCFG-WARNING: api.swInterfaceSetFlags() " + + "ctxId = {} failed: retval = {}!", ctxId, rv); + /* DAW-FIXME: throw exception on failure? */ + } else { + LOG.info("VPPCFG-INFO: {}() ctxId = {} retval = {} after" + + " {} tries.", apiName, ctxId, rv, cnt); + } + } else { + LOG.error("VPPCFG-ERROR: {} not found!", + swIf.getType().getSimpleName()); + LOG.error("VPPCFG-ERROR: cannot create {} type interfaces : " + + "ignoring create request for {} !", + swIf.getType().getSimpleName(), swIf.getName()); + } + + } else if ((ifType != null) + && ifType.isAssignableFrom(VxlanTunnel.class)) { + LOG.info("VPPCFG-INFO: VxLAN tunnel configuration"); + + // TODO: check name of interface, make use of renumber to change vpp + // interface name to desired one + + if (swIfIndex != -1) { + // interface exists in vpp + if (type == DataChangeType.DELETE) { + // TODO + } else { + // TODO + Vxlan vxlan = vppInterface.getVxlan(); + + LOG.info("Vxlan update: {}", vxlan); + } + } else { + // interface does not exist in vpp + if (type == DataChangeType.DELETE) { + // cannot delete non existent interface + LOG.error("VPPCFG-ERROR: Cannot delete non existing interface ({})", swIf.getName()); + } else { + Vxlan vxlan = vppInterface.getVxlan(); + + createVxlanTunnel(swIfName, vxlan); + + // refresh interfaces to be able to get ifIndex + api.swInterfaceDump((byte)1, "vxlan".getBytes()); + + int newSwIfIndex = api.swIfIndexFromName(swIfName); + + /* set vpp ethernet and l2 containers */ + vppSetVppInterfaceEthernetAndL2(newSwIfIndex, + swIfName, + vppInterface); + + byte enabled = swIf.isEnabled() ? (byte) 1 : (byte) 0; + ctxId = api.swInterfaceSetFlags((int)newSwIfIndex, + (byte)enabled, + (byte)enabled, + (byte)0 /* deleted */); + + swIfIndex = newSwIfIndex; + + apiName = "api.swInterfaceSetFlags"; + LOG.info("VPPCFG-INFO: {}({} ({}), enabled ({}), ...) :" + + " ctxId = {}", apiName, swIfName, + newSwIfIndex, enabled, ctxId); + cnt = 0; + rv = -77; + while (rv == -77) { + rv = api.getRetval(ctxId, 1 /* release */); + cnt++; + } + if (rv < 0) { + LOG.warn("VPPCFG-WARNING: {}() ctxId = {} failed: retval = {}!", apiName, ctxId, rv); + /* DAW-FIXME: throw exception on failure? */ + } else { + LOG.info("VPPCFG-INFO: {}() ctxId = {} retval = {} after {} tries.", apiName, ctxId, rv, cnt); + } + } + } + + /* DAW-FIXME: Add additional interface types here. + * + * } else if ((ifType != null) && ifType.isAssignableFrom(*.class)) { + */ + } else if (ifType != null) { + LOG.error("VPPCFG-ERROR: Unsupported interface type ({}) : {}" + + " cannot be created!", ifType.getSimpleName(), + swIf.getName()); + } + + if (swIfIndex == -1) { + LOG.warn("VPPCFG-INFO: Unknown Interface {}", swIfName); + return; + } + + if (swIf.getDescription() != null) { + api.setInterfaceDescription(swIfName, swIf.getDescription()); + } else { + api.setInterfaceDescription(swIfName, ""); + } + Routing rt = vppInterface.getRouting(); + int vrfId = (rt != null) ? rt.getVrfId().intValue() : 0; + LOG.info("VPPCFG-INFO: vrfId = {}", vrfId); + if (vrfId > 0) { + apiName = "api.swInterfaceSetTable"; + ctxId = api.swInterfaceSetTable((int)swIfIndex, + (byte)0, /* isIpv6 */ + vrfId); + LOG.info("VPPCFG-INFO: {}({} ([]), 0 /* isIpv6 */, {} /* vrfId */)" + + " : ctxId = {}", apiName, swIfName, swIfIndex, + vrfId, ctxId); + cnt = 0; + rv = -77; + while (rv == -77) { + rv = api.getRetval(ctxId, 1 /* release */); + cnt++; + } + if (rv < 0) { + LOG.warn("VPPCFG-WARNING: api.swInterfaceSetTable() ctxId = {} failed: retval = {}!", ctxId, rv); + /* DAW-FIXME: throw exception on failure? */ + } else { + LOG.info("VPPCFG-INFO: {}() ctxId = {} retval = {} after {} tries.", apiName, ctxId, rv, cnt); + } + } + + Interface1 ipIf = swIf.getAugmentation(Interface1.class); + LOG.info("VPPCFG-INFO: ipIf = {}", ipIf); + if (ipIf != null) { + Ipv4 v4 = ipIf.getIpv4(); + if (v4 != null) { + LOG.info("VPPCFG-INFO: v4 = {}", v4); + + for (Address v4Addr : v4.getAddress()) { + Subnet subnet = v4Addr.getSubnet(); + + if (subnet instanceof PrefixLength) { + Short plen = ((PrefixLength)subnet).getPrefixLength(); + byte [] addr = ipv4AddressNoZoneToArray(v4Addr.getIp()); + + if ((plen > 0) && (addr != null)) { + apiName = "api.swInterfaceAddDelAddress"; + ctxId = + api.swInterfaceAddDelAddress((int)swIfIndex, + (byte)1 /* isAdd */, + (byte)0 /* isIpv6 */, + (byte)0 /* delAll */, + plen.byteValue(), addr); + LOG.info("VPPCFG-INFO: {}({}/{}) to {} ({}): {}()" + + " returned ctxId = {}", apiName, addr, + plen, swIfName, swIfIndex, ctxId); + cnt = 0; + rv = -77; + while (rv == -77) { + rv = api.getRetval(ctxId, 1 /* release */); + cnt++; + } + if (rv < 0) { + LOG.warn("VPPCFG-WARNING: {}() ctxId = {} " + + "failed: retval = {}!", apiName, + ctxId, rv); + /* DAW-FIXME: throw exception on failure? */ + } else { + LOG.info("VPPCFG-INFO: {}() ctxId = {} retval" + + " = {} after {} tries.", apiName, + ctxId, rv, cnt); + } + } else { + LOG.warn("VPPCFG-WARNING: Malformed ipv4 address ({}/{}) " + + "specified for {} ({}): ignoring config!", + addr, plen, swIfName, swIfIndex); + } + } else if (subnet instanceof Netmask) { + LOG.warn("VPPCFG-WARNING: Unsupported ipv4 address subnet type 'Netmask' " + + "specified for {} ({}): ignoring config!", + swIfName, swIfIndex); + } else { + LOG.error("VPPCFG-ERROR: Unknown ipv4 address subnet type " + + "specified for {} ({}): ignoring config!", + swIfName, swIfIndex); + } + } + } + + Ipv6 v6 = ipIf.getIpv6(); + if (v6 != null) { + LOG.info("VPPCFG-INFO: v6 = {}", v6); + + // DAW-FIXME: Add Ipv6 address support. + LOG.warn("VPPCFG-WARNING: Ipv6 address support TBD: ignoring config!"); + } + } + } + + private void createOrUpdateInterface(DataObjectModification changeDiff) { + if (changeDiff.getDataBefore() == null) { + // create + vppSetInterface(changeDiff.getDataAfter(), + DataChangeType.CREATE, null); + } else { + // update + vppSetInterface(changeDiff.getDataAfter(), + DataChangeType.UPDATE, + changeDiff.getDataBefore()); + } + } + + private void deleteInterface(DataObjectModification changeDiff) { + Interface swIf = changeDiff.getDataBefore(); + LOG.info("VPPCFG-INFO: "); + LOG.info("VPPCFG-INFO: Name: " + swIf.getName()); + LOG.info("VPPCFG-INFO: Desc: " + swIf.getDescription()); + LOG.info("VPPCFG-INFO: Type: " + swIf.getType().getSimpleName()); + LOG.info("VPPCFG-INFO: "); + + if (swIf.getType().isAssignableFrom(EthernetCsmacd.class)) { + LOG.error("VPPCFG-ERROR: {} Interface {} cannot be deleted!", + swIf.getType().getSimpleName(), + swIf.getName()); + + /* DAW-FIXME: Add additional interface types here. + * + * } else if (swIf.getType().isAssignableFrom(*.class)) { + */ + + } else { + LOG.error("VPPCFG-ERROR: Unsupported interface type ({}) : " + + "{} cannot be deleted!", + swIf.getType().getSimpleName(), + swIf.getName()); + } + } + + @Override + public void close() throws Exception { + registration.close(); + } +} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppPollOperDataImpl.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppPollOperDataImpl.java new file mode 100644 index 000000000..71d4bea4b --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppPollOperDataImpl.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl; + +import java.util.HashMap; +import java.util.concurrent.Future; + +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.V3poService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppPollOperDataOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppPollOperDataOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; +import org.openvpp.vppjapi.vppBridgeDomainDetails; +import org.openvpp.vppjapi.vppBridgeDomainInterfaceDetails; +import org.openvpp.vppjapi.vppL2Fib; +import org.openvpp.vppjapi.vppVersion; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class VppPollOperDataImpl implements V3poService { + private static final Logger LOG = LoggerFactory.getLogger(VppPollOperDataImpl.class); + private vppVersion version; + private DataBroker db; + private int[] bdIds; + private HashMap l2fibByBdId = new HashMap(); + + /** + * TODO-ADD-JAVADOC. + */ + public VppPollOperDataImpl(DataBroker dataBroker) { + db = dataBroker; + } + + /** + * TODO-ADD-JAVADOC. + */ + public DataBroker getDataBroker() { + return db; + } + + /** + * TODO-ADD-JAVADOC. + * Update operational data and return string of space separated + * interfaces names + */ + public String updateOperational() { + V3poApiRequest api = new V3poApiRequest(this); + version = api.getVppVersion(); + + bdIds = api.bridgeDomainDump(-1); + + // TODO: we don't need to cache BDs now that we got rid of callbacks + l2fibByBdId.clear(); + if (bdIds != null) { + for (int idx = 0; idx < bdIds.length; idx++) { + l2fibByBdId.put(bdIds[idx], api.l2FibTableDump(bdIds[idx])); + } + } + api.swInterfaceDumpAll(); + + // build vpp-state + VppStateCustomBuilder stateBuilder = new VppStateCustomBuilder(); + + // bridge domains + for (int i = 0; i < bdIds.length; i++) { + vppBridgeDomainDetails bd = api.getBridgeDomainDetails(bdIds[i]); + VppStateBridgeDomainBuilder bdBuilder = + new VppStateBridgeDomainBuilder( + bd.name, bd.flood, bd.uuFlood, + bd.arpTerm, bd.forward, bd.learn); + + for (int ifIdx = 0; ifIdx < bd.interfaces.length; ifIdx++) { + vppBridgeDomainInterfaceDetails bdIf = bd.interfaces[ifIdx]; + bdBuilder.addInterface(bdIf.interfaceName, + bd.bviInterfaceName == bdIf.interfaceName, + bdIf.splitHorizonGroup); + } + + vppL2Fib[] bdFibs = l2fibByBdId.get(bdIds[i]); + + for (int fibIdx = 0; fibIdx < bdFibs.length; fibIdx++) { + vppL2Fib fib = bdFibs[fibIdx]; + bdBuilder.addL2Fib(fib.filter, fib.bridgedVirtualInterface, + fib.outgoingInterface, fib.physAddress, + fib.staticConfig); + } + + stateBuilder.addBridgeDomain(bdBuilder.build()); + } + + stateBuilder.setVersion(version); + + // write to oper + writeVppState(getVppStateIid(), stateBuilder.build()); + + return api.ifNames; + } + + @Override + public Future> vppPollOperData() { + String ifNames = updateOperational(); + + + VppPollOperDataOutput output = new VppPollOperDataOutputBuilder() + .setStatus(new Long(1)).build(); + + return RpcResultBuilder.success(output).buildFuture(); + } + + private InstanceIdentifier getVppStateIid() { + return (InstanceIdentifier.create(VppState.class)); + } + + private void writeVppState(InstanceIdentifier iid, VppState vppState) { + WriteTransaction transaction = db.newWriteOnlyTransaction(); + + //LOG.info("VPPOPER-INFO: Writing vpp-state to oper DataStore."); + transaction.put(LogicalDatastoreType.OPERATIONAL, iid, vppState); + + CheckedFuture future = transaction.submit(); + Futures.addCallback(future, new LoggingFuturesCallBack( + "VPPOPER-WARNING: Failed to write vpp-state to oper datastore", LOG)); + } +} + diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppStateBridgeDomainBuilder.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppStateBridgeDomainBuilder.java new file mode 100644 index 000000000..d547342bd --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppStateBridgeDomainBuilder.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl; + +import java.util.ArrayList; +import java.util.List; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.Interface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.InterfaceBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.L2Fib; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.L2Fib.Action; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.L2FibBuilder; + +public class VppStateBridgeDomainBuilder { + private BridgeDomainBuilder bdStateBuilder = new BridgeDomainBuilder(); + private List bdIfaces = new ArrayList(); + private List bdL2Fibs = new ArrayList(); + + /** + * TODO-ADD-JAVADOC. + */ + public VppStateBridgeDomainBuilder(String bdName, boolean flood, + boolean unknownUnicastFlood, + boolean arpTermination, + boolean forward, boolean learn) { + bdStateBuilder + .setName(bdName) + .setFlood(flood) + .setUnknownUnicastFlood(unknownUnicastFlood) + .setArpTermination(arpTermination) + .setForward(forward) + .setLearn(learn); + } + + /** + * TODO-ADD-JAVADOC. + */ + public void addInterface(String interfaceName, boolean bvi, + short splitHorizonGroup) { + InterfaceBuilder ifBuilder = new InterfaceBuilder(); + ifBuilder + .setName(interfaceName) + .setBridgedVirtualInterface(bvi) + .setSplitHorizonGroup(splitHorizonGroup); + + bdIfaces.add(ifBuilder.build()); + } + + private static String getMacAddress(byte[] mac) { + StringBuilder sb = new StringBuilder(18); + for (byte b : mac) { + if (sb.length() > 0) { + sb.append(':'); + } + sb.append(String.format("%02x", b)); + } + return sb.toString(); + } + + /** + * TODO-ADD-JAVADOC. + */ + public void addL2Fib(boolean filter, boolean bvi, + String outgoingIfaceName, byte[] physAddress, + boolean isStatic) { + L2FibBuilder l2fibBuilder = new L2FibBuilder(); + l2fibBuilder + .setAction((filter ? Action.Filter : Action.Forward)) + .setBridgedVirtualInterface(bvi) + .setOutgoingInterface(outgoingIfaceName) + .setPhysAddress(new PhysAddress(getMacAddress(physAddress))) + .setStaticConfig(isStatic); + + bdL2Fibs.add(l2fibBuilder.build()); + } + + /** + * TODO-ADD-JAVADOC. + */ + public BridgeDomain build() { + bdStateBuilder.setInterface(bdIfaces); + bdStateBuilder.setL2Fib(bdL2Fibs); + return bdStateBuilder.build(); + } +} diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppStateCustomBuilder.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppStateCustomBuilder.java new file mode 100644 index 000000000..86e44ec0b --- /dev/null +++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppStateCustomBuilder.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.v3po.impl; + +import java.util.ArrayList; +import java.util.List; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppStateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomainsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.VersionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain; +import org.openvpp.vppjapi.vppVersion; + +public class VppStateCustomBuilder { + VppStateBuilder stateBuilder = new VppStateBuilder(); + + List bridgeDomains = new ArrayList(); + + /** + * TODO-ADD-JAVADOC. + */ + public void setVersion(String name, String branch, String buildDate, + String buildDir) { + stateBuilder.setVersion( + new VersionBuilder() + .setBranch(branch) + .setBuildDate(buildDate) + .setBuildDirectory(buildDir) + .setName(name) + .build()); + } + + /** + * TODO-ADD-JAVADOC. + */ + public void setVersion(vppVersion vppVer) { + setVersion(vppVer.programName, vppVer.gitBranch, + vppVer.buildDate, vppVer.buildDirectory); + } + + /** + * TODO-ADD-JAVADOC. + */ + public void addBridgeDomain(BridgeDomain bd) { + bridgeDomains.add(bd); + } + + /** + * TODO-ADD-JAVADOC. + */ + public VppState build() { + stateBuilder.setBridgeDomains( + new BridgeDomainsBuilder() + .setBridgeDomain(bridgeDomains) + .build()); + return stateBuilder.build(); + } +} diff --git a/v3po/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModule.java b/v3po/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModule.java new file mode 100644 index 000000000..5a5fd1147 --- /dev/null +++ b/v3po/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModule.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210; + +import io.fd.honeycomb.v3po.impl.V3poProvider; + +public class V3poModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.AbstractV3poModule { + public V3poModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public V3poModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.V3poModule oldModule, java.lang.AutoCloseable oldInstance) { + super(identifier, dependencyResolver, oldModule, oldInstance); + } + + @Override + public void customValidation() { + // add custom validation form module attributes here. + } + + @Override + public java.lang.AutoCloseable createInstance() { + V3poProvider provider = new V3poProvider(); + getBrokerDependency().registerProvider(provider); + return provider; + } + +} diff --git a/v3po/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactory.java b/v3po/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactory.java new file mode 100644 index 000000000..5c942861d --- /dev/null +++ b/v3po/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactory.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* +* Generated file +* +* Generated from: yang module name: v3po yang module local name: v3po +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Fri Jan 02 13:49:24 CST 2015 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210; +public class V3poModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.AbstractV3poModuleFactory { + +} diff --git a/v3po/impl/src/main/yang/v3po-impl.yang b/v3po/impl/src/main/yang/v3po-impl.yang new file mode 100644 index 000000000..7a6fd4277 --- /dev/null +++ b/v3po/impl/src/main/yang/v3po-impl.yang @@ -0,0 +1,35 @@ +module v3po-impl { + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:v3po:impl"; + prefix "v3po-impl"; + + import config { prefix config; revision-date 2013-04-05; } + import opendaylight-md-sal-binding { prefix md-sal-binding; revision-date 2013-10-28;} + + description + "Service definition for v3po project"; + + revision "2014-12-10" { + description + "Initial revision"; + } + + identity v3po { + base config:module-type; + config:java-name-prefix V3po; + } + + augment "/config:modules/config:module/config:configuration" { + case v3po { + when "/config:modules/config:module/config:type = 'v3po'"; + container broker { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity md-sal-binding:binding-broker-osgi-registry; + } + } + } + } + } +} diff --git a/v3po/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactoryTest.java b/v3po/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactoryTest.java new file mode 100644 index 000000000..5b9a67458 --- /dev/null +++ b/v3po/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactoryTest.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210; + +import org.junit.Test; + +public class V3poModuleFactoryTest { + @Test + public void testFactoryConstructor() { + // ensure no exceptions on construction + new V3poModuleFactory(); + } +} diff --git a/v3po/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleTest.java b/v3po/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleTest.java new file mode 100644 index 000000000..99872549a --- /dev/null +++ b/v3po/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleTest.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210; + +import org.junit.Test; +import org.opendaylight.controller.config.api.DependencyResolver; +import org.opendaylight.controller.config.api.JmxAttribute; +import org.opendaylight.controller.config.api.ModuleIdentifier; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; +import io.fd.honeycomb.v3po.impl.V3poProvider; + +import javax.management.ObjectName; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class V3poModuleTest { + @Test + public void testCustomValidation() { + V3poModule module = new V3poModule(mock(ModuleIdentifier.class), mock(DependencyResolver.class)); + + // ensure no exceptions on validation + // currently this method is empty + module.customValidation(); + } + + @Test + public void testCreateInstance() throws Exception { + // configure mocks + DependencyResolver dependencyResolver = mock(DependencyResolver.class); + BindingAwareBroker broker = mock(BindingAwareBroker.class); + when(dependencyResolver.resolveInstance(eq(BindingAwareBroker.class), any(ObjectName.class), any(JmxAttribute.class))).thenReturn(broker); + + // create instance of module with injected mocks + V3poModule module = new V3poModule(mock(ModuleIdentifier.class), dependencyResolver); + + // getInstance calls resolveInstance to get the broker dependency and then calls createInstance + AutoCloseable closeable = module.getInstance(); + + // verify that the module registered the returned provider with the broker + verify(broker).registerProvider((V3poProvider)closeable); + + // ensure no exceptions on close + closeable.close(); + } +} diff --git a/v3po/it/pom.xml b/v3po/it/pom.xml new file mode 100644 index 000000000..e7afb7535 --- /dev/null +++ b/v3po/it/pom.xml @@ -0,0 +1,48 @@ + + + + + + + io.fd.honeycomb.common + it-parent + 1.0.0-SNAPSHOT + ../../common/it-parent + + + 4.0.0 + io.fd.honeycomb.v3po + v3po-it + 1.0.0-SNAPSHOT + bundle + + + false + io.fd.honeycomb.v3po + v3po-karaf + 1.0.0-SNAPSHOT + zip + + + + + ${project.groupId} + v3po-features + ${project.version} + + + + diff --git a/v3po/it/src/test/java/io/fd/honeycomb/v3po/it/V3poIT.java b/v3po/it/src/test/java/io/fd/honeycomb/v3po/it/V3poIT.java new file mode 100644 index 000000000..abd282183 --- /dev/null +++ b/v3po/it/src/test/java/io/fd/honeycomb/v3po/it/V3poIT.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.fd.honeycomb.v3po.it; + +import static org.ops4j.pax.exam.CoreOptions.composite; +import static org.ops4j.pax.exam.CoreOptions.maven; +import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFilePut; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.opendaylight.controller.mdsal.it.base.AbstractMdsalTestBase; +import org.ops4j.pax.exam.Option; +import org.ops4j.pax.exam.junit.PaxExam; +import org.ops4j.pax.exam.karaf.options.LogLevelOption.LogLevel; +import org.ops4j.pax.exam.options.MavenUrlReference; +import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; +import org.ops4j.pax.exam.spi.reactors.PerClass; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@RunWith(PaxExam.class) +@ExamReactorStrategy(PerClass.class) +public class V3poIT extends AbstractMdsalTestBase { + private static final Logger LOG = LoggerFactory.getLogger(V3poIT.class); + + @Override + public String getModuleName() { + return "v3po"; + } + + @Override + public String getInstanceName() { + return "v3po-default"; + } + + @Override + public MavenUrlReference getFeatureRepo() { + return maven() + .groupId("io.fd.honeycomb.v3po") + .artifactId("v3po-features") + .classifier("features") + .type("xml") + .versionAsInProject(); + } + + @Override + public String getFeatureName() { + return "odl-v3po-ui"; + } + + @Override + public Option getLoggingOption() { + Option option = editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG, + logConfiguration(V3poIT.class), + LogLevel.INFO.name()); + option = composite(option, super.getLoggingOption()); + return option; + } + + @Test + public void testv3poFeatureLoad() { + Assert.assertTrue(true); + } +} diff --git a/v3po/karaf/pom.xml b/v3po/karaf/pom.xml new file mode 100644 index 000000000..17d4a48a3 --- /dev/null +++ b/v3po/karaf/pom.xml @@ -0,0 +1,71 @@ + + + + + io.fd.honeycomb.common + karaf-parent + 1.0.0-SNAPSHOT + ../../common/karaf-parent + + 4.0.0 + io.fd.honeycomb.v3po + v3po-karaf + 1.0.0-SNAPSHOT + ${project.artifactId} + + 3.1.1 + + + + + ${project.groupId} + v3po-artifacts + ${project.version} + pom + import + + + + + + + org.apache.karaf.features + framework + kar + + + + ${project.groupId} + v3po-features + features + xml + runtime + + + + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + + diff --git a/v3po/pom.xml b/v3po/pom.xml new file mode 100644 index 000000000..a21b80f34 --- /dev/null +++ b/v3po/pom.xml @@ -0,0 +1,60 @@ + + + + + + org.opendaylight.odlparent + odlparent + 1.6.0-SNAPSHOT + + + io.fd.honeycomb.v3po + v3po-aggregator + 1.0.0-SNAPSHOT + v3po + pom + 4.0.0 + + 3.1.1 + + + api + impl + karaf + features + artifacts + + + + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + org.apache.maven.plugins + maven-install-plugin + + true + + + + + -- cgit 1.2.3-korg