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 static org.opendaylight.netvirt.vpnmanager.VpnUtil.requireNonNullElse;
12 import com.google.common.base.Optional;
13 import com.google.common.util.concurrent.ListenableFuture;
14 import java.math.BigInteger;
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.List;
18 import javax.annotation.Nonnull;
19 import javax.annotation.PostConstruct;
20 import javax.inject.Inject;
21 import javax.inject.Singleton;
22 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
23 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
24 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
25 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
26 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
27 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
28 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
29 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
30 import org.opendaylight.netvirt.vpnmanager.api.InterfaceUtils;
31 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
32 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.vpn._interface.VpnInstanceNames;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev170119.L2vlan;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntry;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntry;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
41 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
46 public class SubnetRouteInterfaceStateChangeListener extends AsyncDataTreeChangeListenerBase<Interface,
47 SubnetRouteInterfaceStateChangeListener> {
48 private static final Logger LOG = LoggerFactory.getLogger(SubnetRouteInterfaceStateChangeListener.class);
49 private static final String LOGGING_PREFIX = "SUBNETROUTE:";
50 private final DataBroker dataBroker;
51 private final VpnSubnetRouteHandler vpnSubnetRouteHandler;
52 private final SubnetOpDpnManager subOpDpnManager;
53 private final INeutronVpnManager neutronVpnManager;
54 private final JobCoordinator jobCoordinator;
57 public SubnetRouteInterfaceStateChangeListener(final DataBroker dataBroker,
58 final VpnSubnetRouteHandler vpnSubnetRouteHandler, final SubnetOpDpnManager subnetOpDpnManager,
59 final INeutronVpnManager neutronVpnService, final JobCoordinator jobCoordinator) {
60 super(Interface.class, SubnetRouteInterfaceStateChangeListener.class);
61 this.dataBroker = dataBroker;
62 this.vpnSubnetRouteHandler = vpnSubnetRouteHandler;
63 this.subOpDpnManager = subnetOpDpnManager;
64 this.neutronVpnManager = neutronVpnService;
65 this.jobCoordinator = jobCoordinator;
70 LOG.info("{} start", getClass().getSimpleName());
71 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
75 protected InstanceIdentifier<Interface> getWildCardPath() {
76 return InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
80 protected SubnetRouteInterfaceStateChangeListener getDataTreeChangeListener() {
81 return SubnetRouteInterfaceStateChangeListener.this;
85 protected void add(InstanceIdentifier<Interface> identifier, Interface intrf) {
86 LOG.trace("{} add: Received interface {} up event", LOGGING_PREFIX, intrf);
87 if (L2vlan.class.equals(intrf.getType())) {
88 LOG.trace("SubnetRouteInterfaceListener add: Received interface {} up event", intrf);
89 if (Interface.OperStatus.Up.equals(intrf.getOperStatus())) {
90 List<Uuid> subnetIdList = getSubnetId(intrf);
91 if (subnetIdList.isEmpty()) {
92 LOG.trace("SubnetRouteInterfaceListener add: Port {} doesn't exist in configDS",
96 for (Uuid subnetId : subnetIdList) {
97 jobCoordinator.enqueueJob("SUBNETROUTE-" + subnetId,
99 String interfaceName = intrf.getName();
100 BigInteger dpnId = BigInteger.ZERO;
101 LOG.info("{} add: Received port UP event for interface {} subnetId {}",
102 LOGGING_PREFIX, interfaceName, subnetId);
104 dpnId = InterfaceUtils.getDpIdFromInterface(intrf);
105 } catch (NullPointerException e) {
106 LOG.error("{} add: Unable to obtain dpnId for interface {} in subnet {},"
107 + " subnetroute inclusion for this interface failed", LOGGING_PREFIX,
108 interfaceName, subnetId, e);
110 List<ListenableFuture<Void>> futures = new ArrayList<>();
112 InstanceIdentifier<VpnInterface> id = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
113 Optional<VpnInterface> cfgVpnInterface = SingleTransactionDataBroker.syncReadOptional(
114 dataBroker, LogicalDatastoreType.CONFIGURATION, id);
115 if (!cfgVpnInterface.isPresent()) {
118 vpnSubnetRouteHandler.onInterfaceUp(dpnId, intrf.getName(), subnetId);
119 LOG.info("{} add: Processed interface {} up event", LOGGING_PREFIX, intrf.getName());
120 } catch (ReadFailedException e) {
121 LOG.error("add: Failed to read data store for interface {} dpn {}", interfaceName,
131 // TODO Clean up the exception handling
132 @SuppressWarnings("checkstyle:IllegalCatch")
134 protected void remove(InstanceIdentifier<Interface> identifier, Interface intrf) {
135 if (L2vlan.class.equals(intrf.getType())) {
136 LOG.trace("SubnetRouteInterfaceListener remove: Received interface {} down event", intrf);
137 List<Uuid> subnetIdList = getSubnetId(intrf);
138 if (subnetIdList.isEmpty()) {
139 LOG.trace("SubnetRouteInterfaceListener remove: Port {} doesn't exist in configDS",
143 LOG.trace("{} remove: Processing interface {} down event in ", LOGGING_PREFIX, intrf.getName());
144 for (Uuid subnetId : subnetIdList) {
145 jobCoordinator.enqueueJob("SUBNETROUTE-" + subnetId,
147 List<ListenableFuture<Void>> futures = new ArrayList<>();
149 String interfaceName = intrf.getName();
150 BigInteger dpnId = BigInteger.ZERO;
151 LOG.info("{} remove: Received port DOWN event for interface {} in subnet {} ",
152 LOGGING_PREFIX, interfaceName, subnetId);
154 dpnId = InterfaceUtils.getDpIdFromInterface(intrf);
155 } catch (Exception e) {
156 LOG.error("{} remove: Unable to retrieve dpnId for interface {} in subnet {}. "
157 + "Fetching from vpn interface itself",
158 LOGGING_PREFIX, intrf.getName(), subnetId, e);
160 InstanceIdentifier<VpnInterface> id = VpnUtil
161 .getVpnInterfaceIdentifier(interfaceName);
162 Optional<VpnInterface> cfgVpnInterface = SingleTransactionDataBroker.syncReadOptional(
163 dataBroker, LogicalDatastoreType.CONFIGURATION, id);
164 if (!cfgVpnInterface.isPresent()) {
167 boolean interfaceDownEligible = false;
168 for (VpnInstanceNames vpnInterfaceVpnInstance : requireNonNullElse(
169 cfgVpnInterface.get().getVpnInstanceNames(),
170 Collections.<VpnInstanceNames>emptyList())) {
171 String vpnName = vpnInterfaceVpnInstance.getVpnName();
172 InstanceIdentifier<VpnInterfaceOpDataEntry> idOper = VpnUtil
173 .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
174 Optional<VpnInterfaceOpDataEntry> optVpnInterface = SingleTransactionDataBroker
175 .syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL, idOper);
176 if (optVpnInterface.isPresent()) {
177 BigInteger dpnIdLocal = dpnId;
178 if (BigInteger.ZERO.equals(dpnIdLocal)) {
179 dpnIdLocal = optVpnInterface.get().getDpnId();
181 if (!BigInteger.ZERO.equals(dpnIdLocal)) {
182 interfaceDownEligible = true;
187 if (interfaceDownEligible) {
188 vpnSubnetRouteHandler.onInterfaceDown(dpnId, intrf.getName(), subnetId);
190 LOG.info("{} remove: Processed interface {} down event in ", LOGGING_PREFIX,
192 } catch (ReadFailedException e) {
193 LOG.error("{} remove: Failed to read data store for {}", LOGGING_PREFIX, intrf.getName());
202 protected void update(InstanceIdentifier<Interface> identifier,
203 Interface original, Interface update) {
204 String interfaceName = update.getName();
205 if (L2vlan.class.equals(update.getType())) {
206 LOG.trace("{} update: Operation Interface update event - Old: {}, New: {}", LOGGING_PREFIX,
208 List<Uuid> subnetIdList = getSubnetId(update);
209 if (subnetIdList.isEmpty()) {
210 LOG.error("SubnetRouteInterfaceListener update: Port {} doesn't exist in configDS",
214 for (Uuid subnetId : subnetIdList) {
215 jobCoordinator.enqueueJob("SUBNETROUTE-" + subnetId,
217 BigInteger dpnId = BigInteger.ZERO;
219 dpnId = InterfaceUtils.getDpIdFromInterface(update);
220 } catch (NullPointerException e) {
221 LOG.error("{} remove: Unable to retrieve dpnId for interface {} in subnet {}. "
222 + "Fetching from vpn interface itself", LOGGING_PREFIX, update.getName(),
225 List<ListenableFuture<Void>> futures = new ArrayList<>();
227 InstanceIdentifier<VpnInterface> id = VpnUtil
228 .getVpnInterfaceIdentifier(interfaceName);
229 Optional<VpnInterface> cfgVpnInterface = SingleTransactionDataBroker.syncReadOptional(
230 dataBroker, LogicalDatastoreType.CONFIGURATION, id);
231 if (!cfgVpnInterface.isPresent()) {
234 boolean interfaceChangeEligible = false;
235 for (VpnInstanceNames vpnInterfaceVpnInstance : requireNonNullElse(
236 cfgVpnInterface.get().getVpnInstanceNames(),
237 Collections.<VpnInstanceNames>emptyList())) {
238 String vpnName = vpnInterfaceVpnInstance.getVpnName();
239 InstanceIdentifier<VpnInterfaceOpDataEntry> idOper = VpnUtil
240 .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
241 Optional<VpnInterfaceOpDataEntry> optVpnInterface = SingleTransactionDataBroker
242 .syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL, idOper);
243 if (optVpnInterface.isPresent()) {
244 BigInteger dpnIdLocal = dpnId;
245 if (BigInteger.ZERO.equals(dpnIdLocal)) {
246 dpnIdLocal = optVpnInterface.get().getDpnId();
248 if (!BigInteger.ZERO.equals(dpnIdLocal)) {
249 interfaceChangeEligible = true;
254 if (interfaceChangeEligible) {
255 if (Interface.OperStatus.Up.equals(update.getOperStatus())) {
256 LOG.info("{} update: Received port UP event for interface {} in subnet {}",
257 LOGGING_PREFIX, update.getName(), subnetId);
258 vpnSubnetRouteHandler.onInterfaceUp(dpnId, update.getName(), subnetId);
259 } else if (Interface.OperStatus.Down.equals(update.getOperStatus())
260 || Interface.OperStatus.Unknown.equals(update.getOperStatus())) {
262 * If the interface went down voluntarily (or) if the interface is not
263 * reachable from control-path involuntarily, trigger subnetRoute election
265 LOG.info("{} update: Received port {} event for interface {} in subnet {} ",
266 LOGGING_PREFIX, Interface.OperStatus.Unknown.equals(update.getOperStatus())
267 ? "UNKNOWN" : "DOWN", update.getName(), subnetId);
268 vpnSubnetRouteHandler.onInterfaceDown(dpnId, update.getName(), subnetId);
271 } catch (ReadFailedException e) {
272 LOG.error("update: Failed to read data store for interface {} dpn {}", interfaceName,
279 LOG.info("{} update: Processed Interface {} update event", LOGGING_PREFIX, update.getName());
283 protected List<Uuid> getSubnetId(Interface intrf) {
284 List<Uuid> listSubnetIds = new ArrayList<>();
285 if (!NeutronUtils.isUuid(intrf.getName())) {
286 LOG.debug("SubnetRouteInterfaceListener: Interface {} doesn't have valid uuid pattern", intrf.getName());
287 return listSubnetIds;
290 PortOpDataEntry portOpEntry = subOpDpnManager.getPortOpDataEntry(intrf.getName());
291 if (portOpEntry != null) {
292 List<Uuid> subnet = portOpEntry.getSubnetIds();
293 if (subnet != null) {
296 return listSubnetIds;
298 LOG.trace("SubnetRouteInterfaceListener : Received Port {} event for {} that is not part of subnetRoute",
299 intrf.getOperStatus(), intrf.getName());
300 Port port = neutronVpnManager.getNeutronPort(intrf.getName());
302 return listSubnetIds;
304 List<FixedIps> portIps = port.getFixedIps();
305 if (portIps != null) {
306 for (FixedIps portIp : portIps) {
307 listSubnetIds.add(portIp.getSubnetId());
310 return listSubnetIds;