Use Java declarations instead of Google Collections
[netvirt.git] / vpnservice / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / netvirt / vpnmanager / VpnSubnetRouteHandler.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.netvirt.vpnmanager;
9
10 import com.google.common.base.Optional;
11 import com.google.common.base.Preconditions;
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.Arrays;
15 import java.util.HashMap;
16 import java.util.Iterator;
17 import java.util.List;
18 import java.util.Map;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.genius.mdsalutil.MDSALUtil;
22 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
23 import org.opendaylight.netvirt.vpnmanager.VpnOpDataSyncer.VpnOpDataType;
24 import org.opendaylight.netvirt.vpnmanager.utilities.InterfaceUtils;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.LockManagerService;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.PortOpData;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.SubnetOpData;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.TaskState;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntry;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntryKey;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntry;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntryBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntryKey;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.subnet.op.data.entry.SubnetToDpn;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.Networks;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.NetworksKey;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NeutronvpnListener;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.PortAddedToSubnet;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.PortRemovedFromSubnet;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.RouterAssociatedToVpn;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.RouterDisassociatedFromVpn;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.SubnetAddedToVpn;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.SubnetAddedToVpnBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.SubnetDeletedFromVpn;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.SubnetDeletedFromVpnBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.SubnetUpdatedInVpn;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
55 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
58
59 public class VpnSubnetRouteHandler implements NeutronvpnListener {
60     private static final Logger LOG = LoggerFactory.getLogger(VpnSubnetRouteHandler.class);
61     private final DataBroker dataBroker;
62     private final SubnetOpDpnManager subOpDpnManager;
63     private final IBgpManager bgpManager;
64     private final VpnInterfaceManager vpnInterfaceManager;
65     private final IdManagerService idManager;
66     private LockManagerService lockManager;
67     private final VpnOpDataSyncer vpnOpDataSyncer;
68
69     public VpnSubnetRouteHandler(final DataBroker dataBroker, final SubnetOpDpnManager subnetOpDpnManager,
70         final IBgpManager bgpManager, final VpnInterfaceManager vpnIntfManager, final IdManagerService idManager,
71         LockManagerService lockManagerService, final VpnOpDataSyncer vpnOpDataSyncer) {
72         this.dataBroker = dataBroker;
73         this.subOpDpnManager = subnetOpDpnManager;
74         this.bgpManager = bgpManager;
75         this.vpnInterfaceManager = vpnIntfManager;
76         this.idManager = idManager;
77         this.lockManager = lockManagerService;
78         this.vpnOpDataSyncer = vpnOpDataSyncer;
79     }
80
81     // TODO Clean up the exception handling
82     @SuppressWarnings("checkstyle:IllegalCatch")
83     @Override
84     public void onSubnetAddedToVpn(SubnetAddedToVpn notification) {
85         if (!notification.isExternalVpn()) {
86             return;
87         }
88
89         Uuid subnetId = notification.getSubnetId();
90         String vpnName = notification.getVpnName();
91         String subnetIp = notification.getSubnetIp();
92         Long elanTag = notification.getElanTag();
93         boolean isRouteAdvertised = false;
94
95         Preconditions.checkNotNull(subnetId, "SubnetId cannot be null or empty!");
96         Preconditions.checkNotNull(subnetIp, "SubnetPrefix cannot be null or empty!");
97         Preconditions.checkNotNull(vpnName, "VpnName cannot be null or empty!");
98         Preconditions.checkNotNull(elanTag, "ElanTag cannot be null or empty!");
99
100         LOG.info("onSubnetAddedToVpn: Subnet {} being added to vpn", subnetId.getValue());
101         long vpnId = VpnUtil.getVpnId(dataBroker, vpnName);
102         if (vpnId == VpnConstants.INVALID_ID) {
103             vpnOpDataSyncer.waitForVpnDataReady(VpnOpDataType.vpnInstanceToId, vpnName,
104                 VpnConstants.PER_VPN_INSTANCE_MAX_WAIT_TIME_IN_MILLISECONDS);
105             vpnId = VpnUtil.getVpnId(dataBroker, vpnName);
106             if (vpnId == VpnConstants.INVALID_ID) {
107                 LOG.error(
108                     "onSubnetAddedToVpn: VpnInstance to VPNId mapping not yet available for VpnName {} processing "
109                         + "subnet {} with IP {}, bailing out now.", vpnName, subnetId, subnetIp);
110                 return;
111             }
112         }
113         //TODO(vivek): Change this to use more granularized lock at subnetId level
114         try {
115             VpnUtil.lockSubnet(lockManager, subnetId.getValue());
116             try {
117                 Subnetmap subMap = null;
118
119                 // Please check if subnetId belongs to an External Network
120                 InstanceIdentifier<Subnetmap> subMapid =
121                     InstanceIdentifier.builder(Subnetmaps.class).child(Subnetmap.class,
122                         new SubnetmapKey(subnetId)).build();
123                 Optional<Subnetmap> sm = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, subMapid);
124                 if (!sm.isPresent()) {
125                     LOG.error("onSubnetAddedToVpn: Unable to retrieve subnetmap entry for subnet : " + subnetId);
126                     return;
127                 }
128                 subMap = sm.get();
129                 InstanceIdentifier<Networks> netsIdentifier =
130                     InstanceIdentifier.builder(ExternalNetworks.class).child(Networks.class,
131                         new NetworksKey(subMap.getNetworkId())).build();
132                 Optional<Networks> optionalNets =
133                     VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, netsIdentifier);
134                 if (optionalNets.isPresent()) {
135                     LOG.info(
136                         "onSubnetAddedToVpn: subnet {} is an external subnet on external network {}, so ignoring this"
137                             + " for SubnetRoute", subnetId.getValue(), subMap.getNetworkId().getValue());
138                     return;
139                 }
140                 //Create and add SubnetOpDataEntry object for this subnet to the SubnetOpData container
141                 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier =
142                     InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class,
143                         new SubnetOpDataEntryKey(subnetId)).build();
144                 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(dataBroker,
145                         LogicalDatastoreType.OPERATIONAL,
146                         subOpIdentifier);
147                 if (optionalSubs.isPresent()) {
148                     LOG.error("onSubnetAddedToVpn: SubnetOpDataEntry for subnet {} already detected to be present",
149                         subnetId.getValue());
150                     return;
151                 }
152                 LOG.debug("onSubnetAddedToVpn: Creating new SubnetOpDataEntry node for subnet: " + subnetId.getValue());
153                 Map<BigInteger, SubnetToDpn> subDpnMap = new HashMap<BigInteger, SubnetToDpn>();
154                 BigInteger dpnId = null;
155                 BigInteger nhDpnId = null;
156                 SubnetToDpn subDpn = null;
157
158                 SubnetOpDataEntryBuilder subOpBuilder =
159                     new SubnetOpDataEntryBuilder().setKey(new SubnetOpDataEntryKey(subnetId));
160                 subOpBuilder.setSubnetId(subnetId);
161                 subOpBuilder.setSubnetCidr(subnetIp);
162                 String rd = VpnUtil.getVpnRdFromVpnInstanceConfig(dataBroker, vpnName);
163                 if (rd == null) {
164                     LOG.error("onSubnetAddedToVpn: The VPN Instance name {} does not have RD",
165                         notification.getVpnName());
166                     return;
167                 }
168                 subOpBuilder.setVrfId(rd);
169                 subOpBuilder.setVpnName(vpnName);
170                 subOpBuilder.setSubnetToDpn(new ArrayList<SubnetToDpn>());
171                 subOpBuilder.setRouteAdvState(TaskState.Na);
172                 subOpBuilder.setElanTag(elanTag);
173
174                 // First recover set of ports available in this subnet
175                 List<Uuid> portList = subMap.getPortList();
176                 if (portList != null) {
177                     for (Uuid port: portList) {
178                         Interface intfState = InterfaceUtils.getInterfaceStateFromOperDS(dataBroker,port.getValue());
179                         if (intfState != null) {
180                             try {
181                                 dpnId = InterfaceUtils.getDpIdFromInterface(intfState);
182                             } catch (Exception e) {
183                                 LOG.error("onSubnetAddedToVpn: Unable to obtain dpnId for interface {},",
184                                         " subnetroute inclusion for this interface failed with exception {}",
185                                         port.getValue(), e);
186                                 continue;
187                             }
188                             if (dpnId.equals(BigInteger.ZERO)) {
189                                 LOG.info("onSubnetAddedToVpn: Port " + port.getValue()
190                                     + " is not assigned DPN yet, ignoring ");
191                                 continue;
192                             }
193                             subOpDpnManager.addPortOpDataEntry(port.getValue(), subnetId, dpnId);
194                             if (intfState.getOperStatus() != OperStatus.Up) {
195                                 LOG.info("onSubnetAddedToVpn: Port " + port.getValue() + " is not UP yet, ignoring ");
196                                 continue;
197                             }
198                             subDpn = subOpDpnManager.addInterfaceToDpn(subnetId, dpnId, port.getValue());
199                             if (intfState.getOperStatus() == OperStatus.Up) {
200                                 // port is UP
201                                 subDpnMap.put(dpnId, subDpn);
202                                 if (nhDpnId == null) {
203                                     nhDpnId = dpnId;
204                                 }
205                             }
206                         } else {
207                             subOpDpnManager.addPortOpDataEntry(port.getValue(), subnetId, null);
208                         }
209                     }
210                     if (subDpnMap.size() > 0) {
211                         subOpBuilder.setSubnetToDpn(new ArrayList<SubnetToDpn>(subDpnMap.values()));
212                     }
213                 }
214
215                 if (nhDpnId != null) {
216                     LOG.info("Next-Hop dpn {} is available for rd {} subnetIp {} vpn {}", nhDpnId, rd, subnetIp,
217                         vpnName);
218                     subOpBuilder.setNhDpnId(nhDpnId);
219                     try {
220                         /*
221                         Write the subnet route entry to the FIB.
222                         And also advertise the subnet route entry via BGP.
223                         */
224                         int label = getLabel(rd, subnetIp);
225                         if (label == 0) {
226                             LOG.error(
227                                 "Unable to fetch label from Id Manager. Bailing out of handling addition of subnet {}"
228                                     + " to vpn {}",
229                                 subnetIp, vpnName);
230                             return;
231                         }
232                         isRouteAdvertised =
233                             addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
234                         if (isRouteAdvertised) {
235                             subOpBuilder.setRouteAdvState(TaskState.Done);
236                         } else {
237                             subOpBuilder.setNhDpnId(null);
238                             subOpBuilder.setRouteAdvState(TaskState.Na);
239                         }
240                     } catch (Exception ex) {
241                         LOG.error(
242                             "onSubnetAddedToVpn: FIB rules and Advertising nhDpnId {} information for subnet {} to "
243                                 + "BGP failed",
244                             nhDpnId, subnetId.getValue(), ex);
245                         subOpBuilder.setRouteAdvState(TaskState.Pending);
246                     }
247                 } else {
248                     LOG.info("Next-Hop dpn is unavailable for rd {} subnetIp {} vpn {}", rd, subnetIp, vpnName);
249                 }
250
251                 SubnetOpDataEntry subOpEntry = subOpBuilder.build();
252                 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
253                 LOG.info("onSubnetAddedToVpn: Added subnetopdataentry to OP Datastore for subnet {}",
254                         subnetId.getValue());
255             } catch (Exception ex) {
256                 LOG.error("Creation of SubnetOpDataEntry for subnet {} failed", subnetId.getValue(), ex);
257             } finally {
258                 VpnUtil.unlockSubnet(lockManager, subnetId.getValue());
259             }
260         } catch (Exception e) {
261             LOG.error("Unable to handle subnet {} added to vpn {} {}", subnetIp, vpnName, e);
262         }
263     }
264
265     // TODO Clean up the exception handling
266     @SuppressWarnings("checkstyle:IllegalCatch")
267     @Override
268     public void onSubnetDeletedFromVpn(SubnetDeletedFromVpn notification) {
269         Uuid subnetId = notification.getSubnetId();
270
271         if (!notification.isExternalVpn()) {
272             return;
273         }
274         LOG.info("onSubnetDeletedFromVpn: Subnet " + subnetId.getValue() + " being removed from vpn");
275         //TODO(vivek): Change this to use more granularized lock at subnetId level
276         try {
277             VpnUtil.lockSubnet(lockManager, subnetId.getValue());
278             try {
279                 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier =
280                     InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class,
281                         new SubnetOpDataEntryKey(subnetId)).build();
282                 LOG.trace(" Removing the SubnetOpDataEntry node for subnet: " +  subnetId.getValue());
283                 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(dataBroker,
284                         LogicalDatastoreType.OPERATIONAL,
285                         subOpIdentifier);
286                 if (!optionalSubs.isPresent()) {
287                     LOG.error("onSubnetDeletedFromVpn: SubnetOpDataEntry for subnet {} not available in datastore",
288                         subnetId.getValue());
289                     return;
290                 }
291
292                 /* If subnet is deleted (or if its removed from VPN), the ports that are DOWN on that subnet
293                  * will continue to be stale in portOpData DS, as subDpnList used for portOpData removal will
294                  * contain only ports that are UP. So here we explicitly cleanup the ports of the subnet by
295                  * going through the list of ports on the subnet
296                  */
297                 InstanceIdentifier<Subnetmap> subMapid =
298                     InstanceIdentifier.builder(Subnetmaps.class).child(Subnetmap.class,
299                         new SubnetmapKey(subnetId)).build();
300                 Optional<Subnetmap> sm = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, subMapid);
301                 if (!sm.isPresent()) {
302                     LOG.error("Stale ports removal: Unable to retrieve subnetmap entry for subnet : " + subnetId);
303                 } else {
304                     Subnetmap subMap = sm.get();
305                     List<Uuid> portList = subMap.getPortList();
306                     if (portList != null) {
307                         for (Uuid port : portList) {
308                             InstanceIdentifier<PortOpDataEntry> portOpIdentifier =
309                                 InstanceIdentifier.builder(PortOpData.class).child(PortOpDataEntry.class,
310                                     new PortOpDataEntryKey(port.getValue())).build();
311                             LOG.trace("Deleting portOpData entry for port " + port.getValue());
312                             MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, portOpIdentifier);
313                         }
314                     }
315                 }
316
317                 SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
318                 String rd = subOpBuilder.getVrfId();
319                 String subnetIp = subOpBuilder.getSubnetCidr();
320                 String vpnName = subOpBuilder.getVpnName();
321                 BigInteger nhDpnId = subOpBuilder.getNhDpnId();
322                 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier);
323                 LOG.info("onSubnetDeletedFromVpn: Removed subnetopdataentry for subnet {} successfully from Datastore",
324                     subnetId.getValue());
325                 try {
326                     //Withdraw the routes for all the interfaces on this subnet
327                     //Remove subnet route entry from FIB
328                     deleteSubnetRouteFromFib(rd, subnetIp, vpnName);
329                 } catch (Exception ex) {
330                     LOG.error("onSubnetAddedToVpn: Withdrawing routes from BGP for subnet {} failed",
331                         subnetId.getValue(), ex);
332                 }
333             } catch (Exception ex) {
334                 LOG.error("Removal of SubnetOpDataEntry for subnet {} failed", subnetId.getValue(), ex);
335             } finally {
336                 VpnUtil.unlockSubnet(lockManager, subnetId.getValue());
337             }
338         } catch (Exception e) {
339             LOG.error("Unable to handle subnet {} removed to vpn {}", notification.getSubnetIp(),
340                 notification.getVpnName(), e);
341         }
342     }
343
344     @Override
345     public void onSubnetUpdatedInVpn(SubnetUpdatedInVpn notification) {
346         Uuid subnetId = notification.getSubnetId();
347         String vpnName = notification.getVpnName();
348         String subnetIp = notification.getSubnetIp();
349         Long elanTag = notification.getElanTag();
350
351         Preconditions.checkNotNull(subnetId, "SubnetId cannot be null or empty!");
352         Preconditions.checkNotNull(subnetIp, "SubnetPrefix cannot be null or empty!");
353         Preconditions.checkNotNull(vpnName, "VpnName cannot be null or empty!");
354         Preconditions.checkNotNull(elanTag, "ElanTag cannot be null or empty!");
355
356         InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier =
357             InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class,
358                 new SubnetOpDataEntryKey(subnetId)).build();
359         Optional<SubnetOpDataEntry> optionalSubs =
360             VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier);
361         if (optionalSubs.isPresent()) {
362             if (!notification.isExternalVpn()) {
363                 SubnetDeletedFromVpnBuilder bldr = new SubnetDeletedFromVpnBuilder().setVpnName(vpnName);
364                 bldr.setElanTag(elanTag).setExternalVpn(true).setSubnetIp(subnetIp).setSubnetId(subnetId);
365                 onSubnetDeletedFromVpn(bldr.build());
366             }
367             // TODO(vivek): Something got updated, but we donot know what ?
368         } else {
369             if (notification.isExternalVpn()) {
370                 SubnetAddedToVpnBuilder bldr = new SubnetAddedToVpnBuilder().setVpnName(vpnName).setElanTag(elanTag);
371                 bldr.setSubnetIp(subnetIp).setSubnetId(subnetId).setExternalVpn(true);
372                 onSubnetAddedToVpn(bldr.build());
373             }
374             // TODO(vivek): Something got updated, but we donot know what ?
375         }
376     }
377
378     // TODO Clean up the exception handling
379     @SuppressWarnings("checkstyle:IllegalCatch")
380     @Override
381     public void onPortAddedToSubnet(PortAddedToSubnet notification) {
382         Uuid subnetId = notification.getSubnetId();
383         Uuid portId = notification.getPortId();
384         boolean isRouteAdvertised = false;
385
386         LOG.info("onPortAddedToSubnet: Port " + portId.getValue() + " being added to subnet " + subnetId.getValue());
387         //TODO(vivek): Change this to use more granularized lock at subnetId level
388         try {
389             VpnUtil.lockSubnet(lockManager, subnetId.getValue());
390             try {
391                 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier =
392                     InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class,
393                         new SubnetOpDataEntryKey(subnetId)).build();
394
395                 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
396                         subOpIdentifier);
397                 if (!optionalSubs.isPresent()) {
398                     LOG.info("onPortAddedToSubnet: Port {} is part of a subnet {} that is not in VPN, ignoring",
399                         portId.getValue(), subnetId.getValue());
400                     return;
401                 }
402                 Interface intfState = InterfaceUtils.getInterfaceStateFromOperDS(dataBroker,portId.getValue());
403                 if (intfState == null) {
404                     // Interface State not yet available
405                     subOpDpnManager.addPortOpDataEntry(portId.getValue(), subnetId, null);
406                     return;
407                 }
408                 BigInteger dpnId = BigInteger.ZERO;
409                 try {
410                     dpnId = InterfaceUtils.getDpIdFromInterface(intfState);
411                 } catch (Exception e) {
412                     LOG.error("onSubnetAddedToVpn: Unable to obtain dpnId for interface {},",
413                             " subnetroute inclusion for this interface failed with exception {}",
414                             portId.getValue(), e);
415                     return;
416                 }
417                 if (dpnId.equals(BigInteger.ZERO)) {
418                     LOG.info("onPortAddedToSubnet: Port " + portId.getValue() + " is not assigned DPN yet, ignoring ");
419                     return;
420                 }
421                 subOpDpnManager.addPortOpDataEntry(portId.getValue(), subnetId, dpnId);
422                 if (intfState.getOperStatus() != OperStatus.Up) {
423                     LOG.info("onPortAddedToSubnet: Port " + portId.getValue() + " is not UP yet, ignoring ");
424                     return;
425                 }
426                 LOG.debug("onPortAddedToSubnet: Updating the SubnetOpDataEntry node for subnet {}",
427                     subnetId.getValue());
428                 SubnetToDpn subDpn = subOpDpnManager.addInterfaceToDpn(subnetId, dpnId, portId.getValue());
429                 if (subDpn == null) {
430                     return;
431                 }
432                 SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
433                 List<SubnetToDpn> subDpnList = subOpBuilder.getSubnetToDpn();
434                 subDpnList.add(subDpn);
435                 subOpBuilder.setSubnetToDpn(subDpnList);
436                 if (subOpBuilder.getNhDpnId()  == null) {
437                     subOpBuilder.setNhDpnId(dpnId);
438                 }
439                 BigInteger nhDpnId = subOpBuilder.getNhDpnId();
440                 String rd = subOpBuilder.getVrfId();
441                 String subnetIp = subOpBuilder.getSubnetCidr();
442                 String vpnName = subOpBuilder.getVpnName();
443                 Long elanTag = subOpBuilder.getElanTag();
444                 if ((subOpBuilder.getRouteAdvState() == TaskState.Pending)
445                     || (subOpBuilder.getRouteAdvState() == TaskState.Na)) {
446                     try {
447                         // Write the Subnet Route Entry to FIB
448                         // Advertise BGP Route here and set route_adv_state to DONE
449                         int label = getLabel(rd, subnetIp);
450                         if (label == 0) {
451                             LOG.error(
452                                 "Unable to fetch label from Id Manager. Bailing out of handling addition of port {} "
453                                     + "to subnet {} in vpn {}",
454                                 portId.getValue(), subnetIp, vpnName);
455                             return;
456                         }
457                         isRouteAdvertised =
458                             addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
459                         if (isRouteAdvertised) {
460                             subOpBuilder.setRouteAdvState(TaskState.Done);
461                         } else {
462                             subOpBuilder.setNhDpnId(null);
463                             subOpBuilder.setRouteAdvState(TaskState.Na);
464                         }
465                     } catch (Exception ex) {
466                         LOG.error(
467                             "onPortAddedToSubnet: Advertising NextHopDPN {} information for subnet {} to BGP failed",
468                             nhDpnId, subnetId.getValue(), ex);
469                     }
470                 }
471                 SubnetOpDataEntry subOpEntry = subOpBuilder.build();
472                 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
473                 LOG.info("onPortAddedToSubnet: Updated subnetopdataentry to OP Datastore for port {}",
474                     portId.getValue());
475
476             } catch (Exception ex) {
477                 LOG.error("Creation of SubnetOpDataEntry for subnet {} failed", subnetId.getValue(), ex);
478             } finally {
479                 VpnUtil.unlockSubnet(lockManager, subnetId.getValue());
480             }
481         } catch (Exception e) {
482             LOG.error("Unable to handle port {} added to subnet {} {}", portId.getValue(), subnetId.getValue(), e);
483         }
484     }
485
486     // TODO Clean up the exception handling
487     @SuppressWarnings("checkstyle:IllegalCatch")
488     @Override
489     public void onPortRemovedFromSubnet(PortRemovedFromSubnet notification) {
490         Uuid subnetId = notification.getSubnetId();
491         Uuid portId = notification.getPortId();
492         boolean isRouteAdvertised = false;
493
494         LOG.info(
495             "onPortRemovedFromSubnet: Port " + portId.getValue() + " being removed from subnet " + subnetId.getValue());
496         //TODO(vivek): Change this to use more granularized lock at subnetId level
497         try {
498             VpnUtil.lockSubnet(lockManager, subnetId.getValue());
499             try {
500                 PortOpDataEntry portOpEntry = subOpDpnManager.removePortOpDataEntry(portId.getValue());
501                 if (portOpEntry == null) {
502                     return;
503                 }
504                 BigInteger dpnId = portOpEntry.getDpnId();
505                 if (dpnId == null) {
506                     LOG.debug("onPortRemovedFromSubnet:  Port {} does not have a DPNId associated, ignoring",
507                         portId.getValue());
508                     return;
509                 }
510                 LOG.debug(
511                     "onPortRemovedFromSubnet: Updating the SubnetOpDataEntry node for subnet: " + subnetId.getValue());
512                 boolean last = subOpDpnManager.removeInterfaceFromDpn(subnetId, dpnId, portId.getValue());
513                 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier =
514                     InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class,
515                         new SubnetOpDataEntryKey(subnetId)).build();
516                 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
517                     subOpIdentifier);
518                 if (!optionalSubs.isPresent()) {
519                     LOG.info("onPortRemovedFromSubnet: Port {} is part of a subnet {} that is not in VPN, ignoring",
520                         portId.getValue(), subnetId.getValue());
521                     return;
522                 }
523                 SubnetOpDataEntry subOpEntry = null;
524                 List<SubnetToDpn> subDpnList = null;
525                 SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
526                 String rd = subOpBuilder.getVrfId();
527                 String subnetIp = subOpBuilder.getSubnetCidr();
528                 String vpnName = subOpBuilder.getVpnName();
529                 Long elanTag = subOpBuilder.getElanTag();
530                 BigInteger nhDpnId = subOpBuilder.getNhDpnId();
531                 if ((nhDpnId != null) && (nhDpnId.equals(dpnId))) {
532                     // select another NhDpnId
533                     if (last) {
534                         LOG.debug("onPortRemovedFromSubnet: Last port {} on the subnet {}", portId,
535                             subnetId.getValue());
536                         // last port on this DPN, so we need to swap the NHDpnId
537                         subDpnList = subOpBuilder.getSubnetToDpn();
538                         if (subDpnList.isEmpty()) {
539                             subOpBuilder.setNhDpnId(null);
540                             try {
541                                 // withdraw route from BGP
542                                 deleteSubnetRouteFromFib(rd, subnetIp, vpnName);
543                                 subOpBuilder.setRouteAdvState(TaskState.Na);
544                             } catch (Exception ex) {
545                                 LOG.error(
546                                     "onPortRemovedFromSubnet: Withdrawing NextHopDPN {} information for subnet {} "
547                                         + "from BGP failed ",
548                                     dpnId, subnetId.getValue(), ex);
549                                 subOpBuilder.setRouteAdvState(TaskState.Pending);
550                             }
551                         } else {
552                             nhDpnId = subDpnList.get(0).getDpnId();
553                             subOpBuilder.setNhDpnId(nhDpnId);
554                             LOG.debug("onInterfaceDown: Swapping the Designated DPN to {} for subnet {}", nhDpnId,
555                                 subnetId.getValue());
556                             try {
557                                 // Best effort Withdrawal of route from BGP for this subnet
558                                 // Advertise the new NexthopIP to BGP for this subnet
559                                 //withdrawSubnetRoutefromBgp(rd, subnetIp);
560                                 int label = getLabel(rd, subnetIp);
561                                 if (label == 0) {
562                                     LOG.error(
563                                         "Unable to fetch label from Id Manager. Bailing out of handling removal of "
564                                             + "port {} from subnet {} in vpn {}",
565                                         portId.getValue(), subnetIp, vpnName);
566                                     return;
567                                 }
568                                 isRouteAdvertised =
569                                     addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
570                                 if (isRouteAdvertised) {
571                                     subOpBuilder.setRouteAdvState(TaskState.Done);
572                                 } else {
573                                     subOpBuilder.setNhDpnId(null);
574                                     subOpBuilder.setRouteAdvState(TaskState.Na);
575                                 }
576                             } catch (Exception ex) {
577                                 LOG.error(
578                                     "onPortRemovedFromSubnet: Swapping Withdrawing NextHopDPN {} information for "
579                                         + "subnet {} to BGP failed",
580                                     dpnId, subnetId.getValue(), ex);
581                                 subOpBuilder.setRouteAdvState(TaskState.Pending);
582                             }
583                         }
584                     }
585                 }
586                 subOpEntry = subOpBuilder.build();
587                 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
588                 LOG.info(
589                     "onPortRemovedFromSubnet: Updated subnetopdataentry to OP Datastore removing port " + portId
590                         .getValue());
591             } catch (Exception ex) {
592                 LOG.error("Creation of SubnetOpDataEntry for subnet {} failed", subnetId.getValue(), ex);
593             } finally {
594                 VpnUtil.unlockSubnet(lockManager, subnetId.getValue());
595             }
596         } catch (Exception e) {
597             LOG.error("Unable to handle port {} removed from subnet {} {}", portId.getValue(), subnetId.getValue(),
598                 e);
599         }
600     }
601
602     // TODO Clean up the exception handling
603     @SuppressWarnings("checkstyle:IllegalCatch")
604     public void onInterfaceUp(BigInteger dpnId, String intfName) {
605         LOG.info("onInterfaceUp: Port " + intfName);
606         //TODO(vivek): Change this to use more granularized lock at subnetId level
607         SubnetToDpn subDpn = null;
608         boolean isRouteAdvertised = false;
609         PortOpDataEntry portOpEntry = subOpDpnManager.getPortOpDataEntry(intfName);
610         if (portOpEntry == null) {
611             LOG.info("onInterfaceUp: Port " + intfName + "is part of a subnet not in VPN, ignoring");
612             return;
613         }
614         if ((dpnId == null) || (dpnId == BigInteger.ZERO)) {
615             dpnId = portOpEntry.getDpnId();
616             if (dpnId == null) {
617                 LOG.error("onInterfaceUp: Unable to determine the DPNID for port " + intfName);
618                 return;
619             }
620         }
621         Uuid subnetId = portOpEntry.getSubnetId();
622         try {
623             VpnUtil.lockSubnet(lockManager, subnetId.getValue());
624             try {
625                 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier =
626                     InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class,
627                         new SubnetOpDataEntryKey(subnetId)).build();
628                 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
629                     subOpIdentifier);
630                 if (!optionalSubs.isPresent()) {
631                     LOG.error("onInterfaceUp: SubnetOpDataEntry for subnet {} is not available", subnetId.getValue());
632                     return;
633                 }
634
635                 LOG.debug("onInterfaceUp: Updating the SubnetOpDataEntry node for subnet: " + subnetId.getValue());
636                 subOpDpnManager.addPortOpDataEntry(intfName, subnetId, dpnId);
637                 subDpn = subOpDpnManager.addInterfaceToDpn(subnetId, dpnId, intfName);
638                 if (subDpn == null) {
639                     return;
640                 }
641                 SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
642                 List<SubnetToDpn> subDpnList = subOpBuilder.getSubnetToDpn();
643                 subDpnList.add(subDpn);
644                 subOpBuilder.setSubnetToDpn(subDpnList);
645                 if (subOpBuilder.getNhDpnId() == null) {
646                     subOpBuilder.setNhDpnId(dpnId);
647                 }
648                 BigInteger nhDpnId = subOpBuilder.getNhDpnId();
649                 String rd = subOpBuilder.getVrfId();
650                 String subnetIp = subOpBuilder.getSubnetCidr();
651                 String vpnName = subOpBuilder.getVpnName();
652                 Long elanTag = subOpBuilder.getElanTag();
653                 if ((subOpBuilder.getRouteAdvState() == TaskState.Pending)
654                     || (subOpBuilder.getRouteAdvState() == TaskState.Na)) {
655                     try {
656                         // Write the Subnet Route Entry to FIB
657                         // Advertise BGP Route here and set route_adv_state to DONE
658                         int label = getLabel(rd, subnetIp);
659                         if (label == 0) {
660                             LOG.error(
661                                 "Unable to fetch label from Id Manager. Bailing out of handling interface up event "
662                                     + "for port {} for subnet {} in vpn {}",
663                                 intfName, subnetIp, vpnName);
664                             return;
665                         }
666                         isRouteAdvertised =
667                             addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
668                         if (isRouteAdvertised) {
669                             subOpBuilder.setRouteAdvState(TaskState.Done);
670                         } else {
671                             subOpBuilder.setNhDpnId(null);
672                             subOpBuilder.setRouteAdvState(TaskState.Na);
673                         }
674                     } catch (Exception ex) {
675                         LOG.error("onInterfaceUp: Advertising NextHopDPN {} information for subnet {} to BGP failed",
676                             nhDpnId, subnetId.getValue(), ex);
677                     }
678                 }
679                 SubnetOpDataEntry subOpEntry = subOpBuilder.build();
680                 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
681                 LOG.info("onInterfaceUp: Updated subnetopdataentry to OP Datastore port up " + intfName);
682             } catch (Exception ex) {
683                 LOG.error("Creation of SubnetOpDataEntry for subnet {} failed", subnetId.getValue(), ex);
684             } finally {
685                 VpnUtil.unlockSubnet(lockManager, subnetId.getValue());
686             }
687         } catch (Exception e) {
688             LOG.error("Unable to handle interface up event for port {} in subnet {} {}", portOpEntry.getPortId(),
689                 subnetId.getValue(), e);
690         }
691     }
692
693     // TODO Clean up the exception handling
694     @SuppressWarnings("checkstyle:IllegalCatch")
695     public void onInterfaceDown(final BigInteger dpnId, final String interfaceName) {
696         boolean isRouteAdvertised = false;
697         LOG.info("onInterfaceDown: Port " + interfaceName);
698         //TODO(vivek): Change this to use more granularized lock at subnetId level
699         PortOpDataEntry portOpEntry = subOpDpnManager.getPortOpDataEntry(interfaceName);
700         if (portOpEntry == null) {
701             LOG.info("onInterfaceDown: Port " + interfaceName + "is part of a subnet not in VPN, ignoring");
702             return;
703         }
704         if ((dpnId == null) || (dpnId == BigInteger.ZERO)) {
705             LOG.error("onInterfaceDown: Unable to determine the DPNID for port " + interfaceName);
706             return;
707         }
708         Uuid subnetId = portOpEntry.getSubnetId();
709         try {
710             VpnUtil.lockSubnet(lockManager, subnetId.getValue());
711             try {
712                 LOG.debug("onInterfaceDown: Updating the SubnetOpDataEntry node for subnet: " + subnetId.getValue());
713                 boolean last = subOpDpnManager.removeInterfaceFromDpn(subnetId, dpnId, interfaceName);
714                 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier =
715                     InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class,
716                         new SubnetOpDataEntryKey(subnetId)).build();
717                 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(dataBroker,
718                     LogicalDatastoreType.OPERATIONAL,
719                     subOpIdentifier);
720                 if (!optionalSubs.isPresent()) {
721                     LOG.error("onInterfaceDown: SubnetOpDataEntry for subnet {} is not available", subnetId.getValue());
722                     return;
723                 }
724                 SubnetOpDataEntry subOpEntry = null;
725                 List<SubnetToDpn> subDpnList = null;
726                 SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
727                 String rd = subOpBuilder.getVrfId();
728                 String subnetIp = subOpBuilder.getSubnetCidr();
729                 String vpnName = subOpBuilder.getVpnName();
730                 Long elanTag = subOpBuilder.getElanTag();
731                 BigInteger nhDpnId = subOpBuilder.getNhDpnId();
732                 if ((nhDpnId != null) && (nhDpnId.equals(dpnId))) {
733                     // select another NhDpnId
734                     if (last) {
735                         LOG.debug(
736                             "onInterfaceDown: Last active port " + interfaceName + " on the subnet: " + subnetId
737                                 .getValue());
738                         // last port on this DPN, so we need to swap the NHDpnId
739                         subDpnList = subOpBuilder.getSubnetToDpn();
740                         if (subDpnList.isEmpty()) {
741                             subOpBuilder.setNhDpnId(null);
742                             try {
743                                 // Withdraw route from BGP for this subnet
744                                 deleteSubnetRouteFromFib(rd, subnetIp, vpnName);
745                                 subOpBuilder.setRouteAdvState(TaskState.Na);
746                             } catch (Exception ex) {
747                                 LOG.error(
748                                     "onInterfaceDown: Withdrawing NextHopDPN {} information for subnet {} from BGP "
749                                         + "failed",
750                                     dpnId, subnetId.getValue(), ex);
751                                 subOpBuilder.setRouteAdvState(TaskState.Pending);
752                             }
753                         } else {
754                             nhDpnId = subDpnList.get(0).getDpnId();
755                             subOpBuilder.setNhDpnId(nhDpnId);
756                             LOG.debug(
757                                 "onInterfaceDown: Swapping the Designated DPN to {} for subnet {}" , nhDpnId,
758                                     subnetId.getValue());
759                             try {
760                                 // Best effort Withdrawal of route from BGP for this subnet
761                                 //withdrawSubnetRoutefromBgp(rd, subnetIp);
762                                 int label = getLabel(rd, subnetIp);
763                                 if (label == 0) {
764                                     LOG.error(
765                                         "Unable to fetch label from Id Manager. Bailing out of handling interface "
766                                             + "down event for port {} in subnet {} for vpn {}",
767                                         interfaceName, subnetIp, vpnName);
768                                     return;
769                                 }
770                                 isRouteAdvertised =
771                                     addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
772                                 if (isRouteAdvertised) {
773                                     subOpBuilder.setRouteAdvState(TaskState.Done);
774                                 } else {
775                                     subOpBuilder.setNhDpnId(null);
776                                     subOpBuilder.setRouteAdvState(TaskState.Na);
777                                 }
778                             } catch (Exception ex) {
779                                 LOG.error(
780                                     "onInterfaceDown: Swapping Withdrawing NextHopDPN {} information for "
781                                         + "subnet {} to BGP failed", dpnId, subnetId.getValue(), ex);
782                                 subOpBuilder.setRouteAdvState(TaskState.Pending);
783                             }
784                         }
785                     }
786                 }
787                 subOpEntry = subOpBuilder.build();
788                 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
789                 LOG.info("onInterfaceDown: Updated subnetopdataentry to OP Datastore port down " + interfaceName);
790             } catch (Exception ex) {
791                 LOG.error("Creation of SubnetOpDataEntry for subnet {} failed", subnetId.getValue(), ex);
792             } finally {
793                 VpnUtil.unlockSubnet(lockManager, subnetId.getValue());
794             }
795         } catch (Exception e) {
796             LOG.error("Unable to handle interface down event for port {} in subnet {} {}", portOpEntry.getPortId(),
797                 subnetId.getValue(), e);
798         }
799     }
800
801     @Override
802     public void onRouterAssociatedToVpn(RouterAssociatedToVpn notification) {
803     }
804
805     @Override
806     public void onRouterDisassociatedFromVpn(RouterDisassociatedFromVpn notification) {
807     }
808
809     // TODO Clean up the exception handling
810     @SuppressWarnings("checkstyle:IllegalCatch")
811     public void updateSubnetRouteOnTunnelUpEvent(Uuid subnetId, BigInteger dpnId) {
812         boolean isRouteAdvertised = false;
813         LOG.info("updateSubnetRouteOnTunnelUpEvent: Subnet {} Dpn {}", subnetId.getValue(), dpnId.toString());
814         try {
815             VpnUtil.lockSubnet(lockManager, subnetId.getValue());
816             try {
817                 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier =
818                     InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class,
819                         new SubnetOpDataEntryKey(subnetId)).build();
820                 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(dataBroker,
821                     LogicalDatastoreType.OPERATIONAL,
822                     subOpIdentifier);
823                 if (!optionalSubs.isPresent()) {
824                     LOG.error("updateSubnetRouteOnTunnelUpEvent: SubnetOpDataEntry for subnet {} is not available",
825                         subnetId.getValue());
826                     return;
827                 }
828                 SubnetOpDataEntry subOpEntry = null;
829                 SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
830                 String rd = subOpBuilder.getVrfId();
831                 String subnetIp = subOpBuilder.getSubnetCidr();
832                 String vpnName = subOpBuilder.getVpnName();
833                 List<SubnetToDpn> subDpnList = subOpBuilder.getSubnetToDpn();
834                 long elanTag = subOpBuilder.getElanTag();
835                 if ((subOpBuilder.getRouteAdvState() == TaskState.Pending)
836                     || (subOpBuilder.getRouteAdvState() == TaskState.Na)) {
837                     for (SubnetToDpn subDpn : subDpnList) {
838                         if (subDpn.getDpnId().equals(dpnId)) {
839                             if (subOpBuilder.getNhDpnId() == null) {
840                                 try {
841                                     subOpBuilder.setNhDpnId(dpnId);
842                                     int label = getLabel(rd, subnetIp);
843                                     isRouteAdvertised =
844                                         addSubnetRouteToFib(rd, subnetIp, dpnId, vpnName, elanTag, label, subnetId);
845                                     if (isRouteAdvertised) {
846                                         subOpBuilder.setRouteAdvState(TaskState.Done);
847                                     } else {
848                                         subOpBuilder.setNhDpnId(null);
849                                         subOpBuilder.setRouteAdvState(TaskState.Na);
850                                     }
851                                 } catch (Exception ex) {
852                                     LOG.error(
853                                         "updateSubnetRouteOnTunnelUpEvent: Advertising NextHopDPN {} information for "
854                                             + "subnet {} to BGP failed",
855                                         dpnId, subnetId.getValue(), ex);
856                                 }
857                             }
858                         }
859                     }
860                     subOpEntry = subOpBuilder.build();
861                     MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
862                     LOG.info(
863                         "updateSubnetRouteOnTunnelUpEvent: Updated subnetopdataentry to OP Datastore tunnel up on dpn"
864                             + " {} for subnet {}",
865                         dpnId.toString(), subnetId.getValue());
866                 }
867             } catch (Exception ex) {
868                 LOG.error("Creation of SubnetOpDataEntry for subnet {} failed", subnetId.getValue(), ex);
869             } finally {
870                 VpnUtil.unlockSubnet(lockManager, subnetId.getValue());
871             }
872         } catch (Exception e) {
873             LOG.error("Unable to handle tunnel up event for subnetId {} dpnId {}", subnetId.getValue(),
874                 dpnId.toString());
875         }
876     }
877
878     // TODO Clean up the exception handling
879     @SuppressWarnings("checkstyle:IllegalCatch")
880     public void updateSubnetRouteOnTunnelDownEvent(Uuid subnetId, BigInteger dpnId) {
881         LOG.info("updateSubnetRouteOnTunnelDownEvent: Subnet {} Dpn {}", subnetId.getValue(), dpnId.toString());
882         //TODO(vivek): Change this to use more granularized lock at subnetId level
883         try {
884             VpnUtil.lockSubnet(lockManager, subnetId.getValue());
885             try {
886                 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier =
887                     InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class,
888                         new SubnetOpDataEntryKey(subnetId)).build();
889                 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(dataBroker,
890                     LogicalDatastoreType.OPERATIONAL,
891                     subOpIdentifier);
892                 if (!optionalSubs.isPresent()) {
893                     LOG.error("updateSubnetRouteOnTunnelDownEvent: SubnetOpDataEntry for subnet {} is not available",
894                         subnetId.getValue());
895                     return;
896                 }
897                 SubnetOpDataEntry subOpEntry = null;
898                 SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
899                 BigInteger nhDpnId = subOpBuilder.getNhDpnId();
900                 if ((nhDpnId != null) && (nhDpnId.equals(dpnId))) {
901                     electNewDPNForSubNetRoute(subOpBuilder, dpnId, subnetId);
902                     subOpEntry = subOpBuilder.build();
903                     MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
904                     LOG.info(
905                         "updateSubnetRouteOnTunnelDownEvent: Updated subnetopdataentry to OP Datastore tunnnel down "
906                             + "on dpn {} for subnet {}",
907                         dpnId.toString(), subnetId.getValue());
908                 }
909             } catch (Exception ex) {
910                 LOG.error("Updation of SubnetOpDataEntry for subnet {} failed", subnetId.getValue(), ex);
911             } finally {
912                 VpnUtil.unlockSubnet(lockManager, subnetId.getValue());
913             }
914         } catch (Exception e) {
915             LOG.error("Unable to handle tunnel down event for subnetId {} dpnId {}", subnetId.getValue(),
916                 dpnId.toString());
917         }
918     }
919
920     // TODO Clean up the exception handling
921     @SuppressWarnings("checkstyle:IllegalCatch")
922     private boolean addSubnetRouteToFib(String rd, String subnetIp, BigInteger nhDpnId, String vpnName,
923         Long elanTag, int label, Uuid subnetId) throws Exception {
924         Preconditions.checkNotNull(rd, "RouteDistinguisher cannot be null or empty!");
925         Preconditions.checkNotNull(subnetIp, "SubnetRouteIp cannot be null or empty!");
926         Preconditions.checkNotNull(vpnName, "vpnName cannot be null or empty!");
927         Preconditions.checkNotNull(elanTag, "elanTag cannot be null or empty!");
928         String nexthopIp = null;
929         try {
930             nexthopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, nhDpnId);
931         } catch (Exception e) {
932             LOG.warn("Unable to find nexthopip for subnetroute subnetip {}", subnetIp);
933             return false;
934         }
935         if (nexthopIp != null) {
936             VpnUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
937                 VpnUtil.getPrefixToInterfaceIdentifier(VpnUtil.getVpnId(dataBroker, vpnName), subnetIp),
938                 VpnUtil.getPrefixToInterface(nhDpnId, subnetId.getValue(), subnetIp));
939             vpnInterfaceManager.addSubnetRouteFibEntryToDS(rd, vpnName, subnetIp, nexthopIp, label, elanTag, nhDpnId,
940                 null);
941             try {
942                 //BGP manager will handle withdraw and advertise internally if prefix
943                 //already exist
944                 bgpManager.advertisePrefix(rd, subnetIp, Arrays.asList(nexthopIp), label);
945             } catch (Exception e) {
946                 LOG.error("Fail: Subnet route not advertised for rd {} subnetIp {}", rd, subnetIp, e);
947                 throw e;
948             }
949         } else {
950             LOG.warn("The nexthopip is empty for subnetroute subnetip {}, ignoring fib route addition", subnetIp);
951             return false;
952         }
953         return true;
954     }
955
956     private int getLabel(String rd, String subnetIp) {
957         int label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
958             VpnUtil.getNextHopLabelKey(rd, subnetIp));
959         LOG.trace("Allocated subnetroute label {} for rd {} prefix {}", label, rd, subnetIp);
960         return label;
961     }
962
963     // TODO Clean up the exception handling
964     @SuppressWarnings("checkstyle:IllegalCatch")
965     private void deleteSubnetRouteFromFib(String rd, String subnetIp, String vpnName) throws Exception {
966         Preconditions.checkNotNull(rd, "RouteDistinguisher cannot be null or empty!");
967         Preconditions.checkNotNull(subnetIp, "SubnetRouteIp cannot be null or empty!");
968         vpnInterfaceManager.deleteSubnetRouteFibEntryFromDS(rd, subnetIp, vpnName);
969         try {
970             bgpManager.withdrawPrefix(rd, subnetIp);
971         } catch (Exception e) {
972             LOG.error("Fail: Subnet route not withdrawn for rd {} subnetIp {}", rd, subnetIp, e);
973             throw e;
974         }
975     }
976
977     // TODO Clean up the exception handling
978     @SuppressWarnings("checkstyle:IllegalCatch")
979     private void electNewDPNForSubNetRoute(SubnetOpDataEntryBuilder subOpBuilder, BigInteger dpnId, Uuid subnetId) {
980         List<SubnetToDpn> subDpnList = null;
981         boolean isRouteAdvertised = false;
982         subDpnList = subOpBuilder.getSubnetToDpn();
983         String rd = subOpBuilder.getVrfId();
984         String subnetIp = subOpBuilder.getSubnetCidr();
985         String vpnName = subOpBuilder.getVpnName();
986         long elanTag = subOpBuilder.getElanTag();
987         BigInteger nhDpnId = null;
988         boolean isAlternateDpnSelected = false;
989         Iterator<SubnetToDpn> subNetIt = subDpnList.iterator();
990         int label = getLabel(rd, subnetIp);
991         while (subNetIt.hasNext()) {
992             SubnetToDpn subnetToDpn = subNetIt.next();
993             nhDpnId = subnetToDpn.getDpnId();
994             if (!nhDpnId.equals(dpnId)) {
995                 try {
996                     //update the VRF entry for the subnetroute.
997                     isRouteAdvertised = addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
998                     if (isRouteAdvertised) {
999                         subOpBuilder.setRouteAdvState(TaskState.Done);
1000                         subOpBuilder.setNhDpnId(nhDpnId);
1001                         isAlternateDpnSelected = true;
1002                         break;
1003                     }
1004                 } catch (Exception ex) {
1005                     LOG.error(
1006                         "electNewDPNForSubNetRoute: Swapping and trying to configure NextHopDPN {} for subnet {} "
1007                             + "failed ex {}",
1008                         dpnId.toString(), subnetId.getValue(), ex);
1009                     subOpBuilder.setRouteAdvState(TaskState.Na);
1010                 }
1011             }
1012         }
1013
1014         //If no alternate Dpn is selected as nextHopDpn ,withdraw the subnetroute.
1015         if (!isAlternateDpnSelected) {
1016             LOG.info("No alternate DPN available for subnet {}.Prefix withdrawn from BGP", subnetIp);
1017             try {
1018                 // Withdraw route from BGP for this subnet
1019                 deleteSubnetRouteFromFib(rd, subnetIp, vpnName);
1020                 subOpBuilder.setNhDpnId(null);
1021                 subOpBuilder.setRouteAdvState(TaskState.Na);
1022             } catch (Exception ex) {
1023                 LOG.error(
1024                     "electNewDPNForSubNetRoute: Withdrawing NextHopDPN " + dpnId.toString() + " information for subnet "
1025                         +
1026                         subnetId.getValue() + " from BGP failed {}" + ex);
1027                 subOpBuilder.setRouteAdvState(TaskState.Pending);
1028             }
1029         }
1030     }
1031 }
1032