0f021ded0a808aef908512ef710bb22da0df1e7e
[groupbasedpolicy.git] / renderers / ofoverlay / src / main / java / org / opendaylight / groupbasedpolicy / renderer / ofoverlay / node / FlowCapableNodeConnectorListener.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. 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.groupbasedpolicy.renderer.ofoverlay.node;
10
11 import com.google.common.base.Objects;
12 import com.google.common.base.Optional;
13 import com.google.common.util.concurrent.Futures;
14 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
15 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
16 import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
17 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
18 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
19 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
20 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Name;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.Endpoints;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContextBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayL3Context;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayL3ContextBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
38 import org.opendaylight.yangtools.concepts.ListenerRegistration;
39 import org.opendaylight.yangtools.yang.binding.DataObject;
40 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 import java.util.Collections;
45 import java.util.HashMap;
46 import java.util.Map;
47 import java.util.Map.Entry;
48
49 import static com.google.common.base.Preconditions.checkNotNull;
50
51 public class FlowCapableNodeConnectorListener implements DataChangeListener, AutoCloseable {
52
53     private static final Logger LOG = LoggerFactory.getLogger(FlowCapableNodeConnectorListener.class);
54
55     private final static InstanceIdentifier<FlowCapableNodeConnector> fcNodeConnectorIid = InstanceIdentifier.builder(
56             Nodes.class)
57         .child(Node.class)
58         .child(NodeConnector.class)
59         .augmentation(FlowCapableNodeConnector.class)
60         .build();
61     private final static InstanceIdentifier<Endpoints> endpointsIid = InstanceIdentifier.builder(Endpoints.class)
62         .build();
63     private final DataBroker dataProvider;
64     private final SwitchManager switchManager;
65     private final ListenerRegistration<DataChangeListener> listenerRegistration;
66
67     public FlowCapableNodeConnectorListener(DataBroker dataProvider, SwitchManager switchManager) {
68         this.dataProvider = checkNotNull(dataProvider);
69         this.switchManager = checkNotNull(switchManager);
70         listenerRegistration = dataProvider.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
71                 fcNodeConnectorIid, this, DataChangeScope.BASE);
72     }
73
74     @Override
75     public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
76         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
77
78         //endpoint and endpoint L3 maps
79         Map<Name, Endpoint> epWithOfOverlayAugByPortName = readEpsWithOfOverlayAugByPortName(rwTx);
80         Map<Name, EndpointL3> l3EpWithOfOverlayAugByPortName = readL3EpsWithOfOverlayAugByPortName(rwTx);
81
82         boolean isDataPutToTx = false;
83         for (Entry<InstanceIdentifier<?>, DataObject> fcncEntry : change.getCreatedData().entrySet()) {
84             if (FlowCapableNodeConnector.class.equals(fcncEntry.getKey().getTargetType())) {
85                 InstanceIdentifier<NodeConnector> ncIid = fcncEntry.getKey().firstIdentifierOf(NodeConnector.class);
86                 FlowCapableNodeConnector fcnc = (FlowCapableNodeConnector) fcncEntry.getValue();
87                 LOG.trace(
88                         "FlowCapableNodeConnector created: NodeId: {} NodeConnectorId: {} FlowCapableNodeConnector: {}",
89                         ncIid.firstKeyOf(Node.class, NodeKey.class).getId().getValue(),
90                         ncIid.firstKeyOf(NodeConnector.class, NodeConnectorKey.class).getId().getValue(), fcnc);
91                 switchManager.updateSwitchNodeConnectorConfig(ncIid, fcnc);
92                 Name portName = getPortName(fcnc);
93                 boolean updated = updateEpWithNodeConnectorInfo(epWithOfOverlayAugByPortName.get(portName), ncIid, rwTx);
94                 boolean l3Updated = updateL3EpWithNodeConnectorInfo(l3EpWithOfOverlayAugByPortName.get(portName), ncIid, rwTx);
95                 if (updated || l3Updated) {
96                     isDataPutToTx = true;
97                 }
98             }
99         }
100         for (Entry<InstanceIdentifier<?>, DataObject> fcncEntry : change.getUpdatedData().entrySet()) {
101             if (FlowCapableNodeConnector.class.equals(fcncEntry.getKey().getTargetType())) {
102                 InstanceIdentifier<NodeConnector> ncIid = fcncEntry.getKey().firstIdentifierOf(NodeConnector.class);
103                 FlowCapableNodeConnector fcnc = (FlowCapableNodeConnector) fcncEntry.getValue();
104                 LOG.trace(
105                         "FlowCapableNodeConnector updated: NodeId: {} NodeConnectorId: {} FlowCapableNodeConnector: {}",
106                         ncIid.firstKeyOf(Node.class, NodeKey.class).getId().getValue(),
107                         ncIid.firstKeyOf(NodeConnector.class, NodeConnectorKey.class).getId().getValue(), fcnc);
108                 switchManager.updateSwitchNodeConnectorConfig(ncIid, fcnc);
109                 Name portName = getPortName(fcnc);
110                 boolean updated = updateEpWithNodeConnectorInfo(epWithOfOverlayAugByPortName.get(portName), ncIid, rwTx);
111                 boolean l3Updated = updateL3EpWithNodeConnectorInfo(l3EpWithOfOverlayAugByPortName.get(portName), ncIid, rwTx);
112                 if (updated || l3Updated) {
113                     isDataPutToTx = true;
114                 }
115                 FlowCapableNodeConnector originalFcnc = (FlowCapableNodeConnector) change.getOriginalData().get(
116                         fcncEntry.getKey());
117                 Name portNameFromOriginalFcnc = getPortName(originalFcnc);
118                 // port name already existed and then was changed
119                 if (portNameFromOriginalFcnc != null && !Objects.equal(portNameFromOriginalFcnc, portName)) {
120                     updated = updateEpWithNodeConnectorInfo(epWithOfOverlayAugByPortName
121                             .get(portNameFromOriginalFcnc), null, rwTx);
122                     l3Updated = updateL3EpWithNodeConnectorInfo(l3EpWithOfOverlayAugByPortName
123                             .get(portNameFromOriginalFcnc), null, rwTx);
124                     if (updated || l3Updated) {
125                         isDataPutToTx = true;
126                     }
127                 }
128             }
129         }
130         for (InstanceIdentifier<?> fcncIid : change.getRemovedPaths()) {
131             if (FlowCapableNodeConnector.class.equals(fcncIid.getTargetType())) {
132                 InstanceIdentifier<NodeConnector> ncIid = fcncIid.firstIdentifierOf(NodeConnector.class);
133                 FlowCapableNodeConnector originalFcnc = (FlowCapableNodeConnector) change.getOriginalData()
134                     .get(fcncIid);
135                 LOG.trace("FlowCapableNodeConnector removed: NodeId: {} NodeConnectorId: {}",
136                         ncIid.firstKeyOf(Node.class, NodeKey.class).getId().getValue(),
137                         ncIid.firstKeyOf(NodeConnector.class, NodeConnectorKey.class).getId().getValue());
138                 switchManager.updateSwitchNodeConnectorConfig(ncIid, null);
139                 Name portNameFromOriginalFcnc = getPortName(originalFcnc);
140                 boolean updated = updateEpWithNodeConnectorInfo(epWithOfOverlayAugByPortName.get(portNameFromOriginalFcnc), null, rwTx);
141                 boolean l3Updated = updateL3EpWithNodeConnectorInfo(l3EpWithOfOverlayAugByPortName.get(portNameFromOriginalFcnc), null, rwTx);
142                 if (updated || l3Updated) {
143                     isDataPutToTx = true;
144                 }
145             }
146         }
147         if (isDataPutToTx) {
148             rwTx.submit();
149         } else {
150             rwTx.cancel();
151         }
152     }
153
154     //read endpoints from listener entry
155     private Map<Name, Endpoint> readEpsWithOfOverlayAugByPortName(ReadTransaction rTx) {
156         Optional<Endpoints> potentialEps = Futures.getUnchecked(rTx.read(LogicalDatastoreType.OPERATIONAL, endpointsIid));
157         if (!potentialEps.isPresent() || potentialEps.get().getEndpoint() == null) {
158             return Collections.emptyMap();
159         }
160         Map<Name, Endpoint> epsByPortName = new HashMap<>();
161         for (Endpoint ep : potentialEps.get().getEndpoint()) {
162             OfOverlayContext ofOverlayEp = ep.getAugmentation(OfOverlayContext.class);
163             if (ofOverlayEp != null && ofOverlayEp.getPortName() != null) {
164                 epsByPortName.put(ofOverlayEp.getPortName(), ep);
165             }
166         }
167         return epsByPortName;
168     }
169
170     //read l3 endpoint from listener entry
171     private Map<Name, EndpointL3> readL3EpsWithOfOverlayAugByPortName(ReadTransaction rTx) {
172         Optional<Endpoints> potentialEps = Futures.getUnchecked(rTx.read(LogicalDatastoreType.OPERATIONAL, endpointsIid));
173         if (!potentialEps.isPresent() || potentialEps.get().getEndpoint() == null) {
174             return Collections.emptyMap();
175         }
176         Map<Name, EndpointL3> epsByPortName = new HashMap<>();
177         for (EndpointL3 epL3 : potentialEps.get().getEndpointL3()) {
178             OfOverlayL3Context ofOverlayL3Ep = epL3.getAugmentation(OfOverlayL3Context.class);
179             if (ofOverlayL3Ep != null && ofOverlayL3Ep.getPortName() != null) {
180                 epsByPortName.put(ofOverlayL3Ep.getPortName(), epL3);
181             }
182         }
183         return epsByPortName;
184     }
185
186     private Name getPortName(FlowCapableNodeConnector fcnc) {
187         if (fcnc == null || fcnc.getName() == null) {
188             return null;
189         }
190         return new Name(fcnc.getName());
191     }
192
193     /**
194      * @return {@code true} if data (Endpoint) was put to the transaction; {@code false} otherwise
195      */
196     private boolean updateEpWithNodeConnectorInfo(Endpoint epWithOfOverlayAug, InstanceIdentifier<NodeConnector> ncIid,
197             WriteTransaction tx) {
198         if (epWithOfOverlayAug == null) {
199             return false;
200         }
201         OfOverlayContext oldOfOverlayAug = epWithOfOverlayAug.getAugmentation(OfOverlayContext.class);
202         OfOverlayContextBuilder newOfOverlayAug = new OfOverlayContextBuilder(oldOfOverlayAug);
203         if (ncIid == null && oldOfOverlayAug.getNodeConnectorId() == null) {
204             return false;
205         }
206         if (ncIid != null) {
207             NodeConnectorId ncId = ncIid.firstKeyOf(NodeConnector.class, NodeConnectorKey.class).getId();
208             if (ncId.equals(oldOfOverlayAug.getNodeConnectorId())) {
209                 return false;
210             }
211             NodeId nodeId = ncIid.firstKeyOf(Node.class, NodeKey.class).getId();
212             newOfOverlayAug.setNodeId(nodeId);
213             newOfOverlayAug.setNodeConnectorId(ncId);
214         } else {
215             //when nodeId is null, remove info about that node from endpoint
216             newOfOverlayAug.setNodeId(null);
217             newOfOverlayAug.setNodeConnectorId(null);
218         }
219         InstanceIdentifier<OfOverlayContext> epOfOverlayAugIid = InstanceIdentifier.builder(Endpoints.class)
220             .child(Endpoint.class, epWithOfOverlayAug.getKey())
221             .augmentation(OfOverlayContext.class)
222             .build();
223         tx.put(LogicalDatastoreType.OPERATIONAL, epOfOverlayAugIid, newOfOverlayAug.build());
224         return true;
225     }
226
227     /**
228      * @return {@code true} if data (EndpointL3) was put to the transaction; {@code false} otherwise
229      */
230     private boolean updateL3EpWithNodeConnectorInfo(EndpointL3 epWithOfOverlayL3Aug,
231             InstanceIdentifier<NodeConnector> ncIid, WriteTransaction tx) {
232         if (epWithOfOverlayL3Aug == null) {
233             return false;
234         }
235         OfOverlayL3Context oldOfOverlayL3Aug = epWithOfOverlayL3Aug.getAugmentation(OfOverlayL3Context.class);
236         OfOverlayL3ContextBuilder newOfOverlayL3Aug = new OfOverlayL3ContextBuilder(oldOfOverlayL3Aug);
237         if (ncIid == null && oldOfOverlayL3Aug.getNodeConnectorId() == null) {
238             return false;
239         }
240         if (ncIid != null) {
241             NodeConnectorId ncId = ncIid.firstKeyOf(NodeConnector.class, NodeConnectorKey.class).getId();
242             if (ncId.equals(oldOfOverlayL3Aug.getNodeConnectorId())) {
243                 return false;
244             }
245             NodeId nodeId = ncIid.firstKeyOf(Node.class, NodeKey.class).getId();
246             newOfOverlayL3Aug.setNodeId(nodeId);
247             newOfOverlayL3Aug.setNodeConnectorId(ncId);
248         } else {
249             // remove node info
250             newOfOverlayL3Aug.setNodeId(null);
251             newOfOverlayL3Aug.setNodeConnectorId(null);
252         }
253         InstanceIdentifier<OfOverlayL3Context> epOfOverlayAugIid = InstanceIdentifier.builder(Endpoints.class)
254                 .child(EndpointL3.class, epWithOfOverlayL3Aug.getKey())
255                 .augmentation(OfOverlayL3Context.class)
256                 .build();
257         tx.put(LogicalDatastoreType.OPERATIONAL, epOfOverlayAugIid, newOfOverlayL3Aug.build());
258         return true;
259     }
260
261     @Override
262     public void close() throws Exception {
263         if (listenerRegistration != null) {
264             listenerRegistration.close();
265         }
266     }
267
268 }