/* * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node; import com.google.common.base.Objects; import com.google.common.base.Optional; import com.google.common.util.concurrent.Futures; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; import org.opendaylight.controller.md.sal.binding.api.ReadTransaction; import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Name; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.Endpoints; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContextBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayL3Context; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayL3ContextBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import static com.google.common.base.Preconditions.checkNotNull; public class FlowCapableNodeConnectorListener implements DataChangeListener, AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(FlowCapableNodeConnectorListener.class); private final static InstanceIdentifier<FlowCapableNodeConnector> fcNodeConnectorIid = InstanceIdentifier.builder( Nodes.class) .child(Node.class) .child(NodeConnector.class) .augmentation(FlowCapableNodeConnector.class) .build(); private final static InstanceIdentifier<Endpoints> endpointsIid = InstanceIdentifier.builder(Endpoints.class) .build(); private final DataBroker dataProvider; private final SwitchManager switchManager; private final ListenerRegistration<DataChangeListener> listenerRegistration; public FlowCapableNodeConnectorListener(DataBroker dataProvider, SwitchManager switchManager) { this.dataProvider = checkNotNull(dataProvider); this.switchManager = checkNotNull(switchManager); listenerRegistration = dataProvider.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, fcNodeConnectorIid, this, DataChangeScope.BASE); } @Override public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) { ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction(); //endpoint and endpoint L3 maps Map<Name, Endpoint> epWithOfOverlayAugByPortName = readEpsWithOfOverlayAugByPortName(rwTx); Map<Name, EndpointL3> l3EpWithOfOverlayAugByPortName = readL3EpsWithOfOverlayAugByPortName(rwTx); boolean isDataPutToTx = false; for (Entry<InstanceIdentifier<?>, DataObject> fcncEntry : change.getCreatedData().entrySet()) { if (FlowCapableNodeConnector.class.equals(fcncEntry.getKey().getTargetType())) { InstanceIdentifier<NodeConnector> ncIid = fcncEntry.getKey().firstIdentifierOf(NodeConnector.class); FlowCapableNodeConnector fcnc = (FlowCapableNodeConnector) fcncEntry.getValue(); LOG.trace( "FlowCapableNodeConnector created: NodeId: {} NodeConnectorId: {} FlowCapableNodeConnector: {}", ncIid.firstKeyOf(Node.class, NodeKey.class).getId().getValue(), ncIid.firstKeyOf(NodeConnector.class, NodeConnectorKey.class).getId().getValue(), fcnc); switchManager.updateSwitchNodeConnectorConfig(ncIid, fcnc); Name portName = getPortName(fcnc); boolean updated = updateEpWithNodeConnectorInfo(epWithOfOverlayAugByPortName.get(portName), ncIid, rwTx); boolean l3Updated = updateL3EpWithNodeConnectorInfo(l3EpWithOfOverlayAugByPortName.get(portName), ncIid, rwTx); if (updated || l3Updated) { isDataPutToTx = true; } } } for (Entry<InstanceIdentifier<?>, DataObject> fcncEntry : change.getUpdatedData().entrySet()) { if (FlowCapableNodeConnector.class.equals(fcncEntry.getKey().getTargetType())) { InstanceIdentifier<NodeConnector> ncIid = fcncEntry.getKey().firstIdentifierOf(NodeConnector.class); FlowCapableNodeConnector fcnc = (FlowCapableNodeConnector) fcncEntry.getValue(); LOG.trace( "FlowCapableNodeConnector updated: NodeId: {} NodeConnectorId: {} FlowCapableNodeConnector: {}", ncIid.firstKeyOf(Node.class, NodeKey.class).getId().getValue(), ncIid.firstKeyOf(NodeConnector.class, NodeConnectorKey.class).getId().getValue(), fcnc); switchManager.updateSwitchNodeConnectorConfig(ncIid, fcnc); Name portName = getPortName(fcnc); boolean updated = updateEpWithNodeConnectorInfo(epWithOfOverlayAugByPortName.get(portName), ncIid, rwTx); boolean l3Updated = updateL3EpWithNodeConnectorInfo(l3EpWithOfOverlayAugByPortName.get(portName), ncIid, rwTx); if (updated || l3Updated) { isDataPutToTx = true; } FlowCapableNodeConnector originalFcnc = (FlowCapableNodeConnector) change.getOriginalData().get( fcncEntry.getKey()); Name portNameFromOriginalFcnc = getPortName(originalFcnc); // port name already existed and then was changed if (portNameFromOriginalFcnc != null && !Objects.equal(portNameFromOriginalFcnc, portName)) { updated = updateEpWithNodeConnectorInfo(epWithOfOverlayAugByPortName .get(portNameFromOriginalFcnc), null, rwTx); l3Updated = updateL3EpWithNodeConnectorInfo(l3EpWithOfOverlayAugByPortName .get(portNameFromOriginalFcnc), null, rwTx); if (updated || l3Updated) { isDataPutToTx = true; } } } } for (InstanceIdentifier<?> fcncIid : change.getRemovedPaths()) { if (FlowCapableNodeConnector.class.equals(fcncIid.getTargetType())) { InstanceIdentifier<NodeConnector> ncIid = fcncIid.firstIdentifierOf(NodeConnector.class); FlowCapableNodeConnector originalFcnc = (FlowCapableNodeConnector) change.getOriginalData() .get(fcncIid); LOG.trace("FlowCapableNodeConnector removed: NodeId: {} NodeConnectorId: {}", ncIid.firstKeyOf(Node.class, NodeKey.class).getId().getValue(), ncIid.firstKeyOf(NodeConnector.class, NodeConnectorKey.class).getId().getValue()); switchManager.updateSwitchNodeConnectorConfig(ncIid, null); Name portNameFromOriginalFcnc = getPortName(originalFcnc); boolean updated = updateEpWithNodeConnectorInfo(epWithOfOverlayAugByPortName.get(portNameFromOriginalFcnc), null, rwTx); boolean l3Updated = updateL3EpWithNodeConnectorInfo(l3EpWithOfOverlayAugByPortName.get(portNameFromOriginalFcnc), null, rwTx); if (updated || l3Updated) { isDataPutToTx = true; } } } if (isDataPutToTx) { rwTx.submit(); } else { rwTx.cancel(); } } //read endpoints from listener entry private Map<Name, Endpoint> readEpsWithOfOverlayAugByPortName(ReadTransaction rTx) { Optional<Endpoints> potentialEps = Futures.getUnchecked(rTx.read(LogicalDatastoreType.OPERATIONAL, endpointsIid)); if (!potentialEps.isPresent() || potentialEps.get().getEndpoint() == null) { return Collections.emptyMap(); } Map<Name, Endpoint> epsByPortName = new HashMap<>(); for (Endpoint ep : potentialEps.get().getEndpoint()) { OfOverlayContext ofOverlayEp = ep.getAugmentation(OfOverlayContext.class); if (ofOverlayEp != null && ofOverlayEp.getPortName() != null) { epsByPortName.put(ofOverlayEp.getPortName(), ep); } } return epsByPortName; } //read l3 endpoint from listener entry private Map<Name, EndpointL3> readL3EpsWithOfOverlayAugByPortName(ReadTransaction rTx) { Optional<Endpoints> potentialEps = Futures.getUnchecked(rTx.read(LogicalDatastoreType.OPERATIONAL, endpointsIid)); if (!potentialEps.isPresent() || potentialEps.get().getEndpoint() == null) { return Collections.emptyMap(); } Map<Name, EndpointL3> epsByPortName = new HashMap<>(); for (EndpointL3 epL3 : potentialEps.get().getEndpointL3()) { OfOverlayL3Context ofOverlayL3Ep = epL3.getAugmentation(OfOverlayL3Context.class); if (ofOverlayL3Ep != null && ofOverlayL3Ep.getPortName() != null) { epsByPortName.put(ofOverlayL3Ep.getPortName(), epL3); } } return epsByPortName; } private Name getPortName(FlowCapableNodeConnector fcnc) { if (fcnc == null || fcnc.getName() == null) { return null; } return new Name(fcnc.getName()); } /** * @return {@code true} if data (Endpoint) was put to the transaction; {@code false} otherwise */ private boolean updateEpWithNodeConnectorInfo(Endpoint epWithOfOverlayAug, InstanceIdentifier<NodeConnector> ncIid, WriteTransaction tx) { if (epWithOfOverlayAug == null) { return false; } OfOverlayContext oldOfOverlayAug = epWithOfOverlayAug.getAugmentation(OfOverlayContext.class); OfOverlayContextBuilder newOfOverlayAug = new OfOverlayContextBuilder(oldOfOverlayAug); if (ncIid == null && oldOfOverlayAug.getNodeConnectorId() == null) { return false; } if (ncIid != null) { NodeConnectorId ncId = ncIid.firstKeyOf(NodeConnector.class, NodeConnectorKey.class).getId(); if (ncId.equals(oldOfOverlayAug.getNodeConnectorId())) { return false; } NodeId nodeId = ncIid.firstKeyOf(Node.class, NodeKey.class).getId(); newOfOverlayAug.setNodeId(nodeId); newOfOverlayAug.setNodeConnectorId(ncId); } else { //when nodeId is null, remove info about that node from endpoint newOfOverlayAug.setNodeId(null); newOfOverlayAug.setNodeConnectorId(null); } InstanceIdentifier<OfOverlayContext> epOfOverlayAugIid = InstanceIdentifier.builder(Endpoints.class) .child(Endpoint.class, epWithOfOverlayAug.getKey()) .augmentation(OfOverlayContext.class) .build(); tx.put(LogicalDatastoreType.OPERATIONAL, epOfOverlayAugIid, newOfOverlayAug.build()); return true; } /** * @return {@code true} if data (EndpointL3) was put to the transaction; {@code false} otherwise */ private boolean updateL3EpWithNodeConnectorInfo(EndpointL3 epWithOfOverlayL3Aug, InstanceIdentifier<NodeConnector> ncIid, WriteTransaction tx) { if (epWithOfOverlayL3Aug == null) { return false; } OfOverlayL3Context oldOfOverlayL3Aug = epWithOfOverlayL3Aug.getAugmentation(OfOverlayL3Context.class); OfOverlayL3ContextBuilder newOfOverlayL3Aug = new OfOverlayL3ContextBuilder(oldOfOverlayL3Aug); if (ncIid == null && oldOfOverlayL3Aug.getNodeConnectorId() == null) { return false; } if (ncIid != null) { NodeConnectorId ncId = ncIid.firstKeyOf(NodeConnector.class, NodeConnectorKey.class).getId(); if (ncId.equals(oldOfOverlayL3Aug.getNodeConnectorId())) { return false; } NodeId nodeId = ncIid.firstKeyOf(Node.class, NodeKey.class).getId(); newOfOverlayL3Aug.setNodeId(nodeId); newOfOverlayL3Aug.setNodeConnectorId(ncId); } else { // remove node info newOfOverlayL3Aug.setNodeId(null); newOfOverlayL3Aug.setNodeConnectorId(null); } InstanceIdentifier<OfOverlayL3Context> epOfOverlayAugIid = InstanceIdentifier.builder(Endpoints.class) .child(EndpointL3.class, epWithOfOverlayL3Aug.getKey()) .augmentation(OfOverlayL3Context.class) .build(); tx.put(LogicalDatastoreType.OPERATIONAL, epOfOverlayAugIid, newOfOverlayL3Aug.build()); return true; } @Override public void close() throws Exception { if (listenerRegistration != null) { listenerRegistration.close(); } } }