Merge "creation of tunnel ingress flow and lfib table entries moved to interface...
[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.IdManagerService;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdOutput;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.ReleaseIdInput;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.ReleaseIdInputBuilder;
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                 String prefix = VpnUtil.getIpPrefix(nextHop.getIpAddress());
206 //                long label = getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME, VpnUtil
207 //                        .getNextHopLabelKey((rd == null) ? intf.getVpnInstanceName() : rd, prefix));
208                 long label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
209                         VpnUtil.getNextHopLabelKey(rd, nextHop.getIpAddress()));
210                 value.add(new AdjacencyBuilder(nextHop).setLabel(label).build());
211             }
212
213             Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(value);
214             VpnInterface opInterface = VpnUtil.getVpnInterface(intfName, intf.getVpnInstanceName(), aug);
215             InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(intfName);
216             syncWrite(LogicalDatastoreType.OPERATIONAL, interfaceId, opInterface, DEFAULT_CALLBACK);
217             for (Adjacency nextHop : nextHops) {
218                 String key = rd + VpnConstants.SEPARATOR + nextHop.getIpAddress();
219                 String prefix = VpnUtil.getIpPrefix(nextHop.getIpAddress());
220 //                long label = getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME, VpnUtil
221 //                        .getNextHopLabelKey((rd == null) ? intf.getVpnInstanceName() : rd, prefix));
222                 long label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
223                         VpnUtil.getNextHopLabelKey(rd, nextHop.getIpAddress()));
224                 updatePrefixToBGP(rd, nextHop, nextHopIp, label);
225             }
226         }
227     }
228
229     private long getVpnId(String vpnName) {
230         //TODO: This should be a Util function
231         InstanceIdentifier<VpnInstance1> id = InstanceIdentifier.builder(VpnInstances.class)
232                 .child(VpnInstance.class, new VpnInstanceKey(vpnName)).augmentation(VpnInstance1.class).build();
233         Optional<VpnInstance1> vpnInstance = read(LogicalDatastoreType.OPERATIONAL, id);
234
235         long vpnId = VpnConstants.INVALID_ID;
236         if(vpnInstance.isPresent()) {
237             vpnId = vpnInstance.get().getVpnId();
238         }
239         return vpnId;
240     }
241
242     private String getRouteDistinguisher(String vpnName) {
243         InstanceIdentifier<VpnInstance> id = InstanceIdentifier.builder(VpnInstances.class)
244                                       .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
245         Optional<VpnInstance> vpnInstance = read(LogicalDatastoreType.CONFIGURATION, id);
246         String rd = "";
247         if(vpnInstance.isPresent()) {
248             VpnInstance instance = vpnInstance.get();
249             VpnAfConfig config = instance.getIpv4Family();
250             rd = config.getRouteDistinguisher();
251         }
252         return rd;
253     }
254
255     private synchronized void updateMappingDbs(long vpnId, BigInteger dpnId, String intfName, String rd) {
256         Collection<BigInteger> dpnIds = vpnToDpnsDb.get(vpnId);
257         if(dpnIds == null) {
258             dpnIds = new HashSet<>();
259         }
260         if(dpnIds.add(dpnId)) {
261             vpnToDpnsDb.put(vpnId, dpnIds);
262             fibManager.populateFibOnNewDpn(dpnId, vpnId, rd);
263         }
264
265         Collection<String> intfNames = dpnToInterfaceDb.get(dpnId);
266         if(intfNames == null) {
267             intfNames = new ArrayList<>();
268         }
269         intfNames.add(intfName);
270         dpnToInterfaceDb.put(dpnId, intfNames);
271     }
272
273     private synchronized void remoteFromMappingDbs(long vpnId, BigInteger dpnId, String inftName, String rd) {
274         Collection<String> intfNames = dpnToInterfaceDb.get(dpnId);
275         if(intfNames == null) {
276             return;
277         }
278         intfNames.remove(inftName);
279         dpnToInterfaceDb.put(dpnId, intfNames);
280         //TODO: Delay 'DPN' removal so that other services can cleanup the entries for this dpn
281         if(intfNames.isEmpty()) {
282             Collection<BigInteger> dpnIds = vpnToDpnsDb.get(vpnId);
283             if(dpnIds == null) {
284                 return;
285             }
286             dpnIds.remove(dpnId);
287             vpnToDpnsDb.put(vpnId, dpnIds);
288             fibManager.cleanUpDpnForVpn(dpnId, vpnId, rd);
289         }
290     }
291
292     private void bindServiceOnInterface(Interface intf, String vpnName) {
293         LOG.trace("Bind service on interface {} for VPN: {}", intf, vpnName);
294
295         long vpnId = getVpnId(vpnName);
296         BigInteger dpId = interfaceManager.getDpnForInterface(intf.getName()); 
297         if(dpId.equals(BigInteger.ZERO)) {
298             LOG.warn("DPN for interface {} not found. Bind service on this interface aborted.", intf.getName());
299             return;
300         } else {
301             String rd = getRouteDistinguisher(vpnName);
302             updateMappingDbs(vpnId, dpId, intf.getName(), rd);
303         }
304
305         long portNo = interfaceManager.getPortForInterface(intf.getName());
306         String flowRef = getVpnInterfaceFlowRef(dpId, VpnConstants.LPORT_INGRESS_TABLE, vpnId, portNo);
307
308         String flowName = intf.getName();
309         BigInteger COOKIE_VM_INGRESS_TABLE = new BigInteger("8000001", 16);
310
311         int priority = VpnConstants.DEFAULT_FLOW_PRIORITY;
312         short gotoTableId = VpnConstants.FIB_TABLE;
313         if(intf.getType().equals(Tunnel.class)){
314             gotoTableId = VpnConstants.LFIB_TABLE;
315         }
316
317         List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
318         mkInstructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] {
319                 BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
320
321         mkInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { gotoTableId }));
322
323         List<MatchInfo> matches = new ArrayList<MatchInfo>();
324         matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[] {
325                 dpId, BigInteger.valueOf(portNo) }));
326
327         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, VpnConstants.LPORT_INGRESS_TABLE, flowRef,
328                           priority, flowName, 0, 0, COOKIE_VM_INGRESS_TABLE, matches, mkInstructions);
329
330         mdsalManager.installFlow(flowEntity);
331     }
332
333     private String getVpnInterfaceFlowRef(BigInteger dpId, short tableId,
334             long vpnId, long portNo) {
335         return new StringBuilder().append(dpId).append(tableId).append(vpnId).append(portNo).toString();
336     }
337
338     private void updatePrefixToBGP(String rd, Adjacency nextHop, String nextHopIp, long label) {
339         try {
340             bgpManager.addPrefix(rd, nextHop.getIpAddress(), nextHopIp, (int)label);
341         } catch(Exception e) {
342             LOG.error("Add prefix failed", e);
343         }
344     }
345
346     private <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
347             InstanceIdentifier<T> path) {
348
349         ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
350
351         Optional<T> result = Optional.absent();
352         try {
353             result = tx.read(datastoreType, path).get();
354         } catch (Exception e) {
355             throw new RuntimeException(e);
356         }
357
358         return result;
359     }
360
361     private InstanceIdentifier<VpnInterface> getWildCardPath() {
362         return InstanceIdentifier.create(VpnInterfaces.class).child(VpnInterface.class);
363     }
364
365     @Override
366     protected void remove( InstanceIdentifier<VpnInterface> identifier, VpnInterface vpnInterface) {
367         LOG.trace("Remove event - key: {}, value: {}" ,identifier, vpnInterface );
368         final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
369         String interfaceName = key.getName();
370         InstanceIdentifierBuilder<Interface> idBuilder = 
371                 InstanceIdentifier.builder(Interfaces.class).child(Interface.class, new InterfaceKey(interfaceName));
372         InstanceIdentifier<Interface> id = idBuilder.build();
373         Optional<Interface> port = read(LogicalDatastoreType.CONFIGURATION, id);
374         if (port.isPresent()) {
375             Interface interf = port.get();
376             removeNextHops(identifier, vpnInterface);
377             unbindServiceOnInterface(interf, vpnInterface.getVpnInstanceName());
378             //InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
379             delete(LogicalDatastoreType.OPERATIONAL, identifier);
380         } else {
381             LOG.warn("No nexthops were available to handle remove event {}", interfaceName);
382         }
383     }
384
385     private void removeNextHops(final InstanceIdentifier<VpnInterface> identifier, VpnInterface intf) {
386         //Read NextHops
387         InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
388         Optional<Adjacencies> adjacencies = read(LogicalDatastoreType.OPERATIONAL, path);
389         String intfName = intf.getName();
390         String rd = getRouteDistinguisher(intf.getVpnInstanceName());
391         if (adjacencies.isPresent()) {
392             List<Adjacency> nextHops = adjacencies.get().getAdjacency();
393
394             if (!nextHops.isEmpty()) {
395                 LOG.trace("NextHops are " + nextHops);
396                 for (Adjacency nextHop : nextHops) {
397                     removePrefixFromBGP(rd, nextHop);
398                 }
399             }
400         }
401     }
402
403     private <T extends DataObject> void delete(LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
404         WriteTransaction tx = broker.newWriteOnlyTransaction();
405         tx.delete(datastoreType, path);
406         Futures.addCallback(tx.submit(), DEFAULT_CALLBACK);
407     }
408
409     private void unbindServiceOnInterface(Interface intf, String vpnName) {
410         LOG.trace("Unbind service on interface {} for VPN: {}", intf, vpnName);
411
412         long vpnId = getVpnId(vpnName);
413         BigInteger dpId = interfaceManager.getDpnForInterface(intf);
414         if(dpId.equals(BigInteger.ZERO)) {
415             LOG.warn("DPN for interface {} not found. Unbind service on this interface aborted.", intf.getName());
416             return;
417         } else {
418             String rd = getRouteDistinguisher(vpnName);
419             remoteFromMappingDbs(vpnId, dpId, intf.getName(), rd);
420             LOG.debug("removed vpn mapping for interface {} from VPN RD {}", intf.getName(), rd);
421         }
422
423         long portNo = interfaceManager.getPortForInterface(intf);
424         String flowRef = getVpnInterfaceFlowRef(dpId, VpnConstants.LPORT_INGRESS_TABLE, vpnId, portNo);
425
426         String flowName = intf.getName();
427
428         int priority = VpnConstants.DEFAULT_FLOW_PRIORITY;
429
430         List<MatchInfo> matches = new ArrayList<MatchInfo>();
431         matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[] {
432                 dpId, BigInteger.valueOf(portNo) }));
433
434         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, VpnConstants.LPORT_INGRESS_TABLE, flowRef,
435                           priority, flowName, 0, 0, null, matches, null);
436         LOG.debug("Remove ingress flow for port {} in dpn {}", portNo, dpId.intValue());
437
438         mdsalManager.removeFlow(flowEntity);
439     }
440
441     private void removePrefixFromBGP(String rd, Adjacency nextHop) {
442         try {
443             bgpManager.deletePrefix(rd, nextHop.getIpAddress());
444         } catch(Exception e) {
445             LOG.error("Delete prefix failed", e);
446         }
447     }
448
449     @Override
450     protected void update(InstanceIdentifier<VpnInterface> identifier, 
451                                    VpnInterface original, VpnInterface update) {
452         LOG.trace("Update VPN Interface {} , original {}, update {}", 
453                                                   identifier, original, update);
454         String vpnName = original.getVpnInstanceName();
455
456         boolean vpnNameChanged = false;
457         String rd = getRouteDistinguisher(vpnName);
458         String newRd = rd;
459         if(!vpnName.equals(update.getVpnInstanceName())) {
460             //VPN for this interface got changed. 
461             //Remove the interface from old VPN and add it to new VPN
462             String newVpnName = update.getVpnInstanceName();
463             newRd = getRouteDistinguisher(newVpnName);
464             if(newRd.equals("")) {
465                 LOG.warn("VPN Instance {} not found. Update operation aborted", newVpnName);
466                 return;
467             }
468             vpnNameChanged = true;
469             LOG.debug("New VPN Name for the interface {} is {}", newVpnName, original.getName());
470         }
471
472         BigInteger dpnId = interfaceManager.getDpnForInterface(original.getName());
473         String nextHopIp = interfaceManager.getEndpointIpForDpn(dpnId);
474         //List<Adjacency> oldAdjs = original.getAugmentation(Adjacencies.class).getAdjacency();
475         List<Adjacency> newAdjs = update.getAugmentation(Adjacencies.class).getAdjacency();
476         if(vpnNameChanged && newAdjs != null && !newAdjs.isEmpty()) {
477             long label = VpnConstants.INVALID_ID;
478             InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
479             Optional<Adjacencies> adjacencies = read(LogicalDatastoreType.OPERATIONAL, path);
480             if (adjacencies.isPresent()) {
481                 List<Adjacency> nextHops = adjacencies.get().getAdjacency();
482                 for(Adjacency nextHop : nextHops) {
483                     label = nextHop.getLabel();
484                     if(label == VpnConstants.INVALID_ID) {
485                         //Generate label using ID Manager
486                         String key = newRd + VpnConstants.SEPARATOR + nextHop.getIpAddress();
487 //                        label = getUniqueId(key);
488                     }
489                     removePrefixFromBGP(rd, nextHop);
490                     //updatePrefixToBGP(newRd, nextHop, nextHopIp, label);
491                 }
492                 updateNextHops(identifier, update);
493                 asyncUpdate(LogicalDatastoreType.OPERATIONAL, identifier, update, DEFAULT_CALLBACK);
494             }
495         } else {
496             LOG.debug("No Update information is available for VPN Interface to proceed");
497         }
498     }
499
500     protected <T extends DataObject> void asyncUpdate(LogicalDatastoreType datastoreType,
501             InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
502         WriteTransaction tx = broker.newWriteOnlyTransaction();
503         tx.merge(datastoreType, path, data, true);
504         Futures.addCallback(tx.submit(), callback);
505     }
506
507     private <T extends DataObject> void asyncWrite(LogicalDatastoreType datastoreType,
508                         InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
509         WriteTransaction tx = broker.newWriteOnlyTransaction();
510         tx.put(datastoreType, path, data, true);
511         Futures.addCallback(tx.submit(), callback);
512     }
513
514     private <T extends DataObject> void syncWrite(LogicalDatastoreType datastoreType,
515                         InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
516         WriteTransaction tx = broker.newWriteOnlyTransaction();
517         tx.put(datastoreType, path, data, true);
518         tx.submit();
519     }
520
521     synchronized Collection<BigInteger> getDpnsForVpn(long vpnId) {
522         Collection<BigInteger> dpnIds = vpnToDpnsDb.get(vpnId);
523         if(dpnIds != null) {
524             return ImmutableList.copyOf(dpnIds);
525         } else {
526             return Collections.emptyList();
527         }
528     }
529
530     VpnInterface getVpnInterface(String interfaceName) {
531         Optional<VpnInterfaces> optVpnInterfaces = read(LogicalDatastoreType.CONFIGURATION, VpnUtil.getVpnInterfacesIdentifier());
532         if(optVpnInterfaces.isPresent()) {
533             List<VpnInterface> interfaces = optVpnInterfaces.get().getVpnInterface();
534             for(VpnInterface intf : interfaces) {
535                 if(intf.getName().equals(interfaceName)) {
536                     return intf;
537                 }
538             }
539         }
540         return null;
541     }
542
543     private Interface getInterface(String interfaceName) {
544         Optional<Interface> optInterface = read(LogicalDatastoreType.CONFIGURATION, VpnUtil.getInterfaceIdentifier(interfaceName));
545         if(optInterface.isPresent()) {
546             return optInterface.get();
547         }
548         return null;
549     }
550
551     private String getTunnelInterfaceFlowRef(BigInteger dpnId, short tableId, String ifName) {
552         return new StringBuilder().append(dpnId).append(tableId).append(ifName).toString();
553     }
554
555
556     protected void makeTunnelIngressFlow(BigInteger dpnId, String ifName, int addOrRemoveFlow) {
557        /* long portNo = 0;
558         String flowName = ifName;
559         String flowRef = getTunnelInterfaceFlowRef(dpnId, VpnConstants.LPORT_INGRESS_TABLE, ifName);
560         List<MatchInfo> matches = new ArrayList<MatchInfo>();
561         List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
562         if (NwConstants.ADD_FLOW == addOrRemoveFlow) {
563             portNo = interfaceManager.getPortForInterface(ifName);
564             matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[] {
565                 dpnId, BigInteger.valueOf(portNo) }));
566             mkInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {VpnConstants.LFIB_TABLE}));
567         }
568
569         BigInteger COOKIE_VM_INGRESS_TABLE = new BigInteger("8000001", 16);
570         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, VpnConstants.LPORT_INGRESS_TABLE, flowRef,
571                 VpnConstants.DEFAULT_FLOW_PRIORITY, flowName, 0, 0, COOKIE_VM_INGRESS_TABLE, matches, mkInstructions);
572
573         if (NwConstants.ADD_FLOW == addOrRemoveFlow) {
574             mdsalManager.installFlow(flowEntity);
575         } else {
576             mdsalManager.removeFlow(flowEntity);
577         }*/
578     }
579
580     private class InterfaceListener extends AbstractDataChangeListener<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface>  {
581
582         public InterfaceListener() {
583             super(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class);
584         }
585
586         @Override
587         protected void remove(InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> identifier,
588                 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface del) {
589             LOG.trace("Operational Interface remove event - {}", del);
590         }
591
592         @Override
593         protected void update(InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> identifier,
594                 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface original, 
595                 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface update) {
596             LOG.trace("Operation Interface update event - Old: {}, New: {}", original, update);
597             String interfaceName = update.getName();
598             Interface intf = getInterface(interfaceName);
599             if (intf != null && intf.getType().equals(Tunnel.class)) {
600                 BigInteger dpnId = interfaceManager.getDpnForInterface(interfaceName);
601                 if(update.getOperStatus().equals(OperStatus.Up)) {
602                     //Create ingress to LFIB
603                     LOG.debug("Installing Ingress for tunnel interface {}", interfaceName);
604                     makeTunnelIngressFlow(dpnId, interfaceName, NwConstants.ADD_FLOW);
605                 } else if(update.getOperStatus().equals(OperStatus.Down)) {
606                     LOG.debug("Removing Ingress flow for tunnel interface {}", interfaceName);
607                     makeTunnelIngressFlow(dpnId, interfaceName, NwConstants.DEL_FLOW);
608                 }
609             } else {
610                 VpnInterface vpnInterface = getVpnInterface(interfaceName);
611                 if(vpnInterface != null) {
612                     if(update.getOperStatus().equals(OperStatus.Up)) {
613                         LOG.debug("Installing VPN related rules for interface {}", interfaceName);
614                         addInterface(VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface);
615                     } else if(update.getOperStatus().equals(OperStatus.Down)) {
616                         LOG.debug("Removing VPN related rules for interface {}", interfaceName);
617                         VpnInterfaceManager.this.remove(VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface);
618                     }
619                 } else {
620                     LOG.debug("No VPN Interface associated with interface {} to handle Update Operation", interfaceName);
621                 }
622             }
623         }
624
625         @Override
626         protected void add(InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> identifier,
627                 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface add) {
628             LOG.trace("Operational Interface add event - {}", add);
629             String interfaceName = add.getName();
630             Interface intf = getInterface(interfaceName);
631             if (intf != null && intf.getType().equals(Tunnel.class)) {
632                 BigInteger dpnId = interfaceManager.getDpnForInterface(interfaceName);
633                 if(add.getOperStatus().equals(OperStatus.Up)) {
634                     //Create ingress to LFIB
635                     LOG.debug("Installing Ingress for tunnel interface {}", interfaceName);
636                     makeTunnelIngressFlow(dpnId, interfaceName, NwConstants.ADD_FLOW);
637                 }
638             } else {
639                 VpnInterface vpnInterface = getVpnInterface(interfaceName);
640                 if(vpnInterface != null) {
641                     if(add.getOperStatus().equals(OperStatus.Up)) {
642                         LOG.debug("Installing VPN related rules for interface {}", interfaceName);
643                         addInterface(VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface);
644                     }
645                 } else {
646                     LOG.debug("No VPN Interface associated with interface {} to handle add Operation", interfaceName);
647                 }
648             }
649         }
650     }
651 }