Remove OvsdbConfigurationService
[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.openstack.netvirt.api.Constants;
24 import org.opendaylight.ovsdb.openstack.netvirt.api.OvsdbConnectionService;
25 import org.opendaylight.ovsdb.utils.mdsal.node.StringConvertor;
26 import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
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.FlowBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
44 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
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     /* TODO SB_MIGRATION */
68     private volatile OvsdbConnectionService connectionService;
69     private volatile MdsalConsumer mdsalConsumer;
70     private volatile PipelineOrchestrator orchestrator;
71
72     // Concrete Service that this AbstractServiceInstance represents
73     private Service service;
74
75     public AbstractServiceInstance (Service service) {
76         this.service = service;
77     }
78
79     void init() {
80         logger.info(">>>>> init service: {}", this.getClass());
81     }
82
83     private String getBridgeName(Node node) {
84         return (node.getAugmentation(OvsdbBridgeAugmentation.class).getBridgeName().getValue());
85     }
86
87     public boolean isBridgeInPipeline (Node node){
88         String bridgeName = getBridgeName(node);
89         logger.debug("isBridgeInPipeline: node {} bridgeName {}", node, bridgeName);
90         if (bridgeName != null && Constants.INTEGRATION_BRIDGE.equalsIgnoreCase(bridgeName)) {
91             return true;
92         }
93         return false;
94     }
95
96     public short getTable() {
97         return service.getTable();
98     }
99
100     public Service getService() {
101         return service;
102     }
103
104     public void setService(Service service) {
105         this.service = service;
106     }
107
108     public NodeBuilder createNodeBuilder(String nodeId) {
109         NodeBuilder builder = new NodeBuilder();
110         builder.setId(new NodeId(nodeId));
111         builder.setKey(new NodeKey(builder.getId()));
112         return builder;
113     }
114
115     private static final InstanceIdentifier<Flow> createFlowPath(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
116         return InstanceIdentifier.builder(Nodes.class)
117                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
118                         nodeBuilder.getKey())
119                 .augmentation(FlowCapableNode.class)
120                 .child(Table.class, new TableKey(flowBuilder.getTableId()))
121                 .child(Flow.class, flowBuilder.getKey()).build();
122     }
123
124     private static final
125     InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node>
126     createNodePath(NodeBuilder nodeBuilder) {
127         return InstanceIdentifier.builder(Nodes.class)
128                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
129                         nodeBuilder.getKey()).build();
130     }
131
132     /**
133      * This method returns the required Pipeline Instructions to by used by any matching flows that need
134      * to be further processed by next service in the pipeline.
135      *
136      * Important to note that this is a convenience method which returns a mutable instructionBuilder which
137      * needs to be further adjusted by the concrete ServiceInstance class such as setting the Instruction Order, etc.
138      * @return Newly created InstructionBuilder to be used along with other instructions on the main flow
139      */
140     protected final InstructionBuilder getMutablePipelineInstructionBuilder() {
141         Service nextService = orchestrator.getNextServiceInPipeline(service);
142         if (nextService != null) {
143             return InstructionUtils.createGotoTableInstructions(new InstructionBuilder(), nextService.getTable());
144         } else {
145             return InstructionUtils.createDropInstructions(new InstructionBuilder());
146         }
147     }
148
149     protected void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
150         Preconditions.checkNotNull(mdsalConsumer);
151         logger.info("writeFlow: flowBuilder: {}, nodeBuilder: {}", flowBuilder, nodeBuilder);
152         if (mdsalConsumer == null) {
153             logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
154             return;
155         }
156
157         DataBroker dataBroker = mdsalConsumer.getDataBroker();
158         if (dataBroker == null) {
159             logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
160             return;
161         }
162
163         ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
164         modification.put(LogicalDatastoreType.CONFIGURATION, createNodePath(nodeBuilder),
165                 nodeBuilder.build(), true /*createMissingParents*/);
166         modification.put(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder),
167                 flowBuilder.build(), true /*createMissingParents*/);
168
169         CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
170         try {
171             commitFuture.get();  // TODO: Make it async (See bug 1362)
172             logger.debug("Transaction success for write of Flow "+flowBuilder.getFlowName());
173             Thread.sleep(500);
174         } catch (Exception e) {
175             logger.error(e.getMessage(), e);
176             modification.cancel();
177         }
178     }
179
180     protected void removeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
181         Preconditions.checkNotNull(mdsalConsumer);
182         if (mdsalConsumer == null) {
183             logger.error("ERROR finding MDSAL Service.");
184             return;
185         }
186
187         DataBroker dataBroker = mdsalConsumer.getDataBroker();
188         if (dataBroker == null) {
189             logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
190             return;
191         }
192
193         WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
194         modification.delete(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder));
195
196         CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
197         try {
198             commitFuture.get();  // TODO: Make it async (See bug 1362)
199             logger.debug("Transaction success for deletion of Flow " + flowBuilder.getFlowName());
200         } catch (Exception e) {
201             logger.error(e.getMessage(), e);
202             modification.cancel();
203         }
204     }
205
206     public Flow getFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
207         Preconditions.checkNotNull(mdsalConsumer);
208         if (mdsalConsumer == null) {
209             logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
210             return null;
211         }
212
213         DataBroker dataBroker = mdsalConsumer.getDataBroker();
214         if (dataBroker == null) {
215             logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
216             return null;
217         }
218
219         ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
220         try {
221             Optional<Flow> data =
222                     readTx.read(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder)).get();
223             if (data.isPresent()) {
224                 return data.get();
225             }
226         } catch (InterruptedException|ExecutionException e) {
227             logger.error(e.getMessage(), e);
228         }
229
230         logger.debug("Cannot find data for Flow " + flowBuilder.getFlowName());
231         return null;
232     }
233
234     private Long getDpid(Node node) {
235         String datapathIdString = node.getAugmentation(OvsdbBridgeAugmentation.class).getDatapathId().getValue();
236         Long dpidLong = StringConvertor.dpidStringToLong(datapathIdString);
237         return dpidLong;
238     }
239
240     /**
241      * Program Default Pipeline Flow.
242      *
243      * @param nodeId Node on which the default pipeline flow is programmed.
244      */
245     protected void programDefaultPipelineRule(Node node) {
246         if (!isBridgeInPipeline(node)) {
247             logger.debug("Bridge {} is not in pipeline", node);
248             return;
249         }
250         MatchBuilder matchBuilder = new MatchBuilder();
251         FlowBuilder flowBuilder = new FlowBuilder();
252         String nodeName = OPENFLOW + getDpid(node);
253         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
254
255         // Create the OF Actions and Instructions
256         InstructionsBuilder isb = new InstructionsBuilder();
257
258         // Instructions List Stores Individual Instructions
259         List<Instruction> instructions = Lists.newArrayList();
260
261         // Call the InstructionBuilder Methods Containing Actions
262         InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
263         ib.setOrder(0);
264         ib.setKey(new InstructionKey(0));
265         instructions.add(ib.build());
266
267         // Add InstructionBuilder to the Instruction(s)Builder List
268         isb.setInstruction(instructions);
269
270         // Add InstructionsBuilder to FlowBuilder
271         flowBuilder.setInstructions(isb.build());
272
273         String flowId = "DEFAULT_PIPELINE_FLOW_"+service.getTable();
274         flowBuilder.setId(new FlowId(flowId));
275         FlowKey key = new FlowKey(new FlowId(flowId));
276         flowBuilder.setMatch(matchBuilder.build());
277         flowBuilder.setPriority(0);
278         flowBuilder.setBarrier(true);
279         flowBuilder.setTableId(service.getTable());
280         flowBuilder.setKey(key);
281         flowBuilder.setFlowName(flowId);
282         flowBuilder.setHardTimeout(0);
283         flowBuilder.setIdleTimeout(0);
284         writeFlow(flowBuilder, nodeBuilder);
285     }
286 }