diff options
author | 2016-12-01 18:15:52 +0100 | |
---|---|---|
committer | 2016-12-01 18:16:47 +0100 | |
commit | 32aa07e5517fba7f78ae79d2ba83b56f72a53293 (patch) | |
tree | 26256f30f2dc5c3521403ef3fcd2e038b2f9bca6 /vpp-common/vpp-translate-utils/src/main/java/io/fd | |
parent | 9c9935c83ce9869ca36cbde7865423ef02f19db8 (diff) |
HONEYCOMB-58 - Routing Plugin Structure
Read/Write support for ipv4/6 static routes.
Restriction due to vpp implementation described
in readme.
Change-Id: I328f406a9b7cb8781f8becf98eca293cebe66859
Signed-off-by: Jan Srnicek <jsrnicek@cisco.com>
Diffstat (limited to 'vpp-common/vpp-translate-utils/src/main/java/io/fd')
6 files changed, 255 insertions, 12 deletions
diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/AddressTranslator.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/AddressTranslator.java index eaa966479..170ff43e5 100644 --- a/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/AddressTranslator.java +++ b/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/AddressTranslator.java @@ -30,6 +30,9 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types. */ public interface AddressTranslator extends Ipv4Translator, Ipv6Translator, MacTranslator { + AddressTranslator INSTANCE = new AddressTranslator() { + }; + default byte[] ipAddressToArray(IpAddress address) { checkNotNull(address, "Cannot resolve null adddress"); diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/ByteDataTranslator.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/ByteDataTranslator.java index a96542623..17aff0e2e 100644 --- a/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/ByteDataTranslator.java +++ b/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/ByteDataTranslator.java @@ -24,6 +24,12 @@ import javax.annotation.Nullable; */ public interface ByteDataTranslator { + ByteDataTranslator INSTANCE = new ByteDataTranslator() { + }; + + byte BYTE_FALSE = 0; + byte BYTE_TRUE = 1; + /** * Returns 0 if argument is null or false, 1 otherwise. * @@ -32,8 +38,22 @@ public interface ByteDataTranslator { */ default byte booleanToByte(@Nullable final Boolean value) { return value != null && value - ? (byte) 1 - : (byte) 0; + ? BYTE_TRUE + : BYTE_FALSE; + } + + /** + * Converts int to byte + */ + default byte toByte(final int value) { + return Integer.valueOf(value).byteValue(); + } + + /** + * Converts short to byte + */ + default byte toByte(final short value) { + return Short.valueOf(value).byteValue(); } /** @@ -45,9 +65,9 @@ public interface ByteDataTranslator { */ @Nonnull default Boolean byteToBoolean(final byte value) { - if (value == 0) { + if (value == BYTE_FALSE) { return Boolean.FALSE; - } else if (value == 1) { + } else if (value == BYTE_TRUE) { return Boolean.TRUE; } throw new IllegalArgumentException(String.format("0 or 1 was expected but was %d", value)); @@ -76,4 +96,13 @@ public interface ByteDataTranslator { default String toString(final byte[] cString) { return new String(cString).replaceAll("\\u0000", "").intern(); } + + /** + * Converts signed byte(filled with unsigned value from vpp) to java integer + * + * For example unsigned C byte 128 is converted by jvpp to -128, this will return 128 + */ + default int toJavaByte(final byte vppByte) { + return Byte.toUnsignedInt(vppByte); + } } diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/Ipv4Translator.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/Ipv4Translator.java index 99d1757b4..02f89d9f8 100644 --- a/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/Ipv4Translator.java +++ b/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/Ipv4Translator.java @@ -108,4 +108,15 @@ public interface Ipv4Translator extends ByteDataTranslator { } return retval; } + + default Ipv4Prefix toIpv4Prefix(final byte[] address, final int prefix) { + try { + return new Ipv4Prefix( + String.format("%s/%s", InetAddress.getByAddress(address).getHostAddress(), + String.valueOf(prefix))); + } catch (UnknownHostException e) { + throw new IllegalArgumentException( + "Cannot create prefix for address[" + Arrays.toString(address) + "],prefix[" + prefix + "]"); + } + } } diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/Ipv6Translator.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/Ipv6Translator.java index cb8b2ac87..2d0b51b40 100644 --- a/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/Ipv6Translator.java +++ b/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/Ipv6Translator.java @@ -39,17 +39,11 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types. */ public interface Ipv6Translator extends ByteDataTranslator { - /** - * Transform Ipv6 address to a byte array acceptable by VPP. VPP expects incoming byte array to be in the same order - * as the address. - * - * @return byte array with address bytes - */ - default byte[] ipv6AddressNoZoneToArray(@Nonnull final Ipv6AddressNoZone ipv6Addr) { + default byte[] ipv6AddressNoZoneToArray(@Nonnull final String address) { byte[] retval = new byte[16]; //splits address and add ommited zeros for easier parsing - List<String> segments = Arrays.asList(ipv6Addr.getValue().split(":")) + List<String> segments = Arrays.asList(address.split(":")) .stream() .map(segment -> StringUtils.repeat('0', 4 - segment.length()) + segment) .collect(Collectors.toList()); @@ -74,6 +68,16 @@ public interface Ipv6Translator extends ByteDataTranslator { } /** + * Transform Ipv6 address to a byte array acceptable by VPP. VPP expects incoming byte array to be in the same order + * as the address. + * + * @return byte array with address bytes + */ + default byte[] ipv6AddressNoZoneToArray(@Nonnull final Ipv6AddressNoZone ipv6Addr) { + return ipv6AddressNoZoneToArray(ipv6Addr.getValue()); + } + + /** * Creates address array from address part of {@link Ipv6Prefix} */ default byte[] ipv6AddressPrefixToArray(@Nonnull final Ipv6Prefix ipv6Prefix) { @@ -136,4 +140,15 @@ public interface Ipv6Translator extends ByteDataTranslator { checkState(!(address.getIpv4Prefix() == null && address.getIpv6Prefix() == null), "Invalid address"); return address.getIpv6Prefix() != null; } + + default Ipv6Prefix toIpv6Prefix(final byte[] address, final int prefix) { + try { + return new Ipv6Prefix( + String.format("%s/%s", InetAddress.getByAddress(address).getHostAddress(), + String.valueOf(prefix))); + } catch (UnknownHostException e) { + throw new IllegalArgumentException( + "Cannot create prefix for address[" + Arrays.toString(address) + "],prefix[" + prefix + "]"); + } + } } diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/MultiNamingContext.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/MultiNamingContext.java new file mode 100644 index 000000000..6b10881d6 --- /dev/null +++ b/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/MultiNamingContext.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.common.translate.util; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; + +import com.google.common.base.Optional; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.util.RWUtils; +import java.util.Collections; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.MultiMappingCtxAugmentation; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.multi.naming.contexts.attributes.MultiNamingContexts; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.multi.naming.contexts.attributes.multi.naming.contexts.MultiNaming; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.multi.naming.contexts.attributes.multi.naming.contexts.MultiNamingKey; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.multi.naming.contexts.attributes.multi.naming.contexts.multi.naming.Mappings; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.multi.naming.contexts.attributes.multi.naming.contexts.multi.naming.mappings.Mapping; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.multi.naming.contexts.attributes.multi.naming.contexts.multi.naming.mappings.MappingBuilder; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.multi.naming.contexts.attributes.multi.naming.contexts.multi.naming.mappings.MappingKey; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.multi.naming.contexts.attributes.multi.naming.contexts.multi.naming.mappings.mapping.Value; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.multi.naming.context.rev160411.multi.naming.contexts.attributes.multi.naming.contexts.multi.naming.mappings.mapping.ValueBuilder; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.Contexts; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; + +/** + * One to many context mapping + */ +public class MultiNamingContext { + + private final KeyedInstanceIdentifier<MultiNaming, MultiNamingKey> + multiNamingContextIid; + + private final int startIndex; + + public MultiNamingContext(@Nonnull final String instanceName, final int startIndex) { + multiNamingContextIid = InstanceIdentifier.create(Contexts.class) + .augmentation(MultiMappingCtxAugmentation.class) + .child(MultiNamingContexts.class) + .child(MultiNaming.class, new MultiNamingKey(instanceName)); + this.startIndex = startIndex; + } + + public synchronized void addChild(@Nonnull final String parentName, final int childIndex, + @Nonnull final String childName, + @Nonnull final MappingContext mappingContext) { + checkArgument(childIndex >= startIndex, "Index cannot be lower than start index %s", startIndex); + final KeyedInstanceIdentifier<Mapping, MappingKey> mappingIid = getMappingIid(parentName); + + //uses merge to preserve previous + mappingContext.merge(mappingIid, + new MappingBuilder().setName(parentName).setValue(Collections.singletonList(new ValueBuilder() + .setIndex(childIndex) + .setName(childName) + .build())).build()); + } + + public synchronized void addChild(@Nonnull final String parentName, + @Nonnull final String childName, + @Nonnull final MappingContext mappingContext) { + addChild(parentName, getNextAvailableChildIndex(parentName, mappingContext), childName, mappingContext); + } + + public synchronized String getChildName(@Nonnull final String parentName, + @Nonnull final int childIndex, + @Nonnull final MappingContext mappingContext) { + final Optional<Mapping> read = mappingContext.read(getMappingIid(parentName)); + + checkState(read.isPresent(), "Mapping not present"); + + return read.get().getValue().stream() + .filter(value -> value.getIndex().equals(childIndex)) + .collect(RWUtils.singleItemCollector()).getName(); + } + + public synchronized int getChildIndex(@Nonnull final String parentName, + @Nonnull final String childName, + @Nonnull final MappingContext mappingContext) { + final Optional<Mapping> read = mappingContext.read(getMappingIid(parentName)); + + checkState(read.isPresent(), "Mapping not present"); + + return read.get().getValue().stream() + .filter(value -> value.getName().equals(childName)) + .collect(RWUtils.singleItemCollector()).getIndex(); + } + + + public synchronized void removeChild(@Nonnull final String parentName, + @Nonnull final String childName, + @Nonnull final MappingContext mappingContext) { + + final Optional<Mapping> read = mappingContext.read(getMappingIid(parentName)); + + // ignore delete's for non-existing parent + if (read.isPresent()) { + final Mapping mapping = read.get(); + + // overrides old data with new(without removed child) + mappingContext.put(getMappingIid(parentName), new MappingBuilder() + .setName(mapping.getName()) + .setKey(mapping.getKey()) + .setValue(mapping.getValue() + .stream() + .filter(value -> !value.getName().equals(childName)) + .collect(Collectors.toList())) + .build()); + } + } + + /** + * Returns next available index for mapping + */ + private int getNextAvailableChildIndex(final String parentName, final MappingContext mappingContext) { + final Optional<Mappings> read = mappingContext.read(mappingIdBase()); + + if (!read.isPresent()) { + return startIndex; + } + + return read.get().getMapping() + .stream() + .filter(mapping -> mapping.getName().equals(parentName)) + .flatMap(mapping -> mapping.getValue().stream()) + .mapToInt(Value::getIndex) + // do not use i++(need increase before, not after + .map(i -> ++i) + .max() + .orElse(startIndex); + } + + private KeyedInstanceIdentifier<Mapping, MappingKey> getMappingIid(final String name) { + return mappingIdBase().child(Mapping.class, new MappingKey(name)); + } + + private InstanceIdentifier<Mappings> mappingIdBase() { + return multiNamingContextIid.child(Mappings.class); + } +} diff --git a/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/NamingContext.java b/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/NamingContext.java index 393df0898..5e0eea71b 100644 --- a/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/NamingContext.java +++ b/vpp-common/vpp-translate-utils/src/main/java/io/fd/hc2vpp/common/translate/util/NamingContext.java @@ -128,6 +128,17 @@ public final class NamingContext implements AutoCloseable { mappingContext.put(mappingIid, new MappingBuilder().setIndex(index).setName(name).build()); } + /** + * Add mapping to current context with next available index. + * Suitable for learned data mappings + * + * @param name name of a mapped item + * @param mappingContext mapping context providing context data for current transaction + */ + public synchronized void addName(final String name, final MappingContext mappingContext) { + addName(getNextAvailableIndex(mappingContext), name, mappingContext); + } + private KeyedInstanceIdentifier<Mapping, MappingKey> getMappingIid(final String name) { return namingContextIid.child(Mappings.class).child(Mapping.class, new MappingKey(name)); } @@ -172,6 +183,25 @@ public final class NamingContext implements AutoCloseable { return artificialNamePrefix + index; } + /** + * Returns next available index for mapping + */ + private int getNextAvailableIndex(final MappingContext mappingContext) { + final Optional<Mappings> read = mappingContext.read(namingContextIid.child(Mappings.class)); + + if (!read.isPresent()) { + return 0; + } + + return read.get().getMapping() + .stream() + .mapToInt(Mapping::getIndex) + // do not use i++(need increase before, not after + .map(i -> ++i) + .max() + .orElse(0); + } + @Override public void close() throws Exception { /// Not removing the mapping from backing storage |