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