diff options
author | Ed Warnicke <eaw@cisco.com> | 2016-01-10 06:15:18 -0800 |
---|---|---|
committer | Robert Varga <nite@hq.sk> | 2016-01-30 00:01:07 +0100 |
commit | 788f314b98ba2b2189e7be6d49edd74c5b9a6322 (patch) | |
tree | ab4b5476d8dba224e6596106d289c625ffbbc323 |
Initial honeycomb code commit.
This commit drops the basic structure with disabled integration tests.
The tests will be enabled in a follow-up patch, which sorts out the
current .so loading problems.
Change-Id: If70f2f13b2cf49af82996f884218ac05d335c2ed
Signed-off-by: Ed Warnicke <eaw@cisco.com>
Signed-off-by: Robert Varga <nite@hq.sk>
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&revision=2014-12-10</capability> + <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&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> |