blob: 60e27372826cfd176f61a37e1f2e937f03a4b3b2 [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 Hart5302b6c2014-08-13 15:57:59 -070017import net.onrc.onos.core.util.Dpid;
Brian O'Connor67c6e662014-02-17 15:20:44 -080018
Pavlin Radoslavovb05aac92014-08-26 18:26:10 -070019import org.apache.commons.lang3.tuple.Pair;
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070020import org.projectfloodlight.openflow.protocol.OFBarrierReply;
Brian O'Connor9b712f62014-02-20 14:22:20 -080021import org.slf4j.Logger;
22import org.slf4j.LoggerFactory;
23
Brian O'Connor67c6e662014-02-17 15:20:44 -080024/**
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070025 * This class is responsible for installing plans (lists of sets of FlowEntries)
26 * into local switches. In this context, a local switch is a switch for which
27 * this ONOS instance is the master. It also is responsible for sending barrier
28 * messages between sets.
Brian O'Connor67c6e662014-02-17 15:20:44 -080029 */
30
Brian O'Connor12861f72014-02-19 20:40:32 -080031public class PlanInstallRuntime {
Brian O'Connora15fb862014-06-12 23:38:54 -070032
Brian O'Connor67c6e662014-02-17 15:20:44 -080033 IFlowPusherService pusher;
34 IFloodlightProviderService provider;
Ray Milkeyec838942014-04-09 11:28:43 -070035 private static final Logger log = LoggerFactory.getLogger(PlanInstallRuntime.class);
Brian O'Connor67c6e662014-02-17 15:20:44 -080036
Brian O'Connora15fb862014-06-12 23:38:54 -070037 /**
38 * Constructor.
39 *
40 * @param provider the FloodlightProviderService for list of local switches
41 * @param pusher the FlowPusherService to use for FlowEntry installation
42 */
43 public PlanInstallRuntime(IFloodlightProviderService provider,
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070044 IFlowPusherService pusher) {
Ray Milkey269ffb92014-04-03 14:43:30 -070045 this.provider = provider;
46 this.pusher = pusher;
Brian O'Connor67c6e662014-02-17 15:20:44 -080047 }
Ray Milkey269ffb92014-04-03 14:43:30 -070048
Brian O'Connora15fb862014-06-12 23:38:54 -070049 /**
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070050 * This class is a temporary class for collecting FlowMod installation
51 * information. It is largely used for debugging purposes, and it should not
52 * be depended on for other purposes.
Brian O'Connora15fb862014-06-12 23:38:54 -070053 * <p>
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070054 * TODO: This class should be wrapped into a more generic debugging
55 * framework when available.
Brian O'Connora15fb862014-06-12 23:38:54 -070056 */
Brian O'Connor2fab2f62014-02-26 12:40:01 -080057 private static class FlowModCount {
Yuta HIGUCHIafadeda2014-07-24 17:11:07 -070058 WeakReference<IOFSwitch> sw;
Ray Milkey269ffb92014-04-03 14:43:30 -070059 long modFlows = 0;
60 long delFlows = 0;
61 long errors = 0;
62
Brian O'Connora15fb862014-06-12 23:38:54 -070063 /**
64 * Constructor.
65 *
66 * @param sw the switch for FlowMod statistics collection
67 */
Ray Milkey269ffb92014-04-03 14:43:30 -070068 FlowModCount(IOFSwitch sw) {
Yuta HIGUCHIafadeda2014-07-24 17:11:07 -070069 this.sw = new WeakReference<>(sw);
Ray Milkey269ffb92014-04-03 14:43:30 -070070 }
71
Brian O'Connora15fb862014-06-12 23:38:54 -070072 /**
73 * Include the FlowEntry in this switch statistics object.
74 *
75 * @param entry the FlowEntry to count
76 */
Ray Milkey269ffb92014-04-03 14:43:30 -070077 void addFlowEntry(FlowEntry entry) {
78 switch (entry.getOperator()) {
Brian O'Connorc67f9fa2014-08-07 18:17:46 -070079 case ADD:
80 modFlows++;
81 break;
82 case ERROR:
83 errors++;
84 break;
85 case REMOVE:
86 delFlows++;
87 break;
88 default:
89 break;
Ray Milkey269ffb92014-04-03 14:43:30 -070090 }
91 }
92
Brian O'Connora15fb862014-06-12 23:38:54 -070093 /**
94 * Returns a string representation of this object.
95 *
96 * @return string representation of this object
97 */
TeruUf9111652014-05-14 23:10:35 -070098 @Override
Ray Milkey269ffb92014-04-03 14:43:30 -070099 public String toString() {
Yuta HIGUCHIafadeda2014-07-24 17:11:07 -0700100 final IOFSwitch swTemp = sw.get();
101 return "sw:" + ((swTemp == null) ? "disconnected" : swTemp.getStringId())
102 + ": modify " + modFlows + " delete " + delFlows + " error " + errors;
Ray Milkey269ffb92014-04-03 14:43:30 -0700103 }
104
Yuta HIGUCHIafadeda2014-07-24 17:11:07 -0700105 static Map<IOFSwitch, FlowModCount> map = new WeakHashMap<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700106
Brian O'Connora15fb862014-06-12 23:38:54 -0700107 /**
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700108 * This function is used for collecting statistics information. It
109 * should be called for every FlowEntry that is pushed to the switch for
110 * accurate statistics.
Brian O'Connora15fb862014-06-12 23:38:54 -0700111 * <p>
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700112 * This class maintains a map of Switches and FlowModCount collection
113 * objects, which are used for collection.
Brian O'Connora15fb862014-06-12 23:38:54 -0700114 * <p>
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700115 * TODO: This should be refactored to use a more generic mechanism when
116 * available.
Brian O'Connora15fb862014-06-12 23:38:54 -0700117 *
118 * @param sw the switch that entry is being pushed to
119 * @param entry the FlowEntry being pushed
120 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700121 static void countFlowEntry(IOFSwitch sw, FlowEntry entry) {
122 FlowModCount count = map.get(sw);
123 if (count == null) {
124 count = new FlowModCount(sw);
125 map.put(sw, count);
126 }
127 count.addFlowEntry(entry);
128 }
129
Brian O'Connora15fb862014-06-12 23:38:54 -0700130 /**
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700131 * Reset the statistics collection. It should be called when required
132 * for debugging.
Brian O'Connora15fb862014-06-12 23:38:54 -0700133 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700134 static void startCount() {
135 map.clear();
136 }
137
Brian O'Connora15fb862014-06-12 23:38:54 -0700138 /**
139 * Print out the statistics information when required for debugging.
140 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700141 static void printCount() {
Pavlin Radoslavov424150c2014-04-09 12:12:36 -0700142 StringBuilder result = new StringBuilder();
143
144 result.append("FLOWMOD COUNT:\n");
Ray Milkey269ffb92014-04-03 14:43:30 -0700145 for (FlowModCount count : map.values()) {
Pavlin Radoslavov424150c2014-04-09 12:12:36 -0700146 result.append(count.toString() + '\n');
Ray Milkey269ffb92014-04-03 14:43:30 -0700147 }
148 if (map.values().isEmpty()) {
Pavlin Radoslavov424150c2014-04-09 12:12:36 -0700149 result.append("No flow mods installed\n");
Ray Milkey269ffb92014-04-03 14:43:30 -0700150 }
Pavlin Radoslavov964f8ae2014-04-18 16:44:14 -0700151 log.debug(result.toString());
Ray Milkey269ffb92014-04-03 14:43:30 -0700152 }
Brian O'Connor2fab2f62014-02-26 12:40:01 -0800153 }
Brian O'Connor67c6e662014-02-17 15:20:44 -0800154
Brian O'Connora15fb862014-06-12 23:38:54 -0700155 /**
156 * This function should be called to install the FlowEntries in the plan.
157 * <p>
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700158 * Each set of FlowEntries can be installed together, but all entries should
159 * be installed proceeded to the next set.
Brian O'Connora15fb862014-06-12 23:38:54 -0700160 * <p>
Brian O'Connorc67f9fa2014-08-07 18:17:46 -0700161 * TODO: This method lack coordination between the other ONOS instances
162 * before proceeded with the next set of entries
Brian O'Connora15fb862014-06-12 23:38:54 -0700163 *
164 * @param plan list of set of FlowEntries for installation on local switches
165 * @return true (we assume installation is successful)
166 */
Brian O'Connor488e5ed2014-02-20 19:50:01 -0800167 public boolean installPlan(List<Set<FlowEntry>> plan) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700168 long start = System.nanoTime();
169 Map<Long, IOFSwitch> switches = provider.getSwitches();
Brian O'Connor2fab2f62014-02-26 12:40:01 -0800170
Ray Milkey269ffb92014-04-03 14:43:30 -0700171 log.debug("IOFSwitches: {}", switches);
Ray Milkey269ffb92014-04-03 14:43:30 -0700172 FlowModCount.startCount();
173 for (Set<FlowEntry> phase : plan) {
Jonathan Hart5302b6c2014-08-13 15:57:59 -0700174 Set<Pair<Dpid, FlowEntry>> entries = new HashSet<>();
Ray Milkey269ffb92014-04-03 14:43:30 -0700175 Set<IOFSwitch> modifiedSwitches = new HashSet<>();
176
177 long step1 = System.nanoTime();
178 // convert flow entries and create pairs
179 for (FlowEntry entry : phase) {
180 IOFSwitch sw = switches.get(entry.getSwitch());
181 if (sw == null) {
182 // no active switch, skip this flow entry
183 log.debug("Skipping flow entry: {}", entry);
184 continue;
185 }
Jonathan Hart5302b6c2014-08-13 15:57:59 -0700186 entries.add(Pair.of(new Dpid(entry.getSwitch()), entry));
Ray Milkey269ffb92014-04-03 14:43:30 -0700187 modifiedSwitches.add(sw);
188 FlowModCount.countFlowEntry(sw, entry);
189 }
190 long step2 = System.nanoTime();
191
192 // push flow entries to switches
193 log.debug("Pushing flow entries: {}", entries);
194 pusher.pushFlowEntries(entries);
195 long step3 = System.nanoTime();
196
Brian O'Connora15fb862014-06-12 23:38:54 -0700197 // insert a barrier after each phase on each modifiedSwitch
198 // wait for confirmation messages before proceeding
Ray Milkey269ffb92014-04-03 14:43:30 -0700199 List<Pair<IOFSwitch, OFMessageFuture<OFBarrierReply>>> barriers = new ArrayList<>();
200 for (IOFSwitch sw : modifiedSwitches) {
Jonathan Hart5302b6c2014-08-13 15:57:59 -0700201 barriers.add(Pair.of(sw, pusher.barrierAsync(new Dpid(sw.getId()))));
Ray Milkey269ffb92014-04-03 14:43:30 -0700202 }
203 for (Pair<IOFSwitch, OFMessageFuture<OFBarrierReply>> pair : barriers) {
Pavlin Radoslavovb05aac92014-08-26 18:26:10 -0700204 IOFSwitch sw = pair.getLeft();
205 OFMessageFuture<OFBarrierReply> future = pair.getRight();
Ray Milkey269ffb92014-04-03 14:43:30 -0700206 try {
207 future.get();
208 } catch (InterruptedException | ExecutionException e) {
209 log.error("Barrier message not received for sw: {}", sw);
210 }
211 }
212 long step4 = System.nanoTime();
Pavlin Radoslavov964f8ae2014-04-18 16:44:14 -0700213 log.debug("MEASUREMENT: convert: {} ns, push: {} ns, barrierWait: {} ns",
Ray Milkey269ffb92014-04-03 14:43:30 -0700214 step2 - step1, step3 - step2, step4 - step3);
215
216 }
217 long end = System.nanoTime();
Pavlin Radoslavov964f8ae2014-04-18 16:44:14 -0700218 log.debug("MEASUREMENT: Install plan: {} ns", (end - start));
Ray Milkey269ffb92014-04-03 14:43:30 -0700219 FlowModCount.printCount();
220
221 // TODO: we assume that the plan installation succeeds for now
222 return true;
Brian O'Connor67c6e662014-02-17 15:20:44 -0800223 }
Brian O'Connor67c6e662014-02-17 15:20:44 -0800224}