Bug-3425 : VM doesn't get the ip address from DHCP
[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 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.WriteTransaction;
15 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
16 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
17 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
18 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
19 import org.opendaylight.ovsdb.openstack.netvirt.providers.NetvirtProvidersProvider;
20 import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
21 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
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.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
39 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
40
41 import com.google.common.base.Optional;
42 import com.google.common.collect.Lists;
43 import com.google.common.util.concurrent.CheckedFuture;
44 import java.util.List;
45 import java.util.concurrent.ExecutionException;
46 import org.osgi.framework.ServiceReference;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49
50 /**
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.
56  *
57  */
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     private DataBroker dataBroker = null;
63     // OSGi Services that we are dependent on.
64     private volatile PipelineOrchestrator orchestrator;
65     private volatile Southbound southbound;
66
67     // Concrete Service that this AbstractServiceInstance represents
68     private Service service;
69
70     public AbstractServiceInstance (Service service) {
71         this.service = service;
72         this.dataBroker = NetvirtProvidersProvider.getDataBroker();
73     }
74
75     protected void setDependencies(final ServiceReference ref, AbstractServiceInstance serviceInstance) {
76         this.orchestrator =
77                 (PipelineOrchestrator) ServiceHelper.getGlobalInstance(PipelineOrchestrator.class, serviceInstance);
78         orchestrator.registerService(ref, serviceInstance);
79         this.southbound =
80                 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, serviceInstance);
81     }
82
83     public boolean isBridgeInPipeline (Node node){
84         String bridgeName = southbound.getBridgeName(node);
85         if (bridgeName != null && Constants.INTEGRATION_BRIDGE.equals(bridgeName)) {
86             return true;
87         }
88         return false;
89     }
90
91     public short getTable() {
92         return service.getTable();
93     }
94
95     public Service getService() {
96         return service;
97     }
98
99     public void setService(Service service) {
100         this.service = service;
101     }
102
103     public NodeBuilder createNodeBuilder(String nodeId) {
104         NodeBuilder builder = new NodeBuilder();
105         builder.setId(new NodeId(nodeId));
106         builder.setKey(new NodeKey(builder.getId()));
107         return builder;
108     }
109
110     private static final InstanceIdentifier<Flow> createFlowPath(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
111         return InstanceIdentifier.builder(Nodes.class)
112                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
113                         nodeBuilder.getKey())
114                 .augmentation(FlowCapableNode.class)
115                 .child(Table.class, new TableKey(flowBuilder.getTableId()))
116                 .child(Flow.class, flowBuilder.getKey()).build();
117     }
118
119     private static final
120     InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node>
121     createNodePath(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()).build();
125     }
126
127     /**
128      * This method returns the required Pipeline Instructions to by used by any matching flows that need
129      * to be further processed by next service in the pipeline.
130      *
131      * Important to note that this is a convenience method which returns a mutable instructionBuilder which
132      * needs to be further adjusted by the concrete ServiceInstance class such as setting the Instruction Order, etc.
133      * @return Newly created InstructionBuilder to be used along with other instructions on the main flow
134      */
135     protected final InstructionBuilder getMutablePipelineInstructionBuilder() {
136         Service nextService = orchestrator.getNextServiceInPipeline(service);
137         if (nextService != null) {
138             return InstructionUtils.createGotoTableInstructions(new InstructionBuilder(), nextService.getTable());
139         } else {
140             return InstructionUtils.createDropInstructions(new InstructionBuilder());
141         }
142     }
143
144     protected void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
145         logger.debug("writeFlow: flowBuilder: {}, nodeBuilder: {}",
146                 flowBuilder.build(), nodeBuilder.build());
147         WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
148         modification.put(LogicalDatastoreType.CONFIGURATION, createNodePath(nodeBuilder),
149                 nodeBuilder.build(), true /*createMissingParents*/);
150         modification.put(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder),
151                 flowBuilder.build(), true /*createMissingParents*/);
152
153         CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
154         try {
155             commitFuture.get();  // TODO: Make it async (See bug 1362)
156             logger.debug("Transaction success for write of Flow "+flowBuilder.getFlowName());
157         } catch (Exception e) {
158             logger.error(e.getMessage(), e);
159             modification.cancel();
160         }
161     }
162
163     protected void removeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
164         WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
165         modification.delete(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder));
166
167         CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
168         try {
169             commitFuture.get();  // TODO: Make it async (See bug 1362)
170             logger.debug("Transaction success for deletion of Flow " + flowBuilder.getFlowName());
171         } catch (Exception e) {
172             logger.error(e.getMessage(), e);
173             modification.cancel();
174         }
175     }
176
177     public Flow getFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
178         ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
179         try {
180             Optional<Flow> data =
181                     readTx.read(LogicalDatastoreType.CONFIGURATION, createFlowPath(flowBuilder, nodeBuilder)).get();
182             if (data.isPresent()) {
183                 return data.get();
184             }
185         } catch (InterruptedException|ExecutionException e) {
186             logger.error(e.getMessage(), e);
187         }
188
189         logger.debug("Cannot find data for Flow " + flowBuilder.getFlowName());
190         return null;
191     }
192
193     private Long getDpid(Node node) {
194         Long dpid = 0L;
195         dpid = southbound.getDataPathId(node);
196         if (dpid == 0) {
197             logger.warn("getDpid: dpid not found: {}", node);
198         }
199         return dpid;
200     }
201
202     /**
203      * Program Default Pipeline Flow.
204      *
205      * @param Node on which the default pipeline flow is programmed.
206      */
207     protected void programDefaultPipelineRule(Node node) {
208         if (!isBridgeInPipeline(node)) {
209             //logger.trace("Bridge is not in pipeline {} ", node);
210             return;
211         }
212         MatchBuilder matchBuilder = new MatchBuilder();
213         FlowBuilder flowBuilder = new FlowBuilder();
214         Long dpid = getDpid(node);
215         if (dpid == 0L) {
216             logger.info("could not find dpid: {}", node.getNodeId());
217             return;
218         }
219         String nodeName = OPENFLOW + getDpid(node);
220         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
221
222         // Create the OF Actions and Instructions
223         InstructionsBuilder isb = new InstructionsBuilder();
224
225         // Instructions List Stores Individual Instructions
226         List<Instruction> instructions = Lists.newArrayList();
227
228         // Call the InstructionBuilder Methods Containing Actions
229         InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
230         ib.setOrder(0);
231         ib.setKey(new InstructionKey(0));
232         instructions.add(ib.build());
233
234         // Add InstructionBuilder to the Instruction(s)Builder List
235         isb.setInstruction(instructions);
236
237         // Add InstructionsBuilder to FlowBuilder
238         flowBuilder.setInstructions(isb.build());
239
240         String flowId = "DEFAULT_PIPELINE_FLOW_"+service.getTable();
241         flowBuilder.setId(new FlowId(flowId));
242         FlowKey key = new FlowKey(new FlowId(flowId));
243         flowBuilder.setMatch(matchBuilder.build());
244         flowBuilder.setPriority(0);
245         flowBuilder.setBarrier(true);
246         flowBuilder.setTableId(service.getTable());
247         flowBuilder.setKey(key);
248         flowBuilder.setFlowName(flowId);
249         flowBuilder.setHardTimeout(0);
250         flowBuilder.setIdleTimeout(0);
251         writeFlow(flowBuilder, nodeBuilder);
252     }
253 }