Cleanup
[netvirt.git] / vpnservice / fibmanager / fibmanager-impl / src / main / java / org / opendaylight / netvirt / fibmanager / FibUtil.java
1 /*
2  * Copyright © 2016, 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;
10
11 import static java.util.stream.Collectors.joining;
12 import static java.util.stream.Collectors.toList;
13 import static org.opendaylight.netvirt.fibmanager.VrfEntryListener.isOpenStackVniSemanticsEnforced;
14
15 import com.google.common.base.Optional;
16 import com.google.common.base.Preconditions;
17 import com.google.common.net.InetAddresses;
18
19 import java.math.BigInteger;
20 import java.net.InetAddress;
21 import java.util.ArrayList;
22 import java.util.Collections;
23 import java.util.List;
24 import java.util.concurrent.ExecutionException;
25 import java.util.concurrent.Future;
26
27 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
28 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
29 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
30 import org.opendaylight.genius.mdsalutil.BucketInfo;
31 import org.opendaylight.genius.mdsalutil.MDSALUtil;
32 import org.opendaylight.genius.mdsalutil.NwConstants;
33 import org.opendaylight.netvirt.fibmanager.NexthopManager.AdjacencyResult;
34 import org.opendaylight.netvirt.fibmanager.api.FibHelper;
35 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
36 import org.opendaylight.netvirt.vpnmanager.api.VpnExtraRouteHelper;
37 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.DpnEndpoints;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfo;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfoKey;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.TunnelEndPoints;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.BucketId;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.BucketsBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.RouterInterface;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePaths;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.DpidL3vpnLbNexthops;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.L3vpnLbNexthops;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnIdToVpnInstance;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceToVpnId;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpid.l3vpn.lb.nexthops.DpnLbNexthops;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpid.l3vpn.lb.nexthops.DpnLbNexthopsBuilder;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpid.l3vpn.lb.nexthops.DpnLbNexthopsKey;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.l3vpn.lb.nexthops.Nexthops;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.l3vpn.lb.nexthops.NexthopsBuilder;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.l3vpn.lb.nexthops.NexthopsKey;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIdsKey;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.extra.routes.Routes;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkAttributes;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
97 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
98 import org.opendaylight.yangtools.yang.common.RpcResult;
99 import org.slf4j.Logger;
100 import org.slf4j.LoggerFactory;
101
102 public final class FibUtil {
103     private static final Logger LOG = LoggerFactory.getLogger(FibUtil.class);
104     private static final String FLOWID_PREFIX = "L3.";
105
106     private FibUtil() {
107     }
108
109     static InstanceIdentifier<Adjacency> getAdjacencyIdentifier(String vpnInterfaceName, String ipAddress) {
110         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang
111             .l3vpn.rev140815.VpnInterfaces.class)
112             .child(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
113                 .VpnInterface.class,
114                 new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
115                     .VpnInterfaceKey(vpnInterfaceName))
116             .augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies.class)
117             .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency.class,
118                 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list
119                     .AdjacencyKey(ipAddress)).build();
120     }
121
122     static InstanceIdentifier<Adjacencies> getAdjListPath(String vpnInterfaceName) {
123         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn
124             .rev140815.VpnInterfaces.class)
125             .child(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
126                 .VpnInterface.class,
127                 new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
128                     .VpnInterfaceKey(vpnInterfaceName))
129             .augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies.class)
130             .build();
131     }
132
133     static InstanceIdentifier<Prefixes> getPrefixToInterfaceIdentifier(long vpnId, String ipPrefix) {
134         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn
135             .rev130911.PrefixToInterface.class)
136             .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface
137                 .VpnIds.class,
138                 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface
139                     .VpnIdsKey(vpnId))
140             .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface
141                     .vpn.ids.Prefixes.class,
142                 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to
143                     ._interface.vpn.ids.PrefixesKey(ipPrefix)).build();
144     }
145
146     static InstanceIdentifier<VpnInterface> getVpnInterfaceIdentifier(String vpnInterfaceName) {
147         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn
148             .rev140815.VpnInterfaces.class)
149             .child(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
150                 .VpnInterface.class,
151                 new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
152                     .VpnInterfaceKey(vpnInterfaceName)).build();
153     }
154
155     static InstanceIdentifier<VpnInstanceOpDataEntry> getVpnInstanceOpDataIdentifier(String rd) {
156         return InstanceIdentifier.builder(VpnInstanceOpData.class)
157             .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)).build();
158     }
159
160     static Optional<VpnInstanceOpDataEntry> getVpnInstanceOpData(DataBroker broker, String rd) {
161         InstanceIdentifier<VpnInstanceOpDataEntry> id = getVpnInstanceOpDataIdentifier(rd);
162         return MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
163     }
164
165     static VpnInstanceOpDataEntry getVpnInstance(DataBroker dataBroker, String rd) {
166         InstanceIdentifier<VpnInstanceOpDataEntry> id =
167                 InstanceIdentifier.create(VpnInstanceOpData.class)
168                         .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd));
169         Optional<VpnInstanceOpDataEntry> vpnInstanceOpData =
170                 MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
171         return vpnInstanceOpData.isPresent() ? vpnInstanceOpData.get() : null;
172     }
173
174     static String getNextHopLabelKey(String rd, String prefix) {
175         return rd + FibConstants.SEPARATOR + prefix;
176     }
177
178     static Prefixes getPrefixToInterface(DataBroker broker, Long vpnId, String ipPrefix) {
179         Optional<Prefixes> localNextHopInfoData = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
180             getPrefixToInterfaceIdentifier(vpnId, ipPrefix));
181         return localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null;
182     }
183
184     static String getMacAddressFromPrefix(DataBroker broker, String ifName, String ipPrefix) {
185         Optional<Adjacency> adjacencyData = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
186             getAdjacencyIdentifier(ifName, ipPrefix));
187         return adjacencyData.isPresent() ? adjacencyData.get().getMacAddress() : null;
188     }
189
190     static void releaseId(IdManagerService idManager, String poolName, String idKey) {
191         ReleaseIdInput idInput = new ReleaseIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
192         try {
193             Future<RpcResult<Void>> result = idManager.releaseId(idInput);
194             RpcResult<Void> rpcResult = result.get();
195             if (!rpcResult.isSuccessful()) {
196                 LOG.error("RPC Call to Get Unique Id for key {} returned with Errors {}", idKey, rpcResult.getErrors());
197             }
198         } catch (InterruptedException | ExecutionException e) {
199             LOG.warn("Exception when getting Unique Id for key {}", idKey, e);
200         }
201     }
202
203     static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
204         .instance.to.vpn.id.VpnInstance> getVpnInstanceToVpnIdIdentifier(String vpnName) {
205         return InstanceIdentifier.builder(VpnInstanceToVpnId.class)
206             .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
207                     .VpnInstance.class,
208                 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
209                     .VpnInstanceKey(vpnName)).build();
210     }
211
212     public static long getVpnId(DataBroker broker, String vpnName) {
213
214         InstanceIdentifier<VpnInstance> id = getVpnInstanceToVpnIdIdentifier(vpnName);
215         return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id).toJavaUtil().map(
216                 VpnInstance::getVpnId).orElse(-1L);
217     }
218
219     /**
220      * Retrieves the VpnInstance name (typically the VPN Uuid) out from the route-distinguisher.
221      *
222      * @param broker The DataBroker
223      * @param rd The route-distinguisher
224      * @return The vpn instance
225      */
226     public static Optional<String> getVpnNameFromRd(DataBroker broker, String rd) {
227         return Optional.fromJavaUtil(
228                 getVpnInstanceOpData(broker, rd).toJavaUtil().map(VpnInstanceOpDataEntry::getVpnInstanceName));
229     }
230
231     public static String getVpnNameFromId(DataBroker broker, long vpnId) {
232         InstanceIdentifier<VpnIds> id = getVpnIdToVpnInstanceIdentifier(vpnId);
233         return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id).toJavaUtil().map(
234                 VpnIds::getVpnInstanceName).orElse(null);
235     }
236
237     static InstanceIdentifier<VpnIds> getVpnIdToVpnInstanceIdentifier(long vpnId) {
238         return InstanceIdentifier.builder(VpnIdToVpnInstance.class)
239             .child(VpnIds.class, new VpnIdsKey(vpnId)).build();
240     }
241
242     // TODO Clean up the exception handling
243     @SuppressWarnings("checkstyle:IllegalCatch")
244     public static void addOrUpdateFibEntry(DataBroker broker, String rd, String macAddress, String prefix,
245                                            List<String> nextHopList, VrfEntry.EncapType encapType, long label,
246                                            long l3vni, String gwMacAddress, String parentVpnRd, RouteOrigin origin,
247                                            WriteTransaction writeConfigTxn) {
248         if (rd == null || rd.isEmpty()) {
249             LOG.error("Prefix {} not associated with vpn", prefix);
250             return;
251         }
252
253         Preconditions.checkNotNull(nextHopList, "NextHopList can't be null");
254
255         try {
256             InstanceIdentifier<VrfEntry> vrfEntryId =
257                 InstanceIdentifier.builder(FibEntries.class)
258                     .child(VrfTables.class, new VrfTablesKey(rd))
259                     .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
260
261             writeFibEntryToDs(vrfEntryId, prefix, nextHopList, label, l3vni, encapType, origin, macAddress,
262                     gwMacAddress, parentVpnRd, writeConfigTxn, broker);
263             LOG.debug("Created/Updated vrfEntry for {} nexthop {} label {}", prefix, nextHopList, label);
264         } catch (Exception e) {
265             LOG.error("addOrUpdateFibEntry: Prefix {} rd {} label {} error ", prefix, rd, label, e);
266         }
267     }
268
269     // TODO Clean up the exception handling
270     @SuppressWarnings("checkstyle:IllegalCatch")
271     public static void writeFibEntryToDs(InstanceIdentifier<VrfEntry> vrfEntryId, String prefix,
272                                          List<String> nextHopList, long label, Long l3vni,
273                                          VrfEntry.EncapType encapType, RouteOrigin origin, String macAddress,
274                                          String gatewayMacAddress, String parentVpnRd,
275                                          WriteTransaction writeConfigTxn, DataBroker broker) {
276         VrfEntryBuilder vrfEntryBuilder = new VrfEntryBuilder().setDestPrefix(prefix).setOrigin(origin.getValue());
277         if (parentVpnRd != null) {
278             vrfEntryBuilder.setParentVpnRd(parentVpnRd);
279         }
280         buildVpnEncapSpecificInfo(vrfEntryBuilder, encapType, label, l3vni, macAddress, gatewayMacAddress, nextHopList);
281         if (writeConfigTxn != null) {
282             writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntryBuilder.build(), true);
283         } else {
284             MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntryBuilder.build());
285         }
286     }
287
288     @SuppressWarnings("checkstyle:IllegalCatch")
289     public static void addFibEntryForRouterInterface(DataBroker broker,
290                                                      String rd,
291                                                      String prefix,
292                                                      RouterInterface routerInterface,
293                                                      long label,
294                                                      WriteTransaction writeConfigTxn) {
295         if (rd == null || rd.isEmpty()) {
296             LOG.error("Prefix {} not associated with vpn", prefix);
297             return;
298         }
299
300         try {
301             InstanceIdentifier<VrfEntry> vrfEntryId =
302                 InstanceIdentifier.builder(FibEntries.class)
303                     .child(VrfTables.class, new VrfTablesKey(rd))
304                     .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
305
306             // Filling the nextHop with dummy nextHopAddress
307             VrfEntry vrfEntry = FibHelper.getVrfEntryBuilder(prefix, label,
308                     FibConstants.DEFAULT_NEXTHOP_IP, RouteOrigin.LOCAL, null /* parentVpnRd */)
309                 .addAugmentation(RouterInterface.class, routerInterface).build();
310
311             if (writeConfigTxn != null) {
312                 writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry, true);
313             } else {
314                 MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry);
315             }
316             LOG.debug("Created vrfEntry for router-interface-prefix {} rd {} label {}", prefix, rd, label);
317         } catch (Exception e) {
318             LOG.error("addFibEntryForRouterInterface: prefix {} rd {} label {} error ", prefix, rd, label, e);
319         }
320     }
321
322     private static void buildVpnEncapSpecificInfo(VrfEntryBuilder builder, VrfEntry.EncapType encapType, long label,
323                                          long l3vni, String macAddress, String gatewayMac, List<String> nextHopList) {
324         if (encapType == null) {
325             builder.setMac(macAddress);
326             return;
327         }
328
329         // TODO - validate this check
330         if (l3vni != 0) {
331             builder.setL3vni(l3vni);
332         }
333         builder.setEncapType(encapType);
334         builder.setGatewayMacAddress(gatewayMac);
335         builder.setMac(macAddress);
336         Long lbl = encapType.equals(VrfEntry.EncapType.Mplsgre) ? label : null;
337         List<RoutePaths> routePaths = nextHopList.stream()
338                         .filter(nextHop -> nextHop != null && !nextHop.isEmpty())
339                         .map(nextHop -> FibHelper.buildRoutePath(nextHop, lbl)).collect(toList());
340         builder.setRoutePaths(routePaths);
341     }
342
343     public static void removeFibEntry(DataBroker broker, String rd, String prefix, WriteTransaction writeConfigTxn) {
344
345         if (rd == null || rd.isEmpty()) {
346             LOG.error("Prefix {} not associated with vpn", prefix);
347             return;
348         }
349         LOG.debug("Removing fib entry with destination prefix {} from vrf table for rd {}", prefix, rd);
350
351         InstanceIdentifier.InstanceIdentifierBuilder<VrfEntry> idBuilder =
352             InstanceIdentifier.builder(FibEntries.class)
353                 .child(VrfTables.class, new VrfTablesKey(rd)).child(VrfEntry.class, new VrfEntryKey(prefix));
354         InstanceIdentifier<VrfEntry> vrfEntryId = idBuilder.build();
355         if (writeConfigTxn != null) {
356             writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, vrfEntryId);
357         } else {
358             MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
359         }
360     }
361
362     /**
363      * Removes a specific Nexthop from a VrfEntry. If Nexthop to remove is the
364      * last one in the VrfEntry, then the VrfEntry is removed too.
365      *
366      * @param broker          dataBroker service reference
367      * @param rd              Route-Distinguisher to which the VrfEntry belongs to
368      * @param prefix          Destination of the route
369      * @param nextHopToRemove Specific nexthop within the Route to be removed.
370      *                        If null or empty, then the whole VrfEntry is removed
371      */
372     public static void removeOrUpdateFibEntry(DataBroker broker, String rd, String prefix, String nextHopToRemove,
373                                               WriteTransaction writeConfigTxn) {
374
375         LOG.debug("Removing fib entry with destination prefix {} from vrf table for rd {}", prefix, rd);
376
377         // Looking for existing prefix in MDSAL database
378         InstanceIdentifier<VrfEntry> vrfEntryId =
379             InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
380                 .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
381         Optional<VrfEntry> entry = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
382         if (entry.isPresent()) {
383             final List<RoutePaths> routePaths = entry.get().getRoutePaths();
384             if (routePaths == null || routePaths.isEmpty()) {
385                 LOG.warn("routePaths is null/empty for given rd {}, prefix {}", rd, prefix);
386                 return;
387             }
388             java.util.Optional<RoutePaths> optRoutePath =
389                     routePaths.stream()
390                               .filter(routePath -> routePath.getNexthopAddress().equals(
391                                     nextHopToRemove)).findFirst();
392             if (!optRoutePath.isPresent()) {
393                 LOG.error("Unable to find a routePath that contains the given nextHop to remove {}", nextHopToRemove);
394                 return;
395             }
396             RoutePaths routePath = optRoutePath.get();
397             if (routePaths.size() == 1) {
398                 // Remove the whole entry
399                 if (writeConfigTxn != null) {
400                     writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, vrfEntryId);
401                 } else {
402                     MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
403                 }
404                 LOG.info("Removed Fib Entry rd {} prefix {}", rd, prefix);
405             } else {
406                 InstanceIdentifier<RoutePaths> routePathsId =
407                         FibHelper.buildRoutePathId(rd, prefix, routePath.getNexthopAddress());
408                 // Remove route
409                 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, routePathsId);
410
411                 LOG.info("Removed Route Path rd {} prefix {}, nextHop {}, label {}", rd, prefix,
412                         routePath.getNexthopAddress(), routePath.getLabel());
413             }
414         } else {
415             LOG.warn("Could not find VrfEntry for Route-Distinguisher={} and prefix={}", rd, prefix);
416         }
417     }
418
419     /**
420      * Adds or removes nextHop from routePath based on the flag nextHopAdd.
421      */
422     public static void updateRoutePathForFibEntry(DataBroker broker, String rd, String prefix, String nextHop,
423             long label, boolean nextHopAdd, WriteTransaction writeConfigTxn) {
424
425         LOG.debug("Updating fib entry for prefix {} with nextHop {} for rd {}.", prefix, nextHop, rd);
426
427         InstanceIdentifier<RoutePaths> routePathId = FibHelper.buildRoutePathId(rd, prefix, nextHop);
428         String routePathKey = rd + prefix + nextHop;
429         synchronized (routePathKey.intern()) {
430             if (nextHopAdd) {
431                 RoutePaths routePaths = FibHelper.buildRoutePath(nextHop, label);
432                 if (writeConfigTxn != null) {
433                     writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION, routePathId, routePaths,
434                             WriteTransaction.CREATE_MISSING_PARENTS);
435                 } else {
436                     MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, routePathId, routePaths);
437                 }
438                 LOG.debug("Added routepath with nextHop {} for prefix {} and label {}.", nextHop, prefix, label);
439             } else {
440                 Optional<RoutePaths> routePath = MDSALUtil.read(broker,
441                         LogicalDatastoreType.CONFIGURATION, routePathId);
442                 if (!routePath.isPresent()) {
443                     LOG.warn("Couldn't find RoutePath with rd {}, prefix {} and nh {} for deleting",
444                             rd, prefix, nextHop);
445                     return;
446                 }
447                 if (writeConfigTxn != null) {
448                     writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, routePathId);
449                 } else {
450                     MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, routePathId);
451                 }
452                 LOG.info("Removed routepath with nextHop {} for prefix {} and rd {}.", nextHop, prefix, rd);
453             }
454         }
455     }
456
457     public static void removeVrfTable(DataBroker broker, String rd, WriteTransaction writeConfigTxn) {
458         LOG.debug("Removing vrf table for rd {}", rd);
459         InstanceIdentifier.InstanceIdentifierBuilder<VrfTables> idBuilder =
460             InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
461         InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
462
463         if (writeConfigTxn != null) {
464             writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, vrfTableId);
465         } else {
466             MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId);
467         }
468     }
469
470     public static java.util.Optional<Long> getLabelFromRoutePaths(final VrfEntry vrfEntry) {
471         List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
472         if (routePaths == null || routePaths.isEmpty() || vrfEntry.getRoutePaths().get(0).getLabel() == null) {
473             return java.util.Optional.empty();
474         }
475         return java.util.Optional.of(vrfEntry.getRoutePaths().get(0).getLabel());
476     }
477
478     public static java.util.Optional<String> getFirstNextHopAddress(final VrfEntry vrfEntry) {
479         List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
480         if (routePaths == null || routePaths.isEmpty()) {
481             return java.util.Optional.empty();
482         }
483         return java.util.Optional.of(vrfEntry.getRoutePaths().get(0).getNexthopAddress());
484     }
485
486     public static java.util.Optional<Long> getLabelForNextHop(final VrfEntry vrfEntry, String nextHopIp) {
487         List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
488         if (routePaths == null || routePaths.isEmpty()) {
489             return java.util.Optional.empty();
490         }
491         return routePaths.stream()
492                 .filter(routePath -> routePath.getNexthopAddress().equals(nextHopIp))
493                 .findFirst()
494                 .map(RoutePaths::getLabel);
495     }
496
497     public static InstanceIdentifier<Interface> buildStateInterfaceId(String interfaceName) {
498         InstanceIdentifier.InstanceIdentifierBuilder<Interface> idBuilder =
499                 InstanceIdentifier.builder(InterfacesState.class)
500                         .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
501                                 .interfaces.state.Interface.class, new org.opendaylight.yang.gen.v1.urn.ietf
502                                 .params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state
503                                 .InterfaceKey(interfaceName));
504         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
505                 .interfaces.state.Interface> id = idBuilder.build();
506         return id;
507     }
508
509     public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
510         .state.Interface getInterfaceStateFromOperDS(DataBroker dataBroker, String interfaceName) {
511         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
512             .interfaces.state.Interface> ifStateId = buildStateInterfaceId(interfaceName);
513         Optional<Interface> ifStateOptional = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, ifStateId);
514         if (ifStateOptional.isPresent()) {
515             return ifStateOptional.get();
516         }
517
518         return null;
519     }
520
521     public static String getCreateLocalNextHopJobKey(Long vpnId, BigInteger dpnId, String prefix) {
522         return "FIB-" + vpnId.toString() + "-" + dpnId.toString() + "-" + prefix;
523     }
524
525     public static String getJobKeyForRdPrefix(String rd, String prefix) {
526         return "FIB-" + rd + "-" + prefix;
527     }
528
529     public static String getJobKeyForVpnIdDpnId(Long vpnId, BigInteger dpnId) {
530         return "FIB-" + vpnId.toString() + "-" + dpnId.toString() ;
531     }
532
533     public static void updateUsedRdAndVpnToExtraRoute(WriteTransaction writeOperTxn, DataBroker broker,
534                                                       String tunnelIpRemoved, String primaryRd, String prefix) {
535         Optional<VpnInstanceOpDataEntry> optVpnInstance = getVpnInstanceOpData(broker, primaryRd);
536         if (!optVpnInstance.isPresent()) {
537             return;
538         }
539         VpnInstanceOpDataEntry vpnInstance = optVpnInstance.get();
540         String vpnName = vpnInstance.getVpnInstanceName();
541         long vpnId = vpnInstance.getVpnId();
542         List<String> usedRds = VpnExtraRouteHelper.getUsedRds(broker, vpnId, prefix);
543         // To identify the rd to be removed, iterate through the allocated rds for the prefix and check
544         // which rd is allocated for the particular OVS.
545         for (String usedRd : usedRds) {
546             Optional<Routes> vpnExtraRoutes = VpnExtraRouteHelper
547                     .getVpnExtraroutes(broker, vpnName, usedRd, prefix);
548             if (vpnExtraRoutes.isPresent()) {
549                 // Since all the nexthops under one OVS will be present under one rd, only 1 nexthop is read
550                 // to identify the OVS
551                 String nextHopRemoved = vpnExtraRoutes.get().getNexthopIpList().get(0);
552                 Prefixes prefixToInterface = getPrefixToInterface(broker, vpnId, getIpPrefix(nextHopRemoved));
553                 if (prefixToInterface != null && tunnelIpRemoved
554                         .equals(getEndpointIpAddressForDPN(broker, prefixToInterface.getDpnId()))) {
555                     InstanceIdentifier<Adjacency> adjId = getAdjacencyIdentifier(
556                             prefixToInterface.getVpnInterfaceName(), prefix);
557                     Interface ifState = FibUtil.getInterfaceStateFromOperDS(
558                             broker, prefixToInterface.getVpnInterfaceName());
559                     //Delete datastore only if extra route is deleted or VM interface is deleted/down
560                     if (!MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, adjId).isPresent()
561                             || ifState == null || ifState.getOperStatus() == OperStatus.Down) {
562                         writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL,
563                                 getAdjacencyIdentifier(prefixToInterface.getVpnInterfaceName(), prefix));
564                         writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL,
565                                 VpnExtraRouteHelper.getVpnToExtrarouteVrfIdIdentifier(vpnName, usedRd, prefix));
566                         writeOperTxn.delete(LogicalDatastoreType.CONFIGURATION,
567                                 VpnExtraRouteHelper.getUsedRdsIdentifier(vpnId, prefix, nextHopRemoved));
568                         break;
569                     }
570                 }
571             }
572         }
573     }
574
575     private static String getEndpointIpAddressForDPN(DataBroker broker, BigInteger dpnId) {
576         //TODO: Move it to a common place for vpn and fib
577         String nextHopIp = null;
578         InstanceIdentifier<DPNTEPsInfo> tunnelInfoId =
579             InstanceIdentifier.builder(DpnEndpoints.class).child(DPNTEPsInfo.class, new DPNTEPsInfoKey(dpnId)).build();
580         Optional<DPNTEPsInfo> tunnelInfo = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, tunnelInfoId);
581         if (tunnelInfo.isPresent()) {
582             List<TunnelEndPoints> nexthopIpList = tunnelInfo.get().getTunnelEndPoints();
583             if (nexthopIpList != null && !nexthopIpList.isEmpty()) {
584                 nextHopIp = String.valueOf(nexthopIpList.get(0).getIpAddress().getValue());
585             }
586         }
587         return nextHopIp;
588     }
589
590     public static String getIpPrefix(String prefix) {
591         String[] prefixValues = prefix.split(FibConstants.PREFIX_SEPARATOR);
592         if (prefixValues.length == 1) {
593             prefix = prefix + NwConstants.IPV4PREFIX;
594         }
595         return prefix;
596     }
597
598     public static boolean isTunnelInterface(AdjacencyResult adjacencyResult) {
599         return Tunnel.class.equals(adjacencyResult.getInterfaceType());
600     }
601
602     public static InstanceIdentifier<VrfEntry> getNextHopIdentifier(String rd, String prefix) {
603         return InstanceIdentifier.builder(FibEntries.class)
604                 .child(VrfTables.class,new VrfTablesKey(rd)).child(VrfEntry.class,new VrfEntryKey(prefix)).build();
605     }
606
607     public static List<String> getNextHopAddresses(DataBroker broker, String rd, String prefix) {
608         InstanceIdentifier<VrfEntry> vrfEntryId = getNextHopIdentifier(rd, prefix);
609         Optional<VrfEntry> vrfEntry = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
610         if (vrfEntry.isPresent()) {
611             return FibHelper.getNextHopListFromRoutePaths(vrfEntry.get());
612         } else {
613             return Collections.emptyList();
614         }
615     }
616
617     public static Subnetmap getSubnetMap(DataBroker broker, Uuid subnetId) {
618         InstanceIdentifier<Subnetmap> subnetmapId = InstanceIdentifier.builder(Subnetmaps.class)
619             .child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
620         return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, subnetmapId).orNull();
621     }
622
623     public static String getGreLbGroupKey(List<String> availableDcGws) {
624         Preconditions.checkNotNull(availableDcGws, "AvailableDcGws is null");
625         return "gre-" + availableDcGws.stream().sorted().collect(joining(":"));
626     }
627
628     public static void updateLbGroupInfo(BigInteger dpnId, String destinationIp, String groupIdKey,
629             String groupId, WriteTransaction tx) {
630         InstanceIdentifier<DpnLbNexthops> id = getDpnLbNexthopsIdentifier(dpnId, destinationIp);
631         DpnLbNexthops dpnToLbNextHop = buildDpnLbNextHops(dpnId, destinationIp, groupIdKey);
632         tx.merge(LogicalDatastoreType.OPERATIONAL, id, dpnToLbNextHop);
633         InstanceIdentifier<Nexthops> nextHopsId = getNextHopsIdentifier(groupIdKey);
634         Nexthops nextHopsToGroupId = buildNextHops(dpnId, groupIdKey, groupId);
635         tx.merge(LogicalDatastoreType.OPERATIONAL, nextHopsId, nextHopsToGroupId);
636     }
637
638     public static void removeDpnIdToNextHopInfo(String destinationIp, BigInteger dpnId, WriteTransaction tx) {
639         InstanceIdentifier<DpnLbNexthops> id = getDpnLbNexthopsIdentifier(dpnId, destinationIp);
640         tx.delete(LogicalDatastoreType.OPERATIONAL, id);
641     }
642
643     public static void removeOrUpdateNextHopInfo(BigInteger dpnId, String nextHopKey, String groupId,
644             Nexthops nexthops, WriteTransaction tx) {
645         InstanceIdentifier<Nexthops> nextHopsId = getNextHopsIdentifier(nextHopKey);
646         List<String> targetDeviceIds = nexthops.getTargetDeviceId();
647         targetDeviceIds.remove(dpnId.toString());
648         if (targetDeviceIds.isEmpty()) {
649             tx.delete(LogicalDatastoreType.OPERATIONAL, nextHopsId);
650         } else {
651             Nexthops nextHopsToGroupId = new NexthopsBuilder().setKey(new NexthopsKey(nextHopKey))
652                 .setNexthopKey(nextHopKey)
653                 .setGroupId(groupId)
654                 .setTargetDeviceId(targetDeviceIds).build();
655             tx.put(LogicalDatastoreType.OPERATIONAL, nextHopsId, nextHopsToGroupId);
656         }
657     }
658
659     private static InstanceIdentifier<DpnLbNexthops> getDpnLbNexthopsIdentifier(BigInteger dpnId,
660             String destinationIp) {
661         return InstanceIdentifier.builder(DpidL3vpnLbNexthops.class)
662                 .child(DpnLbNexthops.class, new DpnLbNexthopsKey(destinationIp, dpnId))
663                 .build();
664     }
665
666     private static InstanceIdentifier<Nexthops> getNextHopsIdentifier(String groupIdKey) {
667         return InstanceIdentifier.builder(L3vpnLbNexthops.class)
668                 .child(Nexthops.class, new NexthopsKey(groupIdKey)).build();
669     }
670
671     private static Nexthops buildNextHops(BigInteger dpnId, String groupIdKey, String groupId) {
672         return new NexthopsBuilder().setKey(new NexthopsKey(groupIdKey))
673                 .setNexthopKey(groupIdKey)
674                 .setGroupId(groupId)
675                 .setTargetDeviceId(Collections.singletonList(dpnId.toString())).build();
676     }
677
678     private static DpnLbNexthops buildDpnLbNextHops(BigInteger dpnId, String destinationIp,
679             String groupIdKey) {
680         return new DpnLbNexthopsBuilder().setKey(new DpnLbNexthopsKey(destinationIp, dpnId))
681                 .setDstDeviceId(destinationIp).setSrcDpId(dpnId)
682                 .setNexthopKey(Collections.singletonList(groupIdKey)).build();
683     }
684
685     public static Optional<Nexthops> getNexthops(DataBroker dataBroker, String nextHopKey) {
686         InstanceIdentifier<Nexthops> nextHopsId = InstanceIdentifier.builder(L3vpnLbNexthops.class)
687                 .child(Nexthops.class, new NexthopsKey(nextHopKey)).build();
688         return MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, nextHopsId);
689     }
690
691     public static Optional<DpnLbNexthops> getDpnLbNexthops(DataBroker dataBroker, BigInteger dpnId,
692             String destinationIp) {
693         InstanceIdentifier<DpnLbNexthops> id = InstanceIdentifier.builder(DpidL3vpnLbNexthops.class)
694                 .child(DpnLbNexthops.class, new DpnLbNexthopsKey(destinationIp, dpnId))
695                 .build();
696         return MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
697     }
698
699     protected static boolean isVxlanNetworkAndInternalRouterVpn(DataBroker dataBroker, Uuid subnetId, String
700             vpnInstanceName, String rd) {
701         if (rd.equals(vpnInstanceName)) {
702             Subnetmap subnetmap = getSubnetMap(dataBroker, subnetId);
703             if (subnetmap != null) {
704                 return subnetmap.getNetworkType() == NetworkAttributes.NetworkType.VXLAN;
705             }
706         }
707         return false;
708     }
709
710     protected static java.util.Optional<Long> getVniForVxlanNetwork(DataBroker dataBroker, Uuid subnetId) {
711         Subnetmap subnetmap = getSubnetMap(dataBroker, subnetId);
712         if (subnetmap != null && subnetmap.getNetworkType() == NetworkAttributes.NetworkType.VXLAN) {
713             return java.util.Optional.of(subnetmap.getSegmentationId());
714         }
715         return java.util.Optional.empty();
716     }
717
718     protected static boolean enforceVxlanDatapathSemanticsforInternalRouterVpn(DataBroker dataBroker, Uuid subnetId,
719                                                                                long vpnId, String rd) {
720         return isOpenStackVniSemanticsEnforced
721                 && isVxlanNetworkAndInternalRouterVpn(dataBroker, subnetId, getVpnNameFromId(dataBroker, vpnId), rd);
722     }
723
724     protected static boolean enforceVxlanDatapathSemanticsforInternalRouterVpn(DataBroker dataBroker, Uuid subnetId,
725                                                                                String vpnName, String rd) {
726         return isOpenStackVniSemanticsEnforced
727                 && isVxlanNetworkAndInternalRouterVpn(dataBroker, subnetId, vpnName, rd);
728     }
729
730     static NodeRef buildNodeRef(BigInteger dpId) {
731         return new NodeRef(InstanceIdentifier.builder(Nodes.class)
732                 .child(Node.class, new NodeKey(new NodeId("openflow:" + dpId))).build());
733     }
734
735     static InstanceIdentifier<Group> buildGroupInstanceIdentifier(long groupId, BigInteger dpId) {
736         return InstanceIdentifier.builder(Nodes.class).child(Node.class, new NodeKey(new NodeId("openflow:" + dpId)))
737                 .augmentation(FlowCapableNode.class).child(Group.class, new GroupKey(new GroupId(groupId))).build();
738     }
739
740     static Buckets buildBuckets(List<BucketInfo> listBucketInfo) {
741         long index = 0;
742         BucketsBuilder bucketsBuilder = new BucketsBuilder();
743         if (listBucketInfo != null) {
744             List<Bucket> bucketList = new ArrayList<>();
745
746             for (BucketInfo bucketInfo : listBucketInfo) {
747                 BucketBuilder bucketBuilder = new BucketBuilder();
748                 bucketBuilder.setAction(bucketInfo.buildActions());
749                 bucketBuilder.setWeight(bucketInfo.getWeight());
750                 bucketBuilder.setBucketId(new BucketId(index++));
751                 bucketBuilder.setWeight(bucketInfo.getWeight()).setWatchPort(bucketInfo.getWatchPort())
752                         .setWatchGroup(bucketInfo.getWatchGroup());
753                 bucketList.add(bucketBuilder.build());
754             }
755
756             bucketsBuilder.setBucket(bucketList);
757         }
758         return bucketsBuilder.build();
759     }
760
761     static String getFlowRef(BigInteger dpnId, short tableId, long label, int priority) {
762         return FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR + label
763                 + NwConstants.FLOWID_SEPARATOR + priority;
764     }
765
766     static String getFlowRef(BigInteger dpnId, short tableId, String rd, int priority, InetAddress destPrefix) {
767         return FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR + rd
768                 + NwConstants.FLOWID_SEPARATOR + priority + NwConstants.FLOWID_SEPARATOR + destPrefix.getHostAddress();
769     }
770
771     static String getL3VpnGatewayFlowRef(short l3GwMacTable, BigInteger dpId, long vpnId, String gwMacAddress) {
772         return gwMacAddress + NwConstants.FLOWID_SEPARATOR + vpnId + NwConstants.FLOWID_SEPARATOR + dpId
773                 + NwConstants.FLOWID_SEPARATOR + l3GwMacTable;
774     }
775
776     static Node buildDpnNode(BigInteger dpnId) {
777         return new NodeBuilder().setId(new NodeId("openflow:" + dpnId))
778                 .setKey(new NodeKey(new NodeId("openflow:" + dpnId))).build();
779     }
780
781     public static String getBroadcastAddressFromCidr(String cidr) {
782         String[] ipaddressValues = cidr.split("/");
783         int address = InetAddresses.coerceToInteger(InetAddresses.forString(ipaddressValues[0]));
784         int cidrPart = Integer.parseInt(ipaddressValues[1]);
785         int netmask = 0;
786         for (int j = 0; j < cidrPart; ++j) {
787             netmask |= 1 << 31 - j;
788         }
789         int network = address & netmask;
790         int broadcast = network | ~netmask;
791         return InetAddresses.toAddrString(InetAddresses.fromInteger(broadcast));
792     }
793 }