2 * Copyright (c) 2016, 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
9 package org.opendaylight.genius.itm.listeners;
11 import com.google.common.base.Optional;
12 import com.google.common.util.concurrent.CheckedFuture;
13 import java.math.BigInteger;
14 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.List;
19 import java.util.concurrent.ConcurrentHashMap;
20 import javax.annotation.PostConstruct;
21 import javax.annotation.PreDestroy;
22 import javax.inject.Inject;
23 import javax.inject.Singleton;
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
28 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
29 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
30 import org.opendaylight.genius.itm.confighelpers.HwVtep;
31 import org.opendaylight.genius.itm.confighelpers.ItmTepAddWorker;
32 import org.opendaylight.genius.itm.confighelpers.ItmTepRemoveWorker;
33 import org.opendaylight.genius.itm.confighelpers.ItmTepsNotHostedMoveWorker;
34 import org.opendaylight.genius.itm.confighelpers.ItmTepsNotHostedRemoveWorker;
35 import org.opendaylight.genius.itm.globals.ITMConstants;
36 import org.opendaylight.genius.itm.impl.ITMManager;
37 import org.opendaylight.genius.itm.impl.ItmUtils;
38 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.config.rev160406.ItmConfig;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfo;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.TunnelEndPoints;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.tunnel.end.points.TzMembership;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.TransportZones;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.TransportZonesBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.TepsNotHostedInTransportZone;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.TepsNotHostedInTransportZoneKey;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.TransportZone;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.tepsnothostedintransportzone.UnknownVteps;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.Subnets;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.subnets.DeviceVteps;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.subnets.Vteps;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.subnets.VtepsBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.subnets.VtepsKey;
58 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
63 * This class listens for interface creation/removal/update in Configuration DS.
64 * This is used to handle interfaces for base of-ports.
67 public class TransportZoneListener extends AsyncDataTreeChangeListenerBase<TransportZone, TransportZoneListener>
68 implements AutoCloseable {
69 private static final Logger LOG = LoggerFactory.getLogger(TransportZoneListener.class);
70 private final DataBroker dataBroker;
71 private final IdManagerService idManagerService;
72 private final IMdsalApiManager mdsalManager;
73 private final ITMManager itmManager;
74 private final ItmConfig itmConfig;
77 public TransportZoneListener(final DataBroker dataBroker, final IdManagerService idManagerService,
78 final IMdsalApiManager mdsalManager,final ITMManager itmManager,
79 final ItmConfig itmConfig) {
80 super(TransportZone.class, TransportZoneListener.class);
81 this.dataBroker = dataBroker;
82 this.idManagerService = idManagerService;
83 initializeTZNode(dataBroker);
84 this.itmManager = itmManager;
85 this.mdsalManager = mdsalManager;
86 this.itmConfig = itmConfig;
91 registerListener(LogicalDatastoreType.CONFIGURATION, this.dataBroker);
92 LOG.info("tzChangeListener Started");
98 LOG.info("tzChangeListener Closed");
101 @SuppressWarnings("checkstyle:IllegalCatch")
102 private void initializeTZNode(DataBroker db) {
103 ReadWriteTransaction transaction = db.newReadWriteTransaction();
104 InstanceIdentifier<TransportZones> path = InstanceIdentifier.create(TransportZones.class);
105 CheckedFuture<Optional<TransportZones>, ReadFailedException> tzones = transaction
106 .read(LogicalDatastoreType.CONFIGURATION, path);
108 if (!tzones.get().isPresent()) {
109 TransportZonesBuilder tzb = new TransportZonesBuilder();
110 transaction.put(LogicalDatastoreType.CONFIGURATION, path, tzb.build());
111 transaction.submit();
113 transaction.cancel();
115 } catch (Exception e) {
116 LOG.error("Error initializing TransportZones {}", e);
121 protected InstanceIdentifier<TransportZone> getWildCardPath() {
122 return InstanceIdentifier.create(TransportZones.class).child(TransportZone.class);
126 protected TransportZoneListener getDataTreeChangeListener() {
127 return TransportZoneListener.this;
131 protected void remove(InstanceIdentifier<TransportZone> key, TransportZone tzOld) {
132 LOG.debug("Received Transport Zone Remove Event: {}, {}", key, tzOld);
134 boolean allowTunnelDeletion = false;
136 // check if TZ received for removal is default-transport-zone,
137 // if yes, then check if it is received from northbound, then
138 // do not entertain request and skip tunnels remove operation
139 // if def-tz removal request is due to def-tz-enabled flag is disabled or
140 // due to change in def-tz-tunnel-type, then allow def-tz tunnels deletion
141 if (tzOld.getZoneName().equalsIgnoreCase(ITMConstants.DEFAULT_TRANSPORT_ZONE)) {
142 // Get TunnelTypeBase object for tunnel-type configured in config file
143 Class<? extends TunnelTypeBase> tunType = ItmUtils.getTunnelType(itmConfig.getDefTzTunnelType());
145 if ((!itmConfig.isDefTzEnabled()) || (!tzOld.getTunnelType().equals(tunType))) {
146 allowTunnelDeletion = true;
148 // this is case when def-tz removal request is from Northbound.
149 allowTunnelDeletion = false;
150 LOG.error("Deletion of {} is an incorrect usage",ITMConstants.DEFAULT_TRANSPORT_ZONE);
153 allowTunnelDeletion = true;
156 if (allowTunnelDeletion) {
157 //TODO : DPList code can be refactor with new specific class
158 // which implement TransportZoneValidator
159 List<DPNTEPsInfo> opDpnList = createDPNTepInfo(tzOld);
160 List<HwVtep> hwVtepList = createhWVteps(tzOld);
161 LOG.trace("Delete: Invoking deleteTunnels in ItmManager with DpnList {}", opDpnList);
162 if (!opDpnList.isEmpty() || !hwVtepList.isEmpty()) {
163 LOG.trace("Delete: Invoking ItmManager with hwVtep List {} " , hwVtepList);
164 DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
165 ItmTepRemoveWorker removeWorker =
166 new ItmTepRemoveWorker(opDpnList, hwVtepList, tzOld, dataBroker,
167 idManagerService, mdsalManager);
168 coordinator.enqueueJob(tzOld.getZoneName(), removeWorker);
174 protected void update(InstanceIdentifier<TransportZone> key, TransportZone tzOld, TransportZone tzNew) {
175 LOG.debug("Received Transport Zone Update Event: Key - {}, Old - {}, Updated - {}", key, tzOld, tzNew);
176 List<DPNTEPsInfo> oldDpnTepsList = createDPNTepInfo(tzOld);
177 List<DPNTEPsInfo> newDpnTepsList = createDPNTepInfo(tzNew);
178 List<DPNTEPsInfo> oldDpnTepsListcopy = new ArrayList<>();
179 oldDpnTepsListcopy.addAll(oldDpnTepsList);
180 LOG.trace("oldcopy0" + oldDpnTepsListcopy);
181 List<DPNTEPsInfo> newDpnTepsListcopy = new ArrayList<>();
182 newDpnTepsListcopy.addAll(newDpnTepsList);
183 LOG.trace("newcopy0" + newDpnTepsListcopy);
184 DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
186 oldDpnTepsList.removeAll(newDpnTepsListcopy);
187 newDpnTepsList.removeAll(oldDpnTepsListcopy);
189 LOG.trace("oldDpnTepsList" + oldDpnTepsList);
190 LOG.trace("newDpnTepsList" + newDpnTepsList);
191 LOG.trace("oldcopy" + oldDpnTepsListcopy);
192 LOG.trace("newcopy" + newDpnTepsListcopy);
193 LOG.trace("oldcopy Size " + oldDpnTepsList.size());
194 LOG.trace("newcopy Size " + newDpnTepsList.size());
195 if (!newDpnTepsList.isEmpty()) {
196 LOG.trace("Adding TEPs ");
197 ItmTepAddWorker addWorker = new ItmTepAddWorker(newDpnTepsList, Collections.emptyList(), dataBroker,
198 idManagerService, mdsalManager);
199 coordinator.enqueueJob(tzNew.getZoneName(), addWorker);
201 if (!oldDpnTepsList.isEmpty()) {
202 LOG.trace("Removing TEPs ");
203 ItmTepRemoveWorker removeWorker = new ItmTepRemoveWorker(oldDpnTepsList, Collections.emptyList(),
204 tzOld, dataBroker, idManagerService, mdsalManager);
205 coordinator.enqueueJob(tzNew.getZoneName(), removeWorker);
207 List<HwVtep> oldHwList = createhWVteps(tzOld);
208 List<HwVtep> newHwList = createhWVteps(tzNew);
209 List<HwVtep> oldHwListcopy = new ArrayList<>();
210 oldHwListcopy.addAll(oldHwList);
211 LOG.trace("oldHwListcopy0" + oldHwListcopy);
212 List<HwVtep> newHwListcopy = new ArrayList<>();
213 newHwListcopy.addAll(newHwList);
214 LOG.trace("newHwListcopy0" + newHwListcopy);
216 oldHwList.removeAll(newHwListcopy);
217 newHwList.removeAll(oldHwListcopy);
218 LOG.trace("oldHwList" + oldHwList);
219 LOG.trace("newHwList" + newHwList);
220 LOG.trace("oldHwListcopy" + oldHwListcopy);
221 LOG.trace("newHwListcopy" + newHwListcopy);
222 if (!newHwList.isEmpty()) {
223 LOG.trace("Adding HW TEPs ");
224 ItmTepAddWorker addWorker = new ItmTepAddWorker(Collections.emptyList(), newHwList, dataBroker,
225 idManagerService, mdsalManager);
226 coordinator.enqueueJob(tzNew.getZoneName(), addWorker);
228 if (!oldHwList.isEmpty()) {
229 LOG.trace("Removing HW TEPs ");
230 ItmTepRemoveWorker removeWorker = new ItmTepRemoveWorker(Collections.emptyList(), oldHwList,
231 tzOld, dataBroker, idManagerService, mdsalManager);
232 coordinator.enqueueJob(tzNew.getZoneName(), removeWorker);
237 protected void add(InstanceIdentifier<TransportZone> key, TransportZone tzNew) {
238 LOG.debug("Received Transport Zone Add Event: {}, {}", key, tzNew);
239 List<DPNTEPsInfo> opDpnList = createDPNTepInfo(tzNew);
240 List<HwVtep> hwVtepList = createhWVteps(tzNew);
241 opDpnList.addAll(getDPNTepInfoFromNotHosted(tzNew));
242 LOG.trace("Add: Operational dpnTepInfo - Before invoking ItmManager {}", opDpnList);
243 if (!opDpnList.isEmpty() || !hwVtepList.isEmpty()) {
244 LOG.trace("Add: Invoking ItmManager with DPN List {} ", opDpnList);
245 LOG.trace("Add: Invoking ItmManager with hwVtep List {} ", hwVtepList);
246 DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
247 ItmTepAddWorker addWorker = new ItmTepAddWorker(opDpnList, hwVtepList, dataBroker, idManagerService,
249 coordinator.enqueueJob(tzNew.getZoneName(), addWorker);
253 private List<DPNTEPsInfo> getDPNTepInfoFromNotHosted(TransportZone tzNew) {
254 List<DPNTEPsInfo> notHostedOpDpnList = new ArrayList<>();
255 if (isNewTZExistInNotHostedTZ(tzNew)) {
256 notHostedOpDpnList = createDPNTepInfoFromNotHosted(tzNew);
258 return notHostedOpDpnList;
261 private List<DPNTEPsInfo> createDPNTepInfoFromNotHosted(TransportZone tzNew) {
262 Map<BigInteger, List<TunnelEndPoints>> mapNotHostedDPNToTunnelEndpt = new ConcurrentHashMap<>();
263 List<DPNTEPsInfo> notHostedDpnTepInfo = new ArrayList<>();
264 String newZoneName = tzNew.getZoneName();
265 List<TzMembership> zones = ItmUtils.createTransportZoneMembership(newZoneName);
266 Class<? extends TunnelTypeBase> tunnelType = tzNew.getTunnelType();
267 DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
269 TepsNotHostedInTransportZone tepNotHostedTransportZone = getNotHostedTransportZone(newZoneName).get();
270 if (tepNotHostedTransportZone == null) {
271 return notHostedDpnTepInfo;
273 List<UnknownVteps> unVtepsLst = tepNotHostedTransportZone.getUnknownVteps();
274 List<Vteps> vtepsList = new ArrayList<Vteps>();
275 if (unVtepsLst != null && !unVtepsLst.isEmpty()) {
276 for (UnknownVteps vteps : unVtepsLst) {
277 BigInteger dpnID = vteps.getDpnId();
278 String port = ITMConstants.DUMMY_PORT;
279 int vlanID = ITMConstants.DUMMY_VLANID;
280 IpPrefix ipPrefix = new IpPrefix(ITMConstants.DUMMY_PREFIX.toCharArray());
281 IpAddress gatewayIP = new IpAddress(ITMConstants.DUMMY_GATEWAY_IP.toCharArray());
282 IpAddress ipAddress = vteps.getIpAddress();
283 boolean useOfTunnel = ItmUtils.falseIfNull(vteps.isOfTunnel());
284 TunnelEndPoints tunnelEndPoints =
285 ItmUtils.createTunnelEndPoints(dpnID, ipAddress, port, useOfTunnel,vlanID, ipPrefix,
286 gatewayIP, zones, tunnelType);
287 List<TunnelEndPoints> tunnelEndPointsList = mapNotHostedDPNToTunnelEndpt.get(dpnID);
288 if (tunnelEndPointsList != null) {
289 tunnelEndPointsList.add(tunnelEndPoints);
291 tunnelEndPointsList = new ArrayList<>();
292 tunnelEndPointsList.add(tunnelEndPoints);
293 mapNotHostedDPNToTunnelEndpt.put(dpnID, tunnelEndPointsList);
295 Vteps newVtep = createVtepFromUnKnownVteps(dpnID,ipAddress,ITMConstants.DUMMY_PORT);
296 vtepsList.add(newVtep);
298 // Enqueue 'remove TEP from TepsNotHosted list' operation
299 // into DataStoreJobCoordinator
300 ItmTepsNotHostedRemoveWorker
301 removeWorker = new ItmTepsNotHostedRemoveWorker(newZoneName, ipAddress, dpnID, dataBroker);
302 coordinator.enqueueJob(newZoneName, removeWorker);
306 // Enqueue 'add TEP received from southbound OVSDB into ITM config DS' operation
307 // into DataStoreJobCoordinator
308 ItmTepsNotHostedMoveWorker
309 moveWorker = new ItmTepsNotHostedMoveWorker(vtepsList, newZoneName, dataBroker);
310 coordinator.enqueueJob(newZoneName, moveWorker);
312 if (mapNotHostedDPNToTunnelEndpt.size() > 0) {
313 Set<BigInteger> keys = mapNotHostedDPNToTunnelEndpt.keySet();
314 for (BigInteger key: keys) {
315 DPNTEPsInfo newDpnTepsInfo = ItmUtils.createDPNTepInfo(key, mapNotHostedDPNToTunnelEndpt.get(key));
316 notHostedDpnTepInfo.add(newDpnTepsInfo);
319 return notHostedDpnTepInfo;
323 private Vteps createVtepFromUnKnownVteps(BigInteger dpnID, IpAddress ipAddress, String port) {
324 VtepsKey vtepkey = new VtepsKey(dpnID, port);
325 Vteps vtepObj = new VtepsBuilder().setDpnId(dpnID).setIpAddress(ipAddress).setKey(vtepkey)
326 .setPortname(port).build();
330 private boolean isNewTZExistInNotHostedTZ(TransportZone tzNew) {
331 boolean isPresent = false;
332 if (getNotHostedTransportZone(tzNew.getZoneName()).isPresent()) {
338 public Optional<TepsNotHostedInTransportZone> getNotHostedTransportZone(String transportZoneName) {
339 InstanceIdentifier<TepsNotHostedInTransportZone> tzonePath = InstanceIdentifier.builder(TransportZones.class)
340 .child(TepsNotHostedInTransportZone.class,
341 new TepsNotHostedInTransportZoneKey(transportZoneName)).build();
342 Optional<TepsNotHostedInTransportZone> tzNotHostedOptional =
343 ItmUtils.read(LogicalDatastoreType.CONFIGURATION, tzonePath, dataBroker);
344 return tzNotHostedOptional;
347 private List<DPNTEPsInfo> createDPNTepInfo(TransportZone transportZone) {
349 Map<BigInteger, List<TunnelEndPoints>> mapDPNToTunnelEndpt = new ConcurrentHashMap<>();
350 List<DPNTEPsInfo> dpnTepInfo = new ArrayList<>();
351 List<TzMembership> zones = ItmUtils.createTransportZoneMembership(transportZone.getZoneName());
352 Class<? extends TunnelTypeBase> tunnelType = transportZone.getTunnelType();
353 LOG.trace("Transport Zone_name: {}", transportZone.getZoneName());
354 List<Subnets> subnetsList = transportZone.getSubnets();
355 if (subnetsList != null) {
356 for (Subnets subnet : subnetsList) {
357 IpPrefix ipPrefix = subnet.getPrefix();
358 IpAddress gatewayIP = subnet.getGatewayIp();
359 int vlanID = subnet.getVlanId();
360 LOG.trace("IpPrefix: {}, gatewayIP: {}, vlanID: {} ", ipPrefix, gatewayIP, vlanID);
361 List<Vteps> vtepsList = subnet.getVteps();
362 if (vtepsList != null && !vtepsList.isEmpty()) {
363 for (Vteps vteps : vtepsList) {
364 BigInteger dpnID = vteps.getDpnId();
365 String port = vteps.getPortname();
366 IpAddress ipAddress = vteps.getIpAddress();
367 boolean useOfTunnel = ItmUtils.falseIfNull(vteps.isOptionOfTunnel());
368 LOG.trace("DpnID: {}, port: {}, ipAddress: {}", dpnID, port, ipAddress);
369 TunnelEndPoints tunnelEndPoints = ItmUtils.createTunnelEndPoints(dpnID, ipAddress, port,
370 useOfTunnel, vlanID, ipPrefix, gatewayIP, zones, tunnelType);
371 List<TunnelEndPoints> tunnelEndPointsList = mapDPNToTunnelEndpt.get(dpnID);
372 if (tunnelEndPointsList != null) {
373 LOG.trace("Existing DPN info list in the Map: {} ", dpnID);
374 tunnelEndPointsList.add(tunnelEndPoints);
376 LOG.trace("Adding new DPN info list to the Map: {} ", dpnID);
377 tunnelEndPointsList = new ArrayList<>();
378 tunnelEndPointsList.add(tunnelEndPoints);
379 mapDPNToTunnelEndpt.put(dpnID, tunnelEndPointsList);
386 if (!mapDPNToTunnelEndpt.isEmpty()) {
387 Set<BigInteger> keys = mapDPNToTunnelEndpt.keySet();
388 LOG.trace("List of dpns in the Map: {} ", keys);
389 for (BigInteger key : keys) {
390 DPNTEPsInfo newDpnTepsInfo = ItmUtils.createDPNTepInfo(key, mapDPNToTunnelEndpt.get(key));
391 dpnTepInfo.add(newDpnTepsInfo);
397 private List<HwVtep> createhWVteps(TransportZone transportZone) {
398 List<HwVtep> hwVtepsList = new ArrayList<>();
400 String zoneName = transportZone.getZoneName();
401 Class<? extends TunnelTypeBase> tunnelType = transportZone.getTunnelType();
402 LOG.trace("Transport Zone_name: {}", zoneName);
403 List<Subnets> subnetsList = transportZone.getSubnets();
404 if (subnetsList != null) {
405 for (Subnets subnet : subnetsList) {
406 IpPrefix ipPrefix = subnet.getPrefix();
407 IpAddress gatewayIP = subnet.getGatewayIp();
408 int vlanID = subnet.getVlanId();
409 LOG.trace("IpPrefix: {}, gatewayIP: {}, vlanID: {} ", ipPrefix, gatewayIP, vlanID);
410 List<DeviceVteps> deviceVtepsList = subnet.getDeviceVteps();
411 if (deviceVtepsList != null) {
412 for (DeviceVteps vteps : deviceVtepsList) {
413 String topologyId = vteps.getTopologyId();
414 String nodeId = vteps.getNodeId();
415 IpAddress ipAddress = vteps.getIpAddress();
416 LOG.trace("topo-id: {}, node-id: {}, ipAddress: {}", topologyId, nodeId, ipAddress);
417 HwVtep hwVtep = ItmUtils.createHwVtepObject(topologyId, nodeId, ipAddress, ipPrefix, gatewayIP,
418 vlanID, tunnelType, transportZone);
420 if (hwVtepsList != null) {
421 LOG.trace("Existing hwVteps");
422 hwVtepsList.add(hwVtep);
424 LOG.trace("Adding new HwVtep {} info ", hwVtep.getHwIp());
425 hwVtepsList.add(hwVtep);
431 LOG.trace("returning hwvteplist {}", hwVtepsList);