summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaros Marsalek <mmarsale@cisco.com>2016-10-05 15:03:33 +0200
committerMarek Gradzki <mgradzki@cisco.com>2016-10-14 05:42:54 +0000
commit0c5820220a4e7ebc3245259085d00551d2687e32 (patch)
treea36bee0753035be5d68f97130bf016feaeb9d2c0
parentc54ae4ac74d6b8ab71c7e166f10ca6b080ffa558 (diff)
HONEYCOMB-229 Introduce NAT to HC
Reflects SNAT from VPP: - 1:1 Static IPv4 mapping - interface in/out NAT feature management Bonus: - Support presence containers in infra Change-Id: Ieb38526f83edbae5e605d5c7e39bb22bbafc50e5 Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
-rw-r--r--infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModifiableDataTreeDelegator.java2
-rw-r--r--infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModificationDiff.java34
-rw-r--r--infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ModificationDiffTest.java32
-rw-r--r--infra/data-impl/src/test/resources/test-diff.yang4
-rw-r--r--nat/asciidoc/Readme.adoc12
-rw-r--r--nat/nat-api/asciidoc/Readme.adoc11
-rw-r--r--nat/nat-api/pom.xml61
-rw-r--r--nat/nat-api/src/main/yang/ietf-nat.yang1074
-rw-r--r--nat/nat-api/src/main/yang/interface-nat.yang44
-rw-r--r--nat/nat-api/src/main/yang/nat-context.yang64
-rw-r--r--nat/nat2vpp/asciidoc/Readme.adoc3
-rw-r--r--nat/nat2vpp/pom.xml119
-rw-r--r--nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/NatModule.java77
-rw-r--r--nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/init/NatInitializer.java63
-rwxr-xr-xnat/nat2vpp/src/main/java/io/fd/honeycomb/nat/jvpp/JVppSnatProvider.java60
-rw-r--r--nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/MappingEntryCustomizer.java151
-rw-r--r--nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/NatInstanceCustomizer.java84
-rw-r--r--nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/NatReaderFactory.java75
-rw-r--r--nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/IfcNatReaderFactory.java55
-rw-r--r--nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/InterfaceInboundNatCustomizer.java55
-rw-r--r--nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/InterfaceOutboundNatCustomizer.java54
-rw-r--r--nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/util/MappingEntryContext.java210
-rw-r--r--nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/MappingEntryCustomizer.java182
-rw-r--r--nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/NatInstaceCustomizer.java53
-rw-r--r--nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/NatWriterFactory.java66
-rw-r--r--nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/ifc/AbstractInterfaceNatCustomizer.java105
-rw-r--r--nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/ifc/IfcNatWriterFactory.java62
-rw-r--r--nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/ifc/InterfaceInboundNatCustomizer.java44
-rw-r--r--nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/ifc/InterfaceOutboundNatCustomizer.java44
-rw-r--r--nat/nat2vpp/src/test/java/io/fd/honeycomb/nat/NatModuleTest.java123
-rw-r--r--nat/nat2vpp/src/test/java/io/fd/honeycomb/nat/util/MappingEntryContextTest.java198
-rw-r--r--nat/nat2vpp/src/test/resources/nat.json3
-rw-r--r--nat/pom.xml56
-rw-r--r--nat/postman_rest_collection.json222
-rwxr-xr-xnsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/VppNshModule.java4
-rw-r--r--pom.xml6
-rw-r--r--tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-api/pom.xml13
-rw-r--r--tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/pom.xml4
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/V3poModule.java6
-rw-r--r--vpp-common/vpp-impl-parent/pom.xml5
-rw-r--r--vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/vpp/util/Ipv4Translator.java2
-rw-r--r--vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/vpp/util/NamingContext.java2
-rw-r--r--vpp-integration/minimal-distribution/pom.xml6
43 files changed, 3522 insertions, 28 deletions
diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModifiableDataTreeDelegator.java b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModifiableDataTreeDelegator.java
index 7af9847d7..7f8b53919 100644
--- a/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModifiableDataTreeDelegator.java
+++ b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModifiableDataTreeDelegator.java
@@ -115,7 +115,7 @@ public final class ModifiableDataTreeDelegator extends ModifiableDataTreeManager
rootPath, rootNode, rootNode.getDataBefore(), rootNode.getDataAfter());
final ModificationDiff modificationDiff =
- ModificationDiff.recursivelyFromCandidate(YangInstanceIdentifier.EMPTY, rootNode);
+ ModificationDiff.recursivelyFromCandidateRoot(rootNode);
LOG.debug("ConfigDataTree.modify() diff: {}", modificationDiff);
// Distinguish between updates (create + update) and deletes
diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModificationDiff.java b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModificationDiff.java
index 1c87bc03a..e78bb876b 100644
--- a/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModificationDiff.java
+++ b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ModificationDiff.java
@@ -41,7 +41,8 @@ import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
final class ModificationDiff {
private static final ModificationDiff EMPTY_DIFF = new ModificationDiff(Collections.emptyMap());
- private static final EnumSet LEAF_MODIFICATIONS = EnumSet.of(ModificationType.WRITE, ModificationType.DELETE);
+ private static final EnumSet VALID_MODIFICATIONS = EnumSet.of(ModificationType.WRITE, ModificationType.DELETE);
+ private static final EnumSet IGNORED_MODIFICATIONS = EnumSet.of(ModificationType.APPEARED, ModificationType.DISAPPEARED);
private final Map<YangInstanceIdentifier, NormalizedNodeUpdate> updates;
@@ -98,12 +99,25 @@ final class ModificationDiff {
}
/**
+ * Same as {@link #recursivelyFromCandidate(YangInstanceIdentifier, DataTreeCandidateNode)} but does not process
+ * the root node for modifications, since it's the artificial data root, that has no child leaves but always is
+ * marked as SUBTREE_MODIFIED.
+ */
+ @Nonnull
+ static ModificationDiff recursivelyFromCandidateRoot(@Nonnull final DataTreeCandidateNode currentCandidate) {
+ return recursivelyChildrenFromCandidate(YangInstanceIdentifier.EMPTY, currentCandidate);
+ }
+
+ /**
* Check whether current node was modified. {@link MixinNode}s are ignored
* and only nodes which direct leaves(or choices) are modified are considered a modification.
*/
private static Boolean isModification(@Nonnull final DataTreeCandidateNode currentCandidate) {
+ // Disappear is not a modification
+ if (IGNORED_MODIFICATIONS.contains(currentCandidate.getModificationType())) {
+ return false;
// Mixin nodes are not considered modifications
- if (isMixin(currentCandidate) && !isAugment(currentCandidate)) {
+ } else if (isMixin(currentCandidate) && !isAugment(currentCandidate)) {
return false;
} else {
return isCurrentModified(currentCandidate);
@@ -111,13 +125,18 @@ final class ModificationDiff {
}
private static Boolean isCurrentModified(final @Nonnull DataTreeCandidateNode currentCandidate) {
+ // First check if it's an empty presence node
+ if (isEmptyPresenceNode(currentCandidate)) {
+ return true;
+ }
+
// Check if there are any modified leaves and if so, consider current node as modified
final Boolean directLeavesModified = currentCandidate.getChildNodes().stream()
.filter(ModificationDiff::isLeaf)
// For some reason, we get modifications on unmodified list keys
// and that messes up our modifications collection here, so we need to skip
.filter(ModificationDiff::isBeforeAndAfterDifferent)
- .filter(child -> LEAF_MODIFICATIONS.contains(child.getModificationType()))
+ .filter(child -> VALID_MODIFICATIONS.contains(child.getModificationType()))
.findFirst()
.isPresent();
@@ -133,6 +152,15 @@ final class ModificationDiff {
}
/**
+ * Check if new data are empty but still to be considered as a modification, meaning it's presence has a meaning
+ * e.g. containers with presence statement.
+ */
+ private static boolean isEmptyPresenceNode(final @Nonnull DataTreeCandidateNode currentCandidate) {
+ return currentCandidate.getChildNodes().isEmpty()
+ && VALID_MODIFICATIONS.contains(currentCandidate.getModificationType());
+ }
+
+ /**
* Process all non-leaf child nodes recursively, creating aggregated {@link ModificationDiff}.
*/
private static ModificationDiff recursivelyChildrenFromCandidate(final @Nonnull YangInstanceIdentifier yangIid,
diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ModificationDiffTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ModificationDiffTest.java
index 2fa82043b..cc00f2dc6 100644
--- a/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ModificationDiffTest.java
+++ b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ModificationDiffTest.java
@@ -1,9 +1,12 @@
package io.fd.honeycomb.data.impl;
+import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.hasItems;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import com.google.common.base.Optional;
import java.util.Map;
import org.junit.Test;
import org.opendaylight.yangtools.yang.common.QName;
@@ -45,10 +48,11 @@ public class ModificationDiffTest {
static final QName IN_CASE1_LEAF_QNAME = QName.create(WITH_CHOICE_CONTAINER_QNAME, "in-case1");
static final QName IN_CASE2_LEAF_QNAME = QName.create(WITH_CHOICE_CONTAINER_QNAME, "in-case2");
+ static final QName PRESENCE_CONTAINER_QNAME = QName.create(TOP_CONTAINER_QNAME, "presence");
+
static final YangInstanceIdentifier TOP_CONTAINER_ID = YangInstanceIdentifier.of(TOP_CONTAINER_QNAME);
static final YangInstanceIdentifier NESTED_LIST_ID = TOP_CONTAINER_ID.node(new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME));
-
@Test
public void testInitialWrite() throws Exception {
final TipProducingDataTree dataTree = getDataTree();
@@ -66,6 +70,30 @@ public class ModificationDiffTest {
}
@Test
+ public void testWritePresenceEmptyContainer() throws Exception {
+ final TipProducingDataTree dataTree = getDataTree();
+ final DataTreeModification dataTreeModification = getModification(dataTree);
+ final NormalizedNode<?, ?> presenceContainer = Builders.containerBuilder()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(PRESENCE_CONTAINER_QNAME))
+ .build();
+ final YangInstanceIdentifier PRESENCE_CONTAINER_ID = YangInstanceIdentifier.of(PRESENCE_CONTAINER_QNAME);
+ dataTreeModification.write(PRESENCE_CONTAINER_ID, presenceContainer);
+ final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification);
+
+ final ModificationDiff modificationDiff = getModificationDiff(prepare);
+
+ dataTree.commit(prepare);
+
+ final Optional<NormalizedNode<?, ?>> presenceAfter = getModification(dataTree).readNode(PRESENCE_CONTAINER_ID);
+ assertTrue(presenceAfter.isPresent());
+ assertThat(presenceAfter.get(), equalTo(presenceContainer));
+
+ assertThat(modificationDiff.getUpdates().size(), is(1));
+ assertThat(modificationDiff.getUpdates().values().size(), is(1));
+ assertUpdate(modificationDiff.getUpdates().values().iterator().next(), PRESENCE_CONTAINER_ID, null, presenceContainer);
+ }
+
+ @Test
public void testInitialWriteForContainerWithChoice() throws Exception {
final TipProducingDataTree dataTree = getDataTree();
final DataTreeModification dataTreeModification = getModification(dataTree);
@@ -132,7 +160,7 @@ public class ModificationDiffTest {
}
private ModificationDiff getModificationDiff(final DataTreeCandidateTip prepare) {
- return ModificationDiff.recursivelyFromCandidate(YangInstanceIdentifier.EMPTY, prepare.getRootNode());
+ return ModificationDiff.recursivelyFromCandidateRoot(prepare.getRootNode());
}
@Test
diff --git a/infra/data-impl/src/test/resources/test-diff.yang b/infra/data-impl/src/test/resources/test-diff.yang
index 5cccc8718..6c27ddc17 100644
--- a/infra/data-impl/src/test/resources/test-diff.yang
+++ b/infra/data-impl/src/test/resources/test-diff.yang
@@ -7,6 +7,10 @@ module test-diff {
description "Initial revision";
}
+ container presence {
+ presence "testing presence";
+ }
+
container top-container {
leaf string {
type string;
diff --git a/nat/asciidoc/Readme.adoc b/nat/asciidoc/Readme.adoc
new file mode 100644
index 000000000..eced90f11
--- /dev/null
+++ b/nat/asciidoc/Readme.adoc
@@ -0,0 +1,12 @@
+= SNAT
+
+Support fot VPP's SNAT plugin:
+https://docs.fd.io/vpp/16.12/plugins_snat-plugin_snat.html
+
+== Supported features
+
+=== 1:1 NAT
+- Create/Read/Delete static 1:1 IPv4 (no port) mappings
+
+=== Interface NAT feature
+- Enable/Disable NAT feature for interface \ No newline at end of file
diff --git a/nat/nat-api/asciidoc/Readme.adoc b/nat/nat-api/asciidoc/Readme.adoc
new file mode 100644
index 000000000..300d83885
--- /dev/null
+++ b/nat/nat-api/asciidoc/Readme.adoc
@@ -0,0 +1,11 @@
+= nat-api
+
+The APIs are based on ietf-nat YANG model draft:
+https://tools.ietf.org/html/draft-sivakumar-yang-nat-05
+
+== Notes on model
+* Nat-instances map to VRF in VPP (nat-instance/id mapps to VRF-ID)
+
+== Deviations
+* nat-state/nat-instances/nat-instance/id type changed to uint32 from int32
+* "mandatory true" statements commented to support partial model implementation
diff --git a/nat/nat-api/pom.xml b/nat/nat-api/pom.xml
new file mode 100644
index 000000000..13d8f0ccf
--- /dev/null
+++ b/nat/nat-api/pom.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>io.fd.honeycomb.common</groupId>
+ <artifactId>api-parent</artifactId>
+ <relativePath>../../common/api-parent</relativePath>
+ <version>1.16.12-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>io.fd.honeycomb.nat</groupId>
+ <artifactId>nat-api</artifactId>
+ <name>${project.artifactId}</name>
+ <version>1.16.12-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <properties>
+ <naming.context.version>1.16.12-SNAPSHOT</naming.context.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.mdsal.model</groupId>
+ <artifactId>iana-if-type-2014-05-08</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal.model</groupId>
+ <artifactId>ietf-yang-types-20130715</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal.model</groupId>
+ <artifactId>ietf-interfaces</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal.model</groupId>
+ <artifactId>ietf-inet-types-2013-07-15</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal.model</groupId>
+ <artifactId>yang-ext</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.fd.honeycomb.vpp</groupId>
+ <artifactId>naming-context-api</artifactId>
+ <version>${naming.context.version}</version>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/nat/nat-api/src/main/yang/ietf-nat.yang b/nat/nat-api/src/main/yang/ietf-nat.yang
new file mode 100644
index 000000000..54707708c
--- /dev/null
+++ b/nat/nat-api/src/main/yang/ietf-nat.yang
@@ -0,0 +1,1074 @@
+module ietf-nat {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-nat";
+ //namespace to be assigned by IANA
+ prefix "nat";
+ import ietf-inet-types {
+ prefix "inet";
+ }
+
+ organization "IETF NetMod Working Group";
+ contact
+ "Senthil Sivakumar <ssenthil@cisco.com>
+ Mohamed Boucadair <mohamed.boucadair@orange.com>
+ Suresh Vinapamula <sureshk@juniper.net>";
+
+ description
+ "This module is a YANG module for NAT implementations
+ (including both NAT44 and NAT64 flavors.
+
+ Copyright (c) 2015 IETF Trust and the persons identified as
+ authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC XXXX; see
+ the RFC itself for full legal notices.";
+
+ revision 2015-09-08 {
+ description "Fixes few YANG errors.";
+ reference "-02";
+ }
+
+ revision 2015-09-07 {
+ description "Completes the NAT64 model.";
+ reference "01";
+ }
+
+ revision 2015-08-29 {
+ description "Initial version.";
+ reference "00";
+ }
+
+ typedef percent {
+ type uint8 {
+ range "0 .. 100";
+ }
+ description
+ "Percentage";
+ }
+
+ /*
+ * Grouping
+ */
+
+ grouping timeouts {
+ description
+ "Configure values of various timeouts.";
+
+ leaf udp-timeouts {
+ type uint32;
+ default 300;
+ description
+ "UDP inactivity timeout.";
+ }
+
+ leaf tcp-idle-timeout {
+ type uint32;
+ default 7440;
+ description
+ "TCP Idle timeout, as per RFC 5382 should be no
+ 2 hours and 4 minutes.";
+ }
+
+ leaf tcp-trans-open-timeout {
+ type uint32;
+ default 240;
+ description
+ "The value of the transitory open connection
+ idle-timeout.";
+ }
+
+ leaf tcp-trans-close-timeout {
+ type uint32;
+ default 240;
+ description
+ "The value of the transitory close connection
+ idle-timeout.";
+ }
+
+ leaf tcp-in-syn-timeout {
+ type uint32;
+ default 6;
+ description
+ "6 seconds, as defined in [RFC5382].";
+ }
+
+ leaf fragment-min-timeout {
+ type uint32;
+ default 2;
+ description
+ "As long as the NAT has available resources,
+ the NAT allows the fragments to arrive
+ over fragment-min-timeout interval.
+ The default value is inspired from RFC6146.";
+ }
+
+ leaf icmp-timeout {
+ type uint32;
+ default 60;
+ description
+ "60 seconds, as defined in [RFC5508].";
+ }
+ }
+
+ // port numbers: single or port range
+
+ grouping port-number {
+ description
+ "Individual port or a range of ports.";
+
+ choice port-type {
+ default single-port-number;
+ description
+ "Port type: single or port-range.";
+
+ case single-port-number {
+ leaf single-port-number {
+ type inet:port-number;
+ description
+ "Used for single port numbers.";
+ }
+ }
+
+ case port-range {
+ leaf start-port-number {
+ type inet:port-number;
+ description
+ "Begining of the port range.";
+ }
+
+ leaf end-port-number {
+ type inet:port-number;
+ description
+ "End of the port range.";
+ }
+ }
+ }
+ }
+
+ grouping mapping-entry {
+ description
+ "NAT mapping entry.";
+
+ leaf index {
+ type uint32;
+ description
+ "A unique identifier of a mapping entry.";
+ }
+
+ leaf type {
+ type enumeration {
+ enum "static" {
+ description
+ "The mapping entry is manually configured.";
+ }
+
+ enum "dynamic" {
+ description
+ "This mapping is created by an outgoing
+ packet.";
+ }
+ }
+ description
+ "Indicates the type of a mapping entry. E.g.,
+ a mapping can be: static or dynamic";
+ }
+
+ leaf internal-src-address {
+ type inet:ip-address;
+ mandatory true;
+ description
+ "Corresponds to the source IPv4/IPv6 address
+ of the IPv4 packet";
+ }
+
+ container internal-src-port {
+ description
+ "Corresponds to the source port of the
+ IPv4 packet.";
+ uses port-number;
+ }
+
+ leaf external-src-address {
+ type inet:ipv4-address;
+ mandatory true;
+ description
+ "External IPv4 address assigned by NAT";
+ }
+
+ container external-src-port {
+ description
+ "External source port number assigned by NAT.";
+ uses port-number;
+ }
+
+ leaf transport-protocol {
+ type uint8;
+ // mandatory true;
+ description
+ "Upper-layer protocol associated with this mapping.
+ Values are taken from the IANA protocol registry.
+ For example, this field contains 6 (TCP) for a TCP
+ mapping or 17 (UDP) for a UDP mapping.";
+ }
+
+ leaf internal-dst-address {
+ type inet:ipv4-prefix;
+ description
+ "Corresponds to the destination IPv4 address
+ of the IPv4 packet, for example, some NAT
+ implementation support translating both source
+ and destination address and ports referred to as
+ Twice NAT";
+ }
+
+ container internal-dst-port {
+ description
+ "Corresponds to the destination port of the
+ IPv4 packet.";
+ uses port-number;
+ }
+
+ leaf external-dst-address {
+ type inet:ipv4-address;
+ description
+ "External destination IPv4 address";
+ }
+
+ container external-dst-port {
+ description
+ "External source port number.";
+ uses port-number;
+ }
+
+ leaf lifetime {
+ type uint32;
+ // mandatory true;
+ description
+ "Lifetime of the mapping.";
+ }
+ }
+
+ grouping nat-parameters {
+ description
+ "NAT parameters for a given instance";
+
+ list external-ip-address-pool {
+ key pool-id;
+
+
+ description
+ "Pool of external IP addresses used to service
+ internal hosts.
+ Both contiguous and non-contiguous pools
+ can be configured for NAT.";
+
+ leaf pool-id {
+ type uint32;
+ description
+ "An identifier of the address pool.";
+ }
+
+ leaf external-ip-pool {
+ type inet:ipv4-prefix;
+ description
+ "An IPv4 prefix used for NAT purposes.";
+ }
+ }
+
+
+ leaf subscriber-mask-v6 {
+ type uint8 {
+ range "0 .. 128";
+ }
+ description
+ "The subscriber-mask is an integer that indicates
+ the length of significant bits to be applied on
+ the source IP address (internal side) to
+ unambiguously identify a CPE.
+
+ Subscriber-mask is a system-wide configuration
+ parameter that is used to enforce generic
+ per-subscriberpolicies (e.g., port-quota).
+
+ The enforcement of these generic policies does not
+ require the configuration of every subscriber's
+ prefix.
+
+ Example: suppose the 2001:db8:100:100::/56 prefix
+ is assigned to a NAT64 serviced CPE. Suppose also
+ that 2001:db8:100:100::1 is the IPv6 address used
+ by the client that resides in that CPE. When the
+ NAT64 receives a packet from this client,
+ it applies the subscriber-mask (e.g., 56) on
+ the source IPv6 address to compute the associated
+ prefix for this client (2001:db8:100:100::/56).
+ Then, the NAT64 enforces policies based on that
+ prefix (2001:db8:100:100::/56), not on the exact
+ source IPv6 address.";
+ }
+
+
+ list subscriber-mask-v4 {
+
+ key sub-mask-id;
+
+ description
+ "IPv4 subscriber mask.";
+
+ leaf sub-mask-id {
+ type uint32;
+ description
+ "An identifier of the subscriber masks.";
+ }
+ leaf sub-mask {
+ type inet:ipv4-prefix;
+ // mandatory true;
+ description
+ "The IP address subnets that matches
+ should be translated. E.g., If the
+ private realms that are to be translated
+ by NAT would be 192.0.2.0/24";
+ }
+ }
+
+ leaf paired-address-pooling {
+ type boolean;
+ default true;
+ description
+ "Paired address pooling is indicating to NAT
+ that all the flows from an internal IP
+ address must be assigned the same external
+ address. This is defined in RFC 4007.";
+ }
+
+ leaf nat-mapping-type {
+ type enumeration {
+ enum "eim" {
+ description
+ "endpoint-independent-mapping.
+ Refer section 4 of RFC 4787.";
+ }
+
+ enum "adm" {
+ description
+ "address-dependent-mapping.
+ Refer section 4 of RFC 4787.";
+ }
+
+ enum "edm" {
+ description
+ "address-and-port-dependent-mapping.
+ Refer section 4 of RFC 4787.";
+ }
+ }
+ description
+ "Indicates the type of a NAT mapping.";
+ }
+ leaf nat-filtering-type {
+ type enumeration {
+ enum "eif" {
+ description
+ "endpoint-independent- filtering.
+ Refer section 5 of RFC 4787.";
+ }
+
+ enum "adf" {
+ description
+ "address-dependent- filtering.
+ Refer section 5 of RFC 4787.";
+ }
+
+ enum "edf" {
+ description
+ "address-and-port-dependent- filtering.
+ Refer section 5 of RFC 4787.";
+ }
+ }
+ description
+ "Indicates the type of a NAT filtering.";
+ }
+
+ leaf port-quota {
+ type uint16;
+ description
+ "Configures a port quota to be assigned per
+ subscriber.";
+ }
+
+ container port-set {
+ description
+ "Manages port-set assignments.";
+
+ leaf port-set-enable {
+ type boolean;
+ description
+ "Enable/Disable port set assignment.";
+ }
+
+ leaf port-set-size {
+ type uint16;
+ description
+ "Indicates the size of assigned port
+ sets.";
+ }
+
+ leaf port-set-timeout {
+ type uint32;
+ description
+ "Inactivty timeout for port sets.";
+ }
+ }
+
+ leaf port-randomization-enable {
+ type boolean;
+ description
+ "Enable/disable port randomization
+ feature.";
+ }
+
+ leaf port-preservation-enable {
+ type boolean;
+ description
+ "Indicates whether the PCP server should
+ preserve the internal port number.";
+ }
+
+ leaf port-range-preservation-enable {
+ type boolean;
+ description
+ "Indicates whether the NAT device should
+ preserve the internal port range.";
+ }
+
+ leaf port-parity-preservation-enable {
+ type boolean;
+ description
+ "Indicates whether the PCP server should
+ preserve the port parity of the
+ internal port number.";
+ }
+ leaf address-roundrobin-enable {
+ type boolean;
+ description
+ "Enable/disable address allocation
+ round robin.";
+ }
+
+ uses timeouts;
+ container logging-info {
+ description
+ "Information about Logging NAT events";
+
+ leaf destination-address {
+ type inet:ipv4-prefix;
+ // mandatory true;
+ description
+ "Address of the collector that receives
+ the logs";
+ }
+ leaf destination-port {
+ type inet:port-number;
+ // mandatory true;
+ description
+ "Destination port of the collector.";
+ }
+
+ }
+ container connection-limit {
+ description
+ "Information on the config parameters that
+ rate limit the translations based on various
+ criteria";
+
+ leaf limit-per-subscriber {
+ type uint32;
+ description
+ "Maximum number of NAT mappings per
+ subscriber.";
+ }
+ leaf limit-per-vrf {
+ type uint32;
+ description
+ "Maximum number of NAT mappings per
+ VLAN/VRF.";
+ }
+ leaf limit-per-subnet {
+ type inet:ipv4-prefix;
+ description
+ "Maximum number of NAT mappings per
+ subnet.";
+ }
+ leaf limit-per-instance {
+ type uint32;
+ // mandatory true;
+ description
+ "Maximum number of NAT mappings per
+ instance.";
+ }
+ }
+ container mapping-limit {
+ description
+ "Information on the config parameters that
+ rate limit the mappings based on various
+ criteria";
+
+ leaf limit-per-subscriber {
+ type uint32;
+ description
+ "Maximum number of NAT mappings per
+ subscriber.";
+ }
+ leaf limit-per-vrf {
+ type uint32;
+ description
+ "Maximum number of NAT mappings per
+ VLAN/VRF.";
+ }
+ leaf limit-per-subnet {
+ type inet:ipv4-prefix;
+ description
+ "Maximum number of NAT mappings per
+ subnet.";
+ }
+ leaf limit-per-instance {
+ type uint32;
+ // mandatory true;
+ description
+ "Maximum number of NAT mappings per
+ instance.";
+ }
+ }
+ leaf ftp-alg-enable {
+ type boolean;
+ description
+ "Enable/Disable FTP ALG";
+ }
+
+ leaf dns-alg-enable {
+ type boolean;
+ description
+ "Enable/Disable DNSALG";
+ }
+
+ leaf tftp-alg-enable {
+ type boolean;
+ description
+ "Enable/Disable TFTP ALG";
+ }
+
+ leaf msrpc-alg-enable {
+ type boolean;
+ description
+ "Enable/Disable MS-RPC ALG";
+ }
+
+ leaf netbios-alg-enable {
+ type boolean;
+ description
+ "Enable/Disable NetBIOS ALG";
+ }
+
+ leaf rcmd-alg-enable {
+ type boolean;
+ description
+ "Enable/Disable rcmd ALG";
+ }
+
+ leaf ldap-alg-enable {
+ type boolean;
+ description
+ "Enable/Disable LDAP ALG";
+ }
+
+ leaf sip-alg-enable {
+ type boolean;
+ description
+ "Enable/Disable SIP ALG";
+ }
+
+ leaf rtsp-alg-enable {
+ type boolean;
+ description
+ "Enable/Disable RTSP ALG";
+ }
+
+ leaf h323-alg-enable {
+ type boolean;
+ description
+ "Enable/Disable H323 ALG";
+ }
+
+ leaf all-algs-enable {
+ type boolean;
+ description
+ "Enable/Disable all the ALGs";
+ }
+
+ container notify-pool-usage {
+ description
+ "Notification of Pool usage when certain criteria
+ is met";
+
+ leaf pool-id {
+ type uint32;
+ description
+ "Pool-ID for which the notification
+ criteria is defined";
+ }
+
+ leaf notify-pool-hi-threshold {
+ type percent;
+ // mandatory true;
+ description
+ "Notification must be generated when the
+ defined high threshold is reached.
+ For example, if a notification is
+ required when the pool utilization reaches
+ 90%, this configuration parameter must
+ be set to 90%";
+ }
+
+ leaf notify-pool-low-threshold {
+ type percent;
+ description
+ "Notification must be generated when the defined
+ low threshold is reached.
+ For example, if a notification is required when
+ the pool utilization reaches below 10%,
+ this configuration parameter must be set to
+ 10%";
+ }
+ }
+ list nat64-prefixes {
+ key nat64-prefix-id;
+
+ description
+ "Provides one or a list of NAT64 prefixes
+ With or without a list of destination IPv4 prefixes.
+
+ Destination-based Pref64::/n is discussed in
+ Section 5.1 of [RFC7050]). For example:
+ 192.0.2.0/24 is mapped to 2001:db8:122:300::/56.
+ 198.51.100.0/24 is mapped to 2001:db8:122::/48.";
+
+ leaf nat64-prefix-id {
+ type uint32;
+ description
+ "An identifier of the NAT64 prefix.";
+ }
+
+ leaf nat64-prefix {
+ type inet:ipv6-prefix;
+ default "64:ff9b::/96";
+ description
+ "A NAT64 prefix. Can be NSP or WKP [RFC6052].";
+ }
+
+ list destination-ipv4-prefix {
+
+ key ipv4-prefix-id;
+
+ description
+ "An IPv4 prefix/address.";
+
+ leaf ipv4-prefix-id {
+ type uint32;
+ description
+ "An identifier of the IPv4 prefix/address.";
+ }
+
+ leaf ipv4-prefix {
+ type inet:ipv4-prefix;
+ description
+ "An IPv4 address/prefix. ";
+ }
+ }
+ }
+ } //nat-parameters group
+
+ container nat-config {
+ description
+ "NAT";
+
+ container nat-instances {
+ description
+ "nat instances";
+
+ list nat-instance {
+
+ key "id";
+
+ description
+ "A NAT instance.";
+
+ leaf id {
+ type uint32;
+ description
+ "NAT instance identifier.";
+ }
+
+ leaf enable {
+ type boolean;
+ description
+ "Status of the the NAT instance.";
+ }
+
+ uses nat-parameters;
+
+ container mapping-table {
+ description
+ "NAT dynamic mapping table used to track
+ sessions";
+
+ list mapping-entry {
+ key "index";
+ description
+ "NAT mapping entry.";
+ uses mapping-entry;
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * NAT State
+ */
+
+ container nat-state {
+
+ config false;
+
+ description
+ "nat-state";
+
+ container nat-instances {
+ description
+ "nat instances";
+
+ list nat-instance {
+ key "id";
+
+ description
+ "nat instance";
+
+ leaf id {
+ // FIXME changed int32 to uint32 to align with nat-config (authors of draft notified)
+ type uint32;
+ description
+ "The identifier of the nat instance.";
+ }
+
+ container nat-capabilities {
+ description
+ "NAT Capabilities";
+
+ leaf nat44-support {
+ type boolean;
+ description
+ "Indicates NAT44 support";
+ }
+
+ leaf nat64-support {
+ type boolean;
+ description
+ "Indicates NAT64 support";
+ }
+
+ leaf static-mapping-support {
+ type boolean;
+ description
+ "Indicates whether static mappings are
+ supported.";
+ }
+
+ leaf port-set-support {
+ type boolean;
+ description
+ "Indicates port set assignment
+ support ";
+ }
+
+ leaf port-randomization-support {
+ type boolean;
+ description
+ "Indicates whether port randomization is
+ supported.";
+ }
+
+ leaf port-range-preservation-support {
+ type boolean;
+ description
+ "Indicates whether port range
+ preservation is supported.";
+ }
+
+ leaf port-preservation-suport {
+ type boolean;
+ description
+ "Indicates whether port preservation
+ is supported.";
+ }
+
+ leaf port-parity-preservation-support {
+ type boolean;
+ description
+ "Indicates whether port parity
+ preservation is supported.";
+ }
+
+ leaf address-roundrobin-support {
+ type boolean;
+ description
+ "Indicates whether address allocation
+ round robin is supported.";
+ }
+
+ leaf ftp-alg-support {
+ type boolean;
+ description
+ "Indicates whether FTP ALG is supported";
+ }
+
+ leaf dns-alg-support {
+ type boolean;
+ description
+ "Indicates whether DNSALG is supported";
+ }
+
+ leaf tftp-support {
+ type boolean;
+ description
+ "Indicates whether TFTP ALG is supported";
+ }
+
+ leaf msrpc-alg-support {
+ type boolean;
+ description
+ "Indicates whether MS-RPC ALG is supported";
+ }
+
+ leaf netbios-alg-support {
+ type boolean;
+ description
+ "Indicates whether NetBIOS ALG is supported";
+ }
+
+ leaf rcmd-alg-support {
+ type boolean;
+ description
+ "Indicates whether rcmd ALG is supported";
+ }
+
+ leaf ldap-alg-support {
+ type boolean;
+ description
+ "Indicates whether LDAP ALG is supported";
+ }
+
+ leaf sip-alg-support {
+ type boolean;
+ description
+ "Indicates whether SIP ALG is supported";
+ }
+
+ leaf rtsp-alg-support {
+ type boolean;
+ description
+ "Indicates whether RTSP ALG is supported";
+ }
+
+ leaf h323-alg-support {
+ type boolean;
+ description
+ "Indicates whether H323 ALG is supported";
+ }
+
+ leaf paired-address-pooling-support {
+ type boolean;
+ description
+ "Indicates whether paired-address-pooling is
+ supported";
+ }
+
+ leaf endpoint-independent-mapping-support {
+ type boolean;
+ description
+ "Indicates whether endpoint-independent-mapping
+ in Section 4 of RFC 4787 is supported.";
+ }
+
+ leaf address-dependent-mapping-support {
+ type boolean;
+ description
+ "Indicates whether endpoint-independent-mapping
+ in Section 4 of RFC 4787 is supported.";
+ }
+
+ leaf address-and-port-dependent-mapping-support {
+ type boolean;
+ description
+ "Indicates whether endpoint-independent-mapping in
+ section 4 of RFC 4787 is supported.";
+ }
+
+ leaf endpoint-independent-filtering-support {
+ type boolean;
+ description
+ "Indicates whether endpoint-independent-mapping in
+ section 5 of RFC 4787 is supported.";
+ }
+
+ leaf address-dependent-filtering {
+ type boolean;
+ description
+ "Indicates whether endpoint-independent-mapping in
+ section 5 of RFC 4787 is supported.";
+ }
+
+ leaf address-and-port-dependent-filtering {
+ type boolean;
+ description
+ "Indicates whether endpoint-independent-mapping in
+ section 5 of RFC 4787 is supported.";
+ }
+
+ leaf stealth-mode-support {
+ type boolean;
+ description
+ "Indicates whether to respond for unsolicited
+ traffic.";
+ }
+
+ }
+
+ container nat-current-config {
+ description
+ "current config";
+
+ uses nat-parameters;
+ }
+
+ container mapping-table {
+ description
+ "Mapping table";
+ list mapping-entry {
+ key "index";
+ description
+ "mapping entry";
+ uses mapping-entry;
+ }
+ }
+
+ container statistics {
+ description
+ "Statistics related to the NAT instance";
+
+ leaf total-mappings {
+ type uint32;
+ description
+ "Total number of NAT Mappings present
+ at the time. This includes all the
+ static and dynamic mappings";
+ }
+ leaf total-tcp-mappings {
+ type uint32;
+ description
+ "Total number of TCP Mappings present
+ at the time.";
+ }
+ leaf total-udp-mappings {
+ type uint32;
+ description
+ "Total number of UDP Mappings present
+ at the time.";
+ }
+ leaf total-icmp-mappings {
+ type uint32;
+ description
+ "Total number of ICMP Mappings present
+ at the time.";
+ }
+ container pool-stats {
+ description
+ "Statistics related to Pool usage";
+ leaf pool-id {
+ type uint32;
+ description
+ "Unique Identifier that represents
+ a pool";
+ }
+ leaf address-allocated {
+ type uint32;
+ description
+ "Number of allocated addresses in
+ the pool";
+ }
+ leaf address-free {
+ type uint32;
+ description
+ "Number of free addresses in
+ the pool.The sum of free
+ addresses and allocated
+ addresses are the total
+ addresses in the pool";
+ }
+ container port-stats {
+ description
+ "Statistics related to port
+ usage.";
+
+ leaf ports-allocated {
+ type uint32;
+ description
+ "Number of allocated ports
+ in the pool";
+ }
+
+ leaf ports-free {
+ type uint32;
+ description
+ "Number of free addresses
+ in the pool";
+ }
+ }
+ }
+ } //statistics
+ } //nat-instance
+ } //nat-instances
+ } //nat-state
+ /*
+ * Notifications
+ */
+ notification nat-event {
+ description
+ "Notifications must be generated when the defined
+ high/low threshold is reached. Related configuration
+ parameters must be provided to trigger
+ the notifications.";
+
+ leaf id {
+ type leafref {
+ path
+ "/nat-state/nat-instances/"
+ + "nat-instance/id";
+ }
+ description
+ "NAT instance ID.";
+ }
+
+ leaf notify-pool-threshold {
+ type percent;
+ // mandatory true;
+ description
+ "A treshhold has been fired.";
+ }
+ }
+} //module nat \ No newline at end of file
diff --git a/nat/nat-api/src/main/yang/interface-nat.yang b/nat/nat-api/src/main/yang/interface-nat.yang
new file mode 100644
index 000000000..43a6bf0c4
--- /dev/null
+++ b/nat/nat-api/src/main/yang/interface-nat.yang
@@ -0,0 +1,44 @@
+module interface-nat {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:interface:nat";
+ prefix "ifc-nat";
+
+ revision "2016-12-14" {
+ description "Initial revision of v3po model";
+ }
+
+ import ietf-interfaces {
+ prefix "if";
+ }
+ import ietf-nat {
+ prefix "nat";
+ }
+ import yang-ext {
+ prefix "ext";
+ }
+
+ description "Augmentations to interfaces model to connect interfaces with nat configuration";
+
+ grouping interface-nat-attributes {
+ container nat {
+ container inbound {
+ presence "Enables inbound NAT";
+ }
+ container outbound {
+ presence "Enables outbound NAT";
+ }
+ }
+ }
+
+ augment /if:interfaces/if:interface {
+ ext:augment-identifier "nat-interface-augmentation";
+
+ uses interface-nat-attributes;
+ }
+
+ augment /if:interfaces-state/if:interface {
+ ext:augment-identifier "nat-interface-state-augmentation";
+
+ uses interface-nat-attributes;
+ }
+} \ No newline at end of file
diff --git a/nat/nat-api/src/main/yang/nat-context.yang b/nat/nat-api/src/main/yang/nat-context.yang
new file mode 100644
index 000000000..dd17ed58c
--- /dev/null
+++ b/nat/nat-api/src/main/yang/nat-context.yang
@@ -0,0 +1,64 @@
+module nat-context {
+ yang-version 1;
+ namespace "urn:honeycomb:params:xml:ns:yang:nat:context";
+ prefix "nc";
+
+ description "Context for nat mapping";
+
+ revision "2016-12-14" {
+ description "Initial revision.";
+ }
+
+ import ietf-inet-types {
+ prefix "inet";
+ }
+
+ import naming-context {
+ prefix "nc";
+ }
+
+ import yang-ext {
+ prefix "ext";
+ }
+
+ grouping mapping-entry-context-attributes {
+ container nat-mapping-entry-context {
+ list nat-instance {
+ key "id";
+
+ leaf id {
+ type uint32;
+ description "ID of the NAT instance from ietf-nat. Maps to VRF-ID in VPP";
+ }
+
+ container mapping-table {
+ list mapping-entry {
+
+ key "internal external";
+ unique "index";
+
+ leaf internal {
+ type inet:ip-address;
+ description "Local IP address set in VPP";
+ }
+
+ leaf external {
+ type inet:ip-address;
+ description "Extarnal IP address set in VPP";
+ }
+
+ leaf index {
+ type uint32;
+ description "ID of the NAT's mapping entry from ietf-nat";
+ }
+ }
+ }
+ }
+ }
+ }
+
+ augment /nc:contexts {
+ ext:augment-identifier "nat-mapping-entry-ctx-augmentation";
+ uses mapping-entry-context-attributes;
+ }
+} \ No newline at end of file
diff --git a/nat/nat2vpp/asciidoc/Readme.adoc b/nat/nat2vpp/asciidoc/Readme.adoc
new file mode 100644
index 000000000..732401198
--- /dev/null
+++ b/nat/nat2vpp/asciidoc/Readme.adoc
@@ -0,0 +1,3 @@
+= nat2vpp
+
+Uses jvpp-snat to work with VPP's SNAT plugin. \ No newline at end of file
diff --git a/nat/nat2vpp/pom.xml b/nat/nat2vpp/pom.xml
new file mode 100644
index 000000000..ba8204d6c
--- /dev/null
+++ b/nat/nat2vpp/pom.xml
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>io.fd.honeycomb.vpp</groupId>
+ <artifactId>vpp-impl-parent</artifactId>
+ <relativePath>../../vpp-common/vpp-impl-parent</relativePath>
+ <version>1.16.12-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>io.fd.honeycomb.nat</groupId>
+ <artifactId>nat2vpp</artifactId>
+ <name>${project.artifactId}</name>
+ <version>1.16.12-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <properties>
+ <honeycomb.infra.version>1.16.12-SNAPSHOT</honeycomb.infra.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>nat-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <!--VPP common-->
+ <dependency>
+ <groupId>io.fd.honeycomb.vpp</groupId>
+ <artifactId>vpp-translate-utils</artifactId>
+ </dependency>
+
+ <!-- JVPP -->
+ <dependency>
+ <groupId>io.fd.vpp</groupId>
+ <artifactId>jvpp-registry</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.fd.vpp</groupId>
+ <artifactId>jvpp-snat</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+
+ <!-- Honeycomb infrastructure-->
+ <dependency>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>minimal-distribution</artifactId>
+ <version>${honeycomb.infra.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>translate-api</artifactId>
+ <version>${honeycomb.infra.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>translate-spi</artifactId>
+ <version>${honeycomb.infra.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>cfg-init</artifactId>
+ <version>${honeycomb.infra.version}</version>
+ </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>
+
+ <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>com.google.inject.extensions</groupId>
+ <artifactId>guice-testlib</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.hamcrest</groupId>
+ <artifactId>hamcrest-all</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/NatModule.java b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/NatModule.java
new file mode 100644
index 000000000..b33f900e5
--- /dev/null
+++ b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/NatModule.java
@@ -0,0 +1,77 @@
+/*
+ * 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.honeycomb.nat;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.inject.AbstractModule;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+import com.google.inject.multibindings.Multibinder;
+import io.fd.honeycomb.data.init.DataTreeInitializer;
+import io.fd.honeycomb.nat.init.NatInitializer;
+import io.fd.honeycomb.nat.jvpp.JVppSnatProvider;
+import io.fd.honeycomb.nat.read.NatReaderFactory;
+import io.fd.honeycomb.nat.read.ifc.IfcNatReaderFactory;
+import io.fd.honeycomb.nat.util.MappingEntryContext;
+import io.fd.honeycomb.nat.write.NatWriterFactory;
+import io.fd.honeycomb.nat.write.ifc.IfcNatWriterFactory;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import io.fd.vpp.jvpp.snat.future.FutureJVppSnatFacade;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Module class instantiating nat plugin components.
+ */
+public final class NatModule extends AbstractModule {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NatModule.class);
+ private final Class<? extends Provider<FutureJVppSnatFacade>> jvppSnatProviderClass;
+
+ public NatModule() {
+ this(JVppSnatProvider.class);
+ }
+
+ @VisibleForTesting
+ NatModule(Class<? extends Provider<FutureJVppSnatFacade>> jvppSnatProvider) {
+ this.jvppSnatProviderClass = jvppSnatProvider;
+ }
+
+ @Override
+ protected void configure() {
+ // Mapping entry context util
+ bind(MappingEntryContext.class).toInstance(new MappingEntryContext());
+
+ LOG.debug("Installing NAT module");
+
+ // Bind to Plugin's JVPP
+ bind(FutureJVppSnatFacade.class).toProvider(jvppSnatProviderClass).in(Singleton.class);
+
+ final Multibinder<ReaderFactory> readBinder = Multibinder.newSetBinder(binder(), ReaderFactory.class);
+ readBinder.addBinding().to(IfcNatReaderFactory.class).in(Singleton.class);
+ readBinder.addBinding().to(NatReaderFactory.class).in(Singleton.class);
+
+ final Multibinder<WriterFactory> writeBinder = Multibinder.newSetBinder(binder(), WriterFactory.class);
+ writeBinder.addBinding().to(IfcNatWriterFactory.class).in(Singleton.class);
+ writeBinder.addBinding().to(NatWriterFactory.class).in(Singleton.class);
+
+ Multibinder.newSetBinder(binder(), DataTreeInitializer.class)
+ .addBinding().to(NatInitializer.class).in(Singleton.class);
+ LOG.info("Module NAT successfully configured");
+ }
+}
diff --git a/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/init/NatInitializer.java b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/init/NatInitializer.java
new file mode 100644
index 000000000..37c456133
--- /dev/null
+++ b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/init/NatInitializer.java
@@ -0,0 +1,63 @@
+/*
+ * 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.honeycomb.nat.init;
+
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import io.fd.honeycomb.data.init.AbstractDataTreeConverter;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.NatConfig;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.NatConfigBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.NatState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.NatInstancesBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.NatInstanceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.MappingTableBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntryBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Initialize nat-config from nat-state.
+ */
+public final class NatInitializer extends AbstractDataTreeConverter<NatState, NatConfig> {
+
+ @Inject
+ public NatInitializer(@Named("honeycomb-initializer") @Nonnull final DataBroker bindingDataBroker) {
+ super(bindingDataBroker, InstanceIdentifier.create(NatState.class), InstanceIdentifier.create(NatConfig.class));
+ }
+
+ @Override
+ public NatConfig convert(final NatState operationalData) {
+ return new NatConfigBuilder()
+ .setNatInstances(new NatInstancesBuilder()
+ .setNatInstance(operationalData.getNatInstances().getNatInstance().stream()
+ .map(operNatInstance -> new NatInstanceBuilder()
+ .setId(operNatInstance.getId())
+ .setMappingTable(new MappingTableBuilder()
+ .setMappingEntry(
+ operNatInstance.getMappingTable().getMappingEntry().stream()
+ .map(operEntry -> new MappingEntryBuilder(operEntry).build())
+ .collect(Collectors.toList()))
+ .build())
+ .build())
+ .collect(Collectors.toList()))
+ .build())
+ .build();
+ // TODO implement initialization for nat inbound/outbound NAT feature after VPP-459
+ }
+}
diff --git a/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/jvpp/JVppSnatProvider.java b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/jvpp/JVppSnatProvider.java
new file mode 100755
index 000000000..b83665679
--- /dev/null
+++ b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/jvpp/JVppSnatProvider.java
@@ -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.honeycomb.nat.jvpp;
+
+import com.google.inject.Inject;
+import io.fd.honeycomb.infra.distro.ProviderTrait;
+import io.fd.vpp.jvpp.JVppRegistry;
+import io.fd.vpp.jvpp.snat.JVppSnatImpl;
+import io.fd.vpp.jvpp.snat.future.FutureJVppSnatFacade;
+import java.io.IOException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Provides future API for jvpp-nsh plugin. Must be a singleton due to shutdown hook usage.
+ * Registers shutdown hook to free plugin's resources on shutdown.
+ */
+public final class JVppSnatProvider extends ProviderTrait<FutureJVppSnatFacade> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(JVppSnatProvider.class);
+
+ @Inject
+ private JVppRegistry registry;
+
+ @Override
+ protected FutureJVppSnatFacade create() {
+ try {
+ final JVppSnatImpl jvppSnat = new JVppSnatImpl();
+ // Free jvpp-nsh plugin's resources on shutdown
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ @Override
+ public void run() {
+ LOG.info("Unloading jvpp-snat plugin");
+ jvppSnat.close();
+ LOG.info("Successfully unloaded jvpp-snat plugin");
+ }
+ });
+
+ LOG.info("Successfully loaded jvpp-snat plugin");
+ return new FutureJVppSnatFacade(registry, jvppSnat);
+ } catch (IOException e) {
+ throw new IllegalStateException("Unable to open VPP management connection", e);
+ }
+ }
+}
+
diff --git a/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/MappingEntryCustomizer.java b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/MappingEntryCustomizer.java
new file mode 100644
index 000000000..469d361ee
--- /dev/null
+++ b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/MappingEntryCustomizer.java
@@ -0,0 +1,151 @@
+/*
+ * 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.honeycomb.nat.read;
+
+import io.fd.honeycomb.nat.util.MappingEntryContext;
+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.honeycomb.translate.util.read.cache.EntityDumpExecutor;
+import io.fd.honeycomb.translate.vpp.util.Ipv4Translator;
+import io.fd.honeycomb.translate.vpp.util.JvppReplyConsumer;
+import io.fd.vpp.jvpp.snat.dto.SnatStaticMappingDetails;
+import io.fd.vpp.jvpp.snat.dto.SnatStaticMappingDetailsReplyDump;
+import io.fd.vpp.jvpp.snat.dto.SnatStaticMappingDump;
+import io.fd.vpp.jvpp.snat.future.FutureJVppSnatFacade;
+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.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.mapping.entry.ExternalSrcPortBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.mapping.entry.InternalSrcPortBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.state.nat.instances.NatInstance;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.state.nat.instances.nat.instance.MappingTableBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.state.nat.instances.nat.instance.mapping.table.MappingEntry;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.state.nat.instances.nat.instance.mapping.table.MappingEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.state.nat.instances.nat.instance.mapping.table.MappingEntryKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.port.number.port.type.SinglePortNumberBuilder;
+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 MappingEntryCustomizer implements Ipv4Translator,
+ ListReaderCustomizer<MappingEntry, MappingEntryKey, MappingEntryBuilder> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(MappingEntryCustomizer.class);
+
+ private final DumpCacheManager<SnatStaticMappingDetailsReplyDump, Void> dumpCacheManager;
+ private final MappingEntryContext mappingEntryContext;
+
+ public MappingEntryCustomizer(final DumpCacheManager<SnatStaticMappingDetailsReplyDump, Void> dumpCacheManager,
+ final MappingEntryContext mappingEntryContext) {
+ this.dumpCacheManager = dumpCacheManager;
+ this.mappingEntryContext = mappingEntryContext;
+ }
+
+ @Nonnull
+ @Override
+ public MappingEntryBuilder getBuilder(@Nonnull final InstanceIdentifier<MappingEntry> id) {
+ return new MappingEntryBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<MappingEntry> id,
+ @Nonnull final MappingEntryBuilder builder, @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+ LOG.trace("Reading current attributes for mapping-entry: {}", id);
+
+ final int idx = id.firstKeyOf(MappingEntry.class).getIndex().intValue();
+ final int natInstanceId = id.firstKeyOf(NatInstance.class).getId().intValue();
+ final List<SnatStaticMappingDetails> details =
+ dumpCacheManager.getDump(id, getClass().getName(), ctx.getModificationCache(), null)
+ .or(new SnatStaticMappingDetailsReplyDump()).snatStaticMappingDetails;
+ final SnatStaticMappingDetails snatStaticMappingDetails =
+ mappingEntryContext.findDetails(details, natInstanceId, idx, ctx.getMappingContext());
+
+ builder.setIndex((long) idx);
+ builder.setType(
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.MappingEntry.Type.Static);
+ // Snat only supports ipv4 for now
+ builder.setExternalSrcAddress(arrayToIpv4AddressNoZoneReversed(snatStaticMappingDetails.externalIpAddress));
+ builder.setInternalSrcAddress(
+ new IpAddress(arrayToIpv4AddressNoZoneReversed(snatStaticMappingDetails.localIpAddress)));
+
+ if (snatStaticMappingDetails.addrOnly == 0) {
+ builder.setExternalSrcPort(new ExternalSrcPortBuilder()
+ .setPortType(new SinglePortNumberBuilder().setSinglePortNumber(new PortNumber(
+ (int) snatStaticMappingDetails.externalPort))
+ .build())
+ .build());
+ builder.setInternalSrcPort(new InternalSrcPortBuilder()
+ .setPortType(new SinglePortNumberBuilder().setSinglePortNumber(new PortNumber(
+ (int) snatStaticMappingDetails.localPort))
+ .build())
+ .build());
+ }
+
+ LOG.trace("Mapping-entry read as: {}", builder);
+ }
+
+ @Nonnull
+ @Override
+ public List<MappingEntryKey> getAllIds(@Nonnull final InstanceIdentifier<MappingEntry> id,
+ @Nonnull final ReadContext context) throws ReadFailedException {
+ final Long natInstanceId = id.firstKeyOf(NatInstance.class).getId();
+ LOG.trace("Listing IDs for all mapping-entries within nat-instance(vrf):{}", natInstanceId);
+
+ final List<MappingEntryKey> entryKeys =
+ dumpCacheManager.getDump(id, getClass().getName(), context.getModificationCache(), null)
+ .or(new SnatStaticMappingDetailsReplyDump()).snatStaticMappingDetails.stream()
+ .filter(detail -> natInstanceId == detail.vrfId)
+ .map(detail -> mappingEntryContext
+ .getStoredOrArtificialIndex(natInstanceId, detail, context.getMappingContext()))
+ .map(MappingEntryKey::new)
+ .collect(Collectors.toList());
+ LOG.debug("List of mapping-entry keys within nat-instance(vrf):{} : {}", natInstanceId, entryKeys);
+
+ return entryKeys;
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> builder,
+ @Nonnull final List<MappingEntry> readData) {
+ ((MappingTableBuilder) builder).setMappingEntry(readData);
+ }
+
+ static final class MappingEntryDumpExecutor
+ implements EntityDumpExecutor<SnatStaticMappingDetailsReplyDump, Void>, JvppReplyConsumer {
+
+ private final FutureJVppSnatFacade jvppSnat;
+
+ MappingEntryDumpExecutor(final FutureJVppSnatFacade jvppSnat) {
+ this.jvppSnat = jvppSnat;
+ }
+
+ @Nonnull
+ @Override
+ public SnatStaticMappingDetailsReplyDump executeDump(final InstanceIdentifier<?> identifier, final Void params)
+ throws ReadFailedException {
+ return getReplyForRead(jvppSnat.snatStaticMappingDump(new SnatStaticMappingDump()).toCompletableFuture(),
+ identifier);
+ }
+ }
+}
diff --git a/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/NatInstanceCustomizer.java b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/NatInstanceCustomizer.java
new file mode 100644
index 000000000..cb639b962
--- /dev/null
+++ b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/NatInstanceCustomizer.java
@@ -0,0 +1,84 @@
+/*
+ * 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.honeycomb.nat.read;
+
+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.snat.dto.SnatStaticMappingDetailsReplyDump;
+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.nat.rev150908.nat.state.NatInstancesBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.state.nat.instances.NatInstance;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.state.nat.instances.NatInstanceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.state.nat.instances.NatInstanceKey;
+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;
+
+/**
+ * Nat instance ID is mapped to VRF-ID in VPP.
+ */
+final class NatInstanceCustomizer implements ListReaderCustomizer<NatInstance, NatInstanceKey, NatInstanceBuilder> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NatInstanceCustomizer.class);
+
+ private final DumpCacheManager<SnatStaticMappingDetailsReplyDump, Void> dumpCacheManager;
+
+ public NatInstanceCustomizer(final DumpCacheManager<SnatStaticMappingDetailsReplyDump, Void> dumpCacheManager) {
+ this.dumpCacheManager = dumpCacheManager;
+ }
+
+ @Nonnull
+ @Override
+ public NatInstanceBuilder getBuilder(@Nonnull final InstanceIdentifier<NatInstance> id) {
+ return new NatInstanceBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<NatInstance> id,
+ @Nonnull final NatInstanceBuilder builder, @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+ LOG.trace("Reading current attributes for nat-instance: {}", id);
+ builder.setId(id.firstKeyOf(NatInstance.class).getId());
+ }
+
+ @Nonnull
+ @Override
+ public List<NatInstanceKey> getAllIds(@Nonnull final InstanceIdentifier<NatInstance> id,
+ @Nonnull final ReadContext context) throws ReadFailedException {
+ LOG.trace("Listing IDs for all nat-instances");
+ final List<NatInstanceKey> vrfIds =
+ dumpCacheManager.getDump(id, getClass().getName(), context.getModificationCache(), null)
+ .or(new SnatStaticMappingDetailsReplyDump()).snatStaticMappingDetails.stream()
+ .map(detail -> detail.vrfId)
+ .map(vrfId -> new NatInstanceKey((long)vrfId))
+ .collect(Collectors.toList());
+
+ LOG.debug("List of nat-instance keys (vrf-ids): {}", vrfIds);
+ return vrfIds;
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> builder, @Nonnull final List<NatInstance> readData) {
+ ((NatInstancesBuilder) builder).setNatInstance(readData);
+ }
+}
diff --git a/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/NatReaderFactory.java b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/NatReaderFactory.java
new file mode 100644
index 000000000..949009c62
--- /dev/null
+++ b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/NatReaderFactory.java
@@ -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.honeycomb.nat.read;
+
+import com.google.common.collect.Sets;
+import com.google.inject.Inject;
+import io.fd.honeycomb.nat.util.MappingEntryContext;
+import io.fd.honeycomb.translate.impl.read.GenericListReader;
+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.snat.dto.SnatStaticMappingDetailsReplyDump;
+import io.fd.vpp.jvpp.snat.future.FutureJVppSnatFacade;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.NatState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.NatStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.mapping.entry.ExternalSrcPort;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.mapping.entry.InternalSrcPort;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.state.NatInstances;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.state.NatInstancesBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.state.nat.instances.NatInstance;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.state.nat.instances.nat.instance.MappingTable;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.state.nat.instances.nat.instance.MappingTableBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.state.nat.instances.nat.instance.mapping.table.MappingEntry;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class NatReaderFactory implements ReaderFactory {
+
+ private static final InstanceIdentifier<NatState> NAT_OPER_ID = InstanceIdentifier.create(NatState.class);
+ private static final InstanceIdentifier<NatInstances> NAT_INSTANCES_ID = NAT_OPER_ID.child(NatInstances.class);
+ private static final InstanceIdentifier<NatInstance> NAT_INSTANCE_ID = NAT_INSTANCES_ID.child(NatInstance.class);
+ private static final InstanceIdentifier<MappingTable> MAP_TABLE_ID = NAT_INSTANCE_ID.child(MappingTable.class);
+ private static final InstanceIdentifier<MappingEntry> MAP_ENTRY_ID = MAP_TABLE_ID.child(MappingEntry.class);
+
+ private final MappingEntryContext mappingEntryContext;
+ private final DumpCacheManager<SnatStaticMappingDetailsReplyDump, Void> dumpCacheManager;
+
+ @Inject
+ public NatReaderFactory(final FutureJVppSnatFacade jvppSnat,
+ final MappingEntryContext mappingEntryContext) {
+ this.mappingEntryContext = mappingEntryContext;
+ this.dumpCacheManager = new DumpCacheManager.DumpCacheManagerBuilder<SnatStaticMappingDetailsReplyDump, Void>()
+ .withExecutor(new MappingEntryCustomizer.MappingEntryDumpExecutor(jvppSnat))
+ .build();
+ }
+
+ @Override
+ public void init(@Nonnull final ModifiableReaderRegistryBuilder registry) {
+ registry.addStructuralReader(NAT_OPER_ID, NatStateBuilder.class);
+ registry.addStructuralReader(NAT_INSTANCES_ID, NatInstancesBuilder.class);
+ registry.add(new GenericListReader<>(NAT_INSTANCE_ID, new NatInstanceCustomizer(dumpCacheManager)));
+ registry.addStructuralReader(MAP_TABLE_ID, MappingTableBuilder.class);
+ registry.subtreeAdd(Sets.newHashSet(InstanceIdentifier.create(MappingEntry.class).child(ExternalSrcPort.class),
+ InstanceIdentifier.create(MappingEntry.class).child(InternalSrcPort.class)),
+ new GenericListReader<>(MAP_ENTRY_ID,
+ new MappingEntryCustomizer(dumpCacheManager, mappingEntryContext)));
+
+ // TODO VPP-453 Implement address range read
+
+ }
+}
diff --git a/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/IfcNatReaderFactory.java b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/IfcNatReaderFactory.java
new file mode 100644
index 000000000..293a3dfd9
--- /dev/null
+++ b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/IfcNatReaderFactory.java
@@ -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.honeycomb.nat.read.ifc;
+
+
+import io.fd.honeycomb.translate.impl.read.GenericReader;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214.NatInterfaceStateAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214.NatInterfaceStateAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.Nat;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.NatBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.nat.Inbound;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.nat.Outbound;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Factory producing readers for nat plugin's data.
+ */
+public final class IfcNatReaderFactory implements ReaderFactory {
+
+ private static final InstanceIdentifier<Interface>
+ IFC_ID = InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
+ private static final InstanceIdentifier<NatInterfaceStateAugmentation> NAT_AUG_ID =
+ IFC_ID.augmentation(NatInterfaceStateAugmentation.class);
+ private static final InstanceIdentifier<Nat> NAT_AUG_CONTAINER_ID = NAT_AUG_ID.child(Nat.class);
+
+ @Override
+ public void init(@Nonnull final ModifiableReaderRegistryBuilder registry) {
+ registry.addStructuralReader(NAT_AUG_ID, NatInterfaceStateAugmentationBuilder.class);
+ registry.addStructuralReader(NAT_AUG_CONTAINER_ID, NatBuilder.class);
+
+ registry.addAfter(
+ new GenericReader<>(NAT_AUG_CONTAINER_ID.child(Inbound.class), new InterfaceInboundNatCustomizer()), IFC_ID);
+ registry.addAfter(
+ new GenericReader<>(NAT_AUG_CONTAINER_ID.child(Outbound.class), new InterfaceOutboundNatCustomizer()), IFC_ID);
+ }
+}
diff --git a/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/InterfaceInboundNatCustomizer.java b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/InterfaceInboundNatCustomizer.java
new file mode 100644
index 000000000..e1ebdd6d8
--- /dev/null
+++ b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/InterfaceInboundNatCustomizer.java
@@ -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.honeycomb.nat.read.ifc;
+
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.NatBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.nat.Inbound;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.nat.InboundBuilder;
+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 final class InterfaceInboundNatCustomizer implements ReaderCustomizer<Inbound, InboundBuilder> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(InterfaceInboundNatCustomizer.class);
+
+ @Nonnull
+ @Override
+ public InboundBuilder getBuilder(@Nonnull final InstanceIdentifier<Inbound> id) {
+ return new InboundBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Inbound> id,
+ @Nonnull final InboundBuilder builder,
+ @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+ // FIXME HONEYCOMB-248 VPP-459 Implement when read is available in VPP/Snat
+ LOG.debug("Unable to read Inbound NAT feature state for an interface");
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final Inbound readValue) {
+ ((NatBuilder) parentBuilder).setInbound(readValue);
+ }
+}
diff --git a/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/InterfaceOutboundNatCustomizer.java b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/InterfaceOutboundNatCustomizer.java
new file mode 100644
index 000000000..fe28584ff
--- /dev/null
+++ b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/read/ifc/InterfaceOutboundNatCustomizer.java
@@ -0,0 +1,54 @@
+/*
+ * 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.honeycomb.nat.read.ifc;
+
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.NatBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.nat.Outbound;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.nat.OutboundBuilder;
+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 final class InterfaceOutboundNatCustomizer implements ReaderCustomizer<Outbound, OutboundBuilder> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(InterfaceOutboundNatCustomizer.class);
+
+ @Nonnull
+ @Override
+ public OutboundBuilder getBuilder(@Nonnull final InstanceIdentifier<Outbound> id) {
+ return new OutboundBuilder();
+ }
+
+ @Override
+ public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Outbound> id,
+ @Nonnull final OutboundBuilder builder, @Nonnull final ReadContext ctx)
+ throws ReadFailedException {
+ // FIXME HONEYCOMB-248 VPP-459 Implement when read is available in VPP/Snat
+ LOG.debug("Unable to read Outbound NAT feature state for an interface");
+ }
+
+ @Override
+ public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final Outbound readValue) {
+ ((NatBuilder) parentBuilder).setOutbound(readValue);
+ }
+}
diff --git a/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/util/MappingEntryContext.java b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/util/MappingEntryContext.java
new file mode 100644
index 000000000..0f2df7e1d
--- /dev/null
+++ b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/util/MappingEntryContext.java
@@ -0,0 +1,210 @@
+/*
+ * 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.honeycomb.nat.util;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.vpp.util.Ipv4Translator;
+import io.fd.vpp.jvpp.snat.dto.SnatStaticMappingDetails;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import javax.annotation.Nonnull;
+import javax.annotation.concurrent.ThreadSafe;
+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.nat.context.rev161214.NatMappingEntryCtxAugmentation;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.nat.context.rev161214.mapping.entry.context.attributes.NatMappingEntryContext;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.nat.context.rev161214.mapping.entry.context.attributes.nat.mapping.entry.context.NatInstance;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.nat.context.rev161214.mapping.entry.context.attributes.nat.mapping.entry.context.NatInstanceKey;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.nat.context.rev161214.mapping.entry.context.attributes.nat.mapping.entry.context.nat.instance.MappingTable;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.nat.context.rev161214.mapping.entry.context.attributes.nat.mapping.entry.context.nat.instance.mapping.table.MappingEntry;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.nat.context.rev161214.mapping.entry.context.attributes.nat.mapping.entry.context.nat.instance.mapping.table.MappingEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.nat.context.rev161214.mapping.entry.context.attributes.nat.mapping.entry.context.nat.instance.mapping.table.MappingEntryKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Context tracker for Nat Mapping entries.
+ */
+@ThreadSafe
+public class MappingEntryContext implements Ipv4Translator {
+
+ private static final Logger LOG = LoggerFactory.getLogger(MappingEntryContext.class);
+
+ /**
+ * Add mapping entry to index mapping to context.
+ */
+ public synchronized void addEntry(final long natInstanceId,
+ final long entryId,
+ @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntry entry,
+ @Nonnull final MappingContext mappingContext) {
+ final InstanceIdentifier<MappingEntry> id = getId(natInstanceId, entryToKey(entry));
+ checkArgument(!containsEntry(natInstanceId, entry, mappingContext), "Mapping for %s already present", id);
+ mappingContext.put(id, toCtxMapEntry(entry, entryId));
+ }
+
+ /**
+ * Check whether mapping entry to index mapping already exists in context.
+ */
+ public synchronized boolean containsEntry(final long natInstanceId,
+ @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntry entry,
+ @Nonnull final MappingContext mappingContext) {
+ final InstanceIdentifier<MappingEntry> id = getId(natInstanceId, entryToKey(entry));
+ return mappingContext.read(id).isPresent();
+ }
+
+ @VisibleForTesting
+ static InstanceIdentifier<MappingEntry> getId(final Long natInstanceId, final MappingEntryKey key) {
+ return getTableId(natInstanceId).child(MappingEntry.class, key);
+ }
+
+ @VisibleForTesting
+ static InstanceIdentifier<MappingTable> getTableId(final long natInstanceId) {
+ return InstanceIdentifier.create(Contexts.class)
+ .augmentation(NatMappingEntryCtxAugmentation.class)
+ .child(NatMappingEntryContext.class)
+ .child(NatInstance.class, new NatInstanceKey(natInstanceId))
+ .child(MappingTable.class);
+ }
+
+ @VisibleForTesting
+ static MappingEntryKey entryToKey(
+ final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntry entry) {
+ // Only IPv4
+ return new MappingEntryKey(new IpAddress(entry.getExternalSrcAddress()), entry.getInternalSrcAddress());
+ }
+
+ private MappingEntryKey entryToKey(final SnatStaticMappingDetails entry) {
+ // Only IPv4
+ return new MappingEntryKey(
+ new IpAddress(new Ipv4Address(arrayToIpv4AddressNoZoneReversed(entry.externalIpAddress))),
+ new IpAddress(new Ipv4Address(arrayToIpv4AddressNoZoneReversed(entry.localIpAddress))));
+ }
+
+ private boolean equalEntries(final SnatStaticMappingDetails detail, final MappingEntry ctxMappingEntry) {
+ final IpAddress internalAddrFromDetails =
+ new IpAddress(new Ipv4Address(arrayToIpv4AddressNoZoneReversed(detail.localIpAddress)));
+ // Only IPv4
+ if (!ctxMappingEntry.getInternal().equals(internalAddrFromDetails)) {
+ return false;
+ }
+ // Only IPv4
+ final IpAddress externalAddrFromDetails =
+ new IpAddress(new Ipv4Address(arrayToIpv4AddressNoZoneReversed(detail.externalIpAddress)));
+ if (!ctxMappingEntry.getExternal().equals(externalAddrFromDetails)) {
+ return false;
+ }
+ return true;
+ }
+
+ @VisibleForTesting
+ static MappingEntry toCtxMapEntry(
+ @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntry entry,
+ final long entryId) {
+ return new MappingEntryBuilder()
+ .setKey(entryToKey(entry))
+ .setIndex(entryId)
+ .build();
+ }
+
+ private MappingEntry toCtxMapEntry(@Nonnull final SnatStaticMappingDetails details, final long entryId) {
+ return new MappingEntryBuilder()
+ .setKey(entryToKey(details))
+ .setIndex(entryId)
+ .build();
+ }
+
+ /**
+ * Delete mapping of mapping entry to index from context.
+ */
+ public synchronized void removeEntry(final long natInstanceId,
+ @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntry entry,
+ @Nonnull final MappingContext mappingContext) {
+ mappingContext.delete(getId(natInstanceId, entryToKey(entry)));
+ }
+
+ /**
+ * Find specific details in provided collection identified with provided index.
+ */
+ public synchronized SnatStaticMappingDetails findDetails(@Nonnull final List<SnatStaticMappingDetails> details,
+ final long natInstanceId, final long idx,
+ @Nonnull final MappingContext mappingContext) {
+ // Find mapping entry for Index
+ final MappingEntry ctxMappingEntry = mappingContext.read(getTableId(natInstanceId))
+ .transform(MappingTable::getMappingEntry)
+ .or(Collections.emptyList())
+ .stream()
+ .filter(entry -> entry.getIndex() == idx)
+ .findFirst()
+ .orElseThrow(() -> new IllegalStateException("Unable to find context mapping for nat-instance: "
+ + natInstanceId + " and ID: " + idx));
+
+ // Find which details matches the context stored entry under index
+ return details.stream()
+ .filter(detail -> equalEntries(detail, ctxMappingEntry))
+ .findFirst()
+ .orElseThrow(() -> new IllegalStateException("Unable to match mapping for nat-instance: "
+ + natInstanceId + " and match: " + ctxMappingEntry + " in: " + details));
+ }
+
+ /**
+ * Get index for a mapping entry details or create an artificial one.
+ */
+ public synchronized long getStoredOrArtificialIndex(final Long natInstanceId,
+ @Nonnull final SnatStaticMappingDetails details,
+ @Nonnull final MappingContext mappingContext) {
+ return mappingContext.read(getId(natInstanceId, entryToKey(details)))
+ .transform(MappingEntry::getIndex)
+ .or(() -> getArtificialId(details, natInstanceId, mappingContext));
+ }
+
+ /**
+ * Get index for a stored mapping entry.
+ */
+ public synchronized Optional<Long> getStoredIndex(final long natInstanceId,
+ @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntry entry,
+ @Nonnull final MappingContext mappingContext) {
+ return mappingContext.read(getId(natInstanceId, entryToKey(entry)))
+ .transform(MappingEntry::getIndex);
+ }
+
+ private long getArtificialId(final SnatStaticMappingDetails details, final Long natInstanceId,
+ final MappingContext mappingContext) {
+ LOG.trace("Assigning artificial ID for {}", details);
+ final long artificialIdx = findFreeIndex(natInstanceId, mappingContext);
+ LOG.debug("Artificial ID for {} assigned as: {}", details, artificialIdx);
+ mappingContext.put(getId(natInstanceId, entryToKey(details)), toCtxMapEntry(details, artificialIdx));
+ return artificialIdx;
+ }
+
+ private long findFreeIndex(final long natInstanceId, final MappingContext mappingContext) {
+ return mappingContext.read(getTableId(natInstanceId))
+ .transform(MappingTable::getMappingEntry)
+ .or(Collections.emptyList())
+ .stream()
+ .map(MappingEntry::getIndex)
+ .max(Comparator.naturalOrder())
+ .map(i -> i + 1)
+ .orElse(0L);
+ }
+}
diff --git a/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/MappingEntryCustomizer.java b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/MappingEntryCustomizer.java
new file mode 100644
index 000000000..785606942
--- /dev/null
+++ b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/MappingEntryCustomizer.java
@@ -0,0 +1,182 @@
+/*
+ * 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.honeycomb.nat.write;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.base.Optional;
+import io.fd.honeycomb.nat.util.MappingEntryContext;
+import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
+import io.fd.honeycomb.translate.vpp.util.Ipv4Translator;
+import io.fd.honeycomb.translate.vpp.util.JvppReplyConsumer;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.snat.dto.SnatAddStaticMapping;
+import io.fd.vpp.jvpp.snat.future.FutureJVppSnatFacade;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.NatInstance;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntry;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntryKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.port.number.PortType;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.port.number.port.type.SinglePortNumber;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class MappingEntryCustomizer implements ListWriterCustomizer<MappingEntry, MappingEntryKey>,
+ JvppReplyConsumer, Ipv4Translator {
+
+ private static final Logger LOG = LoggerFactory.getLogger(MappingEntryCustomizer.class);
+
+ private final FutureJVppSnatFacade jvppSnat;
+ private final MappingEntryContext mappingEntryContext;
+
+ MappingEntryCustomizer(final FutureJVppSnatFacade jvppSnat, final MappingEntryContext mappingEntryContext) {
+ this.jvppSnat = jvppSnat;
+ this.mappingEntryContext = mappingEntryContext;
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<MappingEntry> id,
+ @Nonnull final MappingEntry dataAfter,
+ @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ // Only static mapping supported by SNAT for now
+ checkArgument(dataAfter.getType() ==
+ org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.MappingEntry.Type.Static,
+ "Only static NAT entries are supported currently. Trying to write: %s entry", dataAfter.getType());
+ final Long natInstanceId = id.firstKeyOf(NatInstance.class).getId();
+ final Long mappingEntryId = id.firstKeyOf(MappingEntry.class).getIndex();
+ LOG.debug("Writing mapping entry: {} for nat-instance(vrf): {}", natInstanceId, mappingEntryId);
+
+ final SnatAddStaticMapping request = getRequest(id, dataAfter, natInstanceId, true);
+ getReplyForWrite(jvppSnat.snatAddStaticMapping(request).toCompletableFuture(), id);
+
+ // Store context mapping only if not already present under the same exact mapping
+ synchronized (mappingEntryContext) {
+ if (shouldStoreContextMapping(natInstanceId, mappingEntryId, dataAfter, writeContext)) {
+ mappingEntryContext
+ .addEntry(natInstanceId, mappingEntryId, dataAfter, writeContext.getMappingContext());
+ }
+ }
+ LOG.trace("Mapping entry: {} for nat-instance(vrf): {} written successfully", request.vrfId, id);
+ }
+
+ /**
+ * Check whether entry is already stored in context under the same index.
+ *
+ * @return true if it's not yet stored under same index, false otherwise.
+ */
+ private boolean shouldStoreContextMapping(final long natInstanceId, final long mappingEntryId,
+ final MappingEntry dataAfter,
+ final WriteContext writeCtx) {
+ if (!mappingEntryContext.containsEntry(natInstanceId, dataAfter, writeCtx.getMappingContext())) {
+ return true;
+ }
+
+ final Optional<Long> storedIndex =
+ mappingEntryContext.getStoredIndex(natInstanceId, dataAfter, writeCtx.getMappingContext());
+ if (!storedIndex.isPresent()) {
+ return true;
+ }
+
+ if (storedIndex.get() != mappingEntryId) {
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<MappingEntry> id,
+ @Nonnull final MappingEntry dataBefore,
+ @Nonnull final MappingEntry dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter,
+ new UnsupportedOperationException("Mapping entry update not supported"));
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<MappingEntry> id,
+ @Nonnull final MappingEntry dataBefore,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ final long natInstanceId = id.firstKeyOf(NatInstance.class).getId();
+ final MappingEntryKey mappingEntryKey = id.firstKeyOf(MappingEntry.class);
+ LOG.debug("Deleting mapping entry: {} for nat-instance(vrf): {}", natInstanceId, mappingEntryKey);
+
+ final SnatAddStaticMapping request = getRequest(id, dataBefore, natInstanceId, false);
+ getReplyForWrite(jvppSnat.snatAddStaticMapping(request).toCompletableFuture(), id);
+ mappingEntryContext.removeEntry(natInstanceId, dataBefore, writeContext.getMappingContext());
+ LOG.trace("Mapping entry: {} for nat-instance(vrf): {} deleted successfully", request.vrfId, id);
+ }
+
+ private SnatAddStaticMapping getRequest(final InstanceIdentifier<MappingEntry> id,
+ final MappingEntry dataAfter,
+ final Long natInstanceId,
+ final boolean isAdd)
+ throws WriteFailedException.CreateFailedException {
+ final SnatAddStaticMapping request = new SnatAddStaticMapping();
+ request.isAdd = isAdd
+ ? (byte) 1
+ : 0;
+ request.isIp4 = 1;
+ // VPP uses int, model long
+ request.vrfId = natInstanceId.intValue();
+
+ // Snat supports only ipv4 now
+ if (dataAfter.getInternalSrcAddress().getIpv4Address() == null) {
+ throw new WriteFailedException.CreateFailedException(id, dataAfter,
+ new UnsupportedOperationException(
+ String.format("No Ipv4 present for in address %s. Ipv6 not supported",
+ dataAfter.getInternalSrcAddress())));
+ }
+
+ request.addrOnly = 1;
+ request.localIpAddress =
+ ipv4AddressNoZoneToArray(dataAfter.getInternalSrcAddress().getIpv4Address().getValue());
+ request.externalIpAddress = ipv4AddressNoZoneToArray(dataAfter.getExternalSrcAddress().getValue());
+
+ Optional<Short> internalPortNumber = getPortNumber(id, dataAfter,
+ (entry) -> Optional.fromNullable(entry.getInternalSrcPort()).transform(PortNumber::getPortType));
+ Optional<Short> externalPortNumber = getPortNumber(id, dataAfter,
+ (entry) -> Optional.fromNullable(entry.getExternalSrcPort()).transform(PortNumber::getPortType));
+ if (internalPortNumber.isPresent() && externalPortNumber.isPresent()) {
+ request.addrOnly = 0;
+ request.localPort = internalPortNumber.get();
+ request.externalPort = externalPortNumber.get();
+ }
+ return request;
+ }
+
+ private Optional<Short> getPortNumber(final InstanceIdentifier<MappingEntry> id, final MappingEntry dataAfter,
+ final PortGetter portGetter) {
+ return portGetter.getPortType(dataAfter).transform(port -> {
+ if (port instanceof SinglePortNumber) {
+ return ((SinglePortNumber) port).getSinglePortNumber().getValue().shortValue();
+ } else {
+ throw new IllegalArgumentException(
+ String.format("Only single port number supported. Submitted: %s for entry: %s",
+ dataAfter.getInternalSrcPort(), id));
+ }
+ });
+ }
+
+ interface PortGetter {
+ Optional<PortType> getPortType(MappingEntry entry);
+ }
+}
diff --git a/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/NatInstaceCustomizer.java b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/NatInstaceCustomizer.java
new file mode 100644
index 000000000..3cc477dd0
--- /dev/null
+++ b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/NatInstaceCustomizer.java
@@ -0,0 +1,53 @@
+/*
+ * 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.honeycomb.nat.write;
+
+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.nat.rev150908.nat.config.nat.instances.NatInstance;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.NatInstanceKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class NatInstaceCustomizer implements ListWriterCustomizer<NatInstance, NatInstanceKey> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NatInstaceCustomizer.class);
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<NatInstance> id,
+ @Nonnull final NatInstance dataAfter, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.trace("Writing nat-instance: {}", id);
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<NatInstance> id,
+ @Nonnull final NatInstance dataBefore, @Nonnull final NatInstance dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ LOG.trace("Updating nat-instance: {}", id);
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<NatInstance> id,
+ @Nonnull final NatInstance dataBefore, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ LOG.trace("Deleting nat-instance: {}", id);
+ }
+}
diff --git a/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/NatWriterFactory.java b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/NatWriterFactory.java
new file mode 100644
index 000000000..ecc886bf0
--- /dev/null
+++ b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/NatWriterFactory.java
@@ -0,0 +1,66 @@
+/*
+ * 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.honeycomb.nat.write;
+
+import com.google.common.collect.Sets;
+import com.google.inject.Inject;
+import io.fd.honeycomb.nat.util.MappingEntryContext;
+import io.fd.honeycomb.translate.impl.write.GenericListWriter;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
+import io.fd.vpp.jvpp.snat.future.FutureJVppSnatFacade;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.NatConfig;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.mapping.entry.ExternalSrcPort;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.mapping.entry.InternalSrcPort;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.NatInstances;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.NatInstance;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.MappingTable;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntry;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Nat Writers registration.
+ */
+public final class NatWriterFactory implements WriterFactory {
+
+ private static final InstanceIdentifier<NatConfig> NAT_CFG_ID = InstanceIdentifier.create(NatConfig.class);
+ private static final InstanceIdentifier<NatInstance> NAT_INSTANCE_ID =
+ NAT_CFG_ID.child(NatInstances.class).child(NatInstance.class);
+ private static final InstanceIdentifier<MappingEntry> MAP_ENTRY_ID =
+ NAT_INSTANCE_ID.child(MappingTable.class).child(MappingEntry.class);
+
+ private final FutureJVppSnatFacade jvppSnat;
+ private final MappingEntryContext mappingEntryContext;
+
+ @Inject
+ public NatWriterFactory(final FutureJVppSnatFacade jvppSnat,
+ final MappingEntryContext mappingEntryContext) {
+ this.jvppSnat = jvppSnat;
+ this.mappingEntryContext = mappingEntryContext;
+ }
+
+ @Override
+ public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) {
+ // Nat-instance
+ registry.add(new GenericListWriter<>(NAT_INSTANCE_ID, new NatInstaceCustomizer()));
+ // Mapping-entry
+ registry.subtreeAdd(Sets.newHashSet(InstanceIdentifier.create(MappingEntry.class).child(ExternalSrcPort.class),
+ InstanceIdentifier.create(MappingEntry.class).child(InternalSrcPort.class)),
+ new GenericListWriter<>(MAP_ENTRY_ID, new MappingEntryCustomizer(jvppSnat, mappingEntryContext)));
+ }
+}
diff --git a/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/ifc/AbstractInterfaceNatCustomizer.java b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/ifc/AbstractInterfaceNatCustomizer.java
new file mode 100644
index 000000000..64e714241
--- /dev/null
+++ b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/ifc/AbstractInterfaceNatCustomizer.java
@@ -0,0 +1,105 @@
+/*
+ * 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.honeycomb.nat.write.ifc;
+
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
+import io.fd.honeycomb.translate.vpp.util.JvppReplyConsumer;
+import io.fd.honeycomb.translate.vpp.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriteContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.snat.dto.SnatInterfaceAddDelFeature;
+import io.fd.vpp.jvpp.snat.dto.SnatInterfaceAddDelFeatureReply;
+import io.fd.vpp.jvpp.snat.future.FutureJVppSnatFacade;
+import java.util.concurrent.CompletionStage;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+
+abstract class AbstractInterfaceNatCustomizer<D extends DataObject> implements JvppReplyConsumer, WriterCustomizer<D> {
+
+ private final FutureJVppSnatFacade jvppSnat;
+ private final NamingContext ifcContext;
+
+ AbstractInterfaceNatCustomizer(@Nonnull final FutureJVppSnatFacade jvppSnat,
+ @Nonnull final NamingContext ifcContext) {
+ this.jvppSnat = jvppSnat;
+ this.ifcContext = ifcContext;
+ }
+
+ @Override
+ public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<D> id, @Nonnull final D dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ final String ifcName = id.firstKeyOf(Interface.class).getName();
+ getLog().debug("Enabling " + getType() + " NAT on interface: {}", ifcName);
+ getLog().debug("Enabling " + getType() + " NAT: {}", id);
+
+ final int ifcIndex = ifcContext.getIndex(ifcName, writeContext.getMappingContext());
+ final SnatInterfaceAddDelFeature request = getRequest(ifcIndex, (byte)1);
+ final CompletionStage<SnatInterfaceAddDelFeatureReply> future = jvppSnat.snatInterfaceAddDelFeature(request);
+
+ final SnatInterfaceAddDelFeatureReply reply = getReplyForWrite(future.toCompletableFuture(), id);
+ getLog().debug("NAT " + getType() + " enabled successfully on: {}, reply: {}", ifcName, reply);
+ }
+
+ @Override
+ public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<D> id,
+ @Nonnull final D dataBefore, @Nonnull final D dataAfter,
+ @Nonnull final WriteContext writeContext) throws WriteFailedException {
+ throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter,
+ new UnsupportedOperationException("Unable to update NAT feature"));
+ }
+
+ @Override
+ public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<D> id,
+ @Nonnull final D dataBefore, @Nonnull final WriteContext writeContext)
+ throws WriteFailedException {
+ final String ifcName = id.firstKeyOf(Interface.class).getName();
+ getLog().debug("Disabling " + getType() + " NAT on interface: {}", ifcName);
+ getLog().debug("Disabling " + getType() + " NAT: {}", id);
+
+ final int ifcIndex = ifcContext.getIndex(ifcName, writeContext.getMappingContext());
+ final SnatInterfaceAddDelFeature request = getRequest(ifcIndex, (byte)0);
+ final CompletionStage<SnatInterfaceAddDelFeatureReply> future = jvppSnat.snatInterfaceAddDelFeature(request);
+
+ final SnatInterfaceAddDelFeatureReply reply = getReplyForWrite(future.toCompletableFuture(), id);
+ getLog().debug("NAT " + getType() + " disabled successfully on: {}, reply: {}", ifcName, reply);
+ }
+
+ enum NatType {
+ INBOUND((byte)1), OUTBOUND((byte)0);
+
+ private final byte isInside;
+
+ NatType(final byte isInside) {
+ this.isInside = isInside;
+ }
+ }
+
+ abstract NatType getType();
+ abstract Logger getLog();
+
+ private SnatInterfaceAddDelFeature getRequest(final int ifcIdx, final byte isAdd) {
+ final SnatInterfaceAddDelFeature request = new SnatInterfaceAddDelFeature();
+ request.isAdd = isAdd;
+ request.isInside = getType().isInside;
+ request.swIfIndex = ifcIdx;
+ return request;
+ }
+
+}
diff --git a/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/ifc/IfcNatWriterFactory.java b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/ifc/IfcNatWriterFactory.java
new file mode 100644
index 000000000..bf2c600a2
--- /dev/null
+++ b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/ifc/IfcNatWriterFactory.java
@@ -0,0 +1,62 @@
+/*
+ * 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.honeycomb.nat.write.ifc;
+
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import io.fd.honeycomb.translate.impl.write.GenericWriter;
+import io.fd.honeycomb.translate.vpp.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder;
+import io.fd.vpp.jvpp.snat.future.FutureJVppSnatFacade;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214.NatInterfaceAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.Nat;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.nat.Inbound;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.nat.Outbound;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Nat Writers registration.
+ */
+public final class IfcNatWriterFactory implements WriterFactory {
+
+ private static final InstanceIdentifier<Interface>
+ IFC_ID = InstanceIdentifier.create(Interfaces.class).child(Interface.class);
+ private static final InstanceIdentifier<Nat> NAT_AUG_ID =
+ IFC_ID .augmentation(NatInterfaceAugmentation.class).child(Nat.class);
+
+ private final FutureJVppSnatFacade jvppSnat;
+ private final NamingContext ifcContext;
+
+ @Inject
+ public IfcNatWriterFactory(final FutureJVppSnatFacade jvppSnat,
+ @Named("interface-context") final NamingContext ifcContext) {
+ this.jvppSnat = jvppSnat;
+ this.ifcContext = ifcContext;
+ }
+
+ @Override
+ public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) {
+ registry.addAfter(new GenericWriter<>(NAT_AUG_ID.child(Inbound.class),
+ new InterfaceInboundNatCustomizer(jvppSnat, ifcContext)), IFC_ID);
+ registry.addAfter(new GenericWriter<>(NAT_AUG_ID.child(Outbound.class),
+ new InterfaceOutboundNatCustomizer(jvppSnat, ifcContext)), IFC_ID);
+ }
+}
diff --git a/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/ifc/InterfaceInboundNatCustomizer.java b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/ifc/InterfaceInboundNatCustomizer.java
new file mode 100644
index 000000000..8ab1c284c
--- /dev/null
+++ b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/ifc/InterfaceInboundNatCustomizer.java
@@ -0,0 +1,44 @@
+/*
+ * 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.honeycomb.nat.write.ifc;
+
+import io.fd.honeycomb.translate.vpp.util.NamingContext;
+import io.fd.vpp.jvpp.snat.future.FutureJVppSnatFacade;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.nat.Inbound;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class InterfaceInboundNatCustomizer extends AbstractInterfaceNatCustomizer<Inbound> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(InterfaceInboundNatCustomizer.class);
+
+ InterfaceInboundNatCustomizer(@Nonnull final FutureJVppSnatFacade jvppSnat,
+ @Nonnull final NamingContext ifcContext) {
+ super(jvppSnat, ifcContext);
+ }
+
+ @Override
+ NatType getType() {
+ return NatType.INBOUND;
+ }
+
+ @Override
+ Logger getLog() {
+ return LOG;
+ }
+}
diff --git a/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/ifc/InterfaceOutboundNatCustomizer.java b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/ifc/InterfaceOutboundNatCustomizer.java
new file mode 100644
index 000000000..fdd174eba
--- /dev/null
+++ b/nat/nat2vpp/src/main/java/io/fd/honeycomb/nat/write/ifc/InterfaceOutboundNatCustomizer.java
@@ -0,0 +1,44 @@
+/*
+ * 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.honeycomb.nat.write.ifc;
+
+import io.fd.honeycomb.translate.vpp.util.NamingContext;
+import io.fd.vpp.jvpp.snat.future.FutureJVppSnatFacade;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.nat.rev161214._interface.nat.attributes.nat.Outbound;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class InterfaceOutboundNatCustomizer extends AbstractInterfaceNatCustomizer<Outbound> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(InterfaceOutboundNatCustomizer.class);
+
+ InterfaceOutboundNatCustomizer(@Nonnull final FutureJVppSnatFacade jvppSnat,
+ @Nonnull final NamingContext ifcContext) {
+ super(jvppSnat, ifcContext);
+ }
+
+ @Override
+ NatType getType() {
+ return NatType.OUTBOUND;
+ }
+
+ @Override
+ Logger getLog() {
+ return LOG;
+ }
+}
diff --git a/nat/nat2vpp/src/test/java/io/fd/honeycomb/nat/NatModuleTest.java b/nat/nat2vpp/src/test/java/io/fd/honeycomb/nat/NatModuleTest.java
new file mode 100644
index 000000000..774dd6f2a
--- /dev/null
+++ b/nat/nat2vpp/src/test/java/io/fd/honeycomb/nat/NatModuleTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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.honeycomb.nat;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.Matchers.empty;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import com.google.inject.Guice;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.multibindings.Multibinder;
+import com.google.inject.name.Named;
+import com.google.inject.testing.fieldbinder.Bind;
+import com.google.inject.testing.fieldbinder.BoundFieldModule;
+import io.fd.honeycomb.translate.read.ReaderFactory;
+import io.fd.honeycomb.translate.util.read.registry.CompositeReaderRegistryBuilder;
+import io.fd.honeycomb.translate.util.write.registry.FlatWriterRegistryBuilder;
+import io.fd.honeycomb.translate.vpp.util.NamingContext;
+import io.fd.honeycomb.translate.write.WriterFactory;
+import io.fd.vpp.jvpp.snat.future.FutureJVppSnatFacade;
+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;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+public class NatModuleTest {
+
+ @Named("honeycomb-context")
+ @Bind
+ @Mock
+ private DataBroker honeycombContext;
+
+ @Bind
+ private ReaderFactory ietfIfcReaderFactory;
+
+ @Named("honeycomb-initializer")
+ @Bind
+ @Mock
+ private DataBroker honeycombInitializer;
+
+ @Named("interface-context")
+ @Bind
+ private NamingContext ifcContext;
+
+ @Inject
+ private Set<ReaderFactory> readerFactories = new HashSet<>();
+
+ @Inject
+ private Set<WriterFactory> writerFactories = new HashSet<>();
+
+ @Before
+ public void setUp() throws Exception {
+ ietfIfcReaderFactory = registry -> {
+ registry.addStructuralReader(InstanceIdentifier.create(InterfacesState.class), InterfacesStateBuilder.class);
+ registry.addStructuralReader(InstanceIdentifier.create(InterfacesState.class).child(Interface.class), InterfaceBuilder.class);
+ };
+ initMocks(this);
+ ifcContext = new NamingContext("interface-", "interface-context");
+ // Nat Module adds readers under InterfacesState/Interface and since readers for parents that do nothing need to
+ // be present, add structural readers (or add V3poModule here, but adding the full Module is not the best solution)
+ Guice.createInjector(binder -> Multibinder.newSetBinder(binder, ReaderFactory.class)
+ .addBinding().toInstance(registry -> {
+ registry.addStructuralReader(InstanceIdentifier.create(InterfacesState.class),
+ InterfacesStateBuilder.class);
+ registry.addStructuralReader(InstanceIdentifier.create(InterfacesState.class).child(Interface.class),
+ InterfaceBuilder.class);
+ }), new NatModule(MockJVppSnatProvider.class), 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.forEach(factory -> factory.init(registryBuilder));
+ assertNotNull(registryBuilder.build());
+ }
+
+ @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.forEach(factory -> factory.init(registryBuilder));
+ assertNotNull(registryBuilder.build());
+ }
+
+ private static final class MockJVppSnatProvider implements Provider<FutureJVppSnatFacade> {
+
+ @Override
+ public FutureJVppSnatFacade get() {
+ return mock(FutureJVppSnatFacade.class);
+ }
+ }
+} \ No newline at end of file
diff --git a/nat/nat2vpp/src/test/java/io/fd/honeycomb/nat/util/MappingEntryContextTest.java b/nat/nat2vpp/src/test/java/io/fd/honeycomb/nat/util/MappingEntryContextTest.java
new file mode 100644
index 000000000..fee8def89
--- /dev/null
+++ b/nat/nat2vpp/src/test/java/io/fd/honeycomb/nat/util/MappingEntryContextTest.java
@@ -0,0 +1,198 @@
+/*
+ * 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.honeycomb.nat.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.vpp.util.Ipv4Translator;
+import io.fd.vpp.jvpp.snat.dto.SnatStaticMappingDetails;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.nat.context.rev161214.mapping.entry.context.attributes.nat.mapping.entry.context.nat.instance.MappingTableBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+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.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntry;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntryKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+@SuppressWarnings("unchecked")
+public class MappingEntryContextTest implements Ipv4Translator {
+
+ private MappingEntryContext ctx = new MappingEntryContext();
+ @Mock
+ private MappingContext mappingCtx;
+
+ @Before
+ public void setUp() throws Exception {
+ initMocks(this);
+ }
+
+ @Test
+ public void testAdd() throws Exception {
+ when(mappingCtx.read(any(InstanceIdentifier.class))).thenReturn(Optional.absent());
+ final long natId = 7;
+ final long entryId = 99;
+ final MappingEntry entry = getEntry(natId, "192.168.1.5", "17.14.4.6");
+
+ ctx.addEntry(natId, entryId, entry, mappingCtx);
+
+ verify(mappingCtx).put(MappingEntryContext.getId(natId, MappingEntryContext.entryToKey(entry)), MappingEntryContext.toCtxMapEntry(entry, entryId));
+ }
+
+ @Test
+ public void testRemove() throws Exception {
+ final long natId = 0;
+ final MappingEntry entry = getEntry(natId, "192.168.1.5", "17.14.4.6");
+
+ ctx.removeEntry(natId, entry, mappingCtx);
+
+ verify(mappingCtx).delete(MappingEntryContext.getId(natId, MappingEntryContext.entryToKey(entry)));
+ }
+
+ @Test
+ public void testGetExistingIndex() throws Exception {
+ final long natId = 0;
+ final long entryId = 12;
+ final MappingEntry entry = getEntry(entryId, "192.168.1.5", "17.14.4.6");
+ final SnatStaticMappingDetails details = getDetails(entryId, "192.168.1.5", "17.14.4.6");
+
+ when(mappingCtx.read(MappingEntryContext.getId(natId, MappingEntryContext.entryToKey(entry))))
+ .thenReturn(Optional.of(MappingEntryContext.toCtxMapEntry(entry, entryId)));
+
+ assertEquals(12, ctx.getStoredOrArtificialIndex(natId, details, mappingCtx));
+ verify(mappingCtx).read(MappingEntryContext.getId(natId, MappingEntryContext.entryToKey(entry)));
+ }
+
+ @Test
+ public void testFindDetails() throws Exception {
+ final long natId = 0;
+ final MappingEntry entry = getEntry(0, "192.168.1.5", "17.14.4.6");
+ final SnatStaticMappingDetails details = getDetails(0, "192.168.1.5", "17.14.4.6");
+ final MappingEntry entry2 = getEntry(1, "192.168.1.8", "17.14.4.10");
+ final SnatStaticMappingDetails details2 = getDetails(1, "192.168.1.8", "17.14.4.10");
+
+ final List<SnatStaticMappingDetails> someDetails = Lists.newArrayList(details, details2);
+
+ when(mappingCtx.read(MappingEntryContext.getTableId(natId)))
+ .thenReturn(Optional.of(new MappingTableBuilder()
+ .setMappingEntry(Lists.newArrayList(
+ MappingEntryContext.toCtxMapEntry(entry, 0),
+ MappingEntryContext.toCtxMapEntry(entry2, 1)))
+ .build()));
+
+ assertSame(details, ctx.findDetails(someDetails, natId, 0, mappingCtx));
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testFindDetailsNoMappingStored() throws Exception {
+ final long natId = 0;
+ final long entryId = 12;
+ final SnatStaticMappingDetails details = getDetails(entryId, "192.168.1.5", "17.14.4.6");
+ final List<SnatStaticMappingDetails> someDetails = Lists.newArrayList(details);
+ when(mappingCtx.read(MappingEntryContext.getTableId(natId))).thenReturn(Optional.absent());
+
+ ctx.findDetails(someDetails, natId, entryId, mappingCtx);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testFindDetailsNoMappingStored2() throws Exception {
+ final long natId = 0;
+ final long entryId = 12;
+ final SnatStaticMappingDetails details = getDetails(entryId, "192.168.1.5", "17.14.4.6");
+ final List<SnatStaticMappingDetails> someDetails = Lists.newArrayList(details);
+
+ when(mappingCtx.read(MappingEntryContext.getTableId(natId)))
+ .thenReturn(Optional.of(new MappingTableBuilder().setMappingEntry(Collections.emptyList()).build()));
+
+ ctx.findDetails(someDetails, natId, entryId, mappingCtx);
+ }
+
+ @Test
+ public void testGetArtificialIndex() throws Exception {
+ final long natId = 0;
+ final long entryId = 0;
+ final MappingEntry entry = getEntry(entryId, "192.168.1.5", "17.14.4.6");
+ final long entryId2 = 55;
+ final MappingEntry entry2 = getEntry(entryId2, "192.168.1.6", "17.14.4.7");
+ final long entryId3 = 18954;
+ final MappingEntry entry3 = getEntry(entryId3, "192.168.1.7", "17.14.4.8");
+ final long entryId4 = 18955;
+ final MappingEntry entry4 = getEntry(entryId4, "192.168.1.8", "17.14.4.9");
+
+ final long newEntryId = 18956;
+ final MappingEntry newEntry = getEntry(newEntryId, "192.168.1.99", "17.14.4.99");
+ final SnatStaticMappingDetails newDetails = getDetails(newEntryId, "192.168.1.99", "17.14.4.99");
+ when(mappingCtx.read(MappingEntryContext.getId(natId, MappingEntryContext.entryToKey(newEntry))))
+ .thenReturn(Optional.absent());
+
+ when(mappingCtx.read(MappingEntryContext.getTableId(natId)))
+ .thenReturn(Optional.of(new MappingTableBuilder()
+ .setMappingEntry(Lists.newArrayList(
+ MappingEntryContext.toCtxMapEntry(entry, entryId),
+ MappingEntryContext.toCtxMapEntry(entry3, entryId3),
+ MappingEntryContext.toCtxMapEntry(entry4, entryId4),
+ MappingEntryContext.toCtxMapEntry(entry2, entryId2)))
+ .build()));
+
+ assertFalse(ctx.getStoredIndex(natId, newEntry, mappingCtx).isPresent());
+ assertEquals(newEntryId, ctx.getStoredOrArtificialIndex(natId, newDetails, mappingCtx));
+ }
+
+ private SnatStaticMappingDetails getDetails(final long vrfId, final String localIp, final String externIp) {
+ final SnatStaticMappingDetails snatStaticMappingDetails = new SnatStaticMappingDetails();
+ snatStaticMappingDetails.vrfId = (int) vrfId;
+ snatStaticMappingDetails.addrOnly = 1;
+ snatStaticMappingDetails.isIp4 = 1;
+ snatStaticMappingDetails.localIpAddress = ipv4AddressNoZoneToArray(localIp);
+ snatStaticMappingDetails.externalIpAddress = ipv4AddressNoZoneToArray(externIp);
+ return snatStaticMappingDetails;
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testAddExisting() throws Exception {
+ final long natId = 7;
+ final long entryId = 99;
+ final MappingEntry entry = getEntry(natId, "192.168.1.5", "17.14.4.6");
+ final org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.nat.context.rev161214.mapping.entry.context.attributes.nat.mapping.entry.context.nat.instance.mapping.table.MappingEntry
+ data = MappingEntryContext.toCtxMapEntry(entry, entryId);
+ when(mappingCtx.read(any(InstanceIdentifier.class))).thenReturn(Optional.of(data));
+
+ ctx.addEntry(natId, entryId, entry, mappingCtx);
+ }
+
+ private static MappingEntry getEntry(final long id, final String longernalIpv4, final String externalIpv4) {
+ return new MappingEntryBuilder()
+ .setKey(new MappingEntryKey(id))
+ .setType(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.MappingEntry.Type.Static)
+ .setInternalSrcAddress(new IpAddress(new Ipv4Address(longernalIpv4)))
+ .setExternalSrcAddress(new Ipv4Address(externalIpv4))
+ .build();
+ }
+} \ No newline at end of file
diff --git a/nat/nat2vpp/src/test/resources/nat.json b/nat/nat2vpp/src/test/resources/nat.json
new file mode 100644
index 000000000..c7d9afeb3
--- /dev/null
+++ b/nat/nat2vpp/src/test/resources/nat.json
@@ -0,0 +1,3 @@
+{
+ "enabled": "true"
+} \ No newline at end of file
diff --git a/nat/pom.xml b/nat/pom.xml
new file mode 100644
index 000000000..94d035d02
--- /dev/null
+++ b/nat/pom.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2015 Cisco and/or its affiliates.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>io.fd.honeycomb.common</groupId>
+ <artifactId>honeycomb-parent</artifactId>
+ <version>1.16.12-SNAPSHOT</version>
+ <relativePath>../common/honeycomb-parent</relativePath>
+ </parent>
+
+ <groupId>io.fd.honeycomb.nat</groupId>
+ <artifactId>nat-aggregator</artifactId>
+ <version>1.16.12-SNAPSHOT</version>
+ <name>nat-aggregator</name>
+ <packaging>pom</packaging>
+ <modelVersion>4.0.0</modelVersion>
+
+ <modules>
+ <module>nat-api</module>
+ <module>nat2vpp</module>
+ </modules>
+
+ <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-install-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/nat/postman_rest_collection.json b/nat/postman_rest_collection.json
new file mode 100644
index 000000000..348d60338
--- /dev/null
+++ b/nat/postman_rest_collection.json
@@ -0,0 +1,222 @@
+{
+ "id": "f9258895-49e9-596f-d413-698cbcadfbde",
+ "name": "Honeycomb NAT RESTCONF calls",
+ "description": "Common management operations for Honeycomb + VPP + SNAT plugin",
+ "order": [
+ "d2961af7-47f7-8960-1b00-f5dcd2beafb9",
+ "c00f25d2-f194-2e90-30e5-ca31e8fbd630",
+ "1ffc71e4-9d1e-0c99-7901-605ac8e364b6",
+ "f3a7e1b5-c1d0-ab2f-3cef-3c902f8e72d5"
+ ],
+ "folders": [
+ {
+ "id": "ce93ade0-47c3-a82d-a768-058a2e18e2bb",
+ "name": "1:1 static",
+ "description": "",
+ "order": [
+ "bca19675-d674-0cde-8639-df3d2ecbfd27",
+ "153f5720-fafc-22e6-6282-cf9e18226dbc",
+ "830c4ab3-2e48-5654-8aa5-2d2f9eed84b4",
+ "2c53651a-e31c-24da-122e-c0ce65544c8e",
+ "b54693d5-9226-1c27-77b2-8b1313da2e80"
+ ],
+ "owner": "45557",
+ "collectionId": "f9258895-49e9-596f-d413-698cbcadfbde"
+ }
+ ],
+ "timestamp": 1475147449190,
+ "owner": "45557",
+ "public": false,
+ "published": false,
+ "requests": [
+ {
+ "id": "153f5720-fafc-22e6-6282-cf9e18226dbc",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8183/restconf/operational/naming-context:contexts",
+ "pathVariables": {},
+ "preRequestScript": "",
+ "method": "GET",
+ "collectionId": "f9258895-49e9-596f-d413-698cbcadfbde",
+ "data": [],
+ "dataMode": "raw",
+ "name": "Get NAT context -context",
+ "description": "Read nat context ",
+ "descriptionFormat": "html",
+ "time": 1475678940763,
+ "version": 2,
+ "responses": [],
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "folder": "ce93ade0-47c3-a82d-a768-058a2e18e2bb",
+ "rawModeData": "{\r\n \r\n \"inbound\" : {}\r\n \r\n}"
+ },
+ {
+ "id": "1ffc71e4-9d1e-0c99-7901-605ac8e364b6",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8183/restconf/config/ietf-interfaces:interfaces/interface/local0/interface-nat:nat/outbound",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1475154424741,
+ "name": "Set NAT outbound for ifc - cfg",
+ "description": "Setting intarface NAT outbound feature\n\nCLI: set interface snat in <intfc> out <intfc> [del]\n\nMore information: https://wiki.fd.io/view/VPP/SNAT",
+ "collectionId": "f9258895-49e9-596f-d413-698cbcadfbde",
+ "responses": [],
+ "rawModeData": "{\r\n \r\n \"outbound\" : {}\r\n \r\n}"
+ },
+ {
+ "id": "2c53651a-e31c-24da-122e-c0ce65544c8e",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8183/restconf/config/ietf-nat:nat-config",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "GET",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1475678997603,
+ "name": "Get NAT - config",
+ "description": "Read nat-state",
+ "collectionId": "f9258895-49e9-596f-d413-698cbcadfbde",
+ "responses": [],
+ "rawModeData": "{\r\n \r\n \"inbound\" : {}\r\n \r\n}"
+ },
+ {
+ "id": "830c4ab3-2e48-5654-8aa5-2d2f9eed84b4",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8183/restconf/operational/ietf-nat:nat-state",
+ "pathVariables": {},
+ "preRequestScript": "",
+ "method": "GET",
+ "collectionId": "f9258895-49e9-596f-d413-698cbcadfbde",
+ "data": [],
+ "dataMode": "raw",
+ "name": "Get NAT -state",
+ "description": "Read nat-state\n\nCLI: show snat [detail|verbose]\n\nMore information: https://wiki.fd.io/view/VPP/SNAT",
+ "descriptionFormat": "html",
+ "time": 1475677867416,
+ "version": 2,
+ "responses": [],
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "folder": "ce93ade0-47c3-a82d-a768-058a2e18e2bb",
+ "rawModeData": "{\r\n \r\n \"inbound\" : {}\r\n \r\n}"
+ },
+ {
+ "id": "b54693d5-9226-1c27-77b2-8b1313da2e80",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8183/restconf/config/ietf-nat:nat-config/nat-instances/nat-instance/0/mapping-table/mapping-entry/1/",
+ "pathVariables": {},
+ "preRequestScript": "",
+ "method": "DELETE",
+ "collectionId": "f9258895-49e9-596f-d413-698cbcadfbde",
+ "data": [],
+ "dataMode": "raw",
+ "name": "Delete SNAT 1:1 static entry IPv4 -cfg",
+ "description": "",
+ "descriptionFormat": "html",
+ "time": 1475761660317,
+ "version": 2,
+ "responses": [],
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "folder": "ce93ade0-47c3-a82d-a768-058a2e18e2bb",
+ "rawModeData": "{\r\n\t\"mapping-entry\" : {\r\n\t\t\"index\": 1,\r\n\t\t\"type\": \"static\",\r\n\t\t\"internal-src-address\": \"192.168.1.87\",\r\n\t\t\"external-src-address\": \"45.1.5.7\"\r\n\t}\r\n}"
+ },
+ {
+ "id": "bca19675-d674-0cde-8639-df3d2ecbfd27",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8183/restconf/config/ietf-nat:nat-config/nat-instances/nat-instance/0/mapping-table/mapping-entry/1/",
+ "preRequestScript": "",
+ "pathVariables": {},
+ "method": "PUT",
+ "data": [],
+ "dataMode": "raw",
+ "version": 2,
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "time": 1475758450889,
+ "name": "Add SNAT 1:1 static entry IPv4 -cfg",
+ "description": "CLI: snat add static mapping local 10.0.0.3 external 4.4.4.4\n\nMore information: https://wiki.fd.io/view/VPP/SNAT",
+ "collectionId": "f9258895-49e9-596f-d413-698cbcadfbde",
+ "responses": [],
+ "rawModeData": "{\r\n\t\"mapping-entry\" : {\r\n\t\t\"index\": 1,\r\n\t\t\"type\": \"static\",\r\n\t\t\"internal-src-address\": \"192.168.1.87\",\r\n\t\t\"external-src-address\": \"45.1.5.7\"\r\n\t}\r\n}"
+ },
+ {
+ "id": "c00f25d2-f194-2e90-30e5-ca31e8fbd630",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8183/restconf/config/ietf-interfaces:interfaces/interface/local0/interface-nat:nat/inbound",
+ "pathVariables": {},
+ "preRequestScript": "",
+ "method": "DELETE",
+ "collectionId": "f9258895-49e9-596f-d413-698cbcadfbde",
+ "data": [],
+ "dataMode": "raw",
+ "name": "Disable NAT inbound for ifc - cfg",
+ "description": "Unsetting intarface NAT inbound feature\n\nCLI: set interface snat in <intfc> out <intfc> [del]\n\nMore information: https://wiki.fd.io/view/VPP/SNAT",
+ "descriptionFormat": "html",
+ "time": 1475835912474,
+ "version": 2,
+ "responses": [],
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "rawModeData": "{\r\n \r\n \"inbound\" : {}\r\n \r\n}"
+ },
+ {
+ "id": "d2961af7-47f7-8960-1b00-f5dcd2beafb9",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8183/restconf/config/ietf-interfaces:interfaces/interface/local0/interface-nat:nat/inbound",
+ "pathVariables": {},
+ "preRequestScript": "",
+ "method": "PUT",
+ "collectionId": "f9258895-49e9-596f-d413-698cbcadfbde",
+ "data": [],
+ "dataMode": "raw",
+ "name": "Set NAT inbound for ifc - cfg",
+ "description": "Setting intarface NAT inbound feature\n\nCLI: set interface snat in <intfc> out <intfc> [del]\n\nMore information: https://wiki.fd.io/view/VPP/SNAT",
+ "descriptionFormat": "html",
+ "time": 1475154374071,
+ "version": 2,
+ "responses": [],
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "rawModeData": "{\r\n \r\n \"inbound\" : {}\r\n \r\n}"
+ },
+ {
+ "id": "f3a7e1b5-c1d0-ab2f-3cef-3c902f8e72d5",
+ "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n",
+ "url": "http://localhost:8183/restconf/config/ietf-interfaces:interfaces/interface/local0/interface-nat:nat/outbound",
+ "pathVariables": {},
+ "preRequestScript": "",
+ "method": "DELETE",
+ "collectionId": "f9258895-49e9-596f-d413-698cbcadfbde",
+ "data": [],
+ "dataMode": "raw",
+ "name": "Disable NAT outbound for ifc - cfg",
+ "description": "Unsetting intarface NAT outbound feature\n\nCLI: set interface snat in <intfc> out <intfc> [del]\n\nMore information: https://wiki.fd.io/view/VPP/SNAT",
+ "descriptionFormat": "html",
+ "time": 1475835941689,
+ "version": 2,
+ "responses": [],
+ "tests": "",
+ "currentHelper": "normal",
+ "helperAttributes": {},
+ "rawModeData": "{\r\n \r\n \"outbound\" : {}\r\n \r\n}"
+ }
+ ]
+} \ No newline at end of file
diff --git a/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/VppNshModule.java b/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/VppNshModule.java
index e7d9d1535..94399a5fa 100755
--- a/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/VppNshModule.java
+++ b/nsh/impl/src/main/java/io/fd/honeycomb/vppnsh/impl/VppNshModule.java
@@ -41,7 +41,7 @@ public final class VppNshModule extends AbstractModule {
@Override
protected void configure() {
- LOG.info("Configuring VppNsh module");
+ LOG.debug("Installing NSH module");
// Naming contexts
bind(NamingContext.class)
@@ -59,6 +59,6 @@ public final class VppNshModule extends AbstractModule {
Multibinder.newSetBinder(binder(), WriterFactory.class).addBinding().to(VppNshWriterFactory.class);
Multibinder.newSetBinder(binder(), ReaderFactory.class).addBinding().to(VppNshReaderFactory.class);
Multibinder.newSetBinder(binder(), DataTreeInitializer.class).addBinding().to(VppNshInitializer.class);
- LOG.info("NSH module successfully configured");
+ LOG.info("Module NSH successfully configured");
}
}
diff --git a/pom.xml b/pom.xml
index 83b834da4..01e2d5506 100644
--- a/pom.xml
+++ b/pom.xml
@@ -12,8 +12,7 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>io.fd.honeycomb.common</groupId>
@@ -45,5 +44,6 @@
<module>lisp</module>
<module>samples</module>
<module>tools</module>
+ <module>nat</module>
</modules>
-</project>
+</project> \ No newline at end of file
diff --git a/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-api/pom.xml b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-api/pom.xml
index 3b67a0d7f..75c138891 100644
--- a/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-api/pom.xml
+++ b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-api/pom.xml
@@ -22,21 +22,10 @@
<modelVersion>4.0.0</modelVersion>
<groupId>${groupId}</groupId>
<artifactId>${rootArtifactId}-api</artifactId>
+ <name>${rootArtifactId}-api</name>
<version>${version}</version>
<packaging>bundle</packaging>
- <dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>org.opendaylight.mdsal.model</groupId>
- <artifactId>mdsal-model-artifacts</artifactId>
- <version>0.8.2-Beryllium-SR2</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
- </dependencies>
- </dependencyManagement>
-
<dependencies>
<dependency>
<groupId>org.opendaylight.mdsal.model</groupId>
diff --git a/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/pom.xml b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/pom.xml
index 19564db74..eeb65cf23 100644
--- a/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/pom.xml
+++ b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/pom.xml
@@ -22,6 +22,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>${groupId}</groupId>
<artifactId>${rootArtifactId}-impl</artifactId>
+ <name>${rootArtifactId}-impl</name>
<version>${version}</version>
<packaging>bundle</packaging>
@@ -59,17 +60,14 @@
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
- <version>${guice.version}</version>
</dependency>
<dependency>
<groupId>net.jmob</groupId>
<artifactId>guice.conf</artifactId>
- <version>${guice.config.version}</version>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-multibindings</artifactId>
- <version>${guice.version}</version>
</dependency>
</dependencies>
</project>
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/V3poModule.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/V3poModule.java
index eaecdf025..e30f9e6e8 100644
--- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/V3poModule.java
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/V3poModule.java
@@ -35,11 +35,16 @@ import io.fd.honeycomb.translate.write.WriterFactory;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import net.jmob.guice.conf.core.ConfigurationModule;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class V3poModule extends AbstractModule {
+ private static final Logger LOG = LoggerFactory.getLogger(V3poModule.class);
+
@Override
protected void configure() {
+ LOG.debug("Installing V3PO module");
install(ConfigurationModule.create());
requestInjection(V3poConfiguration.class);
@@ -91,5 +96,6 @@ public class V3poModule extends AbstractModule {
final Multibinder<ManagedNotificationProducer> notifiersBinder =
Multibinder.newSetBinder(binder(), ManagedNotificationProducer.class);
notifiersBinder.addBinding().to(InterfaceChangeNotificationProducer.class);
+ LOG.info("Module V3PO successfully configured");
}
}
diff --git a/vpp-common/vpp-impl-parent/pom.xml b/vpp-common/vpp-impl-parent/pom.xml
index 43e038ce9..83be57ba8 100644
--- a/vpp-common/vpp-impl-parent/pom.xml
+++ b/vpp-common/vpp-impl-parent/pom.xml
@@ -46,6 +46,11 @@
<artifactId>jvpp-registry</artifactId>
<version>${jvpp.version}</version>
</dependency>
+ <dependency>
+ <groupId>io.fd.honeycomb.vpp</groupId>
+ <artifactId>vpp-translate-utils</artifactId>
+ <version>${project.version}</version>
+ </dependency>
</dependencies>
</dependencyManagement>
</project>
diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/vpp/util/Ipv4Translator.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/vpp/util/Ipv4Translator.java
index 56aa4f149..ff737d4ab 100644
--- a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/vpp/util/Ipv4Translator.java
+++ b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/vpp/util/Ipv4Translator.java
@@ -26,7 +26,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
/**
- * Trait providing logic for translation of ipv4-related data
+ * Trait providing logic for translation of ipv4-related data.
*/
public interface Ipv4Translator extends ByteDataTranslator {
diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/vpp/util/NamingContext.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/vpp/util/NamingContext.java
index aecd6efef..467ac5161 100644
--- a/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/vpp/util/NamingContext.java
+++ b/vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/vpp/util/NamingContext.java
@@ -35,7 +35,7 @@ import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
/**
* Utility adapter on top of {@link MappingContext} storing integer to string mappings according to naming-context yang
- * model
+ * model.
*/
public final class NamingContext implements AutoCloseable {
diff --git a/vpp-integration/minimal-distribution/pom.xml b/vpp-integration/minimal-distribution/pom.xml
index 36d1e0f1a..041c0a584 100644
--- a/vpp-integration/minimal-distribution/pom.xml
+++ b/vpp-integration/minimal-distribution/pom.xml
@@ -34,6 +34,7 @@
<lisp.version>1.16.12-SNAPSHOT</lisp.version>
<vpp.common.integration.version>1.16.12-SNAPSHOT</vpp.common.integration.version>
<vppnsh.version>1.16.12-SNAPSHOT</vppnsh.version>
+ <nat.version>1.16.12-SNAPSHOT</nat.version>
<distribution.modules>
io.fd.honeycomb.vpp.common.integration.VppCommonModule,
@@ -88,5 +89,10 @@
<artifactId>vppnsh-impl</artifactId>
<version>${vppnsh.version}</version>
</dependency>
+ <dependency>
+ <groupId>io.fd.honeycomb.nat</groupId>
+ <artifactId>nat2vpp</artifactId>
+ <version>${nat.version}</version>
+ </dependency>
</dependencies>
</project>