2 * Copyright (c) 2016 , NEC Corporation and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.ovsdb.southbound.reconciliation.configuration;
11 import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION;
13 import com.google.common.base.Optional;
14 import com.google.common.util.concurrent.CheckedFuture;
15 import com.google.common.util.concurrent.FutureCallback;
16 import com.google.common.util.concurrent.Futures;
17 import java.util.Collections;
18 import java.util.HashMap;
21 import javax.annotation.Nullable;
22 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
23 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
24 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
25 import org.opendaylight.ovsdb.southbound.OvsdbConnectionInstance;
26 import org.opendaylight.ovsdb.southbound.OvsdbConnectionManager;
27 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
28 import org.opendaylight.ovsdb.southbound.SouthboundMapper;
29 import org.opendaylight.ovsdb.southbound.ovsdb.transact.BridgeOperationalState;
30 import org.opendaylight.ovsdb.southbound.ovsdb.transact.DataChangesManagedByOvsdbNodeEvent;
31 import org.opendaylight.ovsdb.southbound.ovsdb.transact.TransactCommandAggregator;
32 import org.opendaylight.ovsdb.southbound.reconciliation.ReconciliationManager;
33 import org.opendaylight.ovsdb.southbound.reconciliation.ReconciliationTask;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntry;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntryKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntry;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntryKey;
39 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
40 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
41 import org.opendaylight.yangtools.yang.binding.DataObject;
42 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
43 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
48 * Configuration Reconciliation task to reconcile existing bridge configurations in the config datastore and the
49 * switch when the latter is up and connected to the controller.
50 * Created by Vinh Nguyen (vinh.nguyen@hcl.com) on 3/21/16.
52 public class BridgeConfigReconciliationTask extends ReconciliationTask {
54 private static final Logger LOG = LoggerFactory.getLogger(BridgeConfigReconciliationTask.class);
55 private final OvsdbConnectionInstance connectionInstance;
57 public BridgeConfigReconciliationTask(ReconciliationManager reconciliationManager, OvsdbConnectionManager
58 connectionManager, InstanceIdentifier<?> nodeIid, OvsdbConnectionInstance connectionInstance) {
59 super(reconciliationManager, connectionManager, nodeIid, null);
60 this.connectionInstance = connectionInstance;
65 public boolean reconcileConfiguration(OvsdbConnectionManager connectionManager) {
66 InstanceIdentifier<Topology> topologyInstanceIdentifier = SouthboundMapper.createTopologyInstanceIdentifier();
67 ReadOnlyTransaction tx = reconciliationManager.getDb().newReadOnlyTransaction();
69 // find all bridges of the specific device in the config data store
70 // TODO: this query is not efficient. It retrieves all the Nodes in the datastore, loop over them and look for
71 // the bridges of specific device. It is mre efficient if MDSAL allows query nodes using wildcard on node id
72 // (ie: ovsdb://uuid/<device uuid>/bridge/*) r attributes
73 CheckedFuture<Optional<Topology>, ReadFailedException> readTopologyFuture =
74 tx.read(CONFIGURATION, topologyInstanceIdentifier);
75 Futures.addCallback(readTopologyFuture, new FutureCallback<Optional<Topology>>() {
77 public void onSuccess(@Nullable Optional<Topology> optionalTopology) {
78 if (optionalTopology != null && optionalTopology.isPresent()) {
79 @SuppressWarnings("unchecked")
80 InstanceIdentifier<Node> ndIid = (InstanceIdentifier<Node>) nodeIid;
81 Topology topology = optionalTopology.get();
82 if (topology.getNode() != null) {
83 final Map<InstanceIdentifier<?>, DataObject> changes = new HashMap<>();
84 for (Node node : topology.getNode()) {
85 OvsdbBridgeAugmentation bridge = node.getAugmentation(OvsdbBridgeAugmentation.class);
86 if (bridge != null && bridge.getManagedBy() != null
87 && bridge.getManagedBy().getValue().equals(ndIid)) {
88 changes.putAll(extractBridgeConfigurationChanges(node, bridge));
91 if (!changes.isEmpty()) {
92 reconcileBridgeConfigurations(changes);
99 public void onFailure(Throwable throwable) {
100 LOG.warn("Read Config/DS for Topology failed! {}", nodeIid, throwable);
108 private Map<InstanceIdentifier<?>, DataObject> extractBridgeConfigurationChanges(
109 final Node bridgeNode, final OvsdbBridgeAugmentation ovsdbBridge) {
110 Map<InstanceIdentifier<?>, DataObject> changes = new HashMap<>();
111 final InstanceIdentifier<Node> bridgeNodeIid =
112 SouthboundMapper.createInstanceIdentifier(connectionInstance, ovsdbBridge.getBridgeName().getValue());
113 final InstanceIdentifier<OvsdbBridgeAugmentation> ovsdbBridgeIid =
114 bridgeNodeIid.builder().augmentation(OvsdbBridgeAugmentation.class).build();
115 changes.put(bridgeNodeIid, bridgeNode);
116 changes.put(ovsdbBridgeIid, ovsdbBridge);
118 if (ovsdbBridge.getProtocolEntry() != null) {
119 for (ProtocolEntry protocol : ovsdbBridge.getProtocolEntry()) {
120 if (SouthboundConstants.OVSDB_PROTOCOL_MAP.get(protocol.getProtocol()) != null) {
121 KeyedInstanceIdentifier<ProtocolEntry, ProtocolEntryKey> protocolIid =
122 ovsdbBridgeIid.child(ProtocolEntry.class, protocol.getKey());
123 changes.put(protocolIid, protocol);
125 throw new IllegalArgumentException("Unknown protocol " + protocol.getProtocol());
130 if (ovsdbBridge.getControllerEntry() != null) {
131 for (ControllerEntry controller : ovsdbBridge.getControllerEntry()) {
132 KeyedInstanceIdentifier<ControllerEntry, ControllerEntryKey> controllerIid =
133 ovsdbBridgeIid.child(ControllerEntry.class, controller.getKey());
134 changes.put(controllerIid, controller);
141 private void reconcileBridgeConfigurations(final Map<InstanceIdentifier<?>, DataObject> changes) {
142 AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changeEvents = new AsyncDataChangeEvent() {
144 public Map<InstanceIdentifier<?>, DataObject> getCreatedData() {
149 public Map<InstanceIdentifier<?>, DataObject> getUpdatedData() {
150 return Collections.emptyMap();
154 public Map<InstanceIdentifier<?>, DataObject> getOriginalData() {
155 return Collections.emptyMap();
159 public Set<InstanceIdentifier<?>> getRemovedPaths() {
160 return Collections.emptySet();
164 public DataObject getOriginalSubtree() {
169 public DataObject getUpdatedSubtree() {
174 connectionInstance.transact(new TransactCommandAggregator(),
175 new BridgeOperationalState(reconciliationManager.getDb(), changeEvents),
176 new DataChangesManagedByOvsdbNodeEvent(
177 reconciliationManager.getDb(),
178 connectionInstance.getInstanceIdentifier(),
183 public void doRetry(boolean wasPreviousAttemptSuccessful) {
187 public void checkReadinessAndProcess() {
191 public long retryDelayInMills() {