Merge "Add dependency to infrautils-testutils to genius.testutils POM"
[genius.git] / itm / itm-impl / src / main / java / org / opendaylight / genius / itm / listeners / TransportZoneListener.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.genius.itm.listeners;
10
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;
17 import java.util.Map;
18 import java.util.Set;
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.impl.ITMManager;
34 import org.opendaylight.genius.itm.impl.ItmUtils;
35 import org.opendaylight.genius.itm.validator.TransportZoneNameAllowed;
36 import org.opendaylight.genius.itm.validator.TransportZoneValidator;
37 import org.opendaylight.genius.itm.validator.ValidatorErrorCode;
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.op.rev160406.dpn.endpoints.DPNTEPsInfo;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.TunnelEndPoints;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.tunnel.end.points.TzMembership;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.TransportZones;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.TransportZonesBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.TransportZone;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.Subnets;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.subnets.DeviceVteps;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.subnets.Vteps;
52 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 /**
57  * This class listens for interface creation/removal/update in Configuration DS.
58  * This is used to handle interfaces for base of-ports.
59  */
60 @Singleton
61 public class TransportZoneListener extends AsyncDataTreeChangeListenerBase<TransportZone, TransportZoneListener>
62         implements AutoCloseable {
63     private static final Logger LOG = LoggerFactory.getLogger(TransportZoneListener.class);
64     private final DataBroker dataBroker;
65     private final IdManagerService idManagerService;
66     private final IMdsalApiManager mdsalManager;
67     private final ITMManager itmManager;
68
69     @Inject
70     public TransportZoneListener(final DataBroker dataBroker, final IdManagerService idManagerService,
71                                  final IMdsalApiManager iMdsalApiManager,final ITMManager itmManager) {
72         super(TransportZone.class, TransportZoneListener.class);
73         this.dataBroker = dataBroker;
74         this.idManagerService = idManagerService;
75         initializeTZNode(dataBroker);
76         this.itmManager = itmManager;
77         this.mdsalManager = iMdsalApiManager;
78     }
79
80     @PostConstruct
81     public void start() throws Exception {
82         registerListener(LogicalDatastoreType.CONFIGURATION, this.dataBroker);
83         LOG.info("tzChangeListener Started");
84     }
85
86     @Override
87     @PreDestroy
88     public void close() throws Exception {
89         LOG.info("tzChangeListener Closed");
90     }
91
92     private void initializeTZNode(DataBroker db) {
93         ReadWriteTransaction transaction = db.newReadWriteTransaction();
94         InstanceIdentifier<TransportZones> path = InstanceIdentifier.create(TransportZones.class);
95         CheckedFuture<Optional<TransportZones>, ReadFailedException> tzones = transaction
96                 .read(LogicalDatastoreType.CONFIGURATION, path);
97         try {
98             if (!tzones.get().isPresent()) {
99                 TransportZonesBuilder tzb = new TransportZonesBuilder();
100                 transaction.put(LogicalDatastoreType.CONFIGURATION, path, tzb.build());
101                 transaction.submit();
102             } else {
103                 transaction.cancel();
104             }
105         } catch (Exception e) {
106             LOG.error("Error initializing TransportZones {}", e);
107         }
108     }
109
110     @Override
111     protected InstanceIdentifier<TransportZone> getWildCardPath() {
112         return InstanceIdentifier.create(TransportZones.class).child(TransportZone.class);
113     }
114
115     @Override
116     protected TransportZoneListener getDataTreeChangeListener() {
117         return TransportZoneListener.this;
118     }
119
120     @Override
121     protected void remove(InstanceIdentifier<TransportZone> key, TransportZone tzOld) {
122         LOG.debug("Received Transport Zone Remove Event: {}, {}", key, tzOld);
123         if(validateTransportZoneParam(tzOld)){
124             //TODO : DPList code can be refactor with new specific class
125             // which implement TransportZoneValidator
126             List<DPNTEPsInfo> opDpnList = createDPNTepInfo(tzOld);
127             List<HwVtep> hwVtepList = createhWVteps(tzOld);
128             LOG.trace("Delete: Invoking deleteTunnels in ItmManager with DpnList {}", opDpnList);
129             if(!opDpnList.isEmpty() || !hwVtepList.isEmpty()) {
130                 LOG.trace("Delete: Invoking ItmManager with hwVtep List {} " , hwVtepList);
131                 DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
132                 ItmTepRemoveWorker removeWorker =
133                         new ItmTepRemoveWorker(opDpnList, hwVtepList, tzOld, dataBroker, idManagerService, mdsalManager);
134                 coordinator.enqueueJob(tzOld.getZoneName(), removeWorker);
135             }
136         }
137     }
138
139     @Override
140     protected void update(InstanceIdentifier<TransportZone> key, TransportZone tzOld, TransportZone tzNew) {
141         LOG.debug("Received Transport Zone Update Event: Key - {}, Old - {}, Updated - {}", key, tzOld, tzNew);
142         List<DPNTEPsInfo> oldDpnTepsList = createDPNTepInfo(tzOld);
143         List<DPNTEPsInfo> newDpnTepsList = createDPNTepInfo(tzNew);
144         List<DPNTEPsInfo> oldDpnTepsListcopy = new ArrayList<>();
145         oldDpnTepsListcopy.addAll(oldDpnTepsList);
146         LOG.trace("oldcopy0" + oldDpnTepsListcopy);
147         List<DPNTEPsInfo> newDpnTepsListcopy = new ArrayList<>();
148         newDpnTepsListcopy.addAll(newDpnTepsList);
149         LOG.trace("newcopy0" + newDpnTepsListcopy);
150         DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
151
152         oldDpnTepsList.removeAll(newDpnTepsListcopy);
153         newDpnTepsList.removeAll(oldDpnTepsListcopy);
154
155         LOG.trace("oldDpnTepsList" + oldDpnTepsList);
156         LOG.trace("newDpnTepsList" + newDpnTepsList);
157         LOG.trace("oldcopy" + oldDpnTepsListcopy);
158         LOG.trace("newcopy" + newDpnTepsListcopy);
159         LOG.trace("oldcopy Size " + oldDpnTepsList.size());
160         LOG.trace("newcopy Size " + newDpnTepsList.size());
161         if (!newDpnTepsList.isEmpty()) {
162             LOG.trace("Adding TEPs ");
163             ItmTepAddWorker addWorker = new ItmTepAddWorker(newDpnTepsList, Collections.emptyList(), dataBroker,
164                     idManagerService, mdsalManager);
165             coordinator.enqueueJob(tzNew.getZoneName(), addWorker);
166         }
167         if (!oldDpnTepsList.isEmpty()) {
168             LOG.trace("Removing TEPs ");
169             ItmTepRemoveWorker removeWorker = new ItmTepRemoveWorker(oldDpnTepsList, Collections.emptyList(),
170                     tzOld, dataBroker, idManagerService, mdsalManager);
171             coordinator.enqueueJob(tzNew.getZoneName(), removeWorker);
172         }
173         List<HwVtep> oldHwList = createhWVteps(tzOld);
174         List<HwVtep> newHwList = createhWVteps(tzNew);
175         List<HwVtep> oldHwListcopy = new ArrayList<>();
176         oldHwListcopy.addAll(oldHwList);
177         LOG.trace("oldHwListcopy0" + oldHwListcopy);
178         List<HwVtep> newHwListcopy = new ArrayList<>();
179         newHwListcopy.addAll(newHwList);
180         LOG.trace("newHwListcopy0" + newHwListcopy);
181
182         oldHwList.removeAll(newHwListcopy);
183         newHwList.removeAll(oldHwListcopy);
184         LOG.trace("oldHwList" + oldHwList);
185         LOG.trace("newHwList" + newHwList);
186         LOG.trace("oldHwListcopy" + oldHwListcopy);
187         LOG.trace("newHwListcopy" + newHwListcopy);
188         if (!newHwList.isEmpty()) {
189             LOG.trace("Adding HW TEPs ");
190             ItmTepAddWorker addWorker = new ItmTepAddWorker(Collections.emptyList(), newHwList, dataBroker,
191                     idManagerService, mdsalManager);
192             coordinator.enqueueJob(tzNew.getZoneName(), addWorker);
193         }
194         if (!oldHwList.isEmpty()) {
195             LOG.trace("Removing HW TEPs ");
196             ItmTepRemoveWorker removeWorker = new ItmTepRemoveWorker(Collections.emptyList(), oldHwList,
197                     tzOld, dataBroker, idManagerService, mdsalManager);
198             coordinator.enqueueJob(tzNew.getZoneName(), removeWorker);
199         }
200     }
201
202     @Override
203     protected void add(InstanceIdentifier<TransportZone> key, TransportZone tzNew) {
204         LOG.debug("Received Transport Zone Add Event: {}, {}", key, tzNew);
205         List<DPNTEPsInfo> opDpnList = createDPNTepInfo(tzNew);
206         List<HwVtep> hwVtepList = createhWVteps(tzNew);
207         LOG.trace("Add: Operational dpnTepInfo - Before invoking ItmManager {}", opDpnList);
208         if (!opDpnList.isEmpty() || !hwVtepList.isEmpty()) {
209             LOG.trace("Add: Invoking ItmManager with DPN List {} ", opDpnList);
210             LOG.trace("Add: Invoking ItmManager with hwVtep List {} ", hwVtepList);
211             DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
212             ItmTepAddWorker addWorker = new ItmTepAddWorker(opDpnList, hwVtepList, dataBroker, idManagerService,
213                     mdsalManager);
214             coordinator.enqueueJob(tzNew.getZoneName(), addWorker);
215         }
216     }
217
218     private List<DPNTEPsInfo> createDPNTepInfo(TransportZone transportZone) {
219         Map<BigInteger, List<TunnelEndPoints>> mapDPNToTunnelEndpt = new ConcurrentHashMap<>();
220         List<DPNTEPsInfo> dpnTepInfo = new ArrayList<>();
221         List<TzMembership> zones = ItmUtils.createTransportZoneMembership(transportZone.getZoneName());
222         Class<? extends TunnelTypeBase> tunnelType = transportZone.getTunnelType();
223         LOG.trace("Transport Zone_name: {}", transportZone.getZoneName());
224         List<Subnets> subnetsList = transportZone.getSubnets();
225         if (subnetsList != null) {
226             for (Subnets subnet : subnetsList) {
227                 IpPrefix ipPrefix = subnet.getPrefix();
228                 IpAddress gatewayIP = subnet.getGatewayIp();
229                 int vlanID = subnet.getVlanId();
230                 LOG.trace("IpPrefix: {}, gatewayIP: {}, vlanID: {} ", ipPrefix, gatewayIP, vlanID);
231                 List<Vteps> vtepsList = subnet.getVteps();
232                 if (vtepsList != null && !vtepsList.isEmpty()) {
233                     for (Vteps vteps : vtepsList) {
234                         BigInteger dpnID = vteps.getDpnId();
235                         String port = vteps.getPortname();
236                         IpAddress ipAddress = vteps.getIpAddress();
237                         boolean useOfTunnel = ItmUtils.falseIfNull(vteps.isOptionOfTunnel());
238                         LOG.trace("DpnID: {}, port: {}, ipAddress: {}", dpnID, port, ipAddress);
239                         TunnelEndPoints tunnelEndPoints = ItmUtils.createTunnelEndPoints(dpnID, ipAddress, port,
240                             useOfTunnel, vlanID,  ipPrefix, gatewayIP, zones, tunnelType);
241                         List<TunnelEndPoints> tunnelEndPointsList = mapDPNToTunnelEndpt.get(dpnID);
242                         if (tunnelEndPointsList != null) {
243                             LOG.trace("Existing DPN info list in the Map: {} ", dpnID);
244                             tunnelEndPointsList.add(tunnelEndPoints);
245                         } else {
246                             LOG.trace("Adding new DPN info list to the Map: {} ", dpnID);
247                             tunnelEndPointsList = new ArrayList<>();
248                             tunnelEndPointsList.add(tunnelEndPoints);
249                             mapDPNToTunnelEndpt.put(dpnID, tunnelEndPointsList);
250                         }
251                     }
252                 }
253             }
254         }
255
256         if (!mapDPNToTunnelEndpt.isEmpty()) {
257             Set<BigInteger> keys = mapDPNToTunnelEndpt.keySet();
258             LOG.trace("List of dpns in the Map: {} ", keys);
259             for (BigInteger key : keys) {
260                 DPNTEPsInfo newDpnTepsInfo = ItmUtils.createDPNTepInfo(key, mapDPNToTunnelEndpt.get(key));
261                 dpnTepInfo.add(newDpnTepsInfo);
262             }
263         }
264         return dpnTepInfo;
265     }
266
267     private List<HwVtep> createhWVteps(TransportZone transportZone) {
268         List<HwVtep> hwVtepsList = new ArrayList<>();
269
270         String zoneName = transportZone.getZoneName();
271         Class<? extends TunnelTypeBase> tunnelType = transportZone.getTunnelType();
272         LOG.trace("Transport Zone_name: {}", zoneName);
273         List<Subnets> subnetsList = transportZone.getSubnets();
274         if (subnetsList != null) {
275             for (Subnets subnet : subnetsList) {
276                 IpPrefix ipPrefix = subnet.getPrefix();
277                 IpAddress gatewayIP = subnet.getGatewayIp();
278                 int vlanID = subnet.getVlanId();
279                 LOG.trace("IpPrefix: {}, gatewayIP: {}, vlanID: {} ", ipPrefix, gatewayIP, vlanID);
280                 List<DeviceVteps> deviceVtepsList = subnet.getDeviceVteps();
281                 if (deviceVtepsList != null) {
282                     for (DeviceVteps vteps : deviceVtepsList) {
283                         String topologyId = vteps.getTopologyId();
284                         String nodeId = vteps.getNodeId();
285                         IpAddress ipAddress = vteps.getIpAddress();
286                         LOG.trace("topo-id: {}, node-id: {}, ipAddress: {}", topologyId, nodeId, ipAddress);
287                         HwVtep hwVtep = ItmUtils.createHwVtepObject(topologyId, nodeId, ipAddress, ipPrefix, gatewayIP,
288                                 vlanID, tunnelType, transportZone);
289
290                         if (hwVtepsList != null) {
291                             LOG.trace("Existing hwVteps");
292                             hwVtepsList.add(hwVtep);
293                         } else {
294                             LOG.trace("Adding new HwVtep {} info ", hwVtep.getHwIp());
295                             hwVtepsList.add(hwVtep);
296                         }
297                     }
298                 }
299             }
300         }
301         LOG.trace("returning hwvteplist {}", hwVtepsList);
302         return hwVtepsList;
303     }
304
305     private boolean validateTransportZoneParam(TransportZone transportZone) {
306         boolean validateParam = true;
307         ArrayList<TransportZoneValidator> tzValidatorList = new ArrayList<>();
308         tzValidatorList.add(new TransportZoneNameAllowed());
309         for(TransportZoneValidator tzValidator :tzValidatorList){
310             if(tzValidator.validate(transportZone) == ValidatorErrorCode.ERROR){
311                 validateParam = false;
312                 break;
313             }
314         }
315         return validateParam;
316     }
317 }