HONEYCOMB-234: update YANG model to support egress ACLs
[honeycomb.git] / v3po / v3po2vpp / src / main / java / io / fd / honeycomb / translate / v3po / interfaces / VxlanGpeCustomizer.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.translate.v3po.interfaces;
18
19 import static com.google.common.base.Preconditions.checkArgument;
20
21 import com.google.common.net.InetAddresses;
22 import io.fd.honeycomb.translate.v3po.DisabledInterfacesManager;
23 import io.fd.honeycomb.translate.vpp.util.AbstractInterfaceTypeCustomizer;
24 import io.fd.honeycomb.translate.vpp.util.JvppReplyConsumer;
25 import io.fd.honeycomb.translate.vpp.util.NamingContext;
26 import io.fd.honeycomb.translate.vpp.util.WriteTimeoutException;
27 import io.fd.honeycomb.translate.write.WriteContext;
28 import io.fd.honeycomb.translate.write.WriteFailedException;
29 import java.net.InetAddress;
30 import java.util.concurrent.CompletionStage;
31 import javax.annotation.Nonnull;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeTunnel;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.VxlanGpe;
37 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
38 import io.fd.vpp.jvpp.VppBaseCallException;
39 import io.fd.vpp.jvpp.core.dto.VxlanGpeAddDelTunnel;
40 import io.fd.vpp.jvpp.core.dto.VxlanGpeAddDelTunnelReply;
41 import io.fd.vpp.jvpp.core.future.FutureJVppCore;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 public class VxlanGpeCustomizer extends AbstractInterfaceTypeCustomizer<VxlanGpe> implements JvppReplyConsumer {
46
47     private static final Logger LOG = LoggerFactory.getLogger(VxlanGpeCustomizer.class);
48     private final NamingContext interfaceNamingContext;
49     private final DisabledInterfacesManager interfaceDisableContext;
50
51     public VxlanGpeCustomizer(@Nonnull final FutureJVppCore vppApi,
52                               @Nonnull final NamingContext interfaceNamingContext,
53                               @Nonnull final DisabledInterfacesManager interfaceDisableContext) {
54         super(vppApi);
55         this.interfaceNamingContext = interfaceNamingContext;
56         this.interfaceDisableContext = interfaceDisableContext;
57     }
58
59     @Override
60     protected Class<? extends InterfaceType> getExpectedInterfaceType() {
61         return VxlanGpeTunnel.class;
62     }
63
64     @Override
65     protected final void writeInterface(@Nonnull final InstanceIdentifier<VxlanGpe> id,
66                                         @Nonnull final VxlanGpe dataAfter,
67                                         @Nonnull final WriteContext writeContext)
68             throws WriteFailedException {
69         final String swIfName = id.firstKeyOf(Interface.class).getName();
70         try {
71             createVxlanGpeTunnel(id, swIfName, dataAfter, writeContext);
72         } catch (VppBaseCallException | IllegalInterfaceTypeException e) {
73             LOG.warn("Failed to set VxlanGpe tunnel for interface: {}, VxlanGpe: {}", swIfName, dataAfter);
74             throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
75         }
76     }
77
78     @Override
79     public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<VxlanGpe> id,
80                                         @Nonnull final VxlanGpe dataBefore,
81                                         @Nonnull final VxlanGpe dataAfter, @Nonnull final WriteContext writeContext)
82             throws WriteFailedException.UpdateFailedException {
83         throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter,
84                 new UnsupportedOperationException("VxlanGpe tunnel update is not supported"));
85     }
86
87     @Override
88     public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<VxlanGpe> id,
89                                         @Nonnull final VxlanGpe dataBefore,
90                                         @Nonnull final WriteContext writeContext)
91             throws WriteFailedException {
92         final String swIfName = id.firstKeyOf(Interface.class).getName();
93         try {
94             deleteVxlanGpeTunnel(id, swIfName, dataBefore, writeContext);
95         } catch (VppBaseCallException e) {
96             LOG.warn("Failed to delete VxlanGpe tunnel for interface: {}, VxlanGpe: {}", swIfName, dataBefore);
97             throw new WriteFailedException.DeleteFailedException(id, e);
98         }
99     }
100
101     private void createVxlanGpeTunnel(final InstanceIdentifier<VxlanGpe> id, final String swIfName,
102                                       final VxlanGpe vxlanGpe, final WriteContext writeContext)
103             throws VppBaseCallException, WriteTimeoutException {
104         final byte isIpv6 = (byte) (isIpv6(vxlanGpe)
105                 ? 1
106                 : 0);
107         final InetAddress Local = InetAddresses.forString(getAddressString(vxlanGpe.getLocal()));
108         final InetAddress Remote = InetAddresses.forString(getAddressString(vxlanGpe.getRemote()));
109
110         int vni = vxlanGpe.getVni().getValue().intValue();
111         byte protocol = (byte) vxlanGpe.getNextProtocol().getIntValue();
112         int encapVrfId = vxlanGpe.getEncapVrfId().intValue();
113         int decapVrfId = vxlanGpe.getDecapVrfId().intValue();
114
115         LOG.debug("Setting VxlanGpe tunnel for interface: {}. VxlanGpe: {}", swIfName, vxlanGpe);
116         final CompletionStage<VxlanGpeAddDelTunnelReply> VxlanGpeAddDelTunnelReplyCompletionStage =
117                 getFutureJVpp().vxlanGpeAddDelTunnel(getVxlanGpeTunnelRequest((byte) 1 /* is add */, Local.getAddress(),
118                         Remote.getAddress(), vni, protocol, encapVrfId, decapVrfId, isIpv6));
119
120         final VxlanGpeAddDelTunnelReply reply =
121                 getReplyForWrite(VxlanGpeAddDelTunnelReplyCompletionStage.toCompletableFuture(), id);
122         LOG.debug("VxlanGpe tunnel set successfully for: {}, VxlanGpe: {}", swIfName, vxlanGpe);
123         if (interfaceNamingContext.containsName(reply.swIfIndex, writeContext.getMappingContext())) {
124             final String formerName = interfaceNamingContext.getName(reply.swIfIndex, writeContext.getMappingContext());
125             LOG.debug("Removing updated mapping of a vxlan-gpe tunnel, id: {}, former name: {}, new name: {}",
126                     reply.swIfIndex, formerName, swIfName);
127             interfaceNamingContext.removeName(formerName, writeContext.getMappingContext());
128         }
129
130         // Removing disability of an interface in case a vxlan-gpe tunnel formerly deleted is being reused in VPP
131         // further details in above comment
132         if (interfaceDisableContext.isInterfaceDisabled(reply.swIfIndex, writeContext.getMappingContext())) {
133             LOG.debug("Removing disability of vxlan tunnel, id: {}, name: {}", reply.swIfIndex, swIfName);
134             interfaceDisableContext.removeDisabledInterface(reply.swIfIndex, writeContext.getMappingContext());
135         }
136
137         // Add new interface to our interface context
138         interfaceNamingContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext());
139     }
140
141     private boolean isIpv6(final VxlanGpe vxlanGpe) {
142         if (vxlanGpe.getLocal().getIpv4Address() == null) {
143             checkArgument(vxlanGpe.getRemote().getIpv4Address() == null, "Inconsistent ip addresses: %s, %s",
144                     vxlanGpe.getLocal(),
145                     vxlanGpe.getRemote());
146             return true;
147         } else {
148             checkArgument(vxlanGpe.getRemote().getIpv6Address() == null, "Inconsistent ip addresses: %s, %s",
149                     vxlanGpe.getLocal(),
150                     vxlanGpe.getRemote());
151             return false;
152         }
153     }
154
155     private String getAddressString(final IpAddress addr) {
156         return addr.getIpv4Address() == null
157                 ? addr.getIpv6Address().getValue()
158                 : addr.getIpv4Address().getValue();
159     }
160
161     private void deleteVxlanGpeTunnel(final InstanceIdentifier<VxlanGpe> id, final String swIfName,
162                                       final VxlanGpe vxlanGpe, final WriteContext writeContext)
163             throws VppBaseCallException, WriteTimeoutException {
164         final byte isIpv6 = (byte) (isIpv6(vxlanGpe)
165                 ? 1
166                 : 0);
167         final InetAddress local = InetAddresses.forString(getAddressString(vxlanGpe.getLocal()));
168         final InetAddress remote = InetAddresses.forString(getAddressString(vxlanGpe.getRemote()));
169
170         int vni = vxlanGpe.getVni().getValue().intValue();
171         byte protocol = (byte) vxlanGpe.getNextProtocol().getIntValue();
172         int encapVrfId = vxlanGpe.getEncapVrfId().intValue();
173         int decapVrfId = vxlanGpe.getDecapVrfId().intValue();
174
175         LOG.debug("Deleting VxlanGpe tunnel for interface: {}. VxlanGpe: {}", swIfName, vxlanGpe);
176         final CompletionStage<VxlanGpeAddDelTunnelReply> VxlanGpeAddDelTunnelReplyCompletionStage =
177                 getFutureJVpp()
178                         .vxlanGpeAddDelTunnel(getVxlanGpeTunnelRequest((byte) 0 /* is delete */, local.getAddress(),
179                                 remote.getAddress(), vni, protocol, encapVrfId, decapVrfId, isIpv6));
180
181         getReplyForWrite(VxlanGpeAddDelTunnelReplyCompletionStage.toCompletableFuture(), id);
182
183         final int index = interfaceNamingContext.getIndex(swIfName, writeContext.getMappingContext());
184         // Mark this interface as disabled to not include it in operational reads
185         // because VPP will keep the interface there
186         LOG.debug("Marking vxlan tunnel as disabled, id: {}, name: {}", index, swIfName);
187         interfaceDisableContext.disableInterface(index, writeContext.getMappingContext());
188         // Remove interface from our interface naming context
189         interfaceNamingContext.removeName(swIfName, writeContext.getMappingContext());
190     }
191
192     private static VxlanGpeAddDelTunnel getVxlanGpeTunnelRequest(final byte isAdd, final byte[] local,
193                                                                  final byte[] remote,
194                                                                  final int vni, final byte protocol,
195                                                                  final int encapVrfId, final int decapVrfId,
196                                                                  final byte isIpv6) {
197         final VxlanGpeAddDelTunnel VxlanGpeAddDelTunnel = new VxlanGpeAddDelTunnel();
198         VxlanGpeAddDelTunnel.isAdd = isAdd;
199         VxlanGpeAddDelTunnel.local = local;
200         VxlanGpeAddDelTunnel.remote = remote;
201         VxlanGpeAddDelTunnel.vni = vni;
202         VxlanGpeAddDelTunnel.protocol = protocol;
203         VxlanGpeAddDelTunnel.encapVrfId = encapVrfId;
204         VxlanGpeAddDelTunnel.decapVrfId = decapVrfId;
205         VxlanGpeAddDelTunnel.isIpv6 = isIpv6;
206         return VxlanGpeAddDelTunnel;
207     }
208 }