JUnits for Interface Manager
[vpnservice.git] / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / vpnservice / VpnInterfaceManager.java
1 /*
2  * Copyright (c) 2015 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.vpnservice;
9
10 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
11
12 import java.math.BigInteger;
13 import java.util.Collection;
14 import java.util.Collections;
15 import java.util.HashSet;
16 import java.util.List;
17 import java.util.ArrayList;
18 import java.util.Map;
19 import java.util.concurrent.ConcurrentHashMap;
20 import java.util.concurrent.ExecutionException;
21 import java.util.concurrent.Future;
22 import com.google.common.base.Optional;
23 import com.google.common.collect.ImmutableList;
24 import com.google.common.util.concurrent.Futures;
25 import com.google.common.util.concurrent.FutureCallback;
26 import org.opendaylight.bgpmanager.api.IBgpManager;
27 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
28 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
29 import org.opendaylight.fibmanager.api.IFibManager;
30 import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
31 import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
32 import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
33 import org.opendaylight.vpnservice.mdsalutil.InstructionType;
34 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
35 import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
36 import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
37 import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
38 import org.opendaylight.vpnservice.mdsalutil.NwConstants;
39 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
40 import org.opendaylight.yangtools.concepts.ListenerRegistration;
41 import org.opendaylight.yangtools.yang.binding.DataObject;
42 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
43 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
44 import org.opendaylight.yangtools.yang.common.RpcResult;
45 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
46 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
47 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
48 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.AdjacencyList;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.Adjacency;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstance1;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.GetUniqueIdInput;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.GetUniqueIdInputBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.GetUniqueIdOutput;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
62 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.Adjacencies;
64 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig;
65 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
66 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
67 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceKey;
68 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
69 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
70 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.AdjacenciesBuilder;
72 import org.slf4j.Logger;
73 import org.slf4j.LoggerFactory;
74
75 public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface> implements AutoCloseable {
76     private static final Logger LOG = LoggerFactory.getLogger(VpnInterfaceManager.class);
77     private ListenerRegistration<DataChangeListener> listenerRegistration, interfaceListenerRegistration;
78     private final DataBroker broker;
79     private final IBgpManager bgpManager;
80     private IFibManager fibManager;
81     private IMdsalApiManager mdsalManager;
82     private IInterfaceManager interfaceManager;
83     private IdManagerService idManager;
84     private Map<Long, Collection<BigInteger>> vpnToDpnsDb;
85     private Map<BigInteger, Collection<String>> dpnToInterfaceDb;
86     private InterfaceListener interfaceListener;
87
88     private static final FutureCallback<Void> DEFAULT_CALLBACK =
89             new FutureCallback<Void>() {
90                 public void onSuccess(Void result) {
91                     LOG.debug("Success in Datastore operation");
92                 }
93
94                 public void onFailure(Throwable error) {
95                     LOG.error("Error in Datastore operation", error);
96                 };
97             };
98
99     /**
100      * Responsible for listening to data change related to VPN Interface
101      * Bind VPN Service on the interface and informs the BGP service
102      * 
103      * @param db - dataBroker service reference
104      */
105     public VpnInterfaceManager(final DataBroker db, final IBgpManager bgpManager) {
106         super(VpnInterface.class);
107         broker = db;
108         this.bgpManager = bgpManager;
109         vpnToDpnsDb = new ConcurrentHashMap<>();
110         dpnToInterfaceDb = new ConcurrentHashMap<>();
111         interfaceListener = new InterfaceListener();
112         registerListener(db);
113     }
114
115     public void setMdsalManager(IMdsalApiManager mdsalManager) {
116         this.mdsalManager = mdsalManager;
117     }
118
119     public void setInterfaceManager(IInterfaceManager interfaceManager) {
120         this.interfaceManager = interfaceManager;
121     }
122
123     public void setFibManager(IFibManager fibManager) {
124         this.fibManager = fibManager;
125     }
126
127     public void setIdManager(IdManagerService idManager) {
128         this.idManager = idManager;
129     }
130
131     @Override
132     public void close() throws Exception {
133         if (listenerRegistration != null) {
134             try {
135                 listenerRegistration.close();
136                 interfaceListenerRegistration.close();
137             } catch (final Exception e) {
138                 LOG.error("Error when cleaning up DataChangeListener.", e);
139             }
140             listenerRegistration = null;
141             interfaceListenerRegistration = null;
142         }
143         LOG.info("VPN Interface Manager Closed");
144     }
145
146     private void registerListener(final DataBroker db) {
147         try {
148             listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
149                     getWildCardPath(), VpnInterfaceManager.this, DataChangeScope.SUBTREE);
150             interfaceListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
151                     getInterfaceListenerPath(), interfaceListener, DataChangeScope.SUBTREE);
152         } catch (final Exception e) {
153             LOG.error("VPN Service DataChange listener registration fail!", e);
154             throw new IllegalStateException("VPN Service registration Listener failed.", e);
155         }
156     }
157
158     private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> getInterfaceListenerPath() {
159         return InstanceIdentifier.create(InterfacesState.class)
160         .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class);
161     }
162
163     @Override
164     protected void add(final InstanceIdentifier<VpnInterface> identifier,
165             final VpnInterface vpnInterface) {
166         LOG.trace("key: {} , value: {}", identifier, vpnInterface );
167         addInterface(identifier, vpnInterface);
168     }
169
170     private void addInterface(final InstanceIdentifier<VpnInterface> identifier,
171                               final VpnInterface vpnInterface) {
172         final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
173         String interfaceName = key.getName();
174         InstanceIdentifierBuilder<Interface> idBuilder = 
175                 InstanceIdentifier.builder(Interfaces.class).child(Interface.class, new InterfaceKey(interfaceName));
176         InstanceIdentifier<Interface> id = idBuilder.build();
177         Optional<Interface> port = read(LogicalDatastoreType.CONFIGURATION, id);
178         if (port.isPresent()) {
179             Interface interf = port.get();
180             bindServiceOnInterface(interf, vpnInterface.getVpnInstanceName());
181             updateNextHops(identifier, vpnInterface);
182         }
183     }
184
185     private void updateNextHops(final InstanceIdentifier<VpnInterface> identifier, VpnInterface intf) {
186         //Read NextHops
187         InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
188         Optional<Adjacencies> adjacencies = read(LogicalDatastoreType.CONFIGURATION, path);
189         String intfName = intf.getName();
190
191         if (adjacencies.isPresent()) {
192             List<Adjacency> nextHops = adjacencies.get().getAdjacency();
193             List<Adjacency> value = new ArrayList<>();
194
195             //Get the rd of the vpn instance
196             String rd = getRouteDistinguisher(intf.getVpnInstanceName());
197
198             BigInteger dpnId = interfaceManager.getDpnForInterface(intfName);
199             String nextHopIp = interfaceManager.getEndpointIpForDpn(dpnId);
200
201
202             LOG.trace("NextHops are {}", nextHops);
203             for (Adjacency nextHop : nextHops) {
204                 String key = rd + VpnConstants.SEPARATOR + nextHop.getIpAddress();
205                 long label = getUniqueId(key);
206                 value.add(new AdjacencyBuilder(nextHop).setLabel(label).build());
207             }
208
209             Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(value);
210             VpnInterface opInterface = VpnUtil.getVpnInterface(intfName, intf.getVpnInstanceName(), aug);
211             InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(intfName);
212             syncWrite(LogicalDatastoreType.OPERATIONAL, interfaceId, opInterface, DEFAULT_CALLBACK);
213             for (Adjacency nextHop : nextHops) {
214                 String key = rd + VpnConstants.SEPARATOR + nextHop.getIpAddress();
215                 long label = getUniqueId(key);
216                 updatePrefixToBGP(rd, nextHop, nextHopIp, label);
217             }
218         }
219     }
220
221     private Integer getUniqueId(String idKey) {
222         GetUniqueIdInput getIdInput = new GetUniqueIdInputBuilder()
223                                            .setPoolName(VpnConstants.VPN_IDPOOL_NAME)
224                                            .setIdKey(idKey).build();
225
226         try {
227             Future<RpcResult<GetUniqueIdOutput>> result = idManager.getUniqueId(getIdInput);
228             RpcResult<GetUniqueIdOutput> rpcResult = result.get();
229             if(rpcResult.isSuccessful()) {
230                 return rpcResult.getResult().getIdValue().intValue();
231             } else {
232                 LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
233             }
234         } catch (NullPointerException | InterruptedException | ExecutionException e) {
235             LOG.warn("Exception when getting Unique Id",e);
236         }
237         return 0;
238     }
239
240     private long getVpnId(String vpnName) {
241         //TODO: This should be a Util function
242         InstanceIdentifier<VpnInstance1> id = InstanceIdentifier.builder(VpnInstances.class)
243                 .child(VpnInstance.class, new VpnInstanceKey(vpnName)).augmentation(VpnInstance1.class).build();
244         Optional<VpnInstance1> vpnInstance = read(LogicalDatastoreType.OPERATIONAL, id);
245
246         long vpnId = VpnConstants.INVALID_ID;
247         if(vpnInstance.isPresent()) {
248             vpnId = vpnInstance.get().getVpnId();
249         }
250         return vpnId;
251     }
252
253     private String getRouteDistinguisher(String vpnName) {
254         InstanceIdentifier<VpnInstance> id = InstanceIdentifier.builder(VpnInstances.class)
255                                       .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
256         Optional<VpnInstance> vpnInstance = read(LogicalDatastoreType.CONFIGURATION, id);
257         String rd = "";
258         if(vpnInstance.isPresent()) {
259             VpnInstance instance = vpnInstance.get();
260             VpnAfConfig config = instance.getIpv4Family();
261             rd = config.getRouteDistinguisher();
262         }
263         return rd;
264     }
265
266     private synchronized void updateMappingDbs(long vpnId, BigInteger dpnId, String intfName, String rd) {
267         Collection<BigInteger> dpnIds = vpnToDpnsDb.get(vpnId);
268         if(dpnIds == null) {
269             dpnIds = new HashSet<>();
270         }
271         if(dpnIds.add(dpnId)) {
272             vpnToDpnsDb.put(vpnId, dpnIds);
273             fibManager.populateFibOnNewDpn(dpnId, vpnId, rd);
274         }
275
276         Collection<String> intfNames = dpnToInterfaceDb.get(dpnId);
277         if(intfNames == null) {
278             intfNames = new ArrayList<>();
279         }
280         intfNames.add(intfName);
281         dpnToInterfaceDb.put(dpnId, intfNames);
282     }
283
284     private synchronized void remoteFromMappingDbs(long vpnId, BigInteger dpnId, String inftName, String rd) {
285         Collection<String> intfNames = dpnToInterfaceDb.get(dpnId);
286         if(intfNames == null) {
287             return;
288         }
289         intfNames.remove(inftName);
290         dpnToInterfaceDb.put(dpnId, intfNames);
291         //TODO: Delay 'DPN' removal so that other services can cleanup the entries for this dpn
292         if(intfNames.isEmpty()) {
293             Collection<BigInteger> dpnIds = vpnToDpnsDb.get(vpnId);
294             if(dpnIds == null) {
295                 return;
296             }
297             dpnIds.remove(dpnId);
298             vpnToDpnsDb.put(vpnId, dpnIds);
299             fibManager.cleanUpDpnForVpn(dpnId, vpnId, rd);
300         }
301     }
302
303     private void bindServiceOnInterface(Interface intf, String vpnName) {
304         LOG.trace("Bind service on interface {} for VPN: {}", intf, vpnName);
305
306         long vpnId = getVpnId(vpnName);
307         BigInteger dpId = interfaceManager.getDpnForInterface(intf.getName()); 
308         if(dpId.equals(BigInteger.ZERO)) {
309             LOG.warn("DPN for interface {} not found. Bind service on this interface aborted.", intf.getName());
310             return;
311         } else {
312             String rd = getRouteDistinguisher(vpnName);
313             updateMappingDbs(vpnId, dpId, intf.getName(), rd);
314         }
315
316         long portNo = interfaceManager.getPortForInterface(intf.getName());
317         String flowRef = getVpnInterfaceFlowRef(dpId, VpnConstants.LPORT_INGRESS_TABLE, vpnId, portNo);
318
319         String flowName = intf.getName();
320         BigInteger COOKIE_VM_INGRESS_TABLE = new BigInteger("8000001", 16);
321
322         int priority = VpnConstants.DEFAULT_FLOW_PRIORITY;
323         short gotoTableId = VpnConstants.FIB_TABLE;
324         if(intf.getType().equals(Tunnel.class)){
325             gotoTableId = VpnConstants.LFIB_TABLE;
326         }
327
328         List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
329         mkInstructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] {
330                 BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
331
332         mkInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { gotoTableId }));
333
334         List<MatchInfo> matches = new ArrayList<MatchInfo>();
335         matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[] {
336                 dpId, BigInteger.valueOf(portNo) }));
337
338         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, VpnConstants.LPORT_INGRESS_TABLE, flowRef,
339                           priority, flowName, 0, 0, COOKIE_VM_INGRESS_TABLE, matches, mkInstructions);
340
341         mdsalManager.installFlow(flowEntity);
342     }
343
344     private String getVpnInterfaceFlowRef(BigInteger dpId, short tableId,
345             long vpnId, long portNo) {
346         return new StringBuilder().append(dpId).append(tableId).append(vpnId).append(portNo).toString();
347     }
348
349     private void updatePrefixToBGP(String rd, Adjacency nextHop, String nextHopIp, long label) {
350         try {
351             bgpManager.addPrefix(rd, nextHop.getIpAddress(), nextHopIp, (int)label);
352         } catch(Exception e) {
353             LOG.error("Add prefix failed", e);
354         }
355     }
356
357     private <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
358             InstanceIdentifier<T> path) {
359
360         ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
361
362         Optional<T> result = Optional.absent();
363         try {
364             result = tx.read(datastoreType, path).get();
365         } catch (Exception e) {
366             throw new RuntimeException(e);
367         }
368
369         return result;
370     }
371
372     private InstanceIdentifier<VpnInterface> getWildCardPath() {
373         return InstanceIdentifier.create(VpnInterfaces.class).child(VpnInterface.class);
374     }
375
376     @Override
377     protected void remove( InstanceIdentifier<VpnInterface> identifier, VpnInterface vpnInterface) {
378         LOG.trace("Remove event - key: {}, value: {}" ,identifier, vpnInterface );
379         final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
380         String interfaceName = key.getName();
381         InstanceIdentifierBuilder<Interface> idBuilder = 
382                 InstanceIdentifier.builder(Interfaces.class).child(Interface.class, new InterfaceKey(interfaceName));
383         InstanceIdentifier<Interface> id = idBuilder.build();
384         Optional<Interface> port = read(LogicalDatastoreType.CONFIGURATION, id);
385         if (port.isPresent()) {
386             Interface interf = port.get();
387             removeNextHops(identifier, vpnInterface);
388             unbindServiceOnInterface(interf, vpnInterface.getVpnInstanceName());
389             //InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
390             delete(LogicalDatastoreType.OPERATIONAL, identifier);
391         } else {
392             LOG.warn("No nexthops were available to handle remove event {}", interfaceName);
393         }
394     }
395
396     private void removeNextHops(final InstanceIdentifier<VpnInterface> identifier, VpnInterface intf) {
397         //Read NextHops
398         InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
399         Optional<Adjacencies> adjacencies = read(LogicalDatastoreType.OPERATIONAL, path);
400         String intfName = intf.getName();
401         String rd = getRouteDistinguisher(intf.getVpnInstanceName());
402         if (adjacencies.isPresent()) {
403             List<Adjacency> nextHops = adjacencies.get().getAdjacency();
404
405             if (!nextHops.isEmpty()) {
406                 LOG.trace("NextHops are " + nextHops);
407                 for (Adjacency nextHop : nextHops) {
408                     removePrefixFromBGP(rd, nextHop);
409                 }
410             }
411         }
412     }
413
414     private <T extends DataObject> void delete(LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
415         WriteTransaction tx = broker.newWriteOnlyTransaction();
416         tx.delete(datastoreType, path);
417         Futures.addCallback(tx.submit(), DEFAULT_CALLBACK);
418     }
419
420     private void unbindServiceOnInterface(Interface intf, String vpnName) {
421         LOG.trace("Unbind service on interface {} for VPN: {}", intf, vpnName);
422
423         long vpnId = getVpnId(vpnName);
424         BigInteger dpId = interfaceManager.getDpnForInterface(intf);
425         if(dpId.equals(BigInteger.ZERO)) {
426             LOG.warn("DPN for interface {} not found. Unbind service on this interface aborted.", intf.getName());
427             return;
428         } else {
429             String rd = getRouteDistinguisher(vpnName);
430             remoteFromMappingDbs(vpnId, dpId, intf.getName(), rd);
431             LOG.debug("removed vpn mapping for interface {} from VPN RD {}", intf.getName(), rd);
432         }
433
434         long portNo = interfaceManager.getPortForInterface(intf);
435         String flowRef = getVpnInterfaceFlowRef(dpId, VpnConstants.LPORT_INGRESS_TABLE, vpnId, portNo);
436
437         String flowName = intf.getName();
438
439         int priority = VpnConstants.DEFAULT_FLOW_PRIORITY;
440
441         List<MatchInfo> matches = new ArrayList<MatchInfo>();
442         matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[] {
443                 dpId, BigInteger.valueOf(portNo) }));
444
445         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, VpnConstants.LPORT_INGRESS_TABLE, flowRef,
446                           priority, flowName, 0, 0, null, matches, null);
447         LOG.debug("Remove ingress flow for port {} in dpn {}", portNo, dpId.intValue());
448
449         mdsalManager.removeFlow(flowEntity);
450     }
451
452     private void removePrefixFromBGP(String rd, Adjacency nextHop) {
453         try {
454             bgpManager.deletePrefix(rd, nextHop.getIpAddress());
455         } catch(Exception e) {
456             LOG.error("Delete prefix failed", e);
457         }
458     }
459
460     @Override
461     protected void update(InstanceIdentifier<VpnInterface> identifier, 
462                                    VpnInterface original, VpnInterface update) {
463         LOG.trace("Update VPN Interface {} , original {}, update {}", 
464                                                   identifier, original, update);
465         String vpnName = original.getVpnInstanceName();
466
467         boolean vpnNameChanged = false;
468         String rd = getRouteDistinguisher(vpnName);
469         String newRd = rd;
470         if(!vpnName.equals(update.getVpnInstanceName())) {
471             //VPN for this interface got changed. 
472             //Remove the interface from old VPN and add it to new VPN
473             String newVpnName = update.getVpnInstanceName();
474             newRd = getRouteDistinguisher(newVpnName);
475             if(newRd.equals("")) {
476                 LOG.warn("VPN Instance {} not found. Update operation aborted", newVpnName);
477                 return;
478             }
479             vpnNameChanged = true;
480             LOG.debug("New VPN Name for the interface {} is {}", newVpnName, original.getName());
481         }
482
483         BigInteger dpnId = interfaceManager.getDpnForInterface(original.getName());
484         String nextHopIp = interfaceManager.getEndpointIpForDpn(dpnId);
485         //List<Adjacency> oldAdjs = original.getAugmentation(Adjacencies.class).getAdjacency();
486         List<Adjacency> newAdjs = update.getAugmentation(Adjacencies.class).getAdjacency();
487         if(vpnNameChanged && newAdjs != null && !newAdjs.isEmpty()) {
488             long label = VpnConstants.INVALID_ID;
489             InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
490             Optional<Adjacencies> adjacencies = read(LogicalDatastoreType.OPERATIONAL, path);
491             if (adjacencies.isPresent()) {
492                 List<Adjacency> nextHops = adjacencies.get().getAdjacency();
493                 for(Adjacency nextHop : nextHops) {
494                     label = nextHop.getLabel();
495                     if(label == VpnConstants.INVALID_ID) {
496                         //Generate label using ID Manager
497                         String key = newRd + VpnConstants.SEPARATOR + nextHop.getIpAddress();
498                         label = getUniqueId(key);
499                     }
500                     removePrefixFromBGP(rd, nextHop);
501                     //updatePrefixToBGP(newRd, nextHop, nextHopIp, label);
502                 }
503                 updateNextHops(identifier, update);
504                 asyncUpdate(LogicalDatastoreType.OPERATIONAL, identifier, update, DEFAULT_CALLBACK);
505             }
506         } else {
507             LOG.debug("No Update information is available for VPN Interface to proceed");
508         }
509     }
510
511     protected <T extends DataObject> void asyncUpdate(LogicalDatastoreType datastoreType,
512             InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
513         WriteTransaction tx = broker.newWriteOnlyTransaction();
514         tx.merge(datastoreType, path, data, true);
515         Futures.addCallback(tx.submit(), callback);
516     }
517
518     private <T extends DataObject> void asyncWrite(LogicalDatastoreType datastoreType,
519                         InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
520         WriteTransaction tx = broker.newWriteOnlyTransaction();
521         tx.put(datastoreType, path, data, true);
522         Futures.addCallback(tx.submit(), callback);
523     }
524
525     private <T extends DataObject> void syncWrite(LogicalDatastoreType datastoreType,
526                         InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
527         WriteTransaction tx = broker.newWriteOnlyTransaction();
528         tx.put(datastoreType, path, data, true);
529         tx.submit();
530     }
531
532     synchronized Collection<BigInteger> getDpnsForVpn(long vpnId) {
533         Collection<BigInteger> dpnIds = vpnToDpnsDb.get(vpnId);
534         if(dpnIds != null) {
535             return ImmutableList.copyOf(dpnIds);
536         } else {
537             return Collections.emptyList();
538         }
539     }
540
541     VpnInterface getVpnInterface(String interfaceName) {
542         Optional<VpnInterfaces> optVpnInterfaces = read(LogicalDatastoreType.CONFIGURATION, VpnUtil.getVpnInterfacesIdentifier());
543         if(optVpnInterfaces.isPresent()) {
544             List<VpnInterface> interfaces = optVpnInterfaces.get().getVpnInterface();
545             for(VpnInterface intf : interfaces) {
546                 if(intf.getName().equals(interfaceName)) {
547                     return intf;
548                 }
549             }
550         }
551         return null;
552     }
553
554     private Interface getInterface(String interfaceName) {
555         Optional<Interface> optInterface = read(LogicalDatastoreType.CONFIGURATION, VpnUtil.getInterfaceIdentifier(interfaceName));
556         if(optInterface.isPresent()) {
557             return optInterface.get();
558         }
559         return null;
560     }
561
562     private String getTunnelInterfaceFlowRef(BigInteger dpnId, short tableId, String ifName) {
563         return new StringBuilder().append(dpnId).append(tableId).append(ifName).toString();
564     }
565
566
567     protected void makeTunnelIngressFlow(BigInteger dpnId, String ifName, int addOrRemoveFlow) {
568         long portNo = 0;
569         String flowName = ifName;
570         String flowRef = getTunnelInterfaceFlowRef(dpnId, VpnConstants.LPORT_INGRESS_TABLE, ifName);
571         List<MatchInfo> matches = new ArrayList<MatchInfo>();
572         List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
573         if (NwConstants.ADD_FLOW == addOrRemoveFlow) {
574             portNo = interfaceManager.getPortForInterface(ifName);
575             matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[] {
576                 dpnId, BigInteger.valueOf(portNo) }));
577             mkInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {VpnConstants.LFIB_TABLE}));
578         }
579
580         BigInteger COOKIE_VM_INGRESS_TABLE = new BigInteger("8000001", 16);
581         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, VpnConstants.LPORT_INGRESS_TABLE, flowRef,
582                 VpnConstants.DEFAULT_FLOW_PRIORITY, flowName, 0, 0, COOKIE_VM_INGRESS_TABLE, matches, mkInstructions);
583
584         if (NwConstants.ADD_FLOW == addOrRemoveFlow) {
585             mdsalManager.installFlow(flowEntity);
586         } else {
587             mdsalManager.removeFlow(flowEntity);
588         }
589     }
590
591     private class InterfaceListener extends AbstractDataChangeListener<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface>  {
592
593         public InterfaceListener() {
594             super(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class);
595         }
596
597         @Override
598         protected void remove(InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> identifier,
599                 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface del) {
600             LOG.trace("Operational Interface remove event - {}", del);
601         }
602
603         @Override
604         protected void update(InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> identifier,
605                 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface original, 
606                 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface update) {
607             LOG.trace("Operation Interface update event - Old: {}, New: {}", original, update);
608             String interfaceName = update.getName();
609             Interface intf = getInterface(interfaceName);
610             if (intf != null && intf.getType().equals(Tunnel.class)) {
611                 BigInteger dpnId = interfaceManager.getDpnForInterface(interfaceName);
612                 if(update.getOperStatus().equals(OperStatus.Up)) {
613                     //Create ingress to LFIB
614                     LOG.debug("Installing Ingress for tunnel interface {}", interfaceName);
615                     makeTunnelIngressFlow(dpnId, interfaceName, NwConstants.ADD_FLOW);
616                 } else if(update.getOperStatus().equals(OperStatus.Down)) {
617                     LOG.debug("Removing Ingress flow for tunnel interface {}", interfaceName);
618                     makeTunnelIngressFlow(dpnId, interfaceName, NwConstants.DEL_FLOW);
619                 }
620             } else {
621                 VpnInterface vpnInterface = getVpnInterface(interfaceName);
622                 if(vpnInterface != null) {
623                     if(update.getOperStatus().equals(OperStatus.Up)) {
624                         LOG.debug("Installing VPN related rules for interface {}", interfaceName);
625                         addInterface(VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface);
626                     } else if(update.getOperStatus().equals(OperStatus.Down)) {
627                         LOG.debug("Removing VPN related rules for interface {}", interfaceName);
628                         VpnInterfaceManager.this.remove(VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface);
629                     }
630                 } else {
631                     LOG.debug("No VPN Interface associated with interface {} to handle Update Operation", interfaceName);
632                 }
633             }
634         }
635
636         @Override
637         protected void add(InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> identifier,
638                 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface add) {
639             LOG.trace("Operational Interface add event - {}", add);
640             String interfaceName = add.getName();
641             Interface intf = getInterface(interfaceName);
642             if (intf != null && intf.getType().equals(Tunnel.class)) {
643                 BigInteger dpnId = interfaceManager.getDpnForInterface(interfaceName);
644                 if(add.getOperStatus().equals(OperStatus.Up)) {
645                     //Create ingress to LFIB
646                     LOG.debug("Installing Ingress for tunnel interface {}", interfaceName);
647                     makeTunnelIngressFlow(dpnId, interfaceName, NwConstants.ADD_FLOW);
648                 }
649             } else {
650                 VpnInterface vpnInterface = getVpnInterface(interfaceName);
651                 if(vpnInterface != null) {
652                     if(add.getOperStatus().equals(OperStatus.Up)) {
653                         LOG.debug("Installing VPN related rules for interface {}", interfaceName);
654                         addInterface(VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface);
655                     }
656                 } else {
657                     LOG.debug("No VPN Interface associated with interface {} to handle add Operation", interfaceName);
658                 }
659             }
660         }
661     }
662 }