HONEYCOMB-58 - Routing Api
[honeycomb.git] / lisp / lisp2vpp / src / main / java / io / fd / honeycomb / lisp / translate / write / AdjacencyCustomizer.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.lisp.translate.write;
18
19
20 import static com.google.common.base.Preconditions.checkArgument;
21 import static com.google.common.base.Preconditions.checkNotNull;
22 import static io.fd.honeycomb.lisp.translate.read.dump.executor.params.MappingsDumpParams.EidType;
23
24 import io.fd.honeycomb.lisp.context.util.AdjacenciesMappingContext;
25 import io.fd.honeycomb.lisp.context.util.EidMappingContext;
26 import io.fd.honeycomb.lisp.translate.util.EidTranslator;
27 import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
28 import io.fd.honeycomb.translate.vpp.util.ByteDataTranslator;
29 import io.fd.honeycomb.translate.vpp.util.FutureJVppCustomizer;
30 import io.fd.honeycomb.translate.vpp.util.JvppReplyConsumer;
31 import io.fd.honeycomb.translate.write.WriteContext;
32 import io.fd.honeycomb.translate.write.WriteFailedException;
33 import io.fd.vpp.jvpp.VppBaseCallException;
34 import io.fd.vpp.jvpp.core.dto.LispAddDelAdjacency;
35 import io.fd.vpp.jvpp.core.future.FutureJVppCore;
36 import java.util.concurrent.TimeoutException;
37 import javax.annotation.Nonnull;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.adjacencies.grouping.adjacencies.Adjacency;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.adjacencies.grouping.adjacencies.AdjacencyKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.adjacencies.grouping.adjacencies.adjacency.LocalEid;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.adjacencies.grouping.adjacencies.adjacency.RemoteEid;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.eid.table.grouping.eid.table.VniTable;
43 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
44
45 public class AdjacencyCustomizer extends FutureJVppCustomizer
46         implements ListWriterCustomizer<Adjacency, AdjacencyKey>, ByteDataTranslator, EidTranslator,
47         JvppReplyConsumer {
48
49     private final EidMappingContext localEidsMappingContext;
50     private final EidMappingContext remoteEidsMappingContext;
51     private final AdjacenciesMappingContext adjacenciesMappingContext;
52
53     public AdjacencyCustomizer(@Nonnull final FutureJVppCore futureJvpp,
54                                @Nonnull final EidMappingContext localEidsMappingContext,
55                                @Nonnull final EidMappingContext remoteEidsMappingContext,
56                                @Nonnull final AdjacenciesMappingContext adjacenciesMappingContext) {
57         super(futureJvpp);
58         this.localEidsMappingContext =
59                 checkNotNull(localEidsMappingContext, "Eid context for local eid's cannot be null");
60         this.remoteEidsMappingContext =
61                 checkNotNull(remoteEidsMappingContext, "Eid context for remote eid's cannot be null");
62         this.adjacenciesMappingContext = checkNotNull(adjacenciesMappingContext, "Adjacencies context cannot be null");
63     }
64
65     @Override
66     public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Adjacency> id,
67                                        @Nonnull final Adjacency dataAfter, @Nonnull final WriteContext writeContext)
68             throws WriteFailedException {
69         try {
70             addDelAdjacency(true, id, dataAfter, writeContext);
71         } catch (TimeoutException | VppBaseCallException e) {
72             throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
73         }
74
75         //after successful creation, create mapping
76         adjacenciesMappingContext.addEidPair(adjacencyId(id),
77                 localEidId(dataAfter, writeContext),
78                 remoteEidId(dataAfter, writeContext),
79                 writeContext.getMappingContext());
80     }
81
82     private String remoteEidId(final @Nonnull Adjacency dataAfter, final @Nonnull WriteContext writeContext) {
83         return remoteEidsMappingContext.getId(toRemoteEid(dataAfter.getRemoteEid()), writeContext.getMappingContext())
84                 .getValue();
85     }
86
87     private String localEidId(final @Nonnull Adjacency dataAfter, final @Nonnull WriteContext writeContext) {
88         return localEidsMappingContext.getId(toLocalEid(dataAfter.getLocalEid()), writeContext.getMappingContext())
89                 .getValue();
90     }
91
92     private String adjacencyId(final @Nonnull InstanceIdentifier<Adjacency> id) {
93         return id.firstKeyOf(Adjacency.class).getId();
94     }
95
96     @Override
97     public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Adjacency> id,
98                                         @Nonnull final Adjacency dataBefore, @Nonnull final Adjacency dataAfter,
99                                         @Nonnull final WriteContext writeContext) throws WriteFailedException {
100         throw new UnsupportedOperationException("Operation not supported");
101     }
102
103     @Override
104     public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Adjacency> id,
105                                         @Nonnull final Adjacency dataBefore, @Nonnull final WriteContext writeContext)
106             throws WriteFailedException {
107         try {
108             addDelAdjacency(false, id, dataBefore, writeContext);
109         } catch (TimeoutException | VppBaseCallException e) {
110             throw new WriteFailedException.CreateFailedException(id, dataBefore, e);
111         }
112
113         //after successful creation, create mapping
114         adjacenciesMappingContext.removeForIndex(adjacencyId(id),
115                 writeContext.getMappingContext());
116     }
117
118     private void addDelAdjacency(boolean add, final InstanceIdentifier<Adjacency> id, final Adjacency data,
119                                  final WriteContext writeContext)
120             throws TimeoutException, VppBaseCallException {
121
122         final int vni = checkNotNull(id.firstKeyOf(VniTable.class), "Unable to find parent VNI for {}", id)
123                 .getVirtualNetworkIdentifier().intValue();
124
125         // both local and remote eids must be referenced to have respective mapping,
126         // if there is an attempt to add adjacency.
127         // In our case its enough to check if local/remote mapping exist for respective eid,
128         // because such mappings are created while creating mappings
129         final LocalEid localEid = add
130                 ? verifiedLocalEid(data.getLocalEid(), writeContext)
131                 : data.getLocalEid();
132         final RemoteEid remoteEid = add
133                 ? verifiedRemoteEid(data.getRemoteEid(), writeContext)
134                 : data.getRemoteEid();
135         final EidType localEidType = getEidType(localEid);
136         final EidType remoteEidType = getEidType(data.getRemoteEid());
137
138         checkArgument(localEidType ==
139                 remoteEidType, "Local[%s] and Remote[%s] eid types must be the same", localEidType, remoteEidType);
140
141         LispAddDelAdjacency request = new LispAddDelAdjacency();
142
143         request.isAdd = booleanToByte(add);
144         request.leid = getEidAsByteArray(localEid);
145         request.leidLen = getPrefixLength(localEid);
146         request.reid = getEidAsByteArray(remoteEid);
147         request.reidLen = getPrefixLength(remoteEid);
148         request.eidType = (byte) localEidType.getValue();
149         request.vni = vni;
150
151         getReply(getFutureJVpp().lispAddDelAdjacency(request).toCompletableFuture());
152     }
153
154     private LocalEid verifiedLocalEid(final LocalEid localEid, final WriteContext writeContext) {
155         if (localEidsMappingContext.containsId(toLocalEid(localEid), writeContext.getMappingContext())) {
156             return localEid;
157         }
158         throw new IllegalStateException(
159                 "Referenced Local Eid[" + localEid +
160                         "] doesn't have local mapping defined, therefore it can't be used in adjacency");
161     }
162
163     private RemoteEid verifiedRemoteEid(final RemoteEid remoteEid, final WriteContext writeContext) {
164         if (remoteEidsMappingContext.containsId(toRemoteEid(remoteEid), writeContext.getMappingContext())) {
165             return remoteEid;
166         }
167         throw new IllegalStateException(
168                 "Referenced Remote Eid[" + remoteEid +
169                         "] doesn't have remote mapping defined, therefore it can't be used in adjacency");
170     }
171
172     private org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.dp.subtable.grouping.remote.mappings.remote.mapping.Eid toRemoteEid(
173             final RemoteEid remoteEid) {
174         return newRemoteEidBuilder(remoteEid.getAddressType(), remoteEid.getVirtualNetworkId().getValue().intValue())
175                 .setAddress(remoteEid.getAddress()).build();
176     }
177
178     private org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev161214.dp.subtable.grouping.local.mappings.local.mapping.Eid toLocalEid(
179             LocalEid localEid) {
180         return newLocalEidBuilder(localEid.getAddressType(), localEid.getVirtualNetworkId().getValue().intValue())
181                 .setAddress(localEid.getAddress()).build();
182     }
183 }