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 java.util.ArrayList;
11 import java.util.List;
13 import java.util.HashMap;
15 import com.google.common.base.Preconditions;
17 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
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.vpnmanager.utilities.InterfaceUtils;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.*;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntry;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntryKey;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.rd.to.elan.op.RdToElanOpEntry;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.rd.to.elan.op.RdToElanOpEntryBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.rd.to.elan.op.RdToElanOpEntryKey;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntry;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntryKey;
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.neutronvpn.rev150602.*;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.subnet.op.data.entry.SubnetToDpn;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.subnet.op.data.entry.subnet.to.dpn.VpnInterfaces;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
41 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
43 import java.math.BigInteger;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
48 import com.google.common.base.Optional;
51 public class VpnSubnetRouteHandler implements NeutronvpnListener {
52 private static final Logger logger = LoggerFactory.getLogger(VpnSubnetRouteHandler.class);
54 private final DataBroker broker;
55 private SubnetOpDpnManager subOpDpnManager;
56 private final IBgpManager bgpManager;
57 private IdManagerService idManager;
58 private VpnInterfaceManager vpnInterfaceManager;
60 public VpnSubnetRouteHandler(final DataBroker db, IBgpManager bgpManager, VpnInterfaceManager vpnIntfManager) {
62 subOpDpnManager = new SubnetOpDpnManager(broker);
63 this.bgpManager = bgpManager;
64 this.vpnInterfaceManager = vpnIntfManager;
67 public void setIdManager(IdManagerService idManager) {
68 this.idManager = idManager;
72 public void onSubnetAddedToVpn(SubnetAddedToVpn notification) {
73 if (!notification.isExternalVpn()) {
77 Uuid subnetId = notification.getSubnetId();
78 String vpnName = notification.getVpnName();
79 String subnetIp = notification.getSubnetIp();
80 Long elanTag = notification.getElanTag();
82 Preconditions.checkNotNull(subnetId, "SubnetId cannot be null or empty!");
83 Preconditions.checkNotNull(subnetIp, "SubnetPrefix cannot be null or empty!");
84 Preconditions.checkNotNull(vpnName, "VpnName cannot be null or empty!");
85 Preconditions.checkNotNull(elanTag, "ElanTag cannot be null or empty!");
87 logger.info("onSubnetAddedToVpn: Subnet" + subnetId.getValue() + " being added to vpn");
88 //TODO(vivek): Change this to use more granularized lock at subnetId level
91 //Create and add SubnetOpDataEntry object for this subnet to the SubnetOpData container
92 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
93 child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
94 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(broker,
95 LogicalDatastoreType.OPERATIONAL,
97 if (optionalSubs.isPresent()) {
98 logger.error("onSubnetAddedToVpn: SubnetOpDataEntry for subnet " + subnetId.getValue() +
99 " already detected to be present");
102 logger.debug("onSubnetAddedToVpn: Creating new SubnetOpDataEntry node for subnet: " + subnetId.getValue());
103 Map<BigInteger, SubnetToDpn> subDpnMap = new HashMap<>();
104 SubnetOpDataEntry subOpEntry = null;
105 BigInteger dpnId = null;
106 BigInteger nhDpnId = null;
107 SubnetToDpn subDpn = null;
109 SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder().setKey(new SubnetOpDataEntryKey(subnetId));
110 subOpBuilder.setSubnetId(subnetId);
111 subOpBuilder.setSubnetCidr(subnetIp);
112 String rd = VpnUtil.getVpnRdFromVpnInstanceConfig(broker, vpnName);
114 logger.error("onSubnetAddedToVpn: The VPN Instance name " + notification.getVpnName() + " does not have RD ");
117 subOpBuilder.setVrfId(rd);
118 subOpBuilder.setVpnName(vpnName);
119 subOpBuilder.setSubnetToDpn(new ArrayList<>());
120 subOpBuilder.setRouteAdvState(TaskState.Na);
121 subOpBuilder.setElanTag(elanTag);
123 // First recover set of ports available in this subnet
124 InstanceIdentifier<Subnetmap> subMapid = InstanceIdentifier.builder(Subnetmaps.class).
125 child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
126 Optional<Subnetmap> sm = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, subMapid);
127 if (!sm.isPresent()) {
128 logger.error("onSubnetAddedToVpn: Unable to retrieve subnetmap entry for subnet : " + subnetId);
131 Subnetmap subMap = sm.get();
132 List<Uuid> portList = subMap.getPortList();
133 if (portList != null) {
134 for (Uuid port: portList) {
135 Interface intfState = InterfaceUtils.getInterfaceStateFromOperDS(broker,port.getValue());
136 if (intfState != null) {
137 dpnId = InterfaceUtils.getDpIdFromInterface(intfState);
139 logger.info("onSubnetAddedToVpn: Port " + port.getValue() + " is not assigned DPN yet, ignoring ");
142 subOpDpnManager.addPortOpDataEntry(port.getValue(), subnetId, dpnId);
143 if (intfState.getOperStatus() != OperStatus.Up) {
144 logger.info("onSubnetAddedToVpn: Port " + port.getValue() + " is not UP yet, ignoring ");
147 subDpn = subOpDpnManager.addInterfaceToDpn(subnetId, dpnId, port.getValue());
148 if (intfState.getOperStatus() == OperStatus.Up) {
150 subDpnMap.put(dpnId, subDpn);
151 if (nhDpnId == null) {
156 subOpDpnManager.addPortOpDataEntry(port.getValue(), subnetId, null);
159 if (subDpnMap.size() > 0) {
160 subOpBuilder.setSubnetToDpn(new ArrayList<>(subDpnMap.values()));
164 if (nhDpnId != null) {
165 subOpBuilder.setNhDpnId(nhDpnId);
168 Write the subnet route entry to the FIB.
169 And also advertise the subnet route entry via BGP.
171 int label = getLabel(rd, subnetIp);
172 addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label);
173 advertiseSubnetRouteToBgp(rd, subnetIp, nhDpnId, vpnName, elanTag, label);
174 subOpBuilder.setRouteAdvState(TaskState.Done);
175 } catch (Exception ex) {
176 logger.error("onSubnetAddedToVpn: FIB rules and Advertising nhDpnId " + nhDpnId +
177 " information for subnet " + subnetId.getValue() + " to BGP failed {}", ex);
178 subOpBuilder.setRouteAdvState(TaskState.Pending);
183 Write the subnet route entry to the FIB.
184 NOTE: Will not advertise to BGP as NextHopDPN is not available yet.
186 int label = getLabel(rd, subnetIp);
187 addSubnetRouteToFib(rd, subnetIp, null, vpnName, elanTag, label);
188 } catch (Exception ex) {
189 logger.error("onSubnetAddedToVpn: FIB rules writing for subnet {} with exception {} " +
190 subnetId.getValue(), ex);
191 subOpBuilder.setRouteAdvState(TaskState.Pending);
195 subOpEntry = subOpBuilder.build();
196 MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
197 logger.info("onSubnetAddedToVpn: Added subnetopdataentry to OP Datastore for subnet " + subnetId.getValue());
198 } catch (Exception ex) {
199 logger.error("Creation of SubnetOpDataEntry for subnet " +
200 subnetId.getValue() + " failed {}", ex);
207 public void onSubnetDeletedFromVpn(SubnetDeletedFromVpn notification) {
208 Uuid subnetId = notification.getSubnetId();
210 if (!notification.isExternalVpn()) {
213 logger.info("onSubnetDeletedFromVpn: Subnet" + subnetId.getValue() + " being removed to vpn");
214 //TODO(vivek): Change this to use more granularized lock at subnetId level
215 synchronized (this) {
217 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
218 child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
219 logger.trace(" Removing the SubnetOpDataEntry node for subnet: " + subnetId.getValue());
220 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(broker,
221 LogicalDatastoreType.OPERATIONAL,
223 if (!optionalSubs.isPresent()) {
224 logger.error("onSubnetDeletedFromVpn: SubnetOpDataEntry for subnet " + subnetId.getValue() +
225 " not available in datastore");
228 SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
229 List<SubnetToDpn> subDpnList = subOpBuilder.getSubnetToDpn();
230 for (SubnetToDpn subDpn: subDpnList) {
231 List<VpnInterfaces> vpnIntfList = subDpn.getVpnInterfaces();
232 for (VpnInterfaces vpnIntf: vpnIntfList) {
233 subOpDpnManager.removePortOpDataEntry(vpnIntf.getInterfaceName());
236 //Removing Stale Ports in portOpData
237 InstanceIdentifier<Subnetmap> subMapid = InstanceIdentifier.builder(Subnetmaps.class).
238 child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
239 Optional<Subnetmap> sm = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, subMapid);
240 if (!sm.isPresent()) {
241 logger.error("Stale ports removal: Unable to retrieve subnetmap entry for subnet : " + subnetId);
243 Subnetmap subMap = sm.get();
244 List<Uuid> portList = subMap.getPortList();
246 InstanceIdentifier<PortOpData> portOpIdentifier = InstanceIdentifier.builder(PortOpData.class).build();
247 Optional<PortOpData> optionalPortOp = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, portOpIdentifier);
248 if(!optionalPortOp.isPresent()){
249 logger.error("Stale ports removal: Cannot delete port. Not available in data store");
252 PortOpData portOpData = optionalPortOp.get();
253 List<PortOpDataEntry> portOpDataList = portOpData.getPortOpDataEntry();
254 if(portOpDataList!=null){
255 for(PortOpDataEntry portOpDataListEntry : portOpDataList){
256 if(portList.contains(new Uuid(portOpDataListEntry.getPortId()))){
257 logger.trace("Removing stale port: " + portOpDataListEntry + "for dissociated subnetId: " + subnetId);
258 MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, portOpIdentifier.
259 child(PortOpDataEntry.class, new PortOpDataEntryKey(portOpDataListEntry.getKey())));
266 String rd = subOpBuilder.getVrfId();
267 String subnetIp = subOpBuilder.getSubnetCidr();
268 BigInteger nhDpnId = subOpBuilder.getNhDpnId();
269 MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier);
270 logger.trace("Removed subnetopdataentry successfully to CONFIG Datastore");
272 //Withdraw the routes for all the interfaces on this subnet
273 //Remove subnet route entry from FIB
274 deleteSubnetRouteFromFib(rd, subnetIp);
275 withdrawSubnetRoutefromBgp(rd, subnetIp);
276 } catch (Exception ex) {
277 logger.error("onSubnetAddedToVpn: Withdrawing routes from BGP for subnet " +
278 subnetId.getValue() + " failed {}" + ex);
280 } catch (Exception ex) {
281 logger.error("Removal of SubnetOpDataEntry for subnet " +
282 subnetId.getValue() + " failed {}" + ex);
289 public void onSubnetUpdatedInVpn(SubnetUpdatedInVpn notification) {
290 Uuid subnetId = notification.getSubnetId();
291 String vpnName = notification.getVpnName();
292 String subnetIp = notification.getSubnetIp();
293 Long elanTag = notification.getElanTag();
295 Preconditions.checkNotNull(subnetId, "SubnetId cannot be null or empty!");
296 Preconditions.checkNotNull(subnetIp, "SubnetPrefix cannot be null or empty!");
297 Preconditions.checkNotNull(vpnName, "VpnName cannot be null or empty!");
298 Preconditions.checkNotNull(elanTag, "ElanTag cannot be null or empty!");
300 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
301 child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
302 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(broker,
303 LogicalDatastoreType.OPERATIONAL,
305 if (optionalSubs.isPresent()) {
306 if (!notification.isExternalVpn()) {
307 SubnetDeletedFromVpnBuilder bldr = new SubnetDeletedFromVpnBuilder().setVpnName(vpnName);
308 bldr.setElanTag(elanTag).setExternalVpn(true).setSubnetIp(subnetIp).setSubnetId(subnetId);
309 onSubnetDeletedFromVpn(bldr.build());
311 // TODO(vivek): Something got updated, but we donot know what ?
313 if (notification.isExternalVpn()) {
314 SubnetAddedToVpnBuilder bldr = new SubnetAddedToVpnBuilder().setVpnName(vpnName).setElanTag(elanTag);
315 bldr.setSubnetIp(subnetIp).setSubnetId(subnetId).setExternalVpn(true);
316 onSubnetAddedToVpn(bldr.build());
318 // TODO(vivek): Something got updated, but we donot know what ?
323 public void onPortAddedToSubnet(PortAddedToSubnet notification) {
324 Uuid subnetId = notification.getSubnetId();
325 Uuid portId = notification.getPortId();
327 logger.info("onPortAddedToSubnet: Port " + portId.getValue() + " being added to subnet " + subnetId.getValue());
328 //TODO(vivek): Change this to use more granularized lock at subnetId level
329 synchronized (this) {
331 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
332 child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
334 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
336 if (!optionalSubs.isPresent()) {
337 logger.info("onPortAddedToSubnet: Port " + portId.getValue() + " is part of a subnet " + subnetId.getValue() +
338 " that is not in VPN, ignoring");
341 Interface intfState = InterfaceUtils.getInterfaceStateFromOperDS(broker,portId.getValue());
342 if (intfState == null) {
343 // Interface State not yet available
344 subOpDpnManager.addPortOpDataEntry(portId.getValue(), subnetId, null);
347 BigInteger dpnId = InterfaceUtils.getDpIdFromInterface(intfState);
349 logger.info("onPortAddedToSubnet: Port " + portId.getValue() + " is not assigned DPN yet, ignoring ");
352 subOpDpnManager.addPortOpDataEntry(portId.getValue(), subnetId, dpnId);
353 if (intfState.getOperStatus() != OperStatus.Up) {
354 logger.info("onPortAddedToSubnet: Port " + portId.getValue() + " is not UP yet, ignoring ");
357 logger.debug("onPortAddedToSubnet: Updating the SubnetOpDataEntry node for subnet: " + subnetId.getValue());
358 SubnetToDpn subDpn = subOpDpnManager.addInterfaceToDpn(subnetId, dpnId, portId.getValue());
359 if (subDpn == null) {
362 SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
363 List<SubnetToDpn> subDpnList = subOpBuilder.getSubnetToDpn();
364 subDpnList.add(subDpn);
365 subOpBuilder.setSubnetToDpn(subDpnList);
366 if (subOpBuilder.getNhDpnId() == null) {
367 subOpBuilder.setNhDpnId(dpnId);
369 BigInteger nhDpnId = subOpBuilder.getNhDpnId();
370 String rd = subOpBuilder.getVrfId();
371 String subnetIp = subOpBuilder.getSubnetCidr();
372 String vpnName = subOpBuilder.getVpnName();
373 Long elanTag = subOpBuilder.getElanTag();
374 if ((subOpBuilder.getRouteAdvState() == TaskState.Pending) ||
375 (subOpBuilder.getRouteAdvState() == TaskState.Na)) {
377 // Write the Subnet Route Entry to FIB
378 // Advertise BGP Route here and set route_adv_state to DONE
380 VrfEntry vrf = VpnUtil.getVrfEntry(broker, rd, subnetIp);
382 label = (vrf.getLabel()).intValue();
384 label = getLabel(rd, subnetIp);
386 addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label);
387 advertiseSubnetRouteToBgp(rd, subnetIp, nhDpnId, vpnName, elanTag, label);
388 subOpBuilder.setRouteAdvState(TaskState.Done);
389 } catch (Exception ex) {
390 logger.error("onPortAddedToSubnet: Advertising NextHopDPN "+ nhDpnId +
391 " information for subnet " + subnetId.getValue() + " to BGP failed {}", ex);
394 SubnetOpDataEntry subOpEntry = subOpBuilder.build();
395 MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
396 logger.info("onPortAddedToSubnet: Updated subnetopdataentry to OP Datastore for port " + portId.getValue());
398 } catch (Exception ex) {
399 logger.error("Creation of SubnetOpDataEntry for subnet " +
400 subnetId.getValue() + " failed {}", ex);
407 public void onPortRemovedFromSubnet(PortRemovedFromSubnet notification) {
408 Uuid subnetId = notification.getSubnetId();
409 Uuid portId = notification.getPortId();
411 logger.info("onPortRemovedFromSubnet: Port " + portId.getValue() + " being removed from subnet " + subnetId.getValue());
412 //TODO(vivek): Change this to use more granularized lock at subnetId level
413 synchronized (this) {
415 PortOpDataEntry portOpEntry = subOpDpnManager.removePortOpDataEntry(portId.getValue());
416 if (portOpEntry == null) {
419 BigInteger dpnId = portOpEntry.getDpnId();
421 logger.debug("onPortRemovedFromSubnet: Port {} does not have a DPNId associated, ignoring", portId.getValue());
424 logger.debug("onPortRemovedFromSubnet: Updating the SubnetOpDataEntry node for subnet: " + subnetId.getValue());
425 boolean last = subOpDpnManager.removeInterfaceFromDpn(subnetId, dpnId, portId.getValue());
426 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
427 child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
428 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
430 if (!optionalSubs.isPresent()) {
431 logger.info("onPortRemovedFromSubnet: Port " + portId.getValue() + " is part of a subnet " + subnetId.getValue() +
432 " that is not in VPN, ignoring");
435 SubnetOpDataEntry subOpEntry = null;
436 List<SubnetToDpn> subDpnList = null;
437 SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
438 String rd = subOpBuilder.getVrfId();
439 String subnetIp = subOpBuilder.getSubnetCidr();
440 String vpnName = subOpBuilder.getVpnName();
441 Long elanTag = subOpBuilder.getElanTag();
442 BigInteger nhDpnId = subOpBuilder.getNhDpnId();
443 if ((nhDpnId != null) && (nhDpnId.equals(dpnId))) {
444 // select another NhDpnId
446 logger.debug("onPortRemovedFromSubnet: Last port " + portId + " on the subnet: " + subnetId.getValue());
447 // last port on this DPN, so we need to swap the NHDpnId
448 subDpnList = subOpBuilder.getSubnetToDpn();
449 if (subDpnList.isEmpty()) {
450 subOpBuilder.setNhDpnId(null);
452 // withdraw route from BGP
453 deleteSubnetRouteFromFib(rd, subnetIp);
454 withdrawSubnetRoutefromBgp(rd, subnetIp);
455 subOpBuilder.setRouteAdvState(TaskState.Na);
456 } catch (Exception ex) {
457 logger.error("onPortRemovedFromSubnet: Withdrawing NextHopDPN " + dpnId + " information for subnet " +
458 subnetId.getValue() + " from BGP failed ", ex);
459 subOpBuilder.setRouteAdvState(TaskState.Pending);
462 nhDpnId = subDpnList.get(0).getDpnId();
463 subOpBuilder.setNhDpnId(nhDpnId);
464 logger.debug("onInterfaceDown: Swapping the Designated DPN to " + nhDpnId + " for subnet " + subnetId.getValue());
466 // Best effort Withdrawal of route from BGP for this subnet
467 // Advertise the new NexthopIP to BGP for this subnet
468 //withdrawSubnetRoutefromBgp(rd, subnetIp);
470 VrfEntry vrf = VpnUtil.getVrfEntry(broker, rd, subnetIp);
472 label = (vrf.getLabel()).intValue();
474 label = getLabel(rd, subnetIp);
476 addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label);
477 advertiseSubnetRouteToBgp(rd, subnetIp, nhDpnId, vpnName, elanTag, label);
478 subOpBuilder.setRouteAdvState(TaskState.Done);
479 } catch (Exception ex) {
480 logger.error("onPortRemovedFromSubnet: Swapping Withdrawing NextHopDPN " + dpnId +
481 " information for subnet " + subnetId.getValue() +
482 " to BGP failed {}" + ex);
483 subOpBuilder.setRouteAdvState(TaskState.Pending);
488 subOpEntry = subOpBuilder.build();
489 MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
490 logger.info("onPortRemovedFromSubnet: Updated subnetopdataentry to OP Datastore removing port " + portId.getValue());
491 } catch (Exception ex) {
492 logger.error("Creation of SubnetOpDataEntry for subnet " +
493 subnetId.getValue() + " failed {}" + ex);
499 public void onInterfaceUp(Interface intfState) {
501 logger.info("onInterfaceUp: Port " + intfState.getName());
502 //TODO(vivek): Change this to use more granularized lock at subnetId level
503 synchronized (this) {
504 SubnetToDpn subDpn = null;
505 String intfName = intfState.getName();
506 PortOpDataEntry portOpEntry = subOpDpnManager.getPortOpDataEntry(intfName);
507 if (portOpEntry == null) {
508 logger.info("onInterfaceUp: Port " + intfState.getName() + "is part of a subnet not in VPN, ignoring");
511 BigInteger dpnId = portOpEntry.getDpnId();
513 dpnId = InterfaceUtils.getDpIdFromInterface(intfState);
515 logger.error("onInterfaceUp: Unable to determine the DPNID for port " + intfName);
519 Uuid subnetId = portOpEntry.getSubnetId();
521 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
522 child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
523 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
525 if (!optionalSubs.isPresent()) {
526 logger.error("onInterfaceUp: SubnetOpDataEntry for subnet " + subnetId.getValue() +
527 " is not available");
531 SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
532 logger.debug("onInterfaceUp: Updating the SubnetOpDataEntry node for subnet: " + subnetId.getValue());
533 subOpDpnManager.addPortOpDataEntry(intfName, subnetId, dpnId);
534 subDpn = subOpDpnManager.addInterfaceToDpn(subnetId, dpnId, intfName);
535 if (subDpn == null) {
538 List<SubnetToDpn> subDpnList = subOpBuilder.getSubnetToDpn();
539 subDpnList.add(subDpn);
540 subOpBuilder.setSubnetToDpn(subDpnList);
541 if (subOpBuilder.getNhDpnId() == null) {
542 subOpBuilder.setNhDpnId(dpnId);
544 BigInteger nhDpnId = subOpBuilder.getNhDpnId();
545 String rd = subOpBuilder.getVrfId();
546 String subnetIp = subOpBuilder.getSubnetCidr();
547 String vpnName = subOpBuilder.getVpnName();
548 Long elanTag = subOpBuilder.getElanTag();
549 if ((subOpBuilder.getRouteAdvState() == TaskState.Pending) || (subOpBuilder.getRouteAdvState() == TaskState.Na)) {
551 // Write the Subnet Route Entry to FIB
552 // Advertise BGP Route here and set route_adv_state to DONE
554 VrfEntry vrf = VpnUtil.getVrfEntry(broker, rd, subnetIp);
556 label = (vrf.getLabel()).intValue();
558 label = getLabel(rd, subnetIp);
560 addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label);
561 advertiseSubnetRouteToBgp(rd, subnetIp, nhDpnId, vpnName, elanTag, label);
562 subOpBuilder.setRouteAdvState(TaskState.Done);
563 } catch (Exception ex) {
564 logger.error("onInterfaceUp: Advertising NextHopDPN " + nhDpnId + " information for subnet " +
565 subnetId.getValue() + " to BGP failed {}" + ex);
568 SubnetOpDataEntry subOpEntry = subOpBuilder.build();
569 MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
570 logger.info("onInterfaceUp: Updated subnetopdataentry to OP Datastore port up " + intfName);
571 } catch (Exception ex) {
572 logger.error("Creation of SubnetOpDataEntry for subnet " +
573 subnetId.getValue() + " failed {}" + ex);
579 public void onInterfaceDown(Interface intfState) {
580 logger.info("onInterfaceDown: Port " + intfState.getName());
581 //TODO(vivek): Change this to use more granularized lock at subnetId level
582 synchronized (this) {
583 String intfName = intfState.getName();
584 PortOpDataEntry portOpEntry = subOpDpnManager.getPortOpDataEntry(intfName);
585 if (portOpEntry == null) {
586 logger.info("onInterfaceDown: Port " + intfState.getName() + "is part of a subnet not in VPN, ignoring");
589 BigInteger dpnId = portOpEntry.getDpnId();
591 dpnId = InterfaceUtils.getDpIdFromInterface(intfState);
593 logger.error("onInterfaceDown: Unable to determine the DPNID for port " + intfName);
597 Uuid subnetId = portOpEntry.getSubnetId();
599 logger.debug("onInterfaceDown: Updating the SubnetOpDataEntry node for subnet: " + subnetId.getValue());
600 boolean last = subOpDpnManager.removeInterfaceFromDpn(subnetId, dpnId, intfName);
601 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).
602 child(SubnetOpDataEntry.class, new SubnetOpDataEntryKey(subnetId)).build();
603 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(broker,
604 LogicalDatastoreType.OPERATIONAL,
606 if (!optionalSubs.isPresent()) {
607 logger.error("onInterfaceDown: SubnetOpDataEntry for subnet " + subnetId.getValue() +
608 " is not available");
611 SubnetOpDataEntry subOpEntry = null;
612 List<SubnetToDpn> subDpnList = null;
613 SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
614 String rd = subOpBuilder.getVrfId();
615 String subnetIp = subOpBuilder.getSubnetCidr();
616 String vpnName = subOpBuilder.getVpnName();
617 Long elanTag = subOpBuilder.getElanTag();
618 BigInteger nhDpnId = subOpBuilder.getNhDpnId();
619 if ((nhDpnId != null) && (nhDpnId.equals(dpnId))) {
620 // select another NhDpnId
622 logger.debug("onInterfaceDown: Last active port " + intfState.getName() + " on the subnet: " + subnetId.getValue());
623 // last port on this DPN, so we need to swap the NHDpnId
624 subDpnList = subOpBuilder.getSubnetToDpn();
625 if (subDpnList.isEmpty()) {
626 subOpBuilder.setNhDpnId(null);
628 // Withdraw route from BGP for this subnet
629 deleteSubnetRouteFromFib(rd, subnetIp);
630 withdrawSubnetRoutefromBgp(rd, subnetIp);
631 subOpBuilder.setRouteAdvState(TaskState.Na);
632 } catch (Exception ex) {
633 logger.error("onInterfaceDown: Withdrawing NextHopDPN " + dpnId + " information for subnet " +
634 subnetId.getValue() + " from BGP failed {}" + ex);
635 subOpBuilder.setRouteAdvState(TaskState.Pending);
638 nhDpnId = subDpnList.get(0).getDpnId();
639 subOpBuilder.setNhDpnId(nhDpnId);
640 logger.debug("onInterfaceDown: Swapping the Designated DPN to " + nhDpnId + " for subnet " + subnetId.getValue());
642 // Best effort Withdrawal of route from BGP for this subnet
643 //withdrawSubnetRoutefromBgp(rd, subnetIp);
645 VrfEntry vrf = VpnUtil.getVrfEntry(broker, rd, subnetIp);
647 label = (vrf.getLabel()).intValue();
649 label = getLabel(rd, subnetIp);
651 addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label);
652 advertiseSubnetRouteToBgp(rd, subnetIp, nhDpnId, vpnName, elanTag, label);
653 subOpBuilder.setRouteAdvState(TaskState.Done);
654 } catch (Exception ex) {
655 logger.error("onInterfaceDown: Swapping Withdrawing NextHopDPN " + dpnId + " information for subnet " +
656 subnetId.getValue() + " to BGP failed {}" + ex);
657 subOpBuilder.setRouteAdvState(TaskState.Pending);
662 subOpEntry = subOpBuilder.build();
663 MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
664 logger.info("onInterfaceDown: Updated subnetopdataentry to OP Datastore port down " + intfName);
665 } catch (Exception ex) {
666 logger.error("Creation of SubnetOpDataEntry for subnet " +
667 subnetId.getValue() + " failed {}" + ex);
673 private void addSubnetRouteToFib(String rd, String subnetIp, BigInteger nhDpnId, String vpnName,
674 Long elanTag, int label) {
675 Preconditions.checkNotNull(rd, "RouteDistinguisher cannot be null or empty!");
676 Preconditions.checkNotNull(subnetIp, "SubnetRouteIp cannot be null or empty!");
677 Preconditions.checkNotNull(vpnName, "vpnName cannot be null or empty!");
678 Preconditions.checkNotNull(elanTag, "elanTag cannot be null or empty!");
679 String nexthopIp = null;
680 if (nhDpnId != null) {
681 nexthopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, nhDpnId);
683 vpnInterfaceManager.addSubnetRouteFibEntryToDS(rd, subnetIp, nexthopIp, label, elanTag);
686 private int getLabel(String rd, String subnetIp) {
687 int label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
688 VpnUtil.getNextHopLabelKey(rd, subnetIp));
689 logger.trace("Allocated subnetroute label {} for rd {} prefix {}", label, rd, subnetIp);
693 private void deleteSubnetRouteFromFib(String rd, String subnetIp) {
694 Preconditions.checkNotNull(rd, "RouteDistinguisher cannot be null or empty!");
695 Preconditions.checkNotNull(subnetIp, "SubnetRouteIp cannot be null or empty!");
696 vpnInterfaceManager.removeFibEntryFromDS(rd, subnetIp);
699 private void advertiseSubnetRouteToBgp(String rd, String subnetIp, BigInteger nhDpnId, String vpnName,
700 Long elanTag, int label) throws Exception {
701 Preconditions.checkNotNull(rd, "RouteDistinguisher cannot be null or empty!");
702 Preconditions.checkNotNull(subnetIp, "SubnetRouteIp cannot be null or empty!");
703 Preconditions.checkNotNull(elanTag, "elanTag cannot be null or empty!");
704 Preconditions.checkNotNull(nhDpnId, "nhDpnId cannot be null or empty!");
705 Preconditions.checkNotNull(vpnName, "vpnName cannot be null or empty!");
706 String nexthopIp = null;
707 nexthopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, nhDpnId);
708 if (nexthopIp == null) {
709 logger.error("createSubnetRouteInVpn: Unable to obtain endpointIp address for DPNId " + nhDpnId);
710 throw new Exception("Unable to obtain endpointIp address for DPNId " + nhDpnId);
713 bgpManager.advertisePrefix(rd, subnetIp, nexthopIp, label);
714 } catch (Exception e) {
715 logger.error("Subnet route not advertised for rd " + rd + " failed ", e);
720 private void withdrawSubnetRoutefromBgp(String rd, String subnetIp) throws Exception {
721 Preconditions.checkNotNull(rd, "RouteDistinguisher cannot be null or empty!");
722 Preconditions.checkNotNull(subnetIp, "SubnetIp cannot be null or empty!");
724 bgpManager.withdrawPrefix(rd, subnetIp);
725 } catch (Exception e) {
726 logger.error("Subnet route not advertised for rd " + rd + " failed ", e);
732 public void onRouterAssociatedToVpn(RouterAssociatedToVpn notification) {
736 public void onRouterDisassociatedFromVpn(RouterDisassociatedFromVpn notification) {