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