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