Remove redundant names in paths
[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
9 package org.opendaylight.netvirt.fibmanager.api;
10
11 import static java.util.Comparator.comparing;
12 import static java.util.stream.Collectors.toList;
13
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;
37
38 public final class FibHelper {
39
40     private FibHelper() { }
41
42     public static RoutePaths buildRoutePath(String nextHop, Long label) {
43         RoutePathsBuilder builder = new RoutePathsBuilder()
44                 .setKey(new RoutePathsKey(nextHop))
45                 .setNexthopAddress(nextHop);
46         if (label != null) {
47             builder.setLabel(label);
48         }
49         return builder.build();
50     }
51
52     public static VrfEntryBuilder getVrfEntryBuilder(String prefix, RouteOrigin origin, String parentVpnRd) {
53         return new VrfEntryBuilder().setKey(new VrfEntryKey(prefix)).setDestPrefix(prefix)
54                 .setOrigin(origin.getValue()).setParentVpnRd(parentVpnRd);
55     }
56
57     public static VrfEntryBuilder getVrfEntryBuilder(String prefix, List<RoutePaths> routePaths,
58             RouteOrigin origin, String parentVpnRd) {
59         return new VrfEntryBuilder().setKey(new VrfEntryKey(prefix)).setDestPrefix(prefix)
60                 .setRoutePaths(routePaths).setOrigin(origin.getValue()).setParentVpnRd(parentVpnRd);
61     }
62
63     public static VrfEntryBuilder getVrfEntryBuilder(String prefix, long label, String nextHop, RouteOrigin origin,
64             String parentVpnRd) {
65         if (nextHop != null) {
66             RoutePaths routePath = buildRoutePath(nextHop, label);
67             return getVrfEntryBuilder(prefix, Arrays.asList(routePath), origin, parentVpnRd);
68         } else {
69             return getVrfEntryBuilder(prefix, origin, parentVpnRd);
70         }
71     }
72
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))
77                         .collect(toList());
78         return getVrfEntryBuilder(vrfEntry.getDestPrefix(), routePaths, origin, parentvpnRd);
79     }
80
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();
88     }
89
90     public static boolean isControllerManagedRoute(RouteOrigin routeOrigin) {
91         return routeOrigin == RouteOrigin.STATIC
92                 || routeOrigin == RouteOrigin.CONNECTED
93                 || routeOrigin == RouteOrigin.LOCAL
94                 || routeOrigin == RouteOrigin.INTERVPN;
95     }
96
97     public static boolean isControllerManagedNonInterVpnLinkRoute(RouteOrigin routeOrigin) {
98         return routeOrigin == RouteOrigin.STATIC
99                 || routeOrigin == RouteOrigin.CONNECTED
100                 || routeOrigin == RouteOrigin.LOCAL;
101     }
102
103     public static boolean isControllerManagedVpnInterfaceRoute(RouteOrigin routeOrigin) {
104         return routeOrigin == RouteOrigin.STATIC
105                 || routeOrigin == RouteOrigin.LOCAL;
106     }
107
108     public static boolean isControllerManagedNonSelfImportedRoute(RouteOrigin routeOrigin) {
109         return routeOrigin != RouteOrigin.SELF_IMPORTED;
110     }
111
112     public static void sortIpAddress(List<RoutePaths> routePathList) {
113         if (routePathList != null) {
114             routePathList.sort(comparing(RoutePaths::getNexthopAddress));
115         }
116     }
117
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();
122     }
123
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<>();
128         }
129         return routePaths.stream()
130                 .map(RoutePaths::getNexthopAddress)
131                 .collect(Collectors.toList());
132     }
133
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);
139     }
140
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);
147         }
148     }
149
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.
153      */
154     public static boolean isIpv4Prefix(String prefix) {
155         boolean rep = false;
156         if (prefix == null || prefix.length() < 7) {
157             return rep;
158         }
159         try {
160             String ip = getIpFromPrefix(prefix);
161             java.net.Inet4Address.getByName(ip);
162             rep = true;
163         } catch (SecurityException | UnknownHostException | ClassCastException e) {
164             rep = false;
165             return rep;
166         }
167         return rep;
168     }
169
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.
173      */
174     public static boolean isIpv6Prefix(String prefix) {
175         boolean rep = false;
176         if (prefix == null || prefix.length() < 2) {
177             return rep;
178         }
179         try {
180             String ip = getIpFromPrefix(prefix);
181             java.net.Inet6Address.getByName(ip);
182             rep = true;
183         } catch (SecurityException | UnknownHostException | ClassCastException e) {
184             rep = false;
185             return rep;
186         }
187         return rep;
188     }
189
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
193      */
194     public static String getIpFromPrefix(String prefix) {
195         if (prefix == null || prefix.length() < 2) {
196             return null;
197         }
198         String rep = prefix;
199         String[] prefixValues = prefix.split("/");
200         if (prefixValues.length > 0) {
201             rep = prefixValues[0];
202         }
203         return rep;
204     }
205
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
210      */
211     public static boolean isBelongingPrefix(String prefixToTest, String subnet) {
212         return doesPrefixBelongToSubnet(prefixToTest, subnet, true);
213     }
214
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
220      */
221     public static boolean doesPrefixBelongToSubnet(String prefixToTest, String subnet, boolean exactMatch) {
222         boolean rep = false;
223         if (prefixToTest == null || prefixToTest.length() < 7 || subnet == null || subnet.length() < 7) {
224             return rep;
225         }
226         if (isIpv4Prefix(prefixToTest) && isIpv4Prefix(subnet)
227                 || isIpv6Prefix(prefixToTest) && isIpv6Prefix(subnet)) {
228
229             int ipVersion = 4;
230             if (isIpv6Prefix(prefixToTest)) {
231                 ipVersion = 6;
232             }
233
234             String ipPref = getIpFromPrefix(prefixToTest);
235             String ipSub = getIpFromPrefix(subnet);
236             String maskSubString = subnet.substring(subnet.indexOf("/") + 1);
237             String maskPrefString = null;
238             if (prefixToTest.indexOf("/") > -1) {
239                 maskPrefString = prefixToTest.substring(prefixToTest.indexOf("/") + 1);
240             } else if (ipVersion == 4) {
241                 maskPrefString = "32";
242             } else {
243                 maskPrefString = "128";
244             }
245
246             int maskPref = -1;
247             int maskSub = -1;
248             try {
249                 maskPref = Integer.parseInt(maskPrefString);
250                 maskSub = Integer.parseInt(maskSubString);
251                 if (exactMatch && maskPref != maskSub) {
252                  /*because the mask must be exactly the same between them, the return type is false. This behavior could
253                   * be changed to ignored it in including a boolean options to force or not the same mask control*/
254                     rep = false;
255                     return rep;
256                 }
257                 BigInteger maskSubBig = getMaskNetwork(ipVersion, maskSub);
258                 byte[] byteIpSub = InetAddress.getByName(ipSub).getAddress();
259                 byte[] byteIpPref = InetAddress.getByName(ipPref).getAddress();
260                 BigInteger netFromIpSub = packBigInteger(byteIpSub).and(maskSubBig);
261                 BigInteger netFromIpPref = packBigInteger(byteIpPref).and(maskSubBig);
262                 if (netFromIpSub.compareTo(netFromIpPref) == 0) {
263                     rep = true;
264                 }
265             } catch (NumberFormatException | UnknownHostException e) {
266                 return rep;
267             }
268             return rep;
269         }
270         return rep;
271     }
272
273     /**This method converts a byte[] to a BigInteger value.
274      * @param bytes the byte[] of IP
275      * @return (big) integer value of IP_bytes
276      */
277     public static BigInteger packBigInteger(byte[] bytes) {
278         BigInteger val = BigInteger.valueOf(0);
279         for (byte b : bytes) {
280             val = val.shiftLeft(8);
281             val = val.add(BigInteger.valueOf(b & 0xff));
282         }
283         return val;
284     }
285
286     /**This methode return the bytes representation from an IP.
287      * @param ipBigInteger value integer of IP to convert
288      * @param isIpv4 if is ipv4 setup to true if ipv6 setup to false
289      * @return byte[] which contained the representation of bytes from th ip value
290      */
291     public static byte[] unpackBigInteger(BigInteger ipBigInteger, boolean isIpv4) {
292         int sizeBloc = 4;
293         if (!isIpv4) {
294             sizeBloc = 128 / 8;// if ipv6 size of dataIP is 128 bits
295         }
296         byte[] res = new byte[sizeBloc];
297         for (int i = 0 ; i < sizeBloc ; i++) {
298             BigInteger bigInt = ipBigInteger.shiftRight(i * 8);
299             bigInt = bigInt.and(BigInteger.valueOf(0xFF));
300             res[sizeBloc - 1 - i] = bigInt.byteValue();
301         }
302         return res;
303     }
304
305     /**get the bits cache mask of net for a ip version type.
306      * @param ipVersion version of ip must be 4 or 6
307      * @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
308      * @return the bit mask of net ex: x.x.x.x/24 return a BigInteger == 0xFFFFFFotherwise null if any error
309      */
310     public static BigInteger getMaskNetwork(int ipVersion, int mask) {
311         int lenghBitsIp = 0;
312         if (ipVersion == 6) {
313             lenghBitsIp = 128 - 1;
314         } else if (ipVersion == 4) {
315             lenghBitsIp = 32 - 1;
316         } else {
317             return null;//ip version is unknown
318         }
319         BigInteger bb = BigInteger.ZERO;
320         for (int i = 0 ; i < mask; i++) {
321             bb = bb.setBit(lenghBitsIp - i);
322         }
323         return bb;
324     }
325 }