Remove plugin dependencies
[ovsdb.git] / openstack / net-virt-providers / src / main / java / org / opendaylight / ovsdb / openstack / netvirt / providers / openflow13 / AbstractServiceInstance.java
1 /*
2  * Copyright (C) 2014 Red Hat, Inc.
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  * Authors : Madhu Venugopal
9  */
10 package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13;
11
12 import java.util.List;
13 import java.util.Map;
14 import java.util.Set;
15 import java.util.concurrent.ExecutionException;
16
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
19 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
20 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
23 import org.opendaylight.ovsdb.lib.notation.Row;
24 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
25 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
26 import org.opendaylight.ovsdb.utils.mdsal.node.StringConvertor;
27 import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
45 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 import com.google.common.base.Optional;
50 import com.google.common.base.Preconditions;
51 import com.google.common.collect.Lists;
52 import com.google.common.util.concurrent.CheckedFuture;
53
54 /**
55  * Any ServiceInstance class that extends AbstractServiceInstance to be a part of the pipeline
56  * have 2 basic requirements : <br>
57  * 1. Program a default pipeline flow to take any unmatched traffic to the next table in the pipeline. <br>
58  * 2. Get Pipeline Instructions from AbstractServiceInstance (using getMutablePipelineInstructionBuilder) and
59  *    use it in any matching flows that needs to be further processed by next service in the pipeline.
60  *
61  */
62 public abstract class AbstractServiceInstance {
63     public static final String SERVICE_PROPERTY ="serviceProperty";
64     private static final Logger logger = LoggerFactory.getLogger(AbstractServiceInstance.class);
65     public static final String OPENFLOW = "openflow:";
66     // OSGi Services that we are dependent on.
67     private volatile MdsalConsumer mdsalConsumer;
68     private volatile PipelineOrchestrator orchestrator;
69
70     // Concrete Service that this AbstractServiceInstance represent
71     private Service service;
72
73     public AbstractServiceInstance (Service service) {
74         this.service = service;
75     }
76
77     public boolean isBridgeInPipeline (String nodeId){
78         String bridgeName = getBridgeName(nodeId.split(":")[1]);
79         logger.debug("isBridgeInPipeline: nodeId {} bridgeName {}", nodeId, bridgeName);
80         if (bridgeName != null && Constants.INTEGRATION_BRIDGE.equalsIgnoreCase(bridgeName)) {
81             return true;
82         }
83         return false;
84     }
85
86     private String getBridgeName(String nodeId){
87         /* SB_MIGRATION
88         List<Node> ovsNodes = connectionService.getNodes();
89
90         for (Node ovsNode : ovsNodes) {
91             Map<String, Row> bridges = ovsdbConfigService.getRows(ovsNode, ovsdbConfigService.getTableName(ovsNode, Bridge.class));
92             if (bridges == null) continue;
93             for (String brUuid : bridges.keySet()) {
94                 Bridge bridge = ovsdbConfigService.getTypedRow(ovsNode, Bridge.class, bridges.get(brUuid));
95
96                 Set<String> dpids = bridge.getDatapathIdColumn().getData();
97                 if (dpids == null || dpids.size() == 0) return null;
98                 Long dpid = StringConvertor.dpidStringToLong((String) dpids.toArray()[0]);
99                 logger.debug("getBridgeName: bridgeDpid {} ofNodeDpid {}", bridge.getDatapathIdColumn().getData().toArray()[0], nodeId);
100                 if (dpid.equals(Long.parseLong(nodeId))){
101                     // Found the bridge
102                     logger.debug("getOvsNode: found ovsNode {} bridge {} for ofNode {}",
103                             ovsNode.getId().getValue(), bridge.getName(), nodeId);
104                     return bridge.getName();
105                 }
106             }
107         }*/
108         return null;
109     }
110
111     public short getTable() {
112         return service.getTable();
113     }
114
115     public Service getService() {
116         return service;
117     }
118
119     public void setService(Service service) {
120         this.service = service;
121     }
122
123     public NodeBuilder createNodeBuilder(String nodeId) {
124         NodeBuilder builder = new NodeBuilder();
125         builder.setId(new NodeId(nodeId));
126         builder.setKey(new NodeKey(builder.getId()));
127         return builder;
128     }
129
130     private static final InstanceIdentifier<Flow> createFlowPath(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
131         return InstanceIdentifier.builder(Nodes.class)
132                 .child(Node.class, nodeBuilder.getKey())
133                 .augmentation(FlowCapableNode.class)
134                 .child(Table.class, new TableKey(flowBuilder.getTableId()))
135                 .child(Flow.class, flowBuilder.getKey()).build();
136     }
137
138     private static final InstanceIdentifier<Node> createNodePath(NodeBuilder nodeBuilder) {
139         return InstanceIdentifier.builder(Nodes.class).child(Node.class, nodeBuilder.getKey()).build();
140     }
141
142     /**
143      * This method returns the required Pipeline Instructions to by used by any matching flows that needs
144      * to be further processed by next service in the pipeline.
145      *
146      * Important to note that this is a convenience method which returns a mutable instructionBuilder which
147      * needs to be further adjusted by the concrete ServiceInstance class such as setting the Instruction Order, etc.
148      * @return Newly created InstructionBuilder to be used along with other instructions on the main flow
149      */
150     protected final InstructionBuilder getMutablePipelineInstructionBuilder() {
151         Service nextService = orchestrator.getNextServiceInPipeline(service);
152         if (nextService != null) {
153             return InstructionUtils.createGotoTableInstructions(new InstructionBuilder(), nextService.getTable());
154         } else {
155             return InstructionUtils.createDropInstructions(new InstructionBuilder());
156         }
157     }
158
159     protected void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
160         Preconditions.checkNotNull(mdsalConsumer);
161         if (mdsalConsumer == null) {
162             logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
163             return;
164         }
165
166         DataBroker dataBroker = mdsalConsumer.getDataBroker();
167         if (dataBroker == null) {
168             logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
169             return;
170         }
171
172         ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
173         modification.put(LogicalDatastoreType.CONFIGURATION, createNodePath(nodeBuilder),
174                 nodeBuilder.build(), true /*createMissingParents*/);
175         modification.put(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder),
176                 flowBuilder.build(), true /*createMissingParents*/);
177
178         CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
179         try {
180             commitFuture.get();  // TODO: Make it async (See bug 1362)
181             logger.debug("Transaction success for write of Flow "+flowBuilder.getFlowName());
182             Thread.sleep(500);
183         } catch (Exception e) {
184             logger.error(e.getMessage(), e);
185             modification.cancel();
186         }
187     }
188
189     protected void removeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
190         Preconditions.checkNotNull(mdsalConsumer);
191         if (mdsalConsumer == null) {
192             logger.error("ERROR finding MDSAL Service.");
193             return;
194         }
195
196         DataBroker dataBroker = mdsalConsumer.getDataBroker();
197         if (dataBroker == null) {
198             logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
199             return;
200         }
201
202         WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
203         modification.delete(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder));
204
205         CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
206         try {
207             commitFuture.get();  // TODO: Make it async (See bug 1362)
208             logger.debug("Transaction success for deletion of Flow "+flowBuilder.getFlowName());
209         } catch (Exception e) {
210             logger.error(e.getMessage(), e);
211             modification.cancel();
212         }
213     }
214
215     public Flow getFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
216         Preconditions.checkNotNull(mdsalConsumer);
217         if (mdsalConsumer == null) {
218             logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
219             return null;
220         }
221
222         DataBroker dataBroker = mdsalConsumer.getDataBroker();
223         if (dataBroker == null) {
224             logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
225             return null;
226         }
227
228         ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
229         try {
230             Optional<Flow> data =
231                     readTx.read(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder)).get();
232             if (data.isPresent()) {
233                 return data.get();
234             }
235         } catch (InterruptedException|ExecutionException e) {
236             logger.error(e.getMessage(), e);
237         }
238
239         logger.debug("Cannot find data for Flow " + flowBuilder.getFlowName());
240         return null;
241     }
242
243     /**
244      * Program Default Pipeline Flow.
245      *
246      * @param nodeId Node on which the default pipeline flow is programmed.
247      */
248     protected void programDefaultPipelineRule(String nodeId) {
249         if (!isBridgeInPipeline(nodeId)) {
250             logger.debug("Bridge {} is not in pipeline", nodeId);
251             return;
252         }
253         MatchBuilder matchBuilder = new MatchBuilder();
254         FlowBuilder flowBuilder = new FlowBuilder();
255         NodeBuilder nodeBuilder = createNodeBuilder(nodeId);
256
257         // Create the OF Actions and Instructions
258         InstructionsBuilder isb = new InstructionsBuilder();
259
260         // Instructions List Stores Individual Instructions
261         List<Instruction> instructions = Lists.newArrayList();
262
263         // Call the InstructionBuilder Methods Containing Actions
264         InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
265         ib.setOrder(0);
266         ib.setKey(new InstructionKey(0));
267         instructions.add(ib.build());
268
269         // Add InstructionBuilder to the Instruction(s)Builder List
270         isb.setInstruction(instructions);
271
272         // Add InstructionsBuilder to FlowBuilder
273         flowBuilder.setInstructions(isb.build());
274
275         String flowId = "DEFAULT_PIPELINE_FLOW_"+service.getTable();
276         flowBuilder.setId(new FlowId(flowId));
277         FlowKey key = new FlowKey(new FlowId(flowId));
278         flowBuilder.setMatch(matchBuilder.build());
279         flowBuilder.setPriority(0);
280         flowBuilder.setBarrier(true);
281         flowBuilder.setTableId(service.getTable());
282         flowBuilder.setKey(key);
283         flowBuilder.setFlowName(flowId);
284         flowBuilder.setHardTimeout(0);
285         flowBuilder.setIdleTimeout(0);
286         writeFlow(flowBuilder, nodeBuilder);
287     }
288 }