2 * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
9 package org.opendaylight.ovsdb.hwvtepsouthbound;
11 import java.net.UnknownHostException;
12 import java.util.Collection;
13 import java.util.HashMap;
15 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
16 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
17 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType;
18 import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
19 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
20 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.ovsdb.lib.OvsdbClient;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.ConnectionInfo;
25 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
26 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
27 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
28 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
29 import org.opendaylight.yangtools.concepts.ListenerRegistration;
30 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
34 public class HwvtepDataChangeListener implements DataTreeChangeListener<Node>, AutoCloseable {
36 private ListenerRegistration<HwvtepDataChangeListener> registration;
37 private HwvtepConnectionManager hcm;
38 private DataBroker db;
39 private static final Logger LOG = LoggerFactory.getLogger(HwvtepDataChangeListener.class);
41 HwvtepDataChangeListener(DataBroker db, HwvtepConnectionManager hcm) {
42 LOG.info("Registering HwvtepDataChangeListener");
48 private void registerListener(final DataBroker db) {
49 final DataTreeIdentifier<Node> treeId =
50 new DataTreeIdentifier<Node>(LogicalDatastoreType.CONFIGURATION, getWildcardPath());
52 LOG.trace("Registering on path: {}", treeId);
53 registration = db.registerDataTreeChangeListener(treeId, HwvtepDataChangeListener.this);
54 } catch (final Exception e) {
55 LOG.warn("HwvtepDataChangeListener registration failed");
56 //TODO: Should we throw an exception here?
61 public void close() throws Exception {
62 if(registration != null) {
68 public void onDataTreeChanged(Collection<DataTreeModification<Node>> changes) {
69 LOG.trace("onDataTreeChanged: {}", changes);
72 * Currently only handling changes to Global.
73 * Rest will be added later.
77 updateConnections(changes);
83 for (DataTreeModification<Node> change : changes) {
84 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
85 final DataObjectModification<Node> mod = change.getRootNode();
86 switch (mod.getModificationType()) {
88 LOG.trace("Data deleted: {}", mod.getDataBefore());
91 case SUBTREE_MODIFIED:
92 LOG.trace("Data modified: {} to {}", mod.getDataBefore(),mod.getDataAfter());
93 updateConnections(mod);
96 if (mod.getDataBefore() == null) {
97 LOG.trace("Data added: {}", mod.getDataAfter());
98 connect(mod.getDataAfter());
100 LOG.trace("Data modified: {} to {}", mod.getDataBefore(),mod.getDataAfter());
101 updateConnections(mod);
105 throw new IllegalArgumentException("Unhandled modification type " + mod.getModificationType());
111 private void connect(Collection<DataTreeModification<Node>> changes) {
112 for (DataTreeModification<Node> change : changes) {
113 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
114 final DataObjectModification<Node> mod = change.getRootNode();
115 Node node = getCreated(mod);
117 HwvtepGlobalAugmentation hwvtepGlobal = node.getAugmentation(HwvtepGlobalAugmentation.class);
118 ConnectionInfo connection = hwvtepGlobal.getConnectionInfo();
119 InstanceIdentifier<Node> iid = hcm.getInstanceIdentifier(connection);
121 LOG.warn("Connection to device {} already exists. Plugin does not allow multiple connections "
122 + "to same device, hence dropping the request {}", connection, hwvtepGlobal);
125 hcm.connect(HwvtepSouthboundMapper.createInstanceIdentifier(node.getNodeId()), hwvtepGlobal);
126 } catch (UnknownHostException e) {
127 LOG.warn("Failed to connect to OVSDB node", e);
135 private void updateConnections(Collection<DataTreeModification<Node>> changes) {
136 for (DataTreeModification<Node> change : changes) {
137 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
138 final DataObjectModification<Node> mod = change.getRootNode();
139 Node updated = getUpdated(mod);
140 if (updated != null) {
141 Node original = getOriginal(mod);
142 HwvtepGlobalAugmentation hgUpdated = updated.getAugmentation(HwvtepGlobalAugmentation.class);
143 HwvtepGlobalAugmentation hgOriginal = original.getAugmentation(HwvtepGlobalAugmentation.class);
144 OvsdbClient client = hcm.getClient(hgUpdated.getConnectionInfo());
145 if (client == null) {
147 hcm.disconnect(hgOriginal);
148 hcm.connect(HwvtepSouthboundMapper.createInstanceIdentifier(original.getNodeId()), hgUpdated);
149 } catch (UnknownHostException e) {
150 LOG.warn("Failed to update connection on OVSDB Node", e);
158 private void updateData(Collection<DataTreeModification<Node>> changes) {
160 * Get connection instances for each change
161 * Update data for each connection
162 * Requires Command patterns. TBD.
164 connectionInstancesFromChanges(changes);
165 /*for (Entry<InstanceIdentifier<Node>, HwvtepConnectionInstance> connectionInstanceEntry :
166 connectionInstancesFromChanges(changes).entrySet()) {
171 private void disconnect(Collection<DataTreeModification<Node>> changes) {
172 for (DataTreeModification<Node> change : changes) {
173 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
174 final DataObjectModification<Node> mod = change.getRootNode();
175 Node deleted = getRemoved(mod);
176 if (deleted != null) {
177 HwvtepGlobalAugmentation hgDeleted = deleted.getAugmentation(HwvtepGlobalAugmentation.class);
179 hcm.disconnect(hgDeleted);
180 } catch (UnknownHostException e) {
181 LOG.warn("Failed to disconnect OVSDB Node", e);
187 private Node getCreated(DataObjectModification<Node> mod) {
188 if((mod.getModificationType() == ModificationType.WRITE)
189 && (mod.getDataBefore() == null)){
190 return mod.getDataAfter();
195 private Node getRemoved(DataObjectModification<Node> mod) {
196 if(mod.getModificationType() == ModificationType.DELETE){
197 return mod.getDataBefore();
202 private Node getUpdated(DataObjectModification<Node> mod) {
204 switch(mod.getModificationType()) {
205 case SUBTREE_MODIFIED:
206 node = mod.getDataAfter();
209 if(mod.getDataBefore() != null) {
210 node = mod.getDataAfter();
219 private Node getOriginal(DataObjectModification<Node> mod) {
221 switch(mod.getModificationType()) {
222 case SUBTREE_MODIFIED:
223 node = mod.getDataBefore();
226 if(mod.getDataBefore() != null) {
227 node = mod.getDataBefore();
231 node = mod.getDataBefore();
239 private InstanceIdentifier<Node> getWildcardPath() {
240 InstanceIdentifier<Node> path = InstanceIdentifier
241 .create(NetworkTopology.class)
242 .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID))
247 public Map<InstanceIdentifier<Node>, HwvtepConnectionInstance> connectionInstancesFromChanges(
248 Collection<DataTreeModification<Node>> changes) {
249 Map<InstanceIdentifier<Node>, HwvtepConnectionInstance> result =
250 new HashMap<InstanceIdentifier<Node>, HwvtepConnectionInstance>();
251 for (DataTreeModification<Node> change : changes) {
252 final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
253 final DataObjectModification<Node> mod = change.getRootNode();
254 Node created = getCreated(mod);
255 Node updated = getUpdated(mod);
256 Node original = getOriginal(mod);
257 Node deleted = getRemoved(mod);
259 if((original != null) && (deleted == null)) {
260 result.put(key, getConnectionInstance(original));
262 if(created != null) {
263 result.put(key, getConnectionInstance(created));
264 } else if(updated != null) {
265 result.put(key, getConnectionInstance(updated));
268 LOG.trace("Connection Instance Map: {}", result);
272 private HwvtepConnectionInstance getConnectionInstance(Node node) {
273 // TODO Auto-generated method stub