diff options
Diffstat (limited to 'lisp/lisp2vpp/src/main/java/io/fd/hc2vpp/lisp/gpe/translate/write')
3 files changed, 376 insertions, 0 deletions
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)); + + + } +} |