2 * Copyright (c) 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.netvirt.fibmanager.api;
11 import static java.util.Comparator.comparing;
12 import static java.util.stream.Collectors.toList;
14 import java.math.BigInteger;
15 import java.net.InetAddress;
16 import java.net.UnknownHostException;
17 import java.util.ArrayList;
18 import java.util.Arrays;
19 import java.util.List;
20 import java.util.concurrent.ExecutionException;
21 import java.util.stream.Collectors;
22 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
23 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
24 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePaths;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePathsBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePathsKey;
34 import org.opendaylight.yangtools.yang.binding.DataObject;
35 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
36 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
38 public final class FibHelper {
40 private FibHelper() { }
42 public static RoutePaths buildRoutePath(String nextHop, Long label) {
43 RoutePathsBuilder builder = new RoutePathsBuilder()
44 .withKey(new RoutePathsKey(nextHop))
45 .setNexthopAddress(nextHop);
47 builder.setLabel(label);
49 return builder.build();
52 public static VrfEntryBuilder getVrfEntryBuilder(String prefix, RouteOrigin origin, String parentVpnRd) {
53 return new VrfEntryBuilder().withKey(new VrfEntryKey(prefix)).setDestPrefix(prefix)
54 .setOrigin(origin.getValue()).setParentVpnRd(parentVpnRd);
57 public static VrfEntryBuilder getVrfEntryBuilder(String prefix, List<RoutePaths> routePaths,
58 RouteOrigin origin, String parentVpnRd) {
59 return new VrfEntryBuilder().withKey(new VrfEntryKey(prefix)).setDestPrefix(prefix)
60 .setRoutePaths(routePaths).setOrigin(origin.getValue()).setParentVpnRd(parentVpnRd);
63 public static VrfEntryBuilder getVrfEntryBuilder(String prefix, long label, String nextHop, RouteOrigin origin,
65 if (nextHop != null) {
66 RoutePaths routePath = buildRoutePath(nextHop, label);
67 return getVrfEntryBuilder(prefix, Arrays.asList(routePath), origin, parentVpnRd);
69 return getVrfEntryBuilder(prefix, origin, parentVpnRd);
73 public static VrfEntryBuilder getVrfEntryBuilder(VrfEntry vrfEntry, long label,
74 List<String> nextHopList, RouteOrigin origin, String parentvpnRd) {
75 List<RoutePaths> routePaths =
76 nextHopList.stream().map(nextHop -> buildRoutePath(nextHop, label))
78 return getVrfEntryBuilder(vrfEntry.getDestPrefix(), routePaths, origin, parentvpnRd);
81 public static InstanceIdentifier<RoutePaths> buildRoutePathId(String rd, String prefix, String nextHop) {
82 InstanceIdentifierBuilder<RoutePaths> idBuilder =
83 InstanceIdentifier.builder(FibEntries.class)
84 .child(VrfTables.class, new VrfTablesKey(rd))
85 .child(VrfEntry.class, new VrfEntryKey(prefix))
86 .child(RoutePaths.class, new RoutePathsKey(nextHop));
87 return idBuilder.build();
90 public static boolean isControllerManagedRoute(RouteOrigin routeOrigin) {
91 return routeOrigin == RouteOrigin.STATIC
92 || routeOrigin == RouteOrigin.CONNECTED
93 || routeOrigin == RouteOrigin.LOCAL
94 || routeOrigin == RouteOrigin.INTERVPN;
97 public static boolean isControllerManagedNonInterVpnLinkRoute(RouteOrigin routeOrigin) {
98 return routeOrigin == RouteOrigin.STATIC
99 || routeOrigin == RouteOrigin.CONNECTED
100 || routeOrigin == RouteOrigin.LOCAL;
103 public static boolean isControllerManagedVpnInterfaceRoute(RouteOrigin routeOrigin) {
104 return routeOrigin == RouteOrigin.STATIC
105 || routeOrigin == RouteOrigin.LOCAL;
108 public static boolean isControllerManagedNonSelfImportedRoute(RouteOrigin routeOrigin) {
109 return routeOrigin != RouteOrigin.SELF_IMPORTED;
112 public static void sortIpAddress(List<RoutePaths> routePathList) {
113 if (routePathList != null) {
114 routePathList.sort(comparing(RoutePaths::getNexthopAddress));
118 public static InstanceIdentifier<RoutePaths> getRoutePathsIdentifier(String rd, String prefix, String nh) {
119 return InstanceIdentifier.builder(FibEntries.class)
120 .child(VrfTables.class,new VrfTablesKey(rd)).child(VrfEntry.class,new VrfEntryKey(prefix))
121 .child(RoutePaths.class, new RoutePathsKey(nh)).build();
124 public static List<String> getNextHopListFromRoutePaths(final VrfEntry vrfEntry) {
125 List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
126 if (routePaths == null || routePaths.isEmpty()) {
127 return new ArrayList<>();
129 return routePaths.stream()
130 .map(RoutePaths::getNexthopAddress)
131 .collect(Collectors.toList());
134 public static com.google.common.base.Optional<VrfEntry> getVrfEntry(DataBroker broker, String rd, String ipPrefix) {
135 InstanceIdentifier<VrfEntry> vrfEntryId = InstanceIdentifier.builder(FibEntries.class)
136 .child(VrfTables.class, new VrfTablesKey(rd))
137 .child(VrfEntry.class, new VrfEntryKey(ipPrefix)).build();
138 return read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
141 private static <T extends DataObject> com.google.common.base.Optional<T> read(DataBroker broker,
142 LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
143 try (ReadOnlyTransaction tx = broker.newReadOnlyTransaction()) {
144 return tx.read(datastoreType, path).get();
145 } catch (InterruptedException | ExecutionException e) {
146 throw new RuntimeException(e);
150 /** get true if this prefix is an IPv4 version, false otherwise.
151 * @param prefix the prefix as (x.x.x.x/nn) to find if it is in IP version 4
152 * @return true if it is an IPv4 or false if it is not.
154 public static boolean isIpv4Prefix(String prefix) {
156 if (prefix == null || prefix.length() < 7) {
160 String ip = getIpFromPrefix(prefix);
161 java.net.Inet4Address.getByName(ip);
163 } catch (SecurityException | UnknownHostException | ClassCastException e) {
170 /** get true if this prefix is an IPv6 version, false otherwise.
171 * @param prefix the prefix as ( x:x:x::/nn) to find if it is in IP version 6
172 * @return true if it is an IPv4 or false if it is not.
174 public static boolean isIpv6Prefix(String prefix) {
176 if (prefix == null || prefix.length() < 2) {
180 String ip = getIpFromPrefix(prefix);
181 java.net.Inet6Address.getByName(ip);
183 } catch (SecurityException | UnknownHostException | ClassCastException e) {
190 /**get String format IP from prefix as x.x.....x/nn.
191 * @param prefix the prefix as IPv4 or IPv6 as x.....x/nn
192 * @return prefix if "/" is unfindable or the IP only as x.x...x from x.x......x/nn
194 public static String getIpFromPrefix(String prefix) {
195 if (prefix == null || prefix.length() < 2) {
199 String[] prefixValues = prefix.split("/");
200 if (prefixValues.length > 0) {
201 rep = prefixValues[0];
206 /**Return true if this prefix or subnet is belonging the specified subnetwork.
207 * @param prefixToTest the prefix which could be in the subnet
208 * @param subnet the subnet that have to contain the prefixToTest to return true
209 * @return true if the param subnet contained the prefixToTest false otherwise
211 public static boolean isBelongingPrefix(String prefixToTest, String subnet) {
212 return doesPrefixBelongToSubnet(prefixToTest, subnet, true);
215 /**Return true if this prefix or subnet is belonging the specified subnetwork.
216 * @param prefixToTest the prefix which could be in the subnet
217 * @param subnet the subnet that have to contain the prefixToTest to return true
218 * @param exactMatch boolean set to true if exact match is expected
219 * @return true if the param subnet contained the prefixToTest false otherwise
221 public static boolean doesPrefixBelongToSubnet(String prefixToTest, String subnet, boolean exactMatch) {
222 if (prefixToTest == null || prefixToTest.length() < 7 || subnet == null || subnet.length() < 7) {
225 if (isIpv4Prefix(prefixToTest) && isIpv4Prefix(subnet)
226 || isIpv6Prefix(prefixToTest) && isIpv6Prefix(subnet)) {
229 if (isIpv6Prefix(prefixToTest)) {
233 String ipPref = getIpFromPrefix(prefixToTest);
234 String ipSub = getIpFromPrefix(subnet);
235 String maskSubString = subnet.substring(subnet.indexOf("/") + 1);
236 String maskPrefString;
237 if (prefixToTest.contains("/")) {
238 maskPrefString = prefixToTest.substring(prefixToTest.indexOf("/") + 1);
239 } else if (ipVersion == 4) {
240 maskPrefString = "32";
242 maskPrefString = "128";
246 int maskPref = Integer.parseInt(maskPrefString);
247 int maskSub = Integer.parseInt(maskSubString);
248 if (exactMatch && maskPref != maskSub) {
249 /*because the mask must be exactly the same between them, the return type is false. This behavior could
250 * be changed to ignored it in including a boolean options to force or not the same mask control*/
253 BigInteger maskSubBig = getMaskNetwork(ipVersion, maskSub);
254 byte[] byteIpSub = InetAddress.getByName(ipSub).getAddress();
255 byte[] byteIpPref = InetAddress.getByName(ipPref).getAddress();
256 BigInteger netFromIpSub = packBigInteger(byteIpSub).and(maskSubBig);
257 BigInteger netFromIpPref = packBigInteger(byteIpPref).and(maskSubBig);
258 return netFromIpSub.compareTo(netFromIpPref) == 0;
259 } catch (NumberFormatException | UnknownHostException e) {
266 /**This method converts a byte[] to a BigInteger value.
267 * @param bytes the byte[] of IP
268 * @return (big) integer value of IP_bytes
270 public static BigInteger packBigInteger(byte[] bytes) {
271 BigInteger val = BigInteger.valueOf(0);
272 for (byte b : bytes) {
273 val = val.shiftLeft(8);
274 val = val.add(BigInteger.valueOf(b & 0xff));
279 /**This methode return the bytes representation from an IP.
280 * @param ipBigInteger value integer of IP to convert
281 * @param isIpv4 if is ipv4 setup to true if ipv6 setup to false
282 * @return byte[] which contained the representation of bytes from th ip value
284 public static byte[] unpackBigInteger(BigInteger ipBigInteger, boolean isIpv4) {
287 sizeBloc = 128 / 8;// if ipv6 size of dataIP is 128 bits
289 byte[] res = new byte[sizeBloc];
290 for (int i = 0 ; i < sizeBloc ; i++) {
291 BigInteger bigInt = ipBigInteger.shiftRight(i * 8);
292 bigInt = bigInt.and(BigInteger.valueOf(0xFF));
293 res[sizeBloc - 1 - i] = bigInt.byteValue();
298 /**get the bits cache mask of net for a ip version type.
299 * @param ipVersion version of ip must be 4 or 6
300 * @param mask the lengh of the mask of net as 24 from this representation 10.1.1.0/24 or 64 for 2001::1/64
301 * @return the bit mask of net ex: x.x.x.x/24 return a BigInteger == 0xFFFFFFotherwise null if any error
303 public static BigInteger getMaskNetwork(int ipVersion, int mask) {
305 if (ipVersion == 6) {
306 lenghBitsIp = 128 - 1;
307 } else if (ipVersion == 4) {
308 lenghBitsIp = 32 - 1;
310 return null;//ip version is unknown
312 BigInteger bb = BigInteger.ZERO;
313 for (int i = 0 ; i < mask; i++) {
314 bb = bb.setBit(lenghBitsIp - i);