acdbf84960ead5fc7008c0b22702081138bdecd0
[netvirt.git] / vpnservice / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / netvirt / vpnmanager / VpnInterfaceManager.java
1 /*
2  * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.netvirt.vpnmanager;
9
10 import com.google.common.base.*;
11 import com.google.common.collect.FluentIterable;
12 import com.google.common.collect.Iterators;
13 import com.google.common.util.concurrent.ListenableFuture;
14 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
15 import org.opendaylight.netvirt.bgpmanager.api.RouteOrigin;
16 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
17 import org.opendaylight.netvirt.vpnmanager.utilities.InterfaceUtils;
18
19 import com.google.common.util.concurrent.FutureCallback;
20 import com.google.common.util.concurrent.Futures;
21 import com.google.common.util.concurrent.JdkFutureAdapters;
22
23 import org.opendaylight.controller.md.sal.binding.api.*;
24 import org.opendaylight.genius.mdsalutil.*;
25 import org.opendaylight.genius.mdsalutil.AbstractDataChangeListener;
26 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.VpnTargets;
27 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTarget;
28 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceBuilder;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeExternal;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeHwvtep;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeInternal;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelsState;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.LabelRouteMap;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.SubnetRoute;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.SubnetRouteBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfo;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoKey;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.*;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.add.dpn.event.AddEventData;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.add.dpn.event.AddEventDataBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnListBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnListKey;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesListBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesListKey;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfaces;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfacesBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfacesKey;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.remove.dpn.event.RemoveEventData;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.remove.dpn.event.RemoveEventDataBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesKey;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
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.VrfTablesBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilService;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpResponseInput;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpResponseInputBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
77
78 import java.math.BigInteger;
79 import java.util.Collection;
80 import java.util.List;
81 import java.util.ArrayList;
82 import java.util.Arrays;
83 import java.util.Iterator;
84 import java.util.concurrent.ConcurrentHashMap;
85 import java.util.concurrent.Executors;
86 import java.util.concurrent.ExecutorService;
87 import java.util.concurrent.Future;
88
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
92 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NeutronvpnService;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLink;
96 import org.opendaylight.yangtools.concepts.ListenerRegistration;
97 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
98 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
99 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
100 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
101 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
104 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
105 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig;
106 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
107 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
108 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceKey;
109 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
110 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
111 import org.opendaylight.yangtools.yang.common.RpcError;
112 import org.opendaylight.yangtools.yang.common.RpcResult;
113 import org.slf4j.Logger;
114 import org.slf4j.LoggerFactory;
115
116 public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface> implements AutoCloseable {
117     private static final Logger LOG = LoggerFactory.getLogger(VpnInterfaceManager.class);
118     private ListenerRegistration<DataChangeListener> listenerRegistration, opListenerRegistration, tunnelInterfaceStateListenerRegistration;
119     private final DataBroker broker;
120     private final IBgpManager bgpManager;
121     private IFibManager fibManager;
122     private IMdsalApiManager mdsalManager;
123     private OdlInterfaceRpcService ifaceMgrRpcService;
124     private ItmRpcService itmProvider;
125     private IdManagerService idManager;
126     private OdlArputilService arpManager;
127     private NeutronvpnService neuService;
128     private VpnSubnetRouteHandler vpnSubnetRouteHandler;
129     private ConcurrentHashMap<String, Runnable> vpnIntfMap = new ConcurrentHashMap<String, Runnable>();
130     private ExecutorService executorService = Executors.newSingleThreadExecutor();
131     private InterfaceStateChangeListener interfaceListener;
132     private TunnelInterfaceStateListener tunnelInterfaceStateListener;
133     private VpnInterfaceOpListener vpnInterfaceOpListener;
134     private ArpNotificationHandler arpNotificationHandler;
135     private NotificationPublishService notificationPublishService;
136     private FibRpcService fibService;
137     protected enum UpdateRouteAction {
138         ADVERTISE_ROUTE, WITHDRAW_ROUTE
139     }
140
141     /**
142      * Responsible for listening to data change related to VPN Interface
143      * Bind VPN Service on the interface and informs the BGP service
144      *
145      * @param db - dataBroker service reference
146      * @param bgpManager Used to advertise routes to the BGP Router
147      * @param notificationService Used to subscribe to notification events
148      */
149     public VpnInterfaceManager(final DataBroker db, final IBgpManager bgpManager, NotificationService notificationService) {
150         super(VpnInterface.class);
151         broker = db;
152         this.bgpManager = bgpManager;
153         interfaceListener = new InterfaceStateChangeListener(db, this);
154         vpnInterfaceOpListener = new VpnInterfaceOpListener();
155         arpNotificationHandler = new ArpNotificationHandler(this, broker);
156         vpnSubnetRouteHandler = new VpnSubnetRouteHandler(broker, bgpManager, this);
157         tunnelInterfaceStateListener = new TunnelInterfaceStateListener(broker, this);
158         notificationService.registerNotificationListener(vpnSubnetRouteHandler);
159         notificationService.registerNotificationListener(arpNotificationHandler);
160         registerListener(db);
161     }
162
163     public void setMdsalManager(IMdsalApiManager mdsalManager) {
164         this.mdsalManager = mdsalManager;
165     }
166
167     public void setIfaceMgrRpcService(OdlInterfaceRpcService ifMgrRpcService) {
168         this.ifaceMgrRpcService = ifMgrRpcService;
169         interfaceListener.setIfaceMgrRpcService(ifMgrRpcService);
170     }
171
172     public void setITMProvider(ItmRpcService itmProvider) {
173         this.itmProvider = itmProvider;
174     }
175
176
177     public void setFibManager(IFibManager fibManager) {
178         this.fibManager = fibManager;
179     }
180
181     public IFibManager getFibManager() {
182         return this.fibManager;
183     }
184
185
186     public void setIdManager(IdManagerService idManager) {
187         this.idManager = idManager;
188         vpnSubnetRouteHandler.setIdManager(idManager);
189     }
190
191     public void setArpManager(OdlArputilService arpManager) {
192         this.arpManager = arpManager;
193     }
194
195     void setNotificationPublishService(NotificationPublishService notificationPublishService) {
196         this.notificationPublishService = notificationPublishService;
197     }
198
199     public void setNeutronvpnManager(NeutronvpnService neuService) { this.neuService = neuService; }
200
201     public void setFibRpcService(FibRpcService fibService) {
202         this.fibService = fibService;
203     }
204
205     public FibRpcService getFibRpcService() {
206         return fibService;
207     }
208
209     public VpnSubnetRouteHandler getVpnSubnetRouteHandler() {
210         return this.vpnSubnetRouteHandler;
211     }
212
213     @Override
214     public void close() throws Exception {
215         if (listenerRegistration != null) {
216             try {
217                 listenerRegistration.close();
218                 opListenerRegistration.close();
219             } catch (final Exception e) {
220                 LOG.error("Error when cleaning up DataChangeListener.", e);
221             }
222             listenerRegistration = null;
223             opListenerRegistration = null;
224         }
225         LOG.info("VPN Interface Manager Closed");
226     }
227
228     private void registerListener(final DataBroker db) {
229         try {
230             listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
231                     getWildCardPath(), VpnInterfaceManager.this, DataChangeScope.SUBTREE);
232             opListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
233                                                                    getWildCardPath(), vpnInterfaceOpListener, DataChangeScope.SUBTREE);
234             tunnelInterfaceStateListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
235                     getTunnelInterfaceStateListenerPath(), tunnelInterfaceStateListener, DataChangeScope.SUBTREE);
236         } catch (final Exception e) {
237             LOG.error("VPN Service DataChange listener registration fail!", e);
238             throw new IllegalStateException("VPN Service registration Listener failed.", e);
239         }
240     }
241
242     private InstanceIdentifier<StateTunnelList> getTunnelInterfaceStateListenerPath() {
243         return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class);
244     }
245
246     private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> getInterfaceListenerPath() {
247         return InstanceIdentifier.create(InterfacesState.class)
248             .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class);
249     }
250
251     @Override
252     public void add(final InstanceIdentifier<VpnInterface> identifier, final VpnInterface vpnInterface) {
253         LOG.trace("VPN Interface add event - key: {}, value: {}" ,identifier, vpnInterface );
254         final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
255         String interfaceName = key.getName();
256
257         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState =
258             InterfaceUtils.getInterfaceStateFromOperDS(broker, interfaceName);
259         if(interfaceState != null){
260             BigInteger dpnId = BigInteger.ZERO;
261             try{
262                 dpnId = InterfaceUtils.getDpIdFromInterface(interfaceState);
263             }catch (Exception e){
264                 LOG.error("Unable to retrieve dpnId from interface operational data store for interface {}. ", interfaceName, e);
265                 return;
266             }
267             processVpnInterfaceUp(InterfaceUtils.getDpIdFromInterface(interfaceState), interfaceName,
268                                   interfaceState.getIfIndex(), false);
269         } else {
270             LOG.info("Handling addition of VPN interface {} skipped as interfaceState is not available", interfaceName);
271         }
272     }
273
274     protected void processVpnInterfaceUp(BigInteger dpId, String interfaceName, int lPortTag, boolean isInterfaceUp) {
275
276         VpnInterface vpnInterface = VpnUtil.getConfiguredVpnInterface(broker, interfaceName);
277         if(vpnInterface == null) {
278             LOG.info("Unable to process add/up for interface {} as it is not configured", interfaceName);
279             return;
280         }
281         if (!isInterfaceUp) {
282             String vpnName = vpnInterface.getVpnInstanceName();
283             LOG.info("Binding vpn service to interface {} ", interfaceName);
284             long vpnId = VpnUtil.getVpnId(broker, vpnName);
285             if (vpnId == VpnConstants.INVALID_ID) {
286                 LOG.trace("VpnInstance to VPNId mapping is not yet available, bailing out now.");
287                 return;
288             }
289             boolean waitForVpnInterfaceOpRemoval = false;
290             int numAdjs = 0;
291             VpnInterface opVpnInterface = null;
292             synchronized (interfaceName.intern()) {
293                 opVpnInterface = VpnUtil.getOperationalVpnInterface(broker, vpnInterface.getName());
294                 if (opVpnInterface != null ) {
295                     String opVpnName = opVpnInterface.getVpnInstanceName();
296                     String primaryInterfaceIp = null;
297                     if(opVpnName.equals(vpnName)) {
298                         // Please check if the primary VRF Entry does not exist for VPNInterface
299                         // If so, we have to process ADD, as this might be a DPN Restart with Remove and Add triggered
300                         // back to back
301                         // However, if the primary VRF Entry for this VPNInterface exists, please continue bailing out !
302                         List<Adjacency> adjs = VpnUtil.getAdjacenciesForVpnInterfaceFromConfig(broker, interfaceName);
303                         if (adjs == null) {
304                             LOG.info("VPN Interface {} addition failed as adjacencies for this vpn interface could not be obtained", interfaceName);
305                             return;
306                         }
307                         numAdjs = adjs.size();
308                         for (Adjacency adj : adjs) {
309                             if (adj.getMacAddress() != null && !adj.getMacAddress().isEmpty()) {
310                                 primaryInterfaceIp = adj.getIpAddress();
311                                 break;
312                             }
313                         }
314                         if (primaryInterfaceIp == null) {
315                             LOG.info("VPN Interface {} addition failed as primary adjacency for this vpn interface could not be obtained", interfaceName);
316                             return;
317                         }
318                         // Get the rd of the vpn instance
319                         String rd = getRouteDistinguisher(opVpnName);
320                         VrfEntry vrf = VpnUtil.getVrfEntry(broker, rd, primaryInterfaceIp);
321                             if (vrf != null) {
322                                 LOG.info("VPN Interface {} already provisioned , bailing out from here.", interfaceName);
323                                 return;
324                             }
325                         waitForVpnInterfaceOpRemoval = true;
326                     } else {
327                         LOG.info("vpn interface {} to go to configured vpn {}, but in operational vpn {}",
328                              interfaceName, vpnName, opVpnName);
329                     }
330                 }
331                 if (!waitForVpnInterfaceOpRemoval) {
332                     // Add the VPNInterface and quit
333                     bindService(dpId, vpnName, interfaceName, lPortTag);
334                     updateDpnDbs(dpId, vpnName, interfaceName, true);
335                     processVpnInterfaceAdjacencies(dpId, VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()),
336                         vpnInterface);
337                     return;
338                 }
339             }
340
341             // FIB didn't get a chance yet to clean up this VPNInterface
342             // Let us give it a chance here !
343             LOG.info("VPN Interface {} waiting for FIB to clean up! ", interfaceName);
344             try {
345                 Runnable notifyTask = new VpnNotifyTask();
346                 vpnIntfMap.put(interfaceName, notifyTask);
347                 synchronized (notifyTask) {
348                     try {
349                         notifyTask.wait(VpnConstants.MAX_WAIT_TIME_IN_MILLISECONDS);
350                     } catch (InterruptedException e) {
351                     }
352                 }
353             } finally {
354                 vpnIntfMap.remove(interfaceName);
355             }
356
357             opVpnInterface = VpnUtil.getOperationalVpnInterface(broker, interfaceName);
358             if (opVpnInterface != null) {
359                 LOG.error("VPN Interface {} removal by FIB did not complete on time, bailing addition ...", interfaceName);
360                 return;
361             }
362             // VPNInterface got removed, proceed with Add
363             synchronized (interfaceName.intern()) {
364                 bindService(dpId, vpnName, interfaceName, lPortTag);
365                 updateDpnDbs(dpId, vpnName, interfaceName, true);
366                 processVpnInterfaceAdjacencies(dpId, VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()),
367                                                vpnInterface);
368             }
369         } else {
370             synchronized (interfaceName.intern()) {
371                 // Interface is retained in the DPN, but its Link Up.
372                 // Advertise prefixes again for this interface to BGP
373                 advertiseAdjacenciesForVpnToBgp(dpId, VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()),
374                         vpnInterface);
375             }
376         }
377     }
378
379     private void advertiseAdjacenciesForVpnToBgp(BigInteger dpnId, final InstanceIdentifier<VpnInterface> identifier, VpnInterface intf) {
380         //Read NextHops
381         InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
382         Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
383
384         String rd = VpnUtil.getVpnRd(broker, intf.getVpnInstanceName());
385         if (rd == null) {
386             LOG.error("advertiseAdjacenciesForVpnFromBgp: Unable to recover rd for interface {} in vpn {}",
387                     intf.getName(), intf.getVpnInstanceName());
388             return;
389         } else {
390             if (rd.equals(intf.getVpnInstanceName())) {
391                 LOG.info("advertiseAdjacenciesForVpnFromBgp: Ignoring BGP advertisement for interface {} as it is in " +
392                         "internal vpn{} with rd {}", intf.getName(), intf.getVpnInstanceName(), rd);
393
394                 return;
395             }
396         }
397         LOG.info("advertiseAdjacenciesForVpnToBgp: Advertising interface {} in vpn {} with rd {} ", intf.getName(),
398                 intf.getVpnInstanceName(), rd);
399
400         String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
401         if (nextHopIp == null){
402             LOG.trace("advertiseAdjacenciesForVpnToBgp: NextHop for interface {} is null, returning", intf.getName());
403             return;
404         }
405
406         if (adjacencies.isPresent()) {
407             List<Adjacency> nextHops = adjacencies.get().getAdjacency();
408
409             if (!nextHops.isEmpty()) {
410                 LOG.trace("NextHops are " + nextHops);
411                 for (Adjacency nextHop : nextHops) {
412                     long label = nextHop.getLabel();
413                     try {
414                         LOG.info("VPN ADVERTISE: Adding Fib Entry rd {} prefix {} nexthop {} label {}", rd, nextHop.getIpAddress(), nextHopIp, label);
415                         bgpManager.advertisePrefix(rd, nextHop.getIpAddress(), nextHopIp, (int)label);
416                         LOG.info("VPN ADVERTISE: Added Fib Entry rd {} prefix {} nexthop {} label {}", rd, nextHop.getIpAddress(), nextHopIp, label);
417                     } catch(Exception e) {
418                         LOG.error("Failed to advertise prefix {} in vpn {} with rd {} for interface {} ",
419                                 nextHop.getIpAddress(), intf.getVpnInstanceName(), rd, intf.getName(), e);
420                     }
421                 }
422             }
423         }
424     }
425
426     private void withdrawAdjacenciesForVpnFromBgp(final InstanceIdentifier<VpnInterface> identifier, VpnInterface intf) {
427         //Read NextHops
428         InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
429         Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
430
431         String rd = VpnUtil.getVpnRd(broker, intf.getVpnInstanceName());
432         if (rd == null) {
433             LOG.error("withdrawAdjacenciesForVpnFromBgp: Unable to recover rd for interface {} in vpn {}",
434                     intf.getName(), intf.getVpnInstanceName());
435             return;
436         } else {
437             if (rd.equals(intf.getVpnInstanceName())) {
438                 LOG.info("withdrawAdjacenciesForVpnFromBgp: Ignoring BGP withdrawal for interface {} as it is in " +
439                         "internal vpn{} with rd {}", intf.getName(), intf.getVpnInstanceName(), rd);
440                 return;
441             }
442         }
443         LOG.info("withdrawAdjacenciesForVpnFromBgp: For interface {} in vpn {} with rd {}", intf.getName(),
444                 intf.getVpnInstanceName(), rd);
445         if (adjacencies.isPresent()) {
446             List<Adjacency> nextHops = adjacencies.get().getAdjacency();
447
448             if (!nextHops.isEmpty()) {
449                 LOG.trace("NextHops are " + nextHops);
450                 for (Adjacency nextHop : nextHops) {
451                     try {
452                         LOG.info("VPN WITHDRAW: Removing Fib Entry rd {} prefix {}", rd, nextHop.getIpAddress());
453                         bgpManager.withdrawPrefix(rd, nextHop.getIpAddress());
454                         LOG.info("VPN WITHDRAW: Removed Fib Entry rd {} prefix {}", rd, nextHop.getIpAddress());
455                     } catch(Exception e) {
456                         LOG.error("Failed to withdraw prefix {} in vpn {} with rd {} for interface {} ",
457                                 nextHop.getIpAddress(), intf.getVpnInstanceName(), rd, intf.getName(), e);
458                     }
459                 }
460             }
461         }
462     }
463
464     private void updateDpnDbs(BigInteger dpId, String vpnName, String interfaceName, boolean add) {
465         long vpnId = VpnUtil.getVpnId(broker, vpnName);
466         if (dpId == null) {
467             dpId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, interfaceName);
468         }
469         if(!dpId.equals(BigInteger.ZERO)) {
470             if(add)
471                 updateMappingDbs(vpnId, dpId, interfaceName, vpnName);
472             else
473                 removeFromMappingDbs(vpnId, dpId, interfaceName, vpnName);
474         }
475
476     }
477
478     private void bindService(BigInteger dpId, String vpnInstanceName, String vpnInterfaceName, int lPortTag) {
479         int priority = VpnConstants.DEFAULT_FLOW_PRIORITY;
480         long vpnId = VpnUtil.getVpnId(broker, vpnInstanceName);
481
482         int instructionKey = 0;
483         List<Instruction> instructions = new ArrayList<Instruction>();
484
485         instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID, ++instructionKey));
486         instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.L3_FIB_TABLE, ++instructionKey));
487
488         BoundServices
489             serviceInfo =
490             InterfaceUtils.getBoundServices(String.format("%s.%s.%s", "vpn",vpnInstanceName, vpnInterfaceName),
491                                             VpnConstants.L3VPN_SERVICE_IDENTIFIER, priority,
492                                             VpnConstants.COOKIE_VM_INGRESS_TABLE, instructions);
493         VpnUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
494                           InterfaceUtils.buildServiceId(vpnInterfaceName, VpnConstants.L3VPN_SERVICE_IDENTIFIER), serviceInfo);
495         makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
496                     vpnId, ArpReplyOrRequest.REQUEST, NwConstants.ADD_FLOW);
497         makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
498                 vpnId, ArpReplyOrRequest.REPLY, NwConstants.ADD_FLOW);
499
500     }
501
502     private void processVpnInterfaceAdjacencies(BigInteger dpnId, final InstanceIdentifier<VpnInterface> identifier,
503                                                 VpnInterface intf) {
504         String intfName = intf.getName();
505         synchronized (intfName) {
506             // Read NextHops
507             InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
508             Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, path);
509
510             if (adjacencies.isPresent()) {
511                 List<Adjacency> nextHops = adjacencies.get().getAdjacency();
512                 List<Adjacency> value = new ArrayList<>();
513
514                 // Get the rd of the vpn instance
515                 String rd = getRouteDistinguisher(intf.getVpnInstanceName());
516
517                 String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
518                 if (nextHopIp == null){
519                     LOG.error("NextHop for interface {} is null", intfName);
520                     return;
521                 }
522                 List<VpnInstance> vpnsToImportRoute = getVpnsImportingMyRoute(intf.getVpnInstanceName());
523                 LOG.trace("NextHops for interface {} are {}", intfName, nextHops);
524                 for (Adjacency nextHop : nextHops) {
525                     String prefix = VpnUtil.getIpPrefix(nextHop.getIpAddress());
526                     long label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME, VpnUtil
527                             .getNextHopLabelKey((rd == null) ? intf.getVpnInstanceName() : rd, prefix));
528                     List<String> adjNextHop = nextHop.getNextHopIpList();
529                     value.add(new AdjacencyBuilder(nextHop).setLabel(label).setNextHopIpList(
530                             (adjNextHop != null && !adjNextHop.isEmpty()) ? adjNextHop : Arrays.asList(nextHopIp))
531                             .setIpAddress(prefix).setKey(new AdjacencyKey(prefix)).build());
532                     if (nextHop.getMacAddress() != null && !nextHop.getMacAddress().isEmpty()) {
533                         LOG.trace("Adding prefix {} to interface {} for vpn {}", prefix, intfName, intf.getVpnInstanceName());
534                         VpnUtil.syncUpdate(
535                                 broker,
536                                 LogicalDatastoreType.OPERATIONAL,
537                                 VpnUtil.getPrefixToInterfaceIdentifier(
538                                         VpnUtil.getVpnId(broker, intf.getVpnInstanceName()), prefix),
539                                 VpnUtil.getPrefixToInterface(dpnId, intf.getName(), prefix));
540                     } else {
541                         //Extra route adjacency
542                         // FIXME 4: To be fixed with VPNManager patch
543                         LOG.trace("Adding prefix {} and nexthopList {} as extra-route for vpn", nextHop.getIpAddress(), nextHop.getNextHopIpList(), intf.getVpnInstanceName() );
544                         VpnUtil.syncUpdate(
545                                 broker,
546                                 LogicalDatastoreType.OPERATIONAL,
547                                 VpnUtil.getVpnToExtrarouteIdentifier(
548                                         (rd != null) ? rd : intf.getVpnInstanceName(), nextHop.getIpAddress()),
549                                 VpnUtil.getVpnToExtraroute(nextHop.getIpAddress(), nextHop.getNextHopIpList()));
550                     }
551
552                 }
553
554                 Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(value);
555                 VpnInterface opInterface = VpnUtil.getVpnInterface(intfName, intf.getVpnInstanceName(), aug, dpnId, Boolean.FALSE);
556                 InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(intfName);
557                 VpnUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, interfaceId, opInterface);
558                 long vpnId = VpnUtil.getVpnId(broker, intf.getVpnInstanceName());
559                 for (Adjacency nextHop : aug.getAdjacency()) {
560                     long label = nextHop.getLabel();
561                     List<String> nextHopList = new ArrayList<>(nextHop.getNextHopIpList());
562                     if (rd != null) {
563                         addToLabelMapper(label, dpnId, nextHop.getIpAddress(), nextHopList, vpnId,
564                                 intfName, null,false, rd);
565                         addPrefixToBGP(rd, nextHop.getIpAddress(), nextHopIp, label);
566                         //TODO: ERT - check for VPNs importing my route
567                         for (VpnInstance vpn : vpnsToImportRoute) {
568                             String vpnRd = vpn.getIpv4Family().getRouteDistinguisher();
569                             if (vpnRd != null) {
570                                 LOG.debug("Exporting route with rd {} prefix {} nexthop {} label {} to VPN {}", vpnRd, nextHop.getIpAddress(), nextHopIp, label, vpn);
571                                 VpnUtil.addFibEntryToDS(broker, vpnRd, nextHop.getIpAddress(), nextHopIp, (int) label, RouteOrigin.SELF_IMPORTED);
572                             }
573                         }
574                     } else {
575                         // ### add FIB route directly
576                         VpnUtil.addFibEntryToDS(broker, intf.getVpnInstanceName(), nextHop.getIpAddress(), nextHopIp,
577                                                 (int) label, RouteOrigin.STATIC);
578                     }
579                 }
580             }
581         }
582     }
583
584     private List<VpnInstance> getVpnsImportingMyRoute(final String vpnName) {
585         List<VpnInstance> vpnsToImportRoute = new ArrayList<>();
586
587         InstanceIdentifier<VpnInstance> id = InstanceIdentifier.builder(VpnInstances.class)
588                 .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
589         Optional<VpnInstance> optVpnInstance = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
590         final VpnInstance vpnInstance;
591         if (optVpnInstance.isPresent()) {
592             vpnInstance = optVpnInstance.get();
593         } else {
594             LOG.debug("Could not retrieve vpn instance {} to check for vpns importing the routes", vpnName);
595             return vpnsToImportRoute;
596         }
597
598         Predicate<VpnInstance> excludeVpn = new Predicate<VpnInstance>() {
599             @Override
600             public boolean apply(VpnInstance input) {
601                 return !input.getVpnInstanceName().equals(vpnName);
602             }
603         };
604
605         Predicate<VpnInstance> matchRTs = new Predicate<VpnInstance>() {
606             @Override
607             public boolean apply(VpnInstance input) {
608                 Iterable<String> commonRTs = intersection(getRts(vpnInstance, VpnTarget.VrfRTType.ExportExtcommunity),
609                         getRts(input, VpnTarget.VrfRTType.ImportExtcommunity));
610                 return Iterators.size(commonRTs.iterator()) > 0;
611             }
612         };
613
614         Function<VpnInstance, String> toInstanceName = new Function<VpnInstance, String>() {
615             @Override
616             public String apply(VpnInstance vpnInstance) {
617                 //return vpnInstance.getVpnInstanceName();
618                 return vpnInstance.getIpv4Family().getRouteDistinguisher();
619             }
620         };
621
622         vpnsToImportRoute = FluentIterable.from(VpnUtil.getAllVpnInstance(broker)).
623                 filter(excludeVpn).
624                 filter(matchRTs).toList();
625         return vpnsToImportRoute;
626     }
627
628     private List<VpnInstance> getVpnsExportingMyRoute(final String vpnName) {
629         List<VpnInstance> vpnsToExportRoute = new ArrayList<>();
630
631         InstanceIdentifier<VpnInstance> id = InstanceIdentifier.builder(VpnInstances.class)
632                 .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
633         Optional<VpnInstance> optVpnInstance = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
634         final VpnInstance vpnInstance;
635         if (optVpnInstance.isPresent()) {
636             vpnInstance = optVpnInstance.get();
637         } else {
638             LOG.debug("Could not retrieve vpn instance {} to check for vpns exporting the routes", vpnName);
639             return vpnsToExportRoute;
640         }
641
642         Predicate<VpnInstance> excludeVpn = new Predicate<VpnInstance>() {
643             @Override
644             public boolean apply(VpnInstance input) {
645                 return !input.getVpnInstanceName().equals(vpnName);
646             }
647         };
648
649         Predicate<VpnInstance> matchRTs = new Predicate<VpnInstance>() {
650             @Override
651             public boolean apply(VpnInstance input) {
652                 Iterable<String> commonRTs = intersection(getRts(vpnInstance, VpnTarget.VrfRTType.ImportExtcommunity),
653                         getRts(input, VpnTarget.VrfRTType.ExportExtcommunity));
654                 return Iterators.size(commonRTs.iterator()) > 0;
655             }
656         };
657
658         Function<VpnInstance, String> toInstanceName = new Function<VpnInstance, String>() {
659             @Override
660             public String apply(VpnInstance vpnInstance) {
661                 return vpnInstance.getVpnInstanceName();
662             }
663         };
664
665         vpnsToExportRoute = FluentIterable.from(VpnUtil.getAllVpnInstance(broker)).
666                 filter(excludeVpn).
667                 filter(matchRTs).toList();
668         return vpnsToExportRoute;
669     }
670
671     private <T> Iterable<T> intersection(final Collection<T> collection1, final Collection<T> collection2) {
672         final Predicate<T> inPredicate = Predicates.<T>in(collection2);
673         return new Iterable<T>() {
674             @Override
675             public Iterator<T> iterator() {
676                 return Iterators.filter(collection1.iterator(), inPredicate);
677             }
678         };
679     }
680
681     private List<String> getRts(VpnInstance vpnInstance, VpnTarget.VrfRTType rtType) {
682         String name = vpnInstance.getVpnInstanceName();
683         List<String> rts = new ArrayList<>();
684         VpnAfConfig vpnConfig = vpnInstance.getIpv4Family();
685         if (vpnConfig == null) {
686             LOG.trace("vpn config is not available for {}", name);
687             return rts;
688         }
689         VpnTargets targets = vpnConfig.getVpnTargets();
690         if (targets == null) {
691             LOG.trace("vpn targets not available for {}", name);
692             return rts;
693         }
694         List<VpnTarget> vpnTargets = targets.getVpnTarget();
695         if (vpnTargets == null) {
696             LOG.trace("vpnTarget values not available for {}", name);
697             return rts;
698         }
699         for (VpnTarget target : vpnTargets) {
700             //TODO: Check for RT type is Both
701             if(target.getVrfRTType().equals(rtType) ||
702                     target.getVrfRTType().equals(VpnTarget.VrfRTType.Both)) {
703                 String rtValue = target.getVrfRTValue();
704                 rts.add(rtValue);
705             }
706         }
707         return rts;
708     }
709
710     private List<String> getExportRts(VpnInstance vpnInstance) {
711         List<String> exportRts = new ArrayList<>();
712         VpnAfConfig vpnConfig = vpnInstance.getIpv4Family();
713         VpnTargets targets = vpnConfig.getVpnTargets();
714         List<VpnTarget> vpnTargets = targets.getVpnTarget();
715         for (VpnTarget target : vpnTargets) {
716             if (target.getVrfRTType().equals(VpnTarget.VrfRTType.ExportExtcommunity)) {
717                 String rtValue = target.getVrfRTValue();
718                 exportRts.add(rtValue);
719             }
720         }
721         return exportRts;
722     }
723
724     private void makeArpFlow(BigInteger dpId,short sIndex, int lPortTag, String vpnInterfaceName,
725                              long vpnId, ArpReplyOrRequest replyOrRequest, int addOrRemoveFlow){
726         List<MatchInfo> matches = new ArrayList<MatchInfo>();
727         BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lPortTag, ++sIndex, BigInteger.valueOf(vpnId));
728         BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(MetaDataUtil.METADATA_MASK_SERVICE_INDEX,
729                 MetaDataUtil.METADATA_MASK_LPORT_TAG, MetaDataUtil.METADATA_MASK_VRFID);
730
731         // Matching Arp reply flows
732         matches.add(new MatchInfo(MatchFieldType.eth_type, new long[] { NwConstants.ETHTYPE_ARP }));
733         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
734                 metadata, metadataMask }));
735
736         matches.add(new MatchInfo(MatchFieldType.arp_op, new long[] { replyOrRequest.getArpOperation() }));
737
738         // Instruction to punt to controller
739         List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
740         List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
741         actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[] {}));
742         actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[]{
743                 Short.toString(NwConstants.LPORT_DISPATCHER_TABLE)}));
744
745         instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
746
747         // Install the flow entry in L3_INTERFACE_TABLE
748         String flowRef = VpnUtil.getFlowRef(dpId, NwConstants.L3_INTERFACE_TABLE,
749                     NwConstants.ETHTYPE_ARP, lPortTag, replyOrRequest.getArpOperation());
750         FlowEntity flowEntity;
751         flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_INTERFACE_TABLE, flowRef,
752                 NwConstants.DEFAULT_ARP_FLOW_PRIORITY, replyOrRequest.getName(), 0, 0,
753                 VpnUtil.getCookieArpFlow(lPortTag), matches, instructions);
754
755         if (addOrRemoveFlow == NwConstants.ADD_FLOW) {
756             LOG.debug("Creating ARP Flow for interface {}",vpnInterfaceName);
757             mdsalManager.installFlow(flowEntity);
758         } else {
759             LOG.debug("Deleting ARP Flow for interface {}",vpnInterfaceName);
760             mdsalManager.removeFlow(flowEntity);
761         }
762     }
763
764     private String getRouteDistinguisher(String vpnName) {
765         InstanceIdentifier<VpnInstance> id = InstanceIdentifier.builder(VpnInstances.class)
766                                       .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
767         Optional<VpnInstance> vpnInstance = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
768         String rd = "";
769         if(vpnInstance.isPresent()) {
770             VpnInstance instance = vpnInstance.get();
771             VpnAfConfig config = instance.getIpv4Family();
772             rd = config.getRouteDistinguisher();
773         }
774         return rd;
775     }
776
777     private synchronized void updateMappingDbs(long vpnId, BigInteger dpnId, String intfName, String vpnName) {
778         String routeDistinguisher = getRouteDistinguisher(vpnName);
779         String rd = (routeDistinguisher == null) ? vpnName : routeDistinguisher;
780         InstanceIdentifier<VpnToDpnList> id = VpnUtil.getVpnToDpnListIdentifier(rd, dpnId);
781         Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
782         org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces
783             vpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
784
785         if (dpnInVpn.isPresent()) {
786             VpnUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id.child(
787                     org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
788                             .instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
789                     new VpnInterfacesKey(intfName)), vpnInterface);
790         } else {
791             VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
792                                     VpnUtil.getVpnInstanceOpDataIdentifier(rd),
793                                     VpnUtil.getVpnInstanceOpDataBuilder(rd, vpnId, vpnName));
794             VpnToDpnListBuilder vpnToDpnList = new VpnToDpnListBuilder().setDpnId(dpnId);
795             List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
796                     .instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces =  new ArrayList<>();
797             vpnInterfaces.add(vpnInterface);
798             VpnUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id,
799                               vpnToDpnList.setVpnInterfaces(vpnInterfaces).build());
800
801             /**
802              * FIXME: DC Gateway tunnel should be built dynamically
803             //this is the first VM in this VPN on the DPN, may be a new DPN has come up,
804             //if tunnel to DC GW does not exist, create it
805             //if(!tunnelExists(dpnID, bgpManager.getDCGWIP()))
806             String dcGW = bgpManager.getDCGwIP();
807             if(dcGW != null && !dcGW.isEmpty())
808             {
809                 LOG.debug("Building tunnel from DPN {} to DC GW {}", dpnId, dcGW);
810                 itmProvider.buildTunnelFromDPNToDCGW(dpnId, new IpAddress(dcGW.toCharArray()));
811             }*/
812             fibManager.populateFibOnNewDpn(dpnId, vpnId, (rd == null) ? vpnName : rd);
813             publishAddNotification(dpnId, vpnName, rd);
814             //TODO: IRT - import local routes to vpn. check for the VPNs exporting the routes
815             //FIXME: do we need to handle here. since already routes are imported to this vpn
816
817         }
818     }
819
820     void handleVpnsExportingRoutes(String vpnName, String vpnRd) {
821         List<VpnInstance> vpnsToExportRoute = getVpnsExportingMyRoute(vpnName);
822         long vpnId = VpnUtil.getVpnId(broker, vpnName);
823         for (VpnInstance vpn : vpnsToExportRoute) {
824             String rd = vpn.getIpv4Family().getRouteDistinguisher();
825             long exportingVpnId = VpnUtil.getVpnId(broker, vpn.getVpnInstanceName());
826             List<VrfEntry> vrfEntries = VpnUtil.getAllVrfEntries(broker, vpn.getIpv4Family().getRouteDistinguisher());
827             if (vrfEntries != null) {
828                 for (VrfEntry vrfEntry : vrfEntries) {
829                     try {
830                         if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.STATIC) {
831                             continue;
832                         }
833                         String prefix = vrfEntry.getDestPrefix();
834                         long label = vrfEntry.getLabel();
835                         List<String> nextHops = vrfEntry.getNextHopAddressList();
836                         SubnetRoute route = vrfEntry.getAugmentation(SubnetRoute.class);
837                         for (String nh : nextHops) {
838                             if (route != null) {
839                                 LOG.info("Importing subnet route fib entry rd {} prefix {} nexthop {} label {} to vpn {}", vpnRd, prefix, nh, label, vpn.getVpnInstanceName());
840                                 importSubnetRouteForNewVpn(rd, prefix, nh, (int)label, route);
841                             } else {
842                                 LOG.info("Importing fib entry rd {} prefix {} nexthop {} label {} to vpn {}", vpnRd, prefix, nh, label, vpn.getVpnInstanceName());
843                                 VpnUtil.addFibEntryToDS(broker, vpnRd, prefix, nh, (int)label, RouteOrigin.SELF_IMPORTED);
844                             }
845                         }
846                     } catch (Exception e) {
847                         LOG.error("Exception occurred while importing route with prefix {} label {} nexthop {} from vpn {} to vpn {}", vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList(), vpn.getVpnInstanceName(), vpnName);
848                     }
849                 }
850             } else {
851                 LOG.info("No vrf entries to import from vpn {} with rd {}", vpn.getVpnInstanceName(), vpn.getIpv4Family().getRouteDistinguisher());
852             }
853         }
854     }
855
856     private synchronized void removeFromMappingDbs(long vpnId, BigInteger dpnId, String intfName, String vpnName) {
857         //TODO: Delay 'DPN' removal so that other services can cleanup the entries for this dpn
858         String rd = VpnUtil.getVpnRd(broker, vpnName);
859         InstanceIdentifier<VpnToDpnList> id = VpnUtil.getVpnToDpnListIdentifier(rd, dpnId);
860         Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
861         if (dpnInVpn.isPresent()) {
862             List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
863                     .instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
864             org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces
865                     currVpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
866
867             if (vpnInterfaces.remove(currVpnInterface)) {
868                 if (vpnInterfaces.isEmpty()) {
869                     List<IpAddresses> ipAddresses = dpnInVpn.get().getIpAddresses();
870                     if (ipAddresses == null || ipAddresses.isEmpty()) {
871                         LOG.debug("Sending cleanup event for dpn {} in VPN {}", dpnId, vpnName);
872                         VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id, VpnUtil.DEFAULT_CALLBACK);
873                         fibManager.cleanUpDpnForVpn(dpnId, vpnId, rd);
874                         publishRemoveNotification(dpnId, vpnName, rd);
875                     } else {
876                         LOG.debug("vpn interfaces are empty but ip addresses are present for the vpn {} in dpn {}", vpnName, dpnId);
877                     }
878                 } else {
879                     VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id.child(
880                         org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
881                                 .instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
882                             new VpnInterfacesKey(intfName)), VpnUtil.DEFAULT_CALLBACK);
883                 }
884             }
885         }
886     }
887
888     private void addPrefixToBGP(String rd, String prefix, String nextHopIp, long label) {
889         try {
890             LOG.info("ADD: Adding Fib entry rd {} prefix {} nextHop {} label {}", rd, prefix, nextHopIp, label);
891             bgpManager.addPrefix(rd, prefix, Arrays.asList(nextHopIp), (int)label, RouteOrigin.STATIC);
892             LOG.info("ADD: Added Fib entry rd {} prefix {} nextHop {} label {}", rd, prefix, nextHopIp, label);
893         } catch(Exception e) {
894             LOG.error("Add prefix failed", e);
895         }
896     }
897
898
899     private InstanceIdentifier<VpnInterface> getWildCardPath() {
900         return InstanceIdentifier.create(VpnInterfaces.class).child(VpnInterface.class);
901     }
902
903     @Override
904     public void remove( InstanceIdentifier<VpnInterface> identifier, VpnInterface vpnInterface) {
905         LOG.trace("Remove event - key: {}, value: {}" ,identifier, vpnInterface );
906         final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
907         String interfaceName = key.getName();
908
909         InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
910         Optional<VpnInterface> existingVpnInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, interfaceId);
911         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState =
912             InterfaceUtils.getInterfaceStateFromOperDS(broker, interfaceName);
913         if(existingVpnInterface.isPresent()){
914             BigInteger dpnId = BigInteger.ZERO;
915             Boolean dpnIdRetrieved = Boolean.FALSE;
916             if(interfaceState != null){
917                 try{
918                     dpnId = InterfaceUtils.getDpIdFromInterface(interfaceState);
919                     dpnIdRetrieved = Boolean.TRUE;
920                 }catch (Exception e){
921                     LOG.error("Unable to retrieve dpnId from interface operational data store for interface {}. Fetching from vpn interface op data store. ", interfaceName, e);
922                 }
923             }
924             if(dpnIdRetrieved == Boolean.FALSE){
925                 LOG.info("dpnId for {} has not been retrieved yet. Fetching from vpn interface operational DS", interfaceName);
926                 dpnId = existingVpnInterface.get().getDpnId();
927             }
928             processVpnInterfaceDown(dpnId, interfaceName, interfaceState.getIfIndex(), false, true);
929         }else{
930             LOG.warn("VPN interface {} was unavailable in operational data store to handle remove event", interfaceName);
931         }
932     }
933
934     protected void processVpnInterfaceDown(BigInteger dpId, String interfaceName, int lPortTag, boolean isInterfaceStateDown, boolean isConfigRemoval) {
935         InstanceIdentifier<VpnInterface> identifier = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
936         if (!isInterfaceStateDown) {
937             synchronized (interfaceName.intern()) {
938                 VpnInterface vpnInterface = VpnUtil.getOperationalVpnInterface(broker, interfaceName);
939                 if(vpnInterface == null){
940                     LOG.info("Unable to process delete/down for interface {} as it is not available in operational data store", interfaceName);
941                     return;
942                 }else{
943                     String vpnName = vpnInterface.getVpnInstanceName();
944                     if(!vpnInterface.isScheduledForRemove()){
945                         VpnUtil.updateVpnInterface(broker, vpnInterface.getName(), vpnInterface.getDpnId(), vpnInterface.getVpnInstanceName(), Boolean.TRUE);
946                         removeAdjacenciesFromVpn(dpId, identifier, vpnInterface);
947                         LOG.info("Unbinding vpn service from interface {} ", interfaceName);
948                         unbindService(dpId, vpnName, interfaceName, lPortTag, isInterfaceStateDown, isConfigRemoval);
949                     }else{
950                         LOG.info("Unbinding vpn service for interface {} has already been scheduled by a different event ", interfaceName);
951                         return;
952                     }
953                 }
954             }
955
956             // FIB didn't get a chance yet to clean up this VPNInterface
957             // Let us give it a chance here !
958             LOG.info("VPN Interface {} removal waiting for FIB to clean up ! ", interfaceName);
959             try {
960                 Runnable notifyTask = new VpnNotifyTask();
961                 vpnIntfMap.put(interfaceName, notifyTask);
962                 synchronized (notifyTask) {
963                     try {
964                         notifyTask.wait(VpnConstants.PER_INTERFACE_MAX_WAIT_TIME_IN_MILLISECONDS);
965                     } catch (InterruptedException e) {
966                     }
967                 }
968             } finally {
969                 vpnIntfMap.remove(interfaceName);
970             }
971         } else {
972                 synchronized (interfaceName.intern()) {
973                     // Interface is retained in the DPN, but its Link Down.
974                     // Only withdraw the prefixes for this interface from BGP
975                     VpnInterface vpnInterface = VpnUtil.getOperationalVpnInterface(broker, interfaceName);
976                     if(vpnInterface == null){
977                         LOG.info("Unable to withdraw adjacencies for vpn interface {} from BGP as it is not available in operational data store", interfaceName);
978                         return;
979                     }else {
980                         withdrawAdjacenciesForVpnFromBgp(identifier, vpnInterface);
981                     }
982                 }
983         }
984
985     }
986
987     private void removeAdjacenciesFromVpn(BigInteger dpnId, final InstanceIdentifier<VpnInterface> identifier, VpnInterface intf) {
988         //Read NextHops
989         InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
990         Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
991
992         String rd = VpnUtil.getVpnRd(broker, intf.getVpnInstanceName());
993         LOG.trace("removeAdjacenciesFromVpn: For interface {} RD recovered for vpn {} as rd {}", intf.getName(),
994                 intf.getVpnInstanceName(), rd);
995         if (adjacencies.isPresent()) {
996             List<Adjacency> nextHops = adjacencies.get().getAdjacency();
997
998             if (!nextHops.isEmpty()) {
999                 LOG.trace("NextHops are " + nextHops);
1000                 for (Adjacency nextHop : nextHops) {
1001                     List<String> nhList = new ArrayList<String>();
1002                     if (nextHop.getMacAddress() == null || nextHop.getMacAddress().isEmpty()) {
1003                         // This is either an extra-route (or) a learned IP via subnet-route
1004                         String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
1005                         if (nextHopIp == null || nextHopIp.isEmpty()) {
1006                             LOG.error("Unable to obtain nextHopIp for extra-route/learned-route in rd {} prefix {}",
1007                                     rd, nextHop.getIpAddress());
1008                             continue;
1009                         }
1010                         nhList = Arrays.asList(nextHopIp);
1011                     } else {
1012                         // This is a primary adjacency
1013                         nhList = nextHop.getNextHopIpList();
1014                     }
1015                     if (rd.equals(intf.getVpnInstanceName())) {
1016                         //this is an internal vpn - the rd is assigned to the vpn instance name;
1017                         //remove from FIB directly
1018                         for(String nh : nhList) {
1019                             VpnUtil.removeFibEntryFromDS(broker, intf.getVpnInstanceName(), nextHop.getIpAddress(), nh);
1020                         }
1021                     } else {
1022
1023                         List<VpnInstance> vpnsToImportRoute = getVpnsImportingMyRoute(intf.getVpnInstanceName());
1024                         for (String nh : nextHop.getNextHopIpList()) {
1025                             //IRT: remove routes from other vpns importing it
1026                             removePrefixFromBGP(rd, nextHop.getIpAddress(), nh);
1027                             for (VpnInstance vpn : vpnsToImportRoute) {
1028                                 String vpnRd = vpn.getIpv4Family().getRouteDistinguisher();
1029                                 if (vpnRd != null) {
1030                                     LOG.info("Removing Exported route with rd {} prefix {} from VPN {}", vpnRd, nextHop.getIpAddress(), vpn.getVpnInstanceName());
1031                                     VpnUtil.removeFibEntryFromDS(broker, vpnRd, nextHop.getIpAddress(), nh);
1032                                 }
1033                             }
1034                         }
1035                     }
1036                     String ip = nextHop.getIpAddress().split("/")[0];
1037                     VpnPortipToPort vpnPortipToPort = VpnUtil.getNeutronPortFromVpnPortFixedIp(broker,
1038                             intf.getVpnInstanceName(), ip);
1039                     if (vpnPortipToPort != null && !vpnPortipToPort.isConfig()) {
1040                         LOG.trace("VpnInterfaceManager removing adjacency for Interface {} ip {} from VpnPortData Entry",
1041                                 vpnPortipToPort.getPortName(),ip);
1042                         VpnUtil.removeVpnPortFixedIpToPort(broker, intf.getVpnInstanceName(), ip);
1043                     }
1044                 }
1045             }
1046         }
1047     }
1048
1049
1050     private void unbindService(BigInteger dpId, String vpnInstanceName, String vpnInterfaceName,
1051                                int lPortTag, boolean isInterfaceStateDown, boolean isConfigRemoval) {
1052         if (!isInterfaceStateDown && isConfigRemoval) {
1053             MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION,
1054                     InterfaceUtils.buildServiceId(vpnInterfaceName,
1055                             VpnConstants.L3VPN_SERVICE_IDENTIFIER));
1056         }
1057         long vpnId = VpnUtil.getVpnId(broker, vpnInstanceName);
1058         makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
1059                     vpnId, ArpReplyOrRequest.REQUEST, NwConstants.DEL_FLOW);
1060         makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
1061                 vpnId, ArpReplyOrRequest.REPLY, NwConstants.DEL_FLOW);
1062     }
1063
1064
1065     private void removePrefixFromBGP(String rd, String prefix, String nextHop) {
1066         VpnUtil.removeFibEntryFromDS(broker, rd, prefix, nextHop);
1067         try {
1068             LOG.info("VPN WITHDRAW: Removing Fib Entry rd {} prefix {}", rd, prefix);
1069             bgpManager.withdrawPrefix(rd, prefix); // TODO: Might be needed to include nextHop here
1070             LOG.info("VPN WITHDRAW: Removed Fib Entry rd {} prefix {}", rd, prefix);
1071         } catch(Exception e) {
1072             LOG.error("Delete prefix failed", e);
1073         }
1074     }
1075
1076     @Override
1077     protected void update(InstanceIdentifier<VpnInterface> identifier, VpnInterface original, VpnInterface update) {
1078         LOG.trace("Updating VPN Interface : key {},  original value={}, update value={}", identifier, original, update);
1079         String oldVpnName = original.getVpnInstanceName();
1080         String newVpnName = update.getVpnInstanceName();
1081         BigInteger dpnId = update.getDpnId();
1082         List<Adjacency> oldAdjs = original.getAugmentation(Adjacencies.class).getAdjacency();
1083         List<Adjacency> newAdjs = update.getAugmentation(Adjacencies.class).getAdjacency();
1084         if (oldAdjs == null) {
1085             oldAdjs = new ArrayList<>();
1086         }
1087         if (newAdjs == null) {
1088             newAdjs = new ArrayList<>();
1089         }
1090         //handles switching between <internal VPN - external VPN>
1091         if (!oldVpnName.equals(newVpnName)) {
1092             remove(identifier, original);
1093             add(identifier, update);
1094         }
1095         //handle both addition and removal of adjacencies
1096         //currently, new adjacency may be an extra route
1097         if (!oldAdjs.equals(newAdjs)) {
1098             for (Adjacency adj : newAdjs) {
1099                 if (oldAdjs.contains(adj)) {
1100                     oldAdjs.remove(adj);
1101                 } else {
1102                     // add new adjacency - right now only extra route will hit this path
1103                     addNewAdjToVpnInterface(identifier, adj, dpnId);
1104                 }
1105             }
1106             for (Adjacency adj : oldAdjs) {
1107                 delAdjFromVpnInterface(identifier, adj, dpnId);
1108             }
1109         }
1110     }
1111
1112     public void processArpRequest(IpAddress srcIP, PhysAddress srcMac, IpAddress targetIP, PhysAddress targetMac,String srcInterface){
1113         //Build ARP response with ARP requests TargetIp TargetMac as the Arp Response SrcIp and SrcMac
1114         SendArpResponseInput input = new SendArpResponseInputBuilder().setInterface(srcInterface)
1115                 .setDstIpaddress(srcIP).setDstMacaddress(srcMac).setSrcIpaddress(targetIP).setSrcMacaddress(targetMac).build();
1116         final String msgFormat = String.format("Send ARP Response on interface %s to destination %s", srcInterface, srcIP);
1117         Future<RpcResult<Void>> future = arpManager.sendArpResponse(input);
1118         Futures.addCallback(JdkFutureAdapters.listenInPoolThread(future), new FutureCallback<RpcResult<Void>>() {
1119             @Override
1120             public void onFailure(Throwable error) {
1121                 LOG.error("Error - {}", msgFormat, error);
1122             }
1123
1124             @Override
1125             public void onSuccess(RpcResult<Void> result) {
1126                 if(!result.isSuccessful()) {
1127                     LOG.warn("Rpc call to {} failed", msgFormat, getErrorText(result.getErrors()));
1128                 } else {
1129                     LOG.debug("Successful RPC Result - {}", msgFormat);
1130                 }
1131             }
1132         });
1133     }
1134
1135     private String getErrorText(Collection<RpcError> errors) {
1136         StringBuilder errorText = new StringBuilder();
1137         for(RpcError error : errors) {
1138             errorText.append(",").append(error.getErrorType()).append("-")
1139                      .append(error.getMessage());
1140         }
1141         return errorText.toString();
1142     }
1143
1144     private void addToLabelMapper(Long label, BigInteger dpnId, String prefix, List<String> nextHopIpList, Long vpnId,
1145                                   String vpnInterfaceName, Long elanTag, boolean isSubnetRoute, String rd) {
1146         Preconditions.checkNotNull(label, "label cannot be null or empty!");
1147         Preconditions.checkNotNull(prefix, "prefix cannot be null or empty!");
1148         Preconditions.checkNotNull(vpnId, "vpnId cannot be null or empty!");
1149         Preconditions.checkNotNull(rd, "rd cannot be null or empty!");
1150         if (!isSubnetRoute) {
1151             // NextHop must be present for non-subnetroute entries
1152             Preconditions.checkNotNull(nextHopIpList, "nextHopIp cannot be null or empty!");
1153         }
1154         LOG.info("Adding to label mapper : label {} dpn {} prefix {} nexthoplist {} vpnid {} vpnIntfcName {} rd {}", label, dpnId, prefix, nextHopIpList, vpnId, vpnInterfaceName, rd);
1155         if (dpnId != null) {
1156             InstanceIdentifier<LabelRouteInfo> lriIid = InstanceIdentifier.builder(LabelRouteMap.class)
1157                     .child(LabelRouteInfo.class, new LabelRouteInfoKey((long)label)).build();
1158             LabelRouteInfoBuilder lriBuilder = new LabelRouteInfoBuilder();
1159             lriBuilder.setLabel(label).setDpnId(dpnId).setPrefix(prefix).setNextHopIpList(nextHopIpList).setParentVpnid(vpnId)
1160                     .setIsSubnetRoute(isSubnetRoute);
1161             if (elanTag != null) {
1162                 lriBuilder.setElanTag(elanTag);
1163             }
1164             if (vpnInterfaceName != null) {
1165                 lriBuilder.setVpnInterfaceName(vpnInterfaceName);
1166             }
1167             lriBuilder.setParentVpnRd(rd);
1168             VpnInstanceOpDataEntry vpnInstanceOpDataEntry = VpnUtil.getVpnInstanceOpData(broker, rd);
1169             if (vpnInstanceOpDataEntry != null) {
1170                 List<String> vpnInstanceNames = Arrays.asList(vpnInstanceOpDataEntry.getVpnInstanceName());
1171                 lriBuilder.setVpnInstanceList(vpnInstanceNames);
1172             }
1173             LabelRouteInfo lri = lriBuilder.build();
1174             LOG.trace("Adding route info to label map: {}", lri);
1175             VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, lriIid, lri);
1176         } else {
1177             LOG.trace("Can't add entry to label map for lable {},dpnId is null", label);
1178         }
1179     }
1180
1181     public synchronized void addSubnetRouteFibEntryToDS(String rd, String vpnName, String prefix, String nextHop, int label,
1182                                                         long elantag, BigInteger dpnId) {
1183
1184         SubnetRoute route = new SubnetRouteBuilder().setElantag(elantag).build();
1185         RouteOrigin origin = RouteOrigin.STATIC; // Only case when a route is considered as directly connected
1186         VrfEntry vrfEntry = new VrfEntryBuilder().setDestPrefix(prefix).setNextHopAddressList(Arrays.asList(nextHop))
1187                                                  .setLabel((long)label).setOrigin(origin.getValue())
1188                                                  .addAugmentation(SubnetRoute.class, route).build();
1189
1190         LOG.debug("Created vrfEntry for {} nexthop {} label {} and elantag {}", prefix, nextHop, label, elantag);
1191
1192         //TODO: What should be parentVpnId? Get it from RD?
1193         long vpnId = VpnUtil.getVpnId(broker, vpnName);
1194         addToLabelMapper((long)label, dpnId, prefix, Arrays.asList(nextHop), vpnId, null, elantag, true, rd);
1195         List<VrfEntry> vrfEntryList = Arrays.asList(vrfEntry);
1196
1197         InstanceIdentifierBuilder<VrfTables> idBuilder =
1198                 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
1199         InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
1200
1201         VrfTables vrfTableNew = new VrfTablesBuilder().setRouteDistinguisher(rd).
1202                 setVrfEntry(vrfEntryList).build();
1203
1204         VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew);
1205
1206         List<VpnInstance> vpnsToImportRoute = getVpnsImportingMyRoute(vpnName);
1207         if (vpnsToImportRoute.size() > 0) {
1208             VrfEntry importingVrfEntry = new VrfEntryBuilder().setDestPrefix(prefix).setNextHopAddressList(Arrays.asList(nextHop))
1209                     .setLabel((long)label).setOrigin(RouteOrigin.SELF_IMPORTED.getValue())
1210                     .addAugmentation(SubnetRoute.class, route).build();
1211             List<VrfEntry> importingVrfEntryList = Arrays.asList(importingVrfEntry);
1212             for (VpnInstance vpnInstance : vpnsToImportRoute) {
1213                 LOG.info("Exporting subnet route rd {} prefix {} nexthop {} label {} to vpn {}", rd, prefix, nextHop, label, vpnInstance.getVpnInstanceName());
1214                 String importingRd = vpnInstance.getIpv4Family().getRouteDistinguisher();
1215                 InstanceIdentifier<VrfTables> importingVrfTableId = InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(importingRd)).build();
1216                 VrfTables importingVrfTable = new VrfTablesBuilder().setRouteDistinguisher(importingRd).setVrfEntry(importingVrfEntryList).build();
1217                 VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, importingVrfTableId, importingVrfTable);
1218             }
1219         }
1220     }
1221
1222     public synchronized void importSubnetRouteForNewVpn(String rd, String prefix, String nextHop, int label,
1223                                                         SubnetRoute route) {
1224
1225         RouteOrigin origin = RouteOrigin.SELF_IMPORTED;
1226         VrfEntry vrfEntry = new VrfEntryBuilder().setDestPrefix(prefix).setNextHopAddressList(Arrays.asList(nextHop))
1227                 .setLabel((long)label).setOrigin(origin.getValue())
1228                 .addAugmentation(SubnetRoute.class, route).build();
1229         LOG.debug("Created vrfEntry for {} nexthop {} label {} and elantag {}", prefix, nextHop, label, route.getElantag());
1230         List<VrfEntry> vrfEntryList = Arrays.asList(vrfEntry);
1231         InstanceIdentifierBuilder<VrfTables> idBuilder =
1232                 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
1233         InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
1234         VrfTables vrfTableNew = new VrfTablesBuilder().setRouteDistinguisher(rd).
1235                 setVrfEntry(vrfEntryList).build();
1236         VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew);
1237     }
1238
1239     public synchronized void deleteSubnetRouteFibEntryFromDS(String rd, String prefix, String vpnName){
1240         VpnUtil.removeFibEntryFromDS(broker, rd, prefix, null /* nextHopToRemove */);
1241         List<VpnInstance> vpnsToImportRoute = getVpnsImportingMyRoute(vpnName);
1242         for (VpnInstance vpnInstance : vpnsToImportRoute) {
1243             String importingRd = vpnInstance.getIpv4Family().getRouteDistinguisher();
1244             LOG.info("Deleting imported subnet route rd {} prefix {} from vpn {}", rd, prefix, vpnInstance.getVpnInstanceName());
1245             VpnUtil.removeFibEntryFromDS(broker, importingRd, prefix, null);
1246         }
1247     }
1248
1249     public synchronized void removeVrfFromDS(String rd) {
1250         LOG.debug("Removing vrf table for rd {}", rd);
1251
1252         InstanceIdentifierBuilder<VrfTables> idBuilder =
1253                 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
1254         InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
1255
1256         VpnUtil.delete(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId, VpnUtil.DEFAULT_CALLBACK);
1257
1258     }
1259
1260     protected void addNewAdjToVpnInterface(InstanceIdentifier<VpnInterface> identifier, Adjacency adj, BigInteger dpnId) {
1261
1262         Optional<VpnInterface> optVpnInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, identifier);
1263
1264         if (optVpnInterface.isPresent()) {
1265             VpnInterface currVpnIntf = optVpnInterface.get();
1266             String prefix = VpnUtil.getIpPrefix(adj.getIpAddress());
1267             String rd = getRouteDistinguisher(currVpnIntf.getVpnInstanceName());
1268             InstanceIdentifier<Adjacencies> adjPath = identifier.augmentation(Adjacencies.class);
1269             Optional<Adjacencies> optAdjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, adjPath);
1270             long label =
1271                     VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
1272                             VpnUtil.getNextHopLabelKey((rd != null) ? rd : currVpnIntf.getVpnInstanceName(), prefix));
1273
1274             List<Adjacency> adjacencies;
1275             if (optAdjacencies.isPresent()) {
1276                 adjacencies = optAdjacencies.get().getAdjacency();
1277             } else {
1278                 //This code will not be hit since VM adjacency will always be there
1279                 adjacencies = new ArrayList<>();
1280             }
1281
1282
1283             adjacencies.add(new AdjacencyBuilder(adj).setLabel(label).setNextHopIpList(adj.getNextHopIpList())
1284                     .setIpAddress(prefix).setKey(new AdjacencyKey(prefix)).build());
1285             Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencies);
1286             VpnInterface newVpnIntf = VpnUtil.getVpnInterface(currVpnIntf.getName(), currVpnIntf.getVpnInstanceName(), aug, dpnId, currVpnIntf.isScheduledForRemove());
1287             VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, identifier, newVpnIntf);
1288             for (String nh : adj.getNextHopIpList()) {
1289                 addExtraRoute(adj.getIpAddress(), nh, rd, currVpnIntf.getVpnInstanceName(), (int) label,
1290                               currVpnIntf.getName());
1291             }
1292
1293         }
1294
1295     }
1296
1297     protected void delAdjFromVpnInterface(InstanceIdentifier<VpnInterface> identifier, Adjacency adj, BigInteger dpnId) {
1298         Optional<VpnInterface> optVpnInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, identifier);
1299
1300         if (optVpnInterface.isPresent()) {
1301             VpnInterface currVpnIntf = optVpnInterface.get();
1302
1303             InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
1304             Optional<Adjacencies> optAdjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
1305             if (optAdjacencies.isPresent()) {
1306                 List<Adjacency> adjacencies = optAdjacencies.get().getAdjacency();
1307
1308                 if (!adjacencies.isEmpty()) {
1309                     String rd = getRouteDistinguisher(currVpnIntf.getVpnInstanceName());
1310                     LOG.trace("Adjacencies are " + adjacencies);
1311                     Iterator<Adjacency> adjIt = adjacencies.iterator();
1312                     while (adjIt.hasNext()) {
1313                         Adjacency adjElem = adjIt.next();
1314                         if (adjElem.getIpAddress().equals(adj.getIpAddress())) {
1315                             adjIt.remove();
1316
1317                             Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencies);
1318                             VpnInterface newVpnIntf = VpnUtil.getVpnInterface(currVpnIntf.getName(),
1319                                                                               currVpnIntf.getVpnInstanceName(),
1320                                                                               aug, dpnId, currVpnIntf.isScheduledForRemove());
1321
1322                             VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, identifier, newVpnIntf);
1323
1324                             for (String nh : adj.getNextHopIpList()) {
1325                                 delExtraRoute(adj.getIpAddress(), nh, rd, currVpnIntf.getVpnInstanceName(),
1326                                               currVpnIntf.getName());
1327                             }
1328                             break;
1329                         }
1330
1331                     }
1332                 }
1333             }
1334         }
1335
1336     }
1337
1338     protected void addExtraRoute(String destination, String nextHop, String rd, String routerID, int label,
1339                                  String intfName) {
1340
1341         //add extra route to vpn mapping; advertise with nexthop as tunnel ip
1342         VpnUtil.syncUpdate(
1343             broker,
1344             LogicalDatastoreType.OPERATIONAL,
1345             VpnUtil.getVpnToExtrarouteIdentifier( (rd != null) ? rd : routerID, destination),
1346             VpnUtil.getVpnToExtraroute(destination, Arrays.asList(nextHop)));
1347
1348         BigInteger dpnId = null;
1349         if (intfName != null && !intfName.isEmpty()) {
1350             dpnId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, intfName);
1351             String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
1352             if (nextHopIp == null || nextHopIp.isEmpty()) {
1353                 LOG.error("NextHop for interface {} is null / empty. Failed advertising extra route for prefix {}",
1354                           intfName, destination);
1355                 return;
1356             }
1357             nextHop = nextHopIp;
1358         }
1359         List<String> nextHopIpList = Arrays.asList(nextHop);
1360         addToLabelMapper((long)label, dpnId, destination, nextHopIpList, VpnUtil.getVpnId(broker, routerID),
1361                 intfName, null, false, rd);
1362
1363         // TODO (eperefr): This is a limitation to be stated in docs. When configuring static route to go to
1364         // another VPN, there can only be one nexthop or, at least, the nexthop to the interVpnLink should be in
1365         // first place.
1366         InterVpnLink interVpnLink = VpnUtil.getInterVpnLinkByEndpointIp(broker, nextHop);
1367         if ( interVpnLink != null ) {
1368             // If the nexthop is the endpoint of Vpn2, then prefix must be advertised to Vpn1 in DC-GW, with nexthops
1369             // pointing to the DPNs where Vpn1 is instantiated. LFIB in these DPNS must have a flow entry, with lower
1370             // priority, where if Label matches then sets the lportTag of the Vpn2 endpoint and goes to LportDispatcher
1371             // This is like leaking one of the Vpn2 routes towards Vpn1
1372             boolean nexthopIsVpn2 = ( interVpnLink.getSecondEndpoint().getIpAddress().getValue().equals(nextHop) );
1373             String srcVpnUuid = (nexthopIsVpn2) ? interVpnLink.getSecondEndpoint().getVpnUuid().getValue()
1374                                                 : interVpnLink.getFirstEndpoint().getVpnUuid().getValue();
1375             String dstVpnUuid = (nexthopIsVpn2) ? interVpnLink.getFirstEndpoint().getVpnUuid().getValue()
1376                                                 : interVpnLink.getSecondEndpoint().getVpnUuid().getValue();
1377             String dstVpnRd = VpnUtil.getVpnRd(broker, dstVpnUuid);
1378             long newLabel = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
1379                                                 VpnUtil.getNextHopLabelKey(dstVpnRd, destination));
1380             VpnUtil.leakRoute(broker, bgpManager, interVpnLink, srcVpnUuid, dstVpnUuid, destination, newLabel);
1381         } else {
1382             if (rd != null) {
1383                 addPrefixToBGP(rd, destination, nextHop, label);
1384             } else {
1385                 // ### add FIB route directly
1386                 VpnUtil.addFibEntryToDS(broker, routerID, destination, nextHop, label, RouteOrigin.STATIC);
1387             }
1388         }
1389     }
1390
1391     protected void delExtraRoute(String destination, String nextHop, String rd, String routerID, String intfName) {
1392         if (intfName != null && !intfName.isEmpty()) {
1393             BigInteger dpnId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, intfName);
1394             String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
1395             if (nextHopIp == null || nextHopIp.isEmpty()) {
1396                 LOG.warn("NextHop for interface {} is null / empty. Failed advertising extra route for prefix {}",
1397                         intfName, destination);
1398             }
1399             nextHop = nextHopIp;
1400         }
1401
1402         if (rd != null) {
1403             removePrefixFromBGP(rd, destination, nextHop);
1404         } else {
1405             // ### add FIB route directly
1406             VpnUtil.removeFibEntryFromDS(broker, routerID, destination, nextHop);
1407         }
1408     }
1409
1410     class VpnInterfaceOpListener extends AbstractDataChangeListener<VpnInterface> {
1411
1412         public VpnInterfaceOpListener() {
1413             super(VpnInterface.class);
1414         }
1415
1416         @Override
1417         protected void remove(InstanceIdentifier<VpnInterface> identifier, VpnInterface del) {
1418             final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
1419             String interfaceName = key.getName();
1420             String vpnName = del.getVpnInstanceName();
1421
1422             LOG.trace("VpnInterfaceOpListener removed: interface name {} vpnName {}", interfaceName, vpnName);
1423             //decrement the vpn interface count in Vpn Instance Op Data
1424             InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance>
1425                     id = VpnUtil.getVpnInstanceToVpnIdIdentifier(vpnName);
1426             Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> vpnInstance
1427                     = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
1428
1429             if (vpnInstance.isPresent()) {
1430                 String rd = null;
1431                 rd = vpnInstance.get().getVrfId();
1432                 //String rd = getRouteDistinguisher(del.getVpnInstanceName());
1433
1434                 VpnInstanceOpDataEntry vpnInstOp = VpnUtil.getVpnInstanceOpData(broker, rd);
1435                 LOG.trace("VpnInterfaceOpListener removed: interface name {} rd {} vpnName {} in Vpn Op Instance {}",
1436                         interfaceName, rd, vpnName, vpnInstOp);
1437
1438                 if (vpnInstOp != null) {
1439                     // Vpn Interface removed => No more adjacencies from it.
1440                     // Hence clean up interface from vpn-dpn-interface list.
1441                     Adjacency adjacency = del.getAugmentation(Adjacencies.class).getAdjacency().get(0);
1442                     List<Prefixes> prefixToInterface = new ArrayList<>();
1443                     Optional<Prefixes> prefix = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
1444                             VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
1445                                     VpnUtil.getIpPrefix(adjacency.getIpAddress())));
1446                     if (prefix.isPresent()) {
1447                         prefixToInterface.add(prefix.get());
1448                     }
1449                     if (prefixToInterface.isEmpty()) {
1450                         for (String nh : adjacency.getNextHopIpList()) {
1451                             prefix = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
1452                                      VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
1453                                                                            VpnUtil.getIpPrefix(nh)));
1454                             if (prefix.isPresent())
1455                                 prefixToInterface.add(prefix.get());
1456                         }
1457                     }
1458                     for (Prefixes pref : prefixToInterface) {
1459                         VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
1460                                        VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(), pref.getIpAddress()),
1461                                        VpnUtil.DEFAULT_CALLBACK);
1462                         synchronized (interfaceName.intern()) {
1463                             updateDpnDbs(pref.getDpnId(), del.getVpnInstanceName(), interfaceName, false);
1464                         }
1465                     }
1466 //                    Long ifCnt = 0L;
1467 //                    //ifCnt = vpnInstOp.getVpnInterfaceCount();
1468 //                    LOG.trace("VpnInterfaceOpListener removed: interface name {} rd {} vpnName {} Intf count {}",
1469 //                            interfaceName, rd, vpnName, ifCnt);
1470 //                    if ((ifCnt != null) && (ifCnt > 0)) {
1471 //                        VpnUtil.asyncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
1472 //                                VpnUtil.getVpnInstanceOpDataIdentifier(rd),
1473 //                                VpnUtil.updateIntfCntInVpnInstOpData(ifCnt - 1, rd), VpnUtil.DEFAULT_CALLBACK);
1474 //                    }
1475                 }
1476             } else {
1477                 LOG.error("rd not retrievable as vpninstancetovpnid for vpn {} is absent, trying rd as ", vpnName, vpnName);
1478             }
1479             notifyTaskIfRequired(interfaceName);
1480         }
1481
1482         private void notifyTaskIfRequired(String intfName) {
1483             Runnable notifyTask = vpnIntfMap.remove(intfName);
1484             if (notifyTask == null) {
1485                 LOG.trace("VpnInterfaceOpListener update: No Notify Task queued for vpnInterface {}", intfName);
1486                 return;
1487             }
1488             executorService.execute(notifyTask);
1489         }
1490
1491         @Override
1492         protected void update(InstanceIdentifier<VpnInterface> identifier, VpnInterface original, VpnInterface update) {
1493             final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
1494             String interfaceName = key.getName();
1495
1496             if (original.getVpnInstanceName().equals(update.getVpnInstanceName())) {
1497                 return;
1498             }
1499
1500             //increment the vpn interface count in Vpn Instance Op Data
1501             //Long ifCnt = 0L;
1502             VpnInstanceOpDataEntry vpnInstOp = null;
1503 //            InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance>
1504 //                    updId = VpnUtil.getVpnInstanceToVpnIdIdentifier(update.getVpnInstanceName());
1505 //            Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> updVpnInstance
1506 //                    = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, updId);
1507 //
1508 //            if (updVpnInstance.isPresent()) {
1509 //                String rd = null;
1510 //                rd = updVpnInstance.get().getVrfId();
1511 //
1512 //                vpnInstOp = VpnUtil.getVpnInstanceOpData(broker, rd);
1513 //
1514 //                if (vpnInstOp != null && vpnInstOp.getVpnInterfaceCount() != null) {
1515 //                    ifCnt = vpnInstOp.getVpnInterfaceCount();
1516 //                }
1517 //
1518 //                LOG.trace("VpnInterfaceOpListener update: interface name {} rd {} interface count in updated Vpn Op Instance {}", interfaceName, rd, ifCnt);
1519 //
1520 //                VpnUtil.asyncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
1521 //                        VpnUtil.getVpnInstanceOpDataIdentifier(rd),
1522 //                        VpnUtil.updateIntfCntInVpnInstOpData(ifCnt + 1, rd), VpnUtil.DEFAULT_CALLBACK);
1523 //            }
1524 //
1525             InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance>
1526                     origId = VpnUtil.getVpnInstanceToVpnIdIdentifier(original.getVpnInstanceName());
1527             Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> origVpnInstance
1528                     = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, origId);
1529
1530             if (origVpnInstance.isPresent()) {
1531                 String rd = null;
1532                 rd = origVpnInstance.get().getVrfId();
1533
1534                 vpnInstOp = VpnUtil.getVpnInstanceOpData(broker, rd);
1535                 LOG.trace("VpnInterfaceOpListener updated: interface name {} original rd {} original vpnName {}",
1536                         interfaceName, rd, original.getVpnInstanceName());
1537
1538                 if (vpnInstOp != null) {
1539                     Adjacency adjacency = original.getAugmentation(Adjacencies.class).getAdjacency().get(0);
1540                     List<Prefixes> prefixToInterfaceList = new ArrayList<>();
1541                     Optional<Prefixes> prefixToInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
1542                             VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
1543                                     VpnUtil.getIpPrefix(adjacency.getIpAddress())));
1544                     if (prefixToInterface.isPresent()) {
1545                         prefixToInterfaceList.add(prefixToInterface.get());
1546                     } else {
1547                         for (String adj : adjacency.getNextHopIpList()) {
1548                             prefixToInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
1549                                           VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
1550                                           VpnUtil.getIpPrefix(adj)));
1551                             if (prefixToInterface.isPresent()) {
1552                                 prefixToInterfaceList.add(prefixToInterface.get());
1553                             }
1554                         }
1555                     }
1556 //                        VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
1557 //                                VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
1558 //                                        prefixToInterface.get().getIpAddress()),
1559 //                                VpnUtil.DEFAULT_CALLBACK);
1560                     synchronized (interfaceName.intern()) {
1561                         for (Prefixes prefix : prefixToInterfaceList) {
1562                             updateDpnDbs(prefix.getDpnId(), original.getVpnInstanceName(), interfaceName, false);
1563                         }
1564                     }
1565                 }
1566             }
1567             notifyTaskIfRequired(interfaceName);
1568 //                if (vpnInstOp != null && vpnInstOp.getVpnInterfaceCount() != null) {
1569 //                    ifCnt = vpnInstOp.getVpnInterfaceCount();
1570 //                } else {
1571 //                    LOG.debug("VpnInterfaceOpListener update: Vpn interface count not recoverable from original, to handle update for rd {}", rd);
1572 //                    return;
1573 //                }
1574 //                LOG.trace("VpnInterfaceOpListener update: interface name {} rd {} interface count in original Vpn Op Instance {}", interfaceName, rd, ifCnt);
1575 //
1576 //                if (ifCnt > 0) {
1577 //                    VpnUtil.asyncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
1578 //                            VpnUtil.getVpnInstanceOpDataIdentifier(rd),
1579 //                            VpnUtil.updateIntfCntInVpnInstOpData(ifCnt - 1, rd), VpnUtil.DEFAULT_CALLBACK);
1580 //                }
1581 //            }
1582         }
1583
1584         @Override
1585         protected void add(InstanceIdentifier<VpnInterface> identifier, VpnInterface add) {
1586             final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
1587             String interfaceName = key.getName();
1588
1589             //increment the vpn interface count in Vpn Instance Op Data
1590 //            Long ifCnt = 0L;
1591 //            String rd = getRouteDistinguisher(add.getVpnInstanceName());
1592 //            if(rd == null || rd.isEmpty()) rd = add.getVpnInstanceName();
1593 //            VpnInstanceOpDataEntry vpnInstOp = VpnUtil.getVpnInstanceOpData(broker, rd);
1594 //            if(vpnInstOp != null &&  vpnInstOp.getVpnInterfaceCount() != null) {
1595 //                ifCnt = vpnInstOp.getVpnInterfaceCount();
1596 //            }
1597
1598 //            LOG.trace("VpnInterfaceOpListener add: interface name {} rd {} interface count in Vpn Op Instance {}", interfaceName, rd, ifCnt);
1599
1600 //            VpnUtil.asyncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
1601 //                    VpnUtil.getVpnInstanceOpDataIdentifier(rd),
1602 //                    VpnUtil.updateIntfCntInVpnInstOpData(ifCnt + 1, rd), VpnUtil.DEFAULT_CALLBACK);
1603
1604
1605         }
1606     }
1607
1608     protected void handlePrefixesForDPNs(StateTunnelList stateTunnelList, UpdateRouteAction action) {
1609         BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
1610         BigInteger destDpnId;
1611         String srcTepIp =  String.valueOf(stateTunnelList.getSrcInfo().getTepIp().getValue());
1612         String destTepIp = String.valueOf(stateTunnelList.getDstInfo().getTepIp().getValue());
1613
1614         InstanceIdentifierBuilder<VpnInstances> idBuilder = InstanceIdentifier.builder(VpnInstances.class);
1615         InstanceIdentifier<VpnInstances> vpnInstancesId = idBuilder.build();
1616         Optional<VpnInstances> vpnInstances = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vpnInstancesId);
1617         long tunTypeVal = 0, vpnId;
1618
1619         if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) {
1620             tunTypeVal = VpnConstants.ITMTunnelLocType.Internal.getValue();
1621         } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) {
1622             tunTypeVal = VpnConstants.ITMTunnelLocType.External.getValue();
1623         } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeHwvtep.class){
1624             tunTypeVal = VpnConstants.ITMTunnelLocType.Hwvtep.getValue();
1625         } else {
1626             tunTypeVal = VpnConstants.ITMTunnelLocType.Invalid.getValue();
1627         }
1628         LOG.trace("tunTypeVal is {}", tunTypeVal);
1629
1630         if (vpnInstances.isPresent()) {
1631             List<VpnInstance> vpnInstanceList = vpnInstances.get().getVpnInstance();
1632             Iterator<VpnInstance> vpnInstIter = vpnInstanceList.iterator();
1633             LOG.trace("vpnInstIter {}", vpnInstIter);
1634             while (vpnInstIter.hasNext()) {
1635                 VpnInstance vpnInstance = vpnInstIter.next();
1636                 LOG.trace("vpnInstance {}", vpnInstance);
1637                 vpnId = VpnUtil.getVpnId(broker, vpnInstance.getVpnInstanceName());
1638                 try {
1639                     VpnAfConfig vpnConfig = vpnInstance.getIpv4Family();
1640                     LOG.trace("vpnConfig {}", vpnConfig);
1641                     String rd = vpnConfig.getRouteDistinguisher();
1642                     if (rd == null || rd.isEmpty()) {
1643                         rd = vpnInstance.getVpnInstanceName();
1644                         LOG.trace("rd is null or empty. Assigning VpnInstanceName to rd {}", rd);
1645                     }
1646                     InstanceIdentifier<VpnToDpnList> srcId =
1647                         VpnUtil.getVpnToDpnListIdentifier(rd, srcDpnId);
1648                     Optional<VpnToDpnList> srcDpnInVpn =
1649                             VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, srcId);
1650                     if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
1651                         destDpnId = new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId());
1652                         InstanceIdentifier<VpnToDpnList> destId =
1653                                 VpnUtil.getVpnToDpnListIdentifier(rd, destDpnId);
1654                         Optional<VpnToDpnList> destDpnInVpn =
1655                                 VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, destId);
1656                         if (!(srcDpnInVpn.isPresent() &&
1657                                 destDpnInVpn.isPresent())) {
1658                             LOG.trace(" srcDpn {} - destDPN {}, do not share the VPN {} with rd {}.",
1659                                     srcDpnId, destDpnId, vpnInstance.getVpnInstanceName(), rd);
1660                             continue;
1661                         }
1662                     }
1663                     if (srcDpnInVpn.isPresent()) {
1664                         List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
1665                                 .instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces>
1666                             vpnInterfaces = srcDpnInVpn.get().getVpnInterfaces();
1667                         for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
1668                                 .instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces vpnInterface : vpnInterfaces) {
1669                             InstanceIdentifier<VpnInterface> vpnIntfId =
1670                                 VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getInterfaceName());
1671                             LOG.trace("vpnInterface {}", vpnInterface);
1672                             InstanceIdentifier<Adjacencies> path =
1673                                 vpnIntfId.augmentation(Adjacencies.class);
1674                             Optional<Adjacencies> adjacencies =
1675                                 VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
1676                             LOG.trace("adjacencies {}", adjacencies);
1677                             if (adjacencies.isPresent()) {
1678                                 List<Adjacency> adjacencyList = adjacencies.get().getAdjacency();
1679                                 Iterator<Adjacency> adjacencyIterator = adjacencyList.iterator();
1680
1681                                 while (adjacencyIterator.hasNext()) {
1682                                     Adjacency adjacency = adjacencyIterator.next();
1683                                     try {
1684                                         if (action == UpdateRouteAction.ADVERTISE_ROUTE) {
1685                                             LOG.info("VPNInterfaceManager : Added Fib Entry rd {} prefix {} nextHop {} label {}",
1686                                                      rd, adjacency.getIpAddress(), adjacency.getNextHopIpList(),
1687                                                      adjacency.getLabel());
1688 //                                            vrf = new VrfEntryBuilder().set
1689                                             if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
1690                                                 fibManager.handleRemoteRoute(true,
1691                                                         new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId()),
1692                                                         new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId()),
1693                                                         VpnUtil.getVpnId(broker, vpnInstance.getVpnInstanceName()),
1694                                                         rd, adjacency.getIpAddress(), srcTepIp, destTepIp);
1695                                             }
1696                                             if (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) {
1697                                                 bgpManager.advertisePrefix( rd, adjacency.getIpAddress(),
1698                                                                             adjacency.getNextHopIpList(),
1699                                                                             adjacency.getLabel().intValue());
1700                                                 fibManager.populateFibOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
1701                                             }
1702                                         }
1703                                         else if (action == UpdateRouteAction.WITHDRAW_ROUTE) {
1704                                             LOG.info("VPNInterfaceManager : Removed Fib entry rd {} prefix {}",
1705                                                      rd, adjacency.getIpAddress());
1706                                             if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
1707                                                 fibManager.handleRemoteRoute(false, srcDpnId,
1708                                                                 new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId()),
1709                                                                 vpnId, rd, adjacency.getIpAddress(), srcTepIp, destTepIp);
1710                                             }
1711                                             if (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) {
1712                                                 bgpManager.withdrawPrefix(rd, adjacency.getIpAddress());
1713                                                 fibManager.cleanUpDpnForVpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
1714                                             }
1715                                         }
1716                                     } catch (Exception e) {
1717                                         LOG.error("Exception when updating prefix {} in vrf {} to BGP",
1718                                             adjacency.getIpAddress(), rd);
1719                                     }
1720                                 }
1721                             } else {
1722                                 LOG.trace("no adjacencies present for path {}.", path);
1723                             }
1724
1725                         }
1726                         // if (action == UpdateRouteAction.WITHDRAW_ROUTE) {
1727                         //    fibManager.cleanUpDpnForVpn(dpnId, VpnUtil.getVpnId(broker, vpnInstance.getVpnInstanceName()), rd);
1728                         // }
1729                     } else {
1730                         LOG.trace("dpnInVpn check failed for srcDpnId {}.", srcDpnId);
1731                     }
1732                 } catch (Exception e) {
1733                     LOG.error("updatePrefixesForDPN {} in vpn {} failed", 0, vpnInstance.getVpnInstanceName(), e);
1734                 }
1735             }
1736         } else {
1737             LOG.trace("No vpn instances present.");
1738         }
1739     }
1740
1741     void publishAddNotification(final BigInteger dpnId, final String vpnName, final String rd) {
1742         LOG.debug("Sending notification for add dpn {} in vpn {} event ", dpnId, vpnName);
1743         AddEventData data = new AddEventDataBuilder().setVpnName(vpnName).setRd(rd).setDpnId(dpnId).build();
1744         AddDpnEvent event = new AddDpnEventBuilder().setAddEventData(data).build();
1745         final ListenableFuture<? extends Object> eventFuture = notificationPublishService.offerNotification(event);
1746         Futures.addCallback(eventFuture, new FutureCallback<Object>() {
1747             @Override
1748             public void onFailure(Throwable error) {
1749                 LOG.warn("Error in notifying listeners for add dpn {} in vpn {} event ", dpnId, vpnName, error);
1750             }
1751
1752             @Override
1753             public void onSuccess(Object arg) {
1754                 LOG.trace("Successful in notifying listeners for add dpn {} in vpn {} event ", dpnId, vpnName);
1755             }
1756         });
1757     }
1758
1759     void publishRemoveNotification(final BigInteger dpnId, final String vpnName, final String rd) {
1760         LOG.debug("Sending notification for remove dpn {} in vpn {} event ", dpnId, vpnName);
1761         RemoveEventData data = new RemoveEventDataBuilder().setVpnName(vpnName).setRd(rd).setDpnId(dpnId).build();
1762         RemoveDpnEvent event = new RemoveDpnEventBuilder().setRemoveEventData(data).build();
1763         final ListenableFuture<? extends Object> eventFuture = notificationPublishService.offerNotification(event);
1764         Futures.addCallback(eventFuture, new FutureCallback<Object>() {
1765             @Override
1766             public void onFailure(Throwable error) {
1767                 LOG.warn("Error in notifying listeners for remove dpn {} in vpn {} event ", dpnId, vpnName, error);
1768             }
1769
1770             @Override
1771             public void onSuccess(Object arg) {
1772                 LOG.trace("Successful in notifying listeners for remove dpn {} in vpn {} event ", dpnId, vpnName);
1773             }
1774         });
1775     }
1776
1777     InstanceIdentifier<DpnVpninterfacesList> getRouterDpnId(String routerName, BigInteger dpnId) {
1778         return InstanceIdentifier.builder(NeutronRouterDpns.class)
1779             .child(RouterDpnList.class, new RouterDpnListKey(routerName))
1780             .child(DpnVpninterfacesList.class, new DpnVpninterfacesListKey(dpnId)).build();
1781     }
1782
1783     InstanceIdentifier<RouterDpnList> getRouterId(String routerName) {
1784         return InstanceIdentifier.builder(NeutronRouterDpns.class)
1785             .child(RouterDpnList.class, new RouterDpnListKey(routerName)).build();
1786     }
1787
1788     protected void addToNeutronRouterDpnsMap(String routerName, String vpnInterfaceName) {
1789         BigInteger dpId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, vpnInterfaceName);
1790         if(dpId.equals(BigInteger.ZERO)) {
1791             LOG.warn("Could not retrieve dp id for interface {} to handle router {} association model", vpnInterfaceName, routerName);
1792             return;
1793         }
1794         InstanceIdentifier<DpnVpninterfacesList> routerDpnListIdentifier = getRouterDpnId(routerName, dpId);
1795
1796         Optional<DpnVpninterfacesList> optionalRouterDpnList = VpnUtil.read(broker, LogicalDatastoreType
1797                 .OPERATIONAL, routerDpnListIdentifier);
1798         RouterInterfaces routerInterface = new RouterInterfacesBuilder().setKey(new RouterInterfacesKey(vpnInterfaceName)).setInterface(vpnInterfaceName).build();
1799         if (optionalRouterDpnList.isPresent()) {
1800             MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier.child(
1801                     RouterInterfaces.class,  new RouterInterfacesKey(vpnInterfaceName)), routerInterface);
1802         } else {
1803             MDSALUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
1804                     getRouterId(routerName),
1805                     new RouterDpnListBuilder().setRouterId(routerName).build());
1806             //VpnToDpnListBuilder vpnToDpnList = new VpnToDpnListBuilder().setDpnId(dpnId);
1807             DpnVpninterfacesListBuilder dpnVpnList = new DpnVpninterfacesListBuilder().setDpnId(dpId);
1808             List<RouterInterfaces> routerInterfaces =  new ArrayList<>();
1809             routerInterfaces.add(routerInterface);
1810             MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier,
1811                     dpnVpnList.setRouterInterfaces(routerInterfaces).build());
1812         }
1813     }
1814
1815     protected void removeFromNeutronRouterDpnsMap(String routerName, String vpnInterfaceName) {
1816         BigInteger dpId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, vpnInterfaceName);
1817         if(dpId.equals(BigInteger.ZERO)) {
1818             LOG.warn("Could not retrieve dp id for interface {} to handle router {} dissociation model", vpnInterfaceName, routerName);
1819             return;
1820         }
1821         InstanceIdentifier<DpnVpninterfacesList> routerDpnListIdentifier = getRouterDpnId(routerName, dpId);
1822         Optional<DpnVpninterfacesList> optionalRouterDpnList = VpnUtil.read(broker, LogicalDatastoreType
1823                 .OPERATIONAL, routerDpnListIdentifier);
1824         if (optionalRouterDpnList.isPresent()) {
1825             List<RouterInterfaces> routerInterfaces = optionalRouterDpnList.get().getRouterInterfaces();
1826             RouterInterfaces routerInterface = new RouterInterfacesBuilder().setKey(new RouterInterfacesKey(vpnInterfaceName)).setInterface(vpnInterfaceName).build();
1827
1828             if (routerInterfaces != null && routerInterfaces.remove(routerInterface)) {
1829                 if (routerInterfaces.isEmpty()) {
1830                     MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier);
1831                 } else {
1832                     MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier.child(
1833                             RouterInterfaces.class,
1834                             new RouterInterfacesKey(vpnInterfaceName)));
1835                 }
1836             }
1837         }
1838     }
1839
1840     protected void removeFromNeutronRouterDpnsMap(String routerName, String vpnInterfaceName,BigInteger dpId) {
1841         if(dpId.equals(BigInteger.ZERO)) {
1842             LOG.warn("Could not retrieve dp id for interface {} to handle router {} dissociation model", vpnInterfaceName, routerName);
1843             return;
1844         }
1845         InstanceIdentifier<DpnVpninterfacesList> routerDpnListIdentifier = getRouterDpnId(routerName, dpId);
1846         Optional<DpnVpninterfacesList> optionalRouterDpnList = VpnUtil.read(broker, LogicalDatastoreType
1847                 .OPERATIONAL, routerDpnListIdentifier);
1848         if (optionalRouterDpnList.isPresent()) {
1849             List<RouterInterfaces> routerInterfaces = optionalRouterDpnList.get().getRouterInterfaces();
1850             RouterInterfaces routerInterface = new RouterInterfacesBuilder().setKey(new RouterInterfacesKey(vpnInterfaceName)).setInterface(vpnInterfaceName).build();
1851
1852             if (routerInterfaces != null && routerInterfaces.remove(routerInterface)) {
1853                 if (routerInterfaces.isEmpty()) {
1854                     MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier);
1855                 } else {
1856                     MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier.child(
1857                             RouterInterfaces.class,
1858                             new RouterInterfacesKey(vpnInterfaceName)));
1859                 }
1860             }
1861         }
1862     }
1863
1864     public void addMIPAdjacency(String vpnName,String vpnInterface, IpAddress prefix){
1865
1866         LOG.trace("Adding {} adjacency to VPN Interface {} ",prefix,vpnInterface);
1867         InstanceIdentifier<VpnInterface> vpnIfId = VpnUtil.getVpnInterfaceIdentifier(vpnInterface);
1868         InstanceIdentifier<Adjacencies> path = vpnIfId.augmentation(Adjacencies.class);
1869         Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, path);
1870         String nextHopIpAddr = null;
1871         String nextHopMacAddress = null;
1872         String ip = prefix.getIpv4Address().getValue();
1873         if (adjacencies.isPresent()) {
1874             List<Adjacency> adjacencyList = adjacencies.get().getAdjacency();
1875             ip = VpnUtil.getIpPrefix(ip);
1876             for (Adjacency adjacs : adjacencyList) {
1877                 if (adjacs.getMacAddress() != null && !adjacs.getMacAddress().isEmpty()) {
1878                     nextHopIpAddr = adjacs.getIpAddress();
1879                     nextHopMacAddress = adjacs.getMacAddress();
1880                     break;
1881                 }
1882             }
1883             if (nextHopMacAddress != null && ip != null) {
1884                 synchronized (vpnInterface.intern()) {
1885                     String rd = VpnUtil.getVpnRd(broker, vpnName);
1886                     long label =
1887                             VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
1888                                     VpnUtil.getNextHopLabelKey((rd != null) ? rd : vpnName, ip));
1889                     String nextHopIp = nextHopIpAddr.split("/")[0];
1890                     Adjacency newAdj = new AdjacencyBuilder().setIpAddress(ip).setKey
1891                             (new AdjacencyKey(ip)).setNextHopIpList(Arrays.asList(nextHopIp)).build();
1892                     adjacencyList.add(newAdj);
1893                     Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencyList);
1894                     VpnInterface newVpnIntf = new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(vpnInterface)).
1895                             setName(vpnInterface).setVpnInstanceName(vpnName).addAugmentation(Adjacencies.class, aug).build();
1896                     VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vpnIfId, newVpnIntf);
1897                 }
1898                 LOG.debug(" Successfully stored subnetroute Adjacency into VpnInterface {}", vpnInterface);
1899             }
1900         }
1901
1902     }
1903
1904     public void removeMIPAdjacency(String vpnName, String vpnInterface, IpAddress prefix) {
1905         String ip = VpnUtil.getIpPrefix(prefix.getIpv4Address().getValue());
1906         LOG.trace("Removing {} adjacency from Old VPN Interface {} ",ip,vpnInterface);
1907         InstanceIdentifier<VpnInterface> vpnIfId = VpnUtil.getVpnInterfaceIdentifier(vpnInterface);
1908         InstanceIdentifier<Adjacencies> path = vpnIfId.augmentation(Adjacencies.class);
1909         Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
1910         if (adjacencies.isPresent()) {
1911             synchronized (vpnInterface.intern()) {
1912                 InstanceIdentifier<Adjacency> adjacencyIdentifier = InstanceIdentifier.builder(VpnInterfaces.class).
1913                         child(VpnInterface.class, new VpnInterfaceKey(vpnInterface)).augmentation(Adjacencies.class)
1914                         .child(Adjacency.class, new AdjacencyKey(ip)).build();
1915                 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, adjacencyIdentifier);
1916             }
1917             LOG.trace("Successfully Deleted Adjacency into VpnInterface {}", vpnInterface);
1918         }
1919     }
1920
1921     class TunnelInterfaceStateListener extends AbstractDataChangeListener<StateTunnelList>  {
1922         public TunnelInterfaceStateListener(final DataBroker db, VpnInterfaceManager vpnIfMgr) {
1923             super(StateTunnelList.class);
1924         }
1925
1926
1927         @Override
1928         protected void remove(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList del) {
1929             LOG.trace("Tunnel deletion---- {}", del);
1930             handlePrefixesForDPNs(del, UpdateRouteAction.WITHDRAW_ROUTE);
1931         }
1932
1933         @Override
1934         protected void update(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList original, StateTunnelList update) {
1935             LOG.trace("Tunnel updation---- {}", update);
1936             LOG.trace("ITM Tunnel {} of type {} state event changed from :{} to :{}",
1937                     update.getTunnelInterfaceName(),
1938                     fibManager.getTransportTypeStr(update.getTransportType().toString()),
1939                     original.isTunnelState(), update.isTunnelState());
1940                 //withdraw all prefixes in all vpns for this dpn
1941             boolean isTunnelUp = update.isTunnelState();
1942                 handlePrefixesForDPNs(update,isTunnelUp ?  UpdateRouteAction.ADVERTISE_ROUTE :
1943                                                             UpdateRouteAction.WITHDRAW_ROUTE);
1944         }
1945
1946         @Override
1947         protected void add(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList add) {
1948             LOG.trace("Tunnel addition---- {}", add);
1949
1950             if(!add.isTunnelState()) {
1951                 LOG.trace(  "Tunnel {} is not yet UP.",
1952                             add.getTunnelInterfaceName());
1953                 return;
1954             } else {
1955                 LOG.trace("ITM Tunnel ,type {} ,State is UP b/w src: {} and dest: {}",
1956                         fibManager.getTransportTypeStr(add.getTransportType().toString()),
1957                         add.getSrcInfo().getTepDeviceId(), add.getDstInfo().getTepDeviceId());
1958                 handlePrefixesForDPNs(add, UpdateRouteAction.ADVERTISE_ROUTE);
1959             }
1960         }
1961     }
1962
1963 }