Adding java docs, bug 1757.
[l2switch.git] / loopremover / implementation / src / main / java / org / opendaylight / l2switch / loopremover / flow / InitialFlowWriter.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
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 package org.opendaylight.l2switch.loopremover.flow;
9
10 import com.google.common.collect.ImmutableList;
11 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
12 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCaseBuilder;
13 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder;
14 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
15 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
16 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutput;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowTableRef;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowModFlags;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowRef;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.OutputPortValues;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActions;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemoved;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdated;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemoved;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdated;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.OpendaylightInventoryListener;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetTypeBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
50 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
51 import org.opendaylight.yangtools.yang.common.RpcResult;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
55 import java.math.BigInteger;
56 import java.util.concurrent.ExecutorService;
57 import java.util.concurrent.Executors;
58 import java.util.concurrent.Future;
59 import java.util.concurrent.atomic.AtomicLong;
60
61 /**
62  * Adds a flow, which sends all LLDP packets to the controller, on all switches.
63  * Registers as ODL Inventory listener so that it can add flows once a new node i.e. switch is added
64  */
65 public class InitialFlowWriter implements OpendaylightInventoryListener {
66   private final Logger _logger = LoggerFactory.getLogger(InitialFlowWriter.class);
67
68   private final ExecutorService initialFlowExecutor = Executors.newCachedThreadPool();
69   private final SalFlowService salFlowService;
70   private final int LLDP_ETHER_TYPE = 35020;
71   private short flowTableId;
72   private int flowPriority;
73   private int flowIdleTimeout;
74   private int flowHardTimeout;
75
76   private AtomicLong flowIdInc = new AtomicLong();
77   private AtomicLong flowCookieInc = new AtomicLong(0x2b00000000000000L);
78
79
80   public InitialFlowWriter(SalFlowService salFlowService) {
81     this.salFlowService = salFlowService;
82   }
83
84   public void setFlowTableId(short flowTableId) {
85     this.flowTableId = flowTableId;
86   }
87
88   public void setFlowPriority(int flowPriority) {
89     this.flowPriority = flowPriority;
90   }
91
92   public void setFlowIdleTimeout(int flowIdleTimeout) {
93     this.flowIdleTimeout = flowIdleTimeout;
94   }
95
96   public void setFlowHardTimeout(int flowHardTimeout) {
97     this.flowHardTimeout = flowHardTimeout;
98   }
99
100   @Override
101   public void onNodeConnectorRemoved(NodeConnectorRemoved nodeConnectorRemoved) {
102     //do nothing
103   }
104
105   @Override
106   public void onNodeConnectorUpdated(NodeConnectorUpdated nodeConnectorUpdated) {
107     //do nothing
108   }
109
110   @Override
111   public void onNodeRemoved(NodeRemoved nodeRemoved) {
112     //do nothing
113   }
114
115   /**
116    * Called when a node gets updated.
117    * @param nodeUpdated  The notification when a node gets updated.
118    */
119   @Override
120   public void onNodeUpdated(NodeUpdated nodeUpdated) {
121     initialFlowExecutor.submit(new InitialFlowWriterProcessor(nodeUpdated));
122   }
123
124   /**
125    * A private class to process the node updated event in separate thread. Allows to release the
126    * thread that invoked the data node updated event. Avoids any thread lock it may cause.
127    */
128   private class InitialFlowWriterProcessor implements Runnable {
129     private NodeUpdated nodeUpdated;
130
131     public InitialFlowWriterProcessor(NodeUpdated nodeUpdated) {
132       this.nodeUpdated = nodeUpdated;
133     }
134
135     @Override
136     public void run() {
137
138       if(nodeUpdated == null) {
139         return;
140       }
141
142       addInitialFlows((InstanceIdentifier<Node>) nodeUpdated.getNodeRef().getValue());
143
144     }
145
146     /**
147      * Adds a flow, which sends all LLDP packets to the controller, to the specified node.
148      * @param nodeId The node to write the flow on.
149      */
150     public void addInitialFlows(InstanceIdentifier<Node> nodeId) {
151       _logger.debug("adding initial flows for node {} ", nodeId);
152
153       InstanceIdentifier<Table> tableId = getTableInstanceId(nodeId);
154       InstanceIdentifier<Flow> flowId = getFlowInstanceId(tableId);
155
156       //add lldpToController flow
157       writeFlowToController(nodeId, tableId, flowId, createLldpToControllerFlow(flowTableId, flowPriority));
158
159       _logger.debug("Added initial flows for node {} ", nodeId);
160     }
161
162     private InstanceIdentifier<Table> getTableInstanceId(InstanceIdentifier<Node> nodeId) {
163       // get flow table key
164       TableKey flowTableKey = new TableKey(flowTableId);
165
166       return nodeId.builder()
167           .augmentation(FlowCapableNode.class)
168           .child(Table.class, flowTableKey)
169           .build();
170     }
171
172     private InstanceIdentifier<Flow> getFlowInstanceId(InstanceIdentifier<Table> tableId) {
173       // generate unique flow key
174       FlowId flowId = new FlowId(String.valueOf(flowIdInc.getAndIncrement()));
175       FlowKey flowKey = new FlowKey(flowId);
176       return tableId.child(Flow.class, flowKey);
177     }
178
179     private Flow createLldpToControllerFlow(Short tableId, int priority) {
180
181       // start building flow
182       FlowBuilder lldpFlow = new FlowBuilder() //
183           .setTableId(tableId) //
184           .setFlowName("lldptocntrl");
185
186       // use its own hash code for id.
187       lldpFlow.setId(new FlowId(Long.toString(lldpFlow.hashCode())));
188       EthernetMatchBuilder ethernetMatchBuilder = new EthernetMatchBuilder()
189           .setEthernetType(new EthernetTypeBuilder()
190               .setType(new EtherType(Long.valueOf(LLDP_ETHER_TYPE))).build());
191
192       Match match = new MatchBuilder()
193           .setEthernetMatch(ethernetMatchBuilder.build())
194           .build();
195
196       // Create an Apply Action
197       ApplyActions applyActions = new ApplyActionsBuilder().setAction(ImmutableList.of(getSendToControllerAction()))
198           .build();
199
200       // Wrap our Apply Action in an Instruction
201       Instruction applyActionsInstruction = new InstructionBuilder() //
202           .setOrder(0)
203           .setInstruction(new ApplyActionsCaseBuilder()//
204               .setApplyActions(applyActions) //
205               .build()) //
206           .build();
207
208       // Put our Instruction in a list of Instructions
209       lldpFlow
210           .setMatch(match) //
211           .setInstructions(new InstructionsBuilder() //
212               .setInstruction(ImmutableList.of(applyActionsInstruction)) //
213               .build()) //
214           .setPriority(priority) //
215           .setBufferId(0L) //
216           .setHardTimeout(flowHardTimeout) //
217           .setIdleTimeout(flowIdleTimeout) //
218           .setCookie(new FlowCookie(BigInteger.valueOf(flowCookieInc.getAndIncrement())))
219           .setFlags(new FlowModFlags(false, false, false, false, false));
220
221       return lldpFlow.build();
222     }
223
224     private Action getSendToControllerAction() {
225       Action sendToController = new ActionBuilder()
226           .setOrder(0)
227           .setKey(new ActionKey(0))
228           .setAction(new OutputActionCaseBuilder()
229               .setOutputAction(new OutputActionBuilder()
230                   .setMaxLength(new Integer(0xffff))
231                   .setOutputNodeConnector(new Uri(OutputPortValues.CONTROLLER.toString()))
232                   .build())
233               .build())
234           .build();
235
236       return sendToController;
237     }
238
239     private Future<RpcResult<AddFlowOutput>> writeFlowToController(InstanceIdentifier<Node> nodeInstanceId,
240                                                                    InstanceIdentifier<Table> tableInstanceId,
241                                                                    InstanceIdentifier<Flow> flowPath,
242                                                                    Flow flow) {
243       final AddFlowInputBuilder builder = new AddFlowInputBuilder(flow);
244       builder.setNode(new NodeRef(nodeInstanceId));
245       builder.setFlowRef(new FlowRef(flowPath));
246       builder.setFlowTable(new FlowTableRef(tableInstanceId));
247       builder.setTransactionUri(new Uri(flow.getId().getValue()));
248       return salFlowService.addFlow(builder.build());
249     }
250   }
251 }