2 * Copyright (C) 2014 Red Hat, Inc.
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
8 * Authors : Madhu Venugopal
10 package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13;
12 import java.util.List;
13 import java.util.concurrent.ExecutionException;
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;
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;
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.
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;
63 // Concrete Service that this AbstractServiceInstance represent
64 private Service service;
66 public AbstractServiceInstance (Service service) {
67 this.service = service;
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);
73 public short getTable() {
74 return service.getTable();
77 public Service getService() {
81 public void setService(Service service) {
82 this.service = service;
85 public NodeBuilder createNodeBuilder(String nodeId) {
86 NodeBuilder builder = new NodeBuilder();
87 builder.setId(new NodeId(nodeId));
88 builder.setKey(new NodeKey(builder.getId()));
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.
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
100 protected final InstructionBuilder getMutablePipelineInstructionBuilder() {
101 Service nextService = orchestrator.getNextServiceInPipeline(service);
102 if (nextService != null) {
103 return InstructionUtils.createGotoTableInstructions(new InstructionBuilder(), nextService.getTable());
105 return InstructionUtils.createDropInstructions(new InstructionBuilder());
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 ?");
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.");
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();
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();
131 modification.put(LogicalDatastoreType.CONFIGURATION, path1, flowBuilder.build(), true /*createMissingParents*/);
133 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
135 commitFuture.get(); // TODO: Make it async (See bug 1362)
136 logger.debug("Transaction success for write of Flow "+flowBuilder.getFlowName());
137 } catch (Exception e) {
138 logger.error(e.getMessage(), e);
139 modification.cancel();
143 protected void removeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
144 Preconditions.checkNotNull(mdsalConsumer);
145 if (mdsalConsumer == null) {
146 logger.error("ERROR finding MDSAL Service.");
150 DataBroker dataBroker = mdsalConsumer.getDataBroker();
151 if (dataBroker == null) {
152 logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
156 WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
157 InstanceIdentifier<Flow> path1 = InstanceIdentifier.builder(Nodes.class)
158 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
159 .rev130819.nodes.Node.class, nodeBuilder.getKey())
160 .augmentation(FlowCapableNode.class).child(Table.class,
161 new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
162 //modification.delete(LogicalDatastoreType.OPERATIONAL, nodeBuilderToInstanceId(nodeBuilder));
163 //modification.delete(LogicalDatastoreType.OPERATIONAL, path1);
164 //modification.delete(LogicalDatastoreType.CONFIGURATION, nodeBuilderToInstanceId(nodeBuilder));
165 modification.delete(LogicalDatastoreType.CONFIGURATION, path1);
167 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
169 commitFuture.get(); // TODO: Make it async (See bug 1362)
170 logger.debug("Transaction success for deletion of Flow "+flowBuilder.getFlowName());
171 } catch (InterruptedException|ExecutionException e) {
172 logger.error(e.getMessage(), e);
176 public Flow getFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
177 Preconditions.checkNotNull(mdsalConsumer);
178 if (mdsalConsumer == null) {
179 logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
183 DataBroker dataBroker = mdsalConsumer.getDataBroker();
184 if (dataBroker == null) {
185 logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
189 InstanceIdentifier<Flow> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
190 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Table.class,
191 new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
193 ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
195 Optional<Flow> data = readTx.read(LogicalDatastoreType.CONFIGURATION, path1).get();
196 if (data.isPresent()) {
199 } catch (InterruptedException|ExecutionException e) {
200 logger.error(e.getMessage(), e);
203 logger.debug("Cannot find data for Flow " + flowBuilder.getFlowName());
208 * Program Default Pipeline Flow.
210 * @param nodeId Node on which the default pipeline flow is programmed.
212 protected void programDefaultPipelineRule(String nodeId) {
213 MatchBuilder matchBuilder = new MatchBuilder();
214 FlowBuilder flowBuilder = new FlowBuilder();
215 NodeBuilder nodeBuilder = createNodeBuilder(nodeId);
217 // Create the OF Actions and Instructions
218 InstructionsBuilder isb = new InstructionsBuilder();
220 // Instructions List Stores Individual Instructions
221 List<Instruction> instructions = Lists.newArrayList();
223 // Call the InstructionBuilder Methods Containing Actions
224 InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
226 ib.setKey(new InstructionKey(0));
227 instructions.add(ib.build());
229 // Add InstructionBuilder to the Instruction(s)Builder List
230 isb.setInstruction(instructions);
232 // Add InstructionsBuilder to FlowBuilder
233 flowBuilder.setInstructions(isb.build());
235 String flowId = "DEFAULT_PIPELINE_FLOW_"+service.getTable();
236 flowBuilder.setId(new FlowId(flowId));
237 FlowKey key = new FlowKey(new FlowId(flowId));
238 flowBuilder.setMatch(matchBuilder.build());
239 flowBuilder.setPriority(0);
240 flowBuilder.setBarrier(true);
241 flowBuilder.setTableId(service.getTable());
242 flowBuilder.setKey(key);
243 flowBuilder.setFlowName(flowId);
244 flowBuilder.setHardTimeout(0);
245 flowBuilder.setIdleTimeout(0);
246 writeFlow(flowBuilder, nodeBuilder);