diff options
author | Jan Srnicek <jsrnicek@cisco.com> | 2017-05-24 08:45:19 +0200 |
---|---|---|
committer | Jan Srnicek <jsrnicek@cisco.com> | 2017-05-24 08:45:19 +0200 |
commit | 7ca39aa6d228dc552097857afc697ddf52bd3ad3 (patch) | |
tree | e1af2f7bd22ffc83a2958168f2b313dd765dda47 /lisp/lisp2vpp | |
parent | b5d9c75265a5779ed7404b426f3f91a6b1e07e49 (diff) |
HC2VPP-147 - Gpe entry implementation
Change-Id: Ie7887c8e8f10678410ad677c425bfed1690bf440
Signed-off-by: Jan Srnicek <jsrnicek@cisco.com>
Diffstat (limited to 'lisp/lisp2vpp')
25 files changed, 2813 insertions, 0 deletions
diff --git a/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/GpeModule.java b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/GpeModule.java new file mode 100644 index 000000000..13bdbbddb --- /dev/null +++ b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/GpeModule.java @@ -0,0 +1,55 @@ +/* + * 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.lisp.gpe; + +import com.google.inject.AbstractModule; +import com.google.inject.Singleton; +import com.google.inject.multibindings.Multibinder; +import com.google.inject.name.Names; +import io.fd.hc2vpp.lisp.gpe.translate.ctx.GpeEntryMappingContext; +import io.fd.hc2vpp.lisp.gpe.translate.ctx.GpeEntryMappingContextImpl; +import io.fd.hc2vpp.lisp.gpe.translate.ctx.GpeLocatorPairMappingContext; +import io.fd.hc2vpp.lisp.gpe.translate.ctx.GpeLocatorPairMappingContextImpl; +import io.fd.hc2vpp.lisp.gpe.translate.read.GpeReaderFactory; +import io.fd.hc2vpp.lisp.gpe.translate.service.GpeStateCheckService; +import io.fd.hc2vpp.lisp.gpe.translate.service.GpeStateCheckServiceImpl; +import io.fd.hc2vpp.lisp.gpe.translate.write.GpeWriterFactory; +import io.fd.honeycomb.translate.read.ReaderFactory; +import io.fd.honeycomb.translate.write.WriterFactory; + +public class GpeModule extends AbstractModule { + + public static final String GPE_ENTRY_MAPPING_CTX = "gpe-entry-mapping-ctx"; + public static final String GPE_TO_LOCATOR_PAIR_CTX = "gpe-to-locator-pair-ctx"; + + @Override + protected void configure() { + bind(GpeEntryMappingContext.class).annotatedWith(Names.named(GPE_ENTRY_MAPPING_CTX)) + .toInstance(new GpeEntryMappingContextImpl(GPE_ENTRY_MAPPING_CTX)); + + bind(GpeLocatorPairMappingContext.class).annotatedWith(Names.named(GPE_TO_LOCATOR_PAIR_CTX)) + .toInstance(new GpeLocatorPairMappingContextImpl(GPE_TO_LOCATOR_PAIR_CTX)); + + bind(GpeStateCheckService.class).to(GpeStateCheckServiceImpl.class).in(Singleton.class); + + Multibinder.newSetBinder(binder(), ReaderFactory.class).addBinding() + .to(GpeReaderFactory.class); + + Multibinder.newSetBinder(binder(), WriterFactory.class).addBinding() + .to(GpeWriterFactory.class); + } +} diff --git a/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/ctx/GpeEntryIdentifier.java b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/ctx/GpeEntryIdentifier.java new file mode 100644 index 000000000..466a422e1 --- /dev/null +++ b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/ctx/GpeEntryIdentifier.java @@ -0,0 +1,151 @@ +/* + * 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.lisp.gpe.translate.ctx; + +import io.fd.hc2vpp.lisp.translate.read.dump.executor.params.MappingsDumpParams; +import io.fd.hc2vpp.lisp.translate.util.EidTranslator; +import io.fd.vpp.jvpp.core.types.GpeFwdEntry; +import javax.annotation.Nonnull; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.entry.identification.context.rev170517.gpe.entry.identification.context.attributes.gpe.entry.identification.contexts.gpe.entry.identification.mappings.mapping.GpeEntryIdentificator; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.entry.identification.context.rev170517.gpe.entry.identification.context.attributes.gpe.entry.identification.contexts.gpe.entry.identification.mappings.mapping.gpe.entry.identificator.LocalEid; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.entry.identification.context.rev170517.gpe.entry.identification.context.attributes.gpe.entry.identification.contexts.gpe.entry.identification.mappings.mapping.gpe.entry.identificator.LocalEidBuilder; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.entry.identification.context.rev170517.gpe.entry.identification.context.attributes.gpe.entry.identification.contexts.gpe.entry.identification.mappings.mapping.gpe.entry.identificator.RemoteEid; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.entry.identification.context.rev170517.gpe.entry.identification.context.attributes.gpe.entry.identification.contexts.gpe.entry.identification.mappings.mapping.gpe.entry.identificator.RemoteEidBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.GpeEntry; + + +/** + * Uniquely identifies gpe entry in mapping context + */ +public final class GpeEntryIdentifier implements EidTranslator { + + private final long vni; + private final LocalEid localEid; + private final RemoteEid remoteEid; + + private GpeEntryIdentifier(final long vni, + @Nonnull final LocalEid localEid, + @Nonnull final RemoteEid remoteEid) { + this.vni = vni; + this.localEid = localEid; + this.remoteEid = remoteEid; + } + + public long getVni() { + return vni; + } + + public LocalEid getLocalEid() { + return localEid; + } + + public RemoteEid getRemoteEid() { + return remoteEid; + } + + public boolean isSame(@Nonnull final GpeEntryIdentificator identificator) { + return new EqualsBuilder() + .append(true, compareEids(this.getLocalEid(), identificator.getLocalEid())) + .append(true, compareEids(this.getRemoteEid(), identificator.getRemoteEid())) + .append(this.vni, identificator.getVni().longValue()) + .isEquals(); + } + + public static GpeEntryIdentifier fromEntry(final GpeEntry data) { + return new GpeEntryIdentifier.GpeEntryIdentifierBuilder() + .setLocalEid(data.getLocalEid()) + .setRemoteEid(data.getRemoteEid()) + .setVni(data.getVni()) + .createGpeEntryIdentifier(); + } + + public static GpeEntryIdentifier fromDumpDetail(final GpeFwdEntry entry) { + return new GpeEntryIdentifier.GpeEntryIdentifierBuilder() + .setVni(entry.vni) + .setLocalEid( + INSTANCE.getArrayAsGpeLocalEid(MappingsDumpParams.EidType.valueOf(entry.eidType), entry.leid, + entry.leidPrefixLen, entry.vni)) + .setRemoteEid( + INSTANCE.getArrayAsGpeRemoteEid(MappingsDumpParams.EidType.valueOf(entry.eidType), entry.reid, + entry.reidPrefixLen, entry.vni)) + .createGpeEntryIdentifier(); + } + + public static final class GpeEntryIdentifierBuilder { + private long vni; + private LocalEid localEid; + private RemoteEid remoteEid; + + public GpeEntryIdentifierBuilder setVni(final long vni) { + this.vni = vni; + return this; + } + + public GpeEntryIdentifierBuilder setLocalEid( + @Nonnull final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.LocalEid localEid) { + this.localEid = new LocalEidBuilder() + .setAddress(localEid.getAddress()) + .setAddressType(localEid.getAddressType()) + .setVirtualNetworkId(localEid.getVirtualNetworkId()) + .build(); + return this; + } + + public GpeEntryIdentifierBuilder setRemoteEid( + @Nonnull final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.RemoteEid remoteEid) { + this.remoteEid = new RemoteEidBuilder() + .setAddress(remoteEid.getAddress()) + .setAddressType(remoteEid.getAddressType()) + .setVirtualNetworkId(remoteEid.getVirtualNetworkId()) + .build(); + return this; + } + + public GpeEntryIdentifier createGpeEntryIdentifier() { + return new GpeEntryIdentifier(vni, localEid, remoteEid); + } + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + final GpeEntryIdentifier that = (GpeEntryIdentifier) o; + + if (vni != that.vni) { + return false; + } + if (!localEid.equals(that.localEid)) { + return false; + } + return remoteEid.equals(that.remoteEid); + } + + @Override + public int hashCode() { + int result = (int) (vni ^ (vni >>> 32)); + result = 31 * result + localEid.hashCode(); + result = 31 * result + remoteEid.hashCode(); + return result; + } +} diff --git a/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/ctx/GpeEntryMappingContext.java b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/ctx/GpeEntryMappingContext.java new file mode 100644 index 000000000..fb8982add --- /dev/null +++ b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/ctx/GpeEntryMappingContext.java @@ -0,0 +1,54 @@ +/* + * 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.lisp.gpe.translate.ctx; + +import io.fd.honeycomb.translate.MappingContext; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.entry.identification.context.rev170517.gpe.entry.identification.context.attributes.gpe.entry.identification.contexts.gpe.entry.identification.mappings.mapping.GpeEntryIdentificator; + + +/** + * Provides mapping context for gpe entries + */ +public interface GpeEntryMappingContext { + + /** + * Adds context mapping for specified id to gpe entry + */ + void addMapping(@Nonnull final String id, + @Nonnull final GpeEntryIdentifier identifier, + @Nonnull final MappingContext mappingContext); + + /** + * Remove context mapping for specified id + */ + void removeMapping(@Nonnull final String id, + @Nonnull final MappingContext mappingContext); + + /** + * Returns identificator for specific id + */ + GpeEntryIdentificator getIdentificatorById(@Nonnull final String id, + @Nonnull final MappingContext mappingContext); + + + /** + * Returns id for specified identifier + */ + String getIdByEntryIdentifier(@Nonnull final GpeEntryIdentifier identifier, + @Nonnull final MappingContext mappingContext); +} diff --git a/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/ctx/GpeEntryMappingContextImpl.java b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/ctx/GpeEntryMappingContextImpl.java new file mode 100644 index 000000000..759931204 --- /dev/null +++ b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/ctx/GpeEntryMappingContextImpl.java @@ -0,0 +1,144 @@ +/* + * 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.lisp.gpe.translate.ctx; + +import static java.lang.String.format; + +import io.fd.honeycomb.translate.MappingContext; +import java.util.Collection; +import java.util.Optional; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.entry.identification.context.rev170517.GpeEntryIdentificationCtxAugmentation; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.entry.identification.context.rev170517.gpe.entry.identification.context.attributes.GpeEntryIdentificationContexts; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.entry.identification.context.rev170517.gpe.entry.identification.context.attributes.gpe.entry.identification.contexts.GpeEntryIdentification; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.entry.identification.context.rev170517.gpe.entry.identification.context.attributes.gpe.entry.identification.contexts.GpeEntryIdentificationKey; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.entry.identification.context.rev170517.gpe.entry.identification.context.attributes.gpe.entry.identification.contexts.gpe.entry.identification.Mappings; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.entry.identification.context.rev170517.gpe.entry.identification.context.attributes.gpe.entry.identification.contexts.gpe.entry.identification.mappings.Mapping; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.entry.identification.context.rev170517.gpe.entry.identification.context.attributes.gpe.entry.identification.contexts.gpe.entry.identification.mappings.MappingBuilder; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.entry.identification.context.rev170517.gpe.entry.identification.context.attributes.gpe.entry.identification.contexts.gpe.entry.identification.mappings.MappingKey; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.entry.identification.context.rev170517.gpe.entry.identification.context.attributes.gpe.entry.identification.contexts.gpe.entry.identification.mappings.mapping.GpeEntryIdentificator; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.entry.identification.context.rev170517.gpe.entry.identification.context.attributes.gpe.entry.identification.contexts.gpe.entry.identification.mappings.mapping.GpeEntryIdentificatorBuilder; +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; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class GpeEntryMappingContextImpl implements GpeEntryMappingContext { + + private static final Logger LOG = LoggerFactory.getLogger(GpeEntryMappingContextImpl.class); + + private final KeyedInstanceIdentifier<GpeEntryIdentification, GpeEntryIdentificationKey> + namingContextIid; + + /** + * Create new naming context + * + * @param instanceName name of this context instance. Will be used as list item identifier within context data tree + */ + public GpeEntryMappingContextImpl(@Nonnull final String instanceName) { + namingContextIid = InstanceIdentifier.create(Contexts.class) + .augmentation(GpeEntryIdentificationCtxAugmentation.class) + .child(GpeEntryIdentificationContexts.class) + .child(GpeEntryIdentification.class, new GpeEntryIdentificationKey(instanceName)); + } + + @Override + public void addMapping(@Nonnull final String id, + @Nonnull final GpeEntryIdentifier identifier, + @Nonnull final MappingContext mappingContext) { + LOG.debug("Adding mapping for gpe-entry[id={},entry-identifier={}]", id, identifier); + mappingContext.put(getMappingId(id), getMapping(id, identifier)); + LOG.debug("Mapping for gp-entry[id={}] successfully added", id); + } + + @Override + public void removeMapping(@Nonnull final String id, + @Nonnull final MappingContext mappingContext) { + LOG.debug("Removing mapping for gpe-entry[id={}]", id); + mappingContext.delete(getMappingId(id)); + LOG.debug("Mapping for gpe-entry[id={}] removed", id); + } + + @Override + public GpeEntryIdentificator getIdentificatorById(@Nonnull final String id, + @Nonnull final MappingContext mappingContext) { + final com.google.common.base.Optional<Mappings> read = + mappingContext.read(namingContextIid.child(Mappings.class)); + + if (read.isPresent()) { + return Optional.of(read.get()) + .map(Mappings::getMapping) + .map(Collection::stream) + .map(mappingStream -> mappingStream + .filter(mapping -> mapping.getId().equals(id)) + .map(Mapping::getGpeEntryIdentificator) + .findAny().orElse(null)) + .orElseThrow(() -> new IllegalStateException(format("No mapping for id %s", id))); + + } + throw new IllegalStateException(format("No mapping for id %s", id)); + } + + @Override + public String getIdByEntryIdentifier(@Nonnull final GpeEntryIdentifier identifier, + @Nonnull final MappingContext mappingContext) { + final com.google.common.base.Optional<Mappings> read = + mappingContext.read(namingContextIid.child(Mappings.class)); + + if (read.isPresent()) { + return Optional.of(read.get()) + .map(Mappings::getMapping) + .map(Collection::stream) + .map(mappingStream -> mappingStream + .filter(mapping -> identifier.isSame(mapping.getGpeEntryIdentificator())) + .map(Mapping::getId) + .findAny().orElse(null)) + .orElse(addArtificialMapping(identifier, mappingContext)); + } + + return addArtificialMapping(identifier, mappingContext); + } + + private String addArtificialMapping(@Nonnull final GpeEntryIdentifier identifier, + @Nonnull final MappingContext mappingContext) { + final String artificialName = buildArtificialName(identifier); + addMapping(artificialName, identifier, mappingContext); + return artificialName; + } + + private String buildArtificialName(@Nonnull final GpeEntryIdentifier identifier) { + return format("%s_%s_%s", identifier.getVni(), identifier.getLocalEid().getAddress(), + identifier.getRemoteEid().getAddress()); + } + + private KeyedInstanceIdentifier<Mapping, MappingKey> getMappingId(final String id) { + return namingContextIid.child(Mappings.class).child(Mapping.class, new MappingKey(id)); + } + + private Mapping getMapping(@Nonnull final String id, + @Nonnull final GpeEntryIdentifier identifier) { + return new MappingBuilder() + .setId(id) + .setGpeEntryIdentificator(new GpeEntryIdentificatorBuilder() + .setLocalEid(identifier.getLocalEid()) + .setRemoteEid(identifier.getRemoteEid()) + .setVni(identifier.getVni()) + .build()) + .build(); + } +} diff --git a/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/ctx/GpeLocatorPair.java b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/ctx/GpeLocatorPair.java new file mode 100644 index 000000000..a5cf13191 --- /dev/null +++ b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/ctx/GpeLocatorPair.java @@ -0,0 +1,113 @@ +/* + * 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.lisp.gpe.translate.ctx; + +import io.fd.hc2vpp.common.translate.util.AddressTranslator; +import io.fd.vpp.jvpp.core.dto.GpeFwdEntryPathDetails; +import java.util.Arrays; +import javax.annotation.Nonnull; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.locator.pair.identification.context.rev170517.gpe.locator.pair.identification.context.attributes.gpe.locator.pair.identification.contexts.gpe.locator.pair.identification.mappings.mapping.locator.pair.mapping.Pair; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.LocatorPairs; + +public final class GpeLocatorPair implements AddressTranslator { + + private final IpAddress localAddress; + private final IpAddress remoteAddress; + + private GpeLocatorPair(@Nonnull final IpAddress localAddress, @Nonnull final IpAddress remoteAddress) { + this.localAddress = localAddress; + this.remoteAddress = remoteAddress; + } + + public IpAddress getLocalAddress() { + return localAddress; + } + + public IpAddress getRemoteAddress() { + return remoteAddress; + } + + public boolean isSame(@Nonnull final Pair pair) { + return new EqualsBuilder() + .append(true, Arrays.equals(this.localAddress.getValue(), pair.getLocalAddress().getValue())) + .append(true, Arrays.equals(this.remoteAddress.getValue(), pair.getRemoteAddress().getValue())) + .isEquals(); + } + + public static GpeLocatorPair fromDumpDetail(final GpeFwdEntryPathDetails entry) { + return new GpeLocatorPair.GpeLocatorPairBuilder() + .setLocalAddress( + INSTANCE.arrayToIpAddress(!INSTANCE.byteToBoolean(entry.lclLoc.isIp4), + entry.lclLoc.addr)) + .setRemoteAddress( + INSTANCE.arrayToIpAddress(!INSTANCE.byteToBoolean(entry.rmtLoc.isIp4), + entry.rmtLoc.addr)) + .createGpeLocatorPairIdentifier(); + } + + public static GpeLocatorPair fromLocatorPair(final LocatorPairs locatorPair) { + return new GpeLocatorPair.GpeLocatorPairBuilder() + .setLocalAddress(locatorPair.getLocatorPair().getLocalLocator()) + .setRemoteAddress(locatorPair.getLocatorPair().getRemoteLocator()) + .createGpeLocatorPairIdentifier(); + } + + public static final class GpeLocatorPairBuilder { + private IpAddress localAddress; + private IpAddress remoteAddress; + + public GpeLocatorPairBuilder setLocalAddress(@Nonnull final IpAddress localAddress) { + this.localAddress = localAddress; + return this; + } + + public GpeLocatorPairBuilder setRemoteAddress(@Nonnull final IpAddress remoteAddress) { + this.remoteAddress = remoteAddress; + return this; + } + + public GpeLocatorPair createGpeLocatorPairIdentifier() { + return new GpeLocatorPair(localAddress, remoteAddress); + } + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + final GpeLocatorPair that = (GpeLocatorPair) o; + + if (!localAddress.equals(that.localAddress)) { + return false; + } + return remoteAddress.equals(that.remoteAddress); + } + + @Override + public int hashCode() { + int result = localAddress.hashCode(); + result = 31 * result + remoteAddress.hashCode(); + return result; + } +} diff --git a/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/ctx/GpeLocatorPairMappingContext.java b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/ctx/GpeLocatorPairMappingContext.java new file mode 100644 index 000000000..b2226a1b6 --- /dev/null +++ b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/ctx/GpeLocatorPairMappingContext.java @@ -0,0 +1,55 @@ +/* + * 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.lisp.gpe.translate.ctx; + +import io.fd.honeycomb.translate.MappingContext; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.locator.pair.identification.context.rev170517.gpe.locator.pair.identification.context.attributes.gpe.locator.pair.identification.contexts.gpe.locator.pair.identification.mappings.mapping.LocatorPairMapping; + +/** + * Context mapping of gpe entries to locator pairs + */ +public interface GpeLocatorPairMappingContext { + + /** + * Adds mapping for entry and specified locator + */ + void addMapping(@Nonnull String entryId, + @Nonnull String locatorId, + @Nonnull GpeLocatorPair pair, + @Nonnull MappingContext mappingContext); + + /** + * Remote all mappings for entry + */ + void removeMapping(@Nonnull String entryId, + @Nonnull MappingContext mappingContext); + + /** + * Returns mapping for specified entry and locator + */ + LocatorPairMapping getMapping(@Nonnull String entryId, + @Nonnull GpeLocatorPair pair, + @Nonnull MappingContext mappingContext); + + /** + * Returns mapping for specified entry and locator + */ + LocatorPairMapping getMapping(@Nonnull String entryId, + @Nonnull String locatorId, + @Nonnull MappingContext mappingContext); +} diff --git a/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/ctx/GpeLocatorPairMappingContextImpl.java b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/ctx/GpeLocatorPairMappingContextImpl.java new file mode 100644 index 000000000..94b19996b --- /dev/null +++ b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/ctx/GpeLocatorPairMappingContextImpl.java @@ -0,0 +1,127 @@ +/* + * 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.lisp.gpe.translate.ctx; + +import static java.lang.String.format; + +import io.fd.honeycomb.translate.MappingContext; +import java.util.Collections; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.locator.pair.identification.context.rev170517.GpeLocatorPairIdentificationCtxAugmentation; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.locator.pair.identification.context.rev170517.gpe.locator.pair.identification.context.attributes.GpeLocatorPairIdentificationContexts; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.locator.pair.identification.context.rev170517.gpe.locator.pair.identification.context.attributes.gpe.locator.pair.identification.contexts.GpeLocatorPairIdentification; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.locator.pair.identification.context.rev170517.gpe.locator.pair.identification.context.attributes.gpe.locator.pair.identification.contexts.GpeLocatorPairIdentificationKey; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.locator.pair.identification.context.rev170517.gpe.locator.pair.identification.context.attributes.gpe.locator.pair.identification.contexts.gpe.locator.pair.identification.Mappings; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.locator.pair.identification.context.rev170517.gpe.locator.pair.identification.context.attributes.gpe.locator.pair.identification.contexts.gpe.locator.pair.identification.mappings.Mapping; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.locator.pair.identification.context.rev170517.gpe.locator.pair.identification.context.attributes.gpe.locator.pair.identification.contexts.gpe.locator.pair.identification.mappings.MappingBuilder; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.locator.pair.identification.context.rev170517.gpe.locator.pair.identification.context.attributes.gpe.locator.pair.identification.contexts.gpe.locator.pair.identification.mappings.MappingKey; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.locator.pair.identification.context.rev170517.gpe.locator.pair.identification.context.attributes.gpe.locator.pair.identification.contexts.gpe.locator.pair.identification.mappings.mapping.LocatorPairMapping; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.locator.pair.identification.context.rev170517.gpe.locator.pair.identification.context.attributes.gpe.locator.pair.identification.contexts.gpe.locator.pair.identification.mappings.mapping.LocatorPairMappingBuilder; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.locator.pair.identification.context.rev170517.gpe.locator.pair.identification.context.attributes.gpe.locator.pair.identification.contexts.gpe.locator.pair.identification.mappings.mapping.locator.pair.mapping.PairBuilder; +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; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class GpeLocatorPairMappingContextImpl implements GpeLocatorPairMappingContext { + + private static final Logger LOG = LoggerFactory.getLogger(GpeLocatorPairMappingContextImpl.class); + + private final KeyedInstanceIdentifier<GpeLocatorPairIdentification, GpeLocatorPairIdentificationKey> + namingContextIid; + + public GpeLocatorPairMappingContextImpl(@Nonnull final String instanceName) { + namingContextIid = InstanceIdentifier.create(Contexts.class) + .augmentation(GpeLocatorPairIdentificationCtxAugmentation.class) + .child(GpeLocatorPairIdentificationContexts.class) + .child(GpeLocatorPairIdentification.class, new GpeLocatorPairIdentificationKey(instanceName)); + } + + + @Override + public void addMapping(@Nonnull final String entryId, + @Nonnull final String locatorId, + @Nonnull final GpeLocatorPair pair, + @Nonnull final MappingContext mappingContext) { + LOG.debug("Adding mapping for Gpe entry to locator id[entry-id={},locator-pair-id={}]", entryId, locatorId); + mappingContext.merge(getMappingId(entryId), getMappingData(entryId, locatorId, pair)); + LOG.debug("Mapping for Gpe entry to locator id[entry-id={},locator-pair-id={}] successfully added", entryId, + locatorId); + } + + @Override + public void removeMapping(@Nonnull final String entryId, + @Nonnull final MappingContext mappingContext) { + LOG.debug("Removing all mappings for Gpe entry[id={}]", entryId); + mappingContext.delete(getMappingId(entryId)); + LOG.debug("All mappings for Gpe entry[id={}] removed", entryId); + } + + @Override + public LocatorPairMapping getMapping(@Nonnull final String entryId, + @Nonnull final GpeLocatorPair pair, + @Nonnull final MappingContext mappingContext) { + return mappingContext.read(getMappingId(entryId)) + .or(new MappingBuilder().setLocatorPairMapping(Collections.emptyList()).build()) + .getLocatorPairMapping() + .stream() + .filter(mapping -> pair.isSame(mapping.getPair())) + .findAny().orElseGet(() -> { + final String artificialLocatorId = artificialLocatorPairId(entryId, pair); + addMapping(entryId, artificialLocatorId, pair, mappingContext); + return getMapping(entryId, artificialLocatorId, mappingContext); + }); + } + + @Override + public LocatorPairMapping getMapping(@Nonnull final String entryId, + @Nonnull final String locatorId, + @Nonnull final MappingContext mappingContext) { + return mappingContext.read(getMappingId(entryId)) + .or(new MappingBuilder().setLocatorPairMapping(Collections.emptyList()).build()) + .getLocatorPairMapping() + .stream() + .filter(mapping -> mapping.getId().equals(locatorId)) + .findAny().orElseThrow(() -> new IllegalArgumentException( + format("No mapping for entry %s|locator %s", entryId, locatorId))); + } + + private String artificialLocatorPairId(final String entryId, final GpeLocatorPair pair) { + return format("%s_%s_%s", entryId, pair.getLocalAddress(), pair.getRemoteAddress()); + } + + private Mapping getMappingData(final String entryId, + final String locatorId, + final GpeLocatorPair identifier) { + return new MappingBuilder() + .setId(entryId) + .setLocatorPairMapping(Collections.singletonList(new LocatorPairMappingBuilder() + .setId(locatorId) + .setPair(new PairBuilder() + .setLocalAddress(identifier.getLocalAddress()) + .setRemoteAddress(identifier.getRemoteAddress()) + .build()) + .build())).build(); + } + + private KeyedInstanceIdentifier<Mapping, MappingKey> getMappingId(final String id) { + return namingContextIid.child(Mappings.class) + .child(Mapping.class, new MappingKey(id)); + } +} + diff --git a/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/read/GpeFeatureCustomizer.java b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/read/GpeFeatureCustomizer.java new file mode 100644 index 000000000..d274d90dc --- /dev/null +++ b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/read/GpeFeatureCustomizer.java @@ -0,0 +1,81 @@ +/* + * 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.lisp.gpe.translate.read; + + +import io.fd.hc2vpp.common.translate.util.ByteDataTranslator; +import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.Initialized; +import io.fd.honeycomb.translate.spi.read.InitializingReaderCustomizer; +import io.fd.vpp.jvpp.core.dto.ShowLispStatus; +import io.fd.vpp.jvpp.core.dto.ShowLispStatusReply; +import io.fd.vpp.jvpp.core.future.FutureJVppCore; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.Gpe; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.GpeStateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.feature.data.grouping.GpeFeatureData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.feature.data.grouping.GpeFeatureDataBuilder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class GpeFeatureCustomizer extends FutureJVppCustomizer + implements InitializingReaderCustomizer<GpeFeatureData, GpeFeatureDataBuilder>, JvppReplyConsumer, + ByteDataTranslator { + + public GpeFeatureCustomizer(@Nonnull final FutureJVppCore futureJVppCore) { + super(futureJVppCore); + } + + + @Nonnull + @Override + public Initialized<? extends DataObject> init(@Nonnull final InstanceIdentifier<GpeFeatureData> id, + @Nonnull final GpeFeatureData readValue, + @Nonnull final ReadContext ctx) { + return Initialized.create(InstanceIdentifier.create(Gpe.class).child(GpeFeatureData.class), + new GpeFeatureDataBuilder().setEnable(readValue.isEnable()).build()); + } + + @Nonnull + @Override + public GpeFeatureDataBuilder getBuilder(@Nonnull final InstanceIdentifier<GpeFeatureData> id) { + return new GpeFeatureDataBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier<GpeFeatureData> id, + @Nonnull final GpeFeatureDataBuilder builder, @Nonnull final ReadContext ctx) + throws ReadFailedException { + // same api as lispState + final ShowLispStatusReply reply = + getReplyForRead(getFutureJVpp().showLispStatus(new ShowLispStatus()).toCompletableFuture(), id); + + if (reply != null) { + builder.setEnable(byteToBoolean(reply.gpeStatus)); + } + } + + @Override + public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, + @Nonnull final GpeFeatureData readValue) { + ((GpeStateBuilder) parentBuilder).setGpeFeatureData(readValue); + } +} diff --git a/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/read/GpeForwardEntryCustomizer.java b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/read/GpeForwardEntryCustomizer.java new file mode 100644 index 000000000..90ab65bad --- /dev/null +++ b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/read/GpeForwardEntryCustomizer.java @@ -0,0 +1,266 @@ +/* + * 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.lisp.gpe.translate.read; + +import static io.fd.hc2vpp.lisp.gpe.translate.ctx.GpeEntryIdentifier.fromDumpDetail; +import static io.fd.hc2vpp.lisp.gpe.translate.ctx.GpeLocatorPair.fromDumpDetail; +import static io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor.NO_PARAMS; +import static java.lang.String.format; + +import com.google.common.base.Optional; +import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.lisp.gpe.translate.ctx.GpeEntryIdentifier; +import io.fd.hc2vpp.lisp.gpe.translate.ctx.GpeEntryMappingContext; +import io.fd.hc2vpp.lisp.gpe.translate.ctx.GpeLocatorPair; +import io.fd.hc2vpp.lisp.gpe.translate.ctx.GpeLocatorPairMappingContext; +import io.fd.hc2vpp.lisp.gpe.translate.service.GpeStateCheckService; +import io.fd.hc2vpp.lisp.translate.read.dump.executor.params.MappingsDumpParams; +import io.fd.hc2vpp.lisp.translate.util.EidTranslator; +import io.fd.honeycomb.translate.ModificationCache; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.Initialized; +import io.fd.honeycomb.translate.spi.read.InitializingListReaderCustomizer; +import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager; +import io.fd.vpp.jvpp.core.dto.GpeFwdEntriesGet; +import io.fd.vpp.jvpp.core.dto.GpeFwdEntriesGetReply; +import io.fd.vpp.jvpp.core.dto.GpeFwdEntryPathDetails; +import io.fd.vpp.jvpp.core.dto.GpeFwdEntryPathDetailsReplyDump; +import io.fd.vpp.jvpp.core.dto.GpeFwdEntryPathDump; +import io.fd.vpp.jvpp.core.dto.GpeFwdEntryVnisGet; +import io.fd.vpp.jvpp.core.dto.GpeFwdEntryVnisGetReply; +import io.fd.vpp.jvpp.core.future.FutureJVppCore; +import io.fd.vpp.jvpp.core.types.GpeFwdEntry; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.entry.identification.context.rev170517.gpe.entry.identification.context.attributes.gpe.entry.identification.contexts.gpe.entry.identification.mappings.mapping.GpeEntryIdentificator; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.locator.pair.identification.context.rev170517.gpe.locator.pair.identification.context.attributes.gpe.locator.pair.identification.contexts.gpe.locator.pair.identification.mappings.mapping.LocatorPairMapping; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.Gpe; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.GpeEntryTable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.GpeEntryTableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.GpeEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.GpeEntryBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.GpeEntryKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.LocatorPairs; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.LocatorPairsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.feature.data.grouping.GpeFeatureData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.locator.pair.LocatorPairBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev170315.MapReplyAction; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class GpeForwardEntryCustomizer extends FutureJVppCustomizer + implements InitializingListReaderCustomizer<GpeEntry, GpeEntryKey, GpeEntryBuilder>, JvppReplyConsumer, + EidTranslator { + + private final DumpCacheManager<GpeFwdEntriesGetReply, Integer> entryDumpManager; + private final DumpCacheManager<GpeFwdEntryPathDetailsReplyDump, Integer> entryDumpCacheManager; + private final DumpCacheManager<GpeFwdEntryVnisGetReply, Void> activeVnisDumpManager; + private final GpeEntryMappingContext gpeEntryMappingContext; + private final GpeLocatorPairMappingContext gpeLocatorsMappingContext; + private final GpeStateCheckService gpeStateCheckService; + + public GpeForwardEntryCustomizer(@Nonnull final FutureJVppCore futureJVppCore, + @Nonnull final GpeStateCheckService gpeStateCheckService, + @Nonnull final GpeEntryMappingContext gpeEntryMappingContext, + @Nonnull final GpeLocatorPairMappingContext gpeLocatorsMappingContext) { + super(futureJVppCore); + this.gpeStateCheckService = gpeStateCheckService; + this.gpeEntryMappingContext = gpeEntryMappingContext; + this.gpeLocatorsMappingContext = gpeLocatorsMappingContext; + this.entryDumpManager = new DumpCacheManager.DumpCacheManagerBuilder<GpeFwdEntriesGetReply, Integer>() + .acceptOnly(GpeFwdEntriesGetReply.class) + .withExecutor((identifier, vni) -> { + GpeFwdEntriesGet request = new GpeFwdEntriesGet(); + request.vni = vni; + return getReplyForRead(getFutureJVpp().gpeFwdEntriesGet(request).toCompletableFuture(), identifier); + }).build(); + entryDumpCacheManager = + new DumpCacheManager.DumpCacheManagerBuilder<GpeFwdEntryPathDetailsReplyDump, Integer>() + .acceptOnly(GpeFwdEntryPathDetailsReplyDump.class) + .withExecutor((identifier, fwdEntryIndex) -> { + GpeFwdEntryPathDump request = new GpeFwdEntryPathDump(); + request.fwdEntryIndex = fwdEntryIndex; + return getReplyForRead(getFutureJVpp().gpeFwdEntryPathDump(request).toCompletableFuture(), + identifier); + }).build(); + activeVnisDumpManager = new DumpCacheManager.DumpCacheManagerBuilder<GpeFwdEntryVnisGetReply, Void>() + .acceptOnly(GpeFwdEntryVnisGetReply.class) + .withExecutor((identifier, params) -> getReplyForRead( + getFutureJVpp().gpeFwdEntryVnisGet(new GpeFwdEntryVnisGet()).toCompletableFuture(), + identifier)) + .build(); + } + + @Nonnull + @Override + public Initialized<? extends DataObject> init(@Nonnull final InstanceIdentifier<GpeEntry> id, + @Nonnull final GpeEntry readValue, + @Nonnull final ReadContext ctx) { + return Initialized.create(InstanceIdentifier.create(Gpe.class) + .child(GpeFeatureData.class) + .child(GpeEntryTable.class) + .child(GpeEntry.class, id.firstKeyOf(GpeEntry.class)), readValue); + } + + @Nonnull + @Override + public List<GpeEntryKey> getAllIds(@Nonnull final InstanceIdentifier<GpeEntry> id, + @Nonnull final ReadContext context) + throws ReadFailedException { + + if (!gpeStateCheckService.isGpeEnabled(context)) { + return Collections.emptyList(); + } + + return activeVnis(id, context.getModificationCache()) + .flatMap(vni -> getKeysForVni(id, vni, context).stream()) + .collect(Collectors.toList()); + } + + @Override + public void merge(@Nonnull final Builder<? extends DataObject> builder, @Nonnull final List<GpeEntry> readData) { + ((GpeEntryTableBuilder) builder).setGpeEntry(readData); + } + + @Nonnull + @Override + public GpeEntryBuilder getBuilder(@Nonnull final InstanceIdentifier<GpeEntry> id) { + return new GpeEntryBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier<GpeEntry> id, + @Nonnull final GpeEntryBuilder builder, + @Nonnull final ReadContext ctx) throws ReadFailedException { + if (!gpeStateCheckService.isGpeEnabled(ctx)) { + return; + } + + final String entryId = id.firstKeyOf(GpeEntry.class).getId(); + + final GpeEntryIdentificator identificator = + gpeEntryMappingContext.getIdentificatorById(entryId, ctx.getMappingContext()); + + // reads configured vni's, then reads entries for them and filter out current one + final java.util.Optional<GpeFwdEntry> entryCandicate = activeVnis(id, ctx.getModificationCache()) + .flatMap(vni -> getEntriesForVni(id, vni, ctx).stream()) + .filter(entry -> fromDumpDetail(entry).isSame(identificator)) + .findAny(); + + if (entryCandicate.isPresent()) { + final GpeFwdEntry gpeFwdEntry = entryCandicate.get(); + + final int entryVni = gpeFwdEntry.vni; + builder.setId(entryId) + .setDpTable((long) gpeFwdEntry.dpTable) + .setLocalEid(getArrayAsGpeLocalEid(MappingsDumpParams.EidType.valueOf(gpeFwdEntry.eidType), + gpeFwdEntry.leid, gpeFwdEntry.leidPrefixLen, entryVni)) + .setRemoteEid(getArrayAsGpeRemoteEid(MappingsDumpParams.EidType.valueOf(gpeFwdEntry.eidType), + gpeFwdEntry.reid, gpeFwdEntry.reidPrefixLen, entryVni)) + .setVni((long) entryVni); + + final Optional<GpeFwdEntryPathDetailsReplyDump> locatorsDump = + entryDumpCacheManager.getDump(id, ctx.getModificationCache(), gpeFwdEntry.fwdEntryIndex); + + // if any locators exist,it is a positive mapping + if (locatorsDump.isPresent() && locatorsDump.get().gpeFwdEntryPathDetails != null && + !locatorsDump.get().gpeFwdEntryPathDetails.isEmpty()) { + final List<LocatorPairs> pairs = + java.util.Optional.ofNullable(locatorsDump.get().gpeFwdEntryPathDetails) + .orElse(Collections.emptyList()) + .stream() + .map(entry -> { + final GpeLocatorPair gpePair = fromDumpDetail(entry); + final LocatorPairMapping mapping = gpeLocatorsMappingContext + .getMapping(entryId, gpePair, ctx.getMappingContext()); + return buildLocatorPair(entry, gpePair, mapping); + }).collect(Collectors.toList()); + builder.setLocatorPairs(pairs); + } else { + // negative otherwise + builder.setAction(MapReplyAction.forValue(gpeFwdEntry.action)); + } + } + } + + private List<GpeFwdEntry> getEntriesForVni(final InstanceIdentifier<GpeEntry> id, final int vni, + final ReadContext context) { + final Optional<GpeFwdEntriesGetReply> dump = getEntiesDump(id, vni, context); + if (dump.isPresent()) { + return Arrays.stream(java.util.Optional.ofNullable(dump.get().entries).orElse(new GpeFwdEntry[]{})) + .collect(Collectors.toList()); + } + + return Collections.emptyList(); + } + + private List<GpeEntryKey> getKeysForVni(final InstanceIdentifier<GpeEntry> id, final int vni, + final ReadContext context) { + + final Optional<GpeFwdEntriesGetReply> dump = getEntiesDump(id, vni, context); + if (dump.isPresent()) { + return Arrays.stream(java.util.Optional.ofNullable(dump.get().entries).orElse(new GpeFwdEntry[]{})) + .map(GpeEntryIdentifier::fromDumpDetail) + .map(identifier -> gpeEntryMappingContext + .getIdByEntryIdentifier(identifier, context.getMappingContext())) + .map(GpeEntryKey::new) + .collect(Collectors.toList()); + } + + return Collections.emptyList(); + } + + private Optional<GpeFwdEntriesGetReply> getEntiesDump(final InstanceIdentifier<GpeEntry> id, final int vni, + final ReadContext context) { + final Optional<GpeFwdEntriesGetReply> dump; + try { + dump = entryDumpManager.getDump(id, context.getModificationCache(), vni); + } catch (ReadFailedException e) { + throw new IllegalStateException(format("Unable to read Gpe entries for vni %s", vni), e); + } + return dump; + } + + private LocatorPairs buildLocatorPair(final GpeFwdEntryPathDetails entry, final GpeLocatorPair gpePair, + final LocatorPairMapping mapping) { + return new LocatorPairsBuilder() + .setId(mapping.getId()) + .setLocatorPair(new LocatorPairBuilder() + .setLocalLocator(gpePair.getLocalAddress()) + .setRemoteLocator(gpePair.getRemoteAddress()) + .setWeight((short) entry.lclLoc.weight) + .build()) + .build(); + } + + private Stream<Integer> activeVnis(final InstanceIdentifier<GpeEntry> id, + final ModificationCache cache) throws ReadFailedException { + final int[] vnis = activeVnisDumpManager.getDump(id, cache, NO_PARAMS).or(() -> { + final GpeFwdEntryVnisGetReply reply = new GpeFwdEntryVnisGetReply(); + reply.vnis = new int[0]; + return reply; + }).vnis; + return Arrays.stream(vnis).boxed(); + } +} diff --git a/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/read/GpeReaderFactory.java b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/read/GpeReaderFactory.java new file mode 100644 index 000000000..236289033 --- /dev/null +++ b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/read/GpeReaderFactory.java @@ -0,0 +1,85 @@ +/* + * 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.lisp.gpe.translate.read; + +import com.google.common.collect.ImmutableSet; +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.hc2vpp.lisp.gpe.GpeModule; +import io.fd.hc2vpp.lisp.gpe.translate.ctx.GpeEntryMappingContext; +import io.fd.hc2vpp.lisp.gpe.translate.ctx.GpeLocatorPairMappingContext; +import io.fd.hc2vpp.lisp.gpe.translate.service.GpeStateCheckService; +import io.fd.honeycomb.translate.impl.read.GenericInitListReader; +import io.fd.honeycomb.translate.impl.read.GenericInitReader; +import io.fd.honeycomb.translate.read.ReaderFactory; +import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder; +import io.fd.vpp.jvpp.core.future.FutureJVppCore; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.GpeState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.GpeStateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.GpeEntryTable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.GpeEntryTableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.GpeEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.LocalEid; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.LocatorPairs; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.RemoteEid; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.feature.data.grouping.GpeFeatureData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.locator.pair.LocatorPair; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class GpeReaderFactory implements ReaderFactory { + + private static final InstanceIdentifier<GpeState> + GPE_STATE_ID = InstanceIdentifier.create(GpeState.class); + private static final InstanceIdentifier<GpeFeatureData> + GPE_FEATURE_ID = GPE_STATE_ID.child(GpeFeatureData.class); + private static final InstanceIdentifier<GpeEntryTable> + GPE_ENTRY_TABLE_ID = GPE_FEATURE_ID.child(GpeEntryTable.class); + private static final InstanceIdentifier<GpeEntry> + GPE_ENTRY_ID = GPE_ENTRY_TABLE_ID.child(GpeEntry.class); + + @Inject + private FutureJVppCore api; + + @Inject + private GpeStateCheckService gpeStateCheckService; + + @Inject + @Named(GpeModule.GPE_ENTRY_MAPPING_CTX) + private GpeEntryMappingContext gpeEntryMappingContext; + + @Inject + @Named(GpeModule.GPE_TO_LOCATOR_PAIR_CTX) + private GpeLocatorPairMappingContext gpeLocatorPairMappingContext; + + @Override + public void init(@Nonnull final ModifiableReaderRegistryBuilder registry) { + registry.addStructuralReader(GPE_STATE_ID, GpeStateBuilder.class); + registry.add(new GenericInitReader<>(GPE_FEATURE_ID, new GpeFeatureCustomizer(api))); + registry.addStructuralReader(GPE_ENTRY_TABLE_ID, GpeEntryTableBuilder.class); + + final InstanceIdentifier<GpeEntry> entrySubtreeId = InstanceIdentifier.create(GpeEntry.class); + registry.subtreeAdd(ImmutableSet.of( + entrySubtreeId.child(LocalEid.class), + entrySubtreeId.child(RemoteEid.class), + entrySubtreeId.child(LocatorPairs.class), + entrySubtreeId.child(LocatorPairs.class).child(LocatorPair.class)), + new GenericInitListReader<>(GPE_ENTRY_ID, + new GpeForwardEntryCustomizer(api, gpeStateCheckService, gpeEntryMappingContext, + gpeLocatorPairMappingContext))); + } +} diff --git a/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/service/GpeStateCheckService.java b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/service/GpeStateCheckService.java new file mode 100644 index 000000000..ba9828668 --- /dev/null +++ b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/service/GpeStateCheckService.java @@ -0,0 +1,43 @@ +/* + * 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.lisp.gpe.translate.service; + +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.write.WriteContext; +import javax.annotation.Nonnull; + +/** + * Provides logic to check whether gpe feature is enabled + */ +public interface GpeStateCheckService { + + /** + * @throws IllegalStateException if gpe feature is disabled + */ + void checkGpeEnabledBefore(@Nonnull final WriteContext writeContext); + + /** + * @throws IllegalStateException if gpe feature is disabled + */ + void checkGpeEnabledAfter(@Nonnull final WriteContext writeContext); + + + /** + * @return state of gpe feature + */ + boolean isGpeEnabled(@Nonnull final ReadContext readContext); +} diff --git a/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/service/GpeStateCheckServiceImpl.java b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/service/GpeStateCheckServiceImpl.java new file mode 100644 index 000000000..b09b7ad98 --- /dev/null +++ b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/service/GpeStateCheckServiceImpl.java @@ -0,0 +1,82 @@ +/* + * 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.lisp.gpe.translate.service; + +import static com.google.common.base.Preconditions.checkState; +import static io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor.NO_PARAMS; + +import com.google.inject.Inject; +import io.fd.hc2vpp.common.translate.util.ByteDataTranslator; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +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.DumpCacheManager.DumpCacheManagerBuilder; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.vpp.jvpp.core.dto.ShowLispStatus; +import io.fd.vpp.jvpp.core.dto.ShowLispStatusReply; +import io.fd.vpp.jvpp.core.future.FutureJVppCore; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.Gpe; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.GpeState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.feature.data.grouping.GpeFeatureData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.feature.data.grouping.GpeFeatureDataBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public final class GpeStateCheckServiceImpl implements GpeStateCheckService, JvppReplyConsumer, ByteDataTranslator { + + private static final GpeFeatureData DISABLED_GPE = new GpeFeatureDataBuilder().build(); + private static final InstanceIdentifier<GpeFeatureData> + GPE_FEATURE_CONFIG_ID = InstanceIdentifier.create(Gpe.class) + .child(GpeFeatureData.class); + private static final InstanceIdentifier<GpeFeatureData> + GPE_FEATURE_STATE_ID = InstanceIdentifier.create(GpeState.class).child(GpeFeatureData.class); + private static final ShowLispStatusReply DEFAULT_REPLY = new ShowLispStatusReply(); + private final DumpCacheManager<ShowLispStatusReply, Void> dumpCacheManager; + + @Inject + public GpeStateCheckServiceImpl(@Nonnull final FutureJVppCore api) { + dumpCacheManager = new DumpCacheManagerBuilder<ShowLispStatusReply, Void>() + .acceptOnly(ShowLispStatusReply.class) + .withExecutor((identifier, params) -> getReplyForRead( + api.showLispStatus(new ShowLispStatus()).toCompletableFuture(), identifier)) + .build(); + } + + @Override + public void checkGpeEnabledBefore(@Nonnull final WriteContext writeContext) { + checkState(writeContext.readBefore(GPE_FEATURE_CONFIG_ID).or(DISABLED_GPE).isEnable(), + "Gpe feature is disabled"); + } + + @Override + public void checkGpeEnabledAfter(@Nonnull final WriteContext writeContext) { + checkState(writeContext.readAfter(GPE_FEATURE_CONFIG_ID).or(DISABLED_GPE).isEnable(), + "Gpe feature is disabled"); + } + + @Override + public boolean isGpeEnabled(@Nonnull final ReadContext readContext) { + try { + return byteToBoolean( + dumpCacheManager.getDump(GPE_FEATURE_STATE_ID, readContext.getModificationCache(), NO_PARAMS) + .or(DEFAULT_REPLY).gpeStatus); + } catch (ReadFailedException e) { + throw new IllegalStateException("Unable to read Gpe feature status", e); + } + } +} diff --git a/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/write/GpeFeatureCustomizer.java b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/write/GpeFeatureCustomizer.java new file mode 100644 index 000000000..d384af094 --- /dev/null +++ b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/write/GpeFeatureCustomizer.java @@ -0,0 +1,76 @@ +/* + * 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.lisp.gpe.translate.write; + +import io.fd.hc2vpp.common.translate.util.ByteDataTranslator; +import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.vpp.jvpp.core.dto.GpeEnableDisable; +import io.fd.vpp.jvpp.core.dto.GpeEnableDisableReply; +import io.fd.vpp.jvpp.core.future.FutureJVppCore; +import java.util.concurrent.CompletableFuture; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.feature.data.grouping.GpeFeatureData; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class GpeFeatureCustomizer extends FutureJVppCustomizer + implements WriterCustomizer<GpeFeatureData>, JvppReplyConsumer, ByteDataTranslator { + + private static final Logger LOG = LoggerFactory.getLogger(GpeFeatureCustomizer.class); + + public GpeFeatureCustomizer(@Nonnull final FutureJVppCore futureJVppCore) { + super(futureJVppCore); + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<GpeFeatureData> id, + @Nonnull final GpeFeatureData dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + LOG.debug("Writing gpe feature(enabled={})", dataAfter.isEnable()); + getReplyForWrite(enableDisableGpeFeature(dataAfter.isEnable()), id); + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<GpeFeatureData> id, + @Nonnull final GpeFeatureData dataBefore, + @Nonnull final GpeFeatureData dataAfter, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + LOG.debug("Updating gpe feature(enabled={})", dataAfter.isEnable()); + getReplyForUpdate(enableDisableGpeFeature(dataAfter.isEnable()), id, dataBefore, dataAfter); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<GpeFeatureData> id, + @Nonnull final GpeFeatureData dataBefore, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + LOG.debug("Removing gpe feature"); + getReplyForDelete(enableDisableGpeFeature(false), id); + } + + private CompletableFuture<GpeEnableDisableReply> enableDisableGpeFeature(final boolean enable) { + final GpeEnableDisable request = new GpeEnableDisable(); + request.isEn = booleanToByte(enable); + LOG.debug("gpeEnableDisable({})", request); + return getFutureJVpp().gpeEnableDisable(request).toCompletableFuture(); + } +} diff --git a/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/write/GpeForwardEntryCustomizer.java b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/write/GpeForwardEntryCustomizer.java new file mode 100644 index 000000000..1749b5658 --- /dev/null +++ b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/write/GpeForwardEntryCustomizer.java @@ -0,0 +1,203 @@ +/* + * 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.lisp.gpe.translate.write; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static io.fd.hc2vpp.lisp.gpe.translate.ctx.GpeEntryIdentifier.fromEntry; +import static io.fd.hc2vpp.lisp.gpe.translate.ctx.GpeLocatorPair.fromLocatorPair; +import static java.util.Objects.nonNull; + +import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.lisp.gpe.translate.ctx.GpeEntryMappingContext; +import io.fd.hc2vpp.lisp.gpe.translate.ctx.GpeLocatorPairMappingContext; +import io.fd.hc2vpp.lisp.gpe.translate.service.GpeStateCheckService; +import io.fd.hc2vpp.lisp.translate.read.dump.executor.params.MappingsDumpParams.EidType; +import io.fd.hc2vpp.lisp.translate.util.EidTranslator; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.vpp.jvpp.core.dto.GpeAddDelFwdEntry; +import io.fd.vpp.jvpp.core.dto.GpeAddDelFwdEntryReply; +import io.fd.vpp.jvpp.core.future.FutureJVppCore; +import io.fd.vpp.jvpp.core.types.GpeLocator; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.GpeEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.GpeEntryKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.LocalEid; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.LocatorPairs; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.RemoteEid; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.locator.pair.LocatorPair; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class GpeForwardEntryCustomizer extends FutureJVppCustomizer + implements ListWriterCustomizer<GpeEntry, GpeEntryKey>, EidTranslator, JvppReplyConsumer { + + private final GpeStateCheckService gpeStateCheckService; + private final GpeEntryMappingContext entryMappingCtx; + private final GpeLocatorPairMappingContext locatorPairCtx; + + public GpeForwardEntryCustomizer(@Nonnull final FutureJVppCore futureJVppCore, + @Nonnull final GpeStateCheckService gpeStateCheckService, + @Nonnull final GpeEntryMappingContext entryMappingCtx, + @Nonnull final GpeLocatorPairMappingContext locatorPairCtx) { + super(futureJVppCore); + this.gpeStateCheckService = gpeStateCheckService; + this.entryMappingCtx = entryMappingCtx; + this.locatorPairCtx = locatorPairCtx; + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<GpeEntry> id, + @Nonnull final GpeEntry dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + gpeStateCheckService.checkGpeEnabledAfter(writeContext); + getReplyForWrite(sendRequestAndMap(true, dataAfter, writeContext.getMappingContext()).toCompletableFuture(), + id); + } + + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<GpeEntry> id, + @Nonnull final GpeEntry dataBefore, + @Nonnull final GpeEntry dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + gpeStateCheckService.checkGpeEnabledAfter(writeContext); + getReplyForDelete(sendRequestAndMap(false, dataBefore, writeContext.getMappingContext()).toCompletableFuture(), + id); + getReplyForUpdate(sendRequestAndMap(true, dataAfter, writeContext.getMappingContext()).toCompletableFuture(), + id, dataBefore, dataAfter); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<GpeEntry> id, + @Nonnull final GpeEntry dataBefore, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + gpeStateCheckService.checkGpeEnabledBefore(writeContext); + getReplyForDelete(sendRequestAndMap(false, dataBefore, writeContext.getMappingContext()).toCompletableFuture(), + id); + } + + private CompletableFuture<GpeAddDelFwdEntryReply> sendRequestAndMap(final boolean add, + final GpeEntry data, + final MappingContext mappingContext) { + final CompletableFuture<GpeAddDelFwdEntryReply> reply = + getFutureJVpp().gpeAddDelFwdEntry(bindRequest(add, data)).toCompletableFuture(); + + /* + * sync to disallow synchronization issues + */ + synchronized (entryMappingCtx) { + synchronized (locatorPairCtx) { + if (add) { + entryMappingCtx.addMapping(data.getId(), fromEntry(data), mappingContext); + Optional.ofNullable(data.getLocatorPairs()).orElse(Collections.emptyList()).forEach( + locatorPair -> locatorPairCtx + .addMapping(data.getId(), locatorPair.getId(), fromLocatorPair(locatorPair), + mappingContext)); + } else { + entryMappingCtx.removeMapping(data.getId(), mappingContext); + locatorPairCtx.removeMapping(data.getId(), mappingContext); + } + } + } + + return reply; + } + + private GpeAddDelFwdEntry bindRequest(final boolean add, @Nonnull final GpeEntry entry) { + final GpeAddDelFwdEntry request = new GpeAddDelFwdEntry(); + request.isAdd = booleanToByte(add); + request.vni = entry.getVni().byteValue(); + request.dpTable = entry.getDpTable().byteValue(); + + final LocalEid localEid = Optional.ofNullable(entry.getLocalEid()) + .orElseThrow(() -> new IllegalArgumentException("Local eid cannot be null")); + final RemoteEid remoteEid = Optional.ofNullable(entry.getRemoteEid()) + .orElseThrow(() -> new IllegalArgumentException("Remote eid cannot be null")); + + final EidType localEidType = getEidType(localEid); + final EidType remoteEidType = getEidType(remoteEid); + checkArgument(localEidType == remoteEidType, "Different eid type detected - Local[%s]/Remote[%s]", + localEidType, + remoteEidType); + + request.eidType = (byte) localEidType.getVppTypeBinding(); + request.lclEid = getEidAsByteArray(localEid); + request.lclLen = getPrefixLength(localEid); + + request.rmtEid = getEidAsByteArray(remoteEid); + request.rmtLen = getPrefixLength(remoteEid); + + if (nonNull(entry.getAction())) { + request.action = (byte) entry.getAction().getIntValue(); + } + + if (nonNull(entry.getLocatorPairs())) { + request.locs = toRequestLocators(entry.getLocatorPairs()); + request.locNum = request.locs.length; + } + + return request; + } + + + // Locators vector must be ordered in way that local locators are first ,then remote. + // Pair is translated to two locators, one(local) with local address and weight, second one(remote) with remote + // address + private GpeLocator[] toRequestLocators(final List<LocatorPairs> pairs) { + return pairs.stream() + .flatMap(locatorPairContainer -> { + final LocatorPair locatorPair = + checkNotNull(locatorPairContainer.getLocatorPair(), "Locator pair cannot be null"); + + final boolean isLocalIpv6 = isIpv6(locatorPair.getLocalLocator()); + final boolean isRemoteIpv6 = isIpv6(locatorPair.getRemoteLocator()); + + checkArgument(isLocalIpv6 == isRemoteIpv6, + "Invalid combination for locator pair - Local[ipv6=%s]/Remote[ipv6=%s]", isLocalIpv6, + isRemoteIpv6); + + GpeLocator localLocator = new GpeLocator(); + localLocator.addr = ipAddressToArray(locatorPair.getLocalLocator()); + localLocator.isIp4 = booleanToByte(!isLocalIpv6); + localLocator.weight = locatorPair.getWeight().byteValue(); + + GpeLocator remoteLocator = new GpeLocator(); + remoteLocator.addr = ipAddressToArray(locatorPair.getRemoteLocator()); + remoteLocator.isIp4 = booleanToByte(!isRemoteIpv6); + + return Stream.of(localLocator, remoteLocator); + }) + .sorted((first, second) -> { + if (first.weight == 0 && second.weight == 0) { + return 0; + } else if (first.weight == 0) { + return 1; + } else { + return -1; + } + }).toArray(GpeLocator[]::new); + } +} diff --git a/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/write/GpeWriterFactory.java b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/write/GpeWriterFactory.java new file mode 100644 index 000000000..cc5283b34 --- /dev/null +++ b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/write/GpeWriterFactory.java @@ -0,0 +1,97 @@ +/* + * 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.lisp.gpe.translate.write; + +import com.google.common.collect.ImmutableSet; +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.hc2vpp.lisp.gpe.GpeModule; +import io.fd.hc2vpp.lisp.gpe.translate.ctx.GpeEntryMappingContext; +import io.fd.hc2vpp.lisp.gpe.translate.ctx.GpeLocatorPairMappingContext; +import io.fd.hc2vpp.lisp.gpe.translate.service.GpeStateCheckService; +import io.fd.honeycomb.translate.impl.write.GenericListWriter; +import io.fd.honeycomb.translate.impl.write.GenericWriter; +import io.fd.honeycomb.translate.write.WriterFactory; +import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder; +import io.fd.vpp.jvpp.core.future.FutureJVppCore; +import 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.gpe.rev170518.Gpe; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.GpeEntryTable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.GpeEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.LocalEid; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.LocatorPairs; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.RemoteEid; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.feature.data.grouping.GpeFeatureData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.locator.pair.LocatorPair; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev170509.SubinterfaceAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev170509.interfaces._interface.SubInterfaces; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev170509.interfaces._interface.sub.interfaces.SubInterface; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + + +public class GpeWriterFactory implements WriterFactory { + + private static final InstanceIdentifier<Gpe> GPE_ID = InstanceIdentifier.create(Gpe.class); + private static final InstanceIdentifier<GpeFeatureData> + GPE_FEATURE_ID = GPE_ID.child(GpeFeatureData.class); + private static final InstanceIdentifier<GpeEntry> + GPE_ENTRY_ID = GPE_FEATURE_ID.child(GpeEntryTable.class).child(GpeEntry.class); + public static final InstanceIdentifier<Interface> + IFC_ID = InstanceIdentifier.create(Interfaces.class).child(Interface.class); + + @Inject + private FutureJVppCore api; + + @Inject + private GpeStateCheckService gpeStateCheckService; + + @Inject + @Named(GpeModule.GPE_ENTRY_MAPPING_CTX) + private GpeEntryMappingContext gpeEntryMappingContext; + + @Inject + @Named(GpeModule.GPE_TO_LOCATOR_PAIR_CTX) + private GpeLocatorPairMappingContext gpeLocatorPairMappingContext; + + + @Override + public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) { + // gpe must be enabled before interfaces + // because as a byproduct of enabling gpe, lisp_gpe interface is created + // and in scenario when vpp data are lost, it would end up calling + // sw_interface_set_flags for non existing interface index + registry.addBefore(new GenericWriter<>(GPE_FEATURE_ID, new GpeFeatureCustomizer(api)), + IFC_ID); + final InstanceIdentifier<GpeEntry> entrySubtreeId = InstanceIdentifier.create(GpeEntry.class); + + // same situation as above, but with sub-interfaces + registry.subtreeAddBefore(ImmutableSet.of( + entrySubtreeId.child(LocalEid.class), + entrySubtreeId.child(RemoteEid.class), + entrySubtreeId.child(LocatorPairs.class), + entrySubtreeId.child(LocatorPairs.class).child(LocatorPair.class)), + new GenericListWriter<>(GPE_ENTRY_ID, + new GpeForwardEntryCustomizer(api, gpeStateCheckService, gpeEntryMappingContext, + gpeLocatorPairMappingContext)), + IFC_ID.augmentation(SubinterfaceAugmentation.class).child(SubInterfaces.class) + .child(SubInterface.class)); + + + } +} diff --git a/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/translate/util/EidTranslator.java b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/translate/util/EidTranslator.java index deae3f5f6..2b693fd60 100755 --- a/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/translate/util/EidTranslator.java +++ b/lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/translate/util/EidTranslator.java @@ -65,6 +65,7 @@ import org.slf4j.Logger; // TODO - HC2VPP-149 - restructuralize code public interface EidTranslator extends AddressTranslator, EidMetadataProvider { + EidTranslator INSTANCE = new EidTranslator(){}; byte DEFAULT_V4_PREFIX = 32; byte DEFAULT_V6_PREFIX = (byte) 128; @@ -92,6 +93,14 @@ public interface EidTranslator extends AddressTranslator, EidMetadataProvider { return resolverPrefixLength(address.getAddress()); } + default byte getPrefixLength(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.LocalEid address){ + return resolverPrefixLength(address.getAddress()); + } + + default byte getPrefixLength(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.RemoteEid address){ + return resolverPrefixLength(address.getAddress()); + } + static byte resolverPrefixLength(Address address) { switch (resolveType(address)) { @@ -114,6 +123,28 @@ public interface EidTranslator extends AddressTranslator, EidMetadataProvider { return Byte.valueOf(data.substring(data.indexOf('/') + 1)); } + default org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.LocalEid getArrayAsGpeLocalEid( + @Nonnull final EidType type, final byte[] address, final byte prefix, final int vni) { + final Eid eid = getArrayAsEidLocal(type, address, prefix, vni); + + return new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.LocalEidBuilder() + .setAddress(eid.getAddress()) + .setAddressType(eid.getAddressType()) + .setVirtualNetworkId(eid.getVirtualNetworkId()) + .build(); + } + + default org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.RemoteEid getArrayAsGpeRemoteEid( + @Nonnull final EidType type, final byte[] address, final byte prefix, final int vni) { + final Eid eid = getArrayAsEidLocal(type, address, prefix, vni); + + return new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.RemoteEidBuilder() + .setAddress(eid.getAddress()) + .setAddressType(eid.getAddressType()) + .setVirtualNetworkId(eid.getVirtualNetworkId()) + .build(); + } + default Eid getArrayAsEidLocal(@Nonnull final EidType type, final byte[] address, final byte prefix, final int vni) { @@ -326,6 +357,19 @@ public interface EidTranslator extends AddressTranslator, EidMetadataProvider { } } + default EidType getEidType( + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.RemoteEid address) { + checkNotNull(address, "Address cannot be null"); + + return resolveType(address.getAddress()); + } + + default EidType getEidType( + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.LocalEid address) { + checkNotNull(address, "Address cannot be null"); + + return resolveType(address.getAddress()); + } default EidType getEidType( org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.eid.mapping.context.rev160801.contexts.eid.mapping.context.mappings.mapping.Eid address) { @@ -381,6 +425,20 @@ public interface EidTranslator extends AddressTranslator, EidMetadataProvider { } default byte[] getEidAsByteArray( + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.RemoteEid address) { + checkNotNull(address, "Eid cannot be null"); + + return resolveByteArray(getEidType(address), address.getAddress()); + } + + default byte[] getEidAsByteArray( + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.LocalEid address) { + checkNotNull(address, "Eid cannot be null"); + + return resolveByteArray(getEidType(address), address.getAddress()); + } + + default byte[] getEidAsByteArray( org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.eid.mapping.context.rev160801.contexts.eid.mapping.context.mappings.mapping.Eid address) { checkNotNull(address, "Eid cannot be null"); diff --git a/lisp/lisp2vpp/src/test/java/io/fd/hc2vpp/lisp/gpe/translate/read/GpeFeatureCustomizerTest.java b/lisp/lisp2vpp/src/test/java/io/fd/hc2vpp/lisp/gpe/translate/read/GpeFeatureCustomizerTest.java new file mode 100644 index 000000000..965906abd --- /dev/null +++ b/lisp/lisp2vpp/src/test/java/io/fd/hc2vpp/lisp/gpe/translate/read/GpeFeatureCustomizerTest.java @@ -0,0 +1,67 @@ +/* + * 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.lisp.gpe.translate.read; + + +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import io.fd.hc2vpp.common.test.read.InitializingReaderCustomizerTest; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.vpp.jvpp.core.dto.ShowLispStatusReply; +import org.junit.Test; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.Gpe; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.GpeState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.GpeStateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.feature.data.grouping.GpeFeatureData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.feature.data.grouping.GpeFeatureDataBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class GpeFeatureCustomizerTest extends InitializingReaderCustomizerTest<GpeFeatureData, GpeFeatureDataBuilder> { + public GpeFeatureCustomizerTest() { + super(GpeFeatureData.class, GpeStateBuilder.class); + } + + @Override + protected GpeFeatureCustomizer initCustomizer() { + return new GpeFeatureCustomizer(api); + } + + @Test + public void testReadCurrent() throws ReadFailedException { + final ShowLispStatusReply result = new ShowLispStatusReply(); + result.gpeStatus = 1; + when(api.showLispStatus(any())).thenReturn(future(result)); + + final GpeFeatureDataBuilder builder = new GpeFeatureDataBuilder(); + getCustomizer().readCurrentAttributes(InstanceIdentifier.create(GpeFeatureData.class), builder, ctx); + assertTrue(builder.isEnable()); + } + + @Test + public void testInit() { + final InstanceIdentifier<GpeFeatureData> CONFIG_ID = + InstanceIdentifier.create(Gpe.class).child(GpeFeatureData.class); + + final InstanceIdentifier<GpeFeatureData> STATE_ID = + InstanceIdentifier.create(GpeState.class).child(GpeFeatureData.class); + + final GpeFeatureData data = new GpeFeatureDataBuilder().build(); + invokeInitTest(STATE_ID, data, CONFIG_ID, data); + } +} diff --git a/lisp/lisp2vpp/src/test/java/io/fd/hc2vpp/lisp/gpe/translate/read/GpeForwardEntryCustomizerTest.java b/lisp/lisp2vpp/src/test/java/io/fd/hc2vpp/lisp/gpe/translate/read/GpeForwardEntryCustomizerTest.java new file mode 100644 index 000000000..9e1958224 --- /dev/null +++ b/lisp/lisp2vpp/src/test/java/io/fd/hc2vpp/lisp/gpe/translate/read/GpeForwardEntryCustomizerTest.java @@ -0,0 +1,520 @@ +/* + * 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.lisp.gpe.translate.read; + + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import io.fd.hc2vpp.common.test.read.InitializingListReaderCustomizerTest; +import io.fd.hc2vpp.common.translate.util.AddressTranslator; +import io.fd.hc2vpp.lisp.gpe.translate.ctx.GpeEntryIdentifier; +import io.fd.hc2vpp.lisp.gpe.translate.ctx.GpeEntryMappingContext; +import io.fd.hc2vpp.lisp.gpe.translate.ctx.GpeLocatorPair; +import io.fd.hc2vpp.lisp.gpe.translate.ctx.GpeLocatorPairMappingContext; +import io.fd.hc2vpp.lisp.gpe.translate.service.GpeStateCheckService; +import io.fd.hc2vpp.lisp.translate.read.dump.executor.params.MappingsDumpParams.EidType; +import io.fd.hc2vpp.lisp.translate.util.EidTranslator; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.vpp.jvpp.core.dto.GpeFwdEntriesGet; +import io.fd.vpp.jvpp.core.dto.GpeFwdEntriesGetReply; +import io.fd.vpp.jvpp.core.dto.GpeFwdEntryPathDetails; +import io.fd.vpp.jvpp.core.dto.GpeFwdEntryPathDetailsReplyDump; +import io.fd.vpp.jvpp.core.dto.GpeFwdEntryPathDump; +import io.fd.vpp.jvpp.core.dto.GpeFwdEntryVnisGetReply; +import io.fd.vpp.jvpp.core.types.GpeFwdEntry; +import io.fd.vpp.jvpp.core.types.GpeLocator; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.junit.Test; +import org.mockito.Mock; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.entry.identification.context.rev170517.gpe.entry.identification.context.attributes.gpe.entry.identification.contexts.gpe.entry.identification.mappings.mapping.GpeEntryIdentificator; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.entry.identification.context.rev170517.gpe.entry.identification.context.attributes.gpe.entry.identification.contexts.gpe.entry.identification.mappings.mapping.GpeEntryIdentificatorBuilder; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.entry.identification.context.rev170517.gpe.entry.identification.context.attributes.gpe.entry.identification.contexts.gpe.entry.identification.mappings.mapping.gpe.entry.identificator.LocalEidBuilder; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.entry.identification.context.rev170517.gpe.entry.identification.context.attributes.gpe.entry.identification.contexts.gpe.entry.identification.mappings.mapping.gpe.entry.identificator.RemoteEidBuilder; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.locator.pair.identification.context.rev170517.gpe.locator.pair.identification.context.attributes.gpe.locator.pair.identification.contexts.gpe.locator.pair.identification.mappings.mapping.LocatorPairMapping; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.locator.pair.identification.context.rev170517.gpe.locator.pair.identification.context.attributes.gpe.locator.pair.identification.contexts.gpe.locator.pair.identification.mappings.mapping.LocatorPairMappingBuilder; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.gpe.locator.pair.identification.context.rev170517.gpe.locator.pair.identification.context.attributes.gpe.locator.pair.identification.contexts.gpe.locator.pair.identification.mappings.mapping.locator.pair.mapping.PairBuilder; +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.Ipv4Prefix; +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.inet.types.rev130715.Ipv6Prefix; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.Ipv4PrefixAfi; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.Ipv6PrefixAfi; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.MacAfi; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.Ipv4PrefixBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.Ipv6PrefixBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.MacBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.Gpe; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.GpeState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.GpeEntryTable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.GpeEntryTableBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.GpeEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.GpeEntryBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.GpeEntryKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.LocatorPairs; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.feature.data.grouping.GpeFeatureData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.locator.pair.LocatorPair; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev170315.MapReplyAction; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev170315.dp.subtable.grouping.local.mappings.local.mapping.Eid; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; + +public class GpeForwardEntryCustomizerTest + extends InitializingListReaderCustomizerTest<GpeEntry, GpeEntryKey, GpeEntryBuilder> + implements AddressTranslator, EidTranslator { + + private static final String V4_ENTRY_ID = "v4-entry"; + private static final String V4_ENTRY_LOCATOR = "v4-entry-locator"; + private static final int V4_ENTRY_DP_TABLE = 10; + private static final int V4_ENTRY_FWD_INDEX = 4; + private static final int V4_ENTRY_VNI = 45; + private static final KeyedInstanceIdentifier<GpeEntry, GpeEntryKey> V4_IDENTIFIER = + InstanceIdentifier.create(GpeEntryTable.class) + .child(GpeEntry.class, new GpeEntryKey(V4_ENTRY_ID)); + private static final Ipv4Prefix + V4_ENTRY_LOCAL_ADDRESS = new Ipv4Prefix("192.168.2.0/24"); + private static final Ipv4Prefix + V4_ENTRY_REMOTE_ADDRESS = new Ipv4Prefix("192.168.3.0/24"); + private static final Ipv4AddressNoZone + V4_LOCATOR_LOCAL_ADDRESS = new Ipv4AddressNoZone("192.168.5.4"); + private static final Ipv4AddressNoZone + V4_LOCATOR_REMOTE_ADDRESS = new Ipv4AddressNoZone("192.168.7.4"); + + + private static final String V6_ENTRY_ID = "v6-entry"; + private static final String V6_ENTRY_LOCATOR = "v6-entry-locator"; + private static final int V6_ENTRY_DP_TABLE = 11; + private static final int V6_ENTRY_VNI = 22; + private static final int V6_ENTRY_FWD_INDEX = 5; + private static final Ipv6Prefix + V6_ENTRY_LOCAL_ADDRESS = new Ipv6Prefix("2001:0db8:85a3:0000:0000:8a2e:0370:7334/64"); + private static final Ipv6Prefix + V6_ENTRY_REMOTE_ADDRESS = new Ipv6Prefix("2001:0db8:85a7:0000:0000:8a2e:0370:7334/64"); + private static final KeyedInstanceIdentifier<GpeEntry, GpeEntryKey> V6_IDENTIFIER = + InstanceIdentifier.create(GpeEntryTable.class) + .child(GpeEntry.class, new GpeEntryKey(V6_ENTRY_ID)); + private static final Ipv6AddressNoZone + V6_LOCATOR_LOCAL_ADDRESS = new Ipv6AddressNoZone("2001:db8:85a3::8a2e:370:7334"); + private static final Ipv6AddressNoZone + V6_LOCATOR_REMOTE_ADDRESS = new Ipv6AddressNoZone("2001:db8:85a3::8a2e:222:7334"); + + private static final String MAC_ENTRY_ID = "mac-entry"; + private static final int MAC_ENTRY_FWD_INDEX = 7; + private static final int MAC_ENTRY_VNI = 18; + private static final String MAC_ENTRY_LOCATOR = "mac-entry-locator"; + private static final int MAC_ENTRY_DP_TABLE = 12; + private static final KeyedInstanceIdentifier<GpeEntry, GpeEntryKey> MAC_IDENTIFIER = + InstanceIdentifier.create(GpeEntryTable.class) + .child(GpeEntry.class, new GpeEntryKey(MAC_ENTRY_ID)); + private static final String MAC_ENTRY_LOCAL_ADDRESS_VALUE = "aa:bb:cc:dd:ee:ff"; + private static final String MAC_ENTRY_REMOTE_ADDRESS_VALUE = "bb:cc:bb:cc:bb:cc"; + + private static final Ipv4AddressNoZone + MAC_LOCATOR_LOCAL_ADDRESS = new Ipv4AddressNoZone("192.168.7.4"); + private static final Ipv4AddressNoZone + MAC_LOCATOR_REMOTE_ADDRESS = new Ipv4AddressNoZone("192.168.2.4"); + public static final int V6_LOCATOR_LOCAL_WEIGHT = 3; + public static final int MAC_LOCATOR_LOCAL_WEIGHT = 7; + public static final int V4_LOCATOR_LOCAL_WEIGHT = 2; + + + @Mock + private GpeEntryMappingContext gpeEntryMappingContext; + + @Mock + private GpeLocatorPairMappingContext gpeLocatorPairMappingContext; + + @Mock + private GpeStateCheckService gpeStateCheckService; + + public GpeForwardEntryCustomizerTest() { + super(GpeEntry.class, GpeEntryTableBuilder.class); + } + + @Override + protected GpeForwardEntryCustomizer initCustomizer() { + return new GpeForwardEntryCustomizer(api, gpeStateCheckService, gpeEntryMappingContext, + gpeLocatorPairMappingContext); + } + + @Override + protected void setUp() throws Exception { + when(gpeStateCheckService.isGpeEnabled(ctx)).thenReturn(true); + when(api.gpeFwdEntriesGet(entryRequest(V4_ENTRY_VNI))) + .thenReturn(future(getGpeEntryDumpReply(getV4GpeEntry()))); + when(api.gpeFwdEntriesGet(entryRequest(V6_ENTRY_VNI))) + .thenReturn(future(getGpeEntryDumpReply(getV6GpeEntry()))); + when(api.gpeFwdEntriesGet(entryRequest(MAC_ENTRY_VNI))) + .thenReturn(future(getGpeEntryDumpReply(getMacGpeEntry()))); + when(api.gpeFwdEntryVnisGet(any())).thenReturn(future(activeVnisDump())); + mockMappingsForGpeEntries(); + mockMappingsForLocators(); + } + + @Test + public void testGetAll() throws ReadFailedException { + final List<GpeEntryKey> allIds = getCustomizer().getAllIds(V4_IDENTIFIER, ctx); + + assertTrue(allIds.containsAll(Arrays.asList(new GpeEntryKey(V4_ENTRY_ID), + new GpeEntryKey(V6_ENTRY_ID), + new GpeEntryKey(MAC_ENTRY_ID)))); + } + + @Test + public void testReadCurrentV4Entry() throws ReadFailedException { + mockLocatorDump(); + final GpeEntryBuilder builder = new GpeEntryBuilder(); + getCustomizer().readCurrentAttributes(V4_IDENTIFIER, builder, ctx); + + assertEquals(V4_ENTRY_ID, builder.getId()); + assertEquals(10, builder.getDpTable().intValue()); + assertTrue(compareAddresses(new Ipv4PrefixBuilder() + .setIpv4Prefix(V4_ENTRY_LOCAL_ADDRESS) + .build(), builder.getLocalEid().getAddress())); + assertEquals(Ipv4PrefixAfi.class, builder.getLocalEid().getAddressType()); + assertEquals(V4_ENTRY_VNI, builder.getLocalEid().getVirtualNetworkId().getValue().intValue()); + assertTrue(compareAddresses(new Ipv4PrefixBuilder() + .setIpv4Prefix(V4_ENTRY_REMOTE_ADDRESS) + .build(), builder.getRemoteEid().getAddress())); + assertEquals(Ipv4PrefixAfi.class, builder.getRemoteEid().getAddressType()); + assertEquals(V4_ENTRY_VNI, builder.getRemoteEid().getVirtualNetworkId().getValue().intValue()); + assertTrue(V4_ENTRY_VNI == builder.getVni()); + assertEquals(1, builder.getLocatorPairs().size()); + + final LocatorPairs locatorPair = builder.getLocatorPairs().get(0); + assertEquals(V4_ENTRY_LOCATOR, locatorPair.getId()); + + final LocatorPair pair = locatorPair.getLocatorPair(); + assertEquals(V4_LOCATOR_LOCAL_ADDRESS, pair.getLocalLocator().getIpv4Address()); + assertEquals(V4_LOCATOR_REMOTE_ADDRESS, pair.getRemoteLocator().getIpv4Address()); + assertEquals(V4_LOCATOR_LOCAL_WEIGHT, pair.getWeight().byteValue()); + } + + @Test + public void testReadCurrentV6Entry() throws ReadFailedException { + mockLocatorDump(); + final GpeEntryBuilder builder = new GpeEntryBuilder(); + getCustomizer().readCurrentAttributes(V6_IDENTIFIER, builder, ctx); + + assertEquals(V6_ENTRY_ID, builder.getId()); + assertEquals(V6_ENTRY_DP_TABLE, builder.getDpTable().intValue()); + assertTrue(compareAddresses(new Ipv6PrefixBuilder() + .setIpv6Prefix(V6_ENTRY_LOCAL_ADDRESS) + .build(), builder.getLocalEid().getAddress())); + assertEquals(Ipv6PrefixAfi.class, builder.getLocalEid().getAddressType()); + assertEquals(V6_ENTRY_VNI, builder.getLocalEid().getVirtualNetworkId().getValue().intValue()); + assertTrue(compareAddresses(new Ipv6PrefixBuilder() + .setIpv6Prefix(V6_ENTRY_REMOTE_ADDRESS) + .build(), builder.getRemoteEid().getAddress())); + assertEquals(Ipv6PrefixAfi.class, builder.getRemoteEid().getAddressType()); + assertEquals(V6_ENTRY_VNI, builder.getRemoteEid().getVirtualNetworkId().getValue().intValue()); + assertTrue(V6_ENTRY_VNI == builder.getVni()); + + assertEquals(1, builder.getLocatorPairs().size()); + + final LocatorPairs locatorPair = builder.getLocatorPairs().get(0); + assertEquals(V6_ENTRY_LOCATOR, locatorPair.getId()); + + final LocatorPair pair = locatorPair.getLocatorPair(); + assertEquals(V6_LOCATOR_LOCAL_ADDRESS, pair.getLocalLocator().getIpv6Address()); + assertEquals(V6_LOCATOR_REMOTE_ADDRESS, pair.getRemoteLocator().getIpv6Address()); + assertEquals(V6_LOCATOR_LOCAL_WEIGHT, pair.getWeight().byteValue()); + } + + @Test + public void testReadCurrentMacEntry() throws ReadFailedException { + mockLocatorDump(); + final GpeEntryBuilder builder = new GpeEntryBuilder(); + getCustomizer().readCurrentAttributes(MAC_IDENTIFIER, builder, ctx); + + assertEquals(MAC_ENTRY_ID, builder.getId()); + assertEquals(MAC_ENTRY_DP_TABLE, builder.getDpTable().intValue()); + assertTrue(compareAddresses(new MacBuilder() + .setMac(new MacAddress(MAC_ENTRY_LOCAL_ADDRESS_VALUE)) + .build(), builder.getLocalEid().getAddress())); + assertEquals(MAC_ENTRY_VNI, builder.getLocalEid().getVirtualNetworkId().getValue().intValue()); + assertEquals(MacAfi.class, builder.getLocalEid().getAddressType()); + assertTrue(compareAddresses(new MacBuilder() + .setMac(new MacAddress(MAC_ENTRY_REMOTE_ADDRESS_VALUE)) + .build(), builder.getRemoteEid().getAddress())); + assertEquals(MacAfi.class, builder.getRemoteEid().getAddressType()); + assertEquals(MAC_ENTRY_VNI, builder.getRemoteEid().getVirtualNetworkId().getValue().intValue()); + assertTrue(MAC_ENTRY_VNI == builder.getVni()); + + assertEquals(1, builder.getLocatorPairs().size()); + + final LocatorPairs locatorPair = builder.getLocatorPairs().get(0); + assertEquals(MAC_ENTRY_LOCATOR, locatorPair.getId()); + + final LocatorPair pair = locatorPair.getLocatorPair(); + assertEquals(MAC_LOCATOR_LOCAL_ADDRESS, pair.getLocalLocator().getIpv4Address()); + assertEquals(MAC_LOCATOR_REMOTE_ADDRESS, pair.getRemoteLocator().getIpv4Address()); + assertEquals(MAC_LOCATOR_LOCAL_WEIGHT, pair.getWeight().byteValue()); + } + + @Test + public void testReadCurrentNegativeMapping() throws ReadFailedException { + when(api.gpeFwdEntryPathDump(any())).thenReturn(future(new GpeFwdEntryPathDetailsReplyDump())); + final GpeEntryBuilder builder = new GpeEntryBuilder(); + getCustomizer().readCurrentAttributes(V4_IDENTIFIER, builder, ctx); + + assertEquals(V4_ENTRY_ID, builder.getId()); + assertEquals(V4_ENTRY_DP_TABLE, builder.getDpTable().intValue()); + assertTrue(compareAddresses(new Ipv4PrefixBuilder() + .setIpv4Prefix(V4_ENTRY_LOCAL_ADDRESS) + .build(), builder.getLocalEid().getAddress())); + assertEquals(Ipv4PrefixAfi.class, builder.getLocalEid().getAddressType()); + assertTrue(compareAddresses(new Ipv4PrefixBuilder() + .setIpv4Prefix(V4_ENTRY_REMOTE_ADDRESS) + .build(), builder.getRemoteEid().getAddress())); + assertEquals(Ipv4PrefixAfi.class, builder.getRemoteEid().getAddressType()); + assertEquals(MapReplyAction.Drop, builder.getAction()); + } + + @Test + public void testInit() { + final InstanceIdentifier<GpeEntry> CONFIG_ID = + InstanceIdentifier.create(Gpe.class).child(GpeFeatureData.class).child(GpeEntryTable.class) + .child(GpeEntry.class, new GpeEntryKey(V4_ENTRY_ID)); + + final InstanceIdentifier<GpeEntry> STATE_ID = + InstanceIdentifier.create(GpeState.class).child(GpeFeatureData.class).child(GpeEntryTable.class) + .child(GpeEntry.class, new GpeEntryKey(V4_ENTRY_ID)); + + final GpeEntry entry = new GpeEntryBuilder().build(); + + invokeInitTest(STATE_ID, entry, CONFIG_ID, entry); + } + + private GpeFwdEntriesGet entryRequest(final int vni) { + GpeFwdEntriesGet request = new GpeFwdEntriesGet(); + request.vni = vni; + return request; + } + + private void mockLocatorDump() { + when(api.gpeFwdEntryPathDump(pathRequest(V4_ENTRY_FWD_INDEX))).thenReturn(future(locatorDumpForV4EntryReply())); + when(api.gpeFwdEntryPathDump(pathRequest(V6_ENTRY_FWD_INDEX))).thenReturn(future(locatorDumpForV6EntryReply())); + when(api.gpeFwdEntryPathDump(pathRequest(MAC_ENTRY_FWD_INDEX))) + .thenReturn(future(locatorDumpForMacEntryReply())); + } + + private GpeFwdEntryPathDump pathRequest(final int fwdIndex) { + GpeFwdEntryPathDump request = new GpeFwdEntryPathDump(); + request.fwdEntryIndex = fwdIndex; + return request; + } + + private void mockMappingsForGpeEntries() { + when(gpeEntryMappingContext + .getIdByEntryIdentifier(GpeEntryIdentifier.fromDumpDetail(getV4GpeEntry()), mappingContext)) + .thenReturn(V4_ENTRY_ID); + when(gpeEntryMappingContext + .getIdentificatorById(V4_ENTRY_ID, mappingContext)) + .thenReturn(fromDumpDetail(getV4GpeEntry())); + when(gpeEntryMappingContext + .getIdByEntryIdentifier(GpeEntryIdentifier.fromDumpDetail(getV6GpeEntry()), mappingContext)) + .thenReturn(V6_ENTRY_ID); + when(gpeEntryMappingContext + .getIdentificatorById(V6_ENTRY_ID, mappingContext)) + .thenReturn(fromDumpDetail(getV6GpeEntry())); + when(gpeEntryMappingContext + .getIdByEntryIdentifier(GpeEntryIdentifier.fromDumpDetail(getMacGpeEntry()), mappingContext)) + .thenReturn(MAC_ENTRY_ID); + when(gpeEntryMappingContext + .getIdentificatorById(MAC_ENTRY_ID, mappingContext)) + .thenReturn(fromDumpDetail(getMacGpeEntry())); + } + + private void mockMappingsForLocators() { + mockV4LocatorMapping(); + mockV6LocatorMapping(); + mockMacLocatorMapping(); + } + + private void mockV4LocatorMapping() { + final GpeFwdEntryPathDetailsReplyDump forV4EntryReply = locatorDumpForV4EntryReply(); + final GpeFwdEntryPathDetails v4LocatorOne = forV4EntryReply.gpeFwdEntryPathDetails.get(0); + final GpeLocatorPair v4LocatorPairOne = GpeLocatorPair.fromDumpDetail(v4LocatorOne); + when(gpeLocatorPairMappingContext.getMapping(V4_ENTRY_ID, v4LocatorPairOne, mappingContext)) + .thenReturn(fromDump(V4_ENTRY_LOCATOR, v4LocatorOne)); + } + + private void mockV6LocatorMapping() { + final GpeFwdEntryPathDetailsReplyDump forV6EntryReply = locatorDumpForV6EntryReply(); + final GpeFwdEntryPathDetails v6LocatorOne = forV6EntryReply.gpeFwdEntryPathDetails.get(0); + final GpeLocatorPair v6LocatorPairOne = GpeLocatorPair.fromDumpDetail(v6LocatorOne); + when(gpeLocatorPairMappingContext.getMapping(V6_ENTRY_ID, v6LocatorPairOne, mappingContext)) + .thenReturn(fromDump(V6_ENTRY_LOCATOR, v6LocatorOne)); + } + + private void mockMacLocatorMapping() { + final GpeFwdEntryPathDetails macLocator = locatorDumpForMacEntryReply().gpeFwdEntryPathDetails.get(0); + final GpeLocatorPair macLocatorPair = GpeLocatorPair.fromDumpDetail(macLocator); + when(gpeLocatorPairMappingContext.getMapping(MAC_ENTRY_ID, macLocatorPair, mappingContext)) + .thenReturn(fromDump(MAC_ENTRY_LOCATOR, macLocator)); + } + + private LocatorPairMapping fromDump(final String id, final GpeFwdEntryPathDetails dump) { + + final boolean localV4 = byteToBoolean(dump.lclLoc.isIp4); + final boolean remoteV4 = byteToBoolean(dump.rmtLoc.isIp4); + return new LocatorPairMappingBuilder() + .setId(id) + .setPair(new PairBuilder() + .setLocalAddress(arrayToIpAddress(!localV4, dump.lclLoc.addr)) + .setRemoteAddress(arrayToIpAddress(!remoteV4, dump.rmtLoc.addr)) + .build()) + .build(); + } + + private GpeEntryIdentificator fromDumpDetail(final GpeFwdEntry entry) { + final EidType eidType = EidType.valueOf(entry.eidType); + final Eid localEid = getArrayAsEidLocal(eidType, entry.leid, entry.leidPrefixLen, entry.vni); + final Eid remoteEid = getArrayAsEidLocal(eidType, entry.reid, entry.reidPrefixLen, entry.vni); + return new GpeEntryIdentificatorBuilder() + .setLocalEid(new LocalEidBuilder() + .setAddress(localEid.getAddress()) + .setAddressType(localEid.getAddressType()) + .setVirtualNetworkId(localEid.getVirtualNetworkId()) + .build()) + .setRemoteEid(new RemoteEidBuilder() + .setAddress(remoteEid.getAddress()) + .setAddressType(remoteEid.getAddressType()) + .setVirtualNetworkId(remoteEid.getVirtualNetworkId()) + .build()) + .setVni((long) entry.vni) + .build(); + } + + private GpeFwdEntriesGetReply getGpeEntryDumpReply(final GpeFwdEntry entry) { + GpeFwdEntriesGetReply reply = new GpeFwdEntriesGetReply(); + reply.entries = new GpeFwdEntry[]{entry}; + reply.count = reply.entries.length; + return reply; + } + + private GpeFwdEntryVnisGetReply activeVnisDump() { + GpeFwdEntryVnisGetReply reply = new GpeFwdEntryVnisGetReply(); + reply.vnis = new int[]{V4_ENTRY_VNI, V6_ENTRY_VNI, MAC_ENTRY_VNI}; + return reply; + } + + private GpeFwdEntryPathDetailsReplyDump locatorDumpForV4EntryReply() { + GpeFwdEntryPathDetailsReplyDump reply = new GpeFwdEntryPathDetailsReplyDump(); + + GpeFwdEntryPathDetails entry = new GpeFwdEntryPathDetails(); + GpeLocator localLocator = new GpeLocator(); + localLocator.addr = ipv4AddressNoZoneToArray(V4_LOCATOR_LOCAL_ADDRESS); + localLocator.isIp4 = 1; + localLocator.weight = V4_LOCATOR_LOCAL_WEIGHT; + GpeLocator remoteLocator = new GpeLocator(); + remoteLocator.addr = ipv4AddressNoZoneToArray(V4_LOCATOR_REMOTE_ADDRESS); + remoteLocator.isIp4 = 1; + + entry.lclLoc = localLocator; + entry.rmtLoc = remoteLocator; + + reply.gpeFwdEntryPathDetails = Collections.singletonList(entry); + + return reply; + } + + private GpeFwdEntryPathDetailsReplyDump locatorDumpForMacEntryReply() { + GpeFwdEntryPathDetailsReplyDump reply = new GpeFwdEntryPathDetailsReplyDump(); + + GpeFwdEntryPathDetails entry = new GpeFwdEntryPathDetails(); + GpeLocator localLocator = new GpeLocator(); + localLocator.addr = ipv4AddressNoZoneToArray(MAC_LOCATOR_LOCAL_ADDRESS); + localLocator.isIp4 = 1; + localLocator.weight = MAC_LOCATOR_LOCAL_WEIGHT; + GpeLocator remoteLocator = new GpeLocator(); + remoteLocator.addr = ipv4AddressNoZoneToArray(MAC_LOCATOR_REMOTE_ADDRESS); + remoteLocator.isIp4 = 1; + + entry.lclLoc = localLocator; + entry.rmtLoc = remoteLocator; + + reply.gpeFwdEntryPathDetails = Collections.singletonList(entry); + + return reply; + } + + private GpeFwdEntryPathDetailsReplyDump locatorDumpForV6EntryReply() { + GpeFwdEntryPathDetailsReplyDump reply = new GpeFwdEntryPathDetailsReplyDump(); + + GpeFwdEntryPathDetails entry = new GpeFwdEntryPathDetails(); + GpeLocator localLocator = new GpeLocator(); + localLocator.addr = ipv6AddressNoZoneToArray(V6_LOCATOR_LOCAL_ADDRESS); + localLocator.isIp4 = 0; + localLocator.weight = V6_LOCATOR_LOCAL_WEIGHT; + GpeLocator remoteLocator = new GpeLocator(); + remoteLocator.addr = ipv6AddressNoZoneToArray(V6_LOCATOR_REMOTE_ADDRESS); + remoteLocator.isIp4 = 0; + + entry.lclLoc = localLocator; + entry.rmtLoc = remoteLocator; + + reply.gpeFwdEntryPathDetails = Collections.singletonList(entry); + + return reply; + } + + private GpeFwdEntry getMacGpeEntry() { + GpeFwdEntry entryThree = new GpeFwdEntry(); + entryThree.dpTable = MAC_ENTRY_DP_TABLE; + entryThree.vni = MAC_ENTRY_VNI; + entryThree.eidType = 2; + entryThree.fwdEntryIndex = MAC_ENTRY_FWD_INDEX; + entryThree.leid = parseMac(MAC_ENTRY_LOCAL_ADDRESS_VALUE); + entryThree.reid = parseMac(MAC_ENTRY_REMOTE_ADDRESS_VALUE); + + return entryThree; + } + + private GpeFwdEntry getV6GpeEntry() { + GpeFwdEntry entryTwo = new GpeFwdEntry(); + entryTwo.dpTable = V6_ENTRY_DP_TABLE; + entryTwo.vni = V6_ENTRY_VNI; + entryTwo.eidType = 1; + entryTwo.fwdEntryIndex = V6_ENTRY_FWD_INDEX; + entryTwo.leid = ipv6AddressPrefixToArray(V6_ENTRY_LOCAL_ADDRESS); + entryTwo.leidPrefixLen = 64; + entryTwo.reid = ipv6AddressPrefixToArray(V6_ENTRY_REMOTE_ADDRESS); + entryTwo.reidPrefixLen = 64; + return entryTwo; + } + + private GpeFwdEntry getV4GpeEntry() { + GpeFwdEntry entryOne = new GpeFwdEntry(); + entryOne.dpTable = V4_ENTRY_DP_TABLE; + entryOne.vni = V4_ENTRY_VNI; + entryOne.eidType = 0; + entryOne.action = 3; + entryOne.fwdEntryIndex = V4_ENTRY_FWD_INDEX; + entryOne.leid = ipv4AddressPrefixToArray(V4_ENTRY_LOCAL_ADDRESS); + entryOne.leidPrefixLen = 24; + entryOne.reid = ipv4AddressPrefixToArray(V4_ENTRY_REMOTE_ADDRESS); + entryOne.reidPrefixLen = 24; + return entryOne; + } +} diff --git a/lisp/lisp2vpp/src/test/java/io/fd/hc2vpp/lisp/gpe/translate/write/GpeFeatureCustomizerTest.java b/lisp/lisp2vpp/src/test/java/io/fd/hc2vpp/lisp/gpe/translate/write/GpeFeatureCustomizerTest.java new file mode 100644 index 000000000..c7f0ae816 --- /dev/null +++ b/lisp/lisp2vpp/src/test/java/io/fd/hc2vpp/lisp/gpe/translate/write/GpeFeatureCustomizerTest.java @@ -0,0 +1,80 @@ +/* + * 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.lisp.gpe.translate.write; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import io.fd.hc2vpp.common.test.write.WriterCustomizerTest; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.vpp.jvpp.core.dto.GpeEnableDisable; +import io.fd.vpp.jvpp.core.dto.GpeEnableDisableReply; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.feature.data.grouping.GpeFeatureData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.feature.data.grouping.GpeFeatureDataBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class GpeFeatureCustomizerTest extends WriterCustomizerTest { + + private GpeFeatureCustomizer customizer; + + @Captor + private ArgumentCaptor<GpeEnableDisable> requestCaptor; + + @Override + protected void setUpTest() throws Exception { + customizer = new GpeFeatureCustomizer(api); + } + + @Test + public void testWrite() throws WriteFailedException { + when(api.gpeEnableDisable(any())).thenReturn(future(new GpeEnableDisableReply())); + + customizer.writeCurrentAttributes(InstanceIdentifier.create(GpeFeatureData.class), + new GpeFeatureDataBuilder().setEnable(true).build(), writeContext); + verify(api, times(1)).gpeEnableDisable(requestCaptor.capture()); + final GpeEnableDisable request = requestCaptor.getValue(); + assertEquals(1, request.isEn); + } + + @Test + public void testDelete() throws WriteFailedException { + when(api.gpeEnableDisable(any())).thenReturn(future(new GpeEnableDisableReply())); + + customizer.deleteCurrentAttributes(InstanceIdentifier.create(GpeFeatureData.class), + new GpeFeatureDataBuilder().setEnable(true).build(), writeContext); + verify(api, times(1)).gpeEnableDisable(requestCaptor.capture()); + final GpeEnableDisable request = requestCaptor.getValue(); + assertEquals(0, request.isEn); + } + + @Test + public void testUpdate() throws WriteFailedException { + when(api.gpeEnableDisable(any())).thenReturn(future(new GpeEnableDisableReply())); + + customizer.writeCurrentAttributes(InstanceIdentifier.create(GpeFeatureData.class), + new GpeFeatureDataBuilder().setEnable(false).build(), writeContext); + verify(api, times(1)).gpeEnableDisable(requestCaptor.capture()); + final GpeEnableDisable request = requestCaptor.getValue(); + assertEquals(0, request.isEn); + } +} diff --git a/lisp/lisp2vpp/src/test/java/io/fd/hc2vpp/lisp/gpe/translate/write/GpeForwardEntryCustomizerTest.java b/lisp/lisp2vpp/src/test/java/io/fd/hc2vpp/lisp/gpe/translate/write/GpeForwardEntryCustomizerTest.java new file mode 100644 index 000000000..74c9bdeba --- /dev/null +++ b/lisp/lisp2vpp/src/test/java/io/fd/hc2vpp/lisp/gpe/translate/write/GpeForwardEntryCustomizerTest.java @@ -0,0 +1,313 @@ +/* + * 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.lisp.gpe.translate.write; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; + +import com.google.common.collect.ImmutableSet; +import io.fd.hc2vpp.common.test.write.WriterCustomizerTest; +import io.fd.hc2vpp.common.translate.util.ByteDataTranslator; +import io.fd.hc2vpp.lisp.gpe.translate.ctx.GpeEntryIdentifier; +import io.fd.hc2vpp.lisp.gpe.translate.ctx.GpeEntryMappingContext; +import io.fd.hc2vpp.lisp.gpe.translate.ctx.GpeLocatorPair; +import io.fd.hc2vpp.lisp.gpe.translate.ctx.GpeLocatorPairMappingContext; +import io.fd.hc2vpp.lisp.gpe.translate.service.GpeStateCheckService; +import io.fd.honeycomb.test.tools.HoneycombTestRunner; +import io.fd.honeycomb.test.tools.annotations.InjectTestData; +import io.fd.honeycomb.test.tools.annotations.InjectablesProcessor; +import io.fd.honeycomb.test.tools.annotations.SchemaContextProvider; +import io.fd.vpp.jvpp.core.dto.GpeAddDelFwdEntry; +import io.fd.vpp.jvpp.core.dto.GpeAddDelFwdEntryReply; +import io.fd.vpp.jvpp.core.types.GpeLocator; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.GpeEntryTable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.GpeEntry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.GpeEntryKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.gpe.entry.table.grouping.gpe.entry.table.gpe.entry.LocatorPairs; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev170315.$YangModuleInfoImpl; +import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +@RunWith(HoneycombTestRunner.class) +public class GpeForwardEntryCustomizerTest extends WriterCustomizerTest + implements InjectablesProcessor, ByteDataTranslator { + + private static final String GPE_ENTRY_ID = "gpe-fwd-entry-1"; + private static final String GPE_ENTRY_PATH = "/gpe:gpe" + + "/gpe:gpe-feature-data" + + "/gpe:gpe-entry-table"; + private static final byte[] LOCAL_EID_ADDRESS = {-64, -88, 2, 0}; + private static final byte[] REMOTE_EID_ADDRESS = {-64, -88, 3, 0}; + private static final byte[] PAIR_2_LOCAL_ADDRESS = {-64, -88, 5, 1}; + private static final byte[] PAIR_1_LOCAL_ADDRESS = {-64, -88, 4, 1}; + private static final byte[] PAIR_2_REMOTE_ADDRESS = {-64, -88, 5, 2}; + private static final byte[] PAIR_1_REMOTE_ADDRESS = {-64, -88, 4, 2}; + private static final int LOCAL_EID_PREFIX = 24; + private static final int REMOTE_EID_PREFIX = 16; + + @Captor + private ArgumentCaptor<GpeAddDelFwdEntry> requestCaptor; + + @Mock + private GpeEntryMappingContext gpeEntryMappingContext; + + @Mock + private GpeLocatorPairMappingContext gpeLocatorPairMappingContext; + + @Mock + private GpeStateCheckService gpeStateCheckService; + + private InstanceIdentifier<GpeEntry> id; + private GpeForwardEntryCustomizer customizer; + + @Override + protected void setUpTest() throws Exception { + id = InstanceIdentifier.create(GpeEntryTable.class) + .child(GpeEntry.class, new GpeEntryKey(GPE_ENTRY_ID)); + customizer = new GpeForwardEntryCustomizer(api, gpeStateCheckService, gpeEntryMappingContext, + gpeLocatorPairMappingContext); + } + + @SchemaContextProvider + public ModuleInfoBackedContext schemaContext() { + return provideSchemaContextFor(ImmutableSet.of($YangModuleInfoImpl.getInstance(), + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.$YangModuleInfoImpl + .getInstance(), + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170518.$YangModuleInfoImpl + .getInstance())); + } + + @Test + public void testWriteCurrentAttributesFull(@InjectTestData(resourcePath = "/gpe/gpe-fwd-entry-full.json", + id = GPE_ENTRY_PATH) GpeEntryTable entryTable) throws Exception { + when(api.gpeAddDelFwdEntry(any())).thenReturn(future(new GpeAddDelFwdEntryReply())); + final GpeEntry entry = entryTable.getGpeEntry().get(0); + customizer.writeCurrentAttributes(id, entry, writeContext); + verify(api, times(1)).gpeAddDelFwdEntry(requestCaptor.capture()); + assertEquals(expectedFullRequest(true), requestCaptor.getValue()); + verify(gpeEntryMappingContext, times(1)) + .addMapping(entry.getId(), GpeEntryIdentifier.fromEntry(entry), mappingContext); + + final LocatorPairs locatorPairFirst = entry.getLocatorPairs().get(0); + final LocatorPairs locatorPairSecond = entry.getLocatorPairs().get(1); + verify(gpeLocatorPairMappingContext, times(1)) + .addMapping(entry.getId(), locatorPairFirst.getId(), + GpeLocatorPair.fromLocatorPair(locatorPairFirst), mappingContext); + verify(gpeLocatorPairMappingContext, times(1)) + .addMapping(entry.getId(), locatorPairSecond.getId(), + GpeLocatorPair.fromLocatorPair(locatorPairSecond), mappingContext); + } + + @Test + public void testWriteCurrentAttributesWithoutLocators( + @InjectTestData(resourcePath = "/gpe/gpe-fwd-entry-without-locators.json", + id = GPE_ENTRY_PATH) GpeEntryTable entryTable) throws Exception { + when(api.gpeAddDelFwdEntry(any())).thenReturn(future(new GpeAddDelFwdEntryReply())); + final GpeEntry entry = entryTable.getGpeEntry().get(0); + customizer.writeCurrentAttributes(id, entry, writeContext); + verify(api, times(1)).gpeAddDelFwdEntry(requestCaptor.capture()); + assertEquals(expectedLocatorLessRequest(true), requestCaptor.getValue()); + verify(gpeEntryMappingContext, times(1)) + .addMapping(entry.getId(), GpeEntryIdentifier.fromEntry(entry), mappingContext); + verifyZeroInteractions(gpeLocatorPairMappingContext); + } + + @Test + public void testWriteCurrentAttributesWithoutAction( + @InjectTestData(resourcePath = "/gpe/gpe-fwd-entry-without-action.json", + id = GPE_ENTRY_PATH) GpeEntryTable entryTable) throws Exception { + when(api.gpeAddDelFwdEntry(any())).thenReturn(future(new GpeAddDelFwdEntryReply())); + final GpeEntry entry = entryTable.getGpeEntry().get(0); + customizer.writeCurrentAttributes(id, entry, writeContext); + verify(api, times(1)).gpeAddDelFwdEntry(requestCaptor.capture()); + assertEquals(expectedActionLessRequest(true), requestCaptor.getValue()); + verify(gpeEntryMappingContext, times(1)) + .addMapping(entry.getId(), GpeEntryIdentifier.fromEntry(entry), mappingContext); + verifyZeroInteractions(gpeLocatorPairMappingContext); + } + + @Test + public void testWriteCurrentAttributesFailNoLocalEid( + @InjectTestData(resourcePath = "/gpe/invalid/invalid-gpe-fwd-entry-no-local-eid.json", + id = GPE_ENTRY_PATH) GpeEntryTable entryTable) throws Exception { + try { + customizer.writeCurrentAttributes(id, entryTable.getGpeEntry().get(0), writeContext); + } catch (IllegalArgumentException e) { + verifyZeroInteractions(api); + return; + } + fail("Test should have failed"); + } + + @Test + public void testWriteCurrentAttributesFailNoRemoteEid( + @InjectTestData(resourcePath = "/gpe/invalid/invalid-gpe-fwd-entry-no-remote-eid.json", + id = GPE_ENTRY_PATH) GpeEntryTable entryTable) throws Exception { + try { + customizer.writeCurrentAttributes(id, entryTable.getGpeEntry().get(0), writeContext); + } catch (IllegalArgumentException e) { + verifyZeroInteractions(api); + return; + } + fail("Test should have failed"); + } + + @Test + public void testDeleteCurrentAttributesFull(@InjectTestData(resourcePath = "/gpe/gpe-fwd-entry-full.json", + id = GPE_ENTRY_PATH) GpeEntryTable entryTable) throws Exception { + when(api.gpeAddDelFwdEntry(any())).thenReturn(future(new GpeAddDelFwdEntryReply())); + final GpeEntry entry = entryTable.getGpeEntry().get(0); + customizer.deleteCurrentAttributes(id, entry, writeContext); + verify(api, times(1)).gpeAddDelFwdEntry(requestCaptor.capture()); + assertEquals(expectedFullRequest(false), requestCaptor.getValue()); + verify(gpeEntryMappingContext, times(1)) + .removeMapping(entry.getId(), mappingContext); + verify(gpeLocatorPairMappingContext, times(1)) + .removeMapping(entry.getId(), mappingContext); + } + + @Test + public void testDeleteCurrentAttributesWithoutLocators( + @InjectTestData(resourcePath = "/gpe/gpe-fwd-entry-without-locators.json", + id = GPE_ENTRY_PATH) GpeEntryTable entryTable) throws Exception { + when(api.gpeAddDelFwdEntry(any())).thenReturn(future(new GpeAddDelFwdEntryReply())); + final GpeEntry entry = entryTable.getGpeEntry().get(0); + customizer.deleteCurrentAttributes(id, entry, writeContext); + verify(api, times(1)).gpeAddDelFwdEntry(requestCaptor.capture()); + assertEquals(expectedLocatorLessRequest(false), requestCaptor.getValue()); + verify(gpeEntryMappingContext, times(1)) + .removeMapping(entry.getId(), mappingContext); + verify(gpeLocatorPairMappingContext, times(1)) + .removeMapping(entry.getId(), mappingContext); + } + + @Test + public void testDeleteCurrentAttributesWithoutAction( + @InjectTestData(resourcePath = "/gpe/gpe-fwd-entry-without-action.json", + id = GPE_ENTRY_PATH) GpeEntryTable entryTable) throws Exception { + when(api.gpeAddDelFwdEntry(any())).thenReturn(future(new GpeAddDelFwdEntryReply())); + final GpeEntry entry = entryTable.getGpeEntry().get(0); + customizer.deleteCurrentAttributes(id, entry, writeContext); + verify(api, times(1)).gpeAddDelFwdEntry(requestCaptor.capture()); + assertEquals(expectedActionLessRequest(false), requestCaptor.getValue()); + verify(gpeEntryMappingContext, times(1)) + .removeMapping(entry.getId(), mappingContext); + verify(gpeLocatorPairMappingContext, times(1)) + .removeMapping(entry.getId(), mappingContext); + } + + @Test + public void testDeleteCurrentAttributesFailNoLocalEid( + @InjectTestData(resourcePath = "/gpe/invalid/invalid-gpe-fwd-entry-no-local-eid.json", + id = GPE_ENTRY_PATH) GpeEntryTable entryTable) throws Exception { + try { + customizer.deleteCurrentAttributes(id, entryTable.getGpeEntry().get(0), writeContext); + } catch (IllegalArgumentException e) { + verifyZeroInteractions(api); + return; + } + fail("Test should have failed"); + } + + @Test + public void testDeleteCurrentAttributesFailNoRemoteEid( + @InjectTestData(resourcePath = "/gpe/invalid/invalid-gpe-fwd-entry-no-remote-eid.json", + id = GPE_ENTRY_PATH) GpeEntryTable entryTable) throws Exception { + try { + customizer.deleteCurrentAttributes(id, entryTable.getGpeEntry().get(0), writeContext); + } catch (IllegalArgumentException e) { + verifyZeroInteractions(api); + return; + } + fail("Test should have failed"); + } + + private GpeAddDelFwdEntry expectedActionLessRequest(final boolean add) { + final GpeAddDelFwdEntry request = new GpeAddDelFwdEntry(); + + request.isAdd = booleanToByte(add); + request.dpTable = 10; + request.vni = 12; + request.eidType = 0; + request.action = 0; + request.lclEid = LOCAL_EID_ADDRESS; + request.lclLen = LOCAL_EID_PREFIX; + request.rmtEid = REMOTE_EID_ADDRESS; + request.rmtLen = REMOTE_EID_PREFIX; + request.locNum = 0; + return request; + } + + private GpeAddDelFwdEntry expectedLocatorLessRequest(final boolean add) { + final GpeAddDelFwdEntry request = new GpeAddDelFwdEntry(); + + request.isAdd = booleanToByte(add); + request.dpTable = 10; + request.vni = 12; + request.eidType = 0; + request.action = 1; + request.lclEid = LOCAL_EID_ADDRESS; + request.lclLen = LOCAL_EID_PREFIX; + request.rmtEid = REMOTE_EID_ADDRESS; + request.rmtLen = REMOTE_EID_PREFIX; + request.locNum = 0; + return request; + } + + + private GpeAddDelFwdEntry expectedFullRequest(final boolean add) { + final GpeAddDelFwdEntry request = new GpeAddDelFwdEntry(); + + request.isAdd = booleanToByte(add); + request.dpTable = 10; + request.vni = 12; + request.eidType = 0; + request.action = 1; + request.lclEid = LOCAL_EID_ADDRESS; + request.lclLen = LOCAL_EID_PREFIX; + request.rmtEid = REMOTE_EID_ADDRESS; + request.rmtLen = REMOTE_EID_PREFIX; + request.locNum = 4; + request.locs = new GpeLocator[]{ + gpeLocator(PAIR_2_LOCAL_ADDRESS, 1, 2), + gpeLocator(PAIR_1_LOCAL_ADDRESS, 1, 3), + gpeLocator(PAIR_1_REMOTE_ADDRESS, 1, 0), + gpeLocator(PAIR_2_REMOTE_ADDRESS, 1, 0) + }; + + return request; + } + + private GpeLocator gpeLocator(final byte[] address, final int isIpv4, final int weight) { + GpeLocator locator = new GpeLocator(); + locator.isIp4 = (byte) isIpv4; + locator.weight = (byte) weight; + locator.addr = address; + + return locator; + } +}
\ No newline at end of file diff --git a/lisp/lisp2vpp/src/test/resources/gpe/gpe-fwd-entry-full.json b/lisp/lisp2vpp/src/test/resources/gpe/gpe-fwd-entry-full.json new file mode 100644 index 000000000..8bc5cc41e --- /dev/null +++ b/lisp/lisp2vpp/src/test/resources/gpe/gpe-fwd-entry-full.json @@ -0,0 +1,38 @@ +{ + "gpe-entry-table": { + "gpe-entry": { + "id": "gpe-fwd-entry-1", + "dp-table": 10, + "vni": 12, + "local-eid": { + "address-type": "ietf-lisp-address-types:ipv4-prefix-afi", + "virtual-network-id": 12, + "ipv4-prefix": "192.168.2.0/24" + }, + "remote-eid": { + "address-type": "ietf-lisp-address-types:ipv4-prefix-afi", + "virtual-network-id": 12, + "ipv4-prefix": "192.168.3.0/16" + }, + "locator-pairs": [ + { + "id": "gpe-fwd-entry-pair-1", + "locator-pair": { + "local-locator": "192.168.4.1", + "remote-locator": "192.168.4.2", + "weight": 3 + } + }, + { + "id": "gpe-fwd-entry-pair-2", + "locator-pair": { + "local-locator": "192.168.5.1", + "remote-locator": "192.168.5.2", + "weight": 2 + } + } + ], + "action": "natively-forward" + } + } +}
\ No newline at end of file diff --git a/lisp/lisp2vpp/src/test/resources/gpe/gpe-fwd-entry-without-action.json b/lisp/lisp2vpp/src/test/resources/gpe/gpe-fwd-entry-without-action.json new file mode 100644 index 000000000..b004d5a9d --- /dev/null +++ b/lisp/lisp2vpp/src/test/resources/gpe/gpe-fwd-entry-without-action.json @@ -0,0 +1,19 @@ +{ + "gpe-entry-table": { + "gpe-entry": { + "id": "gpe-fwd-entry-1", + "dp-table": 10, + "vni": 12, + "local-eid": { + "address-type": "ietf-lisp-address-types:ipv4-prefix-afi", + "virtual-network-id": 12, + "ipv4-prefix": "192.168.2.0/24" + }, + "remote-eid": { + "address-type": "ietf-lisp-address-types:ipv4-prefix-afi", + "virtual-network-id": 12, + "ipv4-prefix": "192.168.3.0/16" + } + } + } +}
\ No newline at end of file diff --git a/lisp/lisp2vpp/src/test/resources/gpe/gpe-fwd-entry-without-locators.json b/lisp/lisp2vpp/src/test/resources/gpe/gpe-fwd-entry-without-locators.json new file mode 100644 index 000000000..2015b540f --- /dev/null +++ b/lisp/lisp2vpp/src/test/resources/gpe/gpe-fwd-entry-without-locators.json @@ -0,0 +1,20 @@ +{ + "gpe-entry-table": { + "gpe-entry": { + "id": "gpe-fwd-entry-1", + "dp-table": 10, + "vni": 12, + "local-eid": { + "address-type": "ietf-lisp-address-types:ipv4-prefix-afi", + "virtual-network-id": 12, + "ipv4-prefix": "192.168.2.0/24" + }, + "remote-eid": { + "address-type": "ietf-lisp-address-types:ipv4-prefix-afi", + "virtual-network-id": 12, + "ipv4-prefix": "192.168.3.0/16" + }, + "action": "natively-forward" + } + } +}
\ No newline at end of file diff --git a/lisp/lisp2vpp/src/test/resources/gpe/invalid/invalid-gpe-fwd-entry-no-local-eid.json b/lisp/lisp2vpp/src/test/resources/gpe/invalid/invalid-gpe-fwd-entry-no-local-eid.json new file mode 100644 index 000000000..25c12d615 --- /dev/null +++ b/lisp/lisp2vpp/src/test/resources/gpe/invalid/invalid-gpe-fwd-entry-no-local-eid.json @@ -0,0 +1,33 @@ +{ + "gpe-entry-table": { + "gpe-entry": { + "id": "gpe-fwd-entry-1", + "dp-table": 10, + "vni": 12, + "remote-eid": { + "address-type": "ietf-lisp-address-types:ipv4-prefix-afi", + "virtual-network-id": 12, + "ipv4-prefix": "192.168.3.0/16" + }, + "locator-pairs": [ + { + "id": "gpe-fwd-entry-pair-1", + "locator-pair": { + "local-locator": "192.168.4.1", + "remote-locator": "192.168.4.2", + "weight": 3 + } + }, + { + "id": "gpe-fwd-entry-pair-2", + "locator-pair": { + "local-locator": "192.168.5.1", + "remote-locator": "192.168.5.2", + "weight": 2 + } + } + ], + "action": "natively-forward" + } + } +}
\ No newline at end of file diff --git a/lisp/lisp2vpp/src/test/resources/gpe/invalid/invalid-gpe-fwd-entry-no-remote-eid.json b/lisp/lisp2vpp/src/test/resources/gpe/invalid/invalid-gpe-fwd-entry-no-remote-eid.json new file mode 100644 index 000000000..e6d5cc7e5 --- /dev/null +++ b/lisp/lisp2vpp/src/test/resources/gpe/invalid/invalid-gpe-fwd-entry-no-remote-eid.json @@ -0,0 +1,33 @@ +{ + "gpe-entry-table": { + "gpe-entry": { + "id": "gpe-fwd-entry-1", + "dp-table": 10, + "vni": 12, + "local-eid": { + "address-type": "ietf-lisp-address-types:ipv4-prefix-afi", + "virtual-network-id": 12, + "ipv4-prefix": "192.168.2.0/24" + }, + "locator-pairs": [ + { + "id": "gpe-fwd-entry-pair-1", + "locator-pair": { + "local-locator": "192.168.4.1", + "remote-locator": "192.168.4.2", + "weight": 3 + } + }, + { + "id": "gpe-fwd-entry-pair-2", + "locator-pair": { + "local-locator": "192.168.5.1", + "remote-locator": "192.168.5.2", + "weight": 2 + } + } + ], + "action": "natively-forward" + } + } +}
\ No newline at end of file |