HONEYCOMB-58 - Routing Plugin Structure 18/3918/8
authorJan Srnicek <[email protected]>
Thu, 1 Dec 2016 17:15:52 +0000 (18:15 +0100)
committerJan Srnicek <[email protected]>
Thu, 1 Dec 2016 17:16:47 +0000 (18:16 +0100)
Read/Write support for ipv4/6 static routes.
Restriction due to vpp implementation described
in readme.

Change-Id: I328f406a9b7cb8781f8becf98eca293cebe66859
Signed-off-by: Jan Srnicek <[email protected]>
96 files changed:
routing/pom.xml
routing/routing-api/src/main/yang/ietf-ipv4-unicast-routing.yang
routing/routing-api/src/main/yang/ietf-ipv6-unicast-routing.yang
routing/routing-api/src/main/yang/vpp-routing.yang
routing/routing-impl/asciidoc/Readme.adoc [new file with mode: 0644]
routing/routing-impl/pom.xml [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/RoutingConfiguration.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/RoutingModule.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/naming/Ipv4RouteNamesFactory.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/naming/Ipv6RouteNamesFactory.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/Ipv4ReadRoutingNodes.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/Ipv4RouteCustomizer.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/Ipv6ReadRoutingNodes.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/Ipv6RouteCustomizer.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/RoutingInstanceCustomizer.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/RoutingProtocolCustomizer.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/RoutingStateCustomizer.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/RoutingStateReaderFactory.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/trait/Ipv4RoutePathParser.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/trait/Ipv6RoutePathParser.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/trait/RouteMapper.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/Ipv4RouteCustomizer.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/Ipv4WriteRoutingNodes.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/Ipv6RouteCustomizer.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/Ipv6WriteRoutingNodes.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/RoutingCustomizer.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/RoutingInstanceCustomizer.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/RoutingProtocolCustomizer.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/RoutingWriterFactory.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/MultipathHopRequestFactory.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/SimpleHopRequestFactory.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/SpecialNextHopRequestFactory.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/base/BasicHopRequestFactory.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/base/ClassifierContextHolder.java [new file with mode: 0644]
routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/trait/RouteRequestProducer.java [new file with mode: 0644]
routing/routing-impl/src/main/resources/honeycomb-minimal-resources/config/routing.json [new file with mode: 0644]
routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/Ipv4RouteData.java [new file with mode: 0644]
routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/Ipv4RouteNamesFactoryTest.java [new file with mode: 0644]
routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/Ipv6RouteData.java [new file with mode: 0644]
routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/Ipv6RouteNamesFactoryTest.java [new file with mode: 0644]
routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/RoutingModuleTest.java [new file with mode: 0644]
routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/helpers/ClassifyTableTestHelper.java [new file with mode: 0644]
routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/helpers/InterfaceTestHelper.java [new file with mode: 0644]
routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/helpers/RoutingRequestTestHelper.java [new file with mode: 0644]
routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/helpers/SchemaContextTestHelper.java [new file with mode: 0644]
routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/read/Ipv4RouteCustomizerTest.java [new file with mode: 0644]
routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/read/Ipv6RouteCustomizerTest.java [new file with mode: 0644]
routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/read/RoutingProtocolCustomizerTest.java [new file with mode: 0644]
routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/read/RoutingStateCustomizerTest.java [new file with mode: 0644]
routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/Ipv4RouteCustomizerTest.java [new file with mode: 0644]
routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/Ipv6RouteCustomizerTest.java [new file with mode: 0644]
routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/RoutingInstanceCustomizerTest.java [new file with mode: 0644]
routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/RoutingProtocolCustomizerTest.java [new file with mode: 0644]
routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/MultipathHopRequestFactoryIpv4Test.java [new file with mode: 0644]
routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/MultipathHopRequestFactoryIpv6Test.java [new file with mode: 0644]
routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/SimpleHopRequestFactoryIpv4Test.java [new file with mode: 0644]
routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/SimpleHopRequestFactoryIpv6Test.java [new file with mode: 0644]
routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/SpecialNextHopRequestFactoryIpv4Test.java [new file with mode: 0644]
routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/SpecialNextHopRequestFactoryIpv6Test.java [new file with mode: 0644]
routing/routing-impl/src/test/resources/init/config-data.json [new file with mode: 0644]
routing/routing-impl/src/test/resources/init/state-data.json [new file with mode: 0644]
routing/routing-impl/src/test/resources/ipv4/multiHopRouteWithClassifier.json [new file with mode: 0644]
routing/routing-impl/src/test/resources/ipv4/multiHopRouteWithoutClassifier.json [new file with mode: 0644]
routing/routing-impl/src/test/resources/ipv4/simpleHopRouteWithClassifier.json [new file with mode: 0644]
routing/routing-impl/src/test/resources/ipv4/simpleHopRouteWithoutClassifier.json [new file with mode: 0644]
routing/routing-impl/src/test/resources/ipv4/specialHopRouteBlackhole.json [new file with mode: 0644]
routing/routing-impl/src/test/resources/ipv4/specialHopRouteProhibited.json [new file with mode: 0644]
routing/routing-impl/src/test/resources/ipv4/specialHopRouteReceive.json [new file with mode: 0644]
routing/routing-impl/src/test/resources/ipv4/specialHopRouteUnreachable.json [new file with mode: 0644]
routing/routing-impl/src/test/resources/ipv6/multiHopRouteWithClassifier.json [new file with mode: 0644]
routing/routing-impl/src/test/resources/ipv6/multiHopRouteWithoutClassifier.json [new file with mode: 0644]
routing/routing-impl/src/test/resources/ipv6/simpleHopRouteWithClassifier.json [new file with mode: 0644]
routing/routing-impl/src/test/resources/ipv6/simpleHopRouteWithoutClassifier.json [new file with mode: 0644]
routing/routing-impl/src/test/resources/ipv6/specialHopRouteBlackhole.json [new file with mode: 0644]
routing/routing-impl/src/test/resources/ipv6/specialHopRouteProhibited.json [new file with mode: 0644]
routing/routing-impl/src/test/resources/ipv6/specialHopRouteReceive.json [new file with mode: 0644]
routing/routing-impl/src/test/resources/ipv6/specialHopRouteUnreachable.json [new file with mode: 0644]
routing/routing-impl/src/test/resources/routing.json [new file with mode: 0644]
routing/routing_postman_collection.json [new file with mode: 0644]
vpp-common/naming-context-api/pom.xml
vpp-common/naming-context-api/src/main/yang/multi-naming-context.yang [new file with mode: 0644]
vpp-common/vpp-translate-utils/pom.xml
vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/AddressTranslator.java
vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/ByteDataTranslator.java
vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/Ipv4Translator.java
vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/Ipv6Translator.java
vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/MultiNamingContext.java [new file with mode: 0644]
vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/NamingContext.java
vpp-common/vpp-translate-utils/src/test/java/io/fd/hc2vpp/common/translate/util/ByteDataTranslatorTest.java
vpp-common/vpp-translate-utils/src/test/java/io/fd/hc2vpp/common/translate/util/Ipv4TranslatorTest.java
vpp-common/vpp-translate-utils/src/test/java/io/fd/hc2vpp/common/translate/util/Ipv6TranslatorTest.java
vpp-common/vpp-translate-utils/src/test/java/io/fd/hc2vpp/common/translate/util/MultiNamingContextTest.java [new file with mode: 0644]
vpp-common/vpp-translate-utils/src/test/java/io/fd/hc2vpp/common/translate/util/NamingContextTest.java [new file with mode: 0644]
vpp-common/vpp-translate-utils/src/test/resources/multi-mapping.json [new file with mode: 0644]
vpp-common/vpp-translate-utils/src/test/resources/naming.json [new file with mode: 0644]
vpp-integration/minimal-distribution/pom.xml

index 35e3576..12bbeb2 100644 (file)
@@ -13,7 +13,7 @@
  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"
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 
     <parent>
@@ -35,6 +35,7 @@
 
     <modules>
         <module>routing-api</module>
+        <module>routing-impl</module>
     </modules>
 
     <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
index ed320fd..49052c1 100644 (file)
@@ -228,7 +228,7 @@ module ietf-ipv4-unicast-routing {
 
           //TODO modification needed because of yangtools bug(unable to proceed augmentation in separate model of augmentation in this model)
           container vpp-ipv4-route-state{
-              uses vpp-r:vpp-routing-state-attributes;
+              uses vpp-r:vpp-route-attributes;
           }
         }
       }
@@ -348,7 +348,7 @@ module ietf-ipv4-unicast-routing {
 
         //TODO modification needed because of yangtools bug(unable to proceed augmentation in separate model of augmentation in this model)
         container vpp-ipv4-route{
-            uses vpp-r:vpp-routing-attributes;
+            uses vpp-r:vpp-route-attributes;
         }
       }
     }
index 93de395..9c6ce4d 100644 (file)
@@ -632,7 +632,7 @@ module ietf-ipv6-unicast-routing {
 
           //TODO modification needed because of yangtools bug(unable to proceed augmentation in separate model of augmentation in this model)
           container vpp-ipv6-route-state{
-              uses vpp-r:vpp-routing-state-attributes;
+              uses vpp-r:vpp-route-attributes;
           }
         }
       }
@@ -749,7 +749,7 @@ module ietf-ipv6-unicast-routing {
 
         //TODO modification needed because of yangtools bug(unable to proceed augmentation in separate model of augmentation in this model)
         container vpp-ipv6-route{
-            uses vpp-r:vpp-routing-attributes;
+            uses vpp-r:vpp-route-attributes;
         }
       }
     }
index 1979db9..49884ad 100644 (file)
@@ -4,7 +4,7 @@ module vpp-routing{
     prefix "vpp-routing";
     description "General extensions for routes to be able to use VPP route defining apis";
 
-    revision 2016-10-18 {
+    revision 2016-12-14 {
         description "Initial revision.";
     }
 
@@ -15,26 +15,17 @@ module vpp-routing{
     import vpp-classifier {
         prefix "classifier";
     }
+    
+    import ietf-routing {
+        prefix "ietf-r";
+    }
 
     typedef vni-reference{
         type uint32;
         description "Vrf index reference";
     }
 
-    grouping vpp-routing-attributes{
-        //vrf_id
-        leaf primary-vrf{
-            type vni-reference;
-            mandatory true;
-            description "Main vrf associated to route";
-        }
-
-        leaf auto-create-vrf{
-            type boolean;
-            default false;
-            description "If referenced primary vrf not exists,create while creating route";
-        }
-
+    grouping vpp-route-attributes {
         //lookup_in_vrf
         leaf secondary-vrf{
             type vni-reference;
@@ -42,18 +33,34 @@ module vpp-routing{
         }
 
         leaf classify-table{
-            // classify_table_index + is_classify flag
+        // classify_table_index + is_classify flag
             type classifier:classify-table-ref;
             description "Optional reference to classify table";
         }
     }
 
-     grouping vpp-routing-state-attributes{
-            //vrf_id
-            leaf primary-vrf{
-                type vni-reference;
-                mandatory true;
-                description "Main vrf associated to route";
-            }
-     }
+    grouping vpp-routing-protocol-attributes{
+        //vrf_id
+        leaf primary-vrf{
+            type vni-reference;
+            mandatory true;
+            description "Main vrf associated to route";
+        }
+    }
+
+    augment /ietf-r:routing/ietf-r:routing-instance/ietf-r:routing-protocols/ietf-r:routing-protocol{
+        ext:augment-identifier "routing-protocol-vpp-attr";
+        container vpp-protocol-attributes {
+            presence "Config attributes";
+            uses vpp-routing-protocol-attributes;
+        }
+    }
+
+    augment /ietf-r:routing-state/ietf-r:routing-instance/ietf-r:routing-protocols/ietf-r:routing-protocol{
+        ext:augment-identifier "routing-protocol-state-vpp-attr";
+        container vpp-protocol-state-attributes {
+            presence "Operational attributes";
+            uses vpp-routing-protocol-attributes;
+        }
+    }
 }
\ No newline at end of file
diff --git a/routing/routing-impl/asciidoc/Readme.adoc b/routing/routing-impl/asciidoc/Readme.adoc
new file mode 100644 (file)
index 0000000..1624114
--- /dev/null
@@ -0,0 +1,28 @@
+= routing-impl
+
+Overview of routing-impl
+
+# Supported Features
+
+Routing plugin allows to create Ipv4/6 based routes.
+Data are modeled by 4 models.
+
+* ietf-routing - Basic routes model, modeling routing-instances,protocols,...
+* ietf-ipv4-unicast-routing/ietf-ipv6-unicast-routing - Address family specific models
+* vpp-routing - Attributes specific to vpp implementation of routing
+
+WARNING: Specific family models has to be manualy modified to add necessary configuration,
+due to lack of support to handle cross-model multi-level augments(augment of augment)
+
+# Restrictions
+
+* Due to vpp implementation of routing, configuration has been restricted to single *routing-instance*.
+Key/name of this *routing-instace* can be modified by property *"default-routing-instance-name"* in *routing.json*.
+Anny attempt to configure different routing-instance will be rejected.
+
+* *Routing protocols* has been mapped to unique vrf-id's from vpp, so only single *routing-protocol* can be mapped
+ to single *vrf-id*
+
+* Vpp by default contains pre-configured routes. Any vrf-id of this kind is mapped to
+  protocol name with prefix specified by property *"learned-route-name-prefix"* in *routing.json*.
+  Respective routing protocols are prefixed with value *"learned-protocol-"*.
\ No newline at end of file
diff --git a/routing/routing-impl/pom.xml b/routing/routing-impl/pom.xml
new file mode 100644 (file)
index 0000000..4de7810
--- /dev/null
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  ~ Copyright (c) 2016 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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>io.fd.hc2vpp.common</groupId>
+        <artifactId>vpp-impl-parent</artifactId>
+        <version>1.16.12-SNAPSHOT</version>
+        <relativePath>../../vpp-common/vpp-impl-parent</relativePath>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>io.fd.hc2vpp.routing</groupId>
+    <artifactId>routing-impl</artifactId>
+    <version>1.16.12-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>routing-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <!-- Honeycomb infrastructure-->
+        <dependency>
+            <groupId>io.fd.honeycomb</groupId>
+            <artifactId>translate-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>io.fd.honeycomb</groupId>
+            <artifactId>translate-spi</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>io.fd.honeycomb</groupId>
+            <artifactId>cfg-init</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <!-- Translation -->
+        <dependency>
+            <groupId>io.fd.hc2vpp.common</groupId>
+            <artifactId>vpp-translate-utils</artifactId>
+        </dependency>
+
+        <!-- DI -->
+        <dependency>
+            <groupId>com.google.inject</groupId>
+            <artifactId>guice</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>net.jmob</groupId>
+            <artifactId>guice.conf</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.inject.extensions</groupId>
+            <artifactId>guice-multibindings</artifactId>
+        </dependency>
+
+        <!-- Testing dependencies-->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>hamcrest-all</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.google.inject.extensions</groupId>
+            <artifactId>guice-testlib</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.fd.hc2vpp.common</groupId>
+            <artifactId>vpp-translate-test</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <!-- Because of use of VppClassifierContext -->
+        <dependency>
+            <groupId>io.fd.hc2vpp.v3po</groupId>
+            <artifactId>v3po2vpp</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.fd.honeycomb.infra</groupId>
+            <artifactId>test-tools</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/RoutingConfiguration.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/RoutingConfiguration.java
new file mode 100644 (file)
index 0000000..c8f0ba6
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing;
+
+import net.jmob.guice.conf.core.BindConfig;
+import net.jmob.guice.conf.core.InjectConfig;
+import net.jmob.guice.conf.core.Syntax;
+
+@BindConfig(value = "routing", syntax = Syntax.JSON)
+public class RoutingConfiguration {
+
+    /**
+     * Route ids start from
+     */
+    public static final int MULTI_MAPPING_START_INDEX = 1;
+
+    /**
+     * Contains routing protocol to table id mapping
+     */
+    public static final String ROUTING_PROTOCOL_CONTEXT = "routing-protocol-context";
+
+    /**
+     * Used to map routes to routing-protocols
+     */
+    public static final String ROUTE_CONTEXT = "route-context";
+
+    /**
+     * Used to map hop ids to routes
+     */
+    public static final String ROUTE_HOP_CONTEXT = "route-hop-context";
+
+
+    @InjectConfig("default-routing-instance-name")
+    private String defaultRoutingInstanceName;
+
+    @InjectConfig("learned-route-name-prefix")
+    private String learnedRouteNamePrefix;
+
+    public String getDefaultRoutingInstanceName() {
+        return defaultRoutingInstanceName;
+    }
+
+    public String getLearnedRouteNamePrefix() {
+        return learnedRouteNamePrefix;
+    }
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/RoutingModule.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/RoutingModule.java
new file mode 100644 (file)
index 0000000..a6fadf7
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.multibindings.Multibinder;
+import com.google.inject.name.Names;
+import io.fd.hc2vpp.common.translate.util.MultiNamingContext;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.read.RoutingStateReaderFactory;
+import io.fd.hc2vpp.routing.write.RoutingWriterFactory;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import net.jmob.guice.conf.core.ConfigurationModule;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * RoutingModule class instantiating routing plugin components.
+ */
+public final class RoutingModule extends AbstractModule {
+
+    private static final Logger LOG = LoggerFactory.getLogger(RoutingModule.class);
+
+    @Override
+    protected void configure() {
+        LOG.info("Starting initialization");
+        // requests injection of properties
+        install(ConfigurationModule.create());
+        requestInjection(RoutingConfiguration.class);
+
+        bind(NamingContext.class)
+                .annotatedWith(Names.named(RoutingConfiguration.ROUTING_PROTOCOL_CONTEXT))
+                .toInstance(new NamingContext("learned-protocol-", RoutingConfiguration.ROUTING_PROTOCOL_CONTEXT));
+
+        bind(NamingContext.class)
+                .annotatedWith(Names.named(RoutingConfiguration.ROUTE_CONTEXT))
+                .toInstance(new NamingContext("route-", RoutingConfiguration.ROUTE_CONTEXT));
+
+        bind(MultiNamingContext.class)
+                .annotatedWith(Names.named(RoutingConfiguration.ROUTE_HOP_CONTEXT))
+                .toInstance(new MultiNamingContext(RoutingConfiguration.ROUTE_HOP_CONTEXT,
+                        RoutingConfiguration.MULTI_MAPPING_START_INDEX));
+
+        LOG.info("Injecting reader factories");
+        // creates reader factory binding
+        final Multibinder<ReaderFactory> readerFactoryBinder = Multibinder.newSetBinder(binder(), ReaderFactory.class);
+        readerFactoryBinder.addBinding().to(RoutingStateReaderFactory.class);
+
+        LOG.info("Injecting writers factories");
+        // create writer factory binding
+        final Multibinder<WriterFactory> writerFactoryBinder = Multibinder.newSetBinder(binder(), WriterFactory.class);
+        writerFactoryBinder.addBinding().to(RoutingWriterFactory.class);
+
+        LOG.info("Started successfully");
+    }
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/naming/Ipv4RouteNamesFactory.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/naming/Ipv4RouteNamesFactory.java
new file mode 100644 (file)
index 0000000..5d3d76f
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.naming;
+
+
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.trait.RouteMapper;
+import io.fd.hc2vpp.routing.write.trait.RouteRequestProducer;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.vpp.jvpp.core.dto.IpFibDetails;
+import io.fd.vpp.jvpp.core.types.FibPath;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import javax.annotation.Nonnull;
+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.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHop;
+
+
+public final class Ipv4RouteNamesFactory implements RouteMapper, RouteRequestProducer {
+
+    private static final String DOT = ".";
+    private static final String EMPTY = "";
+
+    private final NamingContext interfaceContext;
+    private final NamingContext routingProtocolContext;
+
+    public Ipv4RouteNamesFactory(@Nonnull final NamingContext interfaceContext,
+                                 @Nonnull final NamingContext routingProtocolContext) {
+        this.interfaceContext = interfaceContext;
+        this.routingProtocolContext = routingProtocolContext;
+    }
+
+    /**
+     * Construct unique name from provided {@code Route}
+     */
+    public String uniqueRouteName(@Nonnull final String parentProtocolName, @Nonnull final Route route) {
+        return bindName(parentProtocolName, dotlessAddress(route.getDestinationPrefix()),
+                String.valueOf(extractPrefix(route.getDestinationPrefix())));
+    }
+
+    /**
+     * Construct unique name from provided {@code IpFibDetails}
+     */
+    public String uniqueRouteName(@Nonnull final IpFibDetails details, @Nonnull final MappingContext mappingContext) {
+        return bindName(routingProtocolContext.getName(details.tableId, mappingContext),
+                dotlessAddress(details.address),
+                String.valueOf(details.addressLength));
+    }
+
+
+    public String uniqueRouteHopName(@Nonnull final NextHop hop) {
+        return bindName(hop.getOutgoingInterface(),
+                dotlessAddress(hop.getAddress()),
+                String.valueOf(hop.getWeight()));
+    }
+
+
+    public String uniqueRouteHopName(@Nonnull final FibPath path,
+                                     @Nonnull final MappingContext mappingContext) {
+        return bindName(interfaceContext.getName(path.swIfIndex, mappingContext),
+                dotlessAddress(path.nextHop), String.valueOf(path.weight));
+    }
+
+    private String dotlessAddress(final byte[] address) {
+        // trimming in case of ipv4 address beeing sent as 16 byte array
+        byte[] trimmed = address;
+        if (trimmed.length > 4) {
+            trimmed = Arrays.copyOfRange(trimmed, 0, 4);
+        }
+
+        //no reverting, just takes address as it is and converts it
+        try {
+            return dotless(InetAddress.getByAddress(trimmed).getHostAddress());
+        } catch (UnknownHostException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+
+    private String dotlessAddress(@Nonnull final Ipv4Prefix address) {
+        final String addressValue = address.getValue();
+        return dotless(addressValue.substring(0, addressValue.indexOf("/")));
+    }
+
+    private String dotlessAddress(@Nonnull final Ipv4Address address) {
+        return dotless(address.getValue());
+    }
+
+    private String dotless(@Nonnull final String input) {
+        return input.replace(DOT, EMPTY);
+    }
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/naming/Ipv6RouteNamesFactory.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/naming/Ipv6RouteNamesFactory.java
new file mode 100644 (file)
index 0000000..8408c82
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.naming;
+
+import com.google.common.net.InetAddresses;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.trait.RouteMapper;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.vpp.jvpp.core.dto.Ip6FibDetails;
+import io.fd.vpp.jvpp.core.types.FibPath;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
+
+
+public final class Ipv6RouteNamesFactory implements RouteMapper {
+
+    private static final String DOUBLE_DOT = ":";
+    private static final String EMPTY = "";
+
+    private final NamingContext interfaceContext;
+    private final NamingContext routingProtocolContext;
+
+    public Ipv6RouteNamesFactory(@Nonnull final NamingContext interfaceContext,
+                                 @Nonnull final NamingContext routingProtocolContext) {
+        this.interfaceContext = interfaceContext;
+        this.routingProtocolContext = routingProtocolContext;
+    }
+
+    /**
+     * Construct unique name from provided {@code Route}
+     */
+    public String uniqueRouteName(@Nonnull final String parentProtocolName,
+                                  @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route route) {
+        return bindName(parentProtocolName,
+                // to have address in compressed form
+                doubleDotlessAddress(route.getDestinationPrefix()),
+                String.valueOf(extractPrefix(route.getDestinationPrefix())));
+    }
+
+    /**
+     * Construct unique name from provided {@code IpFibDetails}
+     */
+    public String uniqueRouteName(@Nonnull final Ip6FibDetails details, @Nonnull final MappingContext mappingContext) {
+        return bindName(routingProtocolContext.getName(details.tableId, mappingContext),
+                doubleDotlessAddress(details.address),
+                String.valueOf(details.addressLength));
+    }
+
+    public String uniqueRouteHopName(
+            @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.next.hop.list.NextHop hop) {
+        return bindName(hop.getOutgoingInterface(),
+                doubleDotlessAddress(hop.getAddress()),
+                String.valueOf(hop.getWeight()));
+    }
+
+    public String uniqueRouteHopName(@Nonnull final FibPath path, @Nonnull final MappingContext mappingContext) {
+        return bindName(interfaceContext.getName(path.swIfIndex, mappingContext),
+                doubleDotlessAddress(path.nextHop),
+                String.valueOf(path.weight));
+    }
+
+    /**
+     * Uses combination of standard java.net.InetAddress and com.google.common.net.InetAddresses for following reasons
+     * <ul>
+     * <li>
+     * InetAddresses.toAddrString uses maximal ipv6 compression - eliminate possibility of mismatch between same
+     * addresses with different compression
+     * </li>
+     * <li>
+     * InetAddress.getByAddress just converts byte array to address, that's
+     * why InetAddresses.fromLittleEndianByteArray is not used, because it internaly reverts order of address
+     * bytes,which is something that is not needed here
+     * </li>
+     * </ul>
+     */
+    private String doubleDotlessAddress(final byte[] address) {
+        try {
+            return doubleDotless(InetAddresses.toAddrString(InetAddress.getByAddress(address)));
+        } catch (UnknownHostException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+
+    private String doubleDotlessAddress(@Nonnull final Ipv6Prefix address) {
+        final String addressValue = address.getValue();
+        return doubleDotless(compressedIpv6(addressValue.substring(0, addressValue.indexOf("/"))));
+    }
+
+    private String doubleDotlessAddress(@Nonnull final Ipv6Address address) {
+        // converted to use maximal compression
+        // for details - https://google.github.io/guava/releases/snapshot/api/docs/com/google/common/net/InetAddresses.html#toAddrString-java.net.InetAddress
+        return doubleDotless(compressedIpv6(address.getValue()));
+    }
+
+    /**
+     * Use maximal compresion of ipv6 address string
+     */
+    private String compressedIpv6(@Nonnull final String input) {
+        return InetAddresses.toAddrString(InetAddresses.forString(input));
+    }
+
+    private String doubleDotless(@Nonnull final String input) {
+        return input.replace(DOUBLE_DOT, EMPTY);
+    }
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/Ipv4ReadRoutingNodes.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/Ipv4ReadRoutingNodes.java
new file mode 100644 (file)
index 0000000..dde2f9c
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.read;
+
+
+import com.google.common.collect.ImmutableSet;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.MultiNamingContext;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.RoutingConfiguration;
+import io.fd.honeycomb.translate.impl.read.GenericListReader;
+import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
+import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager;
+import io.fd.vpp.jvpp.core.dto.IpFibDetailsReplyDump;
+import io.fd.vpp.jvpp.core.dto.IpFibDump;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.StaticRoutes2;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.StaticRoutes2Builder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv4;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv4Builder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.VppIpv4RouteState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.NextHopList;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol.StaticRoutes;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+interface Ipv4ReadRoutingNodes extends JvppReplyConsumer {
+
+    static InstanceIdentifier<StaticRoutes2> staticRoutesInstanceIdentifier(
+            final InstanceIdentifier<StaticRoutes> staticRoutesInstanceIdentifier) {
+        return staticRoutesInstanceIdentifier.augmentation(StaticRoutes2.class);
+    }
+
+    static InstanceIdentifier<Ipv4> ipv4Identifier(
+            final InstanceIdentifier<StaticRoutes2> staticRoutes2InstanceIdentifier) {
+        return staticRoutes2InstanceIdentifier.child(Ipv4.class);
+    }
+
+    default DumpCacheManager<IpFibDetailsReplyDump, Void> newIpv4RoutesDumpManager(
+            @Nonnull final FutureJVppCore vppApi) {
+        return new DumpCacheManager.DumpCacheManagerBuilder<IpFibDetailsReplyDump, Void>()
+                .withExecutor(
+                        (identifier, params) -> getReplyForRead(vppApi.ipFibDump(new IpFibDump()).toCompletableFuture(),
+                                identifier))
+                .acceptOnly(IpFibDetailsReplyDump.class)
+                .build();
+    }
+
+    default void registerIpv4Routes(@Nonnull final InstanceIdentifier<StaticRoutes> subTreeId,
+                                    @Nonnull final ModifiableReaderRegistryBuilder registry,
+                                    @Nonnull final DumpCacheManager<IpFibDetailsReplyDump, Void> ipv4DumpManager,
+                                    @Nonnull final RoutingConfiguration configuration,
+                                    @Nonnull final MultiNamingContext routeHopContext,
+                                    @Nonnull final NamingContext interfaceContext,
+                                    @Nonnull final NamingContext routeContext,
+                                    @Nonnull final NamingContext routingProtocolContext) {
+
+        final InstanceIdentifier<StaticRoutes2> staticRoutes2InstanceIdentifier =
+                staticRoutesInstanceIdentifier(subTreeId);
+        final InstanceIdentifier<Ipv4> ipv4InstanceIdentifier = ipv4Identifier(staticRoutes2InstanceIdentifier);
+
+        registry.addStructuralReader(staticRoutes2InstanceIdentifier, StaticRoutes2Builder.class);
+
+        registry.addStructuralReader(ipv4InstanceIdentifier, Ipv4Builder.class);
+        registry.subtreeAdd(ipv4RoutingHandledChildren(InstanceIdentifier.create(Route.class)),
+                new GenericListReader<>(ipv4InstanceIdentifier.child(Route.class),
+                        new Ipv4RouteCustomizer(ipv4DumpManager, configuration, routeHopContext, interfaceContext,
+                                routeContext, routingProtocolContext)));
+    }
+
+    default Set<InstanceIdentifier<?>> ipv4RoutingHandledChildren(
+            final InstanceIdentifier<Route> parent) {
+        return ImmutableSet.of(parent.child(NextHopList.class),
+                parent.child(NextHopList.class).child(NextHop.class),
+                parent.child(VppIpv4RouteState.class));
+    }
+
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/Ipv4RouteCustomizer.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/Ipv4RouteCustomizer.java
new file mode 100644 (file)
index 0000000..71758b4
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.read;
+
+import static io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor.NO_PARAMS;
+
+import com.google.common.base.Optional;
+import io.fd.hc2vpp.common.translate.util.MultiNamingContext;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.RoutingConfiguration;
+import io.fd.hc2vpp.routing.naming.Ipv4RouteNamesFactory;
+import io.fd.hc2vpp.routing.trait.Ipv4RoutePathParser;
+import io.fd.hc2vpp.routing.trait.RouteMapper;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer;
+import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager;
+import io.fd.vpp.jvpp.core.dto.IpFibDetails;
+import io.fd.vpp.jvpp.core.dto.IpFibDetailsReplyDump;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv4Builder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.RouteBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.RouteKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.VppIpv4RouteStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocol;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class Ipv4RouteCustomizer
+        implements ListReaderCustomizer<Route, RouteKey, RouteBuilder>, RouteMapper, Ipv4RoutePathParser {
+
+
+    private final DumpCacheManager<IpFibDetailsReplyDump, Void> ipv4RoutesDumpManager;
+    private final RoutingConfiguration configuration;
+    private final MultiNamingContext routeHopContext;
+    private final NamingContext interfaceContext;
+    private final NamingContext routesContext;
+    private final NamingContext routingProtocolContext;
+
+    private final Ipv4RouteNamesFactory namesFactory;
+
+    public Ipv4RouteCustomizer(@Nonnull final DumpCacheManager<IpFibDetailsReplyDump, Void> ipv4RoutesDumpManager,
+                               @Nonnull final RoutingConfiguration configuration,
+                               @Nonnull final MultiNamingContext routeHopContext,
+                               @Nonnull final NamingContext interfaceContext,
+                               @Nonnull final NamingContext routesContext,
+                               @Nonnull final NamingContext routingProtocolContext) {
+        this.ipv4RoutesDumpManager = ipv4RoutesDumpManager;
+        this.configuration = configuration;
+        this.interfaceContext = interfaceContext;
+        this.routeHopContext = routeHopContext;
+        this.routesContext = routesContext;
+        this.routingProtocolContext = routingProtocolContext;
+        this.namesFactory = new Ipv4RouteNamesFactory(interfaceContext, routingProtocolContext);
+    }
+
+    @Nonnull
+    @Override
+    public List<RouteKey> getAllIds(@Nonnull final InstanceIdentifier<Route> instanceIdentifier,
+                                    @Nonnull final ReadContext readContext) throws ReadFailedException {
+
+        final Optional<IpFibDetailsReplyDump> ipv4RoutesDump =
+                ipv4RoutesDumpManager.getDump(instanceIdentifier, readContext.getModificationCache(), NO_PARAMS);
+
+        final String protocolName = instanceIdentifier.firstKeyOf(RoutingProtocol.class).getName();
+        final int protocolTableId = routingProtocolContext.getIndex(protocolName, readContext.getMappingContext());
+
+        return ipv4RoutesDump.isPresent()
+                ? ipv4RoutesDump.get().ipFibDetails.stream()
+                .filter(details -> protocolTableId == details.tableId)
+                .map(ipFibDetails -> toKey(ipFibDetails, readContext.getMappingContext()))
+                .collect(Collectors.toList())
+                : Collections.emptyList();
+    }
+
+    /**
+     * route id is represented as number, but there's no index in dumped data,
+     * so index is assigned to name formatted as tableId_address_addressLength(should be unique combination)
+     */
+    private RouteKey toKey(final IpFibDetails details, final MappingContext mappingContext) {
+        String routeName = namesFactory.uniqueRouteName(details, mappingContext);
+        // first condition excludes data written manually, second one data that has been already learned
+        if (!routesContext.containsIndex(routeName, mappingContext)) {
+            String learnedRouteName = nameWithPrefix(configuration.getLearnedRouteNamePrefix(), routeName);
+            if (!routesContext.containsIndex(learnedRouteName, mappingContext)) {
+                routesContext.addName(learnedRouteName, mappingContext);
+            }
+            return keyForName(mappingContext, learnedRouteName);
+        }
+        return keyForName(mappingContext, routeName);
+    }
+
+    private RouteKey keyForName(final MappingContext mappingContext, final String name) {
+        return new RouteKey(
+                Long.valueOf(routesContext.getIndex(name, mappingContext)));
+    }
+
+    @Override
+    public void merge(@Nonnull final Builder<? extends DataObject> builder, @Nonnull final List<Route> list) {
+        Ipv4Builder.class.cast(builder).setRoute(list);
+    }
+
+    @Nonnull
+    @Override
+    public RouteBuilder getBuilder(@Nonnull final InstanceIdentifier<Route> instanceIdentifier) {
+        return new RouteBuilder();
+    }
+
+    @Override
+    public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Route> instanceIdentifier,
+                                      @Nonnull final RouteBuilder routeBuilder, @Nonnull final ReadContext readContext)
+            throws ReadFailedException {
+        final RouteKey key = instanceIdentifier.firstKeyOf(Route.class);
+        final String mappedName = routesContext.getName(key.getId().intValue(), readContext.getMappingContext());
+        final String protocolName = instanceIdentifier.firstKeyOf(RoutingProtocol.class).getName();
+        final int protocolTableId = routingProtocolContext.getIndex(protocolName, readContext.getMappingContext());
+        final Optional<IpFibDetailsReplyDump> ipv4RoutesDump =
+                ipv4RoutesDumpManager.getDump(instanceIdentifier, readContext.getModificationCache(), NO_PARAMS);
+
+        if (ipv4RoutesDump.isPresent() && !ipv4RoutesDump.get().ipFibDetails.isEmpty()) {
+
+            final java.util.Optional<IpFibDetails> opDetail = ipv4RoutesDump.get().ipFibDetails.stream()
+                    .filter(details -> protocolTableId == details.tableId)
+                    .filter(details -> equalsWithConfigOrLearned(configuration.getLearnedRouteNamePrefix(), mappedName,
+                            namesFactory.uniqueRouteName(details, readContext.getMappingContext())))
+                    .findAny();
+
+            if (opDetail.isPresent()) {
+                final IpFibDetails detail = opDetail.get();
+
+                routeBuilder.setNextHopOptions(
+                        resolveHopType(mappedName, Arrays.asList(detail.path), interfaceContext, routeHopContext,
+                                readContext.getMappingContext(), namesFactory))
+                        .setKey(key)
+                        .setId(key.getId())
+                        .setDestinationPrefix(toIpv4Prefix(detail.address, toJavaByte(detail.addressLength)))
+                        .setVppIpv4RouteState(new VppIpv4RouteStateBuilder().build());
+            }
+        }
+    }
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/Ipv6ReadRoutingNodes.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/Ipv6ReadRoutingNodes.java
new file mode 100644 (file)
index 0000000..06eaaf9
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.read;
+
+import com.google.common.collect.ImmutableSet;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.MultiNamingContext;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.RoutingConfiguration;
+import io.fd.honeycomb.translate.impl.read.GenericListReader;
+import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
+import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager;
+import io.fd.vpp.jvpp.core.dto.Ip6FibDetailsReplyDump;
+import io.fd.vpp.jvpp.core.dto.Ip6FibDump;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.StaticRoutes2;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.StaticRoutes2Builder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv6;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv6Builder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.VppIpv6RouteState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.NextHopList;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.next.hop.list.NextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol.StaticRoutes;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+interface Ipv6ReadRoutingNodes extends JvppReplyConsumer {
+
+    static InstanceIdentifier<StaticRoutes2> staticRoutesInstanceIdentifier(
+            final InstanceIdentifier<StaticRoutes> staticRoutesInstanceIdentifier) {
+        return staticRoutesInstanceIdentifier.augmentation(StaticRoutes2.class);
+    }
+
+    static InstanceIdentifier<Ipv6> ipv6Identifier(
+            final InstanceIdentifier<StaticRoutes2> staticRoutes2InstanceIdentifier) {
+        return staticRoutes2InstanceIdentifier.child(Ipv6.class);
+    }
+
+    default DumpCacheManager<Ip6FibDetailsReplyDump, Void> newIpv6RoutesDumpManager(
+            @Nonnull final FutureJVppCore vppApi) {
+        return new DumpCacheManager.DumpCacheManagerBuilder<Ip6FibDetailsReplyDump, Void>()
+                .withExecutor(
+                        (identifier, params) -> getReplyForRead(
+                                vppApi.ip6FibDump(new Ip6FibDump()).toCompletableFuture(), identifier))
+                .acceptOnly(Ip6FibDetailsReplyDump.class)
+                .build();
+    }
+
+    default void registerIpv6Routes(@Nonnull final InstanceIdentifier<StaticRoutes> subTreeId,
+                                    @Nonnull final ModifiableReaderRegistryBuilder registry,
+                                    @Nonnull final DumpCacheManager<Ip6FibDetailsReplyDump, Void> ipv6DumpManager,
+                                    @Nonnull final RoutingConfiguration configuration,
+                                    @Nonnull final MultiNamingContext routeHopContext,
+                                    @Nonnull final NamingContext interfaceContext,
+                                    @Nonnull final NamingContext routeContext,
+                                    @Nonnull final NamingContext routingProtocolContext) {
+
+        final InstanceIdentifier<StaticRoutes2> staticRoutes2InstanceIdentifier =
+                staticRoutesInstanceIdentifier(subTreeId);
+        final InstanceIdentifier<Ipv6> ipv6InstanceIdentifier = ipv6Identifier(staticRoutes2InstanceIdentifier);
+
+        registry.addStructuralReader(staticRoutes2InstanceIdentifier, StaticRoutes2Builder.class);
+
+        registry.addStructuralReader(ipv6InstanceIdentifier, Ipv6Builder.class);
+        registry.subtreeAdd(ipv6RoutingHandledChildren(InstanceIdentifier.create(Route.class)),
+                new GenericListReader<>(ipv6InstanceIdentifier.child(Route.class),
+                        new Ipv6RouteCustomizer(ipv6DumpManager, configuration, routeHopContext, interfaceContext,
+                                routeContext, routingProtocolContext)));
+    }
+
+    default Set<InstanceIdentifier<?>> ipv6RoutingHandledChildren(
+            final InstanceIdentifier<Route> parent) {
+        return ImmutableSet.of(parent.child(NextHopList.class),
+                parent.child(NextHopList.class).child(NextHop.class),
+                parent.child(VppIpv6RouteState.class));
+    }
+
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/Ipv6RouteCustomizer.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/Ipv6RouteCustomizer.java
new file mode 100644 (file)
index 0000000..c83891d
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.read;
+
+import static io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor.NO_PARAMS;
+
+import com.google.common.base.Optional;
+import io.fd.hc2vpp.common.translate.util.MultiNamingContext;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.RoutingConfiguration;
+import io.fd.hc2vpp.routing.naming.Ipv6RouteNamesFactory;
+import io.fd.hc2vpp.routing.trait.Ipv6RoutePathParser;
+import io.fd.hc2vpp.routing.trait.RouteMapper;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer;
+import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager;
+import io.fd.vpp.jvpp.core.dto.Ip6FibDetails;
+import io.fd.vpp.jvpp.core.dto.Ip6FibDetailsReplyDump;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv6Builder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.RouteBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.RouteKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.VppIpv6RouteStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocol;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class Ipv6RouteCustomizer
+        implements ListReaderCustomizer<Route, RouteKey, RouteBuilder>, RouteMapper, Ipv6RoutePathParser {
+
+    private final DumpCacheManager<Ip6FibDetailsReplyDump, Void> ipv6RoutesDumpManager;
+    private final RoutingConfiguration configuration;
+    private final MultiNamingContext routeHopContext;
+    private final NamingContext interfaceContext;
+    private final NamingContext routesContext;
+    private final NamingContext routingProtocolContext;
+    private final Ipv6RouteNamesFactory namesFactory;
+
+    public Ipv6RouteCustomizer(@Nonnull final DumpCacheManager<Ip6FibDetailsReplyDump, Void> ipv6RoutesDumpManager,
+                               @Nonnull final RoutingConfiguration configuration,
+                               @Nonnull final MultiNamingContext routeHopContext,
+                               @Nonnull final NamingContext interfaceContext,
+                               @Nonnull final NamingContext routesContext,
+                               @Nonnull final NamingContext routingProtocolContext) {
+        this.ipv6RoutesDumpManager = ipv6RoutesDumpManager;
+        this.configuration = configuration;
+        this.interfaceContext = interfaceContext;
+        this.routeHopContext = routeHopContext;
+        this.routesContext = routesContext;
+        this.routingProtocolContext = routingProtocolContext;
+        this.namesFactory = new Ipv6RouteNamesFactory(interfaceContext, routingProtocolContext);
+    }
+
+    @Nonnull
+    @Override
+    public List<RouteKey> getAllIds(@Nonnull final InstanceIdentifier<Route> instanceIdentifier,
+                                    @Nonnull final ReadContext readContext) throws ReadFailedException {
+
+        final Optional<Ip6FibDetailsReplyDump> ipv6RoutesDump =
+                ipv6RoutesDumpManager.getDump(instanceIdentifier, readContext.getModificationCache(), NO_PARAMS);
+
+        final String protocolName = instanceIdentifier.firstKeyOf(RoutingProtocol.class).getName();
+        final int protocolTableId = routingProtocolContext.getIndex(protocolName, readContext.getMappingContext());
+
+        return ipv6RoutesDump.isPresent()
+                ? ipv6RoutesDump.get().ip6FibDetails.stream()
+                .filter(details -> protocolTableId == details.tableId)
+                .map(ip6FibDetails -> toKey(ip6FibDetails, readContext.getMappingContext()))
+                .collect(Collectors.toList())
+                : Collections.emptyList();
+    }
+
+    /**
+     * route id is represented as number, but there's no index in dumped data,
+     * so index is assigned to name formatted as tableId_address_addressLength(should be unique combination)
+     */
+    private RouteKey toKey(final Ip6FibDetails details, final MappingContext mappingContext) {
+        String routeName = namesFactory.uniqueRouteName(details, mappingContext);
+        // first condition excludes data written manually, second one data that has been already learned
+        if (!routesContext.containsIndex(routeName, mappingContext)) {
+            String learnedRouteName = nameWithPrefix(configuration.getLearnedRouteNamePrefix(), routeName);
+            if (!routesContext.containsIndex(learnedRouteName, mappingContext)) {
+                routesContext.addName(learnedRouteName, mappingContext);
+            }
+            return keyForName(mappingContext, learnedRouteName);
+        }
+        return keyForName(mappingContext, routeName);
+    }
+
+    private RouteKey keyForName(final MappingContext mappingContext, final String name) {
+        return new RouteKey(Long.valueOf(routesContext.getIndex(name, mappingContext)));
+    }
+
+    @Override
+    public void merge(@Nonnull final Builder<? extends DataObject> builder, @Nonnull final List<Route> list) {
+        Ipv6Builder.class.cast(builder).setRoute(list);
+    }
+
+    @Nonnull
+    @Override
+    public RouteBuilder getBuilder(@Nonnull final InstanceIdentifier<Route> instanceIdentifier) {
+        return new RouteBuilder();
+    }
+
+    @Override
+    public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Route> instanceIdentifier,
+                                      @Nonnull final RouteBuilder routeBuilder, @Nonnull final ReadContext readContext)
+            throws ReadFailedException {
+        final RouteKey key = instanceIdentifier.firstKeyOf(Route.class);
+        final String mappedName = routesContext.getName(key.getId().intValue(), readContext.getMappingContext());
+        final String protocolName = instanceIdentifier.firstKeyOf(RoutingProtocol.class).getName();
+        final int protocolTableId = routingProtocolContext.getIndex(protocolName, readContext.getMappingContext());
+        final Optional<Ip6FibDetailsReplyDump> ipv6RoutesDump =
+                ipv6RoutesDumpManager.getDump(instanceIdentifier, readContext.getModificationCache(), NO_PARAMS);
+
+        if (ipv6RoutesDump.isPresent() && !ipv6RoutesDump.get().ip6FibDetails.isEmpty()) {
+
+            final java.util.Optional<Ip6FibDetails> opDetail = ipv6RoutesDump.get().ip6FibDetails.stream()
+                    .filter(details -> protocolTableId == details.tableId)
+                    .filter(details -> equalsWithConfigOrLearned(configuration.getLearnedRouteNamePrefix(), mappedName,
+                            namesFactory.uniqueRouteName(details, readContext.getMappingContext())))
+                    .findAny();
+
+            if (opDetail.isPresent()) {
+                final Ip6FibDetails detail = opDetail.get();
+
+                routeBuilder.setNextHopOptions(
+                        resolveHopType(mappedName, Arrays.asList(detail.path), interfaceContext, routeHopContext,
+                                readContext.getMappingContext(), namesFactory))
+                        .setKey(key)
+                        .setId(key.getId())
+                        .setDestinationPrefix(toIpv6Prefix(detail.address, toJavaByte(detail.addressLength)))
+                        .setVppIpv6RouteState(new VppIpv6RouteStateBuilder().build());
+            }
+        }
+    }
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/RoutingInstanceCustomizer.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/RoutingInstanceCustomizer.java
new file mode 100644 (file)
index 0000000..78e869f
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.read;
+
+import com.google.common.collect.ImmutableList;
+import io.fd.hc2vpp.routing.RoutingConfiguration;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer;
+import java.util.List;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.RoutingStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.StandardRoutingInstance;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.RoutingInstance;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.RoutingInstanceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.RoutingInstanceKey;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Returns default instance of routing instance
+ */
+public class RoutingInstanceCustomizer
+        implements ListReaderCustomizer<RoutingInstance, RoutingInstanceKey, RoutingInstanceBuilder> {
+
+    private RoutingInstanceKey defaultKey;
+
+    public RoutingInstanceCustomizer(@Nonnull final RoutingConfiguration configuration) {
+        defaultKey = new RoutingInstanceKey(configuration.getDefaultRoutingInstanceName());
+    }
+
+    @Nonnull
+    @Override
+    public List<RoutingInstanceKey> getAllIds(@Nonnull final InstanceIdentifier<RoutingInstance> instanceIdentifier,
+                                              @Nonnull final ReadContext readContext) throws ReadFailedException {
+        return ImmutableList.of(defaultKey);
+    }
+
+    @Override
+    public void merge(@Nonnull final Builder<? extends DataObject> builder, @Nonnull final List<RoutingInstance> list) {
+        RoutingStateBuilder.class.cast(builder).setRoutingInstance(list);
+    }
+
+    @Nonnull
+    @Override
+    public RoutingInstanceBuilder getBuilder(@Nonnull final InstanceIdentifier<RoutingInstance> instanceIdentifier) {
+        return new RoutingInstanceBuilder();
+    }
+
+    @Override
+    public void readCurrentAttributes(@Nonnull final InstanceIdentifier<RoutingInstance> instanceIdentifier,
+                                      @Nonnull final RoutingInstanceBuilder routingInstanceBuilder,
+                                      @Nonnull final ReadContext readContext) throws ReadFailedException {
+        routingInstanceBuilder.setType(StandardRoutingInstance.class)
+                .setKey(defaultKey)
+                .setName(defaultKey.getName());
+    }
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/RoutingProtocolCustomizer.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/RoutingProtocolCustomizer.java
new file mode 100644 (file)
index 0000000..c8a379b
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.read;
+
+import static io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor.NO_PARAMS;
+
+import com.google.common.base.Optional;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.trait.RouteMapper;
+import io.fd.honeycomb.translate.ModificationCache;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer;
+import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager;
+import io.fd.vpp.jvpp.core.dto.Ip6FibDetailsReplyDump;
+import io.fd.vpp.jvpp.core.dto.IpFibDetailsReplyDump;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.Static;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.RoutingProtocolsBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocol;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocolBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocolKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.RoutingProtocolStateVppAttr;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.RoutingProtocolStateVppAttrBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.VniReference;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.routing.state.routing.instance.routing.protocols.routing.protocol.VppProtocolStateAttributesBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+
+public class RoutingProtocolCustomizer
+        implements ListReaderCustomizer<RoutingProtocol, RoutingProtocolKey, RoutingProtocolBuilder>, RouteMapper {
+
+    private final NamingContext routingProtocolContext;
+    private final DumpCacheManager<IpFibDetailsReplyDump, Void> ipv4RoutesDumpManager;
+    private final DumpCacheManager<Ip6FibDetailsReplyDump, Void> ipv6RoutesDumpManager;
+
+
+    public RoutingProtocolCustomizer(@Nonnull final NamingContext routingProtocolContext,
+                                     @Nonnull final DumpCacheManager<IpFibDetailsReplyDump, Void> ipv4RoutesDumpManager,
+                                     @Nonnull final DumpCacheManager<Ip6FibDetailsReplyDump, Void> ipv6RoutesDumpManager) {
+        this.routingProtocolContext = routingProtocolContext;
+        this.ipv4RoutesDumpManager = ipv4RoutesDumpManager;
+        this.ipv6RoutesDumpManager = ipv6RoutesDumpManager;
+    }
+
+    @Nonnull
+    @Override
+    public List<RoutingProtocolKey> getAllIds(@Nonnull final InstanceIdentifier<RoutingProtocol> instanceIdentifier,
+                                              @Nonnull final ReadContext readContext) throws ReadFailedException {
+
+        final ModificationCache modificationCache = readContext.getModificationCache();
+
+        // builds keys from routing protocol prefix and unique set of table ids
+        return Stream.of(
+                ipv4TableIds(instanceIdentifier, modificationCache),
+                ipv6TableIds(instanceIdentifier, modificationCache))
+                .flatMap(Collection::stream)
+                .map(tableId -> routingProtocolContext.getName(tableId, readContext.getMappingContext()))
+                .distinct()
+                .map(RoutingProtocolKey::new)
+                .collect(Collectors.toList());
+    }
+
+    private List<Integer> ipv4TableIds(final InstanceIdentifier<RoutingProtocol> instanceIdentifier,
+                                       final ModificationCache modificationCache) throws ReadFailedException {
+        final Optional<IpFibDetailsReplyDump>
+                ipv4Routes = ipv4RoutesDumpManager.getDump(instanceIdentifier, modificationCache, NO_PARAMS);
+
+        if (ipv4Routes.isPresent()) {
+            return ipv4Routes.get().ipFibDetails.stream()
+                    .map(ipFibDetails -> ipFibDetails.tableId)
+                    .collect(Collectors.toList());
+        }
+        return Collections.emptyList();
+    }
+
+    private List<Integer> ipv6TableIds(final InstanceIdentifier<RoutingProtocol> instanceIdentifier,
+                                       final ModificationCache modificationCache) throws ReadFailedException {
+        final Optional<Ip6FibDetailsReplyDump>
+                ipv6Routes = ipv6RoutesDumpManager.getDump(instanceIdentifier, modificationCache, NO_PARAMS);
+
+        if (ipv6Routes.isPresent()) {
+            return ipv6Routes.get().ip6FibDetails.stream()
+                    .map(ipFibDetails -> ipFibDetails.tableId)
+                    .collect(Collectors.toList());
+        }
+        return Collections.emptyList();
+    }
+
+    @Override
+    public void merge(@Nonnull final Builder<? extends DataObject> builder, @Nonnull final List<RoutingProtocol> list) {
+        RoutingProtocolsBuilder.class.cast(builder).setRoutingProtocol(list);
+    }
+
+    @Nonnull
+    @Override
+    public RoutingProtocolBuilder getBuilder(@Nonnull final InstanceIdentifier<RoutingProtocol> instanceIdentifier) {
+        return new RoutingProtocolBuilder();
+    }
+
+    @Override
+    public void readCurrentAttributes(@Nonnull final InstanceIdentifier<RoutingProtocol> instanceIdentifier,
+                                      @Nonnull final RoutingProtocolBuilder routingProtocolBuilder,
+                                      @Nonnull final ReadContext readContext) throws ReadFailedException {
+
+        final RoutingProtocolKey key = instanceIdentifier.firstKeyOf(RoutingProtocol.class);
+        routingProtocolBuilder.setName(key.getName()).setKey(key).setType(Static.class)
+                .addAugmentation(RoutingProtocolStateVppAttr.class, new RoutingProtocolStateVppAttrBuilder()
+                        .setVppProtocolStateAttributes(new VppProtocolStateAttributesBuilder()
+                                .setPrimaryVrf(new VniReference(Long.valueOf(routingProtocolContext
+                                        .getIndex(key.getName(), readContext.getMappingContext()))))
+                                .build())
+                        .build());
+    }
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/RoutingStateCustomizer.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/RoutingStateCustomizer.java
new file mode 100644 (file)
index 0000000..5a6b23b
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.read;
+
+import io.fd.hc2vpp.routing.write.Ipv4WriteRoutingNodes;
+import io.fd.hc2vpp.routing.write.Ipv6WriteRoutingNodes;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.Initialized;
+import io.fd.honeycomb.translate.spi.read.InitializingReaderCustomizer;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.Routing;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.RoutingBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.RoutingState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.RoutingStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.StandardRoutingInstance;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.RoutingInstance;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.RoutingInstanceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.RoutingProtocols;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.RoutingProtocolsBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocol;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocolBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutesBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.RoutingProtocolStateVppAttr;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.RoutingProtocolVppAttr;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.RoutingProtocolVppAttrBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.routing.routing.instance.routing.protocols.routing.protocol.VppProtocolAttributesBuilder;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RoutingStateCustomizer
+        implements InitializingReaderCustomizer<RoutingState, RoutingStateBuilder>, Ipv4WriteRoutingNodes {
+
+    private static final Logger LOG = LoggerFactory.getLogger(RoutingStateCustomizer.class);
+
+    private static RoutingInstance mapRoutingInstances(
+            final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.RoutingInstance state) {
+        return new RoutingInstanceBuilder()
+                .setName(state.getName())
+                .setEnabled(true)
+                .setRouterId(state.getRouterId())
+                .setType(StandardRoutingInstance.class)
+                .setRoutingProtocols(RoutingStateCustomizer.mapRoutingProtocols(state.getRoutingProtocols()))
+                .build();
+    }
+
+    private static RoutingProtocols mapRoutingProtocols(
+            final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.RoutingProtocols state) {
+
+        if (state != null) {
+            return new RoutingProtocolsBuilder()
+                    .setRoutingProtocol(state.getRoutingProtocol() != null
+                            ? RoutingStateCustomizer.mapRoutingProtocol(state.getRoutingProtocol())
+                            : null)
+                    .build();
+        } else {
+            return null;
+        }
+    }
+
+    private static List<RoutingProtocol> mapRoutingProtocol(
+            final List<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocol> state) {
+        return state.stream()
+                .map(routingProtocol -> new RoutingProtocolBuilder()
+                        .setName(routingProtocol.getName())
+                        .setEnabled(true)
+                        .setType(routingProtocol.getType())
+                        .setStaticRoutes(RoutingStateCustomizer.mapStaticRoutes(routingProtocol.getStaticRoutes()))
+                        .addAugmentation(RoutingProtocolVppAttr.class,
+                                mapVppAttr(routingProtocol.getAugmentation(RoutingProtocolStateVppAttr.class)))
+                        .build())
+                .collect(Collectors.toList());
+    }
+
+    private static RoutingProtocolVppAttr mapVppAttr(final RoutingProtocolStateVppAttr attrState) {
+        return new RoutingProtocolVppAttrBuilder()
+                .setVppProtocolAttributes(attrState.getVppProtocolStateAttributes() == null
+                        ? null
+                        :
+                                new VppProtocolAttributesBuilder()
+                                        .setPrimaryVrf(attrState.getVppProtocolStateAttributes().getPrimaryVrf())
+                                        .build())
+                .build();
+    }
+
+    private static StaticRoutes mapStaticRoutes(
+            final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol.StaticRoutes state) {
+        return new StaticRoutesBuilder()
+                .addAugmentation(CONFIG_IPV4_AUG_CLASS,
+                        Ipv4WriteRoutingNodes.INSTANCE.mapIpv4Augmentation(state.getAugmentation(STATE_IPV4_AUG_CLASS)))
+                .addAugmentation(Ipv6WriteRoutingNodes.CONFIG_IPV6_AUG_CLASS,
+                        Ipv6WriteRoutingNodes.INSTANCE.mapIpv6Augmentation(state.getAugmentation(
+                                Ipv6WriteRoutingNodes.STATE_IPV6_AUG_CLASS)))
+                .build();
+    }
+
+    @Nonnull
+    @Override
+    public RoutingStateBuilder getBuilder(@Nonnull final InstanceIdentifier<RoutingState> instanceIdentifier) {
+        return new RoutingStateBuilder();
+    }
+
+    @Override
+    public void readCurrentAttributes(@Nonnull final InstanceIdentifier<RoutingState> instanceIdentifier,
+                                      @Nonnull final RoutingStateBuilder routingStateBuilder,
+                                      @Nonnull final ReadContext readContext) throws ReadFailedException {
+        // does nothing
+        LOG.info("Reading {}", instanceIdentifier);
+    }
+
+    @Override
+    public void merge(@Nonnull final Builder<? extends DataObject> builder, @Nonnull final RoutingState routingState) {
+        //Routing state is root
+    }
+
+    @Nonnull
+    @Override
+    public Initialized<? extends DataObject> init(@Nonnull final InstanceIdentifier<RoutingState> id,
+                                                  @Nonnull final RoutingState readValue,
+                                                  @Nonnull final ReadContext ctx) {
+
+        return Initialized.create(InstanceIdentifier.create(Routing.class), new RoutingBuilder()
+                .setRoutingInstance(readValue.getRoutingInstance()
+                        .stream()
+                        .map(routingInstance -> mapRoutingInstances(routingInstance))
+                        .collect(Collectors.toList()))
+                .build());
+    }
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/RoutingStateReaderFactory.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/read/RoutingStateReaderFactory.java
new file mode 100644 (file)
index 0000000..c26de12
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.read;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import io.fd.hc2vpp.common.translate.util.MultiNamingContext;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.RoutingConfiguration;
+import io.fd.honeycomb.translate.impl.read.GenericListReader;
+import io.fd.honeycomb.translate.impl.read.GenericReader;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
+import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager;
+import io.fd.vpp.jvpp.core.dto.Ip6FibDetailsReplyDump;
+import io.fd.vpp.jvpp.core.dto.IpFibDetailsReplyDump;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.RoutingState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.RoutingInstance;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.RoutingProtocols;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.RoutingProtocolsBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocol;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol.StaticRoutes;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol.StaticRoutesBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.RoutingProtocolStateVppAttr;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.routing.state.routing.instance.routing.protocols.routing.protocol.VppProtocolStateAttributes;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Factory producing readers for routing plugin's data.
+ */
+public final class RoutingStateReaderFactory implements ReaderFactory, Ipv4ReadRoutingNodes, Ipv6ReadRoutingNodes {
+
+    private static final InstanceIdentifier<RoutingState> ROOT_STATE_CONTAINER_ID =
+            InstanceIdentifier.create(RoutingState.class);
+
+    @Inject
+    private RoutingConfiguration configuration;
+
+    @Inject
+    @Named("interface-context")
+    private NamingContext interfaceContext;
+
+    @Inject
+    @Named(RoutingConfiguration.ROUTING_PROTOCOL_CONTEXT)
+    private NamingContext routingProtocolContext;
+
+    @Inject
+    @Named(RoutingConfiguration.ROUTE_CONTEXT)
+    private NamingContext routeContext;
+
+    @Inject
+    @Named(RoutingConfiguration.ROUTE_HOP_CONTEXT)
+    private MultiNamingContext routeHopContext;
+
+    @Inject
+    private FutureJVppCore vppApi;
+
+    @Override
+    public void init(@Nonnull final ModifiableReaderRegistryBuilder registry) {
+        final DumpCacheManager<IpFibDetailsReplyDump, Void> ipv4DumpManager = newIpv4RoutesDumpManager(vppApi);
+        final DumpCacheManager<Ip6FibDetailsReplyDump, Void> ipv6DumpManager = newIpv6RoutesDumpManager(vppApi);
+
+        final InstanceIdentifier<RoutingInstance> routingInstanceInstanceIdentifier =
+                routingInstanceIdentifier(ROOT_STATE_CONTAINER_ID);
+        final InstanceIdentifier<RoutingProtocols> routingProtocolsInstanceIdentifier =
+                routingProtocolsId(routingInstanceInstanceIdentifier);
+        final InstanceIdentifier<RoutingProtocol> routingProtocolInstanceIdentifier =
+                routingProtocolInstanceIdentifier(routingProtocolsInstanceIdentifier);
+        final InstanceIdentifier<StaticRoutes> staticRoutesInstanceIdentifier =
+                staticRoutesInstanceIdentifier(routingProtocolInstanceIdentifier);
+
+        // RoutingState
+        registry.add(new GenericReader<>(ROOT_STATE_CONTAINER_ID, new RoutingStateCustomizer()));
+        // RoutingInstance
+        registry.add(new GenericListReader<>(routingInstanceInstanceIdentifier,
+                new RoutingInstanceCustomizer(configuration)));
+
+        // RoutingProtocols
+        registry.addStructuralReader(routingProtocolsInstanceIdentifier, RoutingProtocolsBuilder.class);
+
+        // RoutingProtocol
+        registry.subtreeAdd(routingProtocolHandledChildren(), new GenericListReader<>(routingProtocolInstanceIdentifier,
+                new RoutingProtocolCustomizer(routingProtocolContext, ipv4DumpManager, ipv6DumpManager)));
+
+        // StaticRoutes
+        registry.addStructuralReader(staticRoutesInstanceIdentifier, StaticRoutesBuilder.class);
+
+        registerIpv4Routes(staticRoutesInstanceIdentifier, registry, ipv4DumpManager, configuration, routeHopContext,
+                interfaceContext, routeContext, routingProtocolContext);
+        registerIpv6Routes(staticRoutesInstanceIdentifier, registry, ipv6DumpManager, configuration, routeHopContext,
+                interfaceContext, routeContext, routingProtocolContext);
+    }
+
+    private static ImmutableSet<InstanceIdentifier<?>> routingProtocolHandledChildren() {
+        return ImmutableSet
+                .of(InstanceIdentifier.create(RoutingProtocol.class).augmentation(RoutingProtocolStateVppAttr.class)
+                        .child(VppProtocolStateAttributes.class));
+    }
+
+    private InstanceIdentifier<StaticRoutes> staticRoutesInstanceIdentifier(
+            final InstanceIdentifier<RoutingProtocol> routingProtocolInstanceIdentifier) {
+        return routingProtocolInstanceIdentifier.child(StaticRoutes.class);
+    }
+
+    private InstanceIdentifier<RoutingProtocol> routingProtocolInstanceIdentifier(
+            final InstanceIdentifier<RoutingProtocols> routingProtocolsInstanceIdentifier) {
+        return routingProtocolsInstanceIdentifier.child(RoutingProtocol.class);
+    }
+
+    private InstanceIdentifier<RoutingProtocols> routingProtocolsId(
+            final InstanceIdentifier<RoutingInstance> routingInstanceInstanceIdentifier) {
+        return routingInstanceInstanceIdentifier.child(RoutingProtocols.class);
+    }
+
+    private InstanceIdentifier<RoutingInstance> routingInstanceIdentifier(
+            final InstanceIdentifier<RoutingState> routingStateId) {
+        return routingStateId.child(RoutingInstance.class);
+    }
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/trait/Ipv4RoutePathParser.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/trait/Ipv4RoutePathParser.java
new file mode 100644 (file)
index 0000000..58dee23
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.trait;
+
+import static io.fd.hc2vpp.routing.trait.RouteMapper.isDefaultInterfaceIndex;
+
+import io.fd.hc2vpp.common.translate.util.AddressTranslator;
+import io.fd.hc2vpp.common.translate.util.MultiNamingContext;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.naming.Ipv4RouteNamesFactory;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.vpp.jvpp.core.types.FibPath;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.NextHopOptions;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SimpleNextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SimpleNextHopBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SpecialNextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SpecialNextHopBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.NextHopListBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHopBuilder;
+
+public interface Ipv4RoutePathParser extends RouteMapper {
+
+    static NextHopOptions resolveOption(final String routeName,
+                                        final List<FibPath> parsedHops,
+                                        final NamingContext interfaceContext,
+                                        final MultiNamingContext routeHopContext,
+                                        final MappingContext mappingContext,
+                                        final Ipv4RouteNamesFactory namesFactory) {
+        return parsedHops.size() == 1
+                ? RouteMapper.INSTANCE.isSpecialHop(parsedHops.get(0))
+                ? specialHop(parsedHops.get(0))
+                : simpleHop(parsedHops.get(0), interfaceContext, mappingContext)
+                : hopList(routeName, parsedHops, interfaceContext, routeHopContext, mappingContext, namesFactory);
+    }
+
+    static SpecialNextHop specialHop(final FibPath singlePath) {
+        return new SpecialNextHopBuilder()
+                .setSpecialNextHop(RouteMapper.INSTANCE.specialHopType(singlePath))
+                .build();
+    }
+
+    static SimpleNextHop simpleHop(final FibPath path, final NamingContext interfaceContext,
+                                   final MappingContext mappingContext) {
+        return resolveInterfaceIfSpecified(new SimpleNextHopBuilder(), path.swIfIndex, interfaceContext, mappingContext)
+                .setNextHop(AddressTranslator.INSTANCE.arrayToIpv4AddressNoZone(path.nextHop))
+                .build();
+    }
+
+    static SimpleNextHopBuilder resolveInterfaceIfSpecified(final SimpleNextHopBuilder builder, final int index,
+                                                            final NamingContext interfaceContext,
+                                                            final MappingContext mappingContext) {
+        if (!isDefaultInterfaceIndex(index)) {
+            builder.setOutgoingInterface(interfaceContext.getName(index, mappingContext));
+        }
+        return builder;
+    }
+
+    static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.NextHopList hopList(
+            final String routeName,
+            final List<FibPath> parsedHops,
+            final NamingContext interfaceContext,
+            final MultiNamingContext routeHopContext,
+            final MappingContext mappingContext,
+            final Ipv4RouteNamesFactory namesFactory) {
+        return new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.NextHopListBuilder()
+                .setNextHopList(
+                        new NextHopListBuilder().setNextHop(parsedHops.stream()
+                                .map(fibPath -> resolveInterfaceIfSpecified(new NextHopBuilder(), fibPath.swIfIndex,
+                                        interfaceContext, mappingContext)
+                                        .setId((long) (routeHopContext.getChildIndex(routeName,
+                                                namesFactory.uniqueRouteHopName(fibPath, mappingContext),
+                                                mappingContext)))
+                                        .setWeight(((short) fibPath.weight))
+                                        .setAddress(
+                                                AddressTranslator.INSTANCE
+                                                        .arrayToIpv4AddressNoZone(fibPath.nextHop))
+                                        .build())
+                                .collect(Collectors.toList()))
+                                .build())
+                .build();
+    }
+
+    static NextHopBuilder resolveInterfaceIfSpecified(final NextHopBuilder builder, final int index,
+                                                      final NamingContext interfaceContext,
+                                                      final MappingContext mappingContext) {
+        if (!isDefaultInterfaceIndex(index)) {
+            builder.setOutgoingInterface(interfaceContext.getName(index, mappingContext));
+        }
+        return builder;
+    }
+
+    default NextHopOptions resolveHopType(@Nonnull final String routeName,
+                                          final List<FibPath> parsedHops,
+                                          @Nonnull final NamingContext interfaceContext,
+                                          @Nonnull final MultiNamingContext routeHopContext,
+                                          @Nonnull final MappingContext mappingContext,
+                                          @Nonnull final Ipv4RouteNamesFactory namesFactory) {
+
+        return parsedHops == null || parsedHops.isEmpty()
+                ? null
+                : resolveOption(routeName, parsedHops, interfaceContext, routeHopContext, mappingContext, namesFactory);
+    }
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/trait/Ipv6RoutePathParser.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/trait/Ipv6RoutePathParser.java
new file mode 100644 (file)
index 0000000..9084729
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.trait;
+
+import static io.fd.hc2vpp.routing.trait.RouteMapper.isDefaultInterfaceIndex;
+
+import io.fd.hc2vpp.common.translate.util.AddressTranslator;
+import io.fd.hc2vpp.common.translate.util.MultiNamingContext;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.naming.Ipv6RouteNamesFactory;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.vpp.jvpp.core.types.FibPath;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.NextHopOptions;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SimpleNextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SimpleNextHopBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SpecialNextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SpecialNextHopBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.NextHopList;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.NextHopListBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.next.hop.list.NextHopBuilder;
+
+public interface Ipv6RoutePathParser extends RouteMapper {
+
+    static NextHopOptions resolveOption(final String routeName,
+                                        final List<FibPath> parsedHops,
+                                        final NamingContext interfaceContext,
+                                        final MultiNamingContext routeHopContext,
+                                        final MappingContext mappingContext,
+                                        final Ipv6RouteNamesFactory namesFactory) {
+        return parsedHops.size() == 1
+                ? INSTANCE.isSpecialHop(parsedHops.get(0))
+                ? specialHop(parsedHops.get(0))
+                : simpleHop(parsedHops.get(0), interfaceContext, mappingContext)
+                : hopList(routeName, parsedHops, interfaceContext, routeHopContext, mappingContext, namesFactory);
+    }
+
+    static SpecialNextHop specialHop(final FibPath fibPath) {
+        return new SpecialNextHopBuilder()
+                .setSpecialNextHop(INSTANCE.specialHopType(fibPath))
+                .build();
+    }
+
+    static SimpleNextHop simpleHop(final FibPath path, final NamingContext interfaceContext,
+                                   final MappingContext mappingContext) {
+        return resolveInterfaceIfSpecified(new SimpleNextHopBuilder(), path.swIfIndex, interfaceContext, mappingContext)
+                .setNextHop(AddressTranslator.INSTANCE.arrayToIpv6AddressNoZone(path.nextHop))
+                .build();
+    }
+
+    static SimpleNextHopBuilder resolveInterfaceIfSpecified(SimpleNextHopBuilder builder, final int index,
+                                                            final NamingContext interfaceContext,
+                                                            final MappingContext mappingContext) {
+        if (!isDefaultInterfaceIndex(index)) {
+            builder.setOutgoingInterface(interfaceContext.getName(index, mappingContext));
+        }
+
+        return builder;
+    }
+
+    static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.NextHopList hopList(
+            final String routeName,
+            final List<FibPath> parsedHops,
+            final NamingContext interfaceContext,
+            final MultiNamingContext routeHopContext,
+            final MappingContext mappingContext,
+            final Ipv6RouteNamesFactory namesFactory) {
+        return new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.NextHopListBuilder()
+                .setNextHopList(
+                        buildNextHopList(routeName, parsedHops, interfaceContext, routeHopContext, mappingContext,
+                                namesFactory))
+                .build();
+    }
+
+    static NextHopList buildNextHopList(final String routeName, final List<FibPath> parsedHops,
+                                        final NamingContext interfaceContext,
+                                        final MultiNamingContext routeHopContext,
+                                        final MappingContext mappingContext,
+                                        final Ipv6RouteNamesFactory namesFactory) {
+        return new NextHopListBuilder().setNextHop(parsedHops.stream()
+                .map(fibPath -> resolveInterfaceIfSpecified(new NextHopBuilder(), fibPath.swIfIndex, interfaceContext,
+                        mappingContext)
+                        .setId(findIdWithinRouteContext(routeName, routeHopContext, mappingContext, fibPath,
+                                namesFactory))
+                        .setWeight((short) fibPath.weight)
+                        .setAddress(AddressTranslator.INSTANCE.arrayToIpv6AddressNoZone(fibPath.nextHop))
+                        .build())
+                .collect(Collectors.toList()))
+                .build();
+    }
+
+    static NextHopBuilder resolveInterfaceIfSpecified(NextHopBuilder builder, final int index,
+                                                      final NamingContext interfaceContext,
+                                                      final MappingContext mappingContext) {
+        if (!isDefaultInterfaceIndex(index)) {
+            builder.setOutgoingInterface(interfaceContext.getName(index, mappingContext));
+        }
+
+        return builder;
+    }
+
+    static long findIdWithinRouteContext(final String routeName, final MultiNamingContext routeHopContext,
+                                         final MappingContext mappingContext, final FibPath fibPath,
+                                         final Ipv6RouteNamesFactory namesFactory) {
+        return (long) (routeHopContext
+                .getChildIndex(routeName, namesFactory.uniqueRouteHopName(fibPath, mappingContext), mappingContext));
+    }
+
+    default NextHopOptions resolveHopType(@Nonnull final String routeName,
+                                          final List<FibPath> parsedHops,
+                                          @Nonnull final NamingContext interfaceContext,
+                                          @Nonnull final MultiNamingContext routeHopContext,
+                                          @Nonnull final MappingContext mappingContext,
+                                          @Nonnull final Ipv6RouteNamesFactory namesFactory) {
+
+        return parsedHops == null || parsedHops.isEmpty()
+                ? null
+                : resolveOption(routeName, parsedHops, interfaceContext, routeHopContext, mappingContext, namesFactory);
+    }
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/trait/RouteMapper.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/trait/RouteMapper.java
new file mode 100644 (file)
index 0000000..deabdac
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.trait;
+
+import io.fd.hc2vpp.common.translate.util.AddressTranslator;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.vpp.jvpp.core.types.FibPath;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.SpecialNextHopGrouping;
+
+public interface RouteMapper extends AddressTranslator, ByteDataTranslator {
+
+    int DEFAULT_INTERFACE_INDEX = -1;
+    RouteMapper INSTANCE = new RouteMapper() {
+    };
+
+    static boolean isDefaultInterfaceIndex(final int index) {
+        return DEFAULT_INTERFACE_INDEX == index;
+    }
+
+    static boolean flagEnabled(final byte flag) {
+        return ByteDataTranslator.INSTANCE.byteToBoolean(flag);
+    }
+
+    /**
+     * Verifies whether provided table id is for provided protocol name
+     */
+    default boolean isWithinProtocol(@Nonnull final String protocolName,
+                                     @Nonnull final String routingProtocolNamePrefix,
+                                     @Nonnull final Integer tableId) {
+        return protocolName.equals(fullRoutingProtocolName(routingProtocolNamePrefix, tableId));
+    }
+
+    /**
+     * Return full protocol name in form routing_protocol_name_prefix + table
+     */
+    default String fullRoutingProtocolName(@Nonnull final String routingProtocolNamePrefix,
+                                           @Nonnull final Integer tableId) {
+        return nameWithPrefix(routingProtocolNamePrefix, String.valueOf(tableId));
+    }
+
+    default String bindName(@Nonnull final String first, @Nonnull final String second, @Nonnull final String third) {
+        return String.format("%s_%s_%s", first, second, third);
+    }
+
+    default String nameWithPrefix(@Nonnull final String prefix, @Nonnull final String name) {
+        return String.format("%s_%s", prefix, name);
+    }
+
+    default boolean equalsWithConfigOrLearned(@Nonnull final String learnedPrefix, @Nonnull final String searched,
+                                              @Nonnull final String name) {
+        return searched.equals(name) || searched.equals(nameWithPrefix(learnedPrefix, name));
+    }
+
+    /**
+     * Resolve if provided {@link FibPath} should be considered as special hop.
+     * Special hop is hop that has any of special flags turned on(drop,local,prohibit,unreachable)
+     */
+    default boolean isSpecialHop(@Nonnull final FibPath path) {
+        return byteToBoolean(path.isDrop) || byteToBoolean(path.isLocal) || byteToBoolean(path.isProhibit) ||
+                byteToBoolean(path.isUnreach);
+    }
+
+    default SpecialNextHopGrouping.SpecialNextHop specialHopType(final FibPath singlePath) {
+        if (flagEnabled(singlePath.isDrop)) {
+            return SpecialNextHopGrouping.SpecialNextHop.Blackhole;
+        } else if (flagEnabled(singlePath.isLocal)) {
+            return SpecialNextHopGrouping.SpecialNextHop.Receive;
+        } else if (flagEnabled(singlePath.isProhibit)) {
+            return SpecialNextHopGrouping.SpecialNextHop.Prohibit;
+        } else if (flagEnabled(singlePath.isUnreach)) {
+            return SpecialNextHopGrouping.SpecialNextHop.Unreachable;
+        } else {
+            throw new IllegalArgumentException(
+                    String.format("An attempt to resolve illegal path %s detected ", singlePath.toString()));
+        }
+    }
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/Ipv4RouteCustomizer.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/Ipv4RouteCustomizer.java
new file mode 100644 (file)
index 0000000..6252b8d
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.write;
+
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.MultiNamingContext;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.naming.Ipv4RouteNamesFactory;
+import io.fd.hc2vpp.routing.trait.RouteMapper;
+import io.fd.hc2vpp.routing.write.factory.MultipathHopRequestFactory;
+import io.fd.hc2vpp.routing.write.factory.SimpleHopRequestFactory;
+import io.fd.hc2vpp.routing.write.factory.SpecialNextHopRequestFactory;
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.IpAddDelRoute;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv4;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.RouteKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.NextHopList;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SimpleNextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SpecialNextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocol;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for handling write operations for {@link Ipv4} according to ietf-ipv4-unicast-routing.yang
+ */
+public class Ipv4RouteCustomizer extends FutureJVppCustomizer
+        implements ListWriterCustomizer<Route, RouteKey>, JvppReplyConsumer, RouteMapper {
+
+    private static final Logger LOG = LoggerFactory.getLogger(Ipv4RouteCustomizer.class);
+
+
+    private final NamingContext routesContext;
+    private final MultiNamingContext routesHopsContext;
+    /**
+     * Request factories
+     */
+    private final SimpleHopRequestFactory simpleHopRequestFactory;
+    private final MultipathHopRequestFactory multipathHopRequestFactory;
+    private final SpecialNextHopRequestFactory specialNextHopRequestFactory;
+
+    /**
+     * Names factory
+     */
+    private final Ipv4RouteNamesFactory routeNamesFactory;
+
+    public Ipv4RouteCustomizer(@Nonnull final FutureJVppCore futureJVppCore,
+                               @Nonnull final NamingContext interfaceContext,
+                               @Nonnull final NamingContext routesContext,
+                               @Nonnull final NamingContext routingProtocolContext,
+                               @Nonnull final MultiNamingContext routesHopsContext,
+                               @Nonnull final VppClassifierContextManager classifierContextManager) {
+        super(futureJVppCore);
+
+        this.routesContext = routesContext;
+        this.routesHopsContext = routesHopsContext;
+        simpleHopRequestFactory =
+                SimpleHopRequestFactory.forContexts(classifierContextManager, interfaceContext, routingProtocolContext);
+        multipathHopRequestFactory = MultipathHopRequestFactory
+                .forContexts(classifierContextManager, interfaceContext, routingProtocolContext);
+        specialNextHopRequestFactory = SpecialNextHopRequestFactory.forClassifierContext(classifierContextManager);
+        routeNamesFactory = new Ipv4RouteNamesFactory(interfaceContext, routingProtocolContext);
+    }
+
+    @Override
+    public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Route> instanceIdentifier,
+                                       @Nonnull final Route route,
+                                       @Nonnull final WriteContext writeContext) throws WriteFailedException {
+        final String parentProtocolName = instanceIdentifier.firstKeyOf(RoutingProtocol.class).getName();
+        final String routeName = routeNamesFactory.uniqueRouteName(parentProtocolName, route);
+        writeRoute(instanceIdentifier, parentProtocolName, routeName, route, writeContext, true);
+
+        // maps new route by next available index,
+        routesContext.addName(routeName, writeContext.getMappingContext());
+    }
+
+    @Override
+    public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Route> instanceIdentifier,
+                                        @Nonnull final Route routeBefore,
+                                        @Nonnull final Route routeAfter, @Nonnull final WriteContext writeContext)
+            throws WriteFailedException {
+        throw new WriteFailedException.UpdateFailedException(instanceIdentifier, routeBefore, routeAfter,
+                new UnsupportedOperationException("Operation not supported"));
+    }
+
+    @Override
+    public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Route> instanceIdentifier,
+                                        @Nonnull final Route route,
+                                        @Nonnull final WriteContext writeContext) throws WriteFailedException {
+        final String parentProtocolName = instanceIdentifier.firstKeyOf(RoutingProtocol.class).getName();
+        final String routeName = routeNamesFactory.uniqueRouteName(parentProtocolName, route);
+        writeRoute(instanceIdentifier, parentProtocolName, routeName, route, writeContext, false);
+        routesContext.removeName(routeName, writeContext.getMappingContext());
+    }
+
+    private void writeRoute(@Nonnull final InstanceIdentifier<Route> identifier,
+                            @Nonnull final String parentProtocolName,
+                            @Nonnull final String routeName,
+                            @Nonnull final Route route,
+                            @Nonnull final WriteContext writeContext,
+                            final boolean isAdd) throws WriteFailedException {
+        if (route.getNextHopOptions() instanceof SimpleNextHop) {
+            writeRoute(
+                    simpleHopRequestFactory.createIpv4SimpleHopRequest(isAdd, parentProtocolName, route,
+                            writeContext.getMappingContext()),
+                    identifier);
+        } else if (route.getNextHopOptions() instanceof NextHopList) {
+            final List<NextHop> createdHops =
+                    writeMultihopRoute(identifier, parentProtocolName, route, writeContext, isAdd);
+
+            // after all hops has been added, add mappings to preserve hop ids, or remove them
+            if (isAdd) {
+                addMappingForEachHop(routeName, writeContext, createdHops);
+            } else {
+                removeMappingForEachHop(routeName, writeContext, createdHops);
+            }
+        } else if (route.getNextHopOptions() instanceof SpecialNextHop) {
+            writeSpecialHopRoute(identifier, route, writeContext, isAdd);
+        } else {
+            throw new IllegalArgumentException("Unsupported next-hop type");
+        }
+    }
+
+    private void removeMappingForEachHop(final @Nonnull String routeName, final @Nonnull WriteContext writeContext,
+                                         final List<NextHop> createdHops) {
+        createdHops.forEach(nextHop -> routesHopsContext.removeChild(routeName,
+                routeNamesFactory.uniqueRouteHopName(nextHop),
+                writeContext.getMappingContext()));
+    }
+
+    private void addMappingForEachHop(final @Nonnull String routeName, final @Nonnull WriteContext writeContext,
+                                      final List<NextHop> createdHops) {
+        createdHops.forEach(nextHop -> routesHopsContext.addChild(routeName,
+                nextHop.getId().intValue(),
+                routeNamesFactory.uniqueRouteHopName(nextHop),
+                writeContext.getMappingContext()));
+    }
+
+    private List<NextHop> writeMultihopRoute(@Nonnull final InstanceIdentifier<Route> identifier,
+                                             @Nonnull final String parentProtocolName,
+                                             @Nonnull final Route route,
+                                             @Nonnull final WriteContext writeContext,
+                                             final boolean isAdd)
+            throws WriteFailedException {
+        // list of next hops
+        final NextHopList hopList = NextHopList.class.cast(route.getNextHopOptions());
+        final MappingContext mappingContext = writeContext.getMappingContext();
+        LOG.debug("Writing hop list {} for route {}", hopList, identifier);
+
+        // order hops to preserve order by ids(even that model is not ordered)
+        final List<NextHop> orderedHops = hopList.getNextHopList().getNextHop()
+                .stream()
+                .sorted((left, right) -> (int) (left.getId() - right.getId()))
+                .collect(Collectors.toList());
+
+        for (NextHop hop : orderedHops) {
+            LOG.debug("Writing hop {} for route {}", hop, identifier);
+
+            final IpAddDelRoute request = multipathHopRequestFactory
+                    .createIpv4MultipathHopRequest(isAdd, parentProtocolName, route, hop, mappingContext);
+
+            writeRoute(request, identifier);
+        }
+
+        return orderedHops;
+    }
+
+
+    private void writeSpecialHopRoute(final @Nonnull InstanceIdentifier<Route> identifier, final @Nonnull Route route,
+                                      final @Nonnull WriteContext writeContext, final boolean isAdd)
+            throws WriteFailedException {
+        final SpecialNextHop hop = SpecialNextHop.class.cast(route.getNextHopOptions());
+        final MappingContext mappingContext = writeContext.getMappingContext();
+
+        final IpAddDelRoute request = specialNextHopRequestFactory
+                .createIpv4SpecialHopRequest(isAdd, route, mappingContext, hop.getSpecialNextHop());
+
+        writeRoute(request, identifier);
+    }
+
+
+    private void writeRoute(final IpAddDelRoute request, final InstanceIdentifier<Route> identifier)
+            throws WriteFailedException {
+        LOG.debug("Writing request {} for path {}", request, identifier);
+        getReplyForWrite(getFutureJVpp().ipAddDelRoute(request).toCompletableFuture(), identifier);
+    }
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/Ipv4WriteRoutingNodes.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/Ipv4WriteRoutingNodes.java
new file mode 100644 (file)
index 0000000..a7a7e94
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.write;
+
+import com.google.common.collect.ImmutableSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.StaticRoutes1;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.StaticRoutes1Builder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.StaticRoutes2;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv4;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv4Builder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.RouteBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.RouteKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.NextHopOptions;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.VppIpv4Route;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.VppIpv4RouteBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.NextHopList;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.NextHopListBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SimpleNextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SimpleNextHopBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SpecialNextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SpecialNextHopBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHopBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHopKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public interface Ipv4WriteRoutingNodes {
+
+    Ipv4WriteRoutingNodes INSTANCE = new Ipv4WriteRoutingNodes() {
+    };
+
+    Class<StaticRoutes1> CONFIG_IPV4_AUG_CLASS = StaticRoutes1.class;
+    Class<StaticRoutes2> STATE_IPV4_AUG_CLASS = StaticRoutes2.class;
+
+    static Ipv4 mapIpv4(
+            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv4 state) {
+        return new Ipv4Builder()
+                .setRoute(state.getRoute()
+                        .stream()
+                        .map(route -> new RouteBuilder()
+                                .setKey(new RouteKey(route.getKey().getId()))
+                                .setDestinationPrefix(route.getDestinationPrefix())
+                                .setDescription(route.getDescription())
+                                .setId(route.getId())
+                                .setVppIpv4Route(mapVppIpv4Route(route.getVppIpv4RouteState()))
+                                .setNextHopOptions(mapNextHopOptions(route.getNextHopOptions()))
+                                .build())
+                        .collect(Collectors.toList()))
+                .build();
+    }
+
+    static VppIpv4Route mapVppIpv4Route(
+            final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.VppIpv4RouteState state) {
+
+        return state == null
+                ? null
+                : new VppIpv4RouteBuilder()
+                        // false is default
+                        .setSecondaryVrf(state.getSecondaryVrf())
+                        .setClassifyTable(state.getClassifyTable())
+                        .build();
+    }
+
+    static NextHopOptions mapNextHopOptions(
+            final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.NextHopOptions state) {
+        if (state instanceof org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SimpleNextHop) {
+            return mapSimpleNextHop(
+                    org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SimpleNextHop.class
+                            .cast(state));
+        } else if (state instanceof org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.NextHopList) {
+            return mapNextHopList(
+                    org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.NextHopList.class
+                            .cast(state));
+        } else if (state instanceof org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SpecialNextHop) {
+            return mapSpecialNextHop(
+                    org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SpecialNextHop.class
+                            .cast(state));
+        } else {
+            throw new UnsupportedOperationException("Unsupported next hop type");
+        }
+    }
+
+    static SimpleNextHop mapSimpleNextHop(
+            final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SimpleNextHop hop) {
+        return new SimpleNextHopBuilder()
+                .setNextHop(hop.getNextHop())
+                .setOutgoingInterface(hop.getOutgoingInterface())
+                .build();
+    }
+
+    static NextHopList mapNextHopList(
+            final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.NextHopList state) {
+        return new NextHopListBuilder()
+                .setNextHopList(mapNextHopListList(state.getNextHopList()))
+                .build();
+    }
+
+    static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.NextHopList mapNextHopListList(
+            final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.NextHopList state) {
+        return new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.NextHopListBuilder()
+                .setNextHop(state.getNextHop()
+                        .stream()
+                        .map(nextHop -> new NextHopBuilder()
+                                .setId(nextHop.getId())
+                                .setOutgoingInterface(nextHop.getOutgoingInterface())
+                                .setWeight(nextHop.getWeight())
+                                .setPriority(nextHop.getPriority())
+                                .setAddress(nextHop.getAddress())
+                                .setKey(new NextHopKey(nextHop.getKey().getId()))
+                                .build())
+                        .collect(Collectors.toList()))
+                .build();
+    }
+
+    static SpecialNextHop mapSpecialNextHop(
+            final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SpecialNextHop hop) {
+        return new SpecialNextHopBuilder()
+                .setSpecialNextHop(hop.getSpecialNextHop())
+                .build();
+    }
+
+    default InstanceIdentifier<Route> ipv4RouteIdentifier(
+            final InstanceIdentifier<StaticRoutes> staticRoutesIdentifier) {
+        return staticRoutesIdentifier
+                .augmentation(StaticRoutes1.class)
+                .child(Ipv4.class)
+                .child(Route.class);
+    }
+
+    default Set<InstanceIdentifier<?>> ipv4RoutingHandledChildren(final InstanceIdentifier<Route> parent) {
+        return ImmutableSet.of(parent
+                        .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.NextHopList.class),
+                parent.child(
+                        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.NextHopList.class)
+                        .child(NextHop.class),
+                parent.child(VppIpv4Route.class));
+    }
+
+    default InstanceIdentifier<Route> ipv4RouteSubtree() {
+        return InstanceIdentifier.create(Route.class);
+    }
+
+    default StaticRoutes1 mapIpv4Augmentation(final StaticRoutes2 state) {
+        if (state == null) {
+            return null;
+        }
+        return new StaticRoutes1Builder()
+                .setIpv4(mapIpv4(state.getIpv4()))
+                .build();
+    }
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/Ipv6RouteCustomizer.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/Ipv6RouteCustomizer.java
new file mode 100644 (file)
index 0000000..aa71386
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.write;
+
+
+import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.MultiNamingContext;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.naming.Ipv6RouteNamesFactory;
+import io.fd.hc2vpp.routing.trait.RouteMapper;
+import io.fd.hc2vpp.routing.write.factory.MultipathHopRequestFactory;
+import io.fd.hc2vpp.routing.write.factory.SimpleHopRequestFactory;
+import io.fd.hc2vpp.routing.write.factory.SpecialNextHopRequestFactory;
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.IpAddDelRoute;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv6;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.RouteKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.NextHopList;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SimpleNextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SpecialNextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.next.hop.list.NextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocol;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Customizer for handling write operations for {@link Ipv6} according to ietf-ipv6-unicast-routing.yang
+ */
+public class Ipv6RouteCustomizer extends FutureJVppCustomizer
+        implements ListWriterCustomizer<Route, RouteKey>, JvppReplyConsumer, RouteMapper {
+
+    private static final Logger LOG = LoggerFactory.getLogger(Ipv6RouteCustomizer.class);
+
+    private final NamingContext routesContext;
+    private final MultiNamingContext routesHopsContext;
+    /**
+     * Request factories
+     */
+    private final SimpleHopRequestFactory simpleHopRequestFactory;
+    private final MultipathHopRequestFactory multipathHopRequestFactory;
+    private final SpecialNextHopRequestFactory specialNextHopRequestFactory;
+
+    /**
+     * Naming factory
+     */
+    private final Ipv6RouteNamesFactory namesFactory;
+
+    public Ipv6RouteCustomizer(@Nonnull final FutureJVppCore futureJVppCore,
+                               @Nonnull final NamingContext interfaceContext,
+                               @Nonnull final NamingContext routesContext,
+                               @Nonnull final NamingContext routingProtocolContext,
+                               @Nonnull final MultiNamingContext routesHopsContext,
+                               @Nonnull final VppClassifierContextManager classifierContextManager) {
+        super(futureJVppCore);
+
+        this.routesContext = routesContext;
+        this.routesHopsContext = routesHopsContext;
+        simpleHopRequestFactory =
+                SimpleHopRequestFactory.forContexts(classifierContextManager, interfaceContext, routingProtocolContext);
+        multipathHopRequestFactory = MultipathHopRequestFactory
+                .forContexts(classifierContextManager, interfaceContext, routingProtocolContext);
+        specialNextHopRequestFactory = SpecialNextHopRequestFactory.forClassifierContext(classifierContextManager);
+        namesFactory = new Ipv6RouteNamesFactory(interfaceContext, routingProtocolContext);
+    }
+
+    @Override
+    public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Route> instanceIdentifier,
+                                       @Nonnull final Route route,
+                                       @Nonnull final WriteContext writeContext) throws WriteFailedException {
+        final String parentProtocolName = instanceIdentifier.firstKeyOf(RoutingProtocol.class).getName();
+        final String routeName = namesFactory.uniqueRouteName(parentProtocolName, route);
+        writeRoute(instanceIdentifier, parentProtocolName, routeName, route, writeContext, true);
+
+        // maps new route by next available index,
+        routesContext.addName(routeName, writeContext.getMappingContext());
+    }
+
+    @Override
+    public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Route> instanceIdentifier,
+                                        @Nonnull final Route route,
+                                        @Nonnull final Route d1, @Nonnull final WriteContext writeContext)
+            throws WriteFailedException {
+        throw new WriteFailedException(instanceIdentifier,
+                new UnsupportedOperationException("Operation not supported"));
+    }
+
+    @Override
+    public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Route> instanceIdentifier,
+                                        @Nonnull final Route route,
+                                        @Nonnull final WriteContext writeContext) throws WriteFailedException {
+        final String parentProtocolName = instanceIdentifier.firstKeyOf(RoutingProtocol.class).getName();
+        final String routeName = namesFactory.uniqueRouteName(parentProtocolName, route);
+        writeRoute(instanceIdentifier, parentProtocolName, routeName, route, writeContext, false);
+        routesContext.removeName(routeName, writeContext.getMappingContext());
+    }
+
+    private void writeRoute(@Nonnull final InstanceIdentifier<Route> identifier,
+                            @Nonnull final String parentProtocolName,
+                            @Nonnull final String routeName,
+                            @Nonnull final Route route,
+                            @Nonnull final WriteContext writeContext,
+                            final boolean isAdd) throws WriteFailedException {
+        if (route.getNextHopOptions() instanceof SimpleNextHop) {
+            writeRoute(
+                    simpleHopRequestFactory.createIpv6SimpleHopRequest(isAdd, parentProtocolName, route,
+                            writeContext.getMappingContext()),
+                    identifier);
+        } else if (route.getNextHopOptions() instanceof NextHopList) {
+            final List<NextHop> createdHops =
+                    writeMultihopRoute(identifier, parentProtocolName, route, writeContext, isAdd);
+
+            // after all hops has been added, add mappings to preserve hop ids, or remove them
+            if (isAdd) {
+                addMappingForEachHop(routeName, writeContext, createdHops);
+            } else {
+                removeMappingForEachHop(routeName, writeContext, createdHops);
+            }
+        } else if (route.getNextHopOptions() instanceof SpecialNextHop) {
+            writeSpecialHopRoute(identifier, route, writeContext, isAdd);
+        } else {
+            throw new IllegalArgumentException("Unsupported next-hop type");
+        }
+    }
+
+    private List<NextHop> writeMultihopRoute(final InstanceIdentifier<Route> identifier,
+                                             final String parentProtocolName,
+                                             final Route route,
+                                             final WriteContext writeContext, final boolean isAdd)
+            throws WriteFailedException {
+        // list of next hops
+        final NextHopList hopList = NextHopList.class.cast(route.getNextHopOptions());
+        final MappingContext mappingContext = writeContext.getMappingContext();
+        LOG.debug("Writing hop list {} for route {}", hopList, identifier);
+
+        // order hops to preserve order by ids(even that model is not ordered)
+        final List<NextHop> orderedHops = hopList.getNextHopList().getNextHop()
+                .stream()
+                .sorted((left, right) -> (int) (left.getId() - right.getId()))
+                .collect(Collectors.toList());
+
+        for (NextHop hop : orderedHops) {
+            LOG.debug("Writing hop {} for route {}", hop, identifier);
+
+            final IpAddDelRoute request = multipathHopRequestFactory
+                    .createIpv6MultipathHopRequest(isAdd, parentProtocolName, route, hop, mappingContext);
+
+            writeRoute(request, identifier);
+        }
+
+        return orderedHops;
+    }
+
+
+    private void writeSpecialHopRoute(final @Nonnull InstanceIdentifier<Route> identifier, final @Nonnull Route route,
+                                      final @Nonnull WriteContext writeContext, final boolean isAdd)
+            throws WriteFailedException {
+        final SpecialNextHop hop = SpecialNextHop.class.cast(route.getNextHopOptions());
+        final MappingContext mappingContext = writeContext.getMappingContext();
+
+        final IpAddDelRoute request = specialNextHopRequestFactory
+                .createIpv6SpecialHopRequest(isAdd, route, mappingContext, hop.getSpecialNextHop());
+
+        writeRoute(request, identifier);
+    }
+
+    private void writeRoute(final IpAddDelRoute request, final InstanceIdentifier<Route> identifier)
+            throws WriteFailedException {
+        LOG.debug("Writing request {} for path {}", request, identifier);
+        getReplyForWrite(getFutureJVpp().ipAddDelRoute(request).toCompletableFuture(), identifier);
+    }
+
+    private void removeMappingForEachHop(final @Nonnull String routeName, final @Nonnull WriteContext writeContext,
+                                         final List<NextHop> createdHops) {
+        createdHops.forEach(nextHop -> routesHopsContext.removeChild(routeName,
+                namesFactory.uniqueRouteHopName(nextHop),
+                writeContext.getMappingContext()));
+    }
+
+    private void addMappingForEachHop(final @Nonnull String routeName, final @Nonnull WriteContext writeContext,
+                                      final List<NextHop> createdHops) {
+        createdHops.forEach(nextHop -> routesHopsContext.addChild(routeName,
+                nextHop.getId().intValue(),
+                namesFactory.uniqueRouteHopName(nextHop),
+                writeContext.getMappingContext()));
+    }
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/Ipv6WriteRoutingNodes.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/Ipv6WriteRoutingNodes.java
new file mode 100644 (file)
index 0000000..2c9bbad
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.write;
+
+import com.google.common.collect.ImmutableSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.StaticRoutes1;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.StaticRoutes1Builder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.StaticRoutes2;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv6;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv6Builder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.RouteBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.RouteKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.NextHopOptions;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.VppIpv6Route;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.VppIpv6RouteBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.NextHopListBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SimpleNextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SimpleNextHopBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SpecialNextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SpecialNextHopBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.NextHopList;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.next.hop.list.NextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.next.hop.list.NextHopBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.next.hop.list.NextHopKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+
+public interface Ipv6WriteRoutingNodes {
+
+    Ipv6WriteRoutingNodes INSTANCE = new Ipv6WriteRoutingNodes() {
+    };
+
+    Class<StaticRoutes1> CONFIG_IPV6_AUG_CLASS = StaticRoutes1.class;
+    Class<StaticRoutes2> STATE_IPV6_AUG_CLASS = StaticRoutes2.class;
+
+    static Ipv6 mapIpv6(
+            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv6 state) {
+        return new Ipv6Builder()
+                .setRoute(state.getRoute()
+                        .stream()
+                        .map(route -> new RouteBuilder()
+                                .setKey(new RouteKey(route.getKey().getId()))
+                                .setDestinationPrefix(route.getDestinationPrefix())
+                                .setDescription(route.getDescription())
+                                .setId(route.getId())
+                                .setVppIpv6Route(mapVppIpv6Route(route.getVppIpv6RouteState()))
+                                .setNextHopOptions(mapNextHopOptions(route.getNextHopOptions()))
+                                .build())
+                        .collect(Collectors.toList()))
+                .build();
+    }
+
+    static VppIpv6Route mapVppIpv6Route(
+            final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.VppIpv6RouteState state) {
+        return state == null
+                ? null
+                : new VppIpv6RouteBuilder()
+                        .setSecondaryVrf(state.getSecondaryVrf())
+                        .setClassifyTable(state.getClassifyTable())
+                        .build();
+    }
+
+    static NextHopOptions mapNextHopOptions(
+            final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.NextHopOptions state) {
+        if (state instanceof org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SimpleNextHop) {
+            return mapSimpleNextHop(
+                    org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SimpleNextHop.class
+                            .cast(state));
+        } else if (state instanceof org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.NextHopList) {
+            return mapNextHopList(
+                    org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.NextHopList.class
+                            .cast(state));
+        } else if (state instanceof org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SpecialNextHop) {
+            return mapSpecialNextHop(
+                    org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SpecialNextHop.class
+                            .cast(state));
+        } else {
+            throw new UnsupportedOperationException("Unsupported next hop type");
+        }
+    }
+
+    static SimpleNextHop mapSimpleNextHop(
+            final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SimpleNextHop hop) {
+        return new SimpleNextHopBuilder()
+                .setNextHop(hop.getNextHop())
+                .setOutgoingInterface(hop.getOutgoingInterface())
+                .build();
+    }
+
+    static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.NextHopList mapNextHopList(
+            final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.NextHopList state) {
+        return new NextHopListBuilder()
+                .setNextHopList(mapNextHopListList(state.getNextHopList()))
+                .build();
+    }
+
+    static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.NextHopList mapNextHopListList(
+            final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.NextHopList state) {
+        return new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.NextHopListBuilder()
+                .setNextHop(state.getNextHop()
+                        .stream()
+                        .map(nextHop -> new NextHopBuilder()
+                                .setId(nextHop.getId())
+                                .setOutgoingInterface(nextHop.getOutgoingInterface())
+                                .setWeight(nextHop.getWeight())
+                                .setPriority(nextHop.getPriority())
+                                .setAddress(nextHop.getAddress())
+                                .setKey(new NextHopKey(nextHop.getKey().getId()))
+                                .build())
+                        .collect(Collectors.toList()))
+                .build();
+    }
+
+    static SpecialNextHop mapSpecialNextHop(
+            final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SpecialNextHop hop) {
+        return new SpecialNextHopBuilder()
+                .setSpecialNextHop(hop.getSpecialNextHop())
+                .build();
+    }
+
+    default InstanceIdentifier<Route> ipv6RouteIdentifier(
+            final InstanceIdentifier<StaticRoutes> staticRoutesIdentifier) {
+        return staticRoutesIdentifier
+                .augmentation(StaticRoutes1.class)
+                .child(Ipv6.class)
+                .child(Route.class);
+    }
+
+    default InstanceIdentifier<Route> ipv6RouteSubtree() {
+        return InstanceIdentifier
+                .create(Route.class);
+    }
+
+    default Set<InstanceIdentifier<?>> ipv6RoutingHandledChildren(
+            final InstanceIdentifier<Route> parent) {
+        return ImmutableSet.of(parent.child(NextHopList.class),
+                parent.child(NextHopList.class).child(NextHop.class),
+                parent.child(VppIpv6Route.class));
+    }
+
+    default org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.StaticRoutes1 mapIpv6Augmentation(
+            final StaticRoutes2 state) {
+        if (state == null) {
+            return null;
+        }
+        return new StaticRoutes1Builder()
+                .setIpv6(mapIpv6(state.getIpv6()))
+                .build();
+    }
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/RoutingCustomizer.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/RoutingCustomizer.java
new file mode 100644 (file)
index 0000000..bd50ce7
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.write;
+
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.Routing;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Dummy customizer for Root node,to "handle" non-operational changes
+ */
+public class RoutingCustomizer implements WriterCustomizer<Routing> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(RoutingCustomizer.class);
+
+    @Override
+    public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Routing> instanceIdentifier,
+                                       @Nonnull final Routing routing, @Nonnull final WriteContext writeContext)
+            throws WriteFailedException {
+        LOG.debug("Writing {}", instanceIdentifier);
+    }
+
+    @Override
+    public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Routing> instanceIdentifier,
+                                        @Nonnull final Routing before, @Nonnull final Routing after,
+                                        @Nonnull final WriteContext writeContext) throws WriteFailedException {
+        LOG.debug("Updating {} to {}", instanceIdentifier, after);
+    }
+
+    @Override
+    public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Routing> instanceIdentifier,
+                                        @Nonnull final Routing routing, @Nonnull final WriteContext writeContext)
+            throws WriteFailedException {
+        LOG.debug("Removing {}", instanceIdentifier);
+    }
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/RoutingInstanceCustomizer.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/RoutingInstanceCustomizer.java
new file mode 100644 (file)
index 0000000..fa6885d
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.write;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import io.fd.hc2vpp.routing.RoutingConfiguration;
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.RoutingInstance;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.RoutingInstanceKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Only ensures that requests are written under singleton instance
+ */
+public class RoutingInstanceCustomizer implements ListWriterCustomizer<RoutingInstance, RoutingInstanceKey> {
+
+    private final RoutingConfiguration configuration;
+
+    public RoutingInstanceCustomizer(@Nonnull final RoutingConfiguration configuration) {
+        this.configuration = configuration;
+    }
+
+    @Override
+    public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<RoutingInstance> id,
+                                       @Nonnull final RoutingInstance dataAfter,
+                                       @Nonnull final WriteContext writeContext)
+            throws WriteFailedException {
+        checkSingletonInstance(dataAfter);
+    }
+
+    @Override
+    public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<RoutingInstance> id,
+                                        @Nonnull final RoutingInstance dataBefore,
+                                        @Nonnull final RoutingInstance dataAfter,
+                                        @Nonnull final WriteContext writeContext) throws WriteFailedException {
+        throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter,
+                new UnsupportedOperationException("Operation not supported"));
+    }
+
+    @Override
+    public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<RoutingInstance> id,
+                                        @Nonnull final RoutingInstance dataBefore,
+                                        @Nonnull final WriteContext writeContext)
+            throws WriteFailedException {
+        checkSingletonInstance(dataBefore);
+    }
+
+    private void checkSingletonInstance(final RoutingInstance data) {
+        final String defaultRoutingInstanceName = configuration.getDefaultRoutingInstanceName();
+        final String instanceName = data.getName();
+
+        checkArgument(defaultRoutingInstanceName.equals(instanceName),
+                "Attempt to write/delete data for different than default routing instance detected." +
+                        "Vpp allows only single instance, configured with name %s, request contains name %s",
+                defaultRoutingInstanceName, instanceName);
+    }
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/RoutingProtocolCustomizer.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/RoutingProtocolCustomizer.java
new file mode 100644 (file)
index 0000000..220f076
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.write;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.Static;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocol;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocolKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.RoutingProtocolVppAttr;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Customizer for handling of write operations for {@link RoutingProtocol}
+ */
+public class RoutingProtocolCustomizer
+        implements ListWriterCustomizer<RoutingProtocol, RoutingProtocolKey> {
+
+    private final NamingContext routingProtocolContext;
+
+    public RoutingProtocolCustomizer(@Nonnull final NamingContext routingProtocolContext) {
+        this.routingProtocolContext = routingProtocolContext;
+    }
+
+    @Override
+    public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<RoutingProtocol> instanceIdentifier,
+                                       @Nonnull final RoutingProtocol routingProtocol,
+                                       @Nonnull final WriteContext writeContext)
+            throws WriteFailedException {
+        checkIsStatic(routingProtocol);
+
+        final int tableId = extractTableId(routingProtocol);
+        final MappingContext mappingContext = writeContext.getMappingContext();
+        final String newProtocolName = routingProtocol.getName();
+
+        // enclosed in synchronized block to prevent change of state after containsName/before addName
+        synchronized (routingProtocolContext) {
+            if (!routingProtocolContext.containsName(tableId, mappingContext)) {
+                // if not present in mapping,create assignment to table id. This works only with auto-create flag enabled
+                // while using ip_add_del_table
+                routingProtocolContext.addName(tableId, newProtocolName, mappingContext);
+            } else {
+                throw new IllegalStateException(String.format(
+                        "An attempt to assign protocol %s to table id %s. Table id already assigned to protocol %s",
+                        newProtocolName, tableId, routingProtocolContext.getName(tableId, mappingContext)));
+            }
+        }
+    }
+
+    @Override
+    public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<RoutingProtocol> instanceIdentifier,
+                                        @Nonnull final RoutingProtocol routingProtocolBefore,
+                                        @Nonnull final RoutingProtocol routingProtocolAfter,
+                                        @Nonnull final WriteContext writeContext) throws WriteFailedException {
+        throw new WriteFailedException.UpdateFailedException(instanceIdentifier, routingProtocolBefore,
+                routingProtocolAfter, new UnsupportedOperationException("Operation not supported"));
+    }
+
+    @Override
+    public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<RoutingProtocol> instanceIdentifier,
+                                        @Nonnull final RoutingProtocol routingProtocol,
+                                        @Nonnull final WriteContext writeContext)
+            throws WriteFailedException {
+        routingProtocolContext.removeName(routingProtocol.getName(), writeContext.getMappingContext());
+    }
+
+    /**
+     * Checks whether routing protocol is static(we support only static ones for now)
+     */
+    private void checkIsStatic(final RoutingProtocol routingProtocol) {
+        checkArgument(routingProtocol.getType() == Static.class, "Only static routes are allowed");
+    }
+
+    private int extractTableId(final RoutingProtocol protocol) {
+        final RoutingProtocolVppAttr vppAttr = protocol.getAugmentation(RoutingProtocolVppAttr.class);
+
+        checkState(vppAttr != null && vppAttr.getVppProtocolAttributes() != null,
+                "Vpp routing protocol attributes not defined");
+
+        return vppAttr.getVppProtocolAttributes().getPrimaryVrf().getValue().intValue();
+    }
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/RoutingWriterFactory.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/RoutingWriterFactory.java
new file mode 100644 (file)
index 0000000..02fa7d1
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.write;
+
+import static io.fd.hc2vpp.routing.RoutingConfiguration.ROUTE_CONTEXT;
+import static io.fd.hc2vpp.routing.RoutingConfiguration.ROUTE_HOP_CONTEXT;
+import static io.fd.hc2vpp.routing.RoutingConfiguration.ROUTING_PROTOCOL_CONTEXT;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import io.fd.hc2vpp.common.translate.util.MultiNamingContext;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.RoutingConfiguration;
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.translate.impl.write.GenericWriter;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.Routing;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.RoutingInstance;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.RoutingProtocols;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocol;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.RoutingProtocolVppAttr;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.routing.routing.instance.routing.protocols.routing.protocol.VppProtocolAttributes;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Factory producing writers for routing plugin's data.
+ */
+public final class RoutingWriterFactory implements WriterFactory, Ipv4WriteRoutingNodes, Ipv6WriteRoutingNodes {
+
+    private static final InstanceIdentifier<Routing> ROOT_CONTAINER_ID = InstanceIdentifier.create(Routing.class);
+
+    @Inject
+    private FutureJVppCore vppApi;
+
+    @Inject
+    private RoutingConfiguration configuration;
+
+    @Inject
+    @Named("interface-context")
+    private NamingContext interfaceContext;
+
+    @Inject
+    @Named(ROUTING_PROTOCOL_CONTEXT)
+    private NamingContext routingProtocolContext;
+
+    @Inject
+    @Named(ROUTE_CONTEXT)
+    private NamingContext routeContext;
+
+    @Inject
+    @Named("classify-table-context")
+    private VppClassifierContextManager vppClassifierContextManager;
+
+    @Inject
+    @Named(ROUTE_HOP_CONTEXT)
+    private MultiNamingContext routHopContext;
+
+    @Override
+    public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) {
+
+        registry.subtreeAdd(rootNodeHandledChildren(ROOT_CONTAINER_ID),
+                new GenericWriter<>(ROOT_CONTAINER_ID, new RoutingCustomizer()));
+
+        registry.add(new GenericWriter<>(routingInstanceIdentifier(), new RoutingInstanceCustomizer(configuration)));
+
+        registry.subtreeAdd(routingProtocolHandledChildren(),new GenericWriter<>(routingProtocolIdentifier(),
+                new RoutingProtocolCustomizer(routingProtocolContext)));
+
+        final InstanceIdentifier<StaticRoutes> staticRoutesInstanceIdentifier = staticRoutesIdentifier();
+        final InstanceIdentifier<Route> ipv4RouteIdentifier = ipv4RouteIdentifier(staticRoutesInstanceIdentifier);
+        final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route>
+                ipv6RouteIdentifier = ipv6RouteIdentifier(staticRoutesInstanceIdentifier);
+        registry.subtreeAdd(ipv4RoutingHandledChildren(ipv4RouteSubtree()), new GenericWriter<>(ipv4RouteIdentifier,
+                new Ipv4RouteCustomizer(vppApi, interfaceContext, routeContext, routingProtocolContext, routHopContext,
+                        vppClassifierContextManager)));
+        registry.subtreeAdd(ipv6RoutingHandledChildren(ipv6RouteSubtree()), new GenericWriter<>(ipv6RouteIdentifier,
+                new Ipv6RouteCustomizer(vppApi, interfaceContext, routeContext, routingProtocolContext, routHopContext,
+                        vppClassifierContextManager)));
+    }
+
+    private static ImmutableSet<InstanceIdentifier<?>> routingProtocolHandledChildren() {
+        return ImmutableSet
+                .of(InstanceIdentifier.create(RoutingProtocol.class).augmentation(RoutingProtocolVppAttr.class).child(VppProtocolAttributes.class));
+    }
+
+    private static InstanceIdentifier<RoutingInstance> routingInstanceIdentifier() {
+        return ROOT_CONTAINER_ID.child(RoutingInstance.class);
+    }
+
+    private static InstanceIdentifier<RoutingProtocol> routingProtocolIdentifier() {
+        return routingInstanceIdentifier().child(RoutingProtocols.class).child(RoutingProtocol.class);
+    }
+
+    private static InstanceIdentifier<StaticRoutes> staticRoutesIdentifier() {
+        return routingProtocolIdentifier().child(StaticRoutes.class);
+    }
+
+    private static Set<InstanceIdentifier<?>> rootNodeHandledChildren(final InstanceIdentifier<Routing> parent) {
+        return ImmutableSet.of(parent.child(RoutingInstance.class).child(RoutingProtocols.class));
+    }
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/MultipathHopRequestFactory.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/MultipathHopRequestFactory.java
new file mode 100644 (file)
index 0000000..4599c8b
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.write.factory;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.write.factory.base.BasicHopRequestFactory;
+import io.fd.hc2vpp.routing.write.trait.RouteRequestProducer;
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.vpp.jvpp.core.dto.IpAddDelRoute;
+import javax.annotation.Nonnull;
+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.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.VppIpv4Route;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.VppIpv6Route;
+
+
+/**
+ * Factory for creating requests to create route with multiple hops
+ */
+public class MultipathHopRequestFactory extends BasicHopRequestFactory implements RouteRequestProducer {
+
+    private MultipathHopRequestFactory(final VppClassifierContextManager classifierContextManager,
+                                       final NamingContext interfaceContext,
+                                       final NamingContext routingProtocolContext) {
+        super(classifierContextManager, interfaceContext, routingProtocolContext);
+    }
+
+    public static MultipathHopRequestFactory forContexts(
+            @Nonnull final VppClassifierContextManager classifierContextManager,
+            @Nonnull final NamingContext interfaceContext,
+            @Nonnull final NamingContext routingProtocolContext) {
+        return new MultipathHopRequestFactory(classifierContextManager, interfaceContext, routingProtocolContext);
+    }
+
+    public IpAddDelRoute createIpv4MultipathHopRequest(final boolean add,
+                                                       @Nonnull final String parentProtocolName,
+                                                       @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route route,
+                                                       @Nonnull final NextHop hop,
+                                                       @Nonnull final MappingContext mappingContext) {
+
+        final VppIpv4Route routingAttributes = checkNotNull(route.getVppIpv4Route(), "VppIpv4Route not defined");
+
+        final int nextHopInterfaceIndex =
+                getInterfaceNamingContext().getIndex(hop.getOutgoingInterface(), mappingContext);
+
+        if (classifyTablePresent(routingAttributes.getClassifyTable(), getVppClassifierContextManager(),
+                mappingContext)) {
+            return getMultipathHopRequest(add,
+                    route.getDestinationPrefix(),
+                    nextHopInterfaceIndex,
+                    hop.getAddress(),
+                    toByte(hop.getWeight()),
+                    getRoutingProtocolContext().getIndex(parentProtocolName, mappingContext),
+                    optionalVni(routingAttributes.getSecondaryVrf()),
+                    classifyTableIndex(routingAttributes.getClassifyTable(), getVppClassifierContextManager(),
+                            mappingContext),
+                    true);
+        } else {
+            return getMultipathHopRequest(add,
+                    route.getDestinationPrefix(),
+                    nextHopInterfaceIndex,
+                    hop.getAddress(),
+                    toByte(hop.getWeight()),
+                    getRoutingProtocolContext().getIndex(parentProtocolName, mappingContext),
+                    optionalVni(routingAttributes.getSecondaryVrf()),
+                    0,
+                    false);
+        }
+    }
+
+    public IpAddDelRoute createIpv6MultipathHopRequest(final boolean add,
+                                                       @Nonnull final String parentProtocolName,
+                                                       @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route route,
+                                                       @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.next.hop.list.NextHop hop,
+                                                       @Nonnull final MappingContext mappingContext) {
+        final VppIpv6Route routingAttributes = checkNotNull(route.getVppIpv6Route(), "VppIpv6Route not defined");
+
+        final int nextHopInterfaceIndex =
+                getInterfaceNamingContext().getIndex(hop.getOutgoingInterface(), mappingContext);
+
+        if (classifyTablePresent(routingAttributes.getClassifyTable(), getVppClassifierContextManager(),
+                mappingContext)) {
+            return getMultipathHopRequest(add,
+                    route.getDestinationPrefix(),
+                    nextHopInterfaceIndex,
+                    hop.getAddress(),
+                    toByte(hop.getWeight()),
+                    getRoutingProtocolContext().getIndex(parentProtocolName, mappingContext),
+                    optionalVni(routingAttributes.getSecondaryVrf()),
+                    classifyTableIndex(routingAttributes.getClassifyTable(), getVppClassifierContextManager(),
+                            mappingContext),
+                    true);
+        } else {
+            return getMultipathHopRequest(add,
+                    route.getDestinationPrefix(),
+                    nextHopInterfaceIndex,
+                    hop.getAddress(),
+                    toByte(hop.getWeight()),
+                    getRoutingProtocolContext().getIndex(parentProtocolName, mappingContext),
+                    optionalVni(routingAttributes.getSecondaryVrf()),
+                    0,
+                    false);
+        }
+    }
+
+
+    private IpAddDelRoute getMultipathHopRequest(final boolean isAdd, @Nonnull final Ipv6Prefix destinationAddress,
+                                                 final int nextHopInterfaceIndex,
+                                                 @Nonnull final Ipv6Address nextHopAddress,
+                                                 final byte nextHopWeight,
+                                                 final int primaryVrf, final int secondaryVrf,
+                                                 final int classifyTableIndex, final boolean classifyIndexSet) {
+        return flaglessAddDelRouteRequest(booleanToByte(isAdd), nextHopInterfaceIndex,
+                ipv6AddressNoZoneToArray(nextHopAddress.getValue()), nextHopWeight, toByte(1),
+                ipv6AddressPrefixToArray(destinationAddress), extractPrefix(destinationAddress.getValue()), toByte(1),
+                primaryVrf, secondaryVrf, classifyTableIndex,
+                booleanToByte(classifyIndexSet));
+    }
+
+    private IpAddDelRoute getMultipathHopRequest(final boolean isAdd, @Nonnull final Ipv4Prefix destinationAddress,
+                                                 final int nextHopInterfaceIndex,
+                                                 @Nonnull final Ipv4Address nextHopAddress,
+                                                 final byte nextHopWeight,
+                                                 final int primaryVrf, final int secondaryVrf,
+                                                 final int classifyTableIndex, final boolean classifyIndexSet) {
+        return flaglessAddDelRouteRequest(booleanToByte(isAdd), nextHopInterfaceIndex,
+                ipv4AddressNoZoneToArray(nextHopAddress.getValue()), nextHopWeight, toByte(0),
+                ipv4AddressPrefixToArray(destinationAddress), extractPrefix(destinationAddress.getValue()), toByte(1),
+                primaryVrf, secondaryVrf, classifyTableIndex,
+                booleanToByte(classifyIndexSet));
+    }
+
+
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/SimpleHopRequestFactory.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/SimpleHopRequestFactory.java
new file mode 100644 (file)
index 0000000..68a5f3d
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.write.factory;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.write.factory.base.BasicHopRequestFactory;
+import io.fd.hc2vpp.routing.write.trait.RouteRequestProducer;
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.vpp.jvpp.core.dto.IpAddDelRoute;
+import javax.annotation.Nonnull;
+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.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.VppIpv4Route;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SimpleNextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.VppIpv6Route;
+
+
+/**
+ * Factory for creating requests to create route with hop simple hop
+ */
+public class SimpleHopRequestFactory extends BasicHopRequestFactory implements RouteRequestProducer {
+
+    private SimpleHopRequestFactory(final VppClassifierContextManager classifierContextManager,
+                                    final NamingContext interfaceContext,
+                                    final NamingContext routingProtocolContext) {
+        super(classifierContextManager, interfaceContext, routingProtocolContext);
+    }
+
+    public static SimpleHopRequestFactory forContexts(
+            @Nonnull final VppClassifierContextManager classifierContextManager,
+            @Nonnull final NamingContext interfaceContext,
+            @Nonnull final NamingContext routingProtocolContext) {
+        return new SimpleHopRequestFactory(classifierContextManager, interfaceContext, routingProtocolContext);
+    }
+
+    public IpAddDelRoute createIpv4SimpleHopRequest(final boolean add,
+                                                    @Nonnull final String parentProtocolName,
+                                                    @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route route,
+                                                    @Nonnull final MappingContext mappingContext) {
+
+        final SimpleNextHop hop = SimpleNextHop.class.cast(route.getNextHopOptions());
+        final VppIpv4Route routingAttributes = checkNotNull(route.getVppIpv4Route(), "VppIpv4Route not defined");
+        final int nextHopInterfaceIndex =
+                getInterfaceNamingContext().getIndex(hop.getOutgoingInterface(), mappingContext);
+
+        if (classifyTablePresent(routingAttributes.getClassifyTable(), getVppClassifierContextManager(),
+                mappingContext)) {
+            return getSimpleHopRequest(add,
+                    route.getDestinationPrefix(),
+                    nextHopInterfaceIndex,
+                    hop.getNextHop(),
+                    getRoutingProtocolContext().getIndex(parentProtocolName, mappingContext),
+                    optionalVni(routingAttributes.getSecondaryVrf()),
+                    classifyTableIndex(routingAttributes.getClassifyTable(), getVppClassifierContextManager(),
+                            mappingContext),
+                    true);
+        } else {
+            return getSimpleHopRequest(add,
+                    route.getDestinationPrefix(),
+                    nextHopInterfaceIndex,
+                    hop.getNextHop(),
+                    getRoutingProtocolContext().getIndex(parentProtocolName, mappingContext),
+                    optionalVni(routingAttributes.getSecondaryVrf()),
+                    0,
+                    false);
+        }
+    }
+
+    public IpAddDelRoute createIpv6SimpleHopRequest(final boolean add,
+                                                    @Nonnull final String parentProtocolName,
+                                                    @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route route,
+                                                    @Nonnull final MappingContext mappingContext) {
+        final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SimpleNextHop
+                hop =
+                (org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SimpleNextHop) route
+                        .getNextHopOptions();
+        final VppIpv6Route routingAttributes = checkNotNull(route.getVppIpv6Route(), "VppIpv6Route not defined");
+        final int nextHopInterfaceIndex =
+                getInterfaceNamingContext().getIndex(hop.getOutgoingInterface(), mappingContext);
+
+        if (classifyTablePresent(routingAttributes.getClassifyTable(), getVppClassifierContextManager(),
+                mappingContext)) {
+            return getSimpleHopRequest(add,
+                    route.getDestinationPrefix(),
+                    nextHopInterfaceIndex,
+                    hop.getNextHop(),
+                    getRoutingProtocolContext().getIndex(parentProtocolName, mappingContext),
+                    optionalVni(routingAttributes.getSecondaryVrf()),
+                    classifyTableIndex(routingAttributes.getClassifyTable(), getVppClassifierContextManager(),
+                            mappingContext),
+                    true);
+        } else {
+            return getSimpleHopRequest(add,
+                    route.getDestinationPrefix(),
+                    nextHopInterfaceIndex,
+                    hop.getNextHop(),
+                    getRoutingProtocolContext().getIndex(parentProtocolName, mappingContext),
+                    optionalVni(routingAttributes.getSecondaryVrf()),
+                    0,
+                    false);
+        }
+    }
+
+
+    private IpAddDelRoute getSimpleHopRequest(final boolean isAdd, @Nonnull final Ipv6Prefix destinationAddress,
+                                              final int nextHopInterfaceIndex,
+                                              @Nonnull final Ipv6Address nextHopAddress,
+                                              final int primaryVrf, final int secondaryVrf,
+                                              final int classifyTableIndex, final boolean classifyIndexSet) {
+        return flaglessAddDelRouteRequest(booleanToByte(isAdd), nextHopInterfaceIndex,
+                ipv6AddressNoZoneToArray(nextHopAddress.getValue()), DEFAULT_HOP_WEIGHT, BYTE_TRUE,
+                ipv6AddressPrefixToArray(destinationAddress), extractPrefix(destinationAddress.getValue()), BYTE_FALSE,
+                primaryVrf, secondaryVrf, classifyTableIndex, booleanToByte(classifyIndexSet));
+    }
+
+    private IpAddDelRoute getSimpleHopRequest(final boolean isAdd, @Nonnull final Ipv4Prefix destinationAddress,
+                                              final int nextHopInterfaceIndex,
+                                              @Nonnull final Ipv4Address nextHopAddress,
+                                              final int primaryVrf, final int secondaryVrf,
+                                              final int classifyTableIndex, final boolean classifyIndexSet) {
+        return flaglessAddDelRouteRequest(booleanToByte(isAdd), nextHopInterfaceIndex,
+                ipv4AddressNoZoneToArray(nextHopAddress.getValue()), DEFAULT_HOP_WEIGHT, BYTE_FALSE,
+                ipv4AddressPrefixToArray(destinationAddress), extractPrefix(destinationAddress.getValue()), BYTE_FALSE,
+                primaryVrf, secondaryVrf, classifyTableIndex, booleanToByte(classifyIndexSet));
+    }
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/SpecialNextHopRequestFactory.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/SpecialNextHopRequestFactory.java
new file mode 100644 (file)
index 0000000..2a5ab98
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.write.factory;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.hc2vpp.routing.write.factory.base.ClassifierContextHolder;
+import io.fd.hc2vpp.routing.write.trait.RouteRequestProducer;
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.vpp.jvpp.core.dto.IpAddDelRoute;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.SpecialNextHopGrouping;
+
+public class SpecialNextHopRequestFactory extends ClassifierContextHolder
+        implements RouteRequestProducer {
+
+    private SpecialNextHopRequestFactory(final VppClassifierContextManager classifierContextManager) {
+        super(classifierContextManager);
+    }
+
+    public static SpecialNextHopRequestFactory forClassifierContext(
+            @Nonnull final VppClassifierContextManager classifierContextManager) {
+        return new SpecialNextHopRequestFactory(classifierContextManager);
+    }
+
+    public IpAddDelRoute createIpv4SpecialHopRequest(final boolean add,
+                                                     @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route route,
+                                                     @Nonnull final MappingContext mappingContext,
+                                                     @Nonnull final SpecialNextHopGrouping.SpecialNextHop flagsVariant) {
+        checkNotNull(route, "Route cannot be null");
+        checkNotNull(mappingContext, "Mapping Context cannot be null");
+        checkNotNull(flagsVariant, "Flags variant cannot be null");
+
+        return resolveFlags(getSpecialHopRequest(add, route.getDestinationPrefix()), flagsVariant);
+    }
+
+    public IpAddDelRoute createIpv6SpecialHopRequest(final boolean add,
+                                                     @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route route,
+                                                     @Nonnull final MappingContext mappingContext,
+                                                     @Nonnull final SpecialNextHopGrouping.SpecialNextHop flagsVariant) {
+
+        checkNotNull(route, "Route cannot be null");
+        checkNotNull(mappingContext, "Mapping Context cannot be null");
+        checkNotNull(flagsVariant, "Flags variant cannot be null");
+
+        return resolveFlags(getSpecialHopRequest(add, route.getDestinationPrefix()), flagsVariant);
+    }
+
+    private IpAddDelRoute getSpecialHopRequest(final boolean isAdd, @Nonnull final Ipv6Prefix destinationAddress) {
+
+        return flaglessAddDelRouteRequest(booleanToByte(isAdd), 0, null, DEFAULT_HOP_WEIGHT, BYTE_TRUE,
+                ipv6AddressPrefixToArray(destinationAddress), extractPrefix(destinationAddress.getValue()), BYTE_FALSE,
+                DEFAULT_VNI, DEFAULT_VNI, DEFAULT_CLASSIFY_TABLE_INDEX, BYTE_FALSE);
+    }
+
+    private IpAddDelRoute getSpecialHopRequest(final boolean isAdd, @Nonnull final Ipv4Prefix destinationAddress) {
+        return flaglessAddDelRouteRequest(booleanToByte(isAdd), 0, null, DEFAULT_HOP_WEIGHT, BYTE_FALSE,
+                ipv4AddressPrefixToArray(destinationAddress), extractPrefix(destinationAddress.getValue()), BYTE_FALSE,
+                DEFAULT_VNI, DEFAULT_VNI, DEFAULT_CLASSIFY_TABLE_INDEX, BYTE_FALSE);
+    }
+
+    private IpAddDelRoute resolveFlags(IpAddDelRoute request,
+                                       final SpecialNextHopGrouping.SpecialNextHop flagsVariant) {
+        switch (flagsVariant) {
+            case Blackhole:
+                return resolveAsBlackholeVariant(request);
+            case Unreachable:
+                return resolveAsUnreachableVariant(request);
+            case Prohibit:
+                return resolveAsProhibitedVariant(request);
+            case Receive:
+                return resolveAsReceiveVariant(request);
+            default:
+                throw new IllegalArgumentException("Unsupported type");
+        }
+    }
+
+    private IpAddDelRoute resolveAsBlackholeVariant(IpAddDelRoute request) {
+        return bindFlags(request, true, false, false, false);
+    }
+
+    private IpAddDelRoute resolveAsReceiveVariant(IpAddDelRoute request) {
+        return bindFlags(request, false, true, false, false);
+    }
+
+    private IpAddDelRoute resolveAsUnreachableVariant(IpAddDelRoute request) {
+        return bindFlags(request, false, false, true, false);
+    }
+
+    private IpAddDelRoute resolveAsProhibitedVariant(IpAddDelRoute request) {
+        return bindFlags(request, false, false, false, true);
+    }
+
+    private IpAddDelRoute bindFlags(IpAddDelRoute request, final boolean isDrop, final boolean isReceive,
+                                    final boolean isUnreachable, final boolean isProhibited) {
+        request.isDrop = booleanToByte(isDrop);
+        request.isLocal = booleanToByte(isReceive);
+        request.isUnreach = booleanToByte(isUnreachable);
+        request.isProhibit = booleanToByte(isProhibited);
+
+        return request;
+    }
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/base/BasicHopRequestFactory.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/base/BasicHopRequestFactory.java
new file mode 100644 (file)
index 0000000..abaf0fa
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.write.factory.base;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import javax.annotation.Nonnull;
+
+/**
+ * Extension to {@code ClassifierContextHolder} to hold also {@code NamingContext}
+ */
+public abstract class BasicHopRequestFactory extends ClassifierContextHolder {
+
+    private final NamingContext interfaceNamingContext;
+    private final NamingContext routingProtocolContext;
+
+    protected BasicHopRequestFactory(
+            @Nonnull final VppClassifierContextManager classifierContextManager,
+            @Nonnull final NamingContext interfaceContext,
+            @Nonnull final NamingContext routingProtocolContext) {
+        super(classifierContextManager);
+        this.interfaceNamingContext = checkNotNull(interfaceContext, "Interface context cannot be null");
+        this.routingProtocolContext = checkNotNull(routingProtocolContext, "Routing protocol context cannot be null");
+    }
+
+    protected NamingContext getInterfaceNamingContext() {
+        return interfaceNamingContext;
+    }
+
+    protected NamingContext getRoutingProtocolContext() {
+        return routingProtocolContext;
+    }
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/base/ClassifierContextHolder.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/factory/base/ClassifierContextHolder.java
new file mode 100644 (file)
index 0000000..0b11a9b
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.write.factory.base;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import javax.annotation.Nonnull;
+
+/**
+ * Holds reference for
+ */
+public abstract class ClassifierContextHolder {
+
+    private final VppClassifierContextManager classifierContextManager;
+
+    protected ClassifierContextHolder(@Nonnull final VppClassifierContextManager classifierContextManager) {
+        this.classifierContextManager = checkNotNull(classifierContextManager, "Classifier context cannot be null");
+    }
+
+    protected VppClassifierContextManager getVppClassifierContextManager() {
+        return this.classifierContextManager;
+    }
+}
diff --git a/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/trait/RouteRequestProducer.java b/routing/routing-impl/src/main/java/io/fd/hc2vpp/routing/write/trait/RouteRequestProducer.java
new file mode 100644 (file)
index 0000000..63ee5a1
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.write.trait;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.Objects.isNull;
+import static org.apache.commons.lang3.StringUtils.isNotEmpty;
+
+import com.google.common.collect.ImmutableSet.Builder;
+import io.fd.hc2vpp.common.translate.util.AddressTranslator;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.vpp.jvpp.core.dto.IpAddDelRoute;
+import java.util.Set;
+import java.util.regex.Pattern;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.VniReference;
+
+
+/**
+ * Common logic for writing of routes
+ */
+public interface RouteRequestProducer extends ByteDataTranslator, AddressTranslator, JvppReplyConsumer {
+
+    Set<String> allowedPrefixPatterns = new Builder<String>().addAll(Ipv4Prefix.PATTERN_CONSTANTS)
+            .addAll(Ipv6Prefix.PATTERN_CONSTANTS).build();
+
+    byte DEFAULT_VNI = 0;
+    byte DEFAULT_CLASSIFY_TABLE_INDEX = 0;
+    byte DEFAULT_HOP_WEIGHT = 0;
+
+    default int mandatoryVni(final VniReference vniReference) {
+        return checkNotNull(vniReference, "Vni reference cannot be null").getValue().intValue();
+    }
+
+    default int optionalVni(final VniReference vniReference) {
+        return isNull(vniReference)
+                ? DEFAULT_VNI
+                : vniReference.getValue().intValue();
+    }
+
+    default byte extractPrefix(final String value) {
+        checkArgument(
+                allowedPrefixPatterns.stream().anyMatch(pattern -> Pattern.compile(pattern).matcher(value).matches()),
+                "%s is not a valid Ip-prefix value");
+        return Byte.valueOf(value.substring(value.indexOf("/") + 1));
+    }
+
+    default boolean classifyTablePresent(final String classifyTableName,
+                                         final VppClassifierContextManager classifierContextManager,
+                                         final MappingContext mappingContext) {
+        return isNotEmpty(classifyTableName) &&
+                classifierContextManager.containsTable(classifyTableName, mappingContext);
+    }
+
+    default int classifyTableIndex(final String classifyTableName,
+                                   final VppClassifierContextManager classifierContextManager,
+                                   final MappingContext mappingContext) {
+        return classifierContextManager.getTableIndex(classifyTableName, mappingContext);
+    }
+
+    /**
+     * Creates fully bind {@code IpAddDelRoute} request
+     *
+     * @param add                            1 if add,delete otherwise
+     * @param nextHopInterfaceIndex          interface for <b>nextHopAddress</b>
+     * @param nextHopAddress                 address of hop
+     * @param nextHopWeight                  if <b>mutlipath</b>, then set to "order" hops
+     * @param ipv6                           determine if writing ipv4/ipv6 route
+     * @param destinationAddress             address of destination for hop
+     * @param destinationAddressPrefixLength prefix length of <b>destinationAddress</b>
+     * @param multipath                      You can only write one next-hop at a time. set this to true when you are
+     *                                       adding paths/next-hops to an existing route. It can be true when adding a
+     *                                       new route.
+     * @param primaryVrf                     primary vrf for configured route
+     * @param secondaryVrf                   lookup vrf for route
+     * @param classifyTableIndex             index of classify table
+     * @param classifyTableSet               set if classify table index was set
+     */
+    default IpAddDelRoute flaglessAddDelRouteRequest(final byte add,
+                                                     final int nextHopInterfaceIndex,
+                                                     final byte[] nextHopAddress,
+                                                     final byte nextHopWeight,
+                                                     final byte ipv6,
+                                                     final byte[] destinationAddress,
+                                                     final byte destinationAddressPrefixLength,
+                                                     final byte multipath,
+                                                     final int primaryVrf,
+                                                     final int secondaryVrf,
+                                                     final int classifyTableIndex,
+                                                     final byte classifyTableSet) {
+
+        final IpAddDelRoute request = new IpAddDelRoute();
+        request.isAdd = add;
+        request.nextHopSwIfIndex = nextHopInterfaceIndex;
+        request.dstAddress = destinationAddress;
+        request.dstAddressLength = destinationAddressPrefixLength;
+        request.isIpv6 = ipv6;
+        request.isMultipath = multipath;
+        request.nextHopAddress = nextHopAddress;
+
+        // Model contains also priority but VPP does not support the concept of priority next-hops
+        request.nextHopWeight = nextHopWeight;
+
+        // vrf_id - fib table /vrf associated with the route Not mentioned in model
+        request.tableId = primaryVrf;
+
+        // create vrf if needed needs to be turned on all the time,due to how we map table ids on routing protocols
+        request.createVrfIfNeeded = 1;
+
+        // nextHopTableId - this is used when you want to have a second lookup done in another table.
+        request.nextHopTableId = secondaryVrf;
+
+        // classify_table_index
+        request.classifyTableIndex = classifyTableIndex;
+        request.isClassify = classifyTableSet;
+
+        return request;
+    }
+}
diff --git a/routing/routing-impl/src/main/resources/honeycomb-minimal-resources/config/routing.json b/routing/routing-impl/src/main/resources/honeycomb-minimal-resources/config/routing.json
new file mode 100644 (file)
index 0000000..95f8541
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "default-routing-instance-name": "vpp-routing-instance",
+  "learned-route-name-prefix": "learned-route"
+}
\ No newline at end of file
diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/Ipv4RouteData.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/Ipv4RouteData.java
new file mode 100644 (file)
index 0000000..71072ba
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing;
+
+
+public class Ipv4RouteData {
+    public static final byte[] FIRST_ADDRESS_AS_ARRAY = {-64, -88, 2, 1};
+    public static final byte[] SECOND_ADDRESS_AS_ARRAY = {-64, -88, 2, 2};
+}
diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/Ipv4RouteNamesFactoryTest.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/Ipv4RouteNamesFactoryTest.java
new file mode 100644 (file)
index 0000000..1fc8152
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing;
+
+import static org.junit.Assert.assertEquals;
+
+import io.fd.hc2vpp.common.test.util.NamingContextHelper;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper;
+import io.fd.hc2vpp.routing.helpers.SchemaContextTestHelper;
+import io.fd.hc2vpp.routing.naming.Ipv4RouteNamesFactory;
+import io.fd.honeycomb.test.tools.HoneycombTestRunner;
+import io.fd.honeycomb.test.tools.annotations.InjectTestData;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.vpp.jvpp.core.dto.IpFibDetails;
+import io.fd.vpp.jvpp.core.types.FibPath;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+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.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHopBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes;
+
+@RunWith(HoneycombTestRunner.class)
+public class Ipv4RouteNamesFactoryTest
+        implements RoutingRequestTestHelper, SchemaContextTestHelper, NamingContextHelper {
+
+    @Mock
+    private MappingContext mappingContext;
+
+    private NamingContext interfaceContext;
+    private NamingContext routingProtocolContext;
+    private IpFibDetails vppRoute;
+    private FibPath vppPath;
+    private Ipv4RouteNamesFactory factory;
+
+    @Before
+    public void init() {
+        MockitoAnnotations.initMocks(this);
+        interfaceContext = new NamingContext("interface-", "interface-context");
+        routingProtocolContext = new NamingContext("routing-protocol-", "routing-protocol-context");
+        vppRoute = new IpFibDetails();
+        vppRoute.address = Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY;
+        vppRoute.addressLength = 24;
+        vppRoute.tableId = 1;
+
+        vppPath = new FibPath();
+        vppPath.nextHop = Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY;
+        vppPath.swIfIndex = 2;
+        vppPath.weight = 3;
+
+        factory = new Ipv4RouteNamesFactory(interfaceContext, routingProtocolContext);
+        defineMapping(mappingContext, "iface", 2, "interface-context");
+        defineMapping(mappingContext, ROUTE_PROTOCOL_NAME, 1, "routing-protocol-context");
+    }
+
+    @Test
+    public void testUniqueRouteName(
+            @InjectTestData(resourcePath = "/ipv4/simpleHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH)
+                    StaticRoutes data) {
+        assertEquals("tst-protocol_19216821_24",
+                factory.uniqueRouteName(ROUTE_PROTOCOL_NAME, getIpv4RouteWithId(data, 1L)));
+        assertEquals("tst-protocol_19216821_24", factory.uniqueRouteName(vppRoute, mappingContext));
+    }
+
+    @Test
+    public void testUniqueRouteHopName() {
+        assertEquals("iface_19216821_3", factory.uniqueRouteHopName(new NextHopBuilder()
+                .setAddress(new Ipv4Address("192.168.2.1"))
+                .setWeight((short) 3)
+                .setOutgoingInterface("iface")
+                .build()));
+        assertEquals("iface_19216821_3", factory.uniqueRouteHopName(vppPath, mappingContext));
+    }
+}
diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/Ipv6RouteData.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/Ipv6RouteData.java
new file mode 100644 (file)
index 0000000..8082528
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.RouteBuilder;
+
+public class Ipv6RouteData {
+
+    public static final Ipv6Prefix
+            FIRST_ADDRESS_AS_V6_PREFIX = new Ipv6Prefix("2001:0db8:0a0b:12f0:0000:0000:0000:0001/64");
+
+    public static final byte[] FIRST_ADDRESS_AS_ARRAY = {32, 1, 13, -72, 10, 11, 18, -16, 0, 0, 0, 0, 0, 0, 0, 1};
+
+    public static final Ipv6Address
+            SECOND_ADDRESS_AS_ADDRESS = new Ipv6Address("2001:0db8:0a0b:12f0:0000:0000:0000:0002");
+
+    public static final byte[] SECOND_ADDRESS_AS_ARRAY = {32, 1, 13, -72, 10, 11, 18, -16, 0, 0, 0, 0, 0, 0, 0, 2};
+
+
+    public static final Route IPV6_ROUTE_WITH_CLASSIFIER_BLACKHOLE_HOP = new RouteBuilder()
+            .setDestinationPrefix(FIRST_ADDRESS_AS_V6_PREFIX)
+            /*.setNextHopOptions(new SpecialNextHopBuilder()
+                    .setSpecialNextHop(SpecialNextHopGrouping.SpecialNextHop.Blackhole)
+                    /*.addAugmentation(SpecialNextHop2.class, new SpecialNextHop2Builder()
+                            .setPrimaryVrf(new VniReference(2L))
+                            .setAutoCreateVrf(true)
+                            .setClassifyTable(CLASSIFY_TABLE_NAME)
+                            .build())
+                    .build())*/
+            .build();
+
+    public static final Route IPV6_ROUTE_WITHOUT_CLASSIFIER_BLACKHOLE_HOP = new RouteBuilder()
+            .setDestinationPrefix(FIRST_ADDRESS_AS_V6_PREFIX)
+            /*.setNextHopOptions(new SpecialNextHopBuilder()
+                    .setSpecialNextHop(SpecialNextHopGrouping.SpecialNextHop.Blackhole)
+                   /* .addAugmentation(SpecialNextHop2.class, new SpecialNextHop2Builder()
+                            .setPrimaryVrf(new VniReference(2L))
+                            .setAutoCreateVrf(true)
+                            .build())
+                    .build())*/
+            .build();
+
+    public static final Route IPV6_ROUTE_WITH_CLASSIFIER_RECEIVE_HOP = new RouteBuilder()
+            .setDestinationPrefix(FIRST_ADDRESS_AS_V6_PREFIX)
+            /*.setNextHopOptions(new SpecialNextHopBuilder()
+                    .setSpecialNextHop(SpecialNextHopGrouping.SpecialNextHop.Blackhole)
+                    /*.addAugmentation(SpecialNextHop2.class, new SpecialNextHop2Builder()
+                            .setPrimaryVrf(new VniReference(2L))
+                            .setAutoCreateVrf(true)
+                            .setClassifyTable(CLASSIFY_TABLE_NAME)
+                            .build())
+                    .build())*/
+            .build();
+
+    public static final Route IPV6_ROUTE_WITHOUT_CLASSIFIER_RECEIVE_HOP = new RouteBuilder()
+            .setDestinationPrefix(FIRST_ADDRESS_AS_V6_PREFIX)
+            /*.setNextHopOptions(new SpecialNextHopBuilder()
+                    .setSpecialNextHop(SpecialNextHopGrouping.SpecialNextHop.Blackhole)
+                    /*.addAugmentation(SpecialNextHop2.class, new SpecialNextHop2Builder()
+                            .setPrimaryVrf(new VniReference(2L))
+                            .setAutoCreateVrf(true)
+                            .build())
+                    .build())*/
+            .build();
+}
diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/Ipv6RouteNamesFactoryTest.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/Ipv6RouteNamesFactoryTest.java
new file mode 100644 (file)
index 0000000..4f95ae3
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing;
+
+import static io.fd.hc2vpp.routing.Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY;
+import static org.junit.Assert.assertEquals;
+
+import io.fd.hc2vpp.common.test.util.NamingContextHelper;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper;
+import io.fd.hc2vpp.routing.helpers.SchemaContextTestHelper;
+import io.fd.hc2vpp.routing.naming.Ipv6RouteNamesFactory;
+import io.fd.honeycomb.test.tools.HoneycombTestRunner;
+import io.fd.honeycomb.test.tools.annotations.InjectTestData;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.vpp.jvpp.core.dto.Ip6FibDetails;
+import io.fd.vpp.jvpp.core.types.FibPath;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.next.hop.list.NextHopBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes;
+
+@RunWith(HoneycombTestRunner.class)
+public class Ipv6RouteNamesFactoryTest implements RoutingRequestTestHelper, SchemaContextTestHelper,
+        NamingContextHelper {
+
+    @Mock
+    private MappingContext mappingContext;
+
+    private NamingContext interfaceContext;
+    private NamingContext routingProtocolContext;
+    private Ip6FibDetails vppRoute;
+    private FibPath vppPath;
+    private Ipv6RouteNamesFactory factory;
+
+    @Before
+    public void init() {
+        MockitoAnnotations.initMocks(this);
+        interfaceContext = new NamingContext("interface-", "interface-context");
+        routingProtocolContext = new NamingContext("routing-protocol-", "routing-protocol-context");
+        vppRoute = new Ip6FibDetails();
+        vppRoute.address = FIRST_ADDRESS_AS_ARRAY;
+        vppRoute.addressLength = 64;
+        vppRoute.tableId = 1;
+
+        vppPath = new FibPath();
+        vppPath.nextHop = FIRST_ADDRESS_AS_ARRAY;
+        vppPath.swIfIndex = 2;
+        vppPath.weight = 3;
+        factory = new Ipv6RouteNamesFactory(interfaceContext, routingProtocolContext);
+        defineMapping(mappingContext, "iface", 2, "interface-context");
+        defineMapping(mappingContext, ROUTE_PROTOCOL_NAME, 1, "routing-protocol-context");
+    }
+
+    @Test
+    public void testUniqueRouteName(
+            @InjectTestData(resourcePath = "/ipv6/simpleHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH)
+                    StaticRoutes data) {
+        assertEquals("tst-protocol_2001db8a0b12f01_64",
+                factory.uniqueRouteName(ROUTE_PROTOCOL_NAME, getIpv6RouteWithId(data, 1L)));
+        assertEquals("tst-protocol_2001db8a0b12f01_64", factory.uniqueRouteName(vppRoute, mappingContext));
+    }
+
+    @Test
+    public void testUniqueRouteHopName() {
+        assertEquals("iface_2001db8a0b12f01_3", factory.uniqueRouteHopName(new NextHopBuilder()
+                .setAddress(new Ipv6Address("2001:0db8:0a0b:12f0:0000:0000:0000:0001"))
+                .setWeight((short) 3)
+                .setOutgoingInterface("iface")
+                .build()));
+        assertEquals("iface_2001db8a0b12f01_3",
+                factory.uniqueRouteHopName(vppPath, mappingContext));
+    }
+}
diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/RoutingModuleTest.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/RoutingModuleTest.java
new file mode 100644 (file)
index 0000000..670f7af
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.Matchers.empty;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import com.google.inject.Guice;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import com.google.inject.testing.fieldbinder.Bind;
+import com.google.inject.testing.fieldbinder.BoundFieldModule;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.read.RoutingStateReaderFactory;
+import io.fd.hc2vpp.routing.write.RoutingWriterFactory;
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.translate.impl.read.registry.CompositeReaderRegistryBuilder;
+import io.fd.honeycomb.translate.impl.write.registry.FlatWriterRegistryBuilder;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.HashSet;
+import java.util.Set;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+
+public class RoutingModuleTest {
+
+    @Named("honeycomb-context")
+    @Bind
+    @Mock
+    private DataBroker honeycombContext;
+
+    @Named("honeycomb-initializer")
+    @Bind
+    @Mock
+    private DataBroker honeycombInitializer;
+
+    @Named("interface-context")
+    @Bind
+    private NamingContext interfaceContext;
+
+    @Named("classify-table-context")
+    @Bind
+    @Mock
+    private VppClassifierContextManager classifierContextManager;
+
+    @Bind
+    @Mock
+    private FutureJVppCore futureJVppCore;
+
+    @Inject
+    private Set<ReaderFactory> readerFactories = new HashSet<>();
+
+    @Inject
+    private Set<WriterFactory> writerFactories = new HashSet<>();
+
+    @Before
+    public void setUp() {
+        initMocks(this);
+        interfaceContext = new NamingContext("interfaceContext", "interfaceContext");
+        Guice.createInjector(new RoutingModule(), BoundFieldModule.of(this)).injectMembers(this);
+    }
+
+    @Test
+    public void testReaderFactories() throws Exception {
+        assertThat(readerFactories, is(not(empty())));
+
+        // Test registration process (all dependencies present, topological order of readers does exist, etc.)
+        final CompositeReaderRegistryBuilder registryBuilder = new CompositeReaderRegistryBuilder();
+        readerFactories.stream().forEach(factory -> factory.init(registryBuilder));
+        assertNotNull(registryBuilder.build());
+        assertEquals(1, readerFactories.size());
+        assertTrue(readerFactories.iterator().next() instanceof RoutingStateReaderFactory);
+    }
+
+    @Test
+    public void testWriterFactories() throws Exception {
+        assertThat(writerFactories, is(not(empty())));
+
+        // Test registration process (all dependencies present, topological order of writers does exist, etc.)
+        final FlatWriterRegistryBuilder registryBuilder = new FlatWriterRegistryBuilder();
+        writerFactories.stream().forEach(factory -> factory.init(registryBuilder));
+        assertNotNull(registryBuilder.build());
+        assertEquals(1, writerFactories.size());
+        assertTrue(writerFactories.iterator().next() instanceof RoutingWriterFactory);
+    }
+}
diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/helpers/ClassifyTableTestHelper.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/helpers/ClassifyTableTestHelper.java
new file mode 100644 (file)
index 0000000..8e8f50c
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.helpers;
+
+
+import static org.mockito.Mockito.when;
+
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.translate.MappingContext;
+
+public interface ClassifyTableTestHelper {
+
+    String CLASSIFY_TABLE_NAME = "classify-table-one";
+    int CLASSIFY_TABLE_INDEX = 2;
+
+    default void addMapping(final VppClassifierContextManager classifyManager, final String name, final int index,
+                            final MappingContext mappingContext) {
+        when(classifyManager.containsTable(name, mappingContext)).thenReturn(true);
+        when(classifyManager.getTableIndex(name, mappingContext)).thenReturn(index);
+    }
+}
diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/helpers/InterfaceTestHelper.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/helpers/InterfaceTestHelper.java
new file mode 100644 (file)
index 0000000..95561e6
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.helpers;
+
+import io.fd.hc2vpp.common.test.util.NamingContextHelper;
+
+public interface InterfaceTestHelper extends NamingContextHelper {
+
+    String INTERFACE_NAME = "iface";
+    int INTERFACE_INDEX = 3;
+}
diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/helpers/RoutingRequestTestHelper.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/helpers/RoutingRequestTestHelper.java
new file mode 100644 (file)
index 0000000..bcb8e68
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.helpers;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import io.fd.hc2vpp.common.test.util.FutureProducer;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.routing.trait.RouteMapper;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.vpp.jvpp.core.dto.IpAddDelRoute;
+import io.fd.vpp.jvpp.core.dto.IpAddDelRouteReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.List;
+import org.mockito.ArgumentCaptor;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.StaticRoutes1;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes;
+
+public interface RoutingRequestTestHelper extends ByteDataTranslator, FutureProducer, RouteMapper {
+
+    String ROUTE_PROTOCOL_NAME = "tst-protocol";
+    String ROUTE_NAME = "tst-route";
+    String STATIC_ROUTE_PATH = "/ietf-routing:routing" +
+            "/ietf-routing:routing-instance[ietf-routing:name='" + ROUTE_PROTOCOL_NAME + "']" +
+            "/ietf-routing:routing-protocols" +
+            "/ietf-routing:routing-protocol[ietf-routing:name='" + ROUTE_NAME + "']" +
+            "/ietf-routing:static-routes";
+
+    default IpAddDelRoute desiredFlaglessResult(final int add, final int ipv6, final int isMultipath,
+                                                final byte[] destinationAddress,
+                                                final int destinationPrefixLength,
+                                                final byte[] nextHopAddr,
+                                                final int nextHopIndex,
+                                                final int nextHopWeight,
+                                                final int vrfId,
+                                                final int createVrfIfNeeded,
+                                                final int secondaryVrfId,
+                                                final int classifyTableIndex,
+                                                final int classifyTableIndexSet) {
+
+        // verification of flagless request, so setting them to 0
+        return desiredResult(add, ipv6, isMultipath, destinationAddress, destinationPrefixLength, nextHopAddr,
+                nextHopIndex, nextHopWeight, vrfId, createVrfIfNeeded, secondaryVrfId, classifyTableIndex,
+                classifyTableIndexSet, 0, 0, 0, 0);
+    }
+
+    default IpAddDelRoute desiredSpecialResult(final int add, final int ipv6,
+                                               final byte[] destinationAddress,
+                                               final int destinationPrefixLength,
+                                               final int isDrop,
+                                               final int isReceive,
+                                               final int isUnreach,
+                                               final int isProhibit) {
+        // verifiaction of special request that has only destination address and flag
+        return desiredResult(add, ipv6, 0, destinationAddress, destinationPrefixLength, null, 0, 0, 0, 1, 0, 0, 0,
+                isDrop, isReceive, isUnreach, isProhibit);
+    }
+
+    default IpAddDelRoute desiredResult(final int add, final int ipv6, final int isMultipath,
+                                        final byte[] destinationAddress,
+                                        final int destinationPrefixLength,
+                                        final byte[] nextHopAddr,
+                                        final int nextHopIndex,
+                                        final int nextHopWeight,
+                                        final int vrfId,
+                                        final int createVrfIfNeeded,
+                                        final int secondaryVrfId,
+                                        final int classifyTableIndex,
+                                        final int classifyTableIndexSet,
+                                        final int isDrop,
+                                        final int isLocal,
+                                        final int isUnreach,
+                                        final int isProhibit) {
+        final IpAddDelRoute request = new IpAddDelRoute();
+
+        request.isAdd = toByte(add);
+        request.isIpv6 = toByte(ipv6);
+        request.isMultipath = toByte(isMultipath);
+        request.dstAddress = destinationAddress;
+        request.dstAddressLength = toByte(destinationPrefixLength);
+        request.nextHopAddress = nextHopAddr;
+        request.nextHopSwIfIndex = nextHopIndex;
+        request.nextHopWeight = toByte(nextHopWeight);
+        request.classifyTableIndex = classifyTableIndexSet;
+        request.tableId = vrfId;
+        request.nextHopTableId = secondaryVrfId;
+        request.createVrfIfNeeded = toByte(createVrfIfNeeded);
+        request.classifyTableIndex = classifyTableIndex;
+        request.isClassify = toByte(classifyTableIndexSet);
+        // special hop flags
+        request.isDrop = toByte(isDrop);
+        request.isLocal = toByte(isLocal);
+        request.isUnreach = toByte(isUnreach);
+        request.isProhibit = toByte(isProhibit);
+        return request;
+    }
+
+    default void verifyInvocation(final int nrOfInvocations, final List<IpAddDelRoute> desiredRequests, final
+    FutureJVppCore api, final ArgumentCaptor<IpAddDelRoute> requestCaptor) {
+        verify(api, times(nrOfInvocations)).ipAddDelRoute(requestCaptor.capture());
+
+        final List<IpAddDelRoute> actualRequests = requestCaptor.getAllValues();
+
+        for (int i = 0; i < nrOfInvocations; i++) {
+            assertEquals(actualRequests.get(i), desiredRequests.get(i));
+        }
+    }
+
+    default void verifyNotInvoked(final FutureJVppCore api) {
+        verify(api, times(0)).ipAddDelRoute(any());
+    }
+
+    default void whenAddRouteThenSuccess(final FutureJVppCore api) {
+        when(api.ipAddDelRoute(any())).thenReturn(future(new IpAddDelRouteReply()));
+    }
+
+    default Route getIpv4RouteWithId(final StaticRoutes staticRoutes, final long id) {
+        return staticRoutes.getAugmentation(StaticRoutes1.class)
+                .getIpv4()
+                .getRoute()
+                .stream()
+                .filter(route -> route.getId() == id)
+                .collect(RWUtils.singleItemCollector());
+    }
+
+    default NextHop getHopWithId(
+            final Route route, final int id) {
+        return org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.NextHopList.class
+                .cast(route.getNextHopOptions())
+                .getNextHopList()
+                .getNextHop()
+                .stream()
+                .filter(nextHop -> nextHop.getKey().getId().intValue() == id)
+                .collect(RWUtils.singleItemCollector());
+    }
+
+    default org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route getIpv6RouteWithId(
+            final StaticRoutes staticRoutes, final long id) {
+        return staticRoutes.getAugmentation(
+                org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.StaticRoutes1.class)
+                .getIpv6()
+                .getRoute()
+                .stream()
+                .filter(route -> route.getId() == id)
+                .collect(RWUtils.singleItemCollector());
+    }
+
+}
diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/helpers/SchemaContextTestHelper.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/helpers/SchemaContextTestHelper.java
new file mode 100644 (file)
index 0000000..118595a
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.helpers;
+
+import com.google.common.collect.ImmutableSet;
+import io.fd.honeycomb.test.tools.annotations.InjectablesProcessor;
+import io.fd.honeycomb.test.tools.annotations.SchemaContextProvider;
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
+
+public interface SchemaContextTestHelper extends InjectablesProcessor {
+
+    @SchemaContextProvider
+    default ModuleInfoBackedContext getSchemaContext() {
+        return provideSchemaContextFor(ImmutableSet.of(
+                // Default ietf-ip
+                org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.$YangModuleInfoImpl
+                        .getInstance(),
+                // Default ietf-routing
+                org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.$YangModuleInfoImpl
+                        .getInstance(),
+                // Ipv4 augmentations
+                org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.$YangModuleInfoImpl
+                        .getInstance(),
+                // Ipv4 augmentations
+                org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.$YangModuleInfoImpl
+                        .getInstance(),
+                // Vpp routing
+                org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.$YangModuleInfoImpl
+                        .getInstance()));
+    }
+}
diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/read/Ipv4RouteCustomizerTest.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/read/Ipv4RouteCustomizerTest.java
new file mode 100644 (file)
index 0000000..814345f
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.read;
+
+import static io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper.ROUTE_PROTOCOL_NAME;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasItems;
+import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+
+import io.fd.hc2vpp.common.test.read.ListReaderCustomizerTest;
+import io.fd.hc2vpp.common.translate.util.MultiNamingContext;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.Ipv4RouteData;
+import io.fd.hc2vpp.routing.RoutingConfiguration;
+import io.fd.hc2vpp.routing.naming.Ipv4RouteNamesFactory;
+import io.fd.hc2vpp.routing.trait.RouteMapper;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager;
+import io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor;
+import io.fd.vpp.jvpp.core.dto.IpFibDetails;
+import io.fd.vpp.jvpp.core.dto.IpFibDetailsReplyDump;
+import io.fd.vpp.jvpp.core.types.FibPath;
+import java.util.Arrays;
+import java.util.List;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.junit.Test;
+import org.mockito.Mock;
+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.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.StaticRoutes2;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv4;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv4Builder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.RouteBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.RouteKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.NextHopOptions;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.NextHopList;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SimpleNextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.SpecialNextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHopBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHopKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.SpecialNextHopGrouping;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.RoutingProtocols;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocol;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocolKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol.StaticRoutes;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class Ipv4RouteCustomizerTest extends ListReaderCustomizerTest<Route, RouteKey, RouteBuilder>
+        implements RouteMapper {
+
+    private final InstanceIdentifier<Ipv4> ipv4InstanceIdentifier = InstanceIdentifier.create(RoutingProtocols.class)
+            .child(RoutingProtocol.class, new RoutingProtocolKey(ROUTE_PROTOCOL_NAME))
+            .child(StaticRoutes.class)
+            .augmentation(StaticRoutes2.class)
+            .child(Ipv4.class);
+    private DumpCacheManager<IpFibDetailsReplyDump, Void> manager;
+    @Mock
+    private RoutingConfiguration configuration;
+    @Mock
+    private MultiNamingContext routeHopContext;
+    @Mock
+    private EntityDumpExecutor<IpFibDetailsReplyDump, Void> executor;
+    private NamingContext interfaceContext = new NamingContext("ifaces", "interface-context");
+    private NamingContext routesContext = new NamingContext("routes", "route-context");
+    private NamingContext routingProtocolContext = new NamingContext("routing-protocol", "routing-protocol-context");
+    private InstanceIdentifier<Route> routeIdSpecialHop = ipv4InstanceIdentifier.child(Route.class, new RouteKey(1L));
+    private InstanceIdentifier<Route> routeIdSimpleHop = ipv4InstanceIdentifier.child(Route.class, new RouteKey(2L));
+    private InstanceIdentifier<Route> routeIdListHop = ipv4InstanceIdentifier.child(Route.class, new RouteKey(3L));
+
+
+    public Ipv4RouteCustomizerTest() {
+        super(Route.class, Ipv4Builder.class);
+    }
+
+    @Override
+    public void setUp() throws ReadFailedException {
+        manager = new DumpCacheManager.DumpCacheManagerBuilder<IpFibDetailsReplyDump, Void>()
+                .withExecutor(executor)
+                .acceptOnly(IpFibDetailsReplyDump.class)
+                .build();
+
+        final IpFibDetailsReplyDump replyDump = replyDump();
+        when(executor.executeDump(routeIdSpecialHop, EntityDumpExecutor.NO_PARAMS)).thenReturn(replyDump);
+        when(executor.executeDump(routeIdSimpleHop, EntityDumpExecutor.NO_PARAMS)).thenReturn(replyDump);
+        when(executor.executeDump(routeIdListHop, EntityDumpExecutor.NO_PARAMS)).thenReturn(replyDump);
+
+        IpFibDetails listRoute = replyDump.ipFibDetails.get(2);
+        final Ipv4RouteNamesFactory factory = new Ipv4RouteNamesFactory(interfaceContext, routingProtocolContext);
+
+        defineMapping(mappingContext, ROUTE_PROTOCOL_NAME, 1, "routing-protocol-context");
+        defineMapping(mappingContext, "iface-1", 1, "interface-context");
+        defineMapping(mappingContext, factory.uniqueRouteName(replyDump.ipFibDetails.get(0), mappingContext), 1,
+                "route-context");
+        defineMapping(mappingContext, factory.uniqueRouteName(replyDump.ipFibDetails.get(1), mappingContext), 2,
+                "route-context");
+
+        String listRouteName = factory.uniqueRouteName(listRoute, mappingContext);
+        defineMapping(mappingContext, listRouteName, 3, "route-context");
+
+        when(routeHopContext.getChildIndex(listRouteName, factory.uniqueRouteHopName(listRoute.path[0], mappingContext),
+                mappingContext)).thenReturn(0);
+        when(routeHopContext.getChildIndex(listRouteName, factory.uniqueRouteHopName(listRoute.path[1], mappingContext),
+                mappingContext)).thenReturn(1);
+    }
+
+    private IpFibDetailsReplyDump replyDump() {
+        IpFibDetailsReplyDump replyDump = new IpFibDetailsReplyDump();
+
+        // first is special
+        IpFibDetails detail1 = new IpFibDetails();
+        detail1.tableId = 1;
+        detail1.address = Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY;
+        detail1.addressLength = 24;
+
+        FibPath path1 = new FibPath();
+        path1.isLocal = 1;
+        detail1.path = new FibPath[]{path1};
+
+
+        //second is simple
+        IpFibDetails detail2 = new IpFibDetails();
+        detail2.tableId = 1;
+        detail2.address = Ipv4RouteData.SECOND_ADDRESS_AS_ARRAY;
+        detail2.addressLength = 22;
+        detail2.path = new FibPath[]{};
+
+        FibPath path2 = new FibPath();
+        path2.weight = 3;
+        path2.nextHop = Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY;
+        path2.afi = 0;
+        path2.swIfIndex = 1;
+        detail2.path = new FibPath[]{path2};
+
+        // third is list
+        IpFibDetails detail3 = new IpFibDetails();
+        detail3.tableId = 1;
+        detail3.address = Ipv4RouteData.SECOND_ADDRESS_AS_ARRAY;
+        detail3.addressLength = 16;
+
+        FibPath path3 = new FibPath();
+        path3.swIfIndex = 1;
+        path3.weight = 1;
+        path3.nextHop = Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY;
+        path3.afi = 0;
+
+        FibPath path4 = new FibPath();
+        path4.swIfIndex = 1;
+        path4.weight = 2;
+        path4.nextHop = Ipv4RouteData.SECOND_ADDRESS_AS_ARRAY;
+        path4.afi = 0;
+
+        detail3.path = new FibPath[]{path3, path4};
+
+        replyDump.ipFibDetails = Arrays.asList(detail1, detail2, detail3);
+        return replyDump;
+    }
+
+    @Test
+    public void getAllIds() throws Exception {
+        final List<RouteKey> keys = getCustomizer().getAllIds(routeIdSpecialHop, ctx);
+
+        assertThat(keys, hasSize(3));
+        assertThat(keys, hasItems(new RouteKey(1L), new RouteKey(2L), new RouteKey(3L)));
+    }
+
+    @Test
+    public void readCurrentAttributesSpecialHop() throws Exception {
+        final RouteBuilder builder = new RouteBuilder();
+        getCustomizer().readCurrentAttributes(routeIdSpecialHop, builder, ctx);
+
+        assertEquals(1, builder.getId().intValue());
+        assertEquals(1, builder.getKey().getId().intValue());
+        assertEquals(new Ipv4Prefix("192.168.2.1/24"), builder.getDestinationPrefix());
+
+        NextHopOptions hopOptions = builder.getNextHopOptions();
+        assertTrue(hopOptions instanceof SpecialNextHop);
+
+        SpecialNextHop hop = SpecialNextHop.class.cast(hopOptions);
+        assertEquals(SpecialNextHopGrouping.SpecialNextHop.Receive, hop.getSpecialNextHop());
+    }
+
+    @Test
+    public void readCurrentAttributesSimpleHop() throws Exception {
+        final RouteBuilder builder = new RouteBuilder();
+        getCustomizer().readCurrentAttributes(routeIdSimpleHop, builder, ctx);
+
+        assertEquals(2, builder.getId().intValue());
+        assertEquals(2, builder.getKey().getId().intValue());
+        assertEquals(new Ipv4Prefix("192.168.2.2/22"), builder.getDestinationPrefix());
+
+        NextHopOptions hopOptions = builder.getNextHopOptions();
+        assertTrue(hopOptions instanceof SimpleNextHop);
+
+        SimpleNextHop hop = SimpleNextHop.class.cast(hopOptions);
+        assertEquals("192.168.2.1", hop.getNextHop().getValue());
+        assertEquals("iface-1", hop.getOutgoingInterface());
+    }
+
+    @Test
+    public void readCurrentAttributesListHop() throws Exception {
+
+        final RouteBuilder builder = new RouteBuilder();
+        getCustomizer().readCurrentAttributes(routeIdListHop, builder, ctx);
+
+        assertEquals(3, builder.getId().intValue());
+        assertEquals(3, builder.getKey().getId().intValue());
+        assertEquals(new Ipv4Prefix("192.168.2.2/16"), builder.getDestinationPrefix());
+
+        NextHopOptions hopOptions = builder.getNextHopOptions();
+        assertTrue(hopOptions instanceof NextHopList);
+
+        NextHopList hop = NextHopList.class.cast(hopOptions);
+        List<NextHop> hops = hop.getNextHopList().getNextHop();
+
+        assertThat(hops, hasSize(2));
+
+        assertTrue(areEqual(hops.get(0), desiredHop(0L, "192.168.2.1", 1, "iface-1")));
+        assertTrue(areEqual(hops.get(1), desiredHop(1L, "192.168.2.2", 2, "iface-1")));
+    }
+
+    private boolean areEqual(final NextHop first, final NextHop second) {
+        return new EqualsBuilder()
+                .append(true, first.getAddress().getValue().equals(second.getAddress().getValue()))
+                .append(true, first.getId().equals(second.getId()))
+                .append(true, first.getKey().equals(second.getKey()))
+                .append(true, first.getOutgoingInterface().equals(second.getOutgoingInterface()))
+                .isEquals();
+    }
+
+    private NextHop desiredHop(final long id, final String address, final int weight, final String iface) {
+        return new NextHopBuilder()
+                .setAddress(new Ipv4Address(address))
+                .setWeight((short) weight)
+                .setOutgoingInterface(iface)
+                .setId(id)
+                .setKey(new NextHopKey(id))
+                .build();
+    }
+
+    @Override
+    protected ReaderCustomizer<Route, RouteBuilder> initCustomizer() {
+        return new Ipv4RouteCustomizer(manager, configuration, routeHopContext, interfaceContext,
+                routesContext, routingProtocolContext);
+    }
+}
\ No newline at end of file
diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/read/Ipv6RouteCustomizerTest.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/read/Ipv6RouteCustomizerTest.java
new file mode 100644 (file)
index 0000000..a026b57
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.read;
+
+import static io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper.ROUTE_PROTOCOL_NAME;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasItems;
+import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+
+import io.fd.hc2vpp.common.test.read.ListReaderCustomizerTest;
+import io.fd.hc2vpp.common.translate.util.MultiNamingContext;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.Ipv6RouteData;
+import io.fd.hc2vpp.routing.RoutingConfiguration;
+import io.fd.hc2vpp.routing.naming.Ipv6RouteNamesFactory;
+import io.fd.hc2vpp.routing.trait.RouteMapper;
+import io.fd.honeycomb.translate.ModificationCache;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager;
+import io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor;
+import io.fd.vpp.jvpp.core.dto.Ip6FibDetails;
+import io.fd.vpp.jvpp.core.dto.Ip6FibDetailsReplyDump;
+import io.fd.vpp.jvpp.core.types.FibPath;
+import java.util.Arrays;
+import java.util.List;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.StaticRoutes2;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv6;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv6Builder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.RouteBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.RouteKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.NextHopOptions;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.NextHopList;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SimpleNextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.SpecialNextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.next.hop.list.NextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.next.hop.list.NextHopBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.state.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.next.hop.list.NextHopKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.SpecialNextHopGrouping;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.RoutingProtocols;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocol;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocolKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.routing.protocol.StaticRoutes;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class Ipv6RouteCustomizerTest extends ListReaderCustomizerTest<Route, RouteKey, RouteBuilder>
+        implements RouteMapper {
+
+    private static final String ROUTING_PROTOCOL_PREFIX = "route-p-";
+    private DumpCacheManager<Ip6FibDetailsReplyDump, Void> manager;
+
+    @Mock
+    private RoutingConfiguration configuration;
+
+    @Mock
+    private MultiNamingContext routeHopContext;
+
+    @Mock
+    private EntityDumpExecutor<Ip6FibDetailsReplyDump, Void> executor;
+
+    @Mock
+    private ModificationCache cache;
+
+    private NamingContext interfaceContext;
+    private NamingContext routesContext;
+    private NamingContext routingProtocolContext;
+
+    private InstanceIdentifier<Route> routeIdSpecialHop;
+    private InstanceIdentifier<Route> routeIdSimpleHop;
+    private InstanceIdentifier<Route> routeIdListHop;
+    private Ipv6RouteNamesFactory factory;
+
+    public Ipv6RouteCustomizerTest() {
+        super(Route.class, Ipv6Builder.class);
+    }
+
+    @Override
+    public void setUp() throws ReadFailedException {
+        manager = new DumpCacheManager.DumpCacheManagerBuilder<Ip6FibDetailsReplyDump, Void>()
+                .withExecutor(executor)
+                .acceptOnly(Ip6FibDetailsReplyDump.class)
+                .build();
+
+        interfaceContext = new NamingContext("ifaces", "interface-context");
+        routesContext = new NamingContext("routes", "route-context");
+        routingProtocolContext = new NamingContext("routing-protocol", "routing-protocol-context");
+
+        final InstanceIdentifier<Ipv6> ipv6InstanceIdentifier = InstanceIdentifier.create(RoutingProtocols.class)
+                .child(RoutingProtocol.class, new RoutingProtocolKey(ROUTE_PROTOCOL_NAME))
+                .child(StaticRoutes.class)
+                .augmentation(StaticRoutes2.class)
+                .child(Ipv6.class);
+
+        routeIdSpecialHop = ipv6InstanceIdentifier.child(Route.class, new RouteKey(1L));
+        routeIdSimpleHop = ipv6InstanceIdentifier.child(Route.class, new RouteKey(2L));
+        routeIdListHop = ipv6InstanceIdentifier.child(Route.class, new RouteKey(3L));
+
+        factory = new Ipv6RouteNamesFactory(interfaceContext, routingProtocolContext);
+
+
+        final Ip6FibDetailsReplyDump replyDump = replyDump();
+        when(executor.executeDump(routeIdSpecialHop, EntityDumpExecutor.NO_PARAMS)).thenReturn(replyDump);
+        when(executor.executeDump(routeIdSimpleHop, EntityDumpExecutor.NO_PARAMS)).thenReturn(replyDump);
+        when(executor.executeDump(routeIdListHop, EntityDumpExecutor.NO_PARAMS)).thenReturn(replyDump);
+
+        defineMapping(mappingContext, "iface-1", 1, "interface-context");
+        defineMapping(mappingContext, ROUTE_PROTOCOL_NAME, 1, "routing-protocol-context");
+        defineMapping(mappingContext, factory.uniqueRouteName(replyDump.ip6FibDetails.get(0), mappingContext), 1,
+                "route-context");
+        defineMapping(mappingContext, factory.uniqueRouteName(replyDump.ip6FibDetails.get(1), mappingContext), 2,
+                "route-context");
+
+        Ip6FibDetails listRoute = replyDump.ip6FibDetails.get(2);
+        String listRouteName = factory.uniqueRouteName(listRoute, mappingContext);
+        defineMapping(mappingContext, listRouteName, 3, "route-context");
+
+        when(routeHopContext.getChildIndex(listRouteName, factory.uniqueRouteHopName(listRoute.path[0], mappingContext),
+                mappingContext))
+                .thenReturn(0);
+        when(routeHopContext.getChildIndex(listRouteName, factory.uniqueRouteHopName(listRoute.path[1], mappingContext),
+                mappingContext))
+                .thenReturn(1);
+    }
+
+    private Ip6FibDetailsReplyDump replyDump() {
+        Ip6FibDetailsReplyDump replyDump = new Ip6FibDetailsReplyDump();
+
+        // first is special
+        Ip6FibDetails detail1 = new Ip6FibDetails();
+        detail1.tableId = 1;
+        detail1.address = Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY;
+        detail1.addressLength = 24;
+
+        FibPath path1 = new FibPath();
+        path1.isLocal = 1;
+        detail1.path = new FibPath[]{path1};
+
+
+        //second is simple
+        Ip6FibDetails detail2 = new Ip6FibDetails();
+        detail2.tableId = 1;
+        detail2.address = Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY;
+        detail2.addressLength = 22;
+        detail2.path = new FibPath[]{};
+
+        FibPath path2 = new FibPath();
+        path2.weight = 3;
+        path2.nextHop = Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY;
+        path2.afi = 0;
+        path2.swIfIndex = 1;
+        detail2.path = new FibPath[]{path2};
+
+        // third is list
+        Ip6FibDetails detail3 = new Ip6FibDetails();
+        detail3.tableId = 1;
+        detail3.address = Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY;
+        detail3.addressLength = 16;
+
+        FibPath path3 = new FibPath();
+        path3.swIfIndex = 1;
+        path3.weight = 1;
+        path3.nextHop = Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY;
+        path3.afi = 0;
+
+        FibPath path4 = new FibPath();
+        path4.swIfIndex = 1;
+        path4.weight = 2;
+        path4.nextHop = Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY;
+        path4.afi = 0;
+
+        detail3.path = new FibPath[]{path3, path4};
+
+        replyDump.ip6FibDetails = Arrays.asList(detail1, detail2, detail3);
+        return replyDump;
+    }
+
+    @Test
+    public void getAllIds() throws Exception {
+        final List<RouteKey> keys = getCustomizer().getAllIds(routeIdSpecialHop, ctx);
+
+        assertThat(keys, hasSize(3));
+        assertThat(keys, hasItems(new RouteKey(1L), new RouteKey(2L), new RouteKey(3L)));
+    }
+
+    @Test
+    public void readCurrentAttributesSpecialHop() throws Exception {
+        final RouteBuilder builder = new RouteBuilder();
+        getCustomizer().readCurrentAttributes(routeIdSpecialHop, builder, ctx);
+
+        assertEquals(1, builder.getId().intValue());
+        assertEquals(1, builder.getKey().getId().intValue());
+        assertEquals("2001:db8:a0b:12f0:0:0:0:1/24", builder.getDestinationPrefix().getValue());
+
+        NextHopOptions hopOptions = builder.getNextHopOptions();
+        assertTrue(hopOptions instanceof SpecialNextHop);
+
+        SpecialNextHop hop = SpecialNextHop.class.cast(hopOptions);
+        assertEquals(SpecialNextHopGrouping.SpecialNextHop.Receive, hop.getSpecialNextHop());
+    }
+
+    @Test
+    public void readCurrentAttributesSimpleHop() throws Exception {
+        final RouteBuilder builder = new RouteBuilder();
+        getCustomizer().readCurrentAttributes(routeIdSimpleHop, builder, ctx);
+
+        assertEquals(2, builder.getId().intValue());
+        assertEquals(2, builder.getKey().getId().intValue());
+        assertEquals("2001:db8:a0b:12f0:0:0:0:2/22", builder.getDestinationPrefix().getValue());
+
+        NextHopOptions hopOptions = builder.getNextHopOptions();
+        assertTrue(hopOptions instanceof SimpleNextHop);
+
+        SimpleNextHop hop = SimpleNextHop.class.cast(hopOptions);
+        assertEquals("2001:db8:a0b:12f0::1", hop.getNextHop().getValue());
+        assertEquals("iface-1", hop.getOutgoingInterface());
+    }
+
+    @Test
+    public void readCurrentAttributesListHop() throws Exception {
+
+
+        final RouteBuilder builder = new RouteBuilder();
+        getCustomizer().readCurrentAttributes(routeIdListHop, builder, ctx);
+
+        assertEquals(3, builder.getId().intValue());
+        assertEquals(3, builder.getKey().getId().intValue());
+        assertEquals("2001:db8:a0b:12f0:0:0:0:2/16", builder.getDestinationPrefix().getValue());
+
+        NextHopOptions hopOptions = builder.getNextHopOptions();
+        assertTrue(hopOptions instanceof NextHopList);
+
+        NextHopList hop = NextHopList.class.cast(hopOptions);
+        List<NextHop> hops = hop.getNextHopList().getNextHop();
+
+        assertThat(hops, hasSize(2));
+
+        assertTrue(areEqual(hops.get(0), desiredHop(0L, "2001:db8:a0b:12f0::1", 1, "iface-1")));
+        assertTrue(areEqual(hops.get(1), desiredHop(1L, "2001:db8:a0b:12f0::2", 2, "iface-1")));
+    }
+
+    private boolean areEqual(final NextHop first, final NextHop second) {
+        return new EqualsBuilder()
+                .append(true, first.getAddress().getValue().equals(second.getAddress().getValue()))
+                .append(true, first.getId().equals(second.getId()))
+                .append(true, first.getKey().equals(second.getKey()))
+                .append(true, first.getOutgoingInterface().equals(second.getOutgoingInterface()))
+                .isEquals();
+    }
+
+    private NextHop desiredHop(final long id, final String address, final int weight, final String iface) {
+        return new NextHopBuilder()
+                .setAddress(new Ipv6Address(address))
+                .setWeight((short) weight)
+                .setOutgoingInterface(iface)
+                .setId(id)
+                .setKey(new NextHopKey(id))
+                .build();
+    }
+
+    @Override
+    protected ReaderCustomizer<Route, RouteBuilder> initCustomizer() {
+        return new Ipv6RouteCustomizer(manager, configuration, routeHopContext,
+                interfaceContext, routesContext, routingProtocolContext);
+    }
+}
\ No newline at end of file
diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/read/RoutingProtocolCustomizerTest.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/read/RoutingProtocolCustomizerTest.java
new file mode 100644 (file)
index 0000000..1d0057c
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.read;
+
+import static io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper.ROUTE_PROTOCOL_NAME;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.core.IsCollectionContaining.hasItems;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import io.fd.hc2vpp.common.test.read.ListReaderCustomizerTest;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.Ipv4RouteData;
+import io.fd.hc2vpp.routing.Ipv6RouteData;
+import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager;
+import io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor;
+import io.fd.vpp.jvpp.core.dto.Ip6FibDetails;
+import io.fd.vpp.jvpp.core.dto.Ip6FibDetailsReplyDump;
+import io.fd.vpp.jvpp.core.dto.IpFibDetails;
+import io.fd.vpp.jvpp.core.dto.IpFibDetailsReplyDump;
+import io.fd.vpp.jvpp.core.types.FibPath;
+import java.util.Arrays;
+import java.util.List;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.Static;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.RoutingProtocols;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.RoutingProtocolsBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocol;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocolBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.state.routing.instance.routing.protocols.RoutingProtocolKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class RoutingProtocolCustomizerTest
+        extends ListReaderCustomizerTest<RoutingProtocol, RoutingProtocolKey, RoutingProtocolBuilder>
+        implements ByteDataTranslator {
+
+    private static final String VPP_PROTOCOL_PREFIX = "vpp-protocol";
+
+    @Mock
+    private EntityDumpExecutor<IpFibDetailsReplyDump, Void> ipv4Executor;
+
+    @Mock
+    private EntityDumpExecutor<Ip6FibDetailsReplyDump, Void> ipv6Executor;
+    private DumpCacheManager<IpFibDetailsReplyDump, Void> ipv4RoutesDumpManager;
+    private DumpCacheManager<Ip6FibDetailsReplyDump, Void> ipv6RoutesDumpManager;
+
+    private NamingContext routingProtocolContext;
+
+    public RoutingProtocolCustomizerTest() {
+        super(RoutingProtocol.class, RoutingProtocolsBuilder.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        when(ipv4Executor.executeDump(any(), any())).thenReturn(replyDumpIpv4());
+        when(ipv6Executor.executeDump(any(), any())).thenReturn(replyDumpIpv6());
+        when(ctx.getModificationCache()).thenReturn(cache);
+
+        ipv4RoutesDumpManager = new DumpCacheManager.DumpCacheManagerBuilder<IpFibDetailsReplyDump, Void>()
+                .withExecutor(ipv4Executor)
+                .acceptOnly(IpFibDetailsReplyDump.class)
+                .build();
+
+        ipv6RoutesDumpManager = new DumpCacheManager.DumpCacheManagerBuilder<Ip6FibDetailsReplyDump, Void>()
+                .withExecutor(ipv6Executor)
+                .acceptOnly(Ip6FibDetailsReplyDump.class)
+                .build();
+
+        routingProtocolContext = new NamingContext("routing-protocol", "routing-protocol-context");
+        defineMapping(mappingContext, ROUTE_PROTOCOL_NAME, 1, "routing-protocol-context");
+        defineMapping(mappingContext, "tst-protocol-2", 2, "routing-protocol-context");
+        defineMapping(mappingContext, "tst-protocol-3", 3, "routing-protocol-context");
+    }
+
+    @Test
+    public void getAllIds() throws Exception {
+        final List<RoutingProtocolKey> keys =
+                getCustomizer().getAllIds(InstanceIdentifier.create(RoutingProtocol.class), ctx);
+
+        assertThat(keys, hasSize(3));
+        assertThat(keys, hasItems(new RoutingProtocolKey(ROUTE_PROTOCOL_NAME), new RoutingProtocolKey("tst-protocol-2"),
+                new RoutingProtocolKey("tst-protocol-3")));
+    }
+
+    @Test
+    public void readCurrentAttributes() throws Exception {
+        final InstanceIdentifier<RoutingProtocol> identifier = InstanceIdentifier.create(RoutingProtocols.class)
+                .child(RoutingProtocol.class, new RoutingProtocolKey(ROUTE_PROTOCOL_NAME));
+
+        final RoutingProtocolBuilder builder = new RoutingProtocolBuilder();
+        getCustomizer().readCurrentAttributes(identifier, builder, ctx);
+
+        assertEquals(ROUTE_PROTOCOL_NAME, builder.getName());
+        assertEquals(ROUTE_PROTOCOL_NAME, builder.getKey().getName());
+        assertEquals(Static.class, builder.getType());
+    }
+
+    @Override
+    protected ReaderCustomizer<RoutingProtocol, RoutingProtocolBuilder> initCustomizer() {
+        return new RoutingProtocolCustomizer(routingProtocolContext, ipv4RoutesDumpManager, ipv6RoutesDumpManager);
+    }
+
+    private Ip6FibDetailsReplyDump replyDumpIpv6() {
+        Ip6FibDetailsReplyDump replyDump = new Ip6FibDetailsReplyDump();
+
+        // first is special
+        Ip6FibDetails detail1 = new Ip6FibDetails();
+        detail1.tableId = 1;
+        detail1.address = Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY;
+        detail1.addressLength = 24;
+
+        FibPath path1 = new FibPath();
+        path1.isLocal = 1;
+        detail1.path = new FibPath[]{path1};
+
+
+        //second is simple
+        Ip6FibDetails detail2 = new Ip6FibDetails();
+        detail2.tableId = 2;
+        detail2.address = Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY;
+        detail2.addressLength = 22;
+        detail2.path = new FibPath[]{};
+
+        FibPath path2 = new FibPath();
+        path2.weight = 3;
+        path2.nextHop = Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY;
+        path2.afi = 0;
+        path2.swIfIndex = 1;
+        detail2.path = new FibPath[]{path2};
+
+        // third is list
+        Ip6FibDetails detail3 = new Ip6FibDetails();
+        detail3.tableId = 1;
+        detail3.address = Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY;
+        detail3.addressLength = 16;
+
+        FibPath path3 = new FibPath();
+        path3.swIfIndex = 1;
+        path3.weight = 1;
+        path3.nextHop = Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY;
+        path3.afi = 0;
+
+        FibPath path4 = new FibPath();
+        path4.swIfIndex = 1;
+        path4.weight = 2;
+        path4.nextHop = Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY;
+        path4.afi = 0;
+
+        detail3.path = new FibPath[]{path3, path4};
+
+        replyDump.ip6FibDetails = Arrays.asList(detail1, detail2, detail3);
+        return replyDump;
+    }
+
+    private IpFibDetailsReplyDump replyDumpIpv4() {
+        IpFibDetailsReplyDump replyDump = new IpFibDetailsReplyDump();
+
+        // first is special
+        IpFibDetails detail1 = new IpFibDetails();
+        detail1.tableId = 1;
+        detail1.address = Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY;
+        detail1.addressLength = 24;
+
+        FibPath path1 = new FibPath();
+        path1.isLocal = 1;
+        detail1.path = new FibPath[]{path1};
+
+
+        //second is simple
+        IpFibDetails detail2 = new IpFibDetails();
+        detail2.tableId = 3;
+        detail2.address = Ipv4RouteData.SECOND_ADDRESS_AS_ARRAY;
+        detail2.addressLength = 22;
+        detail2.path = new FibPath[]{};
+
+        FibPath path2 = new FibPath();
+        path2.weight = 3;
+        path2.nextHop = Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY;
+        path2.afi = 0;
+        path2.swIfIndex = 1;
+        detail2.path = new FibPath[]{path2};
+
+        // third is list
+        IpFibDetails detail3 = new IpFibDetails();
+        detail3.tableId = 1;
+        detail3.address = Ipv4RouteData.SECOND_ADDRESS_AS_ARRAY;
+        detail3.addressLength = 16;
+
+        FibPath path3 = new FibPath();
+        path3.swIfIndex = 1;
+        path3.weight = 1;
+        path3.nextHop = Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY;
+        path3.afi = 0;
+
+        FibPath path4 = new FibPath();
+        path4.swIfIndex = 1;
+        path4.weight = 2;
+        path4.nextHop = Ipv4RouteData.SECOND_ADDRESS_AS_ARRAY;
+        path4.afi = 0;
+
+        detail3.path = new FibPath[]{path3, path4};
+
+        replyDump.ipFibDetails = Arrays.asList(detail1, detail2, detail3);
+        return replyDump;
+    }
+}
\ No newline at end of file
diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/read/RoutingStateCustomizerTest.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/read/RoutingStateCustomizerTest.java
new file mode 100644 (file)
index 0000000..7bece73
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.read;
+
+
+import static org.junit.Assert.assertEquals;
+
+import io.fd.hc2vpp.routing.helpers.SchemaContextTestHelper;
+import io.fd.honeycomb.test.tools.HoneycombTestRunner;
+import io.fd.honeycomb.test.tools.annotations.InjectTestData;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.spi.read.Initialized;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.Routing;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.RoutingState;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+@RunWith(HoneycombTestRunner.class)
+public class RoutingStateCustomizerTest implements SchemaContextTestHelper {
+
+    @InjectTestData(resourcePath = "/init/config-data.json")
+    private Routing config;
+
+    @InjectTestData(resourcePath = "/init/state-data.json")
+    private RoutingState state;
+
+    @Mock
+    private ReadContext readContext;
+
+    @Before
+    public void init() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void testInit() {
+        final InstanceIdentifier<RoutingState> identifier = InstanceIdentifier.create(RoutingState.class);
+        final Initialized<? extends DataObject> initilized =
+                new RoutingStateCustomizer().init(identifier, state, readContext);
+
+        final Routing initializedRouting = Routing.class.cast(initilized.getData());
+
+        assertEquals(config, initializedRouting);
+    }
+}
diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/Ipv4RouteCustomizerTest.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/Ipv4RouteCustomizerTest.java
new file mode 100644 (file)
index 0000000..13b4347
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.write;
+
+
+import static io.fd.hc2vpp.routing.helpers.InterfaceTestHelper.INTERFACE_INDEX;
+import static io.fd.hc2vpp.routing.helpers.InterfaceTestHelper.INTERFACE_NAME;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import com.google.common.collect.ImmutableList;
+import io.fd.hc2vpp.common.test.write.WriterCustomizerTest;
+import io.fd.hc2vpp.common.translate.util.MultiNamingContext;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.Ipv4RouteData;
+import io.fd.hc2vpp.routing.helpers.ClassifyTableTestHelper;
+import io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper;
+import io.fd.hc2vpp.routing.helpers.SchemaContextTestHelper;
+import io.fd.hc2vpp.routing.naming.Ipv4RouteNamesFactory;
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.test.tools.HoneycombTestRunner;
+import io.fd.honeycomb.test.tools.annotations.InjectTestData;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.IpAddDelRoute;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.StaticRoutes1;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv4;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.RouteBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.RoutingProtocols;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocol;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocolKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+@RunWith(HoneycombTestRunner.class)
+public class Ipv4RouteCustomizerTest extends WriterCustomizerTest
+        implements ClassifyTableTestHelper, RoutingRequestTestHelper, SchemaContextTestHelper {
+
+    @Captor
+    private ArgumentCaptor<IpAddDelRoute> requestCaptor;
+
+    @Mock
+    private VppClassifierContextManager classifyManager;
+
+    @Mock
+    private MultiNamingContext routeHopContext;
+
+    private Ipv4RouteCustomizer customizer;
+    private InstanceIdentifier<Route> validId;
+    private Ipv4RouteNamesFactory namesFactory;
+    private NamingContext routingProtocolContext;
+
+    @Override
+    protected void setUpTest() throws Exception {
+        NamingContext interfaceContext = new NamingContext("interface", "interface-context");
+        routingProtocolContext = new NamingContext("routing-protocol", "routing-protocol-context");
+        customizer = new Ipv4RouteCustomizer(api, interfaceContext,
+                new NamingContext("route", "route-context"),
+                routingProtocolContext, routeHopContext, classifyManager);
+
+        validId = InstanceIdentifier.create(RoutingProtocols.class)
+                .child(RoutingProtocol.class, new RoutingProtocolKey(ROUTE_PROTOCOL_NAME))
+                .child(StaticRoutes.class)
+                .augmentation(StaticRoutes1.class)
+                .child(Ipv4.class)
+                .child(Route.class);
+
+        namesFactory = new Ipv4RouteNamesFactory(interfaceContext, routingProtocolContext);
+
+        defineMapping(mappingContext, INTERFACE_NAME, INTERFACE_INDEX, "interface-context");
+        defineMapping(mappingContext, ROUTE_PROTOCOL_NAME, 1, "routing-protocol-context");
+        addMapping(classifyManager, CLASSIFY_TABLE_NAME, CLASSIFY_TABLE_INDEX, mappingContext);
+        whenAddRouteThenSuccess(api);
+    }
+
+    @Test
+    public void testWriteSingleHop(
+            @InjectTestData(resourcePath = "/ipv4/simpleHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH) StaticRoutes route)
+            throws WriteFailedException {
+        final Route route1 = getIpv4RouteWithId(route, 1L);
+        noMappingDefined(mappingContext, namesFactory.uniqueRouteName(ROUTE_PROTOCOL_NAME, route1), "route-context");
+
+        customizer.writeCurrentAttributes(validId, route1, writeContext);
+        verifyInvocation(1, ImmutableList
+                        .of(desiredFlaglessResult(1, 0, 0, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24,
+                                Ipv4RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 0, 1, 1, 0,
+                                CLASSIFY_TABLE_INDEX, 1)),
+                api, requestCaptor);
+    }
+
+    @Test
+    public void testWriteHopList(
+            @InjectTestData(resourcePath = "/ipv4/multiHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH) StaticRoutes route)
+            throws WriteFailedException {
+        final Route route1 = getIpv4RouteWithId(route, 1L);
+        noMappingDefined(mappingContext, namesFactory.uniqueRouteName(ROUTE_PROTOCOL_NAME, route1), "route-context");
+
+        customizer.writeCurrentAttributes(validId, route1, writeContext);
+        verifyInvocation(2,
+                ImmutableList.of(
+                        desiredFlaglessResult(1, 0, 1, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24,
+                                Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 2, 1, 1, 0,
+                                CLASSIFY_TABLE_INDEX, 1),
+                        desiredFlaglessResult(1, 0, 1, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24,
+                                Ipv4RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 3, 1, 1, 0,
+                                CLASSIFY_TABLE_INDEX, 1)), api,
+                requestCaptor);
+
+        verify(routeHopContext, times(1))
+                .addChild(
+                        namesFactory.uniqueRouteName(ROUTE_PROTOCOL_NAME, route1), 1,
+                        namesFactory.uniqueRouteHopName(getHopWithId(route1, 1)),
+                        mappingContext);
+        verify(routeHopContext, times(1))
+                .addChild(
+                        namesFactory.uniqueRouteName(ROUTE_PROTOCOL_NAME, route1), 2,
+                        namesFactory.uniqueRouteHopName(getHopWithId(route1, 2)),
+                        mappingContext);
+    }
+
+    @Test
+    public void testWriteSpecialHop(
+            @InjectTestData(resourcePath = "/ipv4/specialHopRouteBlackhole.json", id = STATIC_ROUTE_PATH) StaticRoutes route)
+            throws WriteFailedException {
+        final Route route1 = getIpv4RouteWithId(route, 1L);
+        noMappingDefined(mappingContext, namesFactory.uniqueRouteName(ROUTE_PROTOCOL_NAME, route1), "route-context");
+
+        customizer.writeCurrentAttributes(validId, route1, writeContext);
+        verifyInvocation(1, ImmutableList
+                        .of(desiredSpecialResult(1, 0, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24, 1, 0, 0, 0)), api,
+                requestCaptor);
+    }
+
+    @Test
+    public void testUpdate(
+            @InjectTestData(resourcePath = "/ipv4/specialHopRouteBlackhole.json", id = STATIC_ROUTE_PATH) StaticRoutes route) {
+        try {
+            customizer.updateCurrentAttributes(validId, new RouteBuilder().build(), getIpv4RouteWithId(route, 1L),
+                    writeContext);
+        } catch (WriteFailedException e) {
+            assertTrue(e.getCause() instanceof UnsupportedOperationException);
+            verifyNotInvoked(api);
+            return;
+        }
+        fail("Test should have thrown exception");
+    }
+
+
+    @Test
+    public void testDeleteSingleHop(
+            @InjectTestData(resourcePath = "/ipv4/simpleHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH) StaticRoutes route)
+            throws WriteFailedException {
+        customizer.deleteCurrentAttributes(validId, getIpv4RouteWithId(route, 1L), writeContext);
+        verifyInvocation(1, ImmutableList
+                .of(desiredFlaglessResult(0, 0, 0, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24,
+                        Ipv4RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX,
+                        0, 1, 1, 0, CLASSIFY_TABLE_INDEX, 1)), api, requestCaptor);
+    }
+
+    @Test
+    public void testDeleteHopList(
+            @InjectTestData(resourcePath = "/ipv4/multiHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH) StaticRoutes route)
+            throws WriteFailedException {
+        final Route route1 = getIpv4RouteWithId(route, 1L);
+        noMappingDefined(mappingContext, namesFactory.uniqueRouteName(ROUTE_PROTOCOL_NAME, route1), "route-context");
+
+        customizer.deleteCurrentAttributes(validId, route1, writeContext);
+        verifyInvocation(2,
+                ImmutableList.of(
+                        desiredFlaglessResult(0, 0, 1, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24,
+                                Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 2, 1, 1, 0,
+                                CLASSIFY_TABLE_INDEX, 1),
+                        desiredFlaglessResult(0, 0, 1, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24,
+                                new byte[]{-64, -88, 2, 2}, INTERFACE_INDEX, 3, 1, 1, 0,
+                                CLASSIFY_TABLE_INDEX, 1)), api, requestCaptor);
+
+        verify(routeHopContext, times(1))
+                .removeChild(
+                        namesFactory.uniqueRouteName(ROUTE_PROTOCOL_NAME, route1),
+                        namesFactory.uniqueRouteHopName(getHopWithId(route1, 1)),
+                        mappingContext);
+        verify(routeHopContext, times(1))
+                .removeChild(
+                        namesFactory.uniqueRouteName(ROUTE_PROTOCOL_NAME, route1),
+                        namesFactory.uniqueRouteHopName(getHopWithId(route1, 2)),
+                        mappingContext);
+    }
+
+    @Test
+    public void testDeleteSpecialHop(
+            @InjectTestData(resourcePath = "/ipv4/specialHopRouteBlackhole.json", id = STATIC_ROUTE_PATH) StaticRoutes route)
+            throws WriteFailedException {
+        customizer.deleteCurrentAttributes(validId, getIpv4RouteWithId(route, 1L), writeContext);
+
+        verifyInvocation(1,
+                ImmutableList.of(desiredSpecialResult(0, 0, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24, 1, 0, 0, 0)), api,
+                requestCaptor);
+    }
+}
diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/Ipv6RouteCustomizerTest.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/Ipv6RouteCustomizerTest.java
new file mode 100644 (file)
index 0000000..c776ca7
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.write;
+
+import static io.fd.hc2vpp.routing.helpers.InterfaceTestHelper.INTERFACE_INDEX;
+import static io.fd.hc2vpp.routing.helpers.InterfaceTestHelper.INTERFACE_NAME;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.google.common.collect.ImmutableList;
+import io.fd.hc2vpp.common.test.write.WriterCustomizerTest;
+import io.fd.hc2vpp.common.translate.util.MultiNamingContext;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.Ipv6RouteData;
+import io.fd.hc2vpp.routing.helpers.ClassifyTableTestHelper;
+import io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper;
+import io.fd.hc2vpp.routing.helpers.SchemaContextTestHelper;
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.test.tools.HoneycombTestRunner;
+import io.fd.honeycomb.test.tools.annotations.InjectTestData;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.IpAddDelRoute;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.StaticRoutes1;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.Ipv6;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.RoutingProtocols;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocol;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocolKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+@RunWith(HoneycombTestRunner.class)
+public class Ipv6RouteCustomizerTest extends WriterCustomizerTest
+        implements RoutingRequestTestHelper, ClassifyTableTestHelper, SchemaContextTestHelper {
+
+    @Captor
+    private ArgumentCaptor<IpAddDelRoute> requestCaptor;
+
+    @Mock
+    private VppClassifierContextManager classifyManager;
+
+    @Mock
+    private MultiNamingContext routeHopContext;
+
+    private NamingContext interfaceContext;
+    private NamingContext routeContext;
+    private NamingContext routingProtocolContext;
+    private Ipv6RouteCustomizer customizer;
+
+    private InstanceIdentifier<Route> validId;
+
+    @Override
+    protected void setUpTest() throws Exception {
+        interfaceContext = new NamingContext("interface", "interface-context");
+        routeContext = new NamingContext("interface", "interface-context");
+        routingProtocolContext = new NamingContext("routing-protocol", "routing-protocol-context");
+        customizer =
+                new Ipv6RouteCustomizer(api, interfaceContext, routeContext, routingProtocolContext, routeHopContext,
+                        classifyManager);
+
+        validId = InstanceIdentifier.create(RoutingProtocols.class)
+                .child(RoutingProtocol.class, new RoutingProtocolKey(ROUTE_PROTOCOL_NAME))
+                .child(StaticRoutes.class)
+                .augmentation(StaticRoutes1.class)
+                .child(Ipv6.class)
+                .child(Route.class);
+
+        defineMapping(mappingContext, INTERFACE_NAME, INTERFACE_INDEX, "interface-context");
+        addMapping(classifyManager, CLASSIFY_TABLE_NAME, CLASSIFY_TABLE_INDEX, mappingContext);
+        defineMapping(mappingContext, ROUTE_PROTOCOL_NAME, 1, "routing-protocol-context");
+    }
+
+    @Test
+    public void testWriteSingleHop(
+            @InjectTestData(resourcePath = "/ipv6/simpleHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH) StaticRoutes route)
+            throws WriteFailedException {
+        whenAddRouteThenSuccess(api);
+        customizer.writeCurrentAttributes(validId, getIpv6RouteWithId(route, 1L), writeContext);
+        verifyInvocation(1, ImmutableList
+                .of(desiredFlaglessResult(1, 1, 0, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 64,
+                        Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 0, 1,
+                        1, 0, CLASSIFY_TABLE_INDEX, 1)), api, requestCaptor);
+    }
+
+    @Test
+    public void testWriteHopList(
+            @InjectTestData(resourcePath = "/ipv6/multiHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH) StaticRoutes route)
+            throws WriteFailedException {
+        whenAddRouteThenSuccess(api);
+        customizer.writeCurrentAttributes(validId, getIpv6RouteWithId(route, 1L), writeContext);
+        verifyInvocation(2,
+                ImmutableList.of(
+                        desiredFlaglessResult(1, 1, 1, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 64,
+                                Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 2, 1, 1, 0,
+                                CLASSIFY_TABLE_INDEX, 1),
+                        desiredFlaglessResult(1, 1, 1, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 64,
+                                Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 2, 1, 1, 0,
+                                CLASSIFY_TABLE_INDEX, 1)), api,
+                requestCaptor);
+    }
+
+    @Test
+    public void testUpdate() {
+        try {
+            customizer.updateCurrentAttributes(validId, Ipv6RouteData.IPV6_ROUTE_WITH_CLASSIFIER_BLACKHOLE_HOP,
+                    Ipv6RouteData.IPV6_ROUTE_WITH_CLASSIFIER_RECEIVE_HOP, writeContext);
+        } catch (WriteFailedException e) {
+            assertTrue(e.getCause() instanceof UnsupportedOperationException);
+            verifyNotInvoked(api);
+            return;
+        }
+        fail("Test should have thrown exception");
+    }
+
+    @Test
+    public void testDeleteSpecialHop(
+            @InjectTestData(resourcePath = "/ipv6/specialHopRouteBlackhole.json", id = STATIC_ROUTE_PATH) StaticRoutes route)
+            throws WriteFailedException {
+        whenAddRouteThenSuccess(api);
+        customizer.deleteCurrentAttributes(validId, getIpv6RouteWithId(route, 1L),
+                writeContext);
+        verifyInvocation(1, ImmutableList
+                        .of(desiredSpecialResult(0, 1, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 24, 1, 0, 0, 0)), api,
+                requestCaptor);
+    }
+
+    @Test
+    public void testDeleteSingleHop(
+            @InjectTestData(resourcePath = "/ipv6/simpleHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH) StaticRoutes route)
+            throws WriteFailedException {
+        whenAddRouteThenSuccess(api);
+        customizer.deleteCurrentAttributes(validId, getIpv6RouteWithId(route, 1L), writeContext);
+        verifyInvocation(1, ImmutableList
+                .of(desiredFlaglessResult(0, 1, 0, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 64,
+                        Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 0, 1,
+                        1, 0, CLASSIFY_TABLE_INDEX, 1)), api, requestCaptor);
+    }
+
+    @Test
+    public void testDeleteHopList(
+            @InjectTestData(resourcePath = "/ipv6/multiHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH) StaticRoutes route)
+            throws WriteFailedException {
+        whenAddRouteThenSuccess(api);
+        customizer.deleteCurrentAttributes(validId, getIpv6RouteWithId(route, 1L), writeContext);
+        verifyInvocation(2,
+                ImmutableList.of(
+                        desiredFlaglessResult(0, 1, 1, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 64,
+                                Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 2, 1, 1, 0,
+                                CLASSIFY_TABLE_INDEX, 1),
+                        desiredFlaglessResult(0, 1, 1, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 64,
+                                Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 2, 1, 1, 0,
+                                CLASSIFY_TABLE_INDEX, 1)), api,
+                requestCaptor);
+    }
+
+    @Test
+    public void testWriteSpecialHop(
+            @InjectTestData(resourcePath = "/ipv6/specialHopRouteBlackhole.json", id = STATIC_ROUTE_PATH) StaticRoutes route)
+            throws WriteFailedException {
+        whenAddRouteThenSuccess(api);
+        customizer.writeCurrentAttributes(validId, getIpv6RouteWithId(route, 1L),
+                writeContext);
+        verifyInvocation(1, ImmutableList
+                        .of(desiredSpecialResult(1, 1, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 24, 1, 0, 0, 0)), api,
+                requestCaptor);
+    }
+}
diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/RoutingInstanceCustomizerTest.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/RoutingInstanceCustomizerTest.java
new file mode 100644 (file)
index 0000000..68fcba5
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.write;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.when;
+
+import io.fd.hc2vpp.common.test.write.WriterCustomizerTest;
+import io.fd.hc2vpp.routing.RoutingConfiguration;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.RoutingInstance;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.RoutingInstanceBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class RoutingInstanceCustomizerTest extends WriterCustomizerTest {
+
+    private static final String VALID_NAME = "valid-name";
+    private static final String INVALID_NAME = "invalid-name";
+
+    @Mock
+    private RoutingConfiguration configuration;
+
+    private RoutingInstanceCustomizer customizer;
+    private InstanceIdentifier<RoutingInstance> id;
+
+    private RoutingInstance validData;
+    private RoutingInstance invalidData;
+
+    @Override
+    protected void setUpTest() throws Exception {
+        customizer = new RoutingInstanceCustomizer(configuration);
+
+        when(configuration.getDefaultRoutingInstanceName()).thenReturn(VALID_NAME);
+
+        id = InstanceIdentifier.create(RoutingInstance.class);
+        validData = new RoutingInstanceBuilder().setName(VALID_NAME).build();
+        invalidData = new RoutingInstanceBuilder().setName(INVALID_NAME).build();
+    }
+
+    @Test
+    public void writeCurrentAttributesValid() throws Exception {
+        try {
+            customizer.writeCurrentAttributes(id, validData, writeContext);
+        } catch (Exception e) {
+            fail("Test should passed without exception");
+        }
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void writeCurrentAttributesInvalid() throws Exception {
+        customizer.writeCurrentAttributes(id, invalidData, writeContext);
+    }
+
+    @Test
+    public void updateCurrentAttributes() throws Exception {
+        try {
+            customizer.updateCurrentAttributes(id, validData, validData, writeContext);
+        } catch (WriteFailedException.UpdateFailedException e) {
+            assertTrue(e.getCause() instanceof UnsupportedOperationException);
+            return;
+        }
+        fail("Test should throw WriteFailedException.UpdateFailedException");
+    }
+
+    @Test
+    public void deleteCurrentAttributesValid() throws Exception {
+        try {
+            customizer.deleteCurrentAttributes(id, validData, writeContext);
+        } catch (Exception e) {
+            fail("Test should passed without exception");
+        }
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void deleteCurrentAttributesInvalid() throws Exception {
+        customizer.deleteCurrentAttributes(id, invalidData, writeContext);
+    }
+
+}
\ No newline at end of file
diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/RoutingProtocolCustomizerTest.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/RoutingProtocolCustomizerTest.java
new file mode 100644 (file)
index 0000000..d734aab
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.write;
+
+import static io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper.ROUTE_PROTOCOL_NAME;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import io.fd.hc2vpp.common.test.write.WriterCustomizerTest;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.Direct;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.Static;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocol;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.RoutingProtocolBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.RoutingProtocolVppAttr;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.RoutingProtocolVppAttrBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.VniReference;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.vpp.routing.rev161214.routing.routing.instance.routing.protocols.routing.protocol.VppProtocolAttributesBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class RoutingProtocolCustomizerTest extends WriterCustomizerTest {
+
+    private InstanceIdentifier<RoutingProtocol> validId;
+    private RoutingProtocol validData;
+    private RoutingProtocol invalidData;
+    private RoutingProtocolCustomizer customizer;
+    private NamingContext routingProtocolContext;
+
+    @Before
+    public void init() {
+        validId = InstanceIdentifier.create(RoutingProtocol.class);
+        validData = new RoutingProtocolBuilder()
+                .setName(ROUTE_PROTOCOL_NAME)
+                .setType(Static.class)
+                .addAugmentation(RoutingProtocolVppAttr.class, new RoutingProtocolVppAttrBuilder()
+                        .setVppProtocolAttributes(new VppProtocolAttributesBuilder()
+                                .setPrimaryVrf(new VniReference(1L))
+                                .build())
+                        .build())
+                .build();
+
+        invalidData = new RoutingProtocolBuilder()
+                .setType(Direct.class)
+                .build();
+
+        routingProtocolContext = new NamingContext("routing-protocol", "routing-protocol-context");
+        customizer = new RoutingProtocolCustomizer(routingProtocolContext);
+    }
+
+    @Test
+    public void testWriteIsStatic() throws WriteFailedException {
+        noMappingDefined(mappingContext, ROUTE_PROTOCOL_NAME, "routing-protocol-context");
+        try {
+            customizer.writeCurrentAttributes(validId, validData, writeContext);
+        } catch (Exception e) {
+            fail("Test should have passed without throwing exception");
+        }
+    }
+
+    @Test
+    public void testWriteIsStaticAllreadyExist() throws WriteFailedException {
+        defineMapping(mappingContext, ROUTE_PROTOCOL_NAME, 1, "routing-protocol-context");
+        try {
+            customizer.writeCurrentAttributes(validId, validData, writeContext);
+        } catch (Exception e) {
+            assertTrue(e instanceof IllegalStateException);
+            return;
+        }
+        fail("Test should have thrown exception");
+    }
+
+    @Test
+    public void testWriteIsntStatic() throws WriteFailedException {
+        try {
+            customizer.writeCurrentAttributes(validId, invalidData, writeContext);
+        } catch (Exception e) {
+            assertTrue(e instanceof IllegalArgumentException);
+            return;
+        }
+        fail("Test should have thrown exception");
+    }
+
+    @Test
+    public void testUpdate() throws WriteFailedException {
+        try {
+            customizer.updateCurrentAttributes(validId, validData, validData, writeContext);
+        } catch (Exception e) {
+            assertTrue(e.getCause() instanceof UnsupportedOperationException);
+            return;
+        }
+        fail("Test should have thrown exception");
+    }
+}
diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/MultipathHopRequestFactoryIpv4Test.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/MultipathHopRequestFactoryIpv4Test.java
new file mode 100644 (file)
index 0000000..43d01ab
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.write.factory;
+
+
+import static org.junit.Assert.assertEquals;
+
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.Ipv4RouteData;
+import io.fd.hc2vpp.routing.helpers.ClassifyTableTestHelper;
+import io.fd.hc2vpp.routing.helpers.InterfaceTestHelper;
+import io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper;
+import io.fd.hc2vpp.routing.helpers.SchemaContextTestHelper;
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.test.tools.HoneycombTestRunner;
+import io.fd.honeycomb.test.tools.annotations.InjectTestData;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.vpp.jvpp.core.dto.IpAddDelRoute;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.NextHopList;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.route.next.hop.options.next.hop.list.next.hop.list.NextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes;
+
+@RunWith(HoneycombTestRunner.class)
+public class MultipathHopRequestFactoryIpv4Test
+        implements RoutingRequestTestHelper, ClassifyTableTestHelper, SchemaContextTestHelper, InterfaceTestHelper {
+
+    @Mock
+    private VppClassifierContextManager classifierContextManager;
+
+    @Mock
+    private MappingContext mappingContext;
+
+    @InjectTestData(resourcePath = "/ipv4/multiHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH)
+    private StaticRoutes ipv4StaticRoutesWithClassifier;
+
+    @InjectTestData(resourcePath = "/ipv4/multiHopRouteWithoutClassifier.json", id = STATIC_ROUTE_PATH)
+    private StaticRoutes ipv4StaticRoutesWithoutClassifier;
+
+    private Route ipv4MutlipathRouteWithClassifier;
+    private NextHop ipv4nextHopWithClassifier;
+
+    private Route ipv4MutlipathRouteWithoutClassifier;
+    private NextHop ipv4nextHopWithoutClassifier;
+
+    private NamingContext interfaceContext;
+    private NamingContext routingProtocolContext;
+    private MultipathHopRequestFactory factory;
+
+    @Before
+    public void init() {
+        MockitoAnnotations.initMocks(this);
+        interfaceContext = new NamingContext("interface", "interface-context");
+        routingProtocolContext = new NamingContext("routing-protocol", "routing-protocol-context");
+        factory = MultipathHopRequestFactory
+                .forContexts(classifierContextManager, interfaceContext, routingProtocolContext);
+
+        addMapping(classifierContextManager, CLASSIFY_TABLE_NAME, CLASSIFY_TABLE_INDEX, mappingContext);
+        defineMapping(mappingContext, INTERFACE_NAME, INTERFACE_INDEX, "interface-context");
+        defineMapping(mappingContext, ROUTE_PROTOCOL_NAME, 1, "routing-protocol-context");
+
+        ipv4MutlipathRouteWithClassifier = getIpv4RouteWithId(ipv4StaticRoutesWithClassifier, 1L);
+        final List<NextHop> ipv4HopsClassified =
+                NextHopList.class.cast(ipv4MutlipathRouteWithClassifier.getNextHopOptions()).getNextHopList()
+                        .getNextHop();
+        ipv4nextHopWithClassifier =
+                ipv4HopsClassified.stream().filter(nextHop -> nextHop.getId() == 1L).findFirst().get();
+
+        ipv4MutlipathRouteWithoutClassifier = getIpv4RouteWithId(ipv4StaticRoutesWithoutClassifier, 1L);
+        final List<NextHop> ipv4HopsNonClassified =
+                NextHopList.class.cast(ipv4MutlipathRouteWithClassifier.getNextHopOptions()).getNextHopList()
+                        .getNextHop();
+        ipv4nextHopWithoutClassifier =
+                ipv4HopsNonClassified.stream().filter(nextHop -> nextHop.getId() == 1L).findFirst().get();
+    }
+
+    @Test
+    public void testIpv4WithClassifier() {
+        final IpAddDelRoute request =
+                factory.createIpv4MultipathHopRequest(false, ROUTE_PROTOCOL_NAME, ipv4MutlipathRouteWithClassifier,
+                        ipv4nextHopWithClassifier,
+                        mappingContext);
+
+        assertEquals(desiredFlaglessResult(0, 0, 1, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24,
+                Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 2, 1, 1, 0, CLASSIFY_TABLE_INDEX, 1), request);
+    }
+
+    @Test
+    public void testIpv4WithoutClassifier() {
+        final IpAddDelRoute request =
+                factory.createIpv4MultipathHopRequest(false, ROUTE_PROTOCOL_NAME, ipv4MutlipathRouteWithoutClassifier,
+                        ipv4nextHopWithoutClassifier,
+                        mappingContext);
+
+        assertEquals(
+                desiredFlaglessResult(0, 0, 1, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24,
+                        Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 2, 1, 1, 0, 0, 0), request);
+    }
+}
diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/MultipathHopRequestFactoryIpv6Test.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/MultipathHopRequestFactoryIpv6Test.java
new file mode 100644 (file)
index 0000000..9fc5fae
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.write.factory;
+
+import static org.junit.Assert.assertEquals;
+
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.Ipv6RouteData;
+import io.fd.hc2vpp.routing.helpers.ClassifyTableTestHelper;
+import io.fd.hc2vpp.routing.helpers.InterfaceTestHelper;
+import io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper;
+import io.fd.hc2vpp.routing.helpers.SchemaContextTestHelper;
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.test.tools.HoneycombTestRunner;
+import io.fd.honeycomb.test.tools.annotations.InjectTestData;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.vpp.jvpp.core.dto.IpAddDelRoute;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.NextHopList;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.route.next.hop.options.next.hop.list.next.hop.list.NextHop;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes;
+
+@RunWith(HoneycombTestRunner.class)
+public class MultipathHopRequestFactoryIpv6Test
+        implements RoutingRequestTestHelper, ClassifyTableTestHelper, InterfaceTestHelper, SchemaContextTestHelper {
+
+    @Mock
+    private VppClassifierContextManager classifierContextManager;
+
+    @Mock
+    private MappingContext mappingContext;
+
+    @InjectTestData(resourcePath = "/ipv6/multiHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH)
+    private StaticRoutes ipv6StaticRoutesWithClassifier;
+
+    @InjectTestData(resourcePath = "/ipv6/multiHopRouteWithoutClassifier.json", id = STATIC_ROUTE_PATH)
+    private StaticRoutes ipv6StaticRoutesWithoutClassifier;
+
+    private Route ipv6MultipathRouteWithClassifier;
+    private NextHop ipv6nextHopForClassified;
+
+    private Route ipv6MultipathRouteWithoutClassifier;
+    private NextHop ipv6nextHopForNonClassified;
+
+    private NamingContext interfaceContext;
+    private NamingContext routingProtocolContext;
+    private MultipathHopRequestFactory factory;
+
+    @Before
+    public void init() {
+        MockitoAnnotations.initMocks(this);
+        interfaceContext = new NamingContext("interface", "interface-context");
+        routingProtocolContext = new NamingContext("routing-protocol", "routing-protocol-context");
+        factory = MultipathHopRequestFactory
+                .forContexts(classifierContextManager, interfaceContext, routingProtocolContext);
+
+        addMapping(classifierContextManager, CLASSIFY_TABLE_NAME, CLASSIFY_TABLE_INDEX, mappingContext);
+        defineMapping(mappingContext, INTERFACE_NAME, INTERFACE_INDEX, "interface-context");
+        defineMapping(mappingContext, ROUTE_PROTOCOL_NAME, 1, "routing-protocol-context");
+
+        ipv6MultipathRouteWithClassifier = getIpv6RouteWithId(ipv6StaticRoutesWithClassifier, 1L);
+        ipv6MultipathRouteWithoutClassifier = getIpv6RouteWithId(ipv6StaticRoutesWithoutClassifier, 1L);
+
+        final List<NextHop> ipv6HopsClassified =
+                NextHopList.class.cast(ipv6MultipathRouteWithClassifier.getNextHopOptions()).getNextHopList()
+                        .getNextHop();
+
+        final List<NextHop> ipv6HopsNonClassified =
+                NextHopList.class.cast(ipv6MultipathRouteWithoutClassifier.getNextHopOptions()).getNextHopList()
+                        .getNextHop();
+
+        ipv6nextHopForClassified = ipv6HopsClassified.stream()
+                .filter(nextHop -> nextHop.getId() == 1L)
+                .findFirst().get();
+        ipv6nextHopForNonClassified = ipv6HopsNonClassified.stream()
+                .filter(nextHop -> nextHop.getId() == 1L)
+                .findFirst().get();
+    }
+
+    @Test
+    public void testIpv6WithClassifier() {
+        final IpAddDelRoute request =
+                factory.createIpv6MultipathHopRequest(false, ROUTE_PROTOCOL_NAME, ipv6MultipathRouteWithClassifier,
+                        ipv6nextHopForClassified,
+                        mappingContext);
+
+        assertEquals(
+                desiredFlaglessResult(0, 1, 1, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 64,
+                        Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 2, 1, 1, 0, CLASSIFY_TABLE_INDEX, 1),
+                request);
+    }
+
+    @Test
+    public void testIpv6WithoutClassifier() {
+        final IpAddDelRoute request =
+                factory.createIpv6MultipathHopRequest(false, ROUTE_PROTOCOL_NAME, ipv6MultipathRouteWithoutClassifier,
+                        ipv6nextHopForNonClassified,
+                        mappingContext);
+
+        assertEquals(
+                desiredFlaglessResult(0, 1, 1, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 64,
+                        Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 2, 1, 1, 0, 0, 0), request);
+    }
+
+
+}
diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/SimpleHopRequestFactoryIpv4Test.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/SimpleHopRequestFactoryIpv4Test.java
new file mode 100644 (file)
index 0000000..cfb352d
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.write.factory;
+
+import static org.junit.Assert.assertEquals;
+
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.Ipv4RouteData;
+import io.fd.hc2vpp.routing.helpers.ClassifyTableTestHelper;
+import io.fd.hc2vpp.routing.helpers.InterfaceTestHelper;
+import io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper;
+import io.fd.hc2vpp.routing.helpers.SchemaContextTestHelper;
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.test.tools.HoneycombTestRunner;
+import io.fd.honeycomb.test.tools.annotations.InjectTestData;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.vpp.jvpp.core.dto.IpAddDelRoute;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.StaticRoutes1;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes;
+
+@RunWith(HoneycombTestRunner.class)
+public class SimpleHopRequestFactoryIpv4Test
+        implements RoutingRequestTestHelper, ClassifyTableTestHelper, InterfaceTestHelper, SchemaContextTestHelper {
+    @Mock
+    private VppClassifierContextManager classifierContextManager;
+
+    @Mock
+    private MappingContext mappingContext;
+
+    @InjectTestData(resourcePath = "/ipv4/simpleHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH)
+    private StaticRoutes ipv4StaticRouteWithClassifier;
+
+    @InjectTestData(resourcePath = "/ipv4/simpleHopRouteWithoutClassifier.json", id = STATIC_ROUTE_PATH)
+    private StaticRoutes ipv4StaticRouteWithoutClassifier;
+
+    private NamingContext interfaceContext;
+    private NamingContext routingProtocolContext;
+    private SimpleHopRequestFactory factory;
+
+    @Before
+    public void init() {
+        MockitoAnnotations.initMocks(this);
+        interfaceContext = new NamingContext("interface", "interface-context");
+        routingProtocolContext = new NamingContext("routing-protocol", "routing-protocol-context");
+        factory =
+                SimpleHopRequestFactory.forContexts(classifierContextManager, interfaceContext, routingProtocolContext);
+
+        addMapping(classifierContextManager, CLASSIFY_TABLE_NAME, CLASSIFY_TABLE_INDEX, mappingContext);
+        defineMapping(mappingContext, INTERFACE_NAME, INTERFACE_INDEX, "interface-context");
+        defineMapping(mappingContext, ROUTE_PROTOCOL_NAME, 1, "routing-protocol-context");
+    }
+
+    @Test
+    public void testIpv4WithClassifier() {
+        final IpAddDelRoute request =
+                factory.createIpv4SimpleHopRequest(false, ROUTE_PROTOCOL_NAME,
+                        getIpv4RouteWithId(ipv4StaticRouteWithClassifier, 1L),
+                        mappingContext);
+
+        assertEquals(desiredFlaglessResult(0, 0, 0, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24,
+                Ipv4RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 0,
+                1, 1, 0, CLASSIFY_TABLE_INDEX, 1), request);
+    }
+
+    @Test
+    public void testIpv4WithoutClassifier() {
+        final IpAddDelRoute request =
+                factory.createIpv4SimpleHopRequest(false, ROUTE_PROTOCOL_NAME,
+                        ipv4StaticRouteWithoutClassifier.getAugmentation(StaticRoutes1.class).getIpv4().getRoute()
+                                .get(0), mappingContext);
+
+        assertEquals(
+                desiredFlaglessResult(0, 0, 0, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24,
+                        Ipv4RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 0, 1, 1, 0, 0, 0), request);
+    }
+}
diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/SimpleHopRequestFactoryIpv6Test.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/SimpleHopRequestFactoryIpv6Test.java
new file mode 100644 (file)
index 0000000..e95a667
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.write.factory;
+
+import static org.junit.Assert.assertEquals;
+
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.routing.Ipv6RouteData;
+import io.fd.hc2vpp.routing.helpers.ClassifyTableTestHelper;
+import io.fd.hc2vpp.routing.helpers.InterfaceTestHelper;
+import io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper;
+import io.fd.hc2vpp.routing.helpers.SchemaContextTestHelper;
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.test.tools.HoneycombTestRunner;
+import io.fd.honeycomb.test.tools.annotations.InjectTestData;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.vpp.jvpp.core.dto.IpAddDelRoute;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.StaticRoutes1;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes;
+
+@RunWith(HoneycombTestRunner.class)
+public class SimpleHopRequestFactoryIpv6Test
+        implements RoutingRequestTestHelper, ClassifyTableTestHelper, InterfaceTestHelper, SchemaContextTestHelper {
+
+    @Mock
+    private VppClassifierContextManager classifierContextManager;
+
+    @Mock
+    private MappingContext mappingContext;
+
+    @InjectTestData(resourcePath = "/ipv6/simpleHopRouteWithClassifier.json", id = STATIC_ROUTE_PATH)
+    private StaticRoutes ipv6StaticRouteWithClassifier;
+
+    @InjectTestData(resourcePath = "/ipv6/simpleHopRouteWithoutClassifier.json", id = STATIC_ROUTE_PATH)
+    private StaticRoutes ipv6StaticRouteWithoutClassifier;
+
+    private NamingContext interfaceContext;
+    private NamingContext routingProtocolContext;
+    private SimpleHopRequestFactory factory;
+
+    @Before
+    public void init() {
+        MockitoAnnotations.initMocks(this);
+        interfaceContext = new NamingContext("interface", "interface-context");
+        routingProtocolContext = new NamingContext("routing-protocol", "routing-protocol-context");
+        factory =
+                SimpleHopRequestFactory.forContexts(classifierContextManager, interfaceContext, routingProtocolContext);
+
+        addMapping(classifierContextManager, CLASSIFY_TABLE_NAME, CLASSIFY_TABLE_INDEX, mappingContext);
+        defineMapping(mappingContext, INTERFACE_NAME, INTERFACE_INDEX, "interface-context");
+        defineMapping(mappingContext, ROUTE_PROTOCOL_NAME, 1, "routing-protocol-context");
+    }
+
+    @Test
+    public void testIpv6WithClassifier() {
+        final IpAddDelRoute request =
+                factory.createIpv6SimpleHopRequest(false, ROUTE_PROTOCOL_NAME,
+                        ipv6StaticRouteWithClassifier.getAugmentation(StaticRoutes1.class).getIpv6().getRoute().get(0),
+                        mappingContext);
+
+        assertEquals(desiredFlaglessResult(0, 1, 0, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 64,
+                Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 0, 1,
+                1, 0, CLASSIFY_TABLE_INDEX, 1), request);
+    }
+
+    @Test
+    public void testIpv6WithoutClassifier() {
+        final IpAddDelRoute request =
+                factory.createIpv6SimpleHopRequest(false, ROUTE_PROTOCOL_NAME,
+                        ipv6StaticRouteWithoutClassifier.getAugmentation(StaticRoutes1.class).getIpv6().getRoute()
+                                .get(0),
+                        mappingContext);
+
+        assertEquals(desiredFlaglessResult(0, 1, 0, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 64,
+                Ipv6RouteData.SECOND_ADDRESS_AS_ARRAY, INTERFACE_INDEX, 0, 1, 1, 0, 0, 0), request);
+    }
+}
diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/SpecialNextHopRequestFactoryIpv4Test.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/SpecialNextHopRequestFactoryIpv4Test.java
new file mode 100644 (file)
index 0000000..dd93de5
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.write.factory;
+
+import static org.junit.Assert.assertEquals;
+import static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.SpecialNextHopGrouping.SpecialNextHop.Prohibit;
+import static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.SpecialNextHopGrouping.SpecialNextHop.Receive;
+import static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.SpecialNextHopGrouping.SpecialNextHop.Unreachable;
+
+import io.fd.hc2vpp.routing.Ipv4RouteData;
+import io.fd.hc2vpp.routing.helpers.ClassifyTableTestHelper;
+import io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper;
+import io.fd.hc2vpp.routing.helpers.SchemaContextTestHelper;
+import io.fd.hc2vpp.routing.write.trait.RouteRequestProducer;
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.test.tools.HoneycombTestRunner;
+import io.fd.honeycomb.test.tools.annotations.InjectTestData;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.vpp.jvpp.core.dto.IpAddDelRoute;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.StaticRoutes1;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv4.unicast.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv4.Route;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.SpecialNextHopGrouping;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes;
+
+@RunWith(HoneycombTestRunner.class)
+public class SpecialNextHopRequestFactoryIpv4Test
+        implements RouteRequestProducer, RoutingRequestTestHelper, ClassifyTableTestHelper,
+        SchemaContextTestHelper {
+
+    @Mock
+    private VppClassifierContextManager classifierContextManager;
+
+    @Mock
+    private MappingContext mappingContext;
+
+    private SpecialNextHopRequestFactory factory;
+
+    @Before
+    public void init() {
+        MockitoAnnotations.initMocks(this);
+        factory = SpecialNextHopRequestFactory.forClassifierContext(classifierContextManager);
+
+        addMapping(classifierContextManager, CLASSIFY_TABLE_NAME, CLASSIFY_TABLE_INDEX, mappingContext);
+    }
+
+    @Test
+    public void testIpv4WithClassifierBlackhole(
+            @InjectTestData(resourcePath = "/ipv4/specialHopRouteBlackhole.json", id = STATIC_ROUTE_PATH)
+                    StaticRoutes routes) {
+        final IpAddDelRoute request =
+                factory.createIpv4SpecialHopRequest(true, extractSingleRoute(routes, 1L), mappingContext,
+                        SpecialNextHopGrouping.SpecialNextHop.Blackhole);
+
+        assertEquals(desiredSpecialResult(1, 0, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24, 1, 0, 0, 0), request);
+    }
+
+    @Test
+    public void testIpv4WithClassifierReceive(
+            @InjectTestData(resourcePath = "/ipv4/specialHopRouteReceive.json", id = STATIC_ROUTE_PATH)
+                    StaticRoutes routes) {
+        final IpAddDelRoute request =
+                factory.createIpv4SpecialHopRequest(true, extractSingleRoute(routes, 1L), mappingContext, Receive);
+
+        assertEquals(desiredSpecialResult(1, 0, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24, 0, 1, 0, 0), request);
+    }
+
+    @Test
+    public void testIpv4WithClassifierUnreach(
+            @InjectTestData(resourcePath = "/ipv4/specialHopRouteUnreachable.json", id = STATIC_ROUTE_PATH)
+                    StaticRoutes routes) {
+        final IpAddDelRoute request =
+                factory.createIpv4SpecialHopRequest(true, extractSingleRoute(routes, 1L), mappingContext, Unreachable);
+
+        assertEquals(desiredSpecialResult(1, 0, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24, 0, 0, 1, 0), request);
+    }
+
+    @Test
+    public void testIpv4WithClassifierProhibited(
+            @InjectTestData(resourcePath = "/ipv4/specialHopRouteProhibited.json", id = STATIC_ROUTE_PATH)
+                    StaticRoutes routes) {
+        final IpAddDelRoute request =
+                factory.createIpv4SpecialHopRequest(true, extractSingleRoute(routes, 1L), mappingContext, Prohibit);
+
+        assertEquals(desiredSpecialResult(1, 0, Ipv4RouteData.FIRST_ADDRESS_AS_ARRAY, 24, 0, 0, 0, 1), request);
+    }
+
+    private Route extractSingleRoute(final StaticRoutes staticRoutes, final long id) {
+        return staticRoutes.getAugmentation(StaticRoutes1.class).getIpv4().getRoute().stream()
+                .filter(route -> route.getId() == id)
+                .collect(RWUtils.singleItemCollector());
+    }
+}
diff --git a/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/SpecialNextHopRequestFactoryIpv6Test.java b/routing/routing-impl/src/test/java/io/fd/hc2vpp/routing/write/factory/SpecialNextHopRequestFactoryIpv6Test.java
new file mode 100644 (file)
index 0000000..b129eef
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.routing.write.factory;
+
+import static org.junit.Assert.assertEquals;
+import static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.SpecialNextHopGrouping.SpecialNextHop.Blackhole;
+import static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.SpecialNextHopGrouping.SpecialNextHop.Prohibit;
+import static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.SpecialNextHopGrouping.SpecialNextHop.Receive;
+import static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.SpecialNextHopGrouping.SpecialNextHop.Unreachable;
+
+import io.fd.hc2vpp.routing.Ipv6RouteData;
+import io.fd.hc2vpp.routing.helpers.ClassifyTableTestHelper;
+import io.fd.hc2vpp.routing.helpers.RoutingRequestTestHelper;
+import io.fd.hc2vpp.routing.helpers.SchemaContextTestHelper;
+import io.fd.hc2vpp.v3po.vppclassifier.VppClassifierContextManager;
+import io.fd.honeycomb.test.tools.HoneycombTestRunner;
+import io.fd.honeycomb.test.tools.annotations.InjectTestData;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.vpp.jvpp.core.dto.IpAddDelRoute;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.StaticRoutes1;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ipv6.unicast.routing.rev140525.routing.routing.instance.routing.protocols.routing.protocol._static.routes.ipv6.Route;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.routing.rev140524.routing.routing.instance.routing.protocols.routing.protocol.StaticRoutes;
+
+@RunWith(HoneycombTestRunner.class)
+public class SpecialNextHopRequestFactoryIpv6Test
+        implements RoutingRequestTestHelper, ClassifyTableTestHelper, SchemaContextTestHelper {
+
+    @Mock
+    private VppClassifierContextManager classifierContextManager;
+
+    @Mock
+    private MappingContext mappingContext;
+
+    private SpecialNextHopRequestFactory factory;
+
+    @Before
+    public void init() {
+        MockitoAnnotations.initMocks(this);
+        factory = SpecialNextHopRequestFactory.forClassifierContext(classifierContextManager);
+
+        addMapping(classifierContextManager, CLASSIFY_TABLE_NAME, CLASSIFY_TABLE_INDEX, mappingContext);
+    }
+
+    @Test
+    public void testIpv6Blackhole(
+            @InjectTestData(resourcePath = "/ipv6/specialHopRouteBlackhole.json", id = STATIC_ROUTE_PATH)
+                    StaticRoutes routes) {
+        final IpAddDelRoute request =
+                factory.createIpv6SpecialHopRequest(true, extractSingleRoute(routes, 1L), mappingContext, Blackhole);
+
+        assertEquals(desiredSpecialResult(1, 1, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 24, 1, 0, 0, 0),
+                request);
+    }
+
+    @Test
+    public void testIpv6Receive(
+            @InjectTestData(resourcePath = "/ipv6/specialHopRouteReceive.json", id = STATIC_ROUTE_PATH)
+                    StaticRoutes routes) {
+        final IpAddDelRoute request =
+                factory.createIpv6SpecialHopRequest(true, extractSingleRoute(routes, 1L), mappingContext, Receive);
+
+        assertEquals(desiredSpecialResult(1, 1, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 24, 0, 1, 0, 0), request);
+    }
+
+    @Test
+    public void testIpv6Unreach(
+            @InjectTestData(resourcePath = "/ipv6/specialHopRouteUnreachable.json", id = STATIC_ROUTE_PATH)
+                    StaticRoutes routes) {
+        final IpAddDelRoute request =
+                factory.createIpv6SpecialHopRequest(true, extractSingleRoute(routes, 1L), mappingContext, Unreachable);
+
+        assertEquals(desiredSpecialResult(1, 1, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 24, 0, 0, 1, 0), request);
+    }
+
+    @Test
+    public void testIpv6Prohibited(
+            @InjectTestData(resourcePath = "/ipv6/specialHopRouteProhibited.json", id = STATIC_ROUTE_PATH)
+                    StaticRoutes routes) {
+        final IpAddDelRoute request =
+                factory.createIpv6SpecialHopRequest(true, extractSingleRoute(routes, 1L), mappingContext, Prohibit);
+
+        assertEquals(desiredSpecialResult(1, 1, Ipv6RouteData.FIRST_ADDRESS_AS_ARRAY, 24, 0, 0, 0, 1), request);
+    }
+
+    private Route extractSingleRoute(final StaticRoutes staticRoutes, final long id) {
+        return staticRoutes.getAugmentation(StaticRoutes1.class).getIpv6().getRoute().stream()
+                .filter(route -> route.getId() == id).collect(
+                        RWUtils.singleItemCollector());
+    }
+
+}
diff --git a/routing/routing-impl/src/test/resources/init/config-data.json b/routing/routing-impl/src/test/resources/init/config-data.json
new file mode 100644 (file)
index 0000000..05a888b
--- /dev/null
@@ -0,0 +1,109 @@
+{
+  "routing": {
+    "routing-instance": {
+      "name": "routing-3",
+      "router-id": "192.168.2.1",
+      "routing-protocols": {
+        "routing-protocol": [
+          {
+            "name": "test-routing-protocol",
+            "type": "static",
+            "vpp-protocol-attributes": {
+              "primary-vrf": "1"
+            },
+            "static-routes": {
+              "ipv4": {
+                "route": [
+                  {
+                    "id": 1,
+                    "destination-prefix": "192.168.2.3/32",
+                    "next-hop": "192.168.2.8",
+                    "outgoing-interface": "local0",
+                    "vpp-ipv4-route": {
+                      "secondary-vrf": "1"
+                    }
+                  },
+                  {
+                    "id": 2,
+                    "destination-prefix": "192.168.2.4/32",
+                    "vpp-ipv4-route": {
+                      "secondary-vrf": "1"
+                    },
+                    "next-hop-list": {
+                      "next-hop": [
+                        {
+                          "id": "1",
+                          "address": "192.168.2.5",
+                          "outgoing-interface": "local0",
+                          "weight": "1"
+                        },
+                        {
+                          "id": "2",
+                          "address": "192.168.2.6",
+                          "outgoing-interface": "local0",
+                          "weight": "2"
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "id": 3,
+                    "destination-prefix": "192.168.2.5/32",
+                    "special-next-hop": "receive"
+                  }
+                ]
+              },
+              "ipv6": {
+                "route": [
+                  {
+                    "id": 1,
+                    "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0001/64",
+                    "next-hop": "2001:0db8:0a0b:12f0:0000:0000:0000:0002",
+                    "outgoing-interface": "GigabitEthernet0/8/0",
+                    "vpp-ipv6-route": {
+                      "secondary-vrf": "1"
+                    }
+                  },
+                  {
+                    "id": 2,
+                    "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0008/64",
+                    "vpp-ipv6-route": {
+                      "secondary-vrf": "1"
+                    },
+                    "next-hop-list": {
+                      "next-hop": [
+                        {
+                          "id": "1",
+                          "address": "2001:0db8:0a0b:12f0:0000:0000:0000:0003",
+                          "outgoing-interface": "GigabitEthernet0/8/0",
+                          "weight": "1"
+                        },
+                        {
+                          "id": "2",
+                          "address": "2001:0db8:0a0b:12f0:0000:0000:0000:0004",
+                          "outgoing-interface": "GigabitEthernet0/8/0",
+                          "weight": "2"
+                        },
+                        {
+                          "id": "3",
+                          "address": "2001:0db8:0a0b:12f0:0000:0000:0000:0005",
+                          "outgoing-interface": "GigabitEthernet0/8/0",
+                          "weight": "3"
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "id": 3,
+                    "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0005/32",
+                    "special-next-hop": "receive"
+                  }
+                ]
+              }
+            }
+          }
+        ]
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/routing/routing-impl/src/test/resources/init/state-data.json b/routing/routing-impl/src/test/resources/init/state-data.json
new file mode 100644 (file)
index 0000000..7830c8e
--- /dev/null
@@ -0,0 +1,109 @@
+{
+  "routing-state": {
+    "routing-instance": {
+      "name": "routing-3",
+      "router-id": "192.168.2.1",
+      "routing-protocols": {
+        "routing-protocol": [
+          {
+            "name": "test-routing-protocol",
+            "type": "static",
+            "vpp-protocol-state-attributes": {
+              "primary-vrf": "1"
+            },
+            "static-routes": {
+              "ipv4": {
+                "route": [
+                  {
+                    "id": 1,
+                    "destination-prefix": "192.168.2.3/32",
+                    "next-hop": "192.168.2.8",
+                    "outgoing-interface": "local0",
+                    "vpp-ipv4-route-state": {
+                      "secondary-vrf": "1"
+                    }
+                  },
+                  {
+                    "id": 2,
+                    "destination-prefix": "192.168.2.4/32",
+                    "vpp-ipv4-route-state": {
+                      "secondary-vrf": "1"
+                    },
+                    "next-hop-list": {
+                      "next-hop": [
+                        {
+                          "id": "1",
+                          "address": "192.168.2.5",
+                          "outgoing-interface": "local0",
+                          "weight": "1"
+                        },
+                        {
+                          "id": "2",
+                          "address": "192.168.2.6",
+                          "outgoing-interface": "local0",
+                          "weight": "2"
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "id": 3,
+                    "destination-prefix": "192.168.2.5/32",
+                    "special-next-hop": "receive"
+                  }
+                ]
+              },
+              "ipv6": {
+                "route": [
+                  {
+                    "id": 1,
+                    "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0001/64",
+                    "next-hop": "2001:0db8:0a0b:12f0:0000:0000:0000:0002",
+                    "outgoing-interface": "GigabitEthernet0/8/0",
+                    "vpp-ipv6-route-state": {
+                      "secondary-vrf": "1"
+                    }
+                  },
+                  {
+                    "id": 2,
+                    "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0008/64",
+                    "vpp-ipv6-route-state": {
+                      "secondary-vrf": "1"
+                    },
+                    "next-hop-list": {
+                      "next-hop": [
+                        {
+                          "id": "1",
+                          "address": "2001:0db8:0a0b:12f0:0000:0000:0000:0003",
+                          "outgoing-interface": "GigabitEthernet0/8/0",
+                          "weight": "1"
+                        },
+                        {
+                          "id": "2",
+                          "address": "2001:0db8:0a0b:12f0:0000:0000:0000:0004",
+                          "outgoing-interface": "GigabitEthernet0/8/0",
+                          "weight": "2"
+                        },
+                        {
+                          "id": "3",
+                          "address": "2001:0db8:0a0b:12f0:0000:0000:0000:0005",
+                          "outgoing-interface": "GigabitEthernet0/8/0",
+                          "weight": "3"
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "id": 3,
+                    "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0005/32",
+                    "special-next-hop": "receive"
+                  }
+                ]
+              }
+            }
+          }
+        ]
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/routing/routing-impl/src/test/resources/ipv4/multiHopRouteWithClassifier.json b/routing/routing-impl/src/test/resources/ipv4/multiHopRouteWithClassifier.json
new file mode 100644 (file)
index 0000000..99c987e
--- /dev/null
@@ -0,0 +1,31 @@
+{
+  "static-routes": {
+    "ipv4": {
+      "route": [
+        {
+          "id": 1,
+          "destination-prefix": "192.168.2.1/24",
+          "vpp-ipv4-route": {
+            "classify-table": "classify-table-one"
+          },
+          "next-hop-list": {
+            "next-hop": [
+              {
+                "id": "1",
+                "address": "192.168.2.1",
+                "outgoing-interface": "iface",
+                "weight": "2"
+              },
+              {
+                "id": "2",
+                "address": "192.168.2.2",
+                "outgoing-interface": "iface",
+                "weight": "3"
+              }
+            ]
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/routing/routing-impl/src/test/resources/ipv4/multiHopRouteWithoutClassifier.json b/routing/routing-impl/src/test/resources/ipv4/multiHopRouteWithoutClassifier.json
new file mode 100644 (file)
index 0000000..d4d4a06
--- /dev/null
@@ -0,0 +1,30 @@
+{
+  "static-routes": {
+    "ipv4": {
+      "route": [
+        {
+          "id": 1,
+          "destination-prefix": "192.168.2.1/24",
+          "vpp-ipv4-route": {
+          },
+          "next-hop-list": {
+            "next-hop": [
+              {
+                "id": "1",
+                "address": "192.168.2.1",
+                "outgoing-interface": "iface",
+                "weight": "2"
+              },
+              {
+                "id": "2",
+                "address": "192.168.2.2",
+                "outgoing-interface": "iface",
+                "weight": "3"
+              }
+            ]
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/routing/routing-impl/src/test/resources/ipv4/simpleHopRouteWithClassifier.json b/routing/routing-impl/src/test/resources/ipv4/simpleHopRouteWithClassifier.json
new file mode 100644 (file)
index 0000000..d00d9a0
--- /dev/null
@@ -0,0 +1,17 @@
+{
+  "static-routes": {
+    "ipv4": {
+      "route": [
+        {
+          "id": 1,
+          "destination-prefix": "192.168.2.1/24",
+          "vpp-ipv4-route": {
+            "classify-table": "classify-table-one"
+          },
+          "next-hop": "192.168.2.2",
+          "outgoing-interface": "iface"
+        }
+      ]
+    }
+  }
+}
diff --git a/routing/routing-impl/src/test/resources/ipv4/simpleHopRouteWithoutClassifier.json b/routing/routing-impl/src/test/resources/ipv4/simpleHopRouteWithoutClassifier.json
new file mode 100644 (file)
index 0000000..0ef7cf7
--- /dev/null
@@ -0,0 +1,16 @@
+{
+  "static-routes": {
+    "ipv4": {
+      "route": [
+        {
+          "id": 1,
+          "destination-prefix": "192.168.2.1/24",
+          "vpp-ipv4-route": {
+          },
+          "next-hop": "192.168.2.2",
+          "outgoing-interface": "iface"
+        }
+      ]
+    }
+  }
+}
diff --git a/routing/routing-impl/src/test/resources/ipv4/specialHopRouteBlackhole.json b/routing/routing-impl/src/test/resources/ipv4/specialHopRouteBlackhole.json
new file mode 100644 (file)
index 0000000..b2ddc23
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  "static-routes": {
+    "ipv4": {
+      "route": [
+        {
+          "id": 1,
+          "destination-prefix": "192.168.2.1/24",
+          "special-next-hop": "blackhole"
+        }
+      ]
+    }
+  }
+}
diff --git a/routing/routing-impl/src/test/resources/ipv4/specialHopRouteProhibited.json b/routing/routing-impl/src/test/resources/ipv4/specialHopRouteProhibited.json
new file mode 100644 (file)
index 0000000..fe9faf4
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  "static-routes": {
+    "ipv4": {
+      "route": [
+        {
+          "id": 1,
+          "destination-prefix": "192.168.2.1/24",
+          "special-next-hop": "prohibit"
+        }
+      ]
+    }
+  }
+}
diff --git a/routing/routing-impl/src/test/resources/ipv4/specialHopRouteReceive.json b/routing/routing-impl/src/test/resources/ipv4/specialHopRouteReceive.json
new file mode 100644 (file)
index 0000000..c967aa5
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  "static-routes": {
+    "ipv4": {
+      "route": [
+        {
+          "id": 1,
+          "destination-prefix": "192.168.2.1/24",
+          "special-next-hop": "receive"
+        }
+      ]
+    }
+  }
+}
diff --git a/routing/routing-impl/src/test/resources/ipv4/specialHopRouteUnreachable.json b/routing/routing-impl/src/test/resources/ipv4/specialHopRouteUnreachable.json
new file mode 100644 (file)
index 0000000..bae467f
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  "static-routes": {
+    "ipv4": {
+      "route": [
+        {
+          "id": 1,
+          "destination-prefix": "192.168.2.1/24",
+          "special-next-hop": "unreachable"
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/routing/routing-impl/src/test/resources/ipv6/multiHopRouteWithClassifier.json b/routing/routing-impl/src/test/resources/ipv6/multiHopRouteWithClassifier.json
new file mode 100644 (file)
index 0000000..c8b1e20
--- /dev/null
@@ -0,0 +1,31 @@
+{
+  "static-routes": {
+    "ipv6": {
+      "route": [
+        {
+          "id": 1,
+          "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0001/64",
+          "vpp-ipv6-route": {
+            "classify-table": "classify-table-one"
+          },
+          "next-hop-list": {
+            "next-hop": [
+              {
+                "id": "1",
+                "address": "2001:0db8:0a0b:12f0:0000:0000:0000:0002",
+                "outgoing-interface": "iface",
+                "weight": "2"
+              },
+              {
+                "id": "2",
+                "address": "2001:0db8:0a0b:12f0:0000:0000:0000:0002",
+                "outgoing-interface": "iface",
+                "weight": "2"
+              }
+            ]
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/routing/routing-impl/src/test/resources/ipv6/multiHopRouteWithoutClassifier.json b/routing/routing-impl/src/test/resources/ipv6/multiHopRouteWithoutClassifier.json
new file mode 100644 (file)
index 0000000..2e44ebc
--- /dev/null
@@ -0,0 +1,30 @@
+{
+  "static-routes": {
+    "ipv6": {
+      "route": [
+        {
+          "id": 1,
+          "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0001/64",
+          "vpp-ipv6-route": {
+          },
+          "next-hop-list": {
+            "next-hop": [
+              {
+                "id": "1",
+                "address": "2001:0db8:0a0b:12f0:0000:0000:0000:0002",
+                "outgoing-interface": "iface",
+                "weight": "2"
+              },
+              {
+                "id": "2",
+                "address": "2001:0db8:0a0b:12f0:0000:0000:0000:0002",
+                "outgoing-interface": "iface",
+                "weight": "2"
+              }
+            ]
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/routing/routing-impl/src/test/resources/ipv6/simpleHopRouteWithClassifier.json b/routing/routing-impl/src/test/resources/ipv6/simpleHopRouteWithClassifier.json
new file mode 100644 (file)
index 0000000..c011a8d
--- /dev/null
@@ -0,0 +1,17 @@
+{
+  "static-routes": {
+    "ipv6": {
+      "route": [
+        {
+          "id": 1,
+          "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0001/64",
+          "vpp-ipv6-route": {
+            "classify-table": "classify-table-one"
+          },
+          "next-hop": "2001:0db8:0a0b:12f0:0000:0000:0000:0002",
+          "outgoing-interface": "iface"
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/routing/routing-impl/src/test/resources/ipv6/simpleHopRouteWithoutClassifier.json b/routing/routing-impl/src/test/resources/ipv6/simpleHopRouteWithoutClassifier.json
new file mode 100644 (file)
index 0000000..1cb663c
--- /dev/null
@@ -0,0 +1,16 @@
+{
+  "static-routes": {
+    "ipv6": {
+      "route": [
+        {
+          "id": 1,
+          "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0001/64",
+          "vpp-ipv6-route": {
+          },
+          "next-hop": "2001:0db8:0a0b:12f0:0000:0000:0000:0002",
+          "outgoing-interface": "iface"
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/routing/routing-impl/src/test/resources/ipv6/specialHopRouteBlackhole.json b/routing/routing-impl/src/test/resources/ipv6/specialHopRouteBlackhole.json
new file mode 100644 (file)
index 0000000..1cc3191
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  "static-routes": {
+    "ipv6": {
+      "route": [
+        {
+          "id": 1,
+          "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0001/24",
+          "special-next-hop": "blackhole"
+        }
+      ]
+    }
+  }
+}
diff --git a/routing/routing-impl/src/test/resources/ipv6/specialHopRouteProhibited.json b/routing/routing-impl/src/test/resources/ipv6/specialHopRouteProhibited.json
new file mode 100644 (file)
index 0000000..d69e817
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  "static-routes": {
+    "ipv6": {
+      "route": [
+        {
+          "id": 1,
+          "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0001/24",
+          "special-next-hop": "prohibit"
+        }
+      ]
+    }
+  }
+}
diff --git a/routing/routing-impl/src/test/resources/ipv6/specialHopRouteReceive.json b/routing/routing-impl/src/test/resources/ipv6/specialHopRouteReceive.json
new file mode 100644 (file)
index 0000000..50d447d
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  "static-routes": {
+    "ipv6": {
+      "route": [
+        {
+          "id": 1,
+          "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0001/24",
+          "special-next-hop": "receive"
+        }
+      ]
+    }
+  }
+}
diff --git a/routing/routing-impl/src/test/resources/ipv6/specialHopRouteUnreachable.json b/routing/routing-impl/src/test/resources/ipv6/specialHopRouteUnreachable.json
new file mode 100644 (file)
index 0000000..c874549
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  "static-routes": {
+    "ipv6": {
+      "route": [
+        {
+          "id": 1,
+          "destination-prefix": "2001:0db8:0a0b:12f0:0000:0000:0000:0001/24",
+          "special-next-hop": "unreachable"
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/routing/routing-impl/src/test/resources/routing.json b/routing/routing-impl/src/test/resources/routing.json
new file mode 100644 (file)
index 0000000..95f8541
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "default-routing-instance-name": "vpp-routing-instance",
+  "learned-route-name-prefix": "learned-route"
+}
\ No newline at end of file
diff --git a/routing/routing_postman_collection.json b/routing/routing_postman_collection.json
new file mode 100644 (file)
index 0000000..a3c529d
--- /dev/null
@@ -0,0 +1,242 @@
+{
+       "id": "91b6ff58-8e6f-06aa-8067-caecb9f95c88",
+       "name": "Routing",
+       "description": "",
+       "order": [
+               "c5701b6a-a684-0a4f-9991-6f1a866baddd",
+               "e8216de3-757d-ce34-87e4-8e25ee6b1f44",
+               "e3510e60-17e7-887b-6a55-5e0f651512b0",
+               "2bf3def8-ef34-fa83-0789-ecebb03f297f",
+               "ea4e8b3d-2333-6c17-1da2-32fd0b88da96",
+               "86b915a1-f85c-939a-0814-fd98b1154162",
+               "41585a9d-5067-05d8-2dc1-3ace153a70b6",
+               "6244bd7f-dedd-bd6d-45c3-00b0fd10bb21",
+               "260fce67-2d84-8557-ff03-b4371fc62cdb",
+               "c50cc4a4-a760-f91a-fe66-dd8a66d6085b",
+               "de73785a-6784-b280-a9bc-6d6e48199f09"
+       ],
+       "folders": [],
+       "timestamp": 1476089780702,
+       "owner": "658985",
+       "public": false,
+       "requests": [
+               {
+                       "id": "260fce67-2d84-8557-ff03-b4371fc62cdb",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+                       "url": "http://localhost:8183/restconf/config/ietf-routing:routing",
+                       "preRequestScript": null,
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": null,
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1476096572969,
+                       "name": "Get Routes",
+                       "description": "",
+                       "collectionId": "91b6ff58-8e6f-06aa-8067-caecb9f95c88",
+                       "responses": [],
+                       "rawModeData": "{\n\t\"routing-instance\":\n\t{\n\t\t\"name\":\"routing-1\",\n\t\t\"enabled\":\"true\",\n\t\t\"router-id\":\"192.168.2.1\",\n\t\t\"description\":\"Test routing instance\",\n\t\t\"routing-protocols\":{\n\t\t\t\"routing-protocol\":[\n\t\t\t\t{\n\t\t\t\t\t\"name\":\"test-routing-protocol\",\n\t\t\t\t\t\"description\":\"Test routing protocol\",\n\t\t\t\t\t\"enabled\":\"true\",\n\t\t\t\t\t\"type\":\"static\",\n\t\t\t\t\t\"static-routes\":{\n\t\t\t\t\t\t\"ipv4\":{\n\t\t\t\t\t\t\t\"route\":[\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"id\":1,\n\t\t\t\t\t\t\t\t\t\"description\":\"Test static route\",\n\t\t\t\t\t\t\t\t\t\"destination-prefix\":\"192.168.2.3/32\",\n\t\t\t\t\t\t\t\t\t\"next-hop\":\"192.168.2.8\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\t\n\t\t\t]\n\t\t}\n\t}\t\n}"
+               },
+               {
+                       "id": "2bf3def8-ef34-fa83-0789-ecebb03f297f",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+                       "url": "http://localhost:8183/restconf/config/ietf-routing:routing/routing-instance/vpp-routing-instance/routing-protocols/routing-protocol/test-routing-protocol-2",
+                       "preRequestScript": null,
+                       "pathVariables": {},
+                       "method": "PUT",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": null,
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1480502653953,
+                       "name": "Add multi hop ipv4",
+                       "description": "",
+                       "collectionId": "91b6ff58-8e6f-06aa-8067-caecb9f95c88",
+                       "responses": [],
+                       "rawModeData": "{\n\t\"routing-protocol\":[\n\t\t{\n\t\t\t\"name\":\"test-routing-protocol-2\",\n\t\t\t\"description\":\"Test routing protocol\",\n\t\t\t\"enabled\":\"true\",\n\t\t\t\"type\":\"static\",\n\t\t\t\"vpp-protocol-attributes\": {\n\t              \"primary-vrf\": \"2\"\n            },\n\t\t\t\"static-routes\":{\n\t\t\t\t\"ipv4\":{\n\t\t\t\t\t\"route\":{\n\t\t\t\t\t\t\t\"id\":2,\n\t\t\t\t\t\t\t\"description\":\"Test static route multi hop ipv4\",\n\t\t\t\t\t\t\t\"destination-prefix\":\"192.168.2.4/32\",\n\t\t\t\t\t\t\t\"vpp-ipv4-route\":{\n\t\t\t\t\t\t\t\t\"secondary-vrf\":2\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"next-hop-list\":{\n\t\t\t\t\t\t\t\t\"next-hop\":[\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"id\":\"1\",\n\t\t\t\t\t\t\t\t\t\"address\":\"192.168.2.5\",\n\t\t\t\t\t\t\t\t\t\"outgoing-interface\":\"local0\",\n\t\t\t\t\t\t\t\t\t\"weight\":\"1\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"id\":\"2\",\n\t\t\t\t\t\t\t\t\t\"address\":\"192.168.2.6\",\n\t\t\t\t\t\t\t\t\t\"outgoing-interface\":\"local0\",\n\t\t\t\t\t\t\t\t\t\"weight\":\"2\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t]\n}\n"
+               },
+               {
+                       "id": "41585a9d-5067-05d8-2dc1-3ace153a70b6",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+                       "url": "http://localhost:8183/restconf/config/ietf-routing:routing/routing-instance/vpp-routing-instance/routing-protocols/routing-protocol/test-routing-protocol-5",
+                       "preRequestScript": null,
+                       "pathVariables": {},
+                       "method": "PUT",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": null,
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1480502689477,
+                       "name": "Add multi hop ipv6",
+                       "description": "",
+                       "collectionId": "91b6ff58-8e6f-06aa-8067-caecb9f95c88",
+                       "responses": [],
+                       "rawModeData": "{\n\t\"routing-protocol\":[\n\t\t{\n\t\t\t\"name\":\"test-routing-protocol-5\",\n\t\t\t\"description\":\"Test routing protocol\",\n\t\t\t\"enabled\":\"true\",\n\t\t\t\"type\":\"static\",\n\t\t\t\"vpp-protocol-attributes\": {\n\t              \"primary-vrf\": \"5\"\n            },\n\t\t\t\"static-routes\":{\n\t\t\t\t\"ipv6\":{\n\t\t\t\t\t\"route\":{\n\t\t\t\t\t\t\t\"id\":2,\n\t\t\t\t\t\t\t\"description\":\"Test static route multi hop ipv6\",\n\t\t\t\t\t\t\t\"destination-prefix\":\"2001:0db8:0a0b:12f0:0000:0000:0000:0001/64\",\n\t\t\t\t\t\t\t\"vpp-ipv6-route\":{\n\t\t\t\t\t\t\t\t\"secondary-vrf\":\"1\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"next-hop-list\":{\n\t\t\t\t\t\t\t\t\"next-hop\":[\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"id\":\"1\",\n\t\t\t\t\t\t\t\t\t\"address\":\"2001:0db8:0a0b:12f0:0000:0000:0000:0002\",\n\t\t\t\t\t\t\t\t\t\"outgoing-interface\":\"local0\",\n\t\t\t\t\t\t\t\t\t\"weight\":\"1\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"id\":\"2\",\n\t\t\t\t\t\t\t\t\t\"address\":\"2001:0db8:0a0b:12f0:0000:0000:0000:0003\",\n\t\t\t\t\t\t\t\t\t\"outgoing-interface\":\"local0\",\n\t\t\t\t\t\t\t\t\t\"weight\":\"2\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t]\n}\n"
+               },
+               {
+                       "id": "6244bd7f-dedd-bd6d-45c3-00b0fd10bb21",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+                       "url": "http://localhost:8183/restconf/config/ietf-routing:routing/routing-instance/vpp-routing-instance/routing-protocols/routing-protocol/test-routing-protocol-6",
+                       "preRequestScript": null,
+                       "pathVariables": {},
+                       "method": "PUT",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": null,
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1480502701577,
+                       "name": "Add special hop ipv6",
+                       "description": "",
+                       "collectionId": "91b6ff58-8e6f-06aa-8067-caecb9f95c88",
+                       "responses": [],
+                       "rawModeData": "{\n\t\"routing-protocol\":[\n\t\t{\n\t\t\t\"name\":\"test-routing-protocol-6\",\n\t\t\t\"description\":\"Test routing protocol\",\n\t\t\t\"enabled\":\"true\",\n\t\t\t\"type\":\"static\",\n\t\t\t\"vpp-protocol-attributes\": {\n\t              \"primary-vrf\": \"6\"\n            },\n\t\t\t\"static-routes\":{\n\t\t\t\t\"ipv6\":{\n\t\t\t\t\t\"route\":{\n\t\t\t\t\t\t\"id\":3,\n\t\t\t\t\t\t\"description\":\"Test static route multi hop ipv6\",\n\t\t\t\t\t\t\"destination-prefix\":\"2001:0db8:0a0b:12f0:0000:0000:0000:0001/64\",\n\t\t\t\t\t\t\"special-next-hop\":\"receive\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t]\n}\n\t\n"
+               },
+               {
+                       "id": "86b915a1-f85c-939a-0814-fd98b1154162",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+                       "url": "http://localhost:8183/restconf/config/ietf-routing:routing/routing-instance/vpp-routing-instance/routing-protocols/routing-protocol/test-routing-protocol-4",
+                       "preRequestScript": null,
+                       "pathVariables": {},
+                       "method": "PUT",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": null,
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1480502678772,
+                       "name": "Add single hop ipv6",
+                       "description": "",
+                       "collectionId": "91b6ff58-8e6f-06aa-8067-caecb9f95c88",
+                       "responses": [],
+                       "rawModeData": "{\n\t\"routing-protocol\":[\n\t\t{\n\t\t\t\"name\":\"test-routing-protocol-4\",\n\t\t\t\"description\":\"Test routing protocol\",\n\t\t\t\"enabled\":\"true\",\n\t\t\t\"type\":\"static\",\n\t\t\t\"vpp-protocol-attributes\": {\n\t              \"primary-vrf\": \"4\"\n            },\n\t\t\t\"static-routes\":{\n\t\t\t\t\"ipv6\":{\n\t\t\t\t\t\"route\":[\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"id\":1,\n\t\t\t\t\t\t\t\"description\":\"Test static route single hop ipv6\",\n\t\t\t\t\t\t\t\"destination-prefix\":\"2001:0db8:0a0b:12f0:0000:0000:0000:0001/64\",\n\t\t\t\t\t\t\t\"next-hop\":\"2001:0db8:0a0b:12f0:0000:0000:0000:0002\",\n\t\t\t\t\t\t\t\"outgoing-interface\":\"local0\",\n\t\t\t\t\t\t\t\"vpp-ipv6-route\":{\n\t\t\t\t\t\t\t\t\"secondary-vrf\":\"2\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t}\n\t\t}\t\n\t]\n}"
+               },
+               {
+                       "id": "c50cc4a4-a760-f91a-fe66-dd8a66d6085b",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+                       "url": "http://localhost:8183/restconf/operational/ietf-routing:routing-state",
+                       "preRequestScript": null,
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": null,
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1479200930229,
+                       "name": "Get Routes Operational",
+                       "description": "",
+                       "collectionId": "91b6ff58-8e6f-06aa-8067-caecb9f95c88",
+                       "responses": [],
+                       "rawModeData": "{\n\t\"routing-instance\":\n\t{\n\t\t\"name\":\"routing-1\",\n\t\t\"enabled\":\"true\",\n\t\t\"router-id\":\"192.168.2.1\",\n\t\t\"description\":\"Test routing instance\",\n\t\t\"routing-protocols\":{\n\t\t\t\"routing-protocol\":[\n\t\t\t\t{\n\t\t\t\t\t\"name\":\"test-routing-protocol\",\n\t\t\t\t\t\"description\":\"Test routing protocol\",\n\t\t\t\t\t\"enabled\":\"true\",\n\t\t\t\t\t\"type\":\"static\",\n\t\t\t\t\t\"static-routes\":{\n\t\t\t\t\t\t\"ipv4\":{\n\t\t\t\t\t\t\t\"route\":[\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"id\":1,\n\t\t\t\t\t\t\t\t\t\"description\":\"Test static route\",\n\t\t\t\t\t\t\t\t\t\"destination-prefix\":\"192.168.2.3/32\",\n\t\t\t\t\t\t\t\t\t\"next-hop\":\"192.168.2.8\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\t\n\t\t\t]\n\t\t}\n\t}\t\n}"
+               },
+               {
+                       "id": "c5701b6a-a684-0a4f-9991-6f1a866baddd",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+                       "url": "http://localhost:8183/restconf/operational/naming-context:contexts",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "raw",
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1478601413071,
+                       "name": "Naming Context Read ",
+                       "description": "",
+                       "collectionId": "91b6ff58-8e6f-06aa-8067-caecb9f95c88",
+                       "responses": [],
+                       "rawModeData": "{\r\n    \r\n        \"interface\": [\r\n            {\r\n                \"name\": \"testInterface\",\r\n                \"description\": \"for testing purposes\",\r\n                \"type\": \"iana-if-type:ethernetCsmacd\",\r\n                \"enabled\": \"true\",\r\n                \"link-up-down-trap-enable\": \"enabled\",\r\n                \"ietf-ip:ipv4\": {\r\n                    \"enabled\": \"true\",\r\n                    \"mtu\": \"1500\",\r\n                    \"address\": [\r\n                        {\r\n                            \"ip\": \"1.2.3.0\",\r\n                            \"netmask\": \"255.255.255.0\"\r\n                        }\r\n                    ]\r\n                }\r\n            }\r\n        ]\r\n    \r\n}"
+               },
+               {
+                       "id": "de73785a-6784-b280-a9bc-6d6e48199f09",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+                       "url": "http://localhost:8183/restconf/operational/ietf-routing:routing-state/routing-instance/vpp-routing-instance/routing-protocols/routing-protocol/vpp-routing-protocol_2",
+                       "preRequestScript": null,
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": null,
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1479210482272,
+                       "name": "Get Specific route Operational",
+                       "description": "",
+                       "collectionId": "91b6ff58-8e6f-06aa-8067-caecb9f95c88",
+                       "responses": [],
+                       "rawModeData": "{\n\t\"routing-instance\":\n\t{\n\t\t\"name\":\"routing-1\",\n\t\t\"enabled\":\"true\",\n\t\t\"router-id\":\"192.168.2.1\",\n\t\t\"description\":\"Test routing instance\",\n\t\t\"routing-protocols\":{\n\t\t\t\"routing-protocol\":[\n\t\t\t\t{\n\t\t\t\t\t\"name\":\"test-routing-protocol\",\n\t\t\t\t\t\"description\":\"Test routing protocol\",\n\t\t\t\t\t\"enabled\":\"true\",\n\t\t\t\t\t\"type\":\"static\",\n\t\t\t\t\t\"static-routes\":{\n\t\t\t\t\t\t\"ipv4\":{\n\t\t\t\t\t\t\t\"route\":[\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"id\":1,\n\t\t\t\t\t\t\t\t\t\"description\":\"Test static route\",\n\t\t\t\t\t\t\t\t\t\"destination-prefix\":\"192.168.2.3/32\",\n\t\t\t\t\t\t\t\t\t\"next-hop\":\"192.168.2.8\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\t\n\t\t\t]\n\t\t}\n\t}\t\n}"
+               },
+               {
+                       "id": "e3510e60-17e7-887b-6a55-5e0f651512b0",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+                       "url": "http://localhost:8183/restconf/config/ietf-routing:routing/routing-instance/vpp-routing-instance/routing-protocols/routing-protocol/test-routing-protocol-1",
+                       "preRequestScript": null,
+                       "pathVariables": {},
+                       "method": "PUT",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": null,
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1480502842270,
+                       "name": "Add single hop ipv4",
+                       "description": "",
+                       "collectionId": "91b6ff58-8e6f-06aa-8067-caecb9f95c88",
+                       "responses": [],
+                       "rawModeData": "{\n\t\"routing-protocol\":[\n\t\t{\n\t\t\t\"name\":\"test-routing-protocol-1\",\n\t\t\t\"description\":\"Test routing protocol\",\n\t\t\t\"enabled\":\"true\",\n\t\t\t\"type\":\"static\",\n\t\t\t\"vpp-protocol-attributes\": {\n\t              \"primary-vrf\": \"1\"\n            },\n\t\t\t\"static-routes\":{\n\t\t\t\t\"ipv4\":{\n\t\t\t\t\t\"route\":[\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"id\":1,\n\t\t\t\t\t\t\t\"description\":\"Test static route single hop ipv4\",\n\t\t\t\t\t\t\t\"destination-prefix\":\"192.168.2.3/32\",\n\t\t\t\t\t\t\t\"next-hop\":\"192.168.2.8\",\n\t\t\t\t\t\t\t\"outgoing-interface\":\"local0\",\n\t\t\t\t\t\t\t\"vpp-ipv4-route\":{\n\t\t\t\t\t\t\t\t\"secondary-vrf\":\"2\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t}\n\t\t}\t\n\t]\n}"
+               },
+               {
+                       "id": "e8216de3-757d-ce34-87e4-8e25ee6b1f44",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+                       "url": "http://localhost:8183/restconf/operational/naming-context:contexts\\multi-naming-context:multi-naming-contexts",
+                       "preRequestScript": "",
+                       "pathVariables": {},
+                       "method": "GET",
+                       "data": [],
+                       "dataMode": "raw",
+                       "tests": "",
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1478778211905,
+                       "name": "Multi Naming Context Read",
+                       "description": "",
+                       "collectionId": "91b6ff58-8e6f-06aa-8067-caecb9f95c88",
+                       "responses": [],
+                       "rawModeData": "{\r\n    \r\n        \"interface\": [\r\n            {\r\n                \"name\": \"testInterface\",\r\n                \"description\": \"for testing purposes\",\r\n                \"type\": \"iana-if-type:ethernetCsmacd\",\r\n                \"enabled\": \"true\",\r\n                \"link-up-down-trap-enable\": \"enabled\",\r\n                \"ietf-ip:ipv4\": {\r\n                    \"enabled\": \"true\",\r\n                    \"mtu\": \"1500\",\r\n                    \"address\": [\r\n                        {\r\n                            \"ip\": \"1.2.3.0\",\r\n                            \"netmask\": \"255.255.255.0\"\r\n                        }\r\n                    ]\r\n                }\r\n            }\r\n        ]\r\n    \r\n}"
+               },
+               {
+                       "id": "ea4e8b3d-2333-6c17-1da2-32fd0b88da96",
+                       "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+                       "url": "http://localhost:8183/restconf/config/ietf-routing:routing/routing-instance/vpp-routing-instance/routing-protocols/routing-protocol/test-routing-protocol-3",
+                       "preRequestScript": null,
+                       "pathVariables": {},
+                       "method": "PUT",
+                       "data": [],
+                       "dataMode": "raw",
+                       "version": 2,
+                       "tests": null,
+                       "currentHelper": "normal",
+                       "helperAttributes": {},
+                       "time": 1480502667293,
+                       "name": "Add special hop ipv4",
+                       "description": "",
+                       "collectionId": "91b6ff58-8e6f-06aa-8067-caecb9f95c88",
+                       "responses": [],
+                       "rawModeData": "{\n\t\"routing-protocol\":[\n\t\t{\n\t\t\t\"name\":\"test-routing-protocol-3\",\n\t\t\t\"description\":\"Test routing protocol\",\n\t\t\t\"enabled\":\"true\",\n\t\t\t\"type\":\"static\",\n\t\t\t\"vpp-protocol-attributes\": {\n\t              \"primary-vrf\": \"3\"\n\t        },\n\t\t\t\"static-routes\":{\n\t\t\t\t\"ipv4\":{\n\t\t\t\t\t\"route\":{\n\t\t\t\t\t\t\"id\":3,\n\t\t\t\t\t\t\"description\":\"Test static route multi hop ipv4\",\n\t\t\t\t\t\t\"destination-prefix\":\"192.168.2.5/32\",\n\t\t\t\t\t\t\"special-next-hop\":\"receive\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t]\n}\n\t\n"
+               }
+       ]
+}
\ No newline at end of file
index ec38c64..c071e50 100644 (file)
@@ -13,7 +13,8 @@
  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">
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+         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.16.12-SNAPSHOT</version>
   <packaging>bundle</packaging>
 
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>yang-ext</artifactId>
+    </dependency>
+  </dependencies>
+
 </project>
diff --git a/vpp-common/naming-context-api/src/main/yang/multi-naming-context.yang b/vpp-common/naming-context-api/src/main/yang/multi-naming-context.yang
new file mode 100644 (file)
index 0000000..2307960
--- /dev/null
@@ -0,0 +1,68 @@
+module multi-naming-context {
+    yang-version 1;
+    namespace "urn:honeycomb:params:xml:ns:yang:multi:naming:context";
+    prefix "mnc";
+
+    description
+        "This module contains data definition for naming multi-mapping context";
+
+    import naming-context {
+       prefix "nc";
+    }
+
+    import yang-ext {
+       prefix "ext";
+    }
+
+
+    revision "2016-4-11" {
+        description
+            "Initial revision.";
+    }
+
+
+    grouping multi-naming-contexts-attributes{
+        container multi-naming-contexts {
+            config false;
+            // context data
+
+            list multi-naming {
+
+                key "name";
+
+                leaf name {
+                    type string;
+                }
+
+                container mappings {
+                    list mapping {
+
+                        key "name";
+
+                        leaf name {
+                            type string;
+                        }
+
+                        list value{
+                            key "name";
+
+                            unique "index";
+                            leaf index {
+                                type int32;
+                            }
+
+                            leaf name {
+                                type string;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    augment /nc:contexts {
+        ext:augment-identifier "multi-mapping-ctx-augmentation";
+        uses multi-naming-contexts-attributes;
+    }
+}
\ No newline at end of file
index c217bdb..94bb07a 100644 (file)
@@ -14,7 +14,7 @@
   ~ 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"
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <parent>
         <groupId>io.fd.hc2vpp.common</groupId>
             <version>${system.rules.version}</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>io.fd.honeycomb.infra</groupId>
+            <artifactId>test-tools</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>hamcrest-all</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 </project>
index eaa9664..170ff43 100644 (file)
@@ -30,6 +30,9 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.
  */
 public interface AddressTranslator extends Ipv4Translator, Ipv6Translator, MacTranslator {
 
+    AddressTranslator INSTANCE = new AddressTranslator() {
+    };
+
     default byte[] ipAddressToArray(IpAddress address) {
         checkNotNull(address, "Cannot resolve null adddress");
 
index a965426..17aff0e 100644 (file)
@@ -24,6 +24,12 @@ import javax.annotation.Nullable;
  */
 public interface ByteDataTranslator {
 
+    ByteDataTranslator INSTANCE = new ByteDataTranslator() {
+    };
+
+    byte BYTE_FALSE = 0;
+    byte BYTE_TRUE = 1;
+
     /**
      * Returns 0 if argument is null or false, 1 otherwise.
      *
@@ -32,8 +38,22 @@ public interface ByteDataTranslator {
      */
     default byte booleanToByte(@Nullable final Boolean value) {
         return value != null && value
-                ? (byte) 1
-                : (byte) 0;
+                ? BYTE_TRUE
+                : BYTE_FALSE;
+    }
+
+    /**
+     * Converts int to byte
+     */
+    default byte toByte(final int value) {
+        return Integer.valueOf(value).byteValue();
+    }
+
+    /**
+     * Converts short to byte
+     */
+    default byte toByte(final short value) {
+        return Short.valueOf(value).byteValue();
     }
 
     /**
@@ -45,9 +65,9 @@ public interface ByteDataTranslator {
      */
     @Nonnull
     default Boolean byteToBoolean(final byte value) {
-        if (value == 0) {
+        if (value == BYTE_FALSE) {
             return Boolean.FALSE;
-        } else if (value == 1) {
+        } else if (value == BYTE_TRUE) {
             return Boolean.TRUE;
         }
         throw new IllegalArgumentException(String.format("0 or 1 was expected but was %d", value));
@@ -76,4 +96,13 @@ public interface ByteDataTranslator {
     default String toString(final byte[] cString) {
         return new String(cString).replaceAll("\\u0000", "").intern();
     }
+
+    /**
+     * Converts signed byte(filled with unsigned value from vpp) to java integer
+     *
+     * For example unsigned C byte 128 is converted by jvpp to -128, this will return 128
+     */
+    default int toJavaByte(final byte vppByte) {
+        return Byte.toUnsignedInt(vppByte);
+    }
 }
index 99d1757..02f89d9 100644 (file)
@@ -108,4 +108,15 @@ public interface Ipv4Translator extends ByteDataTranslator {
         }
         return retval;
     }
+
+    default Ipv4Prefix toIpv4Prefix(final byte[] address, final int prefix) {
+        try {
+            return new Ipv4Prefix(
+                    String.format("%s/%s", InetAddress.getByAddress(address).getHostAddress(),
+                            String.valueOf(prefix)));
+        } catch (UnknownHostException e) {
+            throw new IllegalArgumentException(
+                    "Cannot create prefix for address[" + Arrays.toString(address) + "],prefix[" + prefix + "]");
+        }
+    }
 }
index cb8b2ac..2d0b51b 100644 (file)
@@ -39,17 +39,11 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.
  */
 public interface Ipv6Translator extends ByteDataTranslator {
 
-    /**
-     * Transform Ipv6 address to a byte array acceptable by VPP. VPP expects incoming byte array to be in the same order
-     * as the address.
-     *
-     * @return byte array with address bytes
-     */
-    default byte[] ipv6AddressNoZoneToArray(@Nonnull final Ipv6AddressNoZone ipv6Addr) {
+    default byte[] ipv6AddressNoZoneToArray(@Nonnull final String address) {
         byte[] retval = new byte[16];
 
         //splits address and add ommited zeros for easier parsing
-        List<String> segments = Arrays.asList(ipv6Addr.getValue().split(":"))
+        List<String> segments = Arrays.asList(address.split(":"))
                 .stream()
                 .map(segment -> StringUtils.repeat('0', 4 - segment.length()) + segment)
                 .collect(Collectors.toList());
@@ -73,6 +67,16 @@ public interface Ipv6Translator extends ByteDataTranslator {
         return retval;
     }
 
+    /**
+     * Transform Ipv6 address to a byte array acceptable by VPP. VPP expects incoming byte array to be in the same order
+     * as the address.
+     *
+     * @return byte array with address bytes
+     */
+    default byte[] ipv6AddressNoZoneToArray(@Nonnull final Ipv6AddressNoZone ipv6Addr) {
+        return ipv6AddressNoZoneToArray(ipv6Addr.getValue());
+    }
+
     /**
      * Creates address array from address part of {@link Ipv6Prefix}
      */
@@ -136,4 +140,15 @@ public interface Ipv6Translator extends ByteDataTranslator {
         checkState(!(address.getIpv4Prefix() == null && address.getIpv6Prefix() == null), "Invalid address");
         return address.getIpv6Prefix() != null;
     }
+
+    default Ipv6Prefix toIpv6Prefix(final byte[] address, final int prefix) {
+        try {
+            return new Ipv6Prefix(
+                    String.format("%s/%s", InetAddress.getByAddress(address).getHostAddress(),
+                            String.valueOf(prefix)));
+        } catch (UnknownHostException e) {
+            throw new IllegalArgumentException(
+                    "Cannot create prefix for address[" + Arrays.toString(address) + "],prefix[" + prefix + "]");
+        }
+    }
 }
diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/MultiNamingContext.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/MultiNamingContext.java
new file mode 100644 (file)
index 0000000..6b10881
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.common.translate.util;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.util.RWUtils;
+import java.util.Collections;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.MultiMappingCtxAugmentation;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.multi.naming.contexts.attributes.MultiNamingContexts;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.multi.naming.contexts.attributes.multi.naming.contexts.MultiNaming;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.multi.naming.contexts.attributes.multi.naming.contexts.MultiNamingKey;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.multi.naming.contexts.attributes.multi.naming.contexts.multi.naming.Mappings;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.multi.naming.contexts.attributes.multi.naming.contexts.multi.naming.mappings.Mapping;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.multi.naming.contexts.attributes.multi.naming.contexts.multi.naming.mappings.MappingBuilder;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.multi.naming.contexts.attributes.multi.naming.contexts.multi.naming.mappings.MappingKey;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.multi.naming.contexts.attributes.multi.naming.contexts.multi.naming.mappings.mapping.Value;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.multi.naming.contexts.attributes.multi.naming.contexts.multi.naming.mappings.mapping.ValueBuilder;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.Contexts;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+
+/**
+ * One to many context mapping
+ */
+public class MultiNamingContext {
+
+    private final KeyedInstanceIdentifier<MultiNaming, MultiNamingKey>
+            multiNamingContextIid;
+
+    private final int startIndex;
+
+    public MultiNamingContext(@Nonnull final String instanceName, final int startIndex) {
+        multiNamingContextIid = InstanceIdentifier.create(Contexts.class)
+                .augmentation(MultiMappingCtxAugmentation.class)
+                .child(MultiNamingContexts.class)
+                .child(MultiNaming.class, new MultiNamingKey(instanceName));
+        this.startIndex = startIndex;
+    }
+
+    public synchronized void addChild(@Nonnull final String parentName, final int childIndex,
+                                      @Nonnull final String childName,
+                                      @Nonnull final MappingContext mappingContext) {
+        checkArgument(childIndex >= startIndex, "Index cannot be lower than start index %s", startIndex);
+        final KeyedInstanceIdentifier<Mapping, MappingKey> mappingIid = getMappingIid(parentName);
+
+        //uses merge to preserve previous
+        mappingContext.merge(mappingIid,
+                new MappingBuilder().setName(parentName).setValue(Collections.singletonList(new ValueBuilder()
+                        .setIndex(childIndex)
+                        .setName(childName)
+                        .build())).build());
+    }
+
+    public synchronized void addChild(@Nonnull final String parentName,
+                                      @Nonnull final String childName,
+                                      @Nonnull final MappingContext mappingContext) {
+        addChild(parentName, getNextAvailableChildIndex(parentName, mappingContext), childName, mappingContext);
+    }
+
+    public synchronized String getChildName(@Nonnull final String parentName,
+                                            @Nonnull final int childIndex,
+                                            @Nonnull final MappingContext mappingContext) {
+        final Optional<Mapping> read = mappingContext.read(getMappingIid(parentName));
+
+        checkState(read.isPresent(), "Mapping not present");
+
+        return read.get().getValue().stream()
+                .filter(value -> value.getIndex().equals(childIndex))
+                .collect(RWUtils.singleItemCollector()).getName();
+    }
+
+    public synchronized int getChildIndex(@Nonnull final String parentName,
+                                          @Nonnull final String childName,
+                                          @Nonnull final MappingContext mappingContext) {
+        final Optional<Mapping> read = mappingContext.read(getMappingIid(parentName));
+
+        checkState(read.isPresent(), "Mapping not present");
+
+        return read.get().getValue().stream()
+                .filter(value -> value.getName().equals(childName))
+                .collect(RWUtils.singleItemCollector()).getIndex();
+    }
+
+
+    public synchronized void removeChild(@Nonnull final String parentName,
+                                         @Nonnull final String childName,
+                                         @Nonnull final MappingContext mappingContext) {
+
+        final Optional<Mapping> read = mappingContext.read(getMappingIid(parentName));
+
+        // ignore delete's for non-existing parent
+        if (read.isPresent()) {
+            final Mapping mapping = read.get();
+
+            // overrides old data with new(without removed child)
+            mappingContext.put(getMappingIid(parentName), new MappingBuilder()
+                    .setName(mapping.getName())
+                    .setKey(mapping.getKey())
+                    .setValue(mapping.getValue()
+                            .stream()
+                            .filter(value -> !value.getName().equals(childName))
+                            .collect(Collectors.toList()))
+                    .build());
+        }
+    }
+
+    /**
+     * Returns next available index for mapping
+     */
+    private int getNextAvailableChildIndex(final String parentName, final MappingContext mappingContext) {
+        final Optional<Mappings> read = mappingContext.read(mappingIdBase());
+
+        if (!read.isPresent()) {
+            return startIndex;
+        }
+
+        return read.get().getMapping()
+                .stream()
+                .filter(mapping -> mapping.getName().equals(parentName))
+                .flatMap(mapping -> mapping.getValue().stream())
+                .mapToInt(Value::getIndex)
+                // do not use i++(need increase before, not after
+                .map(i -> ++i)
+                .max()
+                .orElse(startIndex);
+    }
+
+    private KeyedInstanceIdentifier<Mapping, MappingKey> getMappingIid(final String name) {
+        return mappingIdBase().child(Mapping.class, new MappingKey(name));
+    }
+
+    private InstanceIdentifier<Mappings> mappingIdBase() {
+        return multiNamingContextIid.child(Mappings.class);
+    }
+}
index 393df08..5e0eea7 100644 (file)
@@ -128,6 +128,17 @@ public final class NamingContext implements AutoCloseable {
         mappingContext.put(mappingIid, new MappingBuilder().setIndex(index).setName(name).build());
     }
 
+    /**
+     * Add mapping to current context with next available index.
+     * Suitable for learned data mappings
+     *
+     * @param name           name of a mapped item
+     * @param mappingContext mapping context providing context data for current transaction
+     */
+    public synchronized void addName(final String name, final MappingContext mappingContext) {
+        addName(getNextAvailableIndex(mappingContext), name, mappingContext);
+    }
+
     private KeyedInstanceIdentifier<Mapping, MappingKey> getMappingIid(final String name) {
         return namingContextIid.child(Mappings.class).child(Mapping.class, new MappingKey(name));
     }
@@ -172,6 +183,25 @@ public final class NamingContext implements AutoCloseable {
         return artificialNamePrefix + index;
     }
 
+    /**
+     * Returns next available index for mapping
+     */
+    private int getNextAvailableIndex(final MappingContext mappingContext) {
+        final Optional<Mappings> read = mappingContext.read(namingContextIid.child(Mappings.class));
+
+        if (!read.isPresent()) {
+            return 0;
+        }
+
+        return read.get().getMapping()
+                .stream()
+                .mapToInt(Mapping::getIndex)
+                // do not use i++(need increase before, not after
+                .map(i -> ++i)
+                .max()
+                .orElse(0);
+    }
+
     @Override
     public void close() throws Exception {
         /// Not removing the mapping from backing storage
index 8494568..6e801db 100644 (file)
@@ -19,7 +19,6 @@ package io.fd.hc2vpp.common.translate.util;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 
-import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
 import org.junit.Test;
 
 public class ByteDataTranslatorTest implements ByteDataTranslator {
@@ -50,4 +49,11 @@ public class ByteDataTranslatorTest implements ByteDataTranslator {
         final String jString = toString(cString);
         assertArrayEquals(expected, jString.getBytes());
     }
+
+    @Test
+    public void testToJavaByte() {
+        assertEquals(128, toJavaByte((byte) -128));
+        assertEquals(129, toJavaByte((byte) -127));
+        assertEquals(127, toJavaByte((byte) 127));
+    }
 }
\ No newline at end of file
index 37e29d8..484ea2c 100644 (file)
@@ -44,4 +44,9 @@ public class Ipv4TranslatorTest implements Ipv4Translator {
     public void testExtractPrefix() {
         assertEquals(24, extractPrefix(new Ipv4Prefix("192.168.2.1/24")));
     }
+
+    @Test
+    public void testToPrefix() {
+        assertEquals("192.168.2.1/24", toIpv4Prefix(new byte[]{-64, -88, 2, 1}, (byte) 24).getValue());
+    }
 }
\ No newline at end of file
index 43327ea..1099f68 100644 (file)
@@ -51,4 +51,11 @@ public class Ipv6TranslatorTest implements Ipv6Translator {
     public void testExtractPrefix() {
         assertEquals(48, extractPrefix(new Ipv6Prefix("3ffe:1900:4545:3:200:f8ff:fe21:67cf/48")));
     }
+
+    @Test
+    public void toPrefix() {
+        assertEquals("2001:db8:a0b:12f0:0:0:0:1/48",
+                toIpv6Prefix(new byte[]{32, 1, 13, -72, 10, 11, 18, -16, 0, 0, 0, 0, 0, 0, 0, 1},
+                        (byte) 48).getValue());
+    }
 }
\ No newline at end of file
diff --git a/vpp-common/vpp-translate-utils/src/test/java/io/fd/hc2vpp/common/translate/util/MultiNamingContextTest.java b/vpp-common/vpp-translate-utils/src/test/java/io/fd/hc2vpp/common/translate/util/MultiNamingContextTest.java
new file mode 100644 (file)
index 0000000..b38ce6e
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.common.translate.util;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.hasSize;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.test.tools.HoneycombTestRunner;
+import io.fd.honeycomb.test.tools.annotations.InjectTestData;
+import io.fd.honeycomb.test.tools.annotations.InjectablesProcessor;
+import io.fd.honeycomb.test.tools.annotations.SchemaContextProvider;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.util.RWUtils;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.$YangModuleInfoImpl;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.MultiMappingCtxAugmentation;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.multi.naming.contexts.attributes.MultiNamingContexts;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.multi.naming.contexts.attributes.multi.naming.contexts.MultiNaming;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.multi.naming.contexts.attributes.multi.naming.contexts.MultiNamingKey;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.multi.naming.contexts.attributes.multi.naming.contexts.multi.naming.Mappings;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.multi.naming.contexts.attributes.multi.naming.contexts.multi.naming.mappings.Mapping;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.multi.naming.contexts.attributes.multi.naming.contexts.multi.naming.mappings.MappingKey;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.multi.naming.contexts.attributes.multi.naming.contexts.multi.naming.mappings.mapping.Value;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.multi.naming.contexts.attributes.multi.naming.contexts.multi.naming.mappings.mapping.ValueBuilder;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.multi.naming.contexts.attributes.multi.naming.contexts.multi.naming.mappings.mapping.ValueKey;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.Contexts;
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+
+@RunWith(HoneycombTestRunner.class)
+public class MultiNamingContextTest implements InjectablesProcessor {
+
+    private static final String NON_EXISTING_PARENT = "non-existing-parent";
+    private static final String PARENT_1 = "parent-1";
+    private static final String PARENT_2 = "parent-2";
+    private static final String PARENT_3 = "parent-3";
+    private static final String CHILD_1 = "child-1";
+    private static final String CHILD_2 = "child-2";
+    private static final String CHILD_3 = "child-3";
+
+    @Mock
+    private MappingContext mappingContext;
+
+    @Captor
+    private ArgumentCaptor<InstanceIdentifier> instanceIdentifierArgumentCaptor;
+
+    @Captor
+    private ArgumentCaptor<Mapping> mappingArgumentCaptor;
+
+    private MultiNamingContext namingContext;
+    private KeyedInstanceIdentifier<MultiNaming, MultiNamingKey> multiNamingContextIid;
+
+    @InjectTestData(resourcePath = "/multi-mapping.json",
+            id = "/naming-context:contexts/" +
+                    "multi-naming-context:multi-naming-contexts" +
+                    "/multi-naming-context:multi-naming[multi-naming-context:name='context']" +
+                    "/multi-naming-context:mappings")
+    private Mappings mappings;
+
+    @SchemaContextProvider
+    public ModuleInfoBackedContext schemaContext() {
+        return provideSchemaContextFor(Collections.singleton($YangModuleInfoImpl.getInstance()));
+    }
+
+    @Before
+    public void init() {
+        MockitoAnnotations.initMocks(this);
+        this.namingContext = new MultiNamingContext("context", 3);
+        this.multiNamingContextIid = InstanceIdentifier.create(Contexts.class)
+                .augmentation(MultiMappingCtxAugmentation.class)
+                .child(MultiNamingContexts.class)
+                .child(MultiNaming.class, new MultiNamingKey("context"));
+
+        when(mappingContext.read(multiNamingContextIid.child(Mappings.class))).thenReturn(Optional.of(mappings));
+        when(mappingContext.read(parentKey(NON_EXISTING_PARENT))).thenReturn(Optional.absent());
+        when(mappingContext.read(parentKey(PARENT_1))).thenReturn(Optional.of(filterForParent(PARENT_1)));
+        when(mappingContext.read(parentKey(PARENT_2))).thenReturn(Optional.of(filterForParent(PARENT_2)));
+        when(mappingContext.read(parentKey(PARENT_3))).thenReturn(Optional.of(filterForParent(PARENT_3)));
+    }
+
+    private Mapping filterForParent(final String parent) {
+        return mappings.getMapping().stream()
+                .filter(mapping -> mapping.getName().equals(parent))
+                .collect(RWUtils.singleItemCollector());
+    }
+
+    private KeyedInstanceIdentifier<Mapping, MappingKey> parentKey(final String parent) {
+        return multiNamingContextIid.child(Mappings.class).child(Mapping.class, new MappingKey(parent));
+    }
+
+    @Test
+    public void addChildSpecificIndex() throws Exception {
+        namingContext.addChild(PARENT_1, 3, CHILD_1, mappingContext);
+
+        verify(mappingContext, times(1))
+                .merge(instanceIdentifierArgumentCaptor.capture(), mappingArgumentCaptor.capture());
+
+        assertEquals(instanceIdentifierArgumentCaptor.getValue(), parentKey(PARENT_1));
+
+        final Mapping mapping = mappingArgumentCaptor.getValue();
+        final List<Value> values = mapping.getValue();
+        assertEquals(PARENT_1, mapping.getName());
+        assertThat(values, hasSize(1));
+
+        final Value child = values.get(0);
+        assertEquals(CHILD_1, child.getName());
+        assertEquals(3, child.getIndex().intValue());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void addInvalidIndex() {
+        namingContext.addChild(PARENT_1, 2, CHILD_1, mappingContext);
+    }
+
+    @Test
+    public void addChildNextAvailableIndex() throws Exception {
+        namingContext.addChild(PARENT_1, CHILD_1, mappingContext);
+
+        verify(mappingContext, times(1))
+                .merge(instanceIdentifierArgumentCaptor.capture(), mappingArgumentCaptor.capture());
+        assertEquals(instanceIdentifierArgumentCaptor.getValue(), parentKey(PARENT_1));
+
+        final Mapping mapping = mappingArgumentCaptor.getValue();
+        final List<Value> values = mapping.getValue();
+        assertEquals(PARENT_1, mapping.getName());
+        assertThat(values, hasSize(1));
+
+        final Value child = values.get(0);
+        assertEquals(CHILD_1, child.getName());
+        assertEquals(4, child.getIndex().intValue());
+    }
+
+    @Test
+    public void getChildName() throws Exception {
+        assertEquals(CHILD_1, namingContext.getChildName(PARENT_1, 1, mappingContext));
+    }
+
+    @Test
+    public void getChildIndex() throws Exception {
+        assertEquals(1, namingContext.getChildIndex(PARENT_1, CHILD_1, mappingContext));
+    }
+
+    @Test
+    public void removeChild() throws Exception {
+        namingContext.removeChild(PARENT_1, CHILD_1, mappingContext);
+
+        verify(mappingContext, times(1))
+                .put(instanceIdentifierArgumentCaptor.capture(), mappingArgumentCaptor.capture());
+
+        assertEquals(instanceIdentifierArgumentCaptor.getValue(), parentKey(PARENT_1));
+        final Mapping mapping = mappingArgumentCaptor.getValue();
+        final List<Value> values = mapping.getValue();
+
+        assertEquals(PARENT_1, mapping.getName());
+        assertThat(values, hasSize(2));
+        assertThat(values, contains(valueFor(CHILD_2, 2), valueFor(CHILD_3, 3)));
+    }
+
+    @Test
+    public void removeChildNonExistingParent() {
+        namingContext.removeChild(NON_EXISTING_PARENT, CHILD_1, mappingContext);
+        // if parent doest not exist, do nothing
+        verify(mappingContext, times(0)).put(Mockito.any(), Mockito.any());
+    }
+
+    private Value valueFor(final String name, final int index) {
+        return new ValueBuilder().setName(name).setIndex(index).setKey(new ValueKey(name)).build();
+    }
+}
+
diff --git a/vpp-common/vpp-translate-utils/src/test/java/io/fd/hc2vpp/common/translate/util/NamingContextTest.java b/vpp-common/vpp-translate-utils/src/test/java/io/fd/hc2vpp/common/translate/util/NamingContextTest.java
new file mode 100644 (file)
index 0000000..4e66315
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2016 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.hc2vpp.common.translate.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.test.tools.HoneycombTestRunner;
+import io.fd.honeycomb.test.tools.annotations.InjectTestData;
+import io.fd.honeycomb.test.tools.annotations.InjectablesProcessor;
+import io.fd.honeycomb.test.tools.annotations.SchemaContextProvider;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.util.RWUtils;
+import java.util.Collections;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.$YangModuleInfoImpl;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.Contexts;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContextKey;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingBuilder;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey;
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+
+@RunWith(HoneycombTestRunner.class)
+public class NamingContextTest implements InjectablesProcessor {
+
+    private static final String NAME_1 = "name-1";
+    private static final String NAME_2 = "name-2";
+
+    @InjectTestData(resourcePath = "/naming.json", id = "/naming-context:contexts" +
+            "/naming-context:naming-context[naming-context:name='context']" +
+            "/naming-context:mappings")
+    private Mappings mappings;
+
+    @Mock
+    private MappingContext mappingContext;
+
+    @Captor
+    private ArgumentCaptor<InstanceIdentifier> instanceIdentifierArgumentCaptor;
+
+    @Captor
+    private ArgumentCaptor<Mapping> mappingArgumentCaptor;
+
+    private NamingContext namingContext;
+    private KeyedInstanceIdentifier<org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContext, NamingContextKey>
+            namingContextIid;
+
+    @SchemaContextProvider
+    public ModuleInfoBackedContext schemaContext() {
+        return provideSchemaContextFor(Collections.singleton($YangModuleInfoImpl.getInstance()));
+    }
+
+    @Before
+    public void init() {
+        MockitoAnnotations.initMocks(this);
+
+        this.namingContext = new NamingContext("prefix", "context");
+        this.namingContextIid = InstanceIdentifier.create(Contexts.class).child(
+                org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.NamingContext.class,
+                new NamingContextKey("context"));
+
+        when(mappingContext.read(namingContextIid.child(Mappings.class))).thenReturn(Optional.of(mappings));
+        when(mappingContext.read(parentKey(NAME_1))).thenReturn(Optional.of(filterForParent(NAME_1)));
+        when(mappingContext.read(parentKey(NAME_2))).thenReturn(Optional.of(filterForParent(NAME_2)));
+
+    }
+
+    @Test
+    public void addNameNextIndex() throws Exception {
+        namingContext.addName("name-3", mappingContext);
+        verify(mappingContext, times(1))
+                .put(instanceIdentifierArgumentCaptor.capture(), mappingArgumentCaptor.capture());
+
+        assertEquals(instanceIdentifierArgumentCaptor.getValue(), parentKey("name-3"));
+        assertEquals(mappingArgumentCaptor.getValue(), new MappingBuilder()
+                .setIndex(3)
+                .setName("name-3")
+                .build());
+    }
+
+    private Mapping filterForParent(final String parent) {
+        return mappings.getMapping().stream()
+                .filter(mapping -> mapping.getName().equals(parent))
+                .collect(RWUtils.singleItemCollector());
+    }
+
+    private KeyedInstanceIdentifier<Mapping, MappingKey> parentKey(final String parent) {
+        return namingContextIid.child(Mappings.class).child(Mapping.class, new MappingKey(parent));
+    }
+}
diff --git a/vpp-common/vpp-translate-utils/src/test/resources/multi-mapping.json b/vpp-common/vpp-translate-utils/src/test/resources/multi-mapping.json
new file mode 100644 (file)
index 0000000..c20401f
--- /dev/null
@@ -0,0 +1,35 @@
+{
+  "mappings": {
+    "mapping": [
+      {
+        "name": "parent-1",
+        "value": [
+          {
+            "index": 1,
+            "name": "child-1"
+          },
+          {
+            "index": 2,
+            "name": "child-2"
+          },
+          {
+            "index": 3,
+            "name": "child-3"
+          }
+        ]
+      },
+      {
+        "name": "parent-2"
+      },
+      {
+        "name": "parent-3",
+        "value": [
+          {
+            "index": 1,
+            "name": "child-1"
+          }
+        ]
+      }
+    ]
+  }
+}
\ No newline at end of file
diff --git a/vpp-common/vpp-translate-utils/src/test/resources/naming.json b/vpp-common/vpp-translate-utils/src/test/resources/naming.json
new file mode 100644 (file)
index 0000000..0248264
--- /dev/null
@@ -0,0 +1,14 @@
+{
+  "mappings": {
+    "mapping": [
+      {
+        "name": "name-1",
+        "index": 1
+      },
+      {
+        "name": "name-2",
+        "index": 2
+      }
+    ]
+  }
+}
\ No newline at end of file
index 56e821a..b5f9618 100644 (file)
@@ -13,7 +13,8 @@
  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">
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+         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>
     <vppnsh.version>1.16.12-SNAPSHOT</vppnsh.version>
     <nat.version>1.16.12-SNAPSHOT</nat.version>
     <ioam.version>1.16.12-SNAPSHOT</ioam.version>
+    <routing.version>1.16.12-SNAPSHOT</routing.version>
 
     <distribution.modules>
       io.fd.hc2vpp.common.integration.VppCommonModule,
       io.fd.hc2vpp.lisp.LispModule,
       io.fd.hc2vpp.v3po.V3poModule,
       io.fd.hc2vpp.nat.NatModule,
+      io.fd.hc2vpp.routing.RoutingModule,
       // io.fd.hc2vpp.vppnsh.impl.VppNshModule,
       <!-- Nsh module by default disabled, because it needs vpp-nsh plugin, which is not part of vpp codebase.-->
       // io.fd.hc2vpp.vppioam.impl.VppIoamModule
       <artifactId>nat2vpp</artifactId>
       <version>${nat.version}</version>
     </dependency>
+    <dependency>
+      <groupId>io.fd.hc2vpp.routing</groupId>
+      <artifactId>routing-impl</artifactId>
+      <version>${routing.version}</version>
+    </dependency>
     <dependency>
       <groupId>io.fd.hc2vpp.ioam</groupId>
       <artifactId>vppioam-impl</artifactId>