2 * Copyright (c) 2016 Cisco Systems, Inc. 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.openflowplugin.applications.frsync.impl;
10 import com.google.common.util.concurrent.ListenableFuture;
11 import java.util.List;
12 import java.util.Optional;
13 import org.opendaylight.mdsal.binding.api.DataObjectModification;
14 import org.opendaylight.mdsal.binding.api.DataTreeModification;
15 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
16 import org.opendaylight.openflowplugin.applications.frsync.SyncReactor;
17 import org.opendaylight.openflowplugin.applications.frsync.dao.FlowCapableNodeDao;
18 import org.opendaylight.openflowplugin.applications.frsync.dao.FlowCapableNodeSnapshotDao;
19 import org.opendaylight.openflowplugin.applications.frsync.util.PathUtil;
20 import org.opendaylight.openflowplugin.applications.frsync.util.SyncupEntry;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
23 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
28 * Listens to config changes and delegates sync entry to {@link SyncReactor}.
30 public class SimplifiedConfigListener extends AbstractFrmSyncListener<FlowCapableNode> {
32 private static final Logger LOG = LoggerFactory.getLogger(SimplifiedConfigListener.class);
33 private final SyncReactor reactor;
34 private final FlowCapableNodeSnapshotDao configSnapshot;
35 private final FlowCapableNodeDao operationalDao;
37 public SimplifiedConfigListener(final SyncReactor reactor,
38 final FlowCapableNodeSnapshotDao configSnapshot,
39 final FlowCapableNodeDao operationalDao) {
40 this.reactor = reactor;
41 this.configSnapshot = configSnapshot;
42 this.operationalDao = operationalDao;
46 public void onDataTreeChanged(final List<DataTreeModification<FlowCapableNode>> modifications) {
47 super.onDataTreeChanged(modifications);
51 * Update cache. If operational data are present, choose appropriate data and start syncup.
52 * Otherwise skip incoming change.
55 protected Optional<ListenableFuture<Boolean>> processNodeModification(
56 final DataTreeModification<FlowCapableNode> modification) {
57 final InstanceIdentifier<FlowCapableNode> nodePath = modification.getRootPath().getRootIdentifier();
58 final NodeId nodeId = PathUtil.digNodeId(nodePath);
60 configSnapshot.updateCache(nodeId, Optional.ofNullable(modification.getRootNode().getDataAfter()));
62 final Optional<FlowCapableNode> operationalNode = operationalDao.loadByNodeId(nodeId);
63 if (operationalNode.isEmpty()) {
64 LOG.debug("Skip syncup, {} operational is not present", nodeId.getValue());
65 return Optional.empty();
68 final DataObjectModification<FlowCapableNode> configModification = modification.getRootNode();
69 final FlowCapableNode dataBefore = configModification.getDataBefore();
70 final FlowCapableNode dataAfter = configModification.getDataAfter();
71 final ListenableFuture<Boolean> endResult;
72 if (dataBefore == null && dataAfter != null) {
73 endResult = onNodeAdded(nodePath, dataAfter, operationalNode.orElseThrow());
74 } else if (dataBefore != null && dataAfter == null) {
75 endResult = onNodeDeleted(nodePath, dataBefore);
77 endResult = onNodeUpdated(nodePath, dataBefore, dataAfter);
80 return Optional.of(endResult);
84 * If node was added to config DS and it is already present in operational DS (connected) diff between current
85 * new configuration and actual configuration (seen in operational) should be calculated and sent to device.
87 private ListenableFuture<Boolean> onNodeAdded(final InstanceIdentifier<FlowCapableNode> nodePath,
88 final FlowCapableNode dataAfter,
89 final FlowCapableNode operationalNode) {
90 LOG.debug("Reconciliation {}: {}", dsType(), PathUtil.digNodeId(nodePath).getValue());
91 final SyncupEntry syncupEntry = new SyncupEntry(dataAfter, dsType(), operationalNode,
92 LogicalDatastoreType.OPERATIONAL);
93 return reactor.syncup(nodePath, syncupEntry);
97 * Apply minimal changes very fast. For better performance needed just compare config
98 * after+before. Config listener should not be dependent on operational flows/groups/meters while
99 * updating config because operational store is highly async and it depends on another module in
100 * system which is updating operational store (that components is also trying to solve
101 * scale/performance issues on several layers).
103 private ListenableFuture<Boolean> onNodeUpdated(final InstanceIdentifier<FlowCapableNode> nodePath,
104 final FlowCapableNode dataBefore,
105 final FlowCapableNode dataAfter) {
106 final SyncupEntry syncupEntry = new SyncupEntry(dataAfter, dsType(), dataBefore, dsType());
107 return reactor.syncup(nodePath, syncupEntry);
111 * Remove values that are being deleted in the config from the switch.
112 * Note, this could be probably optimized using dedicated wipe-out RPC.
114 private ListenableFuture<Boolean> onNodeDeleted(final InstanceIdentifier<FlowCapableNode> nodePath,
115 final FlowCapableNode dataBefore) {
116 final SyncupEntry syncupEntry = new SyncupEntry(null, dsType(), dataBefore, dsType());
117 return reactor.syncup(nodePath, syncupEntry);
121 public LogicalDatastoreType dsType() {
122 return LogicalDatastoreType.CONFIGURATION;