summaryrefslogtreecommitdiffstats
path: root/l3/utils
diff options
context:
space:
mode:
authorJan Srnicek <jsrnicek@cisco.com>2017-03-10 10:00:43 +0100
committerJan Srnicek <jsrnicek@cisco.com>2017-03-10 10:00:43 +0100
commitfb50d586985f12d1aa39eb6c5fdcd6b8a87b26da (patch)
treed9ddcc1095a51188a8af53daacab6873bb98bf5e /l3/utils
parent17ef7d8eb8bae7b34c0ccd2d4a7610f607a90f5e (diff)
HC2VPP-7 - L3 split to separate module
ipv4/ipv6/proxy arp/nd proxy Change-Id: I536298dd5584f79f357e94da08d402e67e79bb71 Signed-off-by: Jan Srnicek <jsrnicek@cisco.com>
Diffstat (limited to 'l3/utils')
-rw-r--r--l3/utils/asciidoc/Readme.adoc3
-rw-r--r--l3/utils/pom.xml69
-rw-r--r--l3/utils/src/main/java/io/fd/hc2vpp/l3/utils/ip/read/IfaceDumpFilter.java62
-rw-r--r--l3/utils/src/main/java/io/fd/hc2vpp/l3/utils/ip/read/IpAddressReader.java147
-rw-r--r--l3/utils/src/main/java/io/fd/hc2vpp/l3/utils/ip/read/IpNeighbourReader.java102
-rw-r--r--l3/utils/src/main/java/io/fd/hc2vpp/l3/utils/ip/read/IpReader.java59
-rw-r--r--l3/utils/src/main/java/io/fd/hc2vpp/l3/utils/ip/write/IpWriter.java166
7 files changed, 608 insertions, 0 deletions
diff --git a/l3/utils/asciidoc/Readme.adoc b/l3/utils/asciidoc/Readme.adoc
new file mode 100644
index 000000000..45eda20a5
--- /dev/null
+++ b/l3/utils/asciidoc/Readme.adoc
@@ -0,0 +1,3 @@
+= l3-utils
+
+Overview of l3-utils \ No newline at end of file
diff --git a/l3/utils/pom.xml b/l3/utils/pom.xml
new file mode 100644
index 000000000..0f7e7f91b
--- /dev/null
+++ b/l3/utils/pom.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (c) 2017 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.hc2vpp.common</groupId>
+ <artifactId>vpp-impl-parent</artifactId>
+ <version>1.17.04-SNAPSHOT</version>
+ <relativePath>../../vpp-common/vpp-impl-parent</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>io.fd.hc2vpp.l3</groupId>
+ <artifactId>l3-utils</artifactId>
+ <version>1.17.04-SNAPSHOT</version>
+
+ <dependencies>
+ <dependency>
+ <groupId>io.fd.hc2vpp.l3</groupId>
+ <artifactId>l3-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <!-- TODO - HC2VPP-100 - for building subinterface keys,etc,change to interface/subinterface api after split -->
+ <dependency>
+ <groupId>io.fd.hc2vpp.v3po</groupId>
+ <artifactId>v3po-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>io.fd.vpp</groupId>
+ <artifactId>jvpp-core</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>io.fd.honeycomb</groupId>
+ <artifactId>translate-utils</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.fd.hc2vpp.common</groupId>
+ <artifactId>vpp-translate-utils</artifactId>
+ </dependency>
+
+ <!-- TODO - HC2VPP-100 - sub-interface utils,change to interface/subinterface api after split-->
+ <dependency>
+ <groupId>io.fd.hc2vpp.v3po</groupId>
+ <artifactId>v3po2vpp</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+</project> \ No newline at end of file
diff --git a/l3/utils/src/main/java/io/fd/hc2vpp/l3/utils/ip/read/IfaceDumpFilter.java b/l3/utils/src/main/java/io/fd/hc2vpp/l3/utils/ip/read/IfaceDumpFilter.java
new file mode 100644
index 000000000..45893a497
--- /dev/null
+++ b/l3/utils/src/main/java/io/fd/hc2vpp/l3/utils/ip/read/IfaceDumpFilter.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.l3.utils.ip.read;
+
+public class IfaceDumpFilter {
+
+ private final int interfaceIndex;
+ private final boolean isIpv6;
+
+ public IfaceDumpFilter(final int interfaceIndex, final boolean isIpv6) {
+ this.interfaceIndex = interfaceIndex;
+ this.isIpv6 = isIpv6;
+ }
+
+ public int getInterfaceIndex() {
+ return interfaceIndex;
+ }
+
+ public boolean isIpv6() {
+ return isIpv6;
+ }
+
+ @Override
+ public String toString() {
+ return "IfaceDumpFilter{" +
+ "interfaceIndex=" + interfaceIndex +
+ ", isIpv6=" + isIpv6 +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ IfaceDumpFilter that = (IfaceDumpFilter) o;
+
+ if (interfaceIndex != that.interfaceIndex) return false;
+ return isIpv6 == that.isIpv6;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = interfaceIndex;
+ result = 31 * result + (isIpv6 ? 1 : 0);
+ return result;
+ }
+}
diff --git a/l3/utils/src/main/java/io/fd/hc2vpp/l3/utils/ip/read/IpAddressReader.java b/l3/utils/src/main/java/io/fd/hc2vpp/l3/utils/ip/read/IpAddressReader.java
new file mode 100644
index 000000000..369241e47
--- /dev/null
+++ b/l3/utils/src/main/java/io/fd/hc2vpp/l3/utils/ip/read/IpAddressReader.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.l3.utils.ip.read;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Optional;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.v3po.util.SubInterfaceUtils;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.util.RWUtils;
+import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager;
+import io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor;
+import io.fd.vpp.jvpp.core.dto.IpAddressDetails;
+import io.fd.vpp.jvpp.core.dto.IpAddressDetailsReplyDump;
+import io.fd.vpp.jvpp.core.dto.IpAddressDump;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Function;
+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.Ipv4AddressNoZone;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6AddressNoZone;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces.state._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Provides logic for reading of ip addresses
+ */
+public abstract class IpAddressReader extends IpReader {
+
+ private final DumpCacheManager<IpAddressDetailsReplyDump, IfaceDumpFilter> dumpCacheManager;
+
+ protected IpAddressReader(@Nonnull final NamingContext interfaceContext, final boolean isIpv6,
+ @Nonnull final DumpCacheManager<IpAddressDetailsReplyDump, IfaceDumpFilter> dumpCacheManager) {
+ super(interfaceContext, isIpv6);
+ this.dumpCacheManager = dumpCacheManager;
+ }
+
+ @Nonnull
+ protected Optional<IpAddressDetailsReplyDump> interfaceAddressDumpSupplier(@Nonnull final InstanceIdentifier<?> id,
+ @Nonnull final ReadContext context) throws ReadFailedException {
+ return dumpCacheManager.getDump(id, context.getModificationCache(), new IfaceDumpFilter(getInterfaceContext()
+ .getIndex(id.firstKeyOf(Interface.class).getName(), context.getMappingContext()), isIpv6()));
+ }
+
+ @Nonnull
+ protected Optional<IpAddressDetailsReplyDump> subInterfaceAddressDumpSupplier(@Nonnull final InstanceIdentifier<?> id,
+ @Nonnull final ReadContext context) throws ReadFailedException {
+ final String subInterfaceName = SubInterfaceUtils.getSubInterfaceName(id.firstKeyOf(Interface.class).getName(),
+ id.firstKeyOf(SubInterface.class).getIdentifier().intValue());
+ return dumpCacheManager.getDump(id, context.getModificationCache(), new IfaceDumpFilter(getInterfaceContext()
+ .getIndex(subInterfaceName, context.getMappingContext()), isIpv6()));
+ }
+
+ @Nonnull
+ protected <T extends Identifier> List<T> getAllIpv4AddressIds(
+ final Optional<IpAddressDetailsReplyDump> dumpOptional,
+ @Nonnull final Function<Ipv4AddressNoZone, T> keyConstructor) {
+ if (dumpOptional.isPresent() && dumpOptional.get().ipAddressDetails != null) {
+ return dumpOptional.get().ipAddressDetails.stream()
+ .map(detail -> keyConstructor.apply(arrayToIpv4AddressNoZone(detail.ip)))
+ .collect(Collectors.toList());
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ @Nonnull
+ protected <T extends Identifier> List<T> getAllIpv6AddressIds(
+ final Optional<IpAddressDetailsReplyDump> dumpOptional,
+ @Nonnull final Function<Ipv6AddressNoZone, T> keyConstructor) {
+ if (dumpOptional.isPresent() && dumpOptional.get().ipAddressDetails != null) {
+ return dumpOptional.get().ipAddressDetails.stream()
+ .map(detail -> keyConstructor.apply(arrayToIpv6AddressNoZone(detail.ip)))
+ .collect(Collectors.toList());
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ @Nonnull
+ protected Optional<IpAddressDetails> findIpv4AddressDetailsByIp(
+ final Optional<IpAddressDetailsReplyDump> dump,
+ @Nonnull final Ipv4AddressNoZone ip) {
+ checkNotNull(ip, "ip address should not be null");
+
+ if (dump.isPresent() && dump.get().ipAddressDetails != null) {
+ final List<IpAddressDetails> details = dump.get().ipAddressDetails;
+
+ return Optional.of(details.stream()
+ .filter(singleDetail -> ip.equals(arrayToIpv4AddressNoZone(singleDetail.ip)))
+ .collect(RWUtils.singleItemCollector()));
+ }
+ return Optional.absent();
+ }
+
+ @Nonnull
+ protected Optional<IpAddressDetails> findIpv6AddressDetailsByIp(
+ final Optional<IpAddressDetailsReplyDump> dump,
+ @Nonnull final Ipv6AddressNoZone ip) {
+ checkNotNull(ip, "ip address should not be null");
+
+ if (dump.isPresent() && dump.get().ipAddressDetails != null) {
+ final List<IpAddressDetails> details = dump.get().ipAddressDetails;
+
+ return Optional.of(details.stream()
+ .filter(singleDetail -> ip.equals(arrayToIpv6AddressNoZone(singleDetail.ip)))
+ .collect(RWUtils.singleItemCollector()));
+ }
+ return Optional.absent();
+ }
+
+ @Nonnull
+ protected static EntityDumpExecutor<IpAddressDetailsReplyDump, IfaceDumpFilter> createAddressDumpExecutor(
+ @Nonnull final FutureJVppCore vppApi) {
+ return (identifier, params) -> {
+ checkNotNull(params, "Address dump params cannot be null");
+
+ final IpAddressDump dumpRequest = new IpAddressDump();
+ dumpRequest.isIpv6 = ByteDataTranslator.INSTANCE.booleanToByte(params.isIpv6());
+ dumpRequest.swIfIndex = params.getInterfaceIndex();
+
+ return JvppReplyConsumer.INSTANCE.getReplyForRead(vppApi.ipAddressDump(dumpRequest).toCompletableFuture(), identifier);
+ };
+ }
+}
diff --git a/l3/utils/src/main/java/io/fd/hc2vpp/l3/utils/ip/read/IpNeighbourReader.java b/l3/utils/src/main/java/io/fd/hc2vpp/l3/utils/ip/read/IpNeighbourReader.java
new file mode 100644
index 000000000..69df87b62
--- /dev/null
+++ b/l3/utils/src/main/java/io/fd/hc2vpp/l3/utils/ip/read/IpNeighbourReader.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.l3.utils.ip.read;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Optional;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.hc2vpp.v3po.util.SubInterfaceUtils;
+import io.fd.honeycomb.translate.read.ReadContext;
+import io.fd.honeycomb.translate.read.ReadFailedException;
+import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager;
+import io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor;
+import io.fd.vpp.jvpp.core.dto.IpNeighborDetails;
+import io.fd.vpp.jvpp.core.dto.IpNeighborDetailsReplyDump;
+import io.fd.vpp.jvpp.core.dto.IpNeighborDump;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+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.vpp.vlan.rev161214.interfaces.state._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yangtools.yang.binding.Identifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Provides logic for reading ip neighbours
+ */
+public abstract class IpNeighbourReader extends IpReader {
+
+ private final DumpCacheManager<IpNeighborDetailsReplyDump, IfaceDumpFilter> dumpCacheManager;
+
+ protected IpNeighbourReader(@Nonnull final NamingContext interfaceContext, boolean isIpv6,
+ @Nonnull final DumpCacheManager<IpNeighborDetailsReplyDump, IfaceDumpFilter> dumpCacheManager) {
+ super(interfaceContext, isIpv6);
+ this.dumpCacheManager = dumpCacheManager;
+ }
+
+ @Nonnull
+ protected Optional<IpNeighborDetailsReplyDump> interfaceNeighboursDump(@Nonnull final InstanceIdentifier<?> id,
+ @Nonnull final ReadContext context) throws ReadFailedException {
+ return dumpCacheManager.getDump(id, context.getModificationCache(), new IfaceDumpFilter(getInterfaceContext()
+ .getIndex(id.firstKeyOf(Interface.class).getName(), context.getMappingContext()), isIpv6()));
+ }
+
+ @Nonnull
+ protected Optional<IpNeighborDetailsReplyDump> subInterfaceNeighboursDump(@Nonnull final InstanceIdentifier<?> id,
+ @Nonnull final ReadContext context) throws ReadFailedException {
+ final String subInterfaceName = SubInterfaceUtils.getSubInterfaceName(id.firstKeyOf(Interface.class).getName(),
+ id.firstKeyOf(SubInterface.class).getIdentifier().intValue());
+ return dumpCacheManager.getDump(id, context.getModificationCache(), new IfaceDumpFilter(getInterfaceContext()
+ .getIndex(subInterfaceName, context.getMappingContext()), isIpv6()));
+ }
+
+ @Nonnull
+ protected static EntityDumpExecutor<IpNeighborDetailsReplyDump, IfaceDumpFilter> createNeighbourDumpExecutor(
+ @Nonnull final FutureJVppCore vppApi) {
+ return (identifier, params) -> {
+ checkNotNull(params, "Address dump params cannot be null");
+
+ final IpNeighborDump dumpRequest = new IpNeighborDump();
+ dumpRequest.isIpv6 = ByteDataTranslator.INSTANCE.booleanToByte(params.isIpv6());
+ dumpRequest.swIfIndex = params.getInterfaceIndex();
+
+ return JvppReplyConsumer.INSTANCE.getReplyForRead(vppApi.ipNeighborDump(dumpRequest).toCompletableFuture(), identifier);
+ };
+ }
+
+ @Nonnull
+ protected <T extends Identifier> List<T> getNeighborKeys(
+ final Optional<IpNeighborDetailsReplyDump> neighbourDumpOpt,
+ final Function<IpNeighborDetails, T> detailToKey)
+ throws ReadFailedException {
+ if (neighbourDumpOpt.isPresent()) {
+ final IpNeighborDetailsReplyDump neighbourDump = neighbourDumpOpt.get();
+
+ return neighbourDump.ipNeighborDetails.stream()
+ .map(detailToKey)
+ .collect(Collectors.toList());
+ } else {
+ return Collections.emptyList();
+ }
+ }
+}
diff --git a/l3/utils/src/main/java/io/fd/hc2vpp/l3/utils/ip/read/IpReader.java b/l3/utils/src/main/java/io/fd/hc2vpp/l3/utils/ip/read/IpReader.java
new file mode 100644
index 000000000..3ba0ba862
--- /dev/null
+++ b/l3/utils/src/main/java/io/fd/hc2vpp/l3/utils/ip/read/IpReader.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.l3.utils.ip.read;
+
+import com.google.common.collect.ImmutableSet;
+import io.fd.hc2vpp.common.translate.util.AddressTranslator;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.util.read.cache.CacheKeyFactory;
+import io.fd.honeycomb.translate.util.read.cache.TypeAwareIdentifierCacheKeyFactory;
+import javax.annotation.Nonnull;
+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.vpp.vlan.rev161214.interfaces.state._interface.sub.interfaces.SubInterface;
+
+/**
+ * Utility class providing Ipv4/6 read support.
+ */
+public abstract class IpReader implements AddressTranslator, JvppReplyConsumer {
+
+ private final NamingContext interfaceContext;
+ private final boolean isIpv6;
+
+ IpReader(@Nonnull final NamingContext interfaceContext, final boolean isIpv6) {
+ this.interfaceContext = interfaceContext;
+ this.isIpv6 = isIpv6;
+ }
+
+ @Nonnull
+ protected static CacheKeyFactory interfaceScopedCacheKeyFactory(@Nonnull final Class<?> dumpReplyClass) {
+ return new TypeAwareIdentifierCacheKeyFactory(dumpReplyClass, ImmutableSet.of(Interface.class));
+ }
+
+ @Nonnull
+ protected static CacheKeyFactory subInterfaceScopedCacheKeyFactory(@Nonnull final Class<?> dumpReplyClass) {
+ return new TypeAwareIdentifierCacheKeyFactory(dumpReplyClass, ImmutableSet.of(SubInterface.class));
+ }
+
+ protected NamingContext getInterfaceContext() {
+ return interfaceContext;
+ }
+
+ protected boolean isIpv6() {
+ return isIpv6;
+ }
+}
diff --git a/l3/utils/src/main/java/io/fd/hc2vpp/l3/utils/ip/write/IpWriter.java b/l3/utils/src/main/java/io/fd/hc2vpp/l3/utils/ip/write/IpWriter.java
new file mode 100644
index 000000000..3f5023890
--- /dev/null
+++ b/l3/utils/src/main/java/io/fd/hc2vpp/l3/utils/ip/write/IpWriter.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.hc2vpp.l3.utils.ip.write;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import io.fd.hc2vpp.common.translate.util.AddressTranslator;
+import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
+import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
+import io.fd.hc2vpp.common.translate.util.NamingContext;
+import io.fd.honeycomb.translate.MappingContext;
+import io.fd.honeycomb.translate.write.WriteFailedException;
+import io.fd.vpp.jvpp.core.dto.IpNeighborAddDel;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceAddDelAddress;
+import io.fd.vpp.jvpp.core.dto.SwInterfaceAddDelAddressReply;
+import io.fd.vpp.jvpp.core.future.FutureJVppCore;
+import java.util.concurrent.CompletionStage;
+import java.util.function.Supplier;
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6AddressNoZone;
+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.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterface;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Utility class providing Ipv4/6 CUD support.
+ */
+public interface IpWriter extends ByteDataTranslator, AddressTranslator, JvppReplyConsumer {
+
+ int DOTTED_QUAD_MASK_LENGTH = 4;
+ int IPV4_ADDRESS_PART_BITS_COUNT = 8;
+ int NETMASK_PART_LIMIT = 256; // 2 power to 8
+
+ default void addDelAddress(@Nonnull final FutureJVppCore futureJVppCore, final boolean add,
+ final InstanceIdentifier<?> id,
+ @Nonnegative final int ifaceId,
+ @Nonnull final Ipv4AddressNoZone address, @Nonnegative final byte prefixLength)
+ throws WriteFailedException {
+ checkArgument(prefixLength > 0, "Invalid prefix length");
+ checkNotNull(address, "address should not be null");
+
+ final byte[] addressBytes = ipv4AddressNoZoneToArray(address);
+
+ final CompletionStage<SwInterfaceAddDelAddressReply> swInterfaceAddDelAddressReplyCompletionStage =
+ futureJVppCore.swInterfaceAddDelAddress(
+ getSwInterfaceAddDelAddressRequest(ifaceId, booleanToByte(add) /* isAdd */,
+ (byte) 0 /* isIpv6 */, (byte) 0 /* delAll */, prefixLength, addressBytes));
+
+ getReplyForWrite(swInterfaceAddDelAddressReplyCompletionStage.toCompletableFuture(), id);
+ }
+
+ default void addDelAddress(@Nonnull final FutureJVppCore futureJVppCore, final boolean add,
+ final InstanceIdentifier<?> id,
+ @Nonnegative final int ifaceId,
+ @Nonnull final Ipv6AddressNoZone address, @Nonnegative final byte prefixLength)
+ throws WriteFailedException {
+ checkNotNull(address, "address should not be null");
+
+ final byte[] addressBytes = ipv6AddressNoZoneToArray(address);
+
+ final CompletionStage<SwInterfaceAddDelAddressReply> swInterfaceAddDelAddressReplyCompletionStage =
+ futureJVppCore.swInterfaceAddDelAddress(
+ getSwInterfaceAddDelAddressRequest(ifaceId, booleanToByte(add) /* isAdd */,
+ (byte) 1 /* isIpv6 */, (byte) 0 /* delAll */, prefixLength, addressBytes));
+
+ getReplyForWrite(swInterfaceAddDelAddressReplyCompletionStage.toCompletableFuture(), id);
+ }
+
+ default SwInterfaceAddDelAddress getSwInterfaceAddDelAddressRequest(final int swIfc, final byte isAdd,
+ final byte ipv6, final byte deleteAll,
+ final byte length, final byte[] addr) {
+ final SwInterfaceAddDelAddress swInterfaceAddDelAddress = new SwInterfaceAddDelAddress();
+ swInterfaceAddDelAddress.swIfIndex = swIfc;
+ swInterfaceAddDelAddress.isAdd = isAdd;
+ swInterfaceAddDelAddress.isIpv6 = ipv6;
+ swInterfaceAddDelAddress.delAll = deleteAll;
+ swInterfaceAddDelAddress.address = addr;
+ swInterfaceAddDelAddress.addressLength = length;
+ return swInterfaceAddDelAddress;
+ }
+
+ /**
+ * Returns the prefix size in bits of the specified subnet mask. Example: For the subnet mask 255.255.255.128 it
+ * returns 25 while for 255.0.0.0 it returns 8. If the passed subnetMask array is not complete or contains not only
+ * leading ones, IllegalArgumentExpression is thrown
+ *
+ * @param mask the subnet mask in dot notation 255.255.255.255
+ * @return the prefix length as number of bits
+ */
+ default byte getSubnetMaskLength(final String mask) {
+ String[] maskParts = mask.split("\\.");
+
+ checkArgument(maskParts.length == DOTTED_QUAD_MASK_LENGTH,
+ "Network mask %s is not in Quad Dotted Decimal notation!", mask);
+
+ long maskAsNumber = 0;
+ for (int i = 0; i < DOTTED_QUAD_MASK_LENGTH; i++) {
+ maskAsNumber <<= IPV4_ADDRESS_PART_BITS_COUNT;
+ int value = Integer.parseInt(maskParts[i]);
+ checkArgument(value < NETMASK_PART_LIMIT, "Network mask %s contains invalid number(s) over 255!", mask);
+ checkArgument(value >= 0, "Network mask %s contains invalid negative number(s)!", mask);
+ maskAsNumber += value;
+ }
+
+ String bits = Long.toBinaryString(maskAsNumber);
+ checkArgument(bits.length() == IPV4_ADDRESS_PART_BITS_COUNT * DOTTED_QUAD_MASK_LENGTH,
+ "Incorrect network mask %s", mask);
+ final int leadingOnes = bits.indexOf('0');
+ checkArgument(leadingOnes != -1, "Broadcast address %s is not allowed!", mask);
+ checkArgument(bits.substring(leadingOnes).indexOf('1') == -1,
+ "Non-contiguous network mask %s is not allowed!", mask);
+ return (byte) leadingOnes;
+ }
+
+ default int subInterfaceIndex(final InstanceIdentifier<?> id, final NamingContext interfaceContext,
+ final MappingContext mappingContext) {
+ return interfaceContext
+ .getIndex(id.firstKeyOf(Interface.class).getName() + "." + id.firstKeyOf(SubInterface.class).getIdentifier(),
+ mappingContext);
+ }
+
+ default void addDelNeighbour(@Nonnull final InstanceIdentifier<?> id,
+ @Nonnull final Supplier<IpNeighborAddDel> requestSupplier,
+ @Nonnull final FutureJVppCore api) throws WriteFailedException {
+ getReplyForWrite(api.ipNeighborAddDel(requestSupplier.get()).toCompletableFuture(), id);
+ }
+
+ default IpNeighborAddDel preBindIpv4Request(final boolean add) {
+ IpNeighborAddDel request = staticPreBindRequest(add);
+ request.isIpv6 = 0;
+
+ return request;
+ }
+
+ default IpNeighborAddDel preBindIpv6Request(final boolean add) {
+ IpNeighborAddDel request = staticPreBindRequest(add);
+ request.isIpv6 = 1;
+
+ return request;
+ }
+
+ static IpNeighborAddDel staticPreBindRequest(final boolean add) {
+ IpNeighborAddDel request = new IpNeighborAddDel();
+
+ request.isAdd = ByteDataTranslator.INSTANCE.booleanToByte(add);
+ request.isStatic = 1;
+ return request;
+ }
+}