Merge "Custom mailbox that is bounded and instrumented."
[controller.git] / opendaylight / md-sal / forwardingrules-manager / src / main / java / org / opendaylight / controller / frm / reconil / FlowNodeReconcilListener.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.controller.frm.reconil;
10
11 import java.util.Map;
12 import java.util.Map.Entry;
13 import java.util.Set;
14 import java.util.concurrent.ExecutionException;
15
16 import org.opendaylight.controller.frm.AbstractChangeListener;
17 import org.opendaylight.controller.frm.FlowCookieProducer;
18 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
19 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowTableRef;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowRef;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInputBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupRef;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.AddMeterInputBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterRef;
36 import org.opendaylight.yangtools.yang.binding.DataObject;
37 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 import com.google.common.base.Optional;
42 import com.google.common.base.Preconditions;
43 import com.google.common.util.concurrent.ListenableFuture;
44
45 /**
46  * forwardingrules-manager
47  * org.opendaylight.controller.frm
48  *
49  * FlowNode Reconciliation Listener
50  * Reconciliation for a new FlowNode
51  * Remove CookieMapKey for removed FlowNode
52  *
53  * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
54  *
55  * Created: Jun 13, 2014
56  */
57 public class FlowNodeReconcilListener extends AbstractChangeListener {
58
59     private static final Logger LOG = LoggerFactory.getLogger(FlowNodeReconcilListener.class);
60
61     private final FlowNodeReconcilProvider provider;
62
63     public FlowNodeReconcilListener(final FlowNodeReconcilProvider provider) {
64         this.provider = Preconditions.checkNotNull(provider, "Flow Node Reconcil Provider can not be null!");
65     }
66
67     @Override
68     public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changeEvent) {
69         /* FlowCapableNode DataObjects for reconciliation */
70         final Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> createdEntries =
71                 changeEvent.getCreatedData().entrySet();
72         /* FlowCapableNode DataObjects for clean FlowCookieHolder */
73         final Set<InstanceIdentifier<? extends DataObject>> removeEntriesInstanceIdentifiers =
74                 changeEvent.getRemovedPaths();
75         for (final Entry<InstanceIdentifier<? extends DataObject>, DataObject> createdEntry : createdEntries) {
76             InstanceIdentifier<? extends DataObject> entryKey = createdEntry.getKey();
77             DataObject entryValue = createdEntry.getValue();
78             if (preconditionForChange(entryKey, entryValue, null)) {
79                 this.add(entryKey, entryValue);
80             }
81         }
82         for (final InstanceIdentifier<?> instanceId : removeEntriesInstanceIdentifiers) {
83             Map<InstanceIdentifier<? extends DataObject>, DataObject> origConfigData =
84                     changeEvent.getOriginalData();
85             final DataObject removeValue = origConfigData.get(instanceId);
86             if (preconditionForChange(instanceId, removeValue, null)) {
87                 this.remove(instanceId, removeValue);
88             }
89         }
90     }
91
92     @Override
93     /* Cleaning FlowCookieManager holder for all node tables */
94     protected void remove(final InstanceIdentifier<? extends DataObject> identifier,
95                           final DataObject removeDataObj) {
96
97         final InstanceIdentifier<FlowCapableNode> flowNodeIdent =
98                 identifier.firstIdentifierOf(FlowCapableNode.class);
99         final FlowCapableNode flowNode = ((FlowCapableNode) removeDataObj);
100
101         for (Table flowTable : flowNode.getTable()) {
102             final InstanceIdentifier<Table> tableIdent =
103                     flowNodeIdent.child(Table.class, flowTable.getKey());
104             FlowCookieProducer.INSTANCE.clean(tableIdent);
105         }
106     }
107
108     @Override
109     /* Reconciliation by connect new FlowCapableNode */
110     protected void add(final InstanceIdentifier<? extends DataObject> identifier,
111                        final DataObject addDataObj) {
112
113         final InstanceIdentifier<FlowCapableNode> flowNodeIdent =
114                 identifier.firstIdentifierOf(FlowCapableNode.class);
115         final Optional<FlowCapableNode> flowCapNode = this.readFlowCapableNode(flowNodeIdent);
116
117         if (flowCapNode.isPresent()) {
118             final InstanceIdentifier<Node> nodeIdent = identifier.firstIdentifierOf(Node.class);
119             final NodeRef nodeRef = new NodeRef(nodeIdent);
120             /* Groups - have to be first */
121             for (Group group : flowCapNode.get().getGroup()) {
122                 final GroupRef groupRef = new GroupRef(flowNodeIdent.child(Group.class, group.getKey()));
123                 final AddGroupInputBuilder groupBuilder = new AddGroupInputBuilder(group);
124                 groupBuilder.setGroupRef(groupRef);
125                 groupBuilder.setNode(nodeRef);
126                 this.provider.getSalGroupService().addGroup(groupBuilder.build());
127             }
128             /* Meters */
129             for (Meter meter : flowCapNode.get().getMeter()) {
130                 final MeterRef meterRef = new MeterRef(flowNodeIdent.child(Meter.class, meter.getKey()));
131                 final AddMeterInputBuilder meterBuilder = new AddMeterInputBuilder(meter);
132                 meterBuilder.setMeterRef(meterRef);
133                 meterBuilder.setNode(nodeRef);
134                 this.provider.getSalMeterService().addMeter(meterBuilder.build());
135             }
136             /* Flows */
137             for (Table flowTable : flowCapNode.get().getTable()) {
138                 final InstanceIdentifier<Table> tableIdent = flowNodeIdent.child(Table.class, flowTable.getKey());
139                 for (Flow flow : flowTable.getFlow()) {
140                     final FlowCookie flowCookie = new FlowCookie(FlowCookieProducer.INSTANCE.getNewCookie(tableIdent));
141                     final FlowRef flowRef = new FlowRef(tableIdent.child(Flow.class, flow.getKey()));
142                     final FlowTableRef flowTableRef = new FlowTableRef(tableIdent);
143                     final AddFlowInputBuilder flowBuilder = new AddFlowInputBuilder(flow);
144                     flowBuilder.setCookie(flowCookie);
145                     flowBuilder.setNode(nodeRef);
146                     flowBuilder.setFlowTable(flowTableRef);
147                     flowBuilder.setFlowRef(flowRef);
148                     this.provider.getSalFlowService().addFlow(flowBuilder.build());
149                 }
150             }
151         }
152     }
153
154     @Override
155     protected void update(final InstanceIdentifier<? extends DataObject> identifier,
156                           final DataObject original, DataObject update) {
157         // NOOP - Listener is registered for DataChangeScope.BASE only
158     }
159
160     @Override
161     protected boolean preconditionForChange(final InstanceIdentifier<? extends DataObject> identifier,
162                                             final DataObject dataObj, final DataObject update) {
163         return (dataObj instanceof FlowCapableNode);
164     }
165
166     private Optional<FlowCapableNode> readFlowCapableNode(final InstanceIdentifier<FlowCapableNode> flowNodeIdent) {
167         ReadOnlyTransaction readTrans = this.provider.getDataService().newReadOnlyTransaction();
168         try {
169             ListenableFuture<Optional<FlowCapableNode>> confFlowNode =
170                     readTrans.read(LogicalDatastoreType.CONFIGURATION, flowNodeIdent);
171             if (confFlowNode.get().isPresent()) {
172                 return Optional.<FlowCapableNode> of(confFlowNode.get().get());
173             } else {
174                 return Optional.absent();
175             }
176         }
177         catch (InterruptedException | ExecutionException e) {
178             LOG.error("Unexpected exception by reading flow ".concat(flowNodeIdent.toString()), e);
179             return Optional.absent();
180         }
181         finally {
182             readTrans.close();
183         }
184     }
185 }