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