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;
15 import java.util.concurrent.ExecutionException;
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.controller.sal.utils.HexEncode;
24 import org.opendaylight.ovsdb.lib.notation.Row;
25 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
26 import org.opendaylight.ovsdb.plugin.api.OvsdbConfigurationService;
27 import org.opendaylight.ovsdb.plugin.api.OvsdbConnectionService;
28 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
29 import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
46 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
50 import com.google.common.base.Optional;
51 import com.google.common.base.Preconditions;
52 import com.google.common.collect.Lists;
53 import com.google.common.util.concurrent.CheckedFuture;
56 * Any ServiceInstance class that extends AbstractServiceInstance to be a part of the pipeline
57 * have 2 basic requirements : <br>
58 * 1. Program a default pipeline flow to take any unmatched traffic to the next table in the pipeline. <br>
59 * 2. Get Pipeline Instructions from AbstractServiceInstance (using getMutablePipelineInstructionBuilder) and
60 * use it in any matching flows that needs to be further processed by next service in the pipeline.
63 public abstract class AbstractServiceInstance {
64 public static final String SERVICE_PROPERTY ="serviceProperty";
65 private static final Logger logger = LoggerFactory.getLogger(AbstractServiceInstance.class);
66 public static final String OPENFLOW = "openflow:";
67 // OSGi Services that we are dependent on.
68 private volatile MdsalConsumer mdsalConsumer;
69 private volatile PipelineOrchestrator orchestrator;
70 private volatile OvsdbConfigurationService ovsdbConfigService;
71 private volatile OvsdbConnectionService connectionService;
73 // Concrete Service that this AbstractServiceInstance represent
74 private Service service;
76 public AbstractServiceInstance (Service service) {
77 this.service = service;
80 public boolean isBridgeInPipeline (String nodeId){
81 String bridgeName = getBridgeName(nodeId.split(":")[1]);
82 logger.debug("isBridgeInPipeline: nodeId {} bridgeName {}", nodeId, bridgeName);
83 if (bridgeName != null && Constants.INTEGRATION_BRIDGE.equalsIgnoreCase(bridgeName)) {
89 private String getBridgeName(String nodeId){
90 List<org.opendaylight.controller.sal.core.Node> ovsNodes = connectionService.getNodes();
92 for (org.opendaylight.controller.sal.core.Node ovsNode : ovsNodes) {
93 Map<String, Row> bridges = ovsdbConfigService.getRows(ovsNode, ovsdbConfigService.getTableName(ovsNode, Bridge.class));
94 if (bridges == null) continue;
95 for (String brUuid : bridges.keySet()) {
96 Bridge bridge = ovsdbConfigService.getTypedRow(ovsNode, Bridge.class, bridges.get(brUuid));
98 Set<String> dpids = bridge.getDatapathIdColumn().getData();
99 if (dpids == null || dpids.size() == 0) return null;
100 Long dpid = HexEncode.stringToLong((String) dpids.toArray()[0]);
101 logger.debug("getBridgeName: bridgeDpid {} ofNodeDpid {}", bridge.getDatapathIdColumn().getData().toArray()[0], nodeId);
102 if (dpid.equals(Long.parseLong(nodeId))){
104 logger.debug("getOvsNode: found ovsNode {} bridge {} for ofNode {}", ovsNode.getNodeIDString(), bridge.getName(), nodeId);
105 return bridge.getName();
112 public short getTable() {
113 return service.getTable();
116 public Service getService() {
120 public void setService(Service service) {
121 this.service = service;
124 public NodeBuilder createNodeBuilder(String nodeId) {
125 NodeBuilder builder = new NodeBuilder();
126 builder.setId(new NodeId(nodeId));
127 builder.setKey(new NodeKey(builder.getId()));
132 * This method returns the required Pipeline Instructions to by used by any matching flows that needs
133 * to be further processed by next service in the pipeline.
135 * Important to note that this is a convenience method which returns a mutable instructionBuilder which
136 * needs to be further adjusted by the concrete ServiceInstance class such as setting the Instruction Order, etc.
137 * @return Newly created InstructionBuilder to be used along with other instructions on the main flow
139 protected final InstructionBuilder getMutablePipelineInstructionBuilder() {
140 Service nextService = orchestrator.getNextServiceInPipeline(service);
141 if (nextService != null) {
142 return InstructionUtils.createGotoTableInstructions(new InstructionBuilder(), nextService.getTable());
144 return InstructionUtils.createDropInstructions(new InstructionBuilder());
148 protected void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
149 Preconditions.checkNotNull(mdsalConsumer);
150 if (mdsalConsumer == null) {
151 logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
155 DataBroker dataBroker = mdsalConsumer.getDataBroker();
156 if (dataBroker == null) {
157 logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
161 ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
162 InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node> nodePath = InstanceIdentifier.builder(Nodes.class)
163 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, nodeBuilder.getKey()).toInstance();
165 modification.put(LogicalDatastoreType.CONFIGURATION, nodePath, nodeBuilder.build(), true);
166 InstanceIdentifier<Flow> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
167 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Table.class,
168 new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
170 modification.put(LogicalDatastoreType.CONFIGURATION, path1, flowBuilder.build(), true /*createMissingParents*/);
172 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
174 commitFuture.get(); // TODO: Make it async (See bug 1362)
175 logger.debug("Transaction success for write of Flow "+flowBuilder.getFlowName());
177 } catch (Exception e) {
178 logger.error(e.getMessage(), e);
179 modification.cancel();
183 protected void removeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
184 Preconditions.checkNotNull(mdsalConsumer);
185 if (mdsalConsumer == null) {
186 logger.error("ERROR finding MDSAL Service.");
190 DataBroker dataBroker = mdsalConsumer.getDataBroker();
191 if (dataBroker == null) {
192 logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
196 WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
197 InstanceIdentifier<Flow> path1 = InstanceIdentifier.builder(Nodes.class)
198 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
199 .rev130819.nodes.Node.class, nodeBuilder.getKey())
200 .augmentation(FlowCapableNode.class).child(Table.class,
201 new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
202 //modification.delete(LogicalDatastoreType.OPERATIONAL, nodeBuilderToInstanceId(nodeBuilder));
203 //modification.delete(LogicalDatastoreType.OPERATIONAL, path1);
204 //modification.delete(LogicalDatastoreType.CONFIGURATION, nodeBuilderToInstanceId(nodeBuilder));
205 modification.delete(LogicalDatastoreType.CONFIGURATION, path1);
207 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
209 commitFuture.get(); // TODO: Make it async (See bug 1362)
210 logger.debug("Transaction success for deletion of Flow "+flowBuilder.getFlowName());
211 } catch (Exception e) {
212 logger.error(e.getMessage(), e);
213 modification.cancel();
217 public Flow getFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
218 Preconditions.checkNotNull(mdsalConsumer);
219 if (mdsalConsumer == null) {
220 logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
224 DataBroker dataBroker = mdsalConsumer.getDataBroker();
225 if (dataBroker == null) {
226 logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
230 InstanceIdentifier<Flow> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
231 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Table.class,
232 new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
234 ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
236 Optional<Flow> data = readTx.read(LogicalDatastoreType.CONFIGURATION, path1).get();
237 if (data.isPresent()) {
240 } catch (InterruptedException|ExecutionException e) {
241 logger.error(e.getMessage(), e);
244 logger.debug("Cannot find data for Flow " + flowBuilder.getFlowName());
249 * Program Default Pipeline Flow.
251 * @param nodeId Node on which the default pipeline flow is programmed.
253 protected void programDefaultPipelineRule(String nodeId) {
254 if (!isBridgeInPipeline(nodeId)) {
255 logger.debug("Bridge {} is not in pipeline", nodeId);
258 MatchBuilder matchBuilder = new MatchBuilder();
259 FlowBuilder flowBuilder = new FlowBuilder();
260 NodeBuilder nodeBuilder = createNodeBuilder(nodeId);
262 // Create the OF Actions and Instructions
263 InstructionsBuilder isb = new InstructionsBuilder();
265 // Instructions List Stores Individual Instructions
266 List<Instruction> instructions = Lists.newArrayList();
268 // Call the InstructionBuilder Methods Containing Actions
269 InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
271 ib.setKey(new InstructionKey(0));
272 instructions.add(ib.build());
274 // Add InstructionBuilder to the Instruction(s)Builder List
275 isb.setInstruction(instructions);
277 // Add InstructionsBuilder to FlowBuilder
278 flowBuilder.setInstructions(isb.build());
280 String flowId = "DEFAULT_PIPELINE_FLOW_"+service.getTable();
281 flowBuilder.setId(new FlowId(flowId));
282 FlowKey key = new FlowKey(new FlowId(flowId));
283 flowBuilder.setMatch(matchBuilder.build());
284 flowBuilder.setPriority(0);
285 flowBuilder.setBarrier(true);
286 flowBuilder.setTableId(service.getTable());
287 flowBuilder.setKey(key);
288 flowBuilder.setFlowName(flowId);
289 flowBuilder.setHardTimeout(0);
290 flowBuilder.setIdleTimeout(0);
291 writeFlow(flowBuilder, nodeBuilder);