Bump versions by 0.1.0 for next dev cycle
[unimgr.git] / netvirt / src / main / java / org / opendaylight / unimgr / mef / netvirt / EvcUniListener.java
1 /*
2  * Copyright (c) 2016 Hewlett Packard Enterprise, Co. 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.unimgr.mef.netvirt;
10
11 import java.util.Collections;
12 import java.util.List;
13 import java.util.Set;
14
15 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
16 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
17 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
18 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
21 import org.opendaylight.genius.interfacemanager.globals.IfmConstants;
22 import org.opendaylight.unimgr.api.UnimgrDataTreeChangeListener;
23 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.uni.PhysicalLayers;
24 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.uni.physical.layers.Links;
25 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.uni.physical.layers.links.Link;
26 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.services.rev150526.MefServices;
27 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.services.rev150526.mef.services.MefService;
28 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.services.rev150526.mef.services.mef.service.Evc;
29 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.services.rev150526.mef.services.mef.service.evc.Unis;
30 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.services.rev150526.mef.services.mef.service.evc.unis.Uni;
31 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.services.rev150526.mef.services.mef.service.evc.unis.uni.EvcUniCeVlans;
32 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.services.rev150526.mef.services.mef.service.evc.unis.uni.evc.uni.ce.vlans.EvcUniCeVlan;
33 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.types.rev150526.VlanIdType;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
37 import org.opendaylight.yangtools.concepts.ListenerRegistration;
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 import com.google.common.base.Objects;
43 import com.google.common.base.Optional;
44 import com.google.common.collect.Sets;
45 import com.google.common.util.concurrent.CheckedFuture;
46
47 public class EvcUniListener extends UnimgrDataTreeChangeListener<Uni> {
48     private static final Logger logger = LoggerFactory.getLogger(EvcUniListener.class);
49
50     private ListenerRegistration<EvcUniListener> uniListenerRegistration;
51
52     public EvcUniListener(final DataBroker dataBroker) {
53         super(dataBroker);
54
55         registerListener();
56     }
57
58     @Override
59     public void add(DataTreeModification<Uni> newDataObject) {
60         if (newDataObject.getRootPath() != null && newDataObject.getRootNode() != null) {
61             logger.info("uni {} created", newDataObject.getRootNode().getIdentifier());
62             addUni(newDataObject);
63         }
64     }
65
66     @Override
67     public void remove(DataTreeModification<Uni> removedDataObject) {
68         if (removedDataObject.getRootPath() != null && removedDataObject.getRootNode() != null) {
69             logger.info("uni {} deleted", removedDataObject.getRootNode().getIdentifier());
70             removeUni(removedDataObject);
71         }
72     }
73
74     @Override
75     public void update(DataTreeModification<Uni> modifiedDataObject) {
76         if (modifiedDataObject.getRootPath() != null && modifiedDataObject.getRootNode() != null) {
77             logger.info("uni {} updated", modifiedDataObject.getRootNode().getIdentifier());
78             updateUni(modifiedDataObject);
79         }
80     }
81
82     protected void removeUni(DataTreeModification<Uni> removedDataObject) {
83         try {
84             Uni data = removedDataObject.getRootNode().getDataBefore();
85
86             String uniId = data.getUniId().getValue();
87             WriteTransaction tx = createTransaction();
88             logger.info("Removing trunk {}", uniId);
89             delete(uniId, tx);
90
91             Optional<List<EvcUniCeVlan>> ceVlansOptional = getCeVlans(data);
92             if (!ceVlansOptional.isPresent()) {
93                 return;
94             }
95
96             removeTrunkMemberInterfaces(uniId, ceVlansOptional.get(), tx);
97             commitTransaction(tx);
98         } catch (final Exception e) {
99             logger.error("Remove uni failed !", e);
100         }
101     }
102
103     protected void updateUni(DataTreeModification<Uni> modifiedDataObject) {
104         try {
105             Uni original = modifiedDataObject.getRootNode().getDataBefore();
106             Uni update = modifiedDataObject.getRootNode().getDataAfter();
107
108             String uniId = update.getUniId().getValue();
109             WriteTransaction tx = createTransaction();
110             String origTrunkParentName = getTrunkParentName(original);
111             String updatedTrunkParentName = getTrunkParentName(update);
112
113             if (!Objects.equal(origTrunkParentName, updatedTrunkParentName)) {
114                 addTrunkInterface(uniId, updatedTrunkParentName, tx);
115             }
116
117             Set<EvcUniCeVlan> origCeVlans = Sets.newHashSet(getCeVlans(original).or(Collections.emptyList()));
118             Set<EvcUniCeVlan> updatedCeVlans = Sets.newHashSet(getCeVlans(update).or(Collections.emptyList()));
119             Iterable<EvcUniCeVlan> removedCeVlans = Sets.difference(origCeVlans, updatedCeVlans);
120             Iterable<EvcUniCeVlan> addedCeVlans = Sets.difference(updatedCeVlans, origCeVlans);
121             removeTrunkMemberInterfaces(uniId, removedCeVlans, tx);
122             addTrunkMemberInterfaces(uniId, addedCeVlans, tx);
123             commitTransaction(tx);
124         } catch (final Exception e) {
125             logger.error("Update uni failed !", e);
126         }
127
128     }
129
130     protected void addUni(DataTreeModification<Uni> newDataObject) {
131         try {
132             Uni data = newDataObject.getRootNode().getDataAfter();
133
134             String uniId = data.getUniId().getValue();
135             WriteTransaction tx = createTransaction();
136             addTrunkInterface(uniId, getTrunkParentName(data), tx);
137
138             Optional<List<EvcUniCeVlan>> ceVlansOptional = getCeVlans(data);
139             if (ceVlansOptional.isPresent()) {
140                 addTrunkMemberInterfaces(uniId, ceVlansOptional.get(), tx);
141             }
142
143             commitTransaction(tx);
144         } catch (final Exception e) {
145             logger.error("Add uni failed !", e);
146         }
147
148     }
149
150     private void addTrunkInterface(String interfaceName, String parentInterfaceName, WriteTransaction tx) {
151         logger.info("Adding VLAN trunk {} ParentRef {}", interfaceName, parentInterfaceName);
152         Interface trunkInterface = NetvirtUtils.createTrunkInterface(interfaceName, parentInterfaceName);
153         write(trunkInterface, tx);
154     }
155
156     private void addTrunkMemberInterfaces(String parentInterfaceName, Iterable<EvcUniCeVlan> ceVlans,
157             WriteTransaction tx) {
158         for (EvcUniCeVlan ceVlan : ceVlans) {
159             Long vlanId = ((VlanIdType) ceVlan.getVid()).getValue();
160             String interfaceName = NetvirtUtils.getInterfaceNameForVlan(parentInterfaceName, vlanId.toString());
161             logger.info("Adding VLAN trunk-member {} ParentRef {}", interfaceName, parentInterfaceName);
162             Interface trunkMemberInterface = NetvirtUtils.createTrunkMemberInterface(interfaceName, parentInterfaceName,
163                     vlanId.intValue());
164             write(trunkMemberInterface, tx);
165         }
166     }
167
168     private void removeTrunkMemberInterfaces(String parentInterfaceName, Iterable<EvcUniCeVlan> ceVlans,
169             WriteTransaction tx) {
170         for (EvcUniCeVlan ceVlan : ceVlans) {
171             Long vlanId = ((VlanIdType) ceVlan.getVid()).getValue();
172             String interfaceName = NetvirtUtils.getInterfaceNameForVlan(parentInterfaceName, vlanId.toString());
173             logger.info("Removing VLAN trunk-member {}", interfaceName);
174             delete(interfaceName, tx);
175         }
176     }
177
178     private InstanceIdentifier<Interface> createInterfaceIdentifier(String interfaceName) {
179         return InstanceIdentifier.builder(Interfaces.class).child(Interface.class, new InterfaceKey(interfaceName))
180                 .build();
181     }
182
183     private WriteTransaction createTransaction() {
184         WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
185         return tx;
186     }
187
188     private void commitTransaction(WriteTransaction tx) {
189         try {
190             CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
191             futures.get();
192         } catch (Exception e) {
193             logger.error("failed to commit transaction due to exception ", e);
194         }
195     }
196
197     private void write(Interface iface, WriteTransaction tx) {
198         String interfaceName = iface.getName();
199         InstanceIdentifier<Interface> interfaceIdentifier = createInterfaceIdentifier(interfaceName);
200         tx.put(LogicalDatastoreType.CONFIGURATION, interfaceIdentifier, iface, true);
201     }
202
203     private void delete(String interfaceName, WriteTransaction tx) {
204         InstanceIdentifier<Interface> interfaceIdentifier = createInterfaceIdentifier(interfaceName);
205         tx.delete(LogicalDatastoreType.CONFIGURATION, interfaceIdentifier);
206     }
207
208     private String getTrunkParentName(Uni evcUni) {
209
210         Optional<org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.Uni> optional = MdsalUtils
211                 .read(dataBroker, LogicalDatastoreType.CONFIGURATION,
212                         MefUtils.getUniInstanceIdentifier(evcUni.getUniId().getValue()));
213
214         if (!optional.isPresent()) {
215             logger.error("A matching Uni doesn't exist for EvcUni {}", evcUni.getUniId());
216             return null;
217         }
218
219         org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.Uni uni = optional
220                 .get();
221
222         PhysicalLayers physicalLayers = uni.getPhysicalLayers();
223         if (physicalLayers == null) {
224             logger.warn("Uni {} is missing PhysicalLayers", evcUni.getUniId());
225             return null;
226         }
227
228         Links links = physicalLayers.getLinks();
229         if (links == null || links.getLink() == null) {
230             logger.warn("Uni {} is has no links", evcUni.getUniId());
231             return null;
232         }
233
234         Link link = links.getLink().get(0);
235         String deviceName = link.getDevice().getValue();
236         String interfaceName = link.getInterface().toString();
237         return getDeviceInterfaceName(deviceName, interfaceName);
238     }
239
240     private String getDeviceInterfaceName(String deviceName, String interfaceName) {
241         return deviceName + IfmConstants.OF_URI_SEPARATOR + interfaceName;
242     }
243
244     private Optional<List<EvcUniCeVlan>> getCeVlans(Uni uni) {
245         EvcUniCeVlans ceVlans = uni.getEvcUniCeVlans();
246         if (ceVlans == null) {
247             return Optional.absent();
248         }
249
250         return Optional.fromNullable(ceVlans.getEvcUniCeVlan());
251     }
252
253     private void registerListener() {
254         try {
255             final DataTreeIdentifier<Uni> dataTreeIid = new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
256                     getUniTopologyPath());
257             uniListenerRegistration = dataBroker.registerDataTreeChangeListener(dataTreeIid, this);
258             logger.info("UniDataTreeChangeListener created and registered");
259         } catch (final Exception e) {
260             logger.error("Uni DataChange listener registration failed !", e);
261             throw new IllegalStateException("Uni registration Listener failed.", e);
262         }
263     }
264
265     private InstanceIdentifier<Uni> getUniTopologyPath() {
266         return InstanceIdentifier.create(MefServices.class).child(MefService.class).child(Evc.class).child(Unis.class)
267                 .child(Uni.class);
268     }
269
270     @Override
271     public void close() throws Exception {
272         // TODO Auto-generated method stub
273
274     }
275 }