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