blob: 0caef51f46c1dedce543760cc6db26d634684bda [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;
Toshio Koided7d550c2014-08-21 16:08:55 -070021import net.onrc.onos.core.matchaction.MatchActionIdGenerator;
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;
Toshio Koided7d550c2014-08-21 16:08:55 -070024import net.onrc.onos.core.matchaction.MatchActionOperationsIdGenerator;
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;
29import net.onrc.onos.core.util.PortNumber;
Toshio Koidea03915e2014-07-01 18:39:52 -070030import net.onrc.onos.core.util.SwitchPort;
31
32/**
Toshio Koidea0c9e012014-08-20 16:29:28 -070033 * A {@link Flow} object expressing the multipoints-to-point tree flow for the
34 * packet layer.
Toshio Koidea03915e2014-07-01 18:39:52 -070035 * <p>
Toshio Koidea0c9e012014-08-20 16:29:28 -070036 * NOTE: This class might generate the {@link MatchAction} operations which
37 * includes the MAC address modifications or other the label-switching-like
38 * schemes.
Toshio Koidea03915e2014-07-01 18:39:52 -070039 */
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070040public class SingleDstTreeFlow extends Flow {
41 private final PacketMatch match;
42 private final Set<SwitchPort> ingressPorts;
43 private final Tree tree;
Toshio Koidea0c9e012014-08-20 16:29:28 -070044 private final List<Action> egressActions;
Toshio Koidea03915e2014-07-01 18:39:52 -070045
46 /**
Toshio Koide2c67a2d2014-08-27 11:30:56 -070047 * Default constructor for Kryo deserialization.
48 */
49 @Deprecated
50 protected SingleDstTreeFlow() {
51 match = null;
52 ingressPorts = null;
53 tree = null;
54 egressActions = null;
55 }
56
57 /**
Toshio Koidea03915e2014-07-01 18:39:52 -070058 * Creates new instance using Tree object.
59 *
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070060 * @param id ID for this object
61 * @param match the traffic filter for the tree
62 * @param ingressPorts the set of ingress ports of the tree
63 * @param tree the Tree object specifying tree topology for this object
Toshio Koidea0c9e012014-08-20 16:29:28 -070064 * @param egressActions the list of {@link Action} objects to be executed at
65 * the egress edge switch
Toshio Koidea03915e2014-07-01 18:39:52 -070066 */
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070067 public SingleDstTreeFlow(FlowId id, PacketMatch match,
Toshio Koidea0c9e012014-08-20 16:29:28 -070068 Collection<SwitchPort> ingressPorts, Tree tree, List<Action> egressActions) {
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070069 super(id);
70 this.match = checkNotNull(match);
Toshio Koide2c67a2d2014-08-27 11:30:56 -070071 this.ingressPorts = new HashSet<>(checkNotNull(ingressPorts));
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070072 this.tree = checkNotNull(tree);
Toshio Koide2c67a2d2014-08-27 11:30:56 -070073 this.egressActions = new LinkedList<>(checkNotNull(egressActions));
Toshio Koidea03915e2014-07-01 18:39:52 -070074
75 // TODO: check if the tree is a MP2P tree.
Toshio Koidea0c9e012014-08-20 16:29:28 -070076 // TODO: check consistency between ingressPorts and tree topology.
Toshio Koidea03915e2014-07-01 18:39:52 -070077 }
78
Toshio Koidea03915e2014-07-01 18:39:52 -070079 /**
80 * Gets the ingress ports of the tree.
81 *
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070082 * @return the ingress ports of the tree
Toshio Koidea03915e2014-07-01 18:39:52 -070083 */
84 public Collection<SwitchPort> getIngressPorts() {
Toshio Koide2c67a2d2014-08-27 11:30:56 -070085 return ImmutableSet.copyOf(ingressPorts);
Toshio Koidea03915e2014-07-01 18:39:52 -070086 }
87
88 /**
89 * Gets the tree.
90 *
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070091 * @return the tree object
Toshio Koidea03915e2014-07-01 18:39:52 -070092 */
93 public Tree getTree() {
94 return tree;
95 }
96
97 /**
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070098 * Gets the list of actions at the egress edge switch.
Toshio Koidea03915e2014-07-01 18:39:52 -070099 *
Toshio Koide9aa4c0f2014-08-11 16:06:44 -0700100 * @return the list of actions at the egress edge switch
Toshio Koidea03915e2014-07-01 18:39:52 -0700101 */
Toshio Koide9aa4c0f2014-08-11 16:06:44 -0700102 public List<Action> getEgressActions() {
Toshio Koide2c67a2d2014-08-27 11:30:56 -0700103 return ImmutableList.copyOf(egressActions);
Toshio Koidea03915e2014-07-01 18:39:52 -0700104 }
Toshio Koide5c5ca102014-08-19 00:49:52 -0700105
106 @Override
107 public PacketMatch getMatch() {
108 return match;
109 }
110
111 @Override
Toshio Koided7d550c2014-08-21 16:08:55 -0700112 public List<MatchActionOperations> compile(Operator op,
113 MatchActionIdGenerator maIdGenerator,
114 MatchActionOperationsIdGenerator maoIdGenerator) {
Toshio Koidea0c9e012014-08-20 16:29:28 -0700115 switch (op) {
116 case ADD:
117 return compileAddOperation(maIdGenerator, maoIdGenerator);
118 case REMOVE:
119 return compileRemoveOperation();
120 default:
121 throw new UnsupportedOperationException("Unknown operation.");
122 }
123 }
124
125 private MatchAction createMatchAction(SwitchPort port, List<Action> actions,
126 MatchActionIdGenerator maIdGenerator) {
127 checkNotNull(port);
128 checkNotNull(actions);
129
130 return new MatchAction(maIdGenerator.getNewId(), port, getMatch(), actions);
131 }
132
133 /**
134 * Generates MatchAactionOperations at inner ports and at the egress switch.
135 *
136 * @param egressSwitch the egress switch of the tree
137 * @param inPorts a map of a set of incoming ports on each switch in the
138 * tree
139 * @param outPorts a map of outgoing port on each switch in the tree
140 * @param maIdGenerator ID generator for MatchAction objects
141 * @param maoIdGenerator ID generator for MatchActionOperations objects
142 * @return the operations at inner ports and egress switch
143 */
144 private MatchActionOperations generateFirstAddOperations(
145 Dpid egressSwitch,
146 Map<Dpid, Set<PortNumber>> inPorts,
147 Map<Dpid, PortNumber> outPorts,
148 MatchActionIdGenerator maIdGenerator,
149 MatchActionOperationsIdGenerator maoIdGenerator) {
150 MatchActionOperations firstOps =
151 new MatchActionOperations(maoIdGenerator.getNewId());
152 for (Entry<Dpid, Set<PortNumber>> innerSw : inPorts.entrySet()) {
153 for (PortNumber innerPortNumber : innerSw.getValue()) {
154 SwitchPort innerPort = new SwitchPort(innerSw.getKey(), innerPortNumber);
155 MatchAction ma;
156 if (innerPort.getDpid().equals(egressSwitch)) {
157 ma = createMatchAction(innerPort, getEgressActions(), maIdGenerator);
158 } else {
159 PortNumber outputPortNumber = checkNotNull(
160 outPorts.get(innerPort.getDpid()),
161 String.format("The tree has no output port at %s",
162 innerPort.getDpid()));
163 ma = createMatchAction(innerPort,
164 Arrays.asList((Action) new OutputAction(outputPortNumber)),
165 maIdGenerator);
166 }
167 firstOps.addOperation(new MatchActionOperationEntry(
168 MatchActionOperations.Operator.ADD, ma));
169 }
170 }
171 return firstOps;
172 }
173
174 /**
175 * Generates MatchActionOperations for ingress switches in the tree.
176 *
177 * @param egressSwitch the egress switch of the tree
178 * @param outPorts a map of outgoing port on each switch in the tree
179 * @param maIdGenerator ID generator for MatchAction objects
180 * @param maoIdGenerator ID generator for MatchActionOperations objects
181 * @return operations at ingress switches in the tree
182 */
183 private MatchActionOperations generateSecondAddOperations(
184 Dpid egressSwitch,
185 Map<Dpid, PortNumber> outPorts,
186 MatchActionIdGenerator maIdGenerator,
187 MatchActionOperationsIdGenerator maoIdGenerator) {
188 MatchActionOperations secondOps =
189 new MatchActionOperations(maoIdGenerator.getNewId());
190 for (SwitchPort port : getIngressPorts()) {
191 PortNumber outputPort = outPorts.get(port.getDpid());
192 if (outputPort == null) {
193 if (port.getDpid().equals(egressSwitch)) {
194 MatchAction ma = createMatchAction(
195 port, getEgressActions(), maIdGenerator);
196 secondOps.addOperation(new MatchActionOperationEntry(
197 MatchActionOperations.Operator.ADD, ma));
198 } else {
199 throw new IllegalStateException(String.format(
200 "The switch %s specified as one of ingress ports "
201 + "does not have path to the egress switch.",
202 port.getDpid()));
203 }
204 } else {
205 MatchAction ma = createMatchAction(port,
206 Arrays.asList((Action) new OutputAction(outputPort)),
207 maIdGenerator);
208 secondOps.addOperation(new MatchActionOperationEntry(
209 MatchActionOperations.Operator.ADD, ma));
210 }
211 }
212 return secondOps;
213 }
214
215 private List<MatchActionOperations> compileAddOperation(
216 MatchActionIdGenerator maIdGenerator,
217 MatchActionOperationsIdGenerator maoIdGenerator) {
218 checkNotNull(tree);
219 checkState(tree.size() > 0, "Tree object has no link.");
220
221 // TODO: check consistency of the tree topology
222
223 // collect input ports and output ports checking consistency
224 Map<Dpid, PortNumber> outPorts = new HashMap<>();
225 Map<Dpid, Set<PortNumber>> inPorts = new HashMap<>();
226 for (FlowLink link : tree) {
227 SwitchPort srcPort = link.getSrcSwitchPort();
228 if (outPorts.containsKey(srcPort.getDpid())) {
229 throw new IllegalStateException(
230 String.format("Dpid:%s has multiple output ports.",
231 srcPort.getDpid()));
232 }
233 outPorts.put(srcPort.getDpid(), srcPort.getPortNumber());
234
235 SwitchPort dstPort = link.getDstSwitchPort();
236 Set<PortNumber> inPortNumbers = inPorts.get(dstPort.getDpid());
237 if (inPortNumbers == null) {
238 inPortNumbers = new HashSet<>();
239 }
240 inPortNumbers.add(dstPort.getPortNumber());
241 inPorts.put(dstPort.getDpid(), inPortNumbers);
242 }
243
244 // find the egress switch
245 Set<Dpid> egressSwitches = new HashSet<>(inPorts.keySet());
246 egressSwitches.removeAll(outPorts.keySet());
247 checkState(egressSwitches.size() == 1,
248 "The specified tree is not a single destination tree.");
249 Dpid egressSwitch = egressSwitches.iterator().next();
250
251 MatchActionOperations firstOps = generateFirstAddOperations(
252 egressSwitch, inPorts, outPorts, maIdGenerator, maoIdGenerator);
253 checkState(firstOps.size() > 0,
254 "No operations found for the first set of operations.");
255
256 MatchActionOperations secondOps = generateSecondAddOperations(
257 egressSwitch, outPorts, maIdGenerator, maoIdGenerator);
258 checkState(secondOps.size() > 0,
259 "No operations found for the second set of operations.");
260
261 return Arrays.asList(firstOps, secondOps);
262 }
263
264 private List<MatchActionOperations> compileRemoveOperation() {
Toshio Koide5c5ca102014-08-19 00:49:52 -0700265 // TODO Auto-generated method stub
Toshio Koidea0c9e012014-08-20 16:29:28 -0700266 throw new UnsupportedOperationException(
267 "REMOVE operation is not implemented yet.");
Toshio Koide5c5ca102014-08-19 00:49:52 -0700268 }
Toshio Koidea03915e2014-07-01 18:39:52 -0700269}