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.HashMap;
16 import java.util.List;
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.genius.mdsalutil.MDSALUtil;
21 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
22 import org.opendaylight.netvirt.vpnmanager.utilities.InterfaceUtils;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.LockManagerService;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.PortOpData;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.SubnetOpData;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.TaskState;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntry;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntryKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntry;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntryBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntryKey;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.subnet.op.data.entry.SubnetToDpn;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.Networks;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.NetworksKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NeutronvpnListener;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.PortAddedToSubnet;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.PortRemovedFromSubnet;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.RouterAssociatedToVpn;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.RouterDisassociatedFromVpn;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.SubnetAddedToVpn;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.SubnetAddedToVpnBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.SubnetDeletedFromVpn;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.SubnetDeletedFromVpnBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.SubnetUpdatedInVpn;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
53 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
57 public class VpnSubnetRouteHandler implements NeutronvpnListener {
58 private static final Logger logger = LoggerFactory.getLogger(VpnSubnetRouteHandler.class);
59 private final DataBroker dataBroker;
60 private final SubnetOpDpnManager subOpDpnManager;
61 private final IBgpManager bgpManager;
62 private final VpnInterfaceManager vpnInterfaceManager;
63 private final IdManagerService idManager;
64 private LockManagerService lockManager;
66 public VpnSubnetRouteHandler(final DataBroker dataBroker, final SubnetOpDpnManager subnetOpDpnManager,
67 final IBgpManager bgpManager, final VpnInterfaceManager vpnIntfManager,
68 final IdManagerService idManager, LockManagerService lockManagerService) {
69 this.dataBroker = dataBroker;
70 this.subOpDpnManager = subnetOpDpnManager;
71 this.bgpManager = bgpManager;
72 this.vpnInterfaceManager = vpnIntfManager;
73 this.idManager = idManager;
74 this.lockManager = lockManagerService;
78 public void onSubnetAddedToVpn(SubnetAddedToVpn notification) {
79 if (!notification.isExternalVpn()) {
83 Uuid subnetId = notification.getSubnetId();
84 String vpnName = notification.getVpnName();
85 String subnetIp = notification.getSubnetIp();
86 Long elanTag = notification.getElanTag();
88 Preconditions.checkNotNull(subnetId, "SubnetId cannot be null or empty!");
89 Preconditions.checkNotNull(subnetIp, "SubnetPrefix cannot be null or empty!");
90 Preconditions.checkNotNull(vpnName, "VpnName cannot be null or empty!");
91 Preconditions.checkNotNull(elanTag, "ElanTag cannot be null or empty!");
93 logger.info("onSubnetAddedToVpn: Subnet " + subnetId.getValue() + " being added to vpn");
94 long vpnId = VpnUtil.getVpnId(dataBroker, vpnName);
95 if (vpnId == VpnConstants.INVALID_ID) {
96 vpnInterfaceManager.waitForVpnInstance(vpnName, VpnConstants.PER_VPN_INSTANCE_MAX_WAIT_TIME_IN_MILLISECONDS, vpnInterfaceManager.getvpnInstanceToIdSynchronizerMap());
97 vpnId = VpnUtil.getVpnId(dataBroker, vpnName);
98 if (vpnId == VpnConstants.INVALID_ID) {
99 logger.error("onSubnetAddedToVpn: VpnInstance to VPNId mapping not yet available for VpnName {} processing subnet {} with IP {} " +
100 ", bailing out now.", vpnName, subnetId, subnetIp);
104 //TODO(vivek): Change this to use more granularized lock at subnetId level
106 VpnUtil.lockSubnet(lockManager, subnetId.getValue());
108 Subnetmap subMap = null;
110 // Please check if subnetId belongs to an External Network
111 InstanceIdentifier<Subnetmap> subMapid = InstanceIdentifier.builder(Subnetmaps.class).
112 child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
113 Optional<Subnetmap> sm = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, subMapid);
114 if (!sm.isPresent()) {
115 logger.error("onSubnetAddedToVpn: Unable to retrieve subnetmap entry for subnet : " + subnetId);
119 InstanceIdentifier<Networks> netsIdentifier = InstanceIdentifier.builder(ExternalNetworks.class).
120 child(Networks.class, new NetworksKey(subMap.getNetworkId())).build();
121 Optional<Networks> optionalNets = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, netsIdentifier);
122 if (optionalNets.isPresent()) {
123 logger.info("onSubnetAddedToVpn: subnet {} is an external subnet on external network {}, so ignoring this for SubnetRoute",
124 subnetId.getValue(), subMap.getNetworkId().getValue());
127 //Create and add SubnetOpDataEntry object for this subnet to the SubnetOpData container
128 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
129 child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
130 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(dataBroker,
131 LogicalDatastoreType.OPERATIONAL,
133 if (optionalSubs.isPresent()) {
134 logger.error("onSubnetAddedToVpn: SubnetOpDataEntry for subnet " + subnetId.getValue() +
135 " already detected to be present");
138 logger.debug("onSubnetAddedToVpn: Creating new SubnetOpDataEntry node for subnet: " + subnetId.getValue());
139 Map<BigInteger, SubnetToDpn> subDpnMap = new HashMap<BigInteger, SubnetToDpn>();
140 SubnetOpDataEntry subOpEntry = null;
141 BigInteger dpnId = null;
142 BigInteger nhDpnId = null;
143 SubnetToDpn subDpn = null;
145 SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder().setKey(new SubnetOpDataEntryKey(subnetId));
146 subOpBuilder.setSubnetId(subnetId);
147 subOpBuilder.setSubnetCidr(subnetIp);
148 String rd = VpnUtil.getVpnRdFromVpnInstanceConfig(dataBroker, vpnName);
150 logger.error("onSubnetAddedToVpn: The VPN Instance name " + notification.getVpnName() + " does not have RD ");
153 subOpBuilder.setVrfId(rd);
154 subOpBuilder.setVpnName(vpnName);
155 subOpBuilder.setSubnetToDpn(new ArrayList<SubnetToDpn>());
156 subOpBuilder.setRouteAdvState(TaskState.Na);
157 subOpBuilder.setElanTag(elanTag);
159 // First recover set of ports available in this subnet
160 List<Uuid> portList = subMap.getPortList();
161 if (portList != null) {
162 for (Uuid port: portList) {
163 Interface intfState = InterfaceUtils.getInterfaceStateFromOperDS(dataBroker,port.getValue());
164 if (intfState != null) {
166 dpnId = InterfaceUtils.getDpIdFromInterface(intfState);
167 } catch (Exception e) {
168 logger.error("onSubnetAddedToVpn: Unable to obtain dpnId for interface {},",
169 " subnetroute inclusion for this interface failed with exception {}",
173 if (dpnId.equals(BigInteger.ZERO)) {
174 logger.info("onSubnetAddedToVpn: Port " + port.getValue() + " is not assigned DPN yet, ignoring ");
177 subOpDpnManager.addPortOpDataEntry(port.getValue(), subnetId, dpnId);
178 if (intfState.getOperStatus() != OperStatus.Up) {
179 logger.info("onSubnetAddedToVpn: Port " + port.getValue() + " is not UP yet, ignoring ");
182 subDpn = subOpDpnManager.addInterfaceToDpn(subnetId, dpnId, port.getValue());
183 if (intfState.getOperStatus() == OperStatus.Up) {
185 subDpnMap.put(dpnId, subDpn);
186 if (nhDpnId == null) {
191 subOpDpnManager.addPortOpDataEntry(port.getValue(), subnetId, null);
194 if (subDpnMap.size() > 0) {
195 subOpBuilder.setSubnetToDpn(new ArrayList<SubnetToDpn>(subDpnMap.values()));
199 if (nhDpnId != null) {
200 logger.info("Next-Hop dpn {} is available for rd {} subnetIp {} vpn {}", nhDpnId, rd, subnetIp, vpnName);
201 subOpBuilder.setNhDpnId(nhDpnId);
204 Write the subnet route entry to the FIB.
205 And also advertise the subnet route entry via BGP.
207 int label = getLabel(rd, subnetIp);
209 logger.error("Unable to fetch label from Id Manager. Bailing out of handling addition of subnet {} to vpn {}", subnetIp, vpnName);
212 addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
213 subOpBuilder.setRouteAdvState(TaskState.Done);
214 } catch (Exception ex) {
215 logger.error("onSubnetAddedToVpn: FIB rules and Advertising nhDpnId " + nhDpnId +
216 " information for subnet " + subnetId.getValue() + " to BGP failed {}", ex);
217 subOpBuilder.setRouteAdvState(TaskState.Pending);
220 logger.info("Next-Hop dpn is unavailable for rd {} subnetIp {} vpn {}", rd, subnetIp, vpnName);
223 subOpEntry = subOpBuilder.build();
224 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
225 logger.info("onSubnetAddedToVpn: Added subnetopdataentry to OP Datastore for subnet {}",
226 subnetId.getValue());
227 } catch (Exception ex) {
228 logger.error("Creation of SubnetOpDataEntry for subnet " +
229 subnetId.getValue() + " failed {}", ex);
231 VpnUtil.unlockSubnet(lockManager, subnetId.getValue());
233 } catch (Exception e) {
234 logger.error("Unable to handle subnet {} added to vpn {} {}", subnetIp, vpnName, e);
240 public void onSubnetDeletedFromVpn(SubnetDeletedFromVpn notification) {
241 Uuid subnetId = notification.getSubnetId();
243 if (!notification.isExternalVpn()) {
246 logger.info("onSubnetDeletedFromVpn: Subnet " + subnetId.getValue() + " being removed from vpn");
247 //TODO(vivek): Change this to use more granularized lock at subnetId level
249 VpnUtil.lockSubnet(lockManager, subnetId.getValue());
251 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
252 child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
253 logger.trace(" Removing the SubnetOpDataEntry node for subnet: " + subnetId.getValue());
254 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(dataBroker,
255 LogicalDatastoreType.OPERATIONAL,
257 if (!optionalSubs.isPresent()) {
258 logger.error("onSubnetDeletedFromVpn: SubnetOpDataEntry for subnet " + subnetId.getValue() +
259 " not available in datastore");
263 /* If subnet is deleted (or if its removed from VPN), the ports that are DOWN on that subnet
264 * will continue to be stale in portOpData DS, as subDpnList used for portOpData removal will
265 * contain only ports that are UP. So here we explicitly cleanup the ports of the subnet by
266 * going through the list of ports on the subnet
268 InstanceIdentifier<Subnetmap> subMapid = InstanceIdentifier.builder(Subnetmaps.class).
269 child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
270 Optional<Subnetmap> sm = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, subMapid);
271 if (!sm.isPresent()) {
272 logger.error("Stale ports removal: Unable to retrieve subnetmap entry for subnet : " + subnetId);
274 Subnetmap subMap = sm.get();
275 List<Uuid> portList = subMap.getPortList();
276 if (portList != null) {
277 for (Uuid port : portList) {
278 InstanceIdentifier<PortOpDataEntry> portOpIdentifier = InstanceIdentifier.builder(PortOpData.class).
279 child(PortOpDataEntry.class, new PortOpDataEntryKey(port.getValue())).build();
280 logger.trace("Deleting portOpData entry for port " + port.getValue());
281 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, portOpIdentifier);
286 SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
287 String rd = subOpBuilder.getVrfId();
288 String subnetIp = subOpBuilder.getSubnetCidr();
289 String vpnName = subOpBuilder.getVpnName();
290 BigInteger nhDpnId = subOpBuilder.getNhDpnId();
291 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier);
292 logger.info("onSubnetDeletedFromVpn: Removed subnetopdataentry for subnet {} successfully from Datastore", subnetId.getValue());
294 //Withdraw the routes for all the interfaces on this subnet
295 //Remove subnet route entry from FIB
296 deleteSubnetRouteFromFib(rd, subnetIp, vpnName);
297 } catch (Exception ex) {
298 logger.error("onSubnetAddedToVpn: Withdrawing routes from BGP for subnet " +
299 subnetId.getValue() + " failed {}" + ex);
301 } catch (Exception ex) {
302 logger.error("Removal of SubnetOpDataEntry for subnet " +
303 subnetId.getValue() + " failed {}" + ex);
305 VpnUtil.unlockSubnet(lockManager, subnetId.getValue());
307 } catch (Exception e) {
308 logger.error("Unable to handle subnet {} removed to vpn {} {}", notification.getSubnetIp(), notification.getVpnName(), e);
313 public void onSubnetUpdatedInVpn(SubnetUpdatedInVpn notification) {
314 Uuid subnetId = notification.getSubnetId();
315 String vpnName = notification.getVpnName();
316 String subnetIp = notification.getSubnetIp();
317 Long elanTag = notification.getElanTag();
319 Preconditions.checkNotNull(subnetId, "SubnetId cannot be null or empty!");
320 Preconditions.checkNotNull(subnetIp, "SubnetPrefix cannot be null or empty!");
321 Preconditions.checkNotNull(vpnName, "VpnName cannot be null or empty!");
322 Preconditions.checkNotNull(elanTag, "ElanTag cannot be null or empty!");
324 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
325 child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
326 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(dataBroker,
327 LogicalDatastoreType.OPERATIONAL,
329 if (optionalSubs.isPresent()) {
330 if (!notification.isExternalVpn()) {
331 SubnetDeletedFromVpnBuilder bldr = new SubnetDeletedFromVpnBuilder().setVpnName(vpnName);
332 bldr.setElanTag(elanTag).setExternalVpn(true).setSubnetIp(subnetIp).setSubnetId(subnetId);
333 onSubnetDeletedFromVpn(bldr.build());
335 // TODO(vivek): Something got updated, but we donot know what ?
337 if (notification.isExternalVpn()) {
338 SubnetAddedToVpnBuilder bldr = new SubnetAddedToVpnBuilder().setVpnName(vpnName).setElanTag(elanTag);
339 bldr.setSubnetIp(subnetIp).setSubnetId(subnetId).setExternalVpn(true);;
340 onSubnetAddedToVpn(bldr.build());
342 // TODO(vivek): Something got updated, but we donot know what ?
347 public void onPortAddedToSubnet(PortAddedToSubnet notification) {
348 Uuid subnetId = notification.getSubnetId();
349 Uuid portId = notification.getPortId();
351 logger.info("onPortAddedToSubnet: Port " + portId.getValue() + " being added to subnet " + subnetId.getValue());
352 //TODO(vivek): Change this to use more granularized lock at subnetId level
354 VpnUtil.lockSubnet(lockManager, subnetId.getValue());
356 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
357 child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
359 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
361 if (!optionalSubs.isPresent()) {
362 logger.info("onPortAddedToSubnet: Port " + portId.getValue() + " is part of a subnet " + subnetId.getValue() +
363 " that is not in VPN, ignoring");
366 Interface intfState = InterfaceUtils.getInterfaceStateFromOperDS(dataBroker,portId.getValue());
367 if (intfState == null) {
368 // Interface State not yet available
369 subOpDpnManager.addPortOpDataEntry(portId.getValue(), subnetId, null);
372 BigInteger dpnId = BigInteger.ZERO;
374 dpnId = InterfaceUtils.getDpIdFromInterface(intfState);
375 } catch (Exception e) {
376 logger.error("onSubnetAddedToVpn: Unable to obtain dpnId for interface {},",
377 " subnetroute inclusion for this interface failed with exception {}",
378 portId.getValue(), e);
381 if (dpnId.equals(BigInteger.ZERO)) {
382 logger.info("onPortAddedToSubnet: Port " + portId.getValue() + " is not assigned DPN yet, ignoring ");
385 subOpDpnManager.addPortOpDataEntry(portId.getValue(), subnetId, dpnId);
386 if (intfState.getOperStatus() != OperStatus.Up) {
387 logger.info("onPortAddedToSubnet: Port " + portId.getValue() + " is not UP yet, ignoring ");
390 logger.debug("onPortAddedToSubnet: Updating the SubnetOpDataEntry node for subnet: " + subnetId.getValue());
391 SubnetToDpn subDpn = subOpDpnManager.addInterfaceToDpn(subnetId, dpnId, portId.getValue());
392 if (subDpn == null) {
395 SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
396 List<SubnetToDpn> subDpnList = subOpBuilder.getSubnetToDpn();
397 subDpnList.add(subDpn);
398 subOpBuilder.setSubnetToDpn(subDpnList);
399 if (subOpBuilder.getNhDpnId() == null) {
400 subOpBuilder.setNhDpnId(dpnId);
402 BigInteger nhDpnId = subOpBuilder.getNhDpnId();
403 String rd = subOpBuilder.getVrfId();
404 String subnetIp = subOpBuilder.getSubnetCidr();
405 String vpnName = subOpBuilder.getVpnName();
406 Long elanTag = subOpBuilder.getElanTag();
407 if ((subOpBuilder.getRouteAdvState() == TaskState.Pending) ||
408 (subOpBuilder.getRouteAdvState() == TaskState.Na)) {
410 // Write the Subnet Route Entry to FIB
411 // Advertise BGP Route here and set route_adv_state to DONE
412 int label = getLabel(rd, subnetIp);
414 logger.error("Unable to fetch label from Id Manager. Bailing out of handling addition of port {} to subnet {} in vpn {}", portId.getValue(), subnetIp, vpnName);
417 addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
418 subOpBuilder.setRouteAdvState(TaskState.Done);
419 } catch (Exception ex) {
420 logger.error("onPortAddedToSubnet: Advertising NextHopDPN "+ nhDpnId +
421 " information for subnet " + subnetId.getValue() + " to BGP failed {}", ex);
424 SubnetOpDataEntry subOpEntry = subOpBuilder.build();
425 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
426 logger.info("onPortAddedToSubnet: Updated subnetopdataentry to OP Datastore for port " + portId.getValue());
428 } catch (Exception ex) {
429 logger.error("Creation of SubnetOpDataEntry for subnet " +
430 subnetId.getValue() + " failed {}", ex);
432 VpnUtil.unlockSubnet(lockManager, subnetId.getValue());
434 } catch (Exception e) {
435 logger.error("Unable to handle port {} added to subnet {} {}", portId.getValue(), subnetId.getValue(), e);
440 public void onPortRemovedFromSubnet(PortRemovedFromSubnet notification) {
441 Uuid subnetId = notification.getSubnetId();
442 Uuid portId = notification.getPortId();
444 logger.info("onPortRemovedFromSubnet: Port " + portId.getValue() + " being removed from subnet " + subnetId.getValue());
445 //TODO(vivek): Change this to use more granularized lock at subnetId level
447 VpnUtil.lockSubnet(lockManager, subnetId.getValue());
449 PortOpDataEntry portOpEntry = subOpDpnManager.removePortOpDataEntry(portId.getValue());
450 if (portOpEntry == null) {
453 BigInteger dpnId = portOpEntry.getDpnId();
455 logger.debug("onPortRemovedFromSubnet: Port {} does not have a DPNId associated, ignoring", portId.getValue());
458 logger.debug("onPortRemovedFromSubnet: Updating the SubnetOpDataEntry node for subnet: " + subnetId.getValue());
459 boolean last = subOpDpnManager.removeInterfaceFromDpn(subnetId, dpnId, portId.getValue());
460 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
461 child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
462 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
464 if (!optionalSubs.isPresent()) {
465 logger.info("onPortRemovedFromSubnet: Port " + portId.getValue() + " is part of a subnet " + subnetId.getValue() +
466 " that is not in VPN, ignoring");
469 SubnetOpDataEntry subOpEntry = null;
470 List<SubnetToDpn> subDpnList = null;
471 SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
472 String rd = subOpBuilder.getVrfId();
473 String subnetIp = subOpBuilder.getSubnetCidr();
474 String vpnName = subOpBuilder.getVpnName();
475 Long elanTag = subOpBuilder.getElanTag();
476 BigInteger nhDpnId = subOpBuilder.getNhDpnId();
477 if ((nhDpnId != null) && (nhDpnId.equals(dpnId))) {
478 // select another NhDpnId
480 logger.debug("onPortRemovedFromSubnet: Last port " + portId + " on the subnet: " + subnetId.getValue());
481 // last port on this DPN, so we need to swap the NHDpnId
482 subDpnList = subOpBuilder.getSubnetToDpn();
483 if (subDpnList.isEmpty()) {
484 subOpBuilder.setNhDpnId(null);
486 // withdraw route from BGP
487 deleteSubnetRouteFromFib(rd, subnetIp, vpnName);
488 subOpBuilder.setRouteAdvState(TaskState.Na);
489 } catch (Exception ex) {
490 logger.error("onPortRemovedFromSubnet: Withdrawing NextHopDPN " + dpnId + " information for subnet " +
491 subnetId.getValue() + " from BGP failed ", ex);
492 subOpBuilder.setRouteAdvState(TaskState.Pending);
495 nhDpnId = subDpnList.get(0).getDpnId();
496 subOpBuilder.setNhDpnId(nhDpnId);
497 logger.debug("onInterfaceDown: Swapping the Designated DPN to " + nhDpnId + " for subnet " + subnetId.getValue());
499 // Best effort Withdrawal of route from BGP for this subnet
500 // Advertise the new NexthopIP to BGP for this subnet
501 //withdrawSubnetRoutefromBgp(rd, subnetIp);
502 int label = getLabel(rd, subnetIp);
504 logger.error("Unable to fetch label from Id Manager. Bailing out of handling removal of port {} from subnet {} in vpn {}", portId.getValue(), subnetIp, vpnName);
507 addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
508 subOpBuilder.setRouteAdvState(TaskState.Done);
509 } catch (Exception ex) {
510 logger.error("onPortRemovedFromSubnet: Swapping Withdrawing NextHopDPN " + dpnId +
511 " information for subnet " + subnetId.getValue() +
512 " to BGP failed {}" + ex);
513 subOpBuilder.setRouteAdvState(TaskState.Pending);
518 subOpEntry = subOpBuilder.build();
519 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
520 logger.info("onPortRemovedFromSubnet: Updated subnetopdataentry to OP Datastore removing port " + portId.getValue());
521 } catch (Exception ex) {
522 logger.error("Creation of SubnetOpDataEntry for subnet " +
523 subnetId.getValue() + " failed {}" + ex);
525 VpnUtil.unlockSubnet(lockManager, subnetId.getValue());
527 } catch (Exception e) {
528 logger.error("Unable to handle port {} removed from subnet {} {}", portId.getValue(), subnetId.getValue(), e);
532 public void onInterfaceUp(BigInteger dpnId, String intfName) {
533 logger.info("onInterfaceUp: Port " + intfName);
534 //TODO(vivek): Change this to use more granularized lock at subnetId level
535 SubnetToDpn subDpn = null;
536 PortOpDataEntry portOpEntry = subOpDpnManager.getPortOpDataEntry(intfName);
537 if (portOpEntry == null) {
538 logger.info("onInterfaceUp: Port " + intfName + "is part of a subnet not in VPN, ignoring");
541 if ((dpnId == null) || (dpnId == BigInteger.ZERO)) {
542 dpnId = portOpEntry.getDpnId();
544 logger.error("onInterfaceUp: Unable to determine the DPNID for port " + intfName);
548 Uuid subnetId = portOpEntry.getSubnetId();
550 VpnUtil.lockSubnet(lockManager, subnetId.getValue());
552 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
553 child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
554 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
556 if (!optionalSubs.isPresent()) {
557 logger.error("onInterfaceUp: SubnetOpDataEntry for subnet " + subnetId.getValue() +
558 " is not available");
562 SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
563 logger.debug("onInterfaceUp: Updating the SubnetOpDataEntry node for subnet: " + subnetId.getValue());
564 subOpDpnManager.addPortOpDataEntry(intfName, subnetId, dpnId);
565 subDpn = subOpDpnManager.addInterfaceToDpn(subnetId, dpnId, intfName);
566 if (subDpn == null) {
569 List<SubnetToDpn> subDpnList = subOpBuilder.getSubnetToDpn();
570 subDpnList.add(subDpn);
571 subOpBuilder.setSubnetToDpn(subDpnList);
572 if (subOpBuilder.getNhDpnId() == null) {
573 subOpBuilder.setNhDpnId(dpnId);
575 BigInteger nhDpnId = subOpBuilder.getNhDpnId();
576 String rd = subOpBuilder.getVrfId();
577 String subnetIp = subOpBuilder.getSubnetCidr();
578 String vpnName = subOpBuilder.getVpnName();
579 Long elanTag = subOpBuilder.getElanTag();
580 if ((subOpBuilder.getRouteAdvState() == TaskState.Pending) || (subOpBuilder.getRouteAdvState() == TaskState.Na)) {
582 // Write the Subnet Route Entry to FIB
583 // Advertise BGP Route here and set route_adv_state to DONE
584 int label = getLabel(rd, subnetIp);
586 logger.error("Unable to fetch label from Id Manager. Bailing out of handling interface up event for port {} for subnet {} in vpn {}", intfName, subnetIp, vpnName);
589 addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
590 subOpBuilder.setRouteAdvState(TaskState.Done);
591 } catch (Exception ex) {
592 logger.error("onInterfaceUp: Advertising NextHopDPN " + nhDpnId + " information for subnet " +
593 subnetId.getValue() + " to BGP failed {}" + ex);
596 SubnetOpDataEntry subOpEntry = subOpBuilder.build();
597 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
598 logger.info("onInterfaceUp: Updated subnetopdataentry to OP Datastore port up " + intfName);
599 } catch (Exception ex) {
600 logger.error("Creation of SubnetOpDataEntry for subnet " +
601 subnetId.getValue() + " failed {}" + ex);
603 VpnUtil.unlockSubnet(lockManager, subnetId.getValue());
605 } catch (Exception e) {
606 logger.error("Unable to handle interface up event for port {} in subnet {} {}", portOpEntry.getPortId(), subnetId.getValue(), e);
610 public void onInterfaceDown(final BigInteger dpnId, final String interfaceName) {
611 logger.info("onInterfaceDown: Port " + interfaceName);
612 //TODO(vivek): Change this to use more granularized lock at subnetId level
613 PortOpDataEntry portOpEntry = subOpDpnManager.getPortOpDataEntry(interfaceName);
614 if (portOpEntry == null) {
615 logger.info("onInterfaceDown: Port " + interfaceName + "is part of a subnet not in VPN, ignoring");
618 if ((dpnId == null) ||(dpnId == BigInteger.ZERO)) {
619 logger.error("onInterfaceDown: Unable to determine the DPNID for port " + interfaceName);
622 Uuid subnetId = portOpEntry.getSubnetId();
624 VpnUtil.lockSubnet(lockManager, subnetId.getValue());
626 logger.debug("onInterfaceDown: Updating the SubnetOpDataEntry node for subnet: " + subnetId.getValue());
627 boolean last = subOpDpnManager.removeInterfaceFromDpn(subnetId, dpnId, interfaceName);
628 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
629 child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
630 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(dataBroker,
631 LogicalDatastoreType.OPERATIONAL,
633 if (!optionalSubs.isPresent()) {
634 logger.error("onInterfaceDown: SubnetOpDataEntry for subnet " + subnetId.getValue() +
635 " is not available");
638 SubnetOpDataEntry subOpEntry = null;
639 List<SubnetToDpn> subDpnList = null;
640 SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
641 String rd = subOpBuilder.getVrfId();
642 String subnetIp = subOpBuilder.getSubnetCidr();
643 String vpnName = subOpBuilder.getVpnName();
644 Long elanTag = subOpBuilder.getElanTag();
645 BigInteger nhDpnId = subOpBuilder.getNhDpnId();
646 if ((nhDpnId != null) && (nhDpnId.equals(dpnId))) {
647 // select another NhDpnId
649 logger.debug("onInterfaceDown: Last active port " + interfaceName + " on the subnet: " + subnetId.getValue());
650 // last port on this DPN, so we need to swap the NHDpnId
651 subDpnList = subOpBuilder.getSubnetToDpn();
652 if (subDpnList.isEmpty()) {
653 subOpBuilder.setNhDpnId(null);
655 // Withdraw route from BGP for this subnet
656 deleteSubnetRouteFromFib(rd, subnetIp, vpnName);
657 subOpBuilder.setRouteAdvState(TaskState.Na);
658 } catch (Exception ex) {
659 logger.error("onInterfaceDown: Withdrawing NextHopDPN " + dpnId + " information for subnet " +
660 subnetId.getValue() + " from BGP failed {}" + ex);
661 subOpBuilder.setRouteAdvState(TaskState.Pending);
664 nhDpnId = subDpnList.get(0).getDpnId();
665 subOpBuilder.setNhDpnId(nhDpnId);
666 logger.debug("onInterfaceDown: Swapping the Designated DPN to " + nhDpnId + " for subnet " + subnetId.getValue());
668 // Best effort Withdrawal of route from BGP for this subnet
669 //withdrawSubnetRoutefromBgp(rd, subnetIp);
670 int label = getLabel(rd, subnetIp);
672 logger.error("Unable to fetch label from Id Manager. Bailing out of handling interface down event for port {} in subnet {} for vpn {}", interfaceName, subnetIp, vpnName);
675 addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
676 subOpBuilder.setRouteAdvState(TaskState.Done);
677 } catch (Exception ex) {
678 logger.error("onInterfaceDown: Swapping Withdrawing NextHopDPN " + dpnId + " information for subnet " +
679 subnetId.getValue() + " to BGP failed {}" + ex);
680 subOpBuilder.setRouteAdvState(TaskState.Pending);
685 subOpEntry = subOpBuilder.build();
686 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
687 logger.info("onInterfaceDown: Updated subnetopdataentry to OP Datastore port down " + interfaceName);
688 } catch (Exception ex) {
689 logger.error("Creation of SubnetOpDataEntry for subnet " +
690 subnetId.getValue() + " failed {}" + ex);
692 VpnUtil.unlockSubnet(lockManager, subnetId.getValue());
694 } catch (Exception e) {
695 logger.error("Unable to handle interface down event for port {} in subnet {} {}", portOpEntry.getPortId(), subnetId.getValue(), e);
700 public void onRouterAssociatedToVpn(RouterAssociatedToVpn notification) {
704 public void onRouterDisassociatedFromVpn(RouterDisassociatedFromVpn notification) {
707 private void addSubnetRouteToFib(String rd, String subnetIp, BigInteger nhDpnId, String vpnName,
708 Long elanTag, int label, Uuid subnetId) throws Exception {
709 Preconditions.checkNotNull(rd, "RouteDistinguisher cannot be null or empty!");
710 Preconditions.checkNotNull(subnetIp, "SubnetRouteIp cannot be null or empty!");
711 Preconditions.checkNotNull(vpnName, "vpnName cannot be null or empty!");
712 Preconditions.checkNotNull(elanTag, "elanTag cannot be null or empty!");
713 String nexthopIp = null;
715 nexthopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, nhDpnId);
716 } catch (Exception e) {
717 logger.warn("Unable to find nexthopip for subnetroute subnetip {}", subnetIp);
720 if (nexthopIp != null) {
721 VpnUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, VpnUtil.getPrefixToInterfaceIdentifier(VpnUtil.getVpnId(dataBroker, vpnName), subnetIp), VpnUtil.getPrefixToInterface(nhDpnId, subnetId.getValue(), subnetIp));
722 vpnInterfaceManager.addSubnetRouteFibEntryToDS(rd, vpnName, subnetIp, nexthopIp, label, elanTag, nhDpnId, null);
724 // BGPManager (inside ODL) requires a withdraw followed by advertise
725 // due to bugs with ClusterDataChangeListener used by BGPManager.
726 //bgpManager.withdrawPrefix(rd, subnetIp);
727 bgpManager.advertisePrefix(rd, subnetIp, Arrays.asList(nexthopIp), label);
728 } catch (Exception e) {
729 logger.error("Fail: Subnet route not advertised for rd {} subnetIp {}", rd, subnetIp, e);
733 logger.warn("The nexthopip is empty for subnetroute subnetip {}, ignoring fib route addition", subnetIp);
737 private int getLabel(String rd, String subnetIp) {
738 int label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
739 VpnUtil.getNextHopLabelKey(rd, subnetIp));
740 logger.trace("Allocated subnetroute label {} for rd {} prefix {}", label, rd, subnetIp);
744 private void deleteSubnetRouteFromFib(String rd, String subnetIp, String vpnName) throws Exception {
745 Preconditions.checkNotNull(rd, "RouteDistinguisher cannot be null or empty!");
746 Preconditions.checkNotNull(subnetIp, "SubnetRouteIp cannot be null or empty!");
747 vpnInterfaceManager.deleteSubnetRouteFibEntryFromDS(rd, subnetIp, vpnName);
749 bgpManager.withdrawPrefix(rd, subnetIp);
750 } catch (Exception e) {
751 logger.error("Fail: Subnet route not withdrawn for rd {} subnetIp {}", rd, subnetIp, e);