diff options
Diffstat (limited to 'l3/utils')
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; + } +} |