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