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;
14 import java.util.Optional;
15 import java.util.concurrent.ExecutionException;
16 import javax.annotation.PreDestroy;
17 import javax.inject.Inject;
18 import javax.inject.Singleton;
19 import org.eclipse.jdt.annotation.NonNull;
20 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
21 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
22 import org.opendaylight.infrautils.utils.concurrent.Executors;
23 import org.opendaylight.mdsal.binding.api.DataBroker;
24 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
25 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
26 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
27 import org.opendaylight.netvirt.vpnmanager.api.InterfaceUtils;
28 import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev170119.L2vlan;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntry;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntry;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.interfaces.VpnInterface;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.interfaces.vpn._interface.VpnInstanceNames;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIpsKey;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
40 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
41 import org.opendaylight.yangtools.yang.common.Uint64;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
46 public class SubnetRouteInterfaceStateChangeListener extends AbstractAsyncDataTreeChangeListener<Interface> {
47 private static final Logger LOG = LoggerFactory.getLogger(SubnetRouteInterfaceStateChangeListener.class);
48 private static final String LOGGING_PREFIX = "SUBNETROUTE:";
49 private final DataBroker dataBroker;
50 private final VpnSubnetRouteHandler vpnSubnetRouteHandler;
51 private final SubnetOpDpnManager subOpDpnManager;
52 private final INeutronVpnManager neutronVpnManager;
53 private final JobCoordinator jobCoordinator;
56 public SubnetRouteInterfaceStateChangeListener(final DataBroker dataBroker,
57 final VpnSubnetRouteHandler vpnSubnetRouteHandler, final SubnetOpDpnManager subnetOpDpnManager,
58 final INeutronVpnManager neutronVpnService, final JobCoordinator jobCoordinator) {
59 super(dataBroker, LogicalDatastoreType.OPERATIONAL,
60 InstanceIdentifier.create(InterfacesState.class).child(Interface.class),
61 Executors.newListeningSingleThreadExecutor("SubnetRouteInterfaceStateChangeListener", LOG));
62 this.dataBroker = dataBroker;
63 this.vpnSubnetRouteHandler = vpnSubnetRouteHandler;
64 this.subOpDpnManager = subnetOpDpnManager;
65 this.neutronVpnManager = neutronVpnService;
66 this.jobCoordinator = jobCoordinator;
71 LOG.info("{} start", getClass().getSimpleName());
78 Executors.shutdownAndAwaitTermination(getExecutorService());
83 public void add(InstanceIdentifier<Interface> identifier, Interface intrf) {
84 LOG.trace("{} add: Received interface {} up event", LOGGING_PREFIX, intrf);
85 if (L2vlan.class.equals(intrf.getType())) {
86 LOG.trace("SubnetRouteInterfaceListener add: Received interface {} up event", intrf);
87 if (Interface.OperStatus.Up.equals(intrf.getOperStatus())) {
88 List<Uuid> subnetIdList = getSubnetId(intrf);
89 if (subnetIdList.isEmpty()) {
90 LOG.trace("SubnetRouteInterfaceListener add: Port {} doesn't exist in configDS",
94 for (Uuid subnetId : subnetIdList) {
95 jobCoordinator.enqueueJob("SUBNETROUTE-" + subnetId,
97 String interfaceName = intrf.getName();
98 Uint64 dpnId = Uint64.ZERO;
99 LOG.info("{} add: Received port UP event for interface {} subnetId {}",
100 LOGGING_PREFIX, interfaceName, subnetId);
102 dpnId = InterfaceUtils.getDpIdFromInterface(intrf);
103 } catch (NullPointerException e) {
104 LOG.error("{} add: Unable to obtain dpnId for interface {} in subnet {},"
105 + " subnetroute inclusion for this interface failed", LOGGING_PREFIX,
106 interfaceName, subnetId, e);
108 List<ListenableFuture<Void>> futures = new ArrayList<>();
110 InstanceIdentifier<VpnInterface> id = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
111 Optional<VpnInterface> cfgVpnInterface = SingleTransactionDataBroker.syncReadOptional(
112 dataBroker, LogicalDatastoreType.CONFIGURATION, id);
113 if (!cfgVpnInterface.isPresent()) {
116 vpnSubnetRouteHandler.onInterfaceUp(dpnId, intrf.getName(), subnetId);
117 LOG.info("{} add: Processed interface {} up event", LOGGING_PREFIX, intrf.getName());
118 } catch (InterruptedException | ExecutionException e) {
119 LOG.error("add: Failed to read data store for interface {} dpn {}", interfaceName,
129 // TODO Clean up the exception handling
130 @SuppressWarnings("checkstyle:IllegalCatch")
132 public void remove(InstanceIdentifier<Interface> identifier, Interface intrf) {
133 if (L2vlan.class.equals(intrf.getType())) {
134 LOG.trace("SubnetRouteInterfaceListener remove: Received interface {} down event", intrf);
135 List<Uuid> subnetIdList = getSubnetId(intrf);
136 if (subnetIdList.isEmpty()) {
137 LOG.trace("SubnetRouteInterfaceListener remove: Port {} doesn't exist in configDS",
141 LOG.trace("{} remove: Processing interface {} down event in ", LOGGING_PREFIX, intrf.getName());
142 for (Uuid subnetId : subnetIdList) {
143 jobCoordinator.enqueueJob("SUBNETROUTE-" + subnetId,
145 List<ListenableFuture<Void>> futures = new ArrayList<>();
147 String interfaceName = intrf.getName();
148 Uint64 dpnId = Uint64.ZERO;
149 LOG.info("{} remove: Received port DOWN event for interface {} in subnet {} ",
150 LOGGING_PREFIX, interfaceName, subnetId);
152 dpnId = InterfaceUtils.getDpIdFromInterface(intrf);
153 } catch (Exception e) {
154 LOG.error("{} remove: Unable to retrieve dpnId for interface {} in subnet {}. "
155 + "Fetching from vpn interface itself",
156 LOGGING_PREFIX, intrf.getName(), subnetId, e);
158 InstanceIdentifier<VpnInterface> id = VpnUtil
159 .getVpnInterfaceIdentifier(interfaceName);
160 Optional<VpnInterface> cfgVpnInterface = SingleTransactionDataBroker.syncReadOptional(
161 dataBroker, LogicalDatastoreType.CONFIGURATION, id);
162 if (!cfgVpnInterface.isPresent()) {
165 boolean interfaceDownEligible = false;
166 for (VpnInstanceNames vpnInterfaceVpnInstance :
167 cfgVpnInterface.get().nonnullVpnInstanceNames().values()) {
168 String vpnName = vpnInterfaceVpnInstance.getVpnName();
169 InstanceIdentifier<VpnInterfaceOpDataEntry> idOper = VpnUtil
170 .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
171 Optional<VpnInterfaceOpDataEntry> optVpnInterface = SingleTransactionDataBroker
172 .syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL, idOper);
173 if (optVpnInterface.isPresent()) {
174 Uint64 dpnIdLocal = dpnId;
175 if (Uint64.ZERO.equals(dpnIdLocal)) {
176 dpnIdLocal = optVpnInterface.get().getDpnId();
178 if (!Uint64.ZERO.equals(dpnIdLocal)) {
179 interfaceDownEligible = true;
184 if (interfaceDownEligible) {
185 vpnSubnetRouteHandler.onInterfaceDown(dpnId, intrf.getName(), subnetId);
187 LOG.info("{} remove: Processed interface {} down event in ", LOGGING_PREFIX,
189 } catch (InterruptedException | ExecutionException e) {
190 LOG.error("{} remove: Failed to read data store for {}", LOGGING_PREFIX, intrf.getName());
199 public void update(InstanceIdentifier<Interface> identifier,
200 Interface original, Interface update) {
201 String interfaceName = update.getName();
202 if (L2vlan.class.equals(update.getType())) {
203 LOG.trace("{} update: Operation Interface update event - Old: {}, New: {}", LOGGING_PREFIX,
205 List<Uuid> subnetIdList = getSubnetId(update);
206 if (subnetIdList.isEmpty()) {
207 LOG.error("SubnetRouteInterfaceListener update: Port {} doesn't exist in configDS",
211 for (Uuid subnetId : subnetIdList) {
212 jobCoordinator.enqueueJob("SUBNETROUTE-" + subnetId,
214 Uint64 dpnId = Uint64.ZERO;
216 dpnId = InterfaceUtils.getDpIdFromInterface(update);
217 } catch (NullPointerException e) {
218 LOG.error("{} remove: Unable to retrieve dpnId for interface {} in subnet {}. "
219 + "Fetching from vpn interface itself", LOGGING_PREFIX, update.getName(),
222 List<ListenableFuture<Void>> futures = new ArrayList<>();
224 InstanceIdentifier<VpnInterface> id = VpnUtil
225 .getVpnInterfaceIdentifier(interfaceName);
226 Optional<VpnInterface> cfgVpnInterface = SingleTransactionDataBroker.syncReadOptional(
227 dataBroker, LogicalDatastoreType.CONFIGURATION, id);
228 if (!cfgVpnInterface.isPresent()) {
231 boolean interfaceChangeEligible = false;
232 for (VpnInstanceNames vpnInterfaceVpnInstance :
233 cfgVpnInterface.get().nonnullVpnInstanceNames().values()) {
234 String vpnName = vpnInterfaceVpnInstance.getVpnName();
235 InstanceIdentifier<VpnInterfaceOpDataEntry> idOper = VpnUtil
236 .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
237 Optional<VpnInterfaceOpDataEntry> optVpnInterface = SingleTransactionDataBroker
238 .syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL, idOper);
239 if (optVpnInterface.isPresent()) {
240 Uint64 dpnIdLocal = dpnId;
241 if (Uint64.ZERO.equals(dpnIdLocal)) {
242 dpnIdLocal = optVpnInterface.get().getDpnId();
244 if (!Uint64.ZERO.equals(dpnIdLocal)) {
245 interfaceChangeEligible = true;
250 if (interfaceChangeEligible) {
251 if (Interface.OperStatus.Up.equals(update.getOperStatus())) {
252 LOG.info("{} update: Received port UP event for interface {} in subnet {}",
253 LOGGING_PREFIX, update.getName(), subnetId);
254 vpnSubnetRouteHandler.onInterfaceUp(dpnId, update.getName(), subnetId);
255 } else if (Interface.OperStatus.Down.equals(update.getOperStatus())
256 || Interface.OperStatus.Unknown.equals(update.getOperStatus())) {
258 * If the interface went down voluntarily (or) if the interface is not
259 * reachable from control-path involuntarily, trigger subnetRoute election
261 LOG.info("{} update: Received port {} event for interface {} in subnet {} ",
262 LOGGING_PREFIX, Interface.OperStatus.Unknown.equals(update.getOperStatus())
263 ? "UNKNOWN" : "DOWN", update.getName(), subnetId);
264 vpnSubnetRouteHandler.onInterfaceDown(dpnId, update.getName(), subnetId);
267 } catch (InterruptedException | ExecutionException e) {
268 LOG.error("update: Failed to read data store for interface {} dpn {}", interfaceName,
275 LOG.info("{} update: Processed Interface {} update event", LOGGING_PREFIX, update.getName());
279 protected List<Uuid> getSubnetId(Interface intrf) {
280 List<Uuid> listSubnetIds = new ArrayList<>();
281 if (!NeutronUtils.isUuid(intrf.getName())) {
282 LOG.debug("SubnetRouteInterfaceListener: Interface {} doesn't have valid uuid pattern", intrf.getName());
283 return listSubnetIds;
286 PortOpDataEntry portOpEntry = subOpDpnManager.getPortOpDataEntry(intrf.getName());
287 if (portOpEntry != null) {
288 List<Uuid> subnet = portOpEntry.getSubnetIds();
289 if (subnet != null) {
292 return listSubnetIds;
294 LOG.trace("SubnetRouteInterfaceListener : Received Port {} event for {} that is not part of subnetRoute",
295 intrf.getOperStatus(), intrf.getName());
296 Port port = neutronVpnManager.getNeutronPort(intrf.getName());
298 return listSubnetIds;
300 Map<FixedIpsKey, FixedIps> portIpsMap = port.getFixedIps();
301 if (portIpsMap != null) {
302 for (FixedIps portIp : portIpsMap.values()) {
303 listSubnetIds.add(portIp.getSubnetId());
306 return listSubnetIds;