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.translate.v3po.interfaces;
19 import static com.google.common.base.Preconditions.checkArgument;
21 import com.google.common.net.InetAddresses;
22 import io.fd.honeycomb.translate.v3po.DisabledInterfacesManager;
23 import io.fd.honeycomb.translate.v3po.util.AbstractInterfaceTypeCustomizer;
24 import io.fd.honeycomb.translate.v3po.util.NamingContext;
25 import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
26 import io.fd.honeycomb.translate.write.WriteContext;
27 import io.fd.honeycomb.translate.write.WriteFailedException;
28 import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
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 org.openvpp.jvpp.VppBaseCallException;
39 import org.openvpp.jvpp.core.dto.VxlanGpeAddDelTunnel;
40 import org.openvpp.jvpp.core.dto.VxlanGpeAddDelTunnelReply;
41 import org.openvpp.jvpp.core.future.FutureJVppCore;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
45 public class VxlanGpeCustomizer extends AbstractInterfaceTypeCustomizer<VxlanGpe> {
47 private static final Logger LOG = LoggerFactory.getLogger(VxlanGpeCustomizer.class);
48 private final NamingContext interfaceNamingContext;
49 private final DisabledInterfacesManager interfaceDisableContext;
51 public VxlanGpeCustomizer(@Nonnull final FutureJVppCore vppApi,
52 @Nonnull final NamingContext interfaceNamingContext,
53 @Nonnull final DisabledInterfacesManager interfaceDisableContext) {
55 this.interfaceNamingContext = interfaceNamingContext;
56 this.interfaceDisableContext = interfaceDisableContext;
60 protected Class<? extends InterfaceType> getExpectedInterfaceType() {
61 return VxlanGpeTunnel.class;
65 protected final void writeInterface(@Nonnull final InstanceIdentifier<VxlanGpe> id, @Nonnull final VxlanGpe dataAfter,
66 @Nonnull final WriteContext writeContext)
67 throws WriteFailedException {
68 final String swIfName = id.firstKeyOf(Interface.class).getName();
70 createVxlanGpeTunnel(id, swIfName, dataAfter, writeContext);
71 } catch (VppBaseCallException | IllegalInterfaceTypeException e) {
72 LOG.warn("Failed to set VxlanGpe tunnel for interface: {}, VxlanGpe: {}", swIfName, dataAfter);
73 throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
78 public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<VxlanGpe> id, @Nonnull final VxlanGpe dataBefore,
79 @Nonnull final VxlanGpe dataAfter, @Nonnull final WriteContext writeContext)
80 throws WriteFailedException.UpdateFailedException {
81 throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter,
82 new UnsupportedOperationException("VxlanGpe tunnel update is not supported"));
86 public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<VxlanGpe> id, @Nonnull final VxlanGpe dataBefore,
87 @Nonnull final WriteContext writeContext)
88 throws WriteFailedException {
89 final String swIfName = id.firstKeyOf(Interface.class).getName();
91 deleteVxlanGpeTunnel(id, swIfName, dataBefore, writeContext);
92 } catch (VppBaseCallException e) {
93 LOG.warn("Failed to delete VxlanGpe tunnel for interface: {}, VxlanGpe: {}", swIfName, dataBefore);
94 throw new WriteFailedException.DeleteFailedException(id, e);
98 private void createVxlanGpeTunnel(final InstanceIdentifier<VxlanGpe> id, final String swIfName,
99 final VxlanGpe vxlanGpe, final WriteContext writeContext)
100 throws VppBaseCallException, WriteTimeoutException {
101 final byte isIpv6 = (byte) (isIpv6(vxlanGpe) ? 1 : 0);
102 final InetAddress Local = InetAddresses.forString(getAddressString(vxlanGpe.getLocal()));
103 final InetAddress Remote = InetAddresses.forString(getAddressString(vxlanGpe.getRemote()));
105 int vni = vxlanGpe.getVni().getValue().intValue();
106 byte protocol = (byte) vxlanGpe.getNextProtocol().getIntValue();
107 int encapVrfId = vxlanGpe.getEncapVrfId().intValue();
108 int decapVrfId = vxlanGpe.getDecapVrfId().intValue();
110 LOG.debug("Setting VxlanGpe tunnel for interface: {}. VxlanGpe: {}", swIfName, vxlanGpe);
111 final CompletionStage<VxlanGpeAddDelTunnelReply> VxlanGpeAddDelTunnelReplyCompletionStage =
112 getFutureJVpp().vxlanGpeAddDelTunnel(getVxlanGpeTunnelRequest((byte) 1 /* is add */, Local.getAddress(),
113 Remote.getAddress(), vni, protocol, encapVrfId, decapVrfId, isIpv6));
115 final VxlanGpeAddDelTunnelReply reply =
116 TranslateUtils.getReplyForWrite(VxlanGpeAddDelTunnelReplyCompletionStage.toCompletableFuture(), id);
117 LOG.debug("VxlanGpe tunnel set successfully for: {}, VxlanGpe: {}", swIfName, vxlanGpe);
118 if (interfaceNamingContext.containsName(reply.swIfIndex, writeContext.getMappingContext())) {
119 final String formerName = interfaceNamingContext.getName(reply.swIfIndex, writeContext.getMappingContext());
120 LOG.debug("Removing updated mapping of a vxlan-gpe tunnel, id: {}, former name: {}, new name: {}",
121 reply.swIfIndex, formerName, swIfName);
122 interfaceNamingContext.removeName(formerName, writeContext.getMappingContext());
125 // Removing disability of an interface in case a vxlan-gpe tunnel formerly deleted is being reused in VPP
126 // further details in above comment
127 if (interfaceDisableContext.isInterfaceDisabled(reply.swIfIndex, writeContext.getMappingContext())) {
128 LOG.debug("Removing disability of vxlan tunnel, id: {}, name: {}", reply.swIfIndex, swIfName);
129 interfaceDisableContext.removeDisabledInterface(reply.swIfIndex, writeContext.getMappingContext());
132 // Add new interface to our interface context
133 interfaceNamingContext.addName(reply.swIfIndex, swIfName, writeContext.getMappingContext());
136 private boolean isIpv6(final VxlanGpe vxlanGpe) {
137 if (vxlanGpe.getLocal().getIpv4Address() == null) {
138 checkArgument(vxlanGpe.getRemote().getIpv4Address() == null, "Inconsistent ip addresses: %s, %s", vxlanGpe.getLocal(),
139 vxlanGpe.getRemote());
142 checkArgument(vxlanGpe.getRemote().getIpv6Address() == null, "Inconsistent ip addresses: %s, %s", vxlanGpe.getLocal(),
143 vxlanGpe.getRemote());
148 private String getAddressString(final IpAddress addr) {
149 return addr.getIpv4Address() == null ? addr.getIpv6Address().getValue() : addr.getIpv4Address().getValue();
152 private void deleteVxlanGpeTunnel(final InstanceIdentifier<VxlanGpe> id, final String swIfName,
153 final VxlanGpe vxlanGpe, final WriteContext writeContext)
154 throws VppBaseCallException, WriteTimeoutException {
155 final byte isIpv6 = (byte) (isIpv6(vxlanGpe) ? 1 : 0);
156 final InetAddress local = InetAddresses.forString(getAddressString(vxlanGpe.getLocal()));
157 final InetAddress remote = InetAddresses.forString(getAddressString(vxlanGpe.getRemote()));
159 int vni = vxlanGpe.getVni().getValue().intValue();
160 byte protocol = (byte) vxlanGpe.getNextProtocol().getIntValue();
161 int encapVrfId = vxlanGpe.getEncapVrfId().intValue();
162 int decapVrfId = vxlanGpe.getDecapVrfId().intValue();
164 LOG.debug("Deleting VxlanGpe tunnel for interface: {}. VxlanGpe: {}", swIfName, vxlanGpe);
165 final CompletionStage<VxlanGpeAddDelTunnelReply> VxlanGpeAddDelTunnelReplyCompletionStage =
166 getFutureJVpp().vxlanGpeAddDelTunnel(getVxlanGpeTunnelRequest((byte) 0 /* is delete */, local.getAddress(),
167 remote.getAddress(), vni, protocol, encapVrfId, decapVrfId, isIpv6));
169 TranslateUtils.getReplyForWrite(VxlanGpeAddDelTunnelReplyCompletionStage.toCompletableFuture(), id);
171 final int index = interfaceNamingContext.getIndex(swIfName, writeContext.getMappingContext());
172 // Mark this interface as disabled to not include it in operational reads
173 // because VPP will keep the interface there
174 LOG.debug("Marking vxlan tunnel as disabled, id: {}, name: {}", index, swIfName);
175 interfaceDisableContext.disableInterface(index, writeContext.getMappingContext());
176 // Remove interface from our interface naming context
177 interfaceNamingContext.removeName(swIfName, writeContext.getMappingContext());
180 private static VxlanGpeAddDelTunnel getVxlanGpeTunnelRequest(final byte isAdd, final byte[] local, final byte[] remote,
181 final int vni, final byte protocol, final int encapVrfId, final int decapVrfId,
183 final VxlanGpeAddDelTunnel VxlanGpeAddDelTunnel = new VxlanGpeAddDelTunnel();
184 VxlanGpeAddDelTunnel.isAdd = isAdd;
185 VxlanGpeAddDelTunnel.local = local;
186 VxlanGpeAddDelTunnel.remote = remote;
187 VxlanGpeAddDelTunnel.vni = vni;
188 VxlanGpeAddDelTunnel.protocol = protocol;
189 VxlanGpeAddDelTunnel.encapVrfId = encapVrfId;
190 VxlanGpeAddDelTunnel.decapVrfId = decapVrfId;
191 VxlanGpeAddDelTunnel.isIpv6 = isIpv6;
192 return VxlanGpeAddDelTunnel;