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.controller.sample.l2switch.md.flow;
10 import com.google.common.base.Preconditions;
11 import com.google.common.collect.ImmutableList;
12 import org.opendaylight.controller.sample.l2switch.md.topology.NetworkGraphService;
13 import org.opendaylight.controller.sample.l2switch.md.util.InstanceIdentifierUtils;
14 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
15 import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
16 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
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.TableKey;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowModFlags;
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.Match;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActions;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetDestinationBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetSourceBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
46 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
47 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
48 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
49 import org.opendaylight.yangtools.yang.common.RpcResult;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
53 import java.math.BigInteger;
54 import java.util.List;
55 import java.util.concurrent.Future;
56 import java.util.concurrent.atomic.AtomicLong;
59 * Implementation of FlowWriterService{@link org.opendaylight.controller.sample.l2switch.md.flow.FlowWriterService},
60 * that builds required flow and writes to configuration data store using provided DataBrokerService
61 * {@link org.opendaylight.controller.sal.binding.api.data.DataBrokerService}
63 public class FlowWriterServiceImpl implements FlowWriterService {
64 private static final Logger _logger = LoggerFactory.getLogger(FlowWriterServiceImpl.class);
65 private final DataBrokerService dataBrokerService;
66 private final NetworkGraphService networkGraphService;
67 private AtomicLong flowIdInc = new AtomicLong();
68 private AtomicLong flowCookieInc = new AtomicLong(0x2a00000000000000L);
71 public FlowWriterServiceImpl(DataBrokerService dataBrokerService, NetworkGraphService networkGraphService) {
72 Preconditions.checkNotNull(dataBrokerService, "dataBrokerService should not be null.");
73 Preconditions.checkNotNull(networkGraphService, "networkGraphService should not be null.");
74 this.dataBrokerService = dataBrokerService;
75 this.networkGraphService = networkGraphService;
79 * Writes a flow that forwards packets to destPort if destination mac in packet is destMac and
80 * source Mac in packet is sourceMac. If sourceMac is null then flow would not set any source mac,
81 * resulting in all packets with destMac being forwarded to destPort.
85 * @param destNodeConnectorRef
88 public void addMacToMacFlow(MacAddress sourceMac, MacAddress destMac, NodeConnectorRef destNodeConnectorRef) {
90 Preconditions.checkNotNull(destMac, "Destination mac address should not be null.");
91 Preconditions.checkNotNull(destNodeConnectorRef, "Destination port should not be null.");
94 // do not add flow if both macs are same.
95 if(sourceMac != null && destMac.equals(sourceMac)) {
96 _logger.info("In addMacToMacFlow: No flows added. Source and Destination mac are same.");
100 // get flow table key
101 TableKey flowTableKey = new TableKey((short) 0); //TODO: Hard coded Table Id 0, need to get it from Configuration data.
103 //build a flow path based on node connector to program flow
104 InstanceIdentifier<Flow> flowPath = buildFlowPath(destNodeConnectorRef, flowTableKey);
106 // build a flow that target given mac id
107 Flow flowBody = createMacToMacFlow(flowTableKey.getId(), 0, sourceMac, destMac, destNodeConnectorRef);
109 // commit the flow in config data
110 writeFlowToConfigData(flowPath, flowBody);
114 * Writes mac-to-mac flow on all ports that are in the path between given source and destination ports.
115 * It uses path provided by NetworkGraphService
116 * {@link org.opendaylight.controller.sample.l2switch.md.topology.NetworkGraphService} to find a links
117 * {@link org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link}
118 * between given ports. And then writes appropriate flow on each port that is covered in that path.
121 * @param sourceNodeConnectorRef
123 * @param destNodeConnectorRef
126 public void addMacToMacFlowsUsingShortestPath(MacAddress sourceMac,
127 NodeConnectorRef sourceNodeConnectorRef,
129 NodeConnectorRef destNodeConnectorRef) {
130 Preconditions.checkNotNull(sourceMac, "Source mac address should not be null.");
131 Preconditions.checkNotNull(sourceNodeConnectorRef, "Source port should not be null.");
132 Preconditions.checkNotNull(destMac, "Destination mac address should not be null.");
133 Preconditions.checkNotNull(destNodeConnectorRef, "Destination port should not be null.");
135 if(sourceNodeConnectorRef.equals(destNodeConnectorRef)) {
136 _logger.info("In addMacToMacFlowsUsingShortestPath: No flows added. Source and Destination ports are same.");
140 NodeId sourceNodeId = new NodeId(sourceNodeConnectorRef.getValue().firstKeyOf(Node.class, NodeKey.class).getId().getValue());
141 NodeId destNodeId = new NodeId(destNodeConnectorRef.getValue().firstKeyOf(Node.class, NodeKey.class).getId().getValue());
143 // add destMac-To-sourceMac flow on source port
144 addMacToMacFlow(destMac, sourceMac, sourceNodeConnectorRef);
146 // add sourceMac-To-destMac flow on destination port
147 addMacToMacFlow(sourceMac, destMac, destNodeConnectorRef);
149 if(!sourceNodeId.equals(destNodeId)) {
150 List<Link> linksInBeween = networkGraphService.getPath(sourceNodeId, destNodeId);
152 if(linksInBeween != null) {
153 // assumes the list order is maintained and starts with link that has source as source node
154 for(Link link : linksInBeween) {
155 // add sourceMac-To-destMac flow on source port
156 addMacToMacFlow(sourceMac, destMac, getSourceNodeConnectorRef(link));
158 // add destMac-To-sourceMac flow on destination port
159 addMacToMacFlow(destMac, sourceMac, getDestNodeConnectorRef(link));
165 private NodeConnectorRef getSourceNodeConnectorRef(Link link) {
166 InstanceIdentifier<NodeConnector> nodeConnectorInstanceIdentifier
167 = InstanceIdentifierUtils.createNodeConnectorIdentifier(
168 link.getSource().getSourceNode().getValue(),
169 link.getSource().getSourceTp().getValue());
170 return new NodeConnectorRef(nodeConnectorInstanceIdentifier);
173 private NodeConnectorRef getDestNodeConnectorRef(Link link) {
174 InstanceIdentifier<NodeConnector> nodeConnectorInstanceIdentifier
175 = InstanceIdentifierUtils.createNodeConnectorIdentifier(
176 link.getDestination().getDestNode().getValue(),
177 link.getDestination().getDestTp().getValue());
179 return new NodeConnectorRef(nodeConnectorInstanceIdentifier);
183 * @param nodeConnectorRef
186 private InstanceIdentifier<Flow> buildFlowPath(NodeConnectorRef nodeConnectorRef, TableKey flowTableKey) {
188 // generate unique flow key
189 FlowId flowId = new FlowId(String.valueOf(flowIdInc.getAndIncrement()));
190 FlowKey flowKey = new FlowKey(flowId);
192 return InstanceIdentifierUtils.generateFlowInstanceIdentifier(nodeConnectorRef, flowTableKey, flowKey);
201 * @return {@link org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder}
202 * builds flow that forwards all packets with destMac to given port
204 private Flow createMacToMacFlow(Short tableId, int priority,
205 MacAddress sourceMac, MacAddress destMac, NodeConnectorRef destPort) {
207 // start building flow
208 FlowBuilder macToMacFlow = new FlowBuilder() //
209 .setTableId(tableId) //
210 .setFlowName("mac2mac");
212 // use its own hash code for id.
213 macToMacFlow.setId(new FlowId(Long.toString(macToMacFlow.hashCode())));
215 // create a match that has mac to mac ethernet match
216 EthernetMatchBuilder ethernetMatchBuilder = new EthernetMatchBuilder() //
217 .setEthernetDestination(new EthernetDestinationBuilder() //
218 .setAddress(destMac) //
220 // set source in the match only if present
221 if(sourceMac != null) {
222 ethernetMatchBuilder.setEthernetSource(new EthernetSourceBuilder()
223 .setAddress(sourceMac)
226 EthernetMatch ethernetMatch = ethernetMatchBuilder.build();
227 Match match = new MatchBuilder()
228 .setEthernetMatch(ethernetMatch)
232 Uri destPortUri = destPort.getValue().firstKeyOf(NodeConnector.class, NodeConnectorKey.class).getId();
234 Action outputToControllerAction = new ActionBuilder() //
235 .setAction(new OutputActionCaseBuilder() //
236 .setOutputAction(new OutputActionBuilder() //
237 .setMaxLength(new Integer(0xffff)) //
238 .setOutputNodeConnector(destPortUri) //
243 // Create an Apply Action
244 ApplyActions applyActions = new ApplyActionsBuilder().setAction(ImmutableList.of(outputToControllerAction))
247 // Wrap our Apply Action in an Instruction
248 Instruction applyActionsInstruction = new InstructionBuilder() //
249 .setInstruction(new ApplyActionsCaseBuilder()//
250 .setApplyActions(applyActions) //
254 // Put our Instruction in a list of Instructions
257 .setInstructions(new InstructionsBuilder() //
258 .setInstruction(ImmutableList.of(applyActionsInstruction)) //
260 .setPriority(priority) //
262 .setHardTimeout(0) //
263 .setIdleTimeout(0) //
264 .setCookie(BigInteger.valueOf(flowCookieInc.getAndIncrement()))
265 .setFlags(new FlowModFlags(false, false, false, false, false));
267 return macToMacFlow.build();
271 * Starts and commits data change transaction which
272 * modifies provided flow path with supplied body.
276 * @return transaction commit
278 private Future<RpcResult<TransactionStatus>> writeFlowToConfigData(InstanceIdentifier<Flow> flowPath,
280 DataModificationTransaction addFlowTransaction = dataBrokerService.beginTransaction();
281 addFlowTransaction.putConfigurationData(flowPath, flowBody);
282 return addFlowTransaction.commit();