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.collect.ImmutableList;
11 import java.math.BigInteger;
12 import java.util.Collection;
13 import java.util.HashSet;
15 import java.util.concurrent.ExecutorService;
16 import java.util.concurrent.Executors;
17 import java.util.concurrent.Future;
18 import java.util.concurrent.atomic.AtomicLong;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
21 import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
22 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
23 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
24 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
25 import org.opendaylight.openflowplugin.api.OFConstants;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.DropActionCaseBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowTableRef;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowModFlags;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowRef;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActions;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
56 import org.opendaylight.yangtools.concepts.ListenerRegistration;
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;
63 * Adds a flow, which drops all packets, on all switches.
64 * Registers as ODL Inventory listener so that it can add flows once a new node i.e. switch is added.
66 public class InitialFlowWriter implements DataTreeChangeListener<Node> {
67 private static final Logger LOG = LoggerFactory.getLogger(InitialFlowWriter.class);
68 private static final String FLOW_ID_PREFIX = "L2switch-";
70 private final ExecutorService initialFlowExecutor = Executors.newCachedThreadPool();
71 private final SalFlowService salFlowService;
73 private final AtomicLong flowIdInc = new AtomicLong();
74 private final AtomicLong flowCookieInc = new AtomicLong(0x2b00000000000000L);
75 private short flowTableId;
76 private int flowPriority;
77 private int flowIdleTimeout;
78 private int flowHardTimeout;
80 public InitialFlowWriter(SalFlowService salFlowService) {
81 this.salFlowService = salFlowService;
84 public void setFlowTableId(short flowTableId) {
85 this.flowTableId = flowTableId;
88 public void setFlowPriority(int flowPriority) {
89 this.flowPriority = flowPriority;
92 public void setFlowIdleTimeout(int flowIdleTimeout) {
93 this.flowIdleTimeout = flowIdleTimeout;
96 public void setFlowHardTimeout(int flowHardTimeout) {
97 this.flowHardTimeout = flowHardTimeout;
100 public ListenerRegistration<InitialFlowWriter> registerAsDataChangeListener(DataBroker dataBroker) {
101 InstanceIdentifier<Node> nodeInstanceIdentifier = InstanceIdentifier.builder(Nodes.class)
102 .child(Node.class).build();
104 return dataBroker.registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
105 nodeInstanceIdentifier), this);
109 public void onDataTreeChanged(Collection<DataTreeModification<Node>> changes) {
110 Set<InstanceIdentifier<?>> nodeIds = new HashSet<>();
111 for (DataTreeModification<Node> change: changes) {
112 DataObjectModification<Node> rootNode = change.getRootNode();
113 final InstanceIdentifier<Node> identifier = change.getRootPath().getRootIdentifier();
114 switch (rootNode.getModificationType()) {
116 if (rootNode.getDataBefore() == null) {
117 nodeIds.add(identifier);
125 if (!nodeIds.isEmpty()) {
126 initialFlowExecutor.submit(new InitialFlowWriterProcessor(nodeIds));
131 * A private class to process the node updated event in separate thread. Allows to release the
132 * thread that invoked the data node updated event. Avoids any thread lock it may cause.
134 private class InitialFlowWriterProcessor implements Runnable {
135 private final Set<InstanceIdentifier<?>> nodeIds;
137 InitialFlowWriterProcessor(Set<InstanceIdentifier<?>> nodeIds) {
138 this.nodeIds = nodeIds;
143 if (nodeIds == null) {
147 for (InstanceIdentifier<?> nodeId : nodeIds) {
148 if (Node.class.isAssignableFrom(nodeId.getTargetType())) {
149 InstanceIdentifier<Node> invNodeId = (InstanceIdentifier<Node>) nodeId;
150 if (invNodeId.firstKeyOf(Node.class, NodeKey.class).getId().getValue().contains("openflow:")) {
151 addInitialFlows(invNodeId);
158 * Adds a flow, which drops all packets, on the specifide node.
159 * @param nodeId The node to install the flow on.
161 public void addInitialFlows(InstanceIdentifier<Node> nodeId) {
162 LOG.debug("adding initial flows for node {} ", nodeId);
164 InstanceIdentifier<Table> tableId = getTableInstanceId(nodeId);
165 InstanceIdentifier<Flow> flowId = getFlowInstanceId(tableId);
168 writeFlowToController(nodeId, tableId, flowId, createDropAllFlow(flowTableId, flowPriority));
170 LOG.debug("Added initial flows for node {} ", nodeId);
173 private InstanceIdentifier<Table> getTableInstanceId(InstanceIdentifier<Node> nodeId) {
174 // get flow table key
175 TableKey flowTableKey = new TableKey(flowTableId);
176 return nodeId.builder()
177 .augmentation(FlowCapableNode.class)
178 .child(Table.class, flowTableKey)
182 private InstanceIdentifier<Flow> getFlowInstanceId(InstanceIdentifier<Table> tableId) {
183 // generate unique flow key
184 FlowId flowId = new FlowId(FLOW_ID_PREFIX + String.valueOf(flowIdInc.getAndIncrement()));
185 FlowKey flowKey = new FlowKey(flowId);
186 return tableId.child(Flow.class, flowKey);
189 private Flow createDropAllFlow(Short tableId, int priority) {
191 // start building flow
192 FlowBuilder dropAll = new FlowBuilder() //
193 .setTableId(tableId) //
194 .setFlowName("dropall");
196 // use its own hash code for id.
197 dropAll.setId(new FlowId(Long.toString(dropAll.hashCode())));
199 Match match = new MatchBuilder().build();
202 Action dropAllAction = new ActionBuilder() //
204 .setAction(new DropActionCaseBuilder().build())
207 // Create an Apply Action
208 ApplyActions applyActions = new ApplyActionsBuilder().setAction(ImmutableList.of(dropAllAction))
211 // Wrap our Apply Action in an Instruction
212 Instruction applyActionsInstruction = new InstructionBuilder() //
214 .setInstruction(new ApplyActionsCaseBuilder()//
215 .setApplyActions(applyActions) //
219 // Put our Instruction in a list of Instructions
222 .setInstructions(new InstructionsBuilder() //
223 .setInstruction(ImmutableList.of(applyActionsInstruction)) //
225 .setPriority(priority) //
226 .setBufferId(OFConstants.OFP_NO_BUFFER) //
227 .setHardTimeout(flowHardTimeout) //
228 .setIdleTimeout(flowIdleTimeout) //
229 .setCookie(new FlowCookie(BigInteger.valueOf(flowCookieInc.getAndIncrement())))
230 .setFlags(new FlowModFlags(false, false, false, false, false));
232 return dropAll.build();
235 private Future<RpcResult<AddFlowOutput>> writeFlowToController(InstanceIdentifier<Node> nodeInstanceId,
236 InstanceIdentifier<Table> tableInstanceId,
237 InstanceIdentifier<Flow> flowPath,
239 LOG.trace("Adding flow to node {}",nodeInstanceId.firstKeyOf(Node.class, NodeKey.class).getId().getValue());
240 final AddFlowInputBuilder builder = new AddFlowInputBuilder(flow);
241 builder.setNode(new NodeRef(nodeInstanceId));
242 builder.setFlowRef(new FlowRef(flowPath));
243 builder.setFlowTable(new FlowTableRef(tableInstanceId));
244 builder.setTransactionUri(new Uri(flow.getId().getValue()));
245 return salFlowService.addFlow(builder.build());