Merge "Fixing issues with ARP integration of VpnService - Table 0 and Table 80...
[vpnservice.git] / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / vpnservice / 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.vpnservice;
9
10 import org.opendaylight.vpnservice.utilities.InterfaceUtils;
11
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.Futures;
14 import com.google.common.util.concurrent.JdkFutureAdapters;
15
16 import org.opendaylight.controller.md.sal.binding.api.*;
17 import org.opendaylight.vpnservice.mdsalutil.*;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.AdjacencyKey;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListBuilder;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesBuilder;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesKey;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.OdlArputilService;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.SendArpResponseInput;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.SendArpResponseInputBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.services.info.BoundServices;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.FibEntries;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTables;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTablesBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTablesKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.vrfentries.VrfEntry;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.vrfentries.VrfEntryKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
38
39 import java.math.BigInteger;
40 import java.util.Collection;
41 import java.util.Iterator;
42 import java.util.List;
43 import java.util.ArrayList;
44 import java.util.concurrent.Future;
45
46 import com.google.common.base.Optional;
47
48 import org.opendaylight.bgpmanager.api.IBgpManager;
49 import org.opendaylight.fibmanager.api.IFibManager;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
52 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
53 import org.opendaylight.yangtools.concepts.ListenerRegistration;
54 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
55 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
56 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
57 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.Adjacency;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
61 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.Adjacencies;
63 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig;
64 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
65 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
66 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceKey;
67 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
68 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
69 import org.opendaylight.yangtools.yang.common.RpcError;
70 import org.opendaylight.yangtools.yang.common.RpcResult;
71 import org.slf4j.Logger;
72 import org.slf4j.LoggerFactory;
73
74 public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface> implements AutoCloseable {
75     private static final Logger LOG = LoggerFactory.getLogger(VpnInterfaceManager.class);
76     private ListenerRegistration<DataChangeListener> listenerRegistration;
77     private final DataBroker broker;
78     private final IBgpManager bgpManager;
79     private IFibManager fibManager;
80     private IMdsalApiManager mdsalManager;
81     private OdlInterfaceRpcService interfaceManager;
82     private ItmRpcService itmProvider;
83     private IdManagerService idManager;
84     private OdlArputilService arpManager;
85     private InterfaceStateChangeListener interfaceListener;
86     private ArpNotificationHandler arpNotificationHandler;
87     protected enum UpdateRouteAction {
88         ADVERTISE_ROUTE, WITHDRAW_ROUTE
89     }
90     /**
91      * Responsible for listening to data change related to VPN Interface
92      * Bind VPN Service on the interface and informs the BGP service
93      *
94      * @param db - dataBroker service reference
95      */
96     public VpnInterfaceManager(final DataBroker db, final IBgpManager bgpManager, NotificationService notificationService) {
97         super(VpnInterface.class);
98         broker = db;
99         this.bgpManager = bgpManager;
100         interfaceListener = new InterfaceStateChangeListener(db, this);
101         arpNotificationHandler = new ArpNotificationHandler(this, broker);
102         notificationService.registerNotificationListener(arpNotificationHandler);
103         registerListener(db);
104     }
105
106     public void setMdsalManager(IMdsalApiManager mdsalManager) {
107         this.mdsalManager = mdsalManager;
108     }
109
110     public void setInterfaceManager(OdlInterfaceRpcService interfaceManager) {
111         this.interfaceManager = interfaceManager;
112         interfaceListener.setInterfaceManager(interfaceManager);
113     }
114
115     public void setITMProvider(ItmRpcService itmProvider) {
116         this.itmProvider = itmProvider;
117     }
118
119     public void setFibManager(IFibManager fibManager) {
120         this.fibManager = fibManager;
121     }
122
123     public void setIdManager(IdManagerService idManager) {
124         this.idManager = idManager;
125     }
126
127     public void setArpManager(OdlArputilService arpManager) {
128         this.arpManager = arpManager;
129     }
130
131     @Override
132     public void close() throws Exception {
133         if (listenerRegistration != null) {
134             try {
135                 listenerRegistration.close();
136             } catch (final Exception e) {
137                 LOG.error("Error when cleaning up DataChangeListener.", e);
138             }
139             listenerRegistration = null;
140         }
141         LOG.info("VPN Interface Manager Closed");
142     }
143
144     private void registerListener(final DataBroker db) {
145         try {
146             listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
147                     getWildCardPath(), VpnInterfaceManager.this, DataChangeScope.SUBTREE);
148         } catch (final Exception e) {
149             LOG.error("VPN Service DataChange listener registration fail!", e);
150             throw new IllegalStateException("VPN Service registration Listener failed.", e);
151         }
152     }
153
154     private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> getInterfaceListenerPath() {
155         return InstanceIdentifier.create(InterfacesState.class)
156             .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class);
157     }
158
159     @Override
160     protected void add(final InstanceIdentifier<VpnInterface> identifier,
161             final VpnInterface vpnInterface) {
162         LOG.trace("key: {} , value: {}", identifier, vpnInterface );
163         addInterface(identifier, vpnInterface);
164     }
165
166     private void addInterface(final InstanceIdentifier<VpnInterface> identifier,
167                               final VpnInterface vpnInterface) {
168         LOG.trace("Add event - key: {}, value: {}" ,identifier, vpnInterface );
169         final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
170         String interfaceName = key.getName();
171
172         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState =
173             InterfaceUtils.getInterfaceStateFromOperDS(broker, interfaceName);
174         if (interfaceState != null) {
175             // Interface state is up
176             processVpnInterfaceUp(interfaceName, interfaceState.getIfIndex());
177         }
178     }
179
180     protected synchronized void processVpnInterfaceUp(String interfaceName, int lPortTag) {
181
182         VpnInterface vpnInterface = VpnUtil.getConfiguredVpnInterface(broker, interfaceName);
183         if(vpnInterface == null) {
184             LOG.info("Unable to process add/up for interface {} as it is not configured", interfaceName);
185             return;
186         }
187         String vpnName = vpnInterface.getVpnInstanceName();
188         LOG.info("Binding vpn service to interface {} ", interfaceName);
189         bindService(vpnName, interfaceName, lPortTag);
190         updateDpnDbs(vpnName, interfaceName, true);
191         processVpnInterfaceAdjacencies(VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface);
192
193     }
194
195     private void updateDpnDbs(String vpnName, String interfaceName, boolean add) {
196         long vpnId = VpnUtil.getVpnId(broker, vpnName);
197         BigInteger dpId = InterfaceUtils.getDpnForInterface(interfaceManager, interfaceName);
198         if(!dpId.equals(BigInteger.ZERO)) {
199             if(add)
200                 updateMappingDbs(vpnId, dpId, interfaceName, vpnName);
201             else
202                 removeFromMappingDbs(vpnId, dpId, interfaceName, vpnName);
203         }
204
205     }
206
207     private void bindService(String vpnInstanceName, String vpnInterfaceName, int lPortTag) {
208         int priority = VpnConstants.DEFAULT_FLOW_PRIORITY;
209         long vpnId = VpnUtil.getVpnId(broker, vpnInstanceName);
210
211         int instructionKey = 0;
212         List<Instruction> instructions = new ArrayList<Instruction>();
213
214         instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID, ++instructionKey));
215         instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(VpnConstants.FIB_TABLE, ++instructionKey));
216
217         BoundServices
218             serviceInfo =
219             InterfaceUtils.getBoundServices(String.format("%s.%s.%s", "vpn",vpnInstanceName, vpnInterfaceName),
220                                             VpnConstants.L3VPN_SERVICE_IDENTIFIER, priority,
221                                             VpnConstants.COOKIE_VM_INGRESS_TABLE, instructions);
222         VpnUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
223                           InterfaceUtils.buildServiceId(vpnInterfaceName, VpnConstants.L3VPN_SERVICE_IDENTIFIER), serviceInfo);
224         makeArpFlow(VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName, vpnId, ArpReplyOrRequest.REQUEST, NwConstants.ADD_FLOW);
225
226     }
227
228     private void processVpnInterfaceAdjacencies(final InstanceIdentifier<VpnInterface> identifier, VpnInterface intf) {
229         String intfName = intf.getName();
230
231         synchronized (intfName) {
232             // Read NextHops
233             InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
234             Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, path);
235
236             if (adjacencies.isPresent()) {
237                 List<Adjacency> nextHops = adjacencies.get().getAdjacency();
238                 List<Adjacency> value = new ArrayList<>();
239
240                 // Get the rd of the vpn instance
241                 String rd = getRouteDistinguisher(intf.getVpnInstanceName());
242
243                 BigInteger dpnId = InterfaceUtils.getDpnForInterface(interfaceManager, intfName);
244                 String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
245                 if (nextHopIp == null){
246                     LOG.error("NextHop for interface {} is null", intfName);
247                 }
248
249                 LOG.trace("NextHops are {}", nextHops);
250                 for (Adjacency nextHop : nextHops) {
251                     String prefix = VpnUtil.getIpPrefix(nextHop.getIpAddress());
252                     long label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME, VpnUtil
253                             .getNextHopLabelKey((rd == null) ? intf.getVpnInstanceName() : rd, prefix));
254                     String adjNextHop = nextHop.getNextHopIp();
255                     value.add(new AdjacencyBuilder(nextHop).setLabel(label).setNextHopIp((adjNextHop != null && !adjNextHop.isEmpty()) ? adjNextHop : nextHopIp)
256                             .setIpAddress(prefix).setKey(new AdjacencyKey(prefix)).build());
257                     if(nextHop.getMacAddress() != null && !nextHop.getMacAddress().isEmpty()) {
258                         VpnUtil.syncUpdate(
259                                 broker,
260                                 LogicalDatastoreType.OPERATIONAL,
261                                 VpnUtil.getPrefixToInterfaceIdentifier(
262                                         VpnUtil.getVpnId(broker, intf.getVpnInstanceName()), prefix),
263                                 VpnUtil.getPrefixToInterface(dpnId, intf.getName(), prefix));
264                     }
265                 }
266
267                 Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(value);
268                 VpnInterface opInterface = VpnUtil.getVpnInterface(intfName, intf.getVpnInstanceName(), aug);
269                 InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(intfName);
270                 VpnUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, interfaceId, opInterface);
271                 for (Adjacency nextHop : aug.getAdjacency()) {
272                     long label = nextHop.getLabel();
273                     String adjNextHop = nextHop.getNextHopIp();
274                     if (rd != null) {
275                         addPrefixToBGP(rd, nextHop.getIpAddress(),
276                                             (adjNextHop != null && !adjNextHop.isEmpty()) ? adjNextHop : nextHopIp, label);
277                     } else {
278                         // ### add FIB route directly
279                         addFibEntryToDS(intf.getVpnInstanceName(), nextHop.getIpAddress(),
280                                             (adjNextHop != null && !adjNextHop.isEmpty()) ? adjNextHop : nextHopIp, (int) label);
281                     }
282                 }
283             }
284         }
285     }
286
287     private void makeArpFlow(short sIndex, int lPortTag, String vpnInterfaceName, long vpnId, ArpReplyOrRequest replyOrRequest, int addOrRemoveFlow){
288         List<MatchInfo> matches = new ArrayList<MatchInfo>();
289         BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lPortTag, ++sIndex, BigInteger.valueOf(vpnId));
290         BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(MetaDataUtil.METADATA_MASK_SERVICE_INDEX,
291                 MetaDataUtil.METADATA_MASK_LPORT_TAG, MetaDataUtil.METADATA_MASK_VRFID);
292
293         // Matching Arp reply flows
294         matches.add(new MatchInfo(MatchFieldType.eth_type, new long[] { NwConstants.ETHTYPE_ARP }));
295         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
296                 metadata, metadataMask }));
297
298         matches.add(new MatchInfo(MatchFieldType.arp_op, new long[] { replyOrRequest.getArpOperation() }));
299
300         // Instruction to punt to controller
301         List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
302         List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
303         actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[] {}));
304         instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
305
306         // Install the flow entry in L3_INTERFACE_TABLE
307         BigInteger dpId = InterfaceUtils.getDpnForInterface(interfaceManager, vpnInterfaceName);
308         String flowRef = VpnUtil.getFlowRef(dpId, VpnConstants.L3_INTERFACE_TABLE,
309                     NwConstants.ETHTYPE_ARP, lPortTag, replyOrRequest.getArpOperation());
310         FlowEntity flowEntity;
311         flowEntity = MDSALUtil.buildFlowEntity(dpId, VpnConstants.L3_INTERFACE_TABLE, flowRef,
312                 NwConstants.DEFAULT_ARP_FLOW_PRIORITY, replyOrRequest.getName(), 0, 0,
313                 VpnUtil.getCookieArpFlow(lPortTag), matches, instructions);
314
315         if (addOrRemoveFlow == NwConstants.ADD_FLOW) {
316             LOG.debug("Creating ARP Flow for interface {}",vpnInterfaceName);
317             mdsalManager.installFlow(flowEntity);
318         } else {
319             LOG.debug("Deleting ARP Flow for interface {}",vpnInterfaceName);
320             mdsalManager.removeFlow(flowEntity);
321         }
322     }
323
324     private String getRouteDistinguisher(String vpnName) {
325         InstanceIdentifier<VpnInstance> id = InstanceIdentifier.builder(VpnInstances.class)
326                                       .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
327         Optional<VpnInstance> vpnInstance = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
328         String rd = "";
329         if(vpnInstance.isPresent()) {
330             VpnInstance instance = vpnInstance.get();
331             VpnAfConfig config = instance.getIpv4Family();
332             rd = config.getRouteDistinguisher();
333         }
334         return rd;
335     }
336
337     private synchronized void updateMappingDbs(long vpnId, BigInteger dpnId, String intfName, String vpnName) {
338         String routeDistinguisher = getRouteDistinguisher(vpnName);
339         String rd = (routeDistinguisher == null) ? vpnName : routeDistinguisher;
340         InstanceIdentifier<VpnToDpnList> id = VpnUtil.getVpnToDpnListIdentifier(rd, dpnId);
341         Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
342         org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces
343             vpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
344
345         if (dpnInVpn.isPresent()) {
346             VpnUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id.child(
347                 org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance
348                     .op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
349                     new VpnInterfacesKey(intfName)), vpnInterface);
350         } else {
351             VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
352                                     VpnUtil.getVpnInstanceOpDataIdentifier(rd),
353                                     VpnUtil.getVpnInstanceOpData(rd, vpnId));
354             VpnToDpnListBuilder vpnToDpnList = new VpnToDpnListBuilder().setDpnId(dpnId);
355             List<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
356                 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces =  new ArrayList<>();
357             vpnInterfaces.add(vpnInterface);
358             VpnUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id,
359                               vpnToDpnList.setVpnInterfaces(vpnInterfaces).build());
360
361             /**
362              * FIXME: DC Gateway tunnel should be built dynamically
363             //this is the first VM in this VPN on the DPN, may be a new DPN has come up,
364             //if tunnel to DC GW does not exist, create it
365             //if(!tunnelExists(dpnID, bgpManager.getDCGWIP()))
366             String dcGW = bgpManager.getDCGwIP();
367             if(dcGW != null && !dcGW.isEmpty())
368             {
369                 LOG.debug("Building tunnel from DPN {} to DC GW {}", dpnId, dcGW);
370                 itmProvider.buildTunnelFromDPNToDCGW(dpnId, new IpAddress(dcGW.toCharArray()));
371             }*/
372             fibManager.populateFibOnNewDpn(dpnId, vpnId, (rd == null) ? vpnName : rd);
373         }
374     }
375
376     private synchronized void removeFromMappingDbs(long vpnId, BigInteger dpnId, String intfName, String vpnName) {
377         //TODO: Delay 'DPN' removal so that other services can cleanup the entries for this dpn
378         String rd = VpnUtil.getVpnRd(broker, vpnName);
379         InstanceIdentifier<VpnToDpnList> id = VpnUtil.getVpnToDpnListIdentifier(rd, dpnId);
380         Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
381         if (dpnInVpn.isPresent()) {
382             List<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
383                 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
384             org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces
385                     currVpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
386
387             if (vpnInterfaces.remove(currVpnInterface)) {
388                 if (vpnInterfaces.isEmpty()) {
389                     VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id, VpnUtil.DEFAULT_CALLBACK);
390                     fibManager.cleanUpDpnForVpn(dpnId, vpnId, rd);
391                 } else {
392                     VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id.child(
393                         org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
394                             .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
395                             new VpnInterfacesKey(intfName)), VpnUtil.DEFAULT_CALLBACK);
396                 }
397             }
398         }
399     }
400
401     private void addPrefixToBGP(String rd, String prefix, String nextHopIp, long label) {
402         try {
403             bgpManager.addPrefix(rd, prefix, nextHopIp, (int)label);
404         } catch(Exception e) {
405             LOG.error("Add prefix failed", e);
406         }
407     }
408
409
410     private InstanceIdentifier<VpnInterface> getWildCardPath() {
411         return InstanceIdentifier.create(VpnInterfaces.class).child(VpnInterface.class);
412     }
413
414     @Override
415     protected void remove( InstanceIdentifier<VpnInterface> identifier, VpnInterface vpnInterface) {
416         LOG.trace("Remove event - key: {}, value: {}" ,identifier, vpnInterface );
417         final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
418         String interfaceName = key.getName();
419
420         InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
421         Optional<VpnInterface> existingVpnInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, interfaceId);
422         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState =
423             InterfaceUtils.getInterfaceStateFromOperDS(broker, interfaceName);
424
425         if (existingVpnInterface.isPresent() && interfaceState != null) {
426             processVpnInterfaceDown(interfaceName, interfaceState.getIfIndex());
427         } else {
428             LOG.warn("VPN interface {} was unavailable in operational data store to handle remove event", interfaceName);
429         }
430     }
431
432     protected synchronized void processVpnInterfaceDown(String interfaceName, int lPortTag) {
433         VpnInterface vpnInterface = VpnUtil.getOperationalVpnInterface(broker, interfaceName);
434         if(vpnInterface == null) {
435             LOG.info("Unable to process delete/down for interface {} as it is not available in operational data store", interfaceName);
436             return;
437         }
438         String vpnName = vpnInterface.getVpnInstanceName();
439         InstanceIdentifier<VpnInterface> identifier = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
440
441         removeAdjacenciesFromVpn(identifier, vpnInterface);
442         LOG.info("Unbinding vpn service from interface {} ", interfaceName);
443         unbindService(vpnName, interfaceName, lPortTag);
444         updateDpnDbs(vpnName, interfaceName, false);
445         VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, identifier, VpnUtil.DEFAULT_CALLBACK);
446     }
447
448     private void removeAdjacenciesFromVpn(final InstanceIdentifier<VpnInterface> identifier, VpnInterface intf) {
449         //Read NextHops
450         InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
451         Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
452
453         String rd = VpnUtil.getVpnRd(broker, intf.getVpnInstanceName());
454         if (adjacencies.isPresent()) {
455             List<Adjacency> nextHops = adjacencies.get().getAdjacency();
456
457             if (!nextHops.isEmpty()) {
458                 LOG.trace("NextHops are " + nextHops);
459                 for (Adjacency nextHop : nextHops) {
460                     VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME,
461                                       VpnUtil.getNextHopLabelKey(rd, nextHop.getIpAddress()));
462                     VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
463                                    VpnUtil.getPrefixToInterfaceIdentifier(
464                                        VpnUtil.getVpnId(broker, intf.getVpnInstanceName()),
465                                        nextHop.getIpAddress()),
466                                    VpnUtil.DEFAULT_CALLBACK);
467                     if (rd.equals(intf.getVpnInstanceName())) {
468                         //this is an internal vpn - the rd is assigned to the vpn instance name;
469                         //remove from FIB directly
470                         removeFibEntryFromDS(intf.getVpnInstanceName(), nextHop.getIpAddress());
471                     } else {
472                         removePrefixFromBGP(rd, nextHop.getIpAddress());
473                     }
474                 }
475             }
476         }
477     }
478
479
480     private void unbindService(String vpnInstanceName, String vpnInterfaceName, int lPortTag) {
481         VpnUtil.delete(broker, LogicalDatastoreType.CONFIGURATION,
482                        InterfaceUtils.buildServiceId(vpnInterfaceName,VpnConstants.L3VPN_SERVICE_IDENTIFIER),
483                        VpnUtil.DEFAULT_CALLBACK);
484         long vpnId = VpnUtil.getVpnId(broker, vpnInstanceName);
485         makeArpFlow(VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
486                     vpnId, ArpReplyOrRequest.REQUEST, NwConstants.DEL_FLOW);
487     }
488
489
490     private void removePrefixFromBGP(String rd, String prefix) {
491         try {
492             bgpManager.deletePrefix(rd, prefix);
493         } catch(Exception e) {
494             LOG.error("Delete prefix failed", e);
495         }
496     }
497
498     @Override
499     protected void update(InstanceIdentifier<VpnInterface> identifier,
500                                    VpnInterface original, VpnInterface update) {
501         LOG.trace("Update VPN Interface {} , original {}, update {}",
502                                                   identifier, original, update);
503         String vpnName = original.getVpnInstanceName();
504
505         boolean vpnNameChanged = false;
506         String rd = getRouteDistinguisher(vpnName);
507         String newRd = rd;
508         String newVpnName = update.getVpnInstanceName();
509         if(!vpnName.equals(newVpnName)) {
510             //VPN for this interface got changed.
511             //Remove the interface from old VPN and add it to new VPN
512             newRd = getRouteDistinguisher(newVpnName);
513             if(newRd.equals("")) {
514                 LOG.warn("VPN Instance {} not found. Update operation aborted", newVpnName);
515                 return;
516             }
517             vpnNameChanged = true;
518             LOG.debug("New VPN Name for the interface {} is {}", newVpnName, original.getName());
519         }
520
521         List<Adjacency> oldAdjs = original.getAugmentation(Adjacencies.class).getAdjacency();
522         List<Adjacency> newAdjs = update.getAugmentation(Adjacencies.class).getAdjacency();
523         if(vpnNameChanged && newAdjs != null && !newAdjs.isEmpty()) {
524             long label = VpnConstants.INVALID_ID;
525             InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
526             Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
527             if (adjacencies.isPresent()) {
528                 List<Adjacency> nextHops = adjacencies.get().getAdjacency();
529                 for(Adjacency nextHop : nextHops) {
530                     label = nextHop.getLabel();
531                     if(label == VpnConstants.INVALID_ID) {
532                         //Generate label using ID Manager
533                         label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
534                                                     VpnUtil.getNextHopLabelKey(newRd, nextHop.getIpAddress()));
535                     }
536                     if (rd != null) {
537                         removePrefixFromBGP(rd, nextHop.getIpAddress());
538                     } else {
539                         removeFibEntryFromDS(vpnName, nextHop.getIpAddress());
540                     }
541                     //updatePrefixToBGP(newRd, nextHop, nextHopIp, label);
542                 }
543                 processVpnInterfaceAdjacencies(identifier, update);
544                 VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, identifier, update);
545             }
546         } else if (oldAdjs != newAdjs) {
547             //handle both addition and removal of adjacencies
548             //currently, new adjacency may be an extra route
549             for (Adjacency adj : newAdjs) {
550                 if (oldAdjs.contains(adj)) {
551                     oldAdjs.remove(adj);
552                 } else {
553                     // add new adjacency - right now only extra route will hit this path
554                     addNewAdjToVpnInterface(identifier, adj);
555                 }
556             }
557
558             for (Adjacency adj : oldAdjs) {
559                 delAdjFromVpnInterface(identifier, adj);
560             }
561         }
562         else {
563             LOG.debug("No Update information is available for VPN Interface to proceed");
564         }
565
566     }
567
568     public void processArpRequest(IpAddress srcIP, PhysAddress srcMac, IpAddress targetIP, String srcInterface){
569         SendArpResponseInput input = new SendArpResponseInputBuilder().setInterface(srcInterface)
570                                                                     .setIpaddress(srcIP).setSrcIpAddress(targetIP).setMacaddress(srcMac).build();
571         final String msgFormat = String.format("Send ARP Response on interface %s to destination %s", srcInterface, srcIP);
572         Future<RpcResult<Void>> future = arpManager.sendArpResponse(input);
573         Futures.addCallback(JdkFutureAdapters.listenInPoolThread(future), new FutureCallback<RpcResult<Void>>() {
574             @Override
575             public void onFailure(Throwable error) {
576                 LOG.error("Error - {}", msgFormat, error);
577             }
578
579             @Override
580             public void onSuccess(RpcResult<Void> result) {
581                 if(!result.isSuccessful()) {
582                     LOG.warn("Rpc call to {} failed", msgFormat, getErrorText(result.getErrors()));
583                 } else {
584                     LOG.debug("Successful RPC Result - {}", msgFormat);
585                 }
586             }
587         });
588     }
589
590     private String getErrorText(Collection<RpcError> errors) {
591         StringBuilder errorText = new StringBuilder();
592         for(RpcError error : errors) {
593             errorText.append(",").append(error.getErrorType()).append("-")
594                      .append(error.getMessage());
595         }
596         return errorText.toString();
597     }
598
599     private String getTunnelInterfaceFlowRef(BigInteger dpnId, short tableId, String ifName) {
600         return new StringBuilder().append(dpnId).append(tableId).append(ifName).toString();
601     }
602
603
604
605     public synchronized void addFibEntryToDS(String rd, String prefix,
606             String nexthop, int label) {
607
608         VrfEntry vrfEntry = new VrfEntryBuilder().setDestPrefix(prefix).
609                     setNextHopAddress(nexthop).setLabel((long)label).build();
610         LOG.debug("Created vrfEntry for {} nexthop {} label {}", prefix, nexthop, label);
611
612         List<VrfEntry> vrfEntryList = new ArrayList<VrfEntry>();
613         vrfEntryList.add(vrfEntry);
614
615         InstanceIdentifierBuilder<VrfTables> idBuilder =
616                     InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
617         InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
618
619         VrfTables vrfTableNew = new VrfTablesBuilder().setRouteDistinguisher(rd).
620                     setVrfEntry(vrfEntryList).build();
621
622         VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, vrfTableId, vrfTableNew);
623     }
624
625     public synchronized void removeFibEntryFromDS(String rd, String prefix) {
626
627         LOG.debug("Removing fib entry with destination prefix {} from vrf table for rd {}", prefix, rd);
628
629         InstanceIdentifierBuilder<VrfEntry> idBuilder =
630             InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)).child(VrfEntry.class, new VrfEntryKey(prefix));
631         InstanceIdentifier<VrfEntry> vrfEntryId = idBuilder.build();
632         VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, vrfEntryId, VpnUtil.DEFAULT_CALLBACK);
633
634     }
635
636     public synchronized void removeVrfFromDS(String rd) {
637         LOG.debug("Removing vrf table for  rd {}", rd);
638
639         InstanceIdentifierBuilder<VrfTables> idBuilder =
640                 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
641         InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
642
643         VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, vrfTableId, VpnUtil.DEFAULT_CALLBACK);
644
645     }
646
647     protected void addNewAdjToVpnInterface(InstanceIdentifier<VpnInterface> identifier, Adjacency adj) {
648
649         Optional<VpnInterface> optVpnInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, identifier);
650
651         if (optVpnInterface.isPresent()) {
652             VpnInterface currVpnIntf = optVpnInterface.get();
653             String prefix = VpnUtil.getIpPrefix(adj.getIpAddress());
654             String rd = getRouteDistinguisher(currVpnIntf.getVpnInstanceName());
655             InstanceIdentifier<Adjacencies> adjPath = identifier.augmentation(Adjacencies.class);
656             Optional<Adjacencies> optAdjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, adjPath);
657             long label =
658                     VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
659                             VpnUtil.getNextHopLabelKey((rd != null) ? rd : currVpnIntf.getVpnInstanceName(), prefix));
660
661             List<Adjacency> adjacencies;
662             if (optAdjacencies.isPresent()) {
663                 adjacencies = optAdjacencies.get().getAdjacency();
664             } else {
665                 //This code will not be hit since VM adjacency will always be there
666                 adjacencies = new ArrayList<>();
667             }
668
669             adjacencies.add(new AdjacencyBuilder(adj).setLabel(label).setNextHopIp(adj.getNextHopIp())
670                     .setIpAddress(prefix).setKey(new AdjacencyKey(prefix)).build());
671
672             Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencies);
673             VpnInterface newVpnIntf = VpnUtil.getVpnInterface(currVpnIntf.getName(), currVpnIntf.getVpnInstanceName(), aug);
674
675             VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, identifier, newVpnIntf);
676             addExtraRoute(adj.getIpAddress(), adj.getNextHopIp(), rd, currVpnIntf.getVpnInstanceName(), (int) label);
677
678         }
679
680     }
681
682     protected void delAdjFromVpnInterface(InstanceIdentifier<VpnInterface> identifier, Adjacency adj) {
683         Optional<VpnInterface> optVpnInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, identifier);
684
685         if (optVpnInterface.isPresent()) {
686             VpnInterface currVpnIntf = optVpnInterface.get();
687
688             InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
689             Optional<Adjacencies> optAdjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
690             if (optAdjacencies.isPresent()) {
691                 List<Adjacency> adjacencies = optAdjacencies.get().getAdjacency();
692
693                 if (!adjacencies.isEmpty()) {
694                     String rd = getRouteDistinguisher(currVpnIntf.getVpnInstanceName());
695                     LOG.trace("Adjacencies are " + adjacencies);
696                     Iterator<Adjacency> adjIt = adjacencies.iterator();
697                     while (adjIt.hasNext()) {
698                         Adjacency adjElem = adjIt.next();
699                         if (adjElem.getIpAddress().equals(adj.getIpAddress())) {
700                             VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME,
701                                     VpnUtil.getNextHopLabelKey(rd, adj.getIpAddress()));
702                             adjIt.remove();
703
704                             Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencies);
705                             VpnInterface newVpnIntf = VpnUtil.getVpnInterface(currVpnIntf.getName(), currVpnIntf.getVpnInstanceName(), aug);
706
707                             VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, identifier, newVpnIntf);
708
709                             delExtraRoute(adj.getIpAddress(), rd, currVpnIntf.getVpnInstanceName());
710                             break;
711                         }
712
713                     }
714                 }
715             }
716         }
717
718     }
719
720     protected void addExtraRoute(String destination, String nextHop, String rd, String routerID, int label) {
721         if (rd != null) {
722             addPrefixToBGP(rd, destination, nextHop, label);
723         } else {
724             // ### add FIB route directly
725             addFibEntryToDS(routerID, destination, nextHop, label);
726         }
727     }
728
729     protected void delExtraRoute(String destination, String rd, String routerID) {
730         if (rd != null) {
731             removePrefixFromBGP(rd, destination);
732         } else {
733             // ### add FIB route directly
734             removeFibEntryFromDS(routerID, destination);
735         }
736     }
737
738     protected void updatePrefixesForDPN(BigInteger dpnId, UpdateRouteAction action) {
739
740         InstanceIdentifierBuilder<VpnInstances> idBuilder = InstanceIdentifier.builder(VpnInstances.class);
741         InstanceIdentifier<VpnInstances> vpnInstancesId = idBuilder.build();
742         Optional<VpnInstances> vpnInstances = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vpnInstancesId);
743
744         if (vpnInstances.isPresent()) {
745             List<VpnInstance> vpnInstanceList = vpnInstances.get().getVpnInstance();
746             Iterator<VpnInstance> vpnInstIter = vpnInstanceList.iterator();
747             while (vpnInstIter.hasNext()) {
748                 VpnInstance vpnInstance = vpnInstIter.next();
749                 VpnAfConfig vpnConfig = vpnInstance.getIpv4Family();
750                 String rd = vpnConfig.getRouteDistinguisher();
751
752                 InstanceIdentifier<VpnToDpnList> id = VpnUtil.getVpnToDpnListIdentifier(rd, dpnId);
753                 Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
754                 if (dpnInVpn.isPresent()) {
755                     if (action == UpdateRouteAction.ADVERTISE_ROUTE) {
756                         fibManager.populateFibOnNewDpn(dpnId, VpnUtil
757                             .getVpnId(broker, vpnInstance.getVpnInstanceName()), rd);
758                     }
759                     List<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
760                         .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
761                     for(org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
762                         .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces vpnInterface : vpnInterfaces) {
763                         InstanceIdentifier<VpnInterface> vpnIntfId = VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getInterfaceName());
764                         InstanceIdentifier<Adjacencies> path = vpnIntfId.augmentation(Adjacencies.class);
765                         Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
766
767                         if (adjacencies.isPresent()) {
768                             List<Adjacency> adjacencyList = adjacencies.get().getAdjacency();
769                             Iterator<Adjacency> adjacencyIterator = adjacencyList.iterator();
770
771                             while (adjacencyIterator.hasNext()) {
772                                 Adjacency adjacency = adjacencyIterator.next();
773                                 try {
774                                     if(action == UpdateRouteAction.ADVERTISE_ROUTE)
775                                         bgpManager.addPrefix(rd, adjacency.getIpAddress(), adjacency.getNextHopIp(), adjacency.getLabel().intValue());
776                                     else if(action == UpdateRouteAction.WITHDRAW_ROUTE)
777                                         bgpManager.deletePrefix(rd, adjacency.getIpAddress());
778                                 } catch (Exception e) {
779                                     LOG.error("Exception when updating prefix {} in vrf {} to BGP", adjacency.getIpAddress(), rd);
780                                 }
781                             }
782                         }
783
784                     }
785                     if (action == UpdateRouteAction.WITHDRAW_ROUTE) {
786                         fibManager.cleanUpDpnForVpn(dpnId, VpnUtil
787                             .getVpnId(broker, vpnInstance.getVpnInstanceName()), rd);
788                     }
789                 }
790             }
791         }
792     }
793
794 }