Initial honeycomb code commit. 12/112/13
authorEd Warnicke <eaw@cisco.com>
Sun, 10 Jan 2016 14:15:18 +0000 (06:15 -0800)
committerRobert Varga <nite@hq.sk>
Fri, 29 Jan 2016 23:01:07 +0000 (00:01 +0100)
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 <eaw@cisco.com>
Signed-off-by: Robert Varga <nite@hq.sk>
42 files changed:
.gitignore [new file with mode: 0644]
.gitreview [new file with mode: 0644]
NOTES.txt [new file with mode: 0644]
common/api-parent/pom.xml [new file with mode: 0644]
common/features-parent/pom.xml [new file with mode: 0644]
common/features-parent/src/main/features/features.xml [new file with mode: 0644]
common/impl-parent/pom.xml [new file with mode: 0644]
common/it-parent/pom.xml [new file with mode: 0644]
common/karaf-parent/pom.xml [new file with mode: 0644]
common/pom.xml [new file with mode: 0644]
pom.xml [new file with mode: 0644]
v3po/api/pom.xml [new file with mode: 0644]
v3po/api/src/main/yang/ietf-ip.yang [new file with mode: 0644]
v3po/api/src/main/yang/v3po.yang [new file with mode: 0644]
v3po/artifacts/pom.xml [new file with mode: 0644]
v3po/features/pom.xml [new file with mode: 0644]
v3po/features/src/main/features/features.xml [new file with mode: 0644]
v3po/impl/pom.xml [new file with mode: 0644]
v3po/impl/src/main/config/default-config.xml [new file with mode: 0644]
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/DataRegistry.java [new file with mode: 0644]
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/DataResolver.java [new file with mode: 0644]
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/DataResolverInterfaceState.java [new file with mode: 0644]
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/InterfaceStateIpv4Builder.java [new file with mode: 0644]
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/InterfaceStateIpv6Builder.java [new file with mode: 0644]
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/LoggingFuturesCallBack.java [new file with mode: 0644]
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poApiRequest.java [new file with mode: 0644]
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poProvider.java [new file with mode: 0644]
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poRequest.java [new file with mode: 0644]
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppBridgeDomainListener.java [new file with mode: 0644]
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppIetfInterfaceListener.java [new file with mode: 0644]
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppPollOperDataImpl.java [new file with mode: 0644]
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppStateBridgeDomainBuilder.java [new file with mode: 0644]
v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppStateCustomBuilder.java [new file with mode: 0644]
v3po/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModule.java [new file with mode: 0644]
v3po/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactory.java [new file with mode: 0644]
v3po/impl/src/main/yang/v3po-impl.yang [new file with mode: 0644]
v3po/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactoryTest.java [new file with mode: 0644]
v3po/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleTest.java [new file with mode: 0644]
v3po/it/pom.xml [new file with mode: 0644]
v3po/it/src/test/java/io/fd/honeycomb/v3po/it/V3poIT.java [new file with mode: 0644]
v3po/karaf/pom.xml [new file with mode: 0644]
v3po/pom.xml [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..f7e7cca
--- /dev/null
@@ -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 (file)
index 0000000..b9a899e
--- /dev/null
@@ -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 (file)
index 0000000..92f7d9c
--- /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  // <dependency> for 2013-07-15 version of ietf-yang-types
+https://github.com/opendaylight/ovsdb/blob/master/southbound/southbound-api/pom.xml#L54  // <dependencyManagement><dependency> 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
+         </dependencyManagement></dependency> specifications.  When including
+         standard yang models (e.g. from org.opendaylight.mdsal.model), there
+         needs to be a <ManagedDependency> depencency defined to tell
+         maven what version to download into the local repo.  This isw
+         why each dependency  in the </Dependencies> 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/<NODE>?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/<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 <response in json format>
+curl -su admin:admin http://localhost:8181/restconf/config/network-topology:network-topology/topology/topology-netconf/node/<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 <response in xml format>
+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/<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 <response in json format>
+curl -su admin:admin http://localhost:8181/restconf/operational/network-topology:network-topology/topology/topology-netconf/node/<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 (file)
index 0000000..76c2aaf
--- /dev/null
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <groupId>org.opendaylight.mdsal</groupId>
+    <artifactId>binding-parent</artifactId>
+    <version>0.8.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>io.fd.honeycomb.common</groupId>
+  <artifactId>api-parent</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+  <packaging>pom</packaging>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+        <version>${checkstyle.version}</version>
+        <executions>
+          <execution>
+            <id>check-license</id>
+            <goals>
+              <goal>check</goal>
+            </goals>
+            <phase>none</phase>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <version>2.10</version>
+        <executions>
+          <execution>
+            <id>unpack-license</id>
+            <phase>none</phase>
+            <goals><goal>unpack</goal></goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/common/features-parent/pom.xml b/common/features-parent/pom.xml
new file mode 100644 (file)
index 0000000..a3dac73
--- /dev/null
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <groupId>org.opendaylight.odlparent</groupId>
+    <artifactId>features-parent</artifactId>
+    <version>1.6.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+  <groupId>io.fd.honeycomb.common</groupId>
+  <artifactId>features-parent</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+  <modelVersion>4.0.0</modelVersion>
+  <packaging>pom</packaging>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+        <version>${checkstyle.version}</version>
+        <executions>
+          <execution>
+            <id>check-license</id>
+            <goals>
+              <goal>check</goal>
+            </goals>
+            <phase>none</phase>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <version>2.10</version>
+        <executions>
+          <execution>
+            <id>unpack-license</id>
+            <phase>none</phase>
+            <goals><goal>unpack</goal></goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/common/features-parent/src/main/features/features.xml b/common/features-parent/src/main/features/features.xml
new file mode 100644 (file)
index 0000000..7d78e78
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+
+ This program and the accompanying materials are made available under the
+ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ and is available at http://www.eclipse.org/legal/epl-v10.html
+-->
+<!--
+     This is a dummy feature file. It is just a placeholder to keep the
+     artifact working.
+  -->
+<features name="fdio-dummy-feature" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0"/>
diff --git a/common/impl-parent/pom.xml b/common/impl-parent/pom.xml
new file mode 100644 (file)
index 0000000..ac17c8a
--- /dev/null
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>config-parent</artifactId>
+    <version>0.4.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>io.fd.honeycomb.common</groupId>
+  <artifactId>impl-parent</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+  <packaging>pom</packaging>
+  <properties>
+    <checkstyle.header.file>APACHE_HEADER.txt</checkstyle.header.file>
+  </properties>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+        <version>${checkstyle.version}</version>
+        <executions>
+          <execution>
+            <id>check-license</id>
+            <goals>
+              <goal>check</goal>
+            </goals>
+            <phase>none</phase>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <version>2.10</version>
+        <executions>
+          <execution>
+            <id>unpack-license</id>
+            <phase>none</phase>
+            <goals><goal>unpack</goal></goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/common/it-parent/pom.xml b/common/it-parent/pom.xml
new file mode 100644 (file)
index 0000000..9272cc4
--- /dev/null
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>mdsal-it-parent</artifactId>
+    <version>1.3.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>io.fd.honeycomb.common</groupId>
+  <artifactId>it-parent</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+  <packaging>pom</packaging>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+        <version>${checkstyle.version}</version>
+        <executions>
+          <execution>
+            <id>check-license</id>
+            <goals>
+              <goal>check</goal>
+            </goals>
+            <phase>none</phase>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <version>2.10</version>
+        <executions>
+          <execution>
+            <id>unpack-license</id>
+            <phase>none</phase>
+            <goals><goal>unpack</goal></goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/common/karaf-parent/pom.xml b/common/karaf-parent/pom.xml
new file mode 100644 (file)
index 0000000..253dc36
--- /dev/null
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>karaf-parent</artifactId>
+    <version>1.6.0-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>io.fd.honeycomb.common</groupId>
+  <artifactId>karaf-parent</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+  <packaging>pom</packaging>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+        <version>${checkstyle.version}</version>
+        <executions>
+          <execution>
+            <id>check-license</id>
+            <goals>
+              <goal>check</goal>
+            </goals>
+            <phase>none</phase>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <version>2.10</version>
+        <executions>
+          <execution>
+            <id>unpack-license</id>
+            <phase>none</phase>
+            <goals><goal>unpack</goal></goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/common/pom.xml b/common/pom.xml
new file mode 100644 (file)
index 0000000..ad9f382
--- /dev/null
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+<groupId>io.fd.honeycomb.common</groupId>
+  <artifactId>honeycomb-common-aggregator</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+  <name>honeycomb</name>
+  <packaging>pom</packaging>
+  <modelVersion>4.0.0</modelVersion>
+  <prerequisites>
+    <maven>3.1.1</maven>
+  </prerequisites>
+  <modules>
+    <module>api-parent</module>
+    <module>features-parent</module>
+    <module>impl-parent</module>
+    <module>it-parent</module>
+    <module>karaf-parent</module>
+  </modules>
+  <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-install-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/pom.xml b/pom.xml
new file mode 100644 (file)
index 0000000..15fd690
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+<groupId>io.fd.honeycomb</groupId>
+  <artifactId>honeycomb-aggregator</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+  <name>honeycomb</name>
+  <packaging>pom</packaging>
+  <modelVersion>4.0.0</modelVersion>
+  <prerequisites>
+    <maven>3.1.1</maven>
+  </prerequisites>
+  <modules>
+    <module>common</module>
+    <module>v3po</module>
+  </modules>
+  <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-install-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/v3po/api/pom.xml b/v3po/api/pom.xml
new file mode 100644 (file)
index 0000000..e31deea
--- /dev/null
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <groupId>io.fd.honeycomb.common</groupId>
+    <artifactId>api-parent</artifactId>
+    <version>1.0.0-SNAPSHOT</version>
+    <relativePath>../../common/api-parent</relativePath>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>io.fd.honeycomb.v3po</groupId>
+  <artifactId>v3po-api</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.opendaylight.mdsal.model</groupId>
+        <artifactId>mdsal-model-artifacts</artifactId>
+        <version>0.8.0-SNAPSHOT</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>iana-if-type-2014-05-08</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-yang-types-20130715</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-interfaces</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>ietf-inet-types-2013-07-15</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>yang-ext</artifactId>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/v3po/api/src/main/yang/ietf-ip.yang b/v3po/api/src/main/yang/ietf-ip.yang
new file mode 100644 (file)
index 0000000..f6c59ed
--- /dev/null
@@ -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:   <http://tools.ietf.org/wg/netmod/>
+  WG List:  <mailto:netmod@ietf.org>
+
+  WG Chair: Thomas Nadeau
+            <mailto:tnadeau@lucidvision.com>
+
+  WG Chair: Juergen Schoenwaelder
+            <mailto:j.schoenwaelder@jacobs-university.de>
+
+  Editor:   Martin Bjorklund
+            <mailto:mbj@tail-f.com>";
+
+  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 (file)
index 0000000..785e481
--- /dev/null
@@ -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 (file)
index 0000000..b4c2839
--- /dev/null
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>io.fd.honeycomb.v3po</groupId>
+  <artifactId>v3po-artifacts</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+  <packaging>pom</packaging>
+
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>v3po-api</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>v3po-impl</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>v3po-features</artifactId>
+        <version>${project.version}</version>
+        <classifier>features</classifier>
+        <type>xml</type>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+</project>
diff --git a/v3po/features/pom.xml b/v3po/features/pom.xml
new file mode 100644 (file)
index 0000000..e956174
--- /dev/null
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <groupId>io.fd.honeycomb.common</groupId>
+    <artifactId>features-parent</artifactId>
+    <version>1.0.0-SNAPSHOT</version>
+    <relativePath>../../common/features-parent</relativePath>
+  </parent>
+  <groupId>io.fd.honeycomb.v3po</groupId>
+  <artifactId>v3po-features</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+  <name>${project.artifactId}</name>
+  <modelVersion>4.0.0</modelVersion>
+  <prerequisites>
+    <maven>3.1.1</maven>
+  </prerequisites>
+  <properties>
+    <mdsal.model.version>0.8.0-SNAPSHOT</mdsal.model.version>
+    <mdsal.version>1.3.0-SNAPSHOT</mdsal.version>
+    <restconf.version>1.3.0-SNAPSHOT</restconf.version>
+    <netconf.version>1.0.0-SNAPSHOT</netconf.version>
+    <yangtools.version>0.8.0-SNAPSHOT</yangtools.version>
+    <dlux.version>0.3.0-SNAPSHOT</dlux.version>
+    <configfile.directory>etc/opendaylight/karaf</configfile.directory>
+  </properties>
+  <dependencyManagement>
+    <dependencies>
+      <!-- project specific dependencies -->
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>mdsal-artifacts</artifactId>
+        <version>${mdsal.version}</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.opendaylight.netconf</groupId>
+        <artifactId>restconf-artifacts</artifactId>
+        <version>${restconf.version}</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.opendaylight.netconf</groupId>
+        <artifactId>netconf-artifacts</artifactId>
+        <version>${netconf.version}</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>features-yangtools</artifactId>
+      <classifier>features</classifier>
+      <version>${yangtools.version}</version>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>features-mdsal-model</artifactId>
+      <version>${mdsal.model.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>features-mdsal</artifactId>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.netconf</groupId>
+      <artifactId>features-restconf</artifactId>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.netconf</groupId>
+      <artifactId>features-netconf-connector</artifactId>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.dlux</groupId>
+      <artifactId>features-dlux</artifactId>
+      <classifier>features</classifier>
+      <version>${dlux.version}</version>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>v3po-impl</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>v3po-impl</artifactId>
+      <version>${project.version}</version>
+      <type>xml</type>
+      <classifier>config</classifier>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>v3po-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>io.fd.vpp</groupId>
+      <artifactId>vppjapi</artifactId>
+      <version>1.0.0-SNAPSHOT</version>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/v3po/features/src/main/features/features.xml b/v3po/features/src/main/features/features.xml
new file mode 100644 (file)
index 0000000..2055dd9
--- /dev/null
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ 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.
+-->
+<features name="odl-v3po-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
+  <repository>mvn:org.opendaylight.yangtools/features-yangtools/${yangtools.version}/xml/features</repository>
+  <repository>mvn:org.opendaylight.controller/features-mdsal/${mdsal.version}/xml/features</repository>
+  <repository>mvn:org.opendaylight.mdsal.model/features-mdsal-model/${mdsal.model.version}/xml/features</repository>
+  <repository>mvn:org.opendaylight.netconf/features-restconf/${restconf.version}/xml/features</repository>
+  <repository>mvn:org.opendaylight.netconf/features-netconf-connector/${netconf.version}/xml/features</repository>
+  <repository>mvn:org.opendaylight.dlux/features-dlux/${dlux.version}/xml/features</repository>
+
+  <feature name='odl-v3po-api' version='${project.version}' description='OpenDaylight :: v3po :: api'>
+    <feature version='${mdsal.model.version}'>odl-mdsal-models</feature>
+    <bundle>mvn:io.fd.honeycomb.v3po/v3po-api/${project.version}</bundle>
+  </feature>
+
+  <feature name='odl-v3po' version='${project.version}' description='OpenDaylight :: v3po'>
+    <feature version='${mdsal.version}'>odl-mdsal-broker</feature>
+    <feature version='${project.version}'>odl-v3po-api</feature>
+    <feature version='${netconf.version}'>odl-netconf-connector-ssh</feature>
+    <feature version='${mdsal.version}'>odl-netconf-mdsal</feature>
+    <bundle>mvn:io.fd.honeycomb.v3po/v3po-impl/${project.version}</bundle>
+    <bundle>wrap:mvn:io.fd.vpp/vppjapi/1.0.0-SNAPSHOT</bundle>
+    <configfile finalname="${configfile.directory}/v3po.xml">mvn:io.fd.honeycomb.v3po/v3po-impl/${project.version}/xml/config</configfile>
+  </feature>
+
+  <feature name='odl-v3po-rest' version='${project.version}' description='OpenDaylight :: v3po :: REST'>
+    <feature version="${project.version}">odl-v3po</feature>
+    <feature version="${restconf.version}">odl-restconf</feature>
+  </feature>
+
+  <feature name='odl-v3po-ui' version='${project.version}' description='OpenDaylight :: v3po :: UI'>
+    <feature version="${project.version}">odl-v3po-rest</feature>
+    <feature version="${restconf.version}">odl-mdsal-apidocs</feature>
+    <feature version="${mdsal.version}">odl-mdsal-xsql</feature>
+    <feature version="${dlux.version}">odl-dlux-yangui</feature>
+  </feature>
+
+</features>
diff --git a/v3po/impl/pom.xml b/v3po/impl/pom.xml
new file mode 100644 (file)
index 0000000..9315c15
--- /dev/null
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <parent>
+    <groupId>io.fd.honeycomb.common</groupId>
+    <artifactId>impl-parent</artifactId>
+    <version>1.0.0-SNAPSHOT</version>
+    <relativePath>../../common/impl-parent</relativePath>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>io.fd.honeycomb.v3po</groupId>
+  <artifactId>v3po-impl</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+  <dependencies>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>v3po-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>io.fd.vpp</groupId>
+      <artifactId>vppjapi</artifactId>
+      <version>1.0.0-SNAPSHOT</version>
+    </dependency>
+
+    <!-- Testing Dependencies -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/v3po/impl/src/main/config/default-config.xml b/v3po/impl/src/main/config/default-config.xml
new file mode 100644 (file)
index 0000000..08a090e
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ 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.
+-->
+<snapshot>
+  <required-capabilities>
+      <capability>urn:opendaylight:params:xml:ns:yang:v3po:impl?module=v3po-impl&amp;revision=2014-12-10</capability>
+      <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&amp;revision=2013-10-28</capability>
+  </required-capabilities>
+  <configuration>
+
+    <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+      <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+        <module>
+          <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:v3po:impl">prefix:v3po</type>
+          <name>v3po-default</name>
+          <broker>
+            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
+            <name>binding-osgi-broker</name>
+          </broker>
+        </module>
+      </modules>
+    </data>
+  </configuration>
+</snapshot>
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 (file)
index 0000000..5888dc9
--- /dev/null
@@ -0,0 +1,24 @@
+/*\r
+ * Copyright (c) 2015 Cisco and/or its affiliates.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at:\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package io.fd.honeycomb.v3po.impl;\r
+\r
+import org.opendaylight.yangtools.yang.binding.DataObject;\r
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;\r
+\r
+public interface DataRegistry {\r
+    <T extends DataObject> void registerModule(InstanceIdentifier<T> path, DataResolver<T> resolver);\r
+}\r
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 (file)
index 0000000..5ada80f
--- /dev/null
@@ -0,0 +1,26 @@
+/*\r
+ * Copyright (c) 2015 Cisco and/or its affiliates.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at:\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package io.fd.honeycomb.v3po.impl;\r
+\r
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;\r
+import org.opendaylight.yangtools.yang.binding.DataObject;\r
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;\r
+\r
+public interface DataResolver<T extends DataObject> {\r
+    public void resolve(InstanceIdentifier<T> path, WriteTransaction tx);\r
+}\r
+\r
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 (file)
index 0000000..fd2d48c
--- /dev/null
@@ -0,0 +1,36 @@
+/*\r
+ * Copyright (c) 2015 Cisco and/or its affiliates.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at:\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+\r
+package io.fd.honeycomb.v3po.impl;\r
+\r
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;\r
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;\r
+\r
+// Return Interface data from interfaces.state based on InstanceIdentifier \r
+public class DataResolverInterfaceState implements DataResolver<Interface> {\r
+    \r
+    @Override\r
+    public void resolve(InstanceIdentifier<Interface> path,\r
+                        WriteTransaction tx) {\r
+        InterfaceKey key = path.firstKeyOf(Interface.class);\r
+        String interfaceName = key.getName();\r
+        \r
+        return;\r
+    }\r
+}\r
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 (file)
index 0000000..5e2141d
--- /dev/null
@@ -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<Address> addrs = new ArrayList<Address>();
+    private List<Neighbor> neighbors = new ArrayList<Neighbor>();
+    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 (file)
index 0000000..42862a9
--- /dev/null
@@ -0,0 +1,87 @@
+/*\r
+ * Copyright (c) 2015 Cisco and/or its affiliates.\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at:\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package io.fd.honeycomb.v3po.impl;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6AddressNoZone;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.IpAddressOrigin;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.NeighborOrigin;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv6;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv6Builder;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv6.Address;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv6.AddressBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv6.Neighbor;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv6.NeighborBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;\r
+\r
+public class InterfaceStateIpv6Builder {\r
+    private List<Address> addrs = new ArrayList<Address>();\r
+    private List<Neighbor> neighbors = new ArrayList<Neighbor>();\r
+    private Ipv6Builder ipv6Builder = new Ipv6Builder();\r
+    \r
+    /**\r
+     * TODO-ADD-JAVADOC.\r
+     */\r
+    public void addAddress(String ipv6Addr, short prefixLength, IpAddressOrigin origin) {\r
+        // address\r
+        AddressBuilder addrBuilder = new AddressBuilder();\r
+        \r
+        // IpAddressOrigin.Static\r
+        addrBuilder.setOrigin(origin); // FIXME: how to find origin?\r
+        addrBuilder.setPrefixLength(prefixLength);\r
+        addrBuilder.setIp(new Ipv6AddressNoZone(ipv6Addr));\r
+        \r
+        addrs.add(addrBuilder.build());\r
+    }\r
+    \r
+    /**\r
+     * TODO-ADD-JAVADOC.\r
+     */\r
+    public void addNeighbor(String ipv6Addr, String physAddr, NeighborOrigin origin) {\r
+        // address neighbor\r
+        NeighborBuilder nbrBuilder = new NeighborBuilder();\r
+        nbrBuilder.setIp(new Ipv6AddressNoZone(ipv6Addr));\r
+        nbrBuilder.setLinkLayerAddress(new PhysAddress(physAddr)); // TODO ("00:00:00:00:00:00")\r
+        nbrBuilder.setOrigin(origin);\r
+        \r
+        neighbors.add(nbrBuilder.build());\r
+    }\r
+    \r
+    /**\r
+     * TODO-ADD-JAVADOC.\r
+     */\r
+    public void setForwarding(boolean fwd) {\r
+        ipv6Builder.setForwarding(fwd);\r
+    }\r
+    \r
+    /**\r
+     * TODO-ADD-JAVADOC.\r
+     */\r
+    public void setMtu(long mtu) {\r
+        ipv6Builder.setMtu(mtu);\r
+    }\r
+    \r
+    /**\r
+     * TODO-ADD-JAVADOC.\r
+     */\r
+    public Ipv6 build() {\r
+        ipv6Builder.setAddress(addrs);\r
+        ipv6Builder.setNeighbor(neighbors);\r
+        return ipv6Builder.build();\r
+    }\r
+}\r
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 (file)
index 0000000..35795cb
--- /dev/null
@@ -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<V> implements FutureCallback<V> {
+
+    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 (file)
index 0000000..f466adb
--- /dev/null
@@ -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<Interface> getStateInterfaceIid(String interfaceName) {
+        return InstanceIdentifier.create(InterfacesState.class).child(Interface.class,
+                new InterfaceKey(interfaceName));
+    }
+    
+    private InstanceIdentifier<Interface2> getStateInterfaceIpId(InstanceIdentifier<Interface> iid) {
+        return iid.augmentation(Interface2.class);
+    }
+    
+    private InstanceIdentifier<Statistics> getStateInterfaceStatsId(InstanceIdentifier<Interface> 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<? extends InterfaceType> 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<NodeIdentifierWithPredicates, MapEntryNode> 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<Interface> 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<Void, TransactionCommitFailedException> future =
+            transaction.submit();
+        Futures.addCallback(future, new LoggingFuturesCallBack<Void>(
+                "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<Interface> 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 (file)
index 0000000..3b546f1
--- /dev/null
@@ -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> 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<BridgeDomain> 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<Void, TransactionCommitFailedException> future = transaction.submit();
+        Futures.addCallback(future, new LoggingFuturesCallBack<Void>(
+                "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<Address> addrs = new ArrayList<Address>();
+        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<Interface> iid = 
+            InstanceIdentifier.create(Interfaces.class)
+            .child(Interface.class, new InterfaceKey(name));
+        WriteTransaction transaction = db.newWriteOnlyTransaction();
+        transaction.put(LogicalDatastoreType.CONFIGURATION, iid, ifBuilder.build());
+        CheckedFuture<Void, TransactionCommitFailedException> future = transaction.submit();
+        Futures.addCallback(future, new LoggingFuturesCallBack<Void>(
+                "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<Interface> iid = InstanceIdentifier.create(Interfaces.class)
+            .child(Interface.class, new InterfaceKey(name));
+        WriteTransaction transaction = db.newWriteOnlyTransaction();
+        transaction.put(LogicalDatastoreType.CONFIGURATION, iid, ifBuilder.build());
+        CheckedFuture<Void, TransactionCommitFailedException> future = transaction.submit();
+        Futures.addCallback(future, new LoggingFuturesCallBack<Void>(
+                "VPPCFG-WARNING: Failed to write " + name + "interface to ietf-interfaces", LOG));
+    }
+
+    private void initializeVppConfig() {
+
+        WriteTransaction transaction = db.newWriteOnlyTransaction();
+        InstanceIdentifier<Vpp> viid = InstanceIdentifier.create(Vpp.class);
+        Vpp vpp = new VppBuilder().build();
+        transaction.put(LogicalDatastoreType.CONFIGURATION, viid, vpp);
+        CheckedFuture<Void, TransactionCommitFailedException> 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<Interfaces> 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<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.
+         * interfaces.rev140508.interfaces.state.Interface> ifaces = new
+         * ArrayList<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.
+         * ietf.interfaces.rev140508.interfaces.state.Interface>();
+         */
+        LOG.info("VPPOPER-INFO: Preparing to initialize the IETF Interface " + "state list operational db.");
+        InterfacesState ifsState = new InterfacesStateBuilder().build();
+        WriteTransaction tx = db.newWriteOnlyTransaction();
+        InstanceIdentifier<InterfacesState> 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 (file)
index 0000000..9001615
--- /dev/null
@@ -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 (file)
index 0000000..94d8df7
--- /dev/null
@@ -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<BridgeDomain>,
+                                                AutoCloseable {
+    private static final Logger LOG = 
+        LoggerFactory.getLogger(VppBridgeDomainListener.class);
+    private ListenerRegistration<VppBridgeDomainListener> 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<BridgeDomain> iid = InstanceIdentifier
+                .create(Vpp.class)
+                .child(BridgeDomains.class)
+                .child(BridgeDomain.class);
+        LOG.info("VPPCFG-INFO: Register listener for VPP Bridge Domain data changes");
+        
+        DataTreeIdentifier<BridgeDomain> path = 
+                new DataTreeIdentifier<BridgeDomain>(LogicalDatastoreType.CONFIGURATION, iid);
+        registration = this.db.registerDataTreeChangeListener(path, this);
+    }
+
+    @Override 
+    public void onDataTreeChanged(Collection<DataTreeModification<BridgeDomain>> changes) { 
+        
+        for (DataTreeModification<BridgeDomain> change: changes) {
+            InstanceIdentifier<BridgeDomain> iid = change.getRootPath().getRootIdentifier();
+            DataObjectModification<BridgeDomain> 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: {} <bridgeDomain>", 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: {} </bridgeDomain>", 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<BridgeDomain> 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<BridgeDomain> changeDiff) {
+        DataChangeType type = DataChangeType.DELETE;
+        BridgeDomain bridgeDomain = changeDiff.getDataBefore();
+        String bdName = bridgeDomain.getName();
+        int rv = -77;
+        int cnt = 0;
+
+        LOG.info("VPPCFG-INFO: {} <bridgeDomain>", 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: {} </bridgeDomain>", 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 (file)
index 0000000..7e6aa50
--- /dev/null
@@ -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<Interface>, AutoCloseable {
+    private static final Logger LOG = 
+        LoggerFactory.getLogger(VppIetfInterfaceListener.class);
+    
+    private ListenerRegistration<VppIetfInterfaceListener> 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<Interface> iid = InstanceIdentifier
+                .create(Interfaces.class)
+                .child(Interface.class);
+        LOG.info("VPPCFG-INFO: Register listener for VPP Ietf Interface data changes");
+        
+        DataTreeIdentifier<Interface> path = 
+                new DataTreeIdentifier<Interface>(LogicalDatastoreType.CONFIGURATION, iid);
+        
+        registration = this.db.registerDataTreeChangeListener(path, this);
+    }
+    
+    @Override 
+    public void onDataTreeChanged(Collection<DataTreeModification<Interface>> changes) { 
+        LOG.info("VPPCFG-INFO: swIf onDataTreeChanged()");
+        for (DataTreeModification<Interface> change: changes) {
+            InstanceIdentifier<Interface> iid = change.getRootPath().getRootIdentifier();
+            DataObjectModification<Interface> 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: <vppSetVppInterfaceEthernetAndL2>");
+        LOG.info("VPPCFG-INFO:     swIfIndex = {}", swIfIndex);
+        LOG.info("VPPCFG-INFO:     swIfName  = {}", swIfName);
+        LOG.info("VPPCFG-INFO:     vppInterface  = {}", vppInterface);
+        LOG.info("VPPCFG-INFO: </vppSetVppInterfaceEthernetAndL2>");
+        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: {} <swIf>", type);
+        LOG.info("VPPCFG-INFO:    Name: " + swIf.getName());
+        LOG.info("VPPCFG-INFO:    Desc: " + swIf.getDescription());
+        java.lang.Class<? extends 
+            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType>
+            ifType = swIf.getType();
+        if (ifType != null) {
+            LOG.info("VPPCFG-INFO:    Type: " + swIf.getType().getSimpleName());
+        }
+        LOG.info("VPPCFG-INFO: {} </swIf>", 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<Interface> 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<Interface> changeDiff) {
+        Interface swIf = changeDiff.getDataBefore();
+        LOG.info("VPPCFG-INFO: <swIf>");
+        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: </swIf>");
+
+        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 (file)
index 0000000..71d4bea
--- /dev/null
@@ -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<Integer, vppL2Fib[]> l2fibByBdId = new HashMap<Integer, vppL2Fib[]>();
+
+    /**
+     * 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<RpcResult<VppPollOperDataOutput>> vppPollOperData() {
+        String ifNames = updateOperational();
+        
+
+        VppPollOperDataOutput output = new VppPollOperDataOutputBuilder()
+            .setStatus(new Long(1)).build();
+
+        return RpcResultBuilder.success(output).buildFuture();
+    }
+    
+    private InstanceIdentifier<VppState> getVppStateIid() {
+        return (InstanceIdentifier.create(VppState.class));
+    }
+    
+    private void writeVppState(InstanceIdentifier<VppState> iid, VppState vppState) {
+        WriteTransaction transaction = db.newWriteOnlyTransaction();
+
+        //LOG.info("VPPOPER-INFO: Writing vpp-state to oper DataStore.");
+        transaction.put(LogicalDatastoreType.OPERATIONAL, iid, vppState);
+        
+        CheckedFuture<Void, TransactionCommitFailedException> future = transaction.submit();
+        Futures.addCallback(future, new LoggingFuturesCallBack<Void>(
+                "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 (file)
index 0000000..d547342
--- /dev/null
@@ -0,0 +1,102 @@
+/*\r
+ * Copyright (c) 2015 Cisco and/or its affiliates.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at:\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package io.fd.honeycomb.v3po.impl;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.Interface;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.InterfaceBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.L2Fib;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.L2Fib.Action;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.L2FibBuilder;\r
+\r
+public class VppStateBridgeDomainBuilder {\r
+    private BridgeDomainBuilder bdStateBuilder = new BridgeDomainBuilder();\r
+    private List<Interface> bdIfaces = new ArrayList<Interface>();\r
+    private List<L2Fib> bdL2Fibs = new ArrayList<L2Fib>();\r
+    \r
+    /**\r
+     * TODO-ADD-JAVADOC.\r
+     */\r
+    public VppStateBridgeDomainBuilder(String bdName, boolean flood,\r
+                                       boolean unknownUnicastFlood,\r
+                                       boolean arpTermination,\r
+                                       boolean forward, boolean learn) {\r
+        bdStateBuilder\r
+            .setName(bdName)\r
+            .setFlood(flood)\r
+            .setUnknownUnicastFlood(unknownUnicastFlood)\r
+            .setArpTermination(arpTermination)\r
+            .setForward(forward)\r
+            .setLearn(learn);\r
+    }\r
+    \r
+    /**\r
+     * TODO-ADD-JAVADOC.\r
+     */\r
+    public void addInterface(String interfaceName, boolean bvi,\r
+                             short splitHorizonGroup) {\r
+        InterfaceBuilder ifBuilder = new InterfaceBuilder();\r
+        ifBuilder\r
+            .setName(interfaceName)\r
+            .setBridgedVirtualInterface(bvi)\r
+            .setSplitHorizonGroup(splitHorizonGroup);\r
+        \r
+        bdIfaces.add(ifBuilder.build());\r
+    }\r
+    \r
+    private static String getMacAddress(byte[] mac) {\r
+        StringBuilder sb = new StringBuilder(18);\r
+        for (byte b : mac) {\r
+            if (sb.length() > 0) {\r
+                sb.append(':');\r
+            }\r
+            sb.append(String.format("%02x", b));\r
+        }\r
+        return sb.toString();\r
+    }\r
+    \r
+    /**\r
+     * TODO-ADD-JAVADOC.\r
+     */\r
+    public void addL2Fib(boolean filter, boolean bvi,\r
+                         String outgoingIfaceName, byte[] physAddress,\r
+                         boolean isStatic) {\r
+        L2FibBuilder l2fibBuilder = new L2FibBuilder();\r
+        l2fibBuilder\r
+            .setAction((filter ? Action.Filter : Action.Forward))\r
+            .setBridgedVirtualInterface(bvi)\r
+            .setOutgoingInterface(outgoingIfaceName)\r
+            .setPhysAddress(new PhysAddress(getMacAddress(physAddress)))\r
+            .setStaticConfig(isStatic);\r
+        \r
+        bdL2Fibs.add(l2fibBuilder.build());\r
+    }\r
+    \r
+    /**\r
+     * TODO-ADD-JAVADOC.\r
+     */\r
+    public BridgeDomain build() {\r
+        bdStateBuilder.setInterface(bdIfaces);\r
+        bdStateBuilder.setL2Fib(bdL2Fibs);\r
+        return bdStateBuilder.build();\r
+    }\r
+}\r
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 (file)
index 0000000..86e44ec
--- /dev/null
@@ -0,0 +1,73 @@
+/*\r
+ * Copyright (c) 2015 Cisco and/or its affiliates.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at:\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package io.fd.honeycomb.v3po.impl;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppStateBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomainsBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.VersionBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain;\r
+import org.openvpp.vppjapi.vppVersion;\r
+\r
+public class VppStateCustomBuilder {\r
+    VppStateBuilder stateBuilder = new VppStateBuilder();\r
+    \r
+    List<BridgeDomain> bridgeDomains = new ArrayList<BridgeDomain>();\r
+    \r
+    /**\r
+     * TODO-ADD-JAVADOC.\r
+     */\r
+    public void setVersion(String name, String branch, String buildDate,\r
+                           String buildDir) {\r
+        stateBuilder.setVersion(\r
+                new VersionBuilder()\r
+                    .setBranch(branch)\r
+                    .setBuildDate(buildDate)\r
+                    .setBuildDirectory(buildDir)\r
+                    .setName(name)\r
+                    .build());\r
+    }\r
+    \r
+    /**\r
+     * TODO-ADD-JAVADOC.\r
+     */\r
+    public void setVersion(vppVersion vppVer) {\r
+        setVersion(vppVer.programName, vppVer.gitBranch,\r
+                   vppVer.buildDate, vppVer.buildDirectory);\r
+    }\r
+    \r
+    /**\r
+     * TODO-ADD-JAVADOC.\r
+     */\r
+    public void addBridgeDomain(BridgeDomain bd) {\r
+        bridgeDomains.add(bd);\r
+    }\r
+    \r
+    /**\r
+     * TODO-ADD-JAVADOC.\r
+     */\r
+    public VppState build() {\r
+        stateBuilder.setBridgeDomains(\r
+                new BridgeDomainsBuilder()\r
+                    .setBridgeDomain(bridgeDomains)\r
+                    .build());\r
+        return stateBuilder.build();\r
+    }\r
+}\r
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 (file)
index 0000000..5a5fd11
--- /dev/null
@@ -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 (file)
index 0000000..5c94286
--- /dev/null
@@ -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 (file)
index 0000000..7a6fd42
--- /dev/null
@@ -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 (file)
index 0000000..5b9a674
--- /dev/null
@@ -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 (file)
index 0000000..9987254
--- /dev/null
@@ -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 (file)
index 0000000..e7afb75
--- /dev/null
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <parent>
+    <groupId>io.fd.honeycomb.common</groupId>
+    <artifactId>it-parent</artifactId>
+    <version>1.0.0-SNAPSHOT</version>
+    <relativePath>../../common/it-parent</relativePath>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>io.fd.honeycomb.v3po</groupId>
+  <artifactId>v3po-it</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+
+  <properties>
+    <skipITs>false</skipITs>
+    <karaf.distro.groupId>io.fd.honeycomb.v3po</karaf.distro.groupId>
+    <karaf.distro.artifactId>v3po-karaf</karaf.distro.artifactId>
+    <karaf.distro.version>1.0.0-SNAPSHOT</karaf.distro.version>
+    <karaf.distro.type>zip</karaf.distro.type>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>v3po-features</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+
+</project>
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 (file)
index 0000000..abd2821
--- /dev/null
@@ -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 (file)
index 0000000..17d4a48
--- /dev/null
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <groupId>io.fd.honeycomb.common</groupId>
+    <artifactId>karaf-parent</artifactId>
+    <version>1.0.0-SNAPSHOT</version>
+    <relativePath>../../common/karaf-parent</relativePath>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>io.fd.honeycomb.v3po</groupId>
+  <artifactId>v3po-karaf</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+  <name>${project.artifactId}</name>
+  <prerequisites>
+    <maven>3.1.1</maven>
+  </prerequisites>
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>v3po-artifacts</artifactId>
+        <version>${project.version}</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+  <dependencies>
+    <dependency>
+      <!-- scope is compile so all features (there is only one) are installed
+      into startup.properties and the feature repo itself is not installed -->
+      <groupId>org.apache.karaf.features</groupId>
+      <artifactId>framework</artifactId>
+      <type>kar</type>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>v3po-features</artifactId>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+  </dependencies>
+  <!-- DO NOT install or deploy the karaf artifact -->
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/v3po/pom.xml b/v3po/pom.xml
new file mode 100644 (file)
index 0000000..a21b80f
--- /dev/null
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <parent>
+    <groupId>org.opendaylight.odlparent</groupId>
+    <artifactId>odlparent</artifactId>
+    <version>1.6.0-SNAPSHOT</version>
+  </parent>
+
+  <groupId>io.fd.honeycomb.v3po</groupId>
+  <artifactId>v3po-aggregator</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+  <name>v3po</name>
+  <packaging>pom</packaging>
+  <modelVersion>4.0.0</modelVersion>
+  <prerequisites>
+    <maven>3.1.1</maven>
+  </prerequisites>
+  <modules>
+    <module>api</module>
+    <module>impl</module>
+    <module>karaf</module>
+    <module>features</module>
+    <module>artifacts</module>
+    <!--module>it</module-->
+  </modules>
+  <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-install-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>