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