2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
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 package org.opendaylight.l2switch.flow;
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.rev130715.Uri;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.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;
60 * FlowWriterService{@link org.opendaylight.l2switch.flow.FlowWriterService},
61 * that builds required flow and writes to configuration data store using
62 * provided {@link org.opendaylight.controller.md.sal.binding.api.DataBroker}.
64 public class FlowWriterServiceImpl implements FlowWriterService {
65 private static final Logger LOG = LoggerFactory.getLogger(FlowWriterServiceImpl.class);
66 private static final String FLOW_ID_PREFIX = "L2switch-";
68 private final SalFlowService salFlowService;
69 private short flowTableId;
70 private int flowPriority;
71 private int flowIdleTimeout;
72 private int flowHardTimeout;
74 private final AtomicLong flowIdInc = new AtomicLong();
75 private final AtomicLong flowCookieInc = new AtomicLong(0x2a00000000000000L);
77 public FlowWriterServiceImpl(SalFlowService salFlowService) {
78 Preconditions.checkNotNull(salFlowService, "salFlowService should not be null.");
79 this.salFlowService = salFlowService;
82 public void setFlowTableId(short flowTableId) {
83 this.flowTableId = flowTableId;
86 public void setFlowPriority(int flowPriority) {
87 this.flowPriority = flowPriority;
90 public void setFlowIdleTimeout(int flowIdleTimeout) {
91 this.flowIdleTimeout = flowIdleTimeout;
94 public void setFlowHardTimeout(int flowHardTimeout) {
95 this.flowHardTimeout = flowHardTimeout;
99 public void addMacToMacFlow(MacAddress sourceMac, MacAddress destMac, NodeConnectorRef destNodeConnectorRef) {
101 Preconditions.checkNotNull(destMac, "Destination mac address should not be null.");
102 Preconditions.checkNotNull(destNodeConnectorRef, "Destination port should not be null.");
104 // do not add flow if both macs are same.
105 if (sourceMac != null && destMac.equals(sourceMac)) {
106 LOG.info("In addMacToMacFlow: No flows added. Source and Destination mac are same.");
110 // get flow table key
111 TableKey flowTableKey = new TableKey(flowTableId);
113 // build a flow path based on node connector to program flow
114 InstanceIdentifier<Flow> flowPath = buildFlowPath(destNodeConnectorRef, flowTableKey);
116 // build a flow that target given mac id
117 Flow flowBody = createMacToMacFlow(flowTableKey.getId(), flowPriority, sourceMac, destMac,
118 destNodeConnectorRef);
120 // commit the flow in config data
121 writeFlowToConfigData(flowPath, flowBody);
125 public void addBidirectionalMacToMacFlows(MacAddress sourceMac, NodeConnectorRef sourceNodeConnectorRef,
126 MacAddress destMac, NodeConnectorRef destNodeConnectorRef) {
127 Preconditions.checkNotNull(sourceMac, "Source mac address should not be null.");
128 Preconditions.checkNotNull(sourceNodeConnectorRef, "Source port should not be null.");
129 Preconditions.checkNotNull(destMac, "Destination mac address should not be null.");
130 Preconditions.checkNotNull(destNodeConnectorRef, "Destination port should not be null.");
132 if (sourceNodeConnectorRef.equals(destNodeConnectorRef)) {
134 "In addMacToMacFlowsUsingShortestPath: No flows added. Source and Destination ports are same.");
139 // add destMac-To-sourceMac flow on source port
140 addMacToMacFlow(destMac, sourceMac, sourceNodeConnectorRef);
142 // add sourceMac-To-destMac flow on destination port
143 addMacToMacFlow(sourceMac, destMac, destNodeConnectorRef);
146 private InstanceIdentifier<Flow> buildFlowPath(NodeConnectorRef nodeConnectorRef, TableKey flowTableKey) {
148 // generate unique flow key
149 FlowId flowId = new FlowId(FLOW_ID_PREFIX + String.valueOf(flowIdInc.getAndIncrement()));
150 FlowKey flowKey = new FlowKey(flowId);
152 return InstanceIdentifierUtils.generateFlowInstanceIdentifier(nodeConnectorRef, flowTableKey, flowKey);
156 * Builds a flow that forwards all packets with destMac to given port.
158 * @param tableId the table id
159 * @param priority the flow priority
160 * @param sourceMac the source MAC of the flow
161 * @param destMac the destination MAC of the flow
162 * @param destPort the destination port
165 private Flow createMacToMacFlow(Short tableId, int priority, MacAddress sourceMac, MacAddress destMac,
166 NodeConnectorRef destPort) {
168 // start building flow
169 FlowBuilder macToMacFlow = new FlowBuilder() //
170 .setTableId(tableId) //
171 .setFlowName("mac2mac");
173 // use its own hash code for id.
174 macToMacFlow.setId(new FlowId(Long.toString(macToMacFlow.hashCode())));
176 // create a match that has mac to mac ethernet match
177 EthernetMatchBuilder ethernetMatchBuilder = new EthernetMatchBuilder() //
178 .setEthernetDestination(new EthernetDestinationBuilder() //
179 .setAddress(destMac) //
181 // set source in the match only if present
182 if (sourceMac != null) {
183 ethernetMatchBuilder.setEthernetSource(new EthernetSourceBuilder().setAddress(sourceMac).build());
185 EthernetMatch ethernetMatch = ethernetMatchBuilder.build();
186 Match match = new MatchBuilder().setEthernetMatch(ethernetMatch).build();
188 Uri destPortUri = destPort.getValue().firstKeyOf(NodeConnector.class, NodeConnectorKey.class).getId();
190 Action outputToControllerAction = new ActionBuilder() //
192 .setAction(new OutputActionCaseBuilder() //
193 .setOutputAction(new OutputActionBuilder() //
194 .setMaxLength(0xffff) //
195 .setOutputNodeConnector(destPortUri) //
200 // Create an Apply Action
201 ApplyActions applyActions = new ApplyActionsBuilder().setAction(ImmutableList.of(outputToControllerAction))
204 // Wrap our Apply Action in an Instruction
205 Instruction applyActionsInstruction = new InstructionBuilder() //
207 .setInstruction(new ApplyActionsCaseBuilder()//
208 .setApplyActions(applyActions) //
212 // Put our Instruction in a list of Instructions
213 macToMacFlow.setMatch(match) //
214 .setInstructions(new InstructionsBuilder() //
215 .setInstruction(ImmutableList.of(applyActionsInstruction)) //
217 .setPriority(priority) //
218 .setBufferId(OFConstants.OFP_NO_BUFFER) //
219 .setHardTimeout(flowHardTimeout) //
220 .setIdleTimeout(flowIdleTimeout) //
221 .setCookie(new FlowCookie(BigInteger.valueOf(flowCookieInc.getAndIncrement())))
222 .setFlags(new FlowModFlags(false, false, false, false, false));
224 return macToMacFlow.build();
228 * Starts and commits data change transaction which modifies provided flow
229 * path with supplied body.
231 * @param flowPath the Flow path
232 * @param flow the Flow
233 * @return transaction commit
235 private Future<RpcResult<AddFlowOutput>> writeFlowToConfigData(InstanceIdentifier<Flow> flowPath, Flow flow) {
236 final InstanceIdentifier<Table> tableInstanceId = flowPath.<Table>firstIdentifierOf(Table.class);
237 final InstanceIdentifier<Node> nodeInstanceId = flowPath.<Node>firstIdentifierOf(Node.class);
238 final AddFlowInputBuilder builder = new AddFlowInputBuilder(flow);
239 builder.setNode(new NodeRef(nodeInstanceId));
240 builder.setFlowRef(new FlowRef(flowPath));
241 builder.setFlowTable(new FlowTableRef(tableInstanceId));
242 builder.setTransactionUri(new Uri(flow.getId().getValue()));
243 return salFlowService.addFlow(builder.build());