import org.opendaylight.groupbasedpolicy.endpoint.EndpointRpcRegistry;
import org.opendaylight.groupbasedpolicy.endpoint.EpKey;
import org.opendaylight.groupbasedpolicy.endpoint.EpRendererAugmentation;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager;
import org.opendaylight.groupbasedpolicy.resolver.EgKey;
import org.opendaylight.groupbasedpolicy.util.SetUtils;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
LoggerFactory.getLogger(EndpointManager.class);
private final static InstanceIdentifier<Nodes> nodesIid = InstanceIdentifier
.builder(Nodes.class).build();
- private final static InstanceIdentifier<Node> nodeIid = InstanceIdentifier
- .builder(Nodes.class).child(Node.class).build();
- private ListenerRegistration<DataChangeListener> nodesReg;
-
private static final InstanceIdentifier<Endpoint> endpointsIid =
InstanceIdentifier.builder(Endpoints.class)
.child(Endpoint.class).build();
endpointsIid,
this,
DataChangeScope.ONE);
- nodesReg = dataProvider.registerDataChangeListener(
- LogicalDatastoreType.OPERATIONAL, nodeIid,
- new NodesListener(), DataChangeScope.SUBTREE);
-
} else
listenerReg = null;
}
}
- // TODO: alagalah Investigate using the internal project listener structure
- // for this. ie Endpoint should listen to
- // SwitchManager updates and update the EP maps accordingly (update
- // Endpoint). Removal should include the overloaded
- // method updateEndpoint(Node node)
- private class NodesListener implements DataChangeListener {
- @Override
- public void onDataChanged(
- AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
- for (DataObject dao : change.getCreatedData().values()) {
- if (!(dao instanceof Node))
- continue;
- Node node = (Node) dao;
- if (node.getNodeConnector() != null) {
- updateEndpoint(node);
- }
- }
- for (DataObject dao : change.getUpdatedData().values()) {
- if (!(dao instanceof Node))
- continue;
- Node node = (Node) dao;
- if (node.getNodeConnector() != null) {
- updateEndpoint(node);
- }
- }
- }
- }
-
- // TODO Li alagalah move this near to other updateEndpoint()
- private void updateEndpoint(Node node) {
- final InstanceIdentifier<Endpoints> endpointsIid = InstanceIdentifier.builder(Endpoints.class).build();
-
- Optional<Endpoints> epResult;
- EpKey epKey = null;
- for (NodeConnector nc : node.getNodeConnector()) {
- FlowCapableNodeConnector fcnc = nc
- .getAugmentation(FlowCapableNodeConnector.class);
- try {
- epResult = dataProvider.newReadOnlyTransaction().read(LogicalDatastoreType.OPERATIONAL, endpointsIid)
- .get();
- if (epResult.isPresent()) {
- Endpoints endpoints = epResult.get();
- if (endpoints.getEndpoint() != null) {
- Boolean isEmpty = true;
- for (Endpoint ep : endpoints.getEndpoint()) {
- // 2. Search for portname
- OfOverlayContext currentAugmentation = ep.getAugmentation(OfOverlayContext.class);
- if (currentAugmentation.getPortName() != null && fcnc.getName() != null
- && currentAugmentation.getPortName().getValue().equals(fcnc.getName())) {
- NodeId nodeId;
- NodeConnectorId nodeConnectorId;
- Name name;
- try {
- nodeId = currentAugmentation.getNodeId();
- nodeConnectorId = currentAugmentation.getNodeConnectorId();
- name = currentAugmentation.getPortName();
- } catch (Exception e) {
- nodeId = null;
- nodeConnectorId = null;
- name = null;
- }
- Boolean process = false;
- if (nodeId == null && nodeConnectorId == null) {
- LOG.debug("ep NodeID and NC ID Both null");
- process = true;
- }
- if (nodeId != null && nodeConnectorId != null) {
- if (!(nodeConnectorId.getValue().equals(nc.getId().getValue()))) {
- LOG.debug("ep NodeID and NC ID Both NOT null but epNCID !=nodeNCID");
- process = true;
- }
- }
- if (process) {
- WriteTransaction tx = dataProvider.newWriteOnlyTransaction();
- // 3. Update endpoint
- EndpointBuilder epBuilder = new EndpointBuilder(ep);
- OfOverlayContextBuilder ofOverlayAugmentation = new OfOverlayContextBuilder();
- ofOverlayAugmentation.setNodeId(node.getId());
- ofOverlayAugmentation.setNodeConnectorId(nc.getId());
- ofOverlayAugmentation.setPortName(name);
- epBuilder.addAugmentation(OfOverlayContext.class, ofOverlayAugmentation.build());
- epBuilder.setL3Address(ep.getL3Address());
- InstanceIdentifier<Endpoint> iidEp = InstanceIdentifier.builder(Endpoints.class)
- .child(Endpoint.class, ep.getKey()).build();
- tx.put(LogicalDatastoreType.OPERATIONAL, iidEp, epBuilder.build());
- tx.submit().get();
- epKey = new EpKey(ep.getKey().getL2Context(), ep.getKey().getMacAddress());
- notifyEndpointUpdated(epKey);
- LOG.debug("Values:");
- LOG.debug("node: Node ID:" + node.getId().getValue());
- LOG.debug("node: NodeConnectorID: " + nc.getId().getValue());
- if (nodeId != null && nodeConnectorId != null) {
- LOG.debug("ep: nodeID:" + nodeId.getValue());
- LOG.debug("ep: nodeConnectorID:" + nodeConnectorId.getValue());
- }
- isEmpty = false;
- }
- }
- }
- }
- }
- } catch (InterruptedException | ExecutionException e) {
- LOG.error("Exception in UpdateEndpoint", e);
- }
- }
- }
-
// **************
// Implementation
// **************
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager;
import org.opendaylight.groupbasedpolicy.resolver.PolicyResolver;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayConfig;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
//TODO: Consider moving to groupbasedpolicy-ofoverlay-config so as to be user configurable in distribution.
executor = Executors.newScheduledThreadPool(numCPU * 2);
- switchManager = new SwitchManager(dataProvider, executor);
+ switchManager = new SwitchManager(dataProvider);
endpointManager = new EndpointManager(dataProvider, rpcRegistry,
executor, switchManager);
policyResolver = new PolicyResolver(dataProvider, executor);
public void onSuccess(final Optional<OfOverlayConfig> result) {
if (!result.isPresent()) return;
if (result.get() instanceof OfOverlayConfig) {
- config = (OfOverlayConfig)result.get();
+ config = result.get();
applyConfig();
}
}
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager;
import org.opendaylight.groupbasedpolicy.resolver.PolicyResolver;
public class OfContext {
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.PolicyEnforcer;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.PortSecurity;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.SourceMapper;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchListener;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.SubjectFeatures;
import org.opendaylight.groupbasedpolicy.resolver.EgKey;
import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
@Override
public void switchReady(final NodeId nodeId) {
- //TODO Apr15 alagalah : OVSDB CRUD tunnels may go here.
-// WriteTransaction t = dataBroker.newWriteOnlyTransaction();
-//
-// NodeBuilder nb = new NodeBuilder()
-// .setId(nodeId)
-// .addAugmentation(FlowCapableNode.class,
-// new FlowCapableNodeBuilder()
-// .build());
-// t.merge(LogicalDatastoreType.CONFIGURATION,
-// FlowUtils.createNodePath(nodeId),
-// nb.build(), true);
-// ListenableFuture<Void> result = t.submit();
-// Futures.addCallback(result,
-// new FutureCallback<Void>() {
-// @Override
-// public void onSuccess(Void result) {
-// dirty.get().addNode(nodeId);
-// scheduleUpdate();
-// }
-//
-// @Override
-// public void onFailure(Throwable t) {
-// LOG.error("Could not add switch {}", nodeId, t);
-// }
-// });
-
+ scheduleUpdate();
}
@Override
t.read(LogicalDatastoreType.CONFIGURATION, entry.getKey()).get();
if (r.isPresent()) {
- Table curTable = (Table)r.get();
+ Table curTable = r.get();
curr = new HashSet<Flow>(curTable.getFlow());
}
Sets.SetView<Flow> deletions = Sets.difference(curr, update);
@Override
public Void call() throws Exception {
for (NodeId node : switchManager.getReadySwitches()) {
- if (!switchManager.isSwitchReady(node))
- return null;
PolicyInfo info = policyResolver.getCurrentPolicy();
if (info == null)
return null;
+++ /dev/null
-/*
- * 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;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.ScheduledExecutorService;
-
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
-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.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayConfig.EncapsulationFormat;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayNodeConfig;
-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.nodes.Node;
-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 com.google.common.base.Function;
-import com.google.common.base.Optional;
-import com.google.common.base.Predicate;
-import com.google.common.collect.Collections2;
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-
-/**
- * Manage connected switches and ensure their configuration is set up
- * correctly
- * @author readams
- */
-public class SwitchManager implements AutoCloseable {
- private static final Logger LOG =
- LoggerFactory.getLogger(SwitchManager.class);
-
- private final DataBroker dataProvider;
-
- private final static InstanceIdentifier<Nodes> nodesIid =
- InstanceIdentifier.builder(Nodes.class).build();
- private final static InstanceIdentifier<Node> nodeIid =
- InstanceIdentifier.builder(Nodes.class)
- .child(Node.class).build();
- private ListenerRegistration<DataChangeListener> nodesReg;
- private ListenerRegistration<DataChangeListener> nodesConfigReg;
-
- protected ConcurrentHashMap<NodeId, SwitchState> switches =
- new ConcurrentHashMap<>();
- protected List<SwitchListener> listeners = new CopyOnWriteArrayList<>();
-
- public SwitchManager(DataBroker dataProvider,
- ScheduledExecutorService executor) {
- super();
- this.dataProvider = dataProvider;
- if (dataProvider != null) {
- nodesReg = dataProvider
- .registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
- nodeIid, new NodesListener(),
- DataChangeScope.SUBTREE);
- nodesConfigReg = dataProvider
- .registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
- nodeIid, new NodesConfigListener(),
- DataChangeScope.SUBTREE);
- }
- readSwitches();
- LOG.debug("Initialized OFOverlay switch manager");
- }
-
- // *************
- // SwitchManager
- // *************
-
- /**
- * Get the collection of switches that are in the "ready" state. Note
- * that the collection may be concurrently modified
- * @return A {@link Collection} containing the switches that are ready.
- */
- public Collection<NodeId> getReadySwitches() {
- Collection<SwitchState> ready =
- Collections2.filter(switches.values(),
- new Predicate<SwitchState>() {
- @Override
- public boolean apply(SwitchState input) {
- return SwitchStatus.READY.equals(input.status);
- }
- });
- return Collections2.transform(ready,
- new Function<SwitchState, NodeId>() {
- @Override
- public NodeId apply(SwitchState input) {
- return input.nodeId;
- }
- });
- }
-
- /**
- * Check whether the specified switch is in the ready state
- * @param nodeId the node
- * @return <code>true</code> if the switch is in the ready state
- */
- public boolean isSwitchReady(NodeId nodeId) {
- SwitchState state = switches.get(nodeId);
- if (state == null) return false;
- return SwitchStatus.READY.equals(state.status);
- }
-
- public Set<NodeConnectorId> getExternalPorts(NodeId nodeId) {
- SwitchState state = switches.get(nodeId);
- if (state == null) return Collections.emptySet();
- return state.externalPorts;
- }
-
- //TODO OVSDB CRUD belongs in here. (see Trello)
- public NodeConnectorId getTunnelPort(NodeId nodeId) {
- SwitchState state = switches.get(nodeId);
- if (state == null) return null;
- return state.tunnelPort;
- }
-
- public IpAddress getTunnelIP(NodeId nodeId) {
- SwitchState state = switches.get(nodeId);
- if (state == null || state.nodeConfig == null) return null;
- return state.nodeConfig.getTunnelIp();
- }
-
- /**
- * Add a {@link SwitchListener} to get notifications of switch events
- * @param listener the {@link SwitchListener} to add
- */
- public void registerListener(SwitchListener listener) {
- listeners.add(listener);
- }
-
- /**
- * Set the encapsulation format the specified value
- * @param format The new format
- */
- public void setEncapsulationFormat(EncapsulationFormat format) {
- // No-op for now
- }
-
- // *************
- // AutoCloseable
- // *************
-
- @Override
- public void close() throws Exception {
- nodesReg.close();
- nodesConfigReg.close();
- }
-
- // ******************
- // DataChangeListener
- // ******************
-
- private class NodesListener implements DataChangeListener {
-
- @Override
- public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>,
- DataObject> change) {
- for (InstanceIdentifier<?> iid : change.getRemovedPaths()) {
- DataObject old = change.getOriginalData().get(iid);
- if (old != null && old instanceof Node) {
- removeSwitch(((Node)old).getId());
- }
- }
-
- for (DataObject dao : change.getCreatedData().values()) {
- updateSwitch(dao);
- }
- for (DataObject dao : change.getUpdatedData().values()) {
- updateSwitch(dao);
- }
- }
- }
-
- private class NodesConfigListener implements DataChangeListener {
-
- @Override
- public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>,
- DataObject> change) {
- readSwitches();
- }
- }
-
- // **************
- // Implementation
- // **************
-
- private SwitchState getSwitchState(NodeId id) {
- SwitchState state = switches.get(id);
- if (state == null) {
- state = new SwitchState(id);
- SwitchState old =
- switches.putIfAbsent(id, state);
- if (old != null)
- state = old;
- }
- return state;
- }
-
- private void updateSwitch(DataObject dao) {
- if (!(dao instanceof Node)) return;
- // Switches are registered as Nodes in the inventory; OpenFlow switches
- // are of type FlowCapableNode
- Node node = (Node)dao;
- FlowCapableNode fcn = node.getAugmentation(FlowCapableNode.class);
- if (fcn == null) return;
-
- LOG.debug("{} update", node.getId());
-
- SwitchState state = getSwitchState(node.getId());
-
- state.setNode(node);
-
- if (SwitchStatus.DISCONNECTED.equals(state.status))
- switchConnected(node.getId());
- else if (SwitchStatus.READY.equals(state.status))
- notifySwitchUpdated(node.getId());
- }
-
- private void updateSwitchConfig(NodeId nodeId, OfOverlayNodeConfig config) {
- SwitchState state = getSwitchState(nodeId);
- state.setConfig(config);
- notifySwitchUpdated(nodeId);
- }
-
- private void notifySwitchUpdated(NodeId nodeId) {
- for (SwitchListener listener : listeners) {
- listener.switchUpdated(nodeId);
- }
- }
-
- // XXX there's a race condition here if a switch exists at startup and is
- // removed very quickly.
- private final FutureCallback<Optional<Nodes>> readSwitchesCallback =
- new FutureCallback<Optional<Nodes>>() {
- @Override
- public void onSuccess(Optional<Nodes> result) {
- if (result.isPresent() && result.get() instanceof Nodes) {
- Nodes nodes = (Nodes)result.get();
- for (Node node : nodes.getNode()) {
- updateSwitch(node);
- }
- }
- }
-
- @Override
- public void onFailure(Throwable t) {
- LOG.error("Count not read switch information", t);
- }
- };
-
- private final FutureCallback<Optional<Nodes>> readSwitchConfCallback =
- new FutureCallback<Optional<Nodes>>() {
- @Override
- public void onSuccess(Optional<Nodes> result) {
- if (result.isPresent()) {
- Nodes nodes = (Nodes)result.get();
- for (Node node : nodes.getNode()) {
- OfOverlayNodeConfig config =
- node.getAugmentation(OfOverlayNodeConfig.class);
- if (config != null)
- updateSwitchConfig(node.getId(), config);
- }
- }
- }
-
- @Override
- public void onFailure(Throwable t) {
- LOG.error("Count not read switch information", t);
- }
- };
-
- /**
- * Read the set of switches from the ODL inventory and update our internal
- * map.
- *
- * <p>This is safe only if there can only be one notification at a time,
- * as there are race conditions in the face of concurrent data change
- * notifications
- */
- private void readSwitches() {
- if (dataProvider != null) {
- ListenableFuture<Optional<Nodes>> future =
- dataProvider.newReadOnlyTransaction()
- .read(LogicalDatastoreType.CONFIGURATION, nodesIid);
- Futures.addCallback(future, readSwitchConfCallback);
-
- future = dataProvider.newReadOnlyTransaction()
- .read(LogicalDatastoreType.OPERATIONAL, nodesIid);
- Futures.addCallback(future, readSwitchesCallback);
- }
- }
-
- /**
- * Set the ready state of the node to PREPARING and begin the initialization
- * process
- */
- private void switchConnected(NodeId nodeId) {
- SwitchState state = switches.get(nodeId);
- if (state != null) {
- // XXX - TODO - For now we just go straight to ready state.
- // need to configure tunnels and tables as needed
- switchReady(nodeId);
- LOG.info("New switch {} connected", nodeId);
- }
- }
-
- /**
- * Set the ready state of the node to READY and notify listeners
- */
- private void switchReady(NodeId nodeId) {
- SwitchState state = switches.get(nodeId);
- if (state != null) {
- state.status = SwitchStatus.READY;
- for (SwitchListener listener : listeners) {
- listener.switchReady(nodeId);
- }
- }
- }
-
- /**
- * Remove the switch from the switches we're keeping track of and
- * notify listeners
- */
- private void removeSwitch(NodeId nodeId) {
- switches.remove(nodeId);
- for (SwitchListener listener : listeners) {
- listener.switchRemoved(nodeId);
- }
- LOG.info("Switch {} removed", nodeId);
- }
-
- protected enum SwitchStatus {
- /**
- * The switch is not currently connected
- */
- DISCONNECTED,
- /**
- * The switch is connected but not yet configured
- */
- PREPARING,
- /**
- * The switch is ready to for policy rules to be installed
- */
- READY
- }
-
- /**
- * Internal representation of the state of a connected switch
- */
- protected static class SwitchState {
- NodeId nodeId;
-
- Node switchNode;
- OfOverlayNodeConfig nodeConfig;
-
- NodeConnectorId tunnelPort;
- Set<NodeConnectorId> externalPorts = Collections.emptySet();
-
- SwitchStatus status = SwitchStatus.DISCONNECTED;
-
- public SwitchState(NodeId switchNode) {
- super();
- nodeId = switchNode;
- }
-
- /**
- * Constructor used for tests
- */
- public SwitchState(NodeId node,
- NodeConnectorId tunnelPort,
- Set<NodeConnectorId> externalPorts,
- OfOverlayNodeConfig nodeConfig) {
- this.nodeId = node;
- this.tunnelPort = tunnelPort;
- this.externalPorts = externalPorts;
- this.nodeConfig = nodeConfig;
- }
-
- private void update() {
- if (switchNode == null) return;
- FlowCapableNode fcn =
- switchNode.getAugmentation(FlowCapableNode.class);
- if (fcn == null) return;
-
- List<NodeConnector> ports = switchNode.getNodeConnector();
- HashSet<NodeConnectorId> externalPorts = new HashSet<>();
- if (ports != null) {
- for (NodeConnector nc : ports) {
- FlowCapableNodeConnector fcnc =
- nc.getAugmentation(FlowCapableNodeConnector.class);
- if (fcnc == null || fcnc.getName() == null) continue;
-
- if (fcnc.getName().matches(".*_(vxlan|tun)\\d+")) {
- tunnelPort = nc.getId();
- }
- if (nodeConfig != null && nodeConfig.getExternalInterfaces() != null ) {
- for (String pattern : nodeConfig.getExternalInterfaces()) {
- if (fcnc.getName().matches(pattern))
- externalPorts.add(nc.getId());
- }
- }
- }
- }
- this.externalPorts = Collections.unmodifiableSet(externalPorts);
- }
-
- public void setNode(Node switchNode) {
- this.switchNode = switchNode;
- update();
- }
-
- public void setConfig(OfOverlayNodeConfig config) {
- nodeConfig = config;
- update();
- }
- }
-
-}
--- /dev/null
+package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+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.ofoverlay.rev140528.OfOverlayContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContextBuilder;
+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 com.google.common.base.Objects;
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.Futures;
+
+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();
+ Map<Name, Endpoint> epWithOfOverlayAugByPortName = readEpsWithOfOverlayAugByPortName(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);
+ if (updated == true) {
+ 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);
+ if (updated == true) {
+ isDataPutToTx = true;
+ }
+ FlowCapableNodeConnector originalFcnc = (FlowCapableNodeConnector) change.getOriginalData().get(
+ fcncEntry.getKey());
+ Name portNameFromOriginalFcnc = getPortName(originalFcnc);
+ // portname already existed and then was changed
+ if (portNameFromOriginalFcnc != null && !Objects.equal(portNameFromOriginalFcnc, portName)) {
+ updated = updateEpWithNodeConnectorInfo(epWithOfOverlayAugByPortName.get(portNameFromOriginalFcnc),
+ null, rwTx);
+ if (updated == true) {
+ 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);
+ if (updated == true) {
+ isDataPutToTx = true;
+ }
+ }
+ }
+ if (isDataPutToTx) {
+ rwTx.submit();
+ } else {
+ rwTx.cancel();
+ }
+ }
+
+ 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;
+ }
+
+ private Name getPortName(FlowCapableNodeConnector fcnc) {
+ if (fcnc == null || fcnc.getName() == null) {
+ return null;
+ }
+ return new Name(fcnc.getName());
+ }
+
+ /**
+ * @return {@code true} if data 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);
+ }
+ 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;
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (listenerRegistration != null) {
+ listenerRegistration.close();
+ }
+ }
+
+}
--- /dev/null
+package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+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.FlowCapableNode;
+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.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;
+
+public class FlowCapableNodeListener implements DataChangeListener, AutoCloseable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(FlowCapableNodeListener.class);
+
+ private final static InstanceIdentifier<FlowCapableNode> fcNodeIid = InstanceIdentifier.builder(Nodes.class)
+ .child(Node.class)
+ .augmentation(FlowCapableNode.class)
+ .build();
+ private final SwitchManager switchManager;
+ private final ListenerRegistration<DataChangeListener> listenerRegistration;
+
+ public FlowCapableNodeListener(DataBroker dataProvider, SwitchManager switchManager) {
+ this.switchManager = checkNotNull(switchManager);
+ listenerRegistration = checkNotNull(dataProvider).registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+ fcNodeIid, this, DataChangeScope.BASE);
+ }
+
+ @Override
+ public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+ for (Entry<InstanceIdentifier<?>, DataObject> fcNodeEntry : change.getCreatedData().entrySet()) {
+ if (FlowCapableNode.class.equals(fcNodeEntry.getKey().getTargetType())) {
+ NodeId nodeId = fcNodeEntry.getKey().firstKeyOf(Node.class, NodeKey.class).getId();
+ FlowCapableNode fcNode = (FlowCapableNode) fcNodeEntry.getValue();
+ LOG.trace("FlowCapableNode created. NodeId: {} FlowCapableNode: {}", nodeId.getValue(), fcNode);
+ switchManager.updateSwitch(nodeId, fcNode);
+ }
+ }
+ for (Entry<InstanceIdentifier<?>, DataObject> fcNodeEntry : change.getUpdatedData().entrySet()) {
+ if (FlowCapableNode.class.equals(fcNodeEntry.getKey().getTargetType())) {
+ NodeId nodeId = fcNodeEntry.getKey().firstKeyOf(Node.class, NodeKey.class).getId();
+ FlowCapableNode fcNode = (FlowCapableNode) fcNodeEntry.getValue();
+ LOG.trace("FlowCapableNode updated. NodeId: {} FlowCapableNode: {}", nodeId.getValue(), fcNode);
+ switchManager.updateSwitch(nodeId, fcNode);
+ }
+ }
+ for (InstanceIdentifier<?> removedFcNodeIid : change.getRemovedPaths()) {
+ if (FlowCapableNode.class.equals(removedFcNodeIid.getTargetType())) {
+ NodeId nodeId = removedFcNodeIid.firstKeyOf(Node.class, NodeKey.class).getId();
+ LOG.trace("FlowCapableNode removed. NodeId: {}", nodeId.getValue());
+ switchManager.updateSwitch(nodeId, null);
+ }
+ }
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (listenerRegistration != null) {
+ listenerRegistration.close();
+ }
+ }
+
+}
--- /dev/null
+package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+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.groupbasedpolicy.ofoverlay.rev140528.OfOverlayNodeConfig;
+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.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;
+
+public class OfOverlayNodeListener implements DataChangeListener, AutoCloseable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(OfOverlayNodeListener.class);
+
+ private final static InstanceIdentifier<OfOverlayNodeConfig> ofOverlayNodeIid = InstanceIdentifier.builder(
+ Nodes.class)
+ .child(Node.class)
+ .augmentation(OfOverlayNodeConfig.class)
+ .build();
+ private final SwitchManager switchManager;
+ private final ListenerRegistration<DataChangeListener> listenerRegistration;
+
+ public OfOverlayNodeListener(DataBroker dataProvider, SwitchManager switchManager) {
+ this.switchManager = checkNotNull(switchManager);
+ listenerRegistration = checkNotNull(dataProvider).registerDataChangeListener(
+ LogicalDatastoreType.CONFIGURATION, ofOverlayNodeIid, this, DataChangeScope.BASE);
+ }
+
+ @Override
+ public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+ for (Entry<InstanceIdentifier<?>, DataObject> nodeConfigEntry : change.getCreatedData().entrySet()) {
+ if (OfOverlayNodeConfig.class.equals(nodeConfigEntry.getKey().getTargetType())) {
+ NodeId nodeId = nodeConfigEntry.getKey().firstKeyOf(Node.class, NodeKey.class).getId();
+ OfOverlayNodeConfig nodeConfig = (OfOverlayNodeConfig) nodeConfigEntry.getValue();
+ LOG.trace("OfOverlayNodeConfig created. NodeId: {} OfOverlayNodeConfig: {}", nodeId.getValue(),
+ nodeConfig);
+ switchManager.updateSwitchConfig(nodeId, nodeConfig);
+ }
+ }
+ for (Entry<InstanceIdentifier<?>, DataObject> nodeConfigEntry : change.getUpdatedData().entrySet()) {
+ if (OfOverlayNodeConfig.class.equals(nodeConfigEntry.getKey().getTargetType())) {
+ NodeId nodeId = nodeConfigEntry.getKey().firstKeyOf(Node.class, NodeKey.class).getId();
+ OfOverlayNodeConfig nodeConfig = (OfOverlayNodeConfig) nodeConfigEntry.getValue();
+ LOG.trace("OfOverlayNodeConfig updated. NodeId: {} OfOverlayNodeConfig: {}", nodeId.getValue(),
+ nodeConfig);
+ switchManager.updateSwitchConfig(nodeId, nodeConfig);
+ }
+ }
+ for (InstanceIdentifier<?> removedNodeConfigIid : change.getRemovedPaths()) {
+ if (OfOverlayNodeConfig.class.equals(removedNodeConfigIid.getTargetType())) {
+ NodeId nodeId = removedNodeConfigIid.firstKeyOf(Node.class, NodeKey.class).getId();
+ LOG.trace("OfOverlayNodeConfig removed. NodeId: {}", nodeId.getValue());
+ switchManager.updateSwitchConfig(nodeId, null);
+ }
+ }
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (listenerRegistration != null) {
+ listenerRegistration.close();
+ }
+ }
+
+}
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-package org.opendaylight.groupbasedpolicy.renderer.ofoverlay;
+package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
--- /dev/null
+/*
+ * 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 static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import javax.annotation.Nullable;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayConfig.EncapsulationFormat;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayNodeConfig;
+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.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.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Function;
+import com.google.common.base.Objects;
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Maps;
+
+/**
+ * Manage connected switches and ensure their configuration is set up
+ * correctly
+ */
+public class SwitchManager implements AutoCloseable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SwitchManager.class);
+
+ protected Map<NodeId, SwitchState> switches = new HashMap<>();
+ protected List<SwitchListener> listeners = new CopyOnWriteArrayList<>();
+
+ private final FlowCapableNodeListener nodeListener;
+ private final OfOverlayNodeListener ofOverlayNodeListener;
+ private final FlowCapableNodeConnectorListener nodeConnectorListener;
+
+ public SwitchManager(DataBroker dataProvider) {
+ if (dataProvider == null) {
+ LOG.warn("No data provider for {}. Listeners {}, {}, {} are not registered.",
+ SwitchManager.class.getSimpleName(), FlowCapableNodeListener.class.getSimpleName(),
+ OfOverlayNodeListener.class.getSimpleName(), FlowCapableNodeConnectorListener.class.getSimpleName());
+ nodeListener = null;
+ ofOverlayNodeListener = null;
+ nodeConnectorListener = null;
+ } else {
+ nodeListener = new FlowCapableNodeListener(dataProvider, this);
+ ofOverlayNodeListener = new OfOverlayNodeListener(dataProvider, this);
+ nodeConnectorListener = new FlowCapableNodeConnectorListener(dataProvider, this);
+ }
+ LOG.debug("Initialized OFOverlay switch manager");
+ }
+
+ /**
+ * Get the collection of switches that are in the "ready" state. Note
+ * that the collection is immutable.
+ *
+ * @return A {@link Collection} containing the switches that are ready.
+ */
+ public synchronized Collection<NodeId> getReadySwitches() {
+ ImmutableList<NodeId> readySwitches = FluentIterable.from(switches.values())
+ .filter(new Predicate<SwitchState>() {
+
+ @Override
+ public boolean apply(SwitchState input) {
+ return input.status == SwitchStatus.READY;
+ }
+ })
+ .transform(new Function<SwitchState, NodeId>() {
+
+ @Override
+ public NodeId apply(SwitchState input) {
+ return input.nodeId;
+ }
+ })
+ .toList();
+ LOG.trace("Get ready switches: {}", readySwitches);
+ return readySwitches;
+ }
+
+ public synchronized Set<NodeConnectorId> getExternalPorts(NodeId nodeId) {
+ SwitchState state = switches.get(nodeId);
+ if (state == null)
+ return Collections.emptySet();
+ return state.externalPorts;
+ }
+
+ public synchronized NodeConnectorId getTunnelPort(NodeId nodeId) {
+ SwitchState state = switches.get(nodeId);
+ if (state == null)
+ return null;
+ return state.tunnelPort;
+ }
+
+ public synchronized IpAddress getTunnelIP(NodeId nodeId) {
+ SwitchState state = switches.get(nodeId);
+ if (state == null || state.nodeConfig == null)
+ return null;
+ return state.nodeConfig.getTunnelIp();
+ }
+
+ /**
+ * Add a {@link SwitchListener} to get notifications of switch events
+ *
+ * @param listener the {@link SwitchListener} to add
+ */
+ public void registerListener(SwitchListener listener) {
+ listeners.add(listener);
+ }
+
+ /**
+ * Set the encapsulation format the specified value
+ *
+ * @param format The new format
+ */
+ public void setEncapsulationFormat(EncapsulationFormat format) {
+ // No-op for now
+ }
+
+ synchronized void updateSwitch(NodeId nodeId, @Nullable FlowCapableNode fcNode) {
+ SwitchState state = getSwitchState(checkNotNull(nodeId));
+ SwitchStatus oldStatus = state.status;
+ state.setFlowCapableNode(fcNode);
+ handleSwitchState(state, oldStatus);
+ }
+
+ synchronized void updateSwitchNodeConnectorConfig(InstanceIdentifier<NodeConnector> ncIid,
+ @Nullable FlowCapableNodeConnector fcnc) {
+ NodeId nodeId = ncIid.firstKeyOf(Node.class, NodeKey.class).getId();
+ SwitchState state = getSwitchState(nodeId);
+ SwitchStatus oldStatus = state.status;
+ state.setNodeConnectorConfig(ncIid, fcnc);
+ handleSwitchState(state, oldStatus);
+ }
+
+ synchronized void updateSwitchConfig(NodeId nodeId, @Nullable OfOverlayNodeConfig config) {
+ SwitchState state = getSwitchState(checkNotNull(nodeId));
+ SwitchStatus oldStatus = state.status;
+ state.setConfig(config);
+ handleSwitchState(state, oldStatus);
+ }
+
+ private SwitchState getSwitchState(NodeId id) {
+ SwitchState state = switches.get(id);
+ if (state == null) {
+ state = new SwitchState(id);
+ switches.put(id, state);
+ LOG.trace("Switch {} added to switches {}", state.nodeId.getValue(), switches.keySet());
+ }
+ return state;
+ }
+
+ private void handleSwitchState(SwitchState state, SwitchStatus oldStatus) {
+ if (oldStatus == SwitchStatus.READY && state.status != SwitchStatus.READY) {
+ LOG.info("Switch {} removed", state.nodeId.getValue());
+ notifySwitchRemoved(state.nodeId);
+ } else if (oldStatus != SwitchStatus.READY && state.status == SwitchStatus.READY) {
+ LOG.info("Switch {} ready", state.nodeId.getValue());
+ notifySwitchReady(state.nodeId);
+ } else if (oldStatus == SwitchStatus.READY && state.status == SwitchStatus.READY) {
+ // TODO Be msunal we could improve this by ignoring of updates where uninteresting fields are changed
+ LOG.debug("Switch {} updated", state.nodeId.getValue());
+ notifySwitchUpdated(state.nodeId);
+ }
+ if (state.status == SwitchStatus.DISCONNECTED && state.isConfigurationEmpty()) {
+ switches.remove(state.nodeId);
+ LOG.trace("Switch {} removed from switches {}", state.nodeId, switches.keySet());
+ }
+ }
+
+ private void notifySwitchRemoved(NodeId nodeId) {
+ for (SwitchListener listener : listeners) {
+ listener.switchRemoved(nodeId);
+ }
+ }
+
+ private void notifySwitchReady(NodeId nodeId) {
+ for (SwitchListener listener : listeners) {
+ listener.switchReady(nodeId);
+ }
+ }
+
+ private void notifySwitchUpdated(NodeId nodeId) {
+ for (SwitchListener listener : listeners) {
+ listener.switchUpdated(nodeId);
+ }
+ }
+
+ @Override
+ public void close() throws Exception {
+ nodeListener.close();
+ ofOverlayNodeListener.close();
+ nodeConnectorListener.close();
+ }
+
+ /**
+ * Internal representation of the state of a connected switch
+ */
+ protected static final class SwitchState {
+
+ private NodeId nodeId;
+ private FlowCapableNode fcNode;
+ private OfOverlayNodeConfig nodeConfig;
+ private Map<InstanceIdentifier<NodeConnector>, FlowCapableNodeConnector> fcncByNcIid = Maps.newHashMap();
+
+ NodeConnectorId tunnelPort;
+ Set<NodeConnectorId> externalPorts = new HashSet<>();
+
+ SwitchStatus status;
+
+ public SwitchState(NodeId switchNode) {
+ super();
+ nodeId = switchNode;
+ }
+
+ /**
+ * Constructor used for tests
+ */
+ public SwitchState(NodeId node, NodeConnectorId tunnelPort, Set<NodeConnectorId> externalPorts,
+ OfOverlayNodeConfig nodeConfig) {
+ this.nodeId = node;
+ this.tunnelPort = tunnelPort;
+ this.externalPorts = externalPorts;
+ this.nodeConfig = nodeConfig;
+ }
+
+ private void update() {
+ HashSet<NodeConnectorId> externalPorts = new HashSet<>();
+ NodeConnectorId tunnelPort = null;
+ for (Entry<InstanceIdentifier<NodeConnector>, FlowCapableNodeConnector> fcncByNcIidEntry : fcncByNcIid.entrySet()) {
+ FlowCapableNodeConnector fcnc = fcncByNcIidEntry.getValue();
+ if (fcnc.getName() == null) {
+ continue;
+ }
+ InstanceIdentifier<NodeConnector> ncIid = fcncByNcIidEntry.getKey();
+ NodeConnectorId ncId = ncIid.firstKeyOf(NodeConnector.class, NodeConnectorKey.class).getId();
+ if (fcnc.getName().matches(".*(vxlan|tun).*")) {
+ tunnelPort = ncId;
+ }
+ if (nodeConfig != null && nodeConfig.getExternalInterfaces() != null) {
+ for (String pattern : nodeConfig.getExternalInterfaces()) {
+ if (fcnc.getName().matches(pattern)) {
+ externalPorts.add(ncId);
+ break;
+ }
+ }
+ }
+ }
+ this.tunnelPort = tunnelPort;
+ this.externalPorts = Collections.unmodifiableSet(externalPorts);
+ }
+
+ private void updateStatus() {
+ boolean tunnelPortWithIpExists = tunnelPortWithIpExists();
+ if (fcNode != null) {
+ if (tunnelPortWithIpExists) {
+ setStatus(SwitchStatus.READY);
+ } else {
+ setStatus(SwitchStatus.PREPARING);
+ }
+ } else {
+ setStatus(SwitchStatus.DISCONNECTED);
+ }
+ }
+
+ private void setStatus(SwitchStatus newStatus) {
+ if (Objects.equal(status, newStatus)) {
+ return;
+ }
+ LOG.debug("Switch {} is changing status from {} to {}", nodeId.getValue(), this.status, newStatus);
+ this.status = newStatus;
+ }
+
+ private boolean tunnelPortWithIpExists() {
+ boolean tunnelPortWithIpExists = false;
+ if (tunnelPort != null && nodeConfig != null && nodeConfig.getTunnelIp() != null) {
+ tunnelPortWithIpExists = true;
+ }
+ LOG.trace("Status of tunnel on switch {} - tunnelPort: {} tunnelIp: {}", nodeId.getValue(),
+ tunnelPort == null ? null : tunnelPort.getValue(),
+ nodeConfig == null ? null : nodeConfig.getTunnelIp());
+ return tunnelPortWithIpExists;
+ }
+
+ public boolean isConfigurationEmpty() {
+ if (fcNode != null)
+ return false;
+ if (nodeConfig != null)
+ return false;
+ if (!fcncByNcIid.isEmpty())
+ return false;
+ return true;
+ }
+
+ public void setFlowCapableNode(FlowCapableNode fcNode) {
+ this.fcNode = fcNode;
+ LOG.trace("Switch {} set {}", nodeId.getValue(), fcNode);
+ updateStatus();
+ }
+
+ public void setConfig(OfOverlayNodeConfig config) {
+ this.nodeConfig = config;
+ LOG.trace("Switch {} set {}", nodeId.getValue(), config);
+ update();
+ updateStatus();
+ }
+
+ public void setNodeConnectorConfig(InstanceIdentifier<NodeConnector> ncIid, FlowCapableNodeConnector fcnc) {
+ if (fcnc == null) {
+ fcncByNcIid.remove(ncIid);
+ } else {
+ fcncByNcIid.put(ncIid, fcnc);
+ }
+ LOG.trace("Switch {} node connector {} set {}", nodeId.getValue(),
+ ncIid.firstKeyOf(NodeConnector.class, NodeConnectorKey.class).getId().getValue(), fcnc);
+ update();
+ updateStatus();
+ }
+
+ }
+
+ protected enum SwitchStatus {
+ /**
+ * The switch is not currently connected
+ */
+ DISCONNECTED,
+ /**
+ * The switch is connected but not yet configured
+ */
+ PREPARING,
+ /**
+ * The switch is ready to for policy rules to be installed
+ */
+ READY
+ }
+
+}
\r
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.MockEndpointManager;\r
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.MockPolicyManager;\r
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.MockSwitchManager;\r
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;\r
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.MockSwitchManager;\r
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.AllowAction;\r
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.Classifier;\r
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sf.L4Classifier;\r
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-package org.opendaylight.groupbasedpolicy.renderer.ofoverlay;
+package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node;
import java.util.Set;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchListener;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayNodeConfig;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
public class MockSwitchManager extends SwitchManager {
public MockSwitchManager() {
- super(null, null);
+ super(null);
}
- public void addSwitch(NodeId node,
+ public void addSwitch(NodeId node,
NodeConnectorId tunnelPort,
Set<NodeConnectorId> externalPorts,
OfOverlayNodeConfig nodeConfig) {
- SwitchState state = new SwitchState(node, tunnelPort,
+ SwitchState state = new SwitchState(node, tunnelPort,
externalPorts, nodeConfig);
state.status = SwitchStatus.READY;
switches.put(node, state);