Replace Table with TableFeatures in FRM.
[openflowplugin.git] / applications / forwardingrules-manager / src / main / java / org / opendaylight / openflowplugin / applications / frm / impl / FlowNodeReconciliationImpl.java
1 /**
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.openflowplugin.applications.frm.impl;
10
11 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeatures;
12
13 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesKey;
14 import com.google.common.base.Optional;
15 import com.google.common.base.Preconditions;
16 import java.util.Collections;
17 import java.util.List;
18 import java.util.Set;
19 import java.util.concurrent.Callable;
20 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
21 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
22 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
23 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
24 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
25 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
26 import org.opendaylight.openflowplugin.applications.frm.FlowNodeReconciliation;
27 import org.opendaylight.openflowplugin.applications.frm.ForwardingRulesManager;
28 import org.opendaylight.openflowplugin.common.wait.SimpleTaskRetryLooper;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
40 import org.opendaylight.yangtools.concepts.ListenerRegistration;
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;
46
47 /**
48  * forwardingrules-manager
49  * org.opendaylight.openflowplugin.applications.frm
50  *
51  * FlowNode Reconciliation Listener
52  * Reconciliation for a new FlowNode
53  *
54  * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
55  *
56  * Created: Jun 13, 2014
57  */
58 public class FlowNodeReconciliationImpl implements FlowNodeReconciliation {
59
60     private static final Logger LOG = LoggerFactory.getLogger(FlowNodeReconciliationImpl.class);
61
62     private final ForwardingRulesManager provider;
63
64     private ListenerRegistration<DataChangeListener> listenerRegistration;
65
66     public FlowNodeReconciliationImpl (final ForwardingRulesManager manager, final DataBroker db) {
67         this.provider = Preconditions.checkNotNull(manager, "ForwardingRulesManager can not be null!");
68         Preconditions.checkNotNull(db, "DataBroker can not be null!");
69         /* Build Path */
70         final InstanceIdentifier<FlowCapableNode> flowNodeWildCardIdentifier = InstanceIdentifier.create(Nodes.class)
71                 .child(Node.class).augmentation(FlowCapableNode.class);
72
73         SimpleTaskRetryLooper looper = new SimpleTaskRetryLooper(ForwardingRulesManagerImpl.STARTUP_LOOP_TICK,
74                 ForwardingRulesManagerImpl.STARTUP_LOOP_MAX_RETRIES);
75         try {
76             listenerRegistration = looper.loopUntilNoException(new Callable<ListenerRegistration<DataChangeListener>>() {
77                 @Override
78                 public ListenerRegistration<DataChangeListener> call() throws Exception {
79                     return db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
80                             flowNodeWildCardIdentifier, FlowNodeReconciliationImpl.this, DataChangeScope.BASE);
81                 }
82             });
83         } catch (Exception e) {
84             LOG.warn("data listener registration failed: {}", e.getMessage());
85             LOG.debug("data listener registration failed.. ", e);
86             throw new IllegalStateException("FlowNodeReconciliation startup fail! System needs restart.", e);
87         }
88     }
89
90     @Override
91     public void close() {
92         if (listenerRegistration != null) {
93             try {
94                 listenerRegistration.close();
95             } catch (Exception e) {
96                 LOG.error("Error by stop FRM FlowNodeReconilListener.", e);
97             }
98             listenerRegistration = null;
99         }
100     }
101
102     @Override
103     public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changeEvent) {
104         Preconditions.checkNotNull(changeEvent,"Async ChangeEvent can not be null!");
105         /* All DataObjects for create */
106         final Set<InstanceIdentifier<?>>  createdData = changeEvent.getCreatedData() != null
107                 ? changeEvent.getCreatedData().keySet() : Collections.<InstanceIdentifier<?>> emptySet();
108         /* All DataObjects for remove */
109         final Set<InstanceIdentifier<?>> removeData = changeEvent.getRemovedPaths() != null
110                 ? changeEvent.getRemovedPaths() : Collections.<InstanceIdentifier<?>> emptySet();
111
112         for (InstanceIdentifier<?> entryKey : removeData) {
113             final InstanceIdentifier<FlowCapableNode> nodeIdent = entryKey
114                     .firstIdentifierOf(FlowCapableNode.class);
115             if ( ! nodeIdent.isWildcarded()) {
116                 flowNodeDisconnected(nodeIdent);
117             }
118         }
119         for (InstanceIdentifier<?> entryKey : createdData) {
120             final InstanceIdentifier<FlowCapableNode> nodeIdent = entryKey
121                     .firstIdentifierOf(FlowCapableNode.class);
122             if ( ! nodeIdent.isWildcarded()) {
123                 flowNodeConnected(nodeIdent);
124             }
125         }
126     }
127
128     @Override
129     public void flowNodeDisconnected(InstanceIdentifier<FlowCapableNode> disconnectedNode) {
130         provider.unregistrateNode(disconnectedNode);
131     }
132
133     @Override
134     public void flowNodeConnected(InstanceIdentifier<FlowCapableNode> connectedNode) {
135         if ( ! provider.isNodeActive(connectedNode)) {
136             provider.registrateNewNode(connectedNode);
137             reconciliation(connectedNode);
138         }
139     }
140
141     private void reconciliation(final InstanceIdentifier<FlowCapableNode> nodeIdent) {
142
143         ReadOnlyTransaction trans = provider.getReadTranaction();
144         Optional<FlowCapableNode> flowNode = Optional.absent();
145
146         try {
147             flowNode = trans.read(LogicalDatastoreType.CONFIGURATION, nodeIdent).get();
148         }
149         catch (Exception e) {
150             LOG.error("Fail with read Config/DS for Node {} !", nodeIdent, e);
151         }
152
153         if (flowNode.isPresent()) {
154             /* Tables - have to be pushed before groups */
155             // CHECK if while pusing the update, updateTableInput can be null to emulate a table add
156             List<Table> tableList = flowNode.get().getTable() != null
157                     ? flowNode.get().getTable() : Collections.<Table> emptyList() ;
158             for (Table table : tableList) {
159                 TableKey tableKey = table.getKey();
160                 KeyedInstanceIdentifier<TableFeatures, TableFeaturesKey> tableFeaturesII
161                     = nodeIdent.child(Table.class, tableKey).child(TableFeatures.class, new TableFeaturesKey(tableKey.getId()));
162                 for (TableFeatures tableFeatures : table.getTableFeatures()) {
163                     provider.getTableFeaturesCommiter().update(tableFeaturesII, tableFeatures, null, nodeIdent);
164                 }
165             }
166
167             /* Groups - have to be first */
168             List<Group> groups = flowNode.get().getGroup() != null
169                     ? flowNode.get().getGroup() : Collections.<Group> emptyList();
170             for (Group group : groups) {
171                 final KeyedInstanceIdentifier<Group, GroupKey> groupIdent =
172                         nodeIdent.child(Group.class, group.getKey());
173                 this.provider.getGroupCommiter().add(groupIdent, group, nodeIdent);
174             }
175             /* Meters */
176             List<Meter> meters = flowNode.get().getMeter() != null
177                     ? flowNode.get().getMeter() : Collections.<Meter> emptyList();
178             for (Meter meter : meters) {
179                 final KeyedInstanceIdentifier<Meter, MeterKey> meterIdent =
180                         nodeIdent.child(Meter.class, meter.getKey());
181                 this.provider.getMeterCommiter().add(meterIdent, meter, nodeIdent);
182             }
183             /* Flows */
184             List<Table> tables = flowNode.get().getTable() != null
185                     ? flowNode.get().getTable() : Collections.<Table> emptyList();
186             for (Table table : tables) {
187                 final KeyedInstanceIdentifier<Table, TableKey> tableIdent =
188                         nodeIdent.child(Table.class, table.getKey());
189                 List<Flow> flows = table.getFlow() != null ? table.getFlow() : Collections.<Flow> emptyList();
190                 for (Flow flow : flows) {
191                     final KeyedInstanceIdentifier<Flow, FlowKey> flowIdent =
192                             tableIdent.child(Flow.class, flow.getKey());
193                     this.provider.getFlowCommiter().add(flowIdent, flow, nodeIdent);
194                 }
195             }
196         }
197         /* clean transaction */
198         trans.close();
199     }
200 }
201