1 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node;
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;
36 import java.util.Collections;
37 import java.util.HashMap;
39 import java.util.Map.Entry;
41 import static com.google.common.base.Preconditions.checkNotNull;
43 public class FlowCapableNodeConnectorListener implements DataChangeListener, AutoCloseable {
45 private static final Logger LOG = LoggerFactory.getLogger(FlowCapableNodeConnectorListener.class);
47 private final static InstanceIdentifier<FlowCapableNodeConnector> fcNodeConnectorIid = InstanceIdentifier.builder(
50 .child(NodeConnector.class)
51 .augmentation(FlowCapableNodeConnector.class)
53 private final static InstanceIdentifier<Endpoints> endpointsIid = InstanceIdentifier.builder(Endpoints.class)
55 private final DataBroker dataProvider;
56 private final SwitchManager switchManager;
57 private final ListenerRegistration<DataChangeListener> listenerRegistration;
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);
67 public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
68 ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
70 //endpoint and endpoint L3 maps
71 Map<Name, Endpoint> epWithOfOverlayAugByPortName = readEpsWithOfOverlayAugByPortName(rwTx);
72 Map<Name, EndpointL3> l3EpWithOfOverlayAugByPortName = readL3EpsWithOfOverlayAugByPortName(rwTx);
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();
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) {
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();
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;
107 FlowCapableNodeConnector originalFcnc = (FlowCapableNodeConnector) change.getOriginalData().get(
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;
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()
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;
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();
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);
159 return epsByPortName;
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();
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);
175 return epsByPortName;
178 private Name getPortName(FlowCapableNodeConnector fcnc) {
179 if (fcnc == null || fcnc.getName() == null) {
182 return new Name(fcnc.getName());
186 * @return {@code true} if data (Endpoint) was put to the transaction; {@code false} otherwise
188 private boolean updateEpWithNodeConnectorInfo(Endpoint epWithOfOverlayAug, InstanceIdentifier<NodeConnector> ncIid,
189 WriteTransaction tx) {
190 if (epWithOfOverlayAug == null) {
193 OfOverlayContext oldOfOverlayAug = epWithOfOverlayAug.getAugmentation(OfOverlayContext.class);
194 OfOverlayContextBuilder newOfOverlayAug = new OfOverlayContextBuilder(oldOfOverlayAug);
195 if (ncIid == null && oldOfOverlayAug.getNodeConnectorId() == null) {
199 NodeConnectorId ncId = ncIid.firstKeyOf(NodeConnector.class, NodeConnectorKey.class).getId();
200 if (ncId.equals(oldOfOverlayAug.getNodeConnectorId())) {
203 NodeId nodeId = ncIid.firstKeyOf(Node.class, NodeKey.class).getId();
204 newOfOverlayAug.setNodeId(nodeId);
205 newOfOverlayAug.setNodeConnectorId(ncId);
207 //when nodeId is null, remove info about that node from endpoint
208 newOfOverlayAug.setNodeId(null);
209 newOfOverlayAug.setNodeConnectorId(null);
211 InstanceIdentifier<OfOverlayContext> epOfOverlayAugIid = InstanceIdentifier.builder(Endpoints.class)
212 .child(Endpoint.class, epWithOfOverlayAug.getKey())
213 .augmentation(OfOverlayContext.class)
215 tx.put(LogicalDatastoreType.OPERATIONAL, epOfOverlayAugIid, newOfOverlayAug.build());
220 * @return {@code true} if data (EndpointL3) was put to the transaction; {@code false} otherwise
222 private boolean updateL3EpWithNodeConnectorInfo(EndpointL3 epWithOfOverlayL3Aug,
223 InstanceIdentifier<NodeConnector> ncIid, WriteTransaction tx) {
224 if (epWithOfOverlayL3Aug == null) {
227 OfOverlayL3Context oldOfOverlayL3Aug = epWithOfOverlayL3Aug.getAugmentation(OfOverlayL3Context.class);
228 OfOverlayL3ContextBuilder newOfOverlayL3Aug = new OfOverlayL3ContextBuilder(oldOfOverlayL3Aug);
229 if (ncIid == null && oldOfOverlayL3Aug.getNodeConnectorId() == null) {
233 NodeConnectorId ncId = ncIid.firstKeyOf(NodeConnector.class, NodeConnectorKey.class).getId();
234 if (ncId.equals(oldOfOverlayL3Aug.getNodeConnectorId())) {
237 NodeId nodeId = ncIid.firstKeyOf(Node.class, NodeKey.class).getId();
238 newOfOverlayL3Aug.setNodeId(nodeId);
239 newOfOverlayL3Aug.setNodeConnectorId(ncId);
242 newOfOverlayL3Aug.setNodeId(null);
243 newOfOverlayL3Aug.setNodeConnectorId(null);
245 InstanceIdentifier<OfOverlayL3Context> epOfOverlayAugIid = InstanceIdentifier.builder(Endpoints.class)
246 .child(EndpointL3.class, epWithOfOverlayL3Aug.getKey())
247 .augmentation(OfOverlayL3Context.class)
249 tx.put(LogicalDatastoreType.OPERATIONAL, epOfOverlayAugIid, newOfOverlayL3Aug.build());
254 public void close() throws Exception {
255 if (listenerRegistration != null) {
256 listenerRegistration.close();