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/src/main | |
parent | b5d9c75265a5779ed7404b426f3f91a6b1e07e49 (diff) |
HC2VPP-147 - Gpe entry implementation
Change-Id: Ie7887c8e8f10678410ad677c425bfed1690bf440
Signed-off-by: Jan Srnicek <jsrnicek@cisco.com>
Diffstat (limited to 'lisp/lisp2vpp/src/main')
16 files changed, 1690 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"); |