blob: 6fbed8a697a7d0065f72af26c6147da30cc305b2 [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 Koide9aa4c0f2014-08-11 16:06:44 -070010import java.util.List;
Toshio Koidea0c9e012014-08-20 16:29:28 -070011import java.util.Map;
12import java.util.Map.Entry;
Toshio Koidea03915e2014-07-01 18:39:52 -070013import java.util.Set;
14
Toshio Koided7d550c2014-08-21 16:08:55 -070015import net.onrc.onos.api.flowmanager.FlowBatchOperation.Operator;
Toshio Koidea0c9e012014-08-20 16:29:28 -070016import net.onrc.onos.core.matchaction.MatchAction;
Toshio Koided7d550c2014-08-21 16:08:55 -070017import net.onrc.onos.core.matchaction.MatchActionIdGenerator;
Toshio Koidea0c9e012014-08-20 16:29:28 -070018import net.onrc.onos.core.matchaction.MatchActionOperationEntry;
Ray Milkey42ae1b52014-08-15 16:37:06 -070019import net.onrc.onos.core.matchaction.MatchActionOperations;
Toshio Koided7d550c2014-08-21 16:08:55 -070020import net.onrc.onos.core.matchaction.MatchActionOperationsIdGenerator;
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070021import net.onrc.onos.core.matchaction.action.Action;
Toshio Koidea0c9e012014-08-20 16:29:28 -070022import net.onrc.onos.core.matchaction.action.OutputAction;
Toshio Koidea03915e2014-07-01 18:39:52 -070023import net.onrc.onos.core.matchaction.match.PacketMatch;
Toshio Koidea0c9e012014-08-20 16:29:28 -070024import net.onrc.onos.core.util.Dpid;
25import net.onrc.onos.core.util.PortNumber;
Toshio Koidea03915e2014-07-01 18:39:52 -070026import net.onrc.onos.core.util.SwitchPort;
27
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070028import com.google.common.collect.ImmutableList;
29import com.google.common.collect.ImmutableSet;
30
Toshio Koidea03915e2014-07-01 18:39:52 -070031/**
Toshio Koidea0c9e012014-08-20 16:29:28 -070032 * A {@link Flow} object expressing the multipoints-to-point tree flow for the
33 * packet layer.
Toshio Koidea03915e2014-07-01 18:39:52 -070034 * <p>
Toshio Koidea0c9e012014-08-20 16:29:28 -070035 * NOTE: This class might generate the {@link MatchAction} operations which
36 * includes the MAC address modifications or other the label-switching-like
37 * schemes.
Toshio Koidea03915e2014-07-01 18:39:52 -070038 */
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070039public class SingleDstTreeFlow extends Flow {
40 private final PacketMatch match;
41 private final Set<SwitchPort> ingressPorts;
42 private final Tree tree;
Toshio Koidea0c9e012014-08-20 16:29:28 -070043 private final List<Action> egressActions;
Toshio Koidea03915e2014-07-01 18:39:52 -070044
45 /**
46 * Creates new instance using Tree object.
47 *
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070048 * @param id ID for this object
49 * @param match the traffic filter for the tree
50 * @param ingressPorts the set of ingress ports of the tree
51 * @param tree the Tree object specifying tree topology for this object
Toshio Koidea0c9e012014-08-20 16:29:28 -070052 * @param egressActions the list of {@link Action} objects to be executed at
53 * the egress edge switch
Toshio Koidea03915e2014-07-01 18:39:52 -070054 */
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070055 public SingleDstTreeFlow(FlowId id, PacketMatch match,
Toshio Koidea0c9e012014-08-20 16:29:28 -070056 Collection<SwitchPort> ingressPorts, Tree tree, List<Action> egressActions) {
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070057 super(id);
58 this.match = checkNotNull(match);
59 this.ingressPorts = ImmutableSet.copyOf(checkNotNull(ingressPorts));
60 this.tree = checkNotNull(tree);
Toshio Koidea0c9e012014-08-20 16:29:28 -070061 this.egressActions = ImmutableList.copyOf(checkNotNull(egressActions));
Toshio Koidea03915e2014-07-01 18:39:52 -070062
63 // TODO: check if the tree is a MP2P tree.
Toshio Koidea0c9e012014-08-20 16:29:28 -070064 // TODO: check consistency between ingressPorts and tree topology.
Toshio Koidea03915e2014-07-01 18:39:52 -070065 }
66
Toshio Koidea03915e2014-07-01 18:39:52 -070067 /**
68 * Gets the ingress ports of the tree.
69 *
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070070 * @return the ingress ports of the tree
Toshio Koidea03915e2014-07-01 18:39:52 -070071 */
72 public Collection<SwitchPort> getIngressPorts() {
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070073 return ingressPorts;
Toshio Koidea03915e2014-07-01 18:39:52 -070074 }
75
76 /**
77 * Gets the tree.
78 *
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070079 * @return the tree object
Toshio Koidea03915e2014-07-01 18:39:52 -070080 */
81 public Tree getTree() {
82 return tree;
83 }
84
85 /**
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070086 * Gets the list of actions at the egress edge switch.
Toshio Koidea03915e2014-07-01 18:39:52 -070087 *
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070088 * @return the list of actions at the egress edge switch
Toshio Koidea03915e2014-07-01 18:39:52 -070089 */
Toshio Koide9aa4c0f2014-08-11 16:06:44 -070090 public List<Action> getEgressActions() {
Toshio Koidea0c9e012014-08-20 16:29:28 -070091 return egressActions;
Toshio Koidea03915e2014-07-01 18:39:52 -070092 }
Toshio Koide5c5ca102014-08-19 00:49:52 -070093
94 @Override
95 public PacketMatch getMatch() {
96 return match;
97 }
98
99 @Override
Toshio Koided7d550c2014-08-21 16:08:55 -0700100 public List<MatchActionOperations> compile(Operator op,
101 MatchActionIdGenerator maIdGenerator,
102 MatchActionOperationsIdGenerator maoIdGenerator) {
Toshio Koidea0c9e012014-08-20 16:29:28 -0700103 switch (op) {
104 case ADD:
105 return compileAddOperation(maIdGenerator, maoIdGenerator);
106 case REMOVE:
107 return compileRemoveOperation();
108 default:
109 throw new UnsupportedOperationException("Unknown operation.");
110 }
111 }
112
113 private MatchAction createMatchAction(SwitchPort port, List<Action> actions,
114 MatchActionIdGenerator maIdGenerator) {
115 checkNotNull(port);
116 checkNotNull(actions);
117
118 return new MatchAction(maIdGenerator.getNewId(), port, getMatch(), actions);
119 }
120
121 /**
122 * Generates MatchAactionOperations at inner ports and at the egress switch.
123 *
124 * @param egressSwitch the egress switch of the tree
125 * @param inPorts a map of a set of incoming ports on each switch in the
126 * tree
127 * @param outPorts a map of outgoing port on each switch in the tree
128 * @param maIdGenerator ID generator for MatchAction objects
129 * @param maoIdGenerator ID generator for MatchActionOperations objects
130 * @return the operations at inner ports and egress switch
131 */
132 private MatchActionOperations generateFirstAddOperations(
133 Dpid egressSwitch,
134 Map<Dpid, Set<PortNumber>> inPorts,
135 Map<Dpid, PortNumber> outPorts,
136 MatchActionIdGenerator maIdGenerator,
137 MatchActionOperationsIdGenerator maoIdGenerator) {
138 MatchActionOperations firstOps =
139 new MatchActionOperations(maoIdGenerator.getNewId());
140 for (Entry<Dpid, Set<PortNumber>> innerSw : inPorts.entrySet()) {
141 for (PortNumber innerPortNumber : innerSw.getValue()) {
142 SwitchPort innerPort = new SwitchPort(innerSw.getKey(), innerPortNumber);
143 MatchAction ma;
144 if (innerPort.getDpid().equals(egressSwitch)) {
145 ma = createMatchAction(innerPort, getEgressActions(), maIdGenerator);
146 } else {
147 PortNumber outputPortNumber = checkNotNull(
148 outPorts.get(innerPort.getDpid()),
149 String.format("The tree has no output port at %s",
150 innerPort.getDpid()));
151 ma = createMatchAction(innerPort,
152 Arrays.asList((Action) new OutputAction(outputPortNumber)),
153 maIdGenerator);
154 }
155 firstOps.addOperation(new MatchActionOperationEntry(
156 MatchActionOperations.Operator.ADD, ma));
157 }
158 }
159 return firstOps;
160 }
161
162 /**
163 * Generates MatchActionOperations for ingress switches in the tree.
164 *
165 * @param egressSwitch the egress switch of the tree
166 * @param outPorts a map of outgoing port on each switch in the tree
167 * @param maIdGenerator ID generator for MatchAction objects
168 * @param maoIdGenerator ID generator for MatchActionOperations objects
169 * @return operations at ingress switches in the tree
170 */
171 private MatchActionOperations generateSecondAddOperations(
172 Dpid egressSwitch,
173 Map<Dpid, PortNumber> outPorts,
174 MatchActionIdGenerator maIdGenerator,
175 MatchActionOperationsIdGenerator maoIdGenerator) {
176 MatchActionOperations secondOps =
177 new MatchActionOperations(maoIdGenerator.getNewId());
178 for (SwitchPort port : getIngressPorts()) {
179 PortNumber outputPort = outPorts.get(port.getDpid());
180 if (outputPort == null) {
181 if (port.getDpid().equals(egressSwitch)) {
182 MatchAction ma = createMatchAction(
183 port, getEgressActions(), maIdGenerator);
184 secondOps.addOperation(new MatchActionOperationEntry(
185 MatchActionOperations.Operator.ADD, ma));
186 } else {
187 throw new IllegalStateException(String.format(
188 "The switch %s specified as one of ingress ports "
189 + "does not have path to the egress switch.",
190 port.getDpid()));
191 }
192 } else {
193 MatchAction ma = createMatchAction(port,
194 Arrays.asList((Action) new OutputAction(outputPort)),
195 maIdGenerator);
196 secondOps.addOperation(new MatchActionOperationEntry(
197 MatchActionOperations.Operator.ADD, ma));
198 }
199 }
200 return secondOps;
201 }
202
203 private List<MatchActionOperations> compileAddOperation(
204 MatchActionIdGenerator maIdGenerator,
205 MatchActionOperationsIdGenerator maoIdGenerator) {
206 checkNotNull(tree);
207 checkState(tree.size() > 0, "Tree object has no link.");
208
209 // TODO: check consistency of the tree topology
210
211 // collect input ports and output ports checking consistency
212 Map<Dpid, PortNumber> outPorts = new HashMap<>();
213 Map<Dpid, Set<PortNumber>> inPorts = new HashMap<>();
214 for (FlowLink link : tree) {
215 SwitchPort srcPort = link.getSrcSwitchPort();
216 if (outPorts.containsKey(srcPort.getDpid())) {
217 throw new IllegalStateException(
218 String.format("Dpid:%s has multiple output ports.",
219 srcPort.getDpid()));
220 }
221 outPorts.put(srcPort.getDpid(), srcPort.getPortNumber());
222
223 SwitchPort dstPort = link.getDstSwitchPort();
224 Set<PortNumber> inPortNumbers = inPorts.get(dstPort.getDpid());
225 if (inPortNumbers == null) {
226 inPortNumbers = new HashSet<>();
227 }
228 inPortNumbers.add(dstPort.getPortNumber());
229 inPorts.put(dstPort.getDpid(), inPortNumbers);
230 }
231
232 // find the egress switch
233 Set<Dpid> egressSwitches = new HashSet<>(inPorts.keySet());
234 egressSwitches.removeAll(outPorts.keySet());
235 checkState(egressSwitches.size() == 1,
236 "The specified tree is not a single destination tree.");
237 Dpid egressSwitch = egressSwitches.iterator().next();
238
239 MatchActionOperations firstOps = generateFirstAddOperations(
240 egressSwitch, inPorts, outPorts, maIdGenerator, maoIdGenerator);
241 checkState(firstOps.size() > 0,
242 "No operations found for the first set of operations.");
243
244 MatchActionOperations secondOps = generateSecondAddOperations(
245 egressSwitch, outPorts, maIdGenerator, maoIdGenerator);
246 checkState(secondOps.size() > 0,
247 "No operations found for the second set of operations.");
248
249 return Arrays.asList(firstOps, secondOps);
250 }
251
252 private List<MatchActionOperations> compileRemoveOperation() {
Toshio Koide5c5ca102014-08-19 00:49:52 -0700253 // TODO Auto-generated method stub
Toshio Koidea0c9e012014-08-20 16:29:28 -0700254 throw new UnsupportedOperationException(
255 "REMOVE operation is not implemented yet.");
Toshio Koide5c5ca102014-08-19 00:49:52 -0700256 }
Toshio Koidea03915e2014-07-01 18:39:52 -0700257}