2 * Copyright (c) 2014, 2015 Red Hat, Inc. and others. All rights reserved.
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
9 package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13;
11 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
12 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
13 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
14 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
15 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
16 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
17 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
18 import org.opendaylight.ovsdb.openstack.netvirt.providers.NetvirtProvidersProvider;
19 import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
20 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
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.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
40 import com.google.common.base.Optional;
41 import com.google.common.collect.Lists;
42 import com.google.common.util.concurrent.CheckedFuture;
44 import java.util.List;
45 import java.util.concurrent.ExecutionException;
47 import org.osgi.framework.ServiceReference;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
52 * Any ServiceInstance class that extends AbstractServiceInstance to be a part of the pipeline
53 * have 2 basic requirements : <br>
54 * 1. Program a default pipeline flow to take any unmatched traffic to the next table in the pipeline. <br>
55 * 2. Get Pipeline Instructions from AbstractServiceInstance (using getMutablePipelineInstructionBuilder) and
56 * use it in any matching flows that needs to be further processed by next service in the pipeline.
59 public abstract class AbstractServiceInstance {
60 public static final String SERVICE_PROPERTY ="serviceProperty";
61 private static final Logger LOG = LoggerFactory.getLogger(AbstractServiceInstance.class);
62 public static final String OPENFLOW = "openflow:";
63 private DataBroker dataBroker = null;
64 // OSGi Services that we are dependent on.
65 private volatile PipelineOrchestrator orchestrator;
66 private volatile Southbound southbound;
68 // Concrete Service that this AbstractServiceInstance represents
69 private Service service;
71 public AbstractServiceInstance (Service service) {
72 this.service = service;
73 this.dataBroker = NetvirtProvidersProvider.getDataBroker();
76 protected void setDependencies(final ServiceReference ref, AbstractServiceInstance serviceInstance) {
78 (PipelineOrchestrator) ServiceHelper.getGlobalInstance(PipelineOrchestrator.class, serviceInstance);
79 orchestrator.registerService(ref, serviceInstance);
81 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, serviceInstance);
84 public boolean isBridgeInPipeline (Node node){
85 String bridgeName = southbound.getBridgeName(node);
86 return bridgeName != null && Constants.INTEGRATION_BRIDGE.equals(bridgeName);
90 * Return the offset adjusted table for this {@link Service}
91 * @return The table id
93 public short getTable() {
94 return (short)(orchestrator.getTableOffset() + service.getTable());
98 * Return the offset adjusted table for the given {@link Service}
99 * @param service Identifies the openflow {@link Service}
100 * @return The table id
102 public short getTable(Service service) {
103 return (short)(orchestrator.getTableOffset() + service.getTable());
106 public Service getService() {
110 public void setService(Service service) {
111 this.service = service;
114 public NodeBuilder createNodeBuilder(String nodeId) {
115 NodeBuilder builder = new NodeBuilder();
116 builder.setId(new NodeId(nodeId));
117 builder.setKey(new NodeKey(builder.getId()));
121 private static InstanceIdentifier<Flow> createFlowPath(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
122 return InstanceIdentifier.builder(Nodes.class)
123 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
124 nodeBuilder.getKey())
125 .augmentation(FlowCapableNode.class)
126 .child(Table.class, new TableKey(flowBuilder.getTableId()))
127 .child(Flow.class, flowBuilder.getKey()).build();
130 private static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node>
131 createNodePath(NodeBuilder nodeBuilder) {
132 return InstanceIdentifier.builder(Nodes.class)
133 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
134 nodeBuilder.getKey()).build();
138 * This method returns the required Pipeline Instructions to by used by any matching flows that need
139 * to be further processed by next service in the pipeline.
141 * Important to note that this is a convenience method which returns a mutable instructionBuilder which
142 * needs to be further adjusted by the concrete ServiceInstance class such as setting the Instruction Order, etc.
143 * @return Newly created InstructionBuilder to be used along with other instructions on the main flow
145 protected final InstructionBuilder getMutablePipelineInstructionBuilder() {
146 Service nextService = orchestrator.getNextServiceInPipeline(service);
147 if (nextService != null) {
148 return InstructionUtils.createGotoTableInstructions(new InstructionBuilder(),
149 orchestrator.getTable(nextService));
151 return InstructionUtils.createDropInstructions(new InstructionBuilder());
155 protected void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
156 if (NetvirtProvidersProvider.isMasterProviderInstance()) {
157 LOG.debug("writeFlow: flowBuilder: {}, nodeBuilder: {}",
158 flowBuilder.build(), nodeBuilder.build());
159 WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
160 modification.put(LogicalDatastoreType.CONFIGURATION, createNodePath(nodeBuilder),
161 nodeBuilder.build(), true /*createMissingParents*/);
162 modification.put(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder),
163 flowBuilder.build(), true /*createMissingParents*/);
164 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
166 commitFuture.checkedGet(); // TODO: Make it async (See bug 1362)
167 LOG.debug("Transaction success for write of Flow {}", flowBuilder.getFlowName());
168 } catch (Exception e) {
169 LOG.error(e.getMessage(), e);
170 modification.cancel();
175 protected void removeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
176 if (NetvirtProvidersProvider.isMasterProviderInstance()) {
177 WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
178 modification.delete(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder));
180 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
182 commitFuture.get(); // TODO: Make it async (See bug 1362)
183 LOG.debug("Transaction success for deletion of Flow {}", flowBuilder.getFlowName());
184 } catch (Exception e) {
185 LOG.error(e.getMessage(), e);
186 modification.cancel();
191 public Flow getFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
192 ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
194 Optional<Flow> data =
195 readTx.read(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder)).get();
196 if (data.isPresent()) {
199 } catch (InterruptedException|ExecutionException e) {
200 LOG.error(e.getMessage(), e);
203 LOG.debug("Cannot find data for Flow {}", flowBuilder.getFlowName());
207 public org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node
208 getOpenFlowNode(String nodeId) {
210 ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
212 Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node> data =
213 readTx.read(LogicalDatastoreType.OPERATIONAL, createNodePath(createNodeBuilder(nodeId))).get();
214 if (data.isPresent()) {
217 } catch (InterruptedException|ExecutionException e) {
218 LOG.error(e.getMessage(), e);
221 LOG.debug("Cannot find data for Node {}", nodeId);
225 private long getDpid(Node node) {
226 long dpid = southbound.getDataPathId(node);
228 LOG.warn("getDpid: dpid not found: {}", node);
234 * Program Default Pipeline Flow.
236 * @param node on which the default pipeline flow is programmed.
238 protected void programDefaultPipelineRule(Node node) {
239 if (!isBridgeInPipeline(node)) {
240 //LOG.trace("Bridge is not in pipeline {} ", node);
243 MatchBuilder matchBuilder = new MatchBuilder();
244 FlowBuilder flowBuilder = new FlowBuilder();
245 long dpid = getDpid(node);
247 LOG.info("could not find dpid: {}", node.getNodeId());
250 String nodeName = OPENFLOW + getDpid(node);
251 NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
253 // Create the OF Actions and Instructions
254 InstructionsBuilder isb = new InstructionsBuilder();
256 // Instructions List Stores Individual Instructions
257 List<Instruction> instructions = Lists.newArrayList();
259 // Call the InstructionBuilder Methods Containing Actions
260 InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
262 ib.setKey(new InstructionKey(0));
263 instructions.add(ib.build());
265 // Add InstructionBuilder to the Instruction(s)Builder List
266 isb.setInstruction(instructions);
268 // Add InstructionsBuilder to FlowBuilder
269 flowBuilder.setInstructions(isb.build());
271 String flowId = "DEFAULT_PIPELINE_FLOW_" + getTable();
272 flowBuilder.setId(new FlowId(flowId));
273 FlowKey key = new FlowKey(new FlowId(flowId));
274 flowBuilder.setMatch(matchBuilder.build());
275 flowBuilder.setPriority(0);
276 flowBuilder.setBarrier(false);
277 flowBuilder.setTableId(getTable());
278 flowBuilder.setKey(key);
279 flowBuilder.setFlowName(flowId);
280 flowBuilder.setHardTimeout(0);
281 flowBuilder.setIdleTimeout(0);
282 writeFlow(flowBuilder, nodeBuilder);