2 * Copyright (c) 2014 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.frm.impl;
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import java.util.Collections;
14 import java.util.List;
16 import java.util.concurrent.Callable;
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
19 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
20 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
21 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.openflowplugin.applications.frm.FlowNodeReconciliation;
24 import org.opendaylight.openflowplugin.applications.frm.ForwardingRulesManager;
25 import org.opendaylight.openflowplugin.common.wait.SimpleTaskRetryLooper;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
37 import org.opendaylight.yangtools.concepts.ListenerRegistration;
38 import org.opendaylight.yangtools.yang.binding.DataObject;
39 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
40 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
45 * forwardingrules-manager
46 * org.opendaylight.openflowplugin.applications.frm
48 * FlowNode Reconciliation Listener
49 * Reconciliation for a new FlowNode
51 * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
53 * Created: Jun 13, 2014
55 public class FlowNodeReconciliationImpl implements FlowNodeReconciliation {
57 private static final Logger LOG = LoggerFactory.getLogger(FlowNodeReconciliationImpl.class);
59 private final ForwardingRulesManager provider;
61 private ListenerRegistration<DataChangeListener> listenerRegistration;
63 public FlowNodeReconciliationImpl (final ForwardingRulesManager manager, final DataBroker db) {
64 this.provider = Preconditions.checkNotNull(manager, "ForwardingRulesManager can not be null!");
65 Preconditions.checkNotNull(db, "DataBroker can not be null!");
67 final InstanceIdentifier<FlowCapableNode> flowNodeWildCardIdentifier = InstanceIdentifier.create(Nodes.class)
68 .child(Node.class).augmentation(FlowCapableNode.class);
70 SimpleTaskRetryLooper looper = new SimpleTaskRetryLooper(ForwardingRulesManagerImpl.STARTUP_LOOP_TICK,
71 ForwardingRulesManagerImpl.STARTUP_LOOP_MAX_RETRIES);
73 listenerRegistration = looper.loopUntilNoException(new Callable<ListenerRegistration<DataChangeListener>>() {
75 public ListenerRegistration<DataChangeListener> call() throws Exception {
76 return db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
77 flowNodeWildCardIdentifier, FlowNodeReconciliationImpl.this, DataChangeScope.BASE);
80 } catch (Exception e) {
81 LOG.warn("data listener registration failed: {}", e.getMessage());
82 LOG.debug("data listener registration failed.. ", e);
83 throw new IllegalStateException("FlowNodeReconciliation startup fail! System needs restart.", e);
89 if (listenerRegistration != null) {
91 listenerRegistration.close();
92 } catch (Exception e) {
93 LOG.error("Error by stop FRM FlowNodeReconilListener.", e);
95 listenerRegistration = null;
100 public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changeEvent) {
101 Preconditions.checkNotNull(changeEvent,"Async ChangeEvent can not be null!");
102 /* All DataObjects for create */
103 final Set<InstanceIdentifier<?>> createdData = changeEvent.getCreatedData() != null
104 ? changeEvent.getCreatedData().keySet() : Collections.<InstanceIdentifier<?>> emptySet();
105 /* All DataObjects for remove */
106 final Set<InstanceIdentifier<?>> removeData = changeEvent.getRemovedPaths() != null
107 ? changeEvent.getRemovedPaths() : Collections.<InstanceIdentifier<?>> emptySet();
109 for (InstanceIdentifier<?> entryKey : removeData) {
110 final InstanceIdentifier<FlowCapableNode> nodeIdent = entryKey
111 .firstIdentifierOf(FlowCapableNode.class);
112 if ( ! nodeIdent.isWildcarded()) {
113 flowNodeDisconnected(nodeIdent);
116 for (InstanceIdentifier<?> entryKey : createdData) {
117 final InstanceIdentifier<FlowCapableNode> nodeIdent = entryKey
118 .firstIdentifierOf(FlowCapableNode.class);
119 if ( ! nodeIdent.isWildcarded()) {
120 flowNodeConnected(nodeIdent);
126 public void flowNodeDisconnected(InstanceIdentifier<FlowCapableNode> disconnectedNode) {
127 provider.unregistrateNode(disconnectedNode);
131 public void flowNodeConnected(InstanceIdentifier<FlowCapableNode> connectedNode) {
132 if ( ! provider.isNodeActive(connectedNode)) {
133 provider.registrateNewNode(connectedNode);
134 reconciliation(connectedNode);
138 private void reconciliation(final InstanceIdentifier<FlowCapableNode> nodeIdent) {
140 ReadOnlyTransaction trans = provider.getReadTranaction();
141 Optional<FlowCapableNode> flowNode = Optional.absent();
144 flowNode = trans.read(LogicalDatastoreType.CONFIGURATION, nodeIdent).get();
146 catch (Exception e) {
147 LOG.error("Fail with read Config/DS for Node {} !", nodeIdent, e);
150 if (flowNode.isPresent()) {
151 /* Tables - have to be pushed before groups */
152 // CHECK if while pusing the update, updateTableInput can be null to emulate a table add
153 List<Table> tableList = flowNode.get().getTable() != null
154 ? flowNode.get().getTable() : Collections.<Table> emptyList() ;
155 for (Table table : tableList) {
156 final KeyedInstanceIdentifier<Table, TableKey> tableIdent =
157 nodeIdent.child(Table.class, table.getKey());
158 this.provider.getTableCommiter().update(tableIdent, table, null ,nodeIdent) ;
161 /* Groups - have to be first */
162 List<Group> groups = flowNode.get().getGroup() != null
163 ? flowNode.get().getGroup() : Collections.<Group> emptyList();
164 for (Group group : groups) {
165 final KeyedInstanceIdentifier<Group, GroupKey> groupIdent =
166 nodeIdent.child(Group.class, group.getKey());
167 this.provider.getGroupCommiter().add(groupIdent, group, nodeIdent);
170 List<Meter> meters = flowNode.get().getMeter() != null
171 ? flowNode.get().getMeter() : Collections.<Meter> emptyList();
172 for (Meter meter : meters) {
173 final KeyedInstanceIdentifier<Meter, MeterKey> meterIdent =
174 nodeIdent.child(Meter.class, meter.getKey());
175 this.provider.getMeterCommiter().add(meterIdent, meter, nodeIdent);
178 List<Table> tables = flowNode.get().getTable() != null
179 ? flowNode.get().getTable() : Collections.<Table> emptyList();
180 for (Table table : tables) {
181 final KeyedInstanceIdentifier<Table, TableKey> tableIdent =
182 nodeIdent.child(Table.class, table.getKey());
183 List<Flow> flows = table.getFlow() != null ? table.getFlow() : Collections.<Flow> emptyList();
184 for (Flow flow : flows) {
185 final KeyedInstanceIdentifier<Flow, FlowKey> flowIdent =
186 tableIdent.child(Flow.class, flow.getKey());
187 this.provider.getFlowCommiter().add(flowIdent, flow, nodeIdent);
191 /* clean transaction */