0b2136a77d6868d0a1f9112c43e6f3a843621bfa
[unimgr.git] / netvirt / src / main / java / org / opendaylight / unimgr / mef / netvirt / NodeConnectorListener.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.ArrayList;
12 import java.util.List;
13 import java.util.concurrent.ExecutionException;
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;
24 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.UniBuilder;
25 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.uni.PhysicalLayersBuilder;
26 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.uni.physical.layers.LinksBuilder;
27 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.uni.physical.layers.links.Link;
28 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.uni.physical.layers.links.LinkBuilder;
29 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.topology.rev150526.mef.topology.devices.device.interfaces.Interface;
30 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.topology.rev150526.mef.topology.devices.device.interfaces.InterfaceBuilder;
31 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.types.rev150526.Identifier45;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.config.rev150710.ElanConfig;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.config.rev150710.ElanConfigBuilder;
39 import org.opendaylight.yangtools.concepts.ListenerRegistration;
40 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 import com.google.common.util.concurrent.CheckedFuture;
45
46 public class NodeConnectorListener extends UnimgrDataTreeChangeListener<FlowCapableNodeConnector> {
47
48     private static final String BRIDGE_PREFIX = "br-";
49     private static final String TUNNEL_PREFIX = "tun";
50     private static final Logger log = LoggerFactory.getLogger(NodeConnectorListener.class);
51     private final UniPortManager uniPortManager;
52     private ListenerRegistration<NodeConnectorListener> nodeConnectorListenerRegistration;
53
54     public NodeConnectorListener(final DataBroker dataBroker, final UniPortManager uniPortManager) {
55         super(dataBroker);
56         this.uniPortManager = uniPortManager;
57         registerListener();
58     }
59
60     public void registerListener() {
61         try {
62             final DataTreeIdentifier<FlowCapableNodeConnector> dataTreeIid = new DataTreeIdentifier<>(
63                     LogicalDatastoreType.OPERATIONAL, getInstanceIdentifier());
64             nodeConnectorListenerRegistration = dataBroker.registerDataTreeChangeListener(dataTreeIid, this);
65             log.info("NodeConnectorListener created and registered");
66         } catch (final Exception e) {
67             log.error("Node connector listener registration failed !", e);
68             throw new IllegalStateException("Node connector listener registration failed.", e);
69         }
70     }
71
72     @SuppressWarnings("deprecation")
73     private InstanceIdentifier<FlowCapableNodeConnector> getInstanceIdentifier() {
74         return InstanceIdentifier.create(Nodes.class).child(Node.class).child(NodeConnector.class)
75                 .augmentation(FlowCapableNodeConnector.class);
76     }
77
78     @Override
79     public void close() throws Exception {
80         nodeConnectorListenerRegistration.close();
81     }
82
83     @Override
84     public void add(DataTreeModification<FlowCapableNodeConnector> newDataObject) {
85         if (newDataObject.getRootPath() != null && newDataObject.getRootNode() != null) {
86             log.info("node connector {} created", newDataObject.getRootNode().getIdentifier());
87             addFlowCapableNodeConnector(newDataObject);
88         }
89     }
90
91     @Override
92     public void remove(DataTreeModification<FlowCapableNodeConnector> removedDataObject) {
93         if (removedDataObject.getRootPath() != null && removedDataObject.getRootNode() != null) {
94             log.info("node connector {} deleted", removedDataObject.getRootNode().getIdentifier());
95             removeFlowCapableNodeConnector(removedDataObject);
96         }
97     }
98
99     @Override
100     public void update(DataTreeModification<FlowCapableNodeConnector> modifiedDataObject) {
101         if (modifiedDataObject.getRootPath() != null && modifiedDataObject.getRootNode() != null) {
102             log.info("node connector {} updated", modifiedDataObject.getRootNode().getIdentifier());
103             updateFlowCapableNodeConnector(modifiedDataObject);
104         }
105     }
106
107     private void addFlowCapableNodeConnector(DataTreeModification<FlowCapableNodeConnector> newDataObject) {
108         try {
109             FlowCapableNodeConnector data = newDataObject.getRootNode().getDataAfter();
110
111             String dpnFromNodeConnectorId = getDpnIdFromNodeConnector(newDataObject);
112
113             handleNodeConnectorAdded(dataBroker, dpnFromNodeConnectorId, data);
114         } catch (final Exception e) {
115             log.error("Add node connector failed !", e);
116         }
117     }
118
119     private void removeFlowCapableNodeConnector(DataTreeModification<FlowCapableNodeConnector> removedDataObject) {
120         try {
121             FlowCapableNodeConnector data = removedDataObject.getRootNode().getDataBefore();
122
123             String dpnFromNodeConnectorId = getDpnIdFromNodeConnector(removedDataObject);
124
125             handleNodeConnectorRemoved(dataBroker, dpnFromNodeConnectorId, data);
126         } catch (final Exception e) {
127             log.error("Remove node connector failed !", e);
128         }
129     }
130
131     private void updateFlowCapableNodeConnector(DataTreeModification<FlowCapableNodeConnector> modifiedDataObject) {
132         try {
133             FlowCapableNodeConnector original = modifiedDataObject.getRootNode().getDataBefore();
134             FlowCapableNodeConnector update = modifiedDataObject.getRootNode().getDataAfter();
135
136             String dpnFromNodeConnectorId = getDpnIdFromNodeConnector(modifiedDataObject);
137
138             handleNodeConnectorUpdated(dataBroker, dpnFromNodeConnectorId, original, update);
139         } catch (final Exception e) {
140             log.error("Update node connector failed !", e);
141         }
142     }
143
144     @SuppressWarnings("deprecation")
145     private String getDpnIdFromNodeConnector(DataTreeModification<FlowCapableNodeConnector> newDataObject) {
146         InstanceIdentifier<FlowCapableNodeConnector> key = newDataObject.getRootPath().getRootIdentifier();
147         NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(key.firstIdentifierOf(NodeConnector.class)).getId();
148
149         String dpnFromNodeConnectorId = getDpnFromNodeConnectorId(nodeConnectorId);
150         return dpnFromNodeConnectorId;
151     }
152
153     @SuppressWarnings("deprecation")
154     private static String getDpnFromNodeConnectorId(NodeConnectorId portId) {
155         /*
156          * NodeConnectorId is of form 'openflow:dpnid:portnum'
157          */
158         String[] split = portId.getValue().split(IfmConstants.OF_URI_SEPARATOR);
159         return split[1];
160     }
161
162     private void handleNodeConnectorAdded(DataBroker dataBroker, String dpnId, FlowCapableNodeConnector nodeConnector) {
163
164         String uniName = MefInterfaceUtils.getDeviceInterfaceName(dpnId, nodeConnector.getName());
165
166         if (shouldFilterOutNodeConnector(uniName)) {
167             log.info("filtered out interface {} with device {}", nodeConnector.getName(), dpnId);
168             return;
169         }
170
171         WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
172
173         log.info("Adding mef uni/device interface {} with device {}", nodeConnector.getName(), dpnId);
174
175         InstanceIdentifier<Interface> interfacePath = MefInterfaceUtils.getDeviceInterfaceInstanceIdentifier(dpnId,
176                 uniName);
177         InterfaceBuilder interfaceBuilder = new InterfaceBuilder();
178         interfaceBuilder.setPhy(new Identifier45(uniName));
179         Interface deviceInterface = interfaceBuilder.build();
180         tx.merge(LogicalDatastoreType.OPERATIONAL, interfacePath, deviceInterface, true);
181
182         InstanceIdentifier<Uni> uniPath = MefInterfaceUtils.getUniInstanceIdentifier(uniName);
183         UniBuilder uniBuilder = new UniBuilder();
184         uniBuilder.setUniId(new Identifier45(uniName));
185         uniBuilder.setMacAddress(nodeConnector.getHardwareAddress());
186
187         PhysicalLayersBuilder physicalLayersBuilder = new PhysicalLayersBuilder();
188         LinksBuilder linksBuilder = new LinksBuilder();
189         List<Link> links = new ArrayList<>();
190         LinkBuilder linkBuilder = new LinkBuilder();
191         linkBuilder.setDevice(new Identifier45(dpnId));
192         linkBuilder.setInterface(uniName);
193         links.add(linkBuilder.build());
194         linksBuilder.setLink(links);
195         physicalLayersBuilder.setLinks(linksBuilder.build());
196         uniBuilder.setPhysicalLayers(physicalLayersBuilder.build());
197         Uni uni = uniBuilder.build();
198         tx.merge(LogicalDatastoreType.OPERATIONAL, uniPath, uni, true);
199
200         CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
201         try {
202             futures.get();
203         } catch (InterruptedException | ExecutionException e) {
204             log.error("Error writing to datastore (path, data) : ({}, {}), ({}, {})", interfacePath, deviceInterface,
205                     uniPath, uni);
206             throw new RuntimeException(e.getMessage());
207         }
208
209         // Reply UNI port configuration
210         uniPortManager.updateOperUni(uni.getUniId().getValue());
211     }
212
213     private void handleNodeConnectorRemoved(DataBroker dataBroker, String dpnId,
214             FlowCapableNodeConnector nodeConnector) {
215
216         String uniName = MefInterfaceUtils.getDeviceInterfaceName(dpnId, nodeConnector.getName());
217         InstanceIdentifier<Interface> interfacePath = MefInterfaceUtils.getDeviceInterfaceInstanceIdentifier(dpnId,
218                 uniName);
219         if (MefInterfaceUtils.getInterface(dataBroker, dpnId, uniName, LogicalDatastoreType.OPERATIONAL) != null) {
220             MdsalUtils.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, interfacePath);
221         }
222
223         // Reply UNI port configuration
224         uniPortManager.removeUniPorts(uniName);
225         InstanceIdentifier<Uni> uniPath = MefInterfaceUtils.getUniInstanceIdentifier(uniName);
226         if (MefInterfaceUtils.getUni(dataBroker, uniName, LogicalDatastoreType.OPERATIONAL) != null) {
227             MdsalUtils.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, uniPath);
228         }
229     }
230
231     private void handleNodeConnectorUpdated(DataBroker dataBroker, String dpnFromNodeConnectorId,
232             FlowCapableNodeConnector original, FlowCapableNodeConnector update) {
233
234     }
235
236     private boolean shouldFilterOutNodeConnector(String interfaceName) {
237         String[] splits = interfaceName.split(":");
238         return splits.length > 1 && (splits[1].startsWith(TUNNEL_PREFIX) || splits[1].startsWith(BRIDGE_PREFIX));
239     }
240 }