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 org.opendaylight.controller.md.sal.binding.api.DataBroker;
13 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
14 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
15 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
16 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
17 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
18 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
19 import org.opendaylight.ovsdb.openstack.netvirt.MdsalUtils;
20 import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
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.FlowId;
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.TableKey;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
38 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
39 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
41 import com.google.common.base.Optional;
42 import com.google.common.base.Preconditions;
43 import com.google.common.collect.Lists;
44 import com.google.common.util.concurrent.CheckedFuture;
45 import java.util.List;
46 import java.util.concurrent.ExecutionException;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
51 * Any ServiceInstance class that extends AbstractServiceInstance to be a part of the pipeline
52 * have 2 basic requirements : <br>
53 * 1. Program a default pipeline flow to take any unmatched traffic to the next table in the pipeline. <br>
54 * 2. Get Pipeline Instructions from AbstractServiceInstance (using getMutablePipelineInstructionBuilder) and
55 * use it in any matching flows that needs to be further processed by next service in the pipeline.
58 public abstract class AbstractServiceInstance {
59 public static final String SERVICE_PROPERTY ="serviceProperty";
60 private static final Logger logger = LoggerFactory.getLogger(AbstractServiceInstance.class);
61 public static final String OPENFLOW = "openflow:";
62 // OSGi Services that we are dependent on.
63 private volatile MdsalConsumer mdsalConsumer;
64 private volatile PipelineOrchestrator orchestrator;
66 // Concrete Service that this AbstractServiceInstance represents
67 private Service service;
69 public AbstractServiceInstance (Service service) {
70 this.service = service;
74 logger.info(">>>>> init service: {}", this.getClass());
77 public boolean isBridgeInPipeline (Node node){
78 String bridgeName = MdsalUtils.getBridgeName(node);
79 //logger.trace("isBridgeInPipeline: node {} bridgeName {}", node, bridgeName);
80 if (bridgeName != null && Constants.INTEGRATION_BRIDGE.equals(bridgeName)) {
86 public short getTable() {
87 return service.getTable();
90 public Service getService() {
94 public void setService(Service service) {
95 this.service = service;
98 public NodeBuilder createNodeBuilder(String nodeId) {
99 NodeBuilder builder = new NodeBuilder();
100 builder.setId(new NodeId(nodeId));
101 builder.setKey(new NodeKey(builder.getId()));
105 private static final InstanceIdentifier<Flow> createFlowPath(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
106 return InstanceIdentifier.builder(Nodes.class)
107 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
108 nodeBuilder.getKey())
109 .augmentation(FlowCapableNode.class)
110 .child(Table.class, new TableKey(flowBuilder.getTableId()))
111 .child(Flow.class, flowBuilder.getKey()).build();
115 InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node>
116 createNodePath(NodeBuilder nodeBuilder) {
117 return InstanceIdentifier.builder(Nodes.class)
118 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
119 nodeBuilder.getKey()).build();
123 * This method returns the required Pipeline Instructions to by used by any matching flows that need
124 * to be further processed by next service in the pipeline.
126 * Important to note that this is a convenience method which returns a mutable instructionBuilder which
127 * needs to be further adjusted by the concrete ServiceInstance class such as setting the Instruction Order, etc.
128 * @return Newly created InstructionBuilder to be used along with other instructions on the main flow
130 protected final InstructionBuilder getMutablePipelineInstructionBuilder() {
131 Service nextService = orchestrator.getNextServiceInPipeline(service);
132 if (nextService != null) {
133 return InstructionUtils.createGotoTableInstructions(new InstructionBuilder(), nextService.getTable());
135 return InstructionUtils.createDropInstructions(new InstructionBuilder());
139 protected void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
140 Preconditions.checkNotNull(mdsalConsumer);
141 logger.debug("writeFlow: flowBuilder: {}, nodeBuilder: {}",
142 flowBuilder.build(), nodeBuilder.build());
143 if (mdsalConsumer == null) {
144 logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
148 DataBroker dataBroker = mdsalConsumer.getDataBroker();
149 if (dataBroker == null) {
150 logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
154 ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
155 modification.put(LogicalDatastoreType.CONFIGURATION, createNodePath(nodeBuilder),
156 nodeBuilder.build(), true /*createMissingParents*/);
157 modification.put(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder),
158 flowBuilder.build(), true /*createMissingParents*/);
160 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
162 commitFuture.get(); // TODO: Make it async (See bug 1362)
163 logger.debug("Transaction success for write of Flow "+flowBuilder.getFlowName());
165 } catch (Exception e) {
166 logger.error(e.getMessage(), e);
167 modification.cancel();
171 protected void removeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
172 Preconditions.checkNotNull(mdsalConsumer);
173 if (mdsalConsumer == null) {
174 logger.error("ERROR finding MDSAL Service.");
178 DataBroker dataBroker = mdsalConsumer.getDataBroker();
179 if (dataBroker == null) {
180 logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
184 WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
185 modification.delete(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder));
187 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
189 commitFuture.get(); // TODO: Make it async (See bug 1362)
190 logger.debug("Transaction success for deletion of Flow " + flowBuilder.getFlowName());
191 } catch (Exception e) {
192 logger.error(e.getMessage(), e);
193 modification.cancel();
197 public Flow getFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
198 Preconditions.checkNotNull(mdsalConsumer);
199 if (mdsalConsumer == null) {
200 logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
204 DataBroker dataBroker = mdsalConsumer.getDataBroker();
205 if (dataBroker == null) {
206 logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
210 ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
212 Optional<Flow> data =
213 readTx.read(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder)).get();
214 if (data.isPresent()) {
217 } catch (InterruptedException|ExecutionException e) {
218 logger.error(e.getMessage(), e);
221 logger.debug("Cannot find data for Flow " + flowBuilder.getFlowName());
225 private Long getDpid(Node node) {
227 dpid = MdsalUtils.getDataPathId(node);
229 logger.warn("getDpid: dpid not found: {}", node);
235 * Program Default Pipeline Flow.
237 * @param nodeId Node on which the default pipeline flow is programmed.
239 protected void programDefaultPipelineRule(Node node) {
240 if (!isBridgeInPipeline(node)) {
241 //logger.trace("Bridge is not in pipeline {} ", node);
244 MatchBuilder matchBuilder = new MatchBuilder();
245 FlowBuilder flowBuilder = new FlowBuilder();
246 Long dpid = getDpid(node);
248 logger.info("could not find dpid: {}", node.getNodeId());
251 String nodeName = OPENFLOW + getDpid(node);
252 NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
254 // Create the OF Actions and Instructions
255 InstructionsBuilder isb = new InstructionsBuilder();
257 // Instructions List Stores Individual Instructions
258 List<Instruction> instructions = Lists.newArrayList();
260 // Call the InstructionBuilder Methods Containing Actions
261 InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
263 ib.setKey(new InstructionKey(0));
264 instructions.add(ib.build());
266 // Add InstructionBuilder to the Instruction(s)Builder List
267 isb.setInstruction(instructions);
269 // Add InstructionsBuilder to FlowBuilder
270 flowBuilder.setInstructions(isb.build());
272 String flowId = "DEFAULT_PIPELINE_FLOW_"+service.getTable();
273 flowBuilder.setId(new FlowId(flowId));
274 FlowKey key = new FlowKey(new FlowId(flowId));
275 flowBuilder.setMatch(matchBuilder.build());
276 flowBuilder.setPriority(0);
277 flowBuilder.setBarrier(true);
278 flowBuilder.setTableId(service.getTable());
279 flowBuilder.setKey(key);
280 flowBuilder.setFlowName(flowId);
281 flowBuilder.setHardTimeout(0);
282 flowBuilder.setIdleTimeout(0);
283 writeFlow(flowBuilder, nodeBuilder);