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
9 package org.opendaylight.openflowplugin.applications.frsync.impl;
11 import com.google.common.base.Optional;
12 import com.google.common.util.concurrent.ListenableFuture;
13 import java.util.Collection;
14 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
15 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
16 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
17 import org.opendaylight.openflowplugin.applications.frsync.SyncReactor;
18 import org.opendaylight.openflowplugin.applications.frsync.dao.FlowCapableNodeDao;
19 import org.opendaylight.openflowplugin.applications.frsync.dao.FlowCapableNodeSnapshotDao;
20 import org.opendaylight.openflowplugin.applications.frsync.util.PathUtil;
21 import org.opendaylight.openflowplugin.applications.frsync.util.SyncupEntry;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
24 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
29 * Listens to config changes and delegates add/remove/update/barrier to {@link SyncReactor}.
31 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(Collection<DataTreeModification<FlowCapableNode>> modifications) {
47 LOG.trace("Config changes: {}", modifications.size());
48 super.onDataTreeChanged(modifications);
52 * Compare cached operational with current config modification. If operational is not present
53 * skip calling Inventory RPCs.
54 * @throws InterruptedException from syncup
56 protected Optional<ListenableFuture<Boolean>> processNodeModification(
57 DataTreeModification<FlowCapableNode> modification) throws InterruptedException {
58 final InstanceIdentifier<FlowCapableNode> nodePath = modification.getRootPath().getRootIdentifier();
59 final NodeId nodeId = PathUtil.digNodeId(nodePath);
61 configSnapshot.updateCache(nodeId, Optional.fromNullable(modification.getRootNode().getDataAfter()));
63 final Optional<FlowCapableNode> operationalNode = operationalDao.loadByNodeId(nodeId);
64 if (!operationalNode.isPresent()) {
65 LOG.info("Skip syncup, {} operational is not present", nodeId.getValue());
66 return Optional.absent();
69 final DataObjectModification<FlowCapableNode> configModification = modification.getRootNode();
70 final FlowCapableNode dataBefore = configModification.getDataBefore();
71 final FlowCapableNode dataAfter = configModification.getDataAfter();
72 final ListenableFuture<Boolean> endResult;
73 if (dataBefore == null && dataAfter != null) {
74 endResult = onNodeAdded(nodePath, dataAfter, operationalNode.get());
75 } else if (dataBefore != null && dataAfter == null) {
76 endResult = onNodeDeleted(nodePath, dataBefore);
78 endResult = onNodeUpdated(nodePath, dataBefore, dataAfter);
81 return Optional.of(endResult);
85 * Add only what is missing in operational store. Config. node could be added in two situations:
87 * <li>Note very first time after restart was handled by operational listener. Syncup should
88 * calculate no delta (we don want to reconfigure switch if not necessary).</li>
89 * <li>But later the config. node could be deleted, after that config node added again. Syncup
90 * should calculate that everything needs to be added. Operational store should be empty in
91 * optimal case (but the switch could be reprogrammed by another person/system.</li>
94 private ListenableFuture<Boolean> onNodeAdded(final InstanceIdentifier<FlowCapableNode> nodePath,
95 final FlowCapableNode dataAfter,
96 final FlowCapableNode operationalNode) throws InterruptedException {
97 NodeId nodeId = PathUtil.digNodeId(nodePath);
98 LOG.trace("onNodeAdded {}", nodeId.getValue());
99 final SyncupEntry syncupEntry = new SyncupEntry(dataAfter, dsType(), operationalNode, LogicalDatastoreType.OPERATIONAL);
100 return reactor.syncup(nodePath, syncupEntry);
104 * Apply minimal changes very fast. For better performance needed just compare config
105 * after+before. Config listener should not be dependent on operational flows/groups while
106 * updating config because operational store is highly async and it depends on another module in
107 * system which is updating operational store (that components is also trying to solve
108 * scale/performance issues on several layers).
110 private ListenableFuture<Boolean> onNodeUpdated(final InstanceIdentifier<FlowCapableNode> nodePath,
111 final FlowCapableNode dataBefore,
112 final FlowCapableNode dataAfter) throws InterruptedException {
113 NodeId nodeId = PathUtil.digNodeId(nodePath);
114 LOG.trace("onNodeUpdated {}", nodeId.getValue());
115 final SyncupEntry syncupEntry = new SyncupEntry(dataAfter, dsType(), dataBefore, dsType());
116 return reactor.syncup(nodePath, syncupEntry);
120 * Remove values that are being deleted in the config from the switch. Note, this could be
121 * probably optimized using dedicated wipe-out RPC, but it has impact on switch if it is
122 * programmed by two person/system
124 private ListenableFuture<Boolean> onNodeDeleted(final InstanceIdentifier<FlowCapableNode> nodePath,
125 final FlowCapableNode dataBefore) throws InterruptedException {
126 NodeId nodeId = PathUtil.digNodeId(nodePath);
127 LOG.trace("onNodeDeleted {}", nodeId.getValue());
128 final SyncupEntry syncupEntry = new SyncupEntry(null, dsType(), dataBefore, dsType());
129 return reactor.syncup(nodePath, syncupEntry);
133 public LogicalDatastoreType dsType() {
134 return LogicalDatastoreType.CONFIGURATION;