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