555d48c81afafd365ff50d94091d8c2e42713d3c
[honeycomb.git] / v3po / v3po2vpp / src / main / java / io / fd / honeycomb / translate / v3po / interfacesstate / VxlanCustomizer.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.interfacesstate;
18
19 import static com.google.common.base.Preconditions.checkState;
20
21 import io.fd.honeycomb.translate.read.ReadContext;
22 import io.fd.honeycomb.translate.read.ReadFailedException;
23 import io.fd.honeycomb.translate.spi.read.ReaderCustomizer;
24 import io.fd.honeycomb.translate.vpp.util.FutureJVppCustomizer;
25 import io.fd.honeycomb.translate.vpp.util.JvppReplyConsumer;
26 import io.fd.honeycomb.translate.vpp.util.NamingContext;
27 import io.fd.vpp.jvpp.core.dto.VxlanTunnelDetails;
28 import io.fd.vpp.jvpp.core.dto.VxlanTunnelDetailsReplyDump;
29 import io.fd.vpp.jvpp.core.dto.VxlanTunnelDump;
30 import io.fd.vpp.jvpp.core.future.FutureJVppCore;
31 import java.net.InetAddress;
32 import java.net.UnknownHostException;
33 import java.util.Arrays;
34 import java.util.concurrent.CompletionStage;
35 import javax.annotation.Nonnull;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanVni;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.Vxlan;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.VxlanBuilder;
46 import org.opendaylight.yangtools.concepts.Builder;
47 import org.opendaylight.yangtools.yang.binding.DataObject;
48 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
52 public class VxlanCustomizer extends FutureJVppCustomizer
53         implements ReaderCustomizer<Vxlan, VxlanBuilder>, InterfaceDataTranslator, JvppReplyConsumer {
54
55     private static final Logger LOG = LoggerFactory.getLogger(VxlanCustomizer.class);
56     private final NamingContext interfaceContext;
57
58     public VxlanCustomizer(@Nonnull final FutureJVppCore jvpp, @Nonnull final NamingContext interfaceContext) {
59         super(jvpp);
60         this.interfaceContext = interfaceContext;
61     }
62
63     @Override
64     public void merge(@Nonnull Builder<? extends DataObject> parentBuilder,
65                       @Nonnull Vxlan readValue) {
66         ((VppInterfaceStateAugmentationBuilder) parentBuilder).setVxlan(readValue);
67     }
68
69     @Nonnull
70     @Override
71     public VxlanBuilder getBuilder(@Nonnull InstanceIdentifier<Vxlan> id) {
72         return new VxlanBuilder();
73     }
74
75     @Override
76     public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Vxlan> id,
77                                       @Nonnull final VxlanBuilder builder,
78                                       @Nonnull final ReadContext ctx) throws ReadFailedException {
79
80         final InterfaceKey key = id.firstKeyOf(Interface.class);
81         final int index = interfaceContext.getIndex(key.getName(), ctx.getMappingContext());
82         if (!isInterfaceOfType(getFutureJVpp(), ctx.getModificationCache(), id, index, VxlanTunnel.class, LOG)) {
83             return;
84         }
85
86         LOG.debug("Reading attributes for vxlan tunnel: {}", key.getName());
87         // Dump just a single
88         final VxlanTunnelDump request = new VxlanTunnelDump();
89         request.swIfIndex = index;
90
91         final CompletionStage<VxlanTunnelDetailsReplyDump> swInterfaceVxlanDetailsReplyDumpCompletionStage =
92                 getFutureJVpp().vxlanTunnelDump(request);
93         final VxlanTunnelDetailsReplyDump reply =
94                 getReplyForRead(swInterfaceVxlanDetailsReplyDumpCompletionStage.toCompletableFuture(), id);
95
96         // VPP keeps vxlan tunnel interfaces even after they were deleted (optimization)
97         // However there ar no longer any vxlan tunnel specific fields assigned to it and this call
98         // returns nothing
99         if (reply == null || reply.vxlanTunnelDetails == null || reply.vxlanTunnelDetails.isEmpty()) {
100             LOG.debug(
101                     "Vxlan tunnel {}, id {} has no attributes assigned in VPP. Probably is a leftover interface placeholder" +
102                             "after delete", key.getName(), index);
103             return;
104         }
105
106         checkState(reply.vxlanTunnelDetails.size() == 1,
107                 "Unexpected number of returned vxlan tunnels: {} for tunnel: {}", reply.vxlanTunnelDetails,
108                 key.getName());
109         LOG.trace("Vxlan tunnel: {} attributes returned from VPP: {}", key.getName(), reply);
110
111         final VxlanTunnelDetails swInterfaceVxlanDetails = reply.vxlanTunnelDetails.get(0);
112         if (swInterfaceVxlanDetails.isIpv6 == 1) {
113             final Ipv6Address dstIpv6 =
114                     new Ipv6Address(parseAddress(swInterfaceVxlanDetails.dstAddress).getHostAddress());
115             builder.setDst(new IpAddress(dstIpv6));
116             final Ipv6Address srcIpv6 =
117                     new Ipv6Address(parseAddress(swInterfaceVxlanDetails.srcAddress).getHostAddress());
118             builder.setSrc(new IpAddress(srcIpv6));
119         } else {
120             final byte[] dstBytes = Arrays.copyOfRange(swInterfaceVxlanDetails.dstAddress, 0, 4);
121             final Ipv4Address dstIpv4 = new Ipv4Address(parseAddress(dstBytes).getHostAddress());
122             builder.setDst(new IpAddress(dstIpv4));
123             final byte[] srcBytes = Arrays.copyOfRange(swInterfaceVxlanDetails.srcAddress, 0, 4);
124             final Ipv4Address srcIpv4 = new Ipv4Address(parseAddress(srcBytes).getHostAddress());
125             builder.setSrc(new IpAddress(srcIpv4));
126         }
127         builder.setEncapVrfId((long) swInterfaceVxlanDetails.encapVrfId);
128         builder.setVni(new VxlanVni((long) swInterfaceVxlanDetails.vni));
129         LOG.debug("Vxlan tunnel: {}, id: {} attributes read as: {}", key.getName(), index, builder);
130     }
131
132     @Nonnull
133     private static InetAddress parseAddress(@Nonnull final byte[] addr) {
134         try {
135             return InetAddress.getByAddress(addr);
136         } catch (UnknownHostException e) {
137             throw new IllegalArgumentException("Cannot create InetAddress from " + Arrays.toString(addr), e);
138         }
139     }
140 }