blob: 8a444d7111eb5a58074d652ff6143516d3ffbb4f [file] [log] [blame]
Jonathan Hartaa380972014-04-03 10:24:46 -07001package net.onrc.onos.core.intent.runtime;
Brian O'Connor67c6e662014-02-17 15:20:44 -08002
Yuta HIGUCHIafadeda2014-07-24 17:11:07 -07003import java.lang.ref.WeakReference;
Brian O'Connor6dc44e92014-02-24 21:23:46 -08004import java.util.ArrayList;
Brian O'Connor67c6e662014-02-17 15:20:44 -08005import java.util.HashSet;
6import java.util.List;
7import java.util.Map;
8import java.util.Set;
Yuta HIGUCHIafadeda2014-07-24 17:11:07 -07009import java.util.WeakHashMap;
Brian O'Connor6dc44e92014-02-24 21:23:46 -080010import java.util.concurrent.ExecutionException;
Brian O'Connor67c6e662014-02-17 15:20:44 -080011
12import net.floodlightcontroller.core.IFloodlightProviderService;
13import net.floodlightcontroller.core.IOFSwitch;
Brian O'Connor6dc44e92014-02-24 21:23:46 -080014import net.floodlightcontroller.core.internal.OFMessageFuture;
Jonathan Hart23701d12014-04-03 10:45:48 -070015import net.onrc.onos.core.flowprogrammer.IFlowPusherService;
Jonathan Hartaa380972014-04-03 10:24:46 -070016import net.onrc.onos.core.intent.FlowEntry;
Jonathan Hart23701d12014-04-03 10:45:48 -070017import net.onrc.onos.core.util.Pair;
Brian O'Connor67c6e662014-02-17 15:20:44 -080018
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070019import org.projectfloodlight.openflow.protocol.OFBarrierReply;
Brian O'Connor9b712f62014-02-20 14:22:20 -080020import org.slf4j.Logger;
21import org.slf4j.LoggerFactory;
22
Brian O'Connor67c6e662014-02-17 15:20:44 -080023/**
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070024 * This class is responsible for installing plans (lists of sets of FlowEntries)
25 * into local switches. In this context, a local switch is a switch for which
26 * this ONOS instance is the master. It also is responsible for sending barrier
27 * messages between sets.
Brian O'Connor67c6e662014-02-17 15:20:44 -080028 */
29
Brian O'Connor12861f72014-02-19 20:40:32 -080030public class PlanInstallRuntime {
Brian O'Connora15fb862014-06-12 23:38:54 -070031
Brian O'Connor67c6e662014-02-17 15:20:44 -080032 IFlowPusherService pusher;
33 IFloodlightProviderService provider;
Ray Milkeyec838942014-04-09 11:28:43 -070034 private static final Logger log = LoggerFactory.getLogger(PlanInstallRuntime.class);
Brian O'Connor67c6e662014-02-17 15:20:44 -080035
Brian O'Connora15fb862014-06-12 23:38:54 -070036 /**
37 * Constructor.
38 *
39 * @param provider the FloodlightProviderService for list of local switches
40 * @param pusher the FlowPusherService to use for FlowEntry installation
41 */
42 public PlanInstallRuntime(IFloodlightProviderService provider,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070043 IFlowPusherService pusher) {
Ray Milkey269ffb92014-04-03 14:43:30 -070044 this.provider = provider;
45 this.pusher = pusher;
Brian O'Connor67c6e662014-02-17 15:20:44 -080046 }
Ray Milkey269ffb92014-04-03 14:43:30 -070047
Brian O'Connora15fb862014-06-12 23:38:54 -070048 /**
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070049 * This class is a temporary class for collecting FlowMod installation
50 * information. It is largely used for debugging purposes, and it should not
51 * be depended on for other purposes.
Brian O'Connora15fb862014-06-12 23:38:54 -070052 * <p>
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070053 * TODO: This class should be wrapped into a more generic debugging
54 * framework when available.
Brian O'Connora15fb862014-06-12 23:38:54 -070055 */
Brian O'Connor2fab2f62014-02-26 12:40:01 -080056 private static class FlowModCount {
Yuta HIGUCHIafadeda2014-07-24 17:11:07 -070057 WeakReference<IOFSwitch> sw;
Ray Milkey269ffb92014-04-03 14:43:30 -070058 long modFlows = 0;
59 long delFlows = 0;
60 long errors = 0;
61
Brian O'Connora15fb862014-06-12 23:38:54 -070062 /**
63 * Constructor.
64 *
65 * @param sw the switch for FlowMod statistics collection
66 */
Ray Milkey269ffb92014-04-03 14:43:30 -070067 FlowModCount(IOFSwitch sw) {
Yuta HIGUCHIafadeda2014-07-24 17:11:07 -070068 this.sw = new WeakReference<>(sw);
Ray Milkey269ffb92014-04-03 14:43:30 -070069 }
70
Brian O'Connora15fb862014-06-12 23:38:54 -070071 /**
72 * Include the FlowEntry in this switch statistics object.
73 *
74 * @param entry the FlowEntry to count
75 */
Ray Milkey269ffb92014-04-03 14:43:30 -070076 void addFlowEntry(FlowEntry entry) {
77 switch (entry.getOperator()) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070078 case ADD:
79 modFlows++;
80 break;
81 case ERROR:
82 errors++;
83 break;
84 case REMOVE:
85 delFlows++;
86 break;
87 default:
88 break;
Ray Milkey269ffb92014-04-03 14:43:30 -070089 }
90 }
91
Brian O'Connora15fb862014-06-12 23:38:54 -070092 /**
93 * Returns a string representation of this object.
94 *
95 * @return string representation of this object
96 */
TeruUf9111652014-05-14 23:10:35 -070097 @Override
Ray Milkey269ffb92014-04-03 14:43:30 -070098 public String toString() {
Yuta HIGUCHIafadeda2014-07-24 17:11:07 -070099 final IOFSwitch swTemp = sw.get();
100 return "sw:" + ((swTemp == null) ? "disconnected" : swTemp.getStringId())
101 + ": modify " + modFlows + " delete " + delFlows + " error " + errors;
Ray Milkey269ffb92014-04-03 14:43:30 -0700102 }
103
Yuta HIGUCHIafadeda2014-07-24 17:11:07 -0700104 static Map<IOFSwitch, FlowModCount> map = new WeakHashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700105
Brian O'Connora15fb862014-06-12 23:38:54 -0700106 /**
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700107 * This function is used for collecting statistics information. It
108 * should be called for every FlowEntry that is pushed to the switch for
109 * accurate statistics.
Brian O'Connora15fb862014-06-12 23:38:54 -0700110 * <p>
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700111 * This class maintains a map of Switches and FlowModCount collection
112 * objects, which are used for collection.
Brian O'Connora15fb862014-06-12 23:38:54 -0700113 * <p>
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700114 * TODO: This should be refactored to use a more generic mechanism when
115 * available.
Brian O'Connora15fb862014-06-12 23:38:54 -0700116 *
117 * @param sw the switch that entry is being pushed to
118 * @param entry the FlowEntry being pushed
119 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700120 static void countFlowEntry(IOFSwitch sw, FlowEntry entry) {
121 FlowModCount count = map.get(sw);
122 if (count == null) {
123 count = new FlowModCount(sw);
124 map.put(sw, count);
125 }
126 count.addFlowEntry(entry);
127 }
128
Brian O'Connora15fb862014-06-12 23:38:54 -0700129 /**
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700130 * Reset the statistics collection. It should be called when required
131 * for debugging.
Brian O'Connora15fb862014-06-12 23:38:54 -0700132 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700133 static void startCount() {
134 map.clear();
135 }
136
Brian O'Connora15fb862014-06-12 23:38:54 -0700137 /**
138 * Print out the statistics information when required for debugging.
139 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700140 static void printCount() {
Pavlin Radoslavov424150c2014-04-09 12:12:36 -0700141 StringBuilder result = new StringBuilder();
142
143 result.append("FLOWMOD COUNT:\n");
Ray Milkey269ffb92014-04-03 14:43:30 -0700144 for (FlowModCount count : map.values()) {
Pavlin Radoslavov424150c2014-04-09 12:12:36 -0700145 result.append(count.toString() + '\n');
Ray Milkey269ffb92014-04-03 14:43:30 -0700146 }
147 if (map.values().isEmpty()) {
Pavlin Radoslavov424150c2014-04-09 12:12:36 -0700148 result.append("No flow mods installed\n");
Ray Milkey269ffb92014-04-03 14:43:30 -0700149 }
Pavlin Radoslavov964f8ae2014-04-18 16:44:14 -0700150 log.debug(result.toString());
Ray Milkey269ffb92014-04-03 14:43:30 -0700151 }
Brian O'Connor2fab2f62014-02-26 12:40:01 -0800152 }
Brian O'Connor67c6e662014-02-17 15:20:44 -0800153
Brian O'Connora15fb862014-06-12 23:38:54 -0700154 /**
155 * This function should be called to install the FlowEntries in the plan.
156 * <p>
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700157 * Each set of FlowEntries can be installed together, but all entries should
158 * be installed proceeded to the next set.
Brian O'Connora15fb862014-06-12 23:38:54 -0700159 * <p>
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700160 * TODO: This method lack coordination between the other ONOS instances
161 * before proceeded with the next set of entries
Brian O'Connora15fb862014-06-12 23:38:54 -0700162 *
163 * @param plan list of set of FlowEntries for installation on local switches
164 * @return true (we assume installation is successful)
165 */
Brian O'Connor488e5ed2014-02-20 19:50:01 -0800166 public boolean installPlan(List<Set<FlowEntry>> plan) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700167 long start = System.nanoTime();
168 Map<Long, IOFSwitch> switches = provider.getSwitches();
Brian O'Connor2fab2f62014-02-26 12:40:01 -0800169
Ray Milkey269ffb92014-04-03 14:43:30 -0700170 log.debug("IOFSwitches: {}", switches);
Ray Milkey269ffb92014-04-03 14:43:30 -0700171 FlowModCount.startCount();
172 for (Set<FlowEntry> phase : plan) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700173 Set<Pair<IOFSwitch, FlowEntry>> entries = new HashSet<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700174 Set<IOFSwitch> modifiedSwitches = new HashSet<>();
175
176 long step1 = System.nanoTime();
177 // convert flow entries and create pairs
178 for (FlowEntry entry : phase) {
179 IOFSwitch sw = switches.get(entry.getSwitch());
180 if (sw == null) {
181 // no active switch, skip this flow entry
182 log.debug("Skipping flow entry: {}", entry);
183 continue;
184 }
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700185 entries.add(new Pair<>(sw, entry));
Ray Milkey269ffb92014-04-03 14:43:30 -0700186 modifiedSwitches.add(sw);
187 FlowModCount.countFlowEntry(sw, entry);
188 }
189 long step2 = System.nanoTime();
190
191 // push flow entries to switches
192 log.debug("Pushing flow entries: {}", entries);
193 pusher.pushFlowEntries(entries);
194 long step3 = System.nanoTime();
195
Brian O'Connora15fb862014-06-12 23:38:54 -0700196 // insert a barrier after each phase on each modifiedSwitch
197 // wait for confirmation messages before proceeding
Ray Milkey269ffb92014-04-03 14:43:30 -0700198 List<Pair<IOFSwitch, OFMessageFuture<OFBarrierReply>>> barriers = new ArrayList<>();
199 for (IOFSwitch sw : modifiedSwitches) {
200 barriers.add(new Pair<>(sw, pusher.barrierAsync(sw)));
201 }
202 for (Pair<IOFSwitch, OFMessageFuture<OFBarrierReply>> pair : barriers) {
Sho SHIMIZU26d77892014-06-10 11:07:06 -0700203 IOFSwitch sw = pair.getFirst();
204 OFMessageFuture<OFBarrierReply> future = pair.getSecond();
Ray Milkey269ffb92014-04-03 14:43:30 -0700205 try {
206 future.get();
207 } catch (InterruptedException | ExecutionException e) {
208 log.error("Barrier message not received for sw: {}", sw);
209 }
210 }
211 long step4 = System.nanoTime();
Pavlin Radoslavov964f8ae2014-04-18 16:44:14 -0700212 log.debug("MEASUREMENT: convert: {} ns, push: {} ns, barrierWait: {} ns",
Ray Milkey269ffb92014-04-03 14:43:30 -0700213 step2 - step1, step3 - step2, step4 - step3);
214
215 }
216 long end = System.nanoTime();
Pavlin Radoslavov964f8ae2014-04-18 16:44:14 -0700217 log.debug("MEASUREMENT: Install plan: {} ns", (end - start));
Ray Milkey269ffb92014-04-03 14:43:30 -0700218 FlowModCount.printCount();
219
220 // TODO: we assume that the plan installation succeeds for now
221 return true;
Brian O'Connor67c6e662014-02-17 15:20:44 -0800222 }
Brian O'Connor67c6e662014-02-17 15:20:44 -0800223}