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