Thrift changes to support IPv6 calls over Quagga BGP stack
[netvirt.git] / vpnservice / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / netvirt / vpnmanager / intervpnlink / InterVpnLinkUtil.java
index 1a74ded31bcde6eca4de812cb11a6846f19932bf..af8cf620b2f889e4d9b5b112c03d2cc9fb806e30 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ * Copyright (c) 2016, 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -9,37 +9,45 @@ package org.opendaylight.netvirt.vpnmanager.intervpnlink;
 
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
-import org.opendaylight.genius.mdsalutil.MatchFieldType;
 import org.opendaylight.genius.mdsalutil.MatchInfo;
 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
 import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
 import org.opendaylight.genius.utils.ServiceIndex;
 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
+import org.opendaylight.netvirt.fibmanager.api.FibHelper;
+import org.opendaylight.netvirt.fibmanager.api.IFibManager;
 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
 import org.opendaylight.netvirt.vpnmanager.VpnConstants;
+import org.opendaylight.netvirt.vpnmanager.VpnFootprintService;
 import org.opendaylight.netvirt.vpnmanager.VpnUtil;
+import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkCache;
+import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkDataComposite;
 import org.opendaylight.netvirt.vpnmanager.utilities.InterfaceUtils;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.InterVpnLinkStates;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.InterVpnLinks;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkStateBuilder;
-
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn
-        .link.states.InterVpnLinkStateKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkStateKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.inter.vpn.link.state.FirstEndpointState;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.inter.vpn.link.state.SecondEndpointState;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLink;
@@ -48,14 +56,8 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.math.BigInteger;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
 /**
  * This class contains methods to be used as utilities related with inter-vpn-link.
- *
  */
 public class InterVpnLinkUtil {
 
@@ -63,133 +65,143 @@ public class InterVpnLinkUtil {
 
     /**
      * Retrieves the Instance Identifier that points to an InterVpnLink object
-     * in MDSL
+     * in MD-SAL.
      *
-     * @param iVpnLinkName The name of the InterVpnLink
+     * @param interVpnLinkName The name of the InterVpnLink
      * @return The requested InstanceIdentifier
      */
-    public static InstanceIdentifier<InterVpnLink> getInterVpnLinkPath(String iVpnLinkName) {
+    public static InstanceIdentifier<InterVpnLink> getInterVpnLinkPath(String interVpnLinkName) {
         return InstanceIdentifier.builder(InterVpnLinks.class)
-                .child(InterVpnLink.class, new InterVpnLinkKey(iVpnLinkName))
-                .build();
+            .child(InterVpnLink.class, new InterVpnLinkKey(interVpnLinkName))
+            .build();
     }
 
     /**
      * Retrieves the Instance Identifier that points to an InterVpnLinkState object
-     * in MDSL
+     * in MD-SAL.
      *
      * @param vpnLinkName The name of the InterVpnLink
      * @return The requested InstanceIdentifier
      */
     public static InstanceIdentifier<InterVpnLinkState> getInterVpnLinkStateIid(String vpnLinkName) {
         return InstanceIdentifier.builder(InterVpnLinkStates.class)
-                .child(InterVpnLinkState.class, new InterVpnLinkStateKey(vpnLinkName))
-                .build();
+            .child(InterVpnLinkState.class, new InterVpnLinkStateKey(vpnLinkName))
+            .build();
+    }
+
+    public static String buildInterVpnLinkIfaceName(String vpnName, BigInteger dpnId) {
+        return String.format("InterVpnLink.%s.%s", vpnName, dpnId.toString());
     }
 
     /**
      * Updates VpnToDpn map by adding a fake VpnInterface related to an
-     * InterVpnLink in the corresponding DPNs
+     * InterVpnLink in the corresponding DPNs. If the fake iface is the
+     * first one on the any of the specified DPNs, the installation of
+     * Fib flows on that DPN will be triggered.
      *
-     * @param broker dataBroker service reference
-     * @param dpnList List of DPNs where the fake InterVpnLink interface must
-     *     be added
-     * @param vpnUuid UUID of the VPN to which the fake interfaces belong
+     * @param vpnFootprintService VpnFootprintService service reference
+     * @param vpnName Name of the VPN to which the fake interfaces belong
+     * @param dpnList List of DPNs where the fake InterVpnLink interface must be added
      */
-    public static void updateVpnToDpnMap(DataBroker broker, List<BigInteger> dpnList, Uuid vpnUuid) {
-        String rd = VpnUtil.getVpnRd(broker, vpnUuid.getValue());
-        InstanceIdentifier<VpnInstanceOpDataEntry> id = VpnUtil.getVpnInstanceOpDataIdentifier(rd);
-        Optional<VpnInstanceOpDataEntry> vpnInstOpData = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
-        if ( vpnInstOpData.isPresent() ) {
-            for (BigInteger dpnId : dpnList) {
-                String linkIfaceName = String.format("InterVpnLink.%s.%s", vpnUuid.getValue(), dpnId.toString());
-                VpnUtil.mergeDpnInVpnToDpnMap(broker, vpnInstOpData.get(), dpnId, Arrays.asList(linkIfaceName));
-            }
+    public static void updateVpnFootprint(VpnFootprintService vpnFootprintService, String vpnName,
+        List<BigInteger> dpnList) {
+        LOG.debug("updateVpnFootprint (add):  vpn={}  dpnList={}", vpnName, dpnList);
+        // Note: when a set of DPNs is calculated for Vpn1, these DPNs are added to the VpnToDpn map of Vpn2. Why?
+        // because we do the handover from Vpn1 to Vpn2 in those DPNs, so in those DPNs we must know how to reach
+        // to Vpn2 targets. If new Vpn2 targets are added later, the Fib will be maintained in these DPNs even if
+        // Vpn2 is not physically present there.
+        for (BigInteger dpnId : dpnList) {
+            String ifaceName = buildInterVpnLinkIfaceName(vpnName, dpnId);
+            vpnFootprintService.updateVpnToDpnMapping(dpnId, vpnName, ifaceName, true /* addition */);
         }
     }
 
-
     /**
-     * Retrieves the InterVpnLink object searching by its name
+     * Updates VpnToDpn map by removing the fake VpnInterface related to an
+     * InterVpnLink in the corresponding DPNs.
      *
-     * @param broker dataBroker service reference
-     * @param vpnLinkName Name of the InterVpnLink
-     * @return the InterVpnLink or Optional.absent() if there is no
-     *     InterVpnLink with the specified name
+     * @param vpnFootprintService VpnFootprintService service reference
+     * @param vpnName Name of the VPN to which the fake interfaces belong
+     * @param dpnId DPN where the fake InterVpnLink interface must be removed from
      */
-    public static Optional<InterVpnLink> getInterVpnLinkByName(DataBroker broker, String vpnLinkName) {
-        InstanceIdentifier<InterVpnLink> interVpnLinksIid =
-                InstanceIdentifier.builder(InterVpnLinks.class)
-                        .child(InterVpnLink.class, new InterVpnLinkKey(vpnLinkName)).build();
-        return  VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, interVpnLinksIid);
+    public static void removeIVpnLinkIfaceFromVpnFootprint(VpnFootprintService vpnFootprintService,
+        String vpnName, BigInteger dpnId) {
+        String ifaceName = buildInterVpnLinkIfaceName(vpnName, dpnId);
+        LOG.debug("updateVpnFootprint (remove):  vpn={}  dpn={}  ifaceName={}", vpnName, dpnId, ifaceName);
+        vpnFootprintService.updateVpnToDpnMapping(dpnId, vpnName, ifaceName, false /* removal */);
     }
 
+
     /**
-     * Updates inter-VPN link state
+     * Updates inter-VPN link state.
      *
      * @param broker dataBroker service reference
      * @param vpnLinkName The name of the InterVpnLink
      * @param state Sets the state of the InterVpnLink to Active or Error
-     * @param newFirstEndpointState Updates the lportTag and/or DPNs of the 1st
-     *     endpoint of the InterVpnLink
-     * @param newSecondEndpointState Updates the lportTag and/or DPNs of the
-     *     2nd endpoint of the InterVpnLink
+     * @param newFirstEndpointState Updates the lportTag and/or DPNs of the 1st endpoint of the InterVpnLink
+     * @param newSecondEndpointState Updates the lportTag and/or DPNs of the 2nd endpoint of the InterVpnLink
      */
     public static void updateInterVpnLinkState(DataBroker broker, String vpnLinkName, InterVpnLinkState.State state,
-                                               FirstEndpointState newFirstEndpointState,
-                                               SecondEndpointState newSecondEndpointState) {
+        FirstEndpointState newFirstEndpointState,
+        SecondEndpointState newSecondEndpointState) {
         Optional<InterVpnLinkState> optOldVpnLinkState = getInterVpnLinkState(broker, vpnLinkName);
-        if ( optOldVpnLinkState.isPresent() ) {
+        if (optOldVpnLinkState.isPresent()) {
             InterVpnLinkState newVpnLinkState =
-                    new InterVpnLinkStateBuilder(optOldVpnLinkState.get()).setState(state)
+                new InterVpnLinkStateBuilder(optOldVpnLinkState.get()).setState(state)
                             .setFirstEndpointState(newFirstEndpointState)
                             .setSecondEndpointState(newSecondEndpointState)
                             .build();
             VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION,
-                    InterVpnLinkUtil.getInterVpnLinkStateIid(vpnLinkName), newVpnLinkState);
+                InterVpnLinkUtil.getInterVpnLinkStateIid(vpnLinkName), newVpnLinkState);
+            InterVpnLinkCache.addInterVpnLinkStateToCaches(newVpnLinkState);
         } else {
             InterVpnLinkState newIVpnLinkState =
-                    new InterVpnLinkStateBuilder().setKey(new InterVpnLinkStateKey(vpnLinkName))
-                            .setInterVpnLinkName(vpnLinkName)
-                            .setFirstEndpointState(newFirstEndpointState)
-                            .setSecondEndpointState(newSecondEndpointState)
-                            .setState(InterVpnLinkState.State.Active)
-                            .build();
+                new InterVpnLinkStateBuilder().setKey(new InterVpnLinkStateKey(vpnLinkName))
+                    .setInterVpnLinkName(vpnLinkName)
+                    .setFirstEndpointState(newFirstEndpointState)
+                    .setSecondEndpointState(newSecondEndpointState)
+                    .setState(InterVpnLinkState.State.Active)
+                    .build();
             VpnUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
-                    InterVpnLinkUtil.getInterVpnLinkStateIid(vpnLinkName), newIVpnLinkState);
+                InterVpnLinkUtil.getInterVpnLinkStateIid(vpnLinkName), newIVpnLinkState);
+            InterVpnLinkCache.addInterVpnLinkStateToCaches(newIVpnLinkState);
         }
     }
 
     /**
      * Installs a Flow in LPortDispatcher table that matches on SI=2 and
      * the lportTag of one InterVpnLink's endpoint and sets the vrfTag of the
-     * other endpoint and sends to FIB table
+     * other endpoint and sends to FIB table.
      *
      * @param broker dataBroker service reference
      * @param mdsalManager MDSAL API accessor
-     * @param interVpnLink Object that holds the needed information about both
-     *     endpoints of the InterVpnLink.
+     * @param interVpnLinkName Name of the InterVpnLink.
      * @param dpnList The list of DPNs where this flow must be installed
-     * @param vpnUuidOtherEndpoint UUID of the other endpoint of the
-     *     InterVpnLink
-     * @param lPortTagOfOtherEndpoint Dataplane identifier of the other
-     *     endpoint of the InterVpnLink
+     * @param vpnUuidOtherEndpoint UUID of the other endpoint of the InterVpnLink
+     * @param lportTagOfOtherEndpoint Dataplane identifier of the other endpoint of the InterVpnLink
+     * @return the list of Futures for each and every flow that has been installed
      */
-    public static void installLPortDispatcherTableFlow(DataBroker broker, IMdsalApiManager mdsalManager,
-                                                       InterVpnLink interVpnLink, List<BigInteger> dpnList,
-                                                       Uuid vpnUuidOtherEndpoint, Integer lPortTagOfOtherEndpoint) {
-        long vpnId = VpnUtil.getVpnId(broker, vpnUuidOtherEndpoint.getValue());
-        for ( BigInteger dpnId : dpnList ) {
+    public static List<ListenableFuture<Void>> installLPortDispatcherTableFlow(DataBroker broker,
+                                                                               IMdsalApiManager mdsalManager,
+                                                                               String interVpnLinkName,
+                                                                               List<BigInteger> dpnList,
+                                                                               String vpnUuidOtherEndpoint,
+                                                                               Long lportTagOfOtherEndpoint) {
+        List<ListenableFuture<Void>> result = new ArrayList<>();
+        long vpnId = VpnUtil.getVpnId(broker, vpnUuidOtherEndpoint);
+        for (BigInteger dpnId : dpnList) {
             // insert into LPortDispatcher table
-            Flow lPortDispatcherFlow = buildLPortDispatcherFlow(interVpnLink.getName(), vpnId,
-                                                                lPortTagOfOtherEndpoint.intValue());
-            mdsalManager.installFlow(dpnId, lPortDispatcherFlow);
+            Flow lportDispatcherFlow = buildLPortDispatcherFlow(interVpnLinkName, vpnId,
+                                                                lportTagOfOtherEndpoint.intValue());
+            result.add(mdsalManager.installFlow(dpnId, lportDispatcherFlow));
         }
+
+        return result;
     }
 
     /**
      * Builds a Flow to be installed into LPortDispatcher table, that matches on
-     * SI=2 + vpnLinkEndpointPseudoPortTag and sends to FIB
+     * SI=2 + vpnLinkEndpointPseudoPortTag and sends to FIB.
      *
      * @param interVpnLinkName The name of the InterVpnLink
      * @param vpnId Dataplane identifier of the VPN, the Vrf Tag.
@@ -198,137 +210,76 @@ public class InterVpnLinkUtil {
      */
     public static Flow buildLPortDispatcherFlow(String interVpnLinkName, long vpnId, int lportTag) {
         LOG.info("Inter-vpn-link : buildLPortDispatcherFlow. vpnId {}   lportTag {} ", vpnId, lportTag);
-        List<MatchInfo> matches = Arrays.asList(new MatchInfo(MatchFieldType.metadata,
-                new BigInteger[] {
+        List<MatchInfo> matches = Collections.singletonList(new MatchMetadata(
                         MetaDataUtil.getMetaDataForLPortDispatcher(lportTag,
                                 ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants.L3VPN_SERVICE_INDEX)),
-                        MetaDataUtil.getMetaDataMaskForLPortDispatcher() }));
+                        MetaDataUtil.getMetaDataMaskForLPortDispatcher()));
         String flowRef = getLportDispatcherFlowRef(interVpnLinkName, lportTag);
-        Flow lPortDispatcherFlow = MDSALUtil.buildFlowNew(NwConstants.LPORT_DISPATCHER_TABLE, flowRef,
-                VpnConstants.DEFAULT_LPORT_DISPATCHER_FLOW_PRIORITY, flowRef,
-                0, 0, VpnUtil.getCookieL3((int) vpnId), matches,
-                buildLportDispatcherTableInstructions(vpnId));
-        return lPortDispatcherFlow;
+
+        return MDSALUtil.buildFlowNew(NwConstants.LPORT_DISPATCHER_TABLE, flowRef,
+                                      VpnConstants.DEFAULT_LPORT_DISPATCHER_FLOW_PRIORITY, flowRef,
+                                      0, 0, VpnUtil.getCookieL3((int) vpnId), matches,
+                                      buildLportDispatcherTableInstructions(vpnId));
     }
 
     /**
      * Builds a flowRef to be assigned to the flow to be installed into
-     * LPortDispatcher table
+     * LPortDispatcher table.
      *
      * @param interVpnLinkName The name of the InterVpnLink
      * @param lportTag Dataplane identifier of the LogicalPort
      * @return the flow reference string
      */
     public static String getLportDispatcherFlowRef(String interVpnLinkName, Integer lportTag) {
-        String flowRef = new StringBuffer().append(VpnConstants.FLOWID_PREFIX).append("INTERVPNLINK")
-                .append(NwConstants.FLOWID_SEPARATOR).append(interVpnLinkName)
-                .append(NwConstants.FLOWID_SEPARATOR).append(lportTag)
-                .append(NwConstants.FLOWID_SEPARATOR).append(ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants.L3VPN_SERVICE_INDEX))
-                .append(NwConstants.FLOWID_SEPARATOR)
-                .append(VpnConstants.DEFAULT_LPORT_DISPATCHER_FLOW_PRIORITY)
-                .toString();
-        return flowRef;
+        return VpnConstants.FLOWID_PREFIX + "INTERVPNLINK" + NwConstants.FLOWID_SEPARATOR + interVpnLinkName
+             + NwConstants.FLOWID_SEPARATOR + lportTag
+             + NwConstants.FLOWID_SEPARATOR + ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME,
+                                                                    NwConstants.L3VPN_SERVICE_INDEX)
+             + NwConstants.FLOWID_SEPARATOR + VpnConstants.DEFAULT_LPORT_DISPATCHER_FLOW_PRIORITY;
     }
 
 
-    public static List<Instruction> buildLportDispatcherTableInstructions (long vpnId) {
+    public static List<Instruction> buildLportDispatcherTableInstructions(long vpnId) {
         int instructionKey = 0;
-        List<Instruction> instructions = new ArrayList<Instruction>();
+        List<Instruction> instructions = new ArrayList<>();
         instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(MetaDataUtil.getVpnIdMetadata(vpnId),
-                MetaDataUtil.METADATA_MASK_VRFID,
-                ++instructionKey));
+            MetaDataUtil.METADATA_MASK_VRFID,
+            ++instructionKey));
         instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.L3_FIB_TABLE, ++instructionKey));
 
         return instructions;
     }
 
     /**
-     * Retrieves the States of all InterVpnLinks
+     * Retrieves the States of all InterVpnLinks.
      *
      * @param broker dataBroker service reference
      * @return the list of objects that holds the InterVpnLink state information
      */
     public static List<InterVpnLinkState> getAllInterVpnLinkState(DataBroker broker) {
         InstanceIdentifier<InterVpnLinkStates> interVpnLinkStateIid =
-                InstanceIdentifier.builder(InterVpnLinkStates.class).build();
+            InstanceIdentifier.builder(InterVpnLinkStates.class).build();
 
         Optional<InterVpnLinkStates> interVpnLinkStateOpData =
-                MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, interVpnLinkStateIid);
+            MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, interVpnLinkStateIid);
 
         return (interVpnLinkStateOpData.isPresent()) ? interVpnLinkStateOpData.get().getInterVpnLinkState()
-                : new ArrayList<InterVpnLinkState>();
-    }
-
-    /**
-     * Retrieves the State of an InterVpnLink
-     *
-     * @param broker dataBroker service reference
-     * @param iVpnLinkName The name of the InterVpnLink
-     * @return the object that contains the State of the specified InterVpnLink
-     *         or Optional.absent() if it doesnt exist
-     */
-    public static Optional<InterVpnLinkState> getInterVpnLinkState(DataBroker broker, String iVpnLinkName) {
-        return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, getInterVpnLinkStateIid(iVpnLinkName));
-    }
-
-    /**
-     * Checks if the specified InterVpnLink is currently Active
-     *
-     * @param broker dataBroker service reference
-     * @param iVpnLinkName The name of the InterVpnLink
-     * @return true if the InterVpnLink is Active
-     */
-    public static boolean isInterVpnLinkActive(DataBroker broker, String iVpnLinkName) {
-        Optional<InterVpnLinkState> optIVpnLinkState = getInterVpnLinkState(broker, iVpnLinkName);
-        if ( ! optIVpnLinkState.isPresent() ) {
-            return false;
-        }
-        InterVpnLinkState iVpnLinkState = optIVpnLinkState.get();
-        return iVpnLinkState.getState() == InterVpnLinkState.State.Active;
-    }
-
-    /**
-     * Retrieves an InterVpnLink by searching by one of its endpoint's IP.
-     *
-     * @param broker dataBroker service reference
-     * @param endpointIp IP to serch for.
-     * @return the InterVpnLink or null if no InterVpnLink can be found
-     */
-    public static Optional<InterVpnLink> getInterVpnLinkByEndpointIp(DataBroker broker, String endpointIp) {
-        List<InterVpnLink> allInterVpnLinks = InterVpnLinkUtil.getAllInterVpnLinks(broker);
-        for (InterVpnLink interVpnLink : allInterVpnLinks) {
-            if (interVpnLink.getFirstEndpoint().getIpAddress().getValue().equals(endpointIp)
-                    || interVpnLink.getSecondEndpoint().getIpAddress().getValue().equals(endpointIp)) {
-                return Optional.of(interVpnLink);
-            }
-        }
-        return Optional.absent();
+            : new ArrayList<>();
     }
 
-
     /**
-     * Retrieves the InterVpnLink that has one of its 2 endpoints installed in
-     * the specified DpnId
+     * Retrieves the State of an InterVpnLink.
      *
      * @param broker dataBroker service reference
-     * @param dpnId Id of the DPN
-     * @return The InterVpnLink object if found, Optional.absent() otherwise
+     * @param interVpnLinkName The name of the InterVpnLink
+     * @return the object that contains the State of the specified InterVpnLink or Optional.absent() if it doesnt exist
      */
-    public static Optional<InterVpnLink> getInterVpnLinkByDpnId(DataBroker broker, BigInteger dpnId) {
-        List<InterVpnLink> allInterVpnLinks = InterVpnLinkUtil.getAllInterVpnLinks(broker);
-        for (InterVpnLink interVpnLink : allInterVpnLinks) {
-            Optional<InterVpnLinkState> optInterVpnLinkState = getInterVpnLinkState(broker, interVpnLink.getName());
-            if ( optInterVpnLinkState.isPresent()
-                    && ( optInterVpnLinkState.get().getFirstEndpointState().getDpId().contains(dpnId)
-                    || optInterVpnLinkState.get().getSecondEndpointState().getDpId().contains(dpnId) ) ) {
-                return Optional.fromNullable(interVpnLink);
-            }
-        }
-        return Optional.absent();
+    public static Optional<InterVpnLinkState> getInterVpnLinkState(DataBroker broker, String interVpnLinkName) {
+        return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, getInterVpnLinkStateIid(interVpnLinkName));
     }
 
     /**
-     * Retrieves all configured InterVpnLinks
+     * Retrieves all configured InterVpnLinks.
      *
      * @param broker dataBroker service reference
      * @return the list of InterVpnLinks
@@ -337,143 +288,132 @@ public class InterVpnLinkUtil {
         InstanceIdentifier<InterVpnLinks> interVpnLinksIid = InstanceIdentifier.builder(InterVpnLinks.class).build();
 
         Optional<InterVpnLinks> interVpnLinksOpData =
-                MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, interVpnLinksIid);
-
-        return (interVpnLinksOpData.isPresent()) ? interVpnLinksOpData.get().getInterVpnLink()
-                : new ArrayList<InterVpnLink>();
-    }
+            MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, interVpnLinksIid);
 
-    /**
-     * Retrieves the list of DPNs where the endpoint of a VPN in an InterVPNLink was instantiated
-     *
-     * @param broker dataBroker service reference
-     * @param vpnLinkName the name of the InterVpnLink
-     * @param vpnUuid UUID of the VPN whose endpoint to be checked
-     * @return the list of DPN Ids
-     */
-    public static List<BigInteger> getVpnLinkEndpointDPNs(DataBroker broker, String vpnLinkName, String vpnUuid) {
-        Optional<InterVpnLinkState> interVpnLinkState = getInterVpnLinkState(broker, vpnLinkName);
-        if ( interVpnLinkState.isPresent()) {
-            if (interVpnLinkState.get().getFirstEndpointState().getVpnUuid().getValue().equals(vpnUuid)) {
-                return interVpnLinkState.get().getFirstEndpointState().getDpId();
-            } else {
-                return interVpnLinkState.get().getSecondEndpointState().getDpId();
-            }
-        } else {
-            LOG.trace("Could not find InterVpnLinkState for interVpnLink {}", vpnLinkName);
-            return new ArrayList<BigInteger>();
-        }
+        return interVpnLinksOpData.isPresent() ? interVpnLinksOpData.get().getInterVpnLink()
+            : new ArrayList<>();
     }
 
     /**
-     * Retrieves the list of DPNs where the endpoint of a VPN in an InterVPNLink was instantiated
+     * Leaks a route from one VPN to another. By default, the origin for this leaked route is INTERVPN.
      *
      * @param broker dataBroker service reference
-     * @param endpointIp Ip of the endpoint specified in the InterVpnLink
-     * @return the list of DPN Ids
-     */
-    public static List<BigInteger> getVpnLinkEndpointDPNsByIp(DataBroker broker, String endpointIp) {
-        Optional<InterVpnLink> optIVpnLink = getInterVpnLinkByEndpointIp(broker, endpointIp);
-        if ( optIVpnLink.isPresent() ) {
-            InterVpnLink iVpnLink = optIVpnLink.get();
-            boolean isFirstEndpoint = iVpnLink.getFirstEndpoint().getIpAddress().getValue().equals(endpointIp);
-            return isFirstEndpoint ? getVpnLinkEndpointDPNs(broker, iVpnLink.getName(),
-                    iVpnLink.getFirstEndpoint().getVpnUuid().getValue())
-                    : getVpnLinkEndpointDPNs(broker, iVpnLink.getName(),
-                    iVpnLink.getSecondEndpoint().getVpnUuid().getValue());
-        } else {
-            LOG.trace("Could not find an InterVpnLink with endpoint IpAddr={}", endpointIp);
-            return new ArrayList<BigInteger>();
-        }
-    }
-
-
-    /**
-     * Leaks a route from one VPN to another. By default, the origin for this leaked route is INTERVPN
-     *
-     * @param broker           dataBroker service reference
-     * @param bgpManager       Used to advertise routes to the BGP Router
-     * @param interVpnLink     Reference to the object that holds the info about the link between the 2 VPNs
-     * @param srcVpnUuid       UUID of the VPN that has the route that is going to be leaked to the other VPN
-     * @param dstVpnUuid       UUID of the VPN that is going to receive the route
-     * @param prefix           Prefix of the route
-     * @param label            Label of the route in the original VPN
+     * @param bgpManager Used to advertise routes to the BGP Router
+     * @param interVpnLink Reference to the object that holds the info about the link between the 2 VPNs
+     * @param srcVpnUuid UUID of the VPN that has the route that is going to be leaked to the other VPN
+     * @param dstVpnUuid UUID of the VPN that is going to receive the route
+     * @param prefix Prefix of the route
+     * @param label Label of the route in the original VPN
      */
     public static void leakRoute(DataBroker broker, IBgpManager bgpManager, InterVpnLink interVpnLink,
-                                 String srcVpnUuid, String dstVpnUuid, String prefix, Long label) {
+        String srcVpnUuid, String dstVpnUuid, String prefix, Long label) {
         leakRoute(broker, bgpManager, interVpnLink, srcVpnUuid, dstVpnUuid, prefix, label, RouteOrigin.INTERVPN);
     }
 
     /**
      * Leaks a route from one VPN to another.
      *
-     * @param broker           dataBroker service reference
-     * @param bgpManager       Used to advertise routes to the BGP Router
-     * @param interVpnLink     Reference to the object that holds the info about the link between the 2 VPNs
-     * @param srcVpnUuid       UUID of the VPN that has the route that is going to be leaked to the other VPN
-     * @param dstVpnUuid       UUID of the VPN that is going to receive the route
-     * @param prefix           Prefix of the route
-     * @param label            Label of the route in the original VPN
-     * @param forcedOrigin     By default, origin for leaked routes should be INTERVPN, however it is possible to
-     *                         provide a different origin if desired.
+     * @param broker dataBroker service reference
+     * @param bgpManager Used to advertise routes to the BGP Router
+     * @param interVpnLink Reference to the object that holds the info about the link between the 2 VPNs
+     * @param srcVpnUuid UUID of the VPN that has the route that is going to be leaked to the other VPN
+     * @param dstVpnUuid UUID of the VPN that is going to receive the route
+     * @param prefix Prefix of the route
+     * @param label Label of the route in the original VPN
+     * @param forcedOrigin By default, origin for leaked routes should be INTERVPN, however it is possible to provide
+     *     a different origin if desired.
      */
+    // TODO Clean up the exception handling
+    @SuppressWarnings("checkstyle:IllegalCatch")
     public static void leakRoute(DataBroker broker, IBgpManager bgpManager, InterVpnLink interVpnLink,
-                                 String srcVpnUuid, String dstVpnUuid, String prefix, Long label,
-                                 RouteOrigin forcedOrigin) {
+        String srcVpnUuid, String dstVpnUuid, String prefix, Long label,
+        RouteOrigin forcedOrigin) {
         Preconditions.checkNotNull(interVpnLink);
 
         // The source VPN must participate in the InterVpnLink
         Preconditions.checkArgument(interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(srcVpnUuid)
-                        || interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(srcVpnUuid),
-                "The source VPN {} does not participate in the interVpnLink {}",
-                srcVpnUuid, interVpnLink.getName());
+                || interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(srcVpnUuid),
+            "The source VPN {} does not participate in the interVpnLink {}",
+            srcVpnUuid, interVpnLink.getName());
         // The destination VPN must participate in the InterVpnLink
         Preconditions.checkArgument(interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(dstVpnUuid)
-                        || interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(dstVpnUuid),
-                "The destination VPN {} does not participate in the interVpnLink {}",
-                dstVpnUuid, interVpnLink.getName());
+                || interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(dstVpnUuid),
+            "The destination VPN {} does not participate in the interVpnLink {}",
+            dstVpnUuid, interVpnLink.getName());
 
         boolean destinationIs1stEndpoint = interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(dstVpnUuid);
 
-        String endpointIp = (destinationIs1stEndpoint) ? interVpnLink.getSecondEndpoint().getIpAddress().getValue()
-                : interVpnLink.getFirstEndpoint().getIpAddress().getValue();
+        String endpointIp = destinationIs1stEndpoint ? interVpnLink.getSecondEndpoint().getIpAddress().getValue()
+            : interVpnLink.getFirstEndpoint().getIpAddress().getValue();
 
-        VrfEntry newVrfEntry = new VrfEntryBuilder().setKey(new VrfEntryKey(prefix)).setDestPrefix(prefix)
-                .setLabel(label).setNextHopAddressList(Arrays.asList(endpointIp))
-                .setOrigin(RouteOrigin.INTERVPN.getValue())
-                .build();
+        VrfEntry newVrfEntry = FibHelper.getVrfEntryBuilder(prefix, label, endpointIp, RouteOrigin.INTERVPN,
+                null /* parentVpnRd */).build();
 
         String dstVpnRd = VpnUtil.getVpnRd(broker, dstVpnUuid);
         InstanceIdentifier<VrfEntry> newVrfEntryIid =
-                InstanceIdentifier.builder(FibEntries.class)
-                        .child(VrfTables.class, new VrfTablesKey(dstVpnRd))
-                        .child(VrfEntry.class, new VrfEntryKey(newVrfEntry.getDestPrefix()))
-                        .build();
+            InstanceIdentifier.builder(FibEntries.class)
+                .child(VrfTables.class, new VrfTablesKey(dstVpnRd))
+                .child(VrfEntry.class, new VrfEntryKey(newVrfEntry.getDestPrefix()))
+                .build();
         VpnUtil.asyncWrite(broker, LogicalDatastoreType.CONFIGURATION, newVrfEntryIid, newVrfEntry);
 
         // Finally, route is advertised it to the DC-GW. But while in the FibEntries the nexthop is the other
         // endpoint's IP, in the DC-GW the nexthop for those prefixes are the IPs of those DPNs where the target
         // VPN has been instantiated
         Optional<InterVpnLinkState> optVpnLinkState = getInterVpnLinkState(broker, interVpnLink.getName());
-        if ( optVpnLinkState.isPresent() ) {
+        if (optVpnLinkState.isPresent()) {
             InterVpnLinkState vpnLinkState = optVpnLinkState.get();
-            List<BigInteger> dpnIdList = (destinationIs1stEndpoint) ? vpnLinkState.getFirstEndpointState().getDpId()
-                    : vpnLinkState.getSecondEndpointState().getDpId();
-            List<String> nexthops = new ArrayList<String>();
+            List<BigInteger> dpnIdList = destinationIs1stEndpoint ? vpnLinkState.getFirstEndpointState().getDpId()
+                : vpnLinkState.getSecondEndpointState().getDpId();
+            List<String> nexthops = new ArrayList<>();
             for (BigInteger dpnId : dpnIdList) {
                 nexthops.add(InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId));
             }
             try {
                 LOG.debug("Advertising route in VPN={} [prefix={} label={}  nexthops={}] to DC-GW",
-                        dstVpnRd, newVrfEntry.getDestPrefix(), label.intValue(), nexthops);
-                bgpManager.advertisePrefix(dstVpnRd, newVrfEntry.getDestPrefix(), nexthops, label.intValue());
+                    dstVpnRd, newVrfEntry.getDestPrefix(), label.intValue(), nexthops);
+                bgpManager.advertisePrefix(dstVpnRd, null /*macAddress*/, newVrfEntry.getDestPrefix(), nexthops,
+                        VrfEntry.EncapType.Mplsgre, label.intValue(), 0 /*l3vni*/, 0 /*l2vni*/,
+                        null /*gatewayMacAddress*/);
             } catch (Exception exc) {
                 LOG.error("Could not advertise prefix {} with label {} to VPN rd={}",
-                        newVrfEntry.getDestPrefix(), label.intValue(), dstVpnRd);
+                    newVrfEntry.getDestPrefix(), label.intValue(), dstVpnRd);
             }
         } else {
             LOG.warn("Error when advertising leaked routes: Could not find State for InterVpnLink={}",
-                    interVpnLink.getName());
+                interVpnLink.getName());
+        }
+    }
+
+    public static void handleStaticRoute(InterVpnLinkDataComposite interVpnLink, String vpnName,
+        String destination, String nexthop, int label,
+        DataBroker dataBroker, IFibManager fibManager, IBgpManager bgpManager) throws Exception {
+
+        LOG.debug("handleStaticRoute [vpnLink={} srcVpn={} destination={} nextHop={} label={}]",
+            interVpnLink.getInterVpnLinkName(), vpnName, destination, nexthop, label);
+
+        String vpnRd = VpnUtil.getVpnRd(dataBroker, vpnName);
+        if (vpnRd == null) {
+            LOG.warn("Could not find Route-Distinguisher for VpnName {}", vpnName);
+            return;
         }
+        LOG.debug("Writing FibEntry to DS:  vpnRd={}, prefix={}, label={}, nexthop={} (interVpnLink)",
+            vpnRd, destination, label, nexthop);
+        fibManager.addOrUpdateFibEntry(dataBroker, vpnRd, null /*macAddress*/, destination,
+                Collections.singletonList(nexthop), VrfEntry.EncapType.Mplsgre, label,
+                0 /*l3vni*/, null /*gatewayMacAddress*/, null /*parentVpnRd*/, RouteOrigin.STATIC, null /*writeTxn*/);
+
+        // Now advertise to BGP. The nexthop that must be advertised to BGP are the IPs of the DPN where the
+        // VPN's endpoint have been instantiated
+        // List<String> nexthopList = new ArrayList<>(); // The nexthops to be advertised to BGP
+        List<BigInteger> endpointDpns = interVpnLink.getEndpointDpnsByVpnName(vpnName);
+        List<String> nexthopList =
+            endpointDpns.stream().map(dpnId -> InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId))
+                        .collect(Collectors.toList());
+        LOG.debug("advertising IVpnLink route to BGP:  vpnRd={}, prefix={}, label={}, nexthops={}",
+            vpnRd, destination, label, nexthopList);
+        bgpManager.advertisePrefix(vpnRd, null /*macAddress*/, destination, nexthopList,
+                VrfEntry.EncapType.Mplsgre, label, 0 /*l3vni*/, 0 /*l2vni*/,
+                null /*gatewayMacAddress*/);
     }
 }