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