blob: d02351bd2d66a9e86bfcc70d6f26e63f8114aedc [file] [log] [blame]
Toshio Koidea03915e2014-07-01 18:39:52 -07001package net.onrc.onos.api.flowmanager;
2
Toshio Koide9aa4c0f2014-08-11 16:06:44 -07003import static com.google.common.base.Preconditions.checkNotNull;
Toshio Koidea0c9e012014-08-20 16:29:28 -07004import static com.google.common.base.Preconditions.checkState;
Toshio Koide9aa4c0f2014-08-11 16:06:44 -07005
Toshio Koidea0c9e012014-08-20 16:29:28 -07006import java.util.Arrays;
Toshio Koidea03915e2014-07-01 18:39:52 -07007import java.util.Collection;
Toshio Koidea0c9e012014-08-20 16:29:28 -07008import java.util.HashMap;
9import java.util.HashSet;
Toshio Koide2c67a2d2014-08-27 11:30:56 -070010import java.util.LinkedList;
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070011import java.util.List;
Toshio Koidea0c9e012014-08-20 16:29:28 -070012import java.util.Map;
13import java.util.Map.Entry;
Toshio Koidea03915e2014-07-01 18:39:52 -070014import java.util.Set;
15
Toshio Koide2c67a2d2014-08-27 11:30:56 -070016import com.google.common.collect.ImmutableList;
17import com.google.common.collect.ImmutableSet;
18
Toshio Koided7d550c2014-08-21 16:08:55 -070019import net.onrc.onos.api.flowmanager.FlowBatchOperation.Operator;
Toshio Koidea0c9e012014-08-20 16:29:28 -070020import net.onrc.onos.core.matchaction.MatchAction;
Sho SHIMIZU7cd8a422014-08-27 16:05:21 -070021import net.onrc.onos.core.matchaction.MatchActionId;
Toshio Koidea0c9e012014-08-20 16:29:28 -070022import net.onrc.onos.core.matchaction.MatchActionOperationEntry;
Ray Milkey42ae1b52014-08-15 16:37:06 -070023import net.onrc.onos.core.matchaction.MatchActionOperations;
Sho SHIMIZU7cd8a422014-08-27 16:05:21 -070024import net.onrc.onos.core.matchaction.MatchActionOperationsId;
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070025import net.onrc.onos.core.matchaction.action.Action;
Toshio Koidea0c9e012014-08-20 16:29:28 -070026import net.onrc.onos.core.matchaction.action.OutputAction;
Toshio Koidea03915e2014-07-01 18:39:52 -070027import net.onrc.onos.core.matchaction.match.PacketMatch;
Toshio Koidea0c9e012014-08-20 16:29:28 -070028import net.onrc.onos.core.util.Dpid;
Sho SHIMIZU7cd8a422014-08-27 16:05:21 -070029import net.onrc.onos.core.util.IdGenerator;
Toshio Koidea0c9e012014-08-20 16:29:28 -070030import net.onrc.onos.core.util.PortNumber;
Toshio Koidea03915e2014-07-01 18:39:52 -070031import net.onrc.onos.core.util.SwitchPort;
32
33/**
Toshio Koidea0c9e012014-08-20 16:29:28 -070034 * A {@link Flow} object expressing the multipoints-to-point tree flow for the
35 * packet layer.
Toshio Koidea03915e2014-07-01 18:39:52 -070036 * <p>
Toshio Koidea0c9e012014-08-20 16:29:28 -070037 * NOTE: This class might generate the {@link MatchAction} operations which
38 * includes the MAC address modifications or other the label-switching-like
39 * schemes.
Toshio Koidea03915e2014-07-01 18:39:52 -070040 */
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070041public class SingleDstTreeFlow extends Flow {
42 private final PacketMatch match;
43 private final Set<SwitchPort> ingressPorts;
44 private final Tree tree;
Toshio Koidea0c9e012014-08-20 16:29:28 -070045 private final List<Action> egressActions;
Toshio Koidea03915e2014-07-01 18:39:52 -070046
47 /**
Toshio Koide2c67a2d2014-08-27 11:30:56 -070048 * Default constructor for Kryo deserialization.
49 */
50 @Deprecated
51 protected SingleDstTreeFlow() {
52 match = null;
53 ingressPorts = null;
54 tree = null;
55 egressActions = null;
56 }
57
58 /**
Toshio Koidea03915e2014-07-01 18:39:52 -070059 * Creates new instance using Tree object.
60 *
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070061 * @param id ID for this object
62 * @param match the traffic filter for the tree
63 * @param ingressPorts the set of ingress ports of the tree
64 * @param tree the Tree object specifying tree topology for this object
Toshio Koidea0c9e012014-08-20 16:29:28 -070065 * @param egressActions the list of {@link Action} objects to be executed at
66 * the egress edge switch
Toshio Koidea03915e2014-07-01 18:39:52 -070067 */
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070068 public SingleDstTreeFlow(FlowId id, PacketMatch match,
Toshio Koidea0c9e012014-08-20 16:29:28 -070069 Collection<SwitchPort> ingressPorts, Tree tree, List<Action> egressActions) {
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070070 super(id);
71 this.match = checkNotNull(match);
Toshio Koide2c67a2d2014-08-27 11:30:56 -070072 this.ingressPorts = new HashSet<>(checkNotNull(ingressPorts));
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070073 this.tree = checkNotNull(tree);
Toshio Koide2c67a2d2014-08-27 11:30:56 -070074 this.egressActions = new LinkedList<>(checkNotNull(egressActions));
Toshio Koidea03915e2014-07-01 18:39:52 -070075
76 // TODO: check if the tree is a MP2P tree.
Toshio Koidea0c9e012014-08-20 16:29:28 -070077 // TODO: check consistency between ingressPorts and tree topology.
Toshio Koidea03915e2014-07-01 18:39:52 -070078 }
79
Toshio Koidea03915e2014-07-01 18:39:52 -070080 /**
81 * Gets the ingress ports of the tree.
82 *
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070083 * @return the ingress ports of the tree
Toshio Koidea03915e2014-07-01 18:39:52 -070084 */
85 public Collection<SwitchPort> getIngressPorts() {
Toshio Koide2c67a2d2014-08-27 11:30:56 -070086 return ImmutableSet.copyOf(ingressPorts);
Toshio Koidea03915e2014-07-01 18:39:52 -070087 }
88
89 /**
90 * Gets the tree.
91 *
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070092 * @return the tree object
Toshio Koidea03915e2014-07-01 18:39:52 -070093 */
94 public Tree getTree() {
95 return tree;
96 }
97
98 /**
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070099 * Gets the list of actions at the egress edge switch.
Toshio Koidea03915e2014-07-01 18:39:52 -0700100 *
Toshio Koide9aa4c0f2014-08-11 16:06:44 -0700101 * @return the list of actions at the egress edge switch
Toshio Koidea03915e2014-07-01 18:39:52 -0700102 */
Toshio Koide9aa4c0f2014-08-11 16:06:44 -0700103 public List<Action> getEgressActions() {
Toshio Koide2c67a2d2014-08-27 11:30:56 -0700104 return ImmutableList.copyOf(egressActions);
Toshio Koidea03915e2014-07-01 18:39:52 -0700105 }
Toshio Koide5c5ca102014-08-19 00:49:52 -0700106
107 @Override
108 public PacketMatch getMatch() {
109 return match;
110 }
111
112 @Override
Toshio Koided7d550c2014-08-21 16:08:55 -0700113 public List<MatchActionOperations> compile(Operator op,
Sho SHIMIZU7cd8a422014-08-27 16:05:21 -0700114 IdGenerator<MatchActionId> maIdGenerator,
115 IdGenerator<MatchActionOperationsId> maoIdGenerator) {
Toshio Koidea0c9e012014-08-20 16:29:28 -0700116 switch (op) {
117 case ADD:
118 return compileAddOperation(maIdGenerator, maoIdGenerator);
119 case REMOVE:
120 return compileRemoveOperation();
121 default:
122 throw new UnsupportedOperationException("Unknown operation.");
123 }
124 }
125
126 private MatchAction createMatchAction(SwitchPort port, List<Action> actions,
Sho SHIMIZU7cd8a422014-08-27 16:05:21 -0700127 IdGenerator<MatchActionId> maIdGenerator) {
Toshio Koidea0c9e012014-08-20 16:29:28 -0700128 checkNotNull(port);
129 checkNotNull(actions);
130
131 return new MatchAction(maIdGenerator.getNewId(), port, getMatch(), actions);
132 }
133
134 /**
135 * Generates MatchAactionOperations at inner ports and at the egress switch.
136 *
137 * @param egressSwitch the egress switch of the tree
138 * @param inPorts a map of a set of incoming ports on each switch in the
139 * tree
140 * @param outPorts a map of outgoing port on each switch in the tree
141 * @param maIdGenerator ID generator for MatchAction objects
142 * @param maoIdGenerator ID generator for MatchActionOperations objects
143 * @return the operations at inner ports and egress switch
144 */
145 private MatchActionOperations generateFirstAddOperations(
146 Dpid egressSwitch,
147 Map<Dpid, Set<PortNumber>> inPorts,
148 Map<Dpid, PortNumber> outPorts,
Sho SHIMIZU7cd8a422014-08-27 16:05:21 -0700149 IdGenerator<MatchActionId> maIdGenerator,
150 IdGenerator<MatchActionOperationsId> maoIdGenerator) {
Toshio Koidea0c9e012014-08-20 16:29:28 -0700151 MatchActionOperations firstOps =
152 new MatchActionOperations(maoIdGenerator.getNewId());
153 for (Entry<Dpid, Set<PortNumber>> innerSw : inPorts.entrySet()) {
154 for (PortNumber innerPortNumber : innerSw.getValue()) {
155 SwitchPort innerPort = new SwitchPort(innerSw.getKey(), innerPortNumber);
156 MatchAction ma;
157 if (innerPort.getDpid().equals(egressSwitch)) {
158 ma = createMatchAction(innerPort, getEgressActions(), maIdGenerator);
159 } else {
160 PortNumber outputPortNumber = checkNotNull(
161 outPorts.get(innerPort.getDpid()),
162 String.format("The tree has no output port at %s",
163 innerPort.getDpid()));
164 ma = createMatchAction(innerPort,
165 Arrays.asList((Action) new OutputAction(outputPortNumber)),
166 maIdGenerator);
167 }
168 firstOps.addOperation(new MatchActionOperationEntry(
169 MatchActionOperations.Operator.ADD, ma));
170 }
171 }
172 return firstOps;
173 }
174
175 /**
176 * Generates MatchActionOperations for ingress switches in the tree.
177 *
178 * @param egressSwitch the egress switch of the tree
179 * @param outPorts a map of outgoing port on each switch in the tree
180 * @param maIdGenerator ID generator for MatchAction objects
181 * @param maoIdGenerator ID generator for MatchActionOperations objects
182 * @return operations at ingress switches in the tree
183 */
184 private MatchActionOperations generateSecondAddOperations(
185 Dpid egressSwitch,
186 Map<Dpid, PortNumber> outPorts,
Sho SHIMIZU7cd8a422014-08-27 16:05:21 -0700187 IdGenerator<MatchActionId> maIdGenerator,
188 IdGenerator<MatchActionOperationsId> maoIdGenerator) {
Toshio Koidea0c9e012014-08-20 16:29:28 -0700189 MatchActionOperations secondOps =
190 new MatchActionOperations(maoIdGenerator.getNewId());
191 for (SwitchPort port : getIngressPorts()) {
192 PortNumber outputPort = outPorts.get(port.getDpid());
193 if (outputPort == null) {
194 if (port.getDpid().equals(egressSwitch)) {
195 MatchAction ma = createMatchAction(
196 port, getEgressActions(), maIdGenerator);
197 secondOps.addOperation(new MatchActionOperationEntry(
198 MatchActionOperations.Operator.ADD, ma));
199 } else {
200 throw new IllegalStateException(String.format(
201 "The switch %s specified as one of ingress ports "
202 + "does not have path to the egress switch.",
203 port.getDpid()));
204 }
205 } else {
206 MatchAction ma = createMatchAction(port,
207 Arrays.asList((Action) new OutputAction(outputPort)),
208 maIdGenerator);
209 secondOps.addOperation(new MatchActionOperationEntry(
210 MatchActionOperations.Operator.ADD, ma));
211 }
212 }
213 return secondOps;
214 }
215
216 private List<MatchActionOperations> compileAddOperation(
Sho SHIMIZU7cd8a422014-08-27 16:05:21 -0700217 IdGenerator<MatchActionId> maIdGenerator,
218 IdGenerator<MatchActionOperationsId> maoIdGenerator) {
Toshio Koidea0c9e012014-08-20 16:29:28 -0700219 checkNotNull(tree);
220 checkState(tree.size() > 0, "Tree object has no link.");
221
222 // TODO: check consistency of the tree topology
223
224 // collect input ports and output ports checking consistency
225 Map<Dpid, PortNumber> outPorts = new HashMap<>();
226 Map<Dpid, Set<PortNumber>> inPorts = new HashMap<>();
227 for (FlowLink link : tree) {
228 SwitchPort srcPort = link.getSrcSwitchPort();
229 if (outPorts.containsKey(srcPort.getDpid())) {
230 throw new IllegalStateException(
231 String.format("Dpid:%s has multiple output ports.",
232 srcPort.getDpid()));
233 }
234 outPorts.put(srcPort.getDpid(), srcPort.getPortNumber());
235
236 SwitchPort dstPort = link.getDstSwitchPort();
237 Set<PortNumber> inPortNumbers = inPorts.get(dstPort.getDpid());
238 if (inPortNumbers == null) {
239 inPortNumbers = new HashSet<>();
240 }
241 inPortNumbers.add(dstPort.getPortNumber());
242 inPorts.put(dstPort.getDpid(), inPortNumbers);
243 }
244
245 // find the egress switch
246 Set<Dpid> egressSwitches = new HashSet<>(inPorts.keySet());
247 egressSwitches.removeAll(outPorts.keySet());
248 checkState(egressSwitches.size() == 1,
249 "The specified tree is not a single destination tree.");
250 Dpid egressSwitch = egressSwitches.iterator().next();
251
252 MatchActionOperations firstOps = generateFirstAddOperations(
253 egressSwitch, inPorts, outPorts, maIdGenerator, maoIdGenerator);
254 checkState(firstOps.size() > 0,
255 "No operations found for the first set of operations.");
256
257 MatchActionOperations secondOps = generateSecondAddOperations(
258 egressSwitch, outPorts, maIdGenerator, maoIdGenerator);
259 checkState(secondOps.size() > 0,
260 "No operations found for the second set of operations.");
261
262 return Arrays.asList(firstOps, secondOps);
263 }
264
265 private List<MatchActionOperations> compileRemoveOperation() {
Toshio Koide5c5ca102014-08-19 00:49:52 -0700266 // TODO Auto-generated method stub
Toshio Koidea0c9e012014-08-20 16:29:28 -0700267 throw new UnsupportedOperationException(
268 "REMOVE operation is not implemented yet.");
Toshio Koide5c5ca102014-08-19 00:49:52 -0700269 }
Toshio Koidea03915e2014-07-01 18:39:52 -0700270}