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.interfacesstate;
19 import static com.google.common.base.Preconditions.checkArgument;
20 import static java.util.Objects.requireNonNull;
22 import io.fd.honeycomb.translate.ModificationCache;
23 import io.fd.honeycomb.translate.read.ReadFailedException;
24 import io.fd.honeycomb.translate.util.RWUtils;
25 import io.fd.honeycomb.translate.v3po.util.ByteDataTranslator;
26 import io.fd.honeycomb.translate.v3po.util.JvppReplyConsumer;
27 import java.math.BigInteger;
29 import java.util.Objects;
30 import java.util.concurrent.CompletionStage;
31 import java.util.stream.Collector;
32 import java.util.stream.Collectors;
33 import javax.annotation.Nonnull;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.EthernetCsmacd;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfaceType;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Gauge64;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.GreTunnel;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Tap;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUser;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeTunnel;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel;
43 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
44 import org.openvpp.jvpp.VppBaseCallException;
45 import org.openvpp.jvpp.core.dto.SwInterfaceDetails;
46 import org.openvpp.jvpp.core.dto.SwInterfaceDetailsReplyDump;
47 import org.openvpp.jvpp.core.dto.SwInterfaceDump;
48 import org.openvpp.jvpp.core.future.FutureJVppCore;
49 import org.slf4j.Logger;
51 public interface InterfaceDataTranslator extends ByteDataTranslator, JvppReplyConsumer {
53 Gauge64 vppLinkSpeed0 = new Gauge64(BigInteger.ZERO);
54 Gauge64 vppLinkSpeed1 = new Gauge64(BigInteger.valueOf(10L * 1000000));
55 Gauge64 vppLinkSpeed2 = new Gauge64(BigInteger.valueOf(100L * 1000000));
56 Gauge64 vppLinkSpeed4 = new Gauge64(BigInteger.valueOf(1000L * 1000000));
57 Gauge64 vppLinkSpeed8 = new Gauge64(BigInteger.valueOf(10000L * 1000000));
58 Gauge64 vppLinkSpeed16 = new Gauge64(BigInteger.valueOf(40000L * 1000000));
59 Gauge64 vppLinkSpeed32 = new Gauge64(BigInteger.valueOf(100000L * 1000000));
61 char[] HEX_CHARS = "0123456789abcdef".toCharArray();
63 int PHYSICAL_ADDRESS_LENGTH = 6;
65 Collector<SwInterfaceDetails, ?, SwInterfaceDetails> SINGLE_ITEM_COLLECTOR =
66 RWUtils.singleItemCollector();
69 * Convert VPP's link speed bitmask to Yang type. 1 = 10M, 2 = 100M, 4 = 1G, 8 = 10G, 16 = 40G, 32 = 100G
71 * @param vppLinkSpeed Link speed in bitmask format from VPP.
72 * @return Converted value from VPP link speed
74 default Gauge64 vppInterfaceSpeedToYang(byte vppLinkSpeed) {
75 switch (vppLinkSpeed) {
85 return vppLinkSpeed16;
87 return vppLinkSpeed32;
93 default void appendHexByte(final StringBuilder sb, final byte b) {
94 final int v = b & 0xFF;
95 sb.append(HEX_CHARS[v >>> 4]);
96 sb.append(HEX_CHARS[v & 15]);
100 * Reads first 6 bytes of supplied byte array and converts to string as Yang dictates <p> Replace later with
101 * https://git.opendaylight.org/gerrit/#/c/34869/10/model/ietf/ietf-type- util/src/main/
102 * java/org/opendaylight/mdsal/model/ietf/util/AbstractIetfYangUtil.java
104 * @param vppPhysAddress byte array of bytes in big endian order, constructing the network IF physical address.
105 * @return String like "aa:bb:cc:dd:ee:ff"
106 * @throws NullPointerException if vppPhysAddress is null
107 * @throws IllegalArgumentException if vppPhysAddress.length < 6
109 default String vppPhysAddrToYang(@Nonnull final byte[] vppPhysAddress) {
110 return vppPhysAddrToYang(vppPhysAddress, 0);
113 default String vppPhysAddrToYang(@Nonnull final byte[] vppPhysAddress, final int startIndex) {
114 Objects.requireNonNull(vppPhysAddress, "Empty physical address bytes");
115 final int endIndex = startIndex + PHYSICAL_ADDRESS_LENGTH;
116 checkArgument(endIndex <= vppPhysAddress.length,
117 "Invalid physical address size (%s) for given startIndex (%s), expected >= %s", vppPhysAddress.length,
118 startIndex, endIndex);
119 return printHexBinary(vppPhysAddress, startIndex, endIndex);
122 default String printHexBinary(@Nonnull final byte[] bytes) {
123 Objects.requireNonNull(bytes, "bytes array should not be null");
124 return printHexBinary(bytes, 0, bytes.length);
127 default String printHexBinary(@Nonnull final byte[] bytes, final int startIndex, final int endIndex) {
128 StringBuilder str = new StringBuilder();
130 appendHexByte(str, bytes[startIndex]);
131 for (int i = startIndex + 1; i < endIndex; i++) {
133 appendHexByte(str, bytes[i]);
136 return str.toString();
140 * VPP's interface index is counted from 0, whereas ietf-interface's if-index is from 1. This function converts from
141 * VPP's interface index to YANG's interface index.
143 * @param vppIfIndex the sw interface index VPP reported.
144 * @return VPP's interface index incremented by one
146 default int vppIfIndexToYang(int vppIfIndex) {
147 return vppIfIndex + 1;
151 * This function does the opposite of what {@link #vppIfIndexToYang(int)} does.
153 * @param yangIfIndex if-index from ietf-interfaces.
154 * @return VPP's representation of the if-index
156 default int yangIfIndexToVpp(int yangIfIndex) {
157 checkArgument(yangIfIndex >= 1, "YANG if-index has invalid value %s", yangIfIndex);
158 return yangIfIndex - 1;
163 * Queries VPP for interface description given interface key.
165 * @param futureJVppCore VPP Java Future API
166 * @param id InstanceIdentifier, which is passed in ReadFailedException
167 * @param name interface name
168 * @param index VPP index of the interface
169 * @param ctx per-tx scope context containing cached dump with all the interfaces. If the cache is not
170 * available or outdated, another dump will be performed.
171 * @return SwInterfaceDetails DTO or null if interface was not found
172 * @throws IllegalArgumentException If interface cannot be found
173 * @throws ReadFailedException If read operation had failed
176 default SwInterfaceDetails getVppInterfaceDetails(@Nonnull final FutureJVppCore futureJVppCore,
177 @Nonnull final InstanceIdentifier<?> id,
178 @Nonnull final String name, final int index,
179 @Nonnull final ModificationCache ctx,
180 @Nonnull final Logger callerLogger)
181 throws ReadFailedException {
182 requireNonNull(futureJVppCore, "futureJVppCore should not be null");
183 requireNonNull(name, "name should not be null");
184 requireNonNull(ctx, "ctx should not be null");
186 final SwInterfaceDump request = new SwInterfaceDump();
187 request.nameFilter = name.getBytes();
188 request.nameFilterValid = 1;
190 final Map<Integer, SwInterfaceDetails> allInterfaces = InterfaceCustomizer.getCachedInterfaceDump(ctx);
192 // Returned cached if available
193 if (allInterfaces.containsKey(index)) {
194 return allInterfaces.get(index);
197 SwInterfaceDetailsReplyDump ifaces;
199 CompletionStage<SwInterfaceDetailsReplyDump> requestFuture = futureJVppCore.swInterfaceDump(request);
200 ifaces = getReplyForRead(requestFuture.toCompletableFuture(), id);
201 if (null == ifaces || null == ifaces.swInterfaceDetails || ifaces.swInterfaceDetails.isEmpty()) {
202 request.nameFilterValid = 0;
204 callerLogger.warn("VPP returned null instead of interface by key {} and its not cached", name);
205 callerLogger.warn("Iterating through all the interfaces to find interface: {}", name);
207 // Or else just perform full dump and do inefficient filtering
208 requestFuture = futureJVppCore.swInterfaceDump(request);
209 ifaces = getReplyForRead(requestFuture.toCompletableFuture(), id);
212 allInterfaces.clear();
214 .putAll(ifaces.swInterfaceDetails.stream().collect(Collectors.toMap(d -> d.swIfIndex, d -> d)));
216 if (allInterfaces.containsKey(index)) {
217 return allInterfaces.get(index);
219 throw new IllegalArgumentException("Unable to find interface " + name);
221 } catch (VppBaseCallException e) {
222 callerLogger.warn("getVppInterfaceDetails for id :{} and name :{} failed with exception :", id, name, e);
223 throw new ReadFailedException(id, e);
226 // SwInterfaceDump's name filter does prefix match, so we need additional filtering:
227 final SwInterfaceDetails iface =
228 ifaces.swInterfaceDetails.stream().filter(d -> d.swIfIndex == index).collect(SINGLE_ITEM_COLLECTOR);
229 allInterfaces.put(index, iface); // update the cache
234 * Determine interface type based on its VPP name (relying on VPP's interface naming conventions)
236 * @param interfaceName VPP generated interface name
237 * @return Interface type
240 default Class<? extends InterfaceType> getInterfaceType(@Nonnull final String interfaceName) {
241 if (interfaceName.startsWith("tap")) {
245 if (interfaceName.startsWith("vxlan_gpe")) {
246 return VxlanGpeTunnel.class;
249 if (interfaceName.startsWith("vxlan")) {
250 return VxlanTunnel.class;
253 if (interfaceName.startsWith("gre")) {
254 return GreTunnel.class;
257 if (interfaceName.startsWith("VirtualEthernet")) {
258 return VhostUser.class;
261 return EthernetCsmacd.class;
265 * Check interface type. Uses interface details from VPP to determine. Uses {@link
266 * #getVppInterfaceDetails(FutureJVppCore, InstanceIdentifier, String, int, ModificationCache, Logger)} internally so
267 * tries to utilize cache before asking VPP.
269 default boolean isInterfaceOfType(@Nonnull final FutureJVppCore jvpp,
270 @Nonnull final ModificationCache cache,
271 @Nonnull final InstanceIdentifier<?> id,
273 @Nonnull final Class<? extends InterfaceType> ifcType,
274 @Nonnull final Logger callerLogger)
275 throws ReadFailedException {
276 final String name = id.firstKeyOf(Interface.class).getName();
277 final SwInterfaceDetails vppInterfaceDetails =
278 getVppInterfaceDetails(jvpp, id, name, index, cache, callerLogger);
280 return isInterfaceOfType(ifcType, vppInterfaceDetails);
283 default boolean isInterfaceOfType(final Class<? extends InterfaceType> ifcType,
284 final SwInterfaceDetails cachedDetails) {
285 return ifcType.equals(getInterfaceType(toString(cachedDetails.interfaceName)));