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