2 * Copyright (c) 2016 Cisco and/or its affiliates.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package io.fd.honeycomb.nat.util;
19 import static com.google.common.base.Preconditions.checkArgument;
21 import com.google.common.annotations.VisibleForTesting;
22 import com.google.common.base.Optional;
23 import io.fd.honeycomb.translate.MappingContext;
24 import io.fd.honeycomb.translate.vpp.util.Ipv4Translator;
25 import io.fd.vpp.jvpp.snat.dto.SnatStaticMappingDetails;
26 import java.util.Collections;
27 import java.util.Comparator;
28 import java.util.List;
29 import javax.annotation.Nonnull;
30 import javax.annotation.concurrent.ThreadSafe;
31 import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.Contexts;
32 import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.nat.context.rev161214.NatMappingEntryCtxAugmentation;
33 import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.nat.context.rev161214.mapping.entry.context.attributes.NatMappingEntryContext;
34 import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.nat.context.rev161214.mapping.entry.context.attributes.nat.mapping.entry.context.NatInstance;
35 import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.nat.context.rev161214.mapping.entry.context.attributes.nat.mapping.entry.context.NatInstanceKey;
36 import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.nat.context.rev161214.mapping.entry.context.attributes.nat.mapping.entry.context.nat.instance.MappingTable;
37 import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.nat.context.rev161214.mapping.entry.context.attributes.nat.mapping.entry.context.nat.instance.mapping.table.MappingEntry;
38 import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.nat.context.rev161214.mapping.entry.context.attributes.nat.mapping.entry.context.nat.instance.mapping.table.MappingEntryBuilder;
39 import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.nat.context.rev161214.mapping.entry.context.attributes.nat.mapping.entry.context.nat.instance.mapping.table.MappingEntryKey;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
42 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
47 * Context tracker for Nat Mapping entries.
50 public class MappingEntryContext implements Ipv4Translator {
52 private static final Logger LOG = LoggerFactory.getLogger(MappingEntryContext.class);
55 * Add mapping entry to index mapping to context.
57 public synchronized void addEntry(final long natInstanceId,
59 @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntry entry,
60 @Nonnull final MappingContext mappingContext) {
61 final InstanceIdentifier<MappingEntry> id = getId(natInstanceId, entryToKey(entry));
62 checkArgument(!containsEntry(natInstanceId, entry, mappingContext), "Mapping for %s already present", id);
63 mappingContext.put(id, toCtxMapEntry(entry, entryId));
67 * Check whether mapping entry to index mapping already exists in context.
69 public synchronized boolean containsEntry(final long natInstanceId,
70 @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntry entry,
71 @Nonnull final MappingContext mappingContext) {
72 final InstanceIdentifier<MappingEntry> id = getId(natInstanceId, entryToKey(entry));
73 return mappingContext.read(id).isPresent();
77 static InstanceIdentifier<MappingEntry> getId(final Long natInstanceId, final MappingEntryKey key) {
78 return getTableId(natInstanceId).child(MappingEntry.class, key);
82 static InstanceIdentifier<MappingTable> getTableId(final long natInstanceId) {
83 return InstanceIdentifier.create(Contexts.class)
84 .augmentation(NatMappingEntryCtxAugmentation.class)
85 .child(NatMappingEntryContext.class)
86 .child(NatInstance.class, new NatInstanceKey(natInstanceId))
87 .child(MappingTable.class);
91 static MappingEntryKey entryToKey(
92 final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntry entry) {
94 return new MappingEntryKey(new IpAddress(entry.getExternalSrcAddress()), entry.getInternalSrcAddress());
97 private MappingEntryKey entryToKey(final SnatStaticMappingDetails entry) {
99 return new MappingEntryKey(
100 new IpAddress(new Ipv4Address(arrayToIpv4AddressNoZoneReversed(entry.externalIpAddress))),
101 new IpAddress(new Ipv4Address(arrayToIpv4AddressNoZoneReversed(entry.localIpAddress))));
104 private boolean equalEntries(final SnatStaticMappingDetails detail, final MappingEntry ctxMappingEntry) {
105 final IpAddress internalAddrFromDetails =
106 new IpAddress(new Ipv4Address(arrayToIpv4AddressNoZoneReversed(detail.localIpAddress)));
108 if (!ctxMappingEntry.getInternal().equals(internalAddrFromDetails)) {
112 final IpAddress externalAddrFromDetails =
113 new IpAddress(new Ipv4Address(arrayToIpv4AddressNoZoneReversed(detail.externalIpAddress)));
114 if (!ctxMappingEntry.getExternal().equals(externalAddrFromDetails)) {
121 static MappingEntry toCtxMapEntry(
122 @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntry entry,
123 final long entryId) {
124 return new MappingEntryBuilder()
125 .setKey(entryToKey(entry))
130 private MappingEntry toCtxMapEntry(@Nonnull final SnatStaticMappingDetails details, final long entryId) {
131 return new MappingEntryBuilder()
132 .setKey(entryToKey(details))
138 * Delete mapping of mapping entry to index from context.
140 public synchronized void removeEntry(final long natInstanceId,
141 @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntry entry,
142 @Nonnull final MappingContext mappingContext) {
143 mappingContext.delete(getId(natInstanceId, entryToKey(entry)));
147 * Find specific details in provided collection identified with provided index.
149 public synchronized SnatStaticMappingDetails findDetails(@Nonnull final List<SnatStaticMappingDetails> details,
150 final long natInstanceId, final long idx,
151 @Nonnull final MappingContext mappingContext) {
152 // Find mapping entry for Index
153 final MappingEntry ctxMappingEntry = mappingContext.read(getTableId(natInstanceId))
154 .transform(MappingTable::getMappingEntry)
155 .or(Collections.emptyList())
157 .filter(entry -> entry.getIndex() == idx)
159 .orElseThrow(() -> new IllegalStateException("Unable to find context mapping for nat-instance: "
160 + natInstanceId + " and ID: " + idx));
162 // Find which details matches the context stored entry under index
163 return details.stream()
164 .filter(detail -> equalEntries(detail, ctxMappingEntry))
166 .orElseThrow(() -> new IllegalStateException("Unable to match mapping for nat-instance: "
167 + natInstanceId + " and match: " + ctxMappingEntry + " in: " + details));
171 * Get index for a mapping entry details or create an artificial one.
173 public synchronized long getStoredOrArtificialIndex(final Long natInstanceId,
174 @Nonnull final SnatStaticMappingDetails details,
175 @Nonnull final MappingContext mappingContext) {
176 return mappingContext.read(getId(natInstanceId, entryToKey(details)))
177 .transform(MappingEntry::getIndex)
178 .or(() -> getArtificialId(details, natInstanceId, mappingContext));
182 * Get index for a stored mapping entry.
184 public synchronized Optional<Long> getStoredIndex(final long natInstanceId,
185 @Nonnull final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.config.nat.instances.nat.instance.mapping.table.MappingEntry entry,
186 @Nonnull final MappingContext mappingContext) {
187 return mappingContext.read(getId(natInstanceId, entryToKey(entry)))
188 .transform(MappingEntry::getIndex);
191 private long getArtificialId(final SnatStaticMappingDetails details, final Long natInstanceId,
192 final MappingContext mappingContext) {
193 LOG.trace("Assigning artificial ID for {}", details);
194 final long artificialIdx = findFreeIndex(natInstanceId, mappingContext);
195 LOG.debug("Artificial ID for {} assigned as: {}", details, artificialIdx);
196 mappingContext.put(getId(natInstanceId, entryToKey(details)), toCtxMapEntry(details, artificialIdx));
197 return artificialIdx;
200 private long findFreeIndex(final long natInstanceId, final MappingContext mappingContext) {
201 return mappingContext.read(getTableId(natInstanceId))
202 .transform(MappingTable::getMappingEntry)
203 .or(Collections.emptyList())
205 .map(MappingEntry::getIndex)
206 .max(Comparator.naturalOrder())