summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--v3po/api/pom.xml64
-rw-r--r--v3po/api/src/main/yang/ietf-ip.yang742
-rw-r--r--v3po/api/src/main/yang/v3po.yang366
-rw-r--r--v3po/artifacts/pom.xml46
-rw-r--r--v3po/features/pom.xml135
-rw-r--r--v3po/features/src/main/features/features.xml54
-rw-r--r--v3po/impl/pom.xml57
-rw-r--r--v3po/impl/src/main/config/default-config.xml37
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/DataRegistry.java24
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/DataResolver.java26
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/DataResolverInterfaceState.java36
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/InterfaceStateIpv4Builder.java94
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/InterfaceStateIpv6Builder.java87
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/LoggingFuturesCallBack.java48
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poApiRequest.java461
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poProvider.java326
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poRequest.java28
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppBridgeDomainListener.java217
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppIetfInterfaceListener.java566
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppPollOperDataImpl.java147
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppStateBridgeDomainBuilder.java102
-rw-r--r--v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppStateCustomBuilder.java73
-rw-r--r--v3po/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModule.java41
-rw-r--r--v3po/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactory.java28
-rw-r--r--v3po/impl/src/main/yang/v3po-impl.yang35
-rw-r--r--v3po/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactoryTest.java26
-rw-r--r--v3po/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleTest.java62
-rw-r--r--v3po/it/pom.xml48
-rw-r--r--v3po/it/src/test/java/io/fd/honeycomb/v3po/it/V3poIT.java77
-rw-r--r--v3po/karaf/pom.xml71
-rw-r--r--v3po/pom.xml60
31 files changed, 4184 insertions, 0 deletions
diff --git a/v3po/api/pom.xml b/v3po/api/pom.xml
new file mode 100644
index 000000000..e31deea1f
--- /dev/null
+++ b/v3po/api/pom.xml
@@ -0,0 +1,64 @@
+<?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
index 000000000..f6c59edea
--- /dev/null
+++ b/v3po/api/src/main/yang/ietf-ip.yang
@@ -0,0 +1,742 @@
+module ietf-ip {
+
+ yang-version 1;
+
+ namespace
+ "urn:ietf:params:xml:ns:yang:ietf-ip";
+
+ prefix ip;
+
+ import ietf-interfaces {
+ prefix if;
+ }
+ import ietf-inet-types {
+ prefix inet;
+ }
+ import ietf-yang-types {
+ prefix yang;
+ }
+
+ organization
+ "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+ contact
+ "WG Web: <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
index 000000000..785e48146
--- /dev/null
+++ b/v3po/api/src/main/yang/v3po.yang
@@ -0,0 +1,366 @@
+module v3po {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:v3po";
+ prefix "v3po";
+
+ revision "2015-01-05" {
+ description "Initial revision of v3po model";
+ }
+
+ import iana-if-type {
+ prefix "ianaift";
+ }
+ import ietf-interfaces {
+ prefix "if";
+ }
+ import ietf-yang-types {
+ prefix "yang";
+ }
+ import ietf-inet-types {
+ prefix "inet";
+ }
+ import ietf-ip {
+ prefix "ip";
+ }
+ import yang-ext {
+ prefix "ext";
+ }
+
+ typedef bridge-domain-ref {
+ type leafref {
+ path "/vpp/bridge-domains/bridge-domain/name";
+ }
+ description
+ "This type is used by to reference a bridge domain table";
+ }
+
+ typedef bridged-virtual-interface-ref {
+ type leafref {
+ path "/if:interfaces/if:interface/l2/bridged-virtual-interface";
+ }
+ description
+ "This type is used by to reference a bridged virtual interface";
+ }
+
+ identity vxlan-tunnel {
+ base if:interface-type;
+ }
+
+ augment /if:interfaces/if:interface {
+ ext:augment-identifier "vpp-interface-augmentation";
+ container ethernet {
+ when "../if:type = 'ianaift:ethernetCsmacd'";
+ leaf mtu {
+ type uint16 {
+ range "64..9216";
+ }
+ units "octets";
+ default 9216;
+ description
+ "The size, in octets, of the largest packet that the
+ hardware interface will send and receive.";
+ }
+ }
+ container routing {
+ leaf vrf-id {
+ type uint32;
+ default 0;
+ }
+ }
+ container vxlan {
+ when "../if:type = 'v3po:vxlan-tunnel'";
+
+ leaf src {
+ /* mandatory true; */
+ type inet:ipv4-address;
+ }
+ leaf dst {
+ /* mandatory true; */
+ type inet:ipv4-address;
+ }
+ leaf vni {
+ /* mandatory true; */
+ type uint32;
+ }
+ leaf encap-vrf-id {
+ type uint32;
+ }
+ }
+ container l2 {
+ description
+ "Parameters for configuring Layer2 features on interfaces.";
+ must "(not (../if:ipv4[if:enabled = 'true']/if:address/if:ip) and " +
+ "not (../if:ipv6[if:enabled = 'true']/if:address/if:ip))";
+
+ choice interconnection {
+ case xconnect-based {
+ leaf xconnect-outgoing-interface {
+ /* Don't allow selection of this interface */
+ must "../../if:name != current()";
+ type if:interface-ref;
+ description
+ "L2 xconnect mode";
+ }
+ }
+ case bridge-based {
+ leaf bridge-domain {
+ type bridge-domain-ref;
+ description
+ "Interfaces in a bridge-domain forward packets to other
+ interfaces in the same bridge-domain based on
+ destination mac address.";
+ }
+ leaf split-horizon-group {
+ when "../bridge-domain";
+ type uint8 {
+ range "0..255";
+ }
+ default 0;
+ description
+ "Interface's split-horizon group. Interfaces in the same
+ bridge-domain and split-horizon group can not forward
+ packets between each other. ";
+ }
+ leaf bridged-virtual-interface {
+ when "../bridge-domain";
+ type boolean;
+ default false;
+ description
+ "Interface forward packets in the bridge-domain
+ associated with the BVI.";
+ }
+ }
+ }
+ }
+ }
+
+ container vpp {
+ description
+ "VPP config data";
+
+ container bridge-domains {
+ list bridge-domain {
+ key "name";
+ max-elements 1024;
+
+ leaf name {
+ type string;
+ }
+ leaf flood {
+ type boolean;
+ default true;
+ description
+ "Enable/disable L2 flooding.";
+ }
+ leaf forward {
+ type boolean;
+ default true;
+ description
+ "Enable/disable L2 forwarding.";
+ }
+ leaf learn {
+ type boolean;
+ default true;
+ description
+ "Enable/disable L2 learning.";
+ }
+ leaf unknown-unicast-flood {
+ type boolean;
+ default true;
+ }
+ leaf arp-termination {
+ type boolean;
+ default false;
+ }
+ list l2-fib {
+ key "phys-address";
+
+ leaf phys-address {
+ type yang:phys-address;
+ }
+ leaf action {
+ type enumeration {
+ enum "forward";
+ enum "filter";
+ }
+ mandatory true;
+ }
+ leaf outgoing-interface {
+ type if:interface-ref;
+ }
+ }
+ }
+ }
+ }
+
+ augment /if:interfaces-state/if:interface {
+ ext:augment-identifier "vpp-interface-state-augmentation";
+
+ leaf description {
+ type string;
+ }
+ container ethernet {
+ when "../if:type = 'ianaift:ethernetCsmacd'";
+ leaf mtu {
+ type uint16;
+ }
+ leaf manufacturer-description {
+ type string;
+ }
+ leaf duplex {
+ type enumeration {
+ enum "half";
+ enum "full";
+ }
+ }
+ }
+ container vxlan {
+ when "../if:type = 'v3po:vxlan-tunnel'";
+
+ leaf src {
+ type inet:ipv4-address;
+ }
+ leaf dst {
+ type inet:ipv4-address;
+ }
+ leaf vni {
+ type uint32;
+ }
+ leaf encap-vrf-id {
+ type uint32;
+ }
+ }
+ container l2 {
+ choice interconnection {
+ case xconnect-based {
+ leaf xconnect-outgoing-interface {
+ type if:interface-ref;
+ }
+ }
+ case bridge-based {
+ leaf bridge-domain {
+ type bridge-domain-ref;
+ }
+ leaf split-horizon-group {
+ type uint8;
+ }
+ leaf bridged-virtual-interface {
+ type boolean;
+ }
+ }
+ }
+ }
+ }
+
+ augment /if:interfaces-state/if:interface/if:statistics {
+ ext:augment-identifier "vpp-interface-statistics-augmentation";
+ leaf in-errors-no-buf {
+ type yang:counter64;
+ }
+ leaf in-errors-miss {
+ type yang:counter64;
+ }
+ leaf out-discards-fifo-full {
+ type yang:counter64;
+ }
+ }
+
+ container vpp-state {
+ config false;
+
+ description
+ "VPP operational data";
+
+ container bridge-domains {
+ list bridge-domain {
+
+ key "name";
+ leaf name {
+ type string;
+ }
+ leaf flood {
+ type boolean;
+ }
+ leaf unknown-unicast-flood {
+ type boolean;
+ }
+ leaf arp-termination {
+ type boolean;
+ }
+ leaf forward {
+ type boolean;
+ }
+ leaf learn {
+ type boolean;
+ }
+ list interface {
+ key "name";
+
+ leaf name {
+ type if:interface-state-ref;
+ }
+
+ leaf split-horizon-group {
+ type uint8;
+ }
+
+ leaf bridged-virtual-interface {
+ type boolean;
+ }
+ }
+ list l2-fib {
+ key "phys-address";
+
+ leaf phys-address {
+ type yang:phys-address;
+ }
+ leaf static-config {
+ type boolean;
+ }
+ leaf outgoing-interface {
+ when "../v3po:action = 'forward'";
+ type if:interface-state-ref;
+ }
+ leaf action {
+ type enumeration {
+ enum "forward";
+ enum "filter";
+ }
+ mandatory true;
+ }
+ leaf bridged-virtual-interface {
+ when "../v3po:action = 'forward'";
+ type boolean;
+ }
+ }
+ description
+ "bridge-domain operational data";
+ }
+ }
+
+ container version {
+ leaf name {
+ type string;
+ }
+ leaf build-directory {
+ type string;
+ }
+ leaf build-date {
+ type string;
+ }
+ leaf branch {
+ type string;
+ }
+ description
+ "vlib version info";
+ }
+ }
+
+ rpc vpp-poll-oper-data {
+ output {
+ leaf status {
+ type uint32;
+ }
+ }
+ }
+}
diff --git a/v3po/artifacts/pom.xml b/v3po/artifacts/pom.xml
new file mode 100644
index 000000000..b4c283973
--- /dev/null
+++ b/v3po/artifacts/pom.xml
@@ -0,0 +1,46 @@
+<?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
index 000000000..e95617451
--- /dev/null
+++ b/v3po/features/pom.xml
@@ -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
index 000000000..2055dd935
--- /dev/null
+++ b/v3po/features/src/main/features/features.xml
@@ -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
index 000000000..9315c15cc
--- /dev/null
+++ b/v3po/impl/pom.xml
@@ -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
index 000000000..08a090ea2
--- /dev/null
+++ b/v3po/impl/src/main/config/default-config.xml
@@ -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
index 000000000..5888dc998
--- /dev/null
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/DataRegistry.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.impl;
+
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public interface DataRegistry {
+ <T extends DataObject> void registerModule(InstanceIdentifier<T> path, DataResolver<T> resolver);
+}
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/DataResolver.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/DataResolver.java
new file mode 100644
index 000000000..5ada80f86
--- /dev/null
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/DataResolver.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.impl;
+
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public interface DataResolver<T extends DataObject> {
+ public void resolve(InstanceIdentifier<T> path, WriteTransaction tx);
+}
+
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/DataResolverInterfaceState.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/DataResolverInterfaceState.java
new file mode 100644
index 000000000..fd2d48c01
--- /dev/null
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/DataResolverInterfaceState.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package io.fd.honeycomb.v3po.impl;
+
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+// Return Interface data from interfaces.state based on InstanceIdentifier
+public class DataResolverInterfaceState implements DataResolver<Interface> {
+
+ @Override
+ public void resolve(InstanceIdentifier<Interface> path,
+ WriteTransaction tx) {
+ InterfaceKey key = path.firstKeyOf(Interface.class);
+ String interfaceName = key.getName();
+
+ return;
+ }
+}
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/InterfaceStateIpv4Builder.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/InterfaceStateIpv4Builder.java
new file mode 100644
index 000000000..5e2141d6f
--- /dev/null
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/InterfaceStateIpv4Builder.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.IpAddressOrigin;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.NeighborOrigin;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4Builder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.AddressBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.Neighbor;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.NeighborBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.address.subnet.PrefixLength;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.address.subnet.PrefixLengthBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
+
+public class InterfaceStateIpv4Builder {
+ private List<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
index 000000000..42862a944
--- /dev/null
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/InterfaceStateIpv6Builder.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6AddressNoZone;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.IpAddressOrigin;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.NeighborOrigin;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv6;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv6Builder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv6.Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv6.AddressBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv6.Neighbor;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv6.NeighborBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
+
+public class InterfaceStateIpv6Builder {
+ private List<Address> addrs = new ArrayList<Address>();
+ private List<Neighbor> neighbors = new ArrayList<Neighbor>();
+ private Ipv6Builder ipv6Builder = new Ipv6Builder();
+
+ /**
+ * TODO-ADD-JAVADOC.
+ */
+ public void addAddress(String ipv6Addr, short prefixLength, IpAddressOrigin origin) {
+ // address
+ AddressBuilder addrBuilder = new AddressBuilder();
+
+ // IpAddressOrigin.Static
+ addrBuilder.setOrigin(origin); // FIXME: how to find origin?
+ addrBuilder.setPrefixLength(prefixLength);
+ addrBuilder.setIp(new Ipv6AddressNoZone(ipv6Addr));
+
+ addrs.add(addrBuilder.build());
+ }
+
+ /**
+ * TODO-ADD-JAVADOC.
+ */
+ public void addNeighbor(String ipv6Addr, String physAddr, NeighborOrigin origin) {
+ // address neighbor
+ NeighborBuilder nbrBuilder = new NeighborBuilder();
+ nbrBuilder.setIp(new Ipv6AddressNoZone(ipv6Addr));
+ nbrBuilder.setLinkLayerAddress(new PhysAddress(physAddr)); // TODO ("00:00:00:00:00:00")
+ nbrBuilder.setOrigin(origin);
+
+ neighbors.add(nbrBuilder.build());
+ }
+
+ /**
+ * TODO-ADD-JAVADOC.
+ */
+ public void setForwarding(boolean fwd) {
+ ipv6Builder.setForwarding(fwd);
+ }
+
+ /**
+ * TODO-ADD-JAVADOC.
+ */
+ public void setMtu(long mtu) {
+ ipv6Builder.setMtu(mtu);
+ }
+
+ /**
+ * TODO-ADD-JAVADOC.
+ */
+ public Ipv6 build() {
+ ipv6Builder.setAddress(addrs);
+ ipv6Builder.setNeighbor(neighbors);
+ return ipv6Builder.build();
+ }
+}
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/LoggingFuturesCallBack.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/LoggingFuturesCallBack.java
new file mode 100644
index 000000000..35795cb7b
--- /dev/null
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/LoggingFuturesCallBack.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.impl;
+
+import com.google.common.util.concurrent.FutureCallback;
+import org.slf4j.Logger;
+
+public class LoggingFuturesCallBack<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
index 000000000..f466adb53
--- /dev/null
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poApiRequest.java
@@ -0,0 +1,461 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.impl;
+
+import java.math.BigInteger;
+import java.net.InetAddress;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.EthernetCsmacd;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.SoftwareLoopback;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state._interface.Statistics;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state._interface.StatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface2;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface2Builder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.IpAddressOrigin;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Counter32;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Counter64;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Gauge64;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStatisticsAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStatisticsAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Ethernet.Duplex;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.EthernetBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.L2Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Vxlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VxlanBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.l2.interconnection.BridgeBasedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.l2.interconnection.XconnectBasedBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.vppjapi.vppBridgeDomainDetails;
+import org.openvpp.vppjapi.vppBridgeDomainInterfaceDetails;
+import org.openvpp.vppjapi.vppIPv4Address;
+import org.openvpp.vppjapi.vppIPv6Address;
+import org.openvpp.vppjapi.vppInterfaceCounters;
+import org.openvpp.vppjapi.vppInterfaceDetails;
+import org.openvpp.vppjapi.vppVxlanTunnelDetails;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.primitives.Ints;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+/*
+ * VPP API Class overriding interface details callback
+ */
+public class V3poApiRequest extends V3poRequest {
+ private static final Logger LOG = LoggerFactory.getLogger(V3poApiRequest.class);
+ public String ifNames = "";
+ private VppPollOperDataImpl caller;
+
+ public V3poApiRequest(VppPollOperDataImpl vppPollOperData) {
+ caller = vppPollOperData;
+ }
+
+ private InstanceIdentifier<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
index 000000000..3b546f16f
--- /dev/null
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poProvider.java
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.EthernetCsmacd;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1Builder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4Builder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.AddressBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.AddressKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLength;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLengthBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.V3poService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.EthernetBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.L2Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.RoutingBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.l2.interconnection.BridgeBasedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomainKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.vppjapi.vppApi;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+
+public class V3poProvider implements BindingAwareProvider, AutoCloseable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(V3poProvider.class);
+ private RpcRegistration<V3poService> 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
index 000000000..900161577
--- /dev/null
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/V3poRequest.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.impl;
+
+import org.openvpp.vppjapi.vppApi;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/*
+ * Abstract class overriding all callbacks with default error message
+ */
+public abstract class V3poRequest extends vppApi {
+ private static final Logger LOG = LoggerFactory.getLogger(V3poRequest.class);
+}
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppBridgeDomainListener.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppBridgeDomainListener.java
new file mode 100644
index 000000000..94d8df7c7
--- /dev/null
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppBridgeDomainListener.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.impl;
+
+import java.util.Collection;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Vpp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.BridgeDomains;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.bridge.domains.BridgeDomain;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.vppjapi.vppApi;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class VppBridgeDomainListener implements DataTreeChangeListener<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
index 000000000..7e6aa50f1
--- /dev/null
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppIetfInterfaceListener.java
@@ -0,0 +1,566 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.impl;
+
+import java.util.Collection;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.EthernetCsmacd;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv6;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.Subnet;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.Netmask;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLength;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Ethernet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.L2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Routing;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Vxlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.l2.Interconnection;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.l2.interconnection.BridgeBased;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.l2.interconnection.XconnectBased;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.openvpp.vppjapi.vppApi;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class VppIetfInterfaceListener implements DataTreeChangeListener<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
index 000000000..71d4bea4b
--- /dev/null
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppPollOperDataImpl.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.impl;
+
+import java.util.HashMap;
+import java.util.concurrent.Future;
+
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.V3poService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppPollOperDataOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppPollOperDataOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.openvpp.vppjapi.vppBridgeDomainDetails;
+import org.openvpp.vppjapi.vppBridgeDomainInterfaceDetails;
+import org.openvpp.vppjapi.vppL2Fib;
+import org.openvpp.vppjapi.vppVersion;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class VppPollOperDataImpl implements V3poService {
+ private static final Logger LOG = LoggerFactory.getLogger(VppPollOperDataImpl.class);
+ private vppVersion version;
+ private DataBroker db;
+ private int[] bdIds;
+ private HashMap<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
index 000000000..d547342bd
--- /dev/null
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppStateBridgeDomainBuilder.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomainBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.InterfaceBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.L2Fib;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.L2Fib.Action;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.bridge.domain.L2FibBuilder;
+
+public class VppStateBridgeDomainBuilder {
+ private BridgeDomainBuilder bdStateBuilder = new BridgeDomainBuilder();
+ private List<Interface> bdIfaces = new ArrayList<Interface>();
+ private List<L2Fib> bdL2Fibs = new ArrayList<L2Fib>();
+
+ /**
+ * TODO-ADD-JAVADOC.
+ */
+ public VppStateBridgeDomainBuilder(String bdName, boolean flood,
+ boolean unknownUnicastFlood,
+ boolean arpTermination,
+ boolean forward, boolean learn) {
+ bdStateBuilder
+ .setName(bdName)
+ .setFlood(flood)
+ .setUnknownUnicastFlood(unknownUnicastFlood)
+ .setArpTermination(arpTermination)
+ .setForward(forward)
+ .setLearn(learn);
+ }
+
+ /**
+ * TODO-ADD-JAVADOC.
+ */
+ public void addInterface(String interfaceName, boolean bvi,
+ short splitHorizonGroup) {
+ InterfaceBuilder ifBuilder = new InterfaceBuilder();
+ ifBuilder
+ .setName(interfaceName)
+ .setBridgedVirtualInterface(bvi)
+ .setSplitHorizonGroup(splitHorizonGroup);
+
+ bdIfaces.add(ifBuilder.build());
+ }
+
+ private static String getMacAddress(byte[] mac) {
+ StringBuilder sb = new StringBuilder(18);
+ for (byte b : mac) {
+ if (sb.length() > 0) {
+ sb.append(':');
+ }
+ sb.append(String.format("%02x", b));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * TODO-ADD-JAVADOC.
+ */
+ public void addL2Fib(boolean filter, boolean bvi,
+ String outgoingIfaceName, byte[] physAddress,
+ boolean isStatic) {
+ L2FibBuilder l2fibBuilder = new L2FibBuilder();
+ l2fibBuilder
+ .setAction((filter ? Action.Filter : Action.Forward))
+ .setBridgedVirtualInterface(bvi)
+ .setOutgoingInterface(outgoingIfaceName)
+ .setPhysAddress(new PhysAddress(getMacAddress(physAddress)))
+ .setStaticConfig(isStatic);
+
+ bdL2Fibs.add(l2fibBuilder.build());
+ }
+
+ /**
+ * TODO-ADD-JAVADOC.
+ */
+ public BridgeDomain build() {
+ bdStateBuilder.setInterface(bdIfaces);
+ bdStateBuilder.setL2Fib(bdL2Fibs);
+ return bdStateBuilder.build();
+ }
+}
diff --git a/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppStateCustomBuilder.java b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppStateCustomBuilder.java
new file mode 100644
index 000000000..86e44ec0b
--- /dev/null
+++ b/v3po/impl/src/main/java/io/fd/honeycomb/v3po/impl/VppStateCustomBuilder.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.v3po.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppState;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.BridgeDomainsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.VersionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.vpp.state.bridge.domains.BridgeDomain;
+import org.openvpp.vppjapi.vppVersion;
+
+public class VppStateCustomBuilder {
+ VppStateBuilder stateBuilder = new VppStateBuilder();
+
+ List<BridgeDomain> bridgeDomains = new ArrayList<BridgeDomain>();
+
+ /**
+ * TODO-ADD-JAVADOC.
+ */
+ public void setVersion(String name, String branch, String buildDate,
+ String buildDir) {
+ stateBuilder.setVersion(
+ new VersionBuilder()
+ .setBranch(branch)
+ .setBuildDate(buildDate)
+ .setBuildDirectory(buildDir)
+ .setName(name)
+ .build());
+ }
+
+ /**
+ * TODO-ADD-JAVADOC.
+ */
+ public void setVersion(vppVersion vppVer) {
+ setVersion(vppVer.programName, vppVer.gitBranch,
+ vppVer.buildDate, vppVer.buildDirectory);
+ }
+
+ /**
+ * TODO-ADD-JAVADOC.
+ */
+ public void addBridgeDomain(BridgeDomain bd) {
+ bridgeDomains.add(bd);
+ }
+
+ /**
+ * TODO-ADD-JAVADOC.
+ */
+ public VppState build() {
+ stateBuilder.setBridgeDomains(
+ new BridgeDomainsBuilder()
+ .setBridgeDomain(bridgeDomains)
+ .build());
+ return stateBuilder.build();
+ }
+}
diff --git a/v3po/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModule.java b/v3po/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModule.java
new file mode 100644
index 000000000..5a5fd1147
--- /dev/null
+++ b/v3po/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModule.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210;
+
+import io.fd.honeycomb.v3po.impl.V3poProvider;
+
+public class V3poModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.AbstractV3poModule {
+ public V3poModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public V3poModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.V3poModule oldModule, java.lang.AutoCloseable oldInstance) {
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ public void customValidation() {
+ // add custom validation form module attributes here.
+ }
+
+ @Override
+ public java.lang.AutoCloseable createInstance() {
+ V3poProvider provider = new V3poProvider();
+ getBrokerDependency().registerProvider(provider);
+ return provider;
+ }
+
+}
diff --git a/v3po/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactory.java b/v3po/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactory.java
new file mode 100644
index 000000000..5c942861d
--- /dev/null
+++ b/v3po/impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactory.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+* Generated file
+*
+* Generated from: yang module name: v3po yang module local name: v3po
+* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+* Generated at: Fri Jan 02 13:49:24 CST 2015
+*
+* Do not modify this file unless it is present under src/main directory
+*/
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210;
+public class V3poModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210.AbstractV3poModuleFactory {
+
+}
diff --git a/v3po/impl/src/main/yang/v3po-impl.yang b/v3po/impl/src/main/yang/v3po-impl.yang
new file mode 100644
index 000000000..7a6fd4277
--- /dev/null
+++ b/v3po/impl/src/main/yang/v3po-impl.yang
@@ -0,0 +1,35 @@
+module v3po-impl {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:v3po:impl";
+ prefix "v3po-impl";
+
+ import config { prefix config; revision-date 2013-04-05; }
+ import opendaylight-md-sal-binding { prefix md-sal-binding; revision-date 2013-10-28;}
+
+ description
+ "Service definition for v3po project";
+
+ revision "2014-12-10" {
+ description
+ "Initial revision";
+ }
+
+ identity v3po {
+ base config:module-type;
+ config:java-name-prefix V3po;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case v3po {
+ when "/config:modules/config:module/config:type = 'v3po'";
+ container broker {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity md-sal-binding:binding-broker-osgi-registry;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/v3po/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactoryTest.java b/v3po/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactoryTest.java
new file mode 100644
index 000000000..5b9a67458
--- /dev/null
+++ b/v3po/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleFactoryTest.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210;
+
+import org.junit.Test;
+
+public class V3poModuleFactoryTest {
+ @Test
+ public void testFactoryConstructor() {
+ // ensure no exceptions on construction
+ new V3poModuleFactory();
+ }
+}
diff --git a/v3po/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleTest.java b/v3po/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleTest.java
new file mode 100644
index 000000000..99872549a
--- /dev/null
+++ b/v3po/impl/src/test/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/v3po/impl/rev141210/V3poModuleTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.impl.rev141210;
+
+import org.junit.Test;
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.JmxAttribute;
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import io.fd.honeycomb.v3po.impl.V3poProvider;
+
+import javax.management.ObjectName;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class V3poModuleTest {
+ @Test
+ public void testCustomValidation() {
+ V3poModule module = new V3poModule(mock(ModuleIdentifier.class), mock(DependencyResolver.class));
+
+ // ensure no exceptions on validation
+ // currently this method is empty
+ module.customValidation();
+ }
+
+ @Test
+ public void testCreateInstance() throws Exception {
+ // configure mocks
+ DependencyResolver dependencyResolver = mock(DependencyResolver.class);
+ BindingAwareBroker broker = mock(BindingAwareBroker.class);
+ when(dependencyResolver.resolveInstance(eq(BindingAwareBroker.class), any(ObjectName.class), any(JmxAttribute.class))).thenReturn(broker);
+
+ // create instance of module with injected mocks
+ V3poModule module = new V3poModule(mock(ModuleIdentifier.class), dependencyResolver);
+
+ // getInstance calls resolveInstance to get the broker dependency and then calls createInstance
+ AutoCloseable closeable = module.getInstance();
+
+ // verify that the module registered the returned provider with the broker
+ verify(broker).registerProvider((V3poProvider)closeable);
+
+ // ensure no exceptions on close
+ closeable.close();
+ }
+}
diff --git a/v3po/it/pom.xml b/v3po/it/pom.xml
new file mode 100644
index 000000000..e7afb7535
--- /dev/null
+++ b/v3po/it/pom.xml
@@ -0,0 +1,48 @@
+<?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
index 000000000..abd282183
--- /dev/null
+++ b/v3po/it/src/test/java/io/fd/honeycomb/v3po/it/V3poIT.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.fd.honeycomb.v3po.it;
+
+import static org.ops4j.pax.exam.CoreOptions.composite;
+import static org.ops4j.pax.exam.CoreOptions.maven;
+import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFilePut;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.opendaylight.controller.mdsal.it.base.AbstractMdsalTestBase;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.karaf.options.LogLevelOption.LogLevel;
+import org.ops4j.pax.exam.options.MavenUrlReference;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerClass;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerClass.class)
+public class V3poIT extends AbstractMdsalTestBase {
+ private static final Logger LOG = LoggerFactory.getLogger(V3poIT.class);
+
+ @Override
+ public String getModuleName() {
+ return "v3po";
+ }
+
+ @Override
+ public String getInstanceName() {
+ return "v3po-default";
+ }
+
+ @Override
+ public MavenUrlReference getFeatureRepo() {
+ return maven()
+ .groupId("io.fd.honeycomb.v3po")
+ .artifactId("v3po-features")
+ .classifier("features")
+ .type("xml")
+ .versionAsInProject();
+ }
+
+ @Override
+ public String getFeatureName() {
+ return "odl-v3po-ui";
+ }
+
+ @Override
+ public Option getLoggingOption() {
+ Option option = editConfigurationFilePut(ORG_OPS4J_PAX_LOGGING_CFG,
+ logConfiguration(V3poIT.class),
+ LogLevel.INFO.name());
+ option = composite(option, super.getLoggingOption());
+ return option;
+ }
+
+ @Test
+ public void testv3poFeatureLoad() {
+ Assert.assertTrue(true);
+ }
+}
diff --git a/v3po/karaf/pom.xml b/v3po/karaf/pom.xml
new file mode 100644
index 000000000..17d4a48a3
--- /dev/null
+++ b/v3po/karaf/pom.xml
@@ -0,0 +1,71 @@
+<?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
index 000000000..a21b80f34
--- /dev/null
+++ b/v3po/pom.xml
@@ -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>