Bug-5644: Fix checkstyle invocation for l2switch builds
[l2switch.git] / l2switch-main / implementation / src / main / java / org / opendaylight / l2switch / flow / FlowWriterServiceImpl.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.flow;
9
10 import com.google.common.base.Preconditions;
11 import com.google.common.collect.ImmutableList;
12 import java.math.BigInteger;
13 import java.util.concurrent.Future;
14 import java.util.concurrent.atomic.AtomicLong;
15 import org.opendaylight.l2switch.util.InstanceIdentifierUtils;
16 import org.opendaylight.openflowplugin.api.OFConstants;
17 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
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.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.service.rev130819.AddFlowInputBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutput;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowTableRef;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowModFlags;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowRef;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
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.instruction.ApplyActionsCaseBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActions;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetDestinationBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetSourceBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
53 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
54 import org.opendaylight.yangtools.yang.common.RpcResult;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58 /**
59  * Implementation of
60  * FlowWriterService{@link org.opendaylight.l2switch.flow.FlowWriterService},
61  * that builds required flow and writes to configuration data store using
62  * provided DataBrokerService
63  * {@link org.opendaylight.controller.sal.binding.api.data.DataBrokerService}
64  */
65 public class FlowWriterServiceImpl implements FlowWriterService {
66     private static final Logger LOG = LoggerFactory.getLogger(FlowWriterServiceImpl.class);
67     private SalFlowService salFlowService;
68     private short flowTableId;
69     private int flowPriority;
70     private int flowIdleTimeout;
71     private int flowHardTimeout;
72
73     private AtomicLong flowIdInc = new AtomicLong();
74     private AtomicLong flowCookieInc = new AtomicLong(0x2a00000000000000L);
75     private final Integer DEFAULT_TABLE_ID = 0;
76     private final Integer DEFAULT_PRIORITY = 10;
77     private final Integer DEFAULT_HARD_TIMEOUT = 3600;
78     private final Integer DEFAULT_IDLE_TIMEOUT = 1800;
79
80     public FlowWriterServiceImpl(SalFlowService salFlowService) {
81         Preconditions.checkNotNull(salFlowService, "salFlowService should not be null.");
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     /**
102      * Writes a flow that forwards packets to destPort if destination mac in
103      * packet is destMac and source Mac in packet is sourceMac. If sourceMac is
104      * null then flow would not set any source mac, resulting in all packets
105      * with destMac being forwarded to destPort.
106      *
107      * @param sourceMac
108      * @param destMac
109      * @param destNodeConnectorRef
110      */
111     @Override
112     public void addMacToMacFlow(MacAddress sourceMac, MacAddress destMac, NodeConnectorRef destNodeConnectorRef) {
113
114         Preconditions.checkNotNull(destMac, "Destination mac address should not be null.");
115         Preconditions.checkNotNull(destNodeConnectorRef, "Destination port should not be null.");
116
117         // do not add flow if both macs are same.
118         if (sourceMac != null && destMac.equals(sourceMac)) {
119             LOG.info("In addMacToMacFlow: No flows added. Source and Destination mac are same.");
120             return;
121         }
122
123         // get flow table key
124         TableKey flowTableKey = new TableKey((short) flowTableId);
125
126         // build a flow path based on node connector to program flow
127         InstanceIdentifier<Flow> flowPath = buildFlowPath(destNodeConnectorRef, flowTableKey);
128
129         // build a flow that target given mac id
130         Flow flowBody = createMacToMacFlow(flowTableKey.getId(), flowPriority, sourceMac, destMac,
131                 destNodeConnectorRef);
132
133         // commit the flow in config data
134         writeFlowToConfigData(flowPath, flowBody);
135     }
136
137     /**
138      * Writes mac-to-mac flow on all ports that are in the path between given
139      * source and destination ports. It uses path provided by
140      * org.opendaylight.l2switch.loopremover.topology.NetworkGraphService to
141      * find a links
142      * {@link org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link}
143      * between given ports. And then writes appropriate flow on each port that
144      * is covered in that path.
145      *
146      * @param sourceMac
147      * @param sourceNodeConnectorRef
148      * @param destMac
149      * @param destNodeConnectorRef
150      */
151     @Override
152     public void addBidirectionalMacToMacFlows(MacAddress sourceMac, NodeConnectorRef sourceNodeConnectorRef,
153             MacAddress destMac, NodeConnectorRef destNodeConnectorRef) {
154         Preconditions.checkNotNull(sourceMac, "Source mac address should not be null.");
155         Preconditions.checkNotNull(sourceNodeConnectorRef, "Source port should not be null.");
156         Preconditions.checkNotNull(destMac, "Destination mac address should not be null.");
157         Preconditions.checkNotNull(destNodeConnectorRef, "Destination port should not be null.");
158
159         if (sourceNodeConnectorRef.equals(destNodeConnectorRef)) {
160             LOG.info(
161                     "In addMacToMacFlowsUsingShortestPath: No flows added. Source and Destination ports are same.");
162             return;
163
164         }
165
166         // add destMac-To-sourceMac flow on source port
167         addMacToMacFlow(destMac, sourceMac, sourceNodeConnectorRef);
168
169         // add sourceMac-To-destMac flow on destination port
170         addMacToMacFlow(sourceMac, destMac, destNodeConnectorRef);
171     }
172
173     /**
174      * @param nodeConnectorRef
175      * @return
176      */
177     private InstanceIdentifier<Flow> buildFlowPath(NodeConnectorRef nodeConnectorRef, TableKey flowTableKey) {
178
179         // generate unique flow key
180         FlowId flowId = new FlowId(String.valueOf(flowIdInc.getAndIncrement()));
181         FlowKey flowKey = new FlowKey(flowId);
182
183         return InstanceIdentifierUtils.generateFlowInstanceIdentifier(nodeConnectorRef, flowTableKey, flowKey);
184     }
185
186     /**
187      * @param tableId
188      * @param priority
189      * @param sourceMac
190      * @param destMac
191      * @param destPort
192      * @return {@link org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder}
193      *         builds flow that forwards all packets with destMac to given port
194      */
195     private Flow createMacToMacFlow(Short tableId, int priority, MacAddress sourceMac, MacAddress destMac,
196             NodeConnectorRef destPort) {
197
198         // start building flow
199         FlowBuilder macToMacFlow = new FlowBuilder() //
200                 .setTableId(tableId) //
201                 .setFlowName("mac2mac");
202
203         // use its own hash code for id.
204         macToMacFlow.setId(new FlowId(Long.toString(macToMacFlow.hashCode())));
205
206         // create a match that has mac to mac ethernet match
207         EthernetMatchBuilder ethernetMatchBuilder = new EthernetMatchBuilder() //
208                 .setEthernetDestination(new EthernetDestinationBuilder() //
209                         .setAddress(destMac) //
210                         .build());
211         // set source in the match only if present
212         if (sourceMac != null) {
213             ethernetMatchBuilder.setEthernetSource(new EthernetSourceBuilder().setAddress(sourceMac).build());
214         }
215         EthernetMatch ethernetMatch = ethernetMatchBuilder.build();
216         Match match = new MatchBuilder().setEthernetMatch(ethernetMatch).build();
217
218         Uri destPortUri = destPort.getValue().firstKeyOf(NodeConnector.class, NodeConnectorKey.class).getId();
219
220         Action outputToControllerAction = new ActionBuilder() //
221                 .setOrder(0)
222                 .setAction(new OutputActionCaseBuilder() //
223                         .setOutputAction(new OutputActionBuilder() //
224                                 .setMaxLength(0xffff) //
225                                 .setOutputNodeConnector(destPortUri) //
226                                 .build()) //
227                         .build()) //
228                 .build();
229
230         // Create an Apply Action
231         ApplyActions applyActions = new ApplyActionsBuilder().setAction(ImmutableList.of(outputToControllerAction))
232                 .build();
233
234         // Wrap our Apply Action in an Instruction
235         Instruction applyActionsInstruction = new InstructionBuilder() //
236                 .setOrder(0)
237                 .setInstruction(new ApplyActionsCaseBuilder()//
238                         .setApplyActions(applyActions) //
239                         .build()) //
240                 .build();
241
242         // Put our Instruction in a list of Instructions
243         macToMacFlow.setMatch(match) //
244                 .setInstructions(new InstructionsBuilder() //
245                         .setInstruction(ImmutableList.of(applyActionsInstruction)) //
246                         .build()) //
247                 .setPriority(priority) //
248                 .setBufferId(OFConstants.OFP_NO_BUFFER) //
249                 .setHardTimeout(flowHardTimeout) //
250                 .setIdleTimeout(flowIdleTimeout) //
251                 .setCookie(new FlowCookie(BigInteger.valueOf(flowCookieInc.getAndIncrement())))
252                 .setFlags(new FlowModFlags(false, false, false, false, false));
253
254         return macToMacFlow.build();
255     }
256
257     /**
258      * Starts and commits data change transaction which modifies provided flow
259      * path with supplied body.
260      *
261      * @param flowPath
262      * @param flow
263      * @return transaction commit
264      */
265     private Future<RpcResult<AddFlowOutput>> writeFlowToConfigData(InstanceIdentifier<Flow> flowPath, Flow flow) {
266         final InstanceIdentifier<Table> tableInstanceId = flowPath.<Table>firstIdentifierOf(Table.class);
267         final InstanceIdentifier<Node> nodeInstanceId = flowPath.<Node>firstIdentifierOf(Node.class);
268         final AddFlowInputBuilder builder = new AddFlowInputBuilder(flow);
269         builder.setNode(new NodeRef(nodeInstanceId));
270         builder.setFlowRef(new FlowRef(flowPath));
271         builder.setFlowTable(new FlowTableRef(tableInstanceId));
272         builder.setTransactionUri(new Uri(flow.getId().getValue()));
273         return salFlowService.addFlow(builder.build());
274     }
275 }