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.base.Optional;
11 import com.google.common.util.concurrent.ListenableFuture;
12 import java.util.ArrayList;
13 import java.util.List;
14 import javax.annotation.PostConstruct;
15 import javax.inject.Inject;
16 import javax.inject.Singleton;
17 import org.eclipse.jdt.annotation.NonNull;
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.controller.md.sal.common.api.data.ReadFailedException;
21 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
22 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
23 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
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.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev170119.L2vlan;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
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.vpn._interface.op.data.VpnInterfaceOpDataEntry;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.interfaces.VpnInterface;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.interfaces.vpn._interface.VpnInstanceNames;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
37 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
38 import org.opendaylight.yangtools.yang.common.Uint64;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
43 public class SubnetRouteInterfaceStateChangeListener extends AsyncDataTreeChangeListenerBase<Interface,
44 SubnetRouteInterfaceStateChangeListener> {
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(Interface.class, SubnetRouteInterfaceStateChangeListener.class);
58 this.dataBroker = dataBroker;
59 this.vpnSubnetRouteHandler = vpnSubnetRouteHandler;
60 this.subOpDpnManager = subnetOpDpnManager;
61 this.neutronVpnManager = neutronVpnService;
62 this.jobCoordinator = jobCoordinator;
67 LOG.info("{} start", getClass().getSimpleName());
68 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
72 protected InstanceIdentifier<Interface> getWildCardPath() {
73 return InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
77 protected SubnetRouteInterfaceStateChangeListener getDataTreeChangeListener() {
78 return SubnetRouteInterfaceStateChangeListener.this;
82 protected void add(InstanceIdentifier<Interface> identifier, Interface intrf) {
83 LOG.trace("{} add: Received interface {} up event", LOGGING_PREFIX, intrf);
84 if (L2vlan.class.equals(intrf.getType())) {
85 LOG.trace("SubnetRouteInterfaceListener add: Received interface {} up event", intrf);
86 if (Interface.OperStatus.Up.equals(intrf.getOperStatus())) {
87 List<Uuid> subnetIdList = getSubnetId(intrf);
88 if (subnetIdList.isEmpty()) {
89 LOG.trace("SubnetRouteInterfaceListener add: Port {} doesn't exist in configDS",
93 for (Uuid subnetId : subnetIdList) {
94 jobCoordinator.enqueueJob("SUBNETROUTE-" + subnetId,
96 String interfaceName = intrf.getName();
97 Uint64 dpnId = Uint64.ZERO;
98 LOG.info("{} add: Received port UP event for interface {} subnetId {}",
99 LOGGING_PREFIX, interfaceName, subnetId);
101 dpnId = InterfaceUtils.getDpIdFromInterface(intrf);
102 } catch (NullPointerException e) {
103 LOG.error("{} add: Unable to obtain dpnId for interface {} in subnet {},"
104 + " subnetroute inclusion for this interface failed", LOGGING_PREFIX,
105 interfaceName, subnetId, e);
107 List<ListenableFuture<Void>> futures = new ArrayList<>();
109 InstanceIdentifier<VpnInterface> id = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
110 Optional<VpnInterface> cfgVpnInterface = SingleTransactionDataBroker.syncReadOptional(
111 dataBroker, LogicalDatastoreType.CONFIGURATION, id);
112 if (!cfgVpnInterface.isPresent()) {
115 vpnSubnetRouteHandler.onInterfaceUp(dpnId, intrf.getName(), subnetId);
116 LOG.info("{} add: Processed interface {} up event", LOGGING_PREFIX, intrf.getName());
117 } catch (ReadFailedException e) {
118 LOG.error("add: Failed to read data store for interface {} dpn {}", interfaceName,
128 // TODO Clean up the exception handling
129 @SuppressWarnings("checkstyle:IllegalCatch")
131 protected void remove(InstanceIdentifier<Interface> identifier, Interface intrf) {
132 if (L2vlan.class.equals(intrf.getType())) {
133 LOG.trace("SubnetRouteInterfaceListener remove: Received interface {} down event", intrf);
134 List<Uuid> subnetIdList = getSubnetId(intrf);
135 if (subnetIdList.isEmpty()) {
136 LOG.trace("SubnetRouteInterfaceListener remove: Port {} doesn't exist in configDS",
140 LOG.trace("{} remove: Processing interface {} down event in ", LOGGING_PREFIX, intrf.getName());
141 for (Uuid subnetId : subnetIdList) {
142 jobCoordinator.enqueueJob("SUBNETROUTE-" + subnetId,
144 List<ListenableFuture<Void>> futures = new ArrayList<>();
146 String interfaceName = intrf.getName();
147 Uint64 dpnId = Uint64.ZERO;
148 LOG.info("{} remove: Received port DOWN event for interface {} in subnet {} ",
149 LOGGING_PREFIX, interfaceName, subnetId);
151 dpnId = InterfaceUtils.getDpIdFromInterface(intrf);
152 } catch (Exception e) {
153 LOG.error("{} remove: Unable to retrieve dpnId for interface {} in subnet {}. "
154 + "Fetching from vpn interface itself",
155 LOGGING_PREFIX, intrf.getName(), subnetId, e);
157 InstanceIdentifier<VpnInterface> id = VpnUtil
158 .getVpnInterfaceIdentifier(interfaceName);
159 Optional<VpnInterface> cfgVpnInterface = SingleTransactionDataBroker.syncReadOptional(
160 dataBroker, LogicalDatastoreType.CONFIGURATION, id);
161 if (!cfgVpnInterface.isPresent()) {
164 boolean interfaceDownEligible = false;
165 for (VpnInstanceNames vpnInterfaceVpnInstance :
166 cfgVpnInterface.get().nonnullVpnInstanceNames()) {
167 String vpnName = vpnInterfaceVpnInstance.getVpnName();
168 InstanceIdentifier<VpnInterfaceOpDataEntry> idOper = VpnUtil
169 .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
170 Optional<VpnInterfaceOpDataEntry> optVpnInterface = SingleTransactionDataBroker
171 .syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL, idOper);
172 if (optVpnInterface.isPresent()) {
173 Uint64 dpnIdLocal = dpnId;
174 if (Uint64.ZERO.equals(dpnIdLocal)) {
175 dpnIdLocal = optVpnInterface.get().getDpnId();
177 if (!Uint64.ZERO.equals(dpnIdLocal)) {
178 interfaceDownEligible = true;
183 if (interfaceDownEligible) {
184 vpnSubnetRouteHandler.onInterfaceDown(dpnId, intrf.getName(), subnetId);
186 LOG.info("{} remove: Processed interface {} down event in ", LOGGING_PREFIX,
188 } catch (ReadFailedException e) {
189 LOG.error("{} remove: Failed to read data store for {}", LOGGING_PREFIX, intrf.getName());
198 protected void update(InstanceIdentifier<Interface> identifier,
199 Interface original, Interface update) {
200 String interfaceName = update.getName();
201 if (L2vlan.class.equals(update.getType())) {
202 LOG.trace("{} update: Operation Interface update event - Old: {}, New: {}", LOGGING_PREFIX,
204 List<Uuid> subnetIdList = getSubnetId(update);
205 if (subnetIdList.isEmpty()) {
206 LOG.error("SubnetRouteInterfaceListener update: Port {} doesn't exist in configDS",
210 for (Uuid subnetId : subnetIdList) {
211 jobCoordinator.enqueueJob("SUBNETROUTE-" + subnetId,
213 Uint64 dpnId = Uint64.ZERO;
215 dpnId = InterfaceUtils.getDpIdFromInterface(update);
216 } catch (NullPointerException e) {
217 LOG.error("{} remove: Unable to retrieve dpnId for interface {} in subnet {}. "
218 + "Fetching from vpn interface itself", LOGGING_PREFIX, update.getName(),
221 List<ListenableFuture<Void>> futures = new ArrayList<>();
223 InstanceIdentifier<VpnInterface> id = VpnUtil
224 .getVpnInterfaceIdentifier(interfaceName);
225 Optional<VpnInterface> cfgVpnInterface = SingleTransactionDataBroker.syncReadOptional(
226 dataBroker, LogicalDatastoreType.CONFIGURATION, id);
227 if (!cfgVpnInterface.isPresent()) {
230 boolean interfaceChangeEligible = false;
231 for (VpnInstanceNames vpnInterfaceVpnInstance :
232 cfgVpnInterface.get().nonnullVpnInstanceNames()) {
233 String vpnName = vpnInterfaceVpnInstance.getVpnName();
234 InstanceIdentifier<VpnInterfaceOpDataEntry> idOper = VpnUtil
235 .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
236 Optional<VpnInterfaceOpDataEntry> optVpnInterface = SingleTransactionDataBroker
237 .syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL, idOper);
238 if (optVpnInterface.isPresent()) {
239 Uint64 dpnIdLocal = dpnId;
240 if (Uint64.ZERO.equals(dpnIdLocal)) {
241 dpnIdLocal = optVpnInterface.get().getDpnId();
243 if (!Uint64.ZERO.equals(dpnIdLocal)) {
244 interfaceChangeEligible = true;
249 if (interfaceChangeEligible) {
250 if (Interface.OperStatus.Up.equals(update.getOperStatus())) {
251 LOG.info("{} update: Received port UP event for interface {} in subnet {}",
252 LOGGING_PREFIX, update.getName(), subnetId);
253 vpnSubnetRouteHandler.onInterfaceUp(dpnId, update.getName(), subnetId);
254 } else if (Interface.OperStatus.Down.equals(update.getOperStatus())
255 || Interface.OperStatus.Unknown.equals(update.getOperStatus())) {
257 * If the interface went down voluntarily (or) if the interface is not
258 * reachable from control-path involuntarily, trigger subnetRoute election
260 LOG.info("{} update: Received port {} event for interface {} in subnet {} ",
261 LOGGING_PREFIX, Interface.OperStatus.Unknown.equals(update.getOperStatus())
262 ? "UNKNOWN" : "DOWN", update.getName(), subnetId);
263 vpnSubnetRouteHandler.onInterfaceDown(dpnId, update.getName(), subnetId);
266 } catch (ReadFailedException e) {
267 LOG.error("update: Failed to read data store for interface {} dpn {}", interfaceName,
274 LOG.info("{} update: Processed Interface {} update event", LOGGING_PREFIX, update.getName());
278 protected List<Uuid> getSubnetId(Interface intrf) {
279 List<Uuid> listSubnetIds = new ArrayList<>();
280 if (!NeutronUtils.isUuid(intrf.getName())) {
281 LOG.debug("SubnetRouteInterfaceListener: Interface {} doesn't have valid uuid pattern", intrf.getName());
282 return listSubnetIds;
285 PortOpDataEntry portOpEntry = subOpDpnManager.getPortOpDataEntry(intrf.getName());
286 if (portOpEntry != null) {
287 List<Uuid> subnet = portOpEntry.getSubnetIds();
288 if (subnet != null) {
291 return listSubnetIds;
293 LOG.trace("SubnetRouteInterfaceListener : Received Port {} event for {} that is not part of subnetRoute",
294 intrf.getOperStatus(), intrf.getName());
295 Port port = neutronVpnManager.getNeutronPort(intrf.getName());
297 return listSubnetIds;
299 List<FixedIps> portIps = port.getFixedIps();
300 if (portIps != null) {
301 for (FixedIps portIp : portIps) {
302 listSubnetIds.add(portIp.getSubnetId());
305 return listSubnetIds;