2 * Copyright (c) 2015, 2017 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.util.concurrent.ListenableFuture;
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.Optional;
14 import java.util.concurrent.ExecutionException;
15 import javax.annotation.PreDestroy;
16 import javax.inject.Inject;
17 import javax.inject.Singleton;
18 import org.eclipse.jdt.annotation.NonNull;
19 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
20 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
21 import org.opendaylight.infrautils.utils.concurrent.Executors;
22 import org.opendaylight.mdsal.binding.api.DataBroker;
23 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
24 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
25 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
26 import org.opendaylight.netvirt.vpnmanager.api.InterfaceUtils;
27 import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev170119.L2vlan;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntry;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntry;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.interfaces.VpnInterface;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.interfaces.vpn._interface.VpnInstanceNames;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
39 import org.opendaylight.yangtools.yang.common.Uint64;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
44 public class SubnetRouteInterfaceStateChangeListener extends AbstractAsyncDataTreeChangeListener<Interface> {
45 private static final Logger LOG = LoggerFactory.getLogger(SubnetRouteInterfaceStateChangeListener.class);
46 private static final String LOGGING_PREFIX = "SUBNETROUTE:";
47 private final DataBroker dataBroker;
48 private final VpnSubnetRouteHandler vpnSubnetRouteHandler;
49 private final SubnetOpDpnManager subOpDpnManager;
50 private final INeutronVpnManager neutronVpnManager;
51 private final JobCoordinator jobCoordinator;
54 public SubnetRouteInterfaceStateChangeListener(final DataBroker dataBroker,
55 final VpnSubnetRouteHandler vpnSubnetRouteHandler, final SubnetOpDpnManager subnetOpDpnManager,
56 final INeutronVpnManager neutronVpnService, final JobCoordinator jobCoordinator) {
57 super(dataBroker, LogicalDatastoreType.OPERATIONAL,
58 InstanceIdentifier.create(InterfacesState.class).child(Interface.class),
59 Executors.newListeningSingleThreadExecutor("SubnetRouteInterfaceStateChangeListener", LOG));
60 this.dataBroker = dataBroker;
61 this.vpnSubnetRouteHandler = vpnSubnetRouteHandler;
62 this.subOpDpnManager = subnetOpDpnManager;
63 this.neutronVpnManager = neutronVpnService;
64 this.jobCoordinator = jobCoordinator;
69 LOG.info("{} start", getClass().getSimpleName());
76 Executors.shutdownAndAwaitTermination(getExecutorService());
81 public void add(InstanceIdentifier<Interface> identifier, Interface intrf) {
82 LOG.trace("{} add: Received interface {} up event", LOGGING_PREFIX, intrf);
83 if (L2vlan.class.equals(intrf.getType())) {
84 LOG.trace("SubnetRouteInterfaceListener add: Received interface {} up event", intrf);
85 if (Interface.OperStatus.Up.equals(intrf.getOperStatus())) {
86 List<Uuid> subnetIdList = getSubnetId(intrf);
87 if (subnetIdList.isEmpty()) {
88 LOG.trace("SubnetRouteInterfaceListener add: Port {} doesn't exist in configDS",
92 for (Uuid subnetId : subnetIdList) {
93 jobCoordinator.enqueueJob("SUBNETROUTE-" + subnetId,
95 String interfaceName = intrf.getName();
96 Uint64 dpnId = Uint64.ZERO;
97 LOG.info("{} add: Received port UP event for interface {} subnetId {}",
98 LOGGING_PREFIX, interfaceName, subnetId);
100 dpnId = InterfaceUtils.getDpIdFromInterface(intrf);
101 } catch (NullPointerException e) {
102 LOG.error("{} add: Unable to obtain dpnId for interface {} in subnet {},"
103 + " subnetroute inclusion for this interface failed", LOGGING_PREFIX,
104 interfaceName, subnetId, e);
106 List<ListenableFuture<Void>> futures = new ArrayList<>();
108 InstanceIdentifier<VpnInterface> id = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
109 Optional<VpnInterface> cfgVpnInterface = SingleTransactionDataBroker.syncReadOptional(
110 dataBroker, LogicalDatastoreType.CONFIGURATION, id);
111 if (!cfgVpnInterface.isPresent()) {
114 vpnSubnetRouteHandler.onInterfaceUp(dpnId, intrf.getName(), subnetId);
115 LOG.info("{} add: Processed interface {} up event", LOGGING_PREFIX, intrf.getName());
116 } catch (InterruptedException | ExecutionException e) {
117 LOG.error("add: Failed to read data store for interface {} dpn {}", interfaceName,
127 // TODO Clean up the exception handling
128 @SuppressWarnings("checkstyle:IllegalCatch")
130 public void remove(InstanceIdentifier<Interface> identifier, Interface intrf) {
131 if (L2vlan.class.equals(intrf.getType())) {
132 LOG.trace("SubnetRouteInterfaceListener remove: Received interface {} down event", intrf);
133 List<Uuid> subnetIdList = getSubnetId(intrf);
134 if (subnetIdList.isEmpty()) {
135 LOG.trace("SubnetRouteInterfaceListener remove: Port {} doesn't exist in configDS",
139 LOG.trace("{} remove: Processing interface {} down event in ", LOGGING_PREFIX, intrf.getName());
140 for (Uuid subnetId : subnetIdList) {
141 jobCoordinator.enqueueJob("SUBNETROUTE-" + subnetId,
143 List<ListenableFuture<Void>> futures = new ArrayList<>();
145 String interfaceName = intrf.getName();
146 Uint64 dpnId = Uint64.ZERO;
147 LOG.info("{} remove: Received port DOWN event for interface {} in subnet {} ",
148 LOGGING_PREFIX, interfaceName, subnetId);
150 dpnId = InterfaceUtils.getDpIdFromInterface(intrf);
151 } catch (Exception e) {
152 LOG.error("{} remove: Unable to retrieve dpnId for interface {} in subnet {}. "
153 + "Fetching from vpn interface itself",
154 LOGGING_PREFIX, intrf.getName(), subnetId, e);
156 InstanceIdentifier<VpnInterface> id = VpnUtil
157 .getVpnInterfaceIdentifier(interfaceName);
158 Optional<VpnInterface> cfgVpnInterface = SingleTransactionDataBroker.syncReadOptional(
159 dataBroker, LogicalDatastoreType.CONFIGURATION, id);
160 if (!cfgVpnInterface.isPresent()) {
163 boolean interfaceDownEligible = false;
164 for (VpnInstanceNames vpnInterfaceVpnInstance :
165 cfgVpnInterface.get().nonnullVpnInstanceNames()) {
166 String vpnName = vpnInterfaceVpnInstance.getVpnName();
167 InstanceIdentifier<VpnInterfaceOpDataEntry> idOper = VpnUtil
168 .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
169 Optional<VpnInterfaceOpDataEntry> optVpnInterface = SingleTransactionDataBroker
170 .syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL, idOper);
171 if (optVpnInterface.isPresent()) {
172 Uint64 dpnIdLocal = dpnId;
173 if (Uint64.ZERO.equals(dpnIdLocal)) {
174 dpnIdLocal = optVpnInterface.get().getDpnId();
176 if (!Uint64.ZERO.equals(dpnIdLocal)) {
177 interfaceDownEligible = true;
182 if (interfaceDownEligible) {
183 vpnSubnetRouteHandler.onInterfaceDown(dpnId, intrf.getName(), subnetId);
185 LOG.info("{} remove: Processed interface {} down event in ", LOGGING_PREFIX,
187 } catch (InterruptedException | ExecutionException e) {
188 LOG.error("{} remove: Failed to read data store for {}", LOGGING_PREFIX, intrf.getName());
197 public void update(InstanceIdentifier<Interface> identifier,
198 Interface original, Interface update) {
199 String interfaceName = update.getName();
200 if (L2vlan.class.equals(update.getType())) {
201 LOG.trace("{} update: Operation Interface update event - Old: {}, New: {}", LOGGING_PREFIX,
203 List<Uuid> subnetIdList = getSubnetId(update);
204 if (subnetIdList.isEmpty()) {
205 LOG.error("SubnetRouteInterfaceListener update: Port {} doesn't exist in configDS",
209 for (Uuid subnetId : subnetIdList) {
210 jobCoordinator.enqueueJob("SUBNETROUTE-" + subnetId,
212 Uint64 dpnId = Uint64.ZERO;
214 dpnId = InterfaceUtils.getDpIdFromInterface(update);
215 } catch (NullPointerException e) {
216 LOG.error("{} remove: Unable to retrieve dpnId for interface {} in subnet {}. "
217 + "Fetching from vpn interface itself", LOGGING_PREFIX, update.getName(),
220 List<ListenableFuture<Void>> futures = new ArrayList<>();
222 InstanceIdentifier<VpnInterface> id = VpnUtil
223 .getVpnInterfaceIdentifier(interfaceName);
224 Optional<VpnInterface> cfgVpnInterface = SingleTransactionDataBroker.syncReadOptional(
225 dataBroker, LogicalDatastoreType.CONFIGURATION, id);
226 if (!cfgVpnInterface.isPresent()) {
229 boolean interfaceChangeEligible = false;
230 for (VpnInstanceNames vpnInterfaceVpnInstance :
231 cfgVpnInterface.get().nonnullVpnInstanceNames()) {
232 String vpnName = vpnInterfaceVpnInstance.getVpnName();
233 InstanceIdentifier<VpnInterfaceOpDataEntry> idOper = VpnUtil
234 .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
235 Optional<VpnInterfaceOpDataEntry> optVpnInterface = SingleTransactionDataBroker
236 .syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL, idOper);
237 if (optVpnInterface.isPresent()) {
238 Uint64 dpnIdLocal = dpnId;
239 if (Uint64.ZERO.equals(dpnIdLocal)) {
240 dpnIdLocal = optVpnInterface.get().getDpnId();
242 if (!Uint64.ZERO.equals(dpnIdLocal)) {
243 interfaceChangeEligible = true;
248 if (interfaceChangeEligible) {
249 if (Interface.OperStatus.Up.equals(update.getOperStatus())) {
250 LOG.info("{} update: Received port UP event for interface {} in subnet {}",
251 LOGGING_PREFIX, update.getName(), subnetId);
252 vpnSubnetRouteHandler.onInterfaceUp(dpnId, update.getName(), subnetId);
253 } else if (Interface.OperStatus.Down.equals(update.getOperStatus())
254 || Interface.OperStatus.Unknown.equals(update.getOperStatus())) {
256 * If the interface went down voluntarily (or) if the interface is not
257 * reachable from control-path involuntarily, trigger subnetRoute election
259 LOG.info("{} update: Received port {} event for interface {} in subnet {} ",
260 LOGGING_PREFIX, Interface.OperStatus.Unknown.equals(update.getOperStatus())
261 ? "UNKNOWN" : "DOWN", update.getName(), subnetId);
262 vpnSubnetRouteHandler.onInterfaceDown(dpnId, update.getName(), subnetId);
265 } catch (InterruptedException | ExecutionException e) {
266 LOG.error("update: Failed to read data store for interface {} dpn {}", interfaceName,
273 LOG.info("{} update: Processed Interface {} update event", LOGGING_PREFIX, update.getName());
277 protected List<Uuid> getSubnetId(Interface intrf) {
278 List<Uuid> listSubnetIds = new ArrayList<>();
279 if (!NeutronUtils.isUuid(intrf.getName())) {
280 LOG.debug("SubnetRouteInterfaceListener: Interface {} doesn't have valid uuid pattern", intrf.getName());
281 return listSubnetIds;
284 PortOpDataEntry portOpEntry = subOpDpnManager.getPortOpDataEntry(intrf.getName());
285 if (portOpEntry != null) {
286 List<Uuid> subnet = portOpEntry.getSubnetIds();
287 if (subnet != null) {
290 return listSubnetIds;
292 LOG.trace("SubnetRouteInterfaceListener : Received Port {} event for {} that is not part of subnetRoute",
293 intrf.getOperStatus(), intrf.getName());
294 Port port = neutronVpnManager.getNeutronPort(intrf.getName());
296 return listSubnetIds;
298 List<FixedIps> portIps = port.getFixedIps();
299 if (portIps != null) {
300 for (FixedIps portIp : portIps) {
301 listSubnetIds.add(portIp.getSubnetId());
304 return listSubnetIds;