0650280f10c1a24799ce76e0d430c60072f5c539
[honeycomb.git] / nat / nat2vpp / src / main / java / io / fd / honeycomb / nat / read / ExternalIpPoolCustomizer.java
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  *
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:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package io.fd.honeycomb.nat.read;
18
19 import io.fd.honeycomb.translate.read.ReadContext;
20 import io.fd.honeycomb.translate.read.ReadFailedException;
21 import io.fd.honeycomb.translate.spi.read.Initialized;
22 import io.fd.honeycomb.translate.spi.read.InitializingListReaderCustomizer;
23 import io.fd.honeycomb.translate.util.RWUtils;
24 import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager;
25 import io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor;
26 import io.fd.honeycomb.translate.vpp.util.Ipv4Translator;
27 import io.fd.honeycomb.translate.vpp.util.JvppReplyConsumer;
28 import io.fd.vpp.jvpp.snat.dto.SnatAddressDetails;
29 import io.fd.vpp.jvpp.snat.dto.SnatAddressDetailsReplyDump;
30 import io.fd.vpp.jvpp.snat.dto.SnatAddressDump;
31 import io.fd.vpp.jvpp.snat.future.FutureJVppSnatFacade;
32 import java.util.Collections;
33 import java.util.List;
34 import java.util.stream.Collectors;
35 import java.util.stream.LongStream;
36 import javax.annotation.Nonnull;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.parameters.ExternalIpAddressPool;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.parameters.ExternalIpAddressPoolBuilder;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.parameters.ExternalIpAddressPoolKey;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.state.nat.instances.NatInstance;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.state.nat.instances.NatInstanceKey;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.nat.rev150908.nat.state.nat.instances.nat.instance.NatCurrentConfigBuilder;
44 import org.opendaylight.yangtools.concepts.Builder;
45 import org.opendaylight.yangtools.yang.binding.DataObject;
46 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49
50 final class ExternalIpPoolCustomizer implements
51         InitializingListReaderCustomizer<ExternalIpAddressPool, ExternalIpAddressPoolKey, ExternalIpAddressPoolBuilder>,
52         JvppReplyConsumer, Ipv4Translator {
53
54     private static final Logger LOG = LoggerFactory.getLogger(ExternalIpPoolCustomizer.class);
55
56     private final DumpCacheManager<SnatAddressDetailsReplyDump, Void> dumpMgr;
57
58     ExternalIpPoolCustomizer(final DumpCacheManager<SnatAddressDetailsReplyDump, Void> dumpMgr) {
59         this.dumpMgr = dumpMgr;
60     }
61
62     @Nonnull
63     @Override
64     public ExternalIpAddressPoolBuilder getBuilder(@Nonnull final InstanceIdentifier<ExternalIpAddressPool> id) {
65         return new ExternalIpAddressPoolBuilder();
66     }
67
68     @Override
69     public void readCurrentAttributes(@Nonnull final InstanceIdentifier<ExternalIpAddressPool> id,
70                                       @Nonnull final ExternalIpAddressPoolBuilder builder,
71                                       @Nonnull final ReadContext ctx) throws ReadFailedException {
72         LOG.trace("Reading current attributes for external IP pool: {}", id);
73
74         final Long poolId = id.firstKeyOf(ExternalIpAddressPool.class).getPoolId();
75         final SnatAddressDetails details =
76                 dumpMgr.getDump(id, ctx.getModificationCache(), null)
77                         .or(new SnatAddressDetailsReplyDump()).snatAddressDetails.get(Math.toIntExact(poolId));
78
79         builder.setExternalIpPool(
80                 new Ipv4Prefix(arrayToIpv4AddressNoZoneReversed(details.ipAddress).getValue() + "/32"));
81         builder.setPoolId(poolId);
82
83         LOG.trace("External IP pool: {}. Read as: {}", id, builder);
84     }
85
86     @Nonnull
87     @Override
88     public List<ExternalIpAddressPoolKey> getAllIds(@Nonnull final InstanceIdentifier<ExternalIpAddressPool> id,
89                                                     @Nonnull final ReadContext ctx) throws ReadFailedException {
90         final NatInstanceKey natKey = id.firstKeyOf(NatInstance.class);
91         if (!natKey.equals(NatInstanceCustomizer.DEFAULT_VRF_ID)) {
92             // IP Pools are not vrf aware ... so they are only visible under default vrf (nat-instance)
93             return Collections.emptyList();
94         }
95
96         LOG.trace("Listing IDs for all external IP pools within nat-instance(vrf):{}", natKey);
97
98         // Since VPP returns every single (unordered) address instead of address range,
99         // there is no way to determine what the original ranges were when writing the data into VPP.
100
101         // That's why the write and read is not symmetrical in terms of data structure, instead,
102         // this customizer also returns every single address as a 32 prefix and assigns an artificial key to them
103
104         final long addressCount = dumpMgr.getDump(id, ctx.getModificationCache(), null)
105                 .or(new SnatAddressDetailsReplyDump()).snatAddressDetails.stream()
106                 .count();
107
108         final List<ExternalIpAddressPoolKey> ids = LongStream.range(0, addressCount)
109                 .mapToObj(ExternalIpAddressPoolKey::new)
110                 .collect(Collectors.toList());
111
112         LOG.trace("List of external IP pool ids: {}", ids);
113         return ids;
114     }
115
116     @Override
117     public void merge(@Nonnull final Builder<? extends DataObject> builder,
118                       @Nonnull final List<ExternalIpAddressPool> readData) {
119         ((NatCurrentConfigBuilder) builder).setExternalIpAddressPool(readData);
120     }
121
122     @Override
123     public Initialized<ExternalIpAddressPool> init(
124             @Nonnull final InstanceIdentifier<ExternalIpAddressPool> id,
125             @Nonnull final ExternalIpAddressPool readValue,
126             @Nonnull final ReadContext ctx) {
127         return Initialized.create(getCfgId(id), readValue);
128     }
129
130     static InstanceIdentifier<ExternalIpAddressPool> getCfgId(final @Nonnull InstanceIdentifier<ExternalIpAddressPool> id) {
131         return NatInstanceCustomizer.getCfgId(RWUtils.cutId(id, NatInstance.class))
132                 .child(ExternalIpAddressPool.class, id.firstKeyOf(ExternalIpAddressPool.class));
133     }
134
135     static final class AddressRangeDumpExecutor implements EntityDumpExecutor<SnatAddressDetailsReplyDump, Void>,
136             JvppReplyConsumer {
137         private final FutureJVppSnatFacade jvppSnat;
138
139         AddressRangeDumpExecutor(final FutureJVppSnatFacade jvppSnat) {
140             this.jvppSnat = jvppSnat;
141         }
142
143         @Nonnull
144         @Override
145         public SnatAddressDetailsReplyDump executeDump(final InstanceIdentifier<?> identifier, final Void params)
146                 throws ReadFailedException {
147             return getReplyForRead(jvppSnat.snatAddressDump(new SnatAddressDump()).toCompletableFuture(), identifier);
148         }
149     }
150 }