MRI version bumpup for Aluminium
[netvirt.git] / fibmanager / api / src / main / java / org / opendaylight / netvirt / fibmanager / api / FibHelper.java
1 /*
2  * Copyright (c) 2017 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.netvirt.fibmanager.api;
9
10 import static java.util.Comparator.comparing;
11 import static java.util.stream.Collectors.toList;
12
13 import java.math.BigInteger;
14 import java.net.InetAddress;
15 import java.net.UnknownHostException;
16 import java.util.ArrayList;
17 import java.util.Collections;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Optional;
21 import java.util.concurrent.ExecutionException;
22 import java.util.stream.Collectors;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.opendaylight.mdsal.binding.api.DataBroker;
25 import org.opendaylight.mdsal.binding.api.ReadTransaction;
26 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePaths;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePathsBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePathsKey;
36 import org.opendaylight.yangtools.yang.binding.DataObject;
37 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
39 import org.opendaylight.yangtools.yang.common.Uint32;
40 import org.opendaylight.yangtools.yang.common.Uint64;
41
42 public final class FibHelper {
43     private FibHelper() {
44
45     }
46
47     public static RoutePaths buildRoutePath(String nextHop, Uint32 label) {
48         RoutePathsBuilder builder = new RoutePathsBuilder()
49                 .withKey(new RoutePathsKey(nextHop))
50                 .setNexthopAddress(nextHop);
51         if (label != null) {
52             builder.setLabel(label);
53         }
54         return builder.build();
55     }
56
57     public static VrfEntryBuilder getVrfEntryBuilder(String prefix, RouteOrigin origin, @Nullable String parentVpnRd) {
58         return new VrfEntryBuilder().withKey(new VrfEntryKey(prefix)).setDestPrefix(prefix)
59                 .setOrigin(origin.getValue()).setParentVpnRd(parentVpnRd);
60     }
61
62     public static VrfEntryBuilder getVrfEntryBuilder(String prefix, List<RoutePaths> routePaths,
63             RouteOrigin origin, @Nullable String parentVpnRd) {
64         return new VrfEntryBuilder().withKey(new VrfEntryKey(prefix)).setDestPrefix(prefix)
65                 .setRoutePaths(routePaths).setOrigin(origin.getValue()).setParentVpnRd(parentVpnRd);
66     }
67
68     public static VrfEntryBuilder getVrfEntryBuilder(String prefix, Uint32 label, String nextHop, RouteOrigin origin,
69             @Nullable String parentVpnRd) {
70         if (nextHop != null) {
71             RoutePaths routePath = buildRoutePath(nextHop, label);
72             return getVrfEntryBuilder(prefix, Collections.singletonList(routePath), origin, parentVpnRd);
73         } else {
74             return getVrfEntryBuilder(prefix, origin, parentVpnRd);
75         }
76     }
77
78     public static VrfEntryBuilder getVrfEntryBuilder(VrfEntry vrfEntry, Uint32 label,
79             List<String> nextHopList, RouteOrigin origin, @Nullable String parentvpnRd) {
80         List<RoutePaths> routePaths =
81                 nextHopList.stream().map(nextHop -> buildRoutePath(nextHop, label))
82                         .collect(toList());
83         return getVrfEntryBuilder(vrfEntry.getDestPrefix(), routePaths, origin, parentvpnRd);
84     }
85
86     public static InstanceIdentifier<RoutePaths> buildRoutePathId(String rd, String prefix, String nextHop) {
87         InstanceIdentifierBuilder<RoutePaths> idBuilder =
88                 InstanceIdentifier.builder(FibEntries.class)
89                         .child(VrfTables.class, new VrfTablesKey(rd))
90                         .child(VrfEntry.class, new VrfEntryKey(prefix))
91                         .child(RoutePaths.class, new RoutePathsKey(nextHop));
92         return idBuilder.build();
93     }
94
95     public static boolean isControllerManagedNonInterVpnLinkRoute(RouteOrigin routeOrigin) {
96         return routeOrigin == RouteOrigin.STATIC
97                 || routeOrigin == RouteOrigin.CONNECTED
98                 || routeOrigin == RouteOrigin.LOCAL;
99     }
100
101     public static boolean isControllerManagedVpnInterfaceRoute(RouteOrigin routeOrigin) {
102         return routeOrigin == RouteOrigin.STATIC
103                 || routeOrigin == RouteOrigin.LOCAL;
104     }
105
106     public static boolean isControllerManagedNonSelfImportedRoute(RouteOrigin routeOrigin) {
107         return routeOrigin != RouteOrigin.SELF_IMPORTED;
108     }
109
110     public static void sortIpAddress(List<RoutePaths> routePathList) {
111         if (routePathList != null) {
112             routePathList.sort(comparing(RoutePaths::getNexthopAddress));
113         }
114     }
115
116     public static List<String> getNextHopListFromRoutePaths(final VrfEntry vrfEntry) {
117         Map<RoutePathsKey, RoutePaths> keyRoutePathsMap = vrfEntry.getRoutePaths();
118         if (keyRoutePathsMap == null || keyRoutePathsMap.isEmpty()) {
119             return new ArrayList<>();
120         }
121         return keyRoutePathsMap.values().stream()
122                 .map(RoutePaths::getNexthopAddress)
123                 .collect(Collectors.toList());
124     }
125
126     public static Optional<VrfEntry> getVrfEntry(DataBroker broker, String rd, String ipPrefix) {
127         InstanceIdentifier<VrfEntry> vrfEntryId = InstanceIdentifier.builder(FibEntries.class)
128             .child(VrfTables.class, new VrfTablesKey(rd))
129             .child(VrfEntry.class, new VrfEntryKey(ipPrefix)).build();
130         return read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
131     }
132
133     private static <T extends DataObject> Optional<T> read(DataBroker broker,
134             LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
135         try (ReadTransaction tx = broker.newReadOnlyTransaction()) {
136             return tx.read(datastoreType, path).get();
137         } catch (InterruptedException | ExecutionException e) {
138             throw new RuntimeException(e);
139         }
140     }
141
142     /** get true if this prefix is an IPv4 version, false otherwise.
143      * @param prefix the prefix as (x.x.x.x/nn) to find if it is in IP version 4
144      * @return true if it is an IPv4 or false if it is not.
145      */
146     public static boolean isIpv4Prefix(String prefix) {
147         if (prefix == null || prefix.length() < 7) {
148             return false;
149         }
150         try {
151             String ip = getIpFromPrefix(prefix);
152             java.net.Inet4Address.getByName(ip);
153         } catch (SecurityException | UnknownHostException | ClassCastException e) {
154             return false;
155         }
156         return true;
157     }
158
159     /** get true if this prefix is an IPv6 version, false otherwise.
160      * @param prefix the prefix as ( x:x:x::/nn) to find if it is in IP version 6
161      * @return true if it is an IPv4 or false if it is not.
162      */
163     public static boolean isIpv6Prefix(String prefix) {
164         if (prefix == null || prefix.length() < 2) {
165             return false;
166         }
167         try {
168             String ip = getIpFromPrefix(prefix);
169             java.net.Inet6Address.getByName(ip);
170         } catch (SecurityException | UnknownHostException | ClassCastException e) {
171             return false;
172         }
173         return true;
174     }
175
176     /**get String format IP from prefix as x.x.....x/nn.
177      * @param prefix the prefix as IPv4 or IPv6 as x.....x/nn
178      * @return prefix if "/" is unfindable or the IP only as x.x...x from x.x......x/nn
179      */
180     @Nullable
181     public static String getIpFromPrefix(String prefix) {
182         if (prefix == null || prefix.length() < 2) {
183             return null;
184         }
185         String rep = prefix;
186         String[] prefixValues = prefix.split("/");
187         if (prefixValues.length > 0) {
188             rep = prefixValues[0];
189         }
190         return rep;
191     }
192
193     /**Return true if this prefix or subnet is belonging the specified subnetwork.
194      * @param prefixToTest the prefix which could be in the subnet
195      * @param subnet the subnet that have to contain the prefixToTest to return true
196      * @return true if the param subnet contained the prefixToTest false otherwise
197      */
198     public static boolean isBelongingPrefix(String prefixToTest, String subnet) {
199         return doesPrefixBelongToSubnet(prefixToTest, subnet, true);
200     }
201
202     /**Return true if this prefix or subnet is belonging the specified subnetwork.
203      * @param prefixToTest the prefix which could be in the subnet
204      * @param subnet the subnet that have to contain the prefixToTest to return true
205      * @param exactMatch boolean set to true if exact match is expected
206      * @return true if the param subnet contained the prefixToTest false otherwise
207      */
208     public static boolean doesPrefixBelongToSubnet(String prefixToTest, String subnet, boolean exactMatch) {
209         if (prefixToTest == null || prefixToTest.length() < 7 || subnet == null || subnet.length() < 7) {
210             return false;
211         }
212         if (isIpv4Prefix(prefixToTest) && isIpv4Prefix(subnet)
213                 || isIpv6Prefix(prefixToTest) && isIpv6Prefix(subnet)) {
214
215             int ipVersion = 4;
216             if (isIpv6Prefix(prefixToTest)) {
217                 ipVersion = 6;
218             }
219
220             String ipPref = getIpFromPrefix(prefixToTest);
221             String ipSub = getIpFromPrefix(subnet);
222             String maskSubString = subnet.substring(subnet.indexOf("/") + 1);
223             String maskPrefString;
224             if (prefixToTest.contains("/")) {
225                 maskPrefString = prefixToTest.substring(prefixToTest.indexOf("/") + 1);
226             } else if (ipVersion == 4) {
227                 maskPrefString = "32";
228             } else {
229                 maskPrefString = "128";
230             }
231
232             try {
233                 int maskPref = Integer.parseInt(maskPrefString);
234                 int maskSub = Integer.parseInt(maskSubString);
235                 if (exactMatch && maskPref != maskSub) {
236                  /*because the mask must be exactly the same between them, the return type is false. This behavior could
237                   * be changed to ignored it in including a boolean options to force or not the same mask control*/
238                     return false;
239                 }
240                 BigInteger maskSubBig = getMaskNetwork(ipVersion, maskSub);
241                 byte[] byteIpSub = InetAddress.getByName(ipSub).getAddress();
242                 byte[] byteIpPref = InetAddress.getByName(ipPref).getAddress();
243                 BigInteger netFromIpSub = packBigInteger(byteIpSub).and(maskSubBig);
244                 BigInteger netFromIpPref = packBigInteger(byteIpPref).and(maskSubBig);
245                 return netFromIpSub.compareTo(netFromIpPref) == 0;
246             } catch (NumberFormatException | UnknownHostException e) {
247                 return false;
248             }
249         }
250         return false;
251     }
252
253     /**This method converts a byte[] to a BigInteger value.
254      * @param bytes the byte[] of IP
255      * @return (big) integer value of IP_bytes
256      */
257     public static BigInteger packBigInteger(byte[] bytes) {
258         BigInteger val = BigInteger.valueOf(0);
259         for (byte b : bytes) {
260             val = val.shiftLeft(8);
261             val = val.add(BigInteger.valueOf(b & 0xff));
262         }
263         return val;
264     }
265
266     /**get the bits cache mask of net for a ip version type.
267      * @param ipVersion version of ip must be 4 or 6
268      * @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
269      * @return the bit mask of net ex: x.x.x.x/24 return a BigInteger == 0xFFFFFFotherwise null if any error
270      */
271     @Nullable
272     public static BigInteger getMaskNetwork(int ipVersion, int mask) {
273         int lenghBitsIp = 0;
274         if (ipVersion == 6) {
275             lenghBitsIp = 128 - 1;
276         } else if (ipVersion == 4) {
277             lenghBitsIp = 32 - 1;
278         } else {
279             return null;//ip version is unknown
280         }
281         BigInteger bb = BigInteger.ZERO;
282         for (int i = 0 ; i < mask; i++) {
283             bb = bb.setBit(lenghBitsIp - i);
284         }
285         return bb;
286     }
287
288     public static String getJobKeyForDcGwLoadBalancingGroup(Uint64 dpnId) {
289         return new StringBuilder().append("NextHopManager").append(dpnId).toString();
290     }
291 }